<commit_before>/*!
	Copyright 2010 Mal Curtis
*/

// Support for UMD: https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
// This allows for tools such as Browserify to compose the components together into a single HTTP request.
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    if (typeof $(document).on !== 'function') {
        if (typeof $(document).delegate === 'function') {
            // Patch jQuery 1.4.2 - 1.7 with an on function (that uses delegate).
            $.fn.on = function (events, selector, data, handler) {
                return $(this).delegate(selector, events, data, handler);
            };
        } else {
            throw ('jQuery 1.4.2 or higher is required by jquery.dirtyforms');
        }
    }

    // Public General Plugin methods $.DirtyForms
    $.extend({
        DirtyForms: {
            debug: false,
            message: 'You\'ve made changes on this page which aren\'t saved. If you leave you will lose these changes.',
            title: 'Are you sure you want to do that?',
            dirtyClass: 'dirty',
            listeningClass: 'dirtylisten',
            ignoreClass: 'ignoredirty',
            choiceContinue: false,
            helpers: [],
            dialog: {
                refire: function (content, ev) {
                    $.facebox(content);
                },
                fire: function (message, title) {
                    var content = '
' + title + '

' + message + '

ContinueStop';
                    $.facebox(content);
                },
                bind: function () {
                    var close = function (decision) {
                        return function (e) {
                            e.preventDefault();
                            $(document).trigger('close.facebox');
                            decision(e);
                        };
                    };
                    $('#facebox .cancel, #facebox .close, #facebox_overlay').click(close(decidingCancel));
                    $('#facebox .continue').click(close(decidingContinue));
                },
                stash: function () {
                    var fb = $('#facebox');
                    return ($.trim(fb.html()) === '' || fb.css('display') != 'block') ?
					   false :
					   $('#facebox .content').clone(true);
                },
                selector: '#facebox .content'
            },

            isDirty: function () {
                return $(':dirtylistening').dirtyForms('isDirty');
            },

            disable: function () {
                settings.disabled = true;
            },

            ignoreParentDocs: function () {
                settings.watchParentDocs = false;
            },

            choiceCommit: function (e) {
                choiceCommit(e);
            },

            isDeciding: function () {
                return settings.deciding;
            },

            decidingContinue: function (e) {
                decidingContinue(e);
            },

            decidingCancel: function (e) {
                decidingCancel(e);
            },

            dirtylog: function (msg) {
                dirtylog(msg);
            }
        }
    });

    // Create a custom selector $('form:dirty')
    $.extend($.expr[":"], {
        dirtylistening: function (a) {
            return $(a).hasClass(settings.listeningClass);
        },
        dirty: function (a) {
            return $(a).hasClass(settings.dirtyClass);
        }
    });

    // Public Element methods ( $('form').dirtyForms('methodName', args) )
    var methods = {
        init: function () {
            dirtylog('Adding forms to watch');
            bindExit();

            // Initialize settings with the currently focused element (autofocus)
            var focused = $(document.activeElement);
            if (focused) {
                settings.focused.element = focused;
                settings.focused.value = focused.val();
            }

            return this.each(function (e) {
                var $form = $(this);
                if (!$form.is('form')) return;
                dirtylog('Adding form ' + $form.attr('id') + ' to forms to watch');

                $form.addClass(settings.listeningClass)
                    // exclude all HTML 4 except text and password, but include HTML 5 except search
                    .on('focus change', "textarea,input:not([type='checkbox'],[type='radio'],[type='button']," +
					    "[type='image'],[type='submit'],[type='reset'],[type='file'],[type='search'])", onFocus)
                    .on('change', "input[type='checkbox'],input[type='radio'],select", onSelectionChange)
                    .on('click', "input[type='reset']", onReset);
            });
        },
        // Returns true if any of the supplied elements are dirty
        isDirty: function () {
            var isDirty = false,
                node = this;
            if (settings.disabled) return false;
            if (focusedIsDirty()) {
                isDirty = true;
                return true;
            }
            this.each(function (e) {
                if ($(this).hasClass(settings.dirtyClass)) {
                    isDirty = true;
                    return true;
                }
            });
            $.each(settings.helpers, function (key, obj) {
                if ("isDirty" in obj) {
                    if (obj.isDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
                // For backward compatibility, we call isNodeDirty (deprecated)
                if ("isNodeDirty" in obj) {
                    if (obj.isNodeDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
            });

            dirtylog('isDirty returned ' + isDirty);
            return isDirty;
        },
        // Marks the element(s) that match the selector dirty
        setDirty: function () {
            dirtylog('setDirty called');
            return this.each(function (e) {
                $(this).addClass(settings.dirtyClass).parents('form').addClass(settings.dirtyClass);
            });
        },
        // "Cleans" this dirty form by essentially forgetting that it is dirty
        setClean: function () {
            dirtylog('setClean called');
            settings.focused = { element: false, value: false };

            return this.each(function (e) {
                var node = this, $node = $(this);

                // remove the current dirty class
                $node.removeClass(settings.dirtyClass);

                if ($node.is('form')) {
                    // remove all dirty classes from children
                    $node.find(':dirty').removeClass(settings.dirtyClass);
                } else {
                    // if this is last dirty child, set form clean
                    var $form = $node.parents('form');
                    if ($form.find(':dirty').length === 0) {
                        $form.removeClass(settings.dirtyClass);
                    }
                }

                // Clean helpers
                $.each(settings.helpers, function (key, obj) {
                    if ("setClean" in obj) {
                        obj.setClean(node);
                    }
                });
            });
        }

        // ADD NEW METHODS HERE
    };

    $.fn.dirtyForms = function (method) {
        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.dirtyForms');
        }
    };

    // Deprecated Methods for Backward Compatibility
    // DO NOT ADD MORE METHODS LIKE THESE, ADD METHODS WHERE INDICATED ABOVE
    $.fn.setDirty = function () {
        return this.dirtyForms('setDirty');
    };
    $.fn.isDirty = function () {
        return this.dirtyForms('isDirty');
    };
    $.fn.cleanDirty = function () {
        return this.dirtyForms('setClean');
    };

    // Private Properties and Methods
    var settings = $.DirtyForms = $.extend({
        watchParentDocs: true,
        disabled: false,
        exitBound: false,
        formStash: false,
        dialogStash: false,
        deciding: false,
        decidingEvent: false,
        currentForm: false,
        hasFirebug: "console" in window && "firebug" in window.console,
        hasConsoleLog: "console" in window && "log" in window.console,
        focused: { "element": false, "value": false }
    }, $.DirtyForms);

    var onReset = function () {
        $(this).parents('form').dirtyForms('setClean');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onSelectionChange = function () {
        if ($(this).hasClass(settings.ignoreClass)) return;
        $(this).dirtyForms('setDirty');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onFocus = function () {
        var $this = $(this);
        if (focusedIsDirty() && !$this.hasClass(settings.ignoreClass)) {
            settings.focused.element.dirtyForms('setDirty');
            if (settings.onFormCheck) {
                settings.onFormCheck();
            }
        }
        settings.focused.element = $this;
        settings.focused.value = $this.val();
    };

    var focusedIsDirty = function () {
        // Check, whether the value of focused element has changed
        return settings.focused.element &&
			(settings.focused.element.val() !== settings.focused.value);
    };

    var dirtylog = function (msg) {
        if (!settings.debug) return;
        msg = "[DirtyForms] " + msg;
        if (settings.hasFirebug) {
            console.log(msg);
        } else if (settings.hasConsoleLog) {
            window.console.log(msg);
        } else {
            alert(msg);
        }
    };

    var bindExit = function () {
        if (settings.exitBound) return;

        var inIframe = (top !== self);

        $(document).on('click', 'a[href]', aBindFn)
                   .on('submit', 'form', formBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.document).on('click', 'a[href]', aBindFn)
                           .on('submit', 'form', formBindFn);
        }

        $(window).bind('beforeunload', beforeunloadBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.window).bind('beforeunload', beforeunloadBindFn);
        }

        settings.exitBound = true;
    };

    var getIgnoreAnchorSelector = function () {
        var result = '';
        $.each(settings.helpers, function (key, obj) {
            if ("ignoreAnchorSelector" in obj) {
                if (result.length > 0) { result += ','; }
                result += obj.ignoreAnchorSelector;
            }
        });
        return result;
    };

    var aBindFn = function (ev) {
        // Filter out any anchors the helpers wish to exclude
        if (!$(this).is(getIgnoreAnchorSelector())) {
            bindFn(ev);
        }
    };

    var formBindFn = function (ev) {
        settings.currentForm = this;
        bindFn(ev);
    };

    var beforeunloadBindFn = function (ev) {
        var result = bindFn(ev);

        if (result && settings.doubleunloadfix !== true) {
            dirtylog('Before unload will be called, resetting');
            settings.deciding = false;
        }

        settings.doubleunloadfix = true;
        setTimeout(function () { settings.doubleunloadfix = false; }, 200);

        // Bug Fix: Only return the result if it is a string,
        // otherwise don't return anything.
        if (typeof (result) == 'string') {
            ev = ev || window.event;

            // For IE and Firefox prior to version 4
            if (ev) {
                ev.returnValue = result;
            }

            // For Safari
            return result;
        }
    };

    var bindFn = function (ev) {
        var $element = $(ev.target), eventType = ev.type;
        dirtylog('Entering: Leaving Event fired, type: ' + eventType + ', element: ' + ev.target + ', class: ' + $element.attr('class') + ' and id: ' + ev.target.id);

        if (eventType == 'beforeunload' && settings.doubleunloadfix) {
            dirtylog('Skip this unload, Firefox bug triggers the unload event multiple times');
            settings.doubleunloadfix = false;
            return false;
        }

        if ($element.hasClass(settings.ignoreClass) || isDifferentTarget($element)) {
            dirtylog('Leaving: Element has ignore class or has target=\'_blank\'');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (settings.deciding) {
            dirtylog('Leaving: Already in the deciding process');
            return false;
        }

        if (ev.isDefaultPrevented()) {
            dirtylog('Leaving: Event has been stopped elsewhere');
            return false;
        }

        if (!settings.isDirty()) {
            dirtylog('Leaving: Not dirty');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (eventType == 'submit' && $element.dirtyForms('isDirty')) {
            dirtylog('Leaving: Form submitted is a dirty form');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return true;
        }

        if (settings.dialog) {
            settings.deciding = true;
            settings.decidingEvent = ev;
            dirtylog('Setting deciding active');

            if (typeof settings.dialog.stash === 'function') {
                dirtylog('Saving dialog content');
                settings.dialogStash = settings.dialog.stash();
                dirtylog(settings.dialogStash);
            }
        }

        // Callback for page access in current state
        $(document).trigger('defer.dirtyforms');

        if (eventType == 'beforeunload') {
            dirtylog('Returning to beforeunload browser handler with: ' + settings.message);
            return settings.message;
        }
        if (!settings.dialog) return;

        ev.preventDefault();
        ev.stopImmediatePropagation();

        if (typeof settings.dialog.selector === 'string' && $element.is('form') && $element.parents(settings.dialog.selector).length > 0) {
            dirtylog('Stashing form');
            settings.formStash = $element.clone(true).hide();
        } else {
            settings.formStash = false;
        }

        dirtylog('Deferring to the dialog');
        settings.dialog.fire(settings.message, settings.title);
        if (typeof settings.dialog.bind === 'function')
            settings.dialog.bind();
    };

    var isDifferentTarget = function ($element) {
        var aTarget = $element.attr('target');
        return typeof aTarget === 'string' ? aTarget.toLowerCase() === '_blank' : false;
    };

    var choiceCommit = function (ev) {
        if (settings.deciding) {
            $(document).trigger('choicecommit.dirtyforms');
            if (settings.choiceContinue) {
                decidingContinue(ev);
            } else {
                decidingCancel(ev);
            }
            $(document).trigger('choicecommitAfter.dirtyforms');
        }
    };

    var decidingCancel = function (ev) {
        ev.preventDefault();
        $(document).trigger('decidingcancelled.dirtyforms');
        if (settings.dialog !== false && settings.dialogStash !== false && typeof settings.dialog.refire === 'function') {
            dirtylog('Refiring the dialog with stashed content');
            settings.dialog.refire(settings.dialogStash.html(), ev);
        }
        $(document).trigger('decidingcancelledAfter.dirtyforms');
        settings.deciding = settings.currentForm = settings.decidingEvent = settings.dialogStash = false;
    };

    var decidingContinue = function (ev) {
        clearUnload(); // fix for chrome/safari
        ev.preventDefault();
        settings.dialogStash = false;
        $(document).trigger('decidingcontinued.dirtyforms');
        refire(settings.decidingEvent);
        settings.deciding = settings.currentForm = settings.decidingEvent = false;
    };

    var clearUnload = function () {
        // I'd like to just be able to unbind this but there seems
        // to be a bug in jQuery which doesn't unbind onbeforeunload
        dirtylog('Clearing the beforeunload event');
        $(window).unbind('beforeunload', beforeunloadBindFn);
        window.onbeforeunload = null;
        $(document).trigger('beforeunload.dirtyforms');
    };

    var refire = function (e) {
        $(document).trigger('beforeRefire.dirtyforms')
                   .trigger('beforeunload.dirtyforms');
        if (e.type === 'click') {
            dirtylog("Refiring click event");
            var event = new $.Event('click');
            $(e.target).trigger(event);
            if (!event.isDefaultPrevented()) {
                var href = $(e.target).attr('href');
                dirtylog('Sending location to ' + href);
                location.href = href;
                return;
            }
        } else {
            dirtylog("Refiring " + e.type + " event on " + e.target);
            var target;
            if (settings.formStash) {
                dirtylog('Appending stashed form to body');
                target = settings.formStash;
                $('body').append(target);
            }
            else {
                target = $(e.target);
                if (!target.is('form'))
                    target = target.closest('form');
            }
            target.trigger(e.type);
        }
    };

}));
<commit_msg>Fixed HTML 5 autofocus to check whether the focused element belongs to same selector as the ones the event is watching.<commit_after>/*!
	Copyright 2010 Mal Curtis
*/

// Support for UMD: https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
// This allows for tools such as Browserify to compose the components together into a single HTTP request.
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS
        module.exports = factory(require('jquery'));
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    if (typeof $(document).on !== 'function') {
        if (typeof $(document).delegate === 'function') {
            // Patch jQuery 1.4.2 - 1.7 with an on function (that uses delegate).
            $.fn.on = function (events, selector, data, handler) {
                return $(this).delegate(selector, events, data, handler);
            };
        } else {
            throw ('jQuery 1.4.2 or higher is required by jquery.dirtyforms');
        }
    }

    // Public General Plugin methods $.DirtyForms
    $.extend({
        DirtyForms: {
            debug: false,
            message: 'You\'ve made changes on this page which aren\'t saved. If you leave you will lose these changes.',
            title: 'Are you sure you want to do that?',
            dirtyClass: 'dirty',
            listeningClass: 'dirtylisten',
            ignoreClass: 'ignoredirty',
            choiceContinue: false,
            helpers: [],
            dialog: {
                refire: function (content, ev) {
                    $.facebox(content);
                },
                fire: function (message, title) {
                    var content = '
' + title + '

' + message + '

ContinueStop';
                    $.facebox(content);
                },
                bind: function () {
                    var close = function (decision) {
                        return function (e) {
                            e.preventDefault();
                            $(document).trigger('close.facebox');
                            decision(e);
                        };
                    };
                    $('#facebox .cancel, #facebox .close, #facebox_overlay').click(close(decidingCancel));
                    $('#facebox .continue').click(close(decidingContinue));
                },
                stash: function () {
                    var fb = $('#facebox');
                    return ($.trim(fb.html()) === '' || fb.css('display') != 'block') ?
					   false :
					   $('#facebox .content').clone(true);
                },
                selector: '#facebox .content'
            },

            isDirty: function () {
                return $(':dirtylistening').dirtyForms('isDirty');
            },

            disable: function () {
                settings.disabled = true;
            },

            ignoreParentDocs: function () {
                settings.watchParentDocs = false;
            },

            choiceCommit: function (e) {
                choiceCommit(e);
            },

            isDeciding: function () {
                return settings.deciding;
            },

            decidingContinue: function (e) {
                decidingContinue(e);
            },

            decidingCancel: function (e) {
                decidingCancel(e);
            },

            dirtylog: function (msg) {
                dirtylog(msg);
            }
        }
    });

    // Create a custom selector $('form:dirty')
    $.extend($.expr[":"], {
        dirtylistening: function (a) {
            return $(a).hasClass(settings.listeningClass);
        },
        dirty: function (a) {
            return $(a).hasClass(settings.dirtyClass);
        }
    });

    // Public Element methods ( $('form').dirtyForms('methodName', args) )
    var methods = {
        init: function () {
            dirtylog('Adding forms to watch');
            bindExit();

            // exclude all HTML 4 except text and password, but include HTML 5 except search
            var inputSelector = "textarea,input:not([type='checkbox'],[type='radio'],[type='button']," +
        		"[type='image'],[type='submit'],[type='reset'],[type='file'],[type='search'])";

            // Initialize settings with the currently focused element (HTML 5 autofocus)
            var $focused = $(document.activeElement);
            if ($focused.is(inputSelector)) {
                settings.focused.element = $focused;
                settings.focused.value = $focused.val();
            }

            return this.each(function (e) {
                var $form = $(this);
                if (!$form.is('form')) return;

                dirtylog('Adding form ' + $form.attr('id') + ' to forms to watch');
                $form.addClass(settings.listeningClass)
                    .on('focus change', inputSelector, onFocus)
                    .on('change', "input[type='checkbox'],input[type='radio'],select", onSelectionChange)
                    .on('click', "input[type='reset']", onReset);
            });
        },
        // Returns true if any of the supplied elements are dirty
        isDirty: function () {
            var isDirty = false,
                node = this;
            if (settings.disabled) return false;
            if (focusedIsDirty()) {
                isDirty = true;
                return true;
            }
            this.each(function (e) {
                if ($(this).hasClass(settings.dirtyClass)) {
                    isDirty = true;
                    return true;
                }
            });
            $.each(settings.helpers, function (key, obj) {
                if ("isDirty" in obj) {
                    if (obj.isDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
                // For backward compatibility, we call isNodeDirty (deprecated)
                if ("isNodeDirty" in obj) {
                    if (obj.isNodeDirty(node)) {
                        isDirty = true;
                        return true;
                    }
                }
            });

            dirtylog('isDirty returned ' + isDirty);
            return isDirty;
        },
        // Marks the element(s) that match the selector dirty
        setDirty: function () {
            dirtylog('setDirty called');
            return this.each(function (e) {
                $(this).addClass(settings.dirtyClass).parents('form').addClass(settings.dirtyClass);
            });
        },
        // "Cleans" this dirty form by essentially forgetting that it is dirty
        setClean: function () {
            dirtylog('setClean called');
            settings.focused = { element: false, value: false };

            return this.each(function (e) {
                var node = this, $node = $(this);

                // remove the current dirty class
                $node.removeClass(settings.dirtyClass);

                if ($node.is('form')) {
                    // remove all dirty classes from children
                    $node.find(':dirty').removeClass(settings.dirtyClass);
                } else {
                    // if this is last dirty child, set form clean
                    var $form = $node.parents('form');
                    if ($form.find(':dirty').length === 0) {
                        $form.removeClass(settings.dirtyClass);
                    }
                }

                // Clean helpers
                $.each(settings.helpers, function (key, obj) {
                    if ("setClean" in obj) {
                        obj.setClean(node);
                    }
                });
            });
        }

        // ADD NEW METHODS HERE
    };

    $.fn.dirtyForms = function (method) {
        // Method calling logic
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist on jQuery.dirtyForms');
        }
    };

    // Deprecated Methods for Backward Compatibility
    // DO NOT ADD MORE METHODS LIKE THESE, ADD METHODS WHERE INDICATED ABOVE
    $.fn.setDirty = function () {
        return this.dirtyForms('setDirty');
    };
    $.fn.isDirty = function () {
        return this.dirtyForms('isDirty');
    };
    $.fn.cleanDirty = function () {
        return this.dirtyForms('setClean');
    };

    // Private Properties and Methods
    var settings = $.DirtyForms = $.extend({
        watchParentDocs: true,
        disabled: false,
        exitBound: false,
        formStash: false,
        dialogStash: false,
        deciding: false,
        decidingEvent: false,
        currentForm: false,
        hasFirebug: "console" in window && "firebug" in window.console,
        hasConsoleLog: "console" in window && "log" in window.console,
        focused: { "element": false, "value": false }
    }, $.DirtyForms);

    var onReset = function () {
        $(this).parents('form').dirtyForms('setClean');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onSelectionChange = function () {
        if ($(this).hasClass(settings.ignoreClass)) return;
        $(this).dirtyForms('setDirty');
        if (settings.onFormCheck) {
            settings.onFormCheck();
        }
    };

    var onFocus = function () {
        var $this = $(this);
        if (focusedIsDirty() && !$this.hasClass(settings.ignoreClass)) {
            settings.focused.element.dirtyForms('setDirty');
            if (settings.onFormCheck) {
                settings.onFormCheck();
            }
        }
        settings.focused.element = $this;
        settings.focused.value = $this.val();
    };

    var focusedIsDirty = function () {
        // Check, whether the value of focused element has changed
        return settings.focused.element &&
			(settings.focused.element.val() !== settings.focused.value);
    };

    var dirtylog = function (msg) {
        if (!settings.debug) return;
        msg = "[DirtyForms] " + msg;
        if (settings.hasFirebug) {
            console.log(msg);
        } else if (settings.hasConsoleLog) {
            window.console.log(msg);
        } else {
            alert(msg);
        }
    };

    var bindExit = function () {
        if (settings.exitBound) return;

        var inIframe = (top !== self);

        $(document).on('click', 'a[href]', aBindFn)
                   .on('submit', 'form', formBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.document).on('click', 'a[href]', aBindFn)
                           .on('submit', 'form', formBindFn);
        }

        $(window).bind('beforeunload', beforeunloadBindFn);
        if (settings.watchParentDocs && inIframe) {
            $(top.window).bind('beforeunload', beforeunloadBindFn);
        }

        settings.exitBound = true;
    };

    var getIgnoreAnchorSelector = function () {
        var result = '';
        $.each(settings.helpers, function (key, obj) {
            if ("ignoreAnchorSelector" in obj) {
                if (result.length > 0) { result += ','; }
                result += obj.ignoreAnchorSelector;
            }
        });
        return result;
    };

    var aBindFn = function (ev) {
        // Filter out any anchors the helpers wish to exclude
        if (!$(this).is(getIgnoreAnchorSelector())) {
            bindFn(ev);
        }
    };

    var formBindFn = function (ev) {
        settings.currentForm = this;
        bindFn(ev);
    };

    var beforeunloadBindFn = function (ev) {
        var result = bindFn(ev);

        if (result && settings.doubleunloadfix !== true) {
            dirtylog('Before unload will be called, resetting');
            settings.deciding = false;
        }

        settings.doubleunloadfix = true;
        setTimeout(function () { settings.doubleunloadfix = false; }, 200);

        // Bug Fix: Only return the result if it is a string,
        // otherwise don't return anything.
        if (typeof (result) == 'string') {
            ev = ev || window.event;

            // For IE and Firefox prior to version 4
            if (ev) {
                ev.returnValue = result;
            }

            // For Safari
            return result;
        }
    };

    var bindFn = function (ev) {
        var $element = $(ev.target), eventType = ev.type;
        dirtylog('Entering: Leaving Event fired, type: ' + eventType + ', element: ' + ev.target + ', class: ' + $element.attr('class') + ' and id: ' + ev.target.id);

        if (eventType == 'beforeunload' && settings.doubleunloadfix) {
            dirtylog('Skip this unload, Firefox bug triggers the unload event multiple times');
            settings.doubleunloadfix = false;
            return false;
        }

        if ($element.hasClass(settings.ignoreClass) || isDifferentTarget($element)) {
            dirtylog('Leaving: Element has ignore class or has target=\'_blank\'');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (settings.deciding) {
            dirtylog('Leaving: Already in the deciding process');
            return false;
        }

        if (ev.isDefaultPrevented()) {
            dirtylog('Leaving: Event has been stopped elsewhere');
            return false;
        }

        if (!settings.isDirty()) {
            dirtylog('Leaving: Not dirty');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return false;
        }

        if (eventType == 'submit' && $element.dirtyForms('isDirty')) {
            dirtylog('Leaving: Form submitted is a dirty form');
            if (!ev.isDefaultPrevented()) {
                clearUnload();
            }
            return true;
        }

        if (settings.dialog) {
            settings.deciding = true;
            settings.decidingEvent = ev;
            dirtylog('Setting deciding active');

            if (typeof settings.dialog.stash === 'function') {
                dirtylog('Saving dialog content');
                settings.dialogStash = settings.dialog.stash();
                dirtylog(settings.dialogStash);
            }
        }

        // Callback for page access in current state
        $(document).trigger('defer.dirtyforms');

        if (eventType == 'beforeunload') {
            dirtylog('Returning to beforeunload browser handler with: ' + settings.message);
            return settings.message;
        }
        if (!settings.dialog) return;

        ev.preventDefault();
        ev.stopImmediatePropagation();

        if (typeof settings.dialog.selector === 'string' && $element.is('form') && $element.parents(settings.dialog.selector).length > 0) {
            dirtylog('Stashing form');
            settings.formStash = $element.clone(true).hide();
        } else {
            settings.formStash = false;
        }

        dirtylog('Deferring to the dialog');
        settings.dialog.fire(settings.message, settings.title);
        if (typeof settings.dialog.bind === 'function')
            settings.dialog.bind();
    };

    var isDifferentTarget = function ($element) {
        var aTarget = $element.attr('target');
        return typeof aTarget === 'string' ? aTarget.toLowerCase() === '_blank' : false;
    };

    var choiceCommit = function (ev) {
        if (settings.deciding) {
            $(document).trigger('choicecommit.dirtyforms');
            if (settings.choiceContinue) {
                decidingContinue(ev);
            } else {
                decidingCancel(ev);
            }
            $(document).trigger('choicecommitAfter.dirtyforms');
        }
    };

    var decidingCancel = function (ev) {
        ev.preventDefault();
        $(document).trigger('decidingcancelled.dirtyforms');
        if (settings.dialog !== false && settings.dialogStash !== false && typeof settings.dialog.refire === 'function') {
            dirtylog('Refiring the dialog with stashed content');
            settings.dialog.refire(settings.dialogStash.html(), ev);
        }
        $(document).trigger('decidingcancelledAfter.dirtyforms');
        settings.deciding = settings.currentForm = settings.decidingEvent = settings.dialogStash = false;
    };

    var decidingContinue = function (ev) {
        clearUnload(); // fix for chrome/safari
        ev.preventDefault();
        settings.dialogStash = false;
        $(document).trigger('decidingcontinued.dirtyforms');
        refire(settings.decidingEvent);
        settings.deciding = settings.currentForm = settings.decidingEvent = false;
    };

    var clearUnload = function () {
        // I'd like to just be able to unbind this but there seems
        // to be a bug in jQuery which doesn't unbind onbeforeunload
        dirtylog('Clearing the beforeunload event');
        $(window).unbind('beforeunload', beforeunloadBindFn);
        window.onbeforeunload = null;
        $(document).trigger('beforeunload.dirtyforms');
    };

    var refire = function (e) {
        $(document).trigger('beforeRefire.dirtyforms')
                   .trigger('beforeunload.dirtyforms');
        if (e.type === 'click') {
            dirtylog("Refiring click event");
            var event = new $.Event('click');
            $(e.target).trigger(event);
            if (!event.isDefaultPrevented()) {
                var href = $(e.target).attr('href');
                dirtylog('Sending location to ' + href);
                location.href = href;
                return;
            }
        } else {
            dirtylog("Refiring " + e.type + " event on " + e.target);
            var target;
            if (settings.formStash) {
                dirtylog('Appending stashed form to body');
                target = settings.formStash;
                $('body').append(target);
            }
            else {
                target = $(e.target);
                if (!target.is('form'))
                    target = target.closest('form');
            }
            target.trigger(e.type);
        }
    };

}));
<|endoftext|>


<commit_before>/**
 * flexselect: a jQuery plugin, version: %RELEASE_VERSION% (%RELEASE_DATE%)
 * @requires jQuery v1.3 or later
 *
 * FlexSelect is a jQuery plugin that makes it easy to convert a select box into
 * a Quicksilver-style, autocompleting, flex matching selection tool.
 *
 * For usage and examples, visit:
 * http://rmm5t.github.io/jquery-flexselect/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2009-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.flexselect = function(select, options) { this.init(select, options); };

  $.extend($.flexselect.prototype, {
    settings: {
      allowMismatch: false,
      allowMismatchBlank: true, // If "true" a user can backspace such that the value is nothing (even if no blank value was provided in the original criteria)
      sortBy: 'score', // 'score' || 'name'
      blankSortBy: false, // 'initial' || 'score' || 'name'
      preSelection: true,
      hideDropdownOnEmptyInput: false,
      selectedClass: "flexselect_selected",
      dropdownClass: "flexselect_dropdown",
      showDisabledOptions: false,
      inputIdTransform:    function(id)   { return id + "_flexselect"; },
      inputNameTransform:  function(name) { return; },
      dropdownIdTransform: function(id)   { return id + "_flexselect_dropdown"; }
    },
    select: null,
    input: null,
    dropdown: null,
    dropdownList: null,
    cache: [],
    results: [],
    lastAbbreviation: null,
    abbreviationBeforeFocus: null,
    selectedIndex: 0,
    picked: false,
    allowMouseMove: true,
    dropdownMouseover: false, // Workaround for poor IE behaviors
    indexOptgroupLabels: false,

    init: function(select, options) {
      this.settings = $.extend({}, this.settings, options);
      this.select = $(select);
      this.reloadCache();
      this.renderControls();
      this.wire();
    },

    reloadCache: function() {
      var name, group, text, disabled;
      var indexGroup = this.settings.indexOptgroupLabels;
      this.cache = this.select.find("option").map(function() {
        name = $(this).text();
        group = $(this).parent("optgroup").attr("label");
        text = indexGroup ? [name, group].join(" ") : name;
        disabled = $(this).parent("optgroup").attr("disabled") || $(this).attr('disabled');
        return { text: $.trim(text), name: $.trim(name), value: $(this).val(), disabled: disabled, score: 0.0 };
      });
    },

    renderControls: function() {
      var selected = this.settings.preSelection ? this.select.find("option:selected") : null;

      this.input = $("<input type='text' autocomplete='off' />").attr({
        id: this.settings.inputIdTransform(this.select.attr("id")),
        name: this.settings.inputNameTransform(this.select.attr("name")),
        accesskey: this.select.attr("accesskey"),
        tabindex: this.select.attr("tabindex"),
        style: this.select.attr("style"),
        placeholder: this.select.attr("data-placeholder")
      }).addClass(this.select.attr("class")).val($.trim(selected ? selected.text():  '')).css({
        visibility: 'visible'
      });

      this.dropdown = $("

").attr({
        id: this.settings.dropdownIdTransform(this.select.attr("id"))
      }).addClass(this.settings.dropdownClass);
      this.dropdownList = $("

");
      this.dropdown.append(this.dropdownList);

      this.select.after(this.input).hide();
      $("body").append(this.dropdown);
    },

    wire: function() {
      var self = this;

      this.input.click(function() {
        self.lastAbbreviation = null;
        self.focus();
      });

      this.input.mouseup(function(event) {
        // This is so Safari selection actually occurs.
        event.preventDefault();
      });

      this.input.focus(function() {
        self.abbreviationBeforeFocus = self.input.val();
        self.input[0].setSelectionRange(0, self.input.val().length);
        if (!self.picked) self.filterResults();
      });

      this.input.blur(function() {
        if (!self.dropdownMouseover) {
          self.hide();
          if (self.settings.allowMismatchBlank && $.trim($(this).val()) == '')
            self.setValue('');
          else if (!self.settings.allowMismatch && !self.picked)
            self.reset();
        }
      });

      this.dropdownList.mouseover(function(event) {
        if (!self.allowMouseMove) {
          self.allowMouseMove = true;
          return;
        }

        if (event.target.tagName == "LI") {
          var rows = self.dropdown.find("li");
          self.markSelected(rows.index($(event.target)));
        }
      });
      this.dropdownList.mouseleave(function() {
        self.markSelected(-1);
      });
      this.dropdownList.mouseup(function(event) {
        self.pickSelected();
        self.focusAndHide();
      });
      this.dropdownList.bind("touchstart", function(event) {
        if (event.target.tagName == "LI") {
          var rows = self.dropdown.find("li");
          self.markSelected(rows.index($(event.target)));
        }
      });
      this.dropdown.mouseover(function(event) {
        self.dropdownMouseover = true;
      });
      this.dropdown.mouseleave(function(event) {
        self.dropdownMouseover = false;
      });
      this.dropdown.mousedown(function(event) {
        event.preventDefault();
      });

      this.input.keyup(function(event) {
        switch (event.keyCode) {
          case 13: // return
            event.preventDefault();
            self.pickSelected();
            self.focusAndHide();
            break;
          case 27: // esc
            event.preventDefault();
            self.reset();
            self.focusAndHide();
            break;
          default:
            self.filterResults();
            break;
        }
      });

      this.input.keydown(function(event) {
        switch (event.keyCode) {
          case 9:  // tab
            self.pickSelected();
            self.hide();
            break;
          case 33: // pgup
            event.preventDefault();
            self.markFirst();
            break;
          case 34: // pgedown
            event.preventDefault();
            self.markLast();
            break;
          case 38: // up
            event.preventDefault();
            self.moveSelected(-1);
            break;
          case 40: // down
            event.preventDefault();
            self.moveSelected(1);
            break;
          case 13: // return
          case 27: // esc
            event.preventDefault();
            event.stopPropagation();
            break;
        }
      });

      var input = this.input;
      this.select.change(function () {
        input.val($.trim($(this).find('option:selected').text()));
      });
    },

    filterResults: function() {
      var showDisabled = this.settings.showDisabledOptions;
      var abbreviation = this.input.val();
      if (abbreviation == this.lastAbbreviation) return;

      var results = [];
      $.each(this.cache, function() {
        if (this.disabled && !showDisabled) return;
        this.score = LiquidMetal.score(this.text, abbreviation);
        if (this.score > 0.0) results.push(this);
      });
      this.results = results;

      if(this.settings.blankSortBy && $.trim(abbreviation) == ''){
        if (this.settings.blankSortBy == 'score')
          this.sortResultsByScore();
        else if (this.settings.blankSortBy == 'name')
          this.sortResultsByName();
      } else {
        if (this.settings.sortBy == 'score')
          this.sortResultsByScore();
        else if (this.settings.sortBy == 'name')
          this.sortResultsByName();
      }

      this.renderDropdown();
      this.markFirst();
      this.lastAbbreviation = abbreviation;
      this.picked = false;
      this.allowMouseMove = false;

      if (this.settings.hideDropdownOnEmptyInput){
        if(this.input.val() == "")
          this.dropdown.hide();
        else
          this.dropdown.show();
      }
    },

    sortResultsByScore: function() {
      this.results.sort(function(a, b) { return b.score - a.score; });
    },

    sortResultsByName: function() {
      this.results.sort(function(a, b) { return a.name  b.name ? 1 : 0); });
    },

    renderDropdown: function() {
      var showDisabled = this.settings.showDisabledOptions;
      var dropdownBorderWidth = this.dropdown.outerWidth() - this.dropdown.innerWidth();
      var inputOffset = this.input.offset();
      this.dropdown.css({
        width: (this.input.outerWidth() - dropdownBorderWidth) + "px",
        top: (inputOffset.top + this.input.outerHeight()) + "px",
        left: inputOffset.left + "px",
        maxHeight: ''
      });

      var html = '';
      var disabledAttribute = '';
      $.each(this.results, function() {
        if (this.disabled && !showDisabled) return;
        disabledAttribute = this.disabled ? ' class="disabled"' : '';
        html += '
' + this.name + '
';
      });
      this.dropdownList.html(html);
      this.adjustMaxHeight();
      this.dropdown.show();
    },

    adjustMaxHeight: function() {
      var maxTop = $(window).height() + $(window).scrollTop() - this.dropdown.outerHeight();
      var top = parseInt(this.dropdown.css('top'), 10);
      this.dropdown.css('max-height', top > maxTop ? (Math.max(0, maxTop - top + this.dropdown.innerHeight()) + 'px') : '');
    },

    markSelected: function(n) {
      if (n < 0 || n >= this.results.length) return;

      var rows = this.dropdown.find("li");
      rows.removeClass(this.settings.selectedClass);

      var row = $(rows[n]);
      if (row.hasClass('disabled')) {
        this.selectedIndex = null;
        return;
      }

      this.selectedIndex = n;
      row.addClass(this.settings.selectedClass);
      var top = row.position().top;
      var delta = top + row.outerHeight() - this.dropdown.height();
      if (delta > 0) {
        this.allowMouseMove = false;
        this.dropdown.scrollTop(this.dropdown.scrollTop() + delta);
      } else if (top < 0) {
        this.allowMouseMove = false;
        this.dropdown.scrollTop(Math.max(0, this.dropdown.scrollTop() + top));
      }
    },

    pickSelected: function() {
      var selected = this.results[this.selectedIndex];
      if (selected && !selected.disabled) {
        this.input.val(selected.name);
        this.setValue(selected.value);
        this.picked = true;
      } else if (this.settings.allowMismatch) {
        this.setValue.val("");
      } else {
        this.reset();
      }
    },

    setValue: function(val) {
      if (this.select.val() === val) return;
      this.select.val(val).change();
    },

    hide: function() {
      this.dropdown.hide();
      this.lastAbbreviation = null;
    },

    moveSelected: function(n) { this.markSelected(this.selectedIndex+n); },
    markFirst:    function()  { this.markSelected(0); },
    markLast:     function()  { this.markSelected(this.results.length - 1); },
    reset:        function()  { this.input.val(this.abbreviationBeforeFocus); },
    focus:        function()  { this.input.focus(); },
    focusAndHide: function()  { this.focus(); this.hide(); }
  });

  $.fn.flexselect = function(options) {
    this.each(function() {
      if ($(this).data("flexselect")) {
        $(this).data("flexselect").reloadCache();
      } else if (this.tagName == "SELECT") {
        $(this).data("flexselect", new $.flexselect(this, options));
      }
    });
    return this;
  };
})(jQuery);
<commit_msg>Refactored newly added blankSortBy behavior<commit_after>/**
 * flexselect: a jQuery plugin, version: %RELEASE_VERSION% (%RELEASE_DATE%)
 * @requires jQuery v1.3 or later
 *
 * FlexSelect is a jQuery plugin that makes it easy to convert a select box into
 * a Quicksilver-style, autocompleting, flex matching selection tool.
 *
 * For usage and examples, visit:
 * http://rmm5t.github.io/jquery-flexselect/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2009-2015, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
 */
(function($) {
  $.flexselect = function(select, options) { this.init(select, options); };

  $.extend($.flexselect.prototype, {
    settings: {
      allowMismatch: false,
      allowMismatchBlank: true, // If "true" a user can backspace such that the value is nothing (even if no blank value was provided in the original criteria)
      sortBy: 'score', // 'score' || 'name'
      blankSortBy: 'initial', // 'score' || 'name' || 'initial'
      preSelection: true,
      hideDropdownOnEmptyInput: false,
      selectedClass: "flexselect_selected",
      dropdownClass: "flexselect_dropdown",
      showDisabledOptions: false,
      inputIdTransform:    function(id)   { return id + "_flexselect"; },
      inputNameTransform:  function(name) { return; },
      dropdownIdTransform: function(id)   { return id + "_flexselect_dropdown"; }
    },
    select: null,
    input: null,
    dropdown: null,
    dropdownList: null,
    cache: [],
    results: [],
    lastAbbreviation: null,
    abbreviationBeforeFocus: null,
    selectedIndex: 0,
    picked: false,
    allowMouseMove: true,
    dropdownMouseover: false, // Workaround for poor IE behaviors
    indexOptgroupLabels: false,

    init: function(select, options) {
      this.settings = $.extend({}, this.settings, options);
      this.select = $(select);
      this.reloadCache();
      this.renderControls();
      this.wire();
    },

    reloadCache: function() {
      var name, group, text, disabled;
      var indexGroup = this.settings.indexOptgroupLabels;
      this.cache = this.select.find("option").map(function() {
        name = $(this).text();
        group = $(this).parent("optgroup").attr("label");
        text = indexGroup ? [name, group].join(" ") : name;
        disabled = $(this).parent("optgroup").attr("disabled") || $(this).attr('disabled');
        return { text: $.trim(text), name: $.trim(name), value: $(this).val(), disabled: disabled, score: 0.0 };
      });
    },

    renderControls: function() {
      var selected = this.settings.preSelection ? this.select.find("option:selected") : null;

      this.input = $("<input type='text' autocomplete='off' />").attr({
        id: this.settings.inputIdTransform(this.select.attr("id")),
        name: this.settings.inputNameTransform(this.select.attr("name")),
        accesskey: this.select.attr("accesskey"),
        tabindex: this.select.attr("tabindex"),
        style: this.select.attr("style"),
        placeholder: this.select.attr("data-placeholder")
      }).addClass(this.select.attr("class")).val($.trim(selected ? selected.text():  '')).css({
        visibility: 'visible'
      });

      this.dropdown = $("

").attr({
        id: this.settings.dropdownIdTransform(this.select.attr("id"))
      }).addClass(this.settings.dropdownClass);
      this.dropdownList = $("

");
      this.dropdown.append(this.dropdownList);

      this.select.after(this.input).hide();
      $("body").append(this.dropdown);
    },

    wire: function() {
      var self = this;

      this.input.click(function() {
        self.lastAbbreviation = null;
        self.focus();
      });

      this.input.mouseup(function(event) {
        // This is so Safari selection actually occurs.
        event.preventDefault();
      });

      this.input.focus(function() {
        self.abbreviationBeforeFocus = self.input.val();
        self.input[0].setSelectionRange(0, self.input.val().length);
        if (!self.picked) self.filterResults();
      });

      this.input.blur(function() {
        if (!self.dropdownMouseover) {
          self.hide();
          if (self.settings.allowMismatchBlank && $.trim($(this).val()) == '')
            self.setValue('');
          else if (!self.settings.allowMismatch && !self.picked)
            self.reset();
        }
      });

      this.dropdownList.mouseover(function(event) {
        if (!self.allowMouseMove) {
          self.allowMouseMove = true;
          return;
        }

        if (event.target.tagName == "LI") {
          var rows = self.dropdown.find("li");
          self.markSelected(rows.index($(event.target)));
        }
      });
      this.dropdownList.mouseleave(function() {
        self.markSelected(-1);
      });
      this.dropdownList.mouseup(function(event) {
        self.pickSelected();
        self.focusAndHide();
      });
      this.dropdownList.bind("touchstart", function(event) {
        if (event.target.tagName == "LI") {
          var rows = self.dropdown.find("li");
          self.markSelected(rows.index($(event.target)));
        }
      });
      this.dropdown.mouseover(function(event) {
        self.dropdownMouseover = true;
      });
      this.dropdown.mouseleave(function(event) {
        self.dropdownMouseover = false;
      });
      this.dropdown.mousedown(function(event) {
        event.preventDefault();
      });

      this.input.keyup(function(event) {
        switch (event.keyCode) {
          case 13: // return
            event.preventDefault();
            self.pickSelected();
            self.focusAndHide();
            break;
          case 27: // esc
            event.preventDefault();
            self.reset();
            self.focusAndHide();
            break;
          default:
            self.filterResults();
            break;
        }
      });

      this.input.keydown(function(event) {
        switch (event.keyCode) {
          case 9:  // tab
            self.pickSelected();
            self.hide();
            break;
          case 33: // pgup
            event.preventDefault();
            self.markFirst();
            break;
          case 34: // pgedown
            event.preventDefault();
            self.markLast();
            break;
          case 38: // up
            event.preventDefault();
            self.moveSelected(-1);
            break;
          case 40: // down
            event.preventDefault();
            self.moveSelected(1);
            break;
          case 13: // return
          case 27: // esc
            event.preventDefault();
            event.stopPropagation();
            break;
        }
      });

      var input = this.input;
      this.select.change(function () {
        input.val($.trim($(this).find('option:selected').text()));
      });
    },

    filterResults: function() {
      var showDisabled = this.settings.showDisabledOptions;
      var abbreviation = $.trim(this.input.val());
      var sortByMechanism = (abbreviation == "") ? this.settings.blankSortBy : this.settings.sortBy;
      if (abbreviation == this.lastAbbreviation) return;

      var results = [];
      $.each(this.cache, function() {
        if (this.disabled && !showDisabled) return;
        this.score = LiquidMetal.score(this.text, abbreviation);
        if (this.score > 0.0) results.push(this);
      });
      this.results = results;

      this.sortResultsBy(sortByMechanism);
      this.renderDropdown();
      this.markFirst();
      this.lastAbbreviation = abbreviation;
      this.picked = false;
      this.allowMouseMove = false;

      if (this.settings.hideDropdownOnEmptyInput){
        if (abbreviation == "")
          this.dropdown.hide();
        else
          this.dropdown.show();
      }
    },

    sortResultsBy: function(mechanism) {
      if (mechanism == "score") {
        this.sortResultsByScore();
      } else if (mechanism == "name") {
        this.sortResultsByName();
      }
    },

    sortResultsByScore: function() {
      this.results.sort(function(a, b) { return b.score - a.score; });
    },

    sortResultsByName: function() {
      this.results.sort(function(a, b) { return a.name  b.name ? 1 : 0); });
    },

    renderDropdown: function() {
      var showDisabled = this.settings.showDisabledOptions;
      var dropdownBorderWidth = this.dropdown.outerWidth() - this.dropdown.innerWidth();
      var inputOffset = this.input.offset();
      this.dropdown.css({
        width: (this.input.outerWidth() - dropdownBorderWidth) + "px",
        top: (inputOffset.top + this.input.outerHeight()) + "px",
        left: inputOffset.left + "px",
        maxHeight: ''
      });

      var html = '';
      var disabledAttribute = '';
      $.each(this.results, function() {
        if (this.disabled && !showDisabled) return;
        disabledAttribute = this.disabled ? ' class="disabled"' : '';
        html += '
' + this.name + '
';
      });
      this.dropdownList.html(html);
      this.adjustMaxHeight();
      this.dropdown.show();
    },

    adjustMaxHeight: function() {
      var maxTop = $(window).height() + $(window).scrollTop() - this.dropdown.outerHeight();
      var top = parseInt(this.dropdown.css('top'), 10);
      this.dropdown.css('max-height', top > maxTop ? (Math.max(0, maxTop - top + this.dropdown.innerHeight()) + 'px') : '');
    },

    markSelected: function(n) {
      if (n < 0 || n >= this.results.length) return;

      var rows = this.dropdown.find("li");
      rows.removeClass(this.settings.selectedClass);

      var row = $(rows[n]);
      if (row.hasClass('disabled')) {
        this.selectedIndex = null;
        return;
      }

      this.selectedIndex = n;
      row.addClass(this.settings.selectedClass);
      var top = row.position().top;
      var delta = top + row.outerHeight() - this.dropdown.height();
      if (delta > 0) {
        this.allowMouseMove = false;
        this.dropdown.scrollTop(this.dropdown.scrollTop() + delta);
      } else if (top < 0) {
        this.allowMouseMove = false;
        this.dropdown.scrollTop(Math.max(0, this.dropdown.scrollTop() + top));
      }
    },

    pickSelected: function() {
      var selected = this.results[this.selectedIndex];
      if (selected && !selected.disabled) {
        this.input.val(selected.name);
        this.setValue(selected.value);
        this.picked = true;
      } else if (this.settings.allowMismatch) {
        this.setValue.val("");
      } else {
        this.reset();
      }
    },

    setValue: function(val) {
      if (this.select.val() === val) return;
      this.select.val(val).change();
    },

    hide: function() {
      this.dropdown.hide();
      this.lastAbbreviation = null;
    },

    moveSelected: function(n) { this.markSelected(this.selectedIndex+n); },
    markFirst:    function()  { this.markSelected(0); },
    markLast:     function()  { this.markSelected(this.results.length - 1); },
    reset:        function()  { this.input.val(this.abbreviationBeforeFocus); },
    focus:        function()  { this.input.focus(); },
    focusAndHide: function()  { this.focus(); this.hide(); }
  });

  $.fn.flexselect = function(options) {
    this.each(function() {
      if ($(this).data("flexselect")) {
        $(this).data("flexselect").reloadCache();
      } else if (this.tagName == "SELECT") {
        $(this).data("flexselect", new $.flexselect(this, options));
      }
    });
    return this;
  };
})(jQuery);
<|endoftext|>


