1 function resizeIframe(obj) {
3 obj.style.height = obj.contentWindow.document.body.scrollHeight + 'px';
6 function openClose(theID) {
7 if(document.getElementById(theID).style.display == "block") {
8 document.getElementById(theID).style.display = "none"
11 document.getElementById(theID).style.display = "block"
15 function openMenu(theID) {
16 document.getElementById(theID).style.display = "block"
19 function closeMenu(theID) {
20 document.getElementById(theID).style.display = "none"
28 var force_update = false;
30 var totStopped = false;
34 var in_progress = false;
35 var langSelect = false;
36 var commentBusy = false;
37 var last_popup_menu = null;
38 var last_popup_button = null;
41 $.ajaxSetup({cache: false});
43 /* setup tooltips *//*
44 $("a,.tt").each(function(){
47 if (e.hasClass("tttop")) pos="top";
48 if (e.hasClass("ttbottom")) pos="bottom";
49 if (e.hasClass("ttleft")) pos="left";
50 if (e.hasClass("ttright")) pos="right";
51 e.tipTip({defaultPosition: pos, edgeOffset: 8});
54 /* setup comment textarea buttons */
56 $('[data-role="insert-formatting"]').on('click', function(e) {
59 var comment = o.data('comment');
60 var bbcode = o.data('bbcode');
61 var id = o.data('id');
63 $.colorbox({href: baseurl + "/fbrowser/image/?mode=minimal#comment-"+id, iframe:true,innerWidth:'500px',innerHeight:'400px'})
67 insertFormatting(comment, bbcode, id);
70 /* event from comment textarea button popups */
71 /* insert returned bbcode at cursor position or replace selected text */
72 $("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) {
73 console.log("on", id);
75 var textarea = document.getElementById("comment-edit-text-" +id);
76 var start = textarea.selectionStart;
77 var end = textarea.selectionEnd;
78 textarea.value = textarea.value.substring(0, start) + bbcode + textarea.value.substring(end, textarea.value.length);
83 /* setup onoff widgets */
84 $(".onoff input").each(function(){
86 id = $(this).attr("id");
87 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
90 $(".onoff > a").click(function(event){
91 event.preventDefault();
92 var input = $(this).siblings("input");
93 var val = 1-input.val();
94 var id = input.attr("id");
95 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
96 $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden");
101 /* setup field_richtext */
102 setupFieldRichtext();
105 function close_last_popup_menu() {
106 if(last_popup_menu) {
107 last_popup_menu.hide();
108 last_popup_button.removeClass("selected");
109 last_popup_menu = null;
110 last_popup_button = null;
113 $('a[rel^=#]').click(function(e){
115 var parent = $(this).parent();
116 var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id'));
117 close_last_popup_menu();
118 if(isSelected) return false;
119 menu = $( $(this).attr('rel') );
122 if (menu.attr('popup')=="false") return false;
123 parent.toggleClass("selected");
125 if (menu.css("display") == "none") {
126 last_popup_menu = null;
127 last_popup_button = null;
129 last_popup_menu = menu;
130 last_popup_button = parent;
134 $('html').click(function() {
135 close_last_popup_menu();
139 $("a.popupbox").colorbox({
141 'transition' : 'elastic'
145 /* notifications template */
146 var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html());
147 var notifications_all = unescape($('<div>').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack
148 var notifications_mark = unescape($('<div>').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack
149 var notifications_empty = unescape($("#nav-notifications-menu").html());
151 /* nav update event */
152 $('nav').bind('nav-update', function(e,data){;
153 var invalid = $(data).find('invalid').text();
154 if(invalid == 1) { window.location.href=window.location.href }
156 var net = $(data).find('net').text();
157 if(net == 0) { net = ''; $('#net-update').removeClass('show') } else { $('#net-update').addClass('show') }
158 $('#net-update').html(net);
160 var home = $(data).find('home').text();
161 if(home == 0) { home = ''; $('#home-update').removeClass('show') } else { $('#home-update').addClass('show') }
162 $('#home-update').html(home);
164 var intro = $(data).find('intro').text();
165 if(intro == 0) { intro = ''; $('#intro-update').removeClass('show') } else { $('#intro-update').addClass('show') }
166 $('#intro-update').html(intro);
168 var mail = $(data).find('mail').text();
169 if(mail == 0) { mail = ''; $('#mail-update').removeClass('show') } else { $('#mail-update').addClass('show') }
170 $('#mail-update').html(mail);
172 var intro = $(data).find('intro').text();
173 if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') }
174 $('#intro-update-li').html(intro);
176 var mail = $(data).find('mail').text();
177 if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') }
178 $('#mail-update-li').html(mail);
181 var allevents = $(data).find('all-events').text();
182 if(allevents == 0) { allevents = ''; $('#allevents-update').removeClass('show') } else { $('#allevents-update').addClass('show') }
183 $('#allevents-update').html(allevents);
185 var alleventstoday = $(data).find('all-events-today').text();
186 if(alleventstoday == 0) { $('#allevents-update').removeClass('notif-allevents-today') } else { $('#allevents-update').addClass('notif-allevents-today') }
188 var events = $(data).find('events').text();
189 if(events == 0) { events = ''; $('#events-update').removeClass('show') } else { $('#events-update').addClass('show') }
190 $('#events-update').html(events);
192 var eventstoday = $(data).find('events-today').text();
193 if(eventstoday == 0) { $('#events-update').removeClass('notif-events-today') } else { $('#events-update').addClass('notif-events-today') }
195 var birthdays = $(data).find('birthdays').text();
196 if(birthdays == 0) {birthdays = ''; $('#birthdays-update').removeClass('show') } else { $('#birthdays-update').addClass('show') }
197 $('#birthdays-update').html(birthdays);
199 var birthdaystoday = $(data).find('birthdays-today').text();
200 if(birthdaystoday == 0) { $('#birthdays-update').removeClass('notif-birthdays-today') } else { $('#birthdays-update').addClass('notif-birthdays-today') }
203 var eNotif = $(data).find('notif')
205 if (eNotif.children("note").length==0){
206 $("#nav-notifications-menu").html(notifications_empty);
208 nnm = $("#nav-notifications-menu");
209 nnm.html(notifications_all + notifications_mark);
210 //nnm.attr('popup','true');
212 var notification_lastitem = parseInt(localStorage.getItem("notification-lastitem"));
213 var notification_id = 0;
214 eNotif.children("note").each(function(){
216 var text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
217 var seenclass = (e.attr('seen')==1)?"notify-seen":"notify-unseen";
218 var html = notifications_tpl.format(e.attr('href'),
219 e.attr('photo'), // {0}
221 e.attr('date'), // {2}
223 new Date(e.attr('timestamp')*1000) // {4}
227 $(eNotif.children("note").get().reverse()).each(function(){
229 notification_id = parseInt(e.attr('timestamp'));
230 if (notification_lastitem!== null && notification_id > notification_lastitem) {
231 if (getNotificationPermission()==="granted") {
232 var notification = new Notification(document.title, {
233 body: e.text().replace('→ ','').format(e.attr('name')),
234 icon: e.attr('photo'),
236 notification['url'] = e.attr('href');
237 notification.addEventListener("click", function(ev){
238 window.location = ev.target.url;
244 notification_lastitem = notification_id;
245 localStorage.setItem("notification-lastitem", notification_lastitem)
247 $("img[data-src]", nnm).each(function(i, el){
248 // Add src attribute for images with a data-src attribute
249 // However, don't bother if the data-src attribute is empty, because
250 // an empty "src" tag for an image will cause some browsers
251 // to prefetch the root page of the Friendica hub, which will
252 // unnecessarily load an entire profile/ or network/ page
253 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
257 notif = eNotif.attr('count');
259 $("#nav-notifications-linkmenu").addClass("on");
261 $("#nav-notifications-linkmenu").removeClass("on");
263 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
264 $('#notify-update').html(notif);
266 var eSysmsg = $(data).find('sysmsgs');
267 eSysmsg.children("notice").each(function(){
268 text = $(this).text();
269 $.jGrowl(text, { sticky: true, theme: 'notice' });
271 eSysmsg.children("info").each(function(){
272 text = $(this).text();
273 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
279 // Allow folks to stop the ajax page updates with the pause/break key
280 $(document).keydown(function(event) {
281 if(event.keyCode == '8') {
282 var target = event.target || event.srcElement;
283 if (!/input|textarea/i.test(target.nodeName)) {
287 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
288 event.preventDefault();
289 if(stopped == false) {
294 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
308 function NavUpdate() {
311 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
312 $.get(pingCmd,function(data) {
313 $(data).find('result').each(function() {
314 // send nav-update event
315 $('nav').trigger('nav-update', this);
320 if($('#live-network').length) { src = 'network'; liveUpdate(); }
321 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
322 if($('#live-community').length) { src = 'community'; liveUpdate(); }
323 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
324 if($('#live-display').length) { src = 'display'; liveUpdate(); }
325 /* if($('#live-display').length) {
328 window.location.href=window.location.href
331 if($('#live-photos').length) {
334 window.location.href=window.location.href
344 timer = setTimeout(NavUpdate,updateInterval);
347 function liveUpdate() {
348 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
349 if(($('.comment-edit-text-full').length) || (in_progress)) {
351 clearTimeout(livetime);
353 livetime = setTimeout(liveUpdate, 5000);
359 prev = 'live-' + src;
363 if ($(document).scrollTop() == 0)
366 var udargs = ((netargs.length) ? '/' + netargs : '');
367 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
369 $.get(update_url,function(data) {
371 force_update = false;
372 // $('.collapsed-comments',data).each(function() {
373 // var ident = $(this).attr('id');
374 // var is_hidden = $('#' + ident).is(':hidden');
375 // if($('#' + ident).length) {
376 // $('#' + ident).replaceWith($(this));
378 // $('#' + ident).hide();
383 $('.toplevel_item',data).each(function() {
384 var ident = $(this).attr('id');
386 if($('#' + ident).length == 0 && profile_page == 1) {
387 $('img',this).each(function() {
388 $(this).attr('src',$(this).attr('dst'));
390 $('#' + prev).after($(this));
393 // Find out if the hidden comments are open, so we can keep it that way
394 // if a new comment has been posted
395 var id = $('.hide-comments-total', this).attr('id');
396 if(typeof id != 'undefined') {
397 id = id.split('-')[3];
398 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
401 $('img',this).each(function() {
402 $(this).attr('src',$(this).attr('dst'));
404 //vScroll = $(document).scrollTop();
405 $('html').height($('html').height());
406 $('#' + ident).replaceWith($(this));
408 if(typeof id != 'undefined') {
409 if(commentsOpen) showHideComments(id);
411 $('html').height('auto');
412 //$(document).scrollTop(vScroll);
417 // reset vars for inserting individual items
419 /* prev = 'live-' + src;
421 $('.wall-item-outside-wrapper',data).each(function() {
422 var ident = $(this).attr('id');
424 if($('#' + ident).length == 0 && prev != 'live-' + src) {
425 $('img',this).each(function() {
426 $(this).attr('src',$(this).attr('dst'));
428 $('#' + prev).after($(this));
431 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
432 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
433 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
434 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
435 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
436 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
437 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
438 $(this).attr('src',$(this).attr('dst'));
444 $('.like-rotator').hide();
447 $('body').css('cursor', 'auto');
449 /* autocomplete @nicknames */
450 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
452 // setup videos, since VideoJS won't take care of any loaded via AJAX
453 if(typeof videojs != 'undefined') videojs.autoSetup();
457 function imgbright(node) {
458 $(node).removeClass("drophide").addClass("drop");
461 function imgdull(node) {
462 $(node).removeClass("drop").addClass("drophide");
465 // Since our ajax calls are asynchronous, we will give a few
466 // seconds for the first ajax call (setting like/dislike), then
467 // run the updater to pick up any changes and display on the page.
468 // The updater will turn any rotators off when it's done.
469 // This function will have returned long before any of these
470 // events have completed and therefore there won't be any
471 // visible feedback that anything changed without all this
472 // trickery. This still could cause confusion if the "like" ajax call
473 // is delayed and NavUpdate runs before it completes.
475 function dolike(ident,verb) {
477 $('#like-rotator-' + ident.toString()).show();
478 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
483 function dosubthread(ident) {
485 $('#like-rotator-' + ident.toString()).show();
486 $.get('subthread/' + ident.toString(), NavUpdate );
491 function dostar(ident) {
492 ident = ident.toString();
493 $('#like-rotator-' + ident).show();
494 $.get('starred/' + ident, function(data) {
495 if(data.match(/1/)) {
496 $('#starred-' + ident).addClass('starred');
497 $('#starred-' + ident).removeClass('unstarred');
498 $('#star-' + ident).addClass('hidden');
499 $('#unstar-' + ident).removeClass('hidden');
502 $('#starred-' + ident).addClass('unstarred');
503 $('#starred-' + ident).removeClass('starred');
504 $('#star-' + ident).removeClass('hidden');
505 $('#unstar-' + ident).addClass('hidden');
507 $('#like-rotator-' + ident).hide();
511 function doignore(ident) {
512 ident = ident.toString();
513 $('#like-rotator-' + ident).show();
514 $.get('ignored/' + ident, function(data) {
515 if(data.match(/1/)) {
516 $('#ignored-' + ident).addClass('ignored');
517 $('#ignored-' + ident).removeClass('unignored');
518 $('#ignore-' + ident).addClass('hidden');
519 $('#unignore-' + ident).removeClass('hidden');
522 $('#ignored-' + ident).addClass('unignored');
523 $('#ignored-' + ident).removeClass('ignored');
524 $('#ignore-' + ident).removeClass('hidden');
525 $('#unignore-' + ident).addClass('hidden');
527 $('#like-rotator-' + ident).hide();
531 function getPosition(e) {
532 var cursor = {x:0, y:0};
533 if ( e.pageX || e.pageY ) {
538 if( e.clientX || e.clientY ) {
539 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
540 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
552 var lockvisible = false;
554 function lockview(event,id) {
555 event = event || window.event;
556 cursor = getPosition(event);
562 $.get('lockview/' + id, function(data) {
563 $('#panel').html(data);
564 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
570 function lockviewhide() {
575 function post_comment(id) {
578 $('body').css('cursor', 'wait');
579 $("#comment-preview-inp-" + id).val("0");
582 $("#comment-edit-form-" + id).serialize(),
585 $("#comment-edit-wrapper-" + id).hide();
586 $("#comment-edit-text-" + id).val('');
587 var tarea = document.getElementById("comment-edit-text-" + id);
589 commentClose(tarea,id);
590 if(timer) clearTimeout(timer);
591 timer = setTimeout(NavUpdate,10);
595 window.location.href=data.reload;
604 function preview_comment(id) {
605 $("#comment-preview-inp-" + id).val("1");
606 $("#comment-edit-preview-" + id).show();
609 $("#comment-edit-form-" + id).serialize(),
613 $("#comment-edit-preview-" + id).html(data.preview);
614 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
624 function showHideComments(id) {
625 if( $("#collapsed-comments-" + id).is(":visible")) {
626 $("#collapsed-comments-" + id).hide();
627 $("#hide-comments-" + id).html(window.showMore);
630 $("#collapsed-comments-" + id).show();
631 $("#hide-comments-" + id).html(window.showFewer);
637 function preview_post() {
638 $("#jot-preview").val("1");
639 $("#jot-preview-content").show();
640 tinyMCE.triggerSave();
643 $("#profile-jot-form").serialize(),
646 $("#jot-preview-content").html(data.preview);
647 $("#jot-preview-content" + " a").click(function() { return false; });
652 $("#jot-preview").val("0");
658 // unpause auto reloads if they are currently stopped
661 $('#pause').html('');
666 // Converts the binary representation of data to hex
669 // discuss at: http://phpjs.org/functions/bin2hex
670 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
671 // + bugfixed by: Onno Marsman
672 // + bugfixed by: Linuxworld
673 // * example 1: bin2hex('Kev');
674 // * returns 1: '4b6576'
675 // * example 2: bin2hex(String.fromCharCode(0x00));
677 var v,i, f = 0, a = [];
681 for (i = 0; i<f; i++) {
682 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
688 function groupChangeMember(gid, cid, sec_token) {
689 $('body .fakelink').css('cursor', 'wait');
690 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
691 $('#group-update-wrapper').html(data);
692 $('body .fakelink').css('cursor', 'auto');
696 function profChangeMember(gid,cid) {
697 $('body .fakelink').css('cursor', 'wait');
698 $.get('profperm/' + gid + '/' + cid, function(data) {
699 $('#prof-update-wrapper').html(data);
700 $('body .fakelink').css('cursor', 'auto');
704 function contactgroupChangeMember(gid,cid) {
705 $('body').css('cursor', 'wait');
706 $.get('contactgroup/' + gid + '/' + cid, function(data) {
707 $('body').css('cursor', 'auto');
712 function checkboxhighlight(box) {
713 if($(box).is(':checked')) {
714 $(box).addClass('checkeditem');
717 $(box).removeClass('checkeditem');
721 function notifyMarkAll() {
722 $.get('notify/mark/all', function(data) {
723 if(timer) clearTimeout(timer);
724 timer = setTimeout(NavUpdate,1000);
730 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
731 function fcFileBrowser (field_name, url, type, win) {
732 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
733 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
734 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
737 var cmsURL = baseurl+"/fbrowser/"+type+"/";
739 tinyMCE.activeEditor.windowManager.open({
741 title : 'File Browser',
742 width : 420, // Your dimensions may differ - toy around with them!
745 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
746 close_previous : "no"
754 function setupFieldRichtext(){
757 mode : "specific_textareas",
758 editor_selector: "fieldRichtext",
759 plugins : "bbcode,paste, inlinepopups",
760 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
761 theme_advanced_buttons2 : "",
762 theme_advanced_buttons3 : "",
763 theme_advanced_toolbar_location : "top",
764 theme_advanced_toolbar_align : "center",
765 theme_advanced_blockformats : "blockquote,code",
766 theme_advanced_resizing : true,
767 paste_text_sticky : true,
768 entity_encoding : "raw",
769 add_unload_trigger : false,
770 remove_linebreaks : false,
771 //force_p_newlines : false,
772 //force_br_newlines : true,
773 forced_root_block : 'div',
775 content_css: baseurl+"/view/custom_tinymce.css",
776 theme_advanced_path : false,
777 file_browser_callback : "fcFileBrowser",
783 * sprintf in javascript
784 * "{0} and {1}".format('zero','uno');
786 String.prototype.format = function() {
787 var formatted = this;
788 for (var i = 0; i < arguments.length; i++) {
789 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
790 formatted = formatted.replace(regexp, arguments[i]);
795 Array.prototype.remove = function(item) {
796 to=undefined; from=this.indexOf(item);
797 var rest = this.slice((to || from) + 1 || this.length);
798 this.length = from < 0 ? this.length + from : from;
799 return this.push.apply(this, rest);
802 function previewTheme(elm) {
803 theme = $(elm).val();
804 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
805 $('#theme-preview').html('<div id="theme-desc">' + data.desc + '</div><div id="theme-version">' + data.version + '</div><div id="theme-credits">' + data.credits + '</div><a href="' + data.img + '"><img src="' + data.img + '" width="320" height="240" alt="' + theme + '" /></a>');
810 // notification permission settings in localstorage
811 // set by settings page
812 function getNotificationPermission() {
813 if (window["Notification"] === undefined) {
816 if (Notification.permission === 'granted') {
817 var val = localStorage.getItem('notification-permissions');
818 if (val === null) return 'denied';
821 return Notification.permission;