2 function openClose(theID) {
3 if(document.getElementById(theID).style.display == "block") {
4 document.getElementById(theID).style.display = "none"
7 document.getElementById(theID).style.display = "block"
11 function openMenu(theID) {
12 document.getElementById(theID).style.display = "block"
15 function closeMenu(theID) {
16 document.getElementById(theID).style.display = "none"
24 var force_update = false;
26 var totStopped = false;
30 var in_progress = false;
31 var langSelect = false;
32 var commentBusy = false;
33 var last_popup_menu = null;
34 var last_popup_button = null;
37 $.ajaxSetup({cache: false});
39 /* setup tooltips *//*
40 $("a,.tt").each(function(){
43 if (e.hasClass("tttop")) pos="top";
44 if (e.hasClass("ttbottom")) pos="bottom";
45 if (e.hasClass("ttleft")) pos="left";
46 if (e.hasClass("ttright")) pos="right";
47 e.tipTip({defaultPosition: pos, edgeOffset: 8});
52 /* setup onoff widgets */
53 $(".onoff input").each(function(){
55 id = $(this).attr("id");
56 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
59 $(".onoff > a").click(function(event){
60 event.preventDefault();
61 var input = $(this).siblings("input");
62 var val = 1-input.val();
63 var id = input.attr("id");
64 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
65 $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden");
70 /* setup field_richtext */
74 function close_last_popup_menu() {
76 last_popup_menu.hide();
77 last_popup_button.removeClass("selected");
78 last_popup_menu = null;
79 last_popup_button = null;
82 $('a[rel^=#]').click(function(e){
84 var parent = $(this).parent();
85 var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id'));
86 close_last_popup_menu();
87 if(isSelected) return false;
88 menu = $( $(this).attr('rel') );
91 if (menu.attr('popup')=="false") return false;
92 parent.toggleClass("selected");
94 if (menu.css("display") == "none") {
95 last_popup_menu = null;
96 last_popup_button = null;
98 last_popup_menu = menu;
99 last_popup_button = parent;
103 $('html').click(function() {
104 close_last_popup_menu();
108 $("a.popupbox").colorbox({
110 'transition' : 'elastic'
114 /* notifications template */
115 var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html());
116 var notifications_all = unescape($('<div>').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack
117 var notifications_mark = unescape($('<div>').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack
118 var notifications_empty = unescape($("#nav-notifications-menu").html());
120 /* nav update event */
121 $('nav').bind('nav-update', function(e,data){;
122 var invalid = $(data).find('invalid').text();
123 if(invalid == 1) { window.location.href=window.location.href }
125 var net = $(data).find('net').text();
126 if(net == 0) { net = ''; $('#net-update').removeClass('show') } else { $('#net-update').addClass('show') }
127 $('#net-update').html(net);
129 var home = $(data).find('home').text();
130 if(home == 0) { home = ''; $('#home-update').removeClass('show') } else { $('#home-update').addClass('show') }
131 $('#home-update').html(home);
133 var intro = $(data).find('intro').text();
134 if(intro == 0) { intro = ''; $('#intro-update').removeClass('show') } else { $('#intro-update').addClass('show') }
135 $('#intro-update').html(intro);
137 var mail = $(data).find('mail').text();
138 if(mail == 0) { mail = ''; $('#mail-update').removeClass('show') } else { $('#mail-update').addClass('show') }
139 $('#mail-update').html(mail);
141 var intro = $(data).find('intro').text();
142 if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') }
143 $('#intro-update-li').html(intro);
145 var mail = $(data).find('mail').text();
146 if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') }
147 $('#mail-update-li').html(mail);
150 var allevents = $(data).find('all-events').text();
151 if(allevents == 0) { allevents = ''; $('#allevents-update').removeClass('show') } else { $('#allevents-update').addClass('show') }
152 $('#allevents-update').html(allevents);
154 var alleventstoday = $(data).find('all-events-today').text();
155 if(alleventstoday == 0) { $('#allevents-update').removeClass('notif-allevents-today') } else { $('#allevents-update').addClass('notif-allevents-today') }
157 var events = $(data).find('events').text();
158 if(events == 0) { events = ''; $('#events-update').removeClass('show') } else { $('#events-update').addClass('show') }
159 $('#events-update').html(events);
161 var eventstoday = $(data).find('events-today').text();
162 if(eventstoday == 0) { $('#events-update').removeClass('notif-events-today') } else { $('#events-update').addClass('notif-events-today') }
164 var birthdays = $(data).find('birthdays').text();
165 if(birthdays == 0) {birthdays = ''; $('#birthdays-update').removeClass('show') } else { $('#birthdays-update').addClass('show') }
166 $('#birthdays-update').html(birthdays);
168 var birthdaystoday = $(data).find('birthdays-today').text();
169 if(birthdaystoday == 0) { $('#birthdays-update').removeClass('notif-birthdays-today') } else { $('#birthdays-update').addClass('notif-birthdays-today') }
172 var eNotif = $(data).find('notif')
174 if (eNotif.children("note").length==0){
175 $("#nav-notifications-menu").html(notifications_empty);
177 nnm = $("#nav-notifications-menu");
178 nnm.html(notifications_all + notifications_mark);
179 //nnm.attr('popup','true');
180 eNotif.children("note").each(function(){
182 text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
183 html = notifications_tpl.format(e.attr('href'),e.attr('photo'), text, e.attr('date'), e.attr('seen'));
187 $("img[data-src]", nnm).each(function(i, el){
188 // Add src attribute for images with a data-src attribute
189 // However, don't bother if the data-src attribute is empty, because
190 // an empty "src" tag for an image will cause some browsers
191 // to prefetch the root page of the Friendica hub, which will
192 // unnecessarily load an entire profile/ or network/ page
193 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
197 notif = eNotif.attr('count');
199 $("#nav-notifications-linkmenu").addClass("on");
201 $("#nav-notifications-linkmenu").removeClass("on");
203 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
204 $('#notify-update').html(notif);
206 var eSysmsg = $(data).find('sysmsgs');
207 eSysmsg.children("notice").each(function(){
208 text = $(this).text();
209 $.jGrowl(text, { sticky: true, theme: 'notice' });
211 eSysmsg.children("info").each(function(){
212 text = $(this).text();
213 $.jGrowl(text, { sticky: false, theme: 'info', life: 10000 });
219 // Allow folks to stop the ajax page updates with the pause/break key
220 $(document).keydown(function(event) {
221 if(event.keyCode == '8') {
222 var target = event.target || event.srcElement;
223 if (!/input|textarea/i.test(target.nodeName)) {
227 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
228 event.preventDefault();
229 if(stopped == false) {
234 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
248 function NavUpdate() {
251 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
252 $.get(pingCmd,function(data) {
253 $(data).find('result').each(function() {
254 // send nav-update event
255 $('nav').trigger('nav-update', this);
260 if($('#live-network').length) { src = 'network'; liveUpdate(); }
261 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
262 if($('#live-community').length) { src = 'community'; liveUpdate(); }
263 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
264 if($('#live-display').length) { src = 'display'; liveUpdate(); }
265 /* if($('#live-display').length) {
268 window.location.href=window.location.href
271 if($('#live-photos').length) {
274 window.location.href=window.location.href
284 timer = setTimeout(NavUpdate,updateInterval);
287 function liveUpdate() {
288 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
289 if(($('.comment-edit-text-full').length) || (in_progress)) {
291 clearTimeout(livetime);
293 livetime = setTimeout(liveUpdate, 10000);
299 prev = 'live-' + src;
303 if ($(document).scrollTop() == 0)
306 var udargs = ((netargs.length) ? '/' + netargs : '');
307 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
309 $.get(update_url,function(data) {
311 force_update = false;
312 // $('.collapsed-comments',data).each(function() {
313 // var ident = $(this).attr('id');
314 // var is_hidden = $('#' + ident).is(':hidden');
315 // if($('#' + ident).length) {
316 // $('#' + ident).replaceWith($(this));
318 // $('#' + ident).hide();
323 $('.toplevel_item',data).each(function() {
324 var ident = $(this).attr('id');
326 if($('#' + ident).length == 0 && profile_page == 1) {
327 $('img',this).each(function() {
328 $(this).attr('src',$(this).attr('dst'));
330 $('#' + prev).after($(this));
333 // Find out if the hidden comments are open, so we can keep it that way
334 // if a new comment has been posted
335 var id = $('.hide-comments-total', this).attr('id');
336 if(typeof id != 'undefined') {
337 id = id.split('-')[3];
338 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
341 $('img',this).each(function() {
342 $(this).attr('src',$(this).attr('dst'));
344 //vScroll = $(document).scrollTop();
345 $('html').height($('html').height());
346 $('#' + ident).replaceWith($(this));
348 if(typeof id != 'undefined') {
349 if(commentsOpen) showHideComments(id);
351 $('html').height('auto');
352 //$(document).scrollTop(vScroll);
357 // reset vars for inserting individual items
359 /* prev = 'live-' + src;
361 $('.wall-item-outside-wrapper',data).each(function() {
362 var ident = $(this).attr('id');
364 if($('#' + ident).length == 0 && prev != 'live-' + src) {
365 $('img',this).each(function() {
366 $(this).attr('src',$(this).attr('dst'));
368 $('#' + prev).after($(this));
371 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
372 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
373 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
374 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
375 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
376 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
377 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
378 $(this).attr('src',$(this).attr('dst'));
384 $('.like-rotator').hide();
387 $('body').css('cursor', 'auto');
389 /* autocomplete @nicknames */
390 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
392 // setup videos, since VideoJS won't take care of any loaded via AJAX
393 if(typeof videojs != 'undefined') videojs.autoSetup();
397 function imgbright(node) {
398 $(node).removeClass("drophide").addClass("drop");
401 function imgdull(node) {
402 $(node).removeClass("drop").addClass("drophide");
405 // Since our ajax calls are asynchronous, we will give a few
406 // seconds for the first ajax call (setting like/dislike), then
407 // run the updater to pick up any changes and display on the page.
408 // The updater will turn any rotators off when it's done.
409 // This function will have returned long before any of these
410 // events have completed and therefore there won't be any
411 // visible feedback that anything changed without all this
412 // trickery. This still could cause confusion if the "like" ajax call
413 // is delayed and NavUpdate runs before it completes.
415 function dolike(ident,verb) {
417 $('#like-rotator-' + ident.toString()).show();
418 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
423 function dosubthread(ident) {
425 $('#like-rotator-' + ident.toString()).show();
426 $.get('subthread/' + ident.toString(), NavUpdate );
431 function dostar(ident) {
432 ident = ident.toString();
433 $('#like-rotator-' + ident).show();
434 $.get('starred/' + ident, function(data) {
435 if(data.match(/1/)) {
436 $('#starred-' + ident).addClass('starred');
437 $('#starred-' + ident).removeClass('unstarred');
438 $('#star-' + ident).addClass('hidden');
439 $('#unstar-' + ident).removeClass('hidden');
442 $('#starred-' + ident).addClass('unstarred');
443 $('#starred-' + ident).removeClass('starred');
444 $('#star-' + ident).removeClass('hidden');
445 $('#unstar-' + ident).addClass('hidden');
447 $('#like-rotator-' + ident).hide();
451 function doignore(ident) {
452 ident = ident.toString();
453 $('#like-rotator-' + ident).show();
454 $.get('ignored/' + ident, function(data) {
455 if(data.match(/1/)) {
456 $('#ignored-' + ident).addClass('ignored');
457 $('#ignored-' + ident).removeClass('unignored');
458 $('#ignore-' + ident).addClass('hidden');
459 $('#unignore-' + ident).removeClass('hidden');
462 $('#ignored-' + ident).addClass('unignored');
463 $('#ignored-' + ident).removeClass('ignored');
464 $('#ignore-' + ident).removeClass('hidden');
465 $('#unignore-' + ident).addClass('hidden');
467 $('#like-rotator-' + ident).hide();
471 function getPosition(e) {
472 var cursor = {x:0, y:0};
473 if ( e.pageX || e.pageY ) {
478 if( e.clientX || e.clientY ) {
479 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
480 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
492 var lockvisible = false;
494 function lockview(event,id) {
495 event = event || window.event;
496 cursor = getPosition(event);
502 $.get('lockview/' + id, function(data) {
503 $('#panel').html(data);
504 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
510 function lockviewhide() {
515 function post_comment(id) {
518 $('body').css('cursor', 'wait');
519 $("#comment-preview-inp-" + id).val("0");
522 $("#comment-edit-form-" + id).serialize(),
525 $("#comment-edit-wrapper-" + id).hide();
526 $("#comment-edit-text-" + id).val('');
527 var tarea = document.getElementById("comment-edit-text-" + id);
529 commentClose(tarea,id);
530 if(timer) clearTimeout(timer);
531 timer = setTimeout(NavUpdate,10);
535 window.location.href=data.reload;
544 function preview_comment(id) {
545 $("#comment-preview-inp-" + id).val("1");
546 $("#comment-edit-preview-" + id).show();
549 $("#comment-edit-form-" + id).serialize(),
553 $("#comment-edit-preview-" + id).html(data.preview);
554 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
564 function showHideComments(id) {
565 if( $("#collapsed-comments-" + id).is(":visible")) {
566 $("#collapsed-comments-" + id).hide();
567 $("#hide-comments-" + id).html(window.showMore);
570 $("#collapsed-comments-" + id).show();
571 $("#hide-comments-" + id).html(window.showFewer);
577 function preview_post() {
578 $("#jot-preview").val("1");
579 $("#jot-preview-content").show();
580 tinyMCE.triggerSave();
583 $("#profile-jot-form").serialize(),
586 $("#jot-preview-content").html(data.preview);
587 $("#jot-preview-content" + " a").click(function() { return false; });
592 $("#jot-preview").val("0");
598 // unpause auto reloads if they are currently stopped
601 $('#pause').html('');
606 // Converts the binary representation of data to hex
609 // discuss at: http://phpjs.org/functions/bin2hex
610 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
611 // + bugfixed by: Onno Marsman
612 // + bugfixed by: Linuxworld
613 // * example 1: bin2hex('Kev');
614 // * returns 1: '4b6576'
615 // * example 2: bin2hex(String.fromCharCode(0x00));
617 var v,i, f = 0, a = [];
621 for (i = 0; i<f; i++) {
622 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
628 function groupChangeMember(gid, cid, sec_token) {
629 $('body .fakelink').css('cursor', 'wait');
630 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
631 $('#group-update-wrapper').html(data);
632 $('body .fakelink').css('cursor', 'auto');
636 function profChangeMember(gid,cid) {
637 $('body .fakelink').css('cursor', 'wait');
638 $.get('profperm/' + gid + '/' + cid, function(data) {
639 $('#prof-update-wrapper').html(data);
640 $('body .fakelink').css('cursor', 'auto');
644 function contactgroupChangeMember(gid,cid) {
645 $('body').css('cursor', 'wait');
646 $.get('contactgroup/' + gid + '/' + cid, function(data) {
647 $('body').css('cursor', 'auto');
652 function checkboxhighlight(box) {
653 if($(box).is(':checked')) {
654 $(box).addClass('checkeditem');
657 $(box).removeClass('checkeditem');
661 function notifyMarkAll() {
662 $.get('notify/mark/all', function(data) {
663 if(timer) clearTimeout(timer);
664 timer = setTimeout(NavUpdate,1000);
670 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
671 function fcFileBrowser (field_name, url, type, win) {
672 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
673 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
674 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
677 var cmsURL = baseurl+"/fbrowser/"+type+"/";
679 tinyMCE.activeEditor.windowManager.open({
681 title : 'File Browser',
682 width : 420, // Your dimensions may differ - toy around with them!
685 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
686 close_previous : "no"
694 function setupFieldRichtext(){
697 mode : "specific_textareas",
698 editor_selector: "fieldRichtext",
699 plugins : "bbcode,paste, inlinepopups",
700 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
701 theme_advanced_buttons2 : "",
702 theme_advanced_buttons3 : "",
703 theme_advanced_toolbar_location : "top",
704 theme_advanced_toolbar_align : "center",
705 theme_advanced_blockformats : "blockquote,code",
706 theme_advanced_resizing : true,
707 paste_text_sticky : true,
708 entity_encoding : "raw",
709 add_unload_trigger : false,
710 remove_linebreaks : false,
711 //force_p_newlines : false,
712 //force_br_newlines : true,
713 forced_root_block : 'div',
715 content_css: baseurl+"/view/custom_tinymce.css",
716 theme_advanced_path : false,
717 file_browser_callback : "fcFileBrowser",
723 * sprintf in javascript
724 * "{0} and {1}".format('zero','uno');
726 String.prototype.format = function() {
727 var formatted = this;
728 for (var i = 0; i < arguments.length; i++) {
729 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
730 formatted = formatted.replace(regexp, arguments[i]);
735 Array.prototype.remove = function(item) {
736 to=undefined; from=this.indexOf(item);
737 var rest = this.slice((to || from) + 1 || this.length);
738 this.length = from < 0 ? this.length + from : from;
739 return this.push.apply(this, rest);
742 function previewTheme(elm) {
743 theme = $(elm).val();
744 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
745 $('#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>');