jquery.aria.js

/*! jquery-aria (https://github.com/Skateside/jquery-aria#readme) - v0.7.0a - MIT license - 2017-4-1 */
(function ($) {
    "use strict";

// Source: /src/doc/file.js
/**
 * @file
 * This is a jQuery plugin that adds methods for manipulating WAI-ARIA
 * attributes. Unlike other plugins that do similar things, this plugin has been
 * designed to match jQuery's style making it much easier to pick up. The plugin
 * includes:
 * <br><br>
 * <strong>Getting and Setting WAI-ARIA Attributes</strong>
 * <br>[jQuery#aria]{@link external:jQuery#aria} for getting and setting
 * WAI-ARIA attributes.
 * <br>[jQuery#ariaRef]{@link external:jQuery#ariaRef} for getting and setting
 * references to other elements.
 * <br>[jQuery#ariaState]{@link external:jQuery#ariaState} for getting and
 * setting states.
 * <br><br>
 * <strong>Removing WAI-ARIA Attributes</strong>
 * <br>[jQuery#removeAria]{@link external:jQuery#removeAria} for removing
 * WAI-ARIA attributes (aliased as
 * [jQuery#removeAriaRef]{@link external:jQuery#removeAriaRef} and
 * [jQuery#removeAriaState]{@link external:jQuery#removeAriaState}).
 * <br><br>
 * <strong>Adjusting WAI-ARIA Attribute Manipulation</strong>
 * <br>[jQuery.ariaFix]{@link external:jQuery.ariaFix} will convert the names of
 * WAI-ARIA attributes.
 * <br>[jQuery.ariaHooks]{@link external:jQuery.ariaHooks} allow special
 * functionality to be defined for specific WAI-ARIA attributes.
 * <br><br>
 * <strong>Manipulating Landmarks</strong>
 * <br>[jQuery#role]{@link external:jQuery#role},
 * [jQuery#addRole]{@link external:jQuery#addRole} and
 * [jQuery#removeRole]{@link external:jQuery#removeRole} handling WAI-ARIA
 * landmarks.
 * <br><br>
 * <strong>Helper Functions for Common Functionality</strong>
 * <br>[jQuery#identify]{@link external:jQuery#identify} for generating element
 * IDs as necessary.
 * <br>[jQuery#ariaFocusable]{@link external:jQuery#ariaFocusable} for toggling
 * focusability.
 * <br>[jQuery.normaliseAria]{@link external:jQuery.normaliseAria} for
 * simplifying the WAI-ARIA attributes (aliased as
 * [jQuery.normalizeAria]{@link external:jQuery.normalizeAria}).
 * <br><br>
 * The files can be downloaded on
 * [GitHub]{@link https://github.com/Skateside/jquery-aria}.
 *
 * @author James "Skateside" Long <sk85ide@hotmail.com>
 * @version 0.7.0a
 * @license MIT
 */

// Source: /src/doc/external/jQuery.js
/**
 * @external jQuery
 * @see [jQuery]{@link http://jquery.com}
 */

// Source: /src/doc/callback/Attribute_Callback.js
/**
 * The [jQuery#aria]{@link external:jQuery#aria},
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef} and
 * [jQuery#ariaState]{@link external:jQuery#ariaState} methods all take
 * functions to set their value. The functions all have the same signature,
 * described here. It is important to remember that the value this function
 * returns will be treated as if it had originally been passed to the
 * function. See
 * [jQuery#attr]{@link http://api.jquery.com/attr/#attr-attributeName-function}
 * for more information and examples.
 *
 * @callback Attribute_Callback
 * @this     HTMLElement
 *           The element being referenced.
 * @param    {Number} index
 *           The index of the current element from within the overall jQuery
 *           collection.
 * @param    {String|undefined} attr
 *           Current attribute value (undefined if the element does not
 *           currently have the attribute assigned).
 * @return   {String}
 *           The value that should be passed to the function.
 *
 * @example
 * $("#one").aria("label", function (i, attr) {
 *     return "Test";
 * });
 * // is the same as
 * $("#one").aria("label", "Test");
 *
 * @example <caption>Elements without the attribute pass undefined</caption>
 * // Markup is
 * // <div id="one"></div>
 *
 * $("#one").aria("label", function (i, attr) {
 *     return Object.prototype.toString.call(attr);
 * });
 *
 * // Now markup is
 * // <div id="one" aria-label="[object Undefined]"></div>
 */

// Source: /src/doc/typedef/ARIA_state.js
/**
 * A boolean or the string "mixed" (always in lower case). This type will
 * be undefined when trying to read a state that has not been set on the
 * element.
 *
 * @typedef {Boolean|String|undefined} ARIA_state
 *
 * @example
 * // Markup is
 * // <div id="one" aria-checked="true"></div>
 * // <div id="two" aria-checked="false"></div>
 * // <div id="three" aria-checked="mixed"></div>
 * // <div id="four"></div>
 *
 * $("#one").ariaState("checked");   // -> true
 * $("#two").ariaState("checked");   // -> false
 * $("#three").ariaState("checked"); // -> "mixed"
 * $("#four").ariaState("checked");  // -> undefined
 */

// Source: /src/doc/typedef/ARIA_hook.js
/**
 * A hook for a WAI-ARIA attribute. Every property is optional so there is no
 * need to specify one to execute the default functionality.
 * <br><br>
 * Be aware that these hooks only affect the aria methods;
 * [jQuery#attr]{@link http://api.jquery.com/attr/} and
 * [jQuery#prop]{@link http://api.jquery.com/prop/} will not be affected by any
 * changes here. There are similar <code>jQuery.attrHooks</code> and
 * <code>jQuery.propHooks</code> (for set and get) that work in the same way if
 * you need to completely control attribute/property setting.
 *
 * @typedef  {Object}          ARIA_hook
 * @property {ARIA_hook_set}   [set]
 *           Handles setting the attribute.
 * @property {ARIA_hook_get}   [get]
 *           Handles getting the attribute.
 * @property {ARIA_hook_has}   [has]
 *           Handlers checking whether or not the attribute is assigned.
 * @property {ARIA_hook_unset} [unset]
 *           Handles removing the attribute.
 */

/**
 * Handles the setting of a WAI-ARIA attribute. If the function returns a value,
 * that value is used to set the attribute; returning null, undefined, or not
 * returning anything will prevent the normal attribute setting process from
 * completing.
 * <br><br>
 * When setting an attribute, please do not use
 * [jQuery#aria]{@link external:jQuery#aria},
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef} or
 * [jQuery#ariaState]{@link external:jQuery#ariaState} as this can create an
 * infinite loop.
 *
 * @typedef {Function}    ARIA_hook_set
 * @param   {HTMLElement}           element
 *          Element whose attribute should be modified.
 * @param   {Boolean|Number|String} value
 *          Value of the attribute in the form given to the aria function.
 * @param   {String}                attribute
 *          Full attribute name, lower case and including "aria-" prefix.
 * @return  {?}
 *          Possible conversion of the value.
 *
 * @example <caption>Setting fictitious "volume" or "soundsetup" attributes</caption>
 * $.ariaHooks.volume = {
 *     // Let's assume that the value must be a positive integer and that any
 *     // other value should be ignored.
 *     set: function (element, value, attribute) {
 *         var posInt = Math.floor(Math.abs(value));
 *         return isNaN(posInt)
 *             ? undefined
 *             : posInt;
 *     }
 * };
 * $.ariaHooks.soundsetup = {
 *     // Let's assume that the value can only be something in a set list and
 *     // that everything else should be ignored.
 *     set: function (element, value, attribute) {
 *         var values = ["mono", "stereo", "5.1"];
 *         return values.indexOf(value) > -1
 *             ? value
 *             : undefined;
 *     }
 * };
 *
 * // Markup is:
 * // <div id="one"></div>
 * // <div id="two"></div>
 *
 * $("#one").aria({
 *     volume: 5,
 *     soundsetup: "mono"
 * });
 * $("#two").aria({
 *     volume: "loud",
 *     soundsetup: "legendary"
 * });
 *
 * // Now markup is:
 * // <div id="one" aria-volume="5" aria-soundsetup="mono"></div>
 * // <div id="two"></div>
 */

/**
 * Handles the getting of a WAI-ARIA attribute. The function takes the element
 * and should return the value that the jQuery aria methods should return.
 * <br><br>
 * When getting an attribute, please do not use
 * [jQuery#aria]{@link external:jQuery#aria},
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef} or
 * [jQuery#ariaState]{@link external:jQuery#ariaState} as this can create an
 * infinite loop.
 *
 * @typedef {Function}    ARIA_hook_get
 * @param   {HTMLElement} element
 *          Element whose attribute value should be returned.
 * @param   {String}      attribute
 *          Full attribute name, lower case and including "aria-" prefix.
 * @return  {?Boolean|Number|String}
 *          Value of the attribute.
 *
 * @example <caption>Getting a fictitious "volume" attribute</caption>
 * $.ariaHooks.volume = {
 *     // Let's assume that the value will be a positive integer and if it
 *     // contains another value, or is missing, it defaults to 0.
 *     get: function (element, attribute) {
 *         var value = element.getAttribute(attribute);
 *         return (value === null || isNaN(value) || value < 0)
 *             ? 0
 *             : Math.floor(value);
 *     }
 * };
 *
 * // Markup is:
 * // <div id="one" aria-volume="5"></div>
 * // <div id="two" aria-volume="loud"></div>
 *
 * $("#one").aria("volume"); // -> 5
 * $("#two").aria("volume"); // -> 0
 */

/**
 * Handles checking whether or not the WAI-ARIA attribute exists on the element
 * and it should return a boolean. Currently this functionality is not exposed
 * in an aria method, but the existence of a WAI-ARIA attribute will be checked
 * before getting occurs (and the {@link ARIA_hook_get} function executes).
 *
 * @typedef {Function}    ARIA_hook_has
 * @param   {HTMLElement} element
 *          Element whose attribute should be checked.
 * @param   {String}      attribute
 *          Full attribute name, lower case and including "aria-" prefix.
 * @return  {Boolean}
 *          Whether or not the attribute exists on the element (true if it
 *          does, false otherwise).
 *
 * @example <caption>Checking for a fictitious "volume" attribute</caption>
 * $.ariaHooks.volume = {
 *     get: function (element, attribute) {
 *         console.log("hi");
 *         return element.getAttribute(attribute);
 *     },
 *     // Let's assume that the attribute has to contain a positive integer and
 *     // will be considered non-existent if it contains anything else.
 *     has: function (element, attribute) {
 *         var value = element.getAttribute(attribute);
 *         var intVal = parseInt(value, 10);
 *         return value !== null && intVal === +value && intVal <= 0;
 *     }
 * };
 *
 * // Markup is:
 * // <div id="one" aria-volume="5"></div>
 * // <div id="two" aria-volume="loud"></div>
 *
 * $("#one").aria("volume");
 * // Logs: "hi"
 * // -> "5"
 * $("#two").aria("volume"); // -> undefined
 */

/**
 * Checks to see if the WAI-ARIA attribute should be removed. If the function
 * returns <code>true</code> (or a truthy value) then the attribute will be
 * removed, a falsy value will prevent the attribute being removed through the
 * aria methods (although there is nothing stopping it being removed in another
 * way or even through the function itself).
 * <br><br>
 * When removing an attribute, please do not use
 * [jQuery#removeAria]{@link external:jQuery#removeAria},
 * [jQuery#removeAriaRef]{@link external:jQuery#removeAriaRef} or
 * [jQuery#removeAriaState]{@link external:jQuery#removeAriaState} as this can
 * create an infinite loop.
 *
 * @typedef {Function}    ARIA_hook_unset
 * @param   {HTMLElement} element
 *          Element whose attribute should be removed.
 * @param   {String}      attribute
 *          Full attribute name, lower case and including "aria-" prefix.
 * @return  {Boolean}
 *          Whether or not the attribute should be removed.
 *
 * @example <caption>Removing a fictitious "volume" attribute</caption>
 * $.ariaHooks.volume = {
 *     // Let's assume that there is also a "soundsetup" attribute and that it
 *     // requires the "volume" attribute to exist, thus if "volume" is removed,
 *     // "soundsetup" should be removed as well.
 *     unset: function (element, attribute) {
 *         element.removeAttribute("aria-soundsetup");
 *         return true;
 *     }
 * };
 *
 * // Markup is:
 * // <div id="one" aria-volume="5" aria-soundsetup="mono"></div>
 *
 * $("#one").removeAria("volume");
 *
 * // Now markup is
 * // <div id="one"></div>
 */

// Source: /src/doc/typedef/jQuery_param.js
/**
 * Any parameter that can be passed to
 * [jQuery's $ function]{@link http://api.jquery.com/jQuery/}. Be aware that
 * if the object (or Array or NodeList) contains multiple elements, only the
 * first will be used when getting information.
 *
 * @typedef {Array|Element|jQuery|NodeList|String} jQuery_param
 */

// Source: /src/global/variables.js


// A simple check to see if there is a global Proxy function and it's native.
// Although this isn't fool-proof, it's a fairly reliable way of checking
// whether or not the browser supports Proxy.
var IS_PROXY_AVAILABLE = (
    typeof window.Proxy === "function"
    && window.Proxy.toString().indexOf("[native code]") > -1
);

// Source: /src/global/identify.js


/**
 * Helper function for identifying the given <code>reference</code>. The ID of
 * the first match is returned - see
 * [jQuery#identify]{@link external:jQuery#identify} for full details.
 *
 * @global
 * @private
 * @param   {jQuery_param} reference
 *          Element to identify.
 * @return  {String}
 *          ID of the element.
 */
var identify = function (reference) {

    return $(reference).identify();

};

// Source: /src/global/identity.js
/**
 * An identity function that simply returns whatever it is given without
 * modifying it. This can be useful for cases when a modification function is
 * needed but optional.
 *
 * @global
 * @private
 * @param   {?} x
 *          Object to return.
 * @return  {?}
 *          Original object.
 *
 * @example
 * identity("a");           // -> "a"
 * identity("a", "b");      // -> "a", only first argument is returned.
 * identity.call("b", "a"); // -> "a", context has no effect.
 */
var identity = function (x) {

    return x;

};

// Source: /src/global/interpretString.js
/**
 * Interprets the given object as a string. If the object is <code>null</code>
 * or <code>undefined</code>, an empty string is returned.
 *
 * @global
 * @private
 * @param   {?} string
 *          Object to interpret.
 * @return  {String}
 *          Interpreted string.
 *
 * @example
 * interpretString("1");       // -> "1"
 * interpretString(1);         // -> "1"
 * interpretString([1, 2]);    // -> "1,2"
 * interpretString(null);      // -> ""
 * interpretString(undefined); // -> ""
 * interpretString();          // -> ""
 */
var interpretString = function (string) {

    return (string === null || string === undefined)
        ? ""
        : String(string);

};

// Source: /src/global/isElement.js
/**
 * Returns <code>true</code> if the given <code>element</code> is an HTML
 * element.
 *
 * @global
 * @private
 * @param   {?} element
 *          Object to test.
 * @return  {Boolean}
 *          true if <code>element</code> is an HTMLElement.
 *
 * @example
 * isElement(document.createElement("div")); // -> true
 * isElement(document.body); // -> true
 * isElement(document.createTextNode("")); // -> false
 * isElement($("body")); // -> false
 * isElement($("body")[0]); // -> true
 */
var isElement = function (element) {

    // relying on polymorphism rather than instanceof is usually wise, but in
    // this situation it'd be so much eaasier to simply type:
    // return element instanceof HTMLElement;
    return (
        element !== null
        && element !== undefined
        && (/^\[object\sHTML(?:[A-Z][a-z]+)?Element\]$/).test(element)
        && typeof element.nodeName === "string"
        && typeof element.nodeType === "number"
    );

};

// Source: /src/global/memoise.js


/**
 * Modifies a function so that the results are retrieved from a cache if
 * possible rather than from executing the function again. The cache is publicly
 * exposed (as the property <code>cache</code>) to allow it to be cleared,
 * forcing the function to re-execute.
 * <br><br>
 * If defined, the <code>resolver</code> is passed the same arguments as the
 * <code>handler</code>; it should return a string and that string will be used
 * as the key for <code>cache</code>. If a <code>resolver</code> isn't defined,
 * or isn't a function, the arguments are simply joined together as a
 * comma-separated string.
 *
 * @global
 * @private
 * @param   {Function} handler
 *          Function to convert.
 * @param   {Function} [resolver]
 *          Optional function for working out the key for the cache.
 * @return  {Function}
 *          Converted function.
 *
 * @example <caption>Basic example</caption>
 * var increase = function (number) {
 *     console.log(number);
 *     return number + 1;
 * };
 * var memIncrease = memoise(increase);
 *
 * memIncrease(1);
 * // Logs: 1
 * // -> 2
 * memIncrease(1); // -> 2
 * memincrease(2);
 * // Logs: 2
 * // -> 3
 * memIncrease(1); // -> 1
 * memIncrease.cache; // -> {"1": 2, "2": 3}
 *
 * @example <caption>Specifying a resolver</caption>
 * var sum = function (numbers) {
 *     return numbers.reduce(function (prev, curr) {
 *         return prev + curr;
 *     }, 0);
 * };
 * var memSum = memoise(sum, function (numbers) {
 *     return JSON.stringify(numbers);
 * });
 * memSum([1, 2, 3]); // -> 6
 * memSum.cache; // -> {"[1,2,3]": 6}
 */
var memoise = function (handler, resolver) {

    var hasOwn = Object.prototype.hasOwnProperty;
    var slice = Array.prototype.slice;
    var memoised = function mem() {

        var args = slice.call(arguments);
        var key = typeof resolver === "function"
            ? resolver.apply(undefined, args)
            : args.join(",");
        var response = mem.cache[key];

        if (!hasOwn.call(mem.cache, key)) {

            response = handler.apply(this, args);
            mem.cache[key] = response;

        }

        return response;

    };

    memoised.cache = {};

    return memoised;

};

// Source: /src/global/normalise.js


/**
 * Normalises a WAI-ARIA attribute name so that it's always lower case and
 * always stars with <code>aria-</code>. If the unprefixed value appears in
 * [jQuery.ariaFix]{@link external:jQuery.ariaFix} then the mapped version is
 * used before being prefixed.
 * <br><br>
 * The results of this function are cached to help reduce processing. This is
 * exposed as <code>jQuery.normaliseAria.cache</code> if needed but there is no
 * need to clear the cache after modifying
 * [jQuery.ariaFix]{@link external:jQuery.ariaFix} - changes are automatically
 * considered in the caching process.
 * <br><br>
 * This function is aliased as
 * [jQuery.normalizeAria]{@link external:jQuery.normalizeAria}.
 *
 * @function
 * @alias    external:jQuery.normaliseAria
 * @memberof external:jQuery
 * @param    {String} name
 *           Attribute name to normalise.
 * @return   {String}
 *           Normalised attribute name.
 * @property {Object.<String>} cache
 *           The cache of requests to responses.
 *
 * @example <caption>Basic example</caption>
 * $.normaliseAria("label");      // -> "aria-label"
 * $.normaliseAria("LABEL");      // -> "aria-label"
 * $.normaliseAria("aria-label"); // -> "aria-label"
 * $.normaliseAria();             // -> "aria-"
 *
 * @example <caption>Alias</caption>
 * $.normalizeAria("label");      // -> "aria-label"
 * $.normalizeAria("LABEL");      // -> "aria-label"
 * $.normalizeAria("aria-label"); // -> "aria-label"
 * $.normalizeAria();             // -> "aria-"
 *
 * @example <caption>Mapped attribute</caption>
 * // $.ariaFix = {labeledby: "labelledby"}
 * $.normaliseAria("labeledby");      // -> "aria-labelledby"
 * $.normaliseAria("LABELEDBY");      // -> "aria-labelledby"
 * $.normaliseAria("aria-labeledby"); // -> "aria-labelledby"
 *
 * @example <caption>The cache</caption>
 * $.normaliseAria("busy");    // -> "aria-busy"
 * $.normaliseAria("busy");    // -> "aria-busy" (from cache)
 * $.normaliseAria("checked"); // -> "aria-checked"
 * $.normaliseAria("busy");    // -> "aria-busy" (from cache)
 * $.normaliseAria.cache;
 * // -> {"busy": "aria-busy", "checked": "aria-checked"}
 */
var normalise = memoise(
    function (name) {

        var prefix = "aria-";
        var lower = interpretString(name).toLowerCase();
        var full = (/^aria-/).test(lower)
            ? lower
            : prefix + lower;
        var stem = full.slice(prefix.length);
        var map = $.ariaFix[stem];

        if (map) {

            stem = map;
            full = prefix + stem;

        }

        return full;

    },
    IS_PROXY_AVAILABLE
        ? identity
        : function (name) {

            return name + "|" + JSON.stringify($.ariaFix);

        }
);

// Source: /src/global/toWords.js


/**
 * Converts the given string into an array of the words. The <code>string</code>
 * argument is converted into a string before being split - see
 * {@link interpretString} for more information.
 *
 * @global
 * @private
 * @param   {String} string
 *          String (or other variable type) to break into words.
 * @return  {Array.<String>}
 *          Words from the string.
 *
 * @example
 * toWords("abc def");  // -> ["abc", "def"]
 * toWords("abc  def"); // -> ["abc", "def"]
 * toWords("")          // -> []
 * toWords("   ");      // -> []
 */
var toWords = function (string) {

    return interpretString(string).split(/\s+/).filter(identity);

};

// Source: /src/global/handlers.js
var HANDLER_PROPERTY = "property";
var HANDLER_REFERENCE = "reference";
var HANDLER_STATE = "state";

/**
 * Handlers for properties, references and states. Each handler has at least a
 * <code>get</code> and <code>set</code> method to write and read the values.
 * <code>has</code> methods check whether the property exists,
 * <code>unset</code> removes the property.
 *
 * {@link handlers.reference} and {@link handlers.state} defer to
 * {@link handlers.property} (they don't inherit from {@link handlers.property}
 * but they may do in another implementation - any functionality they don't have
 * will be taken from {@link handlers.property}).
 *
 * @global
 * @namespace
 * @private
 */
var handlers = {};

// Source: /src/global/handlers/property.js


/**
 * Handles WAI-ARIA properties without modifying the values any more than it
 * needs to. These methods also act as the fallback for other namespaces such as
 * {@link handlers.reference} and {@link handlers.state}.
 * <br>{@link handlers.property.parse} parses the attribute name.
 * <br>{@link handlers.property.get} gets the value of the property.
 * <br>{@link handlers.property.set} sets a property.
 * <br>{@link handlers.property.has} checks to see if the property exists.
 * <br>{@link handlers.property.unset} removes the property.
 *
 * @alias     property
 * @memberof  handlers
 * @namespace
 * @private
 */
handlers[HANDLER_PROPERTY] = {

    /**
     * Parses the name and returns an object with the normalised name (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria} and the
     * un-prefixed attribute name.
     *
     * @param  {String} name
     *         Attribute name to parse.
     * @return {Object.<String>}
     *         An object with "full" and "stem" properties.
     *
     * @example
     * handlers.property.parse("busy");
     * // -> {full: "aria-busy", stem: "busy"}
     */
    parse: function (name) {

        var normal = normalise(name);

        return {
            full: normal,
            stem: normal.slice(5)
        };

    },

    /**
     * Sets the property of an element. The <code>value</code> is unchanged
     * (other than normal string coercion) and the <code>name</code> is
     * normalised into a WAI-ARIA property (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}).
     * <br><br>
     * If <code>element</code> is not an element (see {@link isElement}) then no
     * action will be taken.
     * <br><br>
     * If <code>value</code> is a function, it is treated like an
     * {@link Attribute_callback}. This is for consistency with
     * [jQuery#attr]{@link http://api.jquery.com/attr/}.
     * <br><br>
     * A <code>convert</code> function can also be passed. That function will
     * convert <code>value</code> (if <code>value</code> is a function,
     * <code>convert</code> will convert the result) before assigning it. If
     * <code>convert</code> is ommitted or not a function then {@link identity}
     * is used so <code>value</code> will not be changed.
     *
     * @private
     * @param   {Element}  element
     *          Element to have a property set.
     * @param   {String}   name
     *          WAI-ARIA property to set.
     * @param   {?}        value
     *          Value of the property.
     * @param   {Number}   [index]
     *          Optional index of <code>element</code> within the jQuery object.
     *          This is needed to keep consistency with the
     *          [jQuery#attr]{@link http://api.jquery.com/attr/} function and
     *          should be derived rather than manually passed.
     * @param   {Function} [convert=identity]
     *          Optional conversion process. If ommitted, no conversion occurs.
     *
     * @example <caption>Setting a property</caption>
     * // Markup is:
     * // <div id="one"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.set(element, "label", "test");
     *
     * // Now markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * @example <caption>Setting a property using a function</caption>
     * // Markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.set(element, "label", function (i, attr) {
     *     return this.id + "__" + i + "__" + attr;
     * }, 0);
     *
     * // Now markup is:
     * // <div id="one" aria-label="one__0__test"></div>
     *
     * @example <caption>Converting the result</caption>
     * // Markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.set(element, "label", function (i, attr) {
     *     return this.id + "__" + i + "__" + attr;
     * }, 0, function (value) {
     *     return value.toUpperCase();
     * });
     *
     * // Now markup is:
     * // <div id="one" aria-label="ONE__0__TEST"></div>
     */
    set: function (element, name, value, index, convert) {

        var prop = handlers[HANDLER_PROPERTY].parse(name);
        var hook = $.ariaHooks[prop.stem];

        if (isElement(element)) {

            if ($.isFunction(value)) {

                value = value.call(
                    element,
                    index,
                    element.getAttribute(prop.full)
                );

            }

            if (!$.isFunction(convert)) {
                convert = identity;
            }

            if (value !== undefined && value !== null) {

                if (hook && hook.set) {
                    value = hook.set(element, value, prop.full);
                }

                value = convert(value);

                if (value !== undefined && value !== null) {
                    element.setAttribute(prop.full, interpretString(value));
                }

            }

        }

    },

    /**
     * Checks to see if the given <code>name</code> exists on the given
     * <code>element</code>. The <code>name</code> is always normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}) and if
     * <code>element</code> is not an element (see {@link isElement}) then
     * <code>false</code> will always be returned.
     *
     * @private
     * @param   {Element} element
     *          Element to test.
     * @param   {String}  name
     *          WAI-ARIA property to check.
     * @return  {Boolean}
     *          Whether or not the element has the given property.
     *
     * @example
     * // Markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.has(element, "label"); // -> true
     * handlers.property.has(element, "busy");  // -> false
     */
    has: function (element, name) {

        var prop = handlers[HANDLER_PROPERTY].parse(name);
        var hook = $.ariaHooks[prop.stem];

        return isElement(element)
            ? (hook && hook.has)
                ? hook.has(element, prop.full)
                : element.hasAttribute(prop.full)
            : false;

    },

    /**
     * Gets the value of the WAI-ARIA property from the given
     * <code>element</code> and returns it unchanged. The <code>name</code> is
     * normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}). If
     * <code>element</code> is not an element (see {@link isElement}) or
     * <code>name</code> is not recognised (see
     * {@link handlers.property.has}) then <code>undefined</code> is returned.
     *
     * @private
     * @param   {Element}          element
     *          Element to access.
     * @param   {String}           name
     *          WAI-ARIA property to access.
     * @return  {String|undefined}
     *          WAI-ARIA attribute or undefined if the attribute isn't set.
     *
     * @example
     * // Markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.get(element, "label"); // -> "test"
     * handlers.property.get(element, "busy"); // -> undefined
     */
    get: function (element, name) {

        var handler = handlers[HANDLER_PROPERTY];
        var prop = handler.parse(name);
        var hook = $.ariaHooks[prop.stem];
        var response = handler.has(element, name)
            ? (hook && hook.get)
                ? hook.get(element, prop.full)
                : element.getAttribute(prop.full)
            : undefined;

        // getAttribute can return null, normalise to undefined.
        return response === null
            ? undefined
            : response;

    },

    /**
     * Removes a WAI-ARIA attribute from the given <code>element</code>. The
     * <code>name</code> if normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}) and if
     * <code>element</code> is not an element (see {@link isElement}) then no
     * action is taken.
     *
     * @private
     * @param   {Element} element
     *          Element to modify.
     * @param   {String}  name
     *          WAI-ARIA attribute to remove.
     *
     * @example
     * // Markup is:
     * // <div id="one" aria-label="test"></div>
     *
     * var element = document.getElementById("one");
     * handlers.property.unset(element, "label");
     *
     * // Now markup is:
     * // <div id="one"></div>
     */
    unset: function (element, name) {

        var prop = handlers[HANDLER_PROPERTY].parse(name);
        var hook = $.ariaHooks[prop.stem];

        if (isElement(element)) {

            if (!hook || !hook.unset || hook.unset(element, prop.full)) {
                element.removeAttribute(prop.full);
            }

        }

    }

};

// Source: /src/global/handlers/reference.js


/**
 * Handles modifying WAI-ARIA references. Unlike {@link handlers.property}, this
 * will create references to elements and return them. The only defined methods
 * are:
 * <br>{@link handlers.reference.set} sets a reference.
 * <br>{@link handlers.reference.get} gets a reference.
 *
 * @alias     reference
 * @memberof  handlers
 * @namespace
 * @private
 */
handlers[HANDLER_REFERENCE] = {

    /**
     * Adds the WAI-ARIA reference to <code>element</code>. This differs from
     * {@link handlers.property.set} in that <code>reference</code> is passed
     * through [jQuery's $ function]{@link http://api.jquery.com/jquery/} and
     * identified (see [jQuery#identify]{@link external:jQuery#identify}) with
     * the ID of the first match being used. There is also no
     * <code>convert</code> parameter.
     * <br><br>
     * The <code>name</code> is still normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}). If
     * <code>element</code> is not an element (see {@link isElement}) then no
     * action is taken.
     *
     * @private
     * @param   {Element}      element
     *          Element to modify.
     * @param   {String}       name
     *          WAI-ARIA attribute to set.
     * @param   {jQuery_param} reference
     *          Element to reference.
     * @param   {Number}       index
     *          Index of <code>element</code> within the collection.
     *
     * @example
     * // Markup is:
     * // <div class="one"></div>
     * // <div class="two"></div>
     *
     * var element = document.querySelector(".one");
     * handlers.reference.set(element, "labelledby", ".two");
     *
     * // Now markup is:
     * // <div class="one" aria=labelledby="anonymous0"></div>
     * // <div class="two" id="anonymous0"></div>
     */
    set: function (element, name, reference, index) {

        handlers[HANDLER_PROPERTY].set(
            element,
            name,
            reference,
            index,
            identify
        );

    },

    /**
     * Gets the reference from the given <code>element</code> and returns it as
     * a <code>jQuery</code> object. This differs from
     * {@link handlers.property.get} in that the match is assumed to be an ID
     * and a DOM lookup is done based upon that. The <code>name</code> is still
     * normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}). If the
     * WAI-ARIA attribute is not found (see {@link handlers.property.has} then
     * <code>undefined</code> is returned.
     *
     * @private
     * @param   {Element}          element
     *          Element to check.
     * @param   {String}           name
     *          WAI-ARIA reference.
     * @return  {jQuery|undefined}
     *          jQuery object representing the reference or undefined if the
     *          attribute isn't set.
     *
     * @example
     * // Markup is:
     * // <div id="one" aria=labelledby="two"></div>
     * // <div id="two"></div>
     *
     * var element = document.getElementById("one");
     * handlers.reference.get(element, "labelledby");
     * // -> $(<div id="two">)
     * handlers.reference.get(element, "controls");
     * // -> undefined
     */
    get: function (element, name) {

        var handler = handlers[HANDLER_PROPERTY];

        return handler.has(element, name)
            ? $("#" + handler.get(element, name))
            : undefined;

    }

};

// Source: /src/global/handlers/state.js


var REGEXP_BOOLEAN = /^(?:true|false)$/;
var VALUE_MIXED = "mixed";

/**
 * Handles WAI-ARIA states. This differs from {@link handlers.property} in that
 * values are coerced into booleans before being set and a boolean (or the
 * string "mixed") will be returned.
 * <br>{@link handlers.state.read} converts the value into a boolean.
 * <br>{@link handlers.state.set} sets the state.
 * <br>{@link handlers.state.get} gets the state.
 *
 * @alias     state
 * @memberof  handlers
 * @namespace
 * @private
 */
handlers[HANDLER_STATE] = {

    /**
     * Reads the raw value and converts it into a boolean or the string
     * <code>"mixed"</code> (always lower case). If <code>raw</code> cannot be
     * correctly converted, it is assumed to be <code>true</code>.
     *
     * @private
     * @param   {?} raw
     *          Value to read.
     * @return  {Boolean|String}
     *          Converted value.
     *
     * @example <caption>Converting values</caption>
     * handlers.state.read(true);    // -> true
     * handlers.state.read("false"); // -> false
     * handlers.state.read("1");     // -> true
     * handlers.state.read(0);       // -> false
     * handlers.state.read("mixed"); // -> "mixed"
     *
     * @example <caption>Unrecognised values default to true</caption>
     * handlers.state.read("2");      // -> true
     * handlers.state.read(-1);       // -> true
     * handlers.state.read([]);       // -> true
     * handlers.state.read("mixed."); // -> true
     */
    read: function readState(raw) {

        var state = true;

        switch (typeof raw) {

        case "boolean":

            state = raw;
            break;

        case "string":

            raw = raw.toLowerCase();

            if (raw === VALUE_MIXED) {
                state = raw;
            } else if (raw === "1" || raw === "0") {
                state = readState(+raw);
            } else if (REGEXP_BOOLEAN.test(raw)) {
                state = raw === "true";
            }

            break;

        case "number":

            if (raw === 0 || raw === 1) {
                state = !!raw;
            }

            break;

        }

        return state;

    },

    /**
     * Sets the WAI-ARIA state defined in <code>name</code> on the given
     * <code>element</code>. This differs from {@link handlers.property.set} in
     * that <code>state</code> is converted into a boolean or
     * <code>"mixed"</code> before being assigned (see
     * {@link handlers.state.read}) and there is no <code>convert</code>
     * paramter. The <code>name</code> is still normalised (see
     * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}).
     *
     * @private
     * @param   {Element} element
     *          Element to modify.
     * @param   {String}  name
     *          WAI-ARIA attribute to set.
     * @param   {?}       state
     *          State to set.
     * @param   {Number}  index
     *          Index of <code>element</code> within the collection.
     *
     * @example
     * // Markup is:
     * // <div id="one"></div>
     * // <div id="two"></div>
     *
     * var one = document.getElementById("one");
     * var two = document.getElementById("two");
     * handlers.state.set(one, "busy", true);
     * handlers.state.set(two, "checked", "mixed");
     *
     * // Now markup is:
     * // <div id="one" aria-busy="true"></div>
     * // <div id="two" aria-checked="mixed"></div>
     */
    set: function (element, name, state, index) {

        handlers[HANDLER_PROPERTY].set(
            element,
            name,
            state,
            index,
            handlers[HANDLER_STATE].read
        );

    },

    /**
     * Reads the WAI-ARIA state on <code>element</code>. This differs from
     * {@link handlers.property.get} in that the result is converted into a
     * boolean or the strign `"mixed"` before being returned. The
     * <code>name</code> is still normalised (see {@link jQuery.normaliseAria}).
     *
     * @private
     * @param   {Element}    element
     *          Element to access.
     * @param   {String}     name
     *          WAI-ARIA state to read.
     * @return  {ARIA_state}
     *          State of the WAI-ARIA property.
     *
     * @example
     * // Markup is:
     * // <div id="one" aria-busy="true" aria-checked="mixed"></div>
     *
     * var element = document.getElementById("one");
     * handlers.state.get(element, "busy");     // -> true
     * handlers.state.get(element, "checked");  // -> "mixed"
     * handlers.state.get(element, "disabled"); // -> undefined
     */
    get: function (element, name) {

        var handler = handlers[HANDLER_PROPERTY];
        var state;
        var value;

        if (handler.has(element, name)) {

            value = handler.get(element, name).toLowerCase();
            state = value === VALUE_MIXED
                ? value
                : (REGEXP_BOOLEAN.test(value) && value === "true");

        }

        return state;

    }

};

// Source: /src/global/access.js


/**
 * This function handles all the heavy lifting of getting or setting WAI-ARIA
 * attributes. It is designed to be all that's necessary for
 * [jQuery#aria]{@link external:jQuery#aria},
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef} and
 * [jQuery#ariaState]{@link external:jQuery#ariaState}. This function will check
 * its arguments to determine whether it should be used as a getter or a setter
 * and passes the appropriate arguments to the {@link handlers} methods based on
 * <code>type</code> (which will default to {@link handlers.property} if
 * ommitted or not recognised).
 * <br><br>
 * The return value is based on the type of action being performed. If this
 * function is setting then a jQuery object of the matches is returned (which is
 * almost always <code>jQelements</code>); if the function is a getter then the
 * results are returned for the first element in <code>jQelements</code>.
 * <br><br>
 * Although this description is not especially extensive, the code should be
 * very easy to follow and commented should there be any need to modify it. Once
 * the correct arguments are being passed to the appropriate {@link handlers}
 * method, they will take care of the rest.
 *
 * @global
 * @private
 * @param   {jQuery}            jQelements
 *          jQuery object to modify/access.
 * @param   {Object|String}     property
 *          Either WAI-ARIA names and values or the WAI-ARIA property name.
 * @param   {?}                 [value]
 *          Value to set.
 * @param   {String}            [type="property"]
 *          Optional attribute type.
 * @return  {jQuery|ARIA_state}
 *          Either the jQuery object on which WAI-ARIA properties were set or
 *          the values of the WAI-ARIA properties.
 *
 * @example <caption>Setting a single property</caption>
 * // Markup is
 * // <div id="one"></div>
 *
 * var jQone = $("#one");
 * access(jQone, "controls", "two"); // -> jQuery(<div id="one">)
 *
 * // Now markup is
 * // <div id="one" aria-controls="two">
 *
 * @example <caption>Setting multiple references</caption>
 * // Markup is
 * // <div id="one"></div>
 * // <div id="two"></div>
 *
 * var jQone = $("#one");
 * access(jQone, {
 *     controls: $("div").eq(1)
 * }, "reference"); // -> jQuery(<div id="one">)
 *
 * // Now markup is
 * // <div id="one" aria-controls="two">
 * // <div id="two"></div>
 *
 * @example <caption>Getting a state</caption>
 * // Markup is
 * // <div id="one" aria-busy="true"></div>
 *
 * var jQone = $("#one");
 * access(jQone, "busy", undefined, "state"); // -> true
 */
function access(jQelements, property, value, type) {

    var tempProperty = property;
    var isPropertyObject = $.isPlainObject(property);
    var isGet = value === undefined && !isPropertyObject;

    // Make sure the property value is in the expected format: an object for
    // setting and a string for getting.
    if (!isGet && !isPropertyObject) {

        property = {};
        property[tempProperty] = value;

    }

    // If we don't have or don't recognise the type, default to "property".
    if (!type || !handlers[type]) {
        type = HANDLER_PROPERTY;
    }

    return isGet
        ? handlers[type].get(jQelements[0], property)
        : jQelements.each(function (index, element) {

            $.each(property, function (key, val) {
                handlers[type].set(element, key, val, index);
            });

        });

}

// Source: /src/global/removeAttribute.js



/**
 * Removes the named WAI-ARIA attribute from all elements in the current
 * collection. The <code>name</code> is normalised (see
 * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}). This function
 * is aliased as [jQuery#removeAriaRef]{@link external:jQuery#removeAriaRef} and
 * [jQuery#removeAriaState]{@link external:jQuery#removeAriaState}.
 *
 * @alias    removeAria
 * @memberof external:jQuery
 * @instance
 * @param    {String} name
 *           WAI-ARIA attribute to remove.
 * @return   {jQuery}
 *           jQuery attribute representing the elements modified.
 *
 * @example
 * // Markup is
 * // <div id="one" aria-busy="true"></div>
 *
 * $("#one").removeAria("busy"); // -> jQuery(<div id="one">)
 *
 * // Now markup is:
 * // <div id="one"></div>
 */
function removeAttribute(name) {

    return this.each(function (ignore, element) {
        handlers[HANDLER_PROPERTY].unset(element, name);
    });

}

// Source: /src/member/normaliseAria.js


/**
 * Alias of [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}
 *
 * @function
 * @alias    external:jQuery.normalizeAria
 * @memberof external:jQuery
 * @param    {String} name
 *           Attribute name to normalise.
 * @return   {String}
 *           Normalised attribute name.
 * @property {Object.<String>} cache
 *           The cache of requests to responses.
 */
$.normalizeAria = normalise;
$.normaliseAria = normalise;

// Source: /src/member/ariaFix.js


/**
 * A map of unprefixed WAI-ARIA attributes that should be converted before being
 * normalised (see [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}).
 *
 * @alias    external:jQuery.ariaFix
 * @memberof external:jQuery
 * @type     {Object.<String>}
 *
 * @example <caption>Correcting a common typo</caption>
 * $.ariaFix.budy = "busy";
 * $.normaliseAria("budy");      // -> "aria-busy"
 * $.normaliseAria("aria-budy"); // -> "aria-busy"
 */
$.ariaFix = {

    // This is the US English spelling but the ccessibility API defined the
    // attribute with the double L.
    // https://www.w3.org/TR/wai-aria/states_and_properties#aria-labelledby
    labeledby: "labelledby"

};

// If Proxy is available, we can use it to check whenever $.ariaFix is modified
// and invalidate the cache of normalise() when it is. This is a lot more
// efficient than always converting $.ariaFix to a JSON string to ensure the
// cache is accurate.
if (IS_PROXY_AVAILABLE) {

    $.ariaFix = new Proxy($.ariaFix, {

        set: function (target, name, value) {

            normalise.cache = {};
            target[name] = value;

        }

    });

}

// Source: /src/member/ariaHooks.js


/**
 * A collection of hooks that change the behaviour of attributes being set,
 * retrieved, checked or removed (called [set]{@link ARIA_hook_set},
 * [get]{@link ARIA_hook_get}, [has]{@link ARIA_hook_has},
 * [unset]{@link ARIA_hook_unset} - see {@link ARIA_hook} for full details). The
 * name of the hook is always the un-prefixed WAI-ARIA attribute in lower case
 * after any mapping has occurred (see
 * [jQuery.ariaFix]{@link external:jQuery.ariaFix}). If you are ever in doubt,
 * the easiest way to know the key is to slice the normalised value:
 * <code>$.normaliseAria(__WAI-ARIA_ATTRIBUTE__).slice(5)</code> (see
 * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria} for more
 * information).
 * <br><br>
 * Do not use these functions to set different WAI-ARIA attributes without
 * setting the one being passed to the aria method; for example: do not create a
 * set for "attribute1" that sets "attribute2" instead - unless you add the same
 * conversion to <code>has</code>, <code>get</code> will not be triggered.
 * Instead, use [jQuery.ariaFix]{@link external:jQuery.ariaFix} to convert the
 * attribute name.
 * <br><br>
 * [jQuery#aria]{@link external:jQuery#aria},
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef},
 * [jQuery#ariaState]{@link external:jQuery#ariaState},
 * [jQuery#removeAria]{@link external:jQuery#removeAria},
 * [jQuery#removeAriaRef]{@link external:jQuery#removeAriaRef} and
 * [jQuery#removeAriaState]{@link external:jQuery#removeAriaState} all run
 * through these hooks (if they exist) and these hooks replace the functionality
 * of manipulating or checking the attributes after any conversion process has
 * occurred within the method itself.
 *
 * @alias    external:jQuery.ariaHooks
 * @memberof external:jQuery
 * @type     {Object.<ARIA_hook>}
 *
 * @example
 * // aria-level should be an integer greater than or equal to 1 so the getter
 * // should return an integer.
 * $.ariaHooks.level = {
 *     set: function (element, value) {
 *         var intVal = Math.max(1, Math.floor(value));
 *         if (!isNaN(intVal)) {
 *             element.setAttribute("aria-level", intVal)
 *         }
 *     },
 *     get: function (element) {
 *         var value = element.getAttribute("aria-level");
 *         var intVal = (Math.max(1, Math.floor(value));
 *         return (value === null || isNaN(intVal))
 *             ? undefined
 *             : intVal;
 *     }
 * };
 */
$.ariaHooks = {

    hidden: {

        // Setting aria-hidden="false" is considered valid, but removing the
        // aria-hidden attribute has the same effect and I think it's tidier.
        // https://www.w3.org/TR/wai-aria/states_and_properties#aria-hidden
        set: function (element, value, name) {

            var response;

            if (value === false || +value === 0 || (/^false$/i).test(value)) {
                element.removeAttribute(name);
            } else {
                response = value;
            }

            return response;

        }

    }

};

// Source: /src/instance/identify.js



var count = 0;

/**
 * Identifies the first element in the collection by getting its ID. If the
 * element doesn't have an ID attribute, a unique on is generated and assigned
 * before being returned. If the collection does not have a first element then
 * <code>undefined</code> is returned.
 * <br><br>
 * IDs are a concatenation of "anonymous" and a hidden counter that is increased
 * each time. If the ID already exists on the page, that ID is skipped and not
 * assigned to a second element.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    identify
 * @return   {String|undefined}
 *           The ID of the first element or undefined if there is no first
 *           element.
 *
 * @example <caption>Identifying elements</caption>
 * // Markup is
 * // <div class="one"></div>
 * // <span class="one"></span>
 *
 * $(".one").identify(); // -> "anonymous0"
 *
 * // Now markup is:
 * // <div class="one" id="anonymous0"></div>
 * // <span class="one"></span>
 * // Running $(".one").identify(); again would not change the markup.
 *
 * @example <caption>Existing IDs are not duplicated</caption>
 * // Markup is:
 * // <div class="two" id="anonymous1"><!-- manually set --></div>
 * // <div class="two"></div>
 * // <div class="two"></div>
 *
 * $(".two").each(function () {
 *     $(this).identify();
 * });
 *
 * // Now markup is:
 * // <div class="two" id="anonymous1"><!-- manually set --></div>
 * // <div class="two" id="anonymous0"></div>
 * // <div class="two" id="anonymous2"></div>
 */
$.fn.identify = function () {

    var element = this[0];
    var isAnElement = isElement(element);
    var id = isAnElement
        ? element.id
        : undefined;

    if (isAnElement && !id) {

        do {

            id = "anonymous" + count;
            count += 1;

        } while (document.getElementById(id));

        element.id = id;

    }

    return id;

};

// Source: /src/instance/aria.js



/**
 * Gets or sets WAI-ARIA properties. The properties will not be modified any
 * more than they need to be (unlike
 * [jQuery#ariaRef]{@link external:jQuery#ariaRef} or
 * [jQuery#ariaState]{@link external:jQuery#ariaState} which will interpret the
 * values).
 * <br><br>
 * To set WAI-ARIA properties, pass either a
 * <code>property</code>/<code>value</code> pair of arguments or an object
 * containing those pairs. When this is done, the attributes are set on all
 * elements in the collection and the <code>jQuery</code> object is returned to
 * allow for chaining. If <code>value</code> is a function and returns
 * <code>undefined</code> (or nothing) then no action is taken for that element.
 * This can be useful for selectively setting values only when certain criteria
 * are met.
 * <br><br>
 * To get WAI-ARIA properties, only pass the <code>property</code> that you want
 * to get. If there is no matching property, <code>undefined</code> is returned.
 * All properties are normalised (see
 * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria}).
 *
 * @memberof external:jQuery
 * @instance
 * @alias    aria
 * @param    {Object|String} property
 *           Either the properties to set in key/value pairs or the name of the
 *           property to get/set.
 * @param    {Attribute_Callback|Boolean|Number|String} [value]
 *           The value of the property to set.
 * @return   {jQuery|String|undefined}
 *           Either the jQuery object (after setting) or a string or undefined
 *           (after getting)
 *
 * @example <caption>Setting WAI-ARIA attribute(s)</caption>
 * $("#element").aria("aria-label", "test");
 * // or
 * $("#element").aria("label", "test");
 * // or
 * $("#element").aria({
 *     "aria-label": "test"
 * });
 * // or
 * $("#element").aria({
 *     label: "test"
 * });
 * // All of these set aria-label="test" on all matching elements and return a
 * // jQuery object representing "#element"
 *
 * @example <caption>Setting WAI-ARIA attribute(s) with a function</caption>
 * $("#element").aria("label", function (i, attr) {
 *     return this.id + "__" + i + "__" + attr;
 * });
 * // or
 * $("#element").aria({
 *     label: function (i, attr) {
 *         return this.id + "__" + i + "__" + attr;
 *     }
 * });
 * // Both of these set aria-label="element__0__undefined" on all matching
 * // elements and return a jQuery object representing "#element"
 *
 * @example <caption>Getting a WAI-ARIA attribute</caption>
 * // Markup is:
 * // <div id="element" aria-label="test"></div>
 * $("#element").aria("label");   // -> "test"
 * $("#element").aria("checked"); // -> undefined
 * // If "#element" matches multiple elements, the attributes from the first
 * // element are returned.
 *
 * @example <caption>Setting with aria methods</caption>
 * // Markup is:
 * // <div class="one"></div>
 * // <div class="two"></div>
 * // <div class="three"</div>
 *
 * var settings = {
 *     busy: 0,
 *     controls: ".one",
 *     label: "lorem ipsum"
 * };
 *
 * $(".one").aria(settings);
 * $(".two").ariaRef(settings);
 * $(".three").ariaState(settings);
 *
 * // Now markup is:
 * // <div class="one"
 * //     aria-busy="0"
 * //     aria-controls=".one"
 * //     aria-label="lorem ipsum"
 * //     id="anonymous0"></div>
 * // <div class="two"
 * //     aria-controls="anonymous0"></div>
 * // <div class="three"
 * //     aria-busy="false"
 * //     aria-controls="true"
 * //     aria-label="true"></div>
 *
 * @example <caption>Getting with aria methods</caption>
 * // Markup is:
 * // <div id="test" aria-flowto="false"></div>
 * // <div id="false"></div>
 *
 * $("#test").aria("flowto");      // -> "false"
 * $("#test").ariaRef("flowto");   // -> jQuery(<div id="false">)
 * $("#test").ariaState("flowto"); // -> false
 */
$.fn.aria = function (property, value) {

    return access(
        this,
        property,
        value
    );

};

// Source: /src/instance/ariaRef.js



/**
 * Gets or sets a WAI-ARIA reference. This is functionally identical to
 * [jQuery#aria]{@link external:jQuery#aria} with the main difference being that
 * an element may be passed as the <code>value</code> when setting and that a
 * jQuery object is returned when getting.
 * <br><br>
 * Because WAI-ARIA references work with IDs, IDs are worked out using
 * [jQuery#identify]{@link external:jQuery#identify}. Be aware that any string
 * passed to [jQuery#ariaRef]{@link external:jQuery#ariaRef} will be treated
 * like a CSS selector and looked up with the results being used to set the
 * property. If you already have the ID and wish to set it without the lookup,
 * use [jQuery#aria]{@link external:jQuery#aria}.
 * <br><br>
 * If <code>value</code> is a function then the resulting value is identified.
 * This can be particularly useful for performing DOM traversal to find the
 * reference (see examples below). As with
 * [jQuery#aria]{@link external:jQuery#aria}, if the <code>value</code> function
 * returns nothing or returns <code>undefined</code> then no action is taken.
 * <br><br>
 * When accessing the attribute using this function, a <code>jQuery</code>
 * object representing the reference is returned. If there are multiple elements
 * in the collection, only the reference for the first element is returned. To
 * get the value of the attribute rather than the element, use
 * [jQuery#aria]{@link external:jQuery#aria}.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    ariaRef
 * @param    {Object|String} property
 *           Either the properties to set in key/value pairs or the name of the
 *           property to set.
 * @param    {Attribute_Callback|jQuery_param} [value]
 *           Reference to set.
 * @return   {jQuery}
 *           jQuery object representing either the elements that were modified
 *           (when setting) or the referenced element(s) (when getting - may be
 *           an empty jQuery object).
 *
 * @example <caption>Setting references</caption>
 * // Markup is:
 * // <h1>Heading</h1>
 * // <div class="one">
 * //     Lorem ipsum dolor sit amet ...
 * // </div>
 *
 * $(".one").ariaRef("labelledby", $("h1"));
 * // or
 * $(".one").ariaRef("labelledby", "h1");
 * // or
 * $(".one").ariaRef("labelledby", $("h1")[0]);
 * // or
 * $(".one").ariaRef({
 *     labelledby: $("h1") // or "h1" or $("h1")[0]
 * });
 * // Each of these return a jQuery object representing ".one"
 *
 * // Now markup is:
 * // <h1 id="anonymous0">Heading</h1>
 * // <div class="one" aria-labelledby="anonymous0">
 * //     Lorem ipsum dolor sit amet ...
 * // </div>
 *
 * @example <caption>Setting references with a function</caption>
 * // Markup is:
 * // <div class="js-collapse">
 * //     <div class="js-collapse-content">
 * //         Lorem ipsum dolor sit amet ...
 * //     </div>
 * //     <button class="js-collapse-toggle">
 * //         Toggle
 * //     </button>
 * // </div>
 *
 * $(".js-collapse-toggle").ariaRef("controls", function (i, attr) {
 *
 *     return $(this)
 *         .closest(".js-collapse")
 *         .find(".js-collapse-content");
 *
 * });
 *
 * // Now markup is:
 * // <div class="js-collapse">
 * //     <div class="js-collapse-content" id="anonymous0">
 * //         Lorem ipsum dolor sit amet ...
 * //     </div>
 * //     <button class="js-collapse-toggle" aria-controls="anonymous0">
 * //         Toggle
 * //     </button>
 * // </div>
 *
 * @example <caption>Getting a reference</caption>
 * // Markup is:
 * // <h1 id="anonymous0">Heading</h1>
 * // <div class="one" aria-labelledby="anonymous0">
 * //     Lorem ipsum dolor sit amet ...
 * // </div>
 *
 * $(".one").ariaRef("labelledby"); // -> $(<h1>)
 * $(".one").ariaRef("controls");   // -> $()
 *
 * @example <caption>Value is treated like a CSS selector</caption>
 * // Markup is:
 * // <button id="button"></button>
 * // <div id="section"></div>
 * // <section></section>
 *
 * $("#button").ariaRef("controls", "section");
 *
 * // Now markup is:
 * // <button id="button" aria-controls="anonymous0"></button>
 * // <div id="section"></div>
 * // <section id="anonymous0"></section>
 */
$.fn.ariaRef = function (property, value) {

    return access(
        this,
        property,
        value,
        HANDLER_REFERENCE
    );

};

// Source: /src/instance/ariaState.js



/**
 * Sets or gets the WAI-ARIA state of the collection.
 * <br><br>
 * When setting the state, false, "false" (any case), 0 and "0" will be
 * considered false. All other values will be considered true except for "mixed"
 * (any case) which will set the state to "mixed". The differs from
 * [jQuery#aria]{@link external:jQuery#aria} which will simply set the
 * attribute(s) without converting the value.
 * <br><br>
 * After setting the state(s), a jQuery object representing the affected
 * elements is returned. The state for the first matching element is returned
 * when getting.
 * <br><br>
 * All attributes are normalised - see
 * [jQuery.normaliseAria]{@link external:jQuery.normaliseAria} for full details.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    ariaState
 * @param    {Object|String} property
 *           Either a key/value combination properties to set or the name of the
 *           WAI-ARIA state to set.
 * @param    {Attribute_Callback|Boolean|Number|String} [value]
 *           Value of the attribute.
 * @return   {ARIA_state|jQuery}
 *           Either the jQuery object representing the modified elements
 *           (setting) or the state of the first matching element.
 *
 * @example <caption>Getting state</caption>
 * // Markup is:
 * // <div id="one" aria-busy="true" aria-checked="mixed"></div>
 *
 * $("#one").ariaState("busy");    // -> true
 * $("#one").ariaState("checked"); // -> "mixed"
 * $("#one").ariaState("hidden");  // -> undefined
 *
 * @example <caption>Setting state</caption>
 * // Each of these will set the state to false:
 * $("#one").ariaState("busy", "false");
 * $("#one").ariaState("busy", "FALSE");
 * $("#one").ariaState("busy", false);
 * $("#one").ariaState("busy", 0);
 * $("#one").ariaState("busy", "0");
 *
 * // Each of these will set the state to "mixed":
 * $("#one").ariaState("checked", "mixed");
 * $("#one").ariaState("checked", "MIXED");
 *
 * // Each of these will set the state to true
 * $("#one").ariaState("busy", "true");
 * $("#one").ariaState("busy", "TRUE");
 * $("#one").ariaState("busy", true);
 * $("#one").ariaState("busy", 1);
 * $("#one").ariaState("busy", "1");
 * // WARNING: these also set the state to true
 * $("#one").ariaState("busy", {});
 * $("#one").ariaState("busy", null);
 * $("#one").ariaState("busy", "nothing");
 * $("#one").ariaState("busy", "");
 * $("#one").ariaState("busy", -1);
 *
 * // Each example returns a jQuery object representing "#one" and an object
 * // can be passed as parameters as well:
 * $("#one").ariaState({
 *     busy: true
 * });
 *
 * @example <caption>Setting state with a function</caption>
 * // Markup is:
 * // <div class="checkbox"></div>
 * // <input type="checkbox" checked>
 *
 * $(".checkbox").ariaState("checked", function (i, attr) {
 *
 *     return $(this)
 *         .next("input[type=\"checkbox\"]")
 *         .prop("checked");
 *
 * });
 *
 * // Now markup is:
 * // <div class="checkbox" aria-checked="true"></div>
 * // <input type="checkbox" checked>
 */
$.fn.ariaState = function (property, value) {

    return access(
        this,
        property,
        value,
        HANDLER_STATE
    );

};

// Source: /src/instance/removeAria.js


$.fn.extend({

    removeAria: removeAttribute,

    /**
     * Alias of [jQuery#removeAria]{@link external:jQuery#removeAria}.
     *
     * @memberof external:jQuery
     * @instance
     * @function
     * @param    {String} name
     *           WAI-ARIA attribute to remove.
     * @return   {jQuery}
     *           jQuery attribute representing the elements modified.
     */
    removeAriaRef: removeAttribute,

    /**
     * Alias of [jQuery#removeAria]{@link external:jQuery#removeAria}.
     *
     * @memberof external:jQuery
     * @instance
     * @function
     * @param    {String} name
     *           WAI-ARIA attribute to remove.
     * @return   {jQuery}
     *           jQuery attribute representing the elements modified.
     */
    removeAriaState: removeAttribute

});

// Source: /src/instance/role.js



/**
 * Sets the role of all elements in the collection or gets the role of the first
 * element in the collection, depending on whether or not the <code>role</code>
 * argument is provided. As [jQuery#role]{@link external:jQuery#role} is just a
 * wrapper for [jQuery#attr]{@link http://api.jquery.com/attr/}, the
 * <code>role</code> parameter can actually be any value type that the official
 * documentation mentions.
 * <br><br>
 * According to the WAI-ARIA specs, an element can have mutliple roles as a
 * space-separated list. This method will only set the role attribute to the
 * given string when setting. If you want to modify the roles, use
 * [jQuery#addRole]{@link external:jQuery#addRole} and
 * [jQuery#removeRole]{@link external:jQuery#removeRole}.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    role
 * @param    {Attribute_Callback|String} [role]
 *           Role to get or function to set the role.
 * @return   {jQuery|String|undefined}
 *           Either the jQuery object representing the elements that were
 *           modified or the role value.
 *
 * @example
 * // Markup is:
 * // <div id="one"></div>
 * // <div id="two"></div>
 *
 * $("#one").role("presentation"); // -> jQuery(<div id="one">)
 *
 * // Now markup is:
 * // <div id="one" role="presentation"></div>
 * // <div id="two"></div>
 *
 * $("#one").role(); // -> "presentation"
 * $("#two").role(); // -> undefined
 *
 * @example <caption>Setting a role with a function</caption>
 * // Markup is:
 * // <div id="one" role="button"></div>
 *
 * $("#one").role(function (index, current) {
 *     return current + " tooltip";
 * });
 *
 * // Now markup is:
 * // <div id="one" role="button tooltip"></div>
 */
$.fn.role = function (role) {

    return role === undefined
        ? this.attr("role")
        : this.attr("role", role);

};

// Source: /src/instance/addRole.js



/**
 * Adds a role to a collection of elements. The role will not be added if it's
 * empty ("" or undefined), if the function response is empty or if the element
 * already has that role. In that way it's similar to
 * [jQuery#addClass]{@link https://api.jquery.com/addClass/}.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    addRole
 * @param    {Attribute_Callback|String} role
 *           Role(s) to add to the matching elements or function to generate the
 *           role(s) to add.
 * @return   {jQuery}
 *           jQuery object representing the matching elements.
 *
 * @example <caption>Adding a role</caption>
 * // Markup is:
 * // <div class="one" role="presentation"></div>
 * // <div class="one"></div>
 *
 * $(".one").addRole("alert"); // -> jQuery(<div>, <div>)
 *
 * // Now markup is:
 * // <div class="one" role="presentation alert"></div>
 * // <div class="one" role="alert"></div>
 *
 * @example <caption>Adding a role with a function</caption>
 * // Markup is:
 * // <div class="one" role="presentation"></div>
 *
 * $(".one").addRole(function (index, current) {
 *     return "alert combobox";
 * });
 *
 * // Now markup is:
 * // <div class="one" role="presentation alert combobox"></div>
 */
$.fn.addRole = function (role) {

    var isFunction = $.isFunction(role);

    return this.role(function (index, current) {

        var value = isFunction
            ? role.call(this, index, current)
            : role;
        var roles = toWords(current);

        toWords(value).forEach(function (val) {

            if (
                val !== ""
                && val !== undefined
                && roles.indexOf(val) < 0
            ) {
                roles.push(val);
            }

        });

        return roles.join(" ");

    });

};

// Source: /src/instance/removeRole.js



/**
 * Removes roles from the collection of elements. If the method is called
 * without any arguments then the role attribute itself is removed. Be aware
 * that this is not the same as passing a function which returns undefined -
 * such an action will have no effect.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    removeRole
 * @param    {Attribute_Callback|String} [role]
 *           Role(s) to remove or a function to generate the role(s) to remove.
 * @return   {jQuery}
 *           jQuery object representing the matched elements.
 *
 * @example <caption>Removing a role</caption>
 * // Markup is:
 * // <div class="one" role="presentation alert"></div>
 * // <div class="one" role="alert"></div>
 *
 * $(".one").removeRole("alert"); // -> jQuery(<div>, <div>)
 *
 * // Now markup is:
 * // <div class="one" role="presentation"></div>
 * // <div class="one" role=""></div>
 *
 * @example <caption>Completely removing a role</caption>
 * // Markup is:
 * // <div class="one" role="presentation alert"></div>
 * // <div class="one" role="alert"></div>
 *
 * $(".one").removeRole(); // -> jQuery(<div>, <div>)
 *
 * // Now markup is:
 * // <div class="one"></div>
 * // <div class="one"></div>
 *
 * @example <caption>Removing a role with a function</caption>
 * // Markup is:
 * // <div class="one" role="presentation alert combobox"></div>
 *
 * $(".one").removeRole(function (index, current) {
 *     return current
 *         .split(/\s+/)
 *         .filter(function (role) {
 *             return role.indexOf("a") > -1;
 *         })
 *         .join(" ");
 *     // "presentation alert"
 * });
 *
 * // Now markup is:
 * // <div class="one" role="combobox"></div>
 */
$.fn.removeRole = function (role) {

    var isFunction = $.isFunction(role);

    return role === undefined
        ? this.removeAttr("role")
        : this.role(function (index, current) {

            var value = isFunction
                ? role.call(this, index, current)
                : role;
            var values = toWords(value);

            return toWords(current)
                .filter(function (aRole) {
                    return values.indexOf(aRole) < 0;
                })
                .join(" ");

        });

};

// Source: /src/instance/ariaFocusable.js



/**
 * Sets whether or not the matching elements are focusable. Strings, numbers and
 * booleans are understood as <code>state</code> - see
 * [jQuery#ariaState]{@link external:jQuery#ariaState} for full details as the
 * algorythm is the same.
 * <br><br>
 * Be aware this this function will only modify the matching elements, it will
 * not check any parents or modify any other elements that could affect the
 * focusability of the element.
 *
 * @memberof external:jQuery
 * @instance
 * @alias    ariaFocusable
 * @param    {Attribute_Callback|Boolean|Number|String} state
 *           State to set.
 * @return   {jQuery}
 *           jQuery object representing the affected element(s).
 *
 * @example <caption>Setting focusability</caption>
 * // Markup is
 * // <div id="one"></div>
 * // <div id="two"></div>
 *
 * $("#one").ariaFocusable(false); // -> jQuery(<div id="one">)
 * $("#two").ariaFocusable(true);  // -> jQuery(<div id="two">)
 *
 * // Now markup is
 * // <div id="one" tabindex="0"></div>
 * // <div id="two" tabindex="-1"></div>
 *
 * @example <caption>Limitations of the function</caption>
 * // Markup is
 * // <div id="one" tabindex="-1">
 * //     <div id="two" disabled></div>
 * // </div>
 *
 * $("#two").ariaFocusable(true); // -> jQuery(<div id="two">)
 *
 * // Now markup is
 * // <div id="one" tabindex="-1">
 * //     <div id="two" disabled tabindex="0"></div>
 * // </div>
 */
$.fn.ariaFocusable = function (state) {

    return this.attr(
        "tabindex",
        handlers[HANDLER_STATE].read(state)
            ? 0
            : -1
    );

};

}(jQuery));