<commit_before>/**
 * Created by davidportella on 27-02-14.
 */
;
(function ($, window, undefined) {

    /**
     * Este metodo se ejecuta despues de agregar la funcionalidad
     * al stock de metodos Jquery ($) configura y gatilla init
     *
     * @param elem
     * @param options
     * @constructor
     */
    var JqGridWrap = function (elem, options) {
        this.elem = elem;
        this.$elem = $(elem);

        if (this.init) {
            this.init(options);
        }
    };

    /**
     * Prototype del objeto JqGridWrap
     * @type {{defaults: {caption: string, datatype: string, viewrecords: boolean, height: number, rowNum: number, cmTemplate: {sortable: boolean}, autowidth: boolean, shrinkToFit: boolean, headertitles: boolean, sortable: boolean}, init: init, getPager: getPager, columnChooser: columnChooser, excelButton: excelButton, extraButtons: extraButtons}}
     */
    JqGridWrap.prototype = {
        defaults     : {
            caption     : "Titulo",
            datatype    : "json",
            viewrecords : true,
            height      : 400,
            rowNum      : 1000000000,
            cmTemplate  : {sortable: false},
            autowidth   : true,
            shrinkToFit : false,
            headertitles: true,
            sortable    : true
        },
        init         : function (options) {
            var grid_options = options.options,
                pager_options = options.pager ?
                    options.pager :
                {edit: false, add: false, del: false, search: false}
                ;

            this.config = $.extend({}, this.defaults, grid_options);
            this.pager = grid_options.pager;
            this.columns = grid_options.columns;

            this.$elem.jqGrid(this.config);

            this.$elem.jqGrid('navGrid', this.pager, pager_options);

        },
        getPager     : function () {
            return pager = this.config.pager;
        },
        columnChooser: function () {
            var pager = this.getPager(),
                that = this
                ;

            this.$elem.jqGrid('navButtonAdd', pager, {
                caption      : "Columnas",
                title        : "Mostrar/ocultar Columnas",
                onClickButton: function () {
                    that.$elem.jqGrid('columnChooser');
                }
            });
            return this.$elem;
        },
        excelButton  : function (args) {
            var pager = this.getPager(),
                that = this,
                defaults = {
                    caption   : "Descargar Excel",
                    buttonicon: "ui-icon-calculator",
                    title     : "Descargar Excel"
                }
                ;

            var config = $.extend({}, defaults, args);
            that.$elem.jqGrid('navButtonAdd', pager, config);

            return this.$elem;
        },
        extraButtons : function (args) {
            var pager = this.getPager(),
                that = this,
                defaults = {
                    position: "last",
                    cursor  : "pointer"
                }
                ;

            $.each(args, function (i, val) {
                var config = $.extend({}, defaults, val);
                that.$elem.jqGrid('navButtonAdd', pager, config);
            });

            return this.$elem;
        }
    };

    /**
     * Se agrega el plugin al stock de jquery
     *
     * En caso de que el llamado se haga a un metodo
     * Caso contrario si es un objeto el que viene
     * Finalmente un mensaje de error
     *
     * @param options
     * @returns {$.fn}
     */
    $.fn.jqGridWrap = function (options) {

        if (typeof options === 'string') {
            var args = Array.prototype.slice.call(arguments, 1);
            var jqGridWrap = this.data('jqGridWrap') ?
                this.data('jqGridWrap') :
                new JqGridWrap(this);

            if (jqGridWrap[options]) {
                jqGridWrap[options].apply(jqGridWrap, args);
            }
        } else if (typeof options == 'object' || !options) {
            this.data('jqGridWrap', new JqGridWrap(this, options));
        } else {
            $.error('Error, parámetro pasado es incorreto');
        }

        return this;
    };

    //window.JqGridWrap = JqGridWrap;

})(jQuery, window);<commit_msg>Mejoras a loadcomplete<commit_after>/**
 * Created by davidportella on 27-02-14.
 */
