<commit_before>var Element = function (parent, viewMode) {
    this.parent = parent;
    this.control = this.createControl(viewMode);
    this.state = {
        Enabled: true
    };

    this.childElements = [];

    this.eventStore = new EventStore();
};

Object.defineProperties(Element.prototype, {
    name: {
        get: function () {
            return this.getName()
        }
    }
});

_.extend(Element.prototype, {

    createControl: function (viewMode) {
        throw ('Не перегружен абстрактный метод Element.createControl');
    },

    setParent: function (parentElement) {
        this.parent = parentElement;
    },

    getParent: function () {
        return this.parent;
    },

    getChildElements: function () {
        return this.childElements;
    },

    findAllChildrenByType: function (type) {
        return this._findAllChildren(predicate, getChildElements);

        function predicate() {
            return this.constructor.name === type;
        }

        function getChildElements(element) {
            return element.findAllChildrenByType(type);
        }
    },

    findAllChildrenByName: function (name) {
        return this._findAllChildren(predicate, getChildElements);

        function predicate () {
            return this.getName() === name;
        }

        function getChildElements (element) {
            return element.findAllChildrenByName(name);
        }

    },

    _findAllChildren: function (predicate, getChildElements) {
        var elements = this.getChildElements();
        var items = [];
        if (Array.isArray(elements)) {
            elements.forEach(function (element) {
                if (predicate.call(element)) {
                    items.push(element);
                }
                Array.prototype.push.apply(items, getChildElements(element));
            });
        }

        return items;
    },

    getView: function () {
        if (!this.parentView) {
            if (this.parent instanceof View) {
                this.parentView = this.parent;

            } else {
                if (this.parent && this.parent.getView) {
                    this.parentView = this.parent.getView();
                } else {
                    this.parentView = null;
                }
            }
        }

        return this.parentView;
    },

    getName: function () {
        return this.control.get('name');
    },

    setName: function (name) {
        if (typeof name == 'string') {
            this.control.set('name', name);
        }
    },

    getProperty: function (name) {
        var getterMethodName = 'get' + this._upperFirstSymbol(name);
        if (typeof this[getterMethodName] == 'function') {
            return this[getterMethodName]();
        } else {
            throw 'expect that ' + getterMethodName + ' is getter function';
        }
    },

    setProperty: function (name, value) {
        var setterMethodName = 'set' + this._upperFirstSymbol(name),
            getterMethodName;

        if (typeof this[setterMethodName] == 'function') {
            this[setterMethodName](value);
        } else {
            if (this._isCollectionProperty(name)) {
                getterMethodName = 'get' + this._upperFirstSymbol(name);
                this[getterMethodName]().set(value);
            } else {
                throw 'expect that ' + setterMethodName + ' is setter function';
            }
        }
    },

    _isCollectionProperty: function (propertyName) {
        var getterMethodName = 'get' + this._upperFirstSymbol(propertyName);
        return (typeof this[getterMethodName] == 'function') && this[getterMethodName]() instanceof Collection;
    },

    onPropertyChanged: function (propertyName, handler) {
        var subscribingMethodName = 'on' + this._upperFirstSymbol(propertyName) + 'Changed';
        if (typeof this[subscribingMethodName] == 'function') {
            this[subscribingMethodName](handler);
        } else {
            this.control.on('change:' + propertyName, function (model, value) {
                var parentView = this.getView(),
                    context = parentView ? parentView.getContext() : undefined,
                    args = {
                        property: propertyName,
                        oldValue: model.previous(propertyName),
                        newValue: value
                    };
                handler(context, args);
            }.bind(this));
        }
    },

    getText: function () {
        return this.control.get('text');
    },

    setText: function (text) {
        if (typeof text !== 'undefined') {
            this.control.set('text', text);
        }
    },

    getEnabled: function () {
        return this.control.get('enabled');
    },

    setEnabled: function (isEnabled) {
        if (typeof isEnabled !== 'boolean') {
            return;
        }

        this.setState('Enabled', isEnabled);

        var parentEnabled = this.control.get('parentEnabled');
        var old = this.control.get('enabled');

        isEnabled = parentEnabled && isEnabled;

        if (isEnabled === old) {
            return;
        }

        this.control.set('enabled', isEnabled);
        this.setParentEnabledOnChild(isEnabled);
    },

    setParentEnabledOnChild: function (value) {
        var elements = this.getChildElements();
        if (_.isEmpty(elements) === false) {
            for (var i = 0, ln = elements.length; i < ln; i = i + 1) {
                if (typeof elements[i].setParentEnabled === 'undefined') {
                    continue;
                }
                elements[i].setParentEnabled(value);
            }
        }
    },

    setParentEnabled: function (value) {

        if (typeof value !== 'boolean') {
            return;
        }

        var old = this.control.get('parentEnabled');
        this.control.set('parentEnabled', value);

        if (old !== value) {
            var enabled = value && this.getState('Enabled');
            this.control.set('enabled', enabled);
            this.setParentEnabled(enabled);
            this.setParentEnabledOnChild(enabled);
        }
    },

    getVisible: function () {
        return this.control.get('visible');
    },

    setVisible: function (isVisible) {
        if (typeof isVisible == 'boolean') {
            this.control.set('visible', isVisible);
        }
    },

    getStyle: function () {
        return this.control.get('style');
    },

    setStyle: function (style) {
        if (typeof style == 'string') {
            this.control.set('style', style);
        }
    },

    getTextHorizontalAlignment: function () {
        return this.control.get('textHorizontalAlignment');
    },

    setTextHorizontalAlignment: function (value) {
        if (InfinniUI.Metadata.isValidValue(value, InfinniUI.Metadata.TextHorizontalAlignment)) {
            this.control.set('textHorizontalAlignment', value);
        }
    },

    getHorizontalAlignment: function () {
        return this.control.get('horizontalAlignment');
    },

    setHorizontalAlignment: function (horizontalAlignment) {
        if (typeof horizontalAlignment == 'string') {
            this.control.set('horizontalAlignment', horizontalAlignment);
        }
    },

    getVerticalAlignment: function () {
        return this.control.get('verticalAlignment');
    },

    setVerticalAlignment: function (verticalAlignment) {
        if (typeof verticalAlignment == 'string') {
            this.control.set('verticalAlignment', verticalAlignment);
        }
    },

    getTextStyle: function () {
        return this.control.get('textStyle');
    },

    setTextStyle: function (textStyle) {
        if (typeof textStyle == 'string') {
            this.control.set('textStyle', textStyle);
        }
    },

    getBackground: function () {
        return this.control.get('background');
    },

    setBackground: function (background) {
        if (typeof background == 'string') {
            this.control.set('background', background);
        }
    },

    getForeground: function () {
        return this.control.get('foreground');
    },

    setForeground: function (foreground) {
        if (typeof foreground == 'string') {
            this.control.set('foreground', foreground);
        }
    },

    getTexture: function () {
        return this.control.get('texture');
    },

    setTexture: function (texture) {
        if (typeof texture == 'string') {
            this.control.set('texture', texture);
        }
    },

    onLoaded: function (handler) {
        this.control.onLoaded(handler);
    },

    isLoaded: function () {
        return this.control.isLoaded();
    },

    getFocusable: function () {
        return this.control.get('focusable')
    },

    setFocusable: function (value) {
        this.control.get('focusable', !!value)
    },

    getFocused: function () {
        return this.control.get('focused');
    },

    setFocused: function (value) {
        return this.control.set('focused', !!value);
    },

    onLostFocus: function (handler) {
        this.control.on('OnLostFocus', handler);
    },

    onGotFocus: function (handler) {
        this.control.on('OnGotFocus', handler);
    },

    setToolTip: function (value) {
        this.control.set('toolTip', value);
    },

    getToolTip: function () {
        return this.control.get('toolTip');
    },

    getIsLoaded: function () {
        return this.control.get('isLoaded');
    },

    setIsLoaded: function () {
        this.control.set('isLoaded', true);
    },

    setTag: function (value) {
        this.control.set('tag', value);
    },

    getTag: function () {
        return this.control.get('tag');
    },

    render: function () {
        return this.control.render();
    },

    getWidth: function () {
    },

    getHeight: function () {
    },

    getScriptsStorage: function () {
        return this.getView();
    },

    /**
     * Установка состояния валидации элеменат
     * @param {String} [state="success"]
     * @param {String} [message]
     */
    setValidationState: function (state, message) {
        this.control.set('validationMessage', message);
        this.control.set('validationState', state);
    },

    /**
     * Получение состояния валидации элеменат
     * @return {String} [state="success"]
     */
    getValidationState: function () {
        return this.control.get('validationState');
    },

    getState: function (name) {
        return this.state[name];
    },

    setState: function (name, value) {
        this.state[name] = value;
    },

    onBeforeClick: function (handler) {
        return this.control.onBeforeClick(handler);
    },

    onKeyDown: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingKeyEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onKeyDown(callback);
    },

    onKeyUp: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingKeyEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onKeyUp(callback);
    },

    onClick: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onClick(callback);
    },

    onDoubleClick: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onDoubleClick(callback);
    },

    onMouseDown: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseDown(callback);
    },

    onMouseUp: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseUp(callback);
    },

    onMouseEnter: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseEnter(callback);
    },

    onMouseLeave: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseLeave(callback);
    },

    onMouseMove: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseMove(callback);
    },

    onShowToolTip: function (handler) {
        var control = this.control;

        control.on('change:showToolTip', function () {
            var showToolTip = control.get('showToolTip');
            if (showToolTip && typeof handler === 'function') {
                handler();
            }
        });
    },

    onHideToolTip: function (handler) {
        var control = this.control;

        control.on('change:showToolTip', function () {
            var showToolTip = control.get('showToolTip');
            if (!showToolTip && typeof handler === 'function') {
                handler();
            }
        });
    },

    remove: function (isInitiatedByParent) {
        var logger = window.InfinniUI.global.logger;
        if(this.isRemoved){
            logger.warn('Element.remove: Попытка удалить элемент, который уже был удален');
            return;
        }

        var children = this.childElements;

        for (var i = 0, ii = children.length; i < ii; i++) {
            children[i].remove(true);
        }

        this.control.remove();

        if (this.parent && this.parent.removeChild && !isInitiatedByParent) {
            if(this.parent.isRemoved){
                logger.warn('Element.remove: Попытка удалить элемент из родителя, который помечан как удаленный');
            }else{
                this.parent.removeChild(this);
            }

        }

        this.isRemoved = true;

        this.childElements = undefined;
    },

    removeChild: function (child) {
        var index = this.childElements.indexOf(child);
        if (index != -1) {
            this.childElements.splice(index, 1);
        }
    },

    addChild: function (child) {
        if(!this.isRemoved){
            this.childElements.push(child);

        }else{
            var logger = window.InfinniUI.global.logger;
            logger.warn('Element.addChild: Попытка добавить потомка в удаленный элемент');
        }

    },

    createControlEventHandler: function(element, handler, additionParams) {
        var context;
        additionParams = additionParams || {};

        if (element.parentView) {
            context = element.getView().context;
        }

        return function (message) {
            _.extend(
                message,
                additionParams
            );
            message.source = element;

            return handler.call(undefined, context, message);
        };
    },

    _getHandlingKeyEventData: function (nativeData) {
        var result = {};

        result = {
            source: this,
            key: nativeData.which,
            altKey: nativeData.altKey,
            ctrlKey: nativeData.ctrlKey,
            shiftKey: nativeData.shiftKey,
            nativeEventData: nativeData
        };
        return result;
    },

    _getHandlingMouseEventData: function (nativeData) {
        var result = {};

        result = {
            source: this,
            button: nativeData.which,
            altKey: nativeData.altKey,
            ctrlKey: nativeData.ctrlKey,
            shiftKey: nativeData.shiftKey,
            nativeEventData: nativeData
        };
        return result;
    },

    _upperFirstSymbol: function (s) {
        return s[0].toUpperCase() + s.substr(1);
    }
});<commit_msg>fix passing context to onValueChange. Again<commit_after>var Element = function (parent, viewMode) {
    this.parent = parent;
    this.control = this.createControl(viewMode);
    this.state = {
        Enabled: true
    };

    this.childElements = [];

    this.eventStore = new EventStore();
};

