/* * jquery.domajax.js v2.0.3 * http://domajax.fuz.org * * Copyright (c) 2012-2015 alain tiemblo * * 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. */ ; (function ($, windowObj) { $.fn.domAjax = function (overwriteSettings) { /* * ------------------------------------------ * Default settings * ------------------------------------------ */ var defaults = { 'endpoint': null, 'endpoint-container': null, 'input': null, 'input-attr': '', 'output': null, 'output-complete': null, 'output-success': null, 'output-failure': null, 'output-empty': null, 'output-not-empty': null, 'output-json': null, 'confirm': null, 'lock': null, 'lock-before': null, 'lock-complete': null, 'lock-success': null, 'lock-failure': null, 'lock-empty': null, 'lock-not-empty': null, 'unlock': null, 'unlock-before': null, 'unlock-complete': null, 'unlock-success': null, 'unlock-failure': null, 'unlock-empty': null, 'unlock-not-empty': null, 'method': 'post', 'cache': 'false', 'cache-name': 'ajax', 'raw': null, 'raw-type': null, 'limit': -1, 'counter': 0, 'highlight': null, 'highlight-before': null, 'highlight-complete': null, 'highlight-success': null, 'highlight-failure': null, 'highlight-empty': null, 'highlight-not-empty': null, 'highlight-color': null, 'highlight-color-before': null, 'highlight-color-complete': null, 'highlight-color-success': null, 'highlight-color-failure': null, 'highlight-color-empty': null, 'highlight-color-not-empty': null, 'callback-before': null, 'callback-complete': null, 'callback-success': null, 'callback-failure': null, 'callback-empty': null, 'callback-not-empty': null, 'alias': null, 'script-before': null, 'script-complete': null, 'script-success': null, 'script-failure': null, 'script-empty': null, 'script-not-empty': null, 'replace': null, 'replace-by': null, 'delay': 0, 'value': null, 'domajax-before': null, 'domajax-complete': null, 'domajax-success': null, 'domajax-failure': null, 'domajax-empty': null, 'domajax-not-empty': null, 'poll': null }; if (overwriteSettings === undefined) { overwriteSettings = {}; } var events = ['before', 'complete', 'success', 'failure', 'empty', 'not-empty']; /* * ------------------------------------------ * Initialization * ------------------------------------------ */ var context = $('body'); var elems = this; if (elems.length === 0) { return elems; } /* * ------------------------------------------ * Options treatment before ajax request * ------------------------------------------ */ return $(elems).each(function () { var settings = {}; var elem = $(this); var prefix = ''; // --- data-domajax-prefix if (elem.data('domajax-prefix') !== undefined) { prefix = elem.data('domajax-prefix'); } // --- data-alias var aliases_seen = []; while ((elem.data(prefix + 'alias') !== undefined) && (elem.data(prefix + 'alias') !== null)) { var aliases = $(elem.data(prefix + 'alias')); elem.data(prefix + 'alias', null); if (aliases.length > 0) { $(aliases).each(function () { var alias = $(this); var alias_prefix = ''; if (alias.data('domajax-prefix') !== undefined) { alias_prefix = alias.data('domajax-prefix'); } var alias_id = tools.getOrCreateId(alias); if ($.inArray(alias_id, aliases_seen) >= 0) { return true; } aliases_seen.push(alias_id); $.each(defaults, function (key) { if (((elem.data(prefix + key) === undefined) || (elem.data(prefix + key) === null)) && (alias.data(alias_prefix + key) !== undefined)) { elem.data(prefix + key, alias.data(alias_prefix + key)); } }); }); } } // --- settings settings = $.extend(true, {}, defaults); $.each(settings, function (key) { if (elem.data(prefix + key) !== undefined) { settings[key] = elem.data(prefix + key); } }); settings = $.extend(true, settings, overwriteSettings); // --- data-delay if (settings['delay'] > 0) { var typeWatch = elem.data('delay-watcher'); if ((typeWatch !== undefined) && (typeWatch !== null)) { clearTimeout(typeWatch); } typeWatch = setTimeout(function () { elem.data('delay-watcher', null); elem.domAjax({ delay: 0 }); }, settings['delay']); elem.data('delay-watcher', typeWatch); return true; } // --- data-value if (settings['value'] !== null) { if (settings['value'] === '') { settings['value'] = '#' + tools.getOrCreateId(elem); } var curValue = JSON.stringify(tools.getInputs(settings['value'], elem, context)); var oldValue = elem.data('delay-old-value'); if (curValue === oldValue) { return true; } elem.data('delay-old-value', curValue); } // --- data-endpoint // --- data-endpoint-container if ((settings['endpoint'] === null) && (elem.attr('href') !== undefined)) { settings['endpoint'] = elem.attr('href'); } var endpoint = settings['endpoint']; if (endpoint === null) { endpoint = tools.getValue(settings['endpoint-container'], context); if (endpoint === null) { endpoint = ''; } } settings['endpoint'] = endpoint; // --- data-confirm if ((settings['confirm'] !== null) && (confirm(settings['confirm']) === false)) { return true; } // --- priority events if (processPriorityEvents(settings, elem, 'before') === false) { return true; } // --- data-counter, data-limit var counter = parseInt(settings['counter']); settings['counter'] = (isNaN(counter) ? 0 : counter) + 1; if ((settings['limit'] >= 0) && (settings['counter'] > settings['limit'])) { return true; } elem.data('counter', settings['counter']); // --- data-cache // --- data-cache-name settings['cache'] += ''; settings['cache-name'] += ''; if (settings['cache'].toLowerCase() === 'true') { if (settings['endpoint'].indexOf('?') === -1) { settings['endpoint'] = settings['endpoint'] + '?'; } else { settings['endpoint'] = settings['endpoint'] + '&'; } settings['cache-name'].replace(/[^a-zA-Z_]/g, '_'); var cacheVar = settings['cache-name'] + '=' + new Date().getTime() + Math.random(); settings['endpoint'] = settings['endpoint'] + cacheVar.replace('.', ''); } // --- data-input var inputs = {}; if (settings['input'] !== null) { inputs = tools.getInputs(settings['input'], elem, context); } settings['input'] = inputs; // --- data-input-attr var inputAttrs = {}; $.each(settings['input-attr'].split(' '), function (index, attribute) { if ((attribute + '').length > 0) { inputAttrs[attribute] = $(elem).data(attribute); } }); settings['input-attr'] = inputAttrs; // --- data-output if (settings['output'] !== null) { settings['output-success'] = settings['output']; } $.each(events, function (index, event) { var output = 'output-' + event; if (settings[output] === '') { settings[output] = '#' + tools.getOrCreateId(elem); } }); // --- data-output-json if (settings['output-json'] !== null) { var outputAttrs = {}; $.each(settings['output-json'].split(' '), function (index, attribute) { if ($(elem).data('json-' + attribute) !== undefined) { outputAttrs[attribute] = $(elem).data('json-' + attribute); } }); settings['output-json'] = outputAttrs; } // --- data-lock if (settings['lock'] !== null) { settings['lock-before'] = settings['lock']; settings['unlock-complete'] = settings['lock']; } // --- data-unlock if (settings['unlock'] !== null) { settings['unlock-complete'] = settings['unlock']; } // --- data-raw if (settings['raw'] !== null) { var selector = settings['raw']; settings['raw'] = tools.getValue(selector, context); if (settings['raw'] === null) { settings['raw'] = selector; } } // --- data-highlight, data-highlight-color var counter = 0; $.each(events, function (index, event) { var highlight_selector = 'highlight-' + event; var highlight_color = 'highlight-color-' + event; if ((settings[highlight_selector] === null) && (settings['highlight'] === null)) { if ((settings[highlight_color] !== null) || (settings['highlight-color'] !== null)) { settings['highlight'] = '#' + tools.getOrCreateId(elem); } } }); if (settings['highlight-color'] === null) { settings['highlight-color'] = 'blue'; } $.each(events, function (index, event) { var highlight_selector = 'highlight-' + event; var highlight_color = 'highlight-color-' + event; if (settings[highlight_color] === null) { settings[highlight_color] = settings['highlight-color']; } else { if ((settings[highlight_selector] === null) && (settings['highlight'] !== null)) { settings[highlight_selector] = settings['highlight']; counter++; } } }); if ((counter === 0) && (settings['highlight'] !== null)) { settings['highlight-success'] = settings['highlight']; } $.each(events, function (index, event) { var highlight_selector = 'highlight-' + event; if (settings[highlight_selector] !== null) { if (settings[highlight_selector] === '') { settings[highlight_selector] = '#' + tools.getOrCreateId(elem); } $(settings[highlight_selector]).each(function (index2, toHighlight) { if (!$(toHighlight).data('highlight-original-color')) { $(toHighlight).data('highlight-original-color', $(toHighlight).css('color')); } }); } }); // --- data-replace, data-replace-by if (settings['replace'] === '') { settings['replace'] = '#' + tools.getOrCreateId(elem); } if (settings['replace-by'] === '') { settings['replace-by'] = '#' + tools.getOrCreateId(elem); } if ((settings['replace'] === settings['replace-by']) || ((settings['replace'] !== null) && (settings['replace-by'] === null)) || ((settings['replace'] === null) && (settings['replace-by'] !== null))) { settings['replace'] = null; settings['replace-by'] = null; } if (settings['replace'] !== null) { var replaceBackup = ''; if (elem.data('replace-backup') !== undefined) { $(elem.data('replace-backup')).remove(); elem.removeData('replace-backup'); } $(settings['replace']).each(function () { var objectToBackup = $(this); var originalContainer = tools.getOrCreateId(objectToBackup); var backup = tools.getValue(objectToBackup, context); var backupContainer = $('
'); var backupId = tools.getOrCreateId(backupContainer); if (replaceBackup !== '') { replaceBackup += ', '; } replaceBackup += '#' + backupId; backupContainer.css('display', 'none').data('replace-backup-original-container', '#' + originalContainer).html(backup).appendTo(context); }); elem.attr('data-replace-backup', replaceBackup); var replace_by_value = tools.getValue(settings['replace-by']); tools.putValue(settings['replace'], replace_by_value); } // --- data-domajax $.each(events, function (index, event) { var domajax = 'domajax-' + event; if (settings[domajax] === '') { settings[domajax] = '#' + tools.getOrCreateId(elem); } }); processEvents(settings, elem, 'before'); /* * ------------------------------------------ * Options treatment after ajax request * ------------------------------------------ */ var responseIsEmpty = true; var responseCopy = null; $.ajax({ url: settings['endpoint'], type: settings['method'], data: settings['raw'] || $.extend(true, {}, settings['input'], settings['input-attr']), dataType: settings['raw-type'] || undefined, processData: settings['raw'] ? false : true, success: function (response, textStatus, jqXHR) { responseCopy = response; processRevertReplace(context, settings, elem); if (response) { responseIsEmpty = false; if (processPriorityEvents(settings, elem, 'not-empty', response, textStatus, jqXHR) === false) { return true; } processEvents(settings, elem, 'not-empty', response); } else { if (processPriorityEvents(settings, elem, 'empty', response, textStatus, jqXHR) === false) { return true; } processEvents(settings, elem, 'empty', response); } if (processPriorityEvents(settings, elem, 'success', response, textStatus, jqXHR) === false) { return true; } // --- data-output-json if (settings['output-json'] !== null) { var jsonResponse = null; if (typeof (response) === 'object') { jsonResponse = response; } else { try { jsonResponse = $.parseJSON(response); } catch (e) {} } if (jsonResponse !== null) { $.each(settings['output-json'], function (attribute, container) { if ((jsonResponse[attribute] !== undefined) && ($(container).length > 0)) { tools.putValue(container, jsonResponse[attribute]); } }); } } processEvents(settings, elem, 'success', response); }, error: function (jqXHR, textStatus, errorThrown) { if (processPriorityEvents(settings, elem, 'failure', errorThrown, textStatus, jqXHR) === false) { return true; } processRevertReplace(context, settings, elem); processEvents(settings, elem, 'failure', jqXHR.status + ' ' + jqXHR.statusText); }, complete: function () { if (processPriorityEvents(settings, elem, 'complete') === false) { return true; } processEvents(settings, elem, 'complete'); // --- data-poll if (settings['poll'] !== null) { var pollReturn = true; var pollCallback = settings['poll']; var pollClosure = tools.getClosureFronString(pollCallback, windowObj); if ($.isFunction(pollClosure)) { pollReturn = pollClosure(elem, responseCopy); } if (pollReturn) { elem.domAjax(); } } } }); return true; }); // $(elems).each }; // $.fn.domAjax /* * ------------------------------------------ * Options treatment on events, according to events * ------------------------------------------ */ $.fn.domAjax.processPriorityEvents = function (settings, elem, event, response, textStatus, jqXHR) { // --- data-script-event var option = 'script-' + event; if (settings[option] !== null) { var code = "(function(){" + settings[option] + ";})();"; try { var scriptReturn = eval(code); if (scriptReturn === false) { return false; } } catch (e) { throw 'data-script thrown an exception: '.e.message; } } // --- data-callback-event var option = 'callback-' + event; if (settings[option] !== null) { var callbacks = settings[option].split(' '); $.each(callbacks, function(index, callback) { var closure = tools.getClosureFronString(callback, windowObj); if ($.isFunction(closure)) { var callbackReturn = closure(elem, response, textStatus, jqXHR); if (callbackReturn === false) { return false; } } else { throw 'data-callback must contain JavaScript function(s).'; } }); } }; $.fn.domAjax.processEvents = function (settings, elem, event, response) { // ~~~ data-output var option = 'output-' + event; if ((settings[option] !== null) && (settings[option] !== undefined)) { $(settings[option]).each(function () { tools.putValue(this, response); }); } // --- data-lock[-event] var option = 'lock-' + event; var lockList = {}; if ((settings[option] !== null) && ($.type(settings[option]) !== 'object')) { lockList = tools.listElements(elem, settings[option], function (node) { return node.attr('disabled') === undefined; }); } $.each(lockList, function (index, selector) { $(selector).attr('disabled', 'disabled'); if ((event === 'before') && (settings['lock-before'] === settings['unlock-complete'])) { $(selector).data('locked', true); } }); // --- data-unlock[-event] var option = 'unlock-' + event; var unlockList = {}; if ((settings[option] !== null) && ($.type(settings[option]) !== 'object')) { unlockList = tools.listElements(elem, settings[option], function (node) { return node.attr('disabled') !== undefined; }); } $.each(unlockList, function (index, selector) { if ((event === 'complete') && (settings['lock-before'] === settings['unlock-complete'])) { if ($(selector).data('locked')) { $(selector).removeAttr('disabled'); $(selector).removeData('locked'); } } else { $(selector).removeAttr('disabled'); } }); // --- data-highlight[-event] var option = 'highlight-' + event; if (settings[option] !== null) { var color_key = 'highlight-color-' + event; var color = settings[color_key] || settings['highlight-color']; if (color !== null) { $(settings[option]).each(function (index, toHighlight) { var qToHighlight = $(toHighlight); setTimeout(function () { qToHighlight.stop().css({ 'color': color }).animate({ 'color': qToHighlight.data('highlight-original-color') }, 2500); }, 0); }); } } // --- data-domajax[-event] var option = 'domajax-' + event; if (settings[option] !== null) { $(settings[option]).domAjax(); } }; $.fn.domAjax.processRevertReplace = function (context, settings, elem) { // --- data-replace, data-replace-by if (settings['replace'] !== null) { $(elem.data('replace-backup')).each(function () { var objectToRestore = $(this); var backup = tools.getValue(objectToRestore, context); var originalContainer = objectToRestore.data('replace-backup-original-container'); objectToRestore.remove(); tools.putValue(originalContainer, backup); }); $(settings['replace']).removeData('replace-backup'); } }; /* * ------------------------------------------ * General methods * ------------------------------------------ */ $.fn.domAjax.tools = { // Get value fron one element according to its type getValue: function (selector, contextSelector) { try { var jqElem = $(selector); } catch (e) { return null; } if (jqElem.length === 0) { return null; } else if (jqElem.is('input[type="checkbox"]')) { return ((jqElem.prop('checked') === true) ? (true) : (undefined)); } else if ((jqElem.is('input[type="radio"]')) && (jqElem.attr('name') !== undefined)) { return $('input[name="' + jqElem.attr('name') + '"]:checked', contextSelector).val(); } else if (jqElem.prop('value') !== undefined) { return ((jqElem.is(':disabled') === false) ? (jqElem.val()) : (undefined)); } else { return jqElem.html(); } }, // Set new value to a field or a container putValue: function (selector, value) { try { var jqElem = $(selector); } catch (e) { return; } if (jqElem.prop('value') !== undefined) { jqElem.val(value); } else { jqElem.html(value); } }, // Get a random number randomNumber: function () { var rand = '' + Math.random() * 1000 * new Date().getTime(); return rand.replace('.', '').split('').sort(function () { return 0.5 - Math.random(); }).join(''); }, // Get element id or create it if it does not exists getOrCreateId: function (obj) { if (!obj.attr('id')) { var generated_id; do { generated_id = 'i' + this.randomNumber(); } while ($('#' + generated_id).length > 0); obj.attr('id', generated_id); } return obj.attr('id'); }, // List input fields of a container listElements: function (elem, container, filter) { var list = {}; if (container !== '') { $.each($(container), function (index, node) { node = $(node); if (node.prop('value') !== undefined) { if ((filter === undefined) || filter(node)) { list[index] = '#' + tools.getOrCreateId(node); } } }); container = container + ' :input'; $.each($(container), function (index, node) { node = $(node); if ((filter === undefined) || filter(node)) { list[index] = '#' + tools.getOrCreateId(node); } }); } else { list[0] = '#' + tools.getOrCreateId(elem); } return list; }, // Returns a callable function from a given path getClosureFronString: function (fullname, context) { var namespaces = fullname.split("."); var func = namespaces.pop(); for (var i = 0; (i < namespaces.length); i++) { context = context[namespaces[i]]; } return context[func]; }, getInputs: function (selector, elem, context) { var inputs = {}; if (selector === '') { var key = elem.attr('name') || elem.attr('id') || 'data'; var value = tools.getValue(elem, context); inputs[key] = value; } else { var selectorContainer = ''; $.each(selector.split(','), function(i, e) { if (i > 0) { selectorContainer += ','; } selectorContainer += e + ' :input'; }); var inputsSelectors = [selectorContainer, selector]; $.each(inputsSelectors, function (index, inputsSelector) { var jqInputsSelector = $(inputsSelector); if (jqInputsSelector.length > 0) { jqInputsSelector.each(function (key, inputSelector) { var jqInputSelector = $(inputSelector); if (!jqInputSelector.attr('name') && !jqInputSelector.attr('id')) { return true; } var key = jqInputSelector.attr('name') || jqInputSelector.attr('id'); var value = tools.getValue(jqInputSelector, context); inputs[key] = value; }); return false; } }); } return inputs; }, setOptionDefault: function (elem, option, value) { elem.each(function () { var that = $(this); if (that.data(option) === undefined) { that.data(option, value); } }); return elem; } }; var processPriorityEvents = $.fn.domAjax.processPriorityEvents; var tools = $.fn.domAjax.tools; var processEvents = $.fn.domAjax.processEvents; var processRevertReplace = $.fn.domAjax.processRevertReplace; })(jQuery, window); /* * ------------------------------------------ * Event Listeners * * This is not recommanded to embed event listeners * with non-user defined selectors inside a jquery * plugin, but I promised to let you do ajax without * any javascript code. * ------------------------------------------ */ $(document).ready(function () { var body = $('body'); // domAjax requirement if (body.length === 0) { throw "Document must have / tags."; } // click body .off('click', '.domajax.click') .on('click', '.domajax.click', function (e) { var that = $(this); that.domAjax(); e.preventDefault(); }); // keyup (with type watching) var typeWatch = null; body .off('keyup', '.domajax.keyup') .on('keyup', '.domajax.keyup', function (e) { var that = $(this); body.domAjax.tools.setOptionDefault(that, 'value', ''); body.domAjax.tools.setOptionDefault(that, 'delay', 800); that.domAjax(); }); // change (with enter-key launcher) body .off('change', '.domajax.change') .on('change', '.domajax.change', function (e) { var that = $(this); body.domAjax.tools.setOptionDefault(that, 'value', ''); that.domAjax(); e.preventDefault(); }); body .off('keypress', '.domajax.change') .on('keypress', '.domajax.change', function (e) { var that = $(this); body.domAjax.tools.setOptionDefault(that, 'value', ''); if ((e.which === 13) && !(that.is('textarea'))) { that.domAjax(); e.preventDefault(); } }); // ajax form submit body .off('click', 'input[type="submit"].domajax, button[type="submit"].domajax') .on('click', 'input[type="submit"].domajax, button[type="submit"].domajax', function (e) { var jqSubmit = $(this); if (jqSubmit.hasClass('click')) { return ; } var jqForms = $(this).closest('form'); if (jqForms.length > 0) { jqForms.each(function () { var jqForm = $(this); var formId = body.domAjax.tools.getOrCreateId(jqForm); jqSubmit.data('endpoint', jqForm.attr('action') || jqForm.data('endpoint') || jqSubmit.data('endpoint')); jqSubmit.data('method', jqForm.attr('method') || 'GET'); jqSubmit.data('input', '#' + formId); jqSubmit.data('alias', '#' + formId); jqSubmit.domAjax(); }); e.preventDefault(); } }); $('.domajax.ready').domAjax(); return true; });