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 */
55 /* comment textarea buttons needs some "data-*" attributes to work:
56 * data-role="insert-formatting" : to mark the element as a formatting button
57 * data-comment="<string>" : string for "Comment", used by insertFormatting() function
58 * data-bbcode="<string>" : name of the bbcode element to insert. insertFormatting() will insert it as "[name][/name]"
59 * data-id="<string>" : id of the comment, used to find other comment-related element, like the textarea
61 $('body').on('click','[data-role="insert-formatting"]', function(e) {
64 var comment = o.data('comment');
65 var bbcode = o.data('bbcode');
66 var id = o.data('id');
68 $.colorbox({href: baseurl + "/fbrowser/image/?mode=minimal#comment-"+id, iframe:true,innerWidth:'500px',innerHeight:'400px'})
72 insertFormatting(comment, bbcode, id);
75 /* event from comment textarea button popups */
76 /* insert returned bbcode at cursor position or replace selected text */
77 $("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) {
78 console.log("on", id);
80 var textarea = document.getElementById("comment-edit-text-" +id);
81 var start = textarea.selectionStart;
82 var end = textarea.selectionEnd;
83 textarea.value = textarea.value.substring(0, start) + bbcode + textarea.value.substring(end, textarea.value.length);
88 /* setup onoff widgets */
89 $(".onoff input").each(function(){
91 id = $(this).attr("id");
92 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
95 $(".onoff > a").click(function(event){
96 event.preventDefault();
97 var input = $(this).siblings("input");
98 var val = 1-input.val();
99 var id = input.attr("id");
100 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
101 $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden");
106 /* setup field_richtext */
107 setupFieldRichtext();
110 function close_last_popup_menu() {
111 if(last_popup_menu) {
112 last_popup_menu.hide();
113 last_popup_button.removeClass("selected");
114 last_popup_menu = null;
115 last_popup_button = null;
118 $('a[rel^=#]').click(function(e){
120 var parent = $(this).parent();
121 var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id'));
122 close_last_popup_menu();
123 if(isSelected) return false;
124 menu = $( $(this).attr('rel') );
127 if (menu.attr('popup')=="false") return false;
128 parent.toggleClass("selected");
130 if (menu.css("display") == "none") {
131 last_popup_menu = null;
132 last_popup_button = null;
134 last_popup_menu = menu;
135 last_popup_button = parent;
139 $('html').click(function() {
140 close_last_popup_menu();
144 $("a.popupbox").colorbox({
146 'transition' : 'elastic'
150 /* notifications template */
151 var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html());
152 var notifications_all = unescape($('<div>').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack
153 var notifications_mark = unescape($('<div>').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack
154 var notifications_empty = unescape($("#nav-notifications-menu").html());
156 /* nav update event */
157 $('nav').bind('nav-update', function(e,data){;
158 var invalid = $(data).find('invalid').text();
159 if(invalid == 1) { window.location.href=window.location.href }
161 var net = $(data).find('net').text();
162 if(net == 0) { net = ''; $('#net-update').removeClass('show') } else { $('#net-update').addClass('show') }
163 $('#net-update').html(net);
165 var home = $(data).find('home').text();
166 if(home == 0) { home = ''; $('#home-update').removeClass('show') } else { $('#home-update').addClass('show') }
167 $('#home-update').html(home);
169 var intro = $(data).find('intro').text();
170 if(intro == 0) { intro = ''; $('#intro-update').removeClass('show') } else { $('#intro-update').addClass('show') }
171 $('#intro-update').html(intro);
173 var mail = $(data).find('mail').text();
174 if(mail == 0) { mail = ''; $('#mail-update').removeClass('show') } else { $('#mail-update').addClass('show') }
175 $('#mail-update').html(mail);
177 var intro = $(data).find('intro').text();
178 if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') }
179 $('#intro-update-li').html(intro);
181 var mail = $(data).find('mail').text();
182 if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') }
183 $('#mail-update-li').html(mail);
186 var allevents = $(data).find('all-events').text();
187 if(allevents == 0) { allevents = ''; $('#allevents-update').removeClass('show') } else { $('#allevents-update').addClass('show') }
188 $('#allevents-update').html(allevents);
190 var alleventstoday = $(data).find('all-events-today').text();
191 if(alleventstoday == 0) { $('#allevents-update').removeClass('notif-allevents-today') } else { $('#allevents-update').addClass('notif-allevents-today') }
193 var events = $(data).find('events').text();
194 if(events == 0) { events = ''; $('#events-update').removeClass('show') } else { $('#events-update').addClass('show') }
195 $('#events-update').html(events);
197 var eventstoday = $(data).find('events-today').text();
198 if(eventstoday == 0) { $('#events-update').removeClass('notif-events-today') } else { $('#events-update').addClass('notif-events-today') }
200 var birthdays = $(data).find('birthdays').text();
201 if(birthdays == 0) {birthdays = ''; $('#birthdays-update').removeClass('show') } else { $('#birthdays-update').addClass('show') }
202 $('#birthdays-update').html(birthdays);
204 var birthdaystoday = $(data).find('birthdays-today').text();
205 if(birthdaystoday == 0) { $('#birthdays-update').removeClass('notif-birthdays-today') } else { $('#birthdays-update').addClass('notif-birthdays-today') }
208 var eNotif = $(data).find('notif')
210 if (eNotif.children("note").length==0){
211 $("#nav-notifications-menu").html(notifications_empty);
213 nnm = $("#nav-notifications-menu");
214 nnm.html(notifications_all + notifications_mark);
215 //nnm.attr('popup','true');
217 var notification_lastitem = parseInt(localStorage.getItem("notification-lastitem"));
218 var notification_id = 0;
219 eNotif.children("note").each(function(){
221 var text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
222 var seenclass = (e.attr('seen')==1)?"notify-seen":"notify-unseen";
223 var html = notifications_tpl.format(e.attr('href'),
224 e.attr('photo'), // {0}
226 e.attr('date'), // {2}
228 new Date(e.attr('timestamp')*1000) // {4}
232 $(eNotif.children("note").get().reverse()).each(function(){
234 notification_id = parseInt(e.attr('timestamp'));
235 if (notification_lastitem!== null && notification_id > notification_lastitem) {
236 if (getNotificationPermission()==="granted") {
237 var notification = new Notification(document.title, {
238 body: e.text().replace('→ ','').format(e.attr('name')),
239 icon: e.attr('photo'),
241 notification['url'] = e.attr('href');
242 notification.addEventListener("click", function(ev){
243 window.location = ev.target.url;
249 notification_lastitem = notification_id;
250 localStorage.setItem("notification-lastitem", notification_lastitem)
252 $("img[data-src]", nnm).each(function(i, el){
253 // Add src attribute for images with a data-src attribute
254 // However, don't bother if the data-src attribute is empty, because
255 // an empty "src" tag for an image will cause some browsers
256 // to prefetch the root page of the Friendica hub, which will
257 // unnecessarily load an entire profile/ or network/ page
258 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
262 notif = eNotif.attr('count');
264 $("#nav-notifications-linkmenu").addClass("on");
266 $("#nav-notifications-linkmenu").removeClass("on");
268 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
269 $('#notify-update').html(notif);
271 var eSysmsg = $(data).find('sysmsgs');
272 eSysmsg.children("notice").each(function(){
273 text = $(this).text();
274 $.jGrowl(text, { sticky: true, theme: 'notice' });
276 eSysmsg.children("info").each(function(){
277 text = $(this).text();
278 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
284 // Allow folks to stop the ajax page updates with the pause/break key
285 $(document).keydown(function(event) {
286 if(event.keyCode == '8') {
287 var target = event.target || event.srcElement;
288 if (!/input|textarea/i.test(target.nodeName)) {
292 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
293 event.preventDefault();
294 if(stopped == false) {
299 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
313 function NavUpdate() {
316 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
317 $.get(pingCmd,function(data) {
318 $(data).find('result').each(function() {
319 // send nav-update event
320 $('nav').trigger('nav-update', this);
325 if($('#live-network').length) { src = 'network'; liveUpdate(); }
326 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
327 if($('#live-community').length) { src = 'community'; liveUpdate(); }
328 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
329 if($('#live-display').length) { src = 'display'; liveUpdate(); }
330 /* if($('#live-display').length) {
333 window.location.href=window.location.href
336 if($('#live-photos').length) {
339 window.location.href=window.location.href
349 timer = setTimeout(NavUpdate,updateInterval);
352 function liveUpdate() {
353 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
354 if(($('.comment-edit-text-full').length) || (in_progress)) {
356 clearTimeout(livetime);
358 livetime = setTimeout(liveUpdate, 5000);
364 prev = 'live-' + src;
368 if ($(document).scrollTop() == 0)
371 var udargs = ((netargs.length) ? '/' + netargs : '');
372 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
374 $.get(update_url,function(data) {
376 force_update = false;
377 // $('.collapsed-comments',data).each(function() {
378 // var ident = $(this).attr('id');
379 // var is_hidden = $('#' + ident).is(':hidden');
380 // if($('#' + ident).length) {
381 // $('#' + ident).replaceWith($(this));
383 // $('#' + ident).hide();
388 $('.toplevel_item',data).each(function() {
389 var ident = $(this).attr('id');
391 if($('#' + ident).length == 0 && profile_page == 1) {
392 $('img',this).each(function() {
393 $(this).attr('src',$(this).attr('dst'));
395 $('#' + prev).after($(this));
398 // Find out if the hidden comments are open, so we can keep it that way
399 // if a new comment has been posted
400 var id = $('.hide-comments-total', this).attr('id');
401 if(typeof id != 'undefined') {
402 id = id.split('-')[3];
403 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
406 $('img',this).each(function() {
407 $(this).attr('src',$(this).attr('dst'));
409 //vScroll = $(document).scrollTop();
410 $('html').height($('html').height());
411 $('#' + ident).replaceWith($(this));
413 if(typeof id != 'undefined') {
414 if(commentsOpen) showHideComments(id);
416 $('html').height('auto');
417 //$(document).scrollTop(vScroll);
422 // reset vars for inserting individual items
424 /* prev = 'live-' + src;
426 $('.wall-item-outside-wrapper',data).each(function() {
427 var ident = $(this).attr('id');
429 if($('#' + ident).length == 0 && prev != 'live-' + src) {
430 $('img',this).each(function() {
431 $(this).attr('src',$(this).attr('dst'));
433 $('#' + prev).after($(this));
436 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
437 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
438 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
439 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
440 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
441 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
442 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
443 $(this).attr('src',$(this).attr('dst'));
449 $('.like-rotator').hide();
452 $('body').css('cursor', 'auto');
454 /* autocomplete @nicknames */
455 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
457 // setup videos, since VideoJS won't take care of any loaded via AJAX
458 if(typeof videojs != 'undefined') videojs.autoSetup();
462 function imgbright(node) {
463 $(node).removeClass("drophide").addClass("drop");
466 function imgdull(node) {
467 $(node).removeClass("drop").addClass("drophide");
470 // Since our ajax calls are asynchronous, we will give a few
471 // seconds for the first ajax call (setting like/dislike), then
472 // run the updater to pick up any changes and display on the page.
473 // The updater will turn any rotators off when it's done.
474 // This function will have returned long before any of these
475 // events have completed and therefore there won't be any
476 // visible feedback that anything changed without all this
477 // trickery. This still could cause confusion if the "like" ajax call
478 // is delayed and NavUpdate runs before it completes.
480 function dolike(ident,verb) {
482 $('#like-rotator-' + ident.toString()).show();
483 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
488 function dosubthread(ident) {
490 $('#like-rotator-' + ident.toString()).show();
491 $.get('subthread/' + ident.toString(), NavUpdate );
496 function dostar(ident) {
497 ident = ident.toString();
498 $('#like-rotator-' + ident).show();
499 $.get('starred/' + ident, function(data) {
500 if(data.match(/1/)) {
501 $('#starred-' + ident).addClass('starred');
502 $('#starred-' + ident).removeClass('unstarred');
503 $('#star-' + ident).addClass('hidden');
504 $('#unstar-' + ident).removeClass('hidden');
507 $('#starred-' + ident).addClass('unstarred');
508 $('#starred-' + ident).removeClass('starred');
509 $('#star-' + ident).removeClass('hidden');
510 $('#unstar-' + ident).addClass('hidden');
512 $('#like-rotator-' + ident).hide();
516 function doignore(ident) {
517 ident = ident.toString();
518 $('#like-rotator-' + ident).show();
519 $.get('ignored/' + ident, function(data) {
520 if(data.match(/1/)) {
521 $('#ignored-' + ident).addClass('ignored');
522 $('#ignored-' + ident).removeClass('unignored');
523 $('#ignore-' + ident).addClass('hidden');
524 $('#unignore-' + ident).removeClass('hidden');
527 $('#ignored-' + ident).addClass('unignored');
528 $('#ignored-' + ident).removeClass('ignored');
529 $('#ignore-' + ident).removeClass('hidden');
530 $('#unignore-' + ident).addClass('hidden');
532 $('#like-rotator-' + ident).hide();
536 function getPosition(e) {
537 var cursor = {x:0, y:0};
538 if ( e.pageX || e.pageY ) {
543 if( e.clientX || e.clientY ) {
544 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
545 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
557 var lockvisible = false;
559 function lockview(event,id) {
560 event = event || window.event;
561 cursor = getPosition(event);
567 $.get('lockview/' + id, function(data) {
568 $('#panel').html(data);
569 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
575 function lockviewhide() {
580 function post_comment(id) {
583 $('body').css('cursor', 'wait');
584 $("#comment-preview-inp-" + id).val("0");
587 $("#comment-edit-form-" + id).serialize(),
590 $("#comment-edit-wrapper-" + id).hide();
591 $("#comment-edit-text-" + id).val('');
592 var tarea = document.getElementById("comment-edit-text-" + id);
594 commentClose(tarea,id);
595 if(timer) clearTimeout(timer);
596 timer = setTimeout(NavUpdate,10);
600 window.location.href=data.reload;
609 function preview_comment(id) {
610 $("#comment-preview-inp-" + id).val("1");
611 $("#comment-edit-preview-" + id).show();
614 $("#comment-edit-form-" + id).serialize(),
618 $("#comment-edit-preview-" + id).html(data.preview);
619 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
629 function showHideComments(id) {
630 if( $("#collapsed-comments-" + id).is(":visible")) {
631 $("#collapsed-comments-" + id).hide();
632 $("#hide-comments-" + id).html(window.showMore);
635 $("#collapsed-comments-" + id).show();
636 $("#hide-comments-" + id).html(window.showFewer);
642 function preview_post() {
643 $("#jot-preview").val("1");
644 $("#jot-preview-content").show();
645 tinyMCE.triggerSave();
648 $("#profile-jot-form").serialize(),
651 $("#jot-preview-content").html(data.preview);
652 $("#jot-preview-content" + " a").click(function() { return false; });
657 $("#jot-preview").val("0");
663 // unpause auto reloads if they are currently stopped
666 $('#pause').html('');
671 // Converts the binary representation of data to hex
674 // discuss at: http://phpjs.org/functions/bin2hex
675 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
676 // + bugfixed by: Onno Marsman
677 // + bugfixed by: Linuxworld
678 // * example 1: bin2hex('Kev');
679 // * returns 1: '4b6576'
680 // * example 2: bin2hex(String.fromCharCode(0x00));
682 var v,i, f = 0, a = [];
686 for (i = 0; i<f; i++) {
687 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
693 function groupChangeMember(gid, cid, sec_token) {
694 $('body .fakelink').css('cursor', 'wait');
695 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
696 $('#group-update-wrapper').html(data);
697 $('body .fakelink').css('cursor', 'auto');
701 function profChangeMember(gid,cid) {
702 $('body .fakelink').css('cursor', 'wait');
703 $.get('profperm/' + gid + '/' + cid, function(data) {
704 $('#prof-update-wrapper').html(data);
705 $('body .fakelink').css('cursor', 'auto');
709 function contactgroupChangeMember(gid,cid) {
710 $('body').css('cursor', 'wait');
711 $.get('contactgroup/' + gid + '/' + cid, function(data) {
712 $('body').css('cursor', 'auto');
717 function checkboxhighlight(box) {
718 if($(box).is(':checked')) {
719 $(box).addClass('checkeditem');
722 $(box).removeClass('checkeditem');
726 function notifyMarkAll() {
727 $.get('notify/mark/all', function(data) {
728 if(timer) clearTimeout(timer);
729 timer = setTimeout(NavUpdate,1000);
735 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
736 function fcFileBrowser (field_name, url, type, win) {
737 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
738 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
739 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
742 var cmsURL = baseurl+"/fbrowser/"+type+"/";
744 tinyMCE.activeEditor.windowManager.open({
746 title : 'File Browser',
747 width : 420, // Your dimensions may differ - toy around with them!
750 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
751 close_previous : "no"
759 function setupFieldRichtext(){
762 mode : "specific_textareas",
763 editor_selector: "fieldRichtext",
764 plugins : "bbcode,paste, inlinepopups",
765 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
766 theme_advanced_buttons2 : "",
767 theme_advanced_buttons3 : "",
768 theme_advanced_toolbar_location : "top",
769 theme_advanced_toolbar_align : "center",
770 theme_advanced_blockformats : "blockquote,code",
771 theme_advanced_resizing : true,
772 paste_text_sticky : true,
773 entity_encoding : "raw",
774 add_unload_trigger : false,
775 remove_linebreaks : false,
776 //force_p_newlines : false,
777 //force_br_newlines : true,
778 forced_root_block : 'div',
780 content_css: baseurl+"/view/custom_tinymce.css",
781 theme_advanced_path : false,
782 file_browser_callback : "fcFileBrowser",
788 * sprintf in javascript
789 * "{0} and {1}".format('zero','uno');
791 String.prototype.format = function() {
792 var formatted = this;
793 for (var i = 0; i < arguments.length; i++) {
794 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
795 formatted = formatted.replace(regexp, arguments[i]);
800 Array.prototype.remove = function(item) {
801 to=undefined; from=this.indexOf(item);
802 var rest = this.slice((to || from) + 1 || this.length);
803 this.length = from < 0 ? this.length + from : from;
804 return this.push.apply(this, rest);
807 function previewTheme(elm) {
808 theme = $(elm).val();
809 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
810 $('#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>');
815 // notification permission settings in localstorage
816 // set by settings page
817 function getNotificationPermission() {
818 if (window["Notification"] === undefined) {
821 if (Notification.permission === 'granted') {
822 var val = localStorage.getItem('notification-permissions');
823 if (val === null) return 'denied';
826 return Notification.permission;