/* global $ */ // $Id$ // JavaScript glue for jQuery in Tiki // // Tiki 6 - $ is now initialised in jquery.js // but let's keep $jq available too for legacy custom code var legacyLoad = jQuery.fn.load; jQuery.fn.load = function (url, _data, _complete) { var element = this; element.show(); element.tikiModal(tr('Loading...')); if (typeof _data === "function") { _complete = _data; _data = ""; } var complete = function (responseText, textStatus, jqXHR) { element.tikiModal(); if (textStatus === 'error') { element.html(''); return; } _complete.call(this, responseText, textStatus, jqXHR) }; return legacyLoad.call(this, url, _data, complete); } var $jq = $, $window = $(window), $document = $(document); // Check / Uncheck all Checkboxes function switchCheckboxes (tform, elements_name, state, hiddenToo) { // checkboxes need to have the same name elements_name // e.g. , will arrive as Array in php. if (hiddenToo == undefined) { hiddenToo = false; } var closeTag; if (hiddenToo) { closeTag = '"]'; } else { closeTag = '"]:visible'; } $(tform).contents().find('input[name="' + jQuery.escapeSelector(elements_name) + closeTag).prop('checked', state).change(); } // add id's of any elements that don't like being animated here var jqNoAnimElements = ['help_sections', 'ajaxLoading']; function show(foo, f, section) { if ($.inArray(foo, jqNoAnimElements) > -1 || typeof jqueryTiki === 'undefined') { // exceptions that don't animate reliably $("#" + foo).show(); } else if ($("#" + foo).hasClass("tabcontent")) { // different anim prefs for tabs showJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction); } else { showJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction); } if (f) {setCookie(foo, "o", section);} } function hide(foo, f, section) { if ($.inArray(foo, jqNoAnimElements) > -1 || typeof jqueryTiki === 'undefined') { // exceptions $("#" + foo).hide(); } else if ($("#" + foo).hasClass("tabcontent")) { hideJQ("#" + foo, jqueryTiki.effect_tabs, jqueryTiki.effect_tabs_speed, jqueryTiki.effect_tabs_direction); } else { hideJQ("#" + foo, jqueryTiki.effect, jqueryTiki.effect_speed, jqueryTiki.effect_direction); } if (f) { // var wasnot = getCookie(foo, section, 'x') == 'x'; setCookie(foo, "c", section); // if (wasnot) { // history.go(0); // used to reload the page with all menu items closed - broken since 3.x // } } } // flip function... unfortunately didn't use show/hide (ay?) function flip(foo, style) { var $foo = $("#" + foo); if (style && style !== 'block' || foo === 'help_sections' || foo === 'fgalexplorer' || typeof jqueryTiki === 'undefined') { // TODO find a better way? $foo.toggle(); // inlines don't animate reliably (yet) (also help) if ($foo.css('display') === 'none') { setSessionVar('show_' + tiki_encodeURIComponent(foo), 'n'); } else { setSessionVar('show_' + tiki_encodeURIComponent(foo), 'y'); } } else { if ($foo.css("display") === "none") { setSessionVar('show_' + tiki_encodeURIComponent(foo), 'y'); show(foo); } else { setSessionVar('show_' + tiki_encodeURIComponent(foo), 'n'); hide(foo); } } } // handle JQ effects function showJQ(selector, effect, speed, dir) { if (effect === 'none') { $(selector).show(); } else if (effect === '' || effect === 'normal') { $(selector).show(400); // jquery 1.4 no longer seems to understand 'nnormal' as a speed } else if (effect == 'slide') { $(selector).slideDown(speed); } else if (effect === 'fade') { $(selector).fadeIn(speed); } else if (effect.match(/(.*)_ui$/).length > 1) { $(selector).show(effect.match(/(.*)_ui$/)[1], {direction: dir}, speed); } else { $(selector).show(); } } function hideJQ(selector, effect, speed, dir) { if (effect === 'none') { $(selector).hide(); } else if (effect === '' || effect === 'normal') { $(selector).hide(400); // jquery 1.4 no longer seems to understand 'nnormal' as a speed } else if (effect === 'slide') { $(selector).slideUp(speed); } else if (effect === 'fade') { $(selector).fadeOut(speed); } else if (effect.match(/(.*)_ui$/).length > 1) { $(selector).hide(effect.match(/(.*)_ui$/)[1], {direction: dir}, speed); } else { $(selector).hide(); } } // ajax loading indicator function ajaxLoadingShow(destName) { var $dest, $loading, pos, x, y, w, h; if (typeof destName === 'string') { $dest = $('#' + destName); } else { $dest = $(destName); } if ($dest.length === 0 || $dest.parents(":hidden").length > 0) { return; } $loading = $('#ajaxLoading'); // find area of destination element pos = $dest.offset(); // clip to page if (pos.left + $dest.width() > $window.width()) { w = $window.width() - pos.left; } else { w = $dest.width(); } if (pos.top + $dest.height() > $window.height()) { h = $window.height() - pos.top; } else { h = $dest.height(); } x = pos.left + (w / 2) - ($loading.width() / 2); y = pos.top + (h / 2) - ($loading.height() / 2); // position loading div $loading.css('left', x).css('top', y); // now BG x = pos.left + ccsValueToInteger($dest.css("margin-left")); y = pos.top + ccsValueToInteger($dest.css("margin-top")); w = ccsValueToInteger($dest.css("padding-left")) + $dest.width() + ccsValueToInteger($dest.css("padding-right")); h = ccsValueToInteger($dest.css("padding-top")) + $dest.height() + ccsValueToInteger($dest.css("padding-bottom")); $('#ajaxLoadingBG').css('left', pos.left).css('top', pos.top).width(w).height(h).fadeIn("fast"); show('ajaxLoading'); } function ajaxLoadingHide() { hide('ajaxLoading'); $('#ajaxLoadingBG').fadeOut("fast"); } function ajaxSubmitEventHandler(successCallback, dataType) { return function (e) { e.preventDefault(); let form = this, act = $(form).attr('action'), modal = $(form).closest('.modal-dialog'), formData = null; if (! act) { if (typeof url !== "undefined") { act = url; } else { return false; } } dataType = dataType || 'json'; if (typeof $(form).valid === "function") { if (!$(form).valid()) { return false; } else if ($(form).validate().pendingRequest > 0) { $(form).validate(); setTimeout(function() {$(form).submit();}, 500); return false; } } modal.tikiModal(tr('Loading...')); // if there is a file is included in form, use FormData, otherwise, serialize the form input values. // FormData still has issues in IE, though they've been fixed in Edge. if ($(form).find("input[type=file]").length){ formData = new FormData(form); } else { formData = $(form).serialize(); } let formSubmission = { type: 'POST', data: formData, dataType: dataType, success: function (data) { successCallback.apply(form, [data]); }, error: function (jqxhr) { // Headers sent from Feedback class already handled through an ajaxComplete if (! jqxhr.getResponseHeader('X-Tiki-Feedback')) { modal.tikiModal(); $(form).showError(jqxhr); } }, complete: function () { modal.tikiModal(); } }; // if the encryption type on the form is set to 'multipart/form-data' or formData is a FormData object // we must set contentType and processData to false on the ajax submission if (form.enctype === "multipart/form-data" || formData.constructor === FormData) { formSubmission.contentType = false; formSubmission.processData = false; } $.ajax(act, formSubmission); return false; }; } function checkDuplicateRows( button, columnSelector, rowSelector, parentSelector ) { if (typeof columnSelector === 'undefined') { columnSelector = "td"; } if (typeof rowSelector === 'undefined') { rowSelector = "tr:not(:first)"; } if (typeof parentSelector === 'undefined') { parentSelector = "table:first"; } var $rows = $(button).parents(parentSelector).find(rowSelector); $rows.each(function( ix, el ){ if ($("input:checked", el).length === 0) { var $el = $(el); var line = $el.find(columnSelector).text(); $rows.each(function( ix, el ){ if ($el[0] !== el && $("input:checked", el).length === 0) { if (line === $(el).find(columnSelector).text()) { $(":checkbox:first", el).prop("checked", true); } } }); } }); } $.fn.tiki_popover = function () { var list, $container = this; // To allow table elements etc in tips and popovers if ($.fn.tooltip.Constructor && typeof $.fn.tooltip.Constructor.Default.allowList === "object") { var myDefaultAllowList = $.fn.tooltip.Constructor.Default.allowList; myDefaultAllowList.table = []; myDefaultAllowList.thead = []; myDefaultAllowList.tbody = []; myDefaultAllowList.tr = []; myDefaultAllowList.th = []; myDefaultAllowList.td = []; myDefaultAllowList.form = ["action", "method"]; myDefaultAllowList.input = ["name", "value", "type"]; myDefaultAllowList.button = ["type", "disabled", "name", "value", "onclick"]; myDefaultAllowList.time = ["datetime"]; // for timeago myDefaultAllowList.a = ["target", "href", "title", "rel", "data-bs-toggle", "data-bs-backdrop", "data-bs-target", "data-bs-size", "onclick"]; // data items for smarty_function_bootstrap_modal } /* * Prepare the data so all elements so the data is all in the right format for bootstrap popovers */ list = $container.find('.tips[title!=""], .tikihelp[title!=""]') .each(function () { var $element = $(this); if ($element.attr('title') && ! $element.hasClass('tikihelp-prefs')) { $.each(['|', ':', '
', '
'], function (key, sep) { var parts = $element.attr('title').split(sep); if (parts.length > 1) { $element.attr('title', parts.shift()); // note setting the jQuery data object doesn't update the DOM, which is what bs5 needs now $element.attr('data-bs-content', parts.join(sep)); } }); } else { $element.attr('title', ''); } if (! $element.data('bs-trigger')) { $element.attr('data-bs-trigger', 'hover focus'); } // default Tiki delay if (! $element.data('bs-delay')) { //$element.attr('data-bs-delay', {"show": 250, "hide": 500}); FIXME (bs5 data object bug) $element.attr('data-bs-delay', 500); } }); $.merge(list, $container.find("a[data-bs-toggle=popover]:not(.tips[title!='']):not(.tikihelp[title!=''])")); list.filter('.bottom').attr('data-bs-placement', 'bottom'); list.filter('.left').attr('data-bs-placement', 'left'); list.filter('.right').attr('data-bs-placement', 'right'); // FIXME temporary fix of https://github.com/twbs/bootstrap/issues/35020 //list.filter('.slow').attr('data-bs-delay', { "show": 1000, "hide": 500 }); list.filter('.slow').attr('data-bs-delay', 1000); list.find('img').attr('title', ''); // Remove the img title to avoid browser tooltip list.filter('[data-bs-trigger="click"]') .click(function (e) { e.preventDefault(); }); list.filter('[data-bs-delay^="{"]').each(function () { // FIXME temporary fix of https://github.com/twbs/bootstrap/issues/35020 only single numeric values work for delay via data attributes const $this = $(this); $this.attr("data-bs-delay", $this.data('bs-delay').show); // only use the show setting }); // Handle common cases list .popover({ container: 'body', html: true, boundary: "window", placement: $.tikiPopoverWhereToPlace }); $container.find('.ajaxtips').each(function() { var me = $(this), trigger = me.data('bs-trigger') || 'hover focus'; $(this).popover({ trigger: trigger, html: true, //bsDelay: { "show": 500, "hide": 500 }, delay: 500, placement: $.tikiPopoverWhereToPlace, boundary: "window", content: function () { const link = this; let content = $(this).data('bs-content'); if (! content) { $.get($(this).data('ajaxtips'), function (data) { content = data; link.dataset.bsContent = content; $(link).attr('data-bs-content', content); bootstrap.Popover.getInstance(link).dispose(); bootstrap.Popover.getOrCreateInstance(link, { trigger: trigger, html: true, delay: 500, placement: $.tikiPopoverWhereToPlace, boundary: "window" }); bootstrap.Popover.getInstance(link).show(); }); // display a spinner while waiting for the ajax call to return the content content = "
Loading...
"; } return content; } }); }); // only have one popover showing at a time $document.on("show.bs.popover", function ( e ) { var event = e; $('.popover:visible:not(.tour-tour)').each(function () { if (this.previousElementSibling !== event.target) { $(this).popover('hide'); } }); }); $document.on("hide.bs.popover", function ( e ) { var $popover = $('.popover:visible:not(.tour-tour)'); // if mouse is over the popover if ($popover.find(":hover").length) { // change the leave event to be when leaving the popover $popover.mouseleave(function () { $(this).popover("hide"); }); // and cancel the hide event e.preventDefault(); return false; } }); return $container; }; $.tikiPopoverWhereToPlace = function (pop, el) { var pxNum = function(str) { return (str || '').replace('px', '') * 1; }, $win = $(window), $el = $(el), width = $el.offsetParent().width(), height = $el.offsetParent().height(), $pop = $(pop), allowedImgWidth = width * 0.60, allowedImgHeight = height * 0.60, manualImageWidth = $el.data('width'), leftPos = $el.offset().left, rightPos = leftPos + $el.outerWidth(), bottomPos = $el.offset().top + $el.outerHeight() - $win.scrollTop(), $img = $pop.find('div[style*="background-image"],img').first(), $imgContainer = $img.parent(), $imgPopover = $imgContainer.parent(), imgWidth = pxNum($img.css('width')), imgHeight = pxNum($img.css('height')), newImgWidth, newImgHeight, widthBuffer, heightBuffer; if ($el.data("bs-placement")) { return $el.data("bs-placement"); // element already has popover placement set } if (manualImageWidth) { $img.css({ width: manualImageWidth + 'px' }); $pop.css({ "max-width" : '100%' }); imgWidth = manualImageWidth; } //lets check the size of the popover img if (imgWidth > allowedImgWidth || imgHeight > allowedImgHeight) { widthBuffer = (pxNum($imgContainer.css('padding-left')) + pxNum($imgContainer.css('margin-left')) + pxNum($imgContainer.css('border-left-width'))) * 2; heightBuffer = (pxNum($imgContainer.css('padding-top')) + pxNum($imgContainer.css('margin-top')) + pxNum($imgContainer.css('border-top-width'))) * 2; // proportionate the image relative to what is allowed if(allowedImgWidth/imgWidth > allowedImgHeight/imgHeight){ newImgWidth = allowedImgWidth; newImgHeight = imgHeight*(allowedImgWidth/imgWidth); } else { newImgWidth = imgWidth*(allowedImgHeight/imgHeight); newImgHeight = allowedImgHeight; } $img.css({ backgroundSize: newImgWidth + 'px ' + newImgHeight + 'px', width: newImgWidth + 'px', height: newImgHeight + 'px' }); $imgPopover.css({ maxWidth: (newImgWidth + widthBuffer) + 'px', maxHeight: (newImgHeight + heightBuffer) +'px' }); } var $popTemp = $("
" + $el.data("bs-content") + "
"); $("body").append($popTemp); var popWidth = $popTemp.outerWidth(), popHeight = $popTemp.outerHeight(); $popTemp.remove(); if (width - leftPos < popWidth && width - rightPos < popWidth) { if (bottomPos > popHeight || bottomPos + popHeight > $win.height()) { return 'top'; } else { return 'bottom'; } } else if (width - leftPos > popWidth) { return 'left'; } else if (width - rightPos > popWidth) { return 'right'; } if (imgWidth && width - leftPos + imgWidth > width) return 'bottom'; return 'auto'; }; $(function() { // JQuery's DOM is ready event - before onload if (!window.jqueryTiki) window.jqueryTiki = {}; // Reflections if (jqueryTiki.reflection) { $("img.reflect").reflect({}); } if (jqueryTiki.tooltips) { $(document).tiki_popover(); } // superfish setup (CSS menu effects) if (jqueryTiki.superfish) { $('ul.cssmenu_horiz').supersubs({ minWidth: 11, // minimum width of sub-menus in em units maxWidth: 20, // maximum width of sub-menus in em units extraWidth: 1 // extra width can ensure lines don't sometimes turn over // due to slight rounding differences and font-family }); $('ul.cssmenu_vert').supersubs({ minWidth: 11, // minimum width of sub-menus in em units maxWidth: 20, // maximum width of sub-menus in em units extraWidth: 1 // extra width can ensure lines don't sometimes turn over // due to slight rounding differences and font-family }); $('ul.cssmenu_horiz').superfish({ animation: {opacity:'show', height:'show'}, // fade-in and slide-down animation speed: 'fast', // faster animation speed onShow: function(){ if ($(this).data('active')) return; $(this) .data('active', true) .moveToWithinWindow(); }, onHide: function(){ $(this).removeData('active'); } }); $('ul.cssmenu_vert').superfish({ animation: {opacity:'show', height:'show'}, // fade-in and slide-down animation speed: 'fast', // faster animation speed onShow: function(){ if ($(this).data('active')) return; $(this) .data('active', true) .moveToWithinWindow(); }, onHide: function(){ $(this).removeData('active'); } }); } $.fn.applyColorbox = function() { $(this).find("a[data-box*='box']").colorbox({ rel: function(){ return $(this).attr('data-box'); }, transition: "elastic", maxHeight:"95%", maxWidth:"95%", overlayClose: true, current: jqueryTiki.cboxCurrent }); // now, first let suppose that we want to display images in ColorBox by default: // this matches data-box attributes containing type=img or no type= specified $(this).find("a[data-box*='box'][data-box*='type=img'], a[data-box*='box'][data-box!='type=']:not([data-is-text])").colorbox({ photo: true }); // data-box attributes containing slideshow (this one must be without #col1) $(this).find("a[data-box*='box'][data-box*='slideshow']").colorbox({ photo: true, slideshow: true, slideshowSpeed: 3500, preloading: false, width: "100%", height: "100%" }); // this are the defaults matching all *box links which are not obviously links to images... // (if we need to support more, add here... otherwise it is possible to override with type=iframe in data-box attribute of a link) // (from here one to speed it up, matches any link in #col1 only - the main content column) $(this).find("#col1 a[data-box*='box']:not([data-box*='type=img']):not([href*='display']):not([href*='preview']):not([href*='thumb']):not([data-box*='slideshow']):not([href*='image']):not([href$='\.jpg']):not([href$='\.jpeg']):not([href$='\.png']):not([href$='\.gif'])").colorbox({ iframe: true, width: "95%", height: "95%" }); // hrefs starting with ftp(s) $(this).find("#col1 a[data-box*='box'][href^='ftp://'], #col1 a[data-box*='box'][href^='ftps://']").colorbox({ iframe: true, width: "95%", height: "95%" }); // data-box attributes containing type=flash $(this).find("#col1 a[data-box*='box'][data-box*='type=flash']").colorbox({ inline: true, width: "60%", height: "60%", href: function () { var $el = $("#cb_swf_player"); if ($el.length === 0) { $el = $("
"); $(document.body).append($("
").hide().append($el)); } //$(this).media.swf(el, { width: 400, height: 300, autoplay: true, src: $(this).attr("href") }); swfobject.embedSWF($(this).attr("href"), "cb_swf_player", "100%", "90%", "9.0.0", "vendor_bundled/vendor/bower-asset/swfobject/swfobject/expressInstall.swf"); return $("#cb_swf_player"); } }); // data-box attributes with type=iframe (if someone needs to override anything above) $(this).find("#col1 a[data-box*='box'][data-box*='type=iframe']").colorbox({ iframe: true }); // inline content: hrefs starting with # $(this).find("#col1 a[data-box*='box'][href^='#']").colorbox({ inline: true, width: "50%", height: "50%", href: function(){ return $(this).attr('href'); } }); // titles (for captions): // by default get title from the title attribute of the link (in all columns) $(this).find("a[data-box*='box'][title]").colorbox({ title: function(){ return $(this).attr('title'); } }); // but prefer the title from title attribute of a wrapped image if any (in all columns) $(this).find("a[data-box*='box'] img[title]").colorbox({ title: function(){ return $(this).attr('title'); }, photo: true, // and if you take title from the image you need photo href: function(){ // and href as well (for colobox 1.3.6 tiki 5.0) return $(this).parent().attr("href"); } }); /* Shadowbox params compatibility extracted using regexp functions */ var re, ret; // data-box attributes containing title param overrides title attribute of the link (shadowbox compatible) $(this).find("#col1 a[data-box*='box'][data-box*='title=']").colorbox({ title: function () { re = /(title=([^;\"]+))/i; ret = $(this).attr("data-box").match(re); return ret[2]; } }); // data-box attributes containing height param (shadowbox compatible) $(this).find("#col1 a[data-box*='box'][data-box*='height=']").colorbox({ height: function () { re = /(height=([^;\"]+))/i; ret = $(this).attr("data-box").match(re); return ret[2]; } }); // data-box attributes containing width param (shadowbox compatible) $(this).find("#col1 a[data-box*='box'][data-box*='width=']").colorbox({ width: function () { re = /(width=([^;\"]+))/i; ret = $(this).attr("data-box").match(re); return ret[2]; } }); // links generated by the {COLORBOX} plugin if (jqueryTiki.colorbox) { $(this).find("a[data-box^='shadowbox[colorbox']").each(function () {$(this).attr('savedTitle', $(this).attr('title'));}); $(this).find("a[data-box^='shadowbox[colorbox']").colorbox({ title: function() { return $(this).attr('savedTitle'); // this fix not required is colorbox was disabled } }); } }; $.applyColorbox = function() { if (jqueryTiki.colorbox) { $('body').applyColorbox(); } }; // ColorBox setup (Shadowbox, actually "box" replacement) if (jqueryTiki.colorbox && !jqueryTiki.mobile) { $().on('cbox_complete', function(){ $("#cboxTitle").wrapInner("
"); }); $.applyColorbox(); } // end if (jqueryTiki.colorbox) if (jqueryTiki.zoom) { $("a[data-box*=zoom]").each(function () { $(this) .wrap('') .parent() .zoom({ url: $(this).attr("href") }); }); } if (jqueryTiki.smartmenus) { // Init all menus var $navbars = $('ul.navbar-nav'); var options = { noMouseOver: jqueryTiki.smartmenus_open_close_click, hideOnClick: jqueryTiki.smartmenus_open_close_click, collapsibleBehavior: jqueryTiki.smartmenus_collapsible_behavior, subIndicators: true, collapsibleShowFunction: function($ul, complete) { $ul.slideDown(200, complete); }, collapsibleHideFunction: function($ul, complete) { $ul.slideUp(250, complete); } }; $.SmartMenus.Bootstrap.init($navbars, options); } // Select2 $.fn.applySelect2 = function () { if (jqueryTiki.select2) { $("select:not(.allow_single_deselect):not(.noselect2)").tiki("select2"); $(document).on('select2:open', () => { let allSelectSearchInputs = document.querySelectorAll('.select2-container--open .select2-search__field'); $(this).one('mouseup',()=>{ setTimeout(()=>{ allSelectSearchInputs[allSelectSearchInputs.length - 1].focus(); },0); }); }); } }; $.applySelect2 = function() { return $('body').applySelect2(); }; if (jqueryTiki.select2) { $.applySelect2(); } $( function() { $("#keepOpenCbx").click(function() { if (this.checked) { setCookie("fgalKeepOpen", "1"); } else { setCookie("fgalKeepOpen", ""); } }); var keepopen = getCookie("fgalKeepOpen"); $("#keepOpenCbx").prop("checked", !! keepopen); }); // end fgal fns $.paginationHelper(); // bind clickModal to links with or in click-modal class $(document).on('click', 'a.click-modal, .click-modal a', $.clickModal({ size: 'modal-lg', backdrop: 'static', success: function (data) { let redirect = $(this).data('modal-submit-redirect-url') || $(this).parent().data('modal-submit-redirect-url'); if (! redirect && data.url) { redirect = data.url; } window.location.href = redirect || window.location.href.replace(/#.*$/, ''); } })); if (jqueryTiki.numericFieldScroll === "none" || jqueryTiki.numericFieldScroll === null){ // disable mousewheel on a input number field when in focus // (to prevent browsers change the value when scrolling) $(document).on('focus', 'input[type=number]', function (e) { $(this).on('wheel.disableScroll', function (e) { e.preventDefault() }) }); $(document).on('blur', 'input[type=number]', function (e) { $(this).off('wheel.disableScroll') }); } }); // end $document.ready //For ajax/custom search $document.on('pageSearchReady', function() { $.paginationHelper(); }); // moved from tiki-list_file_gallery.tpl in tiki 6 function checkClose() { if (!$("#keepOpenCbx").prop("checked")) { window.close(); } else { window.blur(); if (window.opener) { window.opener.focus(); } } } /* * JS only textarea fullscreen function (for Tiki 5+) */ $(function() { // if in translation-diff-mode go fullscreen automatically if ($("#diff_outer").length && !$.trim($(".wikipreview .wikitext").html()).length) { // but not if previewing (TODO better) toggleFullScreen("editwiki"); } }); function sideBySideDiff() { if ($('.side-by-side-fullscreen').size()) { $('.side-by-side-fullscreen').remove(); return; } var $diff = $('#diff_outer').remove(), $zone = $('.edit-zone'); $zone.after($diff.addClass('side-by-side-fullscreen')); $diff.find('#diff_history').height(''); } function toggleFullScreen(area_id) { if ($("input[name=wysiwyg]").val() === "y") { // quick fix to disable side-by-side translation for wysiwyg $("#diff_outer").css({ position: "inherit", height: "400px", overflowX: "auto" }); return; } var textarea = $("#" + area_id); //codemirror interation and preservation var textareaEditor = syntaxHighlighter.get(textarea); if (textareaEditor) { syntaxHighlighter.fullscreen(textarea); sideBySideDiff(); return; } var toolbar = $('#editwiki_toolbar'), preview = $("#autosave_preview"), comment = $("#comment").parents("fieldset:first"), screen = $('.TextArea-fullscreen'), zone = $('.edit-zone', screen); screen.add(textarea).css('height', ''); //removes wiki command buttons (save, cancel, preview) from fullscreen view $('.TextArea-fullscreen .actions').remove(); if (textarea.parent().hasClass("ui-wrapper")) { textarea.resizable("destroy"); // if codemirror is off, jquery-ui resizable messes this up } var textareaParent = textarea.parents(".tab-content:first").toggleClass('TextArea-fullscreen'); if (textareaParent.hasClass('TextArea-fullscreen')) { $('body').css('overflow', 'hidden'); $('.tabs,.rbox-title').toggle(); $('#fullscreenbutton').hide(); var win = $window .data('cm-resize', true), diff = $("#diff_outer"), msg = $(".translation_message"), actions = $('.actions', textarea.parents("form")); //adds wiki command buttons (save, cancel, preview) to fullscreen view actions.clone().appendTo('.TextArea-fullscreen'); actions = $('.actions', $('.TextArea-fullscreen')); comment.css({ // fix comments fieldset to bottom and hide others (like contributions) position: "absolute", bottom: actions.outerHeight() + "px", width: "100%" }).nextAll("fieldset").hide(); preview.css({ position: "absolute", top: 0, left: 0 }); win.resize(function() { screen = $('.TextArea-fullscreen'); actions = $('.actions', screen); comment = $("#comment").parents("fieldset:first"); if (win.data('cm-resize') && screen) { screen.css('height', win.height() + 'px'); var swidth = win.width() + "px"; var commentMargin = parseInt(comment.css("paddingTop").replace("px", "")) * 4; commentMargin += parseInt(comment.css("borderBottomWidth").replace("px", "")) * 2; var innerHeight = win.height() - comment.outerHeight() - commentMargin - actions.outerHeight(); // reducing innerHeight by 85px in prev line makes the "Describe the change you made:" and // "Monitor this page:" edit fields visible and usable. Tested in all 22 themes in Tiki-12 r.48429 if (diff.length) { swidth = (screen.width() / 2) + "px"; innerHeight -= msg.outerHeight(); msg.css("width", (screen.width() / 2 - msg.css("paddingLeft").replace("px", "") - msg.css("paddingRight").replace("px", "")) + "px"); diff.css({ width: swidth, height: innerHeight + 'px' }); $('#diff_history').height(innerHeight + "px"); } textarea.css("width", swidth); toolbar.css('width', swidth); zone.css("width", swidth); preview.css("width", swidth); textarea.css('height', (innerHeight - toolbar.outerHeight()) + "px"); } }); setTimeout(function () {$window.resize();}, 500); // some themes (coelesce) don't show scrollbars unless this is delayed a bit } else { textarea.css("width", ""); toolbar.css('width', ""); zone.css({ width: "", height: ""}); screen.css("width", ""); comment.css({ position: "", bottom: "", width: "" }).nextAll("fieldset").show(); preview.css({ position: "", top: "", left: "" }); $('body').css('overflow', ''); $('.tabs,.rbox-title').toggle(); $('#fullscreenbutton').show(); $window.removeData('cm-resize'); } sideBySideDiff(); } /* Simple tiki plugin for jQuery * Helpers for autocomplete and sheet */ var xhrCache = {}, lastXhr; // for jq-ui autocomplete $.fn.tiki = function(func, type, options, excludepage) { var opts = {}, opt; switch (func) { case "autocomplete": if (jqueryTiki.autocomplete && jqueryTiki.ui) { if (typeof type === 'undefined') { // func and type given // setup error - alert here? return null; } options = options || {}; var requestData = {}, _renderItem = null; var url = ""; switch (type) { case "pagename": url = "tiki-listpages.php?listonly&initial=" + (options.initial ? options.initial + "&nonamespace" : "")+"&exclude_page="+excludepage; break; case "groupname": url = "tiki-ajax_services.php?listonly=groups"; break; case "username": url = "tiki-ajax_services.php?listonly=users"; break; case "usersandcontacts": url = "tiki-ajax_services.php?listonly=usersandcontacts"; break; case "userrealname": url = "tiki-ajax_services.php?listonly=userrealnames"; break; case "tag": url = "tiki-ajax_services.php?listonly=tags&separator=+"; break; case "icon": url = null; opts.source = Object.keys(jqueryTiki.iconset.icons).concat(jqueryTiki.iconset.defaults); _renderItem = function(ul, item) { return $("
  • ") .attr("data-value", item.value ) .append($().getIcon(item.value)) .append(" ") .append(item.label) .appendTo(ul); }; break; case 'trackername': url = "tiki-ajax_services.php?listonly=trackername"; break; case 'trackervalue': if (typeof options.fieldId === "undefined") { // error return null; } $.extend( requestData, options ); options = {}; url = "list-tracker_field_values_ajax.php"; break; case "reference": url = "tiki-ajax_services.php?listonly=references"; break; } var multiple = options.multiple && (type == 'usersandcontacts' || type == 'userrealname' || type == 'username' || type == 'reference'); opts = $.extend({ // default options for autocompletes in tiki minLength: 2, source: function( request, response ) { if( multiple ) { request.term = (''+request.term).split( /,\s*/ ).pop(); } if (options.tiki_replace_term) { request.term = options.tiki_replace_term.apply(null, [request.term]); } var cacheKey = "ac." + type + "." + request.term; if ( cacheKey in xhrCache ) { response( xhrCache[ cacheKey ] ); return; } request.q = request.term; $.extend( request, requestData ); lastXhr = $.getJSON( url, request, function( data, status, xhr ) { xhrCache[ cacheKey ] = data; if ( xhr === lastXhr ) { response( data, function (item) { return item }) }}); }, focus: function(ev) { // Important for usability handling below to prevent non-valid selections ev.preventDefault(); }, search: function() { if( multiple ) { // custom minLength var term = (''+this.value).split( /,\s*/ ).pop(); if ( term.length < 2 ) { return false; } } }, select: function(e, ui) { if( multiple ) { var terms = ''+this.value; terms = terms.replace(';', ','); terms = terms.split( /,\s*/ ); // remove the current input terms.pop(); // add the selected item terms.push( ui.item.value ); // add placeholder to get the comma-and-space at the end terms.push( "" ); this.value = terms.join( ", " ); return false; } else { $(this).data('selected', true); } } }, opts); $.extend(opts, options); if(options.mustMatch && multiple) { // Control editing of autocomplete to avoid messing with selection this.on("keydown", function (e) { if (e.which === 8 || e.which === 46) { e.preventDefault(); var terms = ''+this.value; terms = terms.replace(';', ','); terms = terms.split( /,\s*/ ); // remove the current input and the last previous item var lastterm = terms.pop(); if (lastterm === '') { terms.pop(); } // add placeholder to get the comma-and-space at the end terms.push( "" ); this.value = terms.join( ", " ); } else if (e.which === 37 || e.which === 39) { e.preventDefault(); } }); this.on("focus click", function() { var currentVal = $(this).val(); $(this).val('').val(currentVal); }); } else if (options.mustMatch) { if ($(this).val()) { // if there is value to begin then consider as selected $(this).data('selected', true); } $(this).on("blur", function() { if (! $(this).data('selected')) { $(this).val(''); } }); $(this).on("keydown", function(e) { if ($(this).data('selected') && (e.which === 8 || e.which === 46)) { e.preventDefault(); $(this).val(''); $(this).data('selected', false); } else if ($(this).data('selected') && (e.which > 47 || e.which === 32)) { e.preventDefault(); } else if (e.which === 13 && !$(this).data('selected')) { e.preventDefault(); } }); } return this.each(function() { var $element = $(this).autocomplete(opts).blur( function() { $(this).removeClass( "ui-autocomplete-loading").change(); }); if (_renderItem && $element.length) { $element.autocomplete("instance")._renderItem = _renderItem; } }); } break; case "carousel": if (jqueryTiki.carousel) { opts = { imagePath: "vendor_bundled/vendor/jquery-plugins/infinitecarousel/images/", autoPilot: true }; $.extend(opts, options); return this.each(function() { $(this).infiniteCarousel(opts); }); } break; case "datepicker": case "datetimepicker": if (jqueryTiki.ui) { switch (type) { case "jscalendar": // replacements for jscalendar // timestamp result goes in the options.altField if (typeof options.altField === "undefined") { alert("jQuery.ui datepicker jscalendar replacement setup error: options.altField not set for " + $(this).attr("id")); debugger; } opts = { showOn: "both", buttonText: '', changeMonth: jqueryTiki.changeMonth, changeYear: jqueryTiki.changeYear, dateFormat: jqueryTiki.shortDateFormat, timeFormat: jqueryTiki.shortTimeFormat, showButtonPanel: true, altFormat: "@", altFieldTimeOnly: false, onClose: function(dateText, inst) { $.datepickerAdjustAltField(func, inst); } }; break; default: opts = { showOn: "both", buttonText: '', dateFormat: jqueryTiki.shortDateFormat, showButtonPanel: true, firstDay: jqueryTiki.firstDayofWeek }; break; } $.extend(opts, options); if (func === "datetimepicker") { return this.each(function() { $(this).datetimepicker(opts); }); } else { return this.each(function() { $(this).datepicker(opts); }); } } break; case "accordion": if (jqueryTiki.ui) { opts = { autoHeight: false, collapsible: true, navigation: true // change: function(event, ui) { // // sadly accordion active property is broken in 1.7, but fix is coming in 1.8 so TODO // setCookie(ui, ui.options.active, "accordion"); // } }; $.extend(opts, options); return this.each(function() { $(this).accordion(opts); }); } break; case "select2": if (jqueryTiki.select2) { var selects = this; opts = { containerCssClass: 'select2-selection-tiki', dropdownCssClass: 'select2-dropdown-tiki dropdown-animate', theme: 'bootstrap-5', dir: $('html').attr('dir') || 'ltr', language: { noResults: function () { return tr('No results match'); } }, templateSelection: function (obj) { var $el = $(``); $el.text(obj.text); return $el; }, }; // Adds and/or merge more options $.extend(opts, options); selects.each(function() { let $select = $(this), multiple = $select.prop('multiple'), placeholder = $.trim($select.find("option[value='']").text()); if (! placeholder) { placeholder = multiple ? tr('Select Some Options') : tr('Select an Option'); } // overrides option placeholder opts.allowClear = ! multiple; opts.closeOnSelect = true; opts.placeholder = placeholder; opts.width = $select.parent().hasClass('input-group') ? 'resolve' : '100%'; // Fix Boostrap4 Modal scrolling - move dropdown menu to modal-body opts.dropdownParent = $select.closest('.modal-body').length > 0 ? $select.closest('.modal-body') : $(document.body); // Disables search option for single selects if ($select.hasClass('select2-nosearch')) { opts.minimumResultsForSearch = Infinity; } // Initialize select2 with created options $select.select2(opts); // Fix Boostrap4 modal scrolling while Select is opened // but disables dropdown auto position if ($select.closest('.modal-body').length > 0) { $select .on('select2:open', function () { $select.closest('.modal').off('scroll'); }); } // Disables search option for multiple selects if (multiple && $select.hasClass('select2-nosearch')) { $select.on('select2:opening select2:closing', function (event) { let $searchfield = $(this).parent().find('.select2-search__field'); $searchfield.prop('disabled', true); }); } if (jqueryTiki.select2_sortable && multiple) { $select .next('.select2-container') .find('.select2-selection--multiple ul.select2-selection__rendered') .sortable({ containment: "parent", items: "> li.select2-selection__choice", }) .on("sortstop", function (event, ui) { sortOptionsBySortableOrder(); }) .parents("form:first:not(.customsearch_form)") .submit(function () { if (!$(this).data("select2-multi-submitted") && !$select.hasClass("noselect2")) { sortOptionsBySortableOrder(); $select.trigger('change'); $(this).data("select2-multi-submitted", true); } }) ; } function sortOptionsBySortableOrder() { $select .next('.select2-container') .find("li.select2-selection__choice:not(.select2-search--inline) .select2-selection__choice__value") .each(function () { let option = $select.find(`option[value="${$(this).data("option-value")}"]`)[0]; moveElementToEndOfParent($(option)); }); function moveElementToEndOfParent($element) { let parent = $element.parent(); $element.detach(); parent.append($element); } } }); } break; } // end switch(func) }; (function($) { $.datepickerAdjustAltField = function(func, inst) { $.datepicker._updateAlternate(inst); // make sure the hidden field is up to date var val = $(inst.settings.altField).val(), timestamp; if (func === "datetimepicker") { val = val.substring(0, val.indexOf(" ")); timestamp = parseInt(val / 1000, 10); if (!timestamp || isNaN(timestamp)) { $.datepicker._setDateFromField(inst); // seems to need reminding when starting empty $.datepicker._updateAlternate(inst); val = $(inst.settings.altField).val(); val = val.substring(0, val.indexOf(" ")); timestamp = parseInt(val / 1000, 10); } if (timestamp && inst.settings && inst.settings.timepicker) { // if it's a datetimepicker add on the time let date = new Date(); date.setTime(timestamp * 1000); date.setHours(inst.settings.timepicker.hour, inst.settings.timepicker.minute); timestamp = date.getTime() / 1000; } } else { timestamp = parseInt(val / 1000, 10); } $(inst.settings.altField).val(timestamp ? timestamp : "").change(); }; // the jquery.ui _gotoToday function doesn't seem to work any more, so override that and add a call to _setDate $.datepicker._jquibase_gotoToday = $.datepicker._gotoToday; $.datepicker._gotoToday = function (id) { var inst = this._getInst($(id)[0]); this._jquibase_gotoToday(id); this._setDate(inst, new Date()); // the alternate field gets updated when the dialog closes }; /** * Adds annotations to the content of text in ''container'' based on the * content found in selected dts. * * Used in comments.tpl */ $.fn.addnotes = function( container ) { return this.each(function(){ var comment = this; var text = $('dt:contains("note")', comment).next('dd').text(); var title = $('h4:first', comment).clone(); var body = $('.comment-body:first', comment).clone(); body.find('dt:contains("note")').closest('dl').remove().addClass('card'); if( text.length > 0 ) { var parents = container.find(':contains("' + text + '")').parent(); var node = container.find(':contains("' + text + '")').not(parents) .addClass('note-editor-text alert-info') .each( function() { var child = $('dl.note-list',this); if( ! child.length ) { child = $('
    ') .appendTo(this) .hide(); $(this).click( function() { child.toggle(); } ); } child.append( title ) .append( $('
    ').append(body) ); } ); } }); }; /** * Convert a zone to a note editor by attaching handlers on mouse events. */ $.fn.noteeditor = function (editlink, link) { var hiddenParents = null; var annote = $(link) .click( function( e ) { e.preventDefault(); var $block = $('
    '); var annotation = $(this).attr('annotation'); $(this).fadeOut(100); $block.load(editlink.attr('href'), function () { var msg = ""; if (annotation.length < 20) { msg = tr("The text you have selected is quite short. Select a longer piece to ensure the note is associated with the correct text.") + "
    "; } msg = "

    " + msg + tr("Tip: Leave the first line as it is, starting with \";note:\". This is required") + "

    "; $block.prepend($(msg)); $('textarea', this) .val(';note:' + annotation + "\n\n").focus(); $('form', this).submit(function () { $.post($(this).attr('action'), $(this).serialize(), function () { $block.dialog('destroy'); // update the comments list editlink.closest('.comment-container').reload(); }); return false; }); $block.dialog({ modal: true, width: 500, height: 400 }); }); } ) .appendTo(document.body); $(this).mouseup(function( e ) { var range; if( window.getSelection && window.getSelection().rangeCount ) { range = window.getSelection().getRangeAt(0); } else if( window.selection ) { range = window.selection.getRangeAt(0); } if( range ) { var str = $.trim( range.toString() ); if( str.length && -1 === str.indexOf( "\n" ) ) { annote.attr('annotation', str); annote.fadeIn(100).position( { of: e, at: 'bottom left', my: 'top left', offset: '20 20' } ); } else { if (annote.css("display") != "none") { annote.fadeOut(100); } if ($("form.comments").css("display") == "none") { $("form.comments").show(); } if (hiddenParents) { hiddenParents.hide(); hiddenParents = null; } } } }); }; $.fn.browse_tree = function () { this.each(function () { $('.treenode:not(.done)', this) .addClass('done') .each(function () { if (getCookie($('ul:first', this).attr('data-id'), $('ul:first', this).attr('data-prefix')) !== 'o') { $('ul:first', this).css('display', 'none'); } var $placeholder = $('span.ui-icon:first:not(.control)', this); if ($('ul:first', this).length) { var dir = $('ul:first', this).css('display') === 'block' ? 's' : 'e'; if ($placeholder.length) { $placeholder.replaceWith(''); } else { $(this).prepend(''); } } else { if ($placeholder.length) { $placeholder.replaceWith(''); } else { $(this).prepend(''); } } if ($('div.checkbox', this).length) { $('div.checkbox', this).css("margin-left", "16px"); } }); $('.flipper:not(.done)') .addClass('done') .css('cursor', 'pointer') .click(function () { var body = $(this).parent().find('ul:first'); if ('block' === body.css('display')) { $(this).removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e'); body.hide('fast'); setCookie(body.data("id"), "", body.data("prefix")); } else { $(this).removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s'); body.show('fast'); setCookie(body.data("id"), "o", body.data("prefix")); } }); }); return this; }; $.initTrees = function () { $(".tree.root:not(.init)").browse_tree().addClass("init"); }; setTimeout($.initTrees, 100); var fancy_filter_create_token = function(value, label) { var close, token; console.log(); close = $('') .click(function () { var ed = $(this).parent().parent(); $(this).parent().remove(); ed.change(); return false; }); token = $('') .attr('data-value', value) .text(label) .attr('contenteditable', false) .disableSelection() .append(close); return token[0]; }; var fancy_filter_build_init = function(editable, str, options) { if (str === '') { str = ' '; } editable.html(str.replace(/(\d+)/g, '$1')); if (options && options.map) { editable.find('span').each(function () { var val = $(this).text(); $(this).replaceWith(fancy_filter_create_token(val, JSON.parse(options.map)[val] ? JSON.parse(options.map)[val] : val)); }); } }; $.fn.fancy_filter = function (operation, options) { this.each(function () { switch (operation) { case 'init': var editable = $('
    '), input = this; if (editable[0].contentEditable !== null) { fancy_filter_build_init(editable, $(this).val(), options); editable.attr('contenteditable', true); $(this).after(editable).hide(); } editable .keyup(function() { $(this).change(); $(this).mouseup(); }) .change(function () { $(input).val($('') .html(editable.html()) .find('span').each(function() { $(this).replaceWith(' ' + $(this).attr('data-value') + ' '); }) .end().text().replace(/\s+/g, ' ')); }) .mouseup(function () { input.lastRange = window.getSelection().getRangeAt(0); }); break; case 'add': var editable = $(this).next(); editable.find("span[data-value='"+ options.token +"']").remove(); var node = fancy_filter_create_token(options.token, options.label); editable.append(node); editable.change(); break; } }); return this; }; $.fn.drawGraph = function () { this.each(function () { var $this = $(this); var width = $this.width(); var height = $this.height() ? $this.height() : Math.ceil( width * 9 / 16 ); var nodes = $this.data('graph-nodes'); var edges = $this.data('graph-edges'); var g = new Graph; $.each(nodes, function (k, i) { g.addNode(i); }); $.each(edges, function (k, i) { var style = { directed: true }; if( i.preserve ) { style.color = 'red'; } g.addEdge( i.from, i.to, style ); }); var layouter = new Graph.Layout.Spring(g); layouter.layout(); var renderer = new Graph.Renderer.Raphael($this.attr('id'), g, width, height ); renderer.draw(); }); return this; }; /** * Handle textarea and input text selections * Code from: * * jQuery Autocomplete plugin 1.1 * Copyright (c) 2009 Jörn Zaefferer * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Now deprecated and replaced in Tiki 7 by jquery-ui autocomplete */ $.fn.selection = function(start, end) { if (start !== undefined) { if (end === undefined) { end = start; } return this.each(function() { if( this.selectionStart) { this.selectionStart = start; this.selectionEnd = end; } else if( this.setSelectionRange ){ this.setSelectionRange(start, end); } else if( this.createTextRange ){ var selRange = this.createTextRange(); if (start == end) { selRange.move("character", start); selRange.select(); } else { selRange.collapse(true); selRange.moveStart("character", start); selRange.moveEnd("character", end - start); // moveEnd is relative selRange.select(); } } }); } var field = this[0]; if( field.selectionStart !== undefined) { return { start: field.selectionStart, end: field.selectionEnd } } else if ( field.createTextRange ) { // from http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/ // The current selection var range = document.selection.createRange(); // We'll use this as a 'dummy' var stored_range = range.duplicate(); // Select all text stored_range.moveToElementText( field ); // Now move 'dummy' end point to end point of original range stored_range.setEndPoint( 'EndToEnd', range ); // Now we can calculate start and end points var textProperty = range.htmlText ? "htmlText" : "text"; // behaviour changed in IE10 (approx) so htmlText has unix line-ends which works (not 100% sure why) var selectionStart = stored_range[textProperty].length - range[textProperty].length; var selectionEnd = selectionStart + range[textProperty].length; return { start: selectionStart, end: selectionEnd } } }; $.fn.comment_toggle = function () { this.each(function () { var $target = $(this.hash); $target.hide(); $(this).click(function () { if ($target.is(':visible')) { $target.hide(function () { $(this).empty(); }); } else { $target.comment_load($(this).attr('href')); } return false; }); if (location.search.indexOf("comzone=show") > -1 || location.hash.match(/threadId=?(\d+)/)) { var comButton = this; setTimeout(function() { $(comButton).click(); }, 500); } }); return this; }; $.fn.comment_load = function (url) { var $top = $('#top'); $('.note-list', $top).remove(); this.each(function () { var comment_container = this; if (! comment_container.reload) { comment_container.reload = function () { $(comment_container).empty().comment_load(url); }; } $(this).addClass('comment-container'); $(this).load(url, function (response, status) { $(this).show(); if (jqueryTiki.useInlineComment && ! jqueryTiki.useInlineAnnotations) { $('.comment.inline dt:contains("note")', this) .closest('.comment') .addnotes($top); $top.noteeditor($('.comment-form:last a', comment_container), '#note-editor-comment'); } $('.button.comment-form.autoshow a').addClass('autoshown').click().removeClass('autoshown'); // allow autoshowing of comment forms through autoshow css class var match = location.hash.match(/threadId=?(\d+)/); if (match) { var $tab = $(this).parents(".tab-pane"), $tabContent = $(this).parents(".tab-content"); // if we're in an inactive tab then show the right one for this comment threadId if ($tab.length && ! $tab.is(".active")) { $tabContent.find(".tab-pane").each(function (index) { if (this === $tab[0]) { $(".nav-tabs li:nth(" + index + ") a", $tabContent.parent()).tab("show"); } }) } var $comment = $(".comment[data-comment-thread-id=" + match[1] + "]"); var top = $comment.offset().top; $('html, body').animate({ scrollTop: top },{ duration: 2000, complete: function() { $comment.addClass("comment-highlight"); } }); } }); }); return this; }; $(document).on('click', '.comment-form.buttons > a.btn', function () { var comment_container = $(this).closest('.comment-container, .ui-dialog-content')[0]; $('.comment-form form:not(.commentRatingForm)', comment_container).each(function() { // remove other forms apart from the ratings vote form var $p = $(this).parent(); $p.empty().addClass('button').addClass('buttons').append($p.data('previous')); }); if (!$(this).hasClass('autoshown')) { $(".comment").each(function () { $("article > *:not(ol)", this).each(function () { $(this).css("opacity", 0.6); }); }); } $(this).parents('.comment:first').find("*").css("opacity", 1); var $formContainer = null; if ($(this).data('target')) { $formContainer = $($(this).data('target')); } else { $formContainer = $(this).parents('.buttons'); } $(this).parents('.buttons').data('previous', $(this).siblings().addBack()).empty().removeClass('buttons').removeClass('button'); // Update buttons if loaded as a modal $('.modal.fade.show').trigger('tiki.modal.redraw'); $formContainer.load($(this).attr('href'), function () { var form = $('form', this).submit(function () { var errors, current = this; $(current).tikiModal(tr("Saving...")); //Synchronize textarea and codemirror before comment is posted if (typeof syntaxHighlighter.sync === 'function') { syntaxHighlighter.sync($(current).find("textarea.wikiedit")); } $.post($(current).attr('action'), $(current).serialize(), function (data, st) { $(current).tikiModal(); if (data.threadId) { let threadId = data.threadId; $(current).closest('.comment-container').reload(); $('span.count_comments').each(function () { var action = $(current).attr('action').match(/tiki-comment-(\w*)/), count = parseInt($(this).text()); if (action) { //noinspection FallThroughInSwitchStatementJS switch (action[1]) { case "remove": count--; break; case "post": count++; // fall through to adjust threadId if necessary case "edit": case "moderate": location.hash = location.hash.replace(/threadId=\d+/, "threadId=" + threadId); break; } $(this).text(count); } }); if (data.feedback && data.feedback[0]) { alert(data.feedback.join("\n")); } } else { errors = $('ol.errors', form).empty(); if (!errors.length) { $(':submit', current).after(errors = $('
      ')); } $.each(data.errors, function (k, v) { errors.append($('
    • ').text(v)); }); } }, 'json'); return false; }); //allow syntax highlighting if ($.fn.flexibleSyntaxHighlighter) { window.codeMirrorEditor = []; form.find('textarea.wikiedit').flexibleSyntaxHighlighter(); } $(document).trigger("tiki.ajax.redraw"); }); return false; }); // scroll to post if #threadId on url in forums if ($("body.tiki_forums").length) { let match = location.hash.match(/threadId=?(\d+)/); if (match) { let $comment = $("#" + match[0].replace("=", "") + ".post"); let top = $comment.offset().top; $('html, body').animate({ scrollTop: top }, 2000, function () { $comment.animate({ backgroundColor: "#ff8" }, 250, function () { $comment.animate({ backgroundColor: "" }, 1000); }); }); } } $.fn.input_csv = function (operation, separator, value) { this.each(function () { var values = $(this).val().split(separator); if (values[0] === '') { values.shift(); } if (operation === 'add' && -1 === values.indexOf("" + value)) { values.push(value); } else if (operation === 'delete') { value = String(value); while (-1 !== $.inArray(value, values)) { values.splice($.inArray(value, values), 1); } } $(this).val(values.join(separator)); }); return this; }; $.service = function (controller, action, query) { var append = ''; if (query) { append = '?' + $.buildParams(query); } if (action) { return 'tiki-' + controller + '-' + action + append; } else { return 'tiki-' + controller + '-x' + append; } }; $.serviceUrl = function (options) { var o = $.extend({}, options), controller = options.controller, action = options.action; delete(o.controller); delete(o.action); return $.service(controller, action, o); }; $.buildParams = function (query, prefix, suffix) { prefix = prefix || ''; suffix = suffix || ''; return $.map(query, function (v, k) { if ($.isPlainObject(v)) { return $.buildParams(v, k + '[', ']'); } else { return prefix + k + suffix + '=' + tiki_encodeURIComponent(v); } }).join('&'); }; $.fn.serviceDialog = function (options) { this.each(function () { var $dialog = $('
      '), origin = this, buttons = {}; $(this).append($dialog).data('serviceDialog', $dialog); if (! options.hideButtons) { buttons[tr('OK')] = function () { $dialog.find('form:visible').submit(); }; buttons[tr('Cancel')] = function () { $dialog.dialog('close'); if ($dialog.data('ui-dialog')) { $dialog.dialog('destroy'); } }; } $dialog.dialog({ title: options.title, minWidth: options.width ? options.width : 500, height: (options.fullscreen ? $window.height() - 20 : (options.height ? options.height : 600)), width: (options.fullscreen ? $window.width() - 20 : null), close: function () { if (options.close) { options.close.apply([], this); } if ($(this).data('ui-dialog')) { $(this).dialog('destroy').remove(); } }, buttons: buttons, modal: options.modal, zIndex: options.zIndex }); $dialog.loadService(options.data, $.extend(options, {origin: origin})); }); return this; }; $.fn.loadService = function (data, options) { var $dialog = this, controller = options.controller, action = options.action, url; this.each(function () { if (! this.reload) { this.reload = function () { $(this).loadService(data, options); }; } }); if (typeof data === "string") { data = parseQuery(data); } if (data && data.controller) { controller = data.controller; } if (data && data.action) { action = data.action; } if (options.origin && $(options.origin).is('a')) { url = $(options.origin).attr('href'); } else if (options.url) { url = options.url; } else { url = $.service(controller, action); } $dialog.tikiModal(tr("Loading...")); $.ajax(url, { data: data, error: function (jqxhr) { $dialog.html(jqxhr.responseText); }, success: function (data) { $dialog.html(data); $dialog.find('.ajax').click(function (e) { $dialog.loadService(null, {origin: this}); return false; }); $dialog.find('.service-dialog').click(function (e) { if ($dialog.data('ui-dialog')) { $dialog.dialog('close'); } return true; }); $dialog.find('form .submit').hide(); $dialog.find('form:not(.no-ajax)').off("submit").submit(ajaxSubmitEventHandler(function (data) { data = (data ? data : {}); if (data.FORWARD) { $dialog.loadService(data.FORWARD, options); } else if ($dialog.data('ui-dialog')) { $dialog.dialog('destroy').remove(); } if (options.success) { options.success.apply(options.origin, [data]); } })); if (options.load) { options.load.apply($dialog[0], [data]); } $('.confirm-prompt', this).requireConfirm({ success: function (data) { if (data.FORWARD) { $dialog.loadService(data.FORWARD, options); } else { $dialog.loadService(options.data, options); } } }); }, complete: function () { $dialog.tikiModal(); if ($dialog.find('form').size() == 0 && $dialog.data('ui-dialog')) { // If the result contains no form, skip OK/Cancel, and just allow to close var buttons = $dialog.dialog('option', 'buttons'), n = {}; if (buttons[tr('Cancel')]) { n[tr('OK')] = buttons[tr('Cancel')]; $dialog.dialog('option', 'buttons', n); } } } }); }; $.fn.confirmationDialog = function (options) { var modal = $('#bootstrap-modal'), modalHeader = modal.find('.modal-header'), modalBody = $(''), modalFooter = $(''), modalFooterConfirm = $(''), modalFooterClose = $(''); //needed because modal-content is globally being cleared after appearing for the first time if (!modalHeader || modalHeader.length === 0) { modal.find('.modal-content').append(''); modalHeader = modal.find('.modal-header'); } if (options.title) { modalHeader.find('h4').text(options.title); } else { modalHeader.find('h4').text(tr('Confirmation Modal')); } if (options.message) { modalBody.find('p').text(options.message); } else { modalBody.find('p').text(tr('Please confirm you want to perform this action.')); } modalFooter.append(modalFooterClose, modalFooterConfirm); modalHeader.after(modalBody); modalBody.after(modalFooter); modal.on('hidden.bs.modal', function (e) { if (options.close) { options.close(); } }); modalFooterConfirm.on('click', function (e) { modal.modal('hide'); if (options.success) { options.success(); } }); modal.modal('show'); return this; }; $.fn.requireConfirm = function (options) { this.click(function (e) { e.preventDefault(); $(this).doConfirm(options); return false; }); return this; }; $.fn.doConfirm = function (options) { var message = options.message, link = this; if (! message) { message = $(this).data('confirm'); } if (confirm (message)) { var $this = $(this); $this.tikiModal(" "); $.ajax($(this).attr('href'), { type: 'POST', dataType: 'json', data: { 'confirm': 1 }, success: function (data) { $this.tikiModal(); options.success.apply(link, [data]); }, error: function (jqxhr) { $this.tikiModal(); $(link).closest('form').showError(jqxhr); } }); } }; $.fn.showError = function (message) { if (message.responseText) { if (message.getResponseHeader("Content-Type").indexOf("text/html") === -1) { var data = JSON.parse(message.responseText); message = data.message; } else { message = $(message.responseText).text(); // can be html } } else if (typeof message !== 'string') { message = ""; } this.each(function () { var parts, that = this; if (parts = message.match(/^(.*)$/)) { field = parts[1]; message = parts[2]; if (that[field]) { that = that[field]; } } var validate = false, errors = {}, field, $additional = $('
        '); if (jqueryTiki.validate) { validate = $(that).closest('form').validate() } if (validate) { if (! $(that).attr('name')) { $(that).attr('name', $(that).attr('id')); } if (that !== validate.currentForm) { field = $(that).attr('name'); } if (field) { errors[field] = message; validate.showErrors(errors); } else { // No specific field, assign as form error $additional.append($('
      • ').text(message)); } setTimeout(function () { $('#tikifeedback li').filter(function () { return $(this).text() === message; }).remove(); if ($('#tikifeedback ul').is(':empty')) { $('#tikifeedback').empty(); } }, 100); } else { $additional.append($('
      • ').text(message)); } if (! $additional.is(':empty')) { // Write form errors at the top, please stop removing them $('.ajax-errors', this).remove(); $('
        ') .prependTo(this) .append($additional); } // Style the bootstrap form-group as an error $('.form-group').removeClass('has-error') .find('label.error:visible') .addClass('form-text') .prepend(' ') .closest('.form-group').addClass('has-error') }); return this; }; $.fn.clearError = function () { this.each(function () { $(this).closest('form').find('label.error[for="' + $(this).attr('name') + '"]').remove(); $(this).closest('form').find('.form-group.has-error').removeClass('has-error'); }); return this; }; // sort result containing all galleries function sortResult(result) { result.sort(function(a, b) { if (a.parent_title) { var titleA = a.parent_title.toUpperCase(); // ignore upper and lowercase var titleB = b.parent_title.toUpperCase(); // ignore upper and lowercase if (titleA < titleB) { return -1; } if (titleA > titleB) { return 1; } } // names must be equal return 0; }); } // search the title of each parent gallery function parentTitle(result, parent) { var title=''; $.each(result, function(key, value) { if(value.object_id === parent){ title= value.title + ' > '; } }); return title; } function loadSelectorData(filter, args, success) { if (! $.object_selector_cache) { $.object_selector_cache = {}; } if ($.isFunction(args)) { success = args; args = {}; } var item, url; url = $.service('search', 'lookup', $.extend(args, { filter: filter })); if (item = $.object_selector_cache[url]) { if (item.data) { success(item.data); } else { item.queue.push(success); } } else { item = $.object_selector_cache[url] = { data: null, queue: [success] }; $.getJSON(url, function (data) { item.data = data; $.each(item.queue, function (k, f) { f(data); }); item.queue = []; }); } } $._object_selector_add_item = function (type, $select, $results, parent_title, item, title, status_icon, selected) { var checkname = $select.closest('.object-selector, .object-selector-multi') .find('.primary').attr('id') + '_sel'; var suffix = $results.find('.form-check').lenght || 0; $('