;
(function ($, window, undefined) {

    function loadBase(grid) {
        $("option[value='100000000']").text('Todos');

        // Hack nuevos tooltips
        /**
         * @todo: id match dinamico
         */
        $('.ui-jqgrid-htable th').filter(function () {
            return this.id.match(/^deprecated/) != null;
        }).each(function (i) {
            var col = grid.getGridParam('colModel');

            if (col[i].hasOwnProperty('sigeaAttr')) {
                $(this).tooltip({ content: col[i].sigeaAttr.label });
            } else {
                $(this).tooltip({ content: this.lastChild.innerText });
            }
        });
    }

    function loadFinal() {
        $.unblockUI();
    }

    function loadComplete(loadBase, loadCustom, loadFinal, grid) {
        loadBase(grid);
        if (loadCustom !== false) {
            loadCustom();
        }
        loadFinal();
    }

    /**
     * Este metodo se ejecuta despues de agregar la funcionalidad
     * al stock de metodos Jquery ($) configura y gatilla init
     *
     * @param elem
     * @param options
     * @constructor
     */
    var JqGridWrap = function (elem, options) {
        this.elem = elem;
        this.$elem = $(elem);

        if (this.init) {
            this.init(options);
        }
    };

    /**
     * Prototype del objeto JqGridWrap
     * @type {{defaults: {caption: string, datatype: string, viewrecords: boolean, height: number, rowNum: number, cmTemplate: {sortable: boolean}, autowidth: boolean, shrinkToFit: boolean, headertitles: boolean, sortable: boolean}, init: init, getPager: getPager, columnChooser: columnChooser, excelButton: excelButton, extraButtons: extraButtons}}
     */
    JqGridWrap.prototype = {
        defaults     : {
            caption     : "Titulo",
            datatype    : "json",
            viewrecords : true,
            height      : 400,
            rowNum      : 1000000000,
            cmTemplate  : {sortable: false},
            autowidth   : true,
            shrinkToFit : false,
            headertitles: true,
            sortable    : true,
            loadui      : 'block'
        },
        init         : function (options) {

            var grid_options = options.options,
                pager_options = options.pager ?
                    options.pager :
                {edit: false, add: false, del: false, search: false},
                loadCustom = options.loadCustom,
                pager_extra_options = options.extra_pager ?
                    options.extra_pager :
                {},
                that = this
                ;

            if (grid_options.loadComplete === undefined) {

                grid_options.loadComplete = function () {
                    loadComplete(loadBase, loadCustom, loadFinal,that.$elem);
                };
            } else if (grid_options.loadComplete === 'default') {

                grid_options.loadComplete = function () {
                    loadComplete(loadBase, false, loadFinal, that.$elem);
                };
            }

            this.config = $.extend({}, this.defaults, grid_options);
            this.pager = grid_options.pager;
            this.columns = grid_options.columns;

            this.$elem.jqGrid(this.config);

            pager_options = $.extend(
                {},
                {
                    beforeRefresh: function () {
                        var cm = grid_options.colModel;

                        var i = 0, cmi, l = cm.length;
                        for (; i < l; i++) {
                            cmi = cm[i];
                            if (typeof cmi.hidden === 'undefined' || cmi.hidden === false) {
                                that.$elem.jqGrid('showCol', cmi.name);
                            } else {
                                that.$elem.jqGrid('hideCol', cmi.name);
                            }
                        }
                    }
                },
                pager_options
            );

            if (options.onclickSubmit) {
                this.$elem.jqGrid(
                    'navGrid',
                    this.pager,
                    pager_options,
                    {},
                    {},
                    options.onclickSubmit,
                    {}
                );
            } else {
                this.$elem.jqGrid('navGrid', this.pager, pager_options);
            }

        },
        getPager     : function () {
            return pager = this.config.pager;
        },
        columnChooser: function () {
            var pager = this.getPager(),
                that = this
                ;

            this.$elem.jqGrid('navButtonAdd', pager, {
                caption      : "Columnas",
                title        : 'Seleccione las columnas que desea visualizar en la pantalla.',
                onClickButton: function () {
                    that.$elem.jqGrid('columnChooser', {
                        title: 'Seleccione las columnas que desea visualizar. Para selección múltiple, mantenga presionada la tecla "ctrl" en su teclado'
                    });
                }
            });

            return this.$elem;
        },
        excelButton  : function (args) {
            var pager = this.getPager(),
                that = this,
                defaults = {
                    caption   : "Descargar Excel",
                    buttonicon: "ui-icon-calculator",
                    title     : "Descargar Excel"
                }
                ;

            var config = $.extend({}, defaults, args);
            that.$elem.jqGrid('navButtonAdd', pager, config);

            return this.$elem;
        },
        extraButtons : function (args) {
            var pager = this.getPager(),
                that = this,
                defaults = {
                    position: "last",
                    cursor  : "pointer"
                }
                ;

            $.each(args, function (i, val) {
                var config = $.extend({}, defaults, val);
                that.$elem.jqGrid('navButtonAdd', pager, config);
            });

            return this.$elem;
        }
    };

    /**
     * Se agrega el plugin al stock de jquery
     *
     * En caso de que el llamado se haga a un metodo
     * Caso contrario si es un objeto el que viene
     * Finalmente un mensaje de error
     *
     * @param options
     * @returns {$.fn}
     */
    $.fn.jqGridWrap = function (options) {

        if (typeof options === 'string') {
            var args = Array.prototype.slice.call(arguments, 1);
            var jqGridWrap = this.data('jqGridWrap') ?
                this.data('jqGridWrap') :
                new JqGridWrap(this);

            if (jqGridWrap[options]) {
                jqGridWrap[options].apply(jqGridWrap, args);
            }
        } else if (typeof options == 'object' || !options) {
            this.data('jqGridWrap', new JqGridWrap(this, options));
        } else {
            $.error('Error, parámetro pasado es incorreto');
        }

        return this;
    };

    //window.JqGridWrap = JqGridWrap;

})(jQuery, window);<|endoftext|>


