@ -752,62 +752,76 @@ function checkPostForMentions(post, mentions, max) {
var splitedPostsCount = 1 ;
var splitedPostsCount = 1 ;
var usePostSpliting = false ;
var usePostSpliting = false ;
function replyTextKeypress ( e ) {
function replyTextInput ( e ) {
e = e || event ;
e = e || event ;
var $this = $ ( this ) ;
var $this = $ ( this ) ;
var tweetForm = $this . parents ( "form" ) ;
var tweetForm = $this . parents ( "form" ) ;
if ( tweetForm != undefined ) {
if ( tweetForm != undefined ) {
if ( $ . Options . getUnicodeConversionOpt ( ) !== "disable" )
if ( $ . Options . getUnicodeConversionOpt ( ) !== "disable" )
$this . val ( convert2Unicodes ( $this . val ( ) , $this ) ) ;
$this . val ( convert2Unicodes ( $this . val ( ) , $this ) ) ;
var c = 140 - $this . val ( ) . length ;
if ( usePostSpliting && ! $this . parents ( '.directMessages' ) . length ) {
if ( usePostSpliting && ! $this . parents ( '.directMessages' ) . length ) {
var $tas = tweetForm . find ( "textarea" ) ;
var $tas = tweetForm . find ( "textarea" ) ;
splitedPostsCount = $tas . length ;
splitedPostsCount = $tas . length ;
if ( $this . hasClass ( 'splited-post' ) )
var icurrentta = $tas . index ( this ) ; // current textarea $tas index
$this . css ( 'height' , '28px' ) ;
if ( splitedPostsCount > 1 )
var pml = getPostSplitingPML ( ) ;
else
var pml = 140 ;
var cci = getPostSpittingCI ( icurrentta ) ;
var caretPos = $this . caret ( ) ;
var reply _to = $this . attr ( 'data-reply-to' ) ;
var reply _to = $this . attr ( 'data-reply-to' ) ;
for ( var i = 0 ; i < $tas . length ; i ++ ) {
var pml = 140 - ( i + 1 ) . toString ( ) . length - splitedPostsCount . toString ( ) . length - 4 ;
//if mention exists, we shouldn't add it while posting.
if ( typeof ( reply _to ) !== 'undefined' &&
! checkPostForMentions ( $tas [ i ] . value , reply _to , pml - reply _to . length ) ) {
pml -= reply _to . length ;
}
for ( var i = 0 ; i < $tas . length ; i ++ ) {
if ( $tas [ i ] . value . length > pml ) {
if ( $tas [ i ] . value . length > pml ) {
var endings = $tas [ i ] . value . match ( / |,|;|\.|:|\/|\?|\!|\\|'|"|\n|\t/g ) ;
if ( pml === 140 )
var ci = $tas [ i ] . value . lastIndexOf ( endings [ endings . length - 1 ] ) ;
pml = getPostSplitingPML ( ) ;
for ( var j = endings . length - 2 ; j >= 0 && ci > pml ; j -- ) {
var ci = getPostSpittingCI ( i ) ;
ci = $tas [ i ] . value . lastIndexOf ( endings [ j ] , ci - 1 ) ;
}
ci = ( ci > pml ? pml : ci ) ;
if ( i < splitedPostsCount - 1 ) {
if ( i < splitedPostsCount - 1 ) {
$tas [ i + 1 ] . value = $tas [ i ] . value . substr ( ci ) + $tas [ i + 1 ] . value ;
$tas [ i + 1 ] . value = $tas [ i ] . value . substr ( ci ) + $tas [ i + 1 ] . value ;
$tas [ i ] . value = $tas [ i ] . value . substr ( 0 , ci ) ;
$tas [ i ] . value = $tas [ i ] . value . substr ( 0 , ci ) ;
if ( caretPos > cci ) {
caretPos -= ci ;
icurrentta += 1 ;
cci = getPostSpittingCI ( icurrentta ) ;
var $targetta = $ ( $tas [ icurrentta ] ) ;
} else if ( i === icurrentta )
$ ( $tas [ i ] ) . caret ( caretPos ) ;
} else {
} else {
var $oldta = $ ( $tas [ i ] ) ;
var $oldta = $ ( $tas [ i ] ) ;
if ( typeof ( $ . fn . textcomplete ) === 'function' )
if ( typeof ( $ . fn . textcomplete ) === 'function' ) {
$oldta . textcomplete ( 'destroy' ) ;
$oldta . textcomplete ( 'destroy' ) ;
e . stopImmediatePropagation ( ) ; // something goes wrong in $.fn.textcomplete if we don't stop this immediately
}
var $newta = $ ( $oldta ) . clone ( true ) ;
var $newta = $ ( $oldta ) . clone ( true ) ;
var cp = $oldta . val ( ) ;
var cp = $oldta . val ( ) ;
$oldta . val ( cp . substr ( 0 , ci ) ) ;
$oldta . on ( "click" , function ( e ) {
e . stopPropagation ( ) ;
this . style . height = '80px' ;
} ) ;
e . stopImmediatePropagation ( ) ;
$oldta . off ( 'keyup' ) ;
$oldta . on ( 'focusout' , function ( ) { this . style . height = '28px' ; } ) ; // FIXME move this to CSS
$oldta [ 0 ] . style . height = '28px' ; // FIXME move this to CSS
$oldta . addClass ( 'splited-post' ) ;
$oldta . after ( $newta ) ;
$oldta . after ( $newta ) ;
$newta . val ( cp . substr ( ci ) ) ;
$newta . val ( cp . substr ( ci ) ) ;
$oldta . val ( cp . substr ( 0 , ci ) ) ;
$tas = tweetForm . find ( "textarea" ) ;
$tas = tweetForm . find ( "textarea" ) ;
splitedPostsCount = $tas . length ;
splitedPostsCount = $tas . length ;
pml = getPostSplitingPML ( ) ;
$oldta . on ( 'focus' , function ( ) {
this . style . height = '80px' ;
} ) ;
$oldta . addClass ( 'splited-post' ) ;
$oldta . on ( 'focusout' , function ( ) { this . style . height = '28px' ; } ) ; // FIXME move this to CSS
if ( caretPos > cci ) {
caretPos -= ci ;
icurrentta += 1 ;
cci = getPostSpittingCI ( icurrentta ) ;
var $targetta = $newta ;
$oldta [ 0 ] . style . height = '28px' ; // FIXME move this to CSS
} else if ( i === icurrentta ) {
$ ( $tas [ i ] ) . caret ( caretPos ) ;
replyTextUpdateRemaining ( $tas [ i ] ) ;
if ( typeof ( $ . fn . textcomplete ) === 'function' )
setTextcompleteOn ( $tas [ i ] ) ;
}
}
}
} else if ( $tas . length > 1 && $tas [ i ] . value . length === 0 ) {
} else if ( $tas . length > 1 && $tas [ i ] . value . length === 0 ) {
@ -819,36 +833,113 @@ function replyTextKeypress(e) {
}
}
$tas = tweetForm . find ( "textarea" ) ;
$tas = tweetForm . find ( "textarea" ) ;
splitedPostsCount = $tas . length ;
splitedPostsCount = $tas . length ;
if ( splitedPostsCount > 1 )
pml = getPostSplitingPML ( ) ;
else
pml = 140 ;
caretPos = - 1 ;
if ( icurrentta >= i && icurrentta > 0 ) {
icurrentta -= 1 ;
cci = getPostSpittingCI ( icurrentta ) ;
}
var $targetta = $ ( $tas [ icurrentta ] ) ;
}
}
}
}
if ( typeof ( $newta ) !== 'undefined' && $newta [ 0 ] !== document . activeElement )
$newta . focus ( ) ;
c = 140 - $tas [ $tas . length - 1 ] . value . length - ( 2 * splitedPostsCount . toString ( ) . length ) - 4 ;
if ( typeof ( $targetta ) !== 'undefined' && $targetta [ 0 ] !== document . activeElement ) {
if ( typeof ( reply _to ) !== 'undefined' &&
$this = $targetta ;
! checkPostForMentions ( $tas [ $tas . length - 1 ] . value , reply _to , 140 - c - reply _to . length ) )
$this . focus ( ) ;
c -= reply _to . length ;
$this . caret ( caretPos ) ;
}
}
}
var remainingCount = tweetForm . find ( ".post-area-remaining" ) ;
}
if ( c < 0 )
function getPostSplitingPML ( ) {
remainingCount . addClass ( "warn" ) ;
var pml = 140 - ( i + 1 ) . toString ( ) . length - splitedPostsCount . toString ( ) . length - 4 ;
else
remainingCount . removeClass ( "warn" ) ;
if ( usePostSpliting && ! $this . parents ( '.directMessages' ) . length )
// if mention exists, we shouldn't add it while posting.
remainingCount . text ( splitedPostsCount . toString ( ) + ". post: " + c . toString ( ) ) ;
if ( typeof ( reply _to ) !== 'undefined' &&
else
! checkPostForMentions ( $tas [ i ] . value , reply _to , pml - reply _to . length ) ) {
remainingCount . text ( c . toString ( ) ) ;
pml -= reply _to . length ;
}
return pml ;
}
function getPostSpittingCI ( ita ) {
var ci ;
var endings = $tas [ ita ] . value . match ( / |,|;|\.|:|\/|\?|\!|\\|'|"|\n|\t/g ) ;
if ( endings ) {
ci = $tas [ ita ] . value . lastIndexOf ( endings [ endings . length - 1 ] ) ;
for ( var j = endings . length - 2 ; j >= 0 && ci > pml ; j -- ) {
ci = $tas [ ita ] . value . lastIndexOf ( endings [ j ] , ci - 1 ) ;
}
}
if ( ! ( ci > 0 ) )
ci = pml ;
return ( ci > pml ) ? pml : ci ;
}
}
function replyTextUpdateRemaining ( ta ) {
if ( ta === document . activeElement ) {
var $this = $ ( ta ) ;
var tweetForm = $this . closest ( 'form' ) ;
if ( tweetForm != undefined ) {
var remainingCount = tweetForm . find ( ".post-area-remaining" ) ;
var c = replyTextCountRemaining ( ta ) ;
if ( usePostSpliting && ! $this . parents ( '.directMessages' ) . length && splitedPostsCount > 1 )
remainingCount . text ( ( tweetForm . find ( "textarea" ) . index ( ta ) + 1 ) . toString ( ) + '/' + splitedPostsCount . toString ( ) + ": " + c . toString ( ) ) ;
else
remainingCount . text ( c . toString ( ) ) ;
var tweetAction = tweetForm . find ( ".post-submit" ) ;
if ( ! tweetAction . length ) tweetAction = tweetForm . find ( ".dm-submit" ) ;
var disable = false ;
$this . closest ( 'form' ) . find ( "textarea" ) . each ( function ( ) {
if ( replyTextCountRemaining ( this ) < 0 ) {
disable = true ; // alternatively we could call replyTextInput()
return false ;
}
} ) ;
if ( ! disable && c >= 0 && c < 140 && $this . val ( ) != $this . attr ( "data-reply-to" ) ) {
remainingCount . removeClass ( "warn" ) ;
$ . MAL . enableButton ( tweetAction ) ;
} else {
if ( disable )
remainingCount . addClass ( "warn" ) ;
$ . MAL . disableButton ( tweetAction ) ;
}
}
}
}
function replyTextCountRemaining ( ta ) {
var $this = $ ( ta ) ;
var c ;
if ( usePostSpliting && ! $this . parents ( '.directMessages' ) . length && splitedPostsCount > 1 ) {
c = 140 - ta . value . length - ( $this . closest ( 'form' ) . find ( "textarea" ) . index ( ta ) + 1 ) . toString ( ) . length - splitedPostsCount . toString ( ) . length - 4 ;
var reply _to = $this . attr ( 'data-reply-to' ) ;
if ( typeof ( reply _to ) !== 'undefined' &&
! checkPostForMentions ( ta . value , reply _to , 140 - c - reply _to . length ) )
c -= reply _to . length ;
} else
c = 140 - ta . value . length ;
return c ;
}
function replyTextKeySend ( e ) {
e = e || event ;
var $this = $ ( this ) ;
var tweetForm = $this . parents ( 'form' ) ;
if ( tweetForm != undefined ) {
var tweetAction = tweetForm . find ( ".post-submit" ) ;
var tweetAction = tweetForm . find ( ".post-submit" ) ;
if ( ! tweetAction . length ) tweetAction = tweetForm . find ( ".dm-submit" ) ;
if ( ! tweetAction . length ) tweetAction = tweetForm . find ( ".dm-submit" ) ;
if ( c >= 0 && c < 140 &&
$this . val ( ) != $this . attr ( "data-reply-to" ) ) {
$ . MAL . enableButton ( tweetAction ) ;
} else {
$ . MAL . disableButton ( tweetAction ) ;
}
if ( $ . Options . keyEnterToSend ( ) && $ ( '.dropdown-menu' ) . css ( 'display' ) == 'none' ) {
if ( $ . Options . keyEnterToSend ( ) && $ ( '.dropdown-menu' ) . css ( 'display' ) == 'none' ) {
if ( e . keyCode === 13 && ( ! e . metaKey && ! e . ctrlKey ) ) {
if ( e . keyCode === 13 && ( ! e . metaKey && ! e . ctrlKey ) ) {
@ -1510,7 +1601,9 @@ function initInterfaceCommon() {
$ ( ".undo-unicode" ) . click ( undoLastUnicode ) ;
$ ( ".undo-unicode" ) . click ( undoLastUnicode ) ;
var $replyText = $ ( ".post-area-new textarea" ) ;
var $replyText = $ ( ".post-area-new textarea" ) ;
$replyText . on ( "keyup" , replyTextKeypress ) ;
$replyText . on ( 'input' , replyTextInput ) ; // input event fires in modern browsers (IE9+) on any changes in textarea (and copypasting with mouse too)
$replyText . on ( 'input focus' , function ( ) { replyTextUpdateRemaining ( this ) ; } ) ;
$replyText . on ( 'keyup' , replyTextKeySend ) ;
$ ( ".open-profile-modal" ) . bind ( "click" , function ( e ) { e . stopPropagation ( ) ; } ) ;
$ ( ".open-profile-modal" ) . bind ( "click" , function ( e ) { e . stopPropagation ( ) ; } ) ;
//$( ".open-hashtag-modal").bind( "click", openHashtagModal );
//$( ".open-hashtag-modal").bind( "click", openHashtagModal );
@ -1530,25 +1623,25 @@ function initInterfaceCommon() {
if ( typeof ( $ . fn . textcomplete ) === 'function' ) {
if ( typeof ( $ . fn . textcomplete ) === 'function' ) {
$ ( 'textarea' )
$ ( 'textarea' )
. on ( 'focus' , function ( ) {
. on ( 'focus' , function ( ) { setTextcompleteOn ( this ) ; } )
var element = this ;
. on ( 'focusout' , function ( ) { $ ( this ) . textcomplete ( 'destroy' ) ; } )
// Cursor has not set yet. And wait 100ms to skip global click event.
setTimeout ( function ( ) {
// Cursor is ready.
$ ( element ) . textcomplete ( getMentionsForAutoComplete ( ) , {
'appendTo' : ( $ ( element ) . parents ( '.dashboard' ) . length > 0 ) ? $ ( element ) . parent ( ) : $ ( 'body' ) ,
'listPosition' : setTextcompleteDropdownListPos
} ) ;
} , 100 ) ;
} )
. on ( 'focusout' , function ( ) {
$ ( this ) . textcomplete ( 'destroy' ) ;
} )
;
;
}
}
}
}
function setTextcompleteOn ( element ) {
var $this = $ ( element ) ;
// Cursor has not set yet. And wait 100ms to skip global click event.
setTimeout ( function ( ) {
// Cursor is ready.
$this . textcomplete ( getMentionsForAutoComplete ( ) , {
'appendTo' : ( $this . parents ( '.dashboard' ) . length > 0 ) ? $this . parent ( ) : $ ( 'body' ) ,
'listPosition' : setTextcompleteDropdownListPos
} ) ;
} , 100 ) ;
}
// following workaround function is for calls from $.fn.textcomplete only
// following workaround function is for calls from $.fn.textcomplete only
// we need this because currently implementation of caret position detection is way too imperfect
// we need this because currently implementation of caret position detection is way too imperfect