1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321 |
- /*· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
- · ·
- · ·
- · Q V I T T E R ·
- · ·
- · ·
- · <o) ·
- · /_//// ·
- · (____/ ·
- · (o< ·
- · o> \\\\_\ ·
- · \\) \____) ·
- · ·
- · ·
- · @licstart The following is the entire license notice for the ·
- · JavaScript code in this page. ·
- · ·
- · Copyright (C) 2015 Hannes Mannerheim and other contributors ·
- · ·
- · ·
- · 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/>. ·
- · ·
- · @licend The above is the entire license notice ·
- · for the JavaScript code in this page. ·
- · ·
- · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · */
- // plugins can add translatons to this object
- window.pluginTranslations = [];
- // object to keep old states of streams in, to speed up stream change
- window.oldStreams = new Object();
- // check our localStorage and make sure it's correct
- checkLocalStorage();
- // 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);
- // 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 and chrome 59+ doesn't support this
- if(typeof bowser != 'undefined') {
- var bowserIntVersion = parseInt(bowser.version,10);
- if(typeof bowser.msie == 'undefined'
- && typeof bowser.msedge == 'undefined'
- && !(typeof bowser.chrome != 'undefined' && bowser.chrome === true && bowserIntVersion <= 59)) {
- window.apiRoot = window.apiRoot.replace('://','://x:x@');
- }
- }
- /* ·
- ·
- · Update stream on back button
- ·
- · · · · · · · · · · · · · */
- window.onpopstate = function(event) {
- if(event && event.state) {
- display_spinner();
- setNewCurrentStream(pathToStreamRouter(event.state.strm),false,false,function(){
- remove_spinner();
- });
- }
- }
- /* ·
- ·
- · Discard error messages
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.discard-error-message',function(){
- // don't nag on people
- if($(this).parent().hasClass('language-error-message')) {
- localStorageObjectCache_STORE('languageErrorMessageDiscarded',$(this).parent().attr('data-language-name'), true);
- }
- $(this).addClass('clicked');
- $(this).closest('.error-message, .language-error-message').slideUp(100,function(){
- $(this).remove();
- });
- });
- /* ·
- ·
- · welcome text expand and collapse
- ·
- · · · · · · · · · · · · · */
- $('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;
- $('.front-welcome-text').css('height', welcomeTextInnerObjectsHeightSum + 'px')
- }
- 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;}
- $('html, body').animate({ scrollTop: scrollTo}, 300, 'linear');
- }
- });
- $('body').on('click','.welcome-text-register-link',function(){
- var scrollTo = $('#user-container').offset().top;
- $('html, body').animate({ scrollTop: scrollTo}, 300, 'linear');
- });
- /* ·
- ·
- · Check for tooltips to display
- ·
- · · · · · · · · · · · · · */
- $('body').on({
- mouseover: function (e) {
- removeAllTooltips();
- // convert title to tooltip
- if($(e.target).is('[title]')) {
- var titleAttribute = replaceHtmlSpecialChars($(e.target).attr('title')); // can contain malicious code
- $(e.target).attr('data-tooltip',titleAttribute);
- $(e.target).removeAttr('title');
- }
- // regular tooltips
- if($(e.target).is('[data-tooltip]')) {
- var tooltipClass = '';
- tooltip_data = $(e.target).attr('data-tooltip');
- // 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';
- }
- // 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';
- }
- }
- 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>');
- var tooltipCaret = $('<div class="tooltip-caret"></div>');
- $('body').prepend(tooltipElement);
- $('body').prepend(tooltipCaret);
- // align tooltip to the hovered element
- alignTooltipTohoveredElement(tooltipElement,tooltipCaret,$(e.target));
- // fade in
- tooltipElement.css('opacity','1');
- tooltipCaret.css('opacity','1');
- }
- },
- mouseleave: function (e) {
- removeAllTooltips();
- }
- });
- // 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();
- });
- // removes all tooltips
- function removeAllTooltips() {
- $('.tooltip,.tooltip-caret').remove();
- }
- /* ·
- ·
- · Check for profile hovercards to display
- ·
- · · · · · · · · · · · · · */
- window.userArrayLastRetrieved = new Object();
- $('body').on('mouseover',function (e) {
- // no hovercards on these elements
- 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')) {
- return true;
- }
- var timeNow = new Date().getTime();
- removeAllhoverCards(e,timeNow);
- var hoverCardData = false;
- 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');
- }
- else {
- return true;
- }
- // no hover card if the element has the no-hover-card class
- if(targetElement.hasClass('no-hover-card')) {
- return true;
- }
- // no hovercard for anchor links
- if(hrefAttr.substring(0,1) == '#') {
- return true;
- }
- // 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
- getUserArrayData(hrefAttr, possibleNickname, timeNow, targetElement, function(userArray, timeOut){
- // bad data
- if(typeof userArray.local == 'undefined') {
- return;
- }
- // build card from either the local or external data, depending on what we got
- if (userArray.local !== null && userArray.local.is_local == true) {
- var profileCard = buildProfileCard(userArray.local);
- }
- else if(userArray.local !== null && userArray.local.is_local == false && (typeof userArray.external == 'undefined' || userArray.external === null || userArray.external === false)) {
- var profileCard = buildProfileCard(userArray.local);
- }
- else if ((userArray.local === null || userArray.local === false || userArray.local.is_local == false) && typeof userArray.external != 'undefined' && userArray.external !== false && userArray.external !== null) {
- var profileCard = buildExternalProfileCard(userArray);
- }
- else {
- console.log('could not build profile card...');
- return;
- }
- 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>');
- targetElement.attr('data-awaiting-hover-card',timeNow);
- // let user hover for 600ms before showing the card
- setTimeout(function(){
- // 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);
- // if the user array has not been retrieved from the server for the last 60 seconds,
- // we query it for the lastest data
- if((typeof window.userArrayLastRetrieved[hrefAttr] == 'undefined') || (timeNow - window.userArrayLastRetrieved[hrefAttr]) > 60000) {
- window.userArrayLastRetrieved[hrefAttr] = timeNow;
- // local users
- if(userArray.local && userArray.local.is_local === true) {
- getFromAPI('users/show.json?id=' + userArray.local.screen_name, function(data){
- if(data) {
- var newProfileCard = buildProfileCard(data);
- hoverCardElement.html(newProfileCard.profileCardHtml);
- alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
- }
- });
- }
- // external users
- else if(!userArray.local || userArray.local.is_local === false) {
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(hrefAttr),function(data){
- if(data && data.external !== null) {
- var newProfileCard = buildExternalProfileCard(data);
- hoverCardElement.html(newProfileCard.profileCardHtml);
- alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
- }
- });
- }
- }
- // hide tooltips
- $('.tooltip,.tooltip-caret').remove();
- // align hover card to the hovered element
- alignTooltipTohoveredElement(hoverCardElement,hoverCardCaret,targetElement);
- // fade in
- hoverCardElement.css('opacity','1');
- hoverCardCaret.css('opacity','1');
- }
- }
- },timeOut);
- });
- });
- // get user array from cache (or from server)
- function getUserArrayData(maybeProfileUrl,maybeNickname,timeNow,targetElement,callback) {
- if(maybeProfileUrl && maybeNickname) {
- userArray = userArrayCacheGetByProfileUrlAndNickname(maybeProfileUrl, maybeNickname);
- // no cached user array found, query server if this seems to be a profile url
- if(!userArray) {
- 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")) {
- // don't try this if we already tried it less than a minute ago
- if((typeof window.userArrayLastRetrieved[maybeProfileUrl] == 'undefined') || (timeNow - window.userArrayLastRetrieved[maybeProfileUrl]) > 60000) {
- window.userArrayLastRetrieved[maybeProfileUrl] = timeNow;
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(maybeProfileUrl),function(data){
- if(data) {
- // 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);
- }
- });
- }
- }
- },200);
- }
- // likely an uncached local profile
- else if(streamObject && (streamObject.name == 'profile' || streamObject.name == 'profile by id')) {
- var nicknameOrId = streamObject.nickname;
- if(!nicknameOrId) {
- nicknameOrId = streamObject.id;
- }
- // don't query too often for the same user
- if(typeof window.userArrayLastRetrieved[maybeProfileUrl] == 'undefined' || (timeNow - window.userArrayLastRetrieved[maybeProfileUrl]) > 60000) {
- window.userArrayLastRetrieved[maybeProfileUrl] = timeNow;
- // query server and cache user data (done automatically in getFromAPI)
- getFromAPI('users/show.json?id=' + nicknameOrId, function(data){
- if(data) {
- userArray = {local:data};
- // we want hover cards to appear _at least_ 600ms after hover
- // 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;
- }
- // continue to display the hover card
- callback(userArray,timeOut);
- }
- });
- }
- }
- }
- // from cache
- else {
- // continue to display the hover card
- // 600ms before cards appear feels pretty good
- // but this can be tweaked if cards appear to fast/slow
- callback(userArray,600);
- }
- }
- }
- // hover cards should be removed very easily, e.g. when any of these events happen
- $('body').on("mouseleave touchstart scroll click dblclick mousedown mouseup submit keydown keypress keyup", function(e){
- var timeNow = new Date().getTime();
- removeAllhoverCards(e,timeNow);
- });
- // removes all hover cards
- function removeAllhoverCards(event,priorTo) {
- // 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(){
- $.each($('.hover-card'),function(){
- // don't remove card if it was created after removeAllhoverCards() was called
- if($(this).data('card-created') < priorTo) {
- // don't remove it if we're hovering it right now!
- if(!$(this).hasClass('dont-remove-card')) {
- $('[data-hover-card-active="' + $(this).data('card-created') + '"]').removeAttr('data-hover-card-active');
- $('#hover-card-caret-' + $(this).data('card-created')).remove();
- $(this).remove();
- }
- }
- });
- },100);
- }
- // if we're hovering a hover card, give it a class, so we don't remove it
- $('body').on('mouseover','.hover-card', function(e) {
- $(this).addClass('dont-remove-card');
- });
- $('body').on('mouseleave','.hover-card', function(e) {
- $(this).removeClass('dont-remove-card');
- });
- /* ·
- ·
- · find someone tool
- ·
- · · · · · · · · · · · · · */
- $('#find-someone input').keyup(function(e){
- var thisFindSomeoneInput = $(this);
- if(e.keyCode==13 && !thisFindSomeoneInput.hasClass('submitted')) {
- thisFindSomeoneInput.addClass('submitted');
- thisFindSomeoneInput.attr('disabled','disabled');
- var val = $.trim(thisFindSomeoneInput.val());
- // if this is a simple text input, we assume it is a local user
- if(val.length>1 && /^(@)?[a-zA-Z0-9]+$/.test(val)) {
- if(val.indexOf('@') == 0) {
- val = val.replace('@','');
- }
- setNewCurrentStream(pathToStreamRouter(val),true,false,function(){
- foundSomeone(thisFindSomeoneInput);
- });
- }
- // urls might be a remote user
- else if(val.length==0 || /^(ftp|http|https):\/\/[^ "]+$/.test(val)) {
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(val),function(data){
- if(data && data.local !== null) {
- setNewCurrentStream(pathToStreamRouter('user/' + data.local.id),true,false,function(){
- foundSomeone(thisFindSomeoneInput);
- });
- }
- else {
- cantFindSomeone(thisFindSomeoneInput);
- }
- });
- }
- // @user@instance.domain style syntax
- else if(val.length==0 || /^(@)?[a-zA-Z0-9]+@[a-zA-Z0-9\-]+(\.)(.*)+$/.test(val)) {
- if(val.indexOf('@') == 0) {
- val = val.substring(1)
- }
- var username = val.substring(0, val.indexOf('@'));
- var domain = val.substring(val.indexOf('@')+1);
- var urlToTry = 'https://' + domain + '/' + username;
- var secondUrlToTry = 'http://' + domain + '/' + username;
- var thirdUrlToTry = 'https://' + domain + '/@' + username; // mastodon
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(urlToTry),function(data){
- if(data && data.local !== null) {
- setNewCurrentStream(pathToStreamRouter('user/' + data.local.id),true,false,function(){
- foundSomeone(thisFindSomeoneInput);
- });
- }
- else {
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(secondUrlToTry),function(data){
- if(data && data.local !== null) {
- setNewCurrentStream(pathToStreamRouter('user/' + data.local.id),true,false,function(){
- foundSomeone(thisFindSomeoneInput);
- });
- }
- else {
- getFromAPI('qvitter/external_user_show.json?profileurl=' + encodeURIComponent(thirdUrlToTry),function(data){
- if(data && data.local !== null) {
- setNewCurrentStream(pathToStreamRouter('user/' + data.local.id),true,false,function(){
- foundSomeone(thisFindSomeoneInput);
- });
- }
- else {
- cantFindSomeone(thisFindSomeoneInput);
- }
- });
- }
- });
- }
- });
- }
- else {
- cantFindSomeone(thisFindSomeoneInput);
- }
- }
- });
- function cantFindSomeone(thisFindSomeoneInput) {
- thisFindSomeoneInput.css('background-color','pink');
- thisFindSomeoneInput.effect('shake',{distance:5,times:3,duration:700},function(){
- thisFindSomeoneInput.animate({backgroundColor:'#fff'},1000);
- thisFindSomeoneInput.removeAttr('disabled');
- thisFindSomeoneInput.removeClass('submitted');
- thisFindSomeoneInput.focus();
- });
- }
- function foundSomeone(thisFindSomeoneInput) {
- thisFindSomeoneInput.removeAttr('disabled');
- thisFindSomeoneInput.val('');
- thisFindSomeoneInput.blur();
- thisFindSomeoneInput.removeClass('submitted');
- }
- /* ·
- ·
- · fix login and register box to top when they reach top
- ·
- · · · · · · · · · · · · · */
- $(window).scroll(function(e){
- if($('#page-container > .profile-card').length > 0) {
- var feedOrProfileCardOffsetTop = $('#page-container > .profile-card').offset().top;
- }
- else {
- var feedOrProfileCardOffsetTop = $('#feed').offset().top;
- }
- if ($(this).scrollTop() > (feedOrProfileCardOffsetTop-55) && $('#login-content').css('position') != 'fixed'){
- var loginAndSignUpBoxesHeight = $('#login-content').outerHeight() + $('.front-signup').not('#popup-signup').outerHeight();
- $('#login-register-container').css({'position': 'fixed', 'top': '55px'});
- }
- else if ($(this).scrollTop() < (feedOrProfileCardOffsetTop-55) && $('#login-content').css('position') != 'absolute'){
- $('#login-register-container').css({'position': 'relative', 'top': 'auto'});
- }
- });
- /* ·
- ·
- · Tooltip to show what federated means
- ·
- · · · · · · · · · · · · · */
- $('body').on('mouseenter','#federated-tooltip',function(){
- $('#what-is-federation').fadeIn(100);
- });
- $('body').on('mouseleave','#what-is-federation',function(){
- $('#what-is-federation').fadeOut(100);
- });
- /* ·
- ·
- · Scroll to top when clicking top bar
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.global-nav',function(e) {
- if($(e.target).hasClass('global-nav')) {
- $(window).scrollTop(0);
- }
- });
- /* ·
- ·
- · Register
- ·
- · · · · · · · · · · · · · */
- if(!window.registrationsClosed) {
- $('.front-signup input, .front-signup button').removeAttr('disabled'); // clear this onload
- $('#signup-btn-step1').click(function(){
- $(document).trigger('onClickStep1Register'); // hook
- 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();
- popUpAction('popup-register',window.sL.signUp,'<div id="popup-signup" class="front-signup">' +
- '<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>' +
- '<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>' +
- '<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>' +
- '<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>' +
- '<button id="signup-btn-step2" class="signup-btn disabled" type="submit">' + window.sL.signUpButtonText + '</button>' +
- '</div>',false);
- // ask api if nickname is ok, if no typing for 1 s
- $('#signup-user-nickname-step2').on('keyup',function(){
- clearTimeout(window.checkNicknameTimeout);
- var thisInputElement = $(this);
- var thisValue = $(this).val();
- if(thisValue.length>1 && /^[a-zA-Z0-9]+$/.test(thisValue)) {
- thisInputElement.addClass('nickname-taken');
- 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.checkNicknameTimeout = setTimeout(function(){
- $.get(window.apiRoot + 'check_nickname.json?nickname=' + encodeURIComponent(thisValue),function(data){
- $('.spinner-wrap').remove();
- if(data==0) {
- $('#signup-user-password2-step2').trigger('keyup'); // revalidates
- }
- else {
- 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();
- $('#signup-user-password2-step2').trigger('keyup');
- }
- });
- },1000);
- }
- else {
- $('.spinner-wrap').remove();
- }
- });
- // validate on keyup / paste / blur
- $('#popup-register input').on('keyup paste blur',function(){
- 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);
- });
- $('#popup-register input').trigger('keyup');
- // submit on enter
- $('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) {
- $('#signup-btn-step2').trigger('click');
- }
- });
- $('#signup-btn-step2').click(function(){
- if(!$(this).hasClass('disabled')) {
- $('#popup-register input,#popup-register button').addClass('disabled');
- display_spinner();
- $.ajax({ url: window.apiRoot + 'account/register.json',
- type: "POST",
- data: {
- 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(),
- location: $('#signup-user-location-step2').val(),
- password: $('#signup-user-password1-step2').val(),
- confirm: $('#signup-user-password2-step2').val(),
- cBS: window.cBS,
- cBSm: window.cBSm,
- username: 'none',
- },
- dataType:"json",
- 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'));
- }
- },
- success: function(data) {
- remove_spinner();
- 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');
- }
- }
- });
- }
- });
- // 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');
- });
- },7000);
- });
- // submit on enter
- $('input#signup-user-name,input#signup-user-email,input#signup-user-password').keyup(function(e){
- if(e.keyCode==13) {
- $('#signup-btn-step1').trigger('click');
- }
- });
- }
- /* ·
- ·
- · Show/hide Terms of Use
- ·
- · · · · · · · · · · · · · */
- $('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);
- });
- }
- }
- });
- /* ·
- ·
- · set language, autologin or show welcome screen
- ·
- · · · · · · · · · · · · · */
- $('#submit-login').removeAttr('disabled'); // might be remebered by browser...
- $(window).load(function() {
- // set language, from local storage, else browser language
- var browserLang = navigator.language || navigator.userLanguage;
- // use english if browser has no language set
- if(typeof browserLang == 'undefined') {
- var browserLang = 'en-GB';
- }
- // browsers report e.g. sv-SE but we want it in the format "sv" or "sv_se"
- browserLang = browserLang.replace('-','_').toLowerCase();
- // if we're logged out, we see if there's a saved language in localstorage
- if(window.loggedIn === false) {
- var cacheDataLoggedOut = localStorageObjectCache_GET('selectedLanguage','logged_out');
- if(cacheDataLoggedOut) {
- window.selectedLanguage = cacheDataLoggedOut;
- }
- else {
- window.selectedLanguage = browserLang;
- }
- }
- // 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
- else {
- 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;
- }
- }
- // check that the language is available,
- if(typeof window.availableLanguages[window.selectedLanguage] == 'undefined') {
- var similarLanguageFound = false;
- // if not there might be a base language, e.g. "sv" instead of "sv_se"
- 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;
- }
- else {
- // there's also a chance there no base language, but a similar country specific language that we can use (rather than english)
- if(window.selectedLanguage.indexOf('_') > -1) {
- var baseLan = window.selectedLanguage.indexOf('_');
- }
- else {
- var baseLan = window.selectedLanguage;
- }
- $.each(window.availableLanguages, function(lanCode,lanData){
- if(lanCode.substring(0,lanCode.indexOf('_')) == baseLan) {
- window.selectedLanguage = lanCode;
- similarLanguageFound = true;
- return false;
- }
- });
- }
- // if we can't find a similar language, go with english
- if(similarLanguageFound === false) {
- window.selectedLanguage = 'en';
- }
- }
- // english is always available
- if(window.selectedLanguage == 'en') {
- proceedToSetLanguageAndLogin(window.englishLanguageData);
- }
- else {
- // 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) {
- // store this response in localstorage
- localStorageObjectCache_STORE('languageData',window.availableLanguages[window.selectedLanguage], data);
- proceedToSetLanguageAndLogin(data);
- }
- });
- }
- }
- });
- // proceed to set language and login
- function proceedToSetLanguageAndLogin(data){
- window.sL = data;
- // 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');
- // if this is a RTL-language, add rtl class to body
- if(window.sL.directionality == 'rtl') {
- $('body').addClass('rtl');
- }
- window.siteTitle = $('head title').html(); // remember this for later use
- // replace placeholders in translation
- $.each(window.sL,function(k,v){
- window.sL[k] = v.replace(/{site-title}/g,window.siteTitle);
- });
- // 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>');
- }
- }
- }
- // set some static strings
- if(window.customWelcomeText !== false && typeof window.customWelcomeText[window.selectedLanguage] != 'undefined') {
- $('.front-welcome-text').html(window.customWelcomeText[window.selectedLanguage]);
- // collapse long welcome texts and add expand button
- if($('.front-welcome-text').outerHeight()>250) {
- $('.front-welcome-text').css('height','240px');
- $('.front-welcome-text').css('overflow', 'hidden');
- $('.front-welcome-text').append('<div class="show-full-welcome-text"></div>');
- }
- }
- else {
- $('.front-welcome-text').html('<h1>' + window.sL.welcomeHeading + '</h1>');
- if(window.enableWelcomeText) {
- $('.front-welcome-text').append(window.sL.welcomeText);
- }
- }
- $('#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);
- $('#stream-header').html(window.sL.queetsNounPlural);
- $('#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);
- $('.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)
- $('#search-query').attr('placeholder',window.sL.searchVerb);
- $('#blocking-link').html(window.sL.userBlocks);
- $('#faq-link').html(window.sL.FAQ);
- $('#tou-link').html(window.sL.showTerms);
- $('#add-edit-language-link').html(window.sL.addEditLanguageLink);
- $('#shortcuts-link').html(window.sL.keyboardShortcuts);
- $('#invite-link').html(window.sL.inviteAFriend);
- $('#classic-link').html(window.sL.classicInterface);
- $('#edit-profile-header-link').html(window.sL.editMyProfile);
- $('#mini-logged-in-user-cog-wheel').attr('data-tooltip',window.sL.profileSettings);
- $('#accessibility-toggle-link').html(window.sL.accessibilityToggleLink);
- $('#settingslink .nav-session').attr('data-tooltip',window.sL.profileAndSettings);
- $('#top-compose').attr('data-tooltip',window.sL.compose);
- $('button.upload-image').attr('data-tooltip',window.sL.tooltipAttachFile);
- $('button.shorten').attr('data-tooltip',window.sL.tooltipShortenUrls);
- $('.reload-stream').attr('data-tooltip',window.sL.tooltipReloadStream);
- $('#clear-history').html(window.sL.clearHistory);
- $('#user-screen-name, #user-avatar, #user-name').attr('data-tooltip', window.sL.viewMyProfilePage);
- $('#top-menu-profile-link-view-profile').html(window.sL.viewMyProfilePage);
- $('#find-someone input').attr('placeholder',window.sL.findSomeone);
- $('#find-someone input').attr('data-tooltip',window.sL.findSomeoneTooltip);
- // show site body now
- $('#user-container').css('display','block');
- $('#feed').css('display','block');
- // logged in or not?
- if(window.loggedIn) {
- proceedLoggedIn();
- }
- else {
- proceedLoggedOut();
- }
- }
- /* ·
- ·
- · Stuff we do on load specifically for logged out users
- ·
- · · · · · · · · · · · · · */
- function proceedLoggedOut() {
- display_spinner();
- setNewCurrentStream(getStreamFromUrl(),true,false,function(){
- // $('input#nickname').focus(); --> maybe not a good idea on mobile?
- $('#page-container').css('opacity','1');
- });
- }
- /* ·
- ·
- · Stuff we do on load specifically for logged in users
- ·
- · · · · · · · · · · · · · */
- function proceedLoggedIn() {
- display_spinner();
- // get everyone we follow, block and our memberships and stor in global objects
- getAllFollowsMembershipsAndBlocks(function(){
- // 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)
- $('#queet-box').attr('data-cached-text',encodeURIComponent(localStorageObjectCache_GET('queetBoxInput','queet-box')));
- maybePrefillQueetBoxWithCachedText($('#queet-box'));
- });
- // load history
- loadHistoryFromLocalStorage();
- // show bookmarks
- appendAllBookmarks(window.qvitterProfilePrefs.bookmarks);
- // set stream
- setNewCurrentStream(getStreamFromUrl(),true,false,function(){
- $('.language-dropdown').css('display','none');
- $('#page-container').css('opacity','1');
- $('#search').fadeIn('slow');
- $('#settingslink .dropdown-toggle').fadeIn('slow');
- $('#top-compose').fadeIn('slow');
- $('input#nickname').blur();
- });
- }
- /* ·
- ·
- · 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);
- });
- }
- /* ·
- ·
- · In the login form, we want to check the remember-me-checkbox when its label is clicked
- ·
- · · · · · · · · · · · · · */
- $('#rememberme_label').click(function(){
- if($('#rememberme').prop('checked')) {
- $('#rememberme').prop('checked', false);
- }
- else {
- $('#rememberme').prop('checked', true);
- }
- });
- $('#rememberme_label').disableSelection();
- /* ·
- ·
- · 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();
- });
- }
- });
- /* ·
- ·
- · Logout
- ·
- · · · · · · · · · · · · · */
- $('#logout').click(function(){
- window.location.href =window.siteInstanceURL + 'main/logout';
- });
- /* ·
- ·
- · FAQ
- ·
- · · · · · · · · · · · · · */
- $('#faq-link').click(function(){
- popUpAction('popup-faq', window.siteTitle + ' ' + window.sL.FAQ,'<div id="faq-container"></div>',false);
- getDoc('faq',function(faqHtml){
- $('#faq-container').html(faqHtml);
- });
- });
- /* ·
- ·
- · Terms
- ·
- · · · · · · · · · · · · · */
- $('#tou-link,.tou-link').click(function(){
- popUpAction('popup-terms', window.sL.showTerms,'<div id="terms-container"></div>',false);
- if(window.customTermsOfUse) {
- $('#terms-container').html(window.customTermsOfUse);
- }
- else {
- getDoc('terms',function(termsHtml){
- $('#terms-container').html(termsHtml);
- });
- }
- });
- /* ·
- ·
- · Classic Link, toggle setting in api and redirect to /all
- ·
- · · · · · · · · · · · · · */
- $('#classic-link, #accessibility-toggle-link').click(function(){
- getFromAPI('qvitter/toggle_qvitter.json',function(data){
- if(data.success === true) {
- window.location.href = window.siteInstanceURL + window.loggedIn.screen_name + '/all';
- }
- });
- });
- /* ·
- ·
- · Handling the language dropdown selection
- ·
- · · · · · · · · · · · · · */
- $('.dropdown').click(function(){$(this).toggleClass('dropped')});
- $('.dropdown').disableSelection();
- $(document).bind('click', function (e) {
- 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')) {
- $('.dropdown').removeClass('dropped');
- $('.quitter-settings.dropdown-menu').removeClass('dropped');
- }
- });
- $('.language-link').click(function(){
- if(window.loggedIn === false) {
- var selectedForUser = 'logged_out';
- }
- else {
- var selectedForUser = window.loggedIn.id;
- }
- localStorageObjectCache_STORE('selectedLanguage',selectedForUser, $(this).attr('data-lang-code'));
- location.reload(); // reload
- });
- /* ·
- ·
- · Show the logo menu dropdown on click
- ·
- · · · · · · · · · · · · · */
- $('#settingslink').click(function(){
- removeAllTooltips();
- if(!$('.quitter-settings').hasClass('dropped')) { $('.quitter-settings').addClass('dropped'); }
- else { $('.quitter-settings').removeClass('dropped'); }
- });
- /* ·
- ·
- · 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');
- var userID = $(this).attr('data-user-id');
- var userScreenName = $(this).attr('data-screen-name');
- var silenced = $(this).hasClass('silenced');
- var sandboxed = $(this).hasClass('sandboxed');
- // menu
- var menuArray = [];
- // settings etc if it's me
- if(userID == window.loggedIn.id) {
- menuArray = loggedInUsersMenuArray();
- }
- // block etc if it not me
- 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)
- });
- }
- // 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'
- });
- // moderator actions
- menuArray = appendModeratorUserActionsToMenuArray(menuArray,userID,userScreenName,sandboxed,silenced);
- }
- 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');
- }
- });
- /* ·
- ·
- · 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
- }
- // hide
- else if($(this).hasClass('dropped')) {
- $(this).removeClass('dropped');
- $(this).children('.dropdown-menu').remove();
- }
- // show
- 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');
- }
- });
- /* ·
- ·
- · 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');
- 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');
- // menu
- var menuArray = [];
- // delete my notice, or others notices for mods with rights
- if(streamItemUserID == window.loggedIn.id || window.loggedIn.rights.delete_others_notice === true) {
- menuArray.push({
- type: 'function',
- functionName: 'deleteQueet',
- functionArguments: {
- streamItemID: streamItemID
- },
- label: window.sL.deleteVerb
- });
- }
- // block/unblock if it's not me
- if(streamItemUserID != window.loggedIn.id) {
- 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
- },
- label: window.sL.blockUser.replace('{username}',streamItemUsername)
- });
- }
- // 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'
- });
- }
- // moderator actions
- menuArray = appendModeratorUserActionsToMenuArray(menuArray,streamItemUserID,streamItemUsername,streamItemUserSandboxed,streamItemUserSilenced);
- // 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');
- }
- });
- /* ·
- ·
- · When clicking a function row in a stream menu – invoke the function
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.row-type-function',function(e){
- 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');
- var functionName = $(this).attr('data-function-name');
- if(typeof $(this).attr('data-function-arguments') == 'undefined' || $(this).attr('data-function-arguments') == 'undefined') {
- var functionArguments = false;
- }
- else {
- var functionArguments = JSON.parse($(this).attr('data-function-arguments'));
- }
- window[functionName](functionArguments, function(success){
- if(success) {
- thisFunctionRow.removeClass('clicked');
- }
- });
- });
- /* ·
- ·
- · 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');
- var prefLabel = thisToggle.attr('data-profile-prefs-label');
- var prefEnabledLabel = thisToggle.attr('data-profile-prefs-enabled-label');
- // 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');
- if(prefEnabledLabel != 'undefined') {
- thisToggle.html(prefEnabledLabel);
- }
- 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');
- if(prefEnabledLabel != 'undefined') {
- thisToggle.html(prefLabel);
- }
- window.qvitterProfilePrefs[prefTopic] = '0';
- }
- // 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')]();
- }
- }
- });
- });
- /* ·
- ·
- · 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');
- return;
- }
- }
- $('#feed-body').removeClass('embedded-content-hidden-by-user');
- }
- /* ·
- ·
- · 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');
- return;
- }
- }
- $('#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;
- }
- }
- $('#feed-body').removeClass('hide-notifications-from-muted-users')
- }
- /* ·
- ·
- · When clicking an external follow button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.external-follow-button',function(event){
- 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>');
- $('#popup-external-follow form input#profile').focus();
- $('#popup-external-follow button.primary').click(function(){
- $('#popup-external-follow form').submit();
- });
- });
- /* ·
- ·
- · When clicking an external join button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.external-member-button',function(event){
- 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>');
- $('#popup-external-join form input#profile').focus();
- $('#popup-external-join button.primary').click(function(){
- $('#popup-external-join form').submit();
- });
- });
- /* ·
- ·
- · When clicking a follow/block button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.qvitter-follow-button',function(event){
- 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;
- }
- // follow or unfollow?
- if($(this).hasClass('following')) {
- var followOrUnfollow = 'unfollow';
- }
- else {
- var followOrUnfollow = 'follow';
- }
- // 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);
- }
- }
- });
- return true;
- }
- // 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');
- }
- });
- });
- /* ·
- ·
- · When clicking a join group button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.member-button',function(event){
- if(!$(this).hasClass('disabled')) {
- $(this).addClass('disabled');
- // 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);
- // 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);
- }
- 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);
- // 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);
- }
- }
- }
- });
- }
- });
- /* ·
- ·
- · Go to profile page when clicking the small user header in left column
- ·
- · · · · · · · · · · · · · */
- $('#user-header').on('click',function(e){
- // not if we're clicking the mini-logged-in-user-cog-wheel
- if($(e.target).is('#mini-logged-in-user-cog-wheel')) {
- return;
- }
- setNewCurrentStream(pathToStreamRouter(window.loggedIn.screen_name),true,false);
- });
- /* ·
- ·
- · Searching
- ·
- · · · · · · · · · · · · · */
- $('#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() {
- var path = 'search/notice?q=' + encodeURIComponent(replaceHtmlSpecialChars($('#search-query').val()));
- setNewCurrentStream(pathToStreamRouter(path),true,false);
- }
- /* ·
- · <o
- · Hijack all links and look for local users, tags, searches and groups. (//
- ·
- · If found, select that stream and prevent links default behaviour
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','a', function(e) {
- // don't hijack if metakeys are pressed!
- if(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) {
- return;
- }
- // 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;
- }
- // don't hijack and don't follow link if this is the bookmark stream icon, prevent link but don't set a new currentstream
- if($(e.target).is('i.chev-right')) {
- e.preventDefault();
- return;
- }
- // don't hijack links with donthijack attribute
- if(!!$(this).attr('donthijack') || $(this).attr('donthijack') == '') {
- return;
- }
- // all links opens in new tab
- $(this).attr('target','_blank');
- // only proceed if we really have a href attribute
- if(typeof $(this).attr('href') == 'undefined') {
- return;
- }
- // 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);
- $('.hover-card,.hover-card-caret').remove();
- }
- }
- // hijack link if we find a matching link that qvitter can handle
- else {
- var hrefAttr = $(this).attr('href');
- // this might be a remote profile that we want to reroute to a local instance/user/id url, let's check our cache
- if(typeof window.convertStatusnetProfileUrlToUserArrayCacheKey[hrefAttr] != 'undefined') {
- if(typeof window.userArrayCache[window.convertStatusnetProfileUrlToUserArrayCacheKey[hrefAttr]] != 'undefined') {
- var cachedUserArray = window.userArrayCache[window.convertStatusnetProfileUrlToUserArrayCacheKey[hrefAttr]];
- if(cachedUserArray.local.is_local === false) {
- hrefAttr = window.siteInstanceURL + 'user/' + cachedUserArray.local.id;
- }
- }
- }
- else if(typeof window.convertUriToUserArrayCacheKey[hrefAttr] != 'undefined') {
- if(typeof window.userArrayCache[window.convertUriToUserArrayCacheKey[hrefAttr]] != 'undefined') {
- var cachedUserArray = window.userArrayCache[window.convertUriToUserArrayCacheKey[hrefAttr]];
- if(cachedUserArray.local.is_local === false) {
- hrefAttr = window.siteInstanceURL + 'user/' + cachedUserArray.local.id;
- }
- }
- }
- var streamObject = URLtoStreamRouter(hrefAttr);
- if(streamObject && streamObject.stream) {
- e.preventDefault();
- // if this is a user/{id} type link but we know the nickname already
- if(streamObject.name == 'profile by id' && streamObject.nickname !== false) {
- setNewCurrentStream(pathToStreamRouter(streamObject.nickname),true,streamObject.id);
- }
- // 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)
- else if(/^![a-zA-Z0-9]+$/.test($(e.target).text()) || /^[a-zA-Z0-9]+$/.test($(e.target).text())) {
- 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');
- }
- });
- }
- }
- // all other links that qvitter can handle
- else {
- setNewCurrentStream(streamObject,true,false);
- }
- }
- }
- });
- /* ·
- ·
- · When user clicks the bookmark icon to bookmark
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','#history-container .chev-right',function(event){
- 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){
- $(this).parent('.stream-selection').remove();
- saveAllBookmarks();
- });
- /* ·
- ·
- · When sorting the bookmark menu
- ·
- · · · · · · · · · · · · · */
- $('#bookmark-container').on("sortupdate", function() {
- saveAllBookmarks();
- });
- /* ·
- ·
- · When clearing the browsing history
- ·
- · · · · · · · · · · · · · */
- $('#clear-history').on('click', function() {
- $('#history-container').empty();
- updateHistoryLocalStorage();
- });
- /* ·
- ·
- · Load more from the current stream when scroll is 1000px from bottom
- ·
- · The search API is crap and don't do max_id and last_id, so we have to do pages there...
- ·
- · · · · · · · · · · · · · */
- $(window).scroll(function() {
- if($(window).scrollTop() + $(window).height() > $(document).height() - 1000) {
- // not if we're already loading or if no stream is set yet
- if(!$('body').hasClass('loading-older') && typeof window.currentStreamObject != "undefined" && $('#feed-body').attr('data-end-reached') != 'true') {
- $('body').addClass('loading-older');
- // remove loading class in 10 seconds, i.e. try again if failed to load within 10 s
- if(window.currentStreamObject.name != 'search') {
- setTimeout(function(){$('body').removeClass('loading-older');},10000);
- }
- var lastStreamItemId = $('#feed-body').children('.stream-item').last().attr('id');
- // 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') {
- if(typeof $('#feed-body').attr('data-search-page-number') != 'undefined') {
- var searchPage = parseInt($('#feed-body').attr('data-search-page-number'),10);
- }
- else {
- var searchPage=2;
- }
- var nextPage = searchPage+1;
- 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
- }
- // normal streams
- else {
- var getVars = qOrAmp(window.currentStreamObject.stream) + 'max_id=' + ($('#feed-body').children('.stream-item').last().attr('data-quitter-id-in-stream'));
- }
- display_spinner('#footer-spinner-container');
- getFromAPI(window.currentStreamObject.stream + getVars,function(data){
- // 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) {
- addToFeed(data, lastStreamItemId,'visible');
- $('body').removeClass('loading-older');
- // if this is search our group users lists, we remember page number (if we got any users)
- if(window.currentStreamObject.maxIdOrPage == 'page') {
- $('#feed-body').attr('data-search-page-number',nextPage);
- }
- }
- remove_spinner();
- });
- }
- }
- });
- /* ·
- ·
- · Updates all queets' times/dates
- ·
- · · · · · · · · · · · · · */
- var updateTimesInterval=self.setInterval(function(){
- updateAllQueetsTimes();
- },10000);
- /* ·
- ·
- · Check for new queets
- ·
- · · · · · · · · · · · · · */
- 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');
- // only if logged in and only for notice or notification streams
- if(window.loggedIn && (window.currentStreamObject.type == 'notices' || window.currentStreamObject.type == 'notifications')) {
- 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;
- getFromAPI(addThisStream + qOrAmp(window.currentStreamObject.stream) + 'since_id=' + lastId,function(data){
- $('body').removeClass('loading-newer');
- if(data) {
- if(addThisStream == window.currentStreamObject.stream) {
- addToFeed(data, false, 'hidden');
- // say hello to the api if this is notifications stream, to
- // get correct unread notifcation count
- if(window.currentStreamObject.name == 'notifications') {
- helloAPI();
- }
- // if we have hidden items, show new-queets-bar
- maybeShowTheNewQueetsBar()
- }
- }
- });
- }
- }
- }
- /* ·
- ·
- · Show hidden queets when user clicks on new-queets-bar
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','#new-queets-bar',function(){
- if(window.currentStreamObject.name == 'notifications') {
- document.title = window.siteTitle;
- }
- var hiddenStreamItems = $('.stream-item.hidden');
- hiddenStreamItems.css('opacity','0')
- hiddenStreamItems.animate({opacity:'1'}, 200);
- hiddenStreamItems.addClass('visible');
- hiddenStreamItems.removeClass('hidden');
- $('#new-queets-bar').parent().addClass('hidden');
- // say hello to the api if this is notifications stream, to
- // get correct unread notifcation count
- if(window.currentStreamObject.name == 'notifications') {
- helloAPI();
- }
- });
- /* ·
- ·
- · Expand and de-expand queets when clicking anywhere but on a few element types
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.queet',function (event) {
- if(typeof $(this).attr('href') == 'undefined'
- && $(event.target).closest('a').length == 0
- && !$(event.target).is('\
- 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,\
- .screen-name,\
- .discard-error-message')
- && !$(this).parent('.stream-item').hasClass('user')) { // not if user stream
- expand_queet($(this).parent());
- }
- });
- /* ·
- ·
- · Image popups
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.stream-item .queet img.attachment-thumb',function (event) {
- event.preventDefault();
- // 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 {
- var thisAttachmentThumbSrc = $(this).attr('src');
- var parentStreamItem = $(this).closest('.stream-item');
- var $parentStreamItemClone = $('<div/>').append(parentStreamItem.outerHTML());
- var $queetThumbsClone = $('<div/>').append($parentStreamItemClone.children('.stream-item').children('.queet').find('.queet-thumbs').outerHTML());
- // cleaned version of the stream item to show in the footer
- cleanStreamItemsFromClassesAndConversationElements($parentStreamItemClone);
- $parentStreamItemClone.find('.context,.stream-item-footer').remove();
- var parentStreamItemHTMLWithoutFooter = $parentStreamItemClone.outerHTML();
- $thumbToDisplay = $queetThumbsClone.find('img.attachment-thumb[src="' + thisAttachmentThumbSrc + '"]');
- $thumbToDisplay.parent().addClass('display-this-thumb');
- // "play" all animated gifs and add youtube iframes to all youtube and vimeo videos
- $.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') + '\')');
- }
- 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>');
- }
- });
- // navigation buttons
- var imgNum = parentStreamItem.children('.queet').find('.attachment-thumb').length;
- if(imgNum > 1) {
- $queetThumbsClone.find('.queet-thumbs').before('<div class="prev-thumb"></div>');
- $queetThumbsClone.find('.queet-thumbs').after('<div class="next-thumb"></div>');
- }
- if(parentStreamItem.hasClass('expanded')) {
- var calculatedDimensions = calculatePopUpAndImageDimensions($thumbToDisplay);
- var $thisImgInQueetThumbsClone = $queetThumbsClone.find('img[src="' + $thumbToDisplay.attr('src') + '"]');
- // set dimensions
- $thisImgInQueetThumbsClone.width(calculatedDimensions.displayImgWidth);
- $thisImgInQueetThumbsClone.parent('.thumb-container').width(calculatedDimensions.displayImgWidth);
- $thisImgInQueetThumbsClone.parent('.thumb-container').children('iframe').attr('width',calculatedDimensions.displayImgWidth);
- $thisImgInQueetThumbsClone.parent('.thumb-container').children('iframe').attr('height',calculatedDimensions.displayImgHeight);
- // open popup
- popUpAction('queet-thumb-popup', '', '' + $queetThumbsClone.outerHTML() + '', parentStreamItemHTMLWithoutFooter, calculatedDimensions.popUpWidth);
- disableOrEnableNavigationButtonsInImagePopup($('#queet-thumb-popup'));
- // 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);
- }
- }
- });
- // popups can be max 900px wide, and should not be higher than the window, so we need to do some calculating
- function calculatePopUpAndImageDimensions(img) {
- var img_src = img.attr('src');
- // 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();
- var imgHeight = $('#img-dimension-check img').height();
- $('#img-dimension-check').remove();
- // e.g. svg's may not have dimensions set, in that case we just make them small
- if(typeof imgWidth == 'undefined' && typeof imgHeight == 'undefined') {
- return {popUpWidth: 540, displayImgWidth: 540};
- }
- var thisImgWidth = parseInt(imgWidth,10);
- var thisImgHeight = parseInt(imgHeight,10);
- var maxImageHeight = $(window).height() - 120; // 120 being a little more than a short queet in the footer
- if(thisImgWidth < 540) {
- var displayImgWidth = thisImgWidth;
- var popUpWidth = 540;
- if(thisImgHeight > maxImageHeight) {
- displayImgWidth = Math.round(maxImageHeight/thisImgHeight*displayImgWidth);
- }
- }
- else if(thisImgWidth < 900) {
- var displayImgWidth = thisImgWidth;
- if(thisImgHeight > maxImageHeight) {
- displayImgWidth = Math.round(maxImageHeight/thisImgHeight*displayImgWidth);
- if(displayImgWidth < 540) {
- var popUpWidth = 540;
- }
- else {
- var popUpWidth = displayImgWidth;
- }
- }
- else {
- var popUpWidth = displayImgWidth;
- }
- }
- else {
- var displayImgWidth = 900;
- var displayImgHeight = 900/thisImgWidth*thisImgHeight;
- if(displayImgHeight > maxImageHeight) {
- displayImgWidth = Math.round(maxImageHeight*displayImgWidth/displayImgHeight);
- if(displayImgWidth < 540) {
- var popUpWidth = 540;
- }
- else if(displayImgWidth < 900) {
- var popUpWidth = displayImgWidth;
- }
- else {
- var popUpWidth = 900;
- }
- }
- else {
- var popUpWidth = 900;
- }
- }
- // 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 };
- }
- // switch to next image when clicking the image in the popup
- $('body').on('click','#queet-thumb-popup .attachment-thumb',function (event) {
- event.preventDefault();
- var nextImage = $(this).parent().next().children('.attachment-thumb');
- if(nextImage.length>0) {
- // start and stop youtube videos, if any
- $.each($(this).parent('.host-youtube-com').children('iframe'),function(){
- this.contentWindow.postMessage('{"event":"command","func":"' + 'stopVideo' + '","args":""}', '*');
- });
- $.each(nextImage.parent('.host-youtube-com').children('iframe'),function(){
- this.contentWindow.postMessage('{"event":"command","func":"' + 'playVideo' + '","args":""}', '*');
- });
- // 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"}', '*');
- });
- // set dimensions of next image and the popup
- var calculatedDimensions = calculatePopUpAndImageDimensions(nextImage);
- nextImage.width(calculatedDimensions.displayImgWidth);
- nextImage.parent('.thumb-container').width(calculatedDimensions.displayImgWidth);
- nextImage.parent('.thumb-container').children('iframe').attr('width',calculatedDimensions.displayImgWidth);
- nextImage.parent('.thumb-container').children('iframe').attr('height',calculatedDimensions.displayImgHeight);
- $('#queet-thumb-popup .modal-draggable').width(calculatedDimensions.popUpWidth);
- // switch image
- $(this).parent().removeClass('display-this-thumb');
- $(this).parent().next().addClass('display-this-thumb');
- disableOrEnableNavigationButtonsInImagePopup($('#queet-thumb-popup'));
- centerPopUp($('#queet-thumb-popup .modal-draggable'));
- }
- });
- // 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) {
- // start and stop youtube videos, if any
- $.each($(this).parent().find('.display-this-thumb.host-youtube-com').children('iframe'),function(){
- this.contentWindow.postMessage('{"event":"command","func":"' + 'stopVideo' + '","args":""}', '*');
- });
- $.each(prevImage.parent('.host-youtube-com').children('iframe'),function(){
- this.contentWindow.postMessage('{"event":"command","func":"' + 'playVideo' + '","args":""}', '*');
- });
- // 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"}', '*');
- });
- // set dimensions of next image and the popup
- var calculatedDimensions = calculatePopUpAndImageDimensions(prevImage);
- prevImage.width(calculatedDimensions.displayImgWidth);
- prevImage.parent('.thumb-container').width(calculatedDimensions.displayImgWidth);
- prevImage.parent('.thumb-container').children('iframe').attr('width',calculatedDimensions.displayImgWidth);
- prevImage.parent('.thumb-container').children('iframe').attr('height',calculatedDimensions.displayImgHeight);
- $('#queet-thumb-popup .modal-draggable').width(calculatedDimensions.popUpWidth);
- // switch image
- $(this).parent().find('.display-this-thumb').removeClass('display-this-thumb');
- prevImage.parent().addClass('display-this-thumb');
- disableOrEnableNavigationButtonsInImagePopup($('#queet-thumb-popup'));
- centerPopUp($('#queet-thumb-popup .modal-draggable'));
- }
- });
- function disableOrEnableNavigationButtonsInImagePopup(popUp) {
- if(popUp.find('.display-this-thumb').prev().length < 1) {
- popUp.find('.prev-thumb').addClass('disabled');
- }
- else {
- popUp.find('.prev-thumb').removeClass('disabled');
- }
- if(popUp.find('.display-this-thumb').next().length < 1) {
- popUp.find('.next-thumb').addClass('disabled');
- }
- else {
- popUp.find('.next-thumb').removeClass('disabled');
- }
- }
- /* ·
- ·
- · Collapse all open conversations and the welcome text on esc or when clicking the margin
- ·
- · · · · · · · · · · · · · */
- $('body').click(function(event){
- if($(event.target).is('body') || $(event.target).is('#page-container')) {
- $('.front-welcome-text.expanded > .show-full-welcome-text').trigger('click');
- $.each($('.stream-item.expanded'),function(){
- expand_queet($(this), false);
- });
- }
- });
- $(document).keyup(function(e){
- if(e.keyCode==27) { // esc
- $('.front-welcome-text.expanded > .show-full-welcome-text').trigger('click');
- $.each($('.stream-item.expanded'),function(){
- expand_queet($(this), false);
- });
- }
- });
- /* ·
- ·
- · When clicking the delete-button
- ·
- · · · · · · · · · · · · · */
- function deleteQueet(arg) {
- var this_stream_item = $('.stream-item[data-quitter-id="' + arg.streamItemID + '"]');
- // don't do anything if this is a queet being posted
- if(this_stream_item.hasClass('temp-post')) {
- return;
- }
- var this_qid = this_stream_item.attr('data-quitter-id');
- 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();
- 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>');
- $('#popup-delete-' + this_qid + ' button.primary').on('click',function(){
- display_spinner();
- $('.modal-container').remove();
- // delete
- postActionToAPI('statuses/destroy/' + this_qid + '.json', function(data) {
- if(data) {
- remove_spinner();
- window.knownDeletedNotices[$('.stream-item[data-quitter-id="' + this_qid + '"]').attr('data-uri')] = true;
- slideUpAndRemoveStreamItem($('.stream-item[data-quitter-id="' + this_qid + '"]'));
- }
- else {
- remove_spinner();
- }
- });
- });
- }
- /* ·
- ·
- · When clicking the requeet-button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.action-rt-container .icon:not(.is-mine)',function(){
- var this_stream_item = $(this).closest('.stream-item');
- var this_queet = this_stream_item.children('.queet');
- var this_action = $(this).closest('li');
- // requeet
- if(!this_action.children('.with-icn').hasClass('done')) {
- // 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);
- this_queet.find('.action-rq-num').attr('data-rq-num',newRqNum);
- this_action.children('.with-icn').addClass('done');
- this_stream_item.addClass('requeeted');
- // requeet animation
- 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);
- // 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);
- getFavsAndRequeetsForQueet(this_stream_item, this_stream_item.attr('data-quitter-id'));
- // mark all instances of this notice as repeated
- $('.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');
- }
- else {
- // error
- this_action.children('.with-icn').removeClass('done');
- this_action.find('.with-icn b').html(window.sL.requeetVerb);
- this_stream_item.removeClass('requeeted');
- }
- });
- }
- // un-requeet
- else if(this_action.children('.with-icn').hasClass('done')) {
- display_spinner();
- 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');
- 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');
- }
- });
- }
- });
- /* ·
- ·
- · When clicking the fav-button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.action-fav-container',function(){
- var this_stream_item = $(this).closest('.stream-item');
- var this_queet = this_stream_item.children('.queet');
- // don't do anything if this is a queet being posted
- if(this_stream_item.hasClass('temp-post')) {
- return;
- }
- var this_action = $(this);
- // fav
- if(!this_action.children('.with-icn').hasClass('done')) {
- // 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);
- this_queet.find('.action-fav-num').attr('data-fav-num',newFavNum);
- this_action.children('.with-icn').addClass('done');
- this_stream_item.addClass('favorited');
- // fav animation
- this_action.children('.with-icn').children('.sm-fav').addClass('pulse');
- // 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
- postActionToAPI('favorites/create/' + this_stream_item.attr('data-quitter-id') + '.json', function(data) {
- if(data) {
- // success
- getFavsAndRequeetsForQueet(this_stream_item, this_stream_item.attr('data-quitter-id'));
- // mark all instances of this notice as favorited
- $('.stream-item[data-quitter-id="' + this_stream_item.attr('data-quitter-id') + '"]').addClass('favorited');
- $('.stream-item[data-quitter-id="' + this_stream_item.attr('data-quitter-id') + '"]').children('.queet').find('.action-fav-container').children('.with-icn').addClass('done');
- }
- else {
- // error
- this_action.children('.with-icn').removeClass('done');
- this_action.find('.with-icn b').html(window.sL.favoriteVerb);
- this_stream_item.removeClass('favorited');
- }
- });
- }
- // unfav
- else {
- // 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);
- this_queet.find('.action-fav-num').attr('data-fav-num',newFavNum);
- this_action.children('.with-icn').removeClass('done');
- this_action.find('.with-icn b').html(window.sL.favoriteVerb);
- this_stream_item.removeClass('favorited');
- // 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 unfav
- postActionToAPI('favorites/destroy/' + this_stream_item.attr('data-quitter-id') + '.json', function(data) {
- if(data) {
- // success
- getFavsAndRequeetsForQueet(this_stream_item, this_stream_item.attr('data-quitter-id'));
- // mark all instances of this notice as non-favorited
- $('.stream-item[data-quitter-id="' + this_stream_item.attr('data-quitter-id') + '"]').removeClass('favorited');
- $('.stream-item[data-quitter-id="' + this_stream_item.attr('data-quitter-id') + '"]').children('.queet').find('.action-fav-container').children('.with-icn').removeClass('done');
- }
- else {
- // error
- this_action.children('.with-icn').addClass('done');
- this_action.find('.with-icn b').html(window.sL.favoritedVerb);
- this_stream_item.addClass('favorited');
- }
- });
- }
- });
- /* ·
- ·
- · When clicking the reply-button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.action-reply-container',function(){
- var this_stream_item = $(this).closest('.stream-item');
- // don't do anything if this is a queet being posted
- if(this_stream_item.hasClass('temp-post')) {
- return;
- }
- var this_stream_item_id = this_stream_item.attr('data-quitter-id');
- this_stream_item.addClass('replying-to');
- // 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);
- $('#popup-reply-' + this_stream_item_id).find('.modal-body').find('.queet-box').trigger('click'); // expand
- // fix the width of the queet box, otherwise the syntax highlighting break
- 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);
- maybePrefillQueetBoxWithCachedText(queetBox.children('.queet-box'));
- });
- /* ·
- ·
- · When clicking the compose button
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','#top-compose',function(){
- popUpAction('popup-compose', window.sL.compose,queetBoxPopUpHtml(),false);
- 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);
- $('#popup-compose').find('.queet-box').trigger('click');
- maybePrefillQueetBoxWithCachedText($('#popup-compose').find('.queet-box'));
- });
- /* ·
- ·
- · Close popups
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.modal-container button.close',function(){
- $('.stream-item').removeClass('replying-to');
- $('.modal-container').remove();
- });
- $('body').on('click','.modal-close',function(){
- $('.stream-item').removeClass('replying-to');
- $('.modal-container').remove();
- });
- $('body').on('click','.modal-container',function(e){
- if($(e.target).is('.modal-container')) {
- $('.stream-item').removeClass('replying-to');
- $('.modal-container').remove();
- abortEditProfile();
- }
- });
- $(document).keyup(function(e){
- if(e.keyCode==27) {
- $('.stream-item').removeClass('replying-to');
- $('.modal-container').remove();
- $('*').blur();
- abortEditProfile();
- }
- });
- /* ·
- ·
- · Post queets, inline and popup replies
- ·
- · · · · · · · · · · · · · */
- $('body').on('click', '.queet-toolbar button',function () {
- if($(this).hasClass('enabled')) {
- // set temp post id
- if($('.temp-post').length == 0) {
- var tempPostId = 'stream-item-temp-post-i';
- }
- else {
- var tempPostId = $('.temp-post').attr('id') + 'i';
- }
- var queetBox = $(this).parent().parent().siblings('.queet-box');
- var queetBoxID = queetBox.attr('id');
- // 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.
- // In firefox (and maybe some other browsers), queetBox.html() may have <div>s
- // and may or may not have <br> in them.
- // To deal with this, remove any <br>s right before </div> and then add ones.
- queetBox.html(queetBox.html().replace(/(<br>)*<\/div>/g, '<br></div>').replace(/({|})/g, '!$1').replace(/<br>/g, '{{{lb}}}'));
- var queetText = $.trim(queetBox.text().replace(/^\s+|\s+$/g, '').replace(/\n/g, ''));
- queetText = queetText.replace(/{{{lb}}}/g, "\n").replace(/!({|})/g, '$1');
- var queetTempText = replaceHtmlSpecialChars(queetText.replace(/\n/g,'<br>')); // no xss
- queetTempText = queetTempText.replace(/<br>/g,'<br>'); // but preserve line breaks
- 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>';
- queetHtml = detectRTL(queetHtml);
- // 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');
- }
- // not a reply
- else {
- var in_reply_to_status_id = false;
- }
- // remove any popups
- $('.modal-container').remove();
- // try to find a queet to add the temp queet to:
- var tempQueetInsertedInConversation = false;
- // if the queet is in conversation, add it to parent's conversation
- if($('.stream-item.replying-to').length > 0 && $('.stream-item.replying-to').hasClass('conversation')) {
- var insertedTempQueet = $(queetHtml).appendTo($('.stream-item.replying-to').parent());
- 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
- tempQueetInsertedInConversation = true;
- }
- // if the queet is expanded, add it to its conversation
- else if($('.stream-item.replying-to').length > 0 && $('.stream-item.replying-to').hasClass('expanded')) {
- var insertedTempQueet = $(queetHtml).appendTo($('.stream-item.replying-to'));
- 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
- tempQueetInsertedInConversation = true;
- }
- // maybe the replying-to class is missing but we still have a suiting place to add it
- else if($('.stream-item.expanded[data-quitter-id="' + in_reply_to_status_id + '"]').length > 0) {
- var insertedTempQueet = $(queetHtml).appendTo($('.stream-item.expanded[data-quitter-id="' + in_reply_to_status_id + '"]'));
- 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
- tempQueetInsertedInConversation = true;
- }
- // if we can't find a proper place, add it to top and remove conversation class
- // if this is either 1) our home/all feed, 2) our user timeline or 3) whole site or 4) whole network
- else if(window.currentStreamObject.name == 'friends timeline'
- || window.currentStreamObject.name == 'my profile'
- || window.currentStreamObject.name == 'public timeline'
- || window.currentStreamObject.name == 'public and external timeline') {
- var insertedTempQueet = $(queetHtml).prependTo('#feed-body');
- insertedTempQueet.removeClass('conversation');
- }
- // don't add it to the current stream, open a popup instead, without conversation class
- else {
- popUpAction('popup-sending','','',false);
- var insertedTempQueet = $(queetHtml).prependTo($('#popup-sending').find('.modal-body'));
- insertedTempQueet.removeClass('conversation');
- }
- // 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();
- // remove any replying-to classes
- $('.stream-item').removeClass('replying-to');
- // null reply box
- collapseQueetBox(queetBox);
- // check for new queets (one second from) NOW
- setTimeout('checkForNewQueets()', 1000);
- // post queet
- postQueetToAPI(queetText, in_reply_to_status_id, postToGroups, function(data){ if(data) {
- 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 {
- 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')));
- }
- }
- }
- }
- // remove temp queet
- insertedTempQueet.remove();
- // clear queetbox input cache
- localStorageObjectCache_STORE('queetBoxInput',queetBox.attr('id'),false);
- // queet count
- $('#user-queets strong').html(parseInt($('#user-queets strong').html(),10)+1);
- // fadeout any posting-popups
- setTimeout(function(){
- $('#popup-sending').fadeOut(1000, function(){
- $('#popup-sending').remove();
- });
- },100);
- }});
- }
- });
- /* ·
- ·
- · Count chars in queet box on keyup, also check for any attachments to show/hide
- ·
- · · · · · · · · · · · · · */
- $('body').on('keyup input paste','.queet-box-syntax',function () {
- countCharsInQueetBox($(this),$(this).siblings('.queet-toolbar').find('.queet-counter'),$(this).siblings('.queet-toolbar').find('.queet-button button'));
- 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();
- }
- });
- });
- /* ·
- ·
- · Middle button expands queet box
- ·
- · · · · · · · · · · · · · */
- $('body').on('mousedown','.queet-box-syntax',function (e) {
- if( e.which == 2 ) {
- e.preventDefault();
- $(this).trigger('click');
- }
- });
- /* ·
- ·
- · Shorten URL's
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','button.shorten',function () {
- shortenUrlsInBox($(this));
- });
- /* ·
- ·
- · Reload current stream
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.reload-stream',function () {
- reloadCurrentStream();
- });
- // can be used a callback too, e.g. from profile pref toggles
- function reloadCurrentStream() {
- setNewCurrentStream(URLtoStreamRouter(window.location.href),false,false,false);
- }
- /* ·
- ·
- · Reload current stream and clear cache
- ·
- · · · · · · · · · · · · · */
- function reloadCurrentStreamAndClearCache() {
- $('#feed-body').empty();
- rememberStreamStateInLocalStorage();
- // reload
- reloadCurrentStream();
- }
- /* ·
- ·
- · Expand/collapse queet box on click and blur
- ·
- · · · · · · · · · · · · · */
- $('body').on('click contextmenu','.queet-box-syntax',function () {
- if($(this).html() == decodeURIComponent($(this).attr('data-start-text'))) {
- $(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'));
- $(this)[0].addEventListener("paste", stripHtmlFromPaste);
- if(typeof $(this).attr('data-replies-text') != 'undefined') {
- $(this).html(decodeURIComponent($(this).attr('data-replies-text')));
- var repliesLen = decodeURIComponent($(this).attr('data-replies-text')).replace(' ',' ').length;
- setSelectionRange($(this)[0], repliesLen, repliesLen);
- }
- else {
- $(this).html('');
- }
- $(this).trigger('input');
- $(this).closest('.stream-item').addClass('replying-to');
- }
- });
- $('body').on('mousedown','.syntax-two',function () {
- $(this).addClass('clicked');
- });
- $('body').on('blur','.queet-box-syntax',function (e) {
- // empty the mention suggestions on blur, timeout because we want to capture clicks in .mentions-suggestions
- setTimeout(function(){
- $(this).siblings('.mentions-suggestions').empty();
- },10);
- // 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');
- return true;
- }
- // 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;
- }
- // don't collapse if we're clicking around inside queet-box
- var syntaxTwoBox = $(this).siblings('.syntax-two');
- if(syntaxTwoBox.hasClass('clicked')) {
- syntaxTwoBox.removeClass('clicked');
- return true;
- }
- // don't collapse if we're in a modal
- if($(this).parent().parent().hasClass('modal-body')) {
- return true;
- }
- // collapse if nothing is change
- if($(this).attr('data-replies-text') != 'undefined') {
- 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>') {
- collapseQueetBox($(this));
- }
- }
- // collapse if empty
- else if($(this).html().length == 0 || $(this).html() == '<br>' || $(this).html() == '<br />' || $(this).html() == ' ' || $(this).html() == ' <br>') {
- collapseQueetBox($(this));
- }
- });
- function collapseQueetBox(qB) {
- qB.closest('.stream-item').removeClass('replying-to');
- qB.siblings('.upload-image-container').remove();
- 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');
- qB.html(decodeURIComponent(qB.attr('data-start-text')));
- qB.siblings('.queet-toolbar').find('button').removeClass('enabled');
- qB.siblings('.queet-toolbar').css('display','none');
- qB.removeAttr('style');
- qB[0].removeEventListener("paste", stripHtmlFromPaste);
- }
- /* ·
- ·
- · Syntax highlighting in queetbox
- ·
- · · · · · · · · · · · · · */
- // transfer focus and position/selection to background div
- $('body').on('mouseup', 'div.syntax-two', function(e){
- // 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
- }
- }
- else {
- $(this).removeClass('clicked');
- var caretPos = getSelectionInElement($(this)[0]);
- var thisQueetBox = $(this).siblings('div.queet-box-syntax');
- thisQueetBox.focus();
- setSelectionRange(thisQueetBox[0], caretPos[0], caretPos[1]);
- // fixes problem with caret not showing after delete, unfocus and refocus
- if(thisQueetBox.html() == '<br>') {
- thisQueetBox.html(' ');
- }
- }
- });
- // strip html from paste
- function stripHtmlFromPaste(e) {
- e.preventDefault();
- var text = replaceHtmlSpecialChars(e.clipboardData.getData("text/plain"));
- text = text.replace(/\n/g,'<br>').replace(/\t/g, ' '); // keep line-breaks and tabs
- document.execCommand("insertHTML", false, text);
- }
- // sync divs
- $('body').on('keyup paste input', 'div.queet-box-syntax', function() {
- var currentVal = $(this).html();
- currentVal = currentVal.replace(/<br>$/, '').replace(/ $/, '').replace(/ $/, ''); // fix
- $(this).siblings('.syntax-two').html(currentVal);
- // If user click post area before load finished (top gnu logo), this is undefined.
- if (!window.syntaxHighlightingRegexps) {
- window.syntaxHighlightingRegexps = Object();
- }
- // loop through the regexps and highlight
- $.each(window.syntaxHighlightingRegexps,function(k,v){
- 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
- var currentMatch = currentVal.match(v);
- // 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 {
- // don't include ending char, if any of these (but tags can contain and end with . and -)
- if(currentMatch[0].slice(-1) == '<'
- || currentMatch[0].slice(-1) == '&'
- || currentMatch[0].slice(-1) == '?'
- || currentMatch[0].slice(-1) == '!'
- || currentMatch[0].slice(-1) == ' '
- || (currentMatch[0].slice(-1) == '-' && k != 'tag')
- || currentMatch[0].slice(-1) == ':'
- || (currentMatch[0].slice(-1) == '.' && k != 'tag')
- || currentMatch[0].slice(-1) == ','
- || currentMatch[0].slice(-1) == ')'
- || currentMatch[0].slice(-1) == '\'') {
- currentMatch[0] = currentMatch[0].slice(0,-1);
- }
- // don't include these start strings
- if(currentMatch[0].substring(0,1) == ' '
- || currentMatch[0].substring(0,1) == '(') {
- currentMatch[0] = currentMatch[0].substring(1);
- }
- else if(currentMatch[0].substring(0,6) == ' ') {
- currentMatch[0] = currentMatch[0].substring(6);
- }
- currentVal = currentVal.replace(currentMatch[0],'<span class="' + k + '">' + currentMatch[0].replace('#','#').replace('@','@').replace('.','.').replace('!','!') + '</span>')
- }
- i++;
- }
- });
- // safari fix
- if(typeof bowser.safari != 'undefined') {
- currentVal = currentVal.replace(/ <span/g,' <span');
- }
- $(this).siblings('.syntax-middle').html(currentVal);
- });
- /* ·
- ·
- · Auto suggest mentions in queet-box
- ·
- · · · · · · · · · · · · · */
- // 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(){
- $(this).removeClass('selected');
- });
- $('body').on('click', '.mentions-suggestions > div', function(){
- $(this).parent().siblings('.queet-box-syntax').focus();
- $(this).siblings().removeClass('selected');
- $(this).addClass('selected');
- useSelectedMention($(this).parent().siblings('.queet-box-syntax'));
- });
- // navigate in mentions with keyboard
- $('body').on('keydown', '.queet-box-syntax', function(e) {
- if($(this).siblings('.mentions-suggestions').children('div').length > 0) {
- // enter or tab
- if (!e.ctrlKey && (e.keyCode == '13' || e.keyCode == '9')) {
- e.preventDefault();
- useSelectedMention($(this));
- }
- // downkey
- else if (e.keyCode == '40') {
- e.preventDefault();
- 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 {
- $(this).siblings('.mentions-suggestions').children('div').first().addClass('selected');
- }
- }
- // upkey
- else if (e.keyCode == '38') {
- e.preventDefault();
- 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 {
- $(this).siblings('.mentions-suggestions').children('div').last().addClass('selected');
- }
- }
- }
- });
- function useSelectedMention(queetBox){
- // use selected
- if(queetBox.siblings('.mentions-suggestions').children('div.selected').length > 0) {
- var selectedSuggestion = queetBox.siblings('.mentions-suggestions').children('div.selected');
- }
- // if none selected, take top suggestion
- else {
- 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>');
- }
- }
- // 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);
- range.insertNode(document.createTextNode(username + '\u00a0')); // non-breaking-space, to prevent collapse
- // put caret after
- setSelectionRange(queetBox[0], window.lastMention.mentionPos+username.length+2, window.lastMention.mentionPos+username.length+2);
- queetBox.siblings('.mentions-suggestions').empty();
- queetBox.trigger('input'); // avoid some flickering
- }
- // check for removed group mentions
- $('body').on('keyup', 'div.queet-box-syntax', function(e) {
- var groupMentions = $(this).siblings('.post-to-group');
- var queetBoxGroups = $(this).siblings('.syntax-middle').find('.group');
- var queetBoxGroupsString = '';
- $.each(queetBoxGroups,function(){
- queetBoxGroupsString = queetBoxGroupsString + $(this).html() + ':';
- });
- $.each(groupMentions,function(){
- if(queetBoxGroupsString.indexOf('!' + $(this).data('group-username') + ':') == -1) {
- $(this).remove();
- }
- });
- });
- window.lastMention = new Object();
- // check for user mentions
- $('body').on('keyup', 'div.queet-box-syntax', function(e) { checkMentions(e, true);});
- // check for group mentions
- $('body').on('keyup', 'div.queet-box-syntax', function(e) { checkMentions(e, false);});
- /**
- * check for user/group mentions
- *
- * @param {Object} e: Event object
- * @param {boolean} isUser
- */
- function checkMentions(e, isUser) {
- var mark = '!';
- var prefix = 'group';
- if (isUser) {
- mark = '@';
- prefix = 'user';
- }
- // var queetBox = $(this);
- var queetBox = $('body div.queet-box-syntax');
- var cursorPosArray = getSelectionInElement(queetBox[0]);
- var cursorPos = cursorPosArray[0];
- if(e.keyCode != '40' && e.keyCode != '38' && e.keyCode != '13' && e.keyCode != '9') {
- var contents = queetBox.text().substring(0,cursorPos);
- var mentionPos = contents.lastIndexOf(mark);
- var check_contents = contents.substring(mentionPos - 1, cursorPos);
- var regex = new RegExp('(^|\s|\.|\n)(' + mark + ')[a-zA-Z0-9]+');
- var match = check_contents.match(regex);
- if (contents.indexOf(mark) >= 0 && match) {
- if(contents.lastIndexOf(mark) > 1) {
- match[0] = match[0].substring(1,match[0].length);
- }
- if((contents.lastIndexOf(mark)+match[0].length) == cursorPos) {
- queetBox.siblings('.mentions-suggestions').children('.' + prefix + '-suggestion').remove();
- queetBox.siblings('.mentions-suggestions').css('top',(queetBox.height()+20) + 'px');
- var term = match[0].substring(match[0].lastIndexOf(mark)+1, match[0].length).toLowerCase();
- window.lastMention.mentionPos = mentionPos;
- window.lastMention.cursorPos = cursorPos;
- // see if any user/group we're following matches
- var suggestionsToShow = [];
- var suggestionsUsernameCount = {};
- if (isUser) {
- suggestionsUsernameCount[window.loggedIn.screen_name] = 1; // any suggestions with the same screen name as mine will get their server url added
- }
- var targets = isUser ? (window.following) : (window.groupMemberships);
- $.each(targets, function(){
- var userregex = new RegExp(term);
- if(this.username.toLowerCase().match(userregex) || this.name.toLowerCase().match(userregex)) {
- var suggestion = {avatar:this.avatar, name:this.name, username:this.username,url:this.url};
- if (!isUser) {
- suggestion.id = this.id;
- }
- suggestionsToShow.push(suggestion);
- // 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 = isUser ? ('@' + this.url) : (this.url + '/group/');
- }
- if (isUser) {
- 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').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>')
- }
- });
- }
- else {
- queetBox.siblings('.mentions-suggestions').children('.' + prefix + '-suggestion').remove();
- }
- }
- else {
- queetBox.siblings('.mentions-suggestions').children('.' + prefix + '-suggestion').remove();
- }
- }
- }
- /* ·
- ·
- · Any click empties the mentions-suggestions
- ·
- · · · · · · · · · · · · · */
- $(document).click(function() {
- $('.mentions-suggestions').empty();
- });
- /* ·
- ·
- · Store unposted queets in cache, if the user accidentally reloads the page or something
- ·
- · · · · · · · · · · · · · */
- $('body').on('keyup', 'div.queet-box-syntax', function(e) {
- 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())
- };
- }
- // remove from cache if empty, or same as default text
- if(thisText == ''
- || thisText == window.sL.compose
- || thisText == window.queetBoxCurrentlyActive.startText
- || thisText == window.queetBoxCurrentlyActive.repliesText) {
- localStorageObjectCache_STORE('queetBoxInput',thisId,false);
- }
- else {
- localStorageObjectCache_STORE('queetBoxInput',thisId,$(this).html());
- }
- });
- /* ·
- ·
- · Keyboard shortcuts
- ·
- · · · · · · · · · · · · · */
- // menu
- $('#shortcuts-link').click(function(){
- // not if disabled
- if($(this).hasClass('disabled')) {
- return true;
- }
- 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) {
- // do nothing if shortcuts are disabled
- if(window.disableKeyboardShortcuts === true) {
- return true;
- }
- 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) {
- // do nothing if shortcuts are disabled
- if(window.disableKeyboardShortcuts === true) {
- return true;
- }
- // 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) {
- // shortcuts documentation on '?'
- if(e.shiftKey && (e.which == 171 || e.which == 191)) {
- $('#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');
- var next = selectedQueet.nextAll('.visible').not('.always-hidden').first();
- next.addClass('selected-by-keyboard');
- scrollToQueet(next);
- }
- // prev queet on 'k'
- else if(e.which == 75) {
- selectedQueet.removeClass('selected-by-keyboard');
- var prev = selectedQueet.prevAll('.visible').not('.always-hidden').first();
- prev.addClass('selected-by-keyboard');
- scrollToQueet(prev);
- }
- // 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')) {
- selectedQueet.find('.queet-box-syntax').click();
- }
- else {
- selectedQueet.children('.queet').find('.icon.sm-reply').click();
- }
- }
- }
- }
- });
- /* ·
- ·
- · When clicking show more links, walk upwards or downwards
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.view-more-container-bottom', function(){
- var thisParentStreamItem = $(this).parent('.stream-item');
- findReplyToStatusAndShow(thisParentStreamItem, thisParentStreamItem.attr('data-quitter-id'),$(this).attr('data-replies-after'));
- $(this).remove();
- findAndMarkLastVisibleInConversation(thisParentStreamItem);
- });
- $('body').on('click','.view-more-container-top', function(){
- var this_qid = $(this).closest('.stream-item:not(.conversation)').attr('data-quitter-id');
- var queet = $(this).siblings('.queet');
- var thisParentStreamItem = $(this).parent('.stream-item');
- rememberMyScrollPos(queet,'moretop' + this_qid);
- findInReplyToStatusAndShow(thisParentStreamItem, thisParentStreamItem.attr('data-quitter-id'),$(this).attr('data-trace-from'),false,true);
- $(this).remove();
- backToMyScrollPos(queet,'moretop' + this_qid,false);
- // remove the "show full conversation" link if nothing more to show
- if(thisParentStreamItem.find('.hidden-conversation').length == 0) {
- thisParentStreamItem.children('.queet').find('.show-full-conversation').remove();
- }
- findAndMarkLastVisibleInConversation(thisParentStreamItem);
- });
- /* ·
- ·
- · When clicking "show full conversation", show all hidden queets in conversation
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','.show-full-conversation',function(){
- var this_q = $(this).closest('.queet');
- var thisStreamItem = this_q.parent();
- var this_qid = thisStreamItem.attr('data-quitter-id');
- rememberMyScrollPos(this_q,this_qid);
- thisStreamItem.find('.view-more-container-top').remove();
- thisStreamItem.find('.view-more-container-bottom').remove();
- $.each(thisStreamItem.find('.hidden-conversation'),function(key,obj){
- $(obj).removeClass('hidden-conversation');
- $(obj).animate({opacity:'1'},400,function(){
- $(obj).css('background-color','pink').animate({backgroundColor:'#F6F6F6'},1000);
- });
- });
- $(this).remove();
- backToMyScrollPos(this_q,this_qid,false);
- findAndMarkLastVisibleInConversation(thisStreamItem);
- });
- /* ·
- ·
- · Edit profile
- ·
- · · · · · · · · · · · · · */
- $('body').on('click','#page-container > .profile-card .edit-profile-button',function(){
- if(!$(this).hasClass('disabled')) {
- $(this).addClass('disabled');
- $('html').scrollTop(0);
- $('html').addClass('fixed');
- $('body').prepend('<div id="edit-profile-popup" class="modal-container"></div>');
- display_spinner();
- getFromAPI('users/show/' + window.loggedIn.screen_name + '.json', function(data){
- remove_spinner();
- if(data){
- data = cleanUpUserObject(data);
- // use avatar if no cover photo
- var coverPhotoHtml = '';
- if(data.cover_photo !== false) {
- coverPhotoHtml = 'background-image:url(\'' + data.cover_photo + '\')';
- }
- $('.hover-card,.hover-card-caret').remove();
- $('#edit-profile-popup').prepend('\
- <div class="edit-profile-container">\
- <div class="upload-background-image"></div>\
- <input type="file" name="background-image-input" id="background-image-input" />\
- <div class="profile-card">\
- <div class="profile-header-inner" style="' + coverPhotoHtml + '">\
- <input type="file" name="cover-photo-input" id="cover-photo-input" />\
- <div class="close-edit-profile-window"></div>\
- <div class="upload-cover-photo"></div>\
- <input type="file" name="avatar-input" id="avatar-input" />\
- <div class="upload-avatar"></div>\
- <div class="profile-header-inner-overlay"></div>\
- <a class="profile-picture" href="' + data.profile_image_url_original + '"><img src="' + data.profile_image_url_profile_size + '" /></a>\
- <div class="profile-card-inner">\
- <input class="fullname" id="edit-profile-fullname" placeholder="' + window.sL.signUpFullName + '" data-start-value="' + data.name + '" value="' + data.name + '" />\
- <h2 class="username"><span class="screen-name">@' + data.screen_name + '</span><span class="follow-status"></span></h2>\
- <div class="bio-container">\
- <textarea class="bio" id="edit-profile-bio" data-start-value="' + data.description + '" placeholder="' + window.sL.registerBio + '">' + data.description + '</textarea>\
- </div>\
- <p class="location-and-url">\
- <input class="location" id="edit-profile-location" placeholder="' + window.sL.registerLocation + '" data-start-value="' + data.location + '" value="' + data.location + '" />\
- <span class="divider"> · </span>\
- <input class="url" id="edit-profile-url" placeholder="' + window.sL.registerHomepage + '" data-start-value="' + data.url + '" value="' + data.url + '" />\
- </p>\
- </div>\
- </div>\
- <div class="profile-banner-footer">\
- <div class="color-selection">\
- <label for="link-color-selection">' + window.sL.linkColor + '</label>\
- <input id="link-color-selection" type="text" value="#' + window.loggedIn.linkcolor + '" />\
- </div>\
- <div class="color-selection">\
- <label for="link-color-selection">' + window.sL.backgroundColor + '</label>\
- <input id="background-color-selection" type="text" value="#' + window.loggedIn.backgroundcolor + '" />\
- </div>\
- <div class="user-actions">\
- <button type="button" class="abort-edit-profile-button"><span class="button-text edit-profile-text">' + window.sL.cancelVerb + '</span>\
- <button type="button" class="save-profile-button"><span class="button-text edit-profile-text">' + window.sL.saveChanges + '</span>\
- <button type="button" class="crop-and-save-button"><span class="button-text edit-profile-text">' + window.sL.cropAndSave + '</span>\
- </div>\
- <div class="clearfix"></div>\
- </div>\
- </div>\
- </div>');
- $('#edit-profile-popup .profile-card').css('top',$('#page-container .profile-card').offset().top-53 + 'px'); // position exactly over
- // save colors on change
- $('#link-color-selection').minicolors({
- change: function(hex) {
- // 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));
- window.loggedIn.linkcolor = hex.substring(1);
- }
- },500);
- }
- });
- $('#background-color-selection').minicolors({
- change: function(hex) {
- // 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));
- window.loggedIn.backgroundcolor = hex.substring(1);
- }
- },500);
- }
- });
- // 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());
- });
- // check if profile info is change and show/hide buttons
- $('input.fullname,textarea.bio,input.location,input.url').on('keyup paste input',function(){
- showHideSaveProfileButtons();
- });
- }
- else {
- abortEditProfile();
- }
- });
- }
- });
- // 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')) {
- $('.abort-edit-profile-button, .save-profile-button').show();
- }
- 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 () {
- $('#link-color-selection').minicolors('value',hex);
- changeLinkColor($('#link-color-selection').val());
- postNewLinkColor($('#link-color-selection').val().substring(1));
- }, 500);
- }
- // idle function for bgcolor selection by keyboard input
- var keyupBGColorTimer;
- function keyupSetBGColor(hex) {
- clearTimeout(keyupBGColorTimer);
- keyupBGColorTimer = setTimeout(function () {
- $('#background-color-selection').minicolors('value',hex);
- $('body').css('background-color',$('#background-color-selection').val());
- postNewBackgroundColor($('#background-color-selection').val().substring(1));
- }, 500);
- }
- // cancel
- $('body').on('click','.close-edit-profile-window',function(){
- abortEditProfile();
- });
- $('body').on('click','.abort-edit-profile-button',function(){
- // if this is the avatar or cover photo
- if($('#edit-profile-popup .jwc_frame').length>0) {
- cleanUpAfterCropping();
- }
- // if profile info
- 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');
- $('.save-profile-button').removeClass('disabled');
- }
- else {
- $('.save-profile-button').attr('disabled','disabled');
- $('.save-profile-button').addClass('disabled');
- }
- });
- // submit cover photo or avatar
- $('body').on('click','.crop-and-save-button',function(){
- if($('.crop-and-save-button').attr('disabled') != 'disabled') {
- $('.crop-and-save-button').attr('disabled','disabled');
- $('.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) {
- 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();
- },
- success: function(data) {
- remove_spinner();
- if(typeof data.error == 'undefined') {
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button').removeClass('disabled');
- cleanUpAfterCropping();
- $('.profile-header-inner').css('background-image','url(' + data.url + ')');
- $('#user-header').css('background-image','url(' + data.url + ')');
- }
- else {
- alert('Try again! ' + data.error);
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button').removeClass('disabled');
- }
- }
- });
- }
- // if this is the avatar
- else if($('#edit-profile-popup .jwc_frame.avatar-to-crop').length>0) {
- $.ajax({ url: window.apiRoot + 'qvitter/update_avatar.json',
- type: "POST",
- data: {
- 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) {
- remove_spinner();
- if(typeof data.error == 'undefined') {
- $('.crop-and-save-button').removeAttr('disabled');
- $('.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 + '\')');
- $('.account-group .name[data-user-id="' + window.loggedIn.id + '"]').siblings('.avatar').attr('src',data.profile_image_url_profile_size);
- }
- else {
- alert('Try again! ' + data.error);
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button').removeClass('disabled');
- }
- }
- });
- }
- // if this is the background-image
- else if($('#edit-profile-popup .jwc_frame.background-to-crop').length>0) {
- $.ajax({ url: window.apiRoot + 'qvitter/update_background_image.json',
- type: "POST",
- data: {
- 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) {
- remove_spinner();
- if(typeof data.error == 'undefined') {
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button').removeClass('disabled');
- cleanUpAfterCropping();
- changeDesign({backgroundimage:data.url});
- window.loggedIn.background_image = data.url;
- }
- else {
- alert('Try again! ' + data.error);
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button').removeClass('disabled');
- }
- }
- });
- }
- }
- });
- // submit new profile info
- $('body').on('click','.save-profile-button',function(){
- if($('.save-profile-button').attr('disabled') != 'disabled') {
- $('.save-profile-button').attr('disabled','disabled');
- $('.save-profile-button').addClass('disabled');
- display_spinner();
- if(validateEditProfileForm($('#edit-profile-popup'))) {
- $.ajax({ url: window.apiRoot + 'account/update_profile.json',
- type: "POST",
- data: {
- 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) {
- remove_spinner();
- if(typeof data.error == 'undefined') {
- location.reload(); // reload, hopefully the new profile is saved
- }
- else {
- alert('Try again! ' + data.error);
- $('.save-profile-button').removeAttr('disabled');
- $('.save-profile-button').removeClass('disabled');
- }
- }
- });
- }
- }
- });
- // 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') {
- var inputId = 'avatar-input'
- }
- else if(coverOrAvatar == 'upload-background-image') {
- 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
- coverPhotoAndAvatarSelectAndCrop(e, coverOrAvatar);
- })});
- // trigger click
- triggerClickOnInputFile($('#' + inputId));
- });
- // load image from file input
- function coverPhotoAndAvatarSelectAndCrop(e, coverOrAvatar) {
- 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;
- var cropId = 'avatar-to-crop';
- }
- else if(coverOrAvatar == 'upload-background-image') {
- var targetWidth = $(window).width();
- var targetHeight = $(window).height()-46;
- var maxWidth = 3000;
- var minWidth = 3000;
- var cropId = 'background-to-crop';
- }
- // get orientation
- loadImage.parseMetaData(e.target.files[0], function (data) {
- if (data.exif) {
- var orientation = data.exif.get('Orientation');
- }
- else {
- var orientation = 1;
- }
- display_spinner();
- // clean up
- cleanUpAfterCropping();
- // create image
- loadImage(e.target.files[0],
- function (img) {
- if(typeof img.target == 'undefined') {
- var appendedImg = $('#edit-profile-popup .profile-card').prepend('<img id="' + cropId +'" src="' + img.toDataURL('image/jpeg') + '" />');
- // enable cropping
- $('#' + cropId).jWindowCrop({
- targetWidth:targetWidth,
- targetHeight:targetHeight,
- onChange: function(result) {
- remove_spinner();
- }
- });
- // 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');
- // replace the hardcoded "click to drag" string
- $('#' + cropId).siblings('.jwc_controls').children('span').html(window.sL.clickToDrag);
- window.jwc = $('#' + cropId).getjWindowCrop();
- $('.save-profile-button').hide();
- $('.abort-edit-profile-button, .crop-and-save-button').show();
- }
- else {
- remove_spinner();
- $('.queet-box-loading-cover').remove();
- alert('could not read image');
- }
- },
- { maxWidth: maxWidth,
- minWidth: minWidth,
- canvas: true,
- orientation: orientation } // Options
- );
- });
- }
- function cleanUpAfterCropping(){
- $('.jwc_frame').siblings('.profile-header-inner').children('div,input,a').css('display','block');
- if(typeof window.jwc != 'undefined') {
- window.jwc.destroy();
- }
- $('.jwc_frame').remove();
- $('#cover-photo-to-crop').remove();
- $('#avatar-to-crop').remove();
- $('#background-to-crop').remove();
- $('input:file').unbind('click');
- $('.crop-and-save-button').removeClass('disabled');
- $('.crop-and-save-button').removeAttr('disabled');
- $('.crop-and-save-button, .abort-edit-profile-button').hide();
- showHideSaveProfileButtons();
- }
- /* ·
- ·
- · Upload attachment
- ·
- · · · · · · · · · · · · · */
- $('body').on('mousedown','.upload-image',function () {
- // remember caret position
- var caretPos = getSelectionInElement($(this).closest('.queet-toolbar').siblings('.queet-box-syntax')[0]);
- $(this).attr('data-caret-pos',caretPos);
- // prevent queet-box collapse
- $(this).addClass('clicked');
- });
- $('body').on('click','.upload-image',function () {
- var thisUploadButton = $(this);
- $('#upload-image-input').one('click',function(){ // trick to make the change event only fire once when selecting a file
- $(this).unbind('change');
- $(this).one('change',function(e){
- uploadAttachment(e, thisUploadButton);
- })
- });
- // trigger click
- triggerClickOnInputFile($('#upload-image-input'));
- });
- 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
- if($(data).find('atom\\:link,link').length>0) {
- var mimeType = $(data).find('atom\\:link,link').attr('type');
- if(mimeType.indexOf('image/') == 0) {
- var imgUrl = $(data).find('atom\\:link,link').attr('href');
- thisUploadButton.closest('.queet-toolbar').before('<span class="upload-image-container"><img class="to-upload" src="' + imgUrl + '" /></span>');
- }
- }
- var mediaurl = rsp.find('mediaurl').text();
- $('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();
- }
- }
- });
- }
- /* ·
- ·
- · 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
- ·
- · · · · · · · · · · · · · */
- function goToEditProfile(arg, callback) {
- if(window.currentStreamObject.name == 'my profile') {
- $('#page-container > .profile-card .edit-profile-button').trigger('click');
- if(typeof callback == 'function') {
- callback(true);
- }
- }
- else {
- setNewCurrentStream(pathToStreamRouter(window.loggedIn.screen_name), true, false, function(){
- $('#page-container > .profile-card .edit-profile-button').trigger('click');
- if(typeof callback == 'function') {
- callback(true);
- }
- });
- }
- }
|