<commit_before>/*!
 * PopConfirm 0.4.3
 * http://ifnot.github.io/PopConfirm/
 *
 * Use jQuery & Bootstrap
 * http://jquery.com/
 * http://getbootstrap.com/
 *
 * Copyright 2014 Anael Favre and other contributors
 * Released under the MIT license
 * https://raw.github.com/AnaelFavre/PopConfirm/master/LICENCE
 *
 * Thanks to contributors :
 * Thomas Hanson https://github.com/diresquirrel
 * Mohamed Aymen https://github.com/kernel64
 * Muhammad Ubaid Raza https://github.com/mubaidr
 */

(function ($) {
  'use strict';
  /*global jQuery, $*/
  /*jslint nomen: true, evil: true*/
  $.fn.extend({
    popConfirm: function (options) {
      var defaults = {
          title: 'Confirmation',
          content: 'Are you really sure ?',
          placement: 'right',
          container: 'body',
          yesBtn: 'Yes',
          noBtn: 'No'
        },
        last = null;
      options = $.extend(defaults, options);
      return this.each(function () {
        var self = $(this),
          arrayActions = [],
          arrayDelegatedActions = [],
          eventToConfirm,
          optName,
          optValue,
          i,
          elmType,
          code,
          form;

        // Load data-* attriutes
        for (optName in options) {
          if (options.hasOwnProperty(optName)) {
            optValue = $(this).attr('data-confirm-' + optName);
            if (optValue) {
              options[optName] = optValue;
            }
          }
        }

        // If there are jquery click events
        if (jQuery._data(this, "events") && jQuery._data(this, "events").click) {

          // Save all click handlers
          for (i = 0; i < jQuery._data(this, "events").click.length; i = i + 1) {
            arrayActions.push(jQuery._data(this, "events").click[i].handler);
          }

          // unbind it to prevent it firing
          $(self).unbind("click");
        }

        // If there are jquery delegated click events
        if (self.data('remote') && jQuery._data(document, "events") && jQuery._data(document, "events").click) {

          // Save all delegated click handlers that apply
          for (i = 0; i < jQuery._data(document, "events").click.length; i = i + 1) {
            elmType = self[0].tagName.toLowerCase();
            if (jQuery._data(document, "events").click[i].selector && jQuery._data(document, "events").click[i].selector.indexOf(elmType + "[data-remote]") !== -1) {
              arrayDelegatedActions.push(jQuery._data(document, "events").click[i].handler);
            }
          }
        }

        // If there are hard onclick attribute
        if (self.attr('onclick')) {
          // Extracting the onclick code to evaluate and bring it into a closure
          code = self.attr('onclick');
          arrayActions.push(function () {
            eval(code);
          });
          $(self).prop("onclick", null);
        }

        // If there are href link defined
        if (!self.data('remote') && self.attr('href')) {
          // Assume there is a href attribute to redirect to
          arrayActions.push(function () {
            window.location.href = self.attr('href');
          });
        }

        // If the button is a submit one
        if (self.attr('type') && self.attr('type') === 'submit') {
          // Get the form related to this button then store submiting in closure
          form = $(this).parents('form:first');
          arrayActions.push(function () {
            form.submit();
          });
        }

        self.popover({
          trigger: 'manual',
          title: options.title,
          html: true,
          placement: options.placement,
          container: options.container,
          //Avoid using multiline strings, no support in older browsers.
          content: options.content + '
<button type="button" class="btn btn-small confirm-dialog-btn-abord">' + options.noBtn + '</button> <button type="button" class="btn btn-small btn-danger confirm-dialog-btn-confirm">' + options.yesBtn + '</button>
'
        }).click(function (e) {
          if (last && last !== self) {
            last.popover('hide').removeClass('popconfirm-active');
          }
          last = self;
        });

        $(document).on('click', function () {
          if (last) {
            last.popover('hide').removeClass('popconfirm-active');
          }
        });

        self.bind('click', function (e) {
          eventToConfirm = e;

          e.preventDefault();
          e.stopPropagation();

          $('.popconfirm-active').not(self).popover('hide').removeClass('popconfirm-active');
          self.popover('show').addClass('popconfirm-active');

          $(document).find('.popover .confirm-dialog-btn-confirm').bind('click', function (e) {
            for (i = 0; i < arrayActions.length; i = i + 1) {
              arrayActions[i].apply(self);
            }

            for (i = 0; i < arrayDelegatedActions.length; i = i + 1) {
              arrayDelegatedActions[i].apply(self, [eventToConfirm.originalEvent]);
            }

            self.popover('hide').removeClass('popconfirm-active');
          });
          $(document).find('.popover .confirm-dialog-btn-abord').bind('click', function (e) {
            self.popover('hide').removeClass('popconfirm-active');
          });
        });
      });
    }
  });
}(jQuery));
<commit_msg>Fix typo in no button class<commit_after>/*!
 * PopConfirm 0.4.3
 * http://ifnot.github.io/PopConfirm/
 *
 * Use jQuery & Bootstrap
 * http://jquery.com/
 * http://getbootstrap.com/
 *
 * Copyright 2014 Anael Favre and other contributors
 * Released under the MIT license
 * https://raw.github.com/AnaelFavre/PopConfirm/master/LICENCE
 *
 * Thanks to contributors :
 * Thomas Hanson https://github.com/diresquirrel
 * Mohamed Aymen https://github.com/kernel64
 * Muhammad Ubaid Raza https://github.com/mubaidr
 */

