<commit_before>/**
 * Passenger JS
 * @description Passenger JS is a UI/UX helper tool that allows users to create passwords that meet the minimum requirements of a website or web application with greater ease. Multiple indicators help users to identify what is missing by providing direct instantaneous feedback as users type. UX research has show that there is a notable user frustration with user password creation. This tool helps to alleviate that frustration through numerous proven UX principles.
 * @author  <NAME>
 * @version 0.7.2
 */

/**
 * List of passengers
 * @type {object}
 */
var passengers = {};

/**
 * Passenger main constructor
 * @constructor
 * @param       {object}        config              configuration object with all necessary settings and options
 * @property    {string}        config.field        the password field ID
 * @property    {string}        config.styles       the custom CSS classes to be applied to the passenger box
 * @property    {array}         config.contracts    the custom password contracts
 * @return      {object}                            instance of Passenger
 */
function Passenger(config) {
    // not called with config, fail fast
    if (!config || !config.field) {
        return console.log("Error: config, and at minimum the password field ID is required.");
    }

    var _instance            = this
        , count = 0
        , ID                 = config.field
        , ElField            = _instance.getElement(ID)
        // if there is a contracts array passed in, use that, otherwise use the default passenger contracts
        , aContracts         = config.contracts || _instance.getContracts()
        , nContracts         = aContracts.length
        , box                = _instance.createBox(ElField, aContracts, config)
        , elInputTypeToggle  = _instance.inputTypeToggle(ElField)
        , elBoxDisplayToggle = _instance.boxDisplayToggle(elInputTypeToggle, box)
    ;

    _instance.sBoxID = config.field;
    _instance.box        = box;
    _instance.contracts  = aContracts;
    _instance.nContracts = _instance.contracts.length;

    _instance.setupBoxEvents(ElField, box);

    // add instance to top-level object that tracks instances, initially with unmet password requirements
    passengers[_instance.sBoxID] = {
        fulfilled : false
    }

    _instance.allPassed  = _instance.isPassFulfilled;

    return _instance;
}

/**
 * Is the password contract requirements met for instance?
 * @this        instance object
 * @memberOf    Passenger
 * @return      {boolean}       whether password requirements have been met or not
 */
Passenger.prototype.isPassFulfilled = function () {
    return passengers[this.sBoxID].fulfilled;
}

/**
 * Create Passenger box for user feeback
 * @method      createBox
 * @memberOf    Passenger
 * @param       {string}        elField     the ID of the specific instance of Passenger implementation
 * @param       {array}         aContracts  array list of contracts
 * @param       {object}        config      the configuration object passenger is instantiated with
 * @return      {DOMElement}                the newly created DOM element of the box
 */
Passenger.prototype.createBox = function (elField, aContracts, config) {
    if (!config) {
        return console.log("Error: configuration is required to create passenger box.");
    }
    var i = 0
        , sBoxID = config.field
        , sCSS = (config.styles) ? ' ' + config.styles : ''
        , nContracts = aContracts.length
        , passboxDIV = _after({
            el: elField
            , selNew: "div"
            , sID: "passbox_" + sBoxID
            , sCSS: "passbox" + sCSS
        })
        , passboxLabel = _appendChild({
            el: passboxDIV
            , selNew: "label"
            , sText: "Password Must:"
        })
        , passboxUL = _after({
            el: passboxLabel
            , selNew: "ul"
        })
        // create doc fragment to append all rule LIs
        , docfrag = document.createDocumentFragment()
        , li
        , sRulePrefix = sBoxID + '-rule-'
    ;

    // loop through contracts array and add an LI to docfrag for each...
    for (; i < nContracts; i++) {
        li = document.createElement("li");
        li.textContent = aContracts[i].label;
        li.id = sRulePrefix + aContracts[i].name;
        docfrag.appendChild(li);
    }

    passboxUL.appendChild(docfrag);
    return passboxDIV;
}

/**
 * Toggles the display of the box
 * @method      boxDisplayToggle
 * @memberOf    Passenger
 * @param       {DOMElement}    elAfter     the DOM element to create the toggle link after
 * @param       {DOMElement}    box         the DOM element of the box
 * @return      {DOMElement}                the DOM element of the toggle link
 */
