{"version":3,"sources":["jquery.dirtyforms.min.js"],"names":["$","window","document","undefined","fn","on","events","selector","data","handler","this","delegate","dirtyForms","method","methods","apply","Array","prototype","slice","call","arguments","error","init","options","state","initialized","extend","DirtyForms","trigger","bind","filter","not","each","$form","find","fieldSelector","storeOriginalValue","bindForm","isDirty","excludeHelpers","ignoreSelector","getIgnoreSelector","dirtyClass","index","$node","ignored","isFieldIgnored","hasClass","helpers","i","helper","setClean","excludeIgnored","doSetClean","$field","setDirtyStatus","elementsInRange","parents","fireHelperMethod","rescan","doRescan","hasOriginalValue","isFieldDirty","expr","dirty","element","$element","is","dirtylistening","listeningClass","dirtyignored","message","ignoreClass","dialog","choice","formStash","dialogStash","deciding","decidingEvent","bindKeys","ev","bindEscKey","which","bindEnterKey","doCommit","bindDialog","staySelector","proceedSelector","unbind","click","doProceed","keydown","callDialogClose","proceeding","unstashing","isFunction","close","preventDefault","refireEvent","clearUnload","refire","isUnstashing","unstash","onBeforeUnload","onAnchorClick","onSubmit","isIE8_9","createElement","inputEvents","addClass","onFocus","onFieldChange","onReset","target","type","delay","setFieldStatus","closest","setTimeout","bindFn","result","doubleunloadfix","returnValue","onRefireClick","event","Event","isDefaultPrevented","onRefireAnchorClick","href","attr","location","onbeforeunload","$this","$elements","add","getFieldValue","value","$option","length","val","isEmpty","key","obj","name","$radio","toggleClass","changed","timer","callback","ms","clearTimeout","eventType","stopImmediatePropagation","stash","stashSelector","clone","hide","proceed","commit","open","append","jQuery"],"mappings":"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","file":"jquery.dirtyforms.min.js","sourceRoot":"/","sourcesContent":["/*!\nDirty Forms jQuery Plugin | v2.0.0 | github.com/snikch/jquery.dirtyforms\n(c) 2010-2015 Mal Curtis\nLicense MIT\n*/\n\n(function($, window, document, undefined) {\n // Can't use ECMAScript 5's strict mode because several apps \n // including ASP.NET trace the stack via arguments.caller.callee \n // and Firefox dies if you try to trace through \"use strict\" call chains. \n // See jQuery issue (#13335)\n // Support: Firefox 18+\n //\"use strict\";\n\n if (!$.fn.on) {\n // Patch jQuery 1.4.2 - 1.7 with an on function (that uses delegate).\n $.fn.on = function (events, selector, data, handler) {\n return this.delegate(selector, events, data, handler);\n };\n }\n\n $.fn.dirtyForms = function (method) {\n // Method calling logic\n if (methods[method]) {\n return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));\n } else if (typeof method === 'object' || !method) {\n return methods.init.apply(this, arguments);\n } else {\n $.error('Method ' + method + ' does not exist on jQuery.dirtyForms');\n }\n };\n\n // Public Element methods ( $('form').dirtyForms('methodName', args) )\n var methods = {\n init: function (options) {\n var data = {};\n\n if (!state.initialized) {\n // Override any default options\n $.extend(true, $.DirtyForms, options);\n\n $(document).trigger('bind.dirtyforms', [events]);\n events.bind(window, document, data);\n\n state.initialized = true;\n }\n\n this.filter('form').not(':dirtylistening').each(function () {\n var $form = $(this);\n \n\n // Store original values of the fields\n $form.find($.DirtyForms.fieldSelector).each(function () {\n storeOriginalValue($(this));\n });\n\n $form.trigger('scan.dirtyforms');\n events.bindForm($form, data);\n });\n return this;\n },\n // Returns true if any of the selected elements or their children are dirty\n isDirty: function (excludeHelpers) {\n var ignoreSelector = getIgnoreSelector(),\n dirtyClass = $.DirtyForms.dirtyClass,\n isDirty = false;\n\n this.each(function (index) {\n var $node = $(this),\n ignored = isFieldIgnored($node, ignoreSelector);\n\n if ($node.hasClass(dirtyClass) && !ignored) {\n isDirty = true;\n // Exit out of the .each() function\n return false;\n }\n\n // Check any descendant nodes (if this is a container element)\n $node.find('.' + dirtyClass).each(function () {\n if (!isFieldIgnored($(this), ignoreSelector)) {\n isDirty = true;\n // Exit out of the .each() function\n return false;\n }\n });\n // Exit out of the .each() function\n if (isDirty) return false;\n\n if (!ignored && !excludeHelpers) {\n // Test helpers for this node.\n $.each($.DirtyForms.helpers, function (i, helper) {\n if (helper.isDirty && helper.isDirty($node, index)) {\n isDirty = true;\n // Exit out of the .each() function\n return false;\n }\n });\n\n // Exit out of the .each() function\n if (isDirty) return false;\n }\n });\n\n return isDirty;\n },\n // Marks the element(s) and any helpers within the element not dirty.\n // If all of the fields in a form are marked not dirty, the form itself will be marked not dirty even\n // if it is not included in the selector. Also resets original values to the current state - \n // essentially \"forgetting\" the node or its descendants are dirty.\n setClean: function (excludeIgnored, excludeHelpers) {\n \n\n var doSetClean = function () {\n var $field = $(this);\n\n // Reset by storing the original value again\n storeOriginalValue($field);\n\n // Remove the dirty class\n setDirtyStatus($field, false);\n };\n\n elementsInRange(this, $.DirtyForms.fieldSelector, excludeIgnored)\n .each(doSetClean)\n .parents('form').trigger('setclean.dirtyforms', [excludeIgnored]);\n\n if (excludeHelpers) return this;\n return fireHelperMethod(this, 'setClean', excludeIgnored, getIgnoreSelector());\n },\n // Scans the selected elements and descendants for any new fields and stores their original values.\n // Ignores any original values that had been set previously. Also resets the dirty status of all fields\n // whose ignore status has changed since the last scan.\n rescan: function (excludeIgnored, excludeHelpers) {\n \n\n var doRescan = function () {\n var $field = $(this);\n\n // Skip previously added fields\n if (!hasOriginalValue($field)) {\n // Store the original value\n storeOriginalValue($field);\n }\n\n // Set the dirty status\n setDirtyStatus($field, isFieldDirty($field));\n };\n\n elementsInRange(this, $.DirtyForms.fieldSelector, excludeIgnored)\n .each(doRescan)\n .parents('form').trigger('rescan.dirtyforms', [excludeIgnored]);\n\n if (excludeHelpers) return this;\n return fireHelperMethod(this, 'rescan', excludeIgnored, getIgnoreSelector());\n }\n };\n\n // Custom selectors $('form:dirty')\n $.extend($.expr[\":\"], {\n dirty: function (element) {\n var $element = $(element);\n return $element.hasClass($.DirtyForms.dirtyClass) && !$element.is(':dirtyignored');\n },\n dirtylistening: function (element) {\n return $(element).hasClass($.DirtyForms.listeningClass);\n },\n dirtyignored: function (element) {\n return isFieldIgnored($(element), false);\n }\n });\n\n // Public General Plugin properties and methods $.DirtyForms\n $.DirtyForms = {\n message: \"You've made changes on this page which aren't saved. If you leave you will lose these changes.\",\n dirtyClass: 'dirty',\n listeningClass: 'dirtylisten',\n ignoreClass: 'dirtyignore',\n ignoreSelector: '',\n // exclude all HTML 4 except checkbox, option, text and password, but include HTML 5 except search\n fieldSelector: \"input:not([type='button'],[type='image'],[type='submit'],\" +\n \"[type='reset'],[type='file'],[type='search']),select,textarea\",\n\n helpers: [],\n dialog: false\n };\n\n // Private State Management\n var state = {\n initialized: false,\n formStash: false,\n dialogStash: false,\n deciding: false,\n decidingEvent: false\n };\n\n // Dialog Decision Management\n var choice;\n\n var bindKeys = function (ev) {\n if (ev.data.bindEscKey && ev.which == 27 || ev.data.bindEnterKey && ev.which == 13) {\n return doCommit(ev, false);\n }\n };\n\n var bindDialog = function (choice) {\n var staySelector = choice.staySelector,\n proceedSelector = choice.proceedSelector;\n\n if (staySelector !== '') {\n $(staySelector).unbind('click', doCommit)\n .click(doCommit);\n }\n if (proceedSelector !== '') {\n $(proceedSelector).unbind('click', doProceed)\n .click(doProceed);\n }\n if (choice.bindEscKey || choice.bindEnterKey) {\n $(document).unbind('keydown', bindKeys)\n .keydown(choice, bindKeys);\n }\n };\n\n var callDialogClose = function (proceeding, unstashing) {\n if ($.isFunction($.DirtyForms.dialog.close)) {\n \n $.DirtyForms.dialog.close(proceeding, unstashing);\n }\n };\n\n var doProceed = function (ev) {\n return doCommit(ev, true);\n };\n\n var doCommit = function (ev, proceeding) {\n if (!state.deciding) return;\n ev.preventDefault();\n\n if (proceeding === true) {\n var refireEvent = state.decidingEvent;\n $(document).trigger('proceed.dirtyforms', [refireEvent]);\n events.clearUnload(); // fix for chrome/safari\n callDialogClose(proceeding, false);\n refire(refireEvent);\n } else {\n $(document).trigger('stay.dirtyforms');\n var isUnstashing = $.DirtyForms.dialog !== false && state.dialogStash !== false && $.isFunction($.DirtyForms.dialog.unstash);\n callDialogClose(proceeding, isUnstashing);\n if (isUnstashing) {\n \n $.DirtyForms.dialog.unstash(state.dialogStash, ev);\n }\n $(document).trigger('afterstay.dirtyforms');\n }\n\n state.deciding = state.decidingEvent = state.dialogStash = state.formStash = false;\n return false;\n };\n\n // Event management\n var events = {\n bind: function (window, document, data) {\n $(window).bind('beforeunload', data, events.onBeforeUnload);\n $(document).on('click', 'a:not([target=\"_blank\"])', data, events.onAnchorClick)\n .on('submit', 'form', data, events.onSubmit);\n },\n bindForm: function ($form, data) {\n var dirtyForms = $.DirtyForms;\n\n // Test whether we are dealing with IE < 10\n var isIE8_9 = ('onpropertychange' in document.createElement('input'));\n var inputEvents = 'change input' + (isIE8_9 ? ' keyup selectionchange cut paste' : '');\n $form.addClass(dirtyForms.listeningClass)\n .on('focus keydown', dirtyForms.fieldSelector, data, events.onFocus)\n .on(inputEvents, dirtyForms.fieldSelector, data, events.onFieldChange)\n .bind('reset', data, events.onReset);\n },\n // For any fields added after the form was initialized, store the value when focused.\n onFocus: function (ev) {\n var $field = $(ev.target);\n if (!hasOriginalValue($field)) {\n storeOriginalValue($field);\n }\n },\n onFieldChange: function (ev) {\n var $field = $(ev.target);\n if (ev.type !== 'change') {\n delay(function () { setFieldStatus($field); }, 100);\n } else {\n setFieldStatus($field);\n }\n },\n onReset: function (ev) {\n var $form = $(ev.target).closest('form');\n // Need a delay here because reset is called before the state of the form is reset.\n setTimeout(function () { $form.dirtyForms('setClean'); }, 100);\n },\n onAnchorClick: function (ev) {\n bindFn(ev);\n },\n onSubmit: function (ev) {\n bindFn(ev);\n },\n onBeforeUnload: function (ev) {\n var result = bindFn(ev);\n\n if (result && state.doubleunloadfix !== true) {\n \n state.deciding = false;\n }\n\n state.doubleunloadfix = true;\n setTimeout(function () { state.doubleunloadfix = false; }, 200);\n\n // Only return the result if it is a string, otherwise don't return anything.\n if (typeof result === 'string') {\n // For IE and Firefox prior to version 4, set the returnValue.\n ev.returnValue = result;\n return result;\n }\n },\n onRefireClick: function (ev) {\n var event = new $.Event('click');\n $(ev.target).trigger(event);\n if (!event.isDefaultPrevented()) {\n events.onRefireAnchorClick(ev);\n }\n },\n onRefireAnchorClick: function (ev) {\n var href = $(ev.target).closest('a[href]').attr('href');\n if (href !== undefined) {\n \n window.location.href = href;\n }\n },\n clearUnload: function () {\n // I'd like to just be able to unbind this but there seems\n // to be a bug in jQuery which doesn't unbind onbeforeunload\n \n $(window).unbind('beforeunload', events.onBeforeUnload);\n window.onbeforeunload = null;\n $(document).trigger('beforeunload.dirtyforms');\n }\n };\n\n var elementsInRange = function ($this, selector, excludeIgnored) {\n var $elements = $this.filter(selector).add($this.find(selector));\n if (excludeIgnored) {\n $elements = $elements.not(':dirtyignored');\n }\n return $elements;\n };\n\n var fireHelperMethod = function ($this, method, excludeIgnored, ignoreSelector) {\n return $this.each(function (index) {\n var $node = $(this);\n\n if (!excludeIgnored || !isFieldIgnored($node, ignoreSelector)) {\n $.each($.DirtyForms.helpers, function (i, helper) {\n if (helper[method]) { helper[method]($node, index, excludeIgnored); }\n });\n }\n });\n };\n\n var getFieldValue = function ($field) {\n var value;\n if ($field.is('select')) {\n value = '';\n $field.find('option').each(function () {\n var $option = $(this);\n if ($option.is(':selected')) {\n if (value.length > 0) { value += ','; }\n value += $option.val();\n }\n });\n } else if ($field.is(\":checkbox,:radio\")) {\n value = $field.is(':checked');\n } else {\n value = $field.val();\n }\n\n return value;\n };\n\n var storeOriginalValue = function ($field) {\n \n $field.data('df-orig', getFieldValue($field));\n var isEmpty = ($field.data('df-orig') === undefined);\n $field.data('df-empty', isEmpty);\n };\n\n var hasOriginalValue = function ($field) {\n return ($field.data('df-orig') !== undefined || $field.data('df-empty') === true);\n };\n\n var getIgnoreSelector = function () {\n var dirtyForms = $.DirtyForms,\n result = dirtyForms.ignoreSelector;\n $.each(dirtyForms.helpers, function (key, obj) {\n if ('ignoreSelector' in obj) {\n if (result.length > 0) { result += ','; }\n result += obj.ignoreSelector;\n }\n });\n return result;\n };\n\n var isFieldIgnored = function ($field, ignoreSelector) {\n if (!ignoreSelector) {\n ignoreSelector = getIgnoreSelector();\n }\n return $field.is(ignoreSelector) || $field.closest('.' + $.DirtyForms.ignoreClass).length > 0;\n };\n\n var isFieldDirty = function ($field, ignoreSelector) {\n if (!hasOriginalValue($field) || isFieldIgnored($field, ignoreSelector)) return false;\n return (getFieldValue($field) != $field.data('df-orig'));\n };\n\n var setFieldStatus = function ($field, ignoreSelector) {\n if (isFieldIgnored($field, ignoreSelector)) return;\n\n // Option groups are a special case because they change more than the current element.\n if ($field.is(':radio[name]')) {\n var name = $field.attr('name'),\n $form = $field.parents('form');\n\n $form.find(\":radio[name='\" + name + \"']\").each(function () {\n var $radio = $(this);\n setDirtyStatus($radio, isFieldDirty($radio, ignoreSelector));\n });\n } else {\n setDirtyStatus($field, isFieldDirty($field, ignoreSelector));\n }\n };\n\n var setDirtyStatus = function ($field, isDirty) {\n \n var dirtyClass = $.DirtyForms.dirtyClass,\n $form = $field.parents('form');\n\n // Mark the field dirty/clean\n $field.toggleClass(dirtyClass, isDirty);\n var changed = (isDirty !== ($form.hasClass(dirtyClass) && $form.find(':dirty').length === 0));\n\n if (changed) {\n \n $form.toggleClass(dirtyClass, isDirty);\n\n if (isDirty) $form.trigger('dirty.dirtyforms');\n if (!isDirty) $form.trigger('clean.dirtyforms');\n }\n };\n\n // A delay to keep the key events from slowing down when changing the dirty status on the fly.\n var delay = (function () {\n var timer = 0;\n return function (callback, ms) {\n clearTimeout(timer);\n timer = setTimeout(callback, ms);\n };\n })();\n\n var bindFn = function (ev) {\n var $element = $(ev.target),\n eventType = ev.type,\n dirtyForms = $.DirtyForms;\n \n\n // Important: Do this check before calling events.clearUnload()\n if (ev.isDefaultPrevented()) {\n \n return false;\n }\n\n if (eventType == 'beforeunload' && state.doubleunloadfix) {\n \n state.doubleunloadfix = false;\n return false;\n }\n\n if ($element.is(':dirtyignored')) {\n \n events.clearUnload();\n return false;\n }\n\n if (state.deciding) {\n \n return false;\n }\n\n if (!$('form:dirtylistening').dirtyForms('isDirty')) {\n \n events.clearUnload();\n return false;\n }\n\n if (eventType == 'submit' && $element.dirtyForms('isDirty')) {\n \n events.clearUnload();\n return true;\n }\n\n // Callback for page access in current state\n $(document).trigger('defer.dirtyforms');\n\n if (eventType == 'beforeunload') {\n \n return dirtyForms.message;\n }\n if (!dirtyForms.dialog) return;\n\n // Using the GUI dialog...\n ev.preventDefault();\n ev.stopImmediatePropagation();\n\n \n state.deciding = true;\n state.decidingEvent = ev;\n\n // Stash the dialog (with a form). This is done so it can be shown again via unstash().\n if ($.isFunction(dirtyForms.dialog.stash)) {\n \n state.dialogStash = dirtyForms.dialog.stash();\n \n }\n\n // Stash the form from the dialog. This is done so we can fire events on it if the user makes a proceed choice.\n var stashSelector = dirtyForms.dialog.stashSelector;\n if (typeof stashSelector === 'string' && $element.is('form') && $element.parents(stashSelector).length > 0) {\n \n state.formStash = $element.clone(true).hide();\n } else {\n state.formStash = false;\n }\n\n \n\n // Create a new choice object\n choice = {\n proceed: false,\n commit: function (ev) {\n return doCommit(ev, choice.proceed);\n },\n bindEscKey: true,\n bindEnterKey: false,\n proceedSelector: '',\n staySelector: ''\n };\n\n dirtyForms.dialog.open(choice, dirtyForms.message, dirtyForms.ignoreClass);\n bindDialog(choice);\n };\n\n var refire = function (ev) {\n if (ev.type === 'click') {\n \n events.onRefireClick(ev);\n } else {\n \n var target;\n if (state.formStash) {\n \n target = state.formStash;\n $('body').append(target);\n }\n else {\n target = $(ev.target).closest('form');\n }\n target.trigger(ev.type);\n }\n };\n\n\n\n})(jQuery, window, document);\n"]}