1 function resizeIframe(obj) {
2 //obj.style.height = 0;
6 function _resizeIframe(obj, desth) {
7 var h = obj.style.height;
8 var ch = obj.contentWindow.document.body.scrollHeight;
9 if (h == (ch + 'px')) {
12 if (desth == ch && ch>0) {
13 obj.style.height = ch + 'px';
15 setTimeout(_resizeIframe, 100, obj, ch);
18 function openClose(theID) {
19 if(document.getElementById(theID).style.display == "block") {
20 document.getElementById(theID).style.display = "none"
23 document.getElementById(theID).style.display = "block"
27 function openMenu(theID) {
28 document.getElementById(theID).style.display = "block"
31 function closeMenu(theID) {
32 document.getElementById(theID).style.display = "none"
35 function decodeHtml(html) {
36 var txt = document.createElement("textarea");
45 var force_update = false;
47 var totStopped = false;
51 var in_progress = false;
52 var langSelect = false;
53 var commentBusy = false;
54 var last_popup_menu = null;
55 var last_popup_button = null;
56 var lockLoadContent = false;
59 $.ajaxSetup({cache: false});
61 /* setup tooltips *//*
62 $("a,.tt").each(function(){
65 if (e.hasClass("tttop")) pos="top";
66 if (e.hasClass("ttbottom")) pos="bottom";
67 if (e.hasClass("ttleft")) pos="left";
68 if (e.hasClass("ttright")) pos="right";
69 e.tipTip({defaultPosition: pos, edgeOffset: 8});
72 /* setup comment textarea buttons */
73 /* comment textarea buttons needs some "data-*" attributes to work:
74 * data-role="insert-formatting" : to mark the element as a formatting button
75 * data-comment="<string>" : string for "Comment", used by insertFormatting() function
76 * data-bbcode="<string>" : name of the bbcode element to insert. insertFormatting() will insert it as "[name][/name]"
77 * data-id="<string>" : id of the comment, used to find other comment-related element, like the textarea
79 $('body').on('click','[data-role="insert-formatting"]', function(e) {
82 var comment = o.data('comment');
83 var bbcode = o.data('bbcode');
84 var id = o.data('id');
86 Dialog.doImageBrowser("comment", id);
89 insertFormatting(comment, bbcode, id);
92 /* event from comment textarea button popups */
93 /* insert returned bbcode at cursor position or replace selected text */
94 $("body").on("fbrowser.image.comment", function(e, filename, bbcode, id) {
95 console.log("on", id);
97 var textarea = document.getElementById("comment-edit-text-" +id);
98 var start = textarea.selectionStart;
99 var end = textarea.selectionEnd;
100 textarea.value = textarea.value.substring(0, start) + bbcode + textarea.value.substring(end, textarea.value.length);
105 /* setup onoff widgets */
106 $(".onoff input").each(function(){
108 id = $(this).attr("id");
109 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
112 $(".onoff > a").click(function(event){
113 event.preventDefault();
114 var input = $(this).siblings("input");
115 var val = 1-input.val();
116 var id = input.attr("id");
117 $("#"+id+"_onoff ."+ (val==0?"on":"off")).addClass("hidden");
118 $("#"+id+"_onoff ."+ (val==1?"on":"off")).removeClass("hidden");
123 /* setup field_richtext */
124 setupFieldRichtext();
127 function close_last_popup_menu() {
128 if(last_popup_menu) {
129 last_popup_menu.hide();
130 last_popup_menu.off('click', function(e) {e.stopPropagation()});
131 last_popup_button.removeClass("selected");
132 last_popup_menu = null;
133 last_popup_button = null;
136 $('a[rel^=#]').click(function(e){
138 var parent = $(this).parent();
139 var isSelected = (last_popup_button && parent.attr('id') == last_popup_button.attr('id'));
140 close_last_popup_menu();
141 if(isSelected) return false;
142 menu = $( $(this).attr('rel') );
145 if (menu.attr('popup')=="false") return false;
146 parent.toggleClass("selected");
148 if (menu.css("display") == "none") {
149 last_popup_menu = null;
150 last_popup_button = null;
152 last_popup_menu = menu;
153 last_popup_menu.on('click', function(e) {e.stopPropagation()});
154 last_popup_button = parent;
155 $('#nav-notifications-menu').perfectScrollbar('update');
159 $('html').click(function() {
160 close_last_popup_menu();
164 $("a.popupbox").colorbox({
166 'transition' : 'elastic'
168 $("a.ajax-popupbox").colorbox({
169 'transition' : 'elastic'
172 /* notifications template */
173 var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html());
174 var notifications_all = unescape($('<div>').append( $("#nav-notifications-see-all").clone() ).html()); //outerHtml hack
175 var notifications_mark = unescape($('<div>').append( $("#nav-notifications-mark-all").clone() ).html()); //outerHtml hack
176 var notifications_empty = unescape($("#nav-notifications-menu").html());
178 /* enable perfect-scrollbars for different elements */
179 $('#nav-notifications-menu, aside').perfectScrollbar();
181 /* nav update event */
182 $('nav').bind('nav-update', function(e,data){
183 var invalid = $(data).find('invalid').text();
184 if(invalid == 1) { window.location.href=window.location.href }
186 var net = $(data).find('net').text();
187 if(net == 0) { net = ''; $('#net-update').removeClass('show') } else { $('#net-update').addClass('show') }
188 $('#net-update').html(net);
190 var home = $(data).find('home').text();
191 if(home == 0) { home = ''; $('#home-update').removeClass('show') } else { $('#home-update').addClass('show') }
192 $('#home-update').html(home);
194 var intro = $(data).find('intro').text();
195 if(intro == 0) { intro = ''; $('#intro-update').removeClass('show') } else { $('#intro-update').addClass('show') }
196 $('#intro-update').html(intro);
198 var mail = $(data).find('mail').text();
199 if(mail == 0) { mail = ''; $('#mail-update').removeClass('show') } else { $('#mail-update').addClass('show') }
200 $('#mail-update').html(mail);
202 var intro = $(data).find('intro').text();
203 if(intro == 0) { intro = ''; $('#intro-update-li').removeClass('show') } else { $('#intro-update-li').addClass('show') }
204 $('#intro-update-li').html(intro);
206 var mail = $(data).find('mail').text();
207 if(mail == 0) { mail = ''; $('#mail-update-li').removeClass('show') } else { $('#mail-update-li').addClass('show') }
208 $('#mail-update-li').html(mail);
211 var allevents = $(data).find('all-events').text();
212 if(allevents == 0) { allevents = ''; $('#allevents-update').removeClass('show') } else { $('#allevents-update').addClass('show') }
213 $('#allevents-update').html(allevents);
215 var alleventstoday = $(data).find('all-events-today').text();
216 if(alleventstoday == 0) { $('#allevents-update').removeClass('notif-allevents-today') } else { $('#allevents-update').addClass('notif-allevents-today') }
218 var events = $(data).find('events').text();
219 if(events == 0) { events = ''; $('#events-update').removeClass('show') } else { $('#events-update').addClass('show') }
220 $('#events-update').html(events);
222 var eventstoday = $(data).find('events-today').text();
223 if(eventstoday == 0) { $('#events-update').removeClass('notif-events-today') } else { $('#events-update').addClass('notif-events-today') }
225 var birthdays = $(data).find('birthdays').text();
226 if(birthdays == 0) {birthdays = ''; $('#birthdays-update').removeClass('show') } else { $('#birthdays-update').addClass('show') }
227 $('#birthdays-update').html(birthdays);
229 var birthdaystoday = $(data).find('birthdays-today').text();
230 if(birthdaystoday == 0) { $('#birthdays-update').removeClass('notif-birthdays-today') } else { $('#birthdays-update').addClass('notif-birthdays-today') }
232 $(".sidebar-group-li .notify").removeClass("show");
233 $(data).find("group").each(function() {
235 var gcount = this.innerHTML;
236 $(".group-"+gid+" .notify").addClass("show").text(gcount);
239 $(".forum-widget-entry .notify").removeClass("show");
240 $(data).find("forum").each(function() {
242 var fcount = this.innerHTML;
243 $(".forum-"+fid+" .notify").addClass("show").text(fcount);
247 var eNotif = $(data).find('notif')
249 if (eNotif.children("note").length==0){
250 $("#nav-notifications-menu").html(notifications_empty);
252 nnm = $("#nav-notifications-menu");
253 nnm.html(notifications_all + notifications_mark);
254 //nnm.attr('popup','true');
256 var notification_lastitem = parseInt(localStorage.getItem("notification-lastitem"));
257 var notification_id = 0;
258 eNotif.children("note").each(function(){
260 var text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
261 var contact = ("<a href="+e.attr('url')+"><span class='contactname'>"+e.attr('name')+"</span></a>");
262 var seenclass = (e.attr('seen')==1)?"notify-seen":"notify-unseen";
263 var html = notifications_tpl.format(
264 e.attr('href'), // {0} // link to the source
265 e.attr('photo'), // {1} // photo of the contact
266 text, // {2} // preformatted text (autor + text)
267 e.attr('date'), // {3} // date of notification (time ago)
268 seenclass, // {4} // visited status of the notification
269 new Date(e.attr('timestamp')*1000), // {5} // date of notification
270 e.attr('url'), // {6} // profile url of the contact
271 e.text().format(contact), // {7} // preformatted html (text including author profile url)
272 '' // {8} // Deprecated
276 $(eNotif.children("note").get().reverse()).each(function(){
278 notification_id = parseInt(e.attr('timestamp'));
279 if (notification_lastitem!== null && notification_id > notification_lastitem) {
280 if (getNotificationPermission()==="granted") {
281 var notification = new Notification(document.title, {
282 body: decodeHtml(e.text().replace('→ ','').format(e.attr('name'))),
283 icon: e.attr('photo'),
285 notification['url'] = e.attr('href');
286 notification.addEventListener("click", function(ev){
287 window.location = ev.target.url;
293 notification_lastitem = notification_id;
294 localStorage.setItem("notification-lastitem", notification_lastitem)
296 $("img[data-src]", nnm).each(function(i, el){
297 // Add src attribute for images with a data-src attribute
298 // However, don't bother if the data-src attribute is empty, because
299 // an empty "src" tag for an image will cause some browsers
300 // to prefetch the root page of the Friendica hub, which will
301 // unnecessarily load an entire profile/ or network/ page
302 if($(el).data("src") != '') $(el).attr('src', $(el).data("src"));
306 notif = eNotif.attr('count');
308 $("#nav-notifications-linkmenu").addClass("on");
310 $("#nav-notifications-linkmenu").removeClass("on");
312 if(notif == 0) { notif = ''; $('#notify-update').removeClass('show') } else { $('#notify-update').addClass('show') }
313 $('#notify-update').html(notif);
315 var eSysmsg = $(data).find('sysmsgs');
316 eSysmsg.children("notice").each(function(){
317 text = $(this).text();
318 $.jGrowl(text, { sticky: true, theme: 'notice' });
320 eSysmsg.children("info").each(function(){
321 text = $(this).text();
322 $.jGrowl(text, { sticky: false, theme: 'info', life: 5000 });
325 /* update the js scrollbars */
326 $('#nav-notifications-menu').perfectScrollbar('update');
331 // Allow folks to stop the ajax page updates with the pause/break key
332 $(document).keydown(function(event) {
333 if(event.keyCode == '8') {
334 var target = event.target || event.srcElement;
335 if (!/input|textarea/i.test(target.nodeName)) {
339 if(event.keyCode == '19' || (event.ctrlKey && event.which == '32')) {
340 event.preventDefault();
341 if(stopped == false) {
346 $('#pause').html('<img src="images/pause.gif" alt="pause" style="border: 1px solid black;" />');
357 // Set an event listener for infinite scroll
358 if(typeof infinite_scroll !== 'undefined') {
359 $(window).scroll(function(e){
360 if ($(document).height() != $(window).height()) {
361 // First method that is expected to work - but has problems with Chrome
362 if ($(window).scrollTop() > ($(document).height() - $(window).height() * 1.5))
365 // This method works with Chrome - but seems to be much slower in Firefox
366 if ($(window).scrollTop() > (($("section").height() + $("header").height() + $("footer").height()) - $(window).height() * 1.5))
375 function NavUpdate() {
378 var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : '');
379 $.get(pingCmd,function(data) {
380 $(data).find('result').each(function() {
381 // send nav-update event
382 $('nav').trigger('nav-update', this);
387 if($('#live-network').length) { src = 'network'; liveUpdate(); }
388 if($('#live-profile').length) { src = 'profile'; liveUpdate(); }
389 if($('#live-community').length) { src = 'community'; liveUpdate(); }
390 if($('#live-notes').length) { src = 'notes'; liveUpdate(); }
391 if($('#live-display').length) { src = 'display'; liveUpdate(); }
392 /* if($('#live-display').length) {
395 window.location.href=window.location.href
398 if($('#live-photos').length) {
401 window.location.href=window.location.href
411 timer = setTimeout(NavUpdate,updateInterval);
414 function liveUpdate() {
415 if((src == null) || (stopped) || (! profile_uid)) { $('.like-rotator').hide(); return; }
416 if(($('.comment-edit-text-full').length) || (in_progress)) {
418 clearTimeout(livetime);
420 livetime = setTimeout(liveUpdate, 5000);
426 prev = 'live-' + src;
430 if ($(document).scrollTop() == 0)
433 var udargs = ((netargs.length) ? '/' + netargs : '');
434 var update_url = 'update_' + src + udargs + '&p=' + profile_uid + '&page=' + profile_page + '&force=' + ((force_update) ? 1 : 0);
436 $.get(update_url,function(data) {
438 force_update = false;
439 // $('.collapsed-comments',data).each(function() {
440 // var ident = $(this).attr('id');
441 // var is_hidden = $('#' + ident).is(':hidden');
442 // if($('#' + ident).length) {
443 // $('#' + ident).replaceWith($(this));
445 // $('#' + ident).hide();
450 $('.toplevel_item',data).each(function() {
451 var ident = $(this).attr('id');
453 if($('#' + ident).length == 0 && profile_page == 1) {
454 $('img',this).each(function() {
455 $(this).attr('src',$(this).attr('dst'));
457 $('#' + prev).after($(this));
460 // Find out if the hidden comments are open, so we can keep it that way
461 // if a new comment has been posted
462 var id = $('.hide-comments-total', this).attr('id');
463 if(typeof id != 'undefined') {
464 id = id.split('-')[3];
465 var commentsOpen = $("#collapsed-comments-" + id).is(":visible");
468 $('img',this).each(function() {
469 $(this).attr('src',$(this).attr('dst'));
471 //vScroll = $(document).scrollTop();
472 $('html').height($('html').height());
473 $('#' + ident).replaceWith($(this));
475 if(typeof id != 'undefined') {
476 if(commentsOpen) showHideComments(id);
478 $('html').height('auto');
479 //$(document).scrollTop(vScroll);
484 // reset vars for inserting individual items
486 /* prev = 'live-' + src;
488 $('.wall-item-outside-wrapper',data).each(function() {
489 var ident = $(this).attr('id');
491 if($('#' + ident).length == 0 && prev != 'live-' + src) {
492 $('img',this).each(function() {
493 $(this).attr('src',$(this).attr('dst'));
495 $('#' + prev).after($(this));
498 $('#' + ident + ' ' + '.wall-item-ago').replaceWith($(this).find('.wall-item-ago'));
499 if($('#' + ident + ' ' + '.comment-edit-text-empty').length)
500 $('#' + ident + ' ' + '.wall-item-comment-wrapper').replaceWith($(this).find('.wall-item-comment-wrapper'));
501 $('#' + ident + ' ' + '.hide-comments-total').replaceWith($(this).find('.hide-comments-total'));
502 $('#' + ident + ' ' + '.wall-item-like').replaceWith($(this).find('.wall-item-like'));
503 $('#' + ident + ' ' + '.wall-item-dislike').replaceWith($(this).find('.wall-item-dislike'));
504 $('#' + ident + ' ' + '.my-comment-photo').each(function() {
505 $(this).attr('src',$(this).attr('dst'));
511 $('.like-rotator').hide();
514 $('body').css('cursor', 'auto');
516 /* autocomplete @nicknames */
517 $(".comment-edit-form textarea").editor_autocomplete(baseurl+"/acl");
518 /* autocomplete bbcode */
519 $(".comment-edit-form textarea").bbco_autocomplete('bbcode');
521 // setup videos, since VideoJS won't take care of any loaded via AJAX
522 if(typeof videojs != 'undefined') videojs.autoSetup();
526 function imgbright(node) {
527 $(node).removeClass("drophide").addClass("drop");
530 function imgdull(node) {
531 $(node).removeClass("drop").addClass("drophide");
534 // Since our ajax calls are asynchronous, we will give a few
535 // seconds for the first ajax call (setting like/dislike), then
536 // run the updater to pick up any changes and display on the page.
537 // The updater will turn any rotators off when it's done.
538 // This function will have returned long before any of these
539 // events have completed and therefore there won't be any
540 // visible feedback that anything changed without all this
541 // trickery. This still could cause confusion if the "like" ajax call
542 // is delayed and NavUpdate runs before it completes.
544 function dolike(ident,verb) {
546 $('#like-rotator-' + ident.toString()).show();
547 $.get('like/' + ident.toString() + '?verb=' + verb, NavUpdate );
552 function dosubthread(ident) {
554 $('#like-rotator-' + ident.toString()).show();
555 $.get('subthread/' + ident.toString(), NavUpdate );
560 function dostar(ident) {
561 ident = ident.toString();
562 $('#like-rotator-' + ident).show();
563 $.get('starred/' + ident, function(data) {
564 if(data.match(/1/)) {
565 $('#starred-' + ident).addClass('starred');
566 $('#starred-' + ident).removeClass('unstarred');
567 $('#star-' + ident).addClass('hidden');
568 $('#unstar-' + ident).removeClass('hidden');
571 $('#starred-' + ident).addClass('unstarred');
572 $('#starred-' + ident).removeClass('starred');
573 $('#star-' + ident).removeClass('hidden');
574 $('#unstar-' + ident).addClass('hidden');
576 $('#like-rotator-' + ident).hide();
580 function doignore(ident) {
581 ident = ident.toString();
582 $('#like-rotator-' + ident).show();
583 $.get('ignored/' + ident, function(data) {
584 if(data.match(/1/)) {
585 $('#ignored-' + ident).addClass('ignored');
586 $('#ignored-' + ident).removeClass('unignored');
587 $('#ignore-' + ident).addClass('hidden');
588 $('#unignore-' + ident).removeClass('hidden');
591 $('#ignored-' + ident).addClass('unignored');
592 $('#ignored-' + ident).removeClass('ignored');
593 $('#ignore-' + ident).removeClass('hidden');
594 $('#unignore-' + ident).addClass('hidden');
596 $('#like-rotator-' + ident).hide();
600 function getPosition(e) {
601 var cursor = {x:0, y:0};
602 if ( e.pageX || e.pageY ) {
607 if( e.clientX || e.clientY ) {
608 cursor.x = e.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft) - document.documentElement.clientLeft;
609 cursor.y = e.clientY + (document.documentElement.scrollTop || document.body.scrollTop) - document.documentElement.clientTop;
621 var lockvisible = false;
623 function lockview(event,id) {
624 event = event || window.event;
625 cursor = getPosition(event);
631 $.get('lockview/' + id, function(data) {
632 $('#panel').html(data);
633 $('#panel').css({ 'left': cursor.x + 5 , 'top': cursor.y + 5});
639 function lockviewhide() {
644 function post_comment(id) {
647 $('body').css('cursor', 'wait');
648 $("#comment-preview-inp-" + id).val("0");
651 $("#comment-edit-form-" + id).serialize(),
654 $("#comment-edit-wrapper-" + id).hide();
655 $("#comment-edit-text-" + id).val('');
656 var tarea = document.getElementById("comment-edit-text-" + id);
658 commentClose(tarea,id);
659 if(timer) clearTimeout(timer);
660 timer = setTimeout(NavUpdate,10);
664 window.location.href=data.reload;
673 function preview_comment(id) {
674 $("#comment-preview-inp-" + id).val("1");
675 $("#comment-edit-preview-" + id).show();
678 $("#comment-edit-form-" + id).serialize(),
681 $("#comment-edit-preview-" + id).html(data.preview);
682 $("#comment-edit-preview-" + id + " a").click(function() { return false; });
692 function showHideComments(id) {
693 if( $("#collapsed-comments-" + id).is(":visible")) {
694 $("#collapsed-comments-" + id).hide();
695 $("#hide-comments-" + id).html(window.showMore);
698 $("#collapsed-comments-" + id).show();
699 $("#hide-comments-" + id).html(window.showFewer);
705 function preview_post() {
706 $("#jot-preview").val("1");
707 $("#jot-preview-content").show();
708 tinyMCE.triggerSave();
711 $("#profile-jot-form").serialize(),
714 $("#jot-preview-content").html(data.preview);
715 $("#jot-preview-content" + " a").click(function() { return false; });
720 $("#jot-preview").val("0");
726 // unpause auto reloads if they are currently stopped
729 $('#pause').html('');
732 // load more network content (used for infinite scroll)
733 function loadScrollContent() {
734 if (lockLoadContent) return;
735 lockLoadContent = true;
737 $("#scroll-loader").fadeIn('normal');
739 // the page number to load is one higher than the actual
741 infinite_scroll.pageno+=1;
743 console.log('Loading page ' + infinite_scroll.pageno);
745 // get the raw content from the next page and insert this content
746 // right before "#conversation-end"
747 $.get('network?mode=raw' + infinite_scroll.reload_uri + '&page=' + infinite_scroll.pageno, function(data) {
748 $("#scroll-loader").hide();
749 if ($(data).length > 0) {
750 $(data).insertBefore('#conversation-end');
751 lockLoadContent = false;
753 $("#scroll-end").fadeIn('normal');
759 // Converts the binary representation of data to hex
762 // discuss at: http://phpjs.org/functions/bin2hex
763 // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
764 // + bugfixed by: Onno Marsman
765 // + bugfixed by: Linuxworld
766 // * example 1: bin2hex('Kev');
767 // * returns 1: '4b6576'
768 // * example 2: bin2hex(String.fromCharCode(0x00));
770 var v,i, f = 0, a = [];
774 for (i = 0; i<f; i++) {
775 a[i] = s.charCodeAt(i).toString(16).replace(/^([\da-f])$/,"0$1");
781 function groupChangeMember(gid, cid, sec_token) {
782 $('body .fakelink').css('cursor', 'wait');
783 $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) {
784 $('#group-update-wrapper').html(data);
785 $('body .fakelink').css('cursor', 'auto');
789 function profChangeMember(gid,cid) {
790 $('body .fakelink').css('cursor', 'wait');
791 $.get('profperm/' + gid + '/' + cid, function(data) {
792 $('#prof-update-wrapper').html(data);
793 $('body .fakelink').css('cursor', 'auto');
797 function contactgroupChangeMember(gid,cid) {
798 $('body').css('cursor', 'wait');
799 $.get('contactgroup/' + gid + '/' + cid, function(data) {
800 $('body').css('cursor', 'auto');
805 function checkboxhighlight(box) {
806 if($(box).is(':checked')) {
807 $(box).addClass('checkeditem');
810 $(box).removeClass('checkeditem');
814 function notifyMarkAll() {
815 $.get('notify/mark/all', function(data) {
816 if(timer) clearTimeout(timer);
817 timer = setTimeout(NavUpdate,1000);
823 // code from http://www.tinymce.com/wiki.php/How-to_implement_a_custom_file_browser
824 function fcFileBrowser (field_name, url, type, win) {
825 /* TODO: If you work with sessions in PHP and your client doesn't accept cookies you might need to carry
826 the session name and session ID in the request string (can look like this: "?PHPSESSID=88p0n70s9dsknra96qhuk6etm5").
827 These lines of code extract the necessary parameters and add them back to the filebrowser URL again. */
830 var cmsURL = baseurl+"/fbrowser/"+type+"/";
832 tinyMCE.activeEditor.windowManager.open({
834 title : 'File Browser',
835 width : 420, // Your dimensions may differ - toy around with them!
838 inline : "yes", // This parameter only has an effect if you use the inlinepopups plugin!
839 close_previous : "no"
847 function setupFieldRichtext(){
850 mode : "specific_textareas",
851 editor_selector: "fieldRichtext",
852 plugins : "bbcode,paste, inlinepopups",
853 theme_advanced_buttons1 : "bold,italic,underline,undo,redo,link,unlink,image,forecolor,formatselect,code",
854 theme_advanced_buttons2 : "",
855 theme_advanced_buttons3 : "",
856 theme_advanced_toolbar_location : "top",
857 theme_advanced_toolbar_align : "center",
858 theme_advanced_blockformats : "blockquote,code",
859 theme_advanced_resizing : true,
860 paste_text_sticky : true,
861 entity_encoding : "raw",
862 add_unload_trigger : false,
863 remove_linebreaks : false,
864 //force_p_newlines : false,
865 //force_br_newlines : true,
866 forced_root_block : 'div',
868 content_css: baseurl+"/view/custom_tinymce.css",
869 theme_advanced_path : false,
870 file_browser_callback : "fcFileBrowser",
876 * sprintf in javascript
877 * "{0} and {1}".format('zero','uno');
879 String.prototype.format = function() {
880 var formatted = this;
881 for (var i = 0; i < arguments.length; i++) {
882 var regexp = new RegExp('\\{'+i+'\\}', 'gi');
883 formatted = formatted.replace(regexp, arguments[i]);
888 Array.prototype.remove = function(item) {
889 to=undefined; from=this.indexOf(item);
890 var rest = this.slice((to || from) + 1 || this.length);
891 this.length = from < 0 ? this.length + from : from;
892 return this.push.apply(this, rest);
895 function previewTheme(elm) {
896 theme = $(elm).val();
897 $.getJSON('pretheme?f=&theme=' + theme,function(data) {
898 $('#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>');
903 // notification permission settings in localstorage
904 // set by settings page
905 function getNotificationPermission() {
906 if (window["Notification"] === undefined) {
909 if (Notification.permission === 'granted') {
910 var val = localStorage.getItem('notification-permissions');
911 if (val === null) return 'denied';
914 return Notification.permission;
919 * Show a dialog loaded from an url
920 * By defaults this load the url in an iframe in colorbox
921 * Themes can overwrite `show()` function to personalize it
928 * @return object colorbox
930 show : function (url) {
931 var size = Dialog._get_size();
932 return $.colorbox({href: url, iframe:true,innerWidth: size.width+'px',innerHeight: size.height+'px'})
936 * Show the Image browser dialog
939 * @param string id (optional)
942 * The name will be used to build the event name
943 * fired by image browser dialog when the user select
944 * an image. The optional id will be passed as argument
945 * to the event handler
947 doImageBrowser : function (name, id) {
948 var url = Dialog._get_url("image",name,id);
949 return Dialog.show(url);
953 * Show the File browser dialog
956 * @param string id (optional)
959 * The name will be used to build the event name
960 * fired by file browser dialog when the user select
961 * a file. The optional id will be passed as argument
962 * to the event handler
964 doFileBrowser : function (name, id) {
965 var url = Dialog._get_url("file",name,id);
966 return Dialog.show(url);
969 _get_url : function(type, name, id) {
971 if (id !== undefined) hash = hash + "-" + id;
972 return baseurl + "/fbrowser/"+type+"/?mode=minimal#"+hash;
975 _get_size: function() {
977 width: window.innerWidth-50,
978 height: window.innerHeight-100