Object.defineProperties(Element.prototype, {
    name: {
        get: function () {
            return this.getName()
        }
    }
});

_.extend(Element.prototype, {

    createControl: function (viewMode) {
        throw ('Не перегружен абстрактный метод Element.createControl');
    },

    setParent: function (parentElement) {
        this.parent = parentElement;
    },

    getParent: function () {
        return this.parent;
    },

    getChildElements: function () {
        return this.childElements;
    },

    findAllChildrenByType: function (type) {
        return this._findAllChildren(predicate, getChildElements);

        function predicate() {
            return this.constructor.name === type;
        }

        function getChildElements(element) {
            return element.findAllChildrenByType(type);
        }
    },

    findAllChildrenByName: function (name) {
        return this._findAllChildren(predicate, getChildElements);

        function predicate () {
            return this.getName() === name;
        }

        function getChildElements (element) {
            return element.findAllChildrenByName(name);
        }

    },

    _findAllChildren: function (predicate, getChildElements) {
        var elements = this.getChildElements();
        var items = [];
        if (Array.isArray(elements)) {
            elements.forEach(function (element) {
                if (predicate.call(element)) {
                    items.push(element);
                }
                Array.prototype.push.apply(items, getChildElements(element));
            });
        }

        return items;
    },

    getView: function () {
        if (!this.parentView) {
            if (this.parent instanceof View) {
                this.parentView = this.parent;

            } else {
                if (this.parent && this.parent.getView) {
                    this.parentView = this.parent.getView();
                } else {
                    this.parentView = null;
                }
            }
        }

        return this.parentView;
    },

    getName: function () {
        return this.control.get('name');
    },

    setName: function (name) {
        if (typeof name == 'string') {
            this.control.set('name', name);
        }
    },

    getProperty: function (name) {
        var getterMethodName = 'get' + this._upperFirstSymbol(name);
        if (typeof this[getterMethodName] == 'function') {
            return this[getterMethodName]();
        } else {
            throw 'expect that ' + getterMethodName + ' is getter function';
        }
    },

    setProperty: function (name, value) {
        var setterMethodName = 'set' + this._upperFirstSymbol(name),
            getterMethodName;

        if (typeof this[setterMethodName] == 'function') {
            this[setterMethodName](value);
        } else {
            if (this._isCollectionProperty(name)) {
                getterMethodName = 'get' + this._upperFirstSymbol(name);
                this[getterMethodName]().set(value);
            } else {
                throw 'expect that ' + setterMethodName + ' is setter function';
            }
        }
    },

    _isCollectionProperty: function (propertyName) {
        var getterMethodName = 'get' + this._upperFirstSymbol(propertyName);
        return (typeof this[getterMethodName] == 'function') && this[getterMethodName]() instanceof Collection;
    },

    onPropertyChanged: function (propertyName, handler) {
        var subscribingMethodName = 'on' + this._upperFirstSymbol(propertyName) + 'Changed';
        if (typeof this[subscribingMethodName] == 'function') {
            this[subscribingMethodName](handler);
        } else {
            this.control.on('change:' + propertyName, function (model, value) {
                var parentView = this.getView(),
                    context = parentView ? parentView.getContext() : undefined,
                    args = {
                        property: propertyName,
                        oldValue: model.previous(propertyName),
                        newValue: value
                    };
                handler(context, args);
            }.bind(this));
        }
    },

    getText: function () {
        return this.control.get('text');
    },

    setText: function (text) {
        if (typeof text !== 'undefined') {
            this.control.set('text', text);
        }
    },

    getEnabled: function () {
        return this.control.get('enabled');
    },

    setEnabled: function (isEnabled) {
        if (typeof isEnabled !== 'boolean') {
            return;
        }

        this.setState('Enabled', isEnabled);

        var parentEnabled = this.control.get('parentEnabled');
        var old = this.control.get('enabled');

        isEnabled = parentEnabled && isEnabled;

        if (isEnabled === old) {
            return;
        }

        this.control.set('enabled', isEnabled);
        this.setParentEnabledOnChild(isEnabled);
    },

    setParentEnabledOnChild: function (value) {
        var elements = this.getChildElements();
        if (_.isEmpty(elements) === false) {
            for (var i = 0, ln = elements.length; i < ln; i = i + 1) {
                if (typeof elements[i].setParentEnabled === 'undefined') {
                    continue;
                }
                elements[i].setParentEnabled(value);
            }
        }
    },

    setParentEnabled: function (value) {

        if (typeof value !== 'boolean') {
            return;
        }

        var old = this.control.get('parentEnabled');
        this.control.set('parentEnabled', value);

        if (old !== value) {
            var enabled = value && this.getState('Enabled');
            this.control.set('enabled', enabled);
            this.setParentEnabled(enabled);
            this.setParentEnabledOnChild(enabled);
        }
    },

    getVisible: function () {
        return this.control.get('visible');
    },

    setVisible: function (isVisible) {
        if (typeof isVisible == 'boolean') {
            this.control.set('visible', isVisible);
        }
    },

    getStyle: function () {
        return this.control.get('style');
    },

    setStyle: function (style) {
        if (typeof style == 'string') {
            this.control.set('style', style);
        }
    },

    getTextHorizontalAlignment: function () {
        return this.control.get('textHorizontalAlignment');
    },

    setTextHorizontalAlignment: function (value) {
        if (InfinniUI.Metadata.isValidValue(value, InfinniUI.Metadata.TextHorizontalAlignment)) {
            this.control.set('textHorizontalAlignment', value);
        }
    },

    getHorizontalAlignment: function () {
        return this.control.get('horizontalAlignment');
    },

    setHorizontalAlignment: function (horizontalAlignment) {
        if (typeof horizontalAlignment == 'string') {
            this.control.set('horizontalAlignment', horizontalAlignment);
        }
    },

    getVerticalAlignment: function () {
        return this.control.get('verticalAlignment');
    },

    setVerticalAlignment: function (verticalAlignment) {
        if (typeof verticalAlignment == 'string') {
            this.control.set('verticalAlignment', verticalAlignment);
        }
    },

    getTextStyle: function () {
        return this.control.get('textStyle');
    },

    setTextStyle: function (textStyle) {
        if (typeof textStyle == 'string') {
            this.control.set('textStyle', textStyle);
        }
    },

    getBackground: function () {
        return this.control.get('background');
    },

    setBackground: function (background) {
        if (typeof background == 'string') {
            this.control.set('background', background);
        }
    },

    getForeground: function () {
        return this.control.get('foreground');
    },

    setForeground: function (foreground) {
        if (typeof foreground == 'string') {
            this.control.set('foreground', foreground);
        }
    },

    getTexture: function () {
        return this.control.get('texture');
    },

    setTexture: function (texture) {
        if (typeof texture == 'string') {
            this.control.set('texture', texture);
        }
    },

    onLoaded: function (handler) {
        this.control.onLoaded(handler);
    },

    isLoaded: function () {
        return this.control.isLoaded();
    },

    getFocusable: function () {
        return this.control.get('focusable')
    },

    setFocusable: function (value) {
        this.control.get('focusable', !!value)
    },

    getFocused: function () {
        return this.control.get('focused');
    },

    setFocused: function (value) {
        return this.control.set('focused', !!value);
    },

    onLostFocus: function (handler) {
        this.control.on('OnLostFocus', handler);
    },

    onGotFocus: function (handler) {
        this.control.on('OnGotFocus', handler);
    },

    setToolTip: function (value) {
        this.control.set('toolTip', value);
    },

    getToolTip: function () {
        return this.control.get('toolTip');
    },

    getIsLoaded: function () {
        return this.control.get('isLoaded');
    },

    setIsLoaded: function () {
        this.control.set('isLoaded', true);
    },

    setTag: function (value) {
        this.control.set('tag', value);
    },

    getTag: function () {
        return this.control.get('tag');
    },

    render: function () {
        return this.control.render();
    },

    getWidth: function () {
    },

    getHeight: function () {
    },

    getScriptsStorage: function () {
        return this.getView();
    },

    /**
     * Установка состояния валидации элеменат
     * @param {String} [state="success"]
     * @param {String} [message]
     */
    setValidationState: function (state, message) {
        this.control.set('validationMessage', message);
        this.control.set('validationState', state);
    },

    /**
     * Получение состояния валидации элеменат
     * @return {String} [state="success"]
     */
    getValidationState: function () {
        return this.control.get('validationState');
    },

    getState: function (name) {
        return this.state[name];
    },

    setState: function (name, value) {
        this.state[name] = value;
    },

    onBeforeClick: function (handler) {
        return this.control.onBeforeClick(handler);
    },

    onKeyDown: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingKeyEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onKeyDown(callback);
    },

    onKeyUp: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingKeyEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onKeyUp(callback);
    },

    onClick: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onClick(callback);
    },

    onDoubleClick: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onDoubleClick(callback);
    },

    onMouseDown: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseDown(callback);
    },

    onMouseUp: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseUp(callback);
    },

    onMouseEnter: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseEnter(callback);
    },

    onMouseLeave: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseLeave(callback);
    },

    onMouseMove: function (handler) {
        var that = this,
            callback = function (nativeEventData) {
                var eventData = that._getHandlingMouseEventData(nativeEventData);
                handler(eventData);
            };
        return this.control.onMouseMove(callback);
    },

    onShowToolTip: function (handler) {
        var control = this.control;

        control.on('change:showToolTip', function () {
            var showToolTip = control.get('showToolTip');
            if (showToolTip && typeof handler === 'function') {
                handler();
            }
        });
    },

    onHideToolTip: function (handler) {
        var control = this.control;

        control.on('change:showToolTip', function () {
            var showToolTip = control.get('showToolTip');
            if (!showToolTip && typeof handler === 'function') {
                handler();
            }
        });
    },

    remove: function (isInitiatedByParent) {
        var logger = window.InfinniUI.global.logger;
        if(this.isRemoved){
            logger.warn('Element.remove: Попытка удалить элемент, который уже был удален');
            return;
        }

        var children = this.childElements;

        for (var i = 0, ii = children.length; i < ii; i++) {
            children[i].remove(true);
        }

        this.control.remove();

        if (this.parent && this.parent.removeChild && !isInitiatedByParent) {
            if(this.parent.isRemoved){
                logger.warn('Element.remove: Попытка удалить элемент из родителя, который помечан как удаленный');
            }else{
                this.parent.removeChild(this);
            }

        }

        this.isRemoved = true;

        this.childElements = undefined;
    },

    removeChild: function (child) {
        var index = this.childElements.indexOf(child);
        if (index != -1) {
            this.childElements.splice(index, 1);
        }
    },

    addChild: function (child) {
        if(!this.isRemoved){
            this.childElements.push(child);

        }else{
            var logger = window.InfinniUI.global.logger;
            logger.warn('Element.addChild: Попытка добавить потомка в удаленный элемент');
        }

    },

    createControlEventHandler: function(element, handler, additionParams) {
        var context;
        var parentView = element.getView();
        additionParams = additionParams || {};

        if (parentView) {
            context = parentView.context;
        }

        return function (message) {
            _.extend(
                message,
                additionParams
            );
            message.source = element;

            return handler.call(undefined, context, message);
        };
    },

    _getHandlingKeyEventData: function (nativeData) {
        var result = {};

        result = {
            source: this,
            key: nativeData.which,
            altKey: nativeData.altKey,
            ctrlKey: nativeData.ctrlKey,
            shiftKey: nativeData.shiftKey,
            nativeEventData: nativeData
        };
        return result;
    },

    _getHandlingMouseEventData: function (nativeData) {
        var result = {};

        result = {
            source: this,
            button: nativeData.which,
            altKey: nativeData.altKey,
            ctrlKey: nativeData.ctrlKey,
            shiftKey: nativeData.shiftKey,
            nativeEventData: nativeData
        };
        return result;
    },

    _upperFirstSymbol: function (s) {
        return s[0].toUpperCase() + s.substr(1);
    }
});<|endoftext|>