Passenger.prototype.boxDisplayToggle = function (elAfter, box) {
    if (!elAfter || !box) {
        return console.log("Error: need both, the element to add box toggle link and the box itself");
    }
    var sBoxID = this.sBoxID
        , elBoxToggle = _after({
            el: elAfter
            , selNew: "a"
            , sID   : "passbox_guide_toggle_" + sBoxID
            , sCSS  : "toggle_guide_link"
            , sText : "Toggle Guide"
            , aAttr : [{ name: "href", val: "javascript:void(0);"}]
        })
    ;

    elBoxToggle.addEventListener('click', toggleBoxHandler, false);

    /**
     * Toggles the passenger box to show/hide
     * @return {boolean} false
     */
    function toggleBoxHandler() {
        var sClasses = box.className
            , index = sClasses.indexOf("show")
        ;
        if (index != -1) {
            sClasses = sClasses.substr(0, index - 1);
        } else {
            sClasses = box.className + " show";
        }
        box.className = sClasses;
        return false;
    }

    return elBoxToggle;
}

/**
 * Toggle input type to password/text
 * @method      inputTypeToggle
 * @memberOf    Passenger
 * @param       {DOMElement}    elField     the DOM element of input
 * @return      {DOMElement}                the DOM element of input
 */
Passenger.prototype.inputTypeToggle = function (elField) {
    if (!elField) {
        return console.log("Error: field element required.");
    }
    var sBoxID = this.sBoxID
        , elToggleLink = _after({
            el: elField
            , selNew: "a"
            , sID   : "passbox_type_toggle_" + sBoxID
            , sText : "Toggle Password"
            , sCSS  : "toggle_input_link"
            , aAttr : [{ name: 'href', val: 'javascript:void(0);'}]
        })
    ;

    elToggleLink.addEventListener('click', toggleHandler, false);

    /**
     * Toggle event handler
     * @private<commit_msg>fixed bad references, added more JSDocs and a parameter for getting the true field id through the config<commit_after>/**
 * Passenger JS
 * @description Passenger JS is a UI/UX helper tool that allows users to create passwords that meet the minimum requirements of a website or web application with greater ease. Multiple indicators help users to identify what is missing by providing direct instantaneous feedback as users type. UX research has show that there is a notable user frustration with user password creation. This tool helps to alleviate that frustration through numerous proven UX principles.
 * @author  <NAME>
 * @version 0.7.3
 */

/**
 * List of passengers
 * @type {object}
 */
var passengers = {};

/**
 * Passenger main constructor
 * @constructor
 * @param       {object}        config              configuration object with all necessary settings and options
 * @property    {string}        config.field        the password field ID
 * @property    {string}        config.styles       the custom CSS classes to be applied to the passenger box
 * @property    {array}         config.contracts    the custom password contracts
 * @return      {object}                            instance of Passenger
 */
function Passenger(config) {
    // not called with config, fail fast
    if (!config || !config.field) {
        return console.log("Error: config, and at minimum the password field ID is required.");
    }

    var _instance            = this
        , count = 0
        , ID                 = config.field
        , ElField            = _instance.getElement(ID)
        // if there is a contracts array passed in, use that, otherwise use the default passenger contracts
        , aContracts         = config.contracts || _instance.getContracts()
        , nContracts         = aContracts.length
        , box                = _instance.createBox(ElField, aContracts, config)
        , elInputTypeToggle  = _instance.inputTypeToggle(ElField)
        , elBoxDisplayToggle = _instance.boxDisplayToggle(elInputTypeToggle, box, config)
    ;

    _instance.sBoxID = config.field;
    _instance.box        = box;
    _instance.contracts  = aContracts;
    _instance.nContracts = _instance.contracts.length;

    _instance.setupBoxEvents(ElField, box);

    // add instance to top-level object that tracks instances, initially with unmet password requirements
    passengers[_instance.sBoxID] = {
        fulfilled : false
    }

    _instance.allPassed  = _instance.isPassFulfilled;

    return _instance;
}

/**
 * Is the password contract requirements met for instance?
 * @this        instance object
 * @memberOf    Passenger
 * @return      {boolean}       whether password requirements have been met or not
 */
Passenger.prototype.isPassFulfilled = function () {
    return passengers[this.sBoxID].fulfilled;
}

/**
 * Create Passenger box for user feeback
 * @method      createBox
 * @memberOf    Passenger
 * @param       {string}        elField     the ID of the specific instance of Passenger implementation
 * @param       {array}         aContracts  array list of contracts
 * @param       {object}        config      the configuration object passenger is instantiated with
 * @return      {DOMElement}                the newly created DOM element of the box
 */
Passenger.prototype.createBox = function (elField, aContracts, config) {
    if (!config) {
        return console.log("Error: configuration is required to create passenger box.");
    }
    var i = 0
        , sBoxID = config.field
        , sCSS = (config.styles) ? ' ' + config.styles : ''
        , nContracts = aContracts.length
        , passboxDIV = _after({
            el: elField
            , selNew: "div"
            , sID: "passbox_" + sBoxID
            , sCSS: "passbox" + sCSS
        })
        , passboxLabel = _appendChild({
            el: passboxDIV
            , selNew: "label"
            , sText: "Password Must:"
        })
        , passboxUL = _after({
            el: passboxLabel
            , selNew: "ul"
        })
        // create doc fragment to append all rule LIs
        , docfrag = document.createDocumentFragment()
        , li
        , sRulePrefix = sBoxID + '-rule-'
    ;

    // loop through contracts array and add an LI to docfrag for each...
    for (; i < nContracts; i++) {
        li = document.createElement("li");
        li.textContent = aContracts[i].label;
        li.id = sRulePrefix + aContracts[i].name;
        docfrag.appendChild(li);
    }

    passboxUL.appendChild(docfrag);
    return passboxDIV;
}

/**
 * Toggles the display of the box
 * @method      boxDisplayToggle
 * @memberOf    Passenger
 * @param       {DOMElement}    elAfter     the DOM element to create the toggle link after
 * @param       {DOMElement}    box         the DOM element of the box
 * @param       {object}        config      the configuration object from instantiation
 * @property    {string}        sBoxID      box id
 * @return      {DOMElement}                the DOM element of the toggle link
 */
Passenger.prototype.boxDisplayToggle = function (elAfter, box, config) {
    if (!elAfter || !box) {
        return console.log("Error: need both, the element to add box toggle link and the box itself");
    }
    var sBoxID = config.field
        , elBoxToggle = _after({
            el: elAfter
            , selNew: "a"
            , sID   : "passbox_guide_toggle_" + sBoxID
            , sCSS  : "toggle_guide_link"
            , sText : "Toggle Guide"
            , aAttr : [{ name: "href", val: "javascript:void(0);"}]
        })
    ;

    elBoxToggle.addEventListener('click', toggleBoxHandler, false);

    /**
     * Toggles the passenger box to show/hide
     * @return {boolean} false
     */
    function toggleBoxHandler() {
        var sClasses = box.className
            , index = sClasses.indexOf("show")
        ;
        if (index != -1) {
            sClasses = sClasses.substr(0, index - 1);
        } else {
            sClasses = box.className + " show";
        }
        box.className = sClasses;
        return false;
    }

    return elBoxToggle;
}

/**
 * Toggle input type to password/text
 * @method      inputTypeToggle
 * @memberOf    Passenger
 * @param       {DOMElement}    elField     the DOM element of input
 * @property    {string}        sBoxID      box id
 * @return      {DOMElement}                the DOM element of input
 */
Passenger.prototype.inputTypeToggle = function (elField) {
    if (!elField) {
        return console.log("Error: field element required.");
    }
    var sBoxID = elField.id
        , elToggleLink = _after({
            el: elField
            , selNew: "a"
            , sID   : "passbox_type_toggle_" + sBoxID
            , sText : "Toggle Password"
            , sCSS  : "toggle_input_link"
            , aAttr : [{ name: 'href', val: 'javascript:void(0);'}]
        })
    ;

    elToggleLink.addEventListener('click', toggleHandler, false);

    /**
     * Toggle event handler
     * @private
{'fraction_non_alphanumeric': 0.09176915799432356, 'fraction_numerical': 0.001455498144239866, 'mean_word_length': 2.1288706739526413, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7273060', 'n_tokens_mistral': 3740, 'n_tokens_neox': 3648, 'n_words': 1194}