{"version":3,"sources":["Behavior.js","ElementMissingError.js","Focus.js","Hooks.js","Present.js","registry.js","throttle_single.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8DC/MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KCjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBCrGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BCrJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BC3HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"EVABehaviors.js","sourcesContent":["window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\nwindow.EVASuit.Behaviors.Behavior = function(Element, Document, Behaviors) {\n \"use strict\";\n\n /**\n * Unique name for our list of located instances.\n */\n const LOCATED_INSTANCES = Symbol(\"locatedInstances\");\n\n /**\n * A custom JavaScript behavior that can be repeatedly located onto a set\n * of elements named by a CSS selector.\n */\n class Behavior {\n /**\n * Find markup that this Behavior locates onto within a given context\n * and instantiate the class on that markup.\n * \n * The current class's QUERY parameter will be used as the CSS selector\n * to find markup with. If the given context itself also matches the\n * selector, it \n * \n * @param {jQuery|Element|null} context The context element to find\n * markup in. If null, the current document is checked.\n * @param {...any} _ Any arguments to pass on down into the context.\n * \n * Must either be shaped like a jQuery object or a DOM element.\n */\n static find_markup(context=null) {\n var results = [], i, splitArgs = [], Class = this, nodelist;\n\n function processElem(index, elem) {\n var locateArgs = [elem].concat(splitArgs);\n\n results.push(Class.locate.apply(Class, locateArgs));\n }\n\n for (i = 1; i < arguments.length; i += 1) {\n splitArgs.push(arguments[i]);\n }\n\n if (context === null) {\n context = document;\n }\n\n if (context instanceof Element || context instanceof Document) { //Element-like context\n nodelist = Array.prototype.slice.call(context.querySelectorAll(Class.QUERY));\n nodelist.forEach(element => {\n processElem(undefined, element);\n });\n\n //Documents lack a matches method\n if (context.matches && context.matches(Class.QUERY)) {\n processElem(undefined, context);\n }\n } else if (context.filter && context.find) { //jQuery-like context\n context.filter(Class.QUERY).each(processElem);\n context.find(Class.QUERY).each(processElem);\n } else {\n throw new Behaviors.ElementMissingError(\"Behavior.find_markup called without valid context object\");\n }\n }\n \n /**\n * Instantiate this Behavior onto this element.\n * \n * Behaviors are designed to locate onto a given element once and only\n * once. If it has already been instantiated, then that instance will\n * be returned again.\n * \n * @param {jQuery|Element} elem The element to locate on.\n * \n * May either be a DOM element or jQuery.\n * \n * @param {...any} objectArgs Any other arguments to pass to the\n * behavior's constructor.\n * \n * @returns An instance of the Behavior on this element.\n * \n * @throws ElementMissingError if the element is neither jQuery nor a\n * DOM element, or if it's jQuery but has a length of 0.\n */\n static locate(elem, ...objectArgs) {\n var Class = this, instance;\n\n if (elem instanceof Element || elem instanceof Document) { //Element-like element\n if (Class[LOCATED_INSTANCES] === undefined) {\n Class[LOCATED_INSTANCES] = new WeakMap();\n }\n\n if (!Class[LOCATED_INSTANCES].has(elem)) {\n Class[LOCATED_INSTANCES].set(elem, new Class(elem, ...objectArgs));\n }\n\n return Class[LOCATED_INSTANCES].get(elem);\n } else if (elem !== null && elem.length !== undefined && elem.length > 0) { //jQuery-like element\n return self.locate(elem[0], ...objectArgs);\n } else {\n throw new Behaviors.ElementMissingError(\"Behavior.locate called without valid element\");\n }\n }\n\n /**\n * Indicates to the class that content was added to the page.\n * \n * Subclasses that override this function MUST call find_markup on the\n * full context eventually. You may use this function to delay Behavior\n * processing until a later time, but your Behavior must still be able\n * to handle code locating it before that time.\n * \n * @param {jQuery|Element} context The content that was added to the DOM.\n */\n static content_ready(context) {\n this.find_markup(context);\n }\n\n /**\n * Indicates to the class that content is about to be removed from the\n * page.\n * \n * Most Behaviors do not need to worry about content removal; garbage\n * collection will detach any event handlers and reclaim your object as\n * needed. However, things such as animation timers or other global\n * references to the object will keep it live and potentially leak\n * memory or keep rendering things off-screen. Content removal\n * notifications allow tearing down and disposing of such semantic\n * garbage.\n * \n * Subclasses that need to support tear down upon removal should\n * override the instance method `deinitialize` instead.\n * \n * @param {jQuery|Element} context The content that was removed from\n * the DOM.\n */\n static content_removal(context) {\n var Class = this, nodelist;\n\n function deinitialize_elem(elem) {\n var instance = Class.locate(elem);\n\n instance.deinitialize();\n }\n\n if (context instanceof Element) { //DOM contexts\n nodelist = Array.prototype.slice.call(context.querySelectorAll(Class.QUERY));\n nodelist.forEach(deinitialize_elem);\n\n if (context.matches(Class.QUERY)) {\n deinitialize_elem(context);\n }\n } else if (context.filter && context.find) { //jQuery-like context\n context.filter(Class.QUERY).each((index, elem) => deinitialize_elem(elem));\n context.find(Class.QUERY).each((index, elem) => deinitialize_elem(elem));\n } else {\n throw new Behaviors.ElementMissingError(\"Behavior.content_removal called without valid context object\");\n }\n }\n\n /**\n * Construct a new instance of this Behavior.\n * \n * The given element will be stored in this.elem. If jQuery is loaded,\n * a wrapped jQuery object with the element will be stored in\n * this.$elem.\n * \n * @param {Element} elem The DOM element being located upon.\n */\n constructor(elem) {\n this.elem = elem;\n\n if (window.jQuery) {\n this.$elem = window.jQuery(elem);\n }\n }\n\n /**\n * Tear down any animation timers or other global references to this\n * Behavior.\n */\n deinitialize() {\n\n }\n\n /**\n * Called when the Behavior is presented to the user.\n * \n * Should not be called to programmatically present a Behavior. To do\n * so, call Behaviors.present.\n */\n presented() {\n\n }\n\n /**\n * Called when the Behavior is dismissed.\n * \n * Should not be called to programmatically dismiss a Behavior. To do\n * so, call Behaviors.dismiss.\n */\n dismissed() {\n\n }\n }\n\n return Behavior;\n}(window.Element, window.Document, window.EVASuit.Behaviors);","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\nwindow.EVASuit.Behaviors.ElementMissingError = function() {\n \"use strict\";\n\n /**\n * Error that indicates that a required element is invalid or missing.\n */\n class ElementMissingError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ElementMissingError\";\n }\n }\n\n return ElementMissingError;\n}();","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\nwindow.EVASuit.Behaviors.Focus = (function() {\n \"use strict\";\n\n var module = {}, element_states = new WeakMap();\n\n /**\n * Make an entire element and its children unfocusable.\n * \n * Tabindexes will be set to -1 on all elements. Prior existing indexes\n * will be retained and restored when the element is made focusable again.\n * \n * @param {Element} elem The DOM element to exclude from focus.\n */\n function make_element_unfocusable(elem) {\n var i;\n\n if (elem.attributes.tabIndex !== undefined && (!element_states.has(elem) || elem.tabIndex !== -1)) {\n element_states.set(elem, elem.tabIndex);\n }\n\n elem.tabIndex = -1;\n\n for (i = 0; i < elem.children.length; i += 1) {\n if (elem.children[i]) {\n make_element_unfocusable(elem.children[i]);\n }\n }\n }\n\n /**\n * Make an entire element and its children focusable.\n * \n * This presumes that the element was made unfocusable prior. If it hasn't,\n * no change will be made to the element.\n * \n * @param {Element} elem The DOM element to include back into focus.\n */\n function make_element_focusable(elem) {\n var i;\n\n if (element_states.has(elem)) {\n elem.tabIndex = element_states.get(elem);\n } else {\n delete elem.tabIndex;\n delete elem.removeAttribute(\"tabIndex\");\n }\n\n for (i = 0; i < elem.children.length; i += 1) {\n if (elem.children[i]) {\n make_element_focusable(elem.children[i]);\n }\n }\n }\n\n module.make_element_focusable = make_element_focusable;\n module.make_element_unfocusable = make_element_unfocusable;\n\n return module;\n}());","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\n(window.EVASuit.Behaviors.Hooks = function(Behaviors) {\n \"use strict\";\n\n /**\n * Manages global hooks for Behaviors.\n * \n * A global hook is not tied to any specific instance of a Behavior; unlike\n * events. You add hooks to your behavior by adding one as a property of\n * your class, defining it's hook types, and triggering them in your\n * behavior's methods. Third-party code can then hook into your class by\n * attaching to the class's global hooks mechanism.\n * \n * Hooks are only to be used in cases where you don't particularly care\n * about *which* behavior you are talking to, only that you want to\n * intercept all of them. They are thus distinct from events, which are\n * fired on a specific behavior and can be used to link different, specific\n * behaviors.\n */\n class Hooks {\n constructor() {\n this.hooks = {};\n }\n\n /**\n * Define a hook name.\n * \n * @param {string} hook_name The name of the hook to attach to.\n */\n define_hook_type(hook_name) {\n if (!this.hooks.hasOwnProperty(hook_name)) {\n this.hooks[hook_name] = [];\n }\n }\n \n /**\n * An attached hook callback. Can optionally filter the hook's inherent\n * value.\n * \n * @callback AttachedHook\n * @param {*} value The inherent hook value, which depends on which\n * hook is being attached.\n * \n * May have already been filtered by a previously installed hook\n * function.\n * \n * @param {...*} context Any further context values.\n * \n * These are always the hook's inherent values and cannot be filtered\n * by user code. By convention, the first context value is the hooked\n * Behavior instance.\n * \n * @returns The filtered value.\n * \n * Returning `undefined` (either explicitly, or by not having a\n * `return` statement in your function) indicates that your hook does\n * not wish to change the value.\n */\n \n /**\n * Attach to a particular named hook.\n * \n * @param {string} hook_name The name of the hook to attach to.\n * @param {AttachedHook} impl The instance to be called at hook time.\n * @throws Error if the `hook_name` is invalid.\n */\n attach(hook_name, impl) {\n this.hooks[hook_name].push(impl);\n }\n\n /**\n * Trigger a given named hook.\n * \n * @param {string} hook_name The hook to trigger.\n * @param {*} value The hook value, which hook functions will be\n * expected to modify.\n * @param {Behaviors.Behavior} instance The current behavior being\n * hooked.\n * @param {*} * \n * @returns The hook value, optionally modified by any attached hooks.\n */\n trigger(hook_name, value, instance) {\n var i, new_value, context = [value, instance];\n for (i = 3; i < arguments.length; i += 1) {\n context.push(arguments[i]);\n }\n \n for (i = 0; i < this.hooks[hook_name].length; i += 1) {\n new_value = this.hooks[hook_name][i].apply(this, context);\n if (new_value !== undefined) {\n context[0] = new_value;\n }\n }\n \n return context[0];\n }\n }\n\n return Hooks;\n}(window.Behaviors));","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\nwindow.EVASuit.Behaviors = (function(module) {\n \"use strict\";\n var presentation_stack = [], stack_is_locked = false;\n\n /**\n * Error that indicates that elements were presented or dismissed in ways\n * that are invalid.\n */\n class PresentationLogicError extends Error {\n constructor(message) {\n super(message);\n this.name = \"PresentationLogicError\";\n }\n }\n\n /**\n * Present a given item.\n * \n * Presentation is hierarchial and follows the DOM tree. We maintain a\n * stack of currently-presented elements. Presenting a new element\n * dismisses all prior elements that are *not* parents of the current one.\n * \n * Clicking, focusing, tabbing, or ESCing out of the presented element\n * automatically dismisses it.\n * \n * To respond to presentation and dismissal, implement the presented() and\n * dismissed() methods of your Behavior.\n * \n * @param {Behaviors.Behavior} item A located behavior to present to\n * the user.\n */\n function present(item) {\n var stack_cleaned = false, i;\n \n if (stack_is_locked) {\n throw new PresentationLogicError(\"Cannot present items recursively.\");\n }\n\n stack_is_locked = true;\n\n // Dismiss presented elements off the stack until we catch one that is\n // a parent of the item to be presented.\n while (presentation_stack.length > 0 && !stack_cleaned) {\n var iter = item.elem;\n\n while (iter !== undefined) {\n if (presentation_stack[presentation_stack.length - 1] === iter) {\n stack_cleaned = true;\n break;\n }\n\n iter = iter.parent;\n }\n\n try {\n presentation_stack.pop().dismissed();\n } catch (e) {\n stack_is_locked = false;\n throw e;\n }\n }\n \n presentation_stack.push(item);\n \n try {\n item.presented();\n } finally {\n stack_is_locked = false;\n }\n }\n\n /**\n * Dismiss a given item.\n * \n * All presented children of this item will also be dismissed.\n * \n * @param {Behaviors.Behavior} [item] A located behavior to dismiss.\n * \n * If not provided, the last presented item on the stack will be dismissed.\n */\n function dismiss(item) {\n var stack_index, i = 0;\n \n if (stack_is_locked) {\n throw new PresentationLogicError(\"Cannot dismiss items recursively.\");\n }\n\n if (presentation_stack.length === 0) {\n throw new PresentationLogicError(\"Cannot dismiss without presenting first.\");\n }\n\n if (item === undefined) {\n stack_index = presentation_stack.length - 1;\n item = presentation_stack[stack_index];\n } else {\n stack_index = presentation_stack.indexOf(item);\n }\n\n if (stack_index === -1) {\n throw new PresentationLogicError(\"Cannot dismiss elements that were not presented.\");\n }\n \n while (presentation_stack.length > stack_index) {\n try {\n presentation_stack.pop().dismissed();\n } catch (e) {\n stack_is_locked = false;\n throw e;\n }\n }\n\n stack_is_locked = false;\n }\n\n /**\n * Present or dismiss an item based on if it is already presented.\n * \n * @param {Behaviors.Behavior} item A located behavior to toggle.\n */\n function toggle(item) {\n if (presentation_stack.indexOf(item) !== -1) {\n dismiss(item);\n } else {\n present(item);\n }\n }\n\n document.addEventListener(\"keyup\", function(evt) {\n if (evt.isComposing || evt.keyCode === 229) {\n // Ignore all composition events caused by IMEs (Input Method\n // Editors, used for Chinese, Japanese, Korean, etc) on desktop.\n return;\n }\n\n if (evt.key === \"Esc\" || evt.key === \"Escape\" || evt.keyCode === 27) {\n if (presentation_stack.length > 0) {\n dismiss();\n }\n }\n });\n\n module.present = present;\n module.dismiss = dismiss;\n module.toggle = toggle;\n\n return module;\n}(window.EVASuit.Behaviors));","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\n(function(Behaviors) {\n \"use strict\";\n\n var behavior_registry = {},\n content_ready_listeners = [];\n\n /**\n * Add a class to the behavior registry.\n * \n * @param {Function} Class A behavior subclass.\n * @param {String} name The name of the class.\n * \n * Inferred to be the class's QUERY if not provided.\n */\n function register_behavior(Class, name) {\n if (name === undefined) {\n name = Class.QUERY;\n }\n\n if (behavior_registry[name] === Class) {\n console.warn(\"Attempted to register the same behavior twice to CSS selector \\\"\" + name + \"\\\"\");\n return;\n }\n\n if (behavior_registry[name] !== undefined) {\n console.error(\"Attempted to register a second behavior onto CSS selector \\\"\" +\n name + \"\\\". Only one behavior may be registered to a given CSS selector \" +\n \"at a given time. The offending classes are \" + Class.name +\n \" and \" + behavior_registry[name].name + \".\");\n \n return;\n }\n\n behavior_registry[name] = Class;\n }\n \n /**\n * Register a function that is called when content is added to the page.\n * \n * This function should only be called for tying external code to the\n * content listener system. For example, Drupal ships its own behaviors\n * system separate from this one; you can use registered listeners to\n * trigger it when Behaviors' registry is pinged.\n * \n * @param {Function} func The function to call when content is added.\n */\n function register_content_listener(func) {\n content_ready_listeners.push(func);\n }\n\n /**\n * Indicate that content has been added to the page.\n * \n * All registered Behaviors will locate any matching elements within the\n * provided content. Each Behavior will be isolated to a separate\n * setTimeout call to prevent breaking the whole page.\n * \n * If the page has any alternative frameworks that provide the same\n * facility of notifying JS that content has been added to the page, then\n * that facility should be altered to call this function, and this function\n * should be hotpatched to call that facility. See\n * `register_content_listener` for more information.\n * \n * @param {jQuery|Element} context The content that was added to the page.\n */\n function content_ready(context) {\n var k, i;\n \n function do_later(obj, func) {\n window.setTimeout(func.bind(obj, context), 0);\n }\n \n for (i = 0; i < content_ready_listeners.length; i += 1) {\n do_later(undefined, content_ready_listeners[i]);\n }\n\n for (k in behavior_registry) {\n if (behavior_registry.hasOwnProperty(k)) {\n do_later(behavior_registry[k], behavior_registry[k].content_ready);\n }\n }\n }\n\n /**\n * Indicate that content is about to be removed from the page.\n * \n * This should be called *before* removing the actual elements. Registered\n * Behaviors will stop any animations timers and remove any global\n * references to about-to-be-removed content to prevent it from consuming\n * client resources.\n * \n * If the page has any alternative frameworks that provide the same\n * facility of notifying JS that content will be removed from the page,\n * then that facility should be altered to call this function, and this\n * function should be hotpatched to call that facility.\n * \n * @param {jQuery|Element} context The content that was added to the page.\n */\n function content_removal(context) {\n var k, i;\n \n function do_later(obj, func) {\n window.setTimeout(func.bind(obj, context), 0);\n }\n \n for (k in behavior_registry) {\n if (behavior_registry.hasOwnProperty(k)) {\n do_later(behavior_registry[k], behavior_registry[k].content_removal);\n }\n }\n }\n\n window.document.addEventListener(\"DOMContentLoaded\", function() {\n content_ready(window.document);\n });\n\n Behaviors.register_behavior = register_behavior;\n Behaviors.register_content_listener = register_content_listener;\n Behaviors.content_ready = content_ready;\n Behaviors.content_removal = content_removal;\n}(window.EVASuit.Behaviors));","window.EVASuit = window.EVASuit || {};\nwindow.EVASuit.Behaviors = window.EVASuit.Behaviors || {};\n\nwindow.EVASuit.Behaviors.throttle_single = function() {\n \"use strict\";\n \n /* Throttle an event handler.\n *\n * Returns a function which, no matter how frequently it's called, will\n * only trigger a maximum of once per timeout period. More specifically,\n * the first event will always be processed, then, no events will process\n * until the end of the timeout period. If one or more events occurred\n * during this period, the last event recieved will trigger immediately\n * after the end of the timeout period, as well as restart the throttling\n * period. Any preceding events will be discarded.\n *\n * Not to be confused with a debounce, which only fires the event handler\n * at the end of a string of events spaced closer than the timeout period.\n *\n * The nature of this function means that any passed in function's return\n * value will be discarded.\n */\n function throttle_single(func, timeout) {\n var lastTimeout, afterLastArgs, afterLastThis;\n\n function unthrottle() {\n if (afterLastArgs !== undefined) {\n func.apply(afterLastThis, afterLastArgs);\n afterLastArgs = undefined;\n lastTimeout = window.setTimeout(unthrottle, timeout);\n } else {\n lastTimeout = undefined;\n }\n }\n\n return function () {\n var myThis = this, myArgs = [], i;\n\n for (i = 0; i < arguments.length; i += 1) {\n myArgs.push(arguments[i]);\n }\n\n if (lastTimeout === undefined) {\n func.apply(myThis, myArgs);\n lastTimeout = window.setTimeout(unthrottle, timeout);\n } else {\n afterLastArgs = myArgs;\n afterLastThis = myThis;\n }\n };\n }\n\n return throttle_single;\n}();"]}