<commit_before>var fs = require('fs');

function TumblrClient(credentials) {
  this.credentials = credentials || {};
}

var request;

module.exports = {

  Client: TumblrClient,

  createClient: function (credentials) {
    return new TumblrClient(credentials);
  },

  request: function(r) {
    request = r;
  }

};

var baseURL = 'http://api.tumblr.com/v2';

var calls = {

  postCreation: function (type, requireOptions, acceptsData) {
    return function (blogName, options, callback) {
      requireValidation(options, requireOptions);
      options.type = type;
      if (!acceptsData) {
        delete options.data;
      }
      this._post(blogPath(blogName, '/post'), options, callback);
    };
  },

  getWithOptions: function (path) {
    return function (options, callback) {
      if (isFunction(options)) { callback = options; options = {}; }
      this._get(path, options, callback);
    };
  },

  blogList: function (path) {
    return function (blogName, options, callback) {
      if (isFunction(options)) { callback = options; options = {}; }
      this._get(blogPath(blogName, path), options, callback);
    }
  }

};

TumblrClient.prototype = {

  // Tagged

  tagged: function (tag, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }

    options = options || {};
    options.tag = tag;

    this._get('/tagged', options, callback, true);
  },

  // Blogs

  blogInfo: function (blogName, callback) {
    this._get(blogPath(blogName, '/info'), {}, callback, true);
  },

  avatar: function (blogName, size, callback) {
    if (isFunction(size)) { callback = size; size = null; }
    var path = size ? '/avatar/' + size : '/avatar';
    this._get(blogPath(blogName, path), {}, callback, true);
  },

  blogLikes: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get(blogPath(blogName, '/likes'), options, callback, true);
  },

  followers: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get(blogPath(blogName, '/followers'), options, callback);
  },

  posts: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    options = options || {};
    var path = options.type ? '/posts/' + options.type : '/posts';
    this._get(blogPath(blogName, path), options, callback, true);
  },

  queue:       calls.blogList('/posts/queue'),
  drafts:      calls.blogList('/posts/draft'),
  submissions: calls.blogList('/posts/submission'),

  // Posts

  edit: function (blogName, options, callback) {
    this._post(blogPath(blogName, '/post/edit'), options, callback);
  },

  reblog: function (blogName, options, callback) {
    this._post(blogPath(blogName, '/post/reblog'), options, callback);
  },

  deletePost: function (blogName, id, callback) {
    this._post(blogPath(blogName, '/post/delete'), {id: id}, callback);
  },

  photo: calls.postCreation('photo', ['data', 'source'],       true),
  audio: calls.postCreation('audio', ['data', 'external_url'], true),
  video: calls.postCreation('video', ['data', 'embed'],        true),
  quote: calls.postCreation('quote', ['quote'],                false),
  text:  calls.postCreation('text',  ['body'],                 false),
  link:  calls.postCreation('link',  ['url'],                  false),
  chat:  calls.postCreation('chat',  ['conversation'],         false),

  // User

  userInfo: function (callback) {
    this._get('/user/info', {}, callback);
  },

  likes: function (options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get('/user/likes', options, callback, true);
  },

  follow: function (url, callback) {
    this._post('/user/follow', {url: url}, callback);
  },

  unfollow: function (url, callback) {
    this._post('/user/unfollow', {url: url}, callback);
  },

  like: function (id, reblogKey, callback) {
    this._post('/user/like', {id: id, reblog_key: reblogKey}, callback);
  },

  unlike: function (id, reblogKey, callback) {
    this._post('/user/unlike', {id: id, reblog_key: reblogKey}, callback);
  },

  dashboard: calls.getWithOptions('/user/dashboard'),
  following: calls.getWithOptions('/user/following'),

  // Helpers

  _get: function (path, params, callback, addApiKey) {

    params = params || {};
    if (addApiKey) {
      params.api_key = this.credentials.consumer_key;
    }

    request.get({url: baseURL + path, json: true, qs: params, oauth: this.credentials, followRedirect: false}, requestCallback(callback));

  },

  _post: function (path, params, callback) {

    var data = params.data;
    delete params.data;

    // Sign without multipart data
    var r = request.post(baseURL + path, function (err, response, body) {
      body = JSON.parse(body);
      requestCallback(callback)(err, response, body);
    });

    // Sign it with the non-data parameters
    r.form(params);
    r.oauth(this.credentials);

    // And then add the full body
    var form = r.form();
    for (var key in params) {
      form.append(key, params[key]);
    }
    if (data) {
      form.append('data', fs.createReadStream(data, { encoding: 'base64' }));
    }

  }

};

var requireValidation = function (options, choices) {
  var count = 0;
  for (var i = 0; i < choices.length; i++) {
    if (options[choices[i]]) {
      count += 1;
    }
  }
  if (choices.length === 1) {
    if (count === 0) {
      throw new Error('Missing required field: "' + choices[0] + '"');
    }
  } else if (choices.length > 1) {
    if (count === 0) {
      throw new Error('Missing one of: ' + choices.join(','));
    }
    if (count > 1) {
      throw new Error('Can only use one of: ' + choices.join(','));
    }
  }
};

function blogPath(blogName, path) {
  return '/blog/' + blogName + path;
}

function requestCallback(callback) {
  if (!callback) return;
  return function (err, response, body) {
    if (err) return callback(err);
    if (response.statusCode >= 400) {
      return callback(new Error('API error: ' + response.statusCode + ' ' + body.meta.msg));
    }
    return callback(null, body.response);
  };
}