(function ($) {
  'use strict';
  /*global jQuery, $*/
  /*jslint nomen: true, evil: true*/
  $.fn.extend({
    popConfirm: function (options) {
      var defaults = {
          title: 'Confirmation',
          content: 'Are you really sure ?',
          placement: 'right',
          container: 'body',
          yesBtn: 'Yes',
          noBtn: 'No'
        },
        last = null;
      options = $.extend(defaults, options);
      return this.each(function () {
        var self = $(this),
          arrayActions = [],
          arrayDelegatedActions = [],
          eventToConfirm,
          optName,
          optValue,
          i,
          elmType,
          code,
          form;

        // Load data-* attriutes
        for (optName in options) {
          if (options.hasOwnProperty(optName)) {
            optValue = $(this).attr('data-confirm-' + optName);
            if (optValue) {
              options[optName] = optValue;
            }
          }
        }

        // If there are jquery click events
        if (jQuery._data(this, "events") && jQuery._data(this, "events").click) {

          // Save all click handlers
          for (i = 0; i < jQuery._data(this, "events").click.length; i = i + 1) {
            arrayActions.push(jQuery._data(this, "events").click[i].handler);
          }

          // unbind it to prevent it firing
          $(self).unbind("click");
        }

        // If there are jquery delegated click events
        if (self.data('remote') && jQuery._data(document, "events") && jQuery._data(document, "events").click) {

          // Save all delegated click handlers that apply
          for (i = 0; i < jQuery._data(document, "events").click.length; i = i + 1) {
            elmType = self[0].tagName.toLowerCase();
            if (jQuery._data(document, "events").click[i].selector && jQuery._data(document, "events").click[i].selector.indexOf(elmType + "[data-remote]") !== -1) {
              arrayDelegatedActions.push(jQuery._data(document, "events").click[i].handler);
            }
          }
        }

        // If there are hard onclick attribute
        if (self.attr('onclick')) {
          // Extracting the onclick code to evaluate and bring it into a closure
          code = self.attr('onclick');
          arrayActions.push(function () {
            eval(code);
          });
          $(self).prop("onclick", null);
        }

        // If there are href link defined
        if (!self.data('remote') && self.attr('href')) {
          // Assume there is a href attribute to redirect to
          arrayActions.push(function () {
            window.location.href = self.attr('href');
          });
        }

        // If the button is a submit one
        if (self.attr('type') && self.attr('type') === 'submit') {
          // Get the form related to this button then store submiting in closure
          form = $(this).parents('form:first');
          arrayActions.push(function () {
            form.submit();
          });
        }

        self.popover({
          trigger: 'manual',
          title: options.title,
          html: true,
          placement: options.placement,
          container: options.container,
          //Avoid using multiline strings, no support in older browsers.
          content: options.content + '
<button type="button" class="btn btn-small confirm-dialog-btn-abort">' + options.noBtn + '</button> <button type="button" class="btn btn-small btn-danger confirm-dialog-btn-confirm">' + options.yesBtn + '</button>
'
        }).click(function (e) {
          if (last && last !== self) {
            last.popover('hide').removeClass('popconfirm-active');
          }
          last = self;
        });

        $(document).on('click', function () {
          if (last) {
            last.popover('hide').removeClass('popconfirm-active');
          }
        });

        self.bind('click', function (e) {
          eventToConfirm = e;

          e.preventDefault();
          e.stopPropagation();

          $('.popconfirm-active').not(self).popover('hide').removeClass('popconfirm-active');
          self.popover('show').addClass('popconfirm-active');

          $(document).find('.popover .confirm-dialog-btn-confirm').bind('click', function (e) {
            for (i = 0; i < arrayActions.length; i = i + 1) {
              arrayActions[i].apply(self);
            }

            for (i = 0; i < arrayDelegatedActions.length; i = i + 1) {
              arrayDelegatedActions[i].apply(self, [eventToConfirm.originalEvent]);
            }

            self.popover('hide').removeClass('popconfirm-active');
          });
          $(document).find('.popover .confirm-dialog-btn-abord').bind('click', function (e) {
            self.popover('hide').removeClass('popconfirm-active');
          });
        });
      });
    }
  });
}(jQuery));
<|endoftext|>