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});
56 /* setup onoff widgets */
57 $(".onoff input").each(function(){
59 id = $(this).attr("id");
60 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
63 $(".onoff > a").click(function(event){
64 event.preventDefault();
65 var input = $(this).siblings("input");
66 var val = 1-input.val();
67 var id = input.attr("id");
68 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
69 $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden");
74 /* setup field_richtext */
78 function close_last_popup_menu() {
80 last_popup_menu.hide();
81 last_popup_button.removeClass("selected");
82 last_popup_menu = null;
83 last_popup_button = null;
86 $('a[rel^=#]').click(function(e){
88 var parent = $(this).parent();
89 var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id'));
90 close_last_popup_menu();
91 if(isSelected) return false;
92 menu = $( $(this).attr('rel') );
95 if (menu.attr('popup')=="false") return false;
96 parent.toggleClass("selected");
98 if (menu.css("display") == "none") {
99 last_popup_menu = null;
100 last_popup_button = null;
102 last_popup_menu = menu;
103 last_popup_button = parent;
107 $('html').click(function() {
108 close_last_popup_menu();
112 $("a.popupbox").colorbox({
114 'transition' : 'elastic'
118 /* notifications template */
119 var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html());
120 var notifications_all = unescape($('<div>').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack
121 var notifications_mark = unescape($('<div>').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack
122 var notifications_empty = unescape($("#nav-notifications-menu").html());
124 /* nav update event */
125 $('nav').bind('nav-update', function(e,data){;
126 var invalid = $(data).find('invalid').text();
127 if(invalid == 1) { window.location.href=window.location.href }
129 var net = $(data).find('net').text();
130 if(net == 0) { net = ''; $('#net-update').removeClass('show') } else { $('#net-update').addClass('show') }
131 $('#net-update').html(net);
133 var home = $(data).find('home').text();
134 if(home == 0) { home = ''; $('#home-update').removeClass('show') } else { $('#home-update').addClass('show') }
135 $('#home-update').html(home);
137 var intro = $(data).find('intro').text();
138 if(intro == 0) { intro = ''; $('#intro-update').removeClass('show') } else { $('#intro-update').addClass('show') }
139 $('#intro-update').html(intro);
141 var mail = $(data).find('mail').text();
142 if(mail == 0) { mail = ''; $('#mail-update').removeClass('show') } else { $('#mail-update').addClass('show') }
143 $('#mail-update').html(mail);
145 var intro = $(data).find('intro').text();
146 if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') }
147 $('#intro-update-li').html(intro);
149 var mail = $(data).find('mail').text();
150 if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') }
151 $('#mail-update-li').html(mail);
154 var allevents = $(data).find('all-events').text();
155 if(allevents == 0) { allevents = ''; $('#allevents-update').removeClass('show') } else { $('#allevents-update').addClass('show') }
156 $('#allevents-update').html(allevents);
158 var alleventstoday = $(data).find('all-events-today').text();
159 if(alleventstoday == 0) { $('#allevents-update').removeClass('notif-allevents-today') } else { $('#allevents-update').addClass('notif-allevents-today') }
161 var events = $(data).find('events').text();
162 if(events == 0) { events = ''; $('#events-update').removeClass('show') } else { $('#events-update').addClass('show') }
163 $('#events-update').html(events);
165 var eventstoday = $(data).find('events-today').text();
166 if(eventstoday == 0) { $('#events-update').removeClass('notif-events-today') } else { $('#events-update').addClass('notif-events-today') }
168 var birthdays = $(data).find('birthdays').text();
169 if(birthdays == 0) {birthdays = ''; $('#birthdays-update').removeClass('show') } else { $('#birthdays-update').addClass('show') }
170 $('#birthdays-update').html(birthdays);
172 var birthdaystoday = $(data).find('birthdays-today').text();
173 if(birthdaystoday == 0) { $('#birthdays-update').removeClass('notif-birthdays-today') } else { $('#birthdays-update').addClass('notif-birthdays-today') }
176 var eNotif = $(data).find('notif')
178 if (eNotif.children("note").length==0){
179 $("#nav-notifications-menu").html(notifications_empty);
181 nnm = $("#nav-notifications-menu");
182 nnm.html(notifications_all + notifications_mark);
183 //nnm.attr('popup','true');
185 var notification_lastitem = localStorage.getItem("notification-lastitem");
186 var notification_first_id = 0;
188 eNotif.children("note").each(function(){
190 text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
191 html = notifications_tpl.format(e.attr('href'),e.attr('photo'), text, e.attr('date'), e.attr('seen'));
194 var notification_id = e.attr('href').match(/\d+$/)[0];
195 console.log(notification_lastitem, notification_id);
196 if (notification_lastitem!== null && notification_id!=notification_lastitem) {
197 console.log( "eh!",getNotificationPermission() );
198 if (notification_first_id===0) notification_first_id = notification_id;
199 if (getNotificationPermission()==="granted") {
200 var notification = new Notification(document.title, {
201 body: e.text().replace('→ ','').format(e.attr('name')),
202 icon: e.attr('photo'),
204 // close notification after 5 secs.
205 // see https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API#Closing_notifications
206 setTimeout(notification.close.bind(notification), 5000);
208 notification.addEventListener("click", function(ev){
209 window.location = ev.target.data;
213 if (notification_id == notification_lastitem) {
214 if (notification_first_id===0) notification_first_id = notification_id;
215 notification_lastitem = null;
220 if (notification_first_id!==0) notification_lastitem = notification_first_id;
221 console.log("end:", notification_lastitem, notification_first_id);
222 localStorage.setItem("notification-lastitem", notification_lastitem)
224 $("img[data-src]", nnm).each(function(i, el){
225 // Add src attribute for images with a data-src attribute
226 // However, don't bother if the data-src attribute is empty, because
227 // an empty "src" tag for an image will cause some browsers
228 // to prefetch the root page of the Friendica hub, which will
229 // unnecessarily load an entire profile/ or network/ page
230 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
234 notif = eNotif.attr('count');
236 $("#nav-notifications-linkmenu").addClass("on");
238 $("#nav-notifications-linkmenu").removeClass("on");
240 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
241 $('#notify-update').html(notif);
243 var eSysmsg = $(data).find('sysmsgs');
244 eSysmsg.children("notice").each(function(){
245 text = $(this).text();
246 $.jGrowl(text, { sticky: true, theme: 'notice' });
248 eSysmsg.children("info").each(function(){
249 text = $(this).text();
250 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
256 // Allow folks to stop the ajax page updates with the pause/break key
257 $(document).keydown(function(event) {
258 if(event.keyCode == '8') {
259 var target = event.target || event.srcElement;
260 if (!/input|textarea/i.test(target.nodeName)) {
264 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
265 event.preventDefault();
266 if(stopped == false) {
271 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
285 function NavUpdate() {
288 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
289 $.get(pingCmd,function(data) {
290 $(data).find('result').each(function() {
291 // send nav-update event
292 $('nav').trigger('nav-update', this);
297 if($('#live-network').length) { src = 'network'; liveUpdate(); }
298 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
299 if($('#live-community').length) { src = 'community'; liveUpdate(); }
300 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
301 if($('#live-display').length) { src = 'display'; liveUpdate(); }
302 /* if($('#live-display').length) {
305 window.location.href=window.location.href
308 if($('#live-photos').length) {
311 window.location.href=window.location.href
321 timer = setTimeout(NavUpdate,updateInterval);
324 function liveUpdate() {
325 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
326 if(($('.comment-edit-text-full').length) || (in_progress)) {
328 clearTimeout(livetime);
330 livetime = setTimeout(liveUpdate, 5000);
336 prev = 'live-' + src;
340 if ($(document).scrollTop() == 0)
343 var udargs = ((netargs.length) ? '/' + netargs : '');
344 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
346 $.get(update_url,function(data) {
348 force_update = false;
349 // $('.collapsed-comments',data).each(function() {
350 // var ident = $(this).attr('id');
351 // var is_hidden = $('#' + ident).is(':hidden');
352 // if($('#' + ident).length) {
353 // $('#' + ident).replaceWith($(this));
355 // $('#' + ident).hide();
360 $('.toplevel_item',data).each(function() {
361 var ident = $(this).attr('id');
363 if($('#' + ident).length == 0 && profile_page == 1) {
364 $('img',this).each(function() {
365 $(this).attr('src',$(this).attr('dst'));
367 $('#' + prev).after($(this));
370 // Find out if the hidden comments are open, so we can keep it that way
371 // if a new comment has been posted
372 var id = $('.hide-comments-total', this).attr('id');
373 if(typeof id != 'undefined') {
374 id = id.split('-')[3];
375 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
378 $('img',this).each(function() {
379 $(this).attr('src',$(this).attr('dst'));
381 //vScroll = $(document).scrollTop();
382 $('html').height($('html').height());
383 $('#' + ident).replaceWith($(this));
385 if(typeof id != 'undefined') {
386 if(commentsOpen) showHideComments(id);
388 $('html').height('auto');
389 //$(document).scrollTop(vScroll);
394 // reset vars for inserting individual items
396 /* prev = 'live-' + src;
398 $('.wall-item-outside-wrapper',data).each(function() {
399 var ident = $(this).attr('id');
401 if($('#' + ident).length == 0 && prev != 'live-' + src) {
402 $('img',this).each(function() {
403 $(this).attr('src',$(this).attr('dst'));
405 $('#' + prev).after($(this));
408 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
409 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
410 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
411 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
412 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
413 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
414 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
415 $(this).attr('src',$(this).attr('dst'));
421 $('.like-rotator').hide();
424 $('body').css('cursor', 'auto');
426 /* autocomplete @nicknames */
427 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
429 // setup videos, since VideoJS won't take care of any loaded via AJAX
430 if(typeof videojs != 'undefined') videojs.autoSetup();
434 function imgbright(node) {
435 $(node).removeClass("drophide").addClass("drop");
438 function imgdull(node) {
439 $(node).removeClass("drop").addClass("drophide");
442 // Since our ajax calls are asynchronous, we will give a few
443 // seconds for the first ajax call (setting like/dislike), then
444 // run the updater to pick up any changes and display on the page.
445 // The updater will turn any rotators off when it's done.
446 // This function will have returned long before any of these
447 // events have completed and therefore there won't be any
448 // visible feedback that anything changed without all this
449 // trickery. This still could cause confusion if the "like" ajax call
450 // is delayed and NavUpdate runs before it completes.
452 function dolike(ident,verb) {
454 $('#like-rotator-' + ident.toString()).show();
455 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
460 function dosubthread(ident) {
462 $('#like-rotator-' + ident.toString()).show();
463 $.get('subthread/' + ident.toString(), NavUpdate );
468 function dostar(ident) {
469 ident = ident.toString();
470 $('#like-rotator-' + ident).show();
471 $.get('starred/' + ident, function(data) {
472 if(data.match(/1/)) {
473 $('#starred-' + ident).addClass('starred');
474 $('#starred-' + ident).removeClass('unstarred');
475 $('#star-' + ident).addClass('hidden');
476 $('#unstar-' + ident).removeClass('hidden');
479 $('#starred-' + ident).addClass('unstarred');
480 $('#starred-' + ident).removeClass('starred');
481 $('#star-' + ident).removeClass('hidden');
482 $('#unstar-' + ident).addClass('hidden');
484 $('#like-rotator-' + ident).hide();
488 function doignore(ident) {
489 ident = ident.toString();
490 $('#like-rotator-' + ident).show();
491 $.get('ignored/' + ident, function(data) {
492 if(data.match(/1/)) {
493 $('#ignored-' + ident).addClass('ignored');
494 $('#ignored-' + ident).removeClass('unignored');
495 $('#ignore-' + ident).addClass('hidden');
496 $('#unignore-' + ident).removeClass('hidden');
499 $('#ignored-' + ident).addClass('unignored');
500 $('#ignored-' + ident).removeClass('ignored');
501 $('#ignore-' + ident).removeClass('hidden');
502 $('#unignore-' + ident).addClass('hidden');
504 $('#like-rotator-' + ident).hide();
508 function getPosition(e) {
509 var cursor = {x:0, y:0};
510 if ( e.pageX || e.pageY ) {
515 if( e.clientX || e.clientY ) {
516 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
517 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
529 var lockvisible = false;
531 function lockview(event,id) {
532 event = event || window.event;
533 cursor = getPosition(event);
539 $.get('lockview/' + id, function(data) {
540 $('#panel').html(data);
541 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
547 function lockviewhide() {
552 function post_comment(id) {
555 $('body').css('cursor', 'wait');
556 $("#comment-preview-inp-" + id).val("0");
559 $("#comment-edit-form-" + id).serialize(),
562 $("#comment-edit-wrapper-" + id).hide();
563 $("#comment-edit-text-" + id).val('');
564 var tarea = document.getElementById("comment-edit-text-" + id);
566 commentClose(tarea,id);
567 if(timer) clearTimeout(timer);
568 timer = setTimeout(NavUpdate,10);
572 window.location.href=data.reload;
581 function preview_comment(id) {
582 $("#comment-preview-inp-" + id).val("1");
583 $("#comment-edit-preview-" + id).show();
586 $("#comment-edit-form-" + id).serialize(),
590 $("#comment-edit-preview-" + id).html(data.preview);
591 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
601 function showHideComments(id) {
602 if( $("#collapsed-comments-" + id).is(":visible")) {
603 $("#collapsed-comments-" + id).hide();
604 $("#hide-comments-" + id).html(window.showMore);
607 $("#collapsed-comments-" + id).show();
608 $("#hide-comments-" + id).html(window.showFewer);
614 function preview_post() {
615 $("#jot-preview").val("1");
616 $("#jot-preview-content").show();
617 tinyMCE.triggerSave();
620 $("#profile-jot-form").serialize(),
623 $("#jot-preview-content").html(data.preview);
624 $("#jot-preview-content" + " a").click(function() { return false; });
629 $("#jot-preview").val("0");
635 // unpause auto reloads if they are currently stopped
638 $('#pause').html('');
643 // Converts the binary representation of data to hex
646 // discuss at: http://phpjs.org/functions/bin2hex
647 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
648 // + bugfixed by: Onno Marsman
649 // + bugfixed by: Linuxworld
650 // * example 1: bin2hex('Kev');
651 // * returns 1: '4b6576'
652 // * example 2: bin2hex(String.fromCharCode(0x00));
654 var v,i, f = 0, a = [];
658 for (i = 0; i<f; i++) {
659 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
665 function groupChangeMember(gid, cid, sec_token) {
666 $('body .fakelink').css('cursor', 'wait');
667 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
668 $('#group-update-wrapper').html(data);
669 $('body .fakelink').css('cursor', 'auto');
673 function profChangeMember(gid,cid) {
674 $('body .fakelink').css('cursor', 'wait');
675 $.get('profperm/' + gid + '/' + cid, function(data) {
676 $('#prof-update-wrapper').html(data);
677 $('body .fakelink').css('cursor', 'auto');
681 function contactgroupChangeMember(gid,cid) {
682 $('body').css('cursor', 'wait');
683 $.get('contactgroup/' + gid + '/' + cid, function(data) {
684 $('body').css('cursor', 'auto');
689 function checkboxhighlight(box) {
690 if($(box).is(':checked')) {
691 $(box).addClass('checkeditem');
694 $(box).removeClass('checkeditem');
698 function notifyMarkAll() {
699 $.get('notify/mark/all', function(data) {
700 if(timer) clearTimeout(timer);
701 timer = setTimeout(NavUpdate,1000);
707 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
708 function fcFileBrowser (field_name, url, type, win) {
709 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
710 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
711 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
714 var cmsURL = baseurl+"/fbrowser/"+type+"/";
716 tinyMCE.activeEditor.windowManager.open({
718 title : 'File Browser',
719 width : 420, // Your dimensions may differ - toy around with them!
722 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
723 close_previous : "no"
731 function setupFieldRichtext(){
734 mode : "specific_textareas",
735 editor_selector: "fieldRichtext",
736 plugins : "bbcode,paste, inlinepopups",
737 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
738 theme_advanced_buttons2 : "",
739 theme_advanced_buttons3 : "",
740 theme_advanced_toolbar_location : "top",
741 theme_advanced_toolbar_align : "center",
742 theme_advanced_blockformats : "blockquote,code",
743 theme_advanced_resizing : true,
744 paste_text_sticky : true,
745 entity_encoding : "raw",
746 add_unload_trigger : false,
747 remove_linebreaks : false,
748 //force_p_newlines : false,
749 //force_br_newlines : true,
750 forced_root_block : 'div',
752 content_css: baseurl+"/view/custom_tinymce.css",
753 theme_advanced_path : false,
754 file_browser_callback : "fcFileBrowser",
760 * sprintf in javascript
761 * "{0} and {1}".format('zero','uno');
763 String.prototype.format = function() {
764 var formatted = this;
765 for (var i = 0; i < arguments.length; i++) {
766 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
767 formatted = formatted.replace(regexp, arguments[i]);
772 Array.prototype.remove = function(item) {
773 to=undefined; from=this.indexOf(item);
774 var rest = this.slice((to || from) + 1 || this.length);
775 this.length = from < 0 ? this.length + from : from;
776 return this.push.apply(this, rest);
779 function previewTheme(elm) {
780 theme = $(elm).val();
781 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
782 $('#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>');
787 // notification permission settings in localstorage
788 // set by settings page
789 function getNotificationPermission() {
790 if (window.Notification === undefined) {
793 if (Notification.permission === 'granted') {
794 return localStorage.getItem('notification-permissions');
796 return Notification.permission;