function isFunction(value) {
  return Object.prototype.toString.call(value) == '[object Function]';
}
<commit_msg>Form fix<commit_after>var fs = require('fs');

function TumblrClient(credentials) {
  this.credentials = credentials || {};
}

var request;

module.exports = {

  Client: TumblrClient,

  createClient: function (credentials) {
    return new TumblrClient(credentials);
  },

  request: function(r) {
    request = r;
  }

};

var baseURL = 'http://api.tumblr.com/v2';

var calls = {

  postCreation: function (type, requireOptions, acceptsData) {
    return function (blogName, options, callback) {
      requireValidation(options, requireOptions);
      options.type = type;
      if (!acceptsData) {
        delete options.data;
      }
      this._post(blogPath(blogName, '/post'), options, callback);
    };
  },

  getWithOptions: function (path) {
    return function (options, callback) {
      if (isFunction(options)) { callback = options; options = {}; }
      this._get(path, options, callback);
    };
  },

  blogList: function (path) {
    return function (blogName, options, callback) {
      if (isFunction(options)) { callback = options; options = {}; }
      this._get(blogPath(blogName, path), options, callback);
    }
  }

};

TumblrClient.prototype = {

  // Tagged

  tagged: function (tag, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }

    options = options || {};
    options.tag = tag;

    this._get('/tagged', options, callback, true);
  },

  // Blogs

  blogInfo: function (blogName, callback) {
    this._get(blogPath(blogName, '/info'), {}, callback, true);
  },

  avatar: function (blogName, size, callback) {
    if (isFunction(size)) { callback = size; size = null; }
    var path = size ? '/avatar/' + size : '/avatar';
    this._get(blogPath(blogName, path), {}, callback, true);
  },

  blogLikes: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get(blogPath(blogName, '/likes'), options, callback, true);
  },

  followers: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get(blogPath(blogName, '/followers'), options, callback);
  },

  posts: function (blogName, options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    options = options || {};
    var path = options.type ? '/posts/' + options.type : '/posts';
    this._get(blogPath(blogName, path), options, callback, true);
  },

  queue:       calls.blogList('/posts/queue'),
  drafts:      calls.blogList('/posts/draft'),
  submissions: calls.blogList('/posts/submission'),

  // Posts

  edit: function (blogName, options, callback) {
    this._post(blogPath(blogName, '/post/edit'), options, callback);
  },

  reblog: function (blogName, options, callback) {
    this._post(blogPath(blogName, '/post/reblog'), options, callback);
  },

  deletePost: function (blogName, id, callback) {
    this._post(blogPath(blogName, '/post/delete'), {id: id}, callback);
  },

  photo: calls.postCreation('photo', ['data', 'source'],       true),
  audio: calls.postCreation('audio', ['data', 'external_url'], true),
  video: calls.postCreation('video', ['data', 'embed'],        true),
  quote: calls.postCreation('quote', ['quote'],                false),
  text:  calls.postCreation('text',  ['body'],                 false),
  link:  calls.postCreation('link',  ['url'],                  false),
  chat:  calls.postCreation('chat',  ['conversation'],         false),

  // User

  userInfo: function (callback) {
    this._get('/user/info', {}, callback);
  },

  likes: function (options, callback) {
    if (isFunction(options)) { callback = options; options = {}; }
    this._get('/user/likes', options, callback, true);
  },

  follow: function (url, callback) {
    this._post('/user/follow', {url: url}, callback);
  },

  unfollow: function (url, callback) {
    this._post('/user/unfollow', {url: url}, callback);
  },

  like: function (id, reblogKey, callback) {
    this._post('/user/like', {id: id, reblog_key: reblogKey}, callback);
  },

  unlike: function (id, reblogKey, callback) {
    this._post('/user/unlike', {id: id, reblog_key: reblogKey}, callback);
  },

  dashboard: calls.getWithOptions('/user/dashboard'),
  following: calls.getWithOptions('/user/following'),

  // Helpers

  _get: function (path, params, callback, addApiKey) {

    params = params || {};
    if (addApiKey) {
      params.api_key = this.credentials.consumer_key;
    }

    request.get({url: baseURL + path, json: true, qs: params, oauth: this.credentials, followRedirect: false}, requestCallback(callback));

  },

  _post: function (path, params, callback) {

    var data = params.data;
    delete params.data;

    // Sign without multipart data
    var r = request.post(baseURL + path, function (err, response, body) {
      body = JSON.parse(body);
      requestCallback(callback)(err, response, body);
    });

    // Sign it with the non-data parameters
    r.form(params);
    r.oauth(this.credentials);

    // Clear the side effects from form(param)
    delete r.headers['content-type'];
    delete r.body;

    // And then add the full body
    var form = r.form();
    for (var key in params) {
      form.append(key, params[key]);
    }
    if (data) {
      form.append('data', fs.createReadStream(data));
    }

    // Add the form header back
    var headers = form.getHeaders();
    for (var key in headers) {
      r.headers[key] = headers[key];
    }

  }

};

var requireValidation = function (options, choices) {
  var count = 0;
  for (var i = 0; i < choices.length; i++) {
    if (options[choices[i]]) {
      count += 1;
    }
  }
  if (choices.length === 1) {
    if (count === 0) {
      throw new Error('Missing required field: "' + choices[0] + '"');
    }
  } else if (choices.length > 1) {
    if (count === 0) {
      throw new Error('Missing one of: ' + choices.join(','));
    }
    if (count > 1) {
      throw new Error('Can only use one of: ' + choices.join(','));
    }
  }
};

function blogPath(blogName, path) {
  return '/blog/' + blogName + path;
}

function requestCallback(callback) {
  if (!callback) return;
  return function (err, response, body) {
    if (err) return callback(err);
    if (response.statusCode >= 400) {
      var err = body.meta ? body.meta.msg : body.error;
      return callback(new Error('API error: ' + response.statusCode + ' ' + err));
    }
    return callback(null, body.response);
  };
}

function isFunction(value) {
  return Object.prototype.toString.call(value) == '[object Function]';
}
<|endoftext|>


<commit_before>module.exports = Status

var h = require('virtual-dom/h')

function Status (app) {
  this.app = app
}

Status.prototype.render = function (data) {
  return h('.status', {
    onclick: function () {
      alert('click')
    }
  }, data.username)
}
<commit_msg>standard<commit_after>module.exports = Status

var h = require('virtual-dom/h')

function Status (app) {
  this.app = app
}

Status.prototype.render = function (data) {
  return h('.status', {
    onclick: function () {
      window.alert('click')
    }
  }, data.username)
}
<|endoftext|>


<commit_before>
let log = require('../util/log')('i18n-backend/' + process.type)
let opts = { logger: new log.Logger() }

let sf = require('../util/sf')
let urls = require('../constants/urls')
let env = require('../env')

let path = require('path')

let i18next = require('i18next')

let AppDispatcher = require('../dispatcher/app-dispatcher')
let AppConstants = require('../constants/app-constants')
let AppActions = require('../actions/app-actions')

let being_fetched = {}

// don't overwrite local files
let remote_suffix = '.remote.json'

class Backend {
  constructor (services, options) {
    if (typeof options === 'undefined') {
      options = {}
    }
    this.init(services, options)

    this.type = 'backend'

    AppDispatcher.register('i18n-backend', (payload) => {
      if (payload.action_type === AppConstants.LOCALE_UPDATE_DOWNLOADED) {
        log(opts, `Adding resources to ${payload.lang}`)
        i18next.addResources(
          payload.lang,
          'translation', /* default i18next namespace */
          payload.resources
        )
      } else if (payload.action_type === AppConstants.LOCALE_UPDATE_QUEUE_DOWNLOAD) {
        this.queue_download(payload.lang)
      }
    })
  }

  init (services, options, coreOptions) {
    if (typeof options === 'undefined') {
      options = {}
    }
    if (typeof coreOptions === 'undefined') {
      coreOptions = {}
    }

    this.services = services
    this.options = Object.assign({}, options)
    this.coreOptions = coreOptions
  }

  canonical_filename (candidate) {
    return path.join(this.options.loadPath, candidate + '.json')
  }

  async read (language, namespace, callback) {
    this.queue_download(language)

    let canonical_filename = this.canonical_filename(language)

    if (!await sf.exists(canonical_filename)) {
      canonical_filename = this.canonical_filename(language.substring(0, 2))
      if (!await sf.exists(canonical_filename)) {
        log(opts, `No locale file found for language ${language}`)
        return callback(null, {})
      }
    }

    let loaded_filename = canonical_filename

    // do we have a newer version?
    if (await sf.exists(canonical_filename + remote_suffix)) {
      // neat, use it.
      loaded_filename = canonical_filename + remote_suffix
    }

    let contents = await sf.read_file(loaded_filename)
    try {
      let parsed = JSON.parse(contents)
      log(opts, `Successfully loaded ${language} from ${loaded_filename}`)
      return callback(null, parsed)
    } catch (err) {
      err.message = 'error parsing ' + loaded_filename + ': ' + err.message
      return callback(err)
    }
  }

  async queue_download (language) {
    // only run local updating on the node side
    if (process.type !== 'browser') return

    if (env.name === 'development' && process.env.DID_I_STUTTER !== '1') {
      log(opts, `Not downloading locales in development, export DID_I_STUTTER=1 to override`)
      return
    }

    if (being_fetched[language]) return

    being_fetched[language] = true
    AppActions.locale_update_download_start(language)

    log(opts, `Waiting a bit before downloading ${language} locale..`)
    await cooldown()

    try {
      await this.download_fresh_locale(language)
    } catch (e) {
      log(opts, `While downloading fresh locale: ${e.stack || e}`)
    }

    being_fetched[language] = false
    AppActions.locale_update_download_end(language)
  }

