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'));
186 if(e.text().search('→') == 0) {
187 var notification = new Notification(document.title, {
188 body: e.text().replace('→ ',''),
189 icon: e.attr('photo')
192 // TODO (yet unsupported by most browsers):
193 // Implement notification.onclick()
199 $("img[data-src]", nnm).each(function(i, el){
200 // Add src attribute for images with a data-src attribute
201 // However, don't bother if the data-src attribute is empty, because
202 // an empty "src" tag for an image will cause some browsers
203 // to prefetch the root page of the Friendica hub, which will
204 // unnecessarily load an entire profile/ or network/ page
205 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
209 notif = eNotif.attr('count');
211 $("#nav-notifications-linkmenu").addClass("on");
213 $("#nav-notifications-linkmenu").removeClass("on");
215 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
216 $('#notify-update').html(notif);
218 var eSysmsg = $(data).find('sysmsgs');
219 eSysmsg.children("notice").each(function(){
220 text = $(this).text();
221 $.jGrowl(text, { sticky: true, theme: 'notice' });
223 eSysmsg.children("info").each(function(){
224 text = $(this).text();
225 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
231 // Allow folks to stop the ajax page updates with the pause/break key
232 $(document).keydown(function(event) {
233 if(event.keyCode == '8') {
234 var target = event.target || event.srcElement;
235 if (!/input|textarea/i.test(target.nodeName)) {
239 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
240 event.preventDefault();
241 if(stopped == false) {
246 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
260 function NavUpdate() {
263 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
264 $.get(pingCmd,function(data) {
265 $(data).find('result').each(function() {
266 // send nav-update event
267 $('nav').trigger('nav-update', this);
272 if($('#live-network').length) { src = 'network'; liveUpdate(); }
273 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
274 if($('#live-community').length) { src = 'community'; liveUpdate(); }
275 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
276 if($('#live-display').length) { src = 'display'; liveUpdate(); }
277 /* if($('#live-display').length) {
280 window.location.href=window.location.href
283 if($('#live-photos').length) {
286 window.location.href=window.location.href
296 timer = setTimeout(NavUpdate,updateInterval);
299 function liveUpdate() {
300 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
301 if(($('.comment-edit-text-full').length) || (in_progress)) {
303 clearTimeout(livetime);
305 livetime = setTimeout(liveUpdate, 5000);
311 prev = 'live-' + src;
315 if ($(document).scrollTop() == 0)
318 var udargs = ((netargs.length) ? '/' + netargs : '');
319 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
321 $.get(update_url,function(data) {
323 force_update = false;
324 // $('.collapsed-comments',data).each(function() {
325 // var ident = $(this).attr('id');
326 // var is_hidden = $('#' + ident).is(':hidden');
327 // if($('#' + ident).length) {
328 // $('#' + ident).replaceWith($(this));
330 // $('#' + ident).hide();
335 $('.toplevel_item',data).each(function() {
336 var ident = $(this).attr('id');
338 if($('#' + ident).length == 0 && profile_page == 1) {
339 $('img',this).each(function() {
340 $(this).attr('src',$(this).attr('dst'));
342 $('#' + prev).after($(this));
345 // Find out if the hidden comments are open, so we can keep it that way
346 // if a new comment has been posted
347 var id = $('.hide-comments-total', this).attr('id');
348 if(typeof id != 'undefined') {
349 id = id.split('-')[3];
350 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
353 $('img',this).each(function() {
354 $(this).attr('src',$(this).attr('dst'));
356 //vScroll = $(document).scrollTop();
357 $('html').height($('html').height());
358 $('#' + ident).replaceWith($(this));
360 if(typeof id != 'undefined') {
361 if(commentsOpen) showHideComments(id);
363 $('html').height('auto');
364 //$(document).scrollTop(vScroll);
369 // reset vars for inserting individual items
371 /* prev = 'live-' + src;
373 $('.wall-item-outside-wrapper',data).each(function() {
374 var ident = $(this).attr('id');
376 if($('#' + ident).length == 0 && prev != 'live-' + src) {
377 $('img',this).each(function() {
378 $(this).attr('src',$(this).attr('dst'));
380 $('#' + prev).after($(this));
383 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
384 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
385 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
386 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
387 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
388 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
389 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
390 $(this).attr('src',$(this).attr('dst'));
396 $('.like-rotator').hide();
399 $('body').css('cursor', 'auto');
401 /* autocomplete @nicknames */
402 $(".comment-edit-form textarea").contact_autocomplete(baseurl+"/acl");
404 // setup videos, since VideoJS won't take care of any loaded via AJAX
405 if(typeof videojs != 'undefined') videojs.autoSetup();
409 function imgbright(node) {
410 $(node).removeClass("drophide").addClass("drop");
413 function imgdull(node) {
414 $(node).removeClass("drop").addClass("drophide");
417 // Since our ajax calls are asynchronous, we will give a few
418 // seconds for the first ajax call (setting like/dislike), then
419 // run the updater to pick up any changes and display on the page.
420 // The updater will turn any rotators off when it's done.
421 // This function will have returned long before any of these
422 // events have completed and therefore there won't be any
423 // visible feedback that anything changed without all this
424 // trickery. This still could cause confusion if the "like" ajax call
425 // is delayed and NavUpdate runs before it completes.
427 function dolike(ident,verb) {
429 $('#like-rotator-' + ident.toString()).show();
430 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
435 function dosubthread(ident) {
437 $('#like-rotator-' + ident.toString()).show();
438 $.get('subthread/' + ident.toString(), NavUpdate );
443 function dostar(ident) {
444 ident = ident.toString();
445 $('#like-rotator-' + ident).show();
446 $.get('starred/' + ident, function(data) {
447 if(data.match(/1/)) {
448 $('#starred-' + ident).addClass('starred');
449 $('#starred-' + ident).removeClass('unstarred');
450 $('#star-' + ident).addClass('hidden');
451 $('#unstar-' + ident).removeClass('hidden');
454 $('#starred-' + ident).addClass('unstarred');
455 $('#starred-' + ident).removeClass('starred');
456 $('#star-' + ident).removeClass('hidden');
457 $('#unstar-' + ident).addClass('hidden');
459 $('#like-rotator-' + ident).hide();
463 function doignore(ident) {
464 ident = ident.toString();
465 $('#like-rotator-' + ident).show();
466 $.get('ignored/' + ident, function(data) {
467 if(data.match(/1/)) {
468 $('#ignored-' + ident).addClass('ignored');
469 $('#ignored-' + ident).removeClass('unignored');
470 $('#ignore-' + ident).addClass('hidden');
471 $('#unignore-' + ident).removeClass('hidden');
474 $('#ignored-' + ident).addClass('unignored');
475 $('#ignored-' + ident).removeClass('ignored');
476 $('#ignore-' + ident).removeClass('hidden');
477 $('#unignore-' + ident).addClass('hidden');
479 $('#like-rotator-' + ident).hide();
483 function getPosition(e) {
484 var cursor = {x:0, y:0};
485 if ( e.pageX || e.pageY ) {
490 if( e.clientX || e.clientY ) {
491 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
492 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
504 var lockvisible = false;
506 function lockview(event,id) {
507 event = event || window.event;
508 cursor = getPosition(event);
514 $.get('lockview/' + id, function(data) {
515 $('#panel').html(data);
516 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
522 function lockviewhide() {
527 function post_comment(id) {
530 $('body').css('cursor', 'wait');
531 $("#comment-preview-inp-" + id).val("0");
534 $("#comment-edit-form-" + id).serialize(),
537 $("#comment-edit-wrapper-" + id).hide();
538 $("#comment-edit-text-" + id).val('');
539 var tarea = document.getElementById("comment-edit-text-" + id);
541 commentClose(tarea,id);
542 if(timer) clearTimeout(timer);
543 timer = setTimeout(NavUpdate,10);
547 window.location.href=data.reload;
556 function preview_comment(id) {
557 $("#comment-preview-inp-" + id).val("1");
558 $("#comment-edit-preview-" + id).show();
561 $("#comment-edit-form-" + id).serialize(),
565 $("#comment-edit-preview-" + id).html(data.preview);
566 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
576 function showHideComments(id) {
577 if( $("#collapsed-comments-" + id).is(":visible")) {
578 $("#collapsed-comments-" + id).hide();
579 $("#hide-comments-" + id).html(window.showMore);
582 $("#collapsed-comments-" + id).show();
583 $("#hide-comments-" + id).html(window.showFewer);
589 function preview_post() {
590 $("#jot-preview").val("1");
591 $("#jot-preview-content").show();
592 tinyMCE.triggerSave();
595 $("#profile-jot-form").serialize(),
598 $("#jot-preview-content").html(data.preview);
599 $("#jot-preview-content" + " a").click(function() { return false; });
604 $("#jot-preview").val("0");
610 // unpause auto reloads if they are currently stopped
613 $('#pause').html('');
618 // Converts the binary representation of data to hex
621 // discuss at: http://phpjs.org/functions/bin2hex
622 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
623 // + bugfixed by: Onno Marsman
624 // + bugfixed by: Linuxworld
625 // * example 1: bin2hex('Kev');
626 // * returns 1: '4b6576'
627 // * example 2: bin2hex(String.fromCharCode(0x00));
629 var v,i, f = 0, a = [];
633 for (i = 0; i<f; i++) {
634 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
640 function groupChangeMember(gid, cid, sec_token) {
641 $('body .fakelink').css('cursor', 'wait');
642 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
643 $('#group-update-wrapper').html(data);
644 $('body .fakelink').css('cursor', 'auto');
648 function profChangeMember(gid,cid) {
649 $('body .fakelink').css('cursor', 'wait');
650 $.get('profperm/' + gid + '/' + cid, function(data) {
651 $('#prof-update-wrapper').html(data);
652 $('body .fakelink').css('cursor', 'auto');
656 function contactgroupChangeMember(gid,cid) {
657 $('body').css('cursor', 'wait');
658 $.get('contactgroup/' + gid + '/' + cid, function(data) {
659 $('body').css('cursor', 'auto');
664 function checkboxhighlight(box) {
665 if($(box).is(':checked')) {
666 $(box).addClass('checkeditem');
669 $(box).removeClass('checkeditem');
673 function notifyMarkAll() {
674 $.get('notify/mark/all', function(data) {
675 if(timer) clearTimeout(timer);
676 timer = setTimeout(NavUpdate,1000);
682 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
683 function fcFileBrowser (field_name, url, type, win) {
684 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
685 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
686 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
689 var cmsURL = baseurl+"/fbrowser/"+type+"/";
691 tinyMCE.activeEditor.windowManager.open({
693 title : 'File Browser',
694 width : 420, // Your dimensions may differ - toy around with them!
697 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
698 close_previous : "no"
706 function setupFieldRichtext(){
709 mode : "specific_textareas",
710 editor_selector: "fieldRichtext",
711 plugins : "bbcode,paste, inlinepopups",
712 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
713 theme_advanced_buttons2 : "",
714 theme_advanced_buttons3 : "",
715 theme_advanced_toolbar_location : "top",
716 theme_advanced_toolbar_align : "center",
717 theme_advanced_blockformats : "blockquote,code",
718 theme_advanced_resizing : true,
719 paste_text_sticky : true,
720 entity_encoding : "raw",
721 add_unload_trigger : false,
722 remove_linebreaks : false,
723 //force_p_newlines : false,
724 //force_br_newlines : true,
725 forced_root_block : 'div',
727 content_css: baseurl+"/view/custom_tinymce.css",
728 theme_advanced_path : false,
729 file_browser_callback : "fcFileBrowser",
735 * sprintf in javascript
736 * "{0} and {1}".format('zero','uno');
738 String.prototype.format = function() {
739 var formatted = this;
740 for (var i = 0; i < arguments.length; i++) {
741 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
742 formatted = formatted.replace(regexp, arguments[i]);
747 Array.prototype.remove = function(item) {
748 to=undefined; from=this.indexOf(item);
749 var rest = this.slice((to || from) + 1 || this.length);
750 this.length = from < 0 ? this.length + from : from;
751 return this.push.apply(this, rest);
754 function previewTheme(elm) {
755 theme = $(elm).val();
756 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
757 $('#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>');