<commit_before>import patchOps from '../client/patchOps';
import domAttrs from '../client/domAttrs';
import checkReuse from './utils/checkReuse';
import checkChildren from './utils/checkChildren';
import patchChildren from './utils/patchChildren';
import { addListener, removeListeners } from '../client/events/domEventManager';
import ATTRS_TO_EVENTS from '../client/events/attrsToEvents';
import escapeHtml from '../utils/escapeHtml';
import isInArray from '../utils/isInArray';
import console from '../utils/console';
import emptyObj from '../utils/emptyObj';
import merge from '../utils/merge';
import { isTrident, isEdge } from '../client/utils/ua';
import createElement from '../client/utils/createElement';
import createElementByHtml from '../client/utils/createElementByHtml';
import restrictObjProp from '../utils/restrictObjProp';
import { IS_DEBUG } from '../utils/debug';
import SimpleMap from '../utils/SimpleMap';
import { NODE_TYPE_TAG } from './utils/nodeTypes';
import { setKey, setRef } from './utils/setters';

const SHORT_TAGS = new SimpleMap([
        ['area'],
        ['base'],
        ['br'],
        ['col'],
        ['command'],
        ['embed'],
        ['hr'],
        ['img'],
        ['input'],
        ['keygen'],
        ['link'],
        ['menuitem'],
        ['meta'],
        ['param'],
        ['source'],
        ['track'],
        ['wbr']
    ]),
    USE_DOM_STRINGS = isTrident || isEdge,
    ATTRS_SET = 4,
    CHILDREN_SET = 8,
    NS_SET = 16;

export default function TagNode(tag) {
    if(IS_DEBUG) {
        restrictObjProp(this, 'type');
        restrictObjProp(this, 'tag');
        restrictObjProp(this, 'key');
        restrictObjProp(this, 'attrs');
        restrictObjProp(this, 'children');

        this.__isFrozen = false;
    }

    this.type = NODE_TYPE_TAG;
    this.tag = tag;
    this.key = null;
    this.attrs = emptyObj;
    this.children = null;

    if(IS_DEBUG) {
        this.__isFrozen = true;
        this._sets = 0;
    }

    this._domNode = null;
    this._ns = null;
    this._escapeChildren = true;
    this._ctx = emptyObj;
    this._ref = null;
}

TagNode.prototype = {
    getDomNode() {
        return this._domNode;
    },

    setKey,

    setRef,

    setNs(ns) {
        if(IS_DEBUG) {
            if(this._sets & NS_SET) {
                console.warn('Namespace is already set and shouldn\'t be set again.');
            }
        }

        this._ns = ns;

        if(IS_DEBUG) {
            this._sets |= NS_SET;
        }

        return this;
    },

    setAttrs(attrs) {
        if(IS_DEBUG) {
            if(this._sets & ATTRS_SET) {
                console.warn('Attrs are already set and shouldn\'t be set again.');
            }

            checkAttrs(attrs);
            this.__isFrozen = false;
        }

        this.attrs = this.attrs === emptyObj? attrs : merge(this.attrs, attrs);

        if(IS_DEBUG) {
            Object.freeze(this.attrs);
            this._sets |= ATTRS_SET;
            this.__isFrozen = true;
        }

        return this;
    },

    setChildren(children) {
        if(IS_DEBUG) {
            if(this._sets & CHILDREN_SET) {
                console.warn('Children are already set and shouldn\'t be set again.');
            }

            this.__isFrozen = false;
        }

        this.children = processChildren(children);

        if(IS_DEBUG) {
            if(Array.isArray(this.children)) {
                Object.freeze(this.children);
            }

            this._sets |= CHILDREN_SET;
            this.__isFrozen = true;
        }

        return this;
    },

    setHtml(html) {
        if(IS_DEBUG) {
            if(this._sets & CHILDREN_SET) {
                console.warn('Children are already set and shouldn\'t be set again.');
            }

            this.__isFrozen = false;
        }

        this.children = '' + html;

        if(IS_DEBUG) {
            this._sets |= CHILDREN_SET;
            this.__isFrozen = true;
        }

        this._escapeChildren = false;
        return this;
    },

    setCtx(ctx) {
        if(ctx !== emptyObj) {
            this._ctx = ctx;

            const { children } = this;

            if(children !== null && typeof children !== 'string') {
                const len = children.length;
                let i = 0;

                while(i < len) {
                    children[i++].setCtx(ctx);
                }
            }
        }

        return this;
    },

    renderToDom(parentNs) {
        if(IS_DEBUG) {
            checkReuse(this, this.tag);
        }

        const { tag, children } = this,
            ns = this._ns || parentNs;

        if(USE_DOM_STRINGS && children && typeof children !== 'string') {
            const domNode = createElementByHtml(this.renderToString(), tag, ns);

            this.adoptDom([domNode], 0);
            return domNode;
        }

        const domNode = this._domNode = createElement(tag, ns),
            { attrs } = this;

        if(children !== null) {
            console.log(tag, typeof children);
            if(typeof children === 'string') {
                this._escapeChildren?
                    domNode.textContent = children :
                    domNode.innerHTML = children;
            }
            else {
                let i = 0;
                const len = children.length;

                while(i < len) {
                    domNode.appendChild(children[i++].renderToDom(ns));
                }
            }
        }

        if(attrs !== emptyObj) {
            let name, value;

            for(name in attrs) {
                if((value = attrs[name]) != null) {
                    if(ATTRS_TO_EVENTS.has(name)) {
                        addListener(domNode, ATTRS_TO_EVENTS.get(name), value);
                    }
                    else {
                        domAttrs(name).set(domNode, name, value);
                    }
                }
            }
        }

        return domNode;
    },

    renderToString() {
        const { tag } = this;

        if(tag === '!') {
            return '<!---->';
        }

        const ns = this._ns,
            { attrs } = this;
        let { children } = this,
            res = '<' + tag;

        if(ns !== null) {
            res += ' xmlns="' + ns + '"';
        }

        if(attrs !== emptyObj) {
            let name, value, attrHtml;

            for(name in attrs) {
                value = attrs[name];

                if(value != null) {
                    if(name === 'value') {
                        switch(tag) {
                            case 'textarea':
                                children = value;
                                continue;

                            case 'select':
                                this.setCtx({ value, multiple : attrs.multiple });
                                continue;

                            case 'option':
                                const ctx = this._ctx;

                                if(ctx.multiple? isInArray(ctx.value, value) : ctx.value === value) {
                                    res += ' ' + domAttrs('selected').toString('selected', true);
                                }
                        }
                    }

                    if(!ATTRS_TO_EVENTS.has(name) && (attrHtml = domAttrs(name).toString(name, value)) !== '') {
                        res += ' ' + attrHtml;
                    }
                }
            }
        }

        if(SHORT_TAGS.has(tag)) {
            res += '/>';
        }
        else {
            res += '>';

            if(children !== null) {
                if(typeof children === 'string') {
                    res += this._escapeChildren?
                        escapeHtml(children) :
                        children;
                }
                else {
                    let i = 0;
                    const len = children.length;

                    while(i < len) {
                        res += children[i++].renderToString();
                    }
                }
            }

            res += '</' + tag + '>';
        }

        return res;
    },

    adoptDom(domNodes, domIdx) {
        if(IS_DEBUG) {
            checkReuse(this, this.tag);
        }

        const domNode = this._domNode = domNodes[domIdx],
            { attrs, children } = this;

        if(attrs !== emptyObj) {
            let name, value;
            for(name in attrs) {
                if((value = attrs[name]) != null && ATTRS_TO_EVENTS.has(name)) {
                    addListener(domNode, ATTRS_TO_EVENTS.get(name), value);
                }
            }
        }

        if(children !== null && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            if(len > 0) {
                const domChildren = domNode.childNodes;
                let domChildIdx = 0;

                while(i < len) {
                    domChildIdx = children[i++].adoptDom(domChildren, domChildIdx);
                }
            }
        }

        return domIdx + 1;
    },

    mount() {
        const { children } = this;

        if(children !== null && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            while(i < len) {
                children[i++].mount();
            }
        }

        this._ref && this._ref(this._domNode);
    },

    unmount() {
        const { children } = this;

        if(children && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            while(i < len) {
                children[i++].unmount();
            }
        }

        removeListeners(this._domNode);

        this._domNode = null;

        this._ref && this._ref(null);
    },

    clone() {
        const res = new TagNode(this.tag);

        if(IS_DEBUG) {
            res.__isFrozen = false;
        }

        res.key = this.key;
        res.attrs = this.attrs;
        res.children = this.children;

        if(IS_DEBUG) {
            res.__isFrozen = true;
        }

        res._sets = NS_SET;
        res._ns = this._ns;
        res._escapeChildren = this._escapeChildren;
        res._ctx = this._ctx;
        res._ref = this._ref;

        return res;
    },

    patch(node) {
        if(this === node) {
            this._patchChildren(node);
        }
        else if(this.type === node.type && this.tag === node.tag && this._ns === node._ns) {
            node._domNode = this._domNode;
            this._patchAttrs(node);
            this._patchChildren(node);
            this._patchRef(node);
        }
        else {
            patchOps.replace(this, node);
        }
    },

    _patchChildren(node) {
        const childrenA = this.children,
            childrenB = node.children;

        if(childrenA === null && childrenB === null) {
            return;
        }

        const isChildrenAText = typeof childrenA === 'string',
            isChildrenBText = typeof childrenB === 'string';

        if(isChildrenBText) {
            if(isChildrenAText) {
                if(childrenA !== childrenB) {
                    patchOps.updateText(this, childrenB, node._escapeChildren);
                }
                return;
            }

            if(childrenA !== null && childrenA.length > 0) {
                patchOps.removeChildren(this);
            }

            if(childrenB !== '') {
                patchOps.updateText(this, childrenB, node._escapeChildren);
            }

            return;
        }

        if(childrenB === null || childrenB.length === 0) {
            if(childrenA) {
                if(isChildrenAText) {
                    patchOps.removeText(this);
                }
                else if(childrenA.length > 0) {
                    patchOps.removeChildren(this);
                }
            }

            return;
        }

        if(isChildrenAText && childrenA !== '') {
            patchOps.removeText(this);
        }

        if(isChildrenAText || childrenA === null || childrenA.length === 0) {
            const childrenBLen = childrenB.length;
            let iB = 0;

            while(iB < childrenBLen) {
                patchOps.appendChild(node, childrenB[iB++]);
            }

            return;
        }

        patchChildren(this, node);
    },

    _patchAttrs(node) {
        const attrsA = this.attrs,
            attrsB = node.attrs;

        if(attrsA === attrsB) {
            return;
        }

        let attrName;

        if(attrsB !== emptyObj) {
            let attrAVal, attrBVal, isAttrAValArray, isAttrBValArray;

            for(attrName in attrsB) {
                attrBVal = attrsB[attrName];
                if(attrsA === emptyObj || (attrAVal = attrsA[attrName]) == null) {
                    if(attrBVal != null) {
                        patchOps.updateAttr(this, attrName, attrBVal);
                    }
                }
                else if(attrBVal == null) {
                    patchOps.removeAttr(this, attrName);
                }
                else if(typeof attrBVal === 'object' && typeof attrAVal === 'object') {
                    isAttrBValArray = Array.isArray(attrBVal);
                    isAttrAValArray = Array.isArray(attrAVal);
                    if(isAttrBValArray || isAttrAValArray) {
                        if(isAttrBValArray && isAttrAValArray) {
                            this._patchAttrArr(attrName, attrAVal, attrBVal);
                        }
                        else {
                            patchOps.updateAttr(this, attrName, attrBVal);
                        }
                    }
                    else {
                        this._patchAttrObj(attrName, attrAVal, attrBVal);
                    }
                }
                else if(attrAVal !== attrBVal) {
                    patchOps.updateAttr(this, attrName, attrBVal);
                }
            }
        }

        if(attrsA !== emptyObj) {
            for(attrName in attrsA) {
                if((attrsB === emptyObj || !(attrName in attrsB)) && attrsA[attrName] != null) {
                    patchOps.removeAttr(this, attrName);
                }
            }
        }
    },

    _patchAttrArr(attrName, arrA, arrB) {
        if(arrA === arrB) {
            return;
        }

        const lenA = arrA.length;
        let hasDiff = false;

        if(lenA === arrB.length) {
            let i = 0;
            while(!hasDiff && i < lenA) {
                if(arrA[i] != arrB[i]) {
                    hasDiff = true;
                }
                ++i;
            }
        }
        else {
            hasDiff = true;
        }

        hasDiff && patchOps.updateAttr(this, attrName, arrB);
    },

    _patchAttrObj(attrName, objA, objB) {
        if(objA === objB) {
            return;
        }

        const diffObj = {};
        let hasDiff = false;

        for(const i in objB) {
            if(objA[i] != objB[i]) {
                hasDiff = true;
                diffObj[i] = objB[i];
            }
        }

        for(const i in objA) {
            if(objA[i] != null && !(i in objB)) {
                hasDiff = true;
                diffObj[i] = null;
            }
        }

        hasDiff && patchOps.updateAttr(this, attrName, diffObj);
    },

    _patchRef(node) {
        if(this._ref !== null) {
            if(this._ref !== node._ref) {
                this._ref(null);

                if(node._ref !== null) {
                    node._ref(node._domNode);
                }
            }
        }
        else if(node._ref !== null) {
            node._ref(node._domNode);
        }
    }
};