  async download_fresh_locale (language) {
    let local_filename = this.canonical_filename(language)
    if (!await sf.exists(local_filename)) {
      // try stripping region
      local_filename = this.canonical_filename(language.substring(0, 2))
    }

    let remote_filename = local_filename + '.remote.json'
    let uri = `${urls.remote_locale_path}/${language}.json`

    log(opts, `Downloading fresh locale file from ${uri}`)

    let needle = require('../promised/needle')
    let resp = await needle.requestAsync('GET', uri, {})
    let body = resp.body

    if (resp.statusCode !== 200) {
      log(opts, `Got HTTP ${resp.statusCode} while fetching fresh locale`)
      return
    }

    try {
      let resources = JSON.parse(body)
      log(opts, `Successfully parsed ${language} from remote locale`)
      AppActions.locale_update_downloaded(language, resources)
    } catch (err) {
      log(opts, `Error parsing ${uri}: ${err.message}`)
      return
    }

    log(opts, `Saving fresh ${language} locale to ${remote_filename}`)
    await sf.write_file(remote_filename, body)
  }
}

Backend.type = 'backend'

/** Throttling logic */
// Stolen from api.js, once copied another time, make generic
// cf. https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)

let last_request = 0
let ms_between_requests = 1000

function cooldown () {
  let now = +new Date()
  let next_acceptable = last_request + ms_between_requests
  let quiet = next_acceptable - now

  if (now > next_acceptable) {
    last_request = now
    return Promise.resolve()
  } else {
    last_request = next_acceptable
  }

  return new Promise((resolve, reject) => {
    setTimeout(resolve, quiet)
  })
}

module.exports = Backend
<commit_msg>Woops, needle does the parsing already<commit_after>
let log = require('../util/log')('i18n-backend/' + process.type)
let opts = { logger: new log.Logger() }

let sf = require('../util/sf')
let urls = require('../constants/urls')
let env = require('../env')

let path = require('path')

let i18next = require('i18next')

let AppDispatcher = require('../dispatcher/app-dispatcher')
let AppConstants = require('../constants/app-constants')
let AppActions = require('../actions/app-actions')

let being_fetched = {}

// don't overwrite local files
let remote_suffix = '.remote.json'

class Backend {
  constructor (services, options) {
    if (typeof options === 'undefined') {
      options = {}
    }
    this.init(services, options)

    this.type = 'backend'

    AppDispatcher.register('i18n-backend', (payload) => {
      if (payload.action_type === AppConstants.LOCALE_UPDATE_DOWNLOADED) {
        log(opts, `Adding resources to ${payload.lang}`)
        i18next.addResources(
          payload.lang,
          'translation', /* default i18next namespace */
          payload.resources
        )
      } else if (payload.action_type === AppConstants.LOCALE_UPDATE_QUEUE_DOWNLOAD) {
        this.queue_download(payload.lang)
      }
    })
  }

  init (services, options, coreOptions) {
    if (typeof options === 'undefined') {
      options = {}
    }
    if (typeof coreOptions === 'undefined') {
      coreOptions = {}
    }

    this.services = services
    this.options = Object.assign({}, options)
    this.coreOptions = coreOptions
  }

  canonical_filename (candidate) {
    return path.join(this.options.loadPath, candidate + '.json')
  }

  async read (language, namespace, callback) {
    this.queue_download(language)

    let canonical_filename = this.canonical_filename(language)

    if (!await sf.exists(canonical_filename)) {
      canonical_filename = this.canonical_filename(language.substring(0, 2))
      if (!await sf.exists(canonical_filename)) {
        log(opts, `No locale file found for language ${language}`)
        return callback(null, {})
      }
    }

    let loaded_filename = canonical_filename

    // do we have a newer version?
    if (await sf.exists(canonical_filename + remote_suffix)) {
      // neat, use it.
      loaded_filename = canonical_filename + remote_suffix
    }

    let contents = await sf.read_file(loaded_filename)
    try {
      let parsed = JSON.parse(contents)
      log(opts, `Successfully loaded ${language} from ${loaded_filename}`)
      return callback(null, parsed)
    } catch (err) {
      err.message = 'error parsing ' + loaded_filename + ': ' + err.message
      return callback(err)
    }
  }

  async queue_download (language) {
    // only run local updating on the node side
    if (process.type !== 'browser') return

    if (env.name === 'development' && process.env.DID_I_STUTTER !== '1') {
      log(opts, `Not downloading locales in development, export DID_I_STUTTER=1 to override`)
      return
    }

    if (being_fetched[language]) return

    being_fetched[language] = true
    AppActions.locale_update_download_start(language)

    log(opts, `Waiting a bit before downloading ${language} locale..`)
    await cooldown()

    try {
      await this.download_fresh_locale(language)
    } catch (e) {
      log(opts, `While downloading fresh locale: ${e.stack || e}`)
    }

    being_fetched[language] = false
    AppActions.locale_update_download_end(language)
  }

  async download_fresh_locale (language) {
    let local_filename = this.canonical_filename(language)
    if (!await sf.exists(local_filename)) {
      // try stripping region
      local_filename = this.canonical_filename(language.substring(0, 2))
    }

    let remote_filename = local_filename + '.remote.json'
    let uri = `${urls.remote_locale_path}/${language}.json`

    log(opts, `Downloading fresh locale file from ${uri}`)

    let needle = require('../promised/needle')
    let resp = await needle.requestAsync('GET', uri)
    let resources = resp.body

    if (resp.statusCode !== 200) {
      log(opts, `Got HTTP ${resp.statusCode} while fetching fresh locale`)
      return
    }

    log(opts, `Successfully obtained remote locale ${language}`)
    AppActions.locale_update_downloaded(language, resources)

    log(opts, `Saving fresh ${language} locale to ${remote_filename}`)
    await sf.write_file(remote_filename, resources)
  }
}

Backend.type = 'backend'

/** Throttling logic */
// Stolen from api.js, once copied another time, make generic
// cf. https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)

let last_request = 0
let ms_between_requests = 1000

function cooldown () {
  let now = +new Date()
  let next_acceptable = last_request + ms_between_requests
  let quiet = next_acceptable - now

  if (now > next_acceptable) {
    last_request = now
    return Promise.resolve()
  } else {
    last_request = next_acceptable
  }

  return new Promise((resolve, reject) => {
    setTimeout(resolve, quiet)
  })
}

module.exports = Backend
<|endoftext|>


<commit_before>/**
 * @fileOverview Defines client side API in which files can be uploaded.
 */

/**
 *
 * @param {string} directive - Name of server-directive to use.
 * @param {object} [metaData] - Data to be sent to directive.
 * @constructor
 */

Slingshot.Upload = function (directive, metaData) {

  if (!window.File || !window.FormData) {
    throw new Error("Browser does not support HTML5 uploads");
  }

  var self = this,
      loaded = new ReactiveVar(),
      total = new ReactiveVar(),
      status = new ReactiveVar("idle"),
      dataUri = new ReactiveVar(),
      preloaded= new ReactiveVar();

  function buildFormData() {
    var formData = new window.FormData();

    _.each(self.instructions.postData, function (field) {
      formData.append(field.name, field.value);
    });

    formData.append("file", self.file);

    return formData;
  }

  _.extend(self, {

    /**
     * @returns {string}
     */

    status: function () {
      return status.get();
    },

    /**
     * @returns {number}
     */

    progress: function () {
      return self.uploaded() / total.get();
    },

    /**
     * @returns {number}
     */

    uploaded: function () {
      return loaded.get();
    },

   /**
    * @param {File} file
    * @returns {null|Error} Returns null on success, Error on failure.
    */

    validate: function(file) {
      var context = {
        userId: Meteor.userId()
      };
      try {
        var validators = Slingshot.Validators,
            restrictions = Slingshot.getRestrictions(directive);

        validators.checkAll(context, file, metaData, restrictions) && null;
      } catch(error) {
        return error;
      }
    },

    /**
     * @param {(File|Blob)} file
     * @param {Function} [callback]
     * @returns {Slingshot.Upload}
     */

    send: function (file, callback) {
      if (! (file instanceof window.File) && ! (file instanceof window.Blob))
        throw new Error("Not a file");

      self.file = file;

      self.request(function (error, instructions) {
        if (error) {
          return callback(error);
        }

        self.instructions = instructions;

        self.transfer(callback);
      });

      return self;
    },

    /**
     * @param {Function} [callback]
     * @returns {Slingshot.Upload}
     */

    request: function (callback) {

      if (!self.file) {
        callback(new Error("No file to request upload for"));
      }

      var file = _.pick(self.file, "name", "size", "type");

      status.set("authorizing");

      var error = this.validate(file);
      if (error) {
        status.set("failed");
        callback(error);
        return self;
      }

      Meteor.call("slingshot/uploadRequest", directive,
        file, metaData, function (error, instructions) {
          status.set(error ? "failed" : "authorized");
          callback(error, instructions);
        });

      return self;
    },

    /**
     * @param {Function} [callback]
     *
     * @returns {Slingshot.Upload}
     */

    transfer: function (callback) {
      if (status.curValue !== "authorized") {
        throw new Error("Cannot transfer file at upload status: " +
          status.curValue);
      }

      status.set("transferring");
      loaded.set(0);

      var xhr = new XMLHttpRequest();

      xhr.upload.addEventListener("progress", function (event) {
        if (event.lengthComputable) {
          loaded.set(event.loaded);
          total.set(event.total);
        }
      }, false);

      function getError() {
        return new Meteor.Error(xhr.statusText + " - " + xhr.status,
            "Failed to upload file to cloud storage");
      }

      xhr.addEventListener("load", function () {

        if (xhr.status < 400) {
          status.set("done");
          loaded.set(total.get());
          callback(null, self.instructions.download);
        }
        else {
          status.set("failed");
          callback(getError());
        }
      });

      xhr.addEventListener("error", function () {
        status.set("failed");
        callback(getError());
      });

      xhr.addEventListener("abort", function () {
        status.set("aborted");
        callback(new Meteor.Error("Aborted",
          "The upload has been aborted by the user"));
      });

      xhr.open("POST", self.instructions.upload, true);
      xhr.send(buildFormData());

      return self;
    },

    /**
     * @returns {boolean}
     */

    isImage: function () {
      self.status(); //React to status change.
      return Boolean(self.file && self.file.type.split("/")[0] === "image");
    },

    /**
     * Latency compensated url of the file to be uploaded.
     *
     * @param {boolean} preload
     *
     * @returns {string}
     */

    url: function (preload) {
      var status = self.status();

      if (preload && !self.isImage())
        throw new Error("Cannot pre-load anything other than images");

      if (self.instructions && status === "done") {
        var download = self.instructions.download;

        if (preload && preloaded.get() !== download) {
          preloadImage(download, function () {
            preloaded.set(download);
          });
        }
        else {
          dataUri.set();
          return download;
        }
      }

      if (status !== "failed" && status !== "aborted" && self.file) {
        var URL = (window.URL || window.webkitURL);

        if (URL)
          return URL.createObjectURL(self.file);

        if (Tracker.active && window.FileReader) {
          var url = dataUri.get();

          if (url)
            return url;

          readDataUrl(self.file, function (result) {
            dataUri.set(result);
          });
        }
      }
    },

    /** Gets an upload parameter for the directive.
     *
     * @param {String} name
     * @returns {String|Number|Undefined}
     */

    param: function (name) {
      self.status(); //React to status changes.

      var data = self.instructions && self.instructions.postData,
          field = data && _.findWhere(data, {name: name});

      return field && field.value;
    }

  });
};

