<commit_before>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../../Aria");
var ariaWidgetsFramesFrameFactory = require("../frames/FrameFactory");
var ariaUtilsDom = require("../../utils/Dom");
var ariaDomEvent = require("../../DomEvent");
var ariaUtilsString = require("../../utils/String");
var ariaWidgetsActionButtonStyle = require("./ButtonStyle.tpl.css");
var ariaWidgetsActionActionWidget = require("./ActionWidget");
var ariaCoreBrowser = require("../../core/Browser");

/**
 * Class definition for the button widget.
 */
module.exports = Aria.classDefinition({
    $classpath : "aria.widgets.action.Button",
    $extends : ariaWidgetsActionActionWidget,
    $css : [ariaWidgetsActionButtonStyle],
    /**
     * ActionWidget constructor
     * @param {aria.widgets.CfgBeans:ActionWidgetCfg} cfg the widget configuration
     * @param {aria.templates.TemplateCtxt} ctxt template context
     */
    $constructor : function (cfg, ctxt) {
        this.$ActionWidget.constructor.apply(this, arguments);

        /**
         * Tells if the mouse is currently over the widget.
         * @protected
         * @type Boolean
         */
        this._mouseOver = false;

        /**
         * Tells if the mouse is currently pressing the widget.
         * @protected
         * @type Boolean
         */
        this._mousePressed = false;

        /**
         * Tells if a key down event happened before the last click event. This prevents an enter event to fire the
         * action twice.
         * @protected
         * @type Boolean
         */
        this._keyPressed = false;

        /**
         * Tells if the widget is currently focused.
         * @type Boolean
         */
        this._focused = false;

        this._updateState(true);

        /**
         * Tells if the widgets is using a tabindex (for tab navigation).
         * @protected
         * @type Boolean
         * @override
         */
        this._customTabIndexProvided = true;

        /**
         * Pointer used to store the target on mousedown/mouseup
         * @type HTMLElement
         */
        this.currTarget = null;

        /**
         * Skin configutation for simpleHTML
         * @type Object
         * @protected
         */
        this._simpleHTML = aria.widgets.AriaSkinInterface.getSkinObject(this._skinnableClass, cfg.sclass).simpleHTML;

        if (!this._simpleHTML) {
            /**
             * Frame containing this widget.
             * @protected
             * @type {aria.widgets.frames.Frame}
             */
            this._frame = ariaWidgetsFramesFrameFactory.createFrame({
                height : cfg.height,
                width : cfg.width,
                state : this._state,
                sclass : cfg.sclass,
                skinnableClass : this._skinnableClass,
                // added in PTR 05170822 to avoid the internal scrollbard for content
                scrollBarX : false,
                scrollBarY : false
            });
        }
    },
    $destructor : function () {
        this.currTarget = null;
        if (this._frame) {
            this._frame.$dispose();
            this._frame = null;
        }
        this.$ActionWidget.$destructor.call(this);
    },
    $prototype : {
        /**
         * Skinnable class to use for this widget.
         * @protected
         * @type String
         */
        _skinnableClass : "Button",

        /**
         * Internal method to update the state of the widget
         * @param {Boolean} skipChangeState If true the internal state won't change
         * @protected
         */
        _updateState : function (skipChangeState) {
            var state = "normal";
            var cfg = this._cfg;
            if (cfg.disabled) {
                state = "disabled";
            } else {
                if ((this._mousePressed && this._mouseOver) || this._keyPressed) {
                    state = "msdown";
                } else if (this._mouseOver && !this._focused) {
                    state = "msover";
                } else if (this._focused) {
                    if (this._mouseOver) {
                        state = "msoverFocused";
                    } else {
                        state = "normalFocused";
                    }
                }
            }
            this._state = state;
            if (!skipChangeState) {
                // force widget - DOM mapping
                this.getDom();
                if (!this._simpleHTML) {
                    this._frame.changeState(this._state);
                    var ie8plus = ariaCoreBrowser.isOldIE && ariaCoreBrowser.majorVersion >= 8;
                    if (state == "disabled") {
                        this._focusElt.className = "xButton xButtonDisabled";
                        if (ie8plus) {
                            this._focusElt.onfocusin = function () {
                                this.blur();
                            };
                        }
                    } else {
                        this._focusElt.className = "xButton";
                        if (ie8plus) {
                            this._focusElt.onfocusin = null;
                        }
                    }
                }
                if (state == "disabled") {
                    this._focusElt.setAttribute("disabled", "disabled");
                } else {
                    this._focusElt.removeAttribute("disabled");
                }
            }
        },

        /**
         * A method called when a bindable property has changed in the data model
         * @param {String} propertyName the property name
         * @param {Object} newValue the new value. If transformation is used, refers to widget value and not data model
         * value.
         * @param {Object} oldValue the old property value. If transformation is used, refers to widget value and not
         * data model value.
         * @protected
         */
        _onBoundPropertyChange : function (propertyName, newValue, oldValue) {
            this.$ActionWidget._onBoundPropertyChange.apply(this, arguments);
            var changedState = false;
            if (propertyName === "disabled") {
                changedState = true;
                this._isDisabled = !!newValue;
            }
            if (changedState) {
                this._cfg[propertyName] = newValue;
                this._updateState();
            }
        },

        /**
         * Add the remaining events that are needed for the button
         * @param {HTMLElement} actingDom html element on which actions can happen.
         * @protected
         */
        _initActionWidget : function (actingDom) {
            if (!this._simpleHTML) {
                this._frame.linkToDom(ariaUtilsDom.getDomElementChild(actingDom, 0));
            }
            this._focusElt = actingDom;
        },

        /**
         * Create the button markup from the Div class
         * @param {aria.templates.MarkupWriter} out Output markup writer
         * @protected
         */
        _widgetMarkup : function (out) {
            var cfg = this._cfg;
            var tabIndexString = (cfg.tabIndex != null ? ' tabindex="' + this._calculateTabIndex() + '" ' : '');
            var isIE7 = ariaCoreBrowser.isIE7;
            var ariaTestMode = (Aria.testMode) ? ' id="' + this._domId + '_button" ' : '';
            var buttonClass = cfg.disabled ? "xButton xButtonDisabled" : "xButton";

            var waiAriaAttributes = this._getWaiAriaMarkup();
            var disableMarkup = cfg.disabled ? " disabled='disabled' " : "";
            if (this._simpleHTML) {
                var styleMarkup = cfg.width != "-1" ? " style='width:" + cfg.width + "px;' " : "";

                out.write([
                    '<',
                    !cfg.waiAria
                        ? 'input type="button" value="' + ariaUtilsString.encodeForQuotedHTMLAttribute(cfg.label) + '"'
                        : 'button',
                    waiAriaAttributes,
                    ariaTestMode,
                    tabIndexString,
                    disableMarkup,
                    styleMarkup,
                    !cfg.waiAria
                        ? '/>'
                        : '>' + ariaUtilsString.escapeForHTML(cfg.label, {text: true}) + '</button>'
                ].join(''));
            } else {
                if (isIE7) {
                    // FIXME: find a way to put a button also on IE7
                    // on IE7 the button is having display issues the current frame implementation inside it
                    out.write([''].join(''));
                } else {
                    // PTR 05613372: prevent 'clickability' of greyed out button. Adding "disabled" makes adjusting the
                    // text color impossible in IE, thus onfocusin used (more suitable for this use case than onfocus)
                    var onFocusInString = (ariaCoreBrowser.isOldIE && cfg.disabled)
                            ? " onfocusin='this.blur()' "
                            : "";
                    out.write([
                        '<button',
                        ' type="button"',
                        ' class="' + buttonClass + '"',
                        waiAriaAttributes,
                        onFocusInString,
                        tabIndexString,
                        ariaTestMode,
                        disableMarkup
                        '>'
                    ].join(''));
                }
                this._frame.writeMarkupBegin(out);
                // call the method to write the content of the button - here is is just
                // the label cfg attribute, but the method can be overwritten in child classes
                this._widgetMarkupContent(out);
                this._frame.writeMarkupEnd(out);
                if (isIE7) {
                    out.write('');
                } else {
                    out.write('</button>');
                }
            }
        },

        /**
         * Write the content of the widget (note that _widgetMarkup writes the frame)
         * @param {aria.templates.MarkupWriter} out Output markup writer
         * @protected
         */
        _widgetMarkupContent : function (out) {
            out.write(ariaUtilsString.escapeHTML(this._cfg.label));
        },

        /**
         * React to delegated mouse over events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseover : function (domEvt) {
            this.$ActionWidget._dom_onmouseover.call(this, domEvt);
            this._mouseOver = true;
            this._updateState();
        },

        /**
         * React to delegated mouse out events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseout : function (domEvt) {
            this.$ActionWidget._dom_onmouseout.call(this, domEvt);
            this._mouseOver = false;
            this._mousePressed = false;
            this._updateState();
        },

        /**
         * React to delegated mouse down events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmousedown : function (domEvt) {
            this.focus();
            this._mouseOver = true;
            this._mousePressed = true;
            this._updateState();

            if (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) {
                this.currTarget = domEvt.currentTarget;
            }
        },

        /**
         * React to delegated mouse up events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseup : function (domEvt) {
            // TODO: this method should also be called when the mouse button is released, not depending on where it is
            // released

            if (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) {
                if (this._mousePressed && domEvt.currentTarget == this.currTarget) {
                    // handle an onclick event
                    this._performAction(domEvt);
                }
                this.currTarget = null;
            }

            if (this._cfg) { // this._cfg can become null if e.g. the button triggers a template substitution
                // and the button is part of that template
                this._mousePressed = false;
                this._updateState();
            }

        },

        /**
         * React to delegated key down events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onkeydown : function (domEvt) {
            if (domEvt.keyCode == ariaDomEvent.KC_SPACE || domEvt.keyCode == ariaDomEvent.KC_ENTER) {
                this._keyPressed = true;
                this._updateState();
                domEvt.stopPropagation();
                return false;
            }

            return true;
        },

        /**
         * The method called when the markup is clicked
         * @param {aria.DomEvent} evt Event
         * @method
         * @private
         */
        _dom_onclick : (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) ? function (domEvent) {
            // we don't catch onclick's for buttons on chrome & safari. we catch mouseup's instead
        } : function (domEvent) {
            if (!this._keyPressed) {
                this._performAction(domEvent);
            }
        },

        /**
         * React to delegated key up events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onkeyup : function (domEvt) {
            if (domEvt.keyCode == ariaDomEvent.KC_SPACE || domEvt.keyCode == ariaDomEvent.KC_ENTER) {
                if (this._keyPressed) {
                    this._keyPressed = false;
                    this._updateState();

                    if (!this._performAction(domEvt)) {
                        domEvt.stopPropagation();
                        return false;
                    }
                }
            }
            return true;
        },

        /**
         * React to delegated focus events
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onfocus : function (domEvt) {
            this._focused = true;
            this._updateState();
        },

        /**
         * React to delegated blur events
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onblur : function (domEvt) {
            this._focused = false;
            this._keyPressed = false;
            this._updateState();
        }
    }
});
<commit_msg>fix missing coma that magically passed the CI<commit_after>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../../Aria");
var ariaWidgetsFramesFrameFactory = require("../frames/FrameFactory");
var ariaUtilsDom = require("../../utils/Dom");
var ariaDomEvent = require("../../DomEvent");
var ariaUtilsString = require("../../utils/String");
var ariaWidgetsActionButtonStyle = require("./ButtonStyle.tpl.css");
var ariaWidgetsActionActionWidget = require("./ActionWidget");
var ariaCoreBrowser = require("../../core/Browser");

/**
 * Class definition for the button widget.
 */
module.exports = Aria.classDefinition({
    $classpath : "aria.widgets.action.Button",
    $extends : ariaWidgetsActionActionWidget,
    $css : [ariaWidgetsActionButtonStyle],
    /**
     * ActionWidget constructor
     * @param {aria.widgets.CfgBeans:ActionWidgetCfg} cfg the widget configuration
     * @param {aria.templates.TemplateCtxt} ctxt template context
     */
    $constructor : function (cfg, ctxt) {
        this.$ActionWidget.constructor.apply(this, arguments);

        /**
         * Tells if the mouse is currently over the widget.
         * @protected
         * @type Boolean
         */
        this._mouseOver = false;

        /**
         * Tells if the mouse is currently pressing the widget.
         * @protected
         * @type Boolean
         */
        this._mousePressed = false;

        /**
         * Tells if a key down event happened before the last click event. This prevents an enter event to fire the
         * action twice.
         * @protected
         * @type Boolean
         */
        this._keyPressed = false;

        /**
         * Tells if the widget is currently focused.
         * @type Boolean
         */
        this._focused = false;

        this._updateState(true);

        /**
         * Tells if the widgets is using a tabindex (for tab navigation).
         * @protected
         * @type Boolean
         * @override
         */
        this._customTabIndexProvided = true;

        /**
         * Pointer used to store the target on mousedown/mouseup
         * @type HTMLElement
         */
        this.currTarget = null;

        /**
         * Skin configutation for simpleHTML
         * @type Object
         * @protected
         */
        this._simpleHTML = aria.widgets.AriaSkinInterface.getSkinObject(this._skinnableClass, cfg.sclass).simpleHTML;

        if (!this._simpleHTML) {
            /**
             * Frame containing this widget.
             * @protected
             * @type {aria.widgets.frames.Frame}
             */
            this._frame = ariaWidgetsFramesFrameFactory.createFrame({
                height : cfg.height,
                width : cfg.width,
                state : this._state,
                sclass : cfg.sclass,
                skinnableClass : this._skinnableClass,
                // added in PTR 05170822 to avoid the internal scrollbard for content
                scrollBarX : false,
                scrollBarY : false
            });
        }
    },
    $destructor : function () {
        this.currTarget = null;
        if (this._frame) {
            this._frame.$dispose();
            this._frame = null;
        }
        this.$ActionWidget.$destructor.call(this);
    },
    $prototype : {
        /**
         * Skinnable class to use for this widget.
         * @protected
         * @type String
         */
        _skinnableClass : "Button",

        /**
         * Internal method to update the state of the widget
         * @param {Boolean} skipChangeState If true the internal state won't change
         * @protected
         */
        _updateState : function (skipChangeState) {
            var state = "normal";
            var cfg = this._cfg;
            if (cfg.disabled) {
                state = "disabled";
            } else {
                if ((this._mousePressed && this._mouseOver) || this._keyPressed) {
                    state = "msdown";
                } else if (this._mouseOver && !this._focused) {
                    state = "msover";
                } else if (this._focused) {
                    if (this._mouseOver) {
                        state = "msoverFocused";
                    } else {
                        state = "normalFocused";
                    }
                }
            }
            this._state = state;
            if (!skipChangeState) {
                // force widget - DOM mapping
                this.getDom();
                if (!this._simpleHTML) {
                    this._frame.changeState(this._state);
                    var ie8plus = ariaCoreBrowser.isOldIE && ariaCoreBrowser.majorVersion >= 8;
                    if (state == "disabled") {
                        this._focusElt.className = "xButton xButtonDisabled";
                        if (ie8plus) {
                            this._focusElt.onfocusin = function () {
                                this.blur();
                            };
                        }
                    } else {
                        this._focusElt.className = "xButton";
                        if (ie8plus) {
                            this._focusElt.onfocusin = null;
                        }
                    }
                }
                if (state == "disabled") {
                    this._focusElt.setAttribute("disabled", "disabled");
                } else {
                    this._focusElt.removeAttribute("disabled");
                }
            }
        },

        /**
         * A method called when a bindable property has changed in the data model
         * @param {String} propertyName the property name
         * @param {Object} newValue the new value. If transformation is used, refers to widget value and not data model
         * value.
         * @param {Object} oldValue the old property value. If transformation is used, refers to widget value and not
         * data model value.
         * @protected
         */
        _onBoundPropertyChange : function (propertyName, newValue, oldValue) {
            this.$ActionWidget._onBoundPropertyChange.apply(this, arguments);
            var changedState = false;
            if (propertyName === "disabled") {
                changedState = true;
                this._isDisabled = !!newValue;
            }
            if (changedState) {
                this._cfg[propertyName] = newValue;
                this._updateState();
            }
        },

        /**
         * Add the remaining events that are needed for the button
         * @param {HTMLElement} actingDom html element on which actions can happen.
         * @protected
         */
        _initActionWidget : function (actingDom) {
            if (!this._simpleHTML) {
                this._frame.linkToDom(ariaUtilsDom.getDomElementChild(actingDom, 0));
            }
            this._focusElt = actingDom;
        },

        /**
         * Create the button markup from the Div class
         * @param {aria.templates.MarkupWriter} out Output markup writer
         * @protected
         */
        _widgetMarkup : function (out) {
            var cfg = this._cfg;
            var tabIndexString = (cfg.tabIndex != null ? ' tabindex="' + this._calculateTabIndex() + '" ' : '');
            var isIE7 = ariaCoreBrowser.isIE7;
            var ariaTestMode = (Aria.testMode) ? ' id="' + this._domId + '_button" ' : '';
            var buttonClass = cfg.disabled ? "xButton xButtonDisabled" : "xButton";

            var waiAriaAttributes = this._getWaiAriaMarkup();
            var disableMarkup = cfg.disabled ? " disabled='disabled' " : "";
            if (this._simpleHTML) {
                var styleMarkup = cfg.width != "-1" ? " style='width:" + cfg.width + "px;' " : "";

                out.write([
                    '<',
                    !cfg.waiAria
                        ? 'input type="button" value="' + ariaUtilsString.encodeForQuotedHTMLAttribute(cfg.label) + '"'
                        : 'button',
                    waiAriaAttributes,
                    ariaTestMode,
                    tabIndexString,
                    disableMarkup,
                    styleMarkup,
                    !cfg.waiAria
                        ? '/>'
                        : '>' + ariaUtilsString.escapeForHTML(cfg.label, {text: true}) + '</button>'
                ].join(''));
            } else {
                if (isIE7) {
                    // FIXME: find a way to put a button also on IE7
                    // on IE7 the button is having display issues the current frame implementation inside it
                    out.write([''].join(''));
                } else {
                    // PTR 05613372: prevent 'clickability' of greyed out button. Adding "disabled" makes adjusting the
                    // text color impossible in IE, thus onfocusin used (more suitable for this use case than onfocus)
                    var onFocusInString = (ariaCoreBrowser.isOldIE && cfg.disabled)
                            ? " onfocusin='this.blur()' "
                            : "";
                    out.write([
                        '<button',
                        ' type="button"',
                        ' class="' + buttonClass + '"',
                        waiAriaAttributes,
                        onFocusInString,
                        tabIndexString,
                        ariaTestMode,
                        disableMarkup,
                        '>'
                    ].join(''));
                }
                this._frame.writeMarkupBegin(out);
                // call the method to write the content of the button - here is is just
                // the label cfg attribute, but the method can be overwritten in child classes
                this._widgetMarkupContent(out);
                this._frame.writeMarkupEnd(out);
                if (isIE7) {
                    out.write('');
                } else {
                    out.write('</button>');
                }
            }
        },

        /**
         * Write the content of the widget (note that _widgetMarkup writes the frame)
         * @param {aria.templates.MarkupWriter} out Output markup writer
         * @protected
         */
        _widgetMarkupContent : function (out) {
            out.write(ariaUtilsString.escapeHTML(this._cfg.label));
        },

        /**
         * React to delegated mouse over events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseover : function (domEvt) {
            this.$ActionWidget._dom_onmouseover.call(this, domEvt);
            this._mouseOver = true;
            this._updateState();
        },

        /**
         * React to delegated mouse out events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseout : function (domEvt) {
            this.$ActionWidget._dom_onmouseout.call(this, domEvt);
            this._mouseOver = false;
            this._mousePressed = false;
            this._updateState();
        },

        /**
         * React to delegated mouse down events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmousedown : function (domEvt) {
            this.focus();
            this._mouseOver = true;
            this._mousePressed = true;
            this._updateState();

            if (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) {
                this.currTarget = domEvt.currentTarget;
            }
        },

        /**
         * React to delegated mouse up events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onmouseup : function (domEvt) {
            // TODO: this method should also be called when the mouse button is released, not depending on where it is
            // released

            if (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) {
                if (this._mousePressed && domEvt.currentTarget == this.currTarget) {
                    // handle an onclick event
                    this._performAction(domEvt);
                }
                this.currTarget = null;
            }

            if (this._cfg) { // this._cfg can become null if e.g. the button triggers a template substitution
                // and the button is part of that template
                this._mousePressed = false;
                this._updateState();
            }

        },

        /**
         * React to delegated key down events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onkeydown : function (domEvt) {
            if (domEvt.keyCode == ariaDomEvent.KC_SPACE || domEvt.keyCode == ariaDomEvent.KC_ENTER) {
                this._keyPressed = true;
                this._updateState();
                domEvt.stopPropagation();
                return false;
            }

            return true;
        },

        /**
         * The method called when the markup is clicked
         * @param {aria.DomEvent} evt Event
         * @method
         * @private
         */
        _dom_onclick : (ariaCoreBrowser.isChrome || ariaCoreBrowser.isOpera || ariaCoreBrowser.isSafari) ? function (domEvent) {
            // we don't catch onclick's for buttons on chrome & safari. we catch mouseup's instead
        } : function (domEvent) {
            if (!this._keyPressed) {
                this._performAction(domEvent);
            }
        },

        /**
         * React to delegated key up events
         * @protected
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onkeyup : function (domEvt) {
            if (domEvt.keyCode == ariaDomEvent.KC_SPACE || domEvt.keyCode == ariaDomEvent.KC_ENTER) {
                if (this._keyPressed) {
                    this._keyPressed = false;
                    this._updateState();

                    if (!this._performAction(domEvt)) {
                        domEvt.stopPropagation();
                        return false;
                    }
                }
            }
            return true;
        },

        /**
         * React to delegated focus events
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onfocus : function (domEvt) {
            this._focused = true;
            this._updateState();
        },

        /**
         * React to delegated blur events
         * @param {aria.DomEvent} domEvt Event
         */
        _dom_onblur : function (domEvt) {
            this._focused = false;
            this._keyPressed = false;
            this._updateState();
        }
    }
});
<|endoftext|>


<commit_before>document.elem = function (elemname, attributes, text) {
    return document.createElement(elemname).attribs(attributes).setText(text);
};
document.delElem = function (elemname) {
    if (element && element.parentNode) {
        element.parentNode.removeChild(element);
    }
}
Element.prototype.elem = function (elemname, attr, text, returnparent) {
    var elem = (typeof elemname === 'string') ? document.elem(elemname, attr, text) : elemname;
    this.appendChild(elem);
    return (returnparent !== null && returnparent) ? this : elem;
};
Element.prototype.attribs = function (attributes) {
    if (attributes !== null && typeof attributes == "object") {
        for (var attribute in attributes) {
            if (attributes.hasOwnProperty(attribute)) {
                this.setAttribute(attribute, attributes[attribute]);
            }
        }
    }
    return this;
};
Element.prototype.attrib = function (name, value) {
    if (name) {
        this.setAttribute(name, value);
    }
    return this;
};
Element.prototype.setText = function (text) {
    if (text) {
        this.textContent = text;
    }
    return this;
};
Element.prototype.clearElem = function () {
    if (this.textContent !== null) {
        this.textContent = '';
    }
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
    return this;
};
['span', 'div', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'i', 'em', 'b', 'img', 'table', 'tbody', 'thead', 'tr', 'th', 'td', 'a', 'label', 'input', 'br', 'hr'].map(function (elemname) {
    Element.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, ['br', 'hr'].indexOf(elemname) !== -1 ? true : returnparent);
    };
    document[elemname] = function (attr, text) {
        return this.elem(elemname, attr, text);
    };
});

<commit_msg>getElem & elem shortcut<commit_after>document.elem = function (elemname, attributes, text) {
    if (typeof attributes === 'string') {
        text = attributes;
        attributes = null;
    }
    return document.createElement(elemname).attribs(attributes).setText(text);
};
document.getElem = function(selector) {
    return document.querySelector(selector);
};
document.getElemAll = function(selector) {
    return document.querySelectorAll(selector);
};
document.delElem = function (elemname) {
    if (element && element.parentNode) {
        element.parentNode.removeChild(element);
    }
};
Element.prototype.getElem = function(selector) {
    return this.querySelector(selector);
};
Element.prototype.getElemAll = function(selector) {
    return this.querySelectorAll(selector);
};
Element.prototype.elem = function (elemname, attr, text, returnparent) {
    var elem = (typeof elemname === 'string') ? document.elem(elemname, attr, text) : elemname;
    this.appendChild(elem);
    return (returnparent !== null && returnparent) ? this : elem;
};
Element.prototype.attribs = function (attributes) {
    if (attributes !== null && typeof attributes == "object") {
        for (var attribute in attributes) {
            if (attributes.hasOwnProperty(attribute)) {
                this.setAttribute(attribute, attributes[attribute]);
            }
        }
    }
    return this;
};
Element.prototype.attrib = function (name, value) {
    if (name) {
        this.setAttribute(name, value);
    }
    return this;
};
Element.prototype.setText = function (text) {
    if (text) {
        this.textContent = text;
    }
    return this;
};
Element.prototype.clearElem = function () {
    if (this.textContent !== null) {
        this.textContent = '';
    }
    while (this.firstChild) {
        this.removeChild(this.firstChild);
    }
    return this;
};
['span', 'div', 'ul', 'ol', 'li', 'h1', 'h2', 'h3', 'h4', 'i', 'em', 'b', 'img', 'table', 'tbody', 'thead', 'tr', 'th', 'td', 'a', 'label', 'input', 'br', 'hr'].map(function (elemname) {
    Element.prototype[elemname] = function (attr, text, returnparent) {
        return this.elem(elemname, attr, text, ['br', 'hr'].indexOf(elemname) !== -1 ? true : returnparent);
    };
    document[elemname] = function (attr, text) {
        return this.elem(elemname, attr, text);
    };
});

<|endoftext|>


<commit_before>const fetch = require('node-fetch');

const BASE_URL = 'http://site.api.espn.com/apis/site/v2/sports/football/nfl';

const seasonTypeMapping = {
    1: 'P',
    2: 'R',
    3: 'POST',
    4: 'OFF',
};

const teamNameMapping = {
    LAR: 'LA',
    WSH: 'WAS',
};

function getGameStatus(status = {}) {
    if (status.type?.state === 'pre') {
        return 'P';
    } else if (status.type?.state === 'post') {
        return 'F';
    }

    return status.period;
}

function getTeamName(competitor = {}) {
    const team = competitor.team?.abbreviation;

    return teamNameMapping[team] || team;
}

function mapEventEntry(event = {}) {
    const ongoing = !['pre', 'post'].includes(event.status?.type?.state);
    const remainingTime = ongoing && event.status?.displayClock;

    return {
        $: {
            h: getTeamName(event.competitions?.[0]?.competitors?.[0]),
            hs: event.competitions?.[0]?.competitors?.[0]?.score,
            q: getGameStatus(event.status),
            starttime: event.date,
            v: getTeamName(event.competitions?.[0]?.competitors?.[1]),
            vs: event.competitions?.[0]?.competitors?.[1]?.score,
            k: remainingTime
        }
    };
}

async function getData() {
    const response = await fetch(`${BASE_URL}/scoreboard`);

    if (!response.ok) {
        throw new Error('failed to fetch scoreboard');
    }

    const parsedResponse = await response.json();

    const details = {
        w: parsedResponse?.week?.number,
        y: parsedResponse?.season?.year,
        t: seasonTypeMapping[parsedResponse?.season?.type]
    };

    const events = parsedResponse?.events || [];

    const scores = events.map(mapEventEntry).sort((a, b) => {
        if (a.$.starttime === b.$.starttime) {
            return 0;
        }

        return a.$.starttime > b.$.starttime ? 1 : -1
    });

    return {details, scores};
}

module.exports = {getData};
<commit_msg>display halftime for live games<commit_after>const fetch = require('node-fetch');

const BASE_URL = 'http://site.api.espn.com/apis/site/v2/sports/football/nfl';

const seasonTypeMapping = {
    1: 'P',
    2: 'R',
    3: 'POST',
    4: 'OFF',
};

const teamNameMapping = {
    LAR: 'LA',
    WSH: 'WAS',
};

function getGameStatus(status = {}) {
    if (status.type?.state === 'pre') {
        return 'P';
    } else if (status.type?.name === 'STATUS_HALFTIME') {
        return 'H';
    } else if (status.type?.state === 'post') {
        return 'F';
    }

    return status.period;
}

function getTeamName(competitor = {}) {
    const team = competitor.team?.abbreviation;

    return teamNameMapping[team] || team;
}

function mapEventEntry(event = {}) {
    const ongoing = !['pre', 'post'].includes(event.status?.type?.state);
    const remainingTime = ongoing && event.status?.displayClock;

    return {
        $: {
            h: getTeamName(event.competitions?.[0]?.competitors?.[0]),
            hs: event.competitions?.[0]?.competitors?.[0]?.score,
            q: getGameStatus(event.status),
            starttime: event.date,
            v: getTeamName(event.competitions?.[0]?.competitors?.[1]),
            vs: event.competitions?.[0]?.competitors?.[1]?.score,
            k: remainingTime
        }
    };
}

async function getData() {
    const response = await fetch(`${BASE_URL}/scoreboard`);

    if (!response.ok) {
        throw new Error('failed to fetch scoreboard');
    }

    const parsedResponse = await response.json();

    const details = {
        w: parsedResponse?.week?.number,
        y: parsedResponse?.season?.year,
        t: seasonTypeMapping[parsedResponse?.season?.type]
    };

    const events = parsedResponse?.events || [];

    const scores = events.map(mapEventEntry).sort((a, b) => {
        if (a.$.starttime === b.$.starttime) {
            return 0;
        }

        return a.$.starttime > b.$.starttime ? 1 : -1
    });

    return {details, scores};
}

module.exports = {getData};
<|endoftext|>


<commit_before>(function() {

  var handler = Gmaps.build('Google');
  // console.dir(handler);
  var mapOptions = $('meta[name=mapOptions]').attr('content');
  var locations = $('meta[name=locations]').attr('content');
  var categories = $('meta[name=categories]').attr('content');

  var markerLocations = [];
  var filteredLocations = [];
  var meetupList = $('.list a');
  var defaultCoord = {lat: 49.282982, lng: -123.056554};
  var defaultLatLng = new google.maps.LatLng(defaultCoord.lat, defaultCoord.lng);
  var categoryList = $('.js-menu > ul');
  var cardsWrapper = $('.cards');
  var markerIcon = {
    "url": 'images/directory/map-pin.png',
    "width": 33,
    "height": 39
  };

  var generateMarkerData = function(element) {

    var orgMarkup = "";

    orgMarkup += "
"+element.name+"
";
    orgMarkup += "
"+element.address+"
";
    orgMarkup += "
Go to website
";

    element.infowindow = "
"+orgMarkup+"
";
    element.picture = markerIcon;

    if(element.lat && element.lng){
      markerLocations.push(element);
    }

  };

  var setDefaultLocation = function() {
    handler.buildMap(mapOptions, function() {
      handler.map.centerOn(defaultLatLng);
      handler.getMap().setZoom(14);
    });
  };

  var setZoomBasedOnLatitudePosition = function (latitudePosition) {
    if(latitudePosition != defaultCoord.lat){
      handler.getMap().setZoom(16);
    }else{
      handler.getMap().setZoom(14);
    }
  };

  var setGeolocation = function(pos) {
    var crd = pos.coords;
    var latlng = new google.maps.LatLng(crd.latitude, crd.longitude);
    handler.map.centerOn(latlng);
    setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  };

  var bindLiToMarker = function(json_array) {
    _.each(json_array, function(json){

      var markerId = json.name.toLowerCase().replace(/\W/g, '');
      var currentMarker = $('#'+markerId);

      currentMarker.on('click', function(e){
        meetupList.removeClass('active');
        $(this).addClass("active");
        e.preventDefault();
        handler.getMap().setZoom(16);
        json.marker.setMap(handler.getMap()); //because clusterer removes map property from marker
        json.marker.panTo();
        google.maps.event.trigger(json.marker.getServiceObject(), 'click');

        $("html, body").animate({
          scrollTop:0
        },"slow");
      });

      google.maps.event.addListener(json.marker.getServiceObject(), 'click', function(){
        meetupList.removeClass('active');
        currentMarker.addClass("active");
        handler.getMap().setZoom(20);
      });
    });
  };

  var createCard = function(point){

    var card = $("
", {class: "card"});
    var cardHeader = $("
", {class: "card-header", html: point.name});
    var phone = $("
", {html: point.phone});
    var cardCopy = $("
", {class: "card-copy", html: point.address}).append(phone);

    card.append(cardHeader).append(cardCopy);
    cardsWrapper.append(card);
  };

  var drawMap = function(points) {
    var markers = handler.addMarkers(points);

    _.each(points, function(json, index){
      json.marker = markers[index];

      createCard(json);
    });

    handler.bounds.extendWith(markers);

    // setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  };

  var cleanMap = function(points) {
    handler.removeMarkers();
    cardsWrapper.html('');
  };

  var zoomToPosition = function(position) {
    var marker = handler.addMarker({
      lat: position.coords.latitude,
      lng: position.coords.longitude
    });
    handler.map.centerOn(marker);
    handler.bounds.extendWith(marker);
    handler.getMap().setZoom(18);
  };

  var generateCategoriesList = function(element) {
    var link = $("", {html: element.name, href: '#'});
    var listItem = $("
").append(link);
    categoryList.append(listItem);
    link.on('click', function(e){
      filterCategories(element.name);
      $('.js-menu-screen').trigger('click');
    });
  };

  var generateCategories = function() {
    _.each(categories, generateCategoriesList);
  };

  var filterCategories = function(categoryFilter){

    var filteredLocations = _.filter(markerLocations, function(item){
      if ((typeof(item.category) !== 'undefined') && (item.category !== null)) {
        return item.category.name == categoryFilter;
      }
    });

    cleanMap(markerLocations);
    buildMap(filteredLocations);

    handler.map.centerOn(defaultLatLng);
    handler.getMap().setZoom(16);

  };

  var buildMap = function(points) {
    handler.buildMap(mapOptions, function() {
      drawMap(points);
    });
  };

  mapOptions = JSON.parse(mapOptions);
  locations = JSON.parse(locations);
  categories = JSON.parse(categories);
  mapOptions.provider.zoomControlOptions = google.maps.ZoomControlStyle.SMALL;

  setDefaultLocation();
  navigator.geolocation.getCurrentPosition(setGeolocation);

  // map all locations on page load
  _.each(locations,generateMarkerData);
  buildMap(markerLocations);

  google.maps.event.addDomListener(window, "resize", function() {
     var center = handler.getMap().getCenter();
     google.maps.event.trigger(handler.getMap(), "resize");
     handler.getMap().setCenter(center);
  });

  generateCategories();

})();
<commit_msg>add link to card header<commit_after>(function() {

  var handler = Gmaps.build('Google');
  // console.dir(handler);
  var mapOptions = $('meta[name=mapOptions]').attr('content');
  var locations = $('meta[name=locations]').attr('content');
  var categories = $('meta[name=categories]').attr('content');

  var markerLocations = [];
  var filteredLocations = [];
  var meetupList = $('.list a');
  var defaultCoord = {lat: 49.282982, lng: -123.056554};
  var defaultLatLng = new google.maps.LatLng(defaultCoord.lat, defaultCoord.lng);
  var categoryList = $('.js-menu > ul');
  var cardsWrapper = $('.cards');
  var markerIcon = {
    "url": 'images/directory/map-pin.png',
    "width": 33,
    "height": 39
  };

  var generateMarkerData = function(element) {

    var orgMarkup = "";

    orgMarkup += "
"+element.name+"
";
    orgMarkup += "
"+element.address+"
";
    orgMarkup += "
Go to website
";

    element.infowindow = "
"+orgMarkup+"
";
    element.picture = markerIcon;

    if(element.lat && element.lng){
      markerLocations.push(element);
    }

  };

  var getCardClass = function(name) {
    return name.replace(/[^a-z0-9\s]/gi, '').replace(/[_\s]/g, '-');
  };

  var setDefaultLocation = function() {
    handler.buildMap(mapOptions, function() {
      handler.map.centerOn(defaultLatLng);
      handler.getMap().setZoom(14);
    });
  };

  var setZoomBasedOnLatitudePosition = function (latitudePosition) {
    if(latitudePosition != defaultCoord.lat){
      handler.getMap().setZoom(16);
    }else{
      handler.getMap().setZoom(14);
    }
  };

  var setGeolocation = function(pos) {
    var crd = pos.coords;
    var latlng = new google.maps.LatLng(crd.latitude, crd.longitude);
    handler.map.centerOn(latlng);
    setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  };

  var bindLiToMarker = function(json_array) {
    _.each(json_array, function(json){

      var markerId = json.name.toLowerCase().replace(/\W/g, '');
      var currentMarker = $('#'+markerId);

      currentMarker.on('click', function(e){
        meetupList.removeClass('active');
        $(this).addClass("active");
        e.preventDefault();
        handler.getMap().setZoom(16);
        json.marker.setMap(handler.getMap()); //because clusterer removes map property from marker
        json.marker.panTo();
        google.maps.event.trigger(json.marker.getServiceObject(), 'click');

        $("html, body").animate({
          scrollTop:0
        },"slow");
      });

      google.maps.event.addListener(json.marker.getServiceObject(), 'click', function(){
        meetupList.removeClass('active');
        currentMarker.addClass("active");
        handler.getMap().setZoom(20);
      });
    });
  };

  var createCard = function(point){

    var cardClass = getCardClass(point.name);
    var card = $("
", {class: "card"});
    var markerLink = $("", {html: point.name, class: cardClass});
    var cardHeader = $("
", {class: "card-header"}).append(markerLink);
    var phone = $("
", {html: point.phone});
    var cardCopy = $("
", {class: "card-copy", html: point.address}).append(phone);

    card.append(cardHeader).append(cardCopy);
    cardsWrapper.append(card);

    //console.log($('.'+cardClass));
  };

  var drawMap = function(points) {
    var markers = handler.addMarkers(points);

    _.each(points, function(json, index){
      json.marker = markers[index];

      createCard(json);

      var cardClass = getCardClass(json.name);
      $(document).on('click', '.'+cardClass, function() {
          console.log(cardClass);
      });

    });

    handler.bounds.extendWith(markers);

    // setZoomBasedOnLatitudePosition(handler.getMap().getCenter().k);
  };

  var cleanMap = function(points) {
    handler.removeMarkers();
    cardsWrapper.html('');
  };

  var zoomToPosition = function(position) {
    var marker = handler.addMarker({
      lat: position.coords.latitude,
      lng: position.coords.longitude
    });
    handler.map.centerOn(marker);
    handler.bounds.extendWith(marker);
    handler.getMap().setZoom(18);
  };

  var generateCategoriesList = function(element) {
    var link = $("", {html: element.name, href: '#'});
    var listItem = $("
").append(link);
    categoryList.append(listItem);
    link.on('click', function(e){
      filterCategories(element.name);
      $('.js-menu-screen').trigger('click');
    });
  };

  var generateCategories = function() {
    _.each(categories, generateCategoriesList);
  };

  var filterCategories = function(categoryFilter){

    var filteredLocations = _.filter(markerLocations, function(item){
      if ((typeof(item.category) !== 'undefined') && (item.category !== null)) {
        return item.category.name == categoryFilter;
      }
    });

    cleanMap(markerLocations);
    buildMap(filteredLocations);

    handler.map.centerOn(defaultLatLng);
    handler.getMap().setZoom(16);

  };

  var buildMap = function(points) {
    handler.buildMap(mapOptions, function() {
      drawMap(points);
    });

  };

  mapOptions = JSON.parse(mapOptions);
  locations = JSON.parse(locations);
  categories = JSON.parse(categories);
  mapOptions.provider.zoomControlOptions = google.maps.ZoomControlStyle.SMALL;

  setDefaultLocation();
  navigator.geolocation.getCurrentPosition(setGeolocation);

  // map all locations on page load
  _.each(locations,generateMarkerData);
  buildMap(markerLocations);

  google.maps.event.addDomListener(window, "resize", function() {
     var center = handler.getMap().getCenter();
     google.maps.event.trigger(handler.getMap(), "resize");
     handler.getMap().setCenter(center);
  });

  generateCategories();

})();
<|endoftext|>


<commit_before>
module.exports = E//val

var operators = {
  "<": function (a, b) {
    return E(a, this) < E(b, this)
  },
  "<=": function (a, b) {
    return E(a, this) <= E(b, this)
  },
  ">": function (a, b) {
    return E(a, this) > E(b, this)
  },
  ">=": function (a, b) {
    return E(a, this) >= E(b, this)
  },
  "==": function (a, b) {
    return E(a, this) == E(b, this)
  },
  "!==": function (a, b) {
    return E(a, this) !== E(b, this)
  },
  "!=": function (a, b) {
    return E(a, this) !== E(b, this)
  },
  "===": function (a, b) {
    return E(a, this) === E(b, this)
  },
  '&&': function (a, b) {
    return E(a, this) && E(b, this)
  },
  '||': function (a, b) {
    return E(a, this) || E(b, this)
  },
  '?:': function (a, b, c) {
    return E(a, this) ? E(b, this) : E(c, this)
  },
  '!': function (a) {
    return !E(a, this)
  },
  '!!': function (a) {
    return !!E(a, this)
  },
  '.': function (a, b) {
    return E(a, this)[E(b, this)]
  },
  '$': function () {
    var l = arguments.length
    var env = this
    for(var i = 0; i < l; i++)
      env = env[arguments[i]]
    return env
  },
  ',': function () {
    var l = arguments.length
    var last
    for(var i = 0; i < l; i++)
      last= E(arguments[i], this)
    return last
  },
  '{}': function () {
    var l = arguments.length
    var obj = {}
    for(var i = 0; i < l; i += 2) {
      obj[arguments[i]] = E(arguments[i+1], this)
    }
    return obj
  },
  '[]': function () {
    return [].slice.call(arguments).map(E.bind(this))
  }
}

var isArray = Array.isArray

//eval
function E(list, env) {
  env = env || this
  if(!isArray(list)) return list

  var name = list.shift()
  var op = operators[name]
  if(!op) throw new Error('unknown operator:' + name)
  if(!op.length) //operator takes an arbitary number of args. only [] so far)

  if(op.length && op.length !== list.length)
    throw new Error('operator:'+name + ' expects ' + op.length + ' arguments, but got:' + list.length)

  if(!list.length) throw new Error('operator:'+name + ' must have at least 1 argument')

  return op.apply(env, list)
}

<commit_msg>implement function application<commit_after>
module.exports = E//val

var operators = {
  "<": function (a, b) {
    return E(a, this) < E(b, this)
  },
  "<=": function (a, b) {
    return E(a, this) <= E(b, this)
  },
  ">": function (a, b) {
    return E(a, this) > E(b, this)
  },
  ">=": function (a, b) {
    return E(a, this) >= E(b, this)
  },
  "==": function (a, b) {
    return E(a, this) == E(b, this)
  },
  "!==": function (a, b) {
    return E(a, this) !== E(b, this)
  },
  "!=": function (a, b) {
    return E(a, this) !== E(b, this)
  },
  "===": function (a, b) {
    return E(a, this) === E(b, this)
  },
  '&&': function (a, b) {
    return E(a, this) && E(b, this)
  },
  '||': function (a, b) {
    return E(a, this) || E(b, this)
  },
  '?:': function (a, b, c) {
    return E(a, this) ? E(b, this) : E(c, this)
  },
  '!': function (a) {
    return !E(a, this)
  },
  '!!': function (a) {
    return !!E(a, this)
  },
  '.': function (a, b) {
    return E(a, this)[E(b, this)]
  },
  '$': function () {
    var l = arguments.length
    var env = this
    for(var i = 0; i < l; i++)
      env = env[arguments[i]]
    return env
  },
  ',': function () {
    var l = arguments.length
    var last
    for(var i = 0; i < l; i++)
      last= E(arguments[i], this)
    return last
  },
  '{}': function () {
    var l = arguments.length
    var obj = {}
    for(var i = 0; i < l; i += 2) {
      obj[arguments[i]] = E(arguments[i+1], this)
    }
    return obj
  },
  '[]': function () {
    return [].slice.call(arguments).map(E.bind(this))
  },
  '()': function () {
    var fun = arguments[0]
    var context = fun[0] === '$' && fun.length > 2
      ? E(fun.slice(0, fun.length - 1), this)
      : undefined

    return E(fun, this)
      .apply(
        context,
        [].slice.call(arguments, 1)
        .map(function (arg) { return E(arg, this) })
      )
  }
}

var isArray = Array.isArray

//eval
function E(list, env) {
  env = env || this
  if(!isArray(list)) return list

  var name = list[0]
  var op = operators[name]
  if(!op)
    throw new Error('unknown operator:' + name)

  if(!op.length) //operator takes an arbitary number of args. only [] so far)

  if(op.length && op.length !== list.length)
    throw new Error('operator:'+name + ' expects ' + op.length + ' arguments, but got:' + list.length)

  if(!list.length)
    throw new Error('operator:'+name + ' must have at least 1 argument')

  return op.apply(env, list.slice(1))
}

<|endoftext|>


<commit_before>TC.Util.ExcelExport = function () {

    var EOL = '\r\n';
    var BOM = "\ufeff";

    /**
     * Stringify one field
     * @param data
     * @param delimier
     * @returns {*}
     */
    this.stringifyField = function (data, delimier, quoteText) {
        if (typeof data === 'string') {
            data = data.replace(/"/g, '""'); // Escape double qoutes
            if (quoteText || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) data = delimier + data + delimier;
            return data;
        }

        if (typeof data === 'boolean') {
            return data ? 'TRUE' : 'FALSE';
        }

        return data;
    };

    /**
     * Creates a csv from a data array
     * @param data
     * @param options
     *  * header - Provide the first row (optional)
     *  * fieldSep - Field separator, default: ',',
     *  * addByteOrderMarker - Add Byte order mark, default(false)
     * @param callback
     */
    this.stringify = function (responseData, options) {

        var that = this;
        var csv = "";
        var csvContent = "";

        var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var fromCharCode = String.fromCharCode;
        var INVALID_CHARACTER_ERR = (function () {
            // fabricate a suitable error object
            try {
                document.createElement('$');
            } catch (error) {
                return error;
            }
        }());

        // encoder
        window.btoa || (window.btoa = function (string) {
            var a, b, b1, b2, b3, b4, c, i = 0, len = string.length, max = Math.max, result = '';

            while (i < len) {
                a = string.charCodeAt(i++) || 0;
                b = string.charCodeAt(i++) || 0;
                c = string.charCodeAt(i++) || 0;

                if (max(a, b, c) > 0xFF) {
                    throw INVALID_CHARACTER_ERR;
                }

                b1 = (a >> 2) & 0x3F;
                b2 = ((a & 0x3) << 4) | ((b >> 4) & 0xF);
                b3 = ((b & 0xF) << 2) | ((c >> 6) & 0x3);
                b4 = c & 0x3F;

                if (!b) {
                    b3 = b4 = 64;
                } else if (!c) {
                    b4 = 64;
                }
                result += characters.charAt(b1) + characters.charAt(b2) + characters.charAt(b3) + characters.charAt(b4);
            }
            return result;
        });

        // decoder
        window.atob || (window.atob = function (string) {
            string = string.replace(/=+$/, '');
            var a, b, b1, b2, b3, b4, c, i = 0, len = string.length, chars = [];

            if (len % 4 === 1)
                throw INVALID_CHARACTER_ERR;

            while (i < len) {
                b1 = characters.indexOf(string.charAt(i++));
                b2 = characters.indexOf(string.charAt(i++));
                b3 = characters.indexOf(string.charAt(i++));
                b4 = characters.indexOf(string.charAt(i++));

                a = ((b1 & 0x3F) << 2) | ((b2 >> 4) & 0x3);
                b = ((b2 & 0xF) << 4) | ((b3 >> 2) & 0xF);
                c = ((b3 & 0x3) << 6) | (b4 & 0x3F);

                chars.push(fromCharCode(a));
                b && chars.push(fromCharCode(b));
                c && chars.push(fromCharCode(c));
            }
            return chars.join('');
        });

        var arrData = [];

        if (Array.isArray(responseData)) {
            arrData = responseData;
        }
        else if (TC.Util.isFunction(responseData)) {
            arrData = responseData();
        }
        const object2Table = function (obj, str) {
            var _str = str || '';
            if (obj instanceof Array) {
                _str += "

";
                for (var i = 0; i < obj.length; i++)
                    _str += ("
" + object2Table(obj[i], str) + "
");
                _str += "

";
            }
            else if (obj instanceof Object) {
                _str += "

";
                for (var i in obj) {
                    _str += ("
" + i + "	");
                    if (obj[i] instanceof Object)
                        _str += ("" + object2Table(obj[i], str) + "
");
                    else {
                        var cls = cellFormat(obj[i]);
                        obj[i] = cls.value;
                        _str += ('');
                        switch (true) {
                            case typeof (obj[i]) === "string" && obj[i].startsWith("http"):
                                _str += '' + "Abrir" + '';
                                break;
                            default:
                                _str += obj[i];
                                break
                        }
                        _str += ("
");
                    }
                }
                _str += "

";
            }
            return _str;
        }

        const cellFormat = function (item) {
            var cls;
            if (item !== null && (typeof item === "string" || typeof item === "number")) {
                if (item.value) {
                    item = item.value;
                }
                if (("" + item).indexOf("%") != -1) {
                    item = item.replace(" %", "%").replace(/\.|,/g, ds);
                    cls = "percent";
                } else {
                    var num = 0;
                    if (item) {
                        num = typeof item === "number" ? item : (new Number(item.replace ? (item.replace(/\,/g, "").replace(/./g, ".")).trim() : item.trim()));
                    }
                    if (!isNaN(num)) {
                        item = num.toString().replace(".", ds);
                        if (num % 1 > 0) {
                            cls = "number2d";
                        } else {
                            cls = "number";
                        }
                    } else {
                        if (/^\d{1,2}([.\/-])\d{1,2}\1(\d{4}|\d{2})$/.test(item) || /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])[ ,T]{1}(2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9][Z]{0,1}$/.test(item)) {
                            cls = "date";
                        } else {
                            cls = "string";
                        }
                    }
                }
            }
            else if (cls instanceof Object) {
                cls = "";
            }
            else {
                cls = "string";
            }
            return { "class": cls, "value": item };
        }

        var dataString = '
';
        for (var i = 0; i < 1; i++) {
            dataString += '
';
            for (var j in arrData[i]) {
                if (arrData[i].hasOwnProperty(j)) {
                    dataString += '' + arrData[i][j] + '	';
                }
            }

            dataString += '
';
        }
        dataString += '
';

        dataString += '
';

        //detectamos separador de miles y de coma en función de la confugración regional de la máquina
        let language = navigator.language.substring(0, 5);
        var ds, ms;
        try {
            ds = (1.1).toLocaleString(language).substring(1, 2);
            ms = (1000).toLocaleString(language).substring(1, 2);
        }
        catch (ex) {
            ds = (1.1).toLocaleString("es-ES").substring(1, 2);
            ms = (1000).toLocaleString("es-ES").substring(1, 2);
        }

        for (var i = 1; i < arrData.length; i++) {
            dataString += '
';
            for (var j = 0; j < arrData[i].length; j++) {
                if (arrData[i].hasOwnProperty(j)) {
                    var item = arrData[i][j];
                    // Calculo de formato para Excel
                    const cls = cellFormat(item);
                    item = cls.value;
                    if (item instanceof Object) {
                        dataString += ('' + object2Table(item) + '	');
                    }
                    else {
                        dataString += '' + item.value + '	';
                            } if (item.hasOwnProperty('colspan')) {
                                dataString += ' colspan="' + item.colspan + '">' + item.value + '	';
                            }
                            j++;
                        }
                        else {
                            dataString += '>' + (item == null ? '' : item) + '	';
                        }
                    }
                }
            }
            dataString += '
';
        }
        dataString += '
';

        var template = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name=ProgId content=Excel.Sheet><meta name=Generator content="Microsoft Excel 9">

{caption}
{table}
';
        var format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) };
        var ctx = { worksheet: options.workSheet || 'Hoja1', table: dataString, caption: options.title || "" };
        csv = format(template, ctx);
        return csv;
    };

};
TC.Util.ExcelExport.prototype.Save = function (filename, rows, title) {
    var processRow = function (row) {
        var finalVal = '';
        for (var j = 0; j < row.length; j++) {
            var innerValue = row[j] === null ? '' : row[j].toString();
            if (row[j] instanceof Date) {
                innerValue = row[j].toLocaleString();
            };
            var result = innerValue.replace(/"/g, '""');
            if (result.search(/("|,|\n)/g) >= 0)
                result = '"' + result + '"';
            if (j > 0)
                finalVal += '\t';
            finalVal += result;
        }
        return finalVal + '\n';
    };

    var csvFile;
    for (var i = 0; i < rows.length; i++) {
        csvFile += processRow(rows[i]);
    }

    var exporter = this;
    csvFile = exporter.stringify(rows, { txtDelim: "\"", fieldSep: ";", title: title || "" });

    var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
    if (navigator.msSaveBlob) { // IE 10+
        navigator.msSaveBlob(blob, filename);
    } else {
        var link = document.createElement("a");
        if (link.download !== undefined) { // feature detection
            // Browsers that support HTML5 download attribute
            var url = URL.createObjectURL(blob);
            link.setAttribute("href", url);
            link.setAttribute("download", filename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
    }

    //if (TC.Util.detectIE()) { //IE
    //    if (document.execCommand) {
    //        var downloadWin = window.open("about:blank", "_blank");
    //        downloadWin.document.write(csvFile);
    //        downloadWin.document.close();

    //        var success = downloadWin.document.execCommand('SaveAs', true, filename)
    //        downloadWin.close();
    //    }
    //} else { //Resto de navegadores
    //    var uri = 'data:application/vnd.ms-excel;base64,';
    //    var base64 = function (s) { return window.btoa(unescape(encodeURIComponent(s))) };
    //    csvFile = uri + base64(csvFile);

    //    var downloadLink = document.createElement('a');
    //    downloadLink.setAttribute('href', csvFile);
    //    downloadLink.setAttribute('download', filename);

    //    document.body.appendChild(downloadLink);
    //    window.setTimeout(function () {
    //        downloadLink.click();
    //        document.body.removeChild(downloadLink);
    //    }, 0);
    //}
};
<commit_msg>Add use case, remove unused code<commit_after>TC.Util.ExcelExport = function () {

    var EOL = '\r\n';
    var BOM = "\ufeff";

    /**
     * Stringify one field
     * @param data
     * @param delimier
     * @returns {*}
     */
    this.stringifyField = function (data, delimier, quoteText) {
        if (typeof data === 'string') {
            data = data.replace(/"/g, '""'); // Escape double qoutes
            if (quoteText || data.indexOf(',') > -1 || data.indexOf('\n') > -1 || data.indexOf('\r') > -1) data = delimier + data + delimier;
            return data;
        }

        if (typeof data === 'boolean') {
            return data ? 'TRUE' : 'FALSE';
        }

        return data;
    };

    /**
     * Creates a csv from a data array
     * @param data
     * @param options
     *  * header - Provide the first row (optional)
     *  * fieldSep - Field separator, default: ',',
     *  * addByteOrderMarker - Add Byte order mark, default(false)
     * @param callback
     */
    this.stringify = function (responseData, options) {

        var that = this;
        var csv = "";
        var csvContent = "";

        var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
        var fromCharCode = String.fromCharCode;
        var INVALID_CHARACTER_ERR = (function () {
            // fabricate a suitable error object
            try {
                document.createElement('$');
            } catch (error) {
                return error;
            }
        }());

        // encoder
        window.btoa || (window.btoa = function (string) {
            var a, b, b1, b2, b3, b4, c, i = 0, len = string.length, max = Math.max, result = '';

            while (i < len) {
                a = string.charCodeAt(i++) || 0;
                b = string.charCodeAt(i++) || 0;
                c = string.charCodeAt(i++) || 0;

                if (max(a, b, c) > 0xFF) {
                    throw INVALID_CHARACTER_ERR;
                }

                b1 = (a >> 2) & 0x3F;
                b2 = ((a & 0x3) << 4) | ((b >> 4) & 0xF);
                b3 = ((b & 0xF) << 2) | ((c >> 6) & 0x3);
                b4 = c & 0x3F;

                if (!b) {
                    b3 = b4 = 64;
                } else if (!c) {
                    b4 = 64;
                }
                result += characters.charAt(b1) + characters.charAt(b2) + characters.charAt(b3) + characters.charAt(b4);
            }
            return result;
        });

        // decoder
        window.atob || (window.atob = function (string) {
            string = string.replace(/=+$/, '');
            var a, b, b1, b2, b3, b4, c, i = 0, len = string.length, chars = [];

            if (len % 4 === 1)
                throw INVALID_CHARACTER_ERR;

            while (i < len) {
                b1 = characters.indexOf(string.charAt(i++));
                b2 = characters.indexOf(string.charAt(i++));
                b3 = characters.indexOf(string.charAt(i++));
                b4 = characters.indexOf(string.charAt(i++));

                a = ((b1 & 0x3F) << 2) | ((b2 >> 4) & 0x3);
                b = ((b2 & 0xF) << 4) | ((b3 >> 2) & 0xF);
                c = ((b3 & 0x3) << 6) | (b4 & 0x3F);

                chars.push(fromCharCode(a));
                b && chars.push(fromCharCode(b));
                c && chars.push(fromCharCode(c));
            }
            return chars.join('');
        });

        var arrData = [];

        if (Array.isArray(responseData)) {
            arrData = responseData;
        }
        else if (TC.Util.isFunction(responseData)) {
            arrData = responseData();
        }
        const object2Table = function (obj, str) {
            var _str = str || '';
            if (obj instanceof Array) {
                _str += "

";
                for (var i = 0; i < obj.length; i++)
                    _str += ("
" + object2Table(obj[i], str) + "
");
                _str += "

";
            }
            else if (obj instanceof Object) {
                _str += "

";
                for (var i in obj) {
                    _str += ("
" + i + "	");
                    if (obj[i] instanceof Object)
                        _str += ("" + object2Table(obj[i], str) + "
");
                    else {
                        var cls = cellFormat(obj[i]);
                        obj[i] = cls.value;
                        _str += ('');
                        switch (true) {
                            case typeof (obj[i]) === "string" && obj[i].startsWith("http"):
                                _str += '' + "Abrir" + '';
                                break;
                            default:
                                _str += obj[i];
                                break
                        }
                        _str += ("
");
                    }
                }
                _str += "

";
            } else {
                _str += obj;
            }
            return _str;
        }

        const cellFormat = function (item) {
            var cls;
            if (item !== null && (typeof item === "string" || typeof item === "number")) {
                if (item.value) {
                    item = item.value;
                }
                if (("" + item).indexOf("%") != -1) {
                    item = item.replace(" %", "%").replace(/\.|,/g, ds);
                    cls = "percent";
                } else {
                    var num = 0;
                    if (item) {
                        num = typeof item === "number" ? item : (new Number(item.replace ? (item.replace(/\,/g, "").replace(/./g, ".")).trim() : item.trim()));
                    }
                    if (!isNaN(num)) {
                        item = num.toString().replace(".", ds);
                        if (num % 1 > 0) {
                            cls = "number2d";
                        } else {
                            cls = "number";
                        }
                    } else {
                        if (/^\d{1,2}([.\/-])\d{1,2}\1(\d{4}|\d{2})$/.test(item) || /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])[ ,T]{1}(2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9][Z]{0,1}$/.test(item)) {
                            cls = "date";
                        } else {
                            cls = "string";
                        }
                    }
                }
            }
            else if (cls instanceof Object) {
                cls = "";
            }
            else {
                cls = "string";
            }
            return { "class": cls, "value": item };
        }

        var dataString = '
';
        for (var i = 0; i < 1; i++) {
            dataString += '
';
            for (var j in arrData[i]) {
                if (arrData[i].hasOwnProperty(j)) {
                    dataString += '' + arrData[i][j] + '	';
                }
            }

            dataString += '
';
        }
        dataString += '
';

        dataString += '
';

        //detectamos separador de miles y de coma en función de la confugración regional de la máquina
        let language = navigator.language.substring(0, 5);
        var ds, ms;
        try {
            ds = (1.1).toLocaleString(language).substring(1, 2);
            ms = (1000).toLocaleString(language).substring(1, 2);
        }
        catch (ex) {
            ds = (1.1).toLocaleString("es-ES").substring(1, 2);
            ms = (1000).toLocaleString("es-ES").substring(1, 2);
        }

        for (var i = 1; i < arrData.length; i++) {
            dataString += '
';
            for (var j = 0; j < arrData[i].length; j++) {
                if (arrData[i].hasOwnProperty(j)) {
                    var item = arrData[i][j];
                    // Calculo de formato para Excel
                    const cls = cellFormat(item);
                    item = cls.value;
                    if (item instanceof Object) {
                        dataString += ('' + object2Table(item) + '	');
                    }
                    else {
                        dataString += '' + item.value + '	';
                            } if (item.hasOwnProperty('colspan')) {
                                dataString += ' colspan="' + item.colspan + '">' + item.value + '	';
                            }
                            j++;
                        }
                        else {
                            dataString += '>' + (item == null ? '' : item) + '	';
                        }
                    }
                }
            }
            dataString += '
';
        }
        dataString += '
';

        var template = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name=ProgId content=Excel.Sheet><meta name=Generator content="Microsoft Excel 9">

{caption}
{table}
';
        var format = function (s, c) { return s.replace(/{(\w+)}/g, function (m, p) { return c[p]; }) };
        var ctx = { worksheet: options.workSheet || 'Hoja1', table: dataString, caption: options.title || "" };
        csv = format(template, ctx);
        return csv;
    };

};
TC.Util.ExcelExport.prototype.Save = function (filename, rows, title) {

    var exporter = this;
    csvFile = exporter.stringify(rows, { txtDelim: "\"", fieldSep: ";", title: title || "" });

    var blob = new Blob([csvFile], { type: 'text/csv;charset=utf-8;' });
    if (navigator.msSaveBlob) { // IE 10+
        navigator.msSaveBlob(blob, filename);
    } else {
        var link = document.createElement("a");
        if (link.download !== undefined) { // feature detection
            // Browsers that support HTML5 download attribute
            var url = URL.createObjectURL(blob);
            link.setAttribute("href", url);
            link.setAttribute("download", filename);
            link.style.visibility = 'hidden';
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }
    }

};
<|endoftext|>


<commit_before>/// <reference path="node.d.ts" />
var semver = require('semver');
var getVer = require('get-ver');
var bluebird = require('bluebird');
var GetPkg = bluebird.promisifyAll(require('./getPkg'));
var _ = require('lodash');
var path = require('path');
var pkgInfo = [];
var fs = require('fs');

var deli = '/'

// GetPkg.packageJson(function(err, res) {
//   var pkgs = []
//   var versions = []
//   for (var pkg in res.dependencies) {
//     pkgs.push({
//       name: pkg,
//       path: '',
//       version: res.dependencies[pkg]
//     })
//   }
//   get(pkgs)
//     .then(function(pkgs) {
//       console.log(pkgs)
//       console.log(pkgs.length)
//       var tempTest = _.uniqBy(pkgs, 'name')
//       var temp = _.uniqWith(pkgs, isSame)
//       fs.writeFileSync('pack.json', JSON.stringify(pkgs, null, 2),'utf8')
//       console.log(temp.length)
//       console.log(tempTest.length)
//     })
// })
function getList() {
    try {
        return JSON.parse(fs.readFileSync('pack.json', 'utf8'));
    }
    catch (err) {
        return { err: err };
    }
}
function tree(pkgs) {
    for (var i = 0; i < pkgs.length; i++) {
        pkgs[i].layer = (pkgs[i].path.split(deli)).length;
    }
    // console.log(pkgs)

    var tree = buildTree(pkgs)

    // var uniquePkgs = _.uniqWith(pkgs, isSame)
    // var conflictPkgs = getConflictPkgs(uniquePkgs)
    // console.log(uniquePkgs.length)
    // console.log(conflictPkgs.length)
}

function buildTree (pkgs) {
    var tree = {};
    var layer = 1;
    var layerPkgs = [];
    for (var i = pkgs.length - 1; i >= 0; i--) {
        if (layer !== pkgs[i].layer - 1) {
            layer = pkgs[i].layer - 1
            layerPkgs[layer] ={}
        }
        layerPkgs[layer][path.basename(pkgs[i].path)] = pkgs[i];
    }

    console.log(layerPkgs[1]['tar'].path.split(deli)[layerPkgs[1]['tar'].layer - 2])
    console.log(layerPkgs[1]['tar'].layer)

    // for (var i = 1; i < layerPkgs.length; i++) {
    //     for (var x = 0; x < layerPkgs[i].length; x++) {

    //     }
    // }
}

tree(getList());
function getConflictPkgs(pkgs) {
    var tmp = {};
    var dups = _.reduce(pkgs, function (result, value, key) {
        (result[value.name] || (result[value.name] = [])).push(value);
        return result;
    }, {});
    var conflictPkgs = _.filter(dups, function (o) {
        return o.length > 1;
    });
    return conflictPkgs;
}
function isSame(left, right) {
    if (left.name === right.name) {
        if (left.version !== right.version) {
            return false;
        }
        return true;
    }
    return false;
}
function get(pkgs) {
    if (pkgs.length <= 0) {
        return;
    }
    var dependencies = [];
    return bluebird.map(pkgs, function (pkg) {
        return GetPkg.httpAsync(pkg.name)
            .then(function (res) {
            // Get version
            var version = semver.maxSatisfying(Object.keys(res.versions), pkg.version);
            var index = pkgs.indexOf(pkg);
            pkgs[index] = {
                path: path.join(pkg.path, pkg.name),
                name: pkg.name,
                version: version
            };
            // Get dependencies
            var tmp = res.versions[version].dependencies;
            if (tmp && tmp !== {}) {
                for (var package in tmp) {
                    dependencies.push({
                        name: package,
                        path: pkgs[index].path,
                        version: tmp[package]
                    });
                }
            }
        });
    })
        .then(function () {
        // return pkgs
        if (dependencies.length > 0) {
            return get(dependencies)
                .then(function (dependencies) {
                if (dependencies) {
                    pkgs = _.concat(pkgs, dependencies);
                }
                return pkgs;
            });
        }
    });
}
<commit_msg>check<commit_after>/// <reference path="node.d.ts" />
var semver = require('semver');
var getVer = require('get-ver');
var bluebird = require('bluebird');
var GetPkg = bluebird.promisifyAll(require('./getPkg'));
var _ = require('lodash');
var path = require('path');
var pkgInfo = [];
var fs = require('fs');

var deli = '/'

// GetPkg.packageJson(function(err, res) {
//   var pkgs = []
//   var versions = []
//   for (var pkg in res.dependencies) {
//     pkgs.push({
//       name: pkg,
//       path: '',
//       version: res.dependencies[pkg]
//     })
//   }
//   get(pkgs)
//     .then(function(pkgs) {
//       console.log(pkgs)
//       console.log(pkgs.length)
//       var tempTest = _.uniqBy(pkgs, 'name')
//       var temp = _.uniqWith(pkgs, isSame)
//       fs.writeFileSync('pack.json', JSON.stringify(pkgs, null, 2),'utf8')
//       console.log(temp.length)
//       console.log(tempTest.length)
//     })
// })
function getList() {
    try {
        return JSON.parse(fs.readFileSync('pack.json', 'utf8'));
    }
    catch (err) {
        return { err: err };
    }
}
function tree(pkgs) {
    for (var i = 0; i < pkgs.length; i++) {
        pkgs[i].layer = (pkgs[i].path.split(deli)).length;
    }
    // console.log(pkgs)
    pkgs = construct(pkgs)
    var tree = buildTree(pkgs)

    // var uniquePkgs = _.uniqWith(pkgs, isSame)
    // var conflictPkgs = getConflictPkgs(uniquePkgs)
    // console.log(uniquePkgs.length)
    // console.log(conflictPkgs.length)
}

function construct (pkgs) {
    var result = {}
    for (var i = 0; i < pkgs.length; i++) {
        result[pkgs[i].name] = pkgs[i]
    }
    return result
}

function buildTree (pkgs) {

    var tmp = {}
    var tmp1 = {}

    for (var pkg in pkgs) {

    }

    // var tree = {};
    // var layer = 1;
    // var layerPkgs = [];
    // var dependent = ''
    // var tmpDependencies = {}
    // for (var i = pkgs.length - 1; i >= 0; i--) {
    //     if (layer !== pkgs[i].layer - 1) {
    //         layer = pkgs[i].layer - 1
    //         layerPkgs[layer] ={}
    //         tmpDependencies = {}

    //         for (var pkg in tmpDependencies) {

    //         }
    //     }

    //     var tmpDependent = layerPkgs[i]['tar'].path.split(deli)[layerPkgs[i]['tar'].layer - 2]
    //     if (tmpDependent !== dependent) {
    //         dependent = tmpDependent
    //         tmpDependencies[tmpDependent] = []
    //     }

    //     tmpDependent[tmpDependent].push(pkg)

    //     // layerPkgs[layer][path.basename(pkgs[i].path)] = pkgs[i];
    // }
}

function makeChange (obj, path, value) {
    if (typeof obj === 'object') {
        if (path < 1) {
            obj[path] = value
            return {msg: 'Updated'}
        } else {
            return {error: 'Could not reach destination'}
        }
    }

    return {error: 'Could not reach destination'}
}

tree(getList());
function getConflictPkgs(pkgs) {
    var tmp = {};
    var dups = _.reduce(pkgs, function (result, value, key) {
        (result[value.name] || (result[value.name] = [])).push(value);
        return result;
    }, {});
    var conflictPkgs = _.filter(dups, function (o) {
        return o.length > 1;
    });
    return conflictPkgs;
}
function isSame(left, right) {
    if (left.name === right.name) {
        if (left.version !== right.version) {
            return false;
        }
        return true;
    }
    return false;
}
function get(pkgs) {
    if (pkgs.length <= 0) {
        return;
    }
    var dependencies = [];
    return bluebird.map(pkgs, function (pkg) {
        return GetPkg.httpAsync(pkg.name)
            .then(function (res) {
            // Get version
            var version = semver.maxSatisfying(Object.keys(res.versions), pkg.version);
            var index = pkgs.indexOf(pkg);
            pkgs[index] = {
                path: path.join(pkg.path, pkg.name),
                name: pkg.name,
                version: version
            };
            // Get dependencies
            var tmp = res.versions[version].dependencies;
            if (tmp && tmp !== {}) {
                for (var package in tmp) {
                    dependencies.push({
                        name: package,
                        path: pkgs[index].path,
                        version: tmp[package]
                    });
                }
            }
        });
    })
        .then(function () {
        // return pkgs
        if (dependencies.length > 0) {
            return get(dependencies)
                .then(function (dependencies) {
                if (dependencies) {
                    pkgs = _.concat(pkgs, dependencies);
                }
                return pkgs;
            });
        }
    });
}
<|endoftext|>


<commit_before>"use strict";
// Config file loader

// for "ini" type files
var regex = {
    section:        /^\s*\[\s*([^\]]*)\s*\]\s*$/,
    param:          /^\s*([\w@\._]+)\s*=\s*(.*)\s*$/,
    comment:        /^\s*[;#].*$/,
    line:           /^\s*(.*)\s*$/,
    blank:          /^\s*$/,
    continuation:   /\\[ \t]*$/,
};

var cfreader = exports;

cfreader.watch_files = true;
cfreader._config_cache = {};

cfreader.read_config = function(name, type, cb) {
    // Check cache first
    if (name in cfreader._config_cache) {
        return cfreader._config_cache[name];
    }

    // load config file
    var result = cfreader.load_config(name, type);

    if (result != null && cfreader.watch_files) {
        fs.unwatchFile(name);
        fs.watchFile(name, function (curr, prev) {
            // file has changed, or files has been removed
            if (curr.mtime.getTime() !== prev.mtime.getTime() ||
                curr.nlink !== prev.nlink)
            {
                cfreader.load_config(name, type);
                if (typeof cb === 'function') cb();
            }
        });
    }

    return result;
}

cfreader.empty_config = function(type) {
    if (type === 'ini') {
        return { main: {} };
    }
    else if (type === 'json') {
        return {};
    }
    else {
        return [];
    }
};

cfreader.load_config = function(name, type) {
    var result;

    if (type === 'ini' || /\.ini$/.test(name)) {
        result = cfreader.load_ini_config(name);
    }
    else if (type === 'json' || /\.json$/.test(name)) {
        result = cfreader.load_json_config(name);
    }
    else if (type === 'binary') {
        result = cfreader.load_binary_config(name, type);
    }
    else {
        result = cfreader.load_flat_config(name, type);
        if (result && type !== 'list' && type !== 'data') {
            result = result[0];
            if (/^\d+$/.test(result)) {
                result = parseInt(result);
            }
        }
    }

    cfreader._config_cache[name] = result;

    return result;
};

cfreader.load_json_config = function(name) {
    var result = cfreader.empty_config('json');
    try {
        if (utils.existsSync(name)) {
            result = JSON.parse(fs.readFileSync(name));
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }
    return result;
}

cfreader.load_ini_config = function(name) {
    var result       = cfreader.empty_config('ini');
    var current_sect = result.main;

    try {
        if (utils.existsSync(name)) {
            var data = fs.readFileSync(name, "UTF-8");
            var lines = data.split(/\r\n|\r|\n/);
            var match;
            var pre = '';

            lines.forEach(function(line) {
                if (regex.comment.test(line)) {
                    return;
                }
                else if (regex.blank.test(line)) {
                    return;
                }
                else if (match = regex.section.exec(line)) {
                    current_sect = result[match[1]] = {};
                    return;
                }
                else if (regex.continuation.test(line)) {
                    pre += line.replace(regex.continuation, '');
                    return;
                }
                line = pre + line;
                pre = '';
                if (match = regex.param.exec(line)) {
                    if (/^\d+$/.test(match[2])) {
                        current_sect[match[1]] = parseInt(match[2]);
                    }
                    else {
                        current_sect[match[1]] = match[2];
                    }
                }
                else {
                    logger.logerror("Unvalid line in config file '" + name + "': " + line);
                };
            });
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }

    return result;
};

cfreader.load_flat_config = function(name, type) {
    var result = cfreader.empty_config();

    try {
        if (utils.existsSync(name)) {
            var data   = fs.readFileSync(name, "UTF-8");
            if (type === 'data') {
                while (data.length > 0) {
                    var match = data.match(/^([^\n]*)\n?/);
                    result.push(match[1]);
                    data = data.slice(match[0].length);
                }
                return result;
            }
            var lines  = data.split(/\r\n|\r|\n/);

            lines.forEach( function(line) {
                var line_data;
                if (regex.comment.test(line)) {
                    return;
                }
                else if (regex.blank.test(line)) {
                    return;
                }
                else if (line_data = regex.line.exec(line)) {
                    result.push(line_data[1]);
                }
            });
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }

    // Return hostname for 'me' if no result
    if (/\/me$/.test(name) && !(result && result.length)) {
        return [ require('os').hostname() ];
    }

    // For value types with no result
    if (!(type && (type === 'list' || type === 'data'))) {
        if (!(result && result.length)) {
            return null;
        }
    }
    return result;
};

cfreader.load_binary_config = function(name, type) {
    var result = cfreader.empty_config();

    try {
        if (utils.existsSync(name)) {
            return fs.readFileSync(name);
        }
        return null
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }
};
var fs     = require('fs');
var utils  = require('./utils');
var logger = require('./logger');

<commit_msg>One more caching fix. Reverts 350dd70<commit_after>"use strict";
// Config file loader

// for "ini" type files
var regex = {
    section:        /^\s*\[\s*([^\]]*)\s*\]\s*$/,
    param:          /^\s*([\w@\._]+)\s*=\s*(.*)\s*$/,
    comment:        /^\s*[;#].*$/,
    line:           /^\s*(.*)\s*$/,
    blank:          /^\s*$/,
    continuation:   /\\[ \t]*$/,
};

var cfreader = exports;

cfreader.watch_files = true;
cfreader._config_cache = {};

cfreader.read_config = function(name, type, cb) {
    // Check cache first
    if (name in cfreader._config_cache) {
        return cfreader._config_cache[name];
    }

    // load config file
    var result = cfreader.load_config(name, type);

    if (cfreader.watch_files) {
        fs.unwatchFile(name);
        fs.watchFile(name, function (curr, prev) {
            // file has changed, or files has been removed
            if (curr.mtime.getTime() !== prev.mtime.getTime() ||
                curr.nlink !== prev.nlink)
            {
                cfreader.load_config(name, type);
                if (typeof cb === 'function') cb();
            }
        });
    }

    return result;
}

cfreader.empty_config = function(type) {
    if (type === 'ini') {
        return { main: {} };
    }
    else if (type === 'json') {
        return {};
    }
    else {
        return [];
    }
};

cfreader.load_config = function(name, type) {
    var result;

    if (type === 'ini' || /\.ini$/.test(name)) {
        result = cfreader.load_ini_config(name);
    }
    else if (type === 'json' || /\.json$/.test(name)) {
        result = cfreader.load_json_config(name);
    }
    else if (type === 'binary') {
        result = cfreader.load_binary_config(name, type);
    }
    else {
        result = cfreader.load_flat_config(name, type);
        if (result && type !== 'list' && type !== 'data') {
            result = result[0];
            if (/^\d+$/.test(result)) {
                result = parseInt(result);
            }
        }
    }

    cfreader._config_cache[name] = result;

    return result;
};

cfreader.load_json_config = function(name) {
    var result = cfreader.empty_config('json');
    try {
        if (utils.existsSync(name)) {
            result = JSON.parse(fs.readFileSync(name));
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }
    return result;
}

cfreader.load_ini_config = function(name) {
    var result       = cfreader.empty_config('ini');
    var current_sect = result.main;

    try {
        if (utils.existsSync(name)) {
            var data = fs.readFileSync(name, "UTF-8");
            var lines = data.split(/\r\n|\r|\n/);
            var match;
            var pre = '';

            lines.forEach(function(line) {
                if (regex.comment.test(line)) {
                    return;
                }
                else if (regex.blank.test(line)) {
                    return;
                }
                else if (match = regex.section.exec(line)) {
                    current_sect = result[match[1]] = {};
                    return;
                }
                else if (regex.continuation.test(line)) {
                    pre += line.replace(regex.continuation, '');
                    return;
                }
                line = pre + line;
                pre = '';
                if (match = regex.param.exec(line)) {
                    if (/^\d+$/.test(match[2])) {
                        current_sect[match[1]] = parseInt(match[2]);
                    }
                    else {
                        current_sect[match[1]] = match[2];
                    }
                }
                else {
                    logger.logerror("Unvalid line in config file '" + name + "': " + line);
                };
            });
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }

    return result;
};

cfreader.load_flat_config = function(name, type) {
    var result = cfreader.empty_config();

    try {
        if (utils.existsSync(name)) {
            var data   = fs.readFileSync(name, "UTF-8");
            if (type === 'data') {
                while (data.length > 0) {
                    var match = data.match(/^([^\n]*)\n?/);
                    result.push(match[1]);
                    data = data.slice(match[0].length);
                }
                return result;
            }
            var lines  = data.split(/\r\n|\r|\n/);

            lines.forEach( function(line) {
                var line_data;
                if (regex.comment.test(line)) {
                    return;
                }
                else if (regex.blank.test(line)) {
                    return;
                }
                else if (line_data = regex.line.exec(line)) {
                    result.push(line_data[1]);
                }
            });
        }
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }

    // Return hostname for 'me' if no result
    if (/\/me$/.test(name) && !(result && result.length)) {
        return [ require('os').hostname() ];
    }

    // For value types with no result
    if (!(type && (type === 'list' || type === 'data'))) {
        if (!(result && result.length)) {
            return null;
        }
    }
    return result;
};

cfreader.load_binary_config = function(name, type) {
    var result = cfreader.empty_config();

    try {
        if (utils.existsSync(name)) {
            return fs.readFileSync(name);
        }
        return null
    }
    catch (err) {
        if (err.code === 'EBADF') {
            if (cfreader._config_cache[name]) {
                return cfreader._config_cache[name];
            }
        }
        else {
            throw err;
        }
    }
};
var fs     = require('fs');
var utils  = require('./utils');
var logger = require('./logger');

<|endoftext|>