function processChildren(children) {
    if(children == null) {
        return null;
    }

    const typeOfChildren = typeof children;

    if(typeOfChildren === 'object') {
        const res = Array.isArray(children)? children : [children];

        if(IS_DEBUG) {
            checkChildren(res);
        }

        return res;
    }

    return typeOfChildren === 'string'?
        children :
        '' + children;
}

function checkAttrs(attrs) {
    for(const name in attrs) {
        if(name.substr(0, 2) === 'on' && !ATTRS_TO_EVENTS.has(name)) {
            throw Error(`vidom: Unsupported type of dom event listener "${name}".`);
        }
    }
}
<commit_msg>-console.log<commit_after>import patchOps from '../client/patchOps';
import domAttrs from '../client/domAttrs';
import checkReuse from './utils/checkReuse';
import checkChildren from './utils/checkChildren';
import patchChildren from './utils/patchChildren';
import { addListener, removeListeners } from '../client/events/domEventManager';
import ATTRS_TO_EVENTS from '../client/events/attrsToEvents';
import escapeHtml from '../utils/escapeHtml';
import isInArray from '../utils/isInArray';
import console from '../utils/console';
import emptyObj from '../utils/emptyObj';
import merge from '../utils/merge';
import { isTrident, isEdge } from '../client/utils/ua';
import createElement from '../client/utils/createElement';
import createElementByHtml from '../client/utils/createElementByHtml';
import restrictObjProp from '../utils/restrictObjProp';
import { IS_DEBUG } from '../utils/debug';
import SimpleMap from '../utils/SimpleMap';
import { NODE_TYPE_TAG } from './utils/nodeTypes';
import { setKey, setRef } from './utils/setters';

const SHORT_TAGS = new SimpleMap([
        ['area'],
        ['base'],
        ['br'],
        ['col'],
        ['command'],
        ['embed'],
        ['hr'],
        ['img'],
        ['input'],
        ['keygen'],
        ['link'],
        ['menuitem'],
        ['meta'],
        ['param'],
        ['source'],
        ['track'],
        ['wbr']
    ]),
    USE_DOM_STRINGS = isTrident || isEdge,
    ATTRS_SET = 4,
    CHILDREN_SET = 8,
    NS_SET = 16;

export default function TagNode(tag) {
    if(IS_DEBUG) {
        restrictObjProp(this, 'type');
        restrictObjProp(this, 'tag');
        restrictObjProp(this, 'key');
        restrictObjProp(this, 'attrs');
        restrictObjProp(this, 'children');

        this.__isFrozen = false;
    }

    this.type = NODE_TYPE_TAG;
    this.tag = tag;
    this.key = null;
    this.attrs = emptyObj;
    this.children = null;

    if(IS_DEBUG) {
        this.__isFrozen = true;
        this._sets = 0;
    }

    this._domNode = null;
    this._ns = null;
    this._escapeChildren = true;
    this._ctx = emptyObj;
    this._ref = null;
}