/**
 *
 * @param {String} image - URL of image to preload.
 * @param {Function} callback
 */

function preloadImage(image, callback) {
  var preloader = new window.Image();

  preloader.onload = callback;

  preloader.src = image;
}

function readDataUrl(file, callback) {
  var reader = new window.FileReader();

  reader.onloadend = function () {
    callback(reader.result);
  };

  reader.readAsDataURL(file);
}
<commit_msg>Prevented Flickering when an image is uploaded and `.url()` is used within a volatile autorun.<commit_after>/**
 * @fileOverview Defines client side API in which files can be uploaded.
 */

/**
 *
 * @param {string} directive - Name of server-directive to use.
 * @param {object} [metaData] - Data to be sent to directive.
 * @constructor
 */

Slingshot.Upload = function (directive, metaData) {

  if (!window.File || !window.FormData) {
    throw new Error("Browser does not support HTML5 uploads");
  }

  var self = this,
      loaded = new ReactiveVar(),
      total = new ReactiveVar(),
      status = new ReactiveVar("idle"),
      dataUri,
      preloaded;

  function buildFormData() {
    var formData = new window.FormData();

    _.each(self.instructions.postData, function (field) {
      formData.append(field.name, field.value);
    });

    formData.append("file", self.file);

    return formData;
  }

  _.extend(self, {

    /**
     * @returns {string}
     */

    status: function () {
      return status.get();
    },

    /**
     * @returns {number}
     */

    progress: function () {
      return self.uploaded() / total.get();
    },

    /**
     * @returns {number}
     */

    uploaded: function () {
      return loaded.get();
    },

   /**
    * @param {File} file
    * @returns {null|Error} Returns null on success, Error on failure.
    */

    validate: function(file) {
      var context = {
        userId: Meteor.userId()
      };
      try {
        var validators = Slingshot.Validators,
            restrictions = Slingshot.getRestrictions(directive);

        validators.checkAll(context, file, metaData, restrictions) && null;
      } catch(error) {
        return error;
      }
    },

    /**
     * @param {(File|Blob)} file
     * @param {Function} [callback]
     * @returns {Slingshot.Upload}
     */

    send: function (file, callback) {
      if (! (file instanceof window.File) && ! (file instanceof window.Blob))
        throw new Error("Not a file");

      self.file = file;

      self.request(function (error, instructions) {
        if (error) {
          return callback(error);
        }

        self.instructions = instructions;

        self.transfer(callback);
      });

      return self;
    },

    /**
     * @param {Function} [callback]
     * @returns {Slingshot.Upload}
     */

    request: function (callback) {

      if (!self.file) {
        callback(new Error("No file to request upload for"));
      }

      var file = _.pick(self.file, "name", "size", "type");

      status.set("authorizing");

      var error = this.validate(file);
      if (error) {
        status.set("failed");
        callback(error);
        return self;
      }

      Meteor.call("slingshot/uploadRequest", directive,
        file, metaData, function (error, instructions) {
          status.set(error ? "failed" : "authorized");
          callback(error, instructions);
        });

      return self;
    },

    /**
     * @param {Function} [callback]
     *
     * @returns {Slingshot.Upload}
     */

    transfer: function (callback) {
      if (status.curValue !== "authorized") {
        throw new Error("Cannot transfer file at upload status: " +
          status.curValue);
      }

      status.set("transferring");
      loaded.set(0);

      var xhr = new XMLHttpRequest();

      xhr.upload.addEventListener("progress", function (event) {
        if (event.lengthComputable) {
          loaded.set(event.loaded);
          total.set(event.total);
        }
      }, false);

      function getError() {
        return new Meteor.Error(xhr.statusText + " - " + xhr.status,
            "Failed to upload file to cloud storage");
      }

      xhr.addEventListener("load", function () {

        if (xhr.status < 400) {
          status.set("done");
          loaded.set(total.get());
          callback(null, self.instructions.download);
        }
        else {
          status.set("failed");
          callback(getError());
        }
      });

      xhr.addEventListener("error", function () {
        status.set("failed");
        callback(getError());
      });

      xhr.addEventListener("abort", function () {
        status.set("aborted");
        callback(new Meteor.Error("Aborted",
          "The upload has been aborted by the user"));
      });

      xhr.open("POST", self.instructions.upload, true);
      xhr.send(buildFormData());

      return self;
    },

    /**
     * @returns {boolean}
     */

    isImage: function () {
      self.status(); //React to status change.
      return Boolean(self.file && self.file.type.split("/")[0] === "image");
    },

    /**
     * Latency compensated url of the file to be uploaded.
     *
     * @param {boolean} preload
     *
     * @returns {string}
     */

    url: function (preload) {
      if (!dataUri) {
        var localUrl = new ReactiveVar(),
            URL = (window.URL || window.webkitURL);

        dataUri = new ReactiveVar();

        Tracker.nonreactive(function () {

          /*
           It is important that we generate the local url not more than once
           throughout the entire lifecycle of `self` to prevent flickering.
           */

          var previewRequirement = new Tracker.Dependency();

          Tracker.autorun(function (computation) {
            if (self.file) {
              if (URL) {
                localUrl.set(URL.createObjectURL(self.file));
                computation.stop();
              }
              else if (Tracker.active && window.FileReader) {
                readDataUrl(self.file, function (result) {
                  localUrl.set(result);
                  computation.stop();
                });
              }
            }
            else {
              previewRequirement.depend();
            }
          });

          Tracker.autorun(function (computation) {
            var status = self.status();

            if (self.instructions && status === "done") {
              computation.stop();
              dataUri.set(self.instructions.download);
            }
            else if (status === "failed" || status === "aborted") {
              computation.stop();
            }
            else if (self.file && !dataUri.curValue) {
              previewRequirement.changed();
              dataUri.set(localUrl.get());
            }
          });
        });
      }

      if (preload) {

        if (self.file && !self.isImage())
          throw new Error("Cannot pre-load anything other than images");

        if (!preloaded) {
          Tracker.nonreactive(function () {
            preloaded = new ReactiveVar();

            Tracker.autorun(function (computation) {
              var url = dataUri.get();

              if (self.instructions) {
                preloadImage(url, function () {
                  computation.stop();
                  preloaded.set(url);
                });
              }
              else
                preloaded.set(url);
            });
          });
        }

        return preloaded.get();
      }
      else
        return dataUri.get();
    },

    /** Gets an upload parameter for the directive.
     *
     * @param {String} name
     * @returns {String|Number|Undefined}
     */

    param: function (name) {
      self.status(); //React to status changes.

      var data = self.instructions && self.instructions.postData,
          field = data && _.findWhere(data, {name: name});

      return field && field.value;
    }

  });
};

/**
 *
 * @param {String} image - URL of image to preload.
 * @param {Function} callback
 */

function preloadImage(image, callback) {
  var preloader = new window.Image();

  preloader.onload = callback;

  preloader.src = image;
}

function readDataUrl(file, callback) {
  var reader = new window.FileReader();

  reader.onloadend = function () {
    callback(reader.result);
  };

  reader.readAsDataURL(file);
}
<|endoftext|>


<commit_before>var HashP = require("hashp").HashP;
HashP.update(exports, {
    "/game" : require("./game").app,
    "/move" : require("./move").app,
    "/" : function (env) {
        var File = require("jack/file").File,
            file = require("file"),
            fileServer = File(file.cwd() + "/index.html"),
            resp = fileServer(env);
        HashP.update(resp.headers, {"Content-Type":"text/html"});
        return resp;
    }
});
<commit_msg>Playing some golf.<commit_after>var HashP = require("hashp").HashP;
HashP.update(exports, {
    "/game" : require("./game").app,
    "/move" : require("./move").app,
    "/" : function (env) {
        var resp = require("jack/file").File(require("file").cwd() + "/index.html")(env);
        HashP.update(resp.headers, {"Content-Type":"text/html"});
        return resp;
    }
});
<|endoftext|>


<commit_before>import FileSaver from 'file-saver'

const importData = (event) => {
  const files = event.target.files;

  if (files[0]) {
    return new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = () => {
        try {
          chrome.storage.local.set(JSON.parse(fileReader.result));
          resolve();
        } catch (e) {
          reject(e);
        }
      };

      fileReader.onerror = (arg) => {
        reject(arg);
      };

      fileReader.readAsText(files[0], 'utf-8');
    });
  } else {
    console.log('Nothing to import');

    return Promise.resolve();
  }
}

