2013-08-19 22:30:57 +09:00
2015-06-02 01:27:36 +09:00
/ * · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
· ·
· ·
· Q V I T T E R ·
· ·
2015-07-02 02:15:31 +09:00
· ·
2015-06-02 01:27:36 +09:00
· < o ) ·
· / _ //// ·
· ( _ _ _ _ / ·
· ( o < ·
· o > \ \ \ \ _ \ ·
2015-07-02 02:15:31 +09:00
· \ \ ) \ _ _ _ _ ) ·
· ·
2015-06-02 01:27:36 +09:00
· ·
· @ licstart The following is the entire license notice for the ·
· JavaScript code in this page . ·
· ·
· Copyright ( C ) 2015 Hannes Mannerheim and other contributors ·
2015-07-02 02:15:31 +09:00
· ·
2015-06-02 01:27:36 +09:00
· ·
· This program is free software : you can redistribute it and / or modify ·
· it under the terms of the GNU Affero General Public License as ·
· published by the Free Software Foundation , either version 3 of the ·
· License , or ( at your option ) any later version . ·
· ·
· This program is distributed in the hope that it will be useful , ·
· but WITHOUT ANY WARRANTY ; without even the implied warranty of ·
· MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the ·
· GNU Affero General Public License for more details . ·
· ·
· You should have received a copy of the GNU Affero General Public License ·
· along with this program . If not , see < http : //www.gnu.org/licenses/>. ·
· ·
2015-07-02 02:15:31 +09:00
· @ licend The above is the entire license notice ·
· for the JavaScript code in this page . ·
· ·
2015-06-02 01:27:36 +09:00
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · * /
2015-07-02 02:15:31 +09:00
2015-10-20 01:47:24 +09:00
// plugins can add translatons to this object
window . pluginTranslations = [ ] ;
2015-07-02 02:15:31 +09:00
// object to keep old states of streams in, to speed up stream change
2014-01-29 03:42:47 +09:00
window . oldStreams = new Object ( ) ;
2015-03-06 06:22:48 +09:00
// check our localStorage and make sure it's correct
checkLocalStorage ( ) ;
2015-09-06 07:26:33 +09:00
// don't let users inject html/scripts into their own user data... not that it matters, it is only displayed to themselves, but just to be 200% safe
window . loggedIn = iterateRecursiveReplaceHtmlSpecialChars ( window . loggedIn ) ;
2015-11-17 00:09:01 +09:00
// hack to supress basic auth popup, e.g. if the user has to tabs open and
// log out in one of them. but microsoft browsers doesn't support this
if ( typeof bowser . msie == 'undefined' && typeof bowser . msedge == 'undefined' ) {
window . apiRoot = window . apiRoot . replace ( '://' , '://x:x@' ) ;
}
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-14 16:46:07 +09:00
· Update stream on back button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-05-14 16:46:07 +09:00
window . onpopstate = function ( event ) {
if ( event && event . state ) {
display _spinner ( ) ;
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( pathToStreamRouter ( event . state . strm ) , false , false , function ( ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2015-09-18 08:42:52 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
}
}
2015-07-02 02:15:31 +09:00
2015-09-29 23:31:05 +09:00
/ * ·
·
· Discard error messages
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.discard-error-message' , function ( ) {
2016-01-18 23:26:54 +09:00
// don't nag on people
if ( $ ( this ) . parent ( ) . hasClass ( 'language-error-message' ) ) {
localStorageObjectCache _STORE ( 'languageErrorMessageDiscarded' , $ ( this ) . parent ( ) . attr ( 'data-language-name' ) , true ) ;
}
2015-11-17 04:27:40 +09:00
$ ( this ) . addClass ( 'clicked' ) ;
2016-01-18 23:26:54 +09:00
$ ( this ) . closest ( '.error-message, .language-error-message' ) . slideUp ( 100 , function ( ) {
2015-09-29 23:31:05 +09:00
$ ( this ) . remove ( ) ;
} ) ;
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-05-30 00:30:03 +09:00
· welcome text expand and collapse
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-09-01 06:53:09 +09:00
2015-05-30 00:30:03 +09:00
$ ( 'body' ) . on ( 'click' , '.show-full-welcome-text, .front-welcome-text:not(.expanded) sup' , function ( ) {
$ ( '.front-welcome-text' ) . toggleClass ( 'expanded' ) ;
if ( $ ( '.front-welcome-text' ) . hasClass ( 'expanded' ) ) {
var welcomeTextInnerObjectsHeightSum = $ ( '.front-welcome-text > p' ) . outerHeight ( ) + $ ( '.front-welcome-text > h1' ) . outerHeight ( ) + 50 ;
2015-07-02 02:15:31 +09:00
$ ( '.front-welcome-text' ) . css ( 'height' , welcomeTextInnerObjectsHeightSum + 'px' )
2015-05-30 00:30:03 +09:00
}
else {
$ ( '.front-welcome-text' ) . css ( 'height' , '180px' ) ;
$ ( '.front-welcome-text' ) . css ( 'overflow' , 'hidden' ) ;
var scrollTo = $ ( window ) . scrollTop ( ) - ( $ ( '.front-welcome-text' ) . outerHeight ( ) - 200 ) ;
if ( scrollTo < 0 ) { scrollTo = 0 ; }
2015-07-02 02:15:31 +09:00
$ ( 'html, body' ) . animate ( { scrollTop : scrollTo } , 300 , 'linear' ) ;
2015-05-30 00:30:03 +09:00
}
} ) ;
2015-07-02 02:15:31 +09:00
$ ( 'body' ) . on ( 'click' , '.welcome-text-register-link' , function ( ) {
2015-05-30 00:30:03 +09:00
var scrollTo = $ ( '#user-container' ) . offset ( ) . top ;
2015-07-02 02:15:31 +09:00
$ ( 'html, body' ) . animate ( { scrollTop : scrollTo } , 300 , 'linear' ) ;
2015-05-30 00:30:03 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2015-09-01 06:53:09 +09:00
/ * ·
·
· Check for tooltips to display
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( {
mouseover : function ( e ) {
removeAllTooltips ( ) ;
// convert title to tooltip
if ( $ ( e . target ) . is ( '[title]' ) ) {
2015-09-07 03:31:25 +09:00
var titleAttribute = replaceHtmlSpecialChars ( $ ( e . target ) . attr ( 'title' ) ) ; // can contain malicious code
$ ( e . target ) . attr ( 'data-tooltip' , titleAttribute ) ;
2015-09-01 06:53:09 +09:00
$ ( e . target ) . removeAttr ( 'title' ) ;
}
2015-09-15 10:58:11 +09:00
// regular tooltips
2015-09-01 06:53:09 +09:00
if ( $ ( e . target ) . is ( '[data-tooltip]' ) ) {
2016-01-25 06:02:43 +09:00
var tooltipClass = '' ;
2015-09-15 10:58:11 +09:00
tooltip _data = $ ( e . target ) . attr ( 'data-tooltip' ) ;
2016-01-25 06:02:43 +09:00
// if embedded content is hidden, we show it in tooltips
if ( $ ( '#feed-body' ) . hasClass ( 'embedded-content-hidden-by-user' )
&& ! $ ( e . target ) . is ( '.oembed-item' )
&& $ ( e . target ) . closest ( '.queet' ) . length > 0
&& $ ( e . target ) . closest ( '.queet' ) . find ( '.oembed-item[href="' + $ ( e . target ) . attr ( 'href' ) + '"]' ) . length > 0 ) {
tooltip _data = $ ( e . target ) . closest ( '.queet' ) . find ( '.oembed-item[href="' + $ ( e . target ) . attr ( 'href' ) + '"]' ) . html ( ) ;
tooltipClass = 'oembed' ;
}
else if ( $ ( '#feed-body' ) . hasClass ( 'embedded-content-hidden-by-user' )
&& ! $ ( e . target ) . is ( '.attachment-thumb' )
&& $ ( e . target ) . closest ( '.queet' ) . length > 0
&& $ ( e . target ) . text ( ) . indexOf ( '/attachment/' ) > - 1 ) {
// local attachments has /attachment/-url in its href attribute
if ( $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container[data-local-attachment-url="' + $ ( e . target ) . attr ( 'href' ) + '"]' ) . length > 0 ) {
tooltip _data = $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container[data-local-attachment-url="' + $ ( e . target ) . attr ( 'href' ) + '"]' ) . outerHTML ( ) ;
tooltipClass = 'thumb' ;
}
// remote attachments are identified by full url
else if ( $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container[href="' + $ ( e . target ) . attr ( 'data-tooltip' ) + '"]' ) . length > 0 ) {
tooltip _data = $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container[href="' + $ ( e . target ) . attr ( 'data-tooltip' ) + '"]' ) . outerHTML ( ) ;
tooltipClass = 'thumb' ;
}
2016-01-29 05:12:34 +09:00
// sometimes the attachment link in the queet text does not give us any clue to
// which attachment it is referring to. but if it is the only link and there is
// exactly one attachment, we can safely assume that the link is referring to
// that attachment
else if ( $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container' ) . length == 1
&& $ ( e . target ) . closest ( '.queet-text' ) . find ( 'a.attachment' ) . length == 1 ) {
tooltip _data = $ ( e . target ) . closest ( '.queet' ) . find ( '.thumb-container' ) . outerHTML ( ) ;
tooltipClass = 'thumb' ;
}
2016-01-25 06:02:43 +09:00
}
else if ( $ ( '#feed-body' ) . hasClass ( 'quotes-hidden-by-user' )
&& ! $ ( e . target ) . is ( '.quote-link-container' )
&& $ ( e . target ) . is ( '[data-quote-url]' )
&& $ ( e . target ) . closest ( '.queet-text' ) . find ( '.quote-link-container[data-quote-url="' + $ ( e . target ) . attr ( 'data-quote-url' ) + '"]' ) . length > 0 ) {
tooltip _data = $ ( e . target ) . closest ( '.queet-text' ) . find ( '.quote-link-container[data-quote-url="' + $ ( e . target ) . attr ( 'data-quote-url' ) + '"]' ) . html ( ) ;
tooltipClass = 'quote' ;
}
var tooltipElement = $ ( '<div class="tooltip ' + tooltipClass + '" lang="' + window . selectedLanguage + '">' + tooltip _data + '</div>' ) ;
2015-09-15 01:04:27 +09:00
var tooltipCaret = $ ( '<div class="tooltip-caret"></div>' ) ;
$ ( 'body' ) . prepend ( tooltipElement ) ;
$ ( 'body' ) . prepend ( tooltipCaret ) ;
2015-09-18 08:42:52 +09:00
// align tooltip to the hovered element
alignTooltipTohoveredElement ( tooltipElement , tooltipCaret , $ ( e . target ) ) ;
2015-09-01 06:53:09 +09:00
// fade in
2015-09-15 10:58:11 +09:00
tooltipElement . css ( 'opacity' , '1' ) ;
tooltipCaret . css ( 'opacity' , '1' ) ;
2015-09-01 06:53:09 +09:00
}
} ,
mouseleave : function ( e ) {
removeAllTooltips ( ) ;
}
} ) ;
2015-09-15 00:49:06 +09:00
// tooltips should be removed very easily, e.g. when any of these events happen
$ ( 'body' ) . on ( "touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup" , function ( e ) {
removeAllTooltips ( ) ;
} ) ;
2015-09-01 06:53:09 +09:00
// removes all tooltips
function removeAllTooltips ( ) {
$ ( '.tooltip,.tooltip-caret' ) . remove ( ) ;
}
2015-09-15 10:58:11 +09:00
/ * ·
·
2015-09-18 08:42:52 +09:00
· Check for profile hovercards to display
2015-09-15 10:58:11 +09:00
·
· · · · · · · · · · · · · * /
window . userArrayLastRetrieved = new Object ( ) ;
$ ( 'body' ) . on ( 'mouseover' , function ( e ) {
2015-09-18 08:42:52 +09:00
// no hovercards on these elements
2016-03-12 23:08:22 +09:00
if ( $ ( e . target ) . is ( '#user-queets' ) || $ ( e . target ) . closest ( 'a' ) . is ( '#user-queets' )
|| $ ( e . target ) . is ( '.tweet-stats' ) || $ ( e . target ) . closest ( 'a' ) . is ( '.tweet-stats' ) ) {
2015-09-18 08:42:52 +09:00
return true ;
}
2015-09-15 10:58:11 +09:00
var timeNow = new Date ( ) . getTime ( ) ;
2015-09-18 08:42:52 +09:00
removeAllhoverCards ( e , timeNow ) ;
var hoverCardData = false ;
2015-09-15 10:58:11 +09:00
var userArray = false ;
var hrefAttr = false ;
var possibleNickname = false ;
// closest a-element with a href
if ( $ ( e . target ) . is ( '[href]' ) ) {
var targetElement = $ ( e . target ) ;
}
else if ( $ ( e . target ) . closest ( 'a' ) . length > 0 ) {
if ( $ ( e . target ) . closest ( 'a' ) . is ( '[href]' ) ) {
var targetElement = $ ( e . target ) . closest ( 'a' ) ;
}
else {
var targetElement = $ ( e . target ) ;
}
}
else {
var targetElement = $ ( e . target ) ;
}
// get href-attribute
if ( targetElement . is ( '[href]' ) ) {
hrefAttr = targetElement . attr ( 'href' ) ;
}
2015-09-29 23:31:05 +09:00
else {
return true ;
}
2016-03-05 07:07:15 +09:00
// no hover card if the element has the no-hover-card class
if ( targetElement . hasClass ( 'no-hover-card' ) ) {
return true ;
}
2015-09-29 23:31:05 +09:00
// no hovercard for anchor links
if ( hrefAttr . substring ( 0 , 1 ) == '#' ) {
return true ;
}
2015-09-15 10:58:11 +09:00
// guess what element close by could be a nickname
if ( $ ( e . target ) . is ( '[href]' ) ) {
possibleNickname = $ ( e . target ) . text ( ) ;
}
else if ( $ ( e . target ) . closest ( 'a' ) . length > 0 && $ ( e . target ) . closest ( 'a' ) . is ( '[href]' ) ) {
if ( $ ( e . target ) . siblings ( '.screen-name' ) . length > 0 ) { // the screen name can be in a sibling if we're lucky
possibleNickname = $ ( e . target ) . siblings ( '.screen-name' ) . text ( ) ;
}
else {
possibleNickname = $ ( e . target ) . text ( ) ;
}
}
// see if we have it in cache, otherwise query server
2015-09-19 00:23:08 +09:00
getUserArrayData ( hrefAttr , possibleNickname , timeNow , targetElement , function ( userArray , timeOut ) {
2015-09-15 10:58:11 +09:00
// bad data
if ( typeof userArray . local == 'undefined' ) {
return ;
}
// build card from either the local or external data, depending on what we got
2015-09-19 00:23:08 +09:00
if ( userArray . local !== null && userArray . local . is _local == true ) {
2015-09-15 10:58:11 +09:00
var profileCard = buildProfileCard ( userArray . local ) ;
}
2015-09-19 00:23:08 +09:00
else if ( userArray . local !== null && userArray . local . is _local == false && ( typeof userArray . external == 'undefined' || userArray . external === null || userArray . external === false ) ) {
2015-09-15 10:58:11 +09:00
var profileCard = buildProfileCard ( userArray . local ) ;
}
2015-09-19 00:23:08 +09:00
else if ( ( userArray . local === null || userArray . local === false || userArray . local . is _local == false ) && typeof userArray . external != 'undefined' && userArray . external !== false && userArray . external !== null ) {
2015-09-15 10:58:11 +09:00
var profileCard = buildExternalProfileCard ( userArray ) ;
}
else {
console . log ( 'could not build profile card...' ) ;
return ;
}
2015-09-18 08:42:52 +09:00
var hoverCardElement = $ ( '<div id="hover-card-' + timeNow + '" class="hover-card" data-card-created="' + timeNow + '">' + profileCard . profileCardHtml + '</div>' ) ;
var hoverCardCaret = $ ( '<div id="hover-card-caret-' + timeNow + '" class="hover-card-caret"></div>' ) ;
2015-09-15 10:58:11 +09:00
2015-09-18 08:42:52 +09:00
targetElement . attr ( 'data-awaiting-hover-card' , timeNow ) ;
2015-09-15 10:58:11 +09:00
2015-09-18 08:42:52 +09:00
// let user hover for 600ms before showing the card
2015-09-15 10:58:11 +09:00
setTimeout ( function ( ) {
2015-09-18 08:42:52 +09:00
// make sure user is still hovering the same link and that that the link awaits the same hover card
// (user can have flickered on and off the link triggering two or more hover cards to in setTimeout delay)
if ( targetElement . is ( ":hover" ) && parseInt ( targetElement . attr ( 'data-awaiting-hover-card' ) , 10 ) == timeNow ) {
if ( $ ( '.hover-card' ) . length == 0 ) { // no card if there already is one open
$ ( 'body' ) . prepend ( hoverCardElement ) ;
$ ( 'body' ) . prepend ( hoverCardCaret ) ;
targetElement . attr ( 'data-hover-card-active' , timeNow ) ;
2015-09-15 10:58:11 +09:00
// if the user array has not been retrieved from the server for the last 60 seconds,
// we query it for the lastest data
2016-03-12 23:08:22 +09:00
if ( ( typeof window . userArrayLastRetrieved [ hrefAttr ] == 'undefined' ) || ( timeNow - window . userArrayLastRetrieved [ hrefAttr ] ) > 60000 ) {
2015-09-19 00:23:08 +09:00
window . userArrayLastRetrieved [ hrefAttr ] = timeNow ;
2015-09-15 10:58:11 +09:00
// local users
2015-09-19 00:23:08 +09:00
if ( userArray . local !== null && userArray . local . is _local === true ) {
2015-09-15 10:58:11 +09:00
getFromAPI ( 'users/show.json?id=' + userArray . local . screen _name , function ( data ) {
if ( data ) {
var newProfileCard = buildProfileCard ( data ) ;
2015-09-18 08:42:52 +09:00
hoverCardElement . html ( newProfileCard . profileCardHtml ) ;
alignTooltipTohoveredElement ( hoverCardElement , hoverCardCaret , targetElement ) ;
2015-09-15 10:58:11 +09:00
}
} ) ;
}
// external users
2015-09-19 00:23:08 +09:00
else if ( userArray . local === null || userArray . local . is _local === false ) {
getFromAPI ( 'qvitter/external_user_show.json?profileurl=' + encodeURIComponent ( hrefAttr ) , function ( data ) {
2015-09-15 10:58:11 +09:00
if ( data && data . external !== null ) {
var newProfileCard = buildExternalProfileCard ( data ) ;
2015-09-18 08:42:52 +09:00
hoverCardElement . html ( newProfileCard . profileCardHtml ) ;
alignTooltipTohoveredElement ( hoverCardElement , hoverCardCaret , targetElement ) ;
2015-09-15 10:58:11 +09:00
}
} ) ;
}
}
// hide tooltips
$ ( '.tooltip,.tooltip-caret' ) . remove ( ) ;
2015-09-18 08:42:52 +09:00
// align hover card to the hovered element
alignTooltipTohoveredElement ( hoverCardElement , hoverCardCaret , targetElement ) ;
2015-09-15 10:58:11 +09:00
// fade in
2015-09-18 08:42:52 +09:00
hoverCardElement . css ( 'opacity' , '1' ) ;
hoverCardCaret . css ( 'opacity' , '1' ) ;
2015-09-15 10:58:11 +09:00
}
}
2015-09-17 05:41:48 +09:00
} , timeOut ) ;
2015-09-15 10:58:11 +09:00
} ) ;
} ) ;
2015-09-19 00:23:08 +09:00
// get user array from cache (or from server)
function getUserArrayData ( maybeProfileUrl , maybeNickname , timeNow , targetElement , callback ) {
2015-09-15 10:58:11 +09:00
if ( maybeProfileUrl && maybeNickname ) {
2015-09-17 05:41:48 +09:00
2015-09-15 10:58:11 +09:00
userArray = userArrayCacheGetByProfileUrlAndNickname ( maybeProfileUrl , maybeNickname ) ;
2015-09-17 05:41:48 +09:00
// no cached user array found, query server if this seems to be a profile url
2015-09-15 10:58:11 +09:00
if ( ! userArray ) {
2015-09-19 00:23:08 +09:00
var streamObject = URLtoStreamRouter ( maybeProfileUrl ) ;
// pathToStreamRouter failed finding a local stream for this path, maybe it's a remote profile?
if ( streamObject === false ) {
// we don't want to query the server every time we just pass an a-element with the cursor, so if the user
// hovers the element for, say, 200ms we ask the server if the link could be a remote profile
setTimeout ( function ( ) {
if ( targetElement . is ( ":hover" ) ) {
2016-01-21 02:30:16 +09:00
// don't try this if we already tried it less than a minute ago
2016-03-12 23:08:22 +09:00
if ( ( typeof window . userArrayLastRetrieved [ maybeProfileUrl ] == 'undefined' ) || ( timeNow - window . userArrayLastRetrieved [ maybeProfileUrl ] ) > 60000 ) {
2016-01-21 02:30:16 +09:00
window . userArrayLastRetrieved [ maybeProfileUrl ] = timeNow ;
getFromAPI ( 'qvitter/external_user_show.json?profileurl=' + encodeURIComponent ( maybeProfileUrl ) , function ( data ) {
if ( data && data . external !== null ) {
2015-09-15 10:58:11 +09:00
2016-01-21 02:30:16 +09:00
// we want hover cards to appear _at least_ 600ms after hover (see below)
var timeAfterServerQuery = new Date ( ) . getTime ( ) ;
var queryTime = timeAfterServerQuery - timeNow ;
if ( queryTime < 600 ) {
var timeOut = 600 - queryTime ;
}
else {
var timeOut = 0 ;
}
callback ( data , timeOut ) ;
}
} ) ;
}
2015-09-19 00:23:08 +09:00
}
} , 200 ) ;
}
2015-09-17 05:41:48 +09:00
// likely an uncached local profile
2015-09-19 00:23:08 +09:00
else if ( streamObject && ( streamObject . name == 'profile' || streamObject . name == 'profile by id' ) ) {
2015-09-15 10:58:11 +09:00
2015-09-19 00:23:08 +09:00
var nicknameOrId = streamObject . nickname ;
2016-03-12 23:08:22 +09:00
if ( ! nicknameOrId ) {
2015-09-19 00:23:08 +09:00
nicknameOrId = streamObject . id ;
2015-09-17 05:41:48 +09:00
}
// don't query too often for the same user
2016-03-12 23:08:22 +09:00
if ( typeof window . userArrayLastRetrieved [ maybeProfileUrl ] == 'undefined' || ( timeNow - window . userArrayLastRetrieved [ maybeProfileUrl ] ) > 60000 ) {
2015-09-19 00:23:08 +09:00
window . userArrayLastRetrieved [ maybeProfileUrl ] = timeNow ;
2015-09-17 05:41:48 +09:00
// query server and cache user data (done automatically in getFromAPI)
getFromAPI ( 'users/show.json?id=' + nicknameOrId , function ( data ) {
if ( data ) {
userArray = { local : data } ;
2015-09-18 08:42:52 +09:00
// we want hover cards to appear _at least_ 600ms after hover
2015-09-17 05:41:48 +09:00
// we could just set the timeout to 0 and let the card appear
// whenever it's loaded, but this will not feel good if we're
// on a crazy fast server. so we calculate the diff time and makes
// sure the total delay is at least 600ms
var timeAfterServerQuery = new Date ( ) . getTime ( ) ;
var queryTime = timeAfterServerQuery - timeNow ;
if ( queryTime < 600 ) {
var timeOut = 600 - queryTime ;
}
else {
var timeOut = 0 ;
}
2015-09-18 08:42:52 +09:00
// continue to display the hover card
2015-09-17 05:41:48 +09:00
callback ( userArray , timeOut ) ;
}
} ) ;
}
}
2015-09-15 10:58:11 +09:00
}
// from cache
else {
2015-09-18 08:42:52 +09:00
// continue to display the hover card
2015-09-17 05:41:48 +09:00
// 600ms before cards appear feels pretty good
// but this can be tweaked if cards appear to fast/slow
callback ( userArray , 600 ) ;
2015-09-15 10:58:11 +09:00
}
}
}
2015-09-18 08:42:52 +09:00
// hover cards should be removed very easily, e.g. when any of these events happen
2015-09-15 10:58:11 +09:00
$ ( 'body' ) . on ( "mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup" , function ( e ) {
var timeNow = new Date ( ) . getTime ( ) ;
2015-09-18 08:42:52 +09:00
removeAllhoverCards ( e , timeNow ) ;
2015-09-15 10:58:11 +09:00
} ) ;
// removes all hover cards
2015-09-18 08:42:52 +09:00
function removeAllhoverCards ( event , priorTo ) {
2015-09-15 10:58:11 +09:00
// don't remove hovercards until after 100ms, so user have time to move the cursor to it (which gives it the dont-remove-card class)
setTimeout ( function ( ) {
2015-09-18 08:42:52 +09:00
$ . each ( $ ( '.hover-card' ) , function ( ) {
// don't remove card if it was created after removeAllhoverCards() was called
2015-09-15 10:58:11 +09:00
if ( $ ( this ) . data ( 'card-created' ) < priorTo ) {
2015-09-18 08:42:52 +09:00
// don't remove it if we're hovering it right now!
2015-09-15 10:58:11 +09:00
if ( ! $ ( this ) . hasClass ( 'dont-remove-card' ) ) {
2015-09-18 08:42:52 +09:00
$ ( '[data-hover-card-active="' + $ ( this ) . data ( 'card-created' ) + '"]' ) . removeAttr ( 'data-hover-card-active' ) ;
$ ( '#hover-card-caret-' + $ ( this ) . data ( 'card-created' ) ) . remove ( ) ;
2015-09-15 10:58:11 +09:00
$ ( this ) . remove ( ) ;
}
}
} ) ;
} , 100 ) ;
}
2015-09-18 08:42:52 +09:00
// if we're hovering a hover card, give it a class, so we don't remove it
$ ( 'body' ) . on ( 'mouseover' , '.hover-card' , function ( e ) {
2015-09-15 10:58:11 +09:00
$ ( this ) . addClass ( 'dont-remove-card' ) ;
} ) ;
2015-09-18 08:42:52 +09:00
$ ( 'body' ) . on ( 'mouseleave' , '.hover-card' , function ( e ) {
2015-09-15 10:58:11 +09:00
$ ( this ) . removeClass ( 'dont-remove-card' ) ;
} ) ;
2015-09-01 06:53:09 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
· fix login and register box to top when they reach top
·
· · · · · · · · · · · · · * /
$ ( window ) . scroll ( function ( e ) {
2015-05-30 00:30:03 +09:00
if ( $ ( '#page-container > .profile-card' ) . length > 0 ) {
var feedOrProfileCardOffsetTop = $ ( '#page-container > .profile-card' ) . offset ( ) . top ;
}
else {
var feedOrProfileCardOffsetTop = $ ( '#feed' ) . offset ( ) . top ;
2013-09-03 01:13:15 +09:00
}
2015-07-02 02:15:31 +09:00
if ( $ ( this ) . scrollTop ( ) > ( feedOrProfileCardOffsetTop - 55 ) && $ ( '#login-content' ) . css ( 'position' ) != 'fixed' ) {
2015-12-04 00:06:02 +09:00
var loginAndSignUpBoxesHeight = $ ( '#login-content' ) . outerHeight ( ) + $ ( '.front-signup' ) . not ( '#popup-signup' ) . outerHeight ( ) ;
$ ( '#login-register-container' ) . css ( { 'position' : 'fixed' , 'top' : '55px' } ) ;
2015-07-02 02:15:31 +09:00
}
else if ( $ ( this ) . scrollTop ( ) < ( feedOrProfileCardOffsetTop - 55 ) && $ ( '#login-content' ) . css ( 'position' ) != 'absolute' ) {
2015-12-04 00:06:02 +09:00
$ ( '#login-register-container' ) . css ( { 'position' : 'relative' , 'top' : 'auto' } ) ;
2015-05-30 00:30:03 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-09-03 01:13:15 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-09-03 01:13:15 +09:00
· Tooltip to show what federated means
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-02-28 07:13:44 +09:00
$ ( 'body' ) . on ( 'mouseenter' , '#federated-tooltip' , function ( ) {
2013-09-03 01:13:15 +09:00
$ ( '#what-is-federation' ) . fadeIn ( 100 ) ;
} ) ;
2015-02-28 07:13:44 +09:00
$ ( 'body' ) . on ( 'mouseleave' , '#what-is-federation' , function ( ) {
2013-09-03 01:13:15 +09:00
$ ( '#what-is-federation' ) . fadeOut ( 100 ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2013-09-03 01:13:15 +09:00
2015-08-25 21:12:50 +09:00
/ * ·
·
· Scroll to top when clicking top bar
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.global-nav' , function ( e ) {
2016-01-24 01:12:24 +09:00
if ( $ ( e . target ) . hasClass ( 'global-nav' ) ) {
$ ( window ) . scrollTop ( 0 ) ;
2015-08-25 21:12:50 +09:00
}
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-09-03 01:13:15 +09:00
· Register
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-09-03 01:13:15 +09:00
2014-05-16 11:07:30 +09:00
if ( ! window . registrationsClosed ) {
$ ( '.front-signup input, .front-signup button' ) . removeAttr ( 'disabled' ) ; // clear this onload
$ ( '#signup-btn-step1' ) . click ( function ( ) {
2015-07-02 02:15:31 +09:00
2014-11-28 05:04:41 +09:00
$ ( document ) . trigger ( 'onClickStep1Register' ) ; // hook
2015-07-02 02:15:31 +09:00
2014-05-16 11:07:30 +09:00
display _spinner ( ) ;
$ ( '.front-signup input, .front-signup button' ) . addClass ( 'disabled' ) ;
$ ( '.front-signup input, .front-signup button' ) . attr ( 'disabled' , 'disabled' ) ;
// 7 s timeout to annoy human spammers
setTimeout ( function ( ) {
remove _spinner ( ) ;
2015-07-02 02:15:31 +09:00
popUpAction ( 'popup-register' , window . sL . signUp , '<div id="popup-signup" class="front-signup">' +
2014-05-16 11:07:30 +09:00
'<div class="signup-input-container"><div id="atsign">@</div><input placeholder="' + window . sL . registerNickname + '" type="text" autocomplete="off" class="text-input" id="signup-user-nickname-step2"><div class="fieldhelp">a-z0-9</div></div>' +
'<div class="signup-input-container"><input placeholder="' + window . sL . signUpFullName + '" type="text" autocomplete="off" class="text-input" id="signup-user-name-step2" value="' + $ ( '#signup-user-name' ) . val ( ) + '"></div>' +
2015-07-02 02:15:31 +09:00
'<div class="signup-input-container"><input placeholder="' + window . sL . signUpEmail + '" type="text" autocomplete="off" id="signup-user-email-step2" value="' + $ ( '#signup-user-email' ) . val ( ) + '"></div>' +
2014-05-16 11:07:30 +09:00
'<div class="signup-input-container"><input placeholder="' + window . sL . registerHomepage + '" type="text" autocomplete="off" class="text-input" id="signup-user-homepage-step2"></div>' +
'<div class="signup-input-container"><input placeholder="' + window . sL . registerBio + '" type="text" autocomplete="off" class="text-input" id="signup-user-bio-step2"></div>' +
2015-07-02 02:15:31 +09:00
'<div class="signup-input-container"><input placeholder="' + window . sL . registerLocation + '" type="text" autocomplete="off" class="text-input" id="signup-user-location-step2"></div>' +
'<div class="signup-input-container"><input placeholder="' + window . sL . loginPassword + '" type="password" class="text-input" id="signup-user-password1-step2" value="' + $ ( '#signup-user-password' ) . val ( ) + '"><div class="fieldhelp">>5</div></div>' +
'<div class="signup-input-container"><input placeholder="' + window . sL . registerRepeatPassword + '" type="password" class="text-input" id="signup-user-password2-step2"></div>' +
'<div id="signup-terms-header">' + window . sL . showTerms . replace ( /{site-title}/g , window . siteTitle ) + '</div><div id="signup-terms-container"></div>' +
2014-05-16 11:07:30 +09:00
'<button id="signup-btn-step2" class="signup-btn disabled" type="submit">' + window . sL . signUpButtonText + '</button>' +
2015-07-02 02:15:31 +09:00
'</div>' , false ) ;
2014-05-16 11:07:30 +09:00
// ask api if nickname is ok, if no typing for 1 s
$ ( '#signup-user-nickname-step2' ) . on ( 'keyup' , function ( ) {
clearTimeout ( window . checkNicknameTimeout ) ;
2015-12-15 05:01:27 +09:00
var thisInputElement = $ ( this ) ;
var thisValue = $ ( this ) . val ( ) ;
if ( thisValue . length > 1 && /^[a-zA-Z0-9]+$/ . test ( thisValue ) ) {
thisInputElement . addClass ( 'nickname-taken' ) ;
2014-05-16 11:07:30 +09:00
if ( $ ( '.spinner-wrap' ) . length == 0 ) {
2015-12-15 05:01:27 +09:00
thisInputElement . after ( '<div class="spinner-wrap"><div class="spinner"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div>' ) ;
2015-07-02 02:15:31 +09:00
}
window . checkNicknameTimeout = setTimeout ( function ( ) {
2015-12-15 05:01:27 +09:00
$ . get ( window . apiRoot + 'check_nickname.json?nickname=' + encodeURIComponent ( thisValue ) , function ( data ) {
2014-05-16 11:07:30 +09:00
$ ( '.spinner-wrap' ) . remove ( ) ;
2014-09-25 06:20:35 +09:00
if ( data == 0 ) {
2015-07-02 02:15:31 +09:00
$ ( '#signup-user-password2-step2' ) . trigger ( 'keyup' ) ; // revalidates
2014-05-16 11:07:30 +09:00
}
2015-07-02 02:15:31 +09:00
else {
2015-12-15 05:01:27 +09:00
thisInputElement . removeClass ( 'nickname-taken' ) ;
$ ( '#signup-user-password2-step2' ) . trigger ( 'keyup' ) ;
}
} ) ;
} , 1000 ) ;
}
else {
$ ( '.spinner-wrap' ) . remove ( ) ;
}
} ) ;
// ask api if email is in use, if no typing for 1 s
$ ( '#signup-user-email-step2' ) . on ( 'keyup' , function ( ) {
clearTimeout ( window . checkEmailTimeout ) ;
var thisInputElement = $ ( this ) ;
var thisValue = $ ( this ) . val ( ) ;
if ( thisValue . length > 1 && validEmail ( thisValue ) ) {
thisInputElement . addClass ( 'email-in-use' ) ;
if ( $ ( '.spinner-wrap' ) . length == 0 ) {
thisInputElement . after ( '<div class="spinner-wrap"><div class="spinner"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div>' ) ;
}
window . checkEmailTimeout = setTimeout ( function ( ) {
$ . get ( window . apiRoot + 'qvitter/check_email.json?email=' + encodeURIComponent ( thisValue ) , function ( data ) {
$ ( '.spinner-wrap' ) . remove ( ) ;
if ( data == 1 ) {
$ ( '#signup-user-password2-step2' ) . trigger ( 'keyup' ) ; // revalidates
thisInputElement . after ( '<div class="fieldhelp email-in-use">' + window . sL . emailAlreadyInUse + '</div>' ) ;
}
else {
thisInputElement . removeClass ( 'email-in-use' ) ;
thisInputElement . siblings ( '.fieldhelp.email-in-use' ) . remove ( ) ;
2014-05-16 11:07:30 +09:00
$ ( '#signup-user-password2-step2' ) . trigger ( 'keyup' ) ;
}
} ) ;
} , 1000 ) ;
}
else {
2015-07-02 02:15:31 +09:00
$ ( '.spinner-wrap' ) . remove ( ) ;
2014-05-16 11:07:30 +09:00
}
} ) ;
2013-09-03 01:13:15 +09:00
2015-07-02 02:15:31 +09:00
2016-05-03 02:57:57 +09:00
// validate on keyup / paste / blur
$ ( '#popup-register input' ) . on ( 'keyup paste blur' , function ( ) {
2016-04-27 00:01:54 +09:00
setTimeout ( function ( ) { // defer validation as after paste the content is not immediately available
if ( validateRegisterForm ( $ ( '#popup-register' ) )
&& ! $ ( '#signup-user-nickname-step2' ) . hasClass ( 'nickname-taken' )
&& ! $ ( '#signup-user-email-step2' ) . hasClass ( 'email-in-use' ) ) {
$ ( '#signup-btn-step2' ) . removeClass ( 'disabled' ) ;
}
else {
$ ( '#signup-btn-step2' ) . addClass ( 'disabled' ) ;
}
} , 0 ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-05-16 11:07:30 +09:00
$ ( '#popup-register input' ) . trigger ( 'keyup' ) ;
2015-07-02 02:15:31 +09:00
2014-05-16 11:07:30 +09:00
// submit on enter
2015-07-02 02:15:31 +09:00
$ ( 'input#signup-user-name-step2,input#signup-user-email-step2,input#signup-user-password1-step2, input#signup-user-password2-step2' ) . keyup ( function ( e ) {
if ( e . keyCode == 13 ) {
2014-05-16 11:07:30 +09:00
$ ( '#signup-btn-step2' ) . trigger ( 'click' ) ;
}
2015-07-02 02:15:31 +09:00
} ) ;
2014-05-16 11:07:30 +09:00
$ ( '#signup-btn-step2' ) . click ( function ( ) {
2014-11-24 21:47:45 +09:00
if ( ! $ ( this ) . hasClass ( 'disabled' ) ) {
$ ( '#popup-register input,#popup-register button' ) . addClass ( 'disabled' ) ;
display _spinner ( ) ;
2015-07-02 02:15:31 +09:00
$ . ajax ( { url : window . apiRoot + 'account/register.json' ,
type : "POST" ,
data : {
2014-11-24 21:47:45 +09:00
nickname : $ ( '#signup-user-nickname-step2' ) . val ( ) ,
email : $ ( '#signup-user-email-step2' ) . val ( ) ,
fullname : $ ( '#signup-user-name-step2' ) . val ( ) ,
homepage : $ ( '#signup-user-homepage-step2' ) . val ( ) ,
bio : $ ( '#signup-user-bio-step2' ) . val ( ) ,
2015-07-02 02:15:31 +09:00
location : $ ( '#signup-user-location-step2' ) . val ( ) ,
password : $ ( '#signup-user-password1-step2' ) . val ( ) ,
2014-11-24 21:47:45 +09:00
confirm : $ ( '#signup-user-password2-step2' ) . val ( ) ,
cBS : window . cBS ,
2015-07-02 02:15:31 +09:00
cBSm : window . cBSm ,
2014-11-24 21:47:45 +09:00
username : 'none' ,
} ,
dataType : "json" ,
2015-12-15 05:01:27 +09:00
error : function ( data ) {
if ( typeof data . responseJSON != 'undefined' && typeof data . responseJSON . error != 'undefined' ) {
remove _spinner ( ) ;
$ ( '#popup-register input,#popup-register button' ) . removeClass ( 'disabled' ) ;
$ ( '#signup-user-password2-step2' ) . trigger ( 'keyup' ) ; // revalidate
showErrorMessage ( data . responseJSON . error , $ ( '#popup-register .modal-header' ) ) ;
}
} ,
2014-11-24 21:47:45 +09:00
success : function ( data ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-11-24 21:47:45 +09:00
if ( typeof data . error == 'undefined' ) {
$ ( 'input#nickname' ) . val ( $ ( '#signup-user-nickname-step2' ) . val ( ) ) ;
$ ( 'input#password' ) . val ( $ ( '#signup-user-password1-step2' ) . val ( ) ) ;
$ ( 'input#rememberme' ) . prop ( 'checked' , true ) ;
$ ( '#submit-login' ) . trigger ( 'click' ) ;
$ ( '#popup-register' ) . remove ( ) ;
}
else {
alert ( 'Try again! ' + data . error ) ;
$ ( '#popup-register input,#popup-register button' ) . removeClass ( 'disabled' ) ;
}
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
}
} ) ;
}
2014-05-16 11:07:30 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2014-05-16 11:07:30 +09:00
// reactivate register form on popup close
$ ( '#popup-register' ) . on ( 'remove' , function ( ) {
$ ( '.front-signup input, .front-signup button' ) . removeAttr ( 'disabled' ) ;
$ ( '.front-signup input, .front-signup button' ) . removeClass ( 'disabled' ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-05-16 11:07:30 +09:00
} , 7000 ) ;
} ) ;
// submit on enter
2015-07-02 02:15:31 +09:00
$ ( 'input#signup-user-name,input#signup-user-email,input#signup-user-password' ) . keyup ( function ( e ) {
if ( e . keyCode == 13 ) {
2014-05-16 11:07:30 +09:00
$ ( '#signup-btn-step1' ) . trigger ( 'click' ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
}
2015-01-26 03:05:09 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-01-26 03:05:09 +09:00
· Show / hide Terms of Use
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-01-26 03:05:09 +09:00
$ ( 'body' ) . on ( 'click' , '#signup-terms-header' , function ( ) {
if ( $ ( '#signup-terms-container' ) . text ( ) . length > 0 ) {
$ ( '#signup-terms-container' ) . html ( '' ) ;
}
else {
if ( window . customTermsOfUse ) {
$ ( '#signup-terms-container' ) . html ( window . customTermsOfUse ) ;
}
else {
getDoc ( 'terms' , function ( termsHtml ) {
$ ( '#signup-terms-container' ) . html ( termsHtml ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2015-01-26 03:05:09 +09:00
}
}
2015-07-02 02:15:31 +09:00
} ) ;
2015-01-26 03:05:09 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-02-25 06:36:36 +09:00
· set language , autologin or show welcome screen
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
$ ( '#submit-login' ) . removeAttr ( 'disabled' ) ; // might be remebered by browser...
2013-08-26 05:34:09 +09:00
$ ( window ) . load ( function ( ) {
2013-08-19 22:30:57 +09:00
2015-07-07 01:29:15 +09:00
// set language, from local storage, else browser language
2015-07-02 02:15:31 +09:00
var browserLang = navigator . language || navigator . userLanguage ;
2015-07-07 01:29:15 +09:00
// browsers report e.g. sv-SE but we want it in the format "sv" or "sv_se"
browserLang = browserLang . replace ( '-' , '_' ) . toLowerCase ( ) ;
2015-07-02 02:15:31 +09:00
2015-07-07 01:29:15 +09:00
// if we're logged out, we see if there's a saved language in localstorage
2015-03-06 06:22:48 +09:00
if ( window . loggedIn === false ) {
2015-07-07 01:29:15 +09:00
var cacheDataLoggedOut = localStorageObjectCache _GET ( 'selectedLanguage' , 'logged_out' ) ;
if ( cacheDataLoggedOut ) {
window . selectedLanguage = cacheDataLoggedOut ;
}
else {
window . selectedLanguage = browserLang ;
}
2015-07-02 23:57:51 +09:00
}
2015-07-07 01:29:15 +09:00
// if we're logged in, we check
// 1) check if the logged in user has selected a language
// 2) check if there a selected language for logged_out users (i.e. the user selected the language before logging in)
// 3) go with the browser language
2015-07-02 23:57:51 +09:00
else {
2015-07-07 01:29:15 +09:00
var cacheDataLoggedOut = localStorageObjectCache _GET ( 'selectedLanguage' , 'logged_out' ) ;
var cacheDataLoggedIn = localStorageObjectCache _GET ( 'selectedLanguage' , window . loggedIn . id ) ;
if ( cacheDataLoggedIn ) {
window . selectedLanguage = cacheDataLoggedIn ;
}
else if ( cacheDataLoggedOut ) {
window . selectedLanguage = cacheDataLoggedOut ;
}
else {
window . selectedLanguage = browserLang ;
}
2015-07-02 23:57:51 +09:00
}
2015-07-02 02:15:31 +09:00
2015-07-07 01:29:15 +09:00
// check that the language is available,
2015-03-06 06:22:48 +09:00
if ( typeof window . availableLanguages [ window . selectedLanguage ] == 'undefined' ) {
2016-01-18 23:26:54 +09:00
var similarLanguageFound = false ;
2015-07-07 01:29:15 +09:00
// if not there might be a base language, e.g. "sv" instead of "sv_se"
2016-01-18 23:26:54 +09:00
if ( window . selectedLanguage . indexOf ( '_' ) > - 1
&& typeof window . availableLanguages [ window . selectedLanguage . substring ( 0 , window . selectedLanguage . indexOf ( '_' ) ) ] != 'undefined' ) {
window . selectedLanguage = window . selectedLanguage . substring ( 0 , window . selectedLanguage . indexOf ( '_' ) ) ;
similarLanguageFound = true ;
2015-07-07 01:29:15 +09:00
}
else {
// there's also a chance there no base language, but a similar country specific language that we can use (rather than english)
2016-01-18 23:26:54 +09:00
if ( window . selectedLanguage . indexOf ( '_' ) > - 1 ) {
var baseLan = window . selectedLanguage . indexOf ( '_' ) ;
}
else {
var baseLan = window . selectedLanguage ;
}
2015-07-07 01:29:15 +09:00
$ . each ( window . availableLanguages , function ( lanCode , lanData ) {
2016-01-18 23:26:54 +09:00
if ( lanCode . substring ( 0 , lanCode . indexOf ( '_' ) ) == baseLan ) {
2015-07-07 01:29:15 +09:00
window . selectedLanguage = lanCode ;
similarLanguageFound = true ;
return false ;
}
} ) ;
2016-01-18 23:26:54 +09:00
}
// if we can't find a similar language, go with english
if ( similarLanguageFound === false ) {
window . selectedLanguage = 'en' ;
2015-07-07 01:29:15 +09:00
}
2015-07-02 02:15:31 +09:00
}
2016-01-18 23:26:54 +09:00
// english is always available
if ( window . selectedLanguage == 'en' ) {
proceedToSetLanguageAndLogin ( window . englishLanguageData ) ;
2015-07-02 23:57:51 +09:00
}
else {
2016-01-18 23:26:54 +09:00
// if we already have this version of this language in localstorage, we
// use that cached version. we do this because $.ajax doesn't respect caching, it seems
var cacheData = localStorageObjectCache _GET ( 'languageData' , window . availableLanguages [ window . selectedLanguage ] ) ;
if ( cacheData ) {
proceedToSetLanguageAndLogin ( cacheData ) ;
}
else {
$ . ajax ( {
dataType : "json" ,
url : window . fullUrlToThisQvitterApp + 'locale/' + window . availableLanguages [ window . selectedLanguage ] ,
error : function ( data ) { console . log ( data ) } ,
success : function ( data ) {
2015-07-02 02:15:31 +09:00
2016-01-18 23:26:54 +09:00
// store this response in localstorage
localStorageObjectCache _STORE ( 'languageData' , window . availableLanguages [ window . selectedLanguage ] , data ) ;
2015-02-25 06:36:36 +09:00
2016-01-18 23:26:54 +09:00
proceedToSetLanguageAndLogin ( data ) ;
}
} ) ;
}
2015-07-02 23:57:51 +09:00
}
2015-02-25 08:12:20 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2015-02-25 08:12:20 +09:00
// proceed to set language and login
function proceedToSetLanguageAndLogin ( data ) {
window . sL = data ;
2015-02-25 06:36:36 +09:00
2015-10-20 01:47:24 +09:00
// plugins might have added translations
$ . each ( window . pluginTranslations , function ( k , pluginTranslation ) {
if ( typeof pluginTranslation [ window . selectedLanguage ] != 'undefined' ) {
$ . extend ( window . sL , pluginTranslation [ window . selectedLanguage ] ) ;
}
else if ( typeof pluginTranslation [ 'en' ] != 'undefined' ) {
$ . extend ( window . sL , pluginTranslation [ 'en' ] ) ;
}
} ) ;
// plugins might want to wait and do stuff until after language is set
$ ( document ) . trigger ( 'qvitterAfterLanguageIsSet' ) ;
2015-06-18 21:24:37 +09:00
// if this is a RTL-language, add rtl class to body
if ( window . sL . directionality == 'rtl' ) {
$ ( 'body' ) . addClass ( 'rtl' ) ;
}
2015-02-25 08:12:20 +09:00
window . siteTitle = $ ( 'head title' ) . html ( ) ; // remember this for later use
2015-02-25 06:36:36 +09:00
2015-05-30 00:30:03 +09:00
2015-02-25 08:12:20 +09:00
// replace placeholders in translation
$ . each ( window . sL , function ( k , v ) {
window . sL [ k ] = v . replace ( /{site-title}/g , window . siteTitle ) ;
2015-02-25 06:36:36 +09:00
} ) ;
2016-01-18 23:26:54 +09:00
// suggest user to help translate if their browsers language does't exist
if ( typeof window . availableLanguages [ window . usersLanguageCode ] == 'undefined' && ! localStorageObjectCache _GET ( 'languageErrorMessageDiscarded' , window . usersLanguageNameInEnglish ) ) { // but don't nag
$ ( '#page-container' ) . prepend ( '<div class="language-error-message" data-language-name="' + window . usersLanguageNameInEnglish + '">' + window . siteTitle + ' is not availible in your language (' + replaceHtmlSpecialChars ( window . usersLanguageNameInEnglish ) + '). Visit <a href="https://git.gnu.io/h2p/Qvitter/tree/master/locale">Qvitter\'s repository homepage</a> if you want to help us to translate the interface. <span class="discard-error-message"></span></div>' ) ;
}
// if selected language is too similar to english, we display a message telling people to help with the translation
if ( window . sL . languageName != 'English' ) {
var numberOfStringsSameAsEnglish = 0 ;
var totalStrings = 0 ;
$ . each ( window . sL , function ( k , v ) {
if ( v == window . englishLanguageData [ k ] ) {
numberOfStringsSameAsEnglish ++ ;
}
totalStrings ++ ;
} ) ;
numberOfStringsSameAsEnglish = Math . max ( 0 , numberOfStringsSameAsEnglish - 20 ) ; totalStrings = Math . max ( 0 , totalStrings - 20 ) ; // ~20 strings, e.g. shortened months, is often same in many languages
var percentTranslated = parseInt ( ( 1 - ( numberOfStringsSameAsEnglish / totalStrings ) ) * 100 , 10 ) ;
if ( percentTranslated < 95 ) {
if ( ! localStorageObjectCache _GET ( 'languageErrorMessageDiscarded' , window . sL . languageName ) ) { // but don't nag
$ ( '#page-container' ) . prepend ( '<div class="language-error-message" data-language-name="' + window . sL . languageName + '">' + window . sL . onlyPartlyTranslated . replace ( '{percent}' , percentTranslated ) . replace ( '{language-name}' , window . sL . languageName ) + '<span class="discard-error-message"></span></div>' ) ;
}
}
}
2015-05-30 00:30:03 +09:00
// set some static strings
if ( window . customWelcomeText !== false && typeof window . customWelcomeText [ window . selectedLanguage ] != 'undefined' ) {
$ ( '.front-welcome-text' ) . html ( window . customWelcomeText [ window . selectedLanguage ] ) ;
2015-07-02 02:15:31 +09:00
2015-05-30 00:30:03 +09:00
// collapse long welcome texts and add expand button
if ( $ ( '.front-welcome-text' ) . outerHeight ( ) > 250 ) {
$ ( '.front-welcome-text' ) . css ( 'height' , '240px' ) ;
2015-07-02 02:15:31 +09:00
$ ( '.front-welcome-text' ) . css ( 'overflow' , 'hidden' ) ;
2015-05-30 00:30:03 +09:00
$ ( '.front-welcome-text' ) . append ( '<div class="show-full-welcome-text"></div>' ) ;
}
}
2015-07-02 02:15:31 +09:00
else {
$ ( '.front-welcome-text' ) . html ( '<h1>' + window . sL . welcomeHeading + '</h1>' ) ;
2015-05-30 00:30:03 +09:00
if ( window . enableWelcomeText ) {
2015-07-02 02:15:31 +09:00
$ ( '.front-welcome-text' ) . append ( window . sL . welcomeText ) ;
2015-05-30 00:30:03 +09:00
}
}
2015-09-18 08:42:52 +09:00
2015-02-25 08:12:20 +09:00
$ ( '#nickname' ) . attr ( 'placeholder' , window . sL . loginUsername ) ;
$ ( '#password' ) . attr ( 'placeholder' , window . sL . loginPassword ) ;
$ ( 'button#submit-login' ) . html ( window . sL . loginSignIn ) ;
$ ( '#rememberme_label' ) . html ( window . sL . loginRememberMe ) ;
$ ( '#forgot-password' ) . html ( window . sL . loginForgotPassword ) ;
$ ( '.front-signup h2' ) . html ( '<strong>' + window . sL . newToQuitter + '</strong> ' + window . sL . signUp ) ;
$ ( '#signup-user-name' ) . attr ( 'placeholder' , window . sL . signUpFullName ) ;
$ ( '#signup-user-email' ) . attr ( 'placeholder' , window . sL . signUpEmail ) ;
$ ( '#signup-user-password' ) . attr ( 'placeholder' , window . sL . loginPassword ) ;
$ ( '.front-signup button.signup-btn' ) . html ( window . sL . signUpButtonText ) ;
$ ( '#user-queets .label' ) . html ( window . sL . notices ) ;
$ ( '#user-following .label' ) . html ( window . sL . following ) ;
$ ( '#user-followers .label' ) . html ( window . sL . followers ) ;
$ ( '#user-groups .label' ) . html ( window . sL . groups ) ;
$ ( '#queet-box' ) . html ( window . sL . compose ) ;
$ ( '#queet-box' ) . attr ( 'data-start-text' , encodeURIComponent ( window . sL . compose ) ) ;
$ ( '#user-footer .queet-button button' ) . html ( window . sL . queetVerb ) ;
2016-03-08 04:51:05 +09:00
$ ( '#stream-header' ) . html ( window . sL . queetsNounPlural ) ;
2015-02-25 08:12:20 +09:00
$ ( '#logout' ) . html ( window . sL . logout ) ;
$ ( '#settings' ) . html ( window . sL . settings ) ;
$ ( '#other-servers-link' ) . html ( window . sL . otherServers ) ;
$ ( '.language-dropdown .dropdown-toggle small' ) . html ( window . sL . languageSelected ) ;
$ ( '.language-dropdown .current-language' ) . html ( window . sL . languageName ) ;
2015-09-18 08:42:52 +09:00
$ ( '.stream-selection.friends-timeline' ) . prepend ( window . sL . timeline ) ;
$ ( '.stream-selection.mentions' ) . prepend ( window . sL . mentions ) ;
$ ( '.stream-selection.notifications' ) . prepend ( window . sL . notifications ) ;
$ ( '.stream-selection.favorites' ) . prepend ( window . sL . favoritesNoun ) ;
$ ( '.stream-selection.public-timeline' ) . prepend ( window . sL . publicTimeline ) ;
$ ( '.stream-selection.public-and-external-timeline' ) . prepend ( window . sL . publicAndExtTimeline )
2015-02-25 08:12:20 +09:00
$ ( '#search-query' ) . attr ( 'placeholder' , window . sL . searchVerb ) ;
2016-02-27 07:18:02 +09:00
$ ( '#blocking-link' ) . html ( window . sL . userBlocks ) ;
2015-02-25 08:12:20 +09:00
$ ( '#faq-link' ) . html ( window . sL . FAQ ) ;
2016-02-07 22:17:31 +09:00
$ ( '#tou-link' ) . html ( window . sL . showTerms ) ;
2016-01-18 23:26:54 +09:00
$ ( '#add-edit-language-link' ) . html ( window . sL . addEditLanguageLink ) ;
2015-07-02 02:15:31 +09:00
$ ( '#shortcuts-link' ) . html ( window . sL . keyboardShortcuts ) ;
2015-02-25 08:12:20 +09:00
$ ( '#invite-link' ) . html ( window . sL . inviteAFriend ) ;
2015-08-05 20:49:42 +09:00
$ ( '#classic-link' ) . html ( window . sL . classicInterface ) ;
2015-02-25 08:12:20 +09:00
$ ( '#edit-profile-header-link' ) . html ( window . sL . editMyProfile ) ;
2016-03-05 07:07:15 +09:00
$ ( '#mini-logged-in-user-cog-wheel' ) . attr ( 'data-tooltip' , window . sL . profileSettings ) ;
2015-08-07 04:32:32 +09:00
$ ( '#accessibility-toggle-link' ) . html ( window . sL . accessibilityToggleLink ) ;
2016-03-05 07:07:15 +09:00
$ ( '#settingslink .nav-session' ) . attr ( 'data-tooltip' , window . sL . profileAndSettings ) ;
2015-09-01 06:53:09 +09:00
$ ( '#top-compose' ) . attr ( 'data-tooltip' , window . sL . compose ) ;
$ ( 'button.upload-image' ) . attr ( 'data-tooltip' , window . sL . tooltipAttachImage ) ;
$ ( 'button.shorten' ) . attr ( 'data-tooltip' , window . sL . tooltipShortenUrls ) ;
$ ( '.reload-stream' ) . attr ( 'data-tooltip' , window . sL . tooltipReloadStream ) ;
$ ( '#clear-history' ) . html ( window . sL . clearHistory ) ;
2015-12-04 00:06:02 +09:00
$ ( '#user-screen-name, #user-avatar, #user-name' ) . attr ( 'data-tooltip' , window . sL . viewMyProfilePage ) ;
2016-03-05 07:07:15 +09:00
$ ( '#top-menu-profile-link-view-profile' ) . html ( window . sL . viewMyProfilePage ) ;
2015-09-18 08:42:52 +09:00
2015-07-02 02:15:31 +09:00
// show site body now
2015-02-25 08:12:20 +09:00
$ ( '#user-container' ) . css ( 'display' , 'block' ) ;
2015-07-02 02:15:31 +09:00
$ ( '#feed' ) . css ( 'display' , 'block' ) ;
2015-02-25 08:12:20 +09:00
2015-12-04 00:06:02 +09:00
// logged in or not?
2015-02-25 08:12:20 +09:00
if ( window . loggedIn ) {
2015-12-04 00:06:02 +09:00
proceedLoggedIn ( ) ;
2015-02-25 08:12:20 +09:00
}
else {
2015-12-04 00:06:02 +09:00
proceedLoggedOut ( ) ;
2015-06-21 08:29:14 +09:00
}
2015-07-02 02:15:31 +09:00
}
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-12-04 00:06:02 +09:00
· Stuff we do on load specifically for logged out users
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-12-04 00:06:02 +09:00
function proceedLoggedOut ( ) {
2013-08-19 22:30:57 +09:00
display _spinner ( ) ;
2015-12-04 00:06:02 +09:00
setNewCurrentStream ( getStreamFromUrl ( ) , true , false , function ( ) {
$ ( 'input#nickname' ) . focus ( ) ;
$ ( '#page-container' ) . css ( 'opacity' , '1' ) ;
} ) ;
}
2015-07-02 02:15:31 +09:00
2015-12-04 00:06:02 +09:00
/ * ·
·
· Stuff we do on load specifically for logged in users
·
· · · · · · · · · · · · · * /
function proceedLoggedIn ( ) {
display _spinner ( ) ;
2015-11-05 20:34:12 +09:00
2015-11-19 00:38:19 +09:00
// get everyone we follow, block and our memberships and stor in global objects
getAllFollowsMembershipsAndBlocks ( function ( ) {
2015-08-26 06:27:08 +09:00
2015-11-05 20:34:12 +09:00
// do this now not to stall slow computers, also we know of group memberships to highlight now
cacheSyntaxHighlighting ( ) ;
// we might have cached text for the queet box
// (we need to get the mentions suggestions and cache the syntax highlighting before doing this)
2015-11-23 08:24:33 +09:00
$ ( '#queet-box' ) . attr ( 'data-cached-text' , encodeURIComponent ( localStorageObjectCache _GET ( 'queetBoxInput' , 'queet-box' ) ) ) ;
maybePrefillQueetBoxWithCachedText ( $ ( '#queet-box' ) ) ;
2015-11-05 20:34:12 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2015-11-05 20:34:12 +09:00
// load history
loadHistoryFromLocalStorage ( ) ;
// show bookmarks
2015-11-18 06:48:28 +09:00
appendAllBookmarks ( window . qvitterProfilePrefs . bookmarks ) ;
2015-11-05 20:34:12 +09:00
// set stream
2015-12-04 00:06:02 +09:00
setNewCurrentStream ( getStreamFromUrl ( ) , true , false , function ( ) {
2015-11-05 20:34:12 +09:00
$ ( '.language-dropdown' ) . css ( 'display' , 'none' ) ;
2016-01-17 06:24:48 +09:00
$ ( '#page-container' ) . css ( 'opacity' , '1' ) ;
2015-11-05 20:34:12 +09:00
$ ( '#search' ) . fadeIn ( 'slow' ) ;
$ ( '#settingslink .dropdown-toggle' ) . fadeIn ( 'slow' ) ;
$ ( '#top-compose' ) . fadeIn ( 'slow' ) ;
$ ( 'input#nickname' ) . blur ( ) ;
} ) ;
2013-08-19 22:30:57 +09:00
2013-11-23 08:31:04 +09:00
}
2013-08-19 22:30:57 +09:00
2015-12-04 00:06:02 +09:00
/ * ·
·
· Shake the login box , i . e . when indicating an error
·
· · · · · · · · · · · · · * /
function shakeLoginBox ( ) {
$ ( 'input#nickname' ) . css ( 'background-color' , 'pink' ) ;
$ ( 'input#password' ) . css ( 'background-color' , 'pink' ) ;
$ ( '#login-content' ) . effect ( 'shake' , { distance : 5 , times : 2 } , function ( ) {
$ ( 'input#nickname' ) . animate ( { backgroundColor : '#fff' } , 1000 ) ;
$ ( 'input#password' ) . animate ( { backgroundColor : '#fff' } , 1000 ) ;
} ) ;
}
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· In the login form , we want to check the remember - me - checkbox when its label is clicked
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( '#rememberme_label' ) . click ( function ( ) {
if ( $ ( '#rememberme' ) . prop ( 'checked' ) ) {
$ ( '#rememberme' ) . prop ( 'checked' , false ) ;
}
else {
$ ( '#rememberme' ) . prop ( 'checked' , true ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
$ ( '#rememberme_label' ) . disableSelection ( ) ;
2013-08-19 22:30:57 +09:00
2015-12-04 00:06:02 +09:00
/ * ·
·
· Submit login form
·
· · · · · · · · · · · · · * /
$ ( '#form_login' ) . submit ( function ( e ) {
if ( typeof window . loginCheckSuccessful == 'undefined' ) {
e . preventDefault ( ) ;
checkLogin ( $ ( 'input#nickname' ) . val ( ) , $ ( 'input#password' ) . val ( ) , function ( data ) {
window . loginCheckSuccessful = true ;
$ ( '#form_login' ) . submit ( ) ;
} ) ;
}
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-16 11:07:30 +09:00
· Logout
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( '#logout' ) . click ( function ( ) {
2014-11-27 20:54:56 +09:00
window . location . href = window . siteInstanceURL + 'main/logout' ;
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2013-08-26 03:11:53 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-11-24 21:47:45 +09:00
· FAQ
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-11-24 21:47:45 +09:00
$ ( '#faq-link' ) . click ( function ( ) {
2015-07-02 02:15:31 +09:00
popUpAction ( 'popup-faq' , window . siteTitle + ' ' + window . sL . FAQ , '<div id="faq-container"></div>' , false ) ;
2015-01-26 03:05:09 +09:00
getDoc ( 'faq' , function ( faqHtml ) {
$ ( '#faq-container' ) . html ( faqHtml ) ;
} ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2013-11-23 08:31:04 +09:00
2015-01-26 03:05:09 +09:00
2016-02-07 22:17:31 +09:00
/ * ·
·
· Terms
·
· · · · · · · · · · · · · * /
2016-02-11 22:29:57 +09:00
$ ( '#tou-link,.tou-link' ) . click ( function ( ) {
2016-02-07 22:17:31 +09:00
popUpAction ( 'popup-terms' , window . sL . showTerms , '<div id="terms-container"></div>' , false ) ;
2016-02-11 22:29:57 +09:00
if ( window . customTermsOfUse ) {
$ ( '#terms-container' ) . html ( window . customTermsOfUse ) ;
}
else {
getDoc ( 'terms' , function ( termsHtml ) {
$ ( '#terms-container' ) . html ( termsHtml ) ;
} ) ;
}
2016-02-07 22:17:31 +09:00
} ) ;
2013-11-23 08:31:04 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-11-27 20:54:56 +09:00
· Classic Link , toggle setting in api and redirect to / all
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-11-24 21:47:45 +09:00
2015-08-07 04:32:32 +09:00
$ ( '#classic-link, #accessibility-toggle-link' ) . click ( function ( ) {
2014-11-24 21:47:45 +09:00
getFromAPI ( 'qvitter/toggle_qvitter.json' , function ( data ) {
if ( data . success === true ) {
2014-11-27 20:54:56 +09:00
window . location . href = window . siteInstanceURL + window . loggedIn . screen _name + '/all' ;
2014-11-24 21:47:45 +09:00
}
} ) ;
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
} ) ;
2013-11-23 08:31:04 +09:00
2013-08-26 03:11:53 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Handling the language dropdown selection
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( '.dropdown' ) . click ( function ( ) { $ ( this ) . toggleClass ( 'dropped' ) } ) ;
$ ( '.dropdown' ) . disableSelection ( ) ;
$ ( document ) . bind ( 'click' , function ( e ) {
2013-08-26 03:11:53 +09:00
if ( ! $ ( e . target ) . is ( '#logo' ) && ! $ ( e . target ) . is ( '#settingslink' ) && ! $ ( e . target ) . is ( '.nav-session' ) && ! $ ( e . target ) . is ( '.dropdown-toggle' ) && ! $ ( e . target ) . is ( '.dropdown-toggle small' ) && ! $ ( e . target ) . is ( '.dropdown-toggle span' ) && ! $ ( e . target ) . is ( '.dropdown-toggle b' ) ) {
2013-08-19 22:30:57 +09:00
$ ( '.dropdown' ) . removeClass ( 'dropped' ) ;
$ ( '.quitter-settings.dropdown-menu' ) . removeClass ( 'dropped' ) ;
}
} ) ;
$ ( '.language-link' ) . click ( function ( ) {
2015-03-06 06:22:48 +09:00
if ( window . loggedIn === false ) {
var selectedForUser = 'logged_out' ;
2013-08-20 04:15:15 +09:00
}
2015-03-06 06:22:48 +09:00
else {
var selectedForUser = window . loggedIn . id ;
}
2015-07-02 02:15:31 +09:00
2015-03-06 06:22:48 +09:00
localStorageObjectCache _STORE ( 'selectedLanguage' , selectedForUser , $ ( this ) . attr ( 'data-lang-code' ) ) ;
2015-07-02 02:15:31 +09:00
location . reload ( ) ; // reload
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Show the logo menu dropdown on click
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-26 03:11:53 +09:00
$ ( '#settingslink' ) . click ( function ( ) {
2015-09-01 06:53:09 +09:00
removeAllTooltips ( ) ;
2013-08-19 22:30:57 +09:00
if ( ! $ ( '.quitter-settings' ) . hasClass ( 'dropped' ) ) { $ ( '.quitter-settings' ) . addClass ( 'dropped' ) ; }
else { $ ( '.quitter-settings' ) . removeClass ( 'dropped' ) ; }
} ) ;
2016-03-01 03:36:50 +09:00
/ * ·
·
· Show / hide the user menu dropdown on click
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.user-menu-cog' , function ( e ) {
if ( ! $ ( e . target ) . is ( $ ( this ) ) ) {
// don't show/hide when clicking inside the menu
}
// hide
else if ( $ ( this ) . hasClass ( 'dropped' ) ) {
$ ( this ) . removeClass ( 'dropped' ) ;
$ ( this ) . children ( '.dropdown-menu' ) . remove ( ) ;
}
// show
else {
$ ( this ) . addClass ( 'dropped' ) ;
2016-03-01 09:58:12 +09:00
var userID = $ ( this ) . attr ( 'data-user-id' ) ;
var userScreenName = $ ( this ) . attr ( 'data-screen-name' ) ;
var silenced = $ ( this ) . hasClass ( 'silenced' ) ;
var sandboxed = $ ( this ) . hasClass ( 'sandboxed' ) ;
2016-03-01 03:36:50 +09:00
// menu
var menuArray = [ ] ;
2016-03-01 09:08:55 +09:00
// settings etc if it's me
2016-03-01 03:36:50 +09:00
if ( userID == window . loggedIn . id ) {
2016-03-05 07:07:15 +09:00
menuArray = loggedInUsersMenuArray ( ) ;
2016-03-01 03:36:50 +09:00
}
2016-03-01 09:08:55 +09:00
// block etc if it not me
2016-03-01 03:36:50 +09:00
else {
if ( userIsBlocked ( userID ) ) {
menuArray . push ( {
type : 'function' ,
functionName : 'unblockUser' ,
functionArguments : {
userId : userID
} ,
label : window . sL . unblockUser . replace ( '{username}' , '@' + userScreenName )
} ) ;
}
else {
menuArray . push ( {
type : 'function' ,
functionName : 'blockUser' ,
functionArguments : {
userId : userID
} ,
label : window . sL . blockUser . replace ( '{username}' , '@' + userScreenName )
} ) ;
}
2016-03-01 09:08:55 +09:00
2016-03-05 07:07:15 +09:00
// mute profile pref
menuArray . push ( {
type : 'profile-prefs-toggle' ,
namespace : 'qvitter' ,
topic : 'mute:' + userID ,
label : window . sL . muteUser ,
enabledLabel : window . sL . unmuteUser ,
tickDisabled : true ,
callback : 'hideOrShowNoticesAfterMuteOrUnmute'
} ) ;
2016-03-01 09:08:55 +09:00
// moderator actions
menuArray = appendModeratorUserActionsToMenuArray ( menuArray , userID , userScreenName , sandboxed , silenced ) ;
2016-03-01 03:36:50 +09:00
}
var menu = $ ( getMenu ( menuArray ) ) . appendTo ( this ) ;
alignMenuToParent ( menu , $ ( this ) ) ;
}
} ) ;
// hide the stream menu when clicking outside it
$ ( 'body' ) . on ( 'click' , function ( e ) {
if ( ! $ ( e . target ) . is ( '.user-menu-cog' ) && $ ( '.user-menu-cog' ) . hasClass ( 'dropped' ) && ! $ ( e . target ) . closest ( '.user-menu-cog' ) . length > 0 ) {
$ ( '.user-menu-cog' ) . children ( '.dropdown-menu' ) . remove ( ) ;
$ ( '.user-menu-cog' ) . removeClass ( 'dropped' ) ;
}
} ) ;
2015-11-18 06:48:28 +09:00
/ * ·
·
· Show / hide the stream menu dropdown on click
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '#stream-menu-cog' , function ( e ) {
if ( ! $ ( e . target ) . is ( '#stream-menu-cog' ) && $ ( e . target ) . closest ( '#stream-menu-cog' ) . length > 0 ) {
// don't show/hide when clicking inside the menu
}
2015-11-19 23:39:19 +09:00
// hide
2015-11-18 06:48:28 +09:00
else if ( $ ( this ) . hasClass ( 'dropped' ) ) {
$ ( this ) . removeClass ( 'dropped' ) ;
$ ( this ) . children ( '.dropdown-menu' ) . remove ( ) ;
}
2015-11-19 23:39:19 +09:00
// show
2015-11-18 06:48:28 +09:00
else {
$ ( this ) . addClass ( 'dropped' ) ;
var menu = $ ( streamObjectGetMenu ( window . currentStreamObject ) ) . appendTo ( this ) ;
alignMenuToParent ( menu , $ ( this ) ) ;
}
} ) ;
// hide the stream menu when clicking outside it
$ ( 'body' ) . on ( 'click' , function ( e ) {
if ( ! $ ( e . target ) . is ( '#stream-menu-cog' ) && $ ( '#stream-menu-cog' ) . hasClass ( 'dropped' ) && ! $ ( e . target ) . closest ( '#stream-menu-cog' ) . length > 0 ) {
$ ( '#stream-menu-cog' ) . children ( '.dropdown-menu' ) . remove ( ) ;
$ ( '#stream-menu-cog' ) . removeClass ( 'dropped' ) ;
}
} ) ;
2015-11-19 23:39:19 +09:00
/ * ·
·
· Open a queet menu when clicking ellipsis button
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.sm-ellipsis' , function ( e ) {
if ( ! $ ( e . target ) . is ( '.sm-ellipsis' ) && $ ( e . target ) . closest ( '.sm-ellipsis' ) . length > 0 ) {
// don't show/hide when clicking inside the menu
}
// hide
else if ( $ ( this ) . hasClass ( 'dropped' ) ) {
$ ( this ) . removeClass ( 'dropped' ) ;
$ ( this ) . children ( '.dropdown-menu' ) . remove ( ) ;
}
// show
else {
$ ( this ) . addClass ( 'dropped' ) ;
2016-03-01 09:08:55 +09:00
var closestStreamItem = $ ( this ) . closest ( '.queet' ) . parent ( '.stream-item' ) ;
var streamItemUsername = closestStreamItem . attr ( 'data-user-screen-name' ) ;
var streamItemUserID = closestStreamItem . attr ( 'data-user-id' ) ;
var streamItemID = closestStreamItem . attr ( 'data-quitter-id' ) ;
var streamItemUserSandboxed = closestStreamItem . hasClass ( 'sandboxed' ) ;
var streamItemUserSilenced = closestStreamItem . hasClass ( 'silenced' ) ;
2015-11-19 23:39:19 +09:00
2016-02-02 08:44:44 +09:00
// menu
var menuArray = [ ] ;
2016-02-27 10:01:27 +09:00
// delete my notice, or others notices for mods with rights
if ( streamItemUserID == window . loggedIn . id || window . loggedIn . rights . delete _others _notice === true ) {
2016-02-02 08:44:44 +09:00
menuArray . push ( {
type : 'function' ,
functionName : 'deleteQueet' ,
functionArguments : {
streamItemID : streamItemID
2015-11-19 23:39:19 +09:00
} ,
2016-02-02 08:44:44 +09:00
label : window . sL . deleteVerb
} ) ;
2015-11-19 23:39:19 +09:00
}
2016-02-27 10:01:27 +09:00
// block/unblock if it's not me
if ( streamItemUserID != window . loggedIn . id ) {
2016-02-02 08:44:44 +09:00
if ( userIsBlocked ( streamItemUserID ) ) {
menuArray . push ( {
type : 'function' ,
functionName : 'unblockUser' ,
functionArguments : {
userId : streamItemUserID
} ,
label : window . sL . unblockUser . replace ( '{username}' , streamItemUsername )
} ) ;
}
else {
menuArray . push ( {
type : 'function' ,
functionName : 'blockUser' ,
functionArguments : {
userId : streamItemUserID
} ,
2015-11-19 23:39:19 +09:00
label : window . sL . blockUser . replace ( '{username}' , streamItemUsername )
2016-02-02 08:44:44 +09:00
} ) ;
}
2016-03-05 07:07:15 +09:00
// mute profile pref
menuArray . push ( {
type : 'profile-prefs-toggle' ,
namespace : 'qvitter' ,
topic : 'mute:' + streamItemUserID ,
label : window . sL . muteUser ,
enabledLabel : window . sL . unmuteUser ,
tickDisabled : true ,
callback : 'hideOrShowNoticesAfterMuteOrUnmute'
} ) ;
2015-11-19 23:39:19 +09:00
}
2016-03-01 09:08:55 +09:00
// moderator actions
menuArray = appendModeratorUserActionsToMenuArray ( menuArray , streamItemUserID , streamItemUsername , streamItemUserSandboxed , streamItemUserSilenced ) ;
2015-11-19 23:39:19 +09:00
// add menu to DOM and align it
var menu = $ ( getMenu ( menuArray ) ) . appendTo ( this ) ;
alignMenuToParent ( menu , $ ( this ) ) ;
}
} ) ;
// remove the ellipsis menu when clicking outside it
$ ( 'body' ) . on ( 'click' , function ( e ) {
if ( ! $ ( e . target ) . is ( '.sm-ellipsis' ) && $ ( '.sm-ellipsis.dropped' ) . length > 0 && ! $ ( e . target ) . closest ( '.sm-ellipsis' ) . length > 0 ) {
$ ( '.sm-ellipsis' ) . children ( '.dropdown-menu' ) . remove ( ) ;
$ ( '.sm-ellipsis' ) . removeClass ( 'dropped' ) ;
}
} ) ;
2015-11-18 06:48:28 +09:00
/ * ·
·
2016-03-12 23:08:22 +09:00
· When clicking a function row in a stream menu – invoke the function
2015-11-18 06:48:28 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.row-type-function' , function ( e ) {
2015-11-20 02:32:46 +09:00
var thisFunctionRow = $ ( this ) ;
// don't invoke the function again if it's not finished last time
if ( thisFunctionRow . hasClass ( 'clicked' ) ) {
return true ;
}
thisFunctionRow . addClass ( 'clicked' ) ;
2015-11-19 23:39:19 +09:00
var functionName = $ ( this ) . attr ( 'data-function-name' ) ;
2016-03-05 07:07:15 +09:00
if ( typeof $ ( this ) . attr ( 'data-function-arguments' ) == 'undefined' || $ ( this ) . attr ( 'data-function-arguments' ) == 'undefined' ) {
2015-11-19 23:39:19 +09:00
var functionArguments = false ;
}
else {
var functionArguments = JSON . parse ( $ ( this ) . attr ( 'data-function-arguments' ) ) ;
}
2015-11-20 02:32:46 +09:00
window [ functionName ] ( functionArguments , function ( success ) {
if ( success ) {
thisFunctionRow . removeClass ( 'clicked' ) ;
}
} ) ;
2015-11-18 06:48:28 +09:00
} ) ;
/ * ·
·
· When toggeling a a profile pref in a dropdown menu
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.row-type-profile-prefs-toggle' , function ( e ) {
var thisToggle = $ ( this ) ;
// wait for last toggle to finish before toggeling again
if ( thisToggle . hasClass ( 'clicked' ) ) {
return true ;
}
if ( thisToggle . attr ( 'data-profile-pref-state' ) == 'disabled' ) {
var prefDataToSet = '1' ;
}
else if ( thisToggle . attr ( 'data-profile-pref-state' ) == 'enabled' ) {
var prefDataToSet = '0' ;
}
else { // invalid
return true ;
}
thisToggle . addClass ( 'clicked' ) ;
var prefNamespace = thisToggle . attr ( 'data-profile-prefs-namespace' ) ;
var prefTopic = thisToggle . attr ( 'data-profile-prefs-topic' ) ;
2016-03-05 07:07:15 +09:00
var prefLabel = thisToggle . attr ( 'data-profile-prefs-label' ) ;
var prefEnabledLabel = thisToggle . attr ( 'data-profile-prefs-enabled-label' ) ;
2015-11-18 06:48:28 +09:00
// only prefs in the 'qvitter' namespace allowed
if ( prefNamespace != 'qvitter' ) {
return true ;
}
// save pref to server
postSetProfilePref ( prefNamespace , prefTopic , prefDataToSet , function ( data ) {
if ( data === false ) { // error
showErrorMessage ( window . sL . ERRORfailedSavingYourSetting + ' (' + prefTopic + ')' ) ;
}
else { // success
thisToggle . removeClass ( 'clicked' ) ;
if ( thisToggle . attr ( 'data-profile-pref-state' ) == 'disabled' ) {
thisToggle . removeClass ( 'disabled' ) ;
thisToggle . addClass ( 'enabled' ) ;
thisToggle . attr ( 'data-profile-pref-state' , 'enabled' ) ;
2016-03-05 07:07:15 +09:00
if ( prefEnabledLabel != 'undefined' ) {
thisToggle . html ( prefEnabledLabel ) ;
}
2015-11-18 06:48:28 +09:00
window . qvitterProfilePrefs [ prefTopic ] = '1' ;
}
else if ( thisToggle . attr ( 'data-profile-pref-state' ) == 'enabled' ) {
thisToggle . removeClass ( 'enabled' ) ;
thisToggle . addClass ( 'disabled' ) ;
thisToggle . attr ( 'data-profile-pref-state' , 'disabled' ) ;
2016-03-05 07:07:15 +09:00
if ( prefEnabledLabel != 'undefined' ) {
thisToggle . html ( prefLabel ) ;
}
2015-11-18 06:48:28 +09:00
window . qvitterProfilePrefs [ prefTopic ] = '0' ;
}
2016-01-23 05:19:08 +09:00
// run callback
if ( typeof thisToggle . attr ( 'data-profile-pref-callback' ) != 'undefined'
&& thisToggle . attr ( 'data-profile-pref-state' ) != 'undefined'
&& typeof window [ thisToggle . attr ( 'data-profile-pref-callback' ) ] == 'function' ) {
window [ thisToggle . attr ( 'data-profile-pref-callback' ) ] ( ) ;
}
2015-11-18 06:48:28 +09:00
}
} ) ;
} ) ;
2016-01-23 05:19:08 +09:00
/ * ·
·
· Mark all notifications as seen
·
· · · · · · · · · · · · · * /
function markAllNotificationsAsSeen ( arg , callback ) {
display _spinner ( ) ;
getFromAPI ( 'qvitter/mark_all_notifications_as_seen.json' , function ( data ) {
if ( data === false ) {
showErrorMessage ( window . sL . ERRORfailedMarkingAllNotificationsAsRead ) ;
callback ( true ) ;
}
else {
helloAPI ( function ( ) {
$ ( '.stream-item' ) . removeClass ( 'not-seen' ) ;
$ ( '#new-queets-bar' ) . trigger ( 'click' ) ; // show any hidden notifications (this will also remove the dropdown menu)
remove _spinner ( ) ;
callback ( true ) ;
} ) ;
}
} ) ;
}
/ * ·
·
· Show or hide embedded content in timeline ?
·
· · · · · · · · · · · · · * /
function showOrHideEmbeddedContentInTimelineFromProfilePref ( ) {
if ( typeof window . qvitterProfilePrefs [ 'hide_embedded_in_timeline:' + window . currentStreamObject . path ] != 'undefined' ) {
var showHide = window . qvitterProfilePrefs [ 'hide_embedded_in_timeline:' + window . currentStreamObject . path ] ;
if ( parseInt ( showHide , 10 ) == 1 ) {
$ ( '#feed-body' ) . addClass ( 'embedded-content-hidden-by-user' ) ;
2016-03-05 07:07:15 +09:00
return ;
2016-01-23 05:19:08 +09:00
}
}
2016-03-05 07:07:15 +09:00
$ ( '#feed-body' ) . removeClass ( 'embedded-content-hidden-by-user' ) ;
2016-01-23 05:19:08 +09:00
}
/ * ·
·
· Show or hide quotes in timeline ?
·
· · · · · · · · · · · · · * /
function showOrHideQuotesInTimelineFromProfilePref ( ) {
if ( typeof window . qvitterProfilePrefs [ 'hide_quotes_in_timeline:' + window . currentStreamObject . path ] != 'undefined' ) {
var showHide = window . qvitterProfilePrefs [ 'hide_quotes_in_timeline:' + window . currentStreamObject . path ] ;
if ( parseInt ( showHide , 10 ) == 1 ) {
$ ( '#feed-body' ) . addClass ( 'quotes-hidden-by-user' ) ;
2016-03-05 07:07:15 +09:00
return ;
2016-01-23 05:19:08 +09:00
}
}
2016-03-05 07:07:15 +09:00
$ ( '#feed-body' ) . removeClass ( 'quotes-hidden-by-user' ) ;
}
/ * ·
·
· Show or hide notices from muted users in notifications ?
·
· · · · · · · · · · · · · * /
function showOrHideNoticesFromMutedUsersInNotifications ( ) {
if ( typeof window . qvitterProfilePrefs [ 'hide_notifications_from_muted_users' ] != 'undefined' ) {
var showHide = window . qvitterProfilePrefs [ 'hide_notifications_from_muted_users' ] ;
if ( parseInt ( showHide , 10 ) == 1 ) {
$ ( '#feed-body' ) . addClass ( 'hide-notifications-from-muted-users' ) ;
return ;
}
2016-01-23 05:19:08 +09:00
}
2016-03-05 07:07:15 +09:00
$ ( '#feed-body' ) . removeClass ( 'hide-notifications-from-muted-users' )
2016-01-23 05:19:08 +09:00
}
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-02-25 06:36:36 +09:00
· When clicking an external follow button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2013-11-23 08:31:04 +09:00
$ ( 'body' ) . on ( 'click' , '.external-follow-button' , function ( event ) {
2015-07-02 02:15:31 +09:00
popUpAction ( 'popup-external-follow' , window . sL . userExternalFollow + ' ' + $ ( '.profile-card-inner .screen-name' ) . html ( ) , '<form method="post" action="' + window . siteInstanceURL + 'main/ostatus"><input type="hidden" id="nickname" name="nickname" value="' + $ ( '.profile-card-inner .screen-name' ) . html ( ) . substring ( 1 ) + '"><input type="text" id="profile" name="profile" placeholder="' + window . sL . userExternalFollowHelp + '" /></form>' , '<div class="right"><button class="close">' + window . sL . cancelVerb + '</button><button class="primary">' + window . sL . userExternalFollow + '</button></div>' ) ;
2013-11-23 08:31:04 +09:00
$ ( '#popup-external-follow form input#profile' ) . focus ( ) ;
$ ( '#popup-external-follow button.primary' ) . click ( function ( ) {
$ ( '#popup-external-follow form' ) . submit ( ) ;
} ) ;
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-02-25 06:36:36 +09:00
· When clicking an external join button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.external-member-button' , function ( event ) {
2015-07-02 02:15:31 +09:00
popUpAction ( 'popup-external-join' , window . sL . joinExternalGroup + ' ' + $ ( '.profile-card-inner .screen-name' ) . html ( ) , '<form method="post" action="' + window . siteInstanceURL + 'main/ostatus"><input type="hidden" id="group" name="group" value="' + $ ( '.profile-card-inner .screen-name' ) . html ( ) . substring ( 1 ) + '"><input type="text" id="profile" name="profile" placeholder="' + window . sL . userExternalFollowHelp + '" /></form>' , '<div class="right"><button class="close">' + window . sL . cancelVerb + '</button><button class="primary">' + window . sL . userExternalFollow + '</button></div>' ) ;
2014-01-29 03:42:47 +09:00
$ ( '#popup-external-join form input#profile' ) . focus ( ) ;
$ ( '#popup-external-join button.primary' ) . click ( function ( ) {
$ ( '#popup-external-join form' ) . submit ( ) ;
} ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2013-11-23 08:31:04 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2016-02-02 08:44:44 +09:00
· When clicking a follow / block button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-11-23 08:31:04 +09:00
2015-01-27 01:35:44 +09:00
$ ( 'body' ) . on ( 'click' , '.qvitter-follow-button' , function ( event ) {
2015-07-02 02:15:31 +09:00
2016-02-02 08:44:44 +09:00
if ( $ ( this ) . hasClass ( 'disabled' ) ) {
return true ;
}
$ ( this ) . addClass ( 'disabled' ) ;
var user _id = $ ( this ) . attr ( 'data-follow-user-id' ) ;
// if we have a local id, it's straightforward, but we could be handling an unfollow
if ( typeof user _id != 'undefined' ) {
// unblock?
if ( $ ( this ) . hasClass ( 'blocking' ) ) {
unblockUser ( { userId : user _id , blockButton _jQueryElement : $ ( this ) } ) ;
return true ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
2016-02-02 08:44:44 +09:00
// follow or unfollow?
if ( $ ( this ) . hasClass ( 'following' ) ) {
var followOrUnfollow = 'unfollow' ;
}
2013-08-19 22:30:57 +09:00
else {
2016-02-02 08:44:44 +09:00
var followOrUnfollow = 'follow' ;
}
2015-07-02 02:15:31 +09:00
2016-02-02 08:44:44 +09:00
// post to api
display _spinner ( ) ;
APIFollowOrUnfollowUser ( followOrUnfollow , user _id , this , function ( data , this _element ) {
remove _spinner ( ) ;
$ ( this _element ) . removeClass ( 'disabled' ) ;
if ( data ) {
if ( data . following ) {
$ ( this _element ) . addClass ( 'following' ) ;
$ ( '#user-following strong' ) . html ( parseInt ( $ ( '#user-following strong' ) . html ( ) , 10 ) + 1 ) ;
appendUserToMentionsSuggestionsArray ( data ) ;
}
else {
$ ( this _element ) . removeClass ( 'following' ) ;
$ ( '#user-following strong' ) . html ( parseInt ( $ ( '#user-following strong' ) . html ( ) , 10 ) - 1 ) ;
}
2014-11-24 21:47:45 +09:00
}
2016-02-02 08:44:44 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2016-02-02 08:44:44 +09:00
return true ;
}
2015-07-02 02:15:31 +09:00
2016-02-02 08:44:44 +09:00
// if there's no local user id, we have to take a detour
$ . ajax ( { url : window . siteInstanceURL + 'main/ostatussub' ,
type : "POST" ,
data : {
token : window . commonSessionToken ,
profile : $ ( this ) . attr ( 'data-follow-user' ) ,
submit : 'Confirm'
} ,
error : function ( data ) { console . log ( 'error' ) ; console . log ( data ) ; } ,
success : function ( data ) {
// reload page on success
// since ostatussub doesn't have an api, there's no good way to get the local user id here,
// and change the button to an unsubscribe button.
window . location . replace ( window . siteInstanceURL + window . loggedIn . screen _name + '/subscriptions' ) ;
2015-07-02 02:15:31 +09:00
}
2016-02-02 08:44:44 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking a join group button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( 'body' ) . on ( 'click' , '.member-button' , function ( event ) {
if ( ! $ ( this ) . hasClass ( 'disabled' ) ) {
$ ( this ) . addClass ( 'disabled' ) ;
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
// get group id
var group _id = $ ( this ) . attr ( 'data-group-id' ) ;
// join or leave?
if ( $ ( this ) . hasClass ( 'member' ) ) {
var joinOrLeave = 'leave' ;
}
else {
var joinOrLeave = 'join' ;
}
// post to api
display _spinner ( ) ;
APIJoinOrLeaveGroup ( joinOrLeave , group _id , this , function ( data , this _element ) {
remove _spinner ( ) ;
$ ( this _element ) . removeClass ( 'disabled' ) ;
if ( data ) {
if ( data . member ) {
$ ( this _element ) . addClass ( 'member' ) ;
$ ( '.profile-card .member-stats strong' ) . html ( parseInt ( $ ( '.profile-card .member-stats strong' ) . html ( ) , 10 ) + 1 ) ;
$ ( '#user-groups strong' ) . html ( parseInt ( $ ( '#user-groups strong' ) . html ( ) , 10 ) + 1 ) ;
2015-08-26 08:40:29 +09:00
// add group to mention suggestion array
if ( data . homepage _logo === null ) {
data . homepage _logo = window . defaultAvatarStreamSize ;
}
var groupmembershipObject = { avatar : data . homepage _logo , id : data . id , name : data . fullname , url : data . url , username : data . nickname } ;
window . groupMemberships . push ( groupmembershipObject ) ;
2013-08-19 22:30:57 +09:00
}
else if ( data . member === false ) {
$ ( this _element ) . removeClass ( 'member' ) ;
$ ( '.profile-card .member-stats strong' ) . html ( parseInt ( $ ( '.profile-card .member-stats strong' ) . html ( ) , 10 ) - 1 ) ;
$ ( '#user-groups strong' ) . html ( parseInt ( $ ( '#user-groups strong' ) . html ( ) , 10 ) - 1 ) ;
2015-08-26 08:40:29 +09:00
// remove group from mention suggestion array, if it's there
var groupToRemove = false ;
$ . each ( window . groupMemberships , function ( k , v ) {
if ( v . id == data . id ) {
groupToRemove = k ;
}
} ) ;
if ( groupToRemove ) {
console . log ( 'remove at' + groupToRemove ) ;
window . groupMemberships . splice ( groupToRemove , 1 ) ;
}
2013-08-19 22:30:57 +09:00
}
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-09-18 08:42:52 +09:00
· Go to profile page when clicking the small user header in left column
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2015-09-18 08:42:52 +09:00
$ ( '#user-header' ) . on ( 'click' , function ( e ) {
2016-03-05 07:07:15 +09:00
// not if we're clicking the mini-logged-in-user-cog-wheel
if ( $ ( e . target ) . is ( '#mini-logged-in-user-cog-wheel' ) ) {
2014-11-24 21:47:45 +09:00
return ;
}
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( pathToStreamRouter ( window . loggedIn . screen _name ) , true , false ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Searching
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( '#search-query' ) . on ( 'keyup' , function ( e ) { if ( e . keyCode == 13 ) { showSearchStream ( ) ; } } ) ; // on enter in input field
$ ( 'button.icon.nav-search' ) . on ( 'click' , function ( e ) { showSearchStream ( ) ; } ) ; // on click on magnifying glass
function showSearchStream ( ) {
2015-09-18 08:42:52 +09:00
var path = 'search/notice?q=' + encodeURIComponent ( replaceHtmlSpecialChars ( $ ( '#search-query' ) . val ( ) ) ) ;
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( pathToStreamRouter ( path ) , true , false ) ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
/ * ·
2013-11-23 08:31:04 +09:00
· < o
· Hijack all links and look for local users , tags , searches and groups . ( //
2015-07-02 02:15:31 +09:00
·
2013-08-19 22:30:57 +09:00
· If found , select that stream and prevent links default behaviour
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , 'a' , function ( e ) {
2013-08-19 22:30:57 +09:00
2014-11-24 21:47:45 +09:00
// don't hijack if metakeys are pressed!
2013-11-23 08:31:04 +09:00
if ( e . ctrlKey || e . altKey || e . shiftKey || e . metaKey ) {
return ;
}
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// don't hijack if this is an anchor link in the faq
if ( $ ( this ) . closest ( '.modal-container' ) . attr ( 'id' ) == 'popup-faq' && $ ( this ) . attr ( 'href' ) . indexOf ( '#' ) > - 1 ) {
return ;
}
2015-09-01 06:53:09 +09:00
// don't hijack and don't follow link if this is the bookmark stream icon, prevent link but don't set a new currentstream
2014-01-29 03:42:47 +09:00
if ( $ ( e . target ) . is ( 'i.chev-right' ) ) {
2015-07-02 02:15:31 +09:00
e . preventDefault ( ) ;
2013-11-23 08:31:04 +09:00
return ;
2015-07-02 02:15:31 +09:00
}
2014-11-24 21:47:45 +09:00
2014-12-09 01:39:47 +09:00
// don't hijack links with donthijack attribute
if ( ! ! $ ( this ) . attr ( 'donthijack' ) || $ ( this ) . attr ( 'donthijack' ) == '' ) {
2015-07-02 02:15:31 +09:00
return ;
2014-12-09 01:39:47 +09:00
}
2015-06-05 09:17:33 +09:00
2014-12-09 01:39:47 +09:00
// all links opens in new tab
2015-07-02 02:15:31 +09:00
$ ( this ) . attr ( 'target' , '_blank' ) ;
2013-11-23 08:31:04 +09:00
2015-09-18 08:42:52 +09:00
// only proceed if we really have a href attribute
if ( typeof $ ( this ) . attr ( 'href' ) == 'undefined' ) {
return ;
}
2015-07-02 02:15:31 +09:00
2015-09-18 08:42:52 +09:00
// profile picture
if ( $ ( this ) . hasClass ( 'profile-picture' ) ) {
e . preventDefault ( ) ;
if ( $ ( this ) . closest ( '.modal-container' ) . attr ( 'id' ) != 'edit-profile-popup' ) { // no popup if we're editing our profile
popUpAction ( 'popup-profile-picture' , $ ( '.profile-card-inner .screen-name' ) . html ( ) , '<img style="width:100%;display:block;" src="' + $ ( this ) . attr ( 'href' ) + '" />' , false ) ;
2015-11-17 02:24:34 +09:00
$ ( '.hover-card,.hover-card-caret' ) . remove ( ) ;
2014-11-24 21:47:45 +09:00
}
2015-09-18 08:42:52 +09:00
}
// hijack link if we find a matching link that qvitter can handle
else {
var streamObject = URLtoStreamRouter ( $ ( this ) . attr ( 'href' ) ) ;
if ( streamObject && streamObject . stream ) {
2013-08-19 22:30:57 +09:00
e . preventDefault ( ) ;
2015-06-05 09:17:33 +09:00
2015-09-18 20:42:19 +09:00
// if this is a user/{id} type link we want to find the nickname before setting a new stream
// the main reason is that we want to update the browsers location bar and the .stream-selecton
// links as fast as we can. we rather not wait for the server response
2015-09-18 08:42:52 +09:00
if ( streamObject . name == 'profile by id' ) {
2015-09-18 20:42:19 +09:00
// pathToStreamRouter() might have found a cached nickname
if ( streamObject . nickname ) {
setNewCurrentStream ( pathToStreamRouter ( streamObject . nickname ) , true , streamObject . id ) ;
2015-09-18 08:42:52 +09:00
}
2015-09-18 20:42:19 +09:00
// otherwise we might follow the user and thereby already know its nickname
else if ( typeof window . following != 'undefined' && typeof window . following [ streamObject . id ] != 'undefined' ) {
setNewCurrentStream ( pathToStreamRouter ( window . following [ streamObject . id ] . username ) , true , streamObject . id ) ;
}
// if the text() of the clicked element looks like a user nickname, use that (but send id to setNewCurrentStream() in case this is bad data)
2016-03-12 23:08:22 +09:00
else if ( /^@[a-zA-Z0-9]+$/ . test ( $ ( e . target ) . text ( ) ) || /^[a-zA-Z0-9]+$/ . test ( $ ( e . target ) . text ( ) ) ) {
2015-09-18 20:42:19 +09:00
var nickname = $ ( e . target ) . text ( ) ;
if ( nickname . indexOf ( '@' ) == 0 ) {
nickname = nickname . substring ( 1 ) ; // remove any starting @
}
setNewCurrentStream ( pathToStreamRouter ( nickname ) , true , streamObject . id ) ;
}
// if we can't figure out or guess a nickname, query the server for it
2015-09-18 08:42:52 +09:00
else {
2015-09-18 20:42:19 +09:00
getNicknameByUserIdFromAPI ( streamObject . id , function ( nickname ) {
2015-09-18 08:42:52 +09:00
if ( nickname ) {
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( pathToStreamRouter ( nickname ) , true , false ) ;
2015-09-18 08:42:52 +09:00
}
else {
2015-09-18 20:42:19 +09:00
alert ( 'user not found' ) ;
2015-09-18 08:42:52 +09:00
}
} ) ;
}
2013-08-19 22:30:57 +09:00
}
2015-09-21 09:00:03 +09:00
// same with group/{id}/id links
else if ( streamObject . name == 'group notice stream by id' ) {
// we might be member of the group and thereby already know its nickname
if ( typeof window . groupMemberships != 'undefined' && typeof window . groupMemberships [ streamObject . id ] != 'undefined' ) {
setNewCurrentStream ( pathToStreamRouter ( 'group/' + window . groupMemberships [ streamObject . id ] . username ) , true , streamObject . id ) ;
}
// if the text() of the clicked element looks like a group nickname, use that (but send id to setNewCurrentStream() in case this is bad data)
2016-03-12 23:08:22 +09:00
else if ( /^![a-zA-Z0-9]+$/ . test ( $ ( e . target ) . text ( ) ) || /^[a-zA-Z0-9]+$/ . test ( $ ( e . target ) . text ( ) ) ) {
2015-09-21 09:00:03 +09:00
var nickname = $ ( e . target ) . text ( ) ;
if ( nickname . indexOf ( '!' ) == 0 ) {
nickname = nickname . substring ( 1 ) ; // remove any starting !
}
setNewCurrentStream ( pathToStreamRouter ( 'group/' + nickname ) , true , streamObject . id ) ;
}
// if we can't figure out or guess a nickname, query the server for it
else {
getNicknameByGroupIdFromAPI ( streamObject . id , function ( nickname ) {
if ( nickname ) {
setNewCurrentStream ( pathToStreamRouter ( 'group/' + nickname ) , true , false ) ;
}
else {
alert ( 'group not found' ) ;
}
} ) ;
}
}
2015-09-18 20:42:19 +09:00
// all other links that qvitter can handle
2013-08-19 22:30:57 +09:00
else {
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( streamObject , true , false ) ;
2013-08-19 22:30:57 +09:00
}
}
2015-07-02 02:15:31 +09:00
}
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-09-01 06:53:09 +09:00
· When user clicks the bookmark icon to bookmark
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '#history-container .chev-right' , function ( event ) {
2015-09-01 06:53:09 +09:00
var thisStreamLink = $ ( this ) . parent ( '.stream-selection' ) ;
thisStreamLink . slideUp ( 300 , function ( ) {
$ ( '#bookmark-container' ) . append ( thisStreamLink . outerHTML ( ) ) ;
$ ( '#bookmark-container' ) . children ( ) . last ( ) . children ( '.chev-right' ) . attr ( 'data-tooltip' , window . sL . tooltipRemoveBookmark ) ;
$ ( '#bookmark-container' ) . children ( ) . last ( ) . fadeIn ( 300 , function ( ) {
thisStreamLink . remove ( ) ;
updateHistoryLocalStorage ( ) ;
saveAllBookmarks ( ) ;
} ) ;
} ) ;
} ) ;
/ * ·
·
· When user clicks the x to remove a bookmark
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '#bookmark-container .chev-right' , function ( event ) {
2013-08-19 22:30:57 +09:00
$ ( this ) . parent ( '.stream-selection' ) . remove ( ) ;
2015-09-01 06:53:09 +09:00
saveAllBookmarks ( ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-09-01 06:53:09 +09:00
· When sorting the bookmark menu
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-09-01 06:53:09 +09:00
$ ( '#bookmark-container' ) . on ( "sortupdate" , function ( ) {
saveAllBookmarks ( ) ;
} ) ;
/ * ·
·
· When clearing the browsing history
·
· · · · · · · · · · · · · * /
$ ( '#clear-history' ) . on ( 'click' , function ( ) {
$ ( '#history-container' ) . empty ( ) ;
2013-08-19 22:30:57 +09:00
updateHistoryLocalStorage ( ) ;
} ) ;
2015-07-02 02:15:31 +09:00
2015-09-01 06:53:09 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Load more from the current stream when scroll is 1000 px from bottom
·
2015-07-02 02:15:31 +09:00
· The search API is crap and don ' t do max _id and last _id , so we have to do pages there ...
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( window ) . scroll ( function ( ) {
if ( $ ( window ) . scrollTop ( ) + $ ( window ) . height ( ) > $ ( document ) . height ( ) - 1000 ) {
2015-07-02 02:15:31 +09:00
2013-11-29 20:49:54 +09:00
// not if we're already loading or if no stream is set yet
2015-11-23 08:24:33 +09:00
if ( ! $ ( 'body' ) . hasClass ( 'loading-older' ) && typeof window . currentStreamObject != "undefined" && $ ( '#feed-body' ) . attr ( 'data-end-reached' ) != 'true' ) {
2013-08-20 22:26:25 +09:00
$ ( 'body' ) . addClass ( 'loading-older' ) ;
2015-07-02 02:15:31 +09:00
// remove loading class in 10 seconds, i.e. try again if failed to load within 10 s
2015-11-23 08:24:33 +09:00
if ( window . currentStreamObject . name != 'search' ) {
2015-07-02 02:15:31 +09:00
setTimeout ( function ( ) { $ ( 'body' ) . removeClass ( 'loading-older' ) ; } , 10000 ) ;
2013-08-20 22:26:25 +09:00
}
2015-07-02 02:15:31 +09:00
var lastStreamItemId = $ ( '#feed-body' ) . children ( '.stream-item' ) . last ( ) . attr ( 'id' ) ;
2015-09-18 08:42:52 +09:00
// if this is a stream that uses 'page' for paging, i.e. search or users lists,
// we need page and rpp vars (page number is stored in an attribute in feed-body)
if ( window . currentStreamObject . maxIdOrPage == 'page' ) {
2013-08-20 22:26:25 +09:00
if ( typeof $ ( '#feed-body' ) . attr ( 'data-search-page-number' ) != 'undefined' ) {
var searchPage = parseInt ( $ ( '#feed-body' ) . attr ( 'data-search-page-number' ) , 10 ) ;
2013-08-19 22:30:57 +09:00
}
else {
2013-08-20 22:26:25 +09:00
var searchPage = 2 ;
2013-08-19 22:30:57 +09:00
}
2013-08-20 22:26:25 +09:00
var nextPage = searchPage + 1 ;
2015-11-23 08:24:33 +09:00
var getVars = qOrAmp ( window . currentStreamObject . stream ) + 'rpp=20&page=' + searchPage ; // search uses 'rpp' var and others 'count' for paging, though we can add rrp to others aswell without any problem
2013-08-20 22:26:25 +09:00
}
// normal streams
else {
2015-11-23 08:24:33 +09:00
var getVars = qOrAmp ( window . currentStreamObject . stream ) + 'max_id=' + ( $ ( '#feed-body' ) . children ( '.stream-item' ) . last ( ) . attr ( 'data-quitter-id-in-stream' ) ) ;
2013-08-20 22:26:25 +09:00
}
2015-07-02 02:15:31 +09:00
display _spinner ( '#footer-spinner-container' ) ;
2015-11-23 08:24:33 +09:00
getFromAPI ( window . currentStreamObject . stream + getVars , function ( data ) {
2015-09-18 08:42:52 +09:00
// if data returned an empty array, we have probably reached the bottom
if ( data . length == 0 ) {
$ ( '#feed-body' ) . attr ( 'data-end-reached' , true ) ;
}
else if ( data ) {
2015-07-02 02:15:31 +09:00
addToFeed ( data , lastStreamItemId , 'visible' ) ;
2013-08-20 22:26:25 +09:00
$ ( 'body' ) . removeClass ( 'loading-older' ) ;
2015-07-02 02:15:31 +09:00
2015-09-18 08:42:52 +09:00
// if this is search our group users lists, we remember page number (if we got any users)
if ( window . currentStreamObject . maxIdOrPage == 'page' ) {
2013-08-20 22:26:25 +09:00
$ ( '#feed-body' ) . attr ( 'data-search-page-number' , nextPage ) ;
2013-08-19 22:30:57 +09:00
}
2013-08-20 22:26:25 +09:00
}
2015-09-18 08:42:52 +09:00
remove _spinner ( ) ;
2013-08-20 22:26:25 +09:00
} ) ;
}
}
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Updates all queets ' times / dates
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
var updateTimesInterval = self . setInterval ( function ( ) {
2015-12-22 21:36:44 +09:00
updateAllQueetsTimes ( ) ;
2013-08-19 22:30:57 +09:00
} , 10000 ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-11-24 21:47:45 +09:00
· Check for new queets
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
var checkForNewQueetsInterval = window . setInterval ( function ( ) { checkForNewQueets ( ) } , window . timeBetweenPolling ) ;
function checkForNewQueets ( ) {
// no new requests if requests are very slow, e.g. searches
if ( ! $ ( 'body' ) . hasClass ( 'loading-newer' ) ) {
$ ( 'body' ) . addClass ( 'loading-newer' ) ;
2015-11-18 06:48:28 +09:00
// only if logged in and only for notice or notification streams
2016-03-12 23:08:22 +09:00
if ( window . loggedIn && ( window . currentStreamObject . type == 'notices' || window . currentStreamObject . type == 'notifications' ) ) {
2015-11-23 08:24:33 +09:00
var lastId = $ ( '#feed-body' ) . children ( '.stream-item' ) . not ( '.temp-post' ) . not ( '.posted-from-form' ) . attr ( 'data-quitter-id-in-stream' ) ;
var addThisStream = window . currentStreamObject . stream ;
2014-11-24 21:47:45 +09:00
var timeNow = new Date ( ) . getTime ( ) ;
2015-11-23 08:24:33 +09:00
getFromAPI ( addThisStream + qOrAmp ( window . currentStreamObject . stream ) + 'since_id=' + lastId , function ( data ) {
2013-08-19 22:30:57 +09:00
if ( data ) {
$ ( 'body' ) . removeClass ( 'loading-newer' ) ;
2015-11-23 08:24:33 +09:00
if ( addThisStream == window . currentStreamObject . stream ) {
2015-07-02 02:15:31 +09:00
addToFeed ( data , false , 'hidden' ) ;
2015-11-23 08:24:33 +09:00
// say hello to the api if this is notifications stream, to
// get correct unread notifcation count
if ( window . currentStreamObject . name == 'notifications' ) {
helloAPI ( ) ;
2015-11-18 06:48:28 +09:00
}
2015-11-23 08:24:33 +09:00
// if we have hidden items, show new-queets-bar
maybeShowTheNewQueetsBar ( )
2015-11-18 06:48:28 +09:00
}
}
} ) ;
2015-07-02 02:15:31 +09:00
}
}
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Show hidden queets when user clicks on new - queets - bar
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '#new-queets-bar' , function ( ) {
2015-09-18 08:42:52 +09:00
if ( window . currentStreamObject . name == 'notifications' ) {
2015-07-02 02:15:31 +09:00
document . title = window . siteTitle ;
2014-09-25 06:20:35 +09:00
}
2015-07-02 02:15:31 +09:00
var hiddenStreamItems = $ ( '.stream-item.hidden' ) ;
hiddenStreamItems . css ( 'opacity' , '0' )
hiddenStreamItems . animate ( { opacity : '1' } , 200 ) ;
hiddenStreamItems . addClass ( 'visible' ) ;
hiddenStreamItems . removeClass ( 'hidden' ) ;
2013-08-19 22:30:57 +09:00
$ ( '#new-queets-bar' ) . parent ( ) . addClass ( 'hidden' ) ;
2015-11-18 06:48:28 +09:00
// say hello to the api if this is notifications stream, to
// get correct unread notifcation count
if ( window . currentStreamObject . name == 'notifications' ) {
helloAPI ( ) ;
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Expand and de - expand queets when clicking anywhere but on a few element types
2015-07-02 02:15:31 +09:00
·
2015-06-10 06:42:41 +09:00
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.queet' , function ( event ) {
2016-01-21 01:39:34 +09:00
if ( typeof $ ( this ) . attr ( 'href' ) == 'undefined'
&& $ ( event . target ) . closest ( 'a' ) . length == 0
&& ! $ ( event . target ) . is ( ' \
2015-09-18 19:02:23 +09:00
a , \
video , \
. cm - mention , \
. cm - tag , \
. cm - group , \
. cm - url , \
pre , \
img , \
. name , \
. queet - box , \
. syntax - two , \
button , \
. show - full - conversation , \
span . mention , \
. action - reply - container a span , \
. action - reply - container a b , \
. action - rt - container a span , \
. action - rt - container a b , \
. action - del - container a span , \
. action - del - container a b , \
. action - fav - container a span , \
. action - fav - container a b , \
. action - ellipsis - container a span , \
. action - ellipsis - container a b , \
span . group , \
. longdate , \
2015-11-17 04:27:40 +09:00
. screen - name , \
. discard - error - message ' )
2013-09-03 01:13:15 +09:00
&& ! $ ( this ) . parent ( '.stream-item' ) . hasClass ( 'user' ) ) { // not if user stream
2013-08-19 22:30:57 +09:00
expand _queet ( $ ( this ) . parent ( ) ) ;
2015-07-02 02:15:31 +09:00
}
2013-08-19 22:30:57 +09:00
} ) ;
2015-06-10 06:42:41 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-06-10 06:42:41 +09:00
· Image popups
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2015-06-10 06:42:41 +09:00
$ ( 'body' ) . on ( 'click' , '.stream-item .queet img.attachment-thumb' , function ( event ) {
event . preventDefault ( ) ;
2015-07-02 02:15:31 +09:00
2015-06-10 06:42:41 +09:00
// don't do anything if we are in the middle of collapsing
if ( $ ( this ) . closest ( '.stream-item' ) . hasClass ( 'collapsing' ) ) {
// no action
}
// if the stream item isn't expanded, expand that
else if ( ! $ ( this ) . closest ( '.stream-item' ) . hasClass ( 'expanded' ) ) {
expand _queet ( $ ( this ) . closest ( '.stream-item' ) ) ;
}
// otherwise we open the popup
else {
2015-07-02 02:15:31 +09:00
var thisAttachmentThumbSrc = $ ( this ) . attr ( 'src' ) ;
2015-06-10 06:42:41 +09:00
var parentStreamItem = $ ( this ) . closest ( '.stream-item' ) ;
var $parentStreamItemClone = $ ( '<div/>' ) . append ( parentStreamItem . outerHTML ( ) ) ;
2016-03-08 02:05:58 +09:00
var $queetThumbsClone = $ ( '<div/>' ) . append ( $parentStreamItemClone . children ( '.stream-item' ) . children ( '.queet' ) . find ( '.queet-thumbs' ) . outerHTML ( ) ) ;
2015-07-02 02:15:31 +09:00
2016-03-05 07:07:15 +09:00
// cleaned version of the stream item to show in the footer
cleanStreamItemsFromClassesAndConversationElements ( $parentStreamItemClone ) ;
$parentStreamItemClone . find ( '.context,.stream-item-footer' ) . remove ( ) ;
var parentStreamItemHTMLWithoutFooter = $parentStreamItemClone . outerHTML ( ) ;
2015-06-17 07:44:18 +09:00
$thumbToDisplay = $queetThumbsClone . find ( 'img.attachment-thumb[src="' + thisAttachmentThumbSrc + '"]' ) ;
$thumbToDisplay . parent ( ) . addClass ( 'display-this-thumb' ) ;
2016-03-13 05:36:00 +09:00
// "play" all animated gifs and add youtube iframes to all youtube and vimeo videos
2015-06-17 07:44:18 +09:00
$ . each ( $queetThumbsClone . find ( 'img.attachment-thumb' ) , function ( ) {
if ( $ ( this ) . attr ( 'data-mime-type' ) == 'image/gif'
&& $ ( this ) . parent ( ) . hasClass ( 'play-button' ) ) {
$ ( this ) . attr ( 'src' , $ ( this ) . attr ( 'data-full-image-url' ) ) ;
$ ( this ) . parent ( '.thumb-container' ) . css ( 'background-image' , 'url(\'' + $ ( this ) . attr ( 'data-full-image-url' ) + '\')' ) ;
}
2016-03-13 05:36:00 +09:00
else if ( $ ( this ) . parent ( ) . hasClass ( 'host-youtube-com' ) ) {
$ ( this ) . parent ( ) . prepend ( '<iframe width="510" height="315" src="' + youTubeEmbedLinkFromURL ( $ ( this ) . attr ( 'data-full-image-url' ) , $ ( this ) . parent ( ) . hasClass ( 'display-this-thumb' ) ) + '" frameborder="0" allowscriptaccess="always" allowfullscreen></iframe>' ) ;
}
else if ( $ ( this ) . parent ( ) . hasClass ( 'host-vimeo-com' ) ) {
$ ( this ) . parent ( ) . prepend ( '<iframe src="' + vimeoEmbedLinkFromURL ( $ ( this ) . attr ( 'data-full-image-url' ) , $ ( this ) . parent ( ) . hasClass ( 'display-this-thumb' ) ) + '" width="510" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>' ) ;
2015-07-02 02:15:31 +09:00
}
2015-06-17 07:44:18 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2015-06-17 07:44:18 +09:00
// navigation buttons
2015-06-13 05:35:37 +09:00
var imgNum = parentStreamItem . children ( '.queet' ) . find ( '.attachment-thumb' ) . length ;
2015-06-10 06:42:41 +09:00
if ( imgNum > 1 ) {
$queetThumbsClone . find ( '.queet-thumbs' ) . before ( '<div class="prev-thumb"></div>' ) ;
2015-07-02 02:15:31 +09:00
$queetThumbsClone . find ( '.queet-thumbs' ) . after ( '<div class="next-thumb"></div>' ) ;
2015-06-10 06:42:41 +09:00
}
2015-07-02 02:15:31 +09:00
if ( parentStreamItem . hasClass ( 'expanded' ) ) {
2016-03-13 05:36:00 +09:00
var calculatedDimensions = calculatePopUpAndImageDimensions ( $thumbToDisplay ) ;
2015-06-17 07:44:18 +09:00
var $thisImgInQueetThumbsClone = $queetThumbsClone . find ( 'img[src="' + $thumbToDisplay . attr ( 'src' ) + '"]' ) ;
2015-07-02 02:15:31 +09:00
2015-06-10 06:42:41 +09:00
// set dimensions
$thisImgInQueetThumbsClone . width ( calculatedDimensions . displayImgWidth ) ;
$thisImgInQueetThumbsClone . parent ( '.thumb-container' ) . width ( calculatedDimensions . displayImgWidth ) ;
2015-06-17 07:44:18 +09:00
$thisImgInQueetThumbsClone . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'width' , calculatedDimensions . displayImgWidth ) ;
2015-07-02 02:15:31 +09:00
$thisImgInQueetThumbsClone . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'height' , calculatedDimensions . displayImgHeight ) ;
2015-06-10 06:42:41 +09:00
// open popup
2016-03-05 07:07:15 +09:00
popUpAction ( 'queet-thumb-popup' , '' , '' + $queetThumbsClone . outerHTML ( ) + '' , parentStreamItemHTMLWithoutFooter , calculatedDimensions . popUpWidth ) ;
2015-07-02 02:15:31 +09:00
disableOrEnableNavigationButtonsInImagePopup ( $ ( '#queet-thumb-popup' ) ) ;
2016-03-13 05:36:00 +09:00
// for some reason vimeo autoplays when we have a #t=x start time, so stop any vimeo videos running in the background (delay so it has time to load)
setTimeout ( function ( ) {
$ . each ( $ ( '#queet-thumb-popup' ) . find ( '.thumb-container.host-vimeo-com:not(.display-this-thumb)' ) . children ( 'iframe' ) , function ( ) {
console . log ( $ ( this ) . attr ( 'src' ) ) ;
this . contentWindow . postMessage ( '{"method": "pause"}' , '*' ) ;
} ) ;
} , 1000 ) ;
2015-06-10 06:42:41 +09:00
}
}
} ) ;
2015-07-02 02:15:31 +09:00
// popups can be max 900px wide, and should not be higher than the window, so we need to do some calculating
2016-03-13 05:36:00 +09:00
function calculatePopUpAndImageDimensions ( img ) {
var img _src = img . attr ( 'src' ) ;
2015-06-10 09:27:57 +09:00
// trick to get width and height, we can't go with what gnusocial tells us, because
// gnusocial doesn't (always?) report width and height after proper orientation
$ ( 'body' ) . prepend ( '<div id="img-dimension-check" style="opacity:0;"><img src="' + img _src + '" /></div>' ) ;
var imgWidth = $ ( '#img-dimension-check img' ) . width ( ) ;
2015-07-02 02:15:31 +09:00
var imgHeight = $ ( '#img-dimension-check img' ) . height ( ) ;
2015-06-10 09:27:57 +09:00
$ ( '#img-dimension-check' ) . remove ( ) ;
2015-06-10 06:42:41 +09:00
2015-07-02 02:15:31 +09:00
// e.g. svg's may not have dimensions set, in that case we just make them small
2015-06-10 06:42:41 +09:00
if ( typeof imgWidth == 'undefined' && typeof imgHeight == 'undefined' ) {
2015-07-02 02:15:31 +09:00
return { popUpWidth : 540 , displayImgWidth : 540 } ;
2015-06-10 06:42:41 +09:00
}
var thisImgWidth = parseInt ( imgWidth , 10 ) ;
2015-07-02 02:15:31 +09:00
var thisImgHeight = parseInt ( imgHeight , 10 ) ;
var maxImageHeight = $ ( window ) . height ( ) - 120 ; // 120 being a little more than a short queet in the footer
2015-06-10 06:42:41 +09:00
if ( thisImgWidth < 540 ) {
var displayImgWidth = thisImgWidth ;
var popUpWidth = 540 ;
if ( thisImgHeight > maxImageHeight ) {
2015-06-13 05:35:37 +09:00
displayImgWidth = Math . round ( maxImageHeight / thisImgHeight * displayImgWidth ) ;
2015-06-10 06:42:41 +09:00
}
}
else if ( thisImgWidth < 900 ) {
var displayImgWidth = thisImgWidth ;
if ( thisImgHeight > maxImageHeight ) {
displayImgWidth = Math . round ( maxImageHeight / thisImgHeight * displayImgWidth ) ;
if ( displayImgWidth < 540 ) {
2015-07-02 02:15:31 +09:00
var popUpWidth = 540 ;
2015-06-10 06:42:41 +09:00
}
else {
2015-07-02 02:15:31 +09:00
var popUpWidth = displayImgWidth ;
2015-06-10 06:42:41 +09:00
}
}
else {
var popUpWidth = displayImgWidth ;
}
}
else {
var displayImgWidth = 900 ;
var displayImgHeight = 900 / thisImgWidth * thisImgHeight ;
if ( displayImgHeight > maxImageHeight ) {
2015-07-02 02:15:31 +09:00
displayImgWidth = Math . round ( maxImageHeight * displayImgWidth / displayImgHeight ) ;
2015-06-10 06:42:41 +09:00
if ( displayImgWidth < 540 ) {
2015-07-02 02:15:31 +09:00
var popUpWidth = 540 ;
2015-06-10 06:42:41 +09:00
}
else if ( displayImgWidth < 900 ) {
2015-07-02 02:15:31 +09:00
var popUpWidth = displayImgWidth ;
2015-06-10 06:42:41 +09:00
}
else {
var popUpWidth = 900 ;
}
}
else {
var popUpWidth = 900 ;
2015-07-02 02:15:31 +09:00
}
}
2016-03-13 05:36:00 +09:00
// vimeo can't be too small, or the design freaks out
if ( img . parent ( '.thumb-container' ) . hasClass ( 'host-vimeo-com' ) && displayImgWidth < 540 ) {
displayImgWidth = 540 ;
displayImgHeight = 305 ;
}
return { popUpWidth : popUpWidth , displayImgWidth : displayImgWidth , displayImgHeight : displayImgHeight } ;
2015-06-10 06:42:41 +09:00
}
// switch to next image when clicking the image in the popup
$ ( 'body' ) . on ( 'click' , '#queet-thumb-popup .attachment-thumb' , function ( event ) {
event . preventDefault ( ) ;
2015-07-02 02:15:31 +09:00
2015-06-10 06:42:41 +09:00
var nextImage = $ ( this ) . parent ( ) . next ( ) . children ( '.attachment-thumb' ) ;
if ( nextImage . length > 0 ) {
2015-07-02 02:15:31 +09:00
2015-06-17 07:44:18 +09:00
// start and stop youtube videos, if any
2016-03-13 05:36:00 +09:00
$ . each ( $ ( this ) . parent ( '.host-youtube-com' ) . children ( 'iframe' ) , function ( ) {
2015-06-17 07:44:18 +09:00
this . contentWindow . postMessage ( '{"event":"command","func":"' + 'stopVideo' + '","args":""}' , '*' ) ;
} ) ;
2016-03-13 05:36:00 +09:00
$ . each ( nextImage . parent ( '.host-youtube-com' ) . children ( 'iframe' ) , function ( ) {
2015-06-17 07:44:18 +09:00
this . contentWindow . postMessage ( '{"event":"command","func":"' + 'playVideo' + '","args":""}' , '*' ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2016-03-13 05:36:00 +09:00
// start stop vimeo
$ . each ( $ ( this ) . parent ( '.host-vimeo-com' ) . children ( 'iframe' ) , function ( ) {
this . contentWindow . postMessage ( '{"method": "pause"}' , '*' ) ;
} ) ;
$ . each ( nextImage . parent ( '.host-vimeo-com' ) . children ( 'iframe' ) , function ( ) {
this . contentWindow . postMessage ( '{"method": "play"}' , '*' ) ;
} ) ;
2015-06-10 06:42:41 +09:00
// set dimensions of next image and the popup
2016-03-13 05:36:00 +09:00
var calculatedDimensions = calculatePopUpAndImageDimensions ( nextImage ) ;
2015-07-02 02:15:31 +09:00
nextImage . width ( calculatedDimensions . displayImgWidth ) ;
2015-06-10 06:42:41 +09:00
nextImage . parent ( '.thumb-container' ) . width ( calculatedDimensions . displayImgWidth ) ;
2015-06-17 07:44:18 +09:00
nextImage . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'width' , calculatedDimensions . displayImgWidth ) ;
2015-07-02 02:15:31 +09:00
nextImage . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'height' , calculatedDimensions . displayImgHeight ) ;
$ ( '#queet-thumb-popup .modal-draggable' ) . width ( calculatedDimensions . popUpWidth ) ;
2015-06-10 06:42:41 +09:00
// switch image
$ ( this ) . parent ( ) . removeClass ( 'display-this-thumb' ) ;
$ ( this ) . parent ( ) . next ( ) . addClass ( 'display-this-thumb' ) ;
2015-07-02 02:15:31 +09:00
disableOrEnableNavigationButtonsInImagePopup ( $ ( '#queet-thumb-popup' ) ) ;
centerPopUp ( $ ( '#queet-thumb-popup .modal-draggable' ) ) ;
2015-06-10 06:42:41 +09:00
}
2015-07-02 02:15:31 +09:00
2015-06-10 06:42:41 +09:00
} ) ;
// navigation buttons in image popup
$ ( 'body' ) . on ( 'click' , '#queet-thumb-popup .next-thumb' , function ( event ) {
$ ( this ) . parent ( ) . find ( '.display-this-thumb' ) . children ( 'img' ) . trigger ( 'click' ) ;
} ) ;
$ ( 'body' ) . on ( 'click' , '#queet-thumb-popup .prev-thumb' , function ( event ) {
var prevImage = $ ( this ) . parent ( ) . find ( '.display-this-thumb' ) . prev ( ) . children ( 'img' ) ;
if ( prevImage . length > 0 ) {
2015-07-02 02:15:31 +09:00
2015-06-17 07:44:18 +09:00
// start and stop youtube videos, if any
2016-03-13 05:36:00 +09:00
$ . each ( $ ( this ) . parent ( ) . find ( '.display-this-thumb.host-youtube-com' ) . children ( 'iframe' ) , function ( ) {
2015-06-17 07:44:18 +09:00
this . contentWindow . postMessage ( '{"event":"command","func":"' + 'stopVideo' + '","args":""}' , '*' ) ;
} ) ;
2016-03-13 05:36:00 +09:00
$ . each ( prevImage . parent ( '.host-youtube-com' ) . children ( 'iframe' ) , function ( ) {
2015-06-17 07:44:18 +09:00
this . contentWindow . postMessage ( '{"event":"command","func":"' + 'playVideo' + '","args":""}' , '*' ) ;
} ) ;
2015-07-02 02:15:31 +09:00
2016-03-13 05:36:00 +09:00
// start stop vimeo
$ . each ( $ ( this ) . parent ( ) . find ( '.display-this-thumb.host-vimeo-com' ) . children ( 'iframe' ) , function ( ) {
this . contentWindow . postMessage ( '{"method": "pause"}' , '*' ) ;
} ) ;
$ . each ( prevImage . parent ( '.host-vimeo-com' ) . children ( 'iframe' ) , function ( ) {
this . contentWindow . postMessage ( '{"method": "play"}' , '*' ) ;
} ) ;
2015-06-10 06:42:41 +09:00
// set dimensions of next image and the popup
2016-03-13 05:36:00 +09:00
var calculatedDimensions = calculatePopUpAndImageDimensions ( prevImage ) ;
2015-06-10 06:42:41 +09:00
prevImage . width ( calculatedDimensions . displayImgWidth ) ;
prevImage . parent ( '.thumb-container' ) . width ( calculatedDimensions . displayImgWidth ) ;
2015-06-17 07:44:18 +09:00
prevImage . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'width' , calculatedDimensions . displayImgWidth ) ;
2015-07-02 02:15:31 +09:00
prevImage . parent ( '.thumb-container' ) . children ( 'iframe' ) . attr ( 'height' , calculatedDimensions . displayImgHeight ) ;
2015-06-10 06:42:41 +09:00
$ ( '#queet-thumb-popup .modal-draggable' ) . width ( calculatedDimensions . popUpWidth ) ;
2015-07-02 02:15:31 +09:00
2015-06-10 06:42:41 +09:00
// switch image
$ ( this ) . parent ( ) . find ( '.display-this-thumb' ) . removeClass ( 'display-this-thumb' ) ;
2015-07-02 02:15:31 +09:00
prevImage . parent ( ) . addClass ( 'display-this-thumb' ) ;
2015-06-10 06:42:41 +09:00
disableOrEnableNavigationButtonsInImagePopup ( $ ( '#queet-thumb-popup' ) ) ;
centerPopUp ( $ ( '#queet-thumb-popup .modal-draggable' ) ) ;
2015-07-02 02:15:31 +09:00
}
2015-06-10 06:42:41 +09:00
} ) ;
function disableOrEnableNavigationButtonsInImagePopup ( popUp ) {
if ( popUp . find ( '.display-this-thumb' ) . prev ( ) . length < 1 ) {
popUp . find ( '.prev-thumb' ) . addClass ( 'disabled' ) ;
}
else {
2015-07-02 02:15:31 +09:00
popUp . find ( '.prev-thumb' ) . removeClass ( 'disabled' ) ;
2015-06-10 06:42:41 +09:00
}
if ( popUp . find ( '.display-this-thumb' ) . next ( ) . length < 1 ) {
popUp . find ( '.next-thumb' ) . addClass ( 'disabled' ) ;
}
else {
2015-07-02 02:15:31 +09:00
popUp . find ( '.next-thumb' ) . removeClass ( 'disabled' ) ;
}
2015-06-10 06:42:41 +09:00
}
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-11-18 06:48:28 +09:00
· Collapse all open conversations and the welcome text on esc or when clicking the margin
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . click ( function ( event ) {
2015-11-18 06:48:28 +09:00
if ( $ ( event . target ) . is ( 'body' ) || $ ( event . target ) . is ( '#page-container' ) ) {
2015-05-30 00:30:03 +09:00
$ ( '.front-welcome-text.expanded > .show-full-welcome-text' ) . trigger ( 'click' ) ;
2013-11-23 08:31:04 +09:00
$ . each ( $ ( '.stream-item.expanded' ) , function ( ) {
expand _queet ( $ ( this ) , false ) ;
} ) ;
2015-07-02 02:15:31 +09:00
}
2013-11-23 08:31:04 +09:00
} ) ;
$ ( document ) . keyup ( function ( e ) {
if ( e . keyCode == 27 ) { // esc
2015-07-02 02:15:31 +09:00
$ ( '.front-welcome-text.expanded > .show-full-welcome-text' ) . trigger ( 'click' ) ;
2013-11-23 08:31:04 +09:00
$ . each ( $ ( '.stream-item.expanded' ) , function ( ) {
expand _queet ( $ ( this ) , false ) ;
} ) ;
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking the delete - button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2015-11-19 23:39:19 +09:00
function deleteQueet ( arg ) {
var this _stream _item = $ ( '.stream-item[data-quitter-id="' + arg . streamItemID + '"]' ) ;
2014-11-24 21:47:45 +09:00
2015-07-02 02:15:31 +09:00
// don't do anything if this is a queet being posted
2014-11-24 21:47:45 +09:00
if ( this _stream _item . hasClass ( 'temp-post' ) ) {
return ;
}
2015-07-02 02:15:31 +09:00
var this _qid = this _stream _item . attr ( 'data-quitter-id' ) ;
2016-02-27 11:12:06 +09:00
var $queetHtml = $ ( this _stream _item . outerHTML ( ) ) ;
$queetHtml . children ( '.stream-item.conversation' ) . remove ( ) ;
$queetHtml . find ( '.context,.stream-item-footer,.inline-reply-queetbox,.expanded-content' ) . remove ( ) ;
var queetHtmlWithoutFooterAndConversation = $queetHtml . outerHTML ( ) ;
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
popUpAction ( 'popup-delete-' + this _qid , window . sL . deleteConfirmation , queetHtmlWithoutFooterAndConversation , '<div class="right"><button class="close">' + window . sL . cancelVerb + '</button><button class="primary">' + window . sL . deleteVerb + '</button></div>' ) ;
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
$ ( '#popup-delete-' + this _qid + ' button.primary' ) . on ( 'click' , function ( ) {
display _spinner ( ) ;
2015-07-02 02:15:31 +09:00
$ ( '.modal-container' ) . remove ( ) ;
2013-08-19 22:30:57 +09:00
// delete
postActionToAPI ( 'statuses/destroy/' + this _qid + '.json' , function ( data ) {
if ( data ) {
remove _spinner ( ) ;
2015-11-26 03:51:51 +09:00
window . knownDeletedNotices [ $ ( '.stream-item[data-quitter-id="' + this _qid + '"]' ) . attr ( 'data-uri' ) ] = true ;
slideUpAndRemoveStreamItem ( $ ( '.stream-item[data-quitter-id="' + this _qid + '"]' ) ) ;
2013-08-19 22:30:57 +09:00
}
else {
remove _spinner ( ) ;
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2015-11-19 23:39:19 +09:00
}
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking the requeet - button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2015-01-27 09:57:08 +09:00
$ ( 'body' ) . on ( 'click' , '.action-rt-container .icon:not(.is-mine)' , function ( ) {
var this _stream _item = $ ( this ) . closest ( '.stream-item' ) ;
2015-06-24 22:34:44 +09:00
var this _queet = this _stream _item . children ( '.queet' ) ;
2015-07-02 02:15:31 +09:00
var this _action = $ ( this ) . closest ( 'li' ) ;
2013-08-19 22:30:57 +09:00
// requeet
2015-07-02 02:15:31 +09:00
if ( ! this _action . children ( '.with-icn' ) . hasClass ( 'done' ) ) {
2015-06-24 22:34:44 +09:00
// update the repeat count immediately
var newRqNum = parseInt ( this _queet . find ( '.action-rq-num' ) . html ( ) , 10 ) + 1 ;
this _queet . find ( '.action-rq-num' ) . html ( newRqNum ) ;
2015-07-02 02:15:31 +09:00
this _queet . find ( '.action-rq-num' ) . attr ( 'data-rq-num' , newRqNum ) ;
2015-06-24 22:34:44 +09:00
2013-08-19 22:30:57 +09:00
this _action . children ( '.with-icn' ) . addClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _stream _item . addClass ( 'requeeted' ) ;
2014-11-24 21:47:45 +09:00
// requeet animation
2015-07-02 02:15:31 +09:00
this _action . children ( '.with-icn' ) . children ( '.sm-rt' ) . addClass ( 'rotate' ) ;
// remove the fav and rq cache for this queet, to avoid number flickering
localStorageObjectCache _STORE ( 'favsAndRequeets' , this _stream _item . attr ( 'data-quitter-id' ) , false ) ;
2013-08-19 22:30:57 +09:00
// post requeet
postActionToAPI ( 'statuses/retweet/' + this _stream _item . attr ( 'data-quitter-id' ) + '.json' , function ( data ) {
if ( data ) {
// success
this _stream _item . attr ( 'data-requeeted-by-me-id' , data . id ) ;
2015-07-02 02:15:31 +09:00
getFavsAndRequeetsForQueet ( this _stream _item , this _stream _item . attr ( 'data-quitter-id' ) ) ;
2015-02-26 05:16:24 +09:00
// mark all instances of this notice as repeated
2015-11-23 08:24:33 +09:00
$ ( '.stream-item[data-quitter-id="' + data . retweeted _status . id + '"]' ) . addClass ( 'requeeted' ) ;
$ ( '.stream-item[data-quitter-id="' + data . retweeted _status . id + '"]' ) . attr ( 'data-requeeted-by-me-id' , data . id ) ;
$ ( '.stream-item[data-quitter-id="' + data . retweeted _status . id + '"]' ) . children ( '.queet' ) . find ( '.action-rt-container' ) . children ( '.with-icn' ) . addClass ( 'done' ) ;
2013-08-19 22:30:57 +09:00
}
else {
// error
this _action . children ( '.with-icn' ) . removeClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _action . find ( '.with-icn b' ) . html ( window . sL . requeetVerb ) ;
this _stream _item . removeClass ( 'requeeted' ) ;
2013-08-19 22:30:57 +09:00
}
} ) ;
}
// un-requeet
else if ( this _action . children ( '.with-icn' ) . hasClass ( 'done' ) ) {
2015-07-02 02:15:31 +09:00
display _spinner ( ) ;
2015-11-23 08:24:33 +09:00
var myRequeetID = this _stream _item . attr ( 'data-requeeted-by-me-id' ) ;
// display button as unrepeated
this _action . children ( '.with-icn' ) . removeClass ( 'done' ) ;
this _action . find ( '.with-icn b' ) . html ( window . sL . requeetVerb ) ;
this _stream _item . removeClass ( 'requeeted' ) ;
// post unrequeet
postActionToAPI ( 'statuses/destroy/' + myRequeetID + '.json' , function ( data ) {
if ( data ) {
// remove my repeat-notice from the feed, if it's there
slideUpAndRemoveStreamItem ( $ ( '.stream-item[data-quitter-id-in-stream="' + myRequeetID + '"]' ) ) ;
// mark all instances of this notice as non-repeated
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . removeClass ( 'requeeted' ) ;
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . removeAttr ( 'data-requeeted-by-me-id' ) ;
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . children ( '.queet' ) . find ( '.action-rt-container' ) . children ( '.with-icn' ) . removeClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
2015-11-23 08:24:33 +09:00
getFavsAndRequeetsForQueet ( this _stream _item , this _stream _item . attr ( 'data-quitter-id' ) ) ;
remove _spinner ( ) ;
}
else {
remove _spinner ( ) ;
this _action . children ( '.with-icn' ) . addClass ( 'done' ) ;
this _action . find ( '.with-icn b' ) . html ( window . sL . requeetedVerb ) ;
this _stream _item . addClass ( 'requeeted' ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
}
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking the fav - button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.action-fav-container' , function ( ) {
2015-06-24 22:34:44 +09:00
var this _stream _item = $ ( this ) . closest ( '.stream-item' ) ;
var this _queet = this _stream _item . children ( '.queet' ) ;
2014-11-24 21:47:45 +09:00
2015-07-02 02:15:31 +09:00
// don't do anything if this is a queet being posted
2014-11-24 21:47:45 +09:00
if ( this _stream _item . hasClass ( 'temp-post' ) ) {
return ;
}
2015-07-02 02:15:31 +09:00
var this _action = $ ( this ) ;
2013-08-19 22:30:57 +09:00
// fav
2015-07-02 02:15:31 +09:00
if ( ! this _action . children ( '.with-icn' ) . hasClass ( 'done' ) ) {
2015-06-24 22:34:44 +09:00
// update the fav count immediately
var newFavNum = parseInt ( this _queet . find ( '.action-fav-num' ) . html ( ) , 10 ) + 1 ;
this _queet . find ( '.action-fav-num' ) . html ( newFavNum ) ;
2015-07-02 02:15:31 +09:00
this _queet . find ( '.action-fav-num' ) . attr ( 'data-fav-num' , newFavNum ) ;
2014-11-24 21:47:45 +09:00
2013-08-19 22:30:57 +09:00
this _action . children ( '.with-icn' ) . addClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _stream _item . addClass ( 'favorited' ) ;
2013-08-19 22:30:57 +09:00
2014-11-24 21:47:45 +09:00
// fav animation
this _action . children ( '.with-icn' ) . children ( '.sm-fav' ) . addClass ( 'pulse' ) ;
2015-07-02 02:15:31 +09:00
// remove the fav and rq cache for this queet, to avoid number flickering
localStorageObjectCache _STORE ( 'favsAndRequeets' , this _stream _item . attr ( 'data-quitter-id' ) , false ) ;
// post fav
2013-08-19 22:30:57 +09:00
postActionToAPI ( 'favorites/create/' + this _stream _item . attr ( 'data-quitter-id' ) + '.json' , function ( data ) {
if ( data ) {
// success
2015-07-02 02:15:31 +09:00
getFavsAndRequeetsForQueet ( this _stream _item , this _stream _item . attr ( 'data-quitter-id' ) ) ;
2015-02-26 05:16:24 +09:00
// mark all instances of this notice as favorited
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . addClass ( 'favorited' ) ;
2015-07-02 02:15:31 +09:00
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . children ( '.queet' ) . find ( '.action-fav-container' ) . children ( '.with-icn' ) . addClass ( 'done' ) ;
2013-08-19 22:30:57 +09:00
}
else {
// error
this _action . children ( '.with-icn' ) . removeClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _action . find ( '.with-icn b' ) . html ( window . sL . favoriteVerb ) ;
this _stream _item . removeClass ( 'favorited' ) ;
2013-08-19 22:30:57 +09:00
}
} ) ;
}
// unfav
else {
2015-07-02 02:15:31 +09:00
2015-06-24 22:34:44 +09:00
// update the fav count immediately
var newFavNum = Math . max ( 0 , parseInt ( this _queet . find ( '.action-fav-num' ) . html ( ) , 10 ) - 1 ) ;
this _queet . find ( '.action-fav-num' ) . html ( newFavNum ) ;
2015-07-02 02:15:31 +09:00
this _queet . find ( '.action-fav-num' ) . attr ( 'data-fav-num' , newFavNum ) ;
2013-08-19 22:30:57 +09:00
this _action . children ( '.with-icn' ) . removeClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _action . find ( '.with-icn b' ) . html ( window . sL . favoriteVerb ) ;
this _stream _item . removeClass ( 'favorited' ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
// remove the fav and rq cache for this queet, to avoid number flickering
2015-06-24 22:34:44 +09:00
localStorageObjectCache _STORE ( 'favsAndRequeets' , this _stream _item . attr ( 'data-quitter-id' ) , false ) ;
2013-08-19 22:30:57 +09:00
// post unfav
postActionToAPI ( 'favorites/destroy/' + this _stream _item . attr ( 'data-quitter-id' ) + '.json' , function ( data ) {
if ( data ) {
// success
2015-07-02 02:15:31 +09:00
getFavsAndRequeetsForQueet ( this _stream _item , this _stream _item . attr ( 'data-quitter-id' ) ) ;
2015-02-26 05:16:24 +09:00
// mark all instances of this notice as non-favorited
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . removeClass ( 'favorited' ) ;
2015-07-02 02:15:31 +09:00
$ ( '.stream-item[data-quitter-id="' + this _stream _item . attr ( 'data-quitter-id' ) + '"]' ) . children ( '.queet' ) . find ( '.action-fav-container' ) . children ( '.with-icn' ) . removeClass ( 'done' ) ;
2013-08-19 22:30:57 +09:00
}
else {
// error
this _action . children ( '.with-icn' ) . addClass ( 'done' ) ;
2015-07-02 02:15:31 +09:00
this _action . find ( '.with-icn b' ) . html ( window . sL . favoritedVerb ) ;
this _stream _item . addClass ( 'favorited' ) ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
}
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking the reply - button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.action-reply-container' , function ( ) {
2015-07-02 02:15:31 +09:00
2013-11-23 08:31:04 +09:00
var this _stream _item = $ ( this ) . closest ( '.stream-item' ) ;
2014-11-24 21:47:45 +09:00
2015-07-02 02:15:31 +09:00
// don't do anything if this is a queet being posted
2014-11-24 21:47:45 +09:00
if ( this _stream _item . hasClass ( 'temp-post' ) ) {
return ;
}
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
var this _stream _item _id = this _stream _item . attr ( 'data-quitter-id' ) ;
2014-11-24 21:47:45 +09:00
this _stream _item . addClass ( 'replying-to' ) ;
2013-11-23 08:31:04 +09:00
2016-03-05 07:07:15 +09:00
// grabbing the stream-item and view it in the popup, stripped of conversation footer, reply box and other sruff
var streamItemHTML = $ ( '<div/>' ) . html ( this _stream _item . outerHTML ( ) ) ;
cleanStreamItemsFromClassesAndConversationElements ( streamItemHTML ) ;
streamItemHTML . find ( '.context,.stream-item-footer' ) . remove ( ) ;
var streamItemHTMLWithoutFooter = streamItemHTML . outerHTML ( ) ;
popUpAction ( 'popup-reply-' + this _stream _item _id , window . sL . replyTo + ' ' + this _stream _item . children ( '.queet' ) . find ( '.screen-name' ) . html ( ) , replyFormHtml ( this _stream _item , this _stream _item _id ) , streamItemHTMLWithoutFooter ) ;
2014-10-03 02:24:54 +09:00
2016-01-29 05:12:34 +09:00
$ ( '#popup-reply-' + this _stream _item _id ) . find ( '.modal-body' ) . find ( '.queet-box' ) . trigger ( 'click' ) ; // expand
2014-10-03 02:24:54 +09:00
// fix the width of the queet box, otherwise the syntax highlighting break
2015-11-23 08:24:33 +09:00
var queetBox = $ ( '#popup-reply-' + this _stream _item _id ) . find ( '.modal-body' ) . find ( '.inline-reply-queetbox' ) ;
var queetBoxWidth = queetBox . width ( ) - 20 ;
queetBox . children ( '.queet-box-syntax, .syntax-middle, .syntax-two' ) . width ( queetBoxWidth ) ;
2014-10-03 02:24:54 +09:00
2015-11-23 08:24:33 +09:00
maybePrefillQueetBoxWithCachedText ( queetBox . children ( '.queet-box' ) ) ;
2013-11-23 08:31:04 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-11-24 21:47:45 +09:00
· When clicking the compose button
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-11-23 08:31:04 +09:00
$ ( 'body' ) . on ( 'click' , '#top-compose' , function ( ) {
2015-11-23 08:24:33 +09:00
popUpAction ( 'popup-compose' , window . sL . compose , queetBoxPopUpHtml ( ) , false ) ;
2015-07-12 04:33:02 +09:00
var queetBoxWidth = $ ( '#popup-compose' ) . find ( '.inline-reply-queetbox' ) . width ( ) - 20 ;
$ ( '#popup-compose' ) . find ( '.queet-box-syntax' ) . width ( queetBoxWidth ) ;
$ ( '#popup-compose' ) . find ( '.syntax-middle' ) . width ( queetBoxWidth ) ;
$ ( '#popup-compose' ) . find ( '.syntax-two' ) . width ( queetBoxWidth ) ;
2014-05-28 03:40:51 +09:00
$ ( '#popup-compose' ) . find ( '.queet-box' ) . trigger ( 'click' ) ;
2015-11-23 08:24:33 +09:00
maybePrefillQueetBoxWithCachedText ( $ ( '#popup-compose' ) . find ( '.queet-box' ) ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· Close popups
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
$ ( 'body' ) . on ( 'click' , '.modal-container button.close' , function ( ) {
2014-11-24 21:47:45 +09:00
$ ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
2013-08-19 22:30:57 +09:00
$ ( '.modal-container' ) . remove ( ) ;
} ) ;
$ ( 'body' ) . on ( 'click' , '.modal-close' , function ( ) {
2014-11-24 21:47:45 +09:00
$ ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
2013-08-19 22:30:57 +09:00
$ ( '.modal-container' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-11-24 21:47:45 +09:00
$ ( 'body' ) . on ( 'click' , '.modal-container' , function ( e ) {
if ( $ ( e . target ) . is ( '.modal-container' ) ) {
$ ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
$ ( '.modal-container' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
abortEditProfile ( ) ;
2014-11-24 21:47:45 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
$ ( document ) . keyup ( function ( e ) {
if ( e . keyCode == 27 ) {
2014-11-24 21:47:45 +09:00
$ ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
2013-08-19 22:30:57 +09:00
$ ( '.modal-container' ) . remove ( ) ;
2015-10-13 20:20:48 +09:00
$ ( '*' ) . blur ( ) ;
2014-06-02 04:51:28 +09:00
abortEditProfile ( ) ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-28 03:40:51 +09:00
· Post queets , inline and popup replies
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.queet-toolbar button' , function ( ) {
2013-08-19 22:30:57 +09:00
if ( $ ( this ) . hasClass ( 'enabled' ) ) {
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
// set temp post id
if ( $ ( '.temp-post' ) . length == 0 ) {
var tempPostId = 'stream-item-temp-post-i' ;
}
else {
2015-07-02 02:15:31 +09:00
var tempPostId = $ ( '.temp-post' ) . attr ( 'id' ) + 'i' ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
var queetBox = $ ( this ) . parent ( ) . parent ( ) . siblings ( '.queet-box' ) ;
var queetBoxID = queetBox . attr ( 'id' ) ;
2015-07-02 02:15:31 +09:00
2015-01-27 03:22:05 +09:00
// jquery's .text() function is not consistent in converting <br>:s to \n:s,
// so we do this detour to make sure line breaks are preserved
queetBox . html ( queetBox . html ( ) . replace ( /<br>/g , '{{{lb}}}' ) ) ;
var queetText = $ . trim ( queetBox . text ( ) . replace ( /^\s+|\s+$/g , '' ) . replace ( /\n/g , '' ) ) ;
queetText = queetText . replace ( /{{{lb}}}/g , "\n" ) ;
2015-07-02 02:15:31 +09:00
2015-01-27 03:22:05 +09:00
var queetTempText = replaceHtmlSpecialChars ( queetText . replace ( /\n/g , '<br>' ) ) ; // no xss
queetTempText = queetTempText . replace ( /<br>/g , '<br>' ) ; // but preserve line breaks
2016-01-19 03:30:29 +09:00
var queetHtml = '<div id="' + tempPostId + '" class="stream-item conversation temp-post" style="opacity:1"><div class="queet"><span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group"><img class="avatar" src="' + $ ( '#user-avatar' ) . attr ( 'src' ) + '" /><strong class="name">' + $ ( '#user-name' ) . html ( ) + '</strong> <span class="screen-name">@' + $ ( '#user-screen-name' ) . html ( ) + '</span></a><small class="created-at"> ' + window . sL . posting + '</small></div><div class="queet-text">' + queetTempText + '</div><div class="stream-item-footer"><ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply" title="' + window . sL . replyVerb + '"></span></a></li><li class="action-del-container"><a class="with-icn"><span class="icon sm-trash" title="' + window . sL . deleteVerb + '"></span></a></li></i></li><li class="action-fav-container"><a class="with-icn"><span class="icon sm-fav" title="' + window . sL . favoriteVerb + '"></span></a></li></ul></div></div></div></div>' ;
2015-07-02 02:15:31 +09:00
queetHtml = detectRTL ( queetHtml ) ;
2014-01-29 03:42:47 +09:00
2014-05-28 03:40:51 +09:00
// popup reply
if ( $ ( '.modal-container' ) . find ( '.toolbar-reply button' ) . length > 0 ) {
var in _reply _to _status _id = $ ( '.modal-container' ) . attr ( 'id' ) . substring ( 12 ) ;
}
// if this is a inline reply
else if ( queetBox . parent ( ) . hasClass ( 'inline-reply-queetbox' ) ) {
var in _reply _to _status _id = queetBox . closest ( '.stream-item' ) . attr ( 'data-quitter-id' ) ;
2015-07-02 02:15:31 +09:00
}
2014-05-28 03:40:51 +09:00
// not a reply
else {
var in _reply _to _status _id = false ;
}
2013-11-23 08:31:04 +09:00
2014-11-24 21:47:45 +09:00
// remove any popups
2015-07-02 02:15:31 +09:00
$ ( '.modal-container' ) . remove ( ) ;
2014-11-24 21:47:45 +09:00
2015-07-02 02:15:31 +09:00
// try to find a queet to add the temp queet to:
2015-11-23 08:24:33 +09:00
var tempQueetInsertedInConversation = false ;
2015-07-02 02:15:31 +09:00
// if the queet is in conversation, add it to parent's conversation
2015-03-22 01:16:09 +09:00
if ( $ ( '.stream-item.replying-to' ) . length > 0 && $ ( '.stream-item.replying-to' ) . hasClass ( 'conversation' ) ) {
2015-11-23 08:24:33 +09:00
var insertedTempQueet = $ ( queetHtml ) . appendTo ( $ ( '.stream-item.replying-to' ) . parent ( ) ) ;
2016-01-19 03:30:29 +09:00
findAndMarkLastVisibleInConversation ( $ ( '.stream-item.replying-to' ) . parent ( ) ) ;
insertedTempQueet . parent ( ) . children ( '.view-more-container-bottom' ) . remove ( ) ; // remove any view-more-container-bottom:s, they only cause trouble at this point
2015-11-23 08:24:33 +09:00
tempQueetInsertedInConversation = true ;
2014-11-24 21:47:45 +09:00
}
2015-03-22 01:16:09 +09:00
// if the queet is expanded, add it to its conversation
else if ( $ ( '.stream-item.replying-to' ) . length > 0 && $ ( '.stream-item.replying-to' ) . hasClass ( 'expanded' ) ) {
2015-11-23 08:24:33 +09:00
var insertedTempQueet = $ ( queetHtml ) . appendTo ( $ ( '.stream-item.replying-to' ) ) ;
2016-01-19 03:30:29 +09:00
findAndMarkLastVisibleInConversation ( $ ( '.stream-item.replying-to' ) ) ;
insertedTempQueet . parent ( ) . children ( '.view-more-container-bottom' ) . remove ( ) ; // remove any view-more-container-bottom:s, they only cause trouble at this point
2015-11-23 08:24:33 +09:00
tempQueetInsertedInConversation = true ;
2015-03-22 01:16:09 +09:00
}
// maybe the replying-to class is missing but we still have a suiting place to add it
2014-11-24 21:47:45 +09:00
else if ( $ ( '.stream-item.expanded[data-quitter-id="' + in _reply _to _status _id + '"]' ) . length > 0 ) {
2015-11-23 08:24:33 +09:00
var insertedTempQueet = $ ( queetHtml ) . appendTo ( $ ( '.stream-item.expanded[data-quitter-id="' + in _reply _to _status _id + '"]' ) ) ;
2016-01-19 03:30:29 +09:00
findAndMarkLastVisibleInConversation ( $ ( '.stream-item.expanded[data-quitter-id="' + in _reply _to _status _id + '"]' ) ) ;
insertedTempQueet . parent ( ) . children ( '.view-more-container-bottom' ) . remove ( ) ; // remove any view-more-container-bottom:s, they only cause trouble at this point
2015-11-23 08:24:33 +09:00
tempQueetInsertedInConversation = true ;
2013-08-19 22:30:57 +09:00
}
2015-03-22 01:16:09 +09:00
// if we can't find a proper place, add it to top and remove conversation class
2015-07-02 02:15:31 +09:00
// if this is either 1) our home/all feed, 2) our user timeline or 3) whole site or 4) whole network
2015-09-18 08:42:52 +09:00
else if ( window . currentStreamObject . name == 'friends timeline'
|| window . currentStreamObject . name == 'my profile'
|| window . currentStreamObject . name == 'public timeline'
|| window . currentStreamObject . name == 'public and external timeline' ) {
2015-11-23 08:24:33 +09:00
var insertedTempQueet = $ ( queetHtml ) . prependTo ( '#feed-body' ) ;
insertedTempQueet . removeClass ( 'conversation' ) ;
2014-05-28 03:40:51 +09:00
}
2014-11-24 21:47:45 +09:00
// don't add it to the current stream, open a popup instead, without conversation class
2014-05-28 03:40:51 +09:00
else {
2015-11-23 08:24:33 +09:00
popUpAction ( 'popup-sending' , '' , '' , false ) ;
var insertedTempQueet = $ ( queetHtml ) . prependTo ( $ ( '#popup-sending' ) . find ( '.modal-body' ) ) ;
insertedTempQueet . removeClass ( 'conversation' ) ;
2014-05-28 03:40:51 +09:00
}
2015-07-02 02:15:31 +09:00
2015-08-26 06:27:08 +09:00
// maybe post queet in groups
var postToGroups = '' ;
var postToGropsArray = new Array ( ) ;
$ . each ( queetBox . siblings ( '.post-to-group' ) , function ( ) {
postToGropsArray . push ( $ ( this ) . data ( 'group-id' ) ) ;
} ) ;
if ( postToGropsArray . length > 0 ) {
postToGroups = postToGropsArray . join ( ':' ) ;
}
// remove any post-to-group-divs
queetBox . siblings ( '.post-to-group' ) . remove ( ) ;
2015-03-22 01:16:09 +09:00
// remove any replying-to classes
2015-07-02 02:15:31 +09:00
$ ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
2013-08-19 22:30:57 +09:00
// null reply box
2015-07-02 02:15:31 +09:00
collapseQueetBox ( queetBox ) ;
// check for new queets (one second from) NOW
2013-08-19 22:30:57 +09:00
setTimeout ( 'checkForNewQueets()' , 1000 ) ;
// post queet
2015-08-26 06:27:08 +09:00
postQueetToAPI ( queetText , in _reply _to _status _id , postToGroups , function ( data ) { if ( data ) {
2013-08-19 22:30:57 +09:00
2015-11-23 10:23:44 +09:00
var queetHtml = buildQueetHtml ( data , data . id , 'visible posted-from-form' , false , tempQueetInsertedInConversation ) ;
// while we were waiting for our posted queet to arrive here, it may have already
// arrived in the automatic update of the feed, so if it's already there, we
// replace it (but not if the temp queet is inserted in a conversation of course, or if
// the user has had time to expand it)
var alredyArrived = $ ( '#feed-body > .stream-item[data-quitter-id-in-stream=' + data . id + ']' ) ;
if ( alredyArrived . length > 0 && tempQueetInsertedInConversation === false ) {
if ( ! alredyArrived . hasClass ( 'expanded' ) ) {
alredyArrived . replaceWith ( queetHtml ) ;
}
}
else {
2016-01-19 03:30:29 +09:00
var newInsertedQueet = $ ( queetHtml ) . insertBefore ( insertedTempQueet ) ;
findAndMarkLastVisibleInConversation ( insertedTempQueet . parent ( ) ) ;
// make ranting easier, move the reply-form to this newly created notice
// if we have not started writing in it, or if it's missing
// only if this is an expanded conversation
// and only if we're ranting, i.e. no replies the queetbox
var parentQueetBox = insertedTempQueet . parent ( ) . find ( '.inline-reply-queetbox' ) ;
if ( parentQueetBox . length == 0
|| parentQueetBox . children ( '.syntax-middle' ) . css ( 'display' ) == 'none' ) {
if ( insertedTempQueet . parent ( ) . hasClass ( 'expanded' ) || insertedTempQueet . parent ( ) . hasClass ( 'conversation' ) ) {
if ( parentQueetBox . children ( '.queet-box' ) . attr ( 'data-replies-text' ) == '' ) {
insertedTempQueet . parent ( ) . find ( '.inline-reply-queetbox' ) . remove ( ) ;
newInsertedQueet . children ( '.queet' ) . append ( replyFormHtml ( newInsertedQueet , newInsertedQueet . attr ( 'data-quitter-id' ) ) ) ;
}
}
}
2015-11-23 10:23:44 +09:00
}
// remove temp queet
2015-11-23 08:24:33 +09:00
insertedTempQueet . remove ( ) ;
2015-07-02 02:15:31 +09:00
2015-07-07 00:32:52 +09:00
// clear queetbox input cache
localStorageObjectCache _STORE ( 'queetBoxInput' , queetBox . attr ( 'id' ) , false ) ;
2013-11-23 08:31:04 +09:00
// queet count
2015-07-02 02:15:31 +09:00
$ ( '#user-queets strong' ) . html ( parseInt ( $ ( '#user-queets strong' ) . html ( ) , 10 ) + 1 ) ;
2015-11-23 08:24:33 +09:00
// fadeout any posting-popups
setTimeout ( function ( ) {
$ ( '#popup-sending' ) . fadeOut ( 1000 , function ( ) {
$ ( '#popup-sending' ) . remove ( ) ;
} ) ;
} , 100 ) ;
2013-08-19 22:30:57 +09:00
} } ) ;
}
} ) ;
2013-11-23 08:31:04 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-11-24 21:47:45 +09:00
· Count chars in queet box on keyup , also check for any attachments to show / hide
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-05-28 03:40:51 +09:00
$ ( 'body' ) . on ( 'keyup input paste' , '.queet-box-syntax' , function ( ) {
2014-11-24 21:47:45 +09:00
2014-05-28 03:40:51 +09:00
countCharsInQueetBox ( $ ( this ) , $ ( this ) . siblings ( '.queet-toolbar' ) . find ( '.queet-counter' ) , $ ( this ) . siblings ( '.queet-toolbar' ) . find ( '.queet-button button' ) ) ;
2014-11-24 21:47:45 +09:00
var attachments = $ ( this ) . siblings ( '.upload-image-container' ) ;
$ . each ( attachments , function ( k , attachment ) {
var attachmentShorturl = $ ( attachment ) . children ( 'img' ) . attr ( 'data-shorturl' ) ;
if ( $ ( attachment ) . siblings ( '.queet-box-syntax' ) . text ( ) . indexOf ( attachmentShorturl ) > - 1 ) {
$ ( attachment ) . show ( ) ;
}
else {
$ ( attachment ) . hide ( ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
} ) ;
/ * ·
·
2015-01-27 04:09:42 +09:00
· Middle button expands queet box
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'mousedown' , '.queet-box-syntax' , function ( e ) {
2015-01-27 04:09:42 +09:00
if ( e . which == 2 ) {
e . preventDefault ( ) ;
$ ( this ) . trigger ( 'click' ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-09-20 09:53:10 +09:00
· Shorten URL ' s
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-09-20 09:53:10 +09:00
$ ( 'body' ) . on ( 'click' , 'button.shorten' , function ( ) {
shortenUrlsInBox ( $ ( this ) ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-09-20 09:53:10 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-09-20 09:53:10 +09:00
· Reload current stream
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-09-20 09:53:10 +09:00
$ ( 'body' ) . on ( 'click' , '.reload-stream' , function ( ) {
2016-01-23 05:19:08 +09:00
reloadCurrentStream ( ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2016-01-23 05:19:08 +09:00
// can be used a callback too, e.g. from profile pref toggles
function reloadCurrentStream ( ) {
2016-02-27 10:01:27 +09:00
setNewCurrentStream ( URLtoStreamRouter ( window . location . href ) , false , false , false ) ;
}
2016-02-27 07:18:02 +09:00
2016-02-27 10:01:27 +09:00
/ * ·
·
· Reload current stream and clear cache
·
· · · · · · · · · · · · · * /
function reloadCurrentStreamAndClearCache ( ) {
2016-02-27 11:12:06 +09:00
2016-02-27 07:18:02 +09:00
$ ( '#feed-body' ) . empty ( ) ;
rememberStreamStateInLocalStorage ( ) ;
// reload
2016-02-27 10:01:27 +09:00
reloadCurrentStream ( ) ;
2016-01-23 05:19:08 +09:00
}
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-28 03:40:51 +09:00
· Expand / collapse queet box on click and blur
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-11-24 21:47:45 +09:00
$ ( 'body' ) . on ( 'click contextmenu' , '.queet-box-syntax' , function ( ) {
2014-05-28 03:40:51 +09:00
if ( $ ( this ) . html ( ) == decodeURIComponent ( $ ( this ) . attr ( 'data-start-text' ) ) ) {
2015-07-02 02:15:31 +09:00
$ ( this ) . attr ( 'contenteditable' , 'true' ) ;
$ ( this ) . focus ( ) ;
$ ( this ) . siblings ( '.syntax-middle' ) . html ( ' ' ) ;
$ ( this ) . siblings ( '.syntax-two' ) . html ( ' ' ) ;
$ ( this ) . siblings ( '.queet-toolbar' ) . css ( 'display' , 'block' ) ;
$ ( this ) . siblings ( '.syntax-middle' ) . css ( 'display' , 'block' ) ;
$ ( this ) . siblings ( '.mentions-suggestions' ) . css ( 'display' , 'block' ) ;
$ ( this ) . siblings ( '.syntax-two' ) . css ( 'display' , 'block' ) ;
$ ( this ) . siblings ( '.queet-toolbar' ) . find ( '.queet-button button' ) . addClass ( 'disabled' ) ;
countCharsInQueetBox ( $ ( this ) , $ ( this ) . siblings ( '.queet-toolbar .queet-counter' ) , $ ( this ) . siblings ( '.queet-toolbar button' ) ) ;
2014-05-28 03:40:51 +09:00
$ ( this ) [ 0 ] . addEventListener ( "paste" , stripHtmlFromPaste ) ;
if ( typeof $ ( this ) . attr ( 'data-replies-text' ) != 'undefined' ) {
$ ( this ) . html ( decodeURIComponent ( $ ( this ) . attr ( 'data-replies-text' ) ) ) ;
2016-01-19 03:30:29 +09:00
var repliesLen = decodeURIComponent ( $ ( this ) . attr ( 'data-replies-text' ) ) . replace ( ' ' , ' ' ) . length ;
2015-07-02 02:15:31 +09:00
setSelectionRange ( $ ( this ) [ 0 ] , repliesLen , repliesLen ) ;
2013-08-19 22:30:57 +09:00
}
else {
2015-07-02 02:15:31 +09:00
$ ( this ) . html ( '' ) ;
2013-08-19 22:30:57 +09:00
}
2015-07-02 02:15:31 +09:00
$ ( this ) . trigger ( 'input' ) ;
2016-01-19 03:30:29 +09:00
$ ( this ) . closest ( '.stream-item' ) . addClass ( 'replying-to' ) ;
2014-05-28 03:40:51 +09:00
}
} ) ;
2014-11-24 21:47:45 +09:00
$ ( 'body' ) . on ( 'mousedown' , '.syntax-two' , function ( ) {
$ ( this ) . addClass ( 'clicked' ) ;
2015-07-02 02:15:31 +09:00
} ) ;
$ ( 'body' ) . on ( 'blur' , '.queet-box-syntax' , function ( e ) {
2015-08-26 06:27:08 +09:00
// empty the mention suggestions on blur, timeout because we want to capture clicks in .mentions-suggestions
setTimeout ( function ( ) {
$ ( this ) . siblings ( '.mentions-suggestions' ) . empty ( ) ;
} , 10 ) ;
2015-03-03 08:33:18 +09:00
// don't collapse if a toolbar button has been clicked
var clickedToolbarButtons = $ ( this ) . siblings ( '.queet-toolbar' ) . find ( 'button.clicked' ) ;
if ( clickedToolbarButtons . length > 0 ) {
clickedToolbarButtons . removeClass ( 'clicked' ) ;
2015-07-02 02:15:31 +09:00
return true ;
2014-11-24 21:47:45 +09:00
}
2015-11-17 04:27:40 +09:00
// don't collapse if an error message discard button has been clicked
if ( $ ( this ) . siblings ( '.error-message' ) . children ( '.discard-error-message' ) . length > 0 ) {
return true ;
}
2014-11-24 21:47:45 +09:00
// don't collapse if we're clicking around inside queet-box
var syntaxTwoBox = $ ( this ) . siblings ( '.syntax-two' ) ;
2015-07-02 02:15:31 +09:00
if ( syntaxTwoBox . hasClass ( 'clicked' ) ) {
2014-11-24 21:47:45 +09:00
syntaxTwoBox . removeClass ( 'clicked' ) ;
return true ;
2015-07-02 02:15:31 +09:00
}
2014-11-24 21:47:45 +09:00
// don't collapse if we're in a modal
2015-07-02 02:15:31 +09:00
if ( $ ( this ) . parent ( ) . parent ( ) . hasClass ( 'modal-body' ) ) {
2014-11-24 21:47:45 +09:00
return true ;
2014-05-28 03:40:51 +09:00
}
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// collapse if nothing is change
if ( $ ( this ) . attr ( 'data-replies-text' ) != 'undefined' ) {
2014-05-28 03:40:51 +09:00
var $startText = $ ( '<div/>' ) . append ( decodeURIComponent ( $ ( this ) . attr ( 'data-replies-text' ) ) ) ;
if ( $ . trim ( $startText . text ( ) ) == $ . trim ( $ ( this ) . text ( ) ) || $ ( this ) . html ( ) . length == 0 || $ ( this ) . html ( ) == '<br>' || $ ( this ) . html ( ) == '<br />' || $ ( this ) . html ( ) == ' ' || $ ( this ) . html ( ) == ' <br>' ) {
2015-07-02 02:15:31 +09:00
collapseQueetBox ( $ ( this ) ) ;
2014-05-28 03:40:51 +09:00
}
}
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// collapse if empty
2014-05-28 03:40:51 +09:00
else if ( $ ( this ) . html ( ) . length == 0 || $ ( this ) . html ( ) == '<br>' || $ ( this ) . html ( ) == '<br />' || $ ( this ) . html ( ) == ' ' || $ ( this ) . html ( ) == ' <br>' ) {
collapseQueetBox ( $ ( this ) ) ;
}
} ) ;
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
function collapseQueetBox ( qB ) {
2016-01-19 03:30:29 +09:00
qB . closest ( '.stream-item' ) . removeClass ( 'replying-to' ) ;
2014-11-24 21:47:45 +09:00
qB . siblings ( '.upload-image-container' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
qB . siblings ( '.syntax-middle' ) . css ( 'display' , 'none' ) ;
qB . siblings ( '.syntax-two' ) . css ( 'display' , 'none' ) ;
qB . siblings ( '.mentions-suggestions' ) . css ( 'display' , 'none' ) ;
qB . attr ( 'contenteditable' , 'false' ) ;
2014-05-28 03:40:51 +09:00
qB . html ( decodeURIComponent ( qB . attr ( 'data-start-text' ) ) ) ;
qB . siblings ( '.queet-toolbar' ) . find ( 'button' ) . removeClass ( 'enabled' ) ;
2015-07-02 02:15:31 +09:00
qB . siblings ( '.queet-toolbar' ) . css ( 'display' , 'none' ) ;
qB . removeAttr ( 'style' ) ;
qB [ 0 ] . removeEventListener ( "paste" , stripHtmlFromPaste ) ;
2014-05-28 03:40:51 +09:00
}
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-28 03:40:51 +09:00
· Syntax highlighting in queetbox
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-05-28 03:40:51 +09:00
// transfer focus and position/selection to background div
$ ( 'body' ) . on ( 'mouseup' , 'div.syntax-two' , function ( e ) {
2015-01-28 08:43:24 +09:00
// don't transfer rightclicks, instead wait for oninput and transfer after
// this makes spell checker work
if ( e . which == 3 ) {
$ ( this ) [ 0 ] . oninput = function ( ) {
$ ( this ) . siblings ( 'div.queet-box-syntax' ) . html ( $ ( this ) . html ( ) ) ;
$ ( this ) . trigger ( 'mouseup' ) ; // transfer focus
2015-07-02 02:15:31 +09:00
}
2014-05-28 03:40:51 +09:00
}
2013-08-19 22:30:57 +09:00
2015-01-28 08:43:24 +09:00
else {
$ ( this ) . removeClass ( 'clicked' ) ;
2015-07-02 02:15:31 +09:00
var caretPos = getSelectionInElement ( $ ( this ) [ 0 ] ) ;
2015-01-28 08:43:24 +09:00
var thisQueetBox = $ ( this ) . siblings ( 'div.queet-box-syntax' ) ;
thisQueetBox . focus ( ) ;
2015-07-02 02:15:31 +09:00
setSelectionRange ( thisQueetBox [ 0 ] , caretPos [ 0 ] , caretPos [ 1 ] ) ;
2015-01-28 08:43:24 +09:00
// fixes problem with caret not showing after delete, unfocus and refocus
if ( thisQueetBox . html ( ) == '<br>' ) {
thisQueetBox . html ( ' ' ) ;
}
}
} ) ;
2013-08-19 22:30:57 +09:00
2014-05-28 03:40:51 +09:00
// strip html from paste
2015-06-02 01:27:36 +09:00
function stripHtmlFromPaste ( e ) {
2014-05-28 03:40:51 +09:00
e . preventDefault ( ) ;
2015-01-22 04:45:58 +09:00
var text = replaceHtmlSpecialChars ( e . clipboardData . getData ( "text/plain" ) ) ;
2015-01-27 03:22:05 +09:00
text = text . replace ( /\n/g , '<br>' ) . replace ( /\t/g , ' ' ) ; // keep line-breaks and tabs
2015-07-02 02:15:31 +09:00
document . execCommand ( "insertHTML" , false , text ) ;
2014-05-28 03:40:51 +09:00
}
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
// sync divs
$ ( 'body' ) . on ( 'keyup paste input' , 'div.queet-box-syntax' , function ( ) {
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
var currentVal = $ ( this ) . html ( ) ;
currentVal = currentVal . replace ( /<br>$/ , '' ) . replace ( / $/ , '' ) . replace ( / $/ , '' ) ; // fix
$ ( this ) . siblings ( '.syntax-two' ) . html ( currentVal ) ;
2015-03-30 22:07:45 +09:00
// loop through the regexps and highlight
2015-06-21 08:29:14 +09:00
$ . each ( window . syntaxHighlightingRegexps , function ( k , v ) {
2015-09-20 03:39:01 +09:00
var i = 0 ;
while ( currentVal . match ( v ) && i < 100 ) { // 100 matches is enough, we don't want to get caught in an infinite loop here
2015-03-30 22:07:45 +09:00
var currentMatch = currentVal . match ( v ) ;
2015-09-20 05:17:22 +09:00
// too small match, probably a single ! or something, just replace that with its html code
if ( $ . trim ( currentMatch [ 0 ] ) . length < 2 ) {
currentVal = currentVal . replace ( currentMatch [ 0 ] , currentMatch [ 0 ] . replace ( '#' , '#' ) . replace ( '@' , '@' ) . replace ( '.' , '.' ) . replace ( '!' , '!' ) ) ;
}
// long enough match, create a mention span
else {
2016-02-17 07:41:29 +09:00
// don't include ending char, if any of these (but tags can contain and end with . and -)
2015-09-20 05:17:22 +09:00
if ( currentMatch [ 0 ] . slice ( - 1 ) == '<'
|| currentMatch [ 0 ] . slice ( - 1 ) == '&'
|| currentMatch [ 0 ] . slice ( - 1 ) == '?'
|| currentMatch [ 0 ] . slice ( - 1 ) == '!'
|| currentMatch [ 0 ] . slice ( - 1 ) == ' '
2016-02-17 07:41:29 +09:00
|| ( currentMatch [ 0 ] . slice ( - 1 ) == '-' && k != 'tag' )
2015-09-20 05:17:22 +09:00
|| currentMatch [ 0 ] . slice ( - 1 ) == ':'
2016-02-17 07:41:29 +09:00
|| ( currentMatch [ 0 ] . slice ( - 1 ) == '.' && k != 'tag' )
2016-01-30 00:47:59 +09:00
|| currentMatch [ 0 ] . slice ( - 1 ) == ','
2016-02-16 22:37:16 +09:00
|| currentMatch [ 0 ] . slice ( - 1 ) == ')'
|| currentMatch [ 0 ] . slice ( - 1 ) == '\'' ) {
2015-09-20 05:17:22 +09:00
currentMatch [ 0 ] = currentMatch [ 0 ] . slice ( 0 , - 1 ) ;
}
2015-11-06 11:56:56 +09:00
2016-01-30 00:47:59 +09:00
// don't include these start strings
if ( currentMatch [ 0 ] . substring ( 0 , 1 ) == ' '
|| currentMatch [ 0 ] . substring ( 0 , 1 ) == '(' ) {
2015-11-06 11:56:56 +09:00
currentMatch [ 0 ] = currentMatch [ 0 ] . substring ( 1 ) ;
}
else if ( currentMatch [ 0 ] . substring ( 0 , 6 ) == ' ' ) {
currentMatch [ 0 ] = currentMatch [ 0 ] . substring ( 6 ) ;
}
2015-09-20 05:17:22 +09:00
currentVal = currentVal . replace ( currentMatch [ 0 ] , '<span class="' + k + '">' + currentMatch [ 0 ] . replace ( '#' , '#' ) . replace ( '@' , '@' ) . replace ( '.' , '.' ) . replace ( '!' , '!' ) + '</span>' )
2014-05-28 03:40:51 +09:00
}
2015-09-20 03:39:01 +09:00
i ++ ;
2015-03-30 22:07:45 +09:00
}
2014-05-28 03:40:51 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2016-01-24 01:12:24 +09:00
// safari fix
if ( typeof bowser . safari != 'undefined' ) {
currentVal = currentVal . replace ( / <span/g , ' <span' ) ;
}
2015-11-06 11:56:56 +09:00
2015-03-30 22:07:45 +09:00
$ ( this ) . siblings ( '.syntax-middle' ) . html ( currentVal ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-05-28 03:40:51 +09:00
· Auto suggest mentions in queet - box
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-05-28 03:40:51 +09:00
// navigate in mentions with mouse
$ ( 'body' ) . on ( 'mouseenter' , '.mentions-suggestions > div' , function ( ) {
$ ( '.mentions-suggestions > div' ) . removeClass ( 'selected' ) ;
$ ( this ) . addClass ( 'selected' ) ;
} ) . on ( 'mouseleave' , '.mentions-suggestions > div' , function ( ) {
2015-07-02 02:15:31 +09:00
$ ( this ) . removeClass ( 'selected' ) ;
2014-05-28 03:40:51 +09:00
} ) ;
$ ( 'body' ) . on ( 'click' , '.mentions-suggestions > div' , function ( ) {
$ ( this ) . parent ( ) . siblings ( '.queet-box-syntax' ) . focus ( ) ;
$ ( this ) . siblings ( ) . removeClass ( 'selected' ) ;
$ ( this ) . addClass ( 'selected' ) ;
2015-07-02 02:15:31 +09:00
useSelectedMention ( $ ( this ) . parent ( ) . siblings ( '.queet-box-syntax' ) ) ;
2014-05-28 03:40:51 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
// navigate in mentions with keyboard
2015-07-02 02:15:31 +09:00
$ ( 'body' ) . on ( 'keydown' , '.queet-box-syntax' , function ( e ) {
2014-05-28 03:40:51 +09:00
if ( $ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div' ) . length > 0 ) {
// enter or tab
2016-01-14 05:55:20 +09:00
if ( ! e . ctrlKey && ( e . keyCode == '13' || e . keyCode == '9' ) ) {
2015-07-02 02:15:31 +09:00
e . preventDefault ( ) ;
useSelectedMention ( $ ( this ) ) ;
2013-11-23 08:31:04 +09:00
}
2015-07-02 02:15:31 +09:00
// downkey
2014-05-28 03:40:51 +09:00
else if ( e . keyCode == '40' ) {
2015-07-02 02:15:31 +09:00
e . preventDefault ( ) ;
2014-05-28 03:40:51 +09:00
if ( $ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) . length > 0 ) {
var selected = $ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) ;
selected . removeClass ( 'selected' ) ;
selected . next ( ) . addClass ( 'selected' ) ;
}
else {
2015-07-02 02:15:31 +09:00
$ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div' ) . first ( ) . addClass ( 'selected' ) ;
2014-05-28 03:40:51 +09:00
}
2013-11-23 08:31:04 +09:00
}
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
// upkey
else if ( e . keyCode == '38' ) {
2015-07-02 02:15:31 +09:00
e . preventDefault ( ) ;
2014-05-28 03:40:51 +09:00
if ( $ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) . length > 0 ) {
var selected = $ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) ;
selected . removeClass ( 'selected' ) ;
selected . prev ( ) . addClass ( 'selected' ) ;
}
else {
2015-07-02 02:15:31 +09:00
$ ( this ) . siblings ( '.mentions-suggestions' ) . children ( 'div' ) . last ( ) . addClass ( 'selected' ) ;
2014-05-28 03:40:51 +09:00
}
}
2013-11-23 08:31:04 +09:00
}
2014-05-28 03:40:51 +09:00
} ) ;
2013-11-29 20:49:54 +09:00
2014-05-28 03:40:51 +09:00
function useSelectedMention ( queetBox ) {
2015-08-26 06:27:08 +09:00
2014-05-28 03:40:51 +09:00
// use selected
2015-07-02 02:15:31 +09:00
if ( queetBox . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) . length > 0 ) {
2015-08-26 06:27:08 +09:00
var selectedSuggestion = queetBox . siblings ( '.mentions-suggestions' ) . children ( 'div.selected' ) ;
2014-05-28 03:40:51 +09:00
}
// if none selected, take top suggestion
else {
2015-08-26 06:27:08 +09:00
var selectedSuggestion = queetBox . siblings ( '.mentions-suggestions' ) . children ( 'div' ) . first ( ) ;
}
var username = selectedSuggestion . children ( 'span' ) . html ( ) ;
var name = selectedSuggestion . children ( 'strong' ) . html ( ) ;
// if this is a group, we remember its id, the user might be member of multiple groups with the same username
if ( selectedSuggestion . hasClass ( 'group-suggestion' ) ) {
var groupId = selectedSuggestion . data ( 'group-id' ) ;
if ( queetBox . siblings ( '.post-to-group[data-group-id="' + groupId + '"]' ) . length < 1 ) {
if ( queetBox . siblings ( '.post-to-group' ) . length > 0 ) {
var addAfter = queetBox . siblings ( '.post-to-group' ) . last ( ) ;
}
else {
var addAfter = queetBox ;
}
addAfter . after ( '<div class="post-to-group" data-group-username="' + username + '" data-group-id="' + groupId + '">' + name + '</div>' ) ;
}
2014-05-28 03:40:51 +09:00
}
2013-11-23 08:31:04 +09:00
2014-05-28 03:40:51 +09:00
// replace the halfwritten username with the one we want
deleteBetweenCharacterIndices ( queetBox [ 0 ] , window . lastMention . mentionPos + 1 , window . lastMention . cursorPos ) ;
var range = createRangeFromCharacterIndices ( queetBox [ 0 ] , window . lastMention . mentionPos + 1 , window . lastMention . mentionPos + 1 ) ;
2015-09-20 05:36:15 +09:00
range . insertNode ( document . createTextNode ( username + '\u00a0' ) ) ; // non-breaking-space, to prevent collapse
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
// put caret after
2015-07-02 02:15:31 +09:00
setSelectionRange ( queetBox [ 0 ] , window . lastMention . mentionPos + username . length + 2 , window . lastMention . mentionPos + username . length + 2 ) ;
2014-05-28 03:40:51 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . empty ( ) ;
2015-07-02 02:15:31 +09:00
queetBox . trigger ( 'input' ) ; // avoid some flickering
2014-05-28 03:40:51 +09:00
}
2013-08-19 22:30:57 +09:00
2015-08-26 06:27:08 +09:00
// check for removed group mentions
$ ( 'body' ) . on ( 'keyup' , 'div.queet-box-syntax' , function ( e ) {
var groupMentions = $ ( this ) . siblings ( '.post-to-group' ) ;
2015-08-26 08:00:37 +09:00
var queetBoxGroups = $ ( this ) . siblings ( '.syntax-middle' ) . find ( '.group' ) ;
var queetBoxGroupsString = '' ;
$ . each ( queetBoxGroups , function ( ) {
queetBoxGroupsString = queetBoxGroupsString + $ ( this ) . html ( ) + ':' ;
} ) ;
2015-08-26 06:27:08 +09:00
$ . each ( groupMentions , function ( ) {
2015-08-26 08:00:37 +09:00
if ( queetBoxGroupsString . indexOf ( '!' + $ ( this ) . data ( 'group-username' ) + ':' ) == - 1 ) {
2015-08-26 06:27:08 +09:00
$ ( this ) . remove ( ) ;
}
} ) ;
} ) ;
// check for user mentions
2014-05-28 03:40:51 +09:00
window . lastMention = new Object ( ) ;
2015-07-02 02:15:31 +09:00
$ ( 'body' ) . on ( 'keyup' , 'div.queet-box-syntax' , function ( e ) {
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
var queetBox = $ ( this ) ;
2014-05-28 03:40:51 +09:00
var cursorPosArray = getSelectionInElement ( queetBox [ 0 ] ) ;
2015-07-02 02:15:31 +09:00
var cursorPos = cursorPosArray [ 0 ] ;
2014-05-28 03:40:51 +09:00
// add space before linebreaks (to separate mentions in beginning of new lines when .text():ing later)
if ( e . keyCode == '13' ) {
2015-07-02 02:15:31 +09:00
e . preventDefault ( ) ;
2014-05-28 03:40:51 +09:00
var range = createRangeFromCharacterIndices ( queetBox [ 0 ] , cursorPos , cursorPos ) ;
2015-07-02 02:15:31 +09:00
range . insertNode ( document . createTextNode ( " \n" ) ) ;
2014-05-28 03:40:51 +09:00
}
2015-07-02 02:15:31 +09:00
else if ( e . keyCode != '40' && e . keyCode != '38' && e . keyCode != '13' && e . keyCode != '9' ) {
2014-05-28 03:40:51 +09:00
var contents = queetBox . text ( ) . substring ( 0 , cursorPos ) ;
var mentionPos = contents . lastIndexOf ( '@' ) ;
var check _contents = contents . substring ( mentionPos - 1 , cursorPos ) ;
var regex = /(^|\s|\.|\n)(@)[a-zA-Z0-9]+/ ;
var match = check _contents . match ( regex ) ;
if ( contents . indexOf ( '@' ) >= 0 && match ) {
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
if ( contents . lastIndexOf ( '@' ) > 1 ) {
match [ 0 ] = match [ 0 ] . substring ( 1 , match [ 0 ] . length ) ;
}
if ( ( contents . lastIndexOf ( '@' ) + match [ 0 ] . length ) == cursorPos ) {
2015-08-26 06:27:08 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.user-suggestion' ) . remove ( ) ;
2014-05-28 03:40:51 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . css ( 'top' , ( queetBox . height ( ) + 20 ) + 'px' ) ;
var term = match [ 0 ] . substring ( match [ 0 ] . lastIndexOf ( '@' ) + 1 , match [ 0 ] . length ) . toLowerCase ( ) ;
window . lastMention . mentionPos = mentionPos ;
2015-07-02 02:15:31 +09:00
window . lastMention . cursorPos = cursorPos ;
2015-06-03 00:10:58 +09:00
2015-07-02 02:15:31 +09:00
// see if anyone we're following matches
2015-06-03 00:10:58 +09:00
var suggestionsToShow = [ ] ;
2015-06-17 07:44:18 +09:00
var suggestionsUsernameCount = { } ;
suggestionsUsernameCount [ window . loggedIn . screen _name ] = 1 ; // any suggestions with the same screen name as mine will get their server url added
2014-05-28 03:40:51 +09:00
$ . each ( window . following , function ( ) {
var userregex = new RegExp ( term ) ;
if ( this . username . toLowerCase ( ) . match ( userregex ) || this . name . toLowerCase ( ) . match ( userregex ) ) {
2015-06-03 00:10:58 +09:00
suggestionsToShow . push ( { avatar : this . avatar , name : this . name , username : this . username , url : this . url } ) ;
// count the usernames to see if we need to show the server for any of them
if ( typeof suggestionsUsernameCount [ this . username ] != 'undefined' ) {
suggestionsUsernameCount [ this . username ] = suggestionsUsernameCount [ this . username ] + 1 ;
}
else {
suggestionsUsernameCount [ this . username ] = 1 ;
}
2014-05-28 03:40:51 +09:00
}
2015-07-02 02:15:31 +09:00
} ) ;
2015-06-03 00:10:58 +09:00
// show matches
$ . each ( suggestionsToShow , function ( ) {
var serverHtml = '' ;
2015-06-18 07:09:04 +09:00
if ( suggestionsUsernameCount [ this . username ] > 1 && this . url !== false ) {
2015-06-03 00:10:58 +09:00
serverHtml = '@' + this . url ;
}
2015-08-26 06:27:08 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . append ( '<div class="user-suggestion" title="@' + this . username + serverHtml + '"><img height="24" width="24" src="' + this . avatar + '" /><strong>' + this . name + '</strong> @<span>' + this . username + serverHtml + '</span></div>' )
} ) ;
}
else {
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.user-suggestion' ) . remove ( ) ;
}
}
else {
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.user-suggestion' ) . remove ( ) ;
}
}
} ) ;
// check for group mentions
$ ( 'body' ) . on ( 'keyup' , 'div.queet-box-syntax' , function ( e ) {
var queetBox = $ ( this ) ;
var cursorPosArray = getSelectionInElement ( queetBox [ 0 ] ) ;
var cursorPos = cursorPosArray [ 0 ] ;
// add space before linebreaks (to separate mentions in beginning of new lines when .text():ing later)
if ( e . keyCode == '13' ) {
e . preventDefault ( ) ;
var range = createRangeFromCharacterIndices ( queetBox [ 0 ] , cursorPos , cursorPos ) ;
range . insertNode ( document . createTextNode ( " \n" ) ) ;
}
else if ( e . keyCode != '40' && e . keyCode != '38' && e . keyCode != '13' && e . keyCode != '9' ) {
var contents = queetBox . text ( ) . substring ( 0 , cursorPos ) ;
var mentionPos = contents . lastIndexOf ( '!' ) ;
var check _contents = contents . substring ( mentionPos - 1 , cursorPos ) ;
var regex = /(^|\s|\.|\n)(!)[a-zA-Z0-9]+/ ;
var match = check _contents . match ( regex ) ;
if ( contents . indexOf ( '!' ) >= 0 && match ) {
if ( contents . lastIndexOf ( '!' ) > 1 ) {
match [ 0 ] = match [ 0 ] . substring ( 1 , match [ 0 ] . length ) ;
}
if ( ( contents . lastIndexOf ( '!' ) + match [ 0 ] . length ) == cursorPos ) {
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.group-suggestion' ) . remove ( ) ;
queetBox . siblings ( '.mentions-suggestions' ) . css ( 'top' , ( queetBox . height ( ) + 20 ) + 'px' ) ;
var term = match [ 0 ] . substring ( match [ 0 ] . lastIndexOf ( '!' ) + 1 , match [ 0 ] . length ) . toLowerCase ( ) ;
window . lastMention . mentionPos = mentionPos ;
window . lastMention . cursorPos = cursorPos ;
// see if any group we're member of matches
var suggestionsToShow = [ ] ;
var suggestionsUsernameCount = { } ;
$ . each ( window . groupMemberships , function ( ) {
var userregex = new RegExp ( term ) ;
if ( this . username . toLowerCase ( ) . match ( userregex ) || this . name . toLowerCase ( ) . match ( userregex ) ) {
suggestionsToShow . push ( { id : this . id , avatar : this . avatar , name : this . name , username : this . username , url : this . url } ) ;
// count the usernames to see if we need to show the server for any of them
if ( typeof suggestionsUsernameCount [ this . username ] != 'undefined' ) {
suggestionsUsernameCount [ this . username ] = suggestionsUsernameCount [ this . username ] + 1 ;
}
else {
suggestionsUsernameCount [ this . username ] = 1 ;
}
}
} ) ;
// show matches
$ . each ( suggestionsToShow , function ( ) {
var serverHtml = '' ;
if ( suggestionsUsernameCount [ this . username ] > 1 && this . url !== false ) {
serverHtml = this . url + '/group/' ;
}
queetBox . siblings ( '.mentions-suggestions' ) . append ( '<div class="group-suggestion" title="' + serverHtml + this . username + '" data-group-id="' + this . id + '"><img height="24" width="24" src="' + this . avatar + '" /><strong>' + this . name + '</strong> !<span>' + this . username + '</span></div>' )
2015-06-03 00:10:58 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2014-05-28 03:40:51 +09:00
}
else {
2015-08-26 06:27:08 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.group-suggestion' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
}
2014-05-28 03:40:51 +09:00
}
else {
2015-08-26 06:27:08 +09:00
queetBox . siblings ( '.mentions-suggestions' ) . children ( '.group-suggestion' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
}
}
} ) ;
2016-02-16 20:36:23 +09:00
/ * ·
·
· Any click empties the mentions - suggestions
·
· · · · · · · · · · · · · * /
$ ( document ) . click ( function ( ) {
$ ( '.mentions-suggestions' ) . empty ( ) ;
} ) ;
2015-07-02 23:57:51 +09:00
/ * ·
·
· Store unposted queets in cache , if the user accidentally reloads the page or something
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'keyup' , 'div.queet-box-syntax' , function ( e ) {
2015-11-23 08:24:33 +09:00
var thisId = $ ( this ) . attr ( 'id' ) ;
var thisText = $ . trim ( $ ( this ) . text ( ) ) ;
// keep in global var to avoid doing all these operations every keystroke
if ( typeof window . queetBoxCurrentlyActive == 'undefined'
|| window . queetBoxCurrentlyActive . id != thisId ) {
window . queetBoxCurrentlyActive = {
id : thisId ,
startText : $ . trim ( $ ( '<div/>' ) . append ( decodeURIComponent ( $ ( this ) . attr ( 'data-start-text' ) ) ) . text ( ) ) ,
repliesText : $ . trim ( $ ( '<div/>' ) . append ( decodeURIComponent ( $ ( this ) . attr ( 'data-replies-text' ) ) ) . text ( ) )
} ;
}
2015-07-02 23:57:51 +09:00
// remove from cache if empty, or same as default text
2015-11-23 08:24:33 +09:00
if ( thisText == ''
|| thisText == window . sL . compose
|| thisText == window . queetBoxCurrentlyActive . startText
|| thisText == window . queetBoxCurrentlyActive . repliesText ) {
localStorageObjectCache _STORE ( 'queetBoxInput' , thisId , false ) ;
2015-07-02 23:57:51 +09:00
}
else {
2015-11-23 08:24:33 +09:00
localStorageObjectCache _STORE ( 'queetBoxInput' , thisId , $ ( this ) . html ( ) ) ;
2015-07-02 23:57:51 +09:00
}
} ) ;
2015-07-02 02:15:31 +09:00
/ * ·
·
· Keyboard shortcuts
·
· · · · · · · · · · · · · * /
// menu
$ ( '#shortcuts-link' ) . click ( function ( ) {
popUpAction ( 'popup-shortcuts' , window . sL . keyboardShortcuts , '<div id="shortcuts-container"></div>' , false ) ;
getDoc ( 'shortcuts' , function ( html ) {
$ ( '#shortcuts-container' ) . html ( html ) ;
centerPopUp ( $ ( '#popup-shortcuts' ) . find ( '.modal-draggable' ) ) ;
} ) ;
} ) ;
// send queet on ctrl+enter or ⌘+enter (mac)
$ ( 'body' ) . on ( 'keydown' , '.queet-box-syntax' , function ( e ) {
if ( ( e . ctrlKey && e . which == 13 )
|| ( e . metaKey && e . which == 13 ) ) {
e . preventDefault ( ) ;
var pressThisButton = $ ( this ) . siblings ( '.queet-toolbar' ) . children ( '.queet-button' ) . children ( 'button' ) ;
pressThisButton . click ( ) ;
$ ( this ) . blur ( ) ;
}
} ) ;
$ ( 'body' ) . keyup ( function ( e ) {
2015-07-02 07:08:54 +09:00
// only if queetbox is blurred, and we're not typing in any input, and we're logged in
if ( $ ( '.queet-box-syntax[contenteditable="true"]' ) . length == 0
&& $ ( ":focus" ) . length == 0
&& window . loggedIn !== false ) {
2015-07-02 02:15:31 +09:00
2015-07-02 07:08:54 +09:00
// shortcuts documentation on '?'
2016-03-12 23:08:22 +09:00
if ( e . shiftKey && ( e . which == 171 || e . which == 191 ) ) {
2015-07-02 02:15:31 +09:00
$ ( '#shortcuts-link' ) . click ( ) ;
}
// queet box popup on 'n'
else if ( e . which == 78 ) { // n
e . preventDefault ( ) ;
var pressThis = $ ( '#top-compose' )
pressThis . click ( ) ;
}
// select first queet on first selection, 'j' or 'k'
else if ( ( e . which == 74 || e . which == 75 ) && $ ( '.stream-item.selected-by-keyboard' ) . length == 0 ) {
$ ( '#feed-body' ) . children ( '.stream-item.visible' ) . first ( ) . addClass ( 'selected-by-keyboard' ) ;
}
// only if we have a selected queet
else if ( $ ( '.stream-item.selected-by-keyboard' ) . length == 1 ) {
var selectedQueet = $ ( '#feed-body' ) . children ( '.stream-item.selected-by-keyboard' ) ;
// next queet on 'j'
if ( e . which == 74 ) {
selectedQueet . removeClass ( 'selected-by-keyboard' ) ;
2015-11-26 03:51:51 +09:00
var next = selectedQueet . nextAll ( '.visible' ) . not ( '.always-hidden' ) . first ( ) ;
2015-07-11 02:32:34 +09:00
next . addClass ( 'selected-by-keyboard' ) ;
scrollToQueet ( next ) ;
2015-07-02 02:15:31 +09:00
}
// prev queet on 'k'
else if ( e . which == 75 ) {
selectedQueet . removeClass ( 'selected-by-keyboard' ) ;
2015-11-26 03:51:51 +09:00
var prev = selectedQueet . prevAll ( '.visible' ) . not ( '.always-hidden' ) . first ( ) ;
2015-07-11 02:32:34 +09:00
prev . addClass ( 'selected-by-keyboard' ) ;
scrollToQueet ( prev ) ;
2015-07-02 02:15:31 +09:00
}
// fav queet on 'f'
else if ( e . which == 70 ) {
selectedQueet . children ( '.queet' ) . find ( '.icon.sm-fav' ) . click ( ) ;
}
// rq queet on 't'
else if ( e . which == 84 ) {
selectedQueet . children ( '.queet' ) . find ( '.icon.sm-rt:not(.is-mine)' ) . click ( ) ;
}
// expand/collapse queet on enter
else if ( e . which == 13 ) {
selectedQueet . children ( '.queet' ) . click ( ) ;
}
// reply to queet on 'r'
else if ( e . which == 82 ) {
if ( selectedQueet . hasClass ( 'expanded' ) ) {
2016-01-21 01:39:34 +09:00
selectedQueet . find ( '.queet-box-syntax' ) . click ( ) ;
2015-07-02 02:15:31 +09:00
}
else {
selectedQueet . children ( '.queet' ) . find ( '.icon.sm-reply' ) . click ( ) ;
}
}
}
2013-08-19 22:30:57 +09:00
}
2014-05-28 03:40:51 +09:00
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking show more links , walk upwards or downwards
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.view-more-container-bottom' , function ( ) {
2014-11-26 08:58:56 +09:00
var thisParentStreamItem = $ ( this ) . parent ( '.stream-item' ) ;
2015-02-26 05:16:24 +09:00
findReplyToStatusAndShow ( thisParentStreamItem , thisParentStreamItem . attr ( 'data-quitter-id' ) , $ ( this ) . attr ( 'data-replies-after' ) ) ;
2013-08-19 22:30:57 +09:00
$ ( this ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
findAndMarkLastVisibleInConversation ( thisParentStreamItem ) ;
2013-08-19 22:30:57 +09:00
} ) ;
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.view-more-container-top' , function ( ) {
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
var this _qid = $ ( this ) . closest ( '.stream-item:not(.conversation)' ) . attr ( 'data-quitter-id' ) ;
2013-08-19 22:30:57 +09:00
var queet = $ ( this ) . siblings ( '.queet' ) ;
2015-07-02 02:15:31 +09:00
var thisParentStreamItem = $ ( this ) . parent ( '.stream-item' ) ;
2013-08-19 22:30:57 +09:00
rememberMyScrollPos ( queet , 'moretop' + this _qid ) ;
2015-02-26 05:16:24 +09:00
findInReplyToStatusAndShow ( thisParentStreamItem , thisParentStreamItem . attr ( 'data-quitter-id' ) , $ ( this ) . attr ( 'data-trace-from' ) , false , true ) ;
2013-08-19 22:30:57 +09:00
$ ( this ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
backToMyScrollPos ( queet , 'moretop' + this _qid , false ) ;
2013-08-19 22:30:57 +09:00
// remove the "show full conversation" link if nothing more to show
2015-02-26 05:16:24 +09:00
if ( thisParentStreamItem . find ( '.hidden-conversation' ) . length == 0 ) {
thisParentStreamItem . children ( '.queet' ) . find ( '.show-full-conversation' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
}
findAndMarkLastVisibleInConversation ( thisParentStreamItem ) ;
} ) ;
2013-08-19 22:30:57 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2013-08-19 22:30:57 +09:00
· When clicking "show full conversation" , show all hidden queets in conversation
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2013-08-19 22:30:57 +09:00
2014-01-29 03:42:47 +09:00
$ ( 'body' ) . on ( 'click' , '.show-full-conversation' , function ( ) {
2013-08-19 22:30:57 +09:00
var this _q = $ ( this ) . closest ( '.queet' ) ;
2015-11-23 08:24:33 +09:00
var thisStreamItem = this _q . parent ( ) ;
var this _qid = thisStreamItem . attr ( 'data-quitter-id' ) ;
2013-08-19 22:30:57 +09:00
rememberMyScrollPos ( this _q , this _qid ) ;
2015-07-02 02:15:31 +09:00
thisStreamItem . find ( '.view-more-container-top' ) . remove ( ) ;
thisStreamItem . find ( '.view-more-container-bottom' ) . remove ( ) ;
2014-11-26 08:58:56 +09:00
$ . each ( thisStreamItem . find ( '.hidden-conversation' ) , function ( key , obj ) {
2013-08-19 22:30:57 +09:00
$ ( obj ) . removeClass ( 'hidden-conversation' ) ;
$ ( obj ) . animate ( { opacity : '1' } , 400 , function ( ) {
2015-07-02 02:15:31 +09:00
$ ( obj ) . css ( 'background-color' , 'pink' ) . animate ( { backgroundColor : '#F6F6F6' } , 1000 ) ;
2013-08-19 22:30:57 +09:00
} ) ;
} ) ;
$ ( this ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
2013-08-19 22:30:57 +09:00
backToMyScrollPos ( this _q , this _qid , false ) ;
2015-07-02 02:15:31 +09:00
findAndMarkLastVisibleInConversation ( thisStreamItem ) ;
2014-01-29 03:42:47 +09:00
} ) ;
2014-06-02 04:51:28 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2014-06-02 04:51:28 +09:00
· Edit profile
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-06-02 04:51:28 +09:00
2015-09-15 10:58:11 +09:00
$ ( 'body' ) . on ( 'click' , '#page-container > .profile-card .edit-profile-button' , function ( ) {
2014-06-02 04:51:28 +09:00
if ( ! $ ( this ) . hasClass ( 'disabled' ) ) {
$ ( this ) . addClass ( 'disabled' ) ;
$ ( 'html' ) . scrollTop ( 0 ) ;
$ ( 'html' ) . addClass ( 'fixed' ) ;
2015-07-02 02:15:31 +09:00
$ ( 'body' ) . prepend ( '<div id="edit-profile-popup" class="modal-container"></div>' ) ;
2014-06-02 04:51:28 +09:00
display _spinner ( ) ;
2015-07-02 02:15:31 +09:00
getFromAPI ( 'users/show/' + window . loggedIn . screen _name + '.json' , function ( data ) {
2014-06-02 04:51:28 +09:00
remove _spinner ( ) ;
if ( data ) {
data = cleanUpUserObject ( data ) ;
// use avatar if no cover photo
2014-11-24 21:47:45 +09:00
var coverPhotoHtml = '' ;
if ( data . cover _photo !== false ) {
coverPhotoHtml = 'background-image:url(\'' + data . cover _photo + '\')' ;
2015-07-02 02:15:31 +09:00
}
2015-09-18 08:42:52 +09:00
$ ( '.hover-card,.hover-card-caret' ) . remove ( ) ;
2014-06-02 04:51:28 +09:00
$ ( '#edit-profile-popup' ) . prepend ( ' \
< div class = "edit-profile-container" > \
2014-11-24 21:47:45 +09:00
< div class = "upload-background-image" > < / d i v > \
< input type = "file" name = "background-image-input" id = "background-image-input" / > \
2014-06-02 04:51:28 +09:00
< div class = "profile-card" > \
2014-11-24 21:47:45 +09:00
< div class = "profile-header-inner" style = "' + coverPhotoHtml + '" > \
2014-06-02 04:51:28 +09:00
< input type = "file" name = "cover-photo-input" id = "cover-photo-input" / > \
2014-11-24 21:47:45 +09:00
< div class = "close-edit-profile-window" > < / d i v > \
2014-06-02 04:51:28 +09:00
< div class = "upload-cover-photo" > < / d i v > \
2014-11-24 21:47:45 +09:00
< input type = "file" name = "avatar-input" id = "avatar-input" / > \
< div class = "upload-avatar" > < / d i v > \
2014-06-02 04:51:28 +09:00
< div class = "profile-header-inner-overlay" > < / d i v > \
< a class = "profile-picture" href = "' + data.profile_image_url_original + '" > < img src = "' + data.profile_image_url_profile_size + '" / > < / a > \
< div class = "profile-card-inner" > \
2014-11-24 21:47:45 +09:00
< input class = "fullname" id = "edit-profile-fullname" placeholder = "' + window.sL.signUpFullName + '" data - start - value = "' + data.name + '" value = "' + data.name + '" / > \
2014-06-02 04:51:28 +09:00
< h2 class = "username" > < span class = "screen-name" > @ ' + data.screen_name + ' < / s p a n > < s p a n c l a s s = " f o l l o w - s t a t u s " > < / s p a n > < / h 2 > \
< div class = "bio-container" > \
2014-11-24 21:47:45 +09:00
< textarea class = "bio" id = "edit-profile-bio" data - start - value = "' + data.description + '" placeholder = "' + window.sL.registerBio + '" > ' + data.description + ' < / t e x t a r e a > \
2014-06-02 04:51:28 +09:00
< / d i v > \
< p class = "location-and-url" > \
2014-11-24 21:47:45 +09:00
< input class = "location" id = "edit-profile-location" placeholder = "' + window.sL.registerLocation + '" data - start - value = "' + data.location + '" value = "' + data.location + '" / > \
2014-06-02 04:51:28 +09:00
< span class = "divider" > · < / s p a n > \
2014-11-24 21:47:45 +09:00
< input class = "url" id = "edit-profile-url" placeholder = "' + window.sL.registerHomepage + '" data - start - value = "' + data.url + '" value = "' + data.url + '" / > \
2014-06-02 04:51:28 +09:00
< / p > \
< / d i v > \
< / d i v > \
< div class = "profile-banner-footer" > \
2014-11-24 21:47:45 +09:00
< div class = "color-selection" > \
< label for = "link-color-selection" > ' + window.sL.linkColor + ' < / l a b e l > \
2015-05-30 00:30:03 +09:00
< input id = "link-color-selection" type = "text" value = "#' + window.loggedIn.linkcolor + '" / > \
2014-11-24 21:47:45 +09:00
< / d i v > \
< div class = "color-selection" > \
< label for = "link-color-selection" > ' + window.sL.backgroundColor + ' < / l a b e l > \
2015-05-30 00:30:03 +09:00
< input id = "background-color-selection" type = "text" value = "#' + window.loggedIn.backgroundcolor + '" / > \
2014-11-24 21:47:45 +09:00
< / d i v > \
2014-06-02 04:51:28 +09:00
< div class = "user-actions" > \
< button type = "button" class = "abort-edit-profile-button" > < span class = "button-text edit-profile-text" > ' + window.sL.cancelVerb + ' < / s p a n > \
< button type = "button" class = "save-profile-button" > < span class = "button-text edit-profile-text" > ' + window.sL.saveChanges + ' < / s p a n > \
2014-11-24 21:47:45 +09:00
< button type = "button" class = "crop-and-save-button" > < span class = "button-text edit-profile-text" > ' + window.sL.cropAndSave + ' < / s p a n > \
2014-06-02 04:51:28 +09:00
< / d i v > \
< div class = "clearfix" > < / d i v > \
< / d i v > \
< / d i v > \
< / d i v > ' ) ;
2014-09-25 06:20:35 +09:00
$ ( '#edit-profile-popup .profile-card' ) . css ( 'top' , $ ( '#page-container .profile-card' ) . offset ( ) . top - 53 + 'px' ) ; // position exactly over
2014-11-24 21:47:45 +09:00
// save colors on change
$ ( '#link-color-selection' ) . minicolors ( {
change : function ( hex ) {
2015-07-02 02:15:31 +09:00
2015-06-07 17:52:38 +09:00
// pause for 500ms before saving and displaying color changes
window . changeToLinkColor = hex ;
setTimeout ( function ( ) {
if ( hex == window . changeToLinkColor ) {
changeDesign ( { linkcolor : hex } ) ;
postNewLinkColor ( hex . substring ( 1 ) ) ;
2015-07-02 02:15:31 +09:00
window . loggedIn . linkcolor = hex . substring ( 1 ) ;
2015-06-07 17:52:38 +09:00
}
} , 500 ) ;
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
}
} ) ;
$ ( '#background-color-selection' ) . minicolors ( {
change : function ( hex ) {
2015-06-07 17:52:38 +09:00
// pause for 500ms before saving and displaying color changes
window . changeToBackgroundColor = hex ;
setTimeout ( function ( ) {
if ( hex == window . changeToBackgroundColor ) {
changeDesign ( { backgroundcolor : hex } ) ;
postNewBackgroundColor ( hex . substring ( 1 ) ) ;
2015-07-02 02:15:31 +09:00
window . loggedIn . backgroundcolor = hex . substring ( 1 ) ;
2015-06-07 17:52:38 +09:00
}
} , 500 ) ;
2014-11-24 21:47:45 +09:00
}
} ) ;
// also on keyup in input (minicolors 'change' event does not do this, apparently)
$ ( '#link-color-selection' ) . on ( 'keyup' , function ( ) {
keyupSetLinkColor ( $ ( this ) . val ( ) ) ;
} ) ;
$ ( '#background-color-selection' ) . on ( 'keyup' , function ( ) {
keyupSetBGColor ( $ ( this ) . val ( ) ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-11-24 21:47:45 +09:00
// check if profile info is change and show/hide buttons
$ ( 'input.fullname,textarea.bio,input.location,input.url' ) . on ( 'keyup paste input' , function ( ) {
showHideSaveProfileButtons ( ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-06-02 04:51:28 +09:00
}
else {
abortEditProfile ( ) ;
}
2015-07-02 02:15:31 +09:00
} ) ;
}
2014-06-02 04:51:28 +09:00
} ) ;
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// function to see if anything in profile is changed and show/hide buttons accordingly
function showHideSaveProfileButtons ( ) {
if ( $ ( 'input.fullname' ) . val ( ) != $ ( 'input.fullname' ) . attr ( 'data-start-value' )
|| $ ( 'textarea.bio' ) . val ( ) != $ ( 'textarea.bio' ) . attr ( 'data-start-value' )
|| $ ( 'input.location' ) . val ( ) != $ ( 'input.location' ) . attr ( 'data-start-value' )
|| $ ( 'input.url' ) . val ( ) != $ ( 'input.url' ) . attr ( 'data-start-value' ) ) {
2015-07-02 02:15:31 +09:00
$ ( '.abort-edit-profile-button, .save-profile-button' ) . show ( ) ;
2014-11-24 21:47:45 +09:00
}
else {
$ ( '.abort-edit-profile-button, .save-profile-button' ) . hide ( ) ;
}
}
// idle function for linkcolor selection by keyboard input
var keyupLinkColorTimer ;
function keyupSetLinkColor ( hex ) {
clearTimeout ( keyupLinkColorTimer ) ;
keyupLinkColorTimer = setTimeout ( function ( ) {
2015-07-02 02:15:31 +09:00
$ ( '#link-color-selection' ) . minicolors ( 'value' , hex ) ;
2014-11-24 21:47:45 +09:00
changeLinkColor ( $ ( '#link-color-selection' ) . val ( ) ) ;
2015-07-02 02:15:31 +09:00
postNewLinkColor ( $ ( '#link-color-selection' ) . val ( ) . substring ( 1 ) ) ;
2014-11-24 21:47:45 +09:00
} , 500 ) ;
2015-07-02 02:15:31 +09:00
}
2014-11-24 21:47:45 +09:00
// idle function for bgcolor selection by keyboard input
var keyupBGColorTimer ;
function keyupSetBGColor ( hex ) {
clearTimeout ( keyupBGColorTimer ) ;
keyupBGColorTimer = setTimeout ( function ( ) {
2015-07-02 02:15:31 +09:00
$ ( '#background-color-selection' ) . minicolors ( 'value' , hex ) ;
2014-11-24 21:47:45 +09:00
$ ( 'body' ) . css ( 'background-color' , $ ( '#background-color-selection' ) . val ( ) ) ;
2015-07-02 02:15:31 +09:00
postNewBackgroundColor ( $ ( '#background-color-selection' ) . val ( ) . substring ( 1 ) ) ;
2014-11-24 21:47:45 +09:00
} , 500 ) ;
2015-07-02 02:15:31 +09:00
}
2014-06-02 04:51:28 +09:00
// cancel
2014-11-24 21:47:45 +09:00
$ ( 'body' ) . on ( 'click' , '.close-edit-profile-window' , function ( ) {
abortEditProfile ( ) ;
2015-07-02 02:15:31 +09:00
} ) ;
2014-06-02 04:51:28 +09:00
$ ( 'body' ) . on ( 'click' , '.abort-edit-profile-button' , function ( ) {
2014-11-24 21:47:45 +09:00
// if this is the avatar or cover photo
2014-06-02 04:51:28 +09:00
if ( $ ( '#edit-profile-popup .jwc_frame' ) . length > 0 ) {
2015-07-02 02:15:31 +09:00
cleanUpAfterCropping ( ) ;
2014-06-02 04:51:28 +09:00
}
2015-07-02 02:15:31 +09:00
// if profile info
2014-06-02 04:51:28 +09:00
else {
abortEditProfile ( ) ;
}
} ) ;
function abortEditProfile ( ) {
$ ( '#edit-profile-popup' ) . remove ( ) ;
$ ( '.edit-profile-button' ) . removeClass ( 'disabled' ) ;
$ ( 'html' ) . removeClass ( 'fixed' ) ;
}
// validate
$ ( 'body' ) . on ( 'keyup paste input' , '#edit-profile-popup input,#edit-profile-popup textarea' , function ( ) {
if ( validateEditProfileForm ( $ ( '#edit-profile-popup' ) ) ) {
$ ( '.save-profile-button' ) . removeAttr ( 'disabled' ) ;
2015-07-02 02:15:31 +09:00
$ ( '.save-profile-button' ) . removeClass ( 'disabled' ) ;
2014-06-02 04:51:28 +09:00
}
else {
2015-07-02 02:15:31 +09:00
$ ( '.save-profile-button' ) . attr ( 'disabled' , 'disabled' ) ;
2014-06-02 04:51:28 +09:00
$ ( '.save-profile-button' ) . addClass ( 'disabled' ) ;
}
} ) ;
2014-11-24 21:47:45 +09:00
// submit cover photo or avatar
$ ( 'body' ) . on ( 'click' , '.crop-and-save-button' , function ( ) {
if ( $ ( '.crop-and-save-button' ) . attr ( 'disabled' ) != 'disabled' ) {
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . attr ( 'disabled' , 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . addClass ( 'disabled' ) ;
display _spinner ( ) ;
// if this is the cover photo
if ( $ ( '#edit-profile-popup .jwc_frame.cover-photo-to-crop' ) . length > 0 ) {
2016-01-29 05:12:34 +09:00
var coverImgFormData = new FormData ( ) ;
coverImgFormData . append ( 'banner' , $ ( '#cover-photo-input' ) [ 0 ] . files [ 0 ] ) ;
coverImgFormData . append ( 'height' , window . jwc . result . cropH ) ;
coverImgFormData . append ( 'width' , window . jwc . result . cropW ) ;
coverImgFormData . append ( 'offset_left' , window . jwc . result . cropX ) ;
coverImgFormData . append ( 'offset_top' , window . jwc . result . cropY ) ;
$ . ajax ( {
url : window . apiRoot + 'account/update_profile_banner.json' ,
type : "POST" ,
data : coverImgFormData ,
processData : false ,
contentType : false ,
cache : false ,
dataType : "json" ,
error : function ( data ) {
console . log ( 'error saving profile banner' ) ; console . log ( data ) ;
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
cleanUpAfterCropping ( ) ;
remove _spinner ( ) ;
2014-11-24 21:47:45 +09:00
} ,
success : function ( data ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-11-24 21:47:45 +09:00
if ( typeof data . error == 'undefined' ) {
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
cleanUpAfterCropping ( ) ;
$ ( '.profile-header-inner' ) . css ( 'background-image' , 'url(' + data . url + ')' ) ;
2015-07-02 02:15:31 +09:00
$ ( '#user-header' ) . css ( 'background-image' , 'url(' + data . url + ')' ) ;
2014-11-24 21:47:45 +09:00
}
else {
alert ( 'Try again! ' + data . error ) ;
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
}
}
2015-07-02 02:15:31 +09:00
} ) ;
2014-11-24 21:47:45 +09:00
}
// if this is the avatar
else if ( $ ( '#edit-profile-popup .jwc_frame.avatar-to-crop' ) . length > 0 ) {
2015-07-02 02:15:31 +09:00
$ . ajax ( { url : window . apiRoot + 'qvitter/update_avatar.json' ,
type : "POST" ,
data : {
2014-11-24 21:47:45 +09:00
cropH : window . jwc . result . cropH ,
cropW : window . jwc . result . cropW ,
cropX : window . jwc . result . cropX ,
cropY : window . jwc . result . cropY ,
img : $ ( '#avatar-to-crop' ) . attr ( 'src' )
} ,
dataType : "json" ,
error : function ( data ) { console . log ( 'error' ) ; console . log ( data ) ; } ,
success : function ( data ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-11-24 21:47:45 +09:00
if ( typeof data . error == 'undefined' ) {
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
cleanUpAfterCropping ( ) ;
$ ( '.profile-picture' ) . attr ( 'href' , data . profile _image _url _original ) ;
$ ( '.profile-picture img, #user-avatar' ) . attr ( 'src' , data . profile _image _url _profile _size ) ;
$ ( '#settingslink .nav-session' ) . css ( 'background-image' , 'url(\'' + data . profile _image _url _profile _size + '\')' ) ;
2015-11-05 21:10:11 +09:00
$ ( '.account-group .name[data-user-id="' + window . loggedIn . id + '"]' ) . siblings ( '.avatar' ) . attr ( 'src' , data . profile _image _url _profile _size ) ;
2014-11-24 21:47:45 +09:00
}
else {
alert ( 'Try again! ' + data . error ) ;
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
}
}
2015-07-02 02:15:31 +09:00
} ) ;
2014-11-24 21:47:45 +09:00
}
// if this is the background-image
else if ( $ ( '#edit-profile-popup .jwc_frame.background-to-crop' ) . length > 0 ) {
2015-07-02 02:15:31 +09:00
$ . ajax ( { url : window . apiRoot + 'qvitter/update_background_image.json' ,
type : "POST" ,
data : {
2014-11-24 21:47:45 +09:00
cropH : window . jwc . result . cropH ,
cropW : window . jwc . result . cropW ,
cropX : window . jwc . result . cropX ,
cropY : window . jwc . result . cropY ,
img : $ ( '#background-to-crop' ) . attr ( 'src' )
} ,
dataType : "json" ,
error : function ( data ) { console . log ( 'error' ) ; console . log ( data ) ; } ,
success : function ( data ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-11-24 21:47:45 +09:00
if ( typeof data . error == 'undefined' ) {
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
cleanUpAfterCropping ( ) ;
2015-05-30 00:30:03 +09:00
changeDesign ( { backgroundimage : data . url } ) ;
window . loggedIn . background _image = data . url ;
2014-11-24 21:47:45 +09:00
}
else {
alert ( 'Try again! ' + data . error ) ;
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
}
}
2015-07-02 02:15:31 +09:00
} ) ;
}
2014-06-02 04:51:28 +09:00
}
2014-11-24 21:47:45 +09:00
} ) ;
// submit new profile info
$ ( 'body' ) . on ( 'click' , '.save-profile-button' , function ( ) {
if ( $ ( '.save-profile-button' ) . attr ( 'disabled' ) != 'disabled' ) {
2015-07-02 02:15:31 +09:00
$ ( '.save-profile-button' ) . attr ( 'disabled' , 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.save-profile-button' ) . addClass ( 'disabled' ) ;
display _spinner ( ) ;
2014-06-02 04:51:28 +09:00
if ( validateEditProfileForm ( $ ( '#edit-profile-popup' ) ) ) {
2015-07-02 02:15:31 +09:00
$ . ajax ( { url : window . apiRoot + 'account/update_profile.json' ,
type : "POST" ,
data : {
2014-06-02 04:51:28 +09:00
name : $ ( '#edit-profile-popup input.fullname' ) . val ( ) ,
url : $ ( '#edit-profile-popup input.url' ) . val ( ) ,
location : $ ( '#edit-profile-popup input.location' ) . val ( ) ,
description : $ ( '#edit-profile-popup textarea.bio' ) . val ( ) ,
} ,
dataType : "json" ,
error : function ( data ) { console . log ( 'error' ) ; console . log ( data ) ; } ,
success : function ( data ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-06-02 04:51:28 +09:00
if ( typeof data . error == 'undefined' ) {
2015-07-02 02:15:31 +09:00
location . reload ( ) ; // reload, hopefully the new profile is saved
2014-06-02 04:51:28 +09:00
}
else {
alert ( 'Try again! ' + data . error ) ;
2015-07-02 02:15:31 +09:00
$ ( '.save-profile-button' ) . removeAttr ( 'disabled' ) ;
2014-06-02 04:51:28 +09:00
$ ( '.save-profile-button' ) . removeClass ( 'disabled' ) ;
}
}
2015-07-02 02:15:31 +09:00
} ) ;
2014-06-02 04:51:28 +09:00
}
}
} ) ;
2014-11-24 21:47:45 +09:00
// cover photo, avatar and background image select and crop
$ ( 'body' ) . on ( 'click' , '.upload-cover-photo, .upload-avatar, .upload-background-image' , function ( ) {
var coverOrAvatar = $ ( this ) . attr ( 'class' ) ;
if ( coverOrAvatar == 'upload-cover-photo' ) {
var inputId = 'cover-photo-input'
}
else if ( coverOrAvatar == 'upload-avatar' ) {
2015-07-02 02:15:31 +09:00
var inputId = 'avatar-input'
2014-11-24 21:47:45 +09:00
}
else if ( coverOrAvatar == 'upload-background-image' ) {
2015-07-02 02:15:31 +09:00
var inputId = 'background-image-input'
}
$ ( '#' + inputId ) . click ( function ( ) { $ ( this ) . one ( 'change' , function ( e ) { // trick to make the change event only fire once when selecting a file
2014-11-24 21:47:45 +09:00
coverPhotoAndAvatarSelectAndCrop ( e , coverOrAvatar ) ;
2014-06-02 04:51:28 +09:00
} ) } ) ;
2015-07-02 02:15:31 +09:00
2016-09-07 21:26:46 +09:00
// trigger click
2016-09-07 21:55:21 +09:00
triggerClickOnInputFile ( $ ( '#' + inputId ) ) ;
2014-11-24 21:47:45 +09:00
2014-06-02 04:51:28 +09:00
} ) ;
// load image from file input
2014-11-24 21:47:45 +09:00
function coverPhotoAndAvatarSelectAndCrop ( e , coverOrAvatar ) {
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
if ( coverOrAvatar == 'upload-cover-photo' ) {
var targetWidth = 588 ;
var targetHeight = 260 ;
var cropId = 'cover-photo-to-crop' ;
}
else if ( coverOrAvatar == 'upload-avatar' ) {
var targetWidth = 220 ;
var targetHeight = 220 ;
var maxWidth = 1040 ;
var minWidth = 1040 ;
2015-07-02 02:15:31 +09:00
var cropId = 'avatar-to-crop' ;
}
2014-11-24 21:47:45 +09:00
else if ( coverOrAvatar == 'upload-background-image' ) {
var targetWidth = $ ( window ) . width ( ) ;
var targetHeight = $ ( window ) . height ( ) - 46 ;
var maxWidth = 3000 ;
var minWidth = 3000 ;
2015-07-02 02:15:31 +09:00
var cropId = 'background-to-crop' ;
}
2014-06-02 04:51:28 +09:00
// get orientation
loadImage . parseMetaData ( e . target . files [ 0 ] , function ( data ) {
if ( data . exif ) {
2015-07-02 02:15:31 +09:00
var orientation = data . exif . get ( 'Orientation' ) ;
2014-06-02 04:51:28 +09:00
}
else {
2015-07-02 02:15:31 +09:00
var orientation = 1 ;
2014-06-02 04:51:28 +09:00
}
display _spinner ( ) ;
2015-07-02 02:15:31 +09:00
// clean up
2014-06-02 04:51:28 +09:00
cleanUpAfterCropping ( ) ;
2015-07-02 02:15:31 +09:00
2014-06-02 04:51:28 +09:00
// create image
loadImage ( e . target . files [ 0 ] ,
2015-07-02 02:15:31 +09:00
function ( img ) {
2014-06-02 04:51:28 +09:00
if ( typeof img . target == 'undefined' ) {
2014-11-24 21:47:45 +09:00
var appendedImg = $ ( '#edit-profile-popup .profile-card' ) . prepend ( '<img id="' + cropId + '" src="' + img . toDataURL ( 'image/jpeg' ) + '" />' ) ;
2015-07-02 02:15:31 +09:00
2014-06-02 04:51:28 +09:00
// enable cropping
2014-11-24 21:47:45 +09:00
$ ( '#' + cropId ) . jWindowCrop ( {
targetWidth : targetWidth ,
targetHeight : targetHeight ,
2014-06-02 04:51:28 +09:00
onChange : function ( result ) {
2015-07-02 02:15:31 +09:00
remove _spinner ( ) ;
2014-06-02 04:51:28 +09:00
}
} ) ;
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// align centered, fade out background
$ ( '#' + cropId ) . parent ( ) . addClass ( cropId ) ;
$ ( '#' + cropId ) . parent ( ) . css ( 'position' , 'absolute' )
$ ( '#' + cropId ) . parent ( ) . css ( 'left' , '50%' )
$ ( '#' + cropId ) . parent ( ) . css ( 'margin-left' , '-' + ( targetWidth / 2 ) + 'px' )
$ ( '#' + cropId ) . parent ( ) . siblings ( '.profile-header-inner' ) . children ( 'div,input,a' ) . css ( 'display' , 'none' ) ;
2015-07-02 02:15:31 +09:00
2015-06-18 21:57:23 +09:00
// replace the hardcoded "click to drag" string
$ ( '#' + cropId ) . siblings ( '.jwc_controls' ) . children ( 'span' ) . html ( window . sL . clickToDrag ) ;
2015-07-02 02:15:31 +09:00
window . jwc = $ ( '#' + cropId ) . getjWindowCrop ( ) ;
2014-11-24 21:47:45 +09:00
$ ( '.save-profile-button' ) . hide ( ) ;
2015-07-02 02:15:31 +09:00
$ ( '.abort-edit-profile-button, .crop-and-save-button' ) . show ( ) ;
2014-06-02 04:51:28 +09:00
}
else {
2014-11-24 21:47:45 +09:00
remove _spinner ( ) ;
2015-07-02 02:15:31 +09:00
$ ( '.queet-box-loading-cover' ) . remove ( ) ;
2014-06-02 04:51:28 +09:00
alert ( 'could not read image' ) ;
}
} ,
2014-11-24 21:47:45 +09:00
{ maxWidth : maxWidth ,
minWidth : minWidth ,
2014-09-20 09:53:10 +09:00
canvas : true ,
2014-06-02 04:51:28 +09:00
orientation : orientation } // Options
2015-07-02 02:15:31 +09:00
) ;
} ) ;
2014-06-02 04:51:28 +09:00
}
function cleanUpAfterCropping ( ) {
2014-11-24 21:47:45 +09:00
$ ( '.jwc_frame' ) . siblings ( '.profile-header-inner' ) . children ( 'div,input,a' ) . css ( 'display' , 'block' ) ;
2014-06-02 04:51:28 +09:00
if ( typeof window . jwc != 'undefined' ) {
window . jwc . destroy ( ) ;
}
$ ( '.jwc_frame' ) . remove ( ) ;
$ ( '#cover-photo-to-crop' ) . remove ( ) ;
2014-11-24 21:47:45 +09:00
$ ( '#avatar-to-crop' ) . remove ( ) ;
2015-07-02 02:15:31 +09:00
$ ( '#background-to-crop' ) . remove ( ) ;
2014-11-24 21:47:45 +09:00
$ ( 'input:file' ) . unbind ( 'click' ) ;
$ ( '.crop-and-save-button' ) . removeClass ( 'disabled' ) ;
2015-07-02 02:15:31 +09:00
$ ( '.crop-and-save-button' ) . removeAttr ( 'disabled' ) ;
2014-11-24 21:47:45 +09:00
$ ( '.crop-and-save-button, .abort-edit-profile-button' ) . hide ( ) ;
showHideSaveProfileButtons ( ) ;
}
2015-07-02 02:15:31 +09:00
/ * ·
·
2015-11-17 04:27:40 +09:00
· Upload attachment
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'mousedown' , '.upload-image' , function ( ) {
2014-11-24 21:47:45 +09:00
// remember caret position
var caretPos = getSelectionInElement ( $ ( this ) . closest ( '.queet-toolbar' ) . siblings ( '.queet-box-syntax' ) [ 0 ] ) ;
$ ( this ) . attr ( 'data-caret-pos' , caretPos ) ;
2015-07-02 02:15:31 +09:00
2014-11-24 21:47:45 +09:00
// prevent queet-box collapse
$ ( this ) . addClass ( 'clicked' ) ;
2015-07-02 02:15:31 +09:00
} ) ;
$ ( 'body' ) . on ( 'click' , '.upload-image' , function ( ) {
2014-11-24 21:47:45 +09:00
var thisUploadButton = $ ( this ) ;
2015-07-02 02:15:31 +09:00
$ ( '#upload-image-input' ) . one ( 'click' , function ( ) { // trick to make the change event only fire once when selecting a file
2015-11-17 05:46:09 +09:00
$ ( this ) . unbind ( 'change' ) ;
2015-07-02 02:15:31 +09:00
$ ( this ) . one ( 'change' , function ( e ) {
2015-11-17 04:27:40 +09:00
uploadAttachment ( e , thisUploadButton ) ;
2014-11-24 21:47:45 +09:00
} )
} ) ;
2015-07-02 02:15:31 +09:00
2016-09-07 21:26:46 +09:00
// trigger click
2016-09-07 21:55:21 +09:00
triggerClickOnInputFile ( $ ( '#upload-image-input' ) ) ;
2016-09-07 21:26:46 +09:00
2015-07-02 02:15:31 +09:00
} ) ;
2015-11-17 04:27:40 +09:00
function uploadAttachment ( e , thisUploadButton ) {
// loader cover stuff
thisUploadButton . closest ( '.queet-toolbar' ) . parent ( ) . append ( '<div class="queet-box-loading-cover"></div>' ) ;
thisUploadButton . closest ( '.queet-toolbar' ) . siblings ( '.queet-box-loading-cover' ) . width ( thisUploadButton . closest ( '.queet-toolbar' ) . parent ( ) . outerWidth ( ) ) ;
display _spinner ( thisUploadButton . closest ( '.queet-toolbar' ) . siblings ( '.queet-box-loading-cover' ) [ 0 ] ) ;
thisUploadButton . closest ( '.queet-toolbar' ) . siblings ( '.queet-box-loading-cover' ) . find ( '.loader' ) . css ( 'top' , ( thisUploadButton . closest ( '.queet-toolbar' ) . parent ( ) . outerHeight ( ) / 2 - 20 ) + 'px' ) ;
var uploadButton = thisUploadButton . closest ( '.queet-toolbar' ) . find ( '.upload-image' ) ;
var queetBox = thisUploadButton . closest ( '.queet-toolbar' ) . siblings ( '.queet-box-syntax' ) ;
var caretPos = uploadButton . attr ( 'data-caret-pos' ) . split ( ',' ) ;
var imgFormData = new FormData ( ) ;
imgFormData . append ( 'media' , $ ( '#upload-image-input' ) [ 0 ] . files [ 0 ] ) ;
// upload
$ . ajax ( { url : window . apiRoot + 'statusnet/media/upload' ,
type : "POST" ,
data : imgFormData ,
contentType : false ,
processData : false ,
dataType : "xml" ,
error : function ( data , textStatus , errorThrown ) {
showErrorMessage ( window . sL . ERRORattachmentUploadFailed , queetBox . siblings ( '.syntax-two' ) ) ;
$ ( '.queet-box-loading-cover' ) . remove ( ) ;
queetBox . focus ( ) ;
} ,
success : function ( data ) {
var rsp = $ ( data ) . find ( 'rsp' ) ;
if ( rsp . attr ( 'stat' ) == 'ok' ) {
// maybe add thumbnail below queet box
2016-01-24 01:27:36 +09:00
if ( $ ( data ) . find ( 'atom\\:link,link' ) . length > 0 ) {
var mimeType = $ ( data ) . find ( 'atom\\:link,link' ) . attr ( 'type' ) ;
2015-11-17 04:38:55 +09:00
if ( mimeType . indexOf ( 'image/' ) == 0 ) {
2016-01-24 01:27:36 +09:00
var imgUrl = $ ( data ) . find ( 'atom\\:link,link' ) . attr ( 'href' ) ;
2015-11-17 04:38:55 +09:00
thisUploadButton . closest ( '.queet-toolbar' ) . before ( '<span class="upload-image-container"><img class="to-upload" src="' + imgUrl + '" /></span>' ) ;
}
2015-11-17 04:27:40 +09:00
}
2014-11-24 21:47:45 +09:00
2015-11-17 04:27:40 +09:00
var mediaurl = rsp . find ( 'mediaurl' ) . text ( ) ;
2014-11-24 21:47:45 +09:00
2015-11-17 04:27:40 +09:00
$ ( 'img.to-upload' ) . attr ( 'data-shorturl' , mediaurl ) ;
$ ( 'img.to-upload' ) . addClass ( 'uploaded' ) ;
$ ( 'img.to-upload' ) . removeClass ( 'to-upload' ) ;
// insert shorturl in queet box
deleteBetweenCharacterIndices ( queetBox [ 0 ] , caretPos [ 0 ] , caretPos [ 1 ] ) ;
var range = createRangeFromCharacterIndices ( queetBox [ 0 ] , caretPos [ 0 ] , caretPos [ 0 ] ) ;
if ( typeof range == 'undefined' ) {
// if queetbox is empty no range is returned, and inserting will fail,
// so we insert a space and try to get range again...
queetBox . html ( ' ' ) ;
range = createRangeFromCharacterIndices ( queetBox [ 0 ] , caretPos [ 0 ] , caretPos [ 0 ] ) ;
}
range . insertNode ( document . createTextNode ( ' ' + mediaurl + ' ' ) ) ;
// put caret after
queetBox . focus ( ) ;
var putCaretAt = parseInt ( caretPos [ 0 ] , 10 ) + mediaurl . length + 2 ;
setSelectionRange ( queetBox [ 0 ] , putCaretAt , putCaretAt ) ;
queetBox . trigger ( 'input' ) ; // avoid some flickering
setTimeout ( function ( ) { queetBox . trigger ( 'input' ) ; } , 1 ) ; // make sure chars are counted and shorten-button activated
$ ( '.queet-box-loading-cover' ) . remove ( ) ;
}
else {
alert ( 'Try again! ' + rsp . find ( 'err' ) . attr ( 'msg' ) ) ;
$ ( '.save-profile-button' ) . removeAttr ( 'disabled' ) ;
$ ( '.save-profile-button' ) . removeClass ( 'disabled' ) ;
$ ( 'img.to-upload' ) . parent ( ) . remove ( ) ;
$ ( '.queet-box-loading-cover' ) . remove ( ) ;
}
}
2015-07-02 02:15:31 +09:00
} ) ;
}
2014-11-24 21:47:45 +09:00
2015-07-02 02:15:31 +09:00
/ * ·
·
2016-03-05 07:07:15 +09:00
· Small edit profile button on hover cards goes to edit profile
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '.hover-card .edit-profile-button' , function ( ) {
goToEditProfile ( ) ;
} ) ;
/ * ·
·
· User menu when clicking the mini cog wheel in the logged in mini card
·
· · · · · · · · · · · · · * /
$ ( 'body' ) . on ( 'click' , '#mini-logged-in-user-cog-wheel:not(.dropped)' , function ( ) {
var menu = $ ( getMenu ( loggedInUsersMenuArray ( ) ) ) . appendTo ( this ) ;
alignMenuToParent ( menu , $ ( this ) ) ;
$ ( this ) . addClass ( 'dropped' ) ;
} ) ;
// hide when clicking it again
$ ( 'body' ) . on ( 'click' , '#mini-logged-in-user-cog-wheel.dropped' , function ( e ) {
if ( $ ( e . target ) . is ( '#mini-logged-in-user-cog-wheel' ) ) {
$ ( '#mini-logged-in-user-cog-wheel' ) . children ( '.dropdown-menu' ) . remove ( ) ;
$ ( '#mini-logged-in-user-cog-wheel' ) . removeClass ( 'dropped' ) ;
}
} ) ;
// hide the menu when clicking outside it
$ ( 'body' ) . on ( 'click' , function ( e ) {
if ( $ ( '#mini-logged-in-user-cog-wheel' ) . hasClass ( 'dropped' ) && ! $ ( e . target ) . closest ( '#mini-logged-in-user-cog-wheel' ) . length > 0 ) {
$ ( '#mini-logged-in-user-cog-wheel' ) . children ( '.dropdown-menu' ) . remove ( ) ;
$ ( '#mini-logged-in-user-cog-wheel' ) . removeClass ( 'dropped' ) ;
}
} ) ;
/ * ·
·
· Goes to edit profile
2015-07-02 02:15:31 +09:00
·
· · · · · · · · · · · · · * /
2014-11-24 21:47:45 +09:00
2016-03-05 07:07:15 +09:00
function goToEditProfile ( arg , callback ) {
2015-09-18 08:42:52 +09:00
if ( window . currentStreamObject . name == 'my profile' ) {
2015-09-15 10:58:11 +09:00
$ ( '#page-container > .profile-card .edit-profile-button' ) . trigger ( 'click' ) ;
2016-03-05 07:07:15 +09:00
if ( typeof callback == 'function' ) {
callback ( true ) ;
}
2014-11-24 21:47:45 +09:00
}
else {
2015-09-18 20:42:19 +09:00
setNewCurrentStream ( pathToStreamRouter ( window . loggedIn . screen _name ) , true , false , function ( ) {
2015-09-15 10:58:11 +09:00
$ ( '#page-container > .profile-card .edit-profile-button' ) . trigger ( 'click' ) ;
2016-03-05 07:07:15 +09:00
if ( typeof callback == 'function' ) {
callback ( true ) ;
}
2015-09-18 08:42:52 +09:00
} ) ;
2014-11-24 21:47:45 +09:00
}
2016-03-05 07:07:15 +09:00
2016-03-01 03:36:50 +09:00
}