TagNode.prototype = {
    getDomNode() {
        return this._domNode;
    },

    setKey,

    setRef,

    setNs(ns) {
        if(IS_DEBUG) {
            if(this._sets & NS_SET) {
                console.warn('Namespace is already set and shouldn\'t be set again.');
            }
        }

        this._ns = ns;

        if(IS_DEBUG) {
            this._sets |= NS_SET;
        }

        return this;
    },

    setAttrs(attrs) {
        if(IS_DEBUG) {
            if(this._sets & ATTRS_SET) {
                console.warn('Attrs are already set and shouldn\'t be set again.');
            }

            checkAttrs(attrs);
            this.__isFrozen = false;
        }

        this.attrs = this.attrs === emptyObj? attrs : merge(this.attrs, attrs);

        if(IS_DEBUG) {
            Object.freeze(this.attrs);
            this._sets |= ATTRS_SET;
            this.__isFrozen = true;
        }

        return this;
    },

    setChildren(children) {
        if(IS_DEBUG) {
            if(this._sets & CHILDREN_SET) {
                console.warn('Children are already set and shouldn\'t be set again.');
            }

            this.__isFrozen = false;
        }

        this.children = processChildren(children);

        if(IS_DEBUG) {
            if(Array.isArray(this.children)) {
                Object.freeze(this.children);
            }

            this._sets |= CHILDREN_SET;
            this.__isFrozen = true;
        }

        return this;
    },

    setHtml(html) {
        if(IS_DEBUG) {
            if(this._sets & CHILDREN_SET) {
                console.warn('Children are already set and shouldn\'t be set again.');
            }

            this.__isFrozen = false;
        }

        this.children = '' + html;

        if(IS_DEBUG) {
            this._sets |= CHILDREN_SET;
            this.__isFrozen = true;
        }

        this._escapeChildren = false;
        return this;
    },

    setCtx(ctx) {
        if(ctx !== emptyObj) {
            this._ctx = ctx;

            const { children } = this;

            if(children !== null && typeof children !== 'string') {
                const len = children.length;
                let i = 0;

                while(i < len) {
                    children[i++].setCtx(ctx);
                }
            }
        }

        return this;
    },

    renderToDom(parentNs) {
        if(IS_DEBUG) {
            checkReuse(this, this.tag);
        }

        const { tag, children } = this,
            ns = this._ns || parentNs;

        if(USE_DOM_STRINGS && children && typeof children !== 'string') {
            const domNode = createElementByHtml(this.renderToString(), tag, ns);

            this.adoptDom([domNode], 0);
            return domNode;
        }

        const domNode = this._domNode = createElement(tag, ns),
            { attrs } = this;

        if(children !== null) {
            if(typeof children === 'string') {
                this._escapeChildren?
                    domNode.textContent = children :
                    domNode.innerHTML = children;
            }
            else {
                let i = 0;
                const len = children.length;

                while(i < len) {
                    domNode.appendChild(children[i++].renderToDom(ns));
                }
            }
        }

        if(attrs !== emptyObj) {
            let name, value;

            for(name in attrs) {
                if((value = attrs[name]) != null) {
                    if(ATTRS_TO_EVENTS.has(name)) {
                        addListener(domNode, ATTRS_TO_EVENTS.get(name), value);
                    }
                    else {
                        domAttrs(name).set(domNode, name, value);
                    }
                }
            }
        }

        return domNode;
    },

    renderToString() {
        const { tag } = this;

        if(tag === '!') {
            return '<!---->';
        }

        const ns = this._ns,
            { attrs } = this;
        let { children } = this,
            res = '<' + tag;

        if(ns !== null) {
            res += ' xmlns="' + ns + '"';
        }

        if(attrs !== emptyObj) {
            let name, value, attrHtml;

            for(name in attrs) {
                value = attrs[name];

                if(value != null) {
                    if(name === 'value') {
                        switch(tag) {
                            case 'textarea':
                                children = value;
                                continue;

                            case 'select':
                                this.setCtx({ value, multiple : attrs.multiple });
                                continue;

                            case 'option':
                                const ctx = this._ctx;

                                if(ctx.multiple? isInArray(ctx.value, value) : ctx.value === value) {
                                    res += ' ' + domAttrs('selected').toString('selected', true);
                                }
                        }
                    }

                    if(!ATTRS_TO_EVENTS.has(name) && (attrHtml = domAttrs(name).toString(name, value)) !== '') {
                        res += ' ' + attrHtml;
                    }
                }
            }
        }

        if(SHORT_TAGS.has(tag)) {
            res += '/>';
        }
        else {
            res += '>';

            if(children !== null) {
                if(typeof children === 'string') {
                    res += this._escapeChildren?
                        escapeHtml(children) :
                        children;
                }
                else {
                    let i = 0;
                    const len = children.length;

                    while(i < len) {
                        res += children[i++].renderToString();
                    }
                }
            }

            res += '</' + tag + '>';
        }

        return res;
    },

    adoptDom(domNodes, domIdx) {
        if(IS_DEBUG) {
            checkReuse(this, this.tag);
        }

        const domNode = this._domNode = domNodes[domIdx],
            { attrs, children } = this;

        if(attrs !== emptyObj) {
            let name, value;
            for(name in attrs) {
                if((value = attrs[name]) != null && ATTRS_TO_EVENTS.has(name)) {
                    addListener(domNode, ATTRS_TO_EVENTS.get(name), value);
                }
            }
        }

        if(children !== null && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            if(len > 0) {
                const domChildren = domNode.childNodes;
                let domChildIdx = 0;

                while(i < len) {
                    domChildIdx = children[i++].adoptDom(domChildren, domChildIdx);
                }
            }
        }

        return domIdx + 1;
    },

    mount() {
        const { children } = this;

        if(children !== null && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            while(i < len) {
                children[i++].mount();
            }
        }

        this._ref && this._ref(this._domNode);
    },

    unmount() {
        const { children } = this;

        if(children && typeof children !== 'string') {
            let i = 0;
            const len = children.length;

            while(i < len) {
                children[i++].unmount();
            }
        }

        removeListeners(this._domNode);

        this._domNode = null;

        this._ref && this._ref(null);
    },

    clone() {
        const res = new TagNode(this.tag);

        if(IS_DEBUG) {
            res.__isFrozen = false;
        }

        res.key = this.key;
        res.attrs = this.attrs;
        res.children = this.children;

        if(IS_DEBUG) {
            res.__isFrozen = true;
        }

        res._sets = NS_SET;
        res._ns = this._ns;
        res._escapeChildren = this._escapeChildren;
        res._ctx = this._ctx;
        res._ref = this._ref;

        return res;
    },

    patch(node) {
        if(this === node) {
            this._patchChildren(node);
        }
        else if(this.type === node.type && this.tag === node.tag && this._ns === node._ns) {
            node._domNode = this._domNode;
            this._patchAttrs(node);
            this._patchChildren(node);
            this._patchRef(node);
        }
        else {
            patchOps.replace(this, node);
        }
    },

    _patchChildren(node) {
        const childrenA = this.children,
            childrenB = node.children;

        if(childrenA === null && childrenB === null) {
            return;
        }

        const isChildrenAText = typeof childrenA === 'string',
            isChildrenBText = typeof childrenB === 'string';

        if(isChildrenBText) {
            if(isChildrenAText) {
                if(childrenA !== childrenB) {
                    patchOps.updateText(this, childrenB, node._escapeChildren);
                }
                return;
            }

            if(childrenA !== null && childrenA.length > 0) {
                patchOps.removeChildren(this);
            }

            if(childrenB !== '') {
                patchOps.updateText(this, childrenB, node._escapeChildren);
            }

            return;
        }

        if(childrenB === null || childrenB.length === 0) {
            if(childrenA) {
                if(isChildrenAText) {
                    patchOps.removeText(this);
                }
                else if(childrenA.length > 0) {
                    patchOps.removeChildren(this);
                }
            }

            return;
        }

        if(isChildrenAText && childrenA !== '') {
            patchOps.removeText(this);
        }

        if(isChildrenAText || childrenA === null || childrenA.length === 0) {
            const childrenBLen = childrenB.length;
            let iB = 0;

            while(iB < childrenBLen) {
                patchOps.appendChild(node, childrenB[iB++]);
            }

            return;
        }

        patchChildren(this, node);
    },

    _patchAttrs(node) {
        const attrsA = this.attrs,
            attrsB = node.attrs;

        if(attrsA === attrsB) {
            return;
        }

        let attrName;

        if(attrsB !== emptyObj) {
            let attrAVal, attrBVal, isAttrAValArray, isAttrBValArray;

            for(attrName in attrsB) {
                attrBVal = attrsB[attrName];
                if(attrsA === emptyObj || (attrAVal = attrsA[attrName]) == null) {
                    if(attrBVal != null) {
                        patchOps.updateAttr(this, attrName, attrBVal);
                    }
                }
                else if(attrBVal == null) {
                    patchOps.removeAttr(this, attrName);
                }
                else if(typeof attrBVal === 'object' && typeof attrAVal === 'object') {
                    isAttrBValArray = Array.isArray(attrBVal);
                    isAttrAValArray = Array.isArray(attrAVal);
                    if(isAttrBValArray || isAttrAValArray) {
                        if(isAttrBValArray && isAttrAValArray) {
                            this._patchAttrArr(attrName, attrAVal, attrBVal);
                        }
                        else {
                            patchOps.updateAttr(this, attrName, attrBVal);
                        }
                    }
                    else {
                        this._patchAttrObj(attrName, attrAVal, attrBVal);
                    }
                }
                else if(attrAVal !== attrBVal) {
                    patchOps.updateAttr(this, attrName, attrBVal);
                }
            }
        }

        if(attrsA !== emptyObj) {
            for(attrName in attrsA) {
                if((attrsB === emptyObj || !(attrName in attrsB)) && attrsA[attrName] != null) {
                    patchOps.removeAttr(this, attrName);
                }
            }
        }
    },

    _patchAttrArr(attrName, arrA, arrB) {
        if(arrA === arrB) {
            return;
        }

        const lenA = arrA.length;
        let hasDiff = false;

        if(lenA === arrB.length) {
            let i = 0;
            while(!hasDiff && i < lenA) {
                if(arrA[i] != arrB[i]) {
                    hasDiff = true;
                }
                ++i;
            }
        }
        else {
            hasDiff = true;
        }

        hasDiff && patchOps.updateAttr(this, attrName, arrB);
    },

    _patchAttrObj(attrName, objA, objB) {
        if(objA === objB) {
            return;
        }

        const diffObj = {};
        let hasDiff = false;

        for(const i in objB) {
            if(objA[i] != objB[i]) {
                hasDiff = true;
                diffObj[i] = objB[i];
            }
        }

        for(const i in objA) {
            if(objA[i] != null && !(i in objB)) {
                hasDiff = true;
                diffObj[i] = null;
            }
        }

        hasDiff && patchOps.updateAttr(this, attrName, diffObj);
    },

    _patchRef(node) {
        if(this._ref !== null) {
            if(this._ref !== node._ref) {
                this._ref(null);

                if(node._ref !== null) {
                    node._ref(node._domNode);
                }
            }
        }
        else if(node._ref !== null) {
            node._ref(node._domNode);
        }
    }
};

function processChildren(children) {
    if(children == null) {
        return null;
    }

    const typeOfChildren = typeof children;

    if(typeOfChildren === 'object') {
        const res = Array.isArray(children)? children : [children];

        if(IS_DEBUG) {
            checkChildren(res);
        }

        return res;
    }

    return typeOfChildren === 'string'?
        children :
        '' + children;
}

function checkAttrs(attrs) {
    for(const name in attrs) {
        if(name.substr(0, 2) === 'on' && !ATTRS_TO_EVENTS.has(name)) {
            throw Error(`vidom: Unsupported type of dom event listener "${name}".`);
        }
    }
}
<|endoftext|>


<commit_before>const {knex} = require('../util/database').connect();
import _ from 'lodash';
import {deepChangeKeyCase} from '../util';

function getTeams() {
  return knex.raw(`SELECT teams.id, teams.name, SUM(COALESCE(action_types.value, 0)) AS score
  FROM teams
  LEFT JOIN actions ON teams.id = actions.team_id
  LEFT JOIN action_types ON actions.type_id = action_types.id
  GROUP BY teams.id, teams.name
  ORDER BY score DESC, teams.id`)
  .then(result => {
    return _.map(result.rows, row => deepChangeKeyCase(row, 'camelCase'));
  });
}

export {
  getTeams
};
<commit_msg>Fixed /teams endpoint<commit_after>const {knex} = require('../util/database').connect();
import _ from 'lodash';
import {deepChangeKeyCase} from '../util';

function getTeams() {
  return knex.raw(`SELECT teams.id, teams.name, SUM(COALESCE(action_types.value, 0)) AS score
  FROM teams
  LEFT JOIN actions ON teams.id = actions.team_id
  LEFT JOIN action_types ON actions.action_type_id = action_types.id
  GROUP BY teams.id, teams.name
  ORDER BY score DESC, teams.id`)
  .then(result => {
    return _.map(result.rows, row => deepChangeKeyCase(row, 'camelCase'));
  });
}

export {
  getTeams
};
<|endoftext|>


<commit_before>/**
 * @module Transform
 * @submodule Transform
 * @for p5
 * @requires core
 * @requires constants
 */

'use strict';

var p5 = require('./core');
var constants = require('./constants');

/**
 * Multiplies the current matrix by the one specified through the parameters.
 * This is very slow because it will try to calculate the inverse of the
 * transform, so avoid it whenever possible.
 *
 * @method applyMatrix
 * @param  {Number} n00 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n01 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n02 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n10 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n11 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n12 numbers which define the 3x2 matrix to be multiplied
 * @return {p5}         the p5 object
 * @example
 *

 *
 * // Example in the works.
 *
 *

 */
p5.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) {
  this._renderer.applyMatrix(n00, n01, n02, n10, n11, n12);
  return this;
};

p5.prototype.popMatrix = function() {
  throw new Error('popMatrix() not used, see pop()');
};

p5.prototype.printMatrix = function() {
  throw new Error('printMatrix() not implemented');
};

p5.prototype.pushMatrix = function() {
  throw new Error('pushMatrix() not used, see push()');
};

/**
 * Replaces the current matrix with the identity matrix.
 *
 * @method resetMatrix
 * @return {p5} the p5 object
 * @example
 *

 *
 * // Example in the works.
 *
 *

 */
p5.prototype.resetMatrix = function() {
  this._renderer.resetMatrix();
  return this;
};

/**
 * Rotates a shape the amount specified by the angle parameter. This
 * function accounts for angleMode, so angles can be entered in either
 * RADIANS or DEGREES.
 *

 * Objects are always rotated around their relative position to the
 * origin and positive numbers rotate objects in a clockwise direction.
 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI).
 * All tranformations are reset when draw() begins again.
 *

 * Technically, rotate() multiplies the current transformation matrix
 * by a rotation matrix. This function can be further controlled by
 * the push() and pop().
 *
 * @method rotate
 * @param  {Number} angle the angle of rotation, specified in radians
 *                        or degrees, depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/2, height/2);
 * rotate(PI/3.0);
 * rect(-26, -26, 52, 52);
 *
 *

 */
/**
 * @method rotate
 * @param  {Number} rad  angle in radians
 * @param  {p5.Vector | Array} axis axis to rotate around
 * @return {p5.RendererGL}      [description]
 */