const exportData = () => {
  // since there is storageLocal, I don't know if it would be better to put
  // that function call there
  chrome.storage.local.get('savedTabs', (savedTabs) => {
    const result = JSON.stringify(savedTabs);

    const blob = new Blob([result], {
      type: 'application/json;charset=utf-8',
    });
    FileSaver.saveAs(blob, exportFileName(new Date(Date.now())));
  })
}

const exportFileName = (date) => {
  const localeDateString = date.toLocaleDateString().replace(/\//g, '-')
  return `TabWranglerExport-${localeDateString}.json`
}

export {
  importData,
  exportData,
  exportFileName,
}<commit_msg>-update rimraf - simplify the code to read the data from local storage with a function returning a promise. During export all 4 relevant values for an export are read and returned as one result - updated the test<commit_after>import FileSaver from 'file-saver'

function readLocalStorage(key) {
  return new Promise((resolve) => {
    chrome.storage.local.get(key, (value) => {
      resolve(value);
    });
  });
}

const importData = (event) => {
  const files = event.target.files;

  if (files[0]) {
    return new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = () => {
        try {
          chrome.storage.local.set(JSON.parse(fileReader.result));
          resolve();
        } catch (e) {
          reject(e);
        }
      };

      fileReader.onerror = (arg) => {
        reject(arg);
      };

      fileReader.readAsText(files[0], 'utf-8');
    });
  } else {
    console.log('Nothing to import');

    return Promise.resolve();
  }
}

const exportData = () => {
  // since there is storageLocal, I don't know if it would be better to put
  // that function call there
  Promise.all([
    readLocalStorage('savedTabs'),
    readLocalStorage('totalTabsRemoved'),
    readLocalStorage('totalTabsUnwrangled'),
    readLocalStorage('totalTabsWrangled')]).then((allValues) => {
      // allValues is an array containing all the values stored in local storage
      const _result = JSON.stringify(allValues);

      const blob = new Blob([_result], {
        type: 'application/json;charset=utf-8',
      });
      FileSaver.saveAs(blob, exportFileName(new Date(Date.now())));
    });
}

