/* # Copyright (c) 2012+ Damjan Rems # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ mouseDown = false; /******************************************************************* * Find and extract parameters value from url *******************************************************************/ $.getUrlParam = function(name) { var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); if (results == null) return null; return results[1] || 0; }; /******************************************************************* * Dump all attributes to console *******************************************************************/ dumpAttributes = function(obj) { console.log('Dumping attributes:'); $.each(obj.attributes, function() { console.log(this.name,this.value); }); }; /******************************************************************* * Function checks if there are delay loaded embedded elements on * selected tab and triggers iframe reload. *******************************************************************/ update_embedded_on_tab_select = function(div_name) { let iframes = $(div_name).find("iframe"); $.each(iframes, function(index, iframe) { // delayed load let src_delay = iframe.getAttribute('data-src-delay'); if (src_delay != null && src_delay != '') { iframe.setAttribute('data-src-delay', ''); iframe.setAttribute('src', src_delay); } // always load on tab select let src_always = iframe.getAttribute('data-src-always'); if (src_always != null) { iframe.setAttribute('src', src_always); } }); }; /******************************************************************* * Return false when confirmation is not required *******************************************************************/ confirmation_is_cancled = function(object) { var confirmation = object.getAttribute("data-confirm"); // if confirmation required if (confirmation !== null) { if (!confirm(confirmation)) {return true;} } return false; }; /******************************************************************* * Will update select field on the form which select options are dependend * on other field value. It calls /dc_common/autocomplete and passes * methodname and depend field value to obtain new values for select field. *******************************************************************/ update_select_depend = function(select_name, depend_name, method) { var select_field = $('#'+select_name); var depend_field = $('#'+depend_name); $.ajax({ url: "/dc_common/autocomplete", type: "POST", dataType: "json", data: { input: depend_field.val(), search: method}, success: function(data) { select_field.empty(); $.each(data, function(index, element) { select_field.append( new Option(element['label'], element['id']) ); }); } }); }; /******************************************************************* * Format number input field according to data *******************************************************************/ format_number_field = function(e) { var decimals = e.attr("data-decimal") || 2; var delimiter = e.attr("data-delimiter") || '.'; var separator = e.attr("data-separator") || ','; var currency = e.attr("data-currency") || ''; var whole = e.val().split(separator)[0]; var dec = e.val().split(separator)[1]; // save value to hidden field which will be used for return var field = '#' + e.attr("id").slice(0,-1); var value = e.val().replace(delimiter,'.'); $(field).val( parseFloat(value).toFixed(decimals) ); // decimal part if (dec == null) dec = ''; dec = dec.substring(0, decimals, dec); while (dec.length < decimals) dec = dec + '0'; // whole part if (whole == null || whole == '') whole = '0'; var ar = []; while (whole.length > 0) { var pos1 = whole.length - 3 if (pos1 < 0) pos1 = 0; ar.unshift(whole.substr(pos1,3)); whole = whole.slice(0, -3); }; if (delimiter !== '') whole = ar.join(delimiter); e.val(whole + separator + dec + currency); }; /******************************************************************* * Activate jquery UI tooltip. This needs jquery.ui >= 1.9 *******************************************************************/ /* $(function() { $( document ).tooltip(); }); */ /******************************************************************* * Process json result from ajax call and update parts of document. * I invented my own protocol which is arguably good or wrong. * * Protocol consists of operation and value which are returned as json by * called controller. Controller will return an ajax call usually like this: * render json: {operation: value} * * Operation is further divided into source and determinator which are divided by underline char. * render json: {#div_status: 'OK!'} * will replace html in div="status" with value 'OK!'. Source is '#div' determinator is 'status'. * * Possible operators are: * record_name: will replace value of record[name] field on a form with supplied value * * msg_error: will display error message. * msg_warning: will display warning message. * msg_info: will display informational message. * * popup: will display popup message * * #div_divname : will replace divname with value * #div+_divname : will append value to divname * #+div_divname : will prepend value to divname * .div_classname : will replace all accurencess of classname with value * .+div_classname : will prepend value to all accurencess of classname * .div+_classname : will append value to all accurencess of classname * * url_: Will force loading of url supplied in value into same window * window_: Will force loading of url supplied in value into new window * reload_: Will reload current window * * Operations can be chained and are executed sequential. * render json: {'window_' => "/document.pdf", 'reload_' => 1}.to_json * will open /document.pdf in new window and reload current window. * * render json: {'record_name' => "Damjan", 'record_surname' => 'Rems'}.to_json * will replace values of two fields on the form. *******************************************************************/ process_json_result = function(json) { let i, w, operation, selector, msg_div, field; $.each(json, function(key, value) { i = key.search('_'); if (i > 1) { operation = key.substring(0, i); selector = key.substring(i+1, 100); } else { operation = key; selector = ''; } switch (operation) { /**** update fields on form ****/ case 'record': let name = key.replace('record_','record[') + ']'; field = $('[name="' + name + '"]'); // checkbox field if (field.is(':checkbox')) { field.prop('checked', value); // select field } else if (field.is('select')) { // options for select field if (Array.isArray(value)) { field.empty(); $.each(value, function(index, v) { field.append( new Option(v[0], v[1]) ); }); // select field value } else { field.val(value).change(); } // radio field } else if (field.attr('type') == 'radio') { field.val([value]) // other input fields } else { field.val(value); } break; /**** transfer focus to field ****/ case 'focus': $('#' + value).focus(); break; /**** display message ****/ case 'msg': let msg_div = 'dc-form-' + selector; if ( $('.' + msg_div).length == 0 ) { value = '
' + value + '
'; $('.dc-title').after(value); } else { $('.' + msg_div).html(value); $('.' + msg_div).show(); } break; /**** display popup message ****/ case 'popup': if (selector == 'url') { $('#popup').bPopup({ loadUrl: value, transition: 'slideDown', transitionClose: 'slideDown', speed: 300, opacity: 0, position: ['auto', 20], closeClass: 'dc-link' }); } else { $('#popup').html(value); $('#popup').bPopup( { transition: 'slideDown', transitionClose: 'slideDown', speed: 300, opacity: 0, position: ['auto', 20], closeClass: 'dc-link' }); } break; /**** update div ****/ case '#div+': $('#'+selector).append(value); break; case '#+div': $('#'+selector).prepend(value); break; case '#div': $('#'+selector).html(value); break; case '.div+': $('.'+selector).append(value); break; case '.+div': $('.'+selector).prepend(value); break; case '.div': $('.'+selector).html(value); break; /**** goto url ****/ case 'url': window.location.href = value; break; case 'parenturl': parent.location.href = value; break; case 'alert': alert(value); break; case 'window': if (value == 'close') { window.close(); } else if (value == 'reload') { window.location.href = window.location.href; } else { w = window.open(value, selector); w.focus(); } break; case 'newwindow': w = window.open(value, selector,"location=no,scrollbars=yes,resizable=yes"); w.focus(); break; case 'eval': console.log('from process_json_result: Eval option will be deprecated. Use script instead.') eval (value); break; case 'script': eval (value); break; case 'reload': value = value.toString(); if (value == 'parent') { //parent.location.reload(); parent.location.href = parent.location.href; /*** this would be current window (reload: true) ****/ } else if (value.length < 5) { window.location.href = window.location.href; /*** reload iframe ****/ } else { $( '#' + value ).attr('src', $( '#' + value ).attr('src')); } break; default: console.log("DRGCMS: Invalid ajax result operation: " + operation); } }); }; /******************************************************************* * Will reload window *******************************************************************/ function dc_reload_window() { location.reload(); } /******************************************************************* * Will open popup window *******************************************************************/ function popup_window(url, title, parent_win, w, h) { let y = parent_win.top.outerHeight / 2 + parent_win.top.screenY - (h / 2); let x = parent_win.top.outerWidth / 2 + parent_win.top.screenX - (w / 2); let win = parent_win.open(url, 'dc_popup', `toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=${w}, height=${h}, top=${y}, left=${x}`); win.document.title = title; return win; } /******************************************************************* * Will select first editable input field on form. Works only when tab * is selected. Still have to find out, what to do on initial display. *******************************************************************/ function select_first_input_field(div_name) { $(div_name + " :input:first").each( function() { this.focus(); return true; }); } /******************************************************************* * Will scroll to position on the screen. This is replacement for * location.hash, which doesn't work in Chrome. * * Thanks goes to: http://web-design-weekly.com/snippets/scroll-to-position-with-jquery/ *******************************************************************/ $.fn.dc_scroll_view = function () { return this.each(function () { $('html, body').animate({ scrollTop: $(this).offset().top - 100 }, 500); }); }; /******************************************************************* * Updates single field on parent iframe form of embedded form. *******************************************************************/ process_parent_form_updates = function(element) { let field = element.getAttribute("data-field"); let value = element.getAttribute("data-value"); let selector = '#' + field; // update record if (field.match(/record/)) { if (window.parent.$(selector).length > 0) { if (field.substring(0, 3) === 'td_') { // readonly field window.parent.$(selector + ' > div').html(value); } else { // input field window.parent.$(selector).val(value); } } // any div } else { if (window.parent.$(selector).length > 0) { window.parent.$(selector).html(value); } } }; /***************************************************************** * Toggle show and hide div ******************************************************************/ dc_div_toggle = function(div) { if ($(div).is(":visible")) { $(div).slideUp(); } else { $(div).slideDown(); } }; /***************************************************************** * Process simple ajax call ******************************************************************/ simple_ajax_call = function(url) { $.ajax({ url: url, success: function(data) { process_json_result(data); } }); }; /***************************************************************** * Return value of the input field on a form ******************************************************************/ function dc_field_get_value(field_name) { field_name = field_name.replace('record_', ''); let field = $('[name="record[' + field_name + ']"]'); return field.val(); } /***************************************************************** * Will process data-fields attribute and add field values as parameters to url ******************************************************************/ function dc_url_add_params(form, url) { // check if data-fields attribute present let fields = form.getAttribute("data-fields"); if (fields === null) return url; // url might already contain ? let form_parms = '?'; if (url.match(/\?/)) form_parms = ''; fields.split(',').forEach( function(field) { let value = dc_field_get_value(field); if (value) form_parms += '&' + field + '=' + value; }); return url + form_parms; } /******************************************************************* * Copy div text to clipboard *******************************************************************/ function dc_copy_to_clipboard(div) { let copyText = document.getElementById(div).innerText; console.log(copyText); /* Copy the text inside the text field */ navigator.clipboard.writeText(copyText); } /******************************************************************* * Events start here *******************************************************************/ $(document).ready( function() { /* This could be the way to focus on first input field on document open if ( $('.dc-form')[0] ) { // resize parent iframe to fit selected tab size var div_height = $('.dc-form')[0].clientHeight + 130; window.frameElement.style.height = div_height.toString() + 'px'; // select_first_input_field('.dc-form'); } */ /******************************************************************* * It will scroll display to ypos if return_to_ypos parameter is present *******************************************************************/ if (window.location.href.match(/return_to_ypos=/)) { window.scrollTo(0, $.getUrlParam('return_to_ypos')); } /******************************************************************* * The idea is to update fields on parent iframe form, when embedded document * is updated in its iframe. Update fields are listed in .dc-form-updates div * and are set by flash[:update] Hash object. * * eg. flash[:update] = {'td_record_radonly' => 'New value for read_only field', * 'record_name' => 'New name'} *******************************************************************/ if ( $('.dc-form-updates').length > 0 ) { $('.dc-form-updates').children().each( function( index, element ) { process_parent_form_updates(element); }); } /******************************************************************* * Register ad clicks *******************************************************************/ $('a.link_to_track').click(function() { $.post('/dc_common/ad_click', { id: this.id }); return true; }); /***************************************************************** * Toggle CMS mode. When clicked on left 30 pixels, window will be scrolled approximately * to the position wher toggle was clicked. When clicked from pixel 31 and on it will * stay on the top of window. ******************************************************************/ $('.cms-toggle').bind('click', function(e) { var url = '/dc_common/toggle_edit_mode?return_to=' + window.location.href; if (e.pageX < 30) url = url + '&return_to_ypos=' + e.pageY ; window.location.href = url; }); /******************************************************************* * Popup or close CMS edit menu on icon click *******************************************************************/ $('.drgcms_popmenu').on('click',function(e) { $(e.target).parents('dl:first').find('ul').toggleClass('div-hidden'); }); /******************************************************************* * Popup CMS edit menu option clicked *******************************************************************/ $('.drgcms_popmenu_item').on('click',function(e) { let url = e.target.getAttribute("data-url"); $('#iframe_cms').attr('src', url); // $('#iframe_cms').width(1000).height(1000); // scroll to top of page and hide menu window.scrollTo(0,0); $(e.target).parents('dl:first').find('ul').toggleClass('div-hidden'); }); /******************************************************************* * Sort action clicked on cmsedit *******************************************************************/ $('.dc-sort-select').change( function(e) { let table = e.target.getAttribute("data-table"); let form = e.target.getAttribute("data-form"); if (form === null) form = table; let sort = e.target.value; // e.target.value = null; let url = "/cmsedit/run?control=cmsedit.sort&sort=" + sort + "&table=" + table + "&form_name=" + form; simple_ajax_call(url); }); /******************************************************************* * Click on field name in result header perform sort action *******************************************************************/ $('.dc-result-header span').on('click',function(e) { let url = e.target.getAttribute("data-url"); simple_ajax_call(url); }); /******************************************************************* * Click on dc-check-all icon. Check or uncheck all checkboxes *******************************************************************/ $('.dc-check-all').on('click',function(e) { let checkboxes = $('.dc-check'); if ($(this).hasClass('fa-check-square-o')) { // check all checkboxes checkboxes.each( function() { $(this).prop('checked', true); $(this).parent().closest('div').addClass('dc-checked'); }); $(this).removeClass('fa-check-square-o').addClass('fa-square-o'); } else { // uncheck all checkboxes checkboxes.each( function() { $(this).prop('checked', false); $(this).parent().closest('div').removeClass('dc-checked'); }); $(this).removeClass('fa-square-o').addClass('fa-check-square-o'); } }); /******************************************************************* * Click on dc-check icon. Change color of background of element *******************************************************************/ $('.dc-check').on('click',function(e) { let parent = $(this).parent().closest('div'); if ($(this).prop('checked')) { parent.addClass('dc-checked'); } else { parent.removeClass('dc-checked'); } }); /******************************************************************* * Tab clicked on form. Hide old and show selected div. *******************************************************************/ $('.dc-form-li').on('click', function(e) { // find li with dc-form-li-selected class. This is our old tab let old_tab_id = null; $(e.target).parents('ul').find('li').each( function() { if ($(this).hasClass('dc-form-li-selected')) { // when not already selected toggle dc-form-li-selected class and save old tab if ($(this) !== $(e.target)) { $(this).toggleClass('dc-form-li-selected'); $(e.target).toggleClass('dc-form-li-selected'); old_tab_id = this.getAttribute("data-div"); } return false; } }); // show selected data div if (old_tab_id !== null) { $('#data_' + old_tab_id).toggleClass('div-hidden'); $('#data_' + e.target.getAttribute("data-div")).toggleClass('div-hidden'); // resize parent iframe to fit selected tab size let div_height = document.body.scrollHeight; let frame = window.frameElement if (frame === null) frame = document.body; frame.style.height = div_height.toString() + 'px'; select_first_input_field('#data_' + e.target.getAttribute("data-div")); update_embedded_on_tab_select('#data_' + e.target.getAttribute("data-div")); } }); /******************************************************************* * Resize iframe_cms to the size of its contents. Make at least 500 px high * unless on initial display. *******************************************************************/ $('#iframe_cms').on('load', function() { let new_height = this.contentWindow.document.body.offsetHeight + 50; if (new_height < 500 && new_height > 60) new_height = 500; this.style.height = new_height + 'px'; // scroll to top $('#iframe_cms').dc_scroll_view(); }); /******************************************************************* * Same goes for editiframe. Resize it + 30px * unless on initial display with no data *******************************************************************/ $('#iframe_edit').on('load', function() { if (this.contentWindow.document.body.offsetHeight > 10) { this.style.height = (this.contentWindow.document.body.offsetHeight + 30) + 'px'; $('#iframe_edit').dc_scroll_view(); } }); /******************************************************************* * Same goes for iframe_embedded. Resize it + 30px *******************************************************************/ $('.iframe_embedded').on('load', function() { let embedded_height = this.contentWindow.document.body.offsetHeight; // workaround. It gets tricky when embedded field is on tab if (embedded_height == 0) embedded_height = 50; this.style.height = (embedded_height + 30) + 'px'; // resize parent iframe window too let parentWindow = this.contentWindow.parent; let parent_height = (parentWindow.document.body.offsetHeight + 30) + 'px'; //parentWindow.frameElement.setAttribute('style', 'height:' + parent_height); parentWindow.frameElement.style.height = parent_height; }); /******************************************************************* * Process Ajax call on cmsedit form actions *******************************************************************/ $('.dc-link-ajax').on('click', function(e) { // confirmation if required if (confirmation_is_cancled(this)) {return false;} // url must be specified in data-url let url = this.getAttribute("data-url"); if (url.length < 5) return false; // check HTML5 validations if ($("form")[0] && !$("form")[0].checkValidity() ) { $("form")[0].reportValidity(); return false; } let data = {}; let request = this.getAttribute("data-request"); switch (request) { case 'script': eval(this.getAttribute("data-script")); return false; case 'post': data = $('form').serialize(); break; default: request = 'get'; // by default } // add checkbox id-s to data if checkboxes present let checkboxes = $('.dc-check'); if (checkboxes.length > 0) { let checked = []; checkboxes.each( function() { if ($(this).prop('checked')) checked.push($(this).attr("id")); }) data['checked'] = checked; } $('.dc-spinner').show(); $.ajax({ url: url, type: request, dataType: "json", data: data, success: function(data) { process_json_result(data); $('.dc-spinner').hide(); }, error: function (request, status, error) { $('.dc-spinner').css('color','red'); alert(request.responseText); } }); }); /******************************************************************* * Click on filter off *******************************************************************/ $('.mi-search_off').on('click', function(e) { let url = $(this).parents('.dc-filter').attr("data-url"); if (url.length > 5) simple_ajax_call(url); }); /******************************************************************* * Process action submit button click. *******************************************************************/ $('.dc-action-submit').on('click', function(e) { // confirmation if required if (confirmation_is_cancled(this)) {return false;} // check HTML5 validations var form = $("form")[0]; if (form && !form.checkValidity() ) { form.reportValidity(); return false; } var url = this.getAttribute("data-url"); if (url == null) {return false;} form.setAttribute('action', url); form.setAttribute('method', "post"); form.submit(); }); /******************************************************************* Will open a new window with URL specified. ********************************************************************/ $('.dc-window-open').on('click', function(e) { // confirmation if required if (confirmation_is_cancled(this)) return false; let url = this.getAttribute("data-url"); let title = this.getAttribute("title"); let w = this.getAttribute("data-x") || 1000; let h = this.getAttribute("data-y") || 800; url = dc_url_add_params(this, url) let win = popup_window(url, title, window, w, h); win.focus(); }); /******************************************************************* Will open a new popup with URL specified. ********************************************************************/ $('.dc-popup-open').on('click', function(e) { // confirmation if required if (confirmation_is_cancled(this)) return false; let url = this.getAttribute("data-url"); let title = this.getAttribute("title"); let w = this.getAttribute("data-x") || 1000; let h = this.getAttribute("data-y") || 800; url = dc_url_add_params(this, url) $('#popup').bPopup({ loadUrl: url, transition: 'slideDown', transitionClose: 'slideDown', speed: 300, opacity: 0, position: ['auto', 20], closeClass: 'dc-link' }); }); /******************************************************************* * Animate button on click ****************************************************************** $('.xdc-action-menu li').mousedown( function() { $(this).toggleClass('dc-animate-button'); }); ****************************************************************** * Animate button on click ****************************************************************** $('.xdc-action-menu li').mouseup( function() { $(this).toggleClass('dc-animate-button'); }); */ /******************************************************************* * App menu option clicked *******************************************************************/ $('.app-menu-item a').on('click', function(e) { /* parent of a is li */ $(e.target).parents('li').each( function() { /* for all li's in ul, deselect */ $(this).parents('ul').find('li').each( function() { if ($(this).hasClass('app-menu-item-selected')) { $(this).toggleClass('app-menu-item-selected'); } }); /* select clicked li */ $(this).toggleClass('app-menu-item-selected'); }); }); /******************************************************************* * Display spinner on link with spinner, submit link *******************************************************************/ $('.dc-link.spin').on('click', function(e) { $('.dc-spinner').show(); }); $('.dc-link-submit').on('click', function(e) { $('.dc-spinner').show(); }); /******************************************************************* * Hide spinner when validation error occured *******************************************************************/ $(':input').on("invalid", function(event) { $('.dc-spinner').hide(); }); /******************************************************************* * Add button clicked while in edit. Create window dialog for adding new record * into required table. This is helper scenario, when user is selecting * data from with text_autocomplete and data doesn't exist in belongs_to table. *******************************************************************/ $('.in-edit-add').on('click', function(e) { let id = this.getAttribute("data-id"); let table = this.getAttribute("data-table"); let url = '/cmsedit/new?window_close=0&table=' + table; if (id) { url = '/cmsedit/' + id + '/edit?window_close=0&table=' + table; } let w = popup_window(url, '', window, 1000, 800); w.focus(); }); /********************************************************************** * When filter_field (field name) is selected on filter subform this routine finds * and displays appropriate span with input field. **********************************************************************/ $('#filter_field').on('change', function() { if (this.value.length > 0) { let name = 'filter_' + this.value; $(this).parents('form').find('span').each( function() { if ($(this).attr('id') == name) { if ( $(this).hasClass('div-hidden') ) { $(this).toggleClass('div-hidden'); } } else { if ( !$(this).hasClass('div-hidden') ) { $(this).toggleClass('div-hidden'); } } }); } }); /******************************************************************* * It is not possible to attach any data to submit button except the text * that is written on a button and it is therefore very hard to distinguish * which button was pressed when more than one button is present on a form. * * The purpose of this trigger is to append data hidden in html5 data attributes * to the form. We can now attach any kind of data to submit button and data * will be passed as data[] parameters to controller. *******************************************************************/ $('.dc-submit').on('click', function() { $.each(this.attributes, function() { if (this.name.substring(0,5) == 'data-') { $('').attr({ type: 'hidden', name: 'data[' + this.name.substring(5) + ']', value: this.value }).appendTo('form'); } }); }); /* DOCUMENT INFO */ /******************************************************************* * Popup or hide document information *******************************************************************/ $('#dc-document-info').on('click',function(e) { popup = $('#dc-document-info-popup'); popup.toggleClass('div-hidden'); if (!popup.hasClass('div-hidden')) { var o = { left: e.pageX - popup.width() - 10, top: e.pageY - popup.height() - 20 }; popup.offset(o); }; }); /******************************************************************* * Just hide document information on click. *******************************************************************/ $('#dc-document-info-popup').on('click',function(e) { $('#dc-document-info-popup').toggleClass('div-hidden'); }); /******************************************************************* * Experimental. Force reload of parent page if this div appears. *******************************************************************/ $('#div-reload-parent').on('load', function() { // alert('div-reload-parent 1'); parent.location.href = parent.location.href; }); /******************************************************************* * Force reload of parent page if this div appears. * * Just an Idea. Not needed yet. *******************************************************************/ $('#div-reload').on('load', function() { alert('div-reload 1'); // location.href = location.href; }); $('#div-reload-parent').on('DOMNodeInserted DOMNodeRemoved', function() { alert('div-reload-parent 2'); }); $('#div-reload').on('DOMNodeInserted DOMNodeRemoved', function() { alert('div-reload 2'); }); /******************************************************************* * Fire action (by default show document) when doubleclicked on result row *******************************************************************/ $('.dc-result tr').on('dblclick', function(e) { let url = String( this.getAttribute("data-dblclick") ); // prevent when data-dblclick not set if (url.length > 5) { e.preventDefault(); location.href = url; } }); /******************************************************************* * Fire action (by default show document) when doubleclicked on result row *******************************************************************/ $('.dc-result-data').on('dblclick', function(e) { let url = String( this.getAttribute("data-dblclick") ); // prevent when data-dblclick not set if (url.length > 5) { e.preventDefault(); location.href = url; } }); /******************************************************************* * Fire action clicked on result row. * TODO: Find out how to prevent event when clicked on action icon. *******************************************************************/ $('.dc-result tr').on('click', function(e) { url = String( this.getAttribute("data-click") ); // prevent when data-click not set if (url.length > 5) { e.preventDefault(); location.href = url; } }); $('#1menu-filter').on('click', function(e) { var target = e.target; // if (e.target.src !== undefined) { // target = e.target.parent(); // picture // }; // dumpAttributes(target); req = target.getAttribute("data-request"); $('.menu-filter').toggle(300); }); /******************************************************************* * This will fire cmsedit index action and pass value entered into * filter field and thus refresh browsed result set. *******************************************************************/ $('#_record__filter_field').keydown( function(e) { if (e.which == '13' || e.which == '9') { let url = $(this).parents('span').attr("data-url"); url = url + "&filter_value=" + this.value; simple_ajax_call(url); }; }); /******************************************************************* * Same as above, but when clicked on filter icon. enter and tab don't * work on all field types. *******************************************************************/ $('.record_filter_field_icon').on('click', function(e) { let field = $('#_record__filter_field'); let url = $(this).parents('span').attr("data-url"); let value = null; if (field.is(':checkbox')) { value = field.is(':checked'); } else { value = field.val(); } url = url + "&filter_value=" + value; simple_ajax_call(url); }); /******************************************************************* * Click on show filter form *******************************************************************/ $('#open_drgcms_filter').on('click', function(e) { $('#drgcms_filter').bPopup({ transition: 'slideDown', transitionClose: 'slideDown', speed: 300, opacity: 0, position: ['auto', 20], closeClass: 'dc-link' }); }); /******************************************************************* * Click on preview selected image *******************************************************************/ $('.dc-image-preview').on('click', function(e) { let img = $(this).children(":first").attr('src'); $('#dc-image-preview').bPopup({ content: 'image', //'ajax', 'iframe' or 'image' contentContainer: '#dc-image-preview', loadUrl: img, opacity: 0 }); }); /******************************************************************* * Set new filter *******************************************************************/ $('.dc-filter-set').on('click', function(e) { let url = $(this).attr( 'data-url' ); let field = $('select#filter_field1').val(); let operation = $('select#filter_oper').val(); url = url + '&filter_field=' + field + '&filter_oper=' + operation simple_ajax_call(url); }); /******************************************************************* * Toggle one cmsedit menu level *******************************************************************/ $('.cmsedit-top-level-menu div').on('click', function(e) { $(e.target).siblings('ul').toggle('fast'); $(e.target).toggleClass('expanded'); }); /******************************************************************* * Toggle result set record menu * * This and additional two event hadlers provide expected behavior of submenus popup and close. *******************************************************************/ $('.dc-result-submenu .mi-more_vert').on('click', function(e) { let ul = $(e.target).siblings('ul'); // hide last selected menu if not the same if (typeof dc_last_menu_selected !== 'undefined') { dc_last_menu_selected.hide(); } // if menu is past the bottom fix it to bottom let menu_bottom = ul.height() + ul.parent().position().top + 20; if (menu_bottom > $(document).height()) ul.css('bottom', 0); ul.show(); dc_last_menu_selected = ul; }); /******************************************************************* * Result record menu has lost focus. Hide menu. *******************************************************************/ $('.dc-result-submenu ul').hover(function(e) { }, function(e) { dc_last_menu_selected.hide(); dc_last_menu_selected = undefined; }); /******************************************************************* * Result set record menu is left open if action is canceled. Ex. delete confirm. This will hide menu. *******************************************************************/ $('.dc-result-submenu ul li').on('click', function(e) { console.log('ups'); if (typeof dc_last_menu_selected !== 'undefined') dc_last_menu_selected.hide(); }); /******************************************************************* * Resize result table columns. For now an idea. *******************************************************************/ /* $( ".dc-result-header .spacer" ) .mouseenter(function() { console.log("enter"); }) .mouseleave(function() { console.log("leave"); }); */ /******************************************************************* * number_field type entered *******************************************************************/ $('.dc-number').on('focus', function(e) { var separator = $(this).attr("data-separator") || ','; var field = '#' + $(this).attr("id").slice(0,-1); var value = $(field).val().replace('.',separator); $(this).val( value ); $(this).select(); }); /******************************************************************* * number_field type leaved *******************************************************************/ $('.dc-number').on('focusout', function(e) { var decimals = $(this).attr("data-decimal") || 2; var delimiter = $(this).attr("data-delimiter") || '.'; var separator = $(this).attr("data-separator") || ','; var currency = $(this).attr("data-currency") || ''; var val = this.value; // clear delimiters and replace separator with . val = val.replace(delimiter,''); val = val.replace(separator,'.'); val = parseFloat(val).toFixed(decimals); var whole, dec, sign; // [whole,dec] = val.split('.'); whole = val.split('.')[0]; dec = val.split('.')[1]; // remove negative sign and add at the end var sign = whole.substr(0,1); if (sign == '-') { whole = whole.substr(1,20); } else { sign = ''; } // save value to hidden field which holds return value var field = '#' + $(this).attr("id").slice(0,-1); $(field).val(val); // decimal part if (decimals == 0) separator = ''; if (dec == null) dec = ''; while (dec.length < decimals) dec = dec + '0'; // whole part if (whole == null || whole == '') whole = '0'; var ar = []; while (whole.length > 0) { var pos1 = whole.length - 3 if (pos1 < 0) pos1 = 0; ar.unshift(whole.substr(pos1,3)); whole = whole.slice(0, -3); }; if (delimiter !== '') whole = ar.join(delimiter); $(this).val(sign + whole + separator + dec + currency); }); /******************************************************************* * Key pressed in number_field. * - put minus sign in front of input field * - replace dot and comma separators when required. Not all numeric pads are created equal. * - when enter is pressed, save value to field before form is proccessed *******************************************************************/ $('.dc-number').on('keydown', function(e) { // Minus sign. Put it on first place if (e.which == 109) { if($(this).val().substr(0,1) == '-') { $(this).val( $(this).val().substr(1,20)); } else { $(this).val( '-' + $(this).val()); } e.preventDefault(); } // replace , with . if . is separator. var separator = $(this).attr("data-separator") || '.'; var inp = this; if (e.which == 188) { if (separator == '.') { setTimeout(function() { inp.value = inp.value.replace(/,/g, '.'); }, 0); } } // replace . with , if , is separator if (e.which == 190) { if (separator == ',') { setTimeout(function() { inp.value = inp.value.replace(/\./g, ','); }, 0); } } // Enter means process form. Save the value before form is processed if (e.which == 13) { var decimals = $(this).attr("data-decimal") || 2; var value = $(this).val().replace(separator,'.'); var field = '#' + $(this).attr("id").slice(0,-1); $(field).val( parseFloat(value).toFixed(decimals) ); } }); /******************************************************************* * Slovenian keyboard has comma key instead of dot in numeric pad. * This will catch if comma has been pressed and will replace it with dot. *******************************************************************/ $('.date-picker').keypress( function(e) { if (e.keyCode !== 44) return; var inp = this; setTimeout(function() { inp.value = inp.value.replace(/,/g, '.'); }, 0); }); /******************************************************************* * Result header sort icon is hoverd. Change background icon to filter. *******************************************************************/ $('.dc-result-header .th i').hover( function() { old_sort_icon = ''; // save old sort icon and replace it with filter icon $.each( $(this).attr("class").split(/\s+/), function(index, item) { if (item.match('sort')) { old_sort_icon = item}; } ); $(this).removeClass(old_sort_icon).addClass('mi-ads_click'); // bring back old sort icon }, function() { $(this).removeClass('mi-ads_click').addClass(old_sort_icon); }); /******************************************************************* * Result header sort icon is clicked. Display filter menu for the field. *******************************************************************/ $('.dc-result-header .th i').click( function(e) { e.preventDefault(); if ($(this).hasClass('no-filter')) return; // additional click will close dialog when visible if ($('.filter-popup').is(':visible')) { $('.filter-popup').hide(); return; } // retrieve name of current field and set it in popup let header = $(this).closest('.th'); let field_name = header.attr("data-name"); $('.filter-popup').attr('data-name', field_name); // change popup position and show $('.filter-popup').css({'top': e.pageY + 5, 'left': e.pageX, 'position': 'absolute'}); $('.filter-popup').show(); }); /******************************************************************* * Filter operation is clicked on filter popup. Retrieve data and call * filter on action. *******************************************************************/ $('.filter-popup li').click( function(e) { let url = $(this).data('url'); let operator = $(this).data('operator'); let parent = $(this).closest('.filter-popup'); let field_name = parent.data("name"); url = url + '&filter_field=' + field_name + '&filter_oper=' + operator; simple_ajax_call(url); }); /***************************************************************** * Toggle div ******************************************************************/ $(".dc-handle").click(function() { let div = this.getAttribute("data-div"); dc_div_toggle(div); }); /******************************************************************* * Show-Hide CMS menu on hamburger click *******************************************************************/ $('#menu-hamburger').on('click', function(e) { $('.cmsedit-container #cms-menu').toggleClass('visible'); }); }); /******************************************************************* * Catch ctrl+s key pressed and fire save form event. I press ctrl+s * almost every minute. That was a lesson learned years ago when I lost * few hours of work on computer lockup ;-( *******************************************************************/ $(document).keydown( function(e) { if ((e.which == '115' || e.which == '83' ) && (e.ctrlKey || e.metaKey)) { e.preventDefault(); document.forms[0].submit(); return false; } return true; }); /******************************************************************* ******************************************************************* $(document).onmousedown( function(e) { mouseDown = true; console.log("mouse down"); }); $(document).onmouseup( function(e) { mouseDown = false; console.log("mouse up"); }); **/