p5.prototype.rotate = function() {
  var args = new Array(arguments.length);
  var r;
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }
  if (this._angleMode === constants.DEGREES) {
    r = this.radians(args[0]);
  }
  //in webgl mode
  if(args.length > 1){
    this._renderer.rotate(r, args[1]);
  }
  else {
    this._renderer.rotate(r);
  }
  return this;
};

/**
 * Rotates around X axis.
 * @method  rotateX
 * @param  {Number} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateX = function(rad) {
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }
  if (this._renderer.isP3D) {
    this._validateParameters(
      'rotateX',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateX(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Rotates around Y axis.
 * @method rotateY
 * @param  {[type]} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateY = function(rad) {
  if (this._renderer.isP3D) {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
    this._validateParameters(
      'rotateY',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateY(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Rotates around Z axis.  Webgl mode only.
 * @method rotateZ
 * @param  {[type]} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateZ = function(rad) {
  if (this._renderer.isP3D) {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
    this._validateParameters(
      'rotateZ',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateZ(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Increases or decreases the size of a shape by expanding and contracting
 * vertices. Objects always scale from their relative origin to the
 * coordinate system. Scale values are specified as decimal percentages.
 * For example, the function call scale(2.0) increases the dimension of a
 * shape by 200%.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function multiply the effect. For example, calling scale(2.0)
 * and then scale(1.5) is the same as scale(3.0). If scale() is called
 * within draw(), the transformation is reset when the loop begins again.
 *

 * Using this function with the z parameter is only available in WEBGL mode.
 * This function can be further controlled with push() and pop().
 *
 * @method scale
 * @param  {Number | p5.Vector | Array} s
 *                      percent to scale the object, or percentage to
 *                      scale the object in the x-axis if multiple arguments
 *                      are given
 * @param  {Number} [y] percent to scale the object in the y-axis
 * @param  {Number} [z] percent to scale the object in the z-axis (webgl only)
 * @return {p5}         the p5 object
 * @example
 *

 *
 * translate(width/2, height/2);
 * rotate(PI/3.0);
 * rect(-26, -26, 52, 52);
 *
 *

 *
 *

 *
 * rect(30, 20, 50, 50);
 * scale(0.5, 1.3);
 * rect(30, 20, 50, 50);
 *
 *

 */
p5.prototype.scale = function() {
  var x,y,z;
  var args = new Array(arguments.length);
  for(var i = 0; i < args.length; i++) {
    args[i] = arguments[i];
  }
  if(args[0] instanceof p5.Vector){
    x = args[0].x;
    y = args[0].y;
    z = args[0].z;
  }
  else if(args[0] instanceof Array){
    x = args[0][0];
    y = args[0][1];
    z = args[0][2] || 1;
  }
  else {
    if(args.length === 1){
      x = y = z = args[0];
    }
    else {
      x = args[0];
      y = args[1];
      z = args[2] || 1;
    }
  }

  if(this._renderer.isP3D){
    this._renderer.scale.call(this._renderer, x,y,z);
  }
  else {
    this._renderer.scale.call(this._renderer, x,y);
  }
  return this;
};

/**
 * Shears a shape around the x-axis the amount specified by the angle
 * parameter. Angles should be specified in the current angleMode.
 * Objects are always sheared around their relative position to the origin
 * and positive numbers shear objects in a clockwise direction.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI).
 * If shearX() is called within the draw(), the transformation is reset when
 * the loop begins again.
 *

 * Technically, shearX() multiplies the current transformation matrix by a
 * rotation matrix. This function can be further controlled by the
 * push() and pop() functions.
 *
 * @method shearX
 * @param  {Number} angle angle of shear specified in radians or degrees,
 *                        depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/4, height/4);
 * shearX(PI/4.0);
 * rect(0, 0, 30, 30);
 *
 *

 */
p5.prototype.shearX = function(angle) {
  if (this._angleMode === constants.DEGREES) {
    angle = this.radians(angle);
  }
  this._renderer.shearX(angle);
  return this;
};

/**
 * Shears a shape around the y-axis the amount specified by the angle
 * parameter. Angles should be specified in the current angleMode. Objects
 * are always sheared around their relative position to the origin and
 * positive numbers shear objects in a clockwise direction.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If
 * shearY() is called within the draw(), the transformation is reset when
 * the loop begins again.
 *

 * Technically, shearY() multiplies the current transformation matrix by a
 * rotation matrix. This function can be further controlled by the
 * push() and pop() functions.
 *
 * @method shearY
 * @param  {Number} angle angle of shear specified in radians or degrees,
 *                        depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/4, height/4);
 * shearY(PI/4.0);
 * rect(0, 0, 30, 30);
 *
 *

 */
p5.prototype.shearY = function(angle) {
  if (this._angleMode === constants.DEGREES) {
    angle = this.radians(angle);
  }
  this._renderer.shearY(angle);
  return this;
};

/**
 * Specifies an amount to displace objects within the display window.
 * The x parameter specifies left/right translation, the y parameter
 * specifies up/down translation.
 *

 * Transformations are cumulative and apply to everything that happens after
 * and subsequent calls to the function accumulates the effect. For example,
 * calling translate(50, 0) and then translate(20, 0) is the same as
 * translate(70, 0). If translate() is called within draw(), the
 * transformation is reset when the loop begins again. This function can be
 * further controlled by using push() and pop().
 *
 * @method translate
 * @param  {Number} x left/right translation
 * @param  {Number} y up/down translation
 * @return {p5}       the p5 object
 * @example
 *

 *
 * translate(30, 20);
 * rect(0, 0, 55, 55);
 *
 *

 *
 *

 *
 * rect(0, 0, 55, 55);  // Draw rect at original 0,0
 * translate(30, 20);
 * rect(0, 0, 55, 55);  // Draw rect at new 0,0
 * translate(14, 14);
 * rect(0, 0, 55, 55);  // Draw rect at new 0,0
 *
 *

 */
p5.prototype.translate = function(x, y, z) {
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }

  if (this._renderer.isP3D) {
    this._validateParameters(
      'translate',
      args,
      [
        //p3d
        ['Number', 'Number', 'Number']
      ]
    );
    this._renderer.translate(x, y, z);
  } else {
    this._validateParameters(
      'translate',
      args,
      [
        //p2d
        ['Number', 'Number']
      ]
    );
    this._renderer.translate(x, y);
  }
  return this;
};

module.exports = p5;
<commit_msg>tweaks inline docs parameter for rotate functions<commit_after>/**
 * @module Transform
 * @submodule Transform
 * @for p5
 * @requires core
 * @requires constants
 */

'use strict';

var p5 = require('./core');
var constants = require('./constants');

/**
 * Multiplies the current matrix by the one specified through the parameters.
 * This is very slow because it will try to calculate the inverse of the
 * transform, so avoid it whenever possible.
 *
 * @method applyMatrix
 * @param  {Number} n00 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n01 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n02 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n10 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n11 numbers which define the 3x2 matrix to be multiplied
 * @param  {Number} n12 numbers which define the 3x2 matrix to be multiplied
 * @return {p5}         the p5 object
 * @example
 *

 *
 * // Example in the works.
 *
 *

 */
p5.prototype.applyMatrix = function(n00, n01, n02, n10, n11, n12) {
  this._renderer.applyMatrix(n00, n01, n02, n10, n11, n12);
  return this;
};

p5.prototype.popMatrix = function() {
  throw new Error('popMatrix() not used, see pop()');
};

p5.prototype.printMatrix = function() {
  throw new Error('printMatrix() not implemented');
};

p5.prototype.pushMatrix = function() {
  throw new Error('pushMatrix() not used, see push()');
};

/**
 * Replaces the current matrix with the identity matrix.
 *
 * @method resetMatrix
 * @return {p5} the p5 object
 * @example
 *

 *
 * // Example in the works.
 *
 *

 */
p5.prototype.resetMatrix = function() {
  this._renderer.resetMatrix();
  return this;
};

/**
 * Rotates a shape the amount specified by the angle parameter. This
 * function accounts for angleMode, so angles can be entered in either
 * RADIANS or DEGREES.
 *

 * Objects are always rotated around their relative position to the
 * origin and positive numbers rotate objects in a clockwise direction.
 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * rotate(HALF_PI) and then rotate(HALF_PI) is the same as rotate(PI).
 * All tranformations are reset when draw() begins again.
 *

 * Technically, rotate() multiplies the current transformation matrix
 * by a rotation matrix. This function can be further controlled by
 * the push() and pop().
 *
 * @method rotate
 * @param  {Number} angle the angle of rotation, specified in radians
 *                        or degrees, depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/2, height/2);
 * rotate(PI/3.0);
 * rect(-26, -26, 52, 52);
 *
 *

 */
/**
 * @method rotate
 * @param  {Number} rad  angle in radians
 * @param  {p5.Vector | Array} axis axis to rotate around
 * @return {p5.RendererGL}      [description]
 */
p5.prototype.rotate = function() {
  var args = new Array(arguments.length);
  var r;
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }
  if (this._angleMode === constants.DEGREES) {
    r = this.radians(args[0]);
  }
  //in webgl mode
  if(args.length > 1){
    this._renderer.rotate(r, args[1]);
  }
  else {
    this._renderer.rotate(r);
  }
  return this;
};

/**
 * Rotates around X axis.
 * @method  rotateX
 * @param  {Number} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateX = function(rad) {
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }
  if (this._renderer.isP3D) {
    this._validateParameters(
      'rotateX',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateX(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Rotates around Y axis.
 * @method rotateY
 * @param  {Number} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateY = function(rad) {
  if (this._renderer.isP3D) {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
    this._validateParameters(
      'rotateY',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateY(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Rotates around Z axis.  Webgl mode only.
 * @method rotateZ
 * @param  {Number} rad angles in radians
 * @return {[type]}     [description]
 */
p5.prototype.rotateZ = function(rad) {
  if (this._renderer.isP3D) {
    var args = new Array(arguments.length);
    for (var i = 0; i < args.length; ++i) {
      args[i] = arguments[i];
    }
    this._validateParameters(
      'rotateZ',
      args,
      [
        ['Number']
      ]
    );
    this._renderer.rotateZ(rad);
  } else {
    throw 'not supported in p2d. Please use webgl mode';
  }
  return this;
};