const exportFileName = (date) => {
  const localeDateString = date.toLocaleDateString().replace(/\//g, '-')
  return `TabWranglerExport-${localeDateString}.json`
}

export {
  importData,
  exportData,
  exportFileName,
}<|endoftext|>


<commit_before>;(function($) {
  var columns = 0;
  var padding_width = 0;
  var content_width = 0;
  var scroll_width = 0;
  var content, slider, padding;

  //Cargo-culting from colorbox
  var twoup = $.fn.twoup = $.twoup = function(column_rule) {
    if(content) {
      alert("You already have a twoup!");
      return;
    }

    twoup.content = content = $("

").css({ "-webkit-column-rule": column_rule, "-moz-column-rule": column_rule, "column-rule": column_rule });
    twoup.slider = slider = $("

");
    twoup.padding = padding = $(this).css({ "overflow": "hidden" });

    var children = padding.children().detach();
    padding.append(slider);
    slider.append(content);
    content.append(children);

    if(!twoup.enabled()) return;

    $(window).resize(twoup.layout).resize();

    $(window).bind('hashchange', function() {
console.log("twoup ", (twoup.page() - 1));
      console.log("setting slider left to ", -((twoup.page() - 1) * scroll_width));
      slider.css({ "margin-left": -((twoup.page() - 1) * scroll_width) + "px" });
    }).trigger('hashchange');

    $(window).keydown(function(event) {
      if(event.keyCode == 32 || event.keyCode == 39) {
        event.preventDefault();
        twoup.page(1, true);
      }
      else if(event.keyCode == 8 || event.keyCode == 37) {
        event.preventDefault();
        twoup.page(-1, true);
      }
    });

    return this;
  };

  twoup.enabled = function() {
    //at the moment, only WebKit and MSIE10 has proper support for css3 columns AND getting the right width for a column element with overflow
    return $.browser.webkit || ($.browser.msie && $.browser.version >= 10);
  }

  twoup.columns = function() {
    return Math.max(1, Math.floor($(window).width() / (18 * padding_width)));
  };

  twoup.column_width = function() {
    return twoup.enabled() ? parseInt(content.css("-webkit-column-width") || content.css("-moz-column-width") || content.css("column-width")) : content.width()
  };

  twoup.pages = function() {
    console.log("content_width ", content_width);
    console.log("scroll_width ", scroll_width);
    return Math.ceil(content_width / scroll_width);
  };

  twoup.bound_page_number = function(number) {
    console.log("number ", number);
    var index = parseInt(number);
    if(isNaN(index) || index < 1) index = 1;
    if(index > twoup.pages()) index = twoup.pages();
    console.log("index ", index);

    return index;
  };

  twoup.page_spread = function() {
    var pages = [];
    for(var i = twoup.page(); i < twoup.pages(), pages.length < twoup.columns(); i++) pages.push(i);
    return pages;
  };

  twoup.page = function() {
    if(arguments.length == 2 && arguments[1]) twoup.page(twoup.page() + arguments[0]);
    else if(arguments.length == 1) utils.page(twoup.bound_page_number(arguments[0]));
    else return twoup.bound_page_number(utils.page());
  };

  twoup.layout = function() {
    padding_width = parseInt(padding.css("padding-top"));

    var old_columns = columns;
    columns = twoup.columns();

    var column_gap_width = (padding_width * 2) + parseInt(content.css("-webkit-column-rule-width") || content.css("column-rule-width"));
    var wrapper_width = window.innerWidth;
    var wrapper_height = window.innerHeight;
    var inner_width = wrapper_width - (padding_width * 2);
    var inner_height = wrapper_height - (padding_width * 2);
    console.log("inner_width ", inner_width);
    console.log("inner_height ", inner_height);
    var column_width = Math.floor((inner_width - (column_gap_width * (columns - 1))) / columns);
    scroll_width = inner_width + column_gap_width;

    console.log("column_width ", column_width);
    console.log("scroll_width ", scroll_width);

    padding.css({ "width": wrapper_width + "px", "height": wrapper_height + "px", "overflow": "hidden" });
    content.css({ "width": inner_width + "px", "height": inner_height + "px", "-webkit-column-width": column_width + "px",
     "-moz-column-width": column_width + "px", "column-width": column_width + "px", "-webkit-column-gap": column_gap_width + "px",
     "-moz-column-gap": column_gap_width + "px", "column-gap": column_gap_width + "px" });
    content_width = content[0].scrollWidth;
    console.log("content_width ", content_width);

    if(columns != old_columns) $(window).trigger("onhashchange");
  };
})(jQuery);
<commit_msg>Remove unneeded debugging<commit_after>;(function($) {
  var columns = 0;
  var padding_width = 0;
  var content_width = 0;
  var scroll_width = 0;
  var content, slider, padding;

  //Cargo-culting from colorbox
  var twoup = $.fn.twoup = $.twoup = function(column_rule) {
    if(content) {
      alert("You already have a twoup!");
      return;
    }

    twoup.content = content = $("

").css({ "-webkit-column-rule": column_rule, "-moz-column-rule": column_rule, "column-rule": column_rule });
    twoup.slider = slider = $("

");
    twoup.padding = padding = $(this).css({ "overflow": "hidden" });

    var children = padding.children().detach();
    padding.append(slider);
    slider.append(content);
    content.append(children);

    if(!twoup.enabled()) return;

    $(window).resize(twoup.layout).resize();

    $(window).bind('hashchange', function() {
      slider.css({ "margin-left": -((twoup.page() - 1) * scroll_width) + "px" });
    }).trigger('hashchange');

    $(window).keydown(function(event) {
      if(event.keyCode == 32 || event.keyCode == 39) {
        event.preventDefault();
        twoup.page(1, true);
      }
      else if(event.keyCode == 8 || event.keyCode == 37) {
        event.preventDefault();
        twoup.page(-1, true);
      }
    });

    return this;
  };

  twoup.enabled = function() {
    //at the moment, only WebKit and MSIE10 has proper support for css3 columns AND getting the right width for a column element with overflow
    return $.browser.webkit || ($.browser.msie && $.browser.version >= 10);
  }

  twoup.columns = function() {
    return Math.max(1, Math.floor($(window).width() / (18 * padding_width)));
  };

  twoup.column_width = function() {
    return twoup.enabled() ? parseInt(content.css("-webkit-column-width") || content.css("-moz-column-width") || content.css("column-width")) : content.width()
  };

  twoup.pages = function() {
    return Math.ceil(content_width / scroll_width);
  };

  twoup.bound_page_number = function(number) {
    var index = parseInt(number);
    if(isNaN(index) || index < 1) index = 1;
    if(index > twoup.pages()) index = twoup.pages();

    return index;
  };

  twoup.page_spread = function() {
    var pages = [];
    for(var i = twoup.page(); i < twoup.pages(), pages.length < twoup.columns(); i++) pages.push(i);
    return pages;
  };

  twoup.page = function() {
    if(arguments.length == 2 && arguments[1]) twoup.page(twoup.page() + arguments[0]);
    else if(arguments.length == 1) utils.page(twoup.bound_page_number(arguments[0]));
    else return twoup.bound_page_number(utils.page());
  };

  twoup.layout = function() {
    padding_width = parseInt(padding.css("padding-top"));

    var old_columns = columns;
    columns = twoup.columns();

    var column_gap_width = (padding_width * 2) + parseInt(content.css("-webkit-column-rule-width") || content.css("column-rule-width"));
    var wrapper_width = window.innerWidth;
    var wrapper_height = window.innerHeight;
    var inner_width = wrapper_width - (padding_width * 2);
    var inner_height = wrapper_height - (padding_width * 2);
    var column_width = Math.floor((inner_width - (column_gap_width * (columns - 1))) / columns);
    scroll_width = inner_width + column_gap_width;

    padding.css({ "width": wrapper_width + "px", "height": wrapper_height + "px", "overflow": "hidden" });
    content.css({ "width": inner_width + "px", "height": inner_height + "px", "-webkit-column-width": column_width + "px",
     "-moz-column-width": column_width + "px", "column-width": column_width + "px", "-webkit-column-gap": column_gap_width + "px",
     "-moz-column-gap": column_gap_width + "px", "column-gap": column_gap_width + "px" });
    content_width = content[0].scrollWidth;

    if(columns != old_columns) $(window).trigger("onhashchange");
  };
})(jQuery);
<|endoftext|>


<commit_before>import Entity, { printMessage, action, time, state } from "../Entity.js";

export class AlarmClock extends Entity {
  constructor() {
    super();
  }

  name() {
    return "garage door";
  }

  actions() {
    return [
      action(
        "Open.",
        () => {
          state.garageDoorOpen = true;
          printMessage("You open the garage door. It's a nice day out.");
        },
        () => !state.garageDoorOpen
      ),
      action(
        "Close.",
        () => {
          state.garageDoorOpen = false;
          printMessage("For some reason, you close the garage door again.");
        },
        () => state.garageDoorOpen
      )
    ];
  }
}

export default new AlarmClock();
<commit_msg>names are important<commit_after>import Entity, { printMessage, action, time, state } from "../Entity.js";

export class GarageDoor extends Entity {
  constructor() {
    super();
  }

  name() {
    return "garage door";
  }

  actions() {
    return [
      action(
        "Open.",
        () => {
          state.garageDoorOpen = true;
          printMessage("You open the garage door. It's a nice day out.");
        },
        () => !state.garageDoorOpen
      ),
      action(
        "Close.",
        () => {
          state.garageDoorOpen = false;
          printMessage("For some reason, you close the garage door again.");
        },
        () => state.garageDoorOpen
      )
    ];
  }
}

export default new GarageDoor();
<|endoftext|>


<commit_before>'use strict';

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const port = process.env.PORT || 7000;
let app = express();

app.use(express.static(path.join(__dirname, '../public')));
app.use(express.static(path.join(__dirname, '../assets')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.get('/', (req, res, next) => res.sendFile(path.join(__dirname, '../index.html')));

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send(err);
});

app.listen(port, function() {
  console.log('Server is listening on port ' + port + '!');
});
<commit_msg>fixed routing<commit_after>'use strict';

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const port = process.env.PORT || 7000;
let app = express();

app.use('/static', express.static(path.join(__dirname, '../static')));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

app.get('/', (req, res, next) => res.sendFile(path.join(__dirname, '../index.html')));

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send(err);
});

app.listen(port, function() {
  console.log('Server is listening on port ' + port + '!');
});
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var glob = require('glob');
var parseImports = require('./parse-imports');

// resolve a sass module to a path
function resolveSassPath(sassPath, loadPaths) {
  // trim any file extensions
  var sassPathName = sassPath.replace(/\.\w+$/, '');
  // check all load paths
  for(var p in loadPaths) {
    var scssPath = path.normalize(loadPaths[p] + "/" + sassPathName + ".scss");
    if (fs.existsSync(scssPath)) {
      return scssPath;
    }
    // special case for _partials
    var partialPath = path.join(path.dirname(scssPath), "_" + path.basename(scssPath));
    if (fs.existsSync(partialPath)) {
      return partialPath
    }
  }
  var errMsg = "File to import not found or unreadable: " + sassPath;
  throw errMsg;
}

function Graph(loadPaths, dir) {
  this.dir = dir;
  this.loadPaths = loadPaths;
  this.index = {};

  if(dir) {
    var graph = this;
    _(glob.sync(dir+"/**/*.scss", {})).forEach(function(file) {
      graph.addFile(path.resolve(file));
    });
  }
}

// add a sass file to the graph
Graph.prototype.addFile = function(filepath, parent) {
  var entry = this.index[filepath] = this.index[filepath] || {
    imports: [],
    importedBy: [],
    modified: fs.statSync(filepath).mtime
  };

  var imports = parseImports(fs.readFileSync(filepath, 'utf-8'));
  var cwd = path.dirname(filepath)

  for (var i in imports) {
    [this.dir, cwd].forEach(function (path) {
      if (path) {
        this.loadPaths.push(path);
      }
    }.bind(this));
    var resolved = resolveSassPath(imports[i], _.uniq(this.loadPaths));
    if (!resolved) return false;

    // recurse into dependencies if not already enumerated
    if(!_.contains(entry.imports, resolved)) {
      entry.imports.push(resolved);
      this.addFile(resolved, filepath);
    }
  }

  // add link back to parent
  if(parent != null) {
    entry.importedBy.push(parent);
  }
};

// visits all files that are ancestors of the provided file
Graph.prototype.visitAncestors = function(filepath, callback) {
  this.visit(filepath, callback, function(node) {
    return node.importedBy;
  });
};

// visits all files that are descendents of the provided file
Graph.prototype.visitDescendents = function(filepath, callback) {
  this.visit(filepath, callback, function(node) {
    return node.imports;
  });
};

// a generic visitor that uses an edgeCallback to find the edges to traverse for a node
Graph.prototype.visit = function(filepath, callback, edgeCallback, visited) {
  var visited = visited || [];
  if(!this.index.hasOwnProperty(filepath)) {
    throw "Graph doesn't contain "+filepath;
  }
  var edges = edgeCallback(this.index[filepath]);
  for(var i in edges) {
    if(!_.contains(visited, edges[i])) {
      visited.push(edges[i]);
      callback(edges[i], this.index[edges[i]]);
      this.visit(edges[i], callback, edgeCallback, visited);
    }
  }
};

function processOptions(options) {
  options = options || {};
  if(!options.hasOwnProperty('loadPaths')) options['loadPaths'] = [];
  return options;
}

module.exports.parseFile = function(filepath, options) {
  var filepath = path.resolve(filepath);
  var options = processOptions(options);
  var graph = new Graph(options.loadPaths);
  graph.addFile(filepath);
  return graph;
};

module.exports.parseDir = function(dirpath, options) {
  var dirpath = path.resolve(dirpath);
  var options = processOptions(options);
  var graph = new Graph(options.loadPaths, dirpath);
  return graph;
};
<commit_msg>Normalise index paths<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var glob = require('glob');
var parseImports = require('./parse-imports');

// resolve a sass module to a path
function resolveSassPath(sassPath, loadPaths) {
  // trim any file extensions
  var sassPathName = sassPath.replace(/\.\w+$/, '');
  // check all load paths
  for(var p in loadPaths) {
    var scssPath = path.normalize(loadPaths[p] + "/" + sassPathName + ".scss");
    if (fs.existsSync(scssPath)) {
      return scssPath;
    }
    // special case for _partials
    var partialPath = path.join(path.dirname(scssPath), "_" + path.basename(scssPath));
    if (fs.existsSync(partialPath)) {
      return partialPath
    }
  }
  var errMsg = "File to import not found or unreadable: " + sassPath;
  throw errMsg;
}

function Graph(loadPaths, dir) {
  this.dir = dir;
  this.loadPaths = loadPaths;
  this.index = {};

  if(dir) {
    var graph = this;
    _(glob.sync(dir+"/**/*.scss", {})).forEach(function(file) {
      graph.addFile(path.resolve(file));
    });
  }
}

// add a sass file to the graph
Graph.prototype.addFile = function(filepath, parent) {
  var entry = this.index[filepath] = this.index[filepath] || {
    imports: [],
    importedBy: [],
    modified: fs.statSync(filepath).mtime
  };

  var resolvedParent;
  var imports = parseImports(fs.readFileSync(filepath, 'utf-8'));
  var cwd = path.dirname(filepath);

  for (var i in imports) {
    [this.dir, cwd].forEach(function (path) {
      if (path && this.loadPaths.indexOf(path) === -1) {
        this.loadPaths.push(path);
      }
    }.bind(this));
    var resolved = resolveSassPath(imports[i], _.uniq(this.loadPaths));
    if (!resolved) return false;

    // recurse into dependencies if not already enumerated
    if(!_.contains(entry.imports, resolved)) {
      entry.imports.push(resolved);
      this.addFile(fs.realpathSync(resolved), filepath);
    }
  }

  // add link back to parent
  if(parent) {
    resolvedParent = _.find(this.loadPaths, function(path) {
      return parent.indexOf(path) !== -1;
    }) || parent;
    resolvedParent = parent.substr(parent.indexOf(resolvedParent)).replace(/^\/*/, '');
    entry.importedBy.push(resolvedParent);
  }
};

// visits all files that are ancestors of the provided file
Graph.prototype.visitAncestors = function(filepath, callback) {
  this.visit(filepath, callback, function(node) {
    return node.importedBy;
  });
};

// visits all files that are descendents of the provided file
Graph.prototype.visitDescendents = function(filepath, callback) {
  this.visit(filepath, callback, function(node) {
    return node.imports;
  });
};

// a generic visitor that uses an edgeCallback to find the edges to traverse for a node
Graph.prototype.visit = function(filepath, callback, edgeCallback, visited) {
  filepath = fs.realpathSync(filepath);
  var visited = visited || [];
  if(!this.index.hasOwnProperty(filepath)) {
    throw "Graph doesn't contain "+filepath;
  }
  var edges = edgeCallback(this.index[filepath]);
  for(var i in edges) {
    if(!_.contains(visited, edges[i])) {
      visited.push(edges[i]);
      callback(edges[i], this.index[edges[i]]);
      this.visit(edges[i], callback, edgeCallback, visited);
    }
  }
};

function processOptions(options) {
  options = options || {};
  if(!options.hasOwnProperty('loadPaths')) options['loadPaths'] = [];
  return options;
}

module.exports.parseFile = function(filepath, options) {
  var filepath = path.resolve(filepath);
  var options = processOptions(options);
  var graph = new Graph(options.loadPaths);
  graph.addFile(filepath);
  return graph;
};

module.exports.parseDir = function(dirpath, options) {
  var dirpath = path.resolve(dirpath);
  var options = processOptions(options);
  var graph = new Graph(options.loadPaths, dirpath);
  return graph;
};
<|endoftext|>