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 = parseInt(localStorage.getItem("notification-lastitem"));
186 var notification_id = 0;
187 eNotif.children("note").each(function(){
189 text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
190 html = notifications_tpl.format(e.attr('href'),e.attr('photo'), text, e.attr('date'), e.attr('seen'));
193 $(eNotif.children("note").get().reverse()).each(function(){
195 notification_id = parseInt(e.attr('href').match(/\d+$/)[0]);
196 if (notification_lastitem!== null && notification_id > notification_lastitem) {
197 if (getNotificationPermission()==="granted") {
198 var notification = new Notification(document.title, {
199 body: e.text().replace('→ ','').format(e.attr('name')),
200 icon: e.attr('photo'),
202 notification['url'] = e.attr('href');
203 notification.addEventListener("click", function(ev){
204 window.location = ev.target.url;
210 notification_lastitem = notification_id;
211 localStorage.setItem("notification-lastitem", notification_lastitem)
213 $("img[data-src]", nnm).each(function(i, el){
214 // Add src attribute for images with a data-src attribute
215 // However, don't bother if the data-src attribute is empty, because
216 // an empty "src" tag for an image will cause some browsers
217 // to prefetch the root page of the Friendica hub, which will
218 // unnecessarily load an entire profile/ or network/ page
219 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
223 notif = eNotif.attr('count');
225 $("#nav-notifications-linkmenu").addClass("on");
227 $("#nav-notifications-linkmenu").removeClass("on");
229 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
230 $('#notify-update').html(notif);
232 var eSysmsg = $(data).find('sysmsgs');
233 eSysmsg.children("notice").each(function(){
234 text = $(this).text();
235 $.jGrowl(text, { sticky: true, theme: 'notice' });
237 eSysmsg.children("info").each(function(){
238 text = $(this).text();
239 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
245 // Allow folks to stop the ajax page updates with the pause/break key
246 $(document).keydown(function(event) {
247 if(event.keyCode == '8') {
248 var target = event.target || event.srcElement;
249 if (!/input|textarea/i.test(target.nodeName)) {
253 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
254 event.preventDefault();
255 if(stopped == false) {
260 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
274 function NavUpdate() {
277 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
278 $.get(pingCmd,function(data) {
279 $(data).find('result').each(function() {
280 // send nav-update event
281 $('nav').trigger('nav-update', this);
286 if($('#live-network').length) { src = 'network'; liveUpdate(); }
287 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
288 if($('#live-community').length) { src = 'community'; liveUpdate(); }
289 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
290 if($('#live-display').length) { src = 'display'; liveUpdate(); }
291 /* if($('#live-display').length) {
294 window.location.href=window.location.href
297 if($('#live-photos').length) {
300 window.location.href=window.location.href
310 timer = setTimeout(NavUpdate,updateInterval);
313 function liveUpdate() {
314 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
315 if(($('.comment-edit-text-full').length) || (in_progress)) {
317 clearTimeout(livetime);
319 livetime = setTimeout(liveUpdate, 5000);
325 prev = 'live-' + src;
329 if ($(document).scrollTop() == 0)
332 var udargs = ((netargs.length) ? '/' + netargs : '');
333 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
335 $.get(update_url,function(data) {
337 force_update = false;
338 // $('.collapsed-comments',data).each(function() {
339 // var ident = $(this).attr('id');
340 // var is_hidden = $('#' + ident).is(':hidden');
341 // if($('#' + ident).length) {
342 // $('#' + ident).replaceWith($(this));
344 // $('#' + ident).hide();
349 $('.toplevel_item',data).each(function() {
350 var ident = $(this).attr('id');
352 if($('#' + ident).length == 0 && profile_page == 1) {
353 $('img',this).each(function() {
354 $(this).attr('src',$(this).attr('dst'));
356 $('#' + prev).after($(this));
359 // Find out if the hidden comments are open, so we can keep it that way
360 // if a new comment has been posted
361 var id = $('.hide-comments-total', this).attr('id');
362 if(typeof id != 'undefined') {
363 id = id.split('-')[3];
364 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
367 $('img',this).each(function() {
368 $(this).attr('src',$(this).attr('dst'));
370 //vScroll = $(document).scrollTop();
371 $('html').height($('html').height());
372 $('#' + ident).replaceWith($(this));
374 if(typeof id != 'undefined') {
375 if(commentsOpen) showHideComments(id);
377 $('html').height('auto');
378 //$(document).scrollTop(vScroll);
383 // reset vars for inserting individual items
385 /* prev = 'live-' + src;
387 $('.wall-item-outside-wrapper',data).each(function() {
388 var ident = $(this).attr('id');
390 if($('#' + ident).length == 0 && prev != 'live-' + src) {
391 $('img',this).each(function() {
392 $(this).attr('src',$(this).attr('dst'));
394 $('#' + prev).after($(this));
397 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
398 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
399 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
400 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
401 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
402 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
403 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
404 $(this).attr('src',$(this).attr('dst'));
410 $('.like-rotator').hide();
413 $('body').css('cursor', 'auto');
415 /* autocomplete @nicknames */
416 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
418 // setup videos, since VideoJS won't take care of any loaded via AJAX
419 if(typeof videojs != 'undefined') videojs.autoSetup();
423 function imgbright(node) {
424 $(node).removeClass("drophide").addClass("drop");
427 function imgdull(node) {
428 $(node).removeClass("drop").addClass("drophide");
431 // Since our ajax calls are asynchronous, we will give a few
432 // seconds for the first ajax call (setting like/dislike), then
433 // run the updater to pick up any changes and display on the page.
434 // The updater will turn any rotators off when it's done.
435 // This function will have returned long before any of these
436 // events have completed and therefore there won't be any
437 // visible feedback that anything changed without all this
438 // trickery. This still could cause confusion if the "like" ajax call
439 // is delayed and NavUpdate runs before it completes.
441 function dolike(ident,verb) {
443 $('#like-rotator-' + ident.toString()).show();
444 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
449 function dosubthread(ident) {
451 $('#like-rotator-' + ident.toString()).show();
452 $.get('subthread/' + ident.toString(), NavUpdate );
457 function dostar(ident) {
458 ident = ident.toString();
459 $('#like-rotator-' + ident).show();
460 $.get('starred/' + ident, function(data) {
461 if(data.match(/1/)) {
462 $('#starred-' + ident).addClass('starred');
463 $('#starred-' + ident).removeClass('unstarred');
464 $('#star-' + ident).addClass('hidden');
465 $('#unstar-' + ident).removeClass('hidden');
468 $('#starred-' + ident).addClass('unstarred');
469 $('#starred-' + ident).removeClass('starred');
470 $('#star-' + ident).removeClass('hidden');
471 $('#unstar-' + ident).addClass('hidden');
473 $('#like-rotator-' + ident).hide();
477 function doignore(ident) {
478 ident = ident.toString();
479 $('#like-rotator-' + ident).show();
480 $.get('ignored/' + ident, function(data) {
481 if(data.match(/1/)) {
482 $('#ignored-' + ident).addClass('ignored');
483 $('#ignored-' + ident).removeClass('unignored');
484 $('#ignore-' + ident).addClass('hidden');
485 $('#unignore-' + ident).removeClass('hidden');
488 $('#ignored-' + ident).addClass('unignored');
489 $('#ignored-' + ident).removeClass('ignored');
490 $('#ignore-' + ident).removeClass('hidden');
491 $('#unignore-' + ident).addClass('hidden');
493 $('#like-rotator-' + ident).hide();
497 function getPosition(e) {
498 var cursor = {x:0, y:0};
499 if ( e.pageX || e.pageY ) {
504 if( e.clientX || e.clientY ) {
505 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
506 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
518 var lockvisible = false;
520 function lockview(event,id) {
521 event = event || window.event;
522 cursor = getPosition(event);
528 $.get('lockview/' + id, function(data) {
529 $('#panel').html(data);
530 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
536 function lockviewhide() {
541 function post_comment(id) {
544 $('body').css('cursor', 'wait');
545 $("#comment-preview-inp-" + id).val("0");
548 $("#comment-edit-form-" + id).serialize(),
551 $("#comment-edit-wrapper-" + id).hide();
552 $("#comment-edit-text-" + id).val('');
553 var tarea = document.getElementById("comment-edit-text-" + id);
555 commentClose(tarea,id);
556 if(timer) clearTimeout(timer);
557 timer = setTimeout(NavUpdate,10);
561 window.location.href=data.reload;
570 function preview_comment(id) {
571 $("#comment-preview-inp-" + id).val("1");
572 $("#comment-edit-preview-" + id).show();
575 $("#comment-edit-form-" + id).serialize(),
579 $("#comment-edit-preview-" + id).html(data.preview);
580 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
590 function showHideComments(id) {
591 if( $("#collapsed-comments-" + id).is(":visible")) {
592 $("#collapsed-comments-" + id).hide();
593 $("#hide-comments-" + id).html(window.showMore);
596 $("#collapsed-comments-" + id).show();
597 $("#hide-comments-" + id).html(window.showFewer);
603 function preview_post() {
604 $("#jot-preview").val("1");
605 $("#jot-preview-content").show();
606 tinyMCE.triggerSave();
609 $("#profile-jot-form").serialize(),
612 $("#jot-preview-content").html(data.preview);
613 $("#jot-preview-content" + " a").click(function() { return false; });
618 $("#jot-preview").val("0");
624 // unpause auto reloads if they are currently stopped
627 $('#pause').html('');
632 // Converts the binary representation of data to hex
635 // discuss at: http://phpjs.org/functions/bin2hex
636 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
637 // + bugfixed by: Onno Marsman
638 // + bugfixed by: Linuxworld
639 // * example 1: bin2hex('Kev');
640 // * returns 1: '4b6576'
641 // * example 2: bin2hex(String.fromCharCode(0x00));
643 var v,i, f = 0, a = [];
647 for (i = 0; i<f; i++) {
648 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
654 function groupChangeMember(gid, cid, sec_token) {
655 $('body .fakelink').css('cursor', 'wait');
656 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
657 $('#group-update-wrapper').html(data);
658 $('body .fakelink').css('cursor', 'auto');
662 function profChangeMember(gid,cid) {
663 $('body .fakelink').css('cursor', 'wait');
664 $.get('profperm/' + gid + '/' + cid, function(data) {
665 $('#prof-update-wrapper').html(data);
666 $('body .fakelink').css('cursor', 'auto');
670 function contactgroupChangeMember(gid,cid) {
671 $('body').css('cursor', 'wait');
672 $.get('contactgroup/' + gid + '/' + cid, function(data) {
673 $('body').css('cursor', 'auto');
678 function checkboxhighlight(box) {
679 if($(box).is(':checked')) {
680 $(box).addClass('checkeditem');
683 $(box).removeClass('checkeditem');
687 function notifyMarkAll() {
688 $.get('notify/mark/all', function(data) {
689 if(timer) clearTimeout(timer);
690 timer = setTimeout(NavUpdate,1000);
696 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
697 function fcFileBrowser (field_name, url, type, win) {
698 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
699 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
700 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
703 var cmsURL = baseurl+"/fbrowser/"+type+"/";
705 tinyMCE.activeEditor.windowManager.open({
707 title : 'File Browser',
708 width : 420, // Your dimensions may differ - toy around with them!
711 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
712 close_previous : "no"
720 function setupFieldRichtext(){
723 mode : "specific_textareas",
724 editor_selector: "fieldRichtext",
725 plugins : "bbcode,paste, inlinepopups",
726 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
727 theme_advanced_buttons2 : "",
728 theme_advanced_buttons3 : "",
729 theme_advanced_toolbar_location : "top",
730 theme_advanced_toolbar_align : "center",
731 theme_advanced_blockformats : "blockquote,code",
732 theme_advanced_resizing : true,
733 paste_text_sticky : true,
734 entity_encoding : "raw",
735 add_unload_trigger : false,
736 remove_linebreaks : false,
737 //force_p_newlines : false,
738 //force_br_newlines : true,
739 forced_root_block : 'div',
741 content_css: baseurl+"/view/custom_tinymce.css",
742 theme_advanced_path : false,
743 file_browser_callback : "fcFileBrowser",
749 * sprintf in javascript
750 * "{0} and {1}".format('zero','uno');
752 String.prototype.format = function() {
753 var formatted = this;
754 for (var i = 0; i < arguments.length; i++) {
755 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
756 formatted = formatted.replace(regexp, arguments[i]);
761 Array.prototype.remove = function(item) {
762 to=undefined; from=this.indexOf(item);
763 var rest = this.slice((to || from) + 1 || this.length);
764 this.length = from < 0 ? this.length + from : from;
765 return this.push.apply(this, rest);
768 function previewTheme(elm) {
769 theme = $(elm).val();
770 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
771 $('#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>');
776 // notification permission settings in localstorage
777 // set by settings page
778 function getNotificationPermission() {
779 if (window["Notification"] === undefined) {
782 if (Notification.permission === 'granted') {
783 var val = localStorage.getItem('notification-permissions');
784 if (val === null) return 'denied';
787 return Notification.permission;