/**
 * Increases or decreases the size of a shape by expanding and contracting
 * vertices. Objects always scale from their relative origin to the
 * coordinate system. Scale values are specified as decimal percentages.
 * For example, the function call scale(2.0) increases the dimension of a
 * shape by 200%.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function multiply the effect. For example, calling scale(2.0)
 * and then scale(1.5) is the same as scale(3.0). If scale() is called
 * within draw(), the transformation is reset when the loop begins again.
 *

 * Using this function with the z parameter is only available in WEBGL mode.
 * This function can be further controlled with push() and pop().
 *
 * @method scale
 * @param  {Number | p5.Vector | Array} s
 *                      percent to scale the object, or percentage to
 *                      scale the object in the x-axis if multiple arguments
 *                      are given
 * @param  {Number} [y] percent to scale the object in the y-axis
 * @param  {Number} [z] percent to scale the object in the z-axis (webgl only)
 * @return {p5}         the p5 object
 * @example
 *

 *
 * translate(width/2, height/2);
 * rotate(PI/3.0);
 * rect(-26, -26, 52, 52);
 *
 *

 *
 *

 *
 * rect(30, 20, 50, 50);
 * scale(0.5, 1.3);
 * rect(30, 20, 50, 50);
 *
 *

 */
p5.prototype.scale = function() {
  var x,y,z;
  var args = new Array(arguments.length);
  for(var i = 0; i < args.length; i++) {
    args[i] = arguments[i];
  }
  if(args[0] instanceof p5.Vector){
    x = args[0].x;
    y = args[0].y;
    z = args[0].z;
  }
  else if(args[0] instanceof Array){
    x = args[0][0];
    y = args[0][1];
    z = args[0][2] || 1;
  }
  else {
    if(args.length === 1){
      x = y = z = args[0];
    }
    else {
      x = args[0];
      y = args[1];
      z = args[2] || 1;
    }
  }

  if(this._renderer.isP3D){
    this._renderer.scale.call(this._renderer, x,y,z);
  }
  else {
    this._renderer.scale.call(this._renderer, x,y);
  }
  return this;
};

/**
 * Shears a shape around the x-axis the amount specified by the angle
 * parameter. Angles should be specified in the current angleMode.
 * Objects are always sheared around their relative position to the origin
 * and positive numbers shear objects in a clockwise direction.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * shearX(PI/2) and then shearX(PI/2) is the same as shearX(PI).
 * If shearX() is called within the draw(), the transformation is reset when
 * the loop begins again.
 *

 * Technically, shearX() multiplies the current transformation matrix by a
 * rotation matrix. This function can be further controlled by the
 * push() and pop() functions.
 *
 * @method shearX
 * @param  {Number} angle angle of shear specified in radians or degrees,
 *                        depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/4, height/4);
 * shearX(PI/4.0);
 * rect(0, 0, 30, 30);
 *
 *

 */
p5.prototype.shearX = function(angle) {
  if (this._angleMode === constants.DEGREES) {
    angle = this.radians(angle);
  }
  this._renderer.shearX(angle);
  return this;
};

/**
 * Shears a shape around the y-axis the amount specified by the angle
 * parameter. Angles should be specified in the current angleMode. Objects
 * are always sheared around their relative position to the origin and
 * positive numbers shear objects in a clockwise direction.
 *

 * Transformations apply to everything that happens after and subsequent
 * calls to the function accumulates the effect. For example, calling
 * shearY(PI/2) and then shearY(PI/2) is the same as shearY(PI). If
 * shearY() is called within the draw(), the transformation is reset when
 * the loop begins again.
 *

 * Technically, shearY() multiplies the current transformation matrix by a
 * rotation matrix. This function can be further controlled by the
 * push() and pop() functions.
 *
 * @method shearY
 * @param  {Number} angle angle of shear specified in radians or degrees,
 *                        depending on current angleMode
 * @return {p5}           the p5 object
 * @example
 *

 *
 * translate(width/4, height/4);
 * shearY(PI/4.0);
 * rect(0, 0, 30, 30);
 *
 *

 */
p5.prototype.shearY = function(angle) {
  if (this._angleMode === constants.DEGREES) {
    angle = this.radians(angle);
  }
  this._renderer.shearY(angle);
  return this;
};

/**
 * Specifies an amount to displace objects within the display window.
 * The x parameter specifies left/right translation, the y parameter
 * specifies up/down translation.
 *

 * Transformations are cumulative and apply to everything that happens after
 * and subsequent calls to the function accumulates the effect. For example,
 * calling translate(50, 0) and then translate(20, 0) is the same as
 * translate(70, 0). If translate() is called within draw(), the
 * transformation is reset when the loop begins again. This function can be
 * further controlled by using push() and pop().
 *
 * @method translate
 * @param  {Number} x left/right translation
 * @param  {Number} y up/down translation
 * @return {p5}       the p5 object
 * @example
 *

 *
 * translate(30, 20);
 * rect(0, 0, 55, 55);
 *
 *

 *
 *

 *
 * rect(0, 0, 55, 55);  // Draw rect at original 0,0
 * translate(30, 20);
 * rect(0, 0, 55, 55);  // Draw rect at new 0,0
 * translate(14, 14);
 * rect(0, 0, 55, 55);  // Draw rect at new 0,0
 *
 *

 */
p5.prototype.translate = function(x, y, z) {
  var args = new Array(arguments.length);
  for (var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
  }

  if (this._renderer.isP3D) {
    this._validateParameters(
      'translate',
      args,
      [
        //p3d
        ['Number', 'Number', 'Number']
      ]
    );
    this._renderer.translate(x, y, z);
  } else {
    this._validateParameters(
      'translate',
      args,
      [
        //p2d
        ['Number', 'Number']
      ]
    );
    this._renderer.translate(x, y);
  }
  return this;
};

module.exports = p5;
<|endoftext|>


<commit_before>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Calendar");

(function() {
    Mobile.SalesLogix.Calendar.UserActivityList = Ext.extend(Sage.Platform.Mobile.List, {
        currentDate: (new Date()),

        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Activity.Timeless) { %}',
            'All-Day',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Activity.Description %}',
            '
',
            '
{%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.Activity.ContactName) { %}',
            '{%: $.Activity.ContactName %} / {%: $.Activity.AccountName %}',
            '{% } else if ($.Activity.AccountName) { %}',
            '{%: $.Activity.AccountName %}',
            '{% } else { %}',
            '{%: $.Activity.LeadName %}',
            '{% } %}'
        ]),
        buttonNavBarTemplate: new Simplate([
            '
',
            '<button data-tool="today" data-action="getTodayActivities" class="button headerButton active">Today</button>',
            '<button data-tool="day" data-action="getDayActivities" class="button">Day</button>',
            '<button data-tool="month" data-action="navigateToMonthView" class="button">Month</button>',
            '
',
            '
',
            '

',
            '<button data-tool="next" data-action="getNextActivities" class="button button-next lightGreenButton"></button>',
            '<button data-tool="prev" data-action="getPrevActivities" class="button button-prev lightGreenButton"></button>',
            '
',
        ]),

        //Localization
        titleText: 'Calendar',

        //View Properties
        hideSearch: true,
        id: 'useractivity_list',
        icon: 'content/images/icons/Calendar_24x24.png',
        detailView: 'activity_detail',
        insertView: 'activity_types_list',
        queryOrderBy: 'Activity.Timeless desc, Activity.StartDate',
        querySelect: [
            'Activity/Description',
            'Activity/StartDate',
            'Activity/Type',
            'Activity/AccountName',
            'Activity/ContactName',
            'Activity/LeadId',
            'Activity/LeadName',
            'Activity/UserId',
            'Activity/Timeless'
        ],
        resourceKind: 'useractivities',

        render: function() {
            var attachmentPoints = {
                dateTextEl: '.date-text',
                splitButton: '.split-buttons',
                todayButton: '.button[data-tool="today"]',
                dayButton: '.button[data-tool="day"]',
                monthButton: '.button[data-tool="month"]'
            };

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.render.apply(this, arguments);

            Ext.DomHelper.insertBefore(
                this.contentEl,
                this.buttonNavBarTemplate.apply(this),
                true
            );

            for (var n in attachmentPoints)
                if (attachmentPoints.hasOwnProperty(n))
                    this[n] = this.el.child(attachmentPoints[n]);
        },
        initEvents: function() {
            Mobile.SalesLogix.Calendar.UserActivityList.superclass.initEvents.apply(this, arguments);

            App.on('refresh', this.refreshOnActivityInsert, this);
        },
        refreshOnActivityInsert: function(o) {
            if (o.resourceKind === 'activities')
            {
                this.refreshRequired = true;
            }
        },
        show: function(options) {
            if (!options) options = {};
            options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.show.call(this, options);
        },
        getNextActivities: function() {
            if (this.el.hasClass('list-loading')) return;

            this.currentDate.add({day: 1});
            this.getActivities();
        },
        getTodayActivities: function() {
            if (this.el.hasClass('list-loading')) return;
            if (this.currentDate.equals(Date.today())) return;

            this.currentDate = Date.today();
            this.getActivities();
        },
        getPrevActivities: function() {
            if (this.el.hasClass('list-loading')) return;

            this.currentDate.add({day: -1});
            this.getActivities();
        },
        getActivities: function(date) {
            this.clear();
            this.setOptions();
            this.setSplitButtonStatus();
            this.requestData();
        },
        setNavBarTitle: function() {
            this.dateTextEl.update(this.currentDate.toString('dddd, MM/dd/yyyy'));
        },
        getUTCDateString: function(date) {
            var pad = function(n) { return n < 10 ? '0' + n : n };

            return String.format('{0}-{1}-{2}T{3}:{4}:{5}',
                date.getUTCFullYear(),
                pad(date.getUTCMonth() + 1 ),
                pad(date.getUTCDate()),
                pad(date.getUTCHours()),
                pad(date.getUTCMinutes()),
                pad(date.getUTCSeconds())
            );
        },
        formatQueryForActivities: function() {
            var qry = 'UserId eq "{0}" and (Activity.StartDate between @{1}@ and @{2}@) '
                      + 'or (Activity.Timeless eq true and Activity.StartDate between @{3}@ and @{4}@)';

            return String.format(
                qry,
                App.context.user.$key,
                this.getUTCDateString(this.currentDate),
                this.getUTCDateString(this.currentDate.clone().add({day: 1, second: -1})),
                this.currentDate.toString('yyyy-MM-ddT00:00:00'),
                this.currentDate.toString('yyyy-MM-ddT23:59:59')
            );
        },
        setOptions: function() {
            if (!this.options) this.options = {};
            this.options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();
        },
        setSplitButtonStatus: function() {
            [this.todayButton, this.dayButton, this.monthButton].forEach(function(el){
                el.addClass(['headerButton']);
            });

            if (this.currentDate.equals(Date.today()))
            {
                this.dayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
            else
            {
                this.todayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToMonthView: function() {
            var view = App.getView('slx_calendar');

            if (view)
                view.show();
        }
    });
})();
<commit_msg>fixed an issue with the recent merge.<commit_after>/// <reference path="../../../../../argos-sdk/libraries/ext/ext-core-debug.js"/>
/// <reference path="../../../../../argos-sdk/libraries/sdata/sdata-client-debug"/>
/// <reference path="../../../../../argos-sdk/libraries/Simplate.js"/>
/// <reference path="../../../../../argos-sdk/src/View.js"/>
/// <reference path="../../../../../argos-sdk/src/List.js"/>

Ext.namespace("Mobile.SalesLogix.Calendar");

(function() {
    Mobile.SalesLogix.Calendar.UserActivityList = Ext.extend(Sage.Platform.Mobile.List, {
        currentDate: (new Date()),

        //Templates
        itemTemplate: new Simplate([
            '
',
            '

',
            '{%! $$.contentTemplate %}',
            '
'
        ]),
        activityTimeTemplate: new Simplate([
            '{% if ($.Activity.Timeless) { %}',
            'All-Day',
            '{% } else { %}',
            '{%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "h:mm") %}',
            ' {%: Mobile.SalesLogix.Format.date($.Activity.StartDate, "tt") %},',
            '{% } %}'
        ]),
        contentTemplate: new Simplate([
            '
',
            '{%= $$.activityTimeTemplate.apply($) %}',
            ' {%: $.Activity.Description %}',
            '
',
            '
{%= $$.nameTemplate.apply($) %}
'
        ]),
        nameTemplate: new Simplate([
            '{% if ($.Activity.ContactName) { %}',
            '{%: $.Activity.ContactName %} / {%: $.Activity.AccountName %}',
            '{% } else if ($.Activity.AccountName) { %}',
            '{%: $.Activity.AccountName %}',
            '{% } else { %}',
            '{%: $.Activity.LeadName %}',
            '{% } %}'
        ]),
        buttonNavBarTemplate: new Simplate([
            '
',
            '<button data-tool="today" data-action="getTodayActivities" class="button headerButton active">Today</button>',
            '<button data-tool="day" data-action="getDayActivities" class="button">Day</button>',
            '<button data-tool="month" data-action="navigateToMonthView" class="button">Month</button>',
            '
',
            '
',
            '

',
            '<button data-tool="next" data-action="getNextActivities" class="button button-next lightGreenButton"></button>',
            '<button data-tool="prev" data-action="getPrevActivities" class="button button-prev lightGreenButton"></button>',
            '
',
        ]),

        //Localization
        titleText: 'Calendar',

        //View Properties
        hideSearch: true,
        id: 'useractivity_list',
        icon: 'content/images/icons/Calendar_24x24.png',
        detailView: 'activity_detail',
        insertView: 'activity_types_list',
        queryOrderBy: 'Activity.Timeless desc, Activity.StartDate',
        querySelect: [
            'Activity/Description',
            'Activity/StartDate',
            'Activity/Type',
            'Activity/AccountName',
            'Activity/ContactName',
            'Activity/LeadId',
            'Activity/LeadName',
            'Activity/UserId',
            'Activity/Timeless'
        ],
        resourceKind: 'useractivities',

        render: function() {
            var attachmentPoints = {
                dateTextEl: '.date-text',
                splitButton: '.split-buttons',
                todayButton: '.button[data-tool="today"]',
                dayButton: '.button[data-tool="day"]',
                monthButton: '.button[data-tool="month"]'
            };

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.render.apply(this, arguments);

            Ext.DomHelper.insertBefore(
                this.contentEl,
                this.buttonNavBarTemplate.apply(this),
                true
            );

            for (var n in attachmentPoints)
                if (attachmentPoints.hasOwnProperty(n))
                    this[n] = this.el.child(attachmentPoints[n]);
        },
        initEvents: function() {
            Mobile.SalesLogix.Calendar.UserActivityList.superclass.initEvents.apply(this, arguments);

            App.on('refresh', this.refreshOnActivityInsert, this);
        },
        refreshOnActivityInsert: function(o) {
            if (o.resourceKind === 'activities')
            {
                this.refreshRequired = true;
            }
        },
        show: function(options) {
            if (!options) options = {};
            options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();

            Mobile.SalesLogix.Calendar.UserActivityList.superclass.show.call(this, options);
        },
        getNextActivities: function() {
            if (this.el.hasClass('list-loading')) return;

            this.currentDate.add({day: 1});
            this.getActivities();
        },
        getTodayActivities: function() {
            if (this.el.hasClass('list-loading')) return;
            if (this.currentDate.equals(Date.today())) return;

            this.currentDate = Date.today();
            this.getActivities();
        },
        getPrevActivities: function() {
            if (this.el.hasClass('list-loading')) return;

            this.currentDate.add({day: -1});
            this.getActivities();
        },
        getActivities: function(date) {
            this.clear();
            this.setOptions();
            this.setSplitButtonStatus();
            this.requestData();
        },
        setNavBarTitle: function() {
            this.dateTextEl.update(this.currentDate.toString('dddd, MM/dd/yyyy'));
        },
        getUTCDateString: function(date) {
            var pad = function(n) { return n < 10 ? '0' + n : n };

            return String.format('{0}-{1}-{2}T{3}:{4}:{5}',
                date.getUTCFullYear(),
                pad(date.getUTCMonth() + 1 ),
                pad(date.getUTCDate()),
                pad(date.getUTCHours()),
                pad(date.getUTCMinutes()),
                pad(date.getUTCSeconds())
            );
        },
        formatQueryForActivities: function() {
            var qry = 'UserId eq "{0}" and (Activity.StartDate between @{1}@ and @{2}@) '
                      + 'or (Activity.Timeless eq true and Activity.StartDate between @{3}@ and @{4}@)';

            return String.format(
                qry,
                App.context.user.$key,
                this.getUTCDateString(this.currentDate),
                this.getUTCDateString(this.currentDate.clone().add({day: 1, second: -1})),
                this.currentDate.toString('yyyy-MM-ddT00:00:00'),
                this.currentDate.toString('yyyy-MM-ddT23:59:59')
            );
        },
        setOptions: function() {
            if (!this.options) this.options = {};
            this.options['where'] = this.formatQueryForActivities();
            this.setNavBarTitle();
        },
        setSplitButtonStatus: function() {
            [this.todayButton, this.dayButton, this.monthButton].forEach(function(el){
                el.addClass(['headerButton']);
            });

            if (this.currentDate.equals(Date.today()))
            {
                this.dayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
            else
            {
                this.todayButton.removeClass(['headerButton']);
                this.monthButton.removeClass(['headerButton']);
            }
        },
        isActivityForLead: function(entry) {
            return entry && /^[\w]{12}$/.test(entry['LeadId']);
        },
        navigateToMonthView: function() {
            var view = App.getView('slx_calendar');

            if (view)
                view.show();
        },
        navigateToDetailView: function(key, descriptor) {
            var entry = this.entries[key],
                activity = entry.Activity;

            if (this.isActivityForLead(activity))
            {
                var view = App.getView(this.detailViewForLead);
                if (view)
                    view.show({
                        descriptor: activity.Description,
                        key: activity.$key
                    });
            }
            else
            {
                Mobile.SalesLogix.Activity.List.superclass.navigateToDetailView.apply(this, [activity.$key, activity.Description]);
            }
        }
    });
})();
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
// import { renderRoutes } from 'react-router-config';
import Switch from 'react-router/Switch';
import Route from 'react-router/Route';
import { connect } from 'react-redux';
import ErrorBoundary from 'react-error-boundary';
import TransitionGroup from 'react-transition-group/TransitionGroup';
import CSSTransition from 'react-transition-group/CSSTransition';

import Header from './../../components/header/header';
import Config from './../../components/config/config';
import log from '../../../services/logger_service';

const renderRoutes = (routes, location) =>
  routes ? (
    <Switch key={location.key} location={location}>
      {routes.map(route => (
        <Route
          key={location.key}
          location={location}
          path={route.path}
          exact={route.exact}
          strict={route.strict}
          component={route.component}
        />
      ))}
    </Switch>
  ) : null;

class Layout extends Component {
  livereload() {
    if (this.props.env === 'development') {
      return ;
      return [
        ;
      return [


<commit_before>/* UMD.define */ (function (root, factory) {
    if (typeof define === 'function' && define.amd){ define([], factory); }else if(typeof exports === 'object'){ module.exports = factory(); }else{ root.returnExports = factory(); window.on = factory(); }
}(this, function () {
	// `on` is a simple library for attaching events to nodes. Its primary feature
    // is it returns a handle, from which you can pause, resume and remove the
    // event. Handles are much easier to manipulate than using removeEventListener
    // and recreating (sometimes complex or recursive) function signatures.
    //
    // `on` is touch-friendly and will normalize touch events.
    //
    // `on` also supports a custom `clickoff` event, to detect if you've clicked
    // anywhere in the document other than the passed node
    //
    // USAGE
    //      var handle = on(node, 'clickoff', callback);
    //      //  callback fires if something other than node is clicked
    //
    // USAGE
    //      var handle = on(node, 'mousedown', onStart);
    //      handle.pause();
    //      handle.resume();
    //      handle.remove();
    //
    //  `on` also supports multiple event types at once. The following example is
    //  useful for handling both desktop mouseovers and tablet clicks:
    //
    // USAGE
    //      var handle = on(node, 'mouseover,click', onStart);
    //
    //
    // `on` has an optional context parameter. The fourth argument can be 'this'
    // (or some other object) to conveniently avoid the use of var `self = this;`
    //
    //  USAGE
    //      var handle = on(this.node, 'mousedown', 'onStart', this);
    //
    // `on.multi` allows for connecting multiple events to a node at the same
    // time. Note this requires a context (I think), so it is not applicable for
    // anonymous functions.
    //
    //  USAGE
    //      handle = on.multi(document, {
    //          "touchend":"onEnd",
    //          "touchcancel":"onEnd",
    //          "touchmove":this.method
    //      }, this);
    //
    // `on.bind` is a convenience method for binding context to a method.
    //
    // USAGE
    //      callback = on.bind(this, 'myCallback');
    //
    // `on` supports an optional ID that can be used to track connections to be
    // disposed later.
    //
    // USAGE
    //      on(node, 'click', callback, 'uid-a');
    //      on(node, 'mouseover', callback, 'uid-a');
    //      on(otherNode, 'click', callback, 'uid-a');
    //      on(document, 'load', callback, 'uid-a');
    //      on.remove('uid-a');
    //
    // `on` supports selectors, seperated from the event by a space:
    //
    // USAGE
    //      on(node, 'click div.tab span', callback);
    //

	function hasWheel(){
		var
			isIE = navigator.userAgent.indexOf('Trident') > -1,
			div = document.createElement('div');
		return  "onwheel" in div || "wheel" in div ||
			(isIE && document.implementation.hasFeature("Events.wheel", "3.0")); // IE feature detection
	}

	function has(what){
		switch(what){
			case 'wheel': return hasWheel();
		}
		return false;
	}

    var
		isWin = navigator.userAgent.indexOf('Windows')>-1,
        FACTOR = isWin ? 10 : 0.1,
        XLR8 = 0,
        mouseWheelHandle,
        //numCalls = 0,
        keyCodes = (function(){
            // 48-57 0-9
            // 65 - 90 a-z
            var keys = new Array(46);
            keys = keys.concat([0,1,2,3,4,5,6,7,8,9]);
            keys = keys.concat([0,0,0,0,0,0,0,0,0]);
            keys = keys.concat('a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'.split(','));
            return keys;
        }()),
        registry = {};

	function normalizeKeyEvent (callback){
		// Add alphanumeric property (the letter typed) to the KeyEvent
		//
		return function(e){
			// 48-57 0-9
			// 65 - 90 a-z
			if(keyCodes[e.keyCode]){
				e.alphanumeric = keyCodes[e.keyCode];
			}
			callback(e);
		};
	}

	function register(id, handle){
		if(!registry[id]){
			registry[id] = [];
		}
		registry[id].push(handle);
	}

	function makeMultiHandle (handles){
		return {
			remove: function(){
				handles.forEach(function(h){
					// allow for a simple function in the list
					if(h.remove) {
						h.remove();
					}else if(typeof h === 'function'){
						h();
					}
				});
				handles = [];
				this.remove = this.pause = this.resume = function(){};
			},
			pause: function(){
				handles.forEach(function(h){ if(h.pause){ h.pause(); }});
			},
			resume: function(){
				handles.forEach(function(h){ if(h.resume){ h.resume(); }});
			}
		};
	}

	function onClickoff (node, callback){
		var
			isOver = false,
			mHandle,
			handle,
			lHandle = on(node, 'mouseleave', function(){
				isOver = false;
			}),
			eHandle = on(node, 'mouseenter', function(){
				isOver = true;
			}),
			bHandle = on(document.body, 'click', function(event){
				if(!isOver){
					callback(event);
				}
			});

		mHandle = makeMultiHandle([lHandle, eHandle, bHandle]);

		handle = {
			resume: function () {
				setTimeout(function () {
					mHandle.resume();
				}, 100);
			},
			pause: function () {
				isOver = false;
				mHandle.pause();
			},
			remove: function () {
				isOver = false;
				mHandle.remove();
			}
		};

		handle.pause();

		return handle;
	}

	function getNode(str){
        if(typeof str !== 'string'){
            return str;
        }
		var node;
		if(/\#|\.|\s/.test(str)){
			node = document.body.querySelector(str);
		}else{
			node = document.getElementById(str);
		}
		if(!node){
			console.error('localLib/on Could not find:', str);
		}
		return node;
	}

	function normalizeWheelEvent (callback){
		// normalizes all browsers' events to a standard:
		// delta, wheelY, wheelX
		// also adds acceleration and deceleration to make
		// Mac and Windows behave similarly
		return function(e){
			XLR8 += FACTOR;
			var
				deltaY = Math.max(-1, Math.min(1, (e.wheelDeltaY || e.deltaY))),
				deltaX = Math.max(-10, Math.min(10, (e.wheelDeltaX || e.deltaX)));

			deltaY = deltaY <= 0 ? deltaY - XLR8 : deltaY + XLR8;

			e.delta = deltaY;
			e.wheelY = deltaY;
			e.wheelX = deltaX;

			clearTimeout(mouseWheelHandle);
			mouseWheelHandle = setTimeout(function(){
				XLR8 = 0;
			}, 300);
			callback(e);
		};
	}

	function on (node, eventType, callback, optionalContext, id){
		//  USAGE
		//      var handle = on(this.node, 'mousedown', this, 'onStart');
		//      handle.pause();
		//      handle.resume();
		//      handle.remove();
		//
		var
			handles,
			handle,
			targetCallback,
			childTarget = false;

		if(/,/.test(eventType)){
			// handle multiple event types, like:
			// on(node, 'mouseup, mousedown', callback);
			//
			handles = [];
			eventType.split(',').forEach(function(eStr){
				handles.push(on(node, eStr.trim(), callback, optionalContext, id));
			});
			return makeMultiHandle(handles);
		}

		if(typeof optionalContext === 'string'){
			// no context. Last argument is handle id
			id = optionalContext;
			optionalContext = null;
		}

		node = getNode(node);
		callback = !!optionalContext ? bind(optionalContext, callback) : callback;

		if(/\s/.test(eventType)){
			// handle child selectors, like:
			// on(node, 'click .tab span', callback);
			//
			childTarget = eventType.substring(eventType.indexOf(' ') + 1, eventType.length);
			eventType = eventType.substring(0, eventType.indexOf(' '));
			targetCallback = callback;
			callback = function(e){
				var i, nodes, parent = on.ancestor(e.target, childTarget);
				if(parent){
					e.selectorTarget = parent;
					targetCallback(e);
				}else{
					nodes = node.querySelectorAll(childTarget);
					for(i = 0; i < nodes.length; i ++){
						if(nodes[i] === e.target || on.isAncestor(nodes[i], e.target)){
							e.selectorTarget = nodes[i];
							targetCallback(e);
							break;
						}
					}
				}
			};

		}

		if(eventType === 'clickoff'){
			// custom - used for popups 'n stuff
			return onClickoff(node, callback);
		}

		if(eventType === 'wheel'){
			// mousewheel events, natch
			if(has('wheel')){
				// pass through, but first curry callback to wheel events
				callback = normalizeWheelEvent(callback);
			}else{
				// old Firefox, old IE, Chrome
				return on.multi(node, {
					DOMMouseScroll:normalizeWheelEvent(callback),
					mousewheel:normalizeWheelEvent(callback)
				}, optionalContext);
			}
		}

		if(eventType.indexOf('key') > -1){
			callback = normalizeKeyEvent(callback);
		}

		node.addEventListener(eventType, callback, false);

		handle = {
			remove: function() {
				node.removeEventListener(eventType, callback, false);
				node = callback = null;
				this.remove = this.pause = this.resume = function(){};
			},
			pause: function(){
				node.removeEventListener(eventType, callback, false);
			},
			resume: function(){
				node.addEventListener(eventType, callback, false);
			}
		};

		if(id){
			// If an ID has been passed, register it so it can be used to
			// remove multiple events by id
			register(id, handle);
		}

		return handle;
	}

    on.multi = function(node, map, context, id){
        //  USAGE
        //      handle = on.multi(document, {
        //          "touchend":"onEnd",
        //          "touchcancel":"onEnd",
        //          "touchmove":this.method
        //      }, this);
        //
        var eventType,
            handles = [];

        for( eventType in map ){
            if(map.hasOwnProperty(eventType)){
                handles.push(on(node, eventType, map[eventType], context, id));
            }
        }

        return makeMultiHandle(handles);
    };

    on.remove = function(handles){
        // convenience function;
        // removes one or more handles;
        // accepts one handle or an array of handles;
        // accepts different types of handles (dispose/remove/topic token)
        //
        var i, h, idHandles;
        if(typeof handles === 'string'){
            idHandles = registry[handles];
            if(idHandles){
                idHandles.forEach(function(h){
                    h.remove();
                });
                idHandles = registry[handles] = null;
                delete registry[handles];
            }

            return [];
        }
        handles = Array.isArray(handles) ? handles : [handles];

        for( i = 0; i < handles.length; i++ ){
            h = handles[i];

            if(h){ // check for nulls / already removed handles
                if(h.remove){
                    // on handle, or AOP
                    h.remove();
                }
                else if(h.dispose){
                    // knockout
                    h.dispose();
                }
                else if(typeof h === 'function'){
                    // custom clean up
                    h();
                }
            }
        }
        return [];
    };

    on.ancestor = function(node, selector){
        // gets the ancestor of node based on selector criteria
        // useful for getting the target node when a child node is clicked upon
        //
        // USAGE
        //      on.selector(childNode, '.app.active');
        //      on.selector(childNode, '#thinger');
        //      on.selector(childNode, 'div');
        //	DOES NOT SUPPORT:
		//		combinations of above
        var
            test,
            parent = node;

        if(selector.indexOf('.') === 0){
            // className
            selector = selector.replace('.', ' ').trim();
            test = function(n){
                return n.classList.contains(selector);
            };
        }
        else if(selector.indexOf('#') === 0){
            // node id
            selector = selector.replace('#', '').trim();
            test = function(n){
                return n.id === selector;
            };
        }
        else if(selector.indexOf('[') > -1){
            // attribute
            console.error('attribute selectors are not yet supported');
        }
        else{
            // assuming node name
            selector = selector.toUpperCase();
            test = function(n){
				return n.nodeName === selector;
            };
        }

        while(parent){
            if(parent === document.body || parent === document){ return false; }
            if(test(parent)){ break; }
            parent = parent.parentNode;
        }

        return parent;
    };

    on.isAncestor = function(parent, child){
        // determines if parent is an ancestor of child
        // returns boolean
        //
        if(parent === child){ return false; } // do we always want the same node to be false?
        while(child){
            if(child === parent){
                return true;
            }
            child = child.parentNode;
        }
        return false;
    };

    on.makeMultiHandle = makeMultiHandle;

    return on;

}));
<commit_msg>Add customLoader option to UMD<commit_after>/* UMD.define */ (function (root, factory) {
    if (typeof customLoader === 'function'){ customLoader(factory); }else if (typeof define === 'function' && define.amd){ define([], factory); }else if(typeof exports === 'object'){ module.exports = factory(); }else{ root.returnExports = factory(); window.on = factory(); }
}(this, function () {
	// `on` is a simple library for attaching events to nodes. Its primary feature
    // is it returns a handle, from which you can pause, resume and remove the
    // event. Handles are much easier to manipulate than using removeEventListener
    // and recreating (sometimes complex or recursive) function signatures.
    //
    // `on` is touch-friendly and will normalize touch events.
    //
    // `on` also supports a custom `clickoff` event, to detect if you've clicked
    // anywhere in the document other than the passed node
    //
    // USAGE
    //      var handle = on(node, 'clickoff', callback);
    //      //  callback fires if something other than node is clicked
    //
    // USAGE
    //      var handle = on(node, 'mousedown', onStart);
    //      handle.pause();
    //      handle.resume();
    //      handle.remove();
    //
    //  `on` also supports multiple event types at once. The following example is
    //  useful for handling both desktop mouseovers and tablet clicks:
    //
    // USAGE
    //      var handle = on(node, 'mouseover,click', onStart);
    //
    //
    // `on` has an optional context parameter. The fourth argument can be 'this'
    // (or some other object) to conveniently avoid the use of var `self = this;`
    //
    //  USAGE
    //      var handle = on(this.node, 'mousedown', 'onStart', this);
    //
    // `on.multi` allows for connecting multiple events to a node at the same
    // time. Note this requires a context (I think), so it is not applicable for
    // anonymous functions.
    //
    //  USAGE
    //      handle = on.multi(document, {
    //          "touchend":"onEnd",
    //          "touchcancel":"onEnd",
    //          "touchmove":this.method
    //      }, this);
    //
    // `on.bind` is a convenience method for binding context to a method.
    //
    // USAGE
    //      callback = on.bind(this, 'myCallback');
    //
    // `on` supports an optional ID that can be used to track connections to be
    // disposed later.
    //
    // USAGE
    //      on(node, 'click', callback, 'uid-a');
    //      on(node, 'mouseover', callback, 'uid-a');
    //      on(otherNode, 'click', callback, 'uid-a');
    //      on(document, 'load', callback, 'uid-a');
    //      on.remove('uid-a');
    //
    // `on` supports selectors, seperated from the event by a space:
    //
    // USAGE
    //      on(node, 'click div.tab span', callback);
    //

	function hasWheel(){
		var
			isIE = navigator.userAgent.indexOf('Trident') > -1,
			div = document.createElement('div');
		return  "onwheel" in div || "wheel" in div ||
			(isIE && document.implementation.hasFeature("Events.wheel", "3.0")); // IE feature detection
	}

	function has(what){
		switch(what){
			case 'wheel': return hasWheel();
		}
		return false;
	}

    var
		isWin = navigator.userAgent.indexOf('Windows')>-1,
        FACTOR = isWin ? 10 : 0.1,
        XLR8 = 0,
        mouseWheelHandle,
        //numCalls = 0,
        keyCodes = (function(){
            // 48-57 0-9
            // 65 - 90 a-z
            var keys = new Array(46);
            keys = keys.concat([0,1,2,3,4,5,6,7,8,9]);
            keys = keys.concat([0,0,0,0,0,0,0,0,0]);
            keys = keys.concat('a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'.split(','));
            return keys;
        }()),
        registry = {};

	function normalizeKeyEvent (callback){
		// Add alphanumeric property (the letter typed) to the KeyEvent
		//
		return function(e){
			// 48-57 0-9
			// 65 - 90 a-z
			if(keyCodes[e.keyCode]){
				e.alphanumeric = keyCodes[e.keyCode];
			}
			callback(e);
		};
	}

	function register(id, handle){
		if(!registry[id]){
			registry[id] = [];
		}
		registry[id].push(handle);
	}

	function makeMultiHandle (handles){
		return {
			remove: function(){
				handles.forEach(function(h){
					// allow for a simple function in the list
					if(h.remove) {
						h.remove();
					}else if(typeof h === 'function'){
						h();
					}
				});
				handles = [];
				this.remove = this.pause = this.resume = function(){};
			},
			pause: function(){
				handles.forEach(function(h){ if(h.pause){ h.pause(); }});
			},
			resume: function(){
				handles.forEach(function(h){ if(h.resume){ h.resume(); }});
			}
		};
	}

	function onClickoff (node, callback){
		var
			isOver = false,
			mHandle,
			handle,
			lHandle = on(node, 'mouseleave', function(){
				isOver = false;
			}),
			eHandle = on(node, 'mouseenter', function(){
				isOver = true;
			}),
			bHandle = on(document.body, 'click', function(event){
				if(!isOver){
					callback(event);
				}
			});

		mHandle = makeMultiHandle([lHandle, eHandle, bHandle]);

		handle = {
			resume: function () {
				setTimeout(function () {
					mHandle.resume();
				}, 100);
			},
			pause: function () {
				isOver = false;
				mHandle.pause();
			},
			remove: function () {
				isOver = false;
				mHandle.remove();
			}
		};

		handle.pause();

		return handle;
	}

	function getNode(str){
        if(typeof str !== 'string'){
            return str;
        }
		var node;
		if(/\#|\.|\s/.test(str)){
			node = document.body.querySelector(str);
		}else{
			node = document.getElementById(str);
		}
		if(!node){
			console.error('localLib/on Could not find:', str);
		}
		return node;
	}

	function normalizeWheelEvent (callback){
		// normalizes all browsers' events to a standard:
		// delta, wheelY, wheelX
		// also adds acceleration and deceleration to make
		// Mac and Windows behave similarly
		return function(e){
			XLR8 += FACTOR;
			var
				deltaY = Math.max(-1, Math.min(1, (e.wheelDeltaY || e.deltaY))),
				deltaX = Math.max(-10, Math.min(10, (e.wheelDeltaX || e.deltaX)));

			deltaY = deltaY <= 0 ? deltaY - XLR8 : deltaY + XLR8;

			e.delta = deltaY;
			e.wheelY = deltaY;
			e.wheelX = deltaX;

			clearTimeout(mouseWheelHandle);
			mouseWheelHandle = setTimeout(function(){
				XLR8 = 0;
			}, 300);
			callback(e);
		};
	}

	function on (node, eventType, callback, optionalContext, id){
		//  USAGE
		//      var handle = on(this.node, 'mousedown', this, 'onStart');
		//      handle.pause();
		//      handle.resume();
		//      handle.remove();
		//
		var
			handles,
			handle,
			targetCallback,
			childTarget = false;

		if(/,/.test(eventType)){
			// handle multiple event types, like:
			// on(node, 'mouseup, mousedown', callback);
			//
			handles = [];
			eventType.split(',').forEach(function(eStr){
				handles.push(on(node, eStr.trim(), callback, optionalContext, id));
			});
			return makeMultiHandle(handles);
		}

		if(typeof optionalContext === 'string'){
			// no context. Last argument is handle id
			id = optionalContext;
			optionalContext = null;
		}

		node = getNode(node);
		callback = !!optionalContext ? bind(optionalContext, callback) : callback;

		if(/\s/.test(eventType)){
			// handle child selectors, like:
			// on(node, 'click .tab span', callback);
			//
			childTarget = eventType.substring(eventType.indexOf(' ') + 1, eventType.length);
			eventType = eventType.substring(0, eventType.indexOf(' '));
			targetCallback = callback;
			callback = function(e){
				var i, nodes, parent = on.ancestor(e.target, childTarget);
				if(parent){
					e.selectorTarget = parent;
					targetCallback(e);
				}else{
					nodes = node.querySelectorAll(childTarget);
					for(i = 0; i < nodes.length; i ++){
						if(nodes[i] === e.target || on.isAncestor(nodes[i], e.target)){
							e.selectorTarget = nodes[i];
							targetCallback(e);
							break;
						}
					}
				}
			};

		}

		if(eventType === 'clickoff'){
			// custom - used for popups 'n stuff
			return onClickoff(node, callback);
		}

		if(eventType === 'wheel'){
			// mousewheel events, natch
			if(has('wheel')){
				// pass through, but first curry callback to wheel events
				callback = normalizeWheelEvent(callback);
			}else{
				// old Firefox, old IE, Chrome
				return on.multi(node, {
					DOMMouseScroll:normalizeWheelEvent(callback),
					mousewheel:normalizeWheelEvent(callback)
				}, optionalContext);
			}
		}

		if(eventType.indexOf('key') > -1){
			callback = normalizeKeyEvent(callback);
		}

		node.addEventListener(eventType, callback, false);

		handle = {
			remove: function() {
				node.removeEventListener(eventType, callback, false);
				node = callback = null;
				this.remove = this.pause = this.resume = function(){};
			},
			pause: function(){
				node.removeEventListener(eventType, callback, false);
			},
			resume: function(){
				node.addEventListener(eventType, callback, false);
			}
		};

		if(id){
			// If an ID has been passed, register it so it can be used to
			// remove multiple events by id
			register(id, handle);
		}

		return handle;
	}

    on.multi = function(node, map, context, id){
        //  USAGE
        //      handle = on.multi(document, {
        //          "touchend":"onEnd",
        //          "touchcancel":"onEnd",
        //          "touchmove":this.method
        //      }, this);
        //
        var eventType,
            handles = [];

        for( eventType in map ){
            if(map.hasOwnProperty(eventType)){
                handles.push(on(node, eventType, map[eventType], context, id));
            }
        }

        return makeMultiHandle(handles);
    };

    on.remove = function(handles){
        // convenience function;
        // removes one or more handles;
        // accepts one handle or an array of handles;
        // accepts different types of handles (dispose/remove/topic token)
        //
        var i, h, idHandles;
        if(typeof handles === 'string'){
            idHandles = registry[handles];
            if(idHandles){
                idHandles.forEach(function(h){
                    h.remove();
                });
                idHandles = registry[handles] = null;
                delete registry[handles];
            }

            return [];
        }
        handles = Array.isArray(handles) ? handles : [handles];

        for( i = 0; i < handles.length; i++ ){
            h = handles[i];

            if(h){ // check for nulls / already removed handles
                if(h.remove){
                    // on handle, or AOP
                    h.remove();
                }
                else if(h.dispose){
                    // knockout
                    h.dispose();
                }
                else if(typeof h === 'function'){
                    // custom clean up
                    h();
                }
            }
        }
        return [];
    };

    on.ancestor = function(node, selector){
        // gets the ancestor of node based on selector criteria
        // useful for getting the target node when a child node is clicked upon
        //
        // USAGE
        //      on.selector(childNode, '.app.active');
        //      on.selector(childNode, '#thinger');
        //      on.selector(childNode, 'div');
        //	DOES NOT SUPPORT:
		//		combinations of above
        var
            test,
            parent = node;

        if(selector.indexOf('.') === 0){
            // className
            selector = selector.replace('.', ' ').trim();
            test = function(n){
                return n.classList.contains(selector);
            };
        }
        else if(selector.indexOf('#') === 0){
            // node id
            selector = selector.replace('#', '').trim();
            test = function(n){
                return n.id === selector;
            };
        }
        else if(selector.indexOf('[') > -1){
            // attribute
            console.error('attribute selectors are not yet supported');
        }
        else{
            // assuming node name
            selector = selector.toUpperCase();
            test = function(n){
				return n.nodeName === selector;
            };
        }

        while(parent){
            if(parent === document.body || parent === document){ return false; }
            if(test(parent)){ break; }
            parent = parent.parentNode;
        }

        return parent;
    };

    on.isAncestor = function(parent, child){
        // determines if parent is an ancestor of child
        // returns boolean
        //
        if(parent === child){ return false; } // do we always want the same node to be false?
        while(child){
            if(child === parent){
                return true;
            }
            child = child.parentNode;
        }
        return false;
    };

    on.makeMultiHandle = makeMultiHandle;

    return on;

}));
<|endoftext|>