<commit_before>import noOp from './utils/noOp';
import rafBatch from './client/rafBatch';
import createNode from './createNode';
import merge from './utils/merge';
import console from './utils/console';
import emptyObj from './utils/emptyObj';
import restrictObjProp from './utils/restrictObjProp';
import { IS_DEBUG } from './utils/debug';
import globalHook from './globalHook';

function mountComponent() {
    this.__isMounted = true;
    this.onMount();
}

function unmountComponent() {
    this.__isMounted = false;
    this.onUnmount();
}

function patchComponent(nextAttrs, nextChildren, nextContext, callReceivers) {
    if(!this.isMounted()) {
        return;
    }

    nextAttrs = this.__buildAttrs(nextAttrs);

    const prevAttrs = this.attrs,
        prevChildren = this.children,
        prevContext = this.context;

    if(callReceivers) {
        const isUpdating = this.__isUpdating;

        this.__isUpdating = true;

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

        this.attrs = nextAttrs;

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

        this.onAttrsReceive(prevAttrs);

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

        this.children = nextChildren;

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

        this.onChildrenReceive(prevChildren);

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

        this.context = nextContext;

        if(IS_DEBUG) {
            Object.freeze(this.context);
            this.__isFrozen = true;
        }

        this.onContextReceive(prevContext);

        this.__isUpdating = isUpdating;
    }

    if(this.__isUpdating) {
        return;
    }

    const shouldRerender = this.shouldRerender(prevAttrs, prevChildren, this.__prevState, prevContext);

    if(IS_DEBUG) {
        const shouldRerenderResType = typeof shouldRerender;

        if(shouldRerenderResType !== 'boolean') {
            console.warn(`Component#shouldRerender() should return boolean instead of ${shouldRerenderResType}`);
        }
    }

    if(shouldRerender) {
        const prevRootNode = this.getRootNode();

        this.__rootNode = this.render();
        prevRootNode.patch(this.__rootNode);
        this.onUpdate(prevAttrs, prevChildren, this.__prevState, prevContext);
    }
}

function shouldComponentRerender() {
    return true;
}

function onComponentRender() {
    return null;
}

function renderComponentToDom(parentNs) {
    return this.getRootNode().renderToDom(parentNs);
}

function renderComponentToString() {
    return this.getRootNode().renderToString();
}

function adoptComponentDom(domNode, domIdx) {
    return this.getRootNode().adoptDom(domNode, domIdx);
}

function getComponentDomNode() {
    return this.getRootNode().getDomNode();
}

function requestChildContext() {
    return emptyObj;
}

function setComponentState(state) {
    let nextState;

    if(this.__rootNode === null) { // wasn't inited
        nextState = state === emptyObj? state : merge(this.state, state);
    }
    else {
        this.update(this.state === this.__prevState? updateComponentPrevState : null);
        nextState = merge(this.state, state);
    }

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

    this.state = nextState;

    if(IS_DEBUG) {
        Object.freeze(this.state);
        this.__isFrozen = true;
    }
}

function updateComponentPrevState() {
    this.__prevState = this.state;
}

function renderComponent() {
    const onRenderRes = this.onRender(),
        rootNode = onRenderRes === null? createNode('!') : onRenderRes;

    if(IS_DEBUG) {
        if(typeof rootNode !== 'object' || Array.isArray(rootNode)) {
            throw TypeError('vidom: Component#onRender must return a single node on the top level or null.');
        }
    }

    const childCtx = this.onChildContextRequest(),
        rootNodeCtx = childCtx === emptyObj?
            this.context :
            this.context === emptyObj?
                childCtx :
                merge(this.context, childCtx);

    if(IS_DEBUG) {
        Object.freeze(rootNodeCtx);
    }

    rootNode.setCtx(rootNodeCtx);

    return rootNode;
}

function updateComponent(cb) {
    if(!this.isMounted()) {
        return;
    }

    if(this.__isUpdating) {
        if(cb) {
            rafBatch(() => cb.call(this));
        }
    }
    else {
        this.__isUpdating = true;
        rafBatch(() => {
            if(this.isMounted()) {
                this.__isUpdating = false;
                const prevRootNode = this.__rootNode;

                this.patch(this.attrs, this.children, this.context, false);
                cb && cb.call(this);
                if(IS_DEBUG) {
                    globalHook.emit('replace', prevRootNode, this.__rootNode);
                }
            }
        });
    }
}

function getComponentRootNode() {
    return this.__rootNode === null?
        this.__rootNode = this.render() :
        this.__rootNode;
}

function isComponentMounted() {
    return this.__isMounted;
}

function onComponentRefRequest() {
    return this;
}

function buildComponentAttrs(attrs) {
    if(attrs === this.attrs) {
        return attrs;
    }

    const { defaultAttrs } = this.constructor,
        hasDefaultAttrs = defaultAttrs != null,
        res = attrs === emptyObj?
            hasDefaultAttrs? defaultAttrs : attrs :
            hasDefaultAttrs? merge(defaultAttrs, attrs) : attrs;

    if(IS_DEBUG) {
        Object.freeze(res);
    }

    return res;
}

function createComponent(props, staticProps) {
    const res = function(attrs, children, ctx) {
            if(IS_DEBUG) {
                restrictObjProp(this, 'attrs');
                restrictObjProp(this, 'children');
                restrictObjProp(this, 'state');
                restrictObjProp(this, 'context');

                this.__isFrozen = false;
            }

            this.attrs = this.__buildAttrs(attrs);
            this.children = children;
            this.state = emptyObj;
            this.context = ctx;

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

            this.__isMounted = false;
            this.__isUpdating = false;

            this.__rootNode = null;

            this.onInit();

            this.__prevState = this.state;
        },
        ptp = {
            constructor : res,
            onInit : noOp,
            mount : mountComponent,
            unmount : unmountComponent,
            onMount : noOp,
            onUnmount : noOp,
            onAttrsReceive : noOp,
            onChildrenReceive : noOp,
            onContextReceive : noOp,
            shouldRerender : shouldComponentRerender,
            onRender : onComponentRender,
            onUpdate : noOp,
            isMounted : isComponentMounted,
            setState : setComponentState,
            renderToDom : renderComponentToDom,
            renderToString : renderComponentToString,
            adoptDom : adoptComponentDom,
            getDomNode : getComponentDomNode,
            getRootNode : getComponentRootNode,
            render : renderComponent,
            update : updateComponent,
            patch : patchComponent,
            onChildContextRequest : requestChildContext,
            onRefRequest : onComponentRefRequest,
            __buildAttrs : buildComponentAttrs
        };

    for(const i in props) {
        ptp[i] = props[i];
    }

    res.prototype = ptp;

    for(const i in staticProps) {
        res[i] = staticProps[i];
    }

    res['__vidom__component__'] = true;

    return res;
}

export default createComponent;
<commit_msg>Fix possible wrong previous attrs in some edge cases<commit_after>import noOp from './utils/noOp';
import rafBatch from './client/rafBatch';
import createNode from './createNode';
import merge from './utils/merge';
import console from './utils/console';
import emptyObj from './utils/emptyObj';
import restrictObjProp from './utils/restrictObjProp';
import { IS_DEBUG } from './utils/debug';
import globalHook from './globalHook';

function mountComponent() {
    this.__isMounted = true;
    this.onMount();
}

function unmountComponent() {
    this.__isMounted = false;
    this.onUnmount();
}

function patchComponent(nextAttrs, nextChildren, nextContext, callReceivers) {
    if(!this.isMounted()) {
        return;
    }

    if(callReceivers) {
        this.__prevAttrs = this.attrs;
        this.__prevChildren = this.children;
        this.__prevContext = this.context;

        const isUpdating = this.__isUpdating;

        this.__isUpdating = true;

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

        this.attrs = this.__buildAttrs(nextAttrs);

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

        this.onAttrsReceive(this.__prevAttrs);

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

        this.children = nextChildren;

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

        this.onChildrenReceive(this.__prevChildren);

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

        this.context = nextContext;

        if(IS_DEBUG) {
            Object.freeze(this.context);
            this.__isFrozen = true;
        }

        this.onContextReceive(this.__prevContext);

        this.__isUpdating = isUpdating;
    }

    if(this.__isUpdating) {
        return;
    }

    const shouldRerender = this.shouldRerender(
        this.__prevAttrs,
        this.__prevChildren,
        this.__prevState,
        this.__prevContext);

    if(IS_DEBUG) {
        const shouldRerenderResType = typeof shouldRerender;

        if(shouldRerenderResType !== 'boolean') {
            console.warn(`Component#shouldRerender() should return boolean instead of ${shouldRerenderResType}`);
        }
    }

    if(shouldRerender) {
        const prevRootNode = this.getRootNode();

        this.__rootNode = this.render();
        prevRootNode.patch(this.__rootNode);
        this.onUpdate(
            this.__prevAttrs,
            this.__prevChildren,
            this.__prevState,
            this.__prevContext);
    }

    this.__prevAttrs = this.attrs;
    this.__prevChildren = this.children;
    this.__prevState = this.state;
    this.__prevContext = this.context;
}

function shouldComponentRerender() {
    return true;
}

function onComponentRender() {
    return null;
}

function renderComponentToDom(parentNs) {
    return this.getRootNode().renderToDom(parentNs);
}

function renderComponentToString() {
    return this.getRootNode().renderToString();
}

function adoptComponentDom(domNode, domIdx) {
    return this.getRootNode().adoptDom(domNode, domIdx);
}

function getComponentDomNode() {
    return this.getRootNode().getDomNode();
}

function requestChildContext() {
    return emptyObj;
}

function setComponentState(state) {
    let nextState;

    if(this.__rootNode === null) { // wasn't inited
        nextState = state === emptyObj? state : merge(this.state, state);
    }
    else {
        this.update();
        nextState = merge(this.state, state);
    }

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

    this.state = nextState;

    if(IS_DEBUG) {
        Object.freeze(this.state);
        this.__isFrozen = true;
    }
}

function renderComponent() {
    const onRenderRes = this.onRender(),
        rootNode = onRenderRes === null? createNode('!') : onRenderRes;

    if(IS_DEBUG) {
        if(typeof rootNode !== 'object' || Array.isArray(rootNode)) {
            throw TypeError('vidom: Component#onRender must return a single node on the top level or null.');
        }
    }

    const childCtx = this.onChildContextRequest(),
        rootNodeCtx = childCtx === emptyObj?
            this.context :
            this.context === emptyObj?
                childCtx :
                merge(this.context, childCtx);

    if(IS_DEBUG) {
        Object.freeze(rootNodeCtx);
    }

    rootNode.setCtx(rootNodeCtx);

    return rootNode;
}

function updateComponent(cb) {
    if(!this.isMounted()) {
        return;
    }

    if(this.__isUpdating) {
        if(cb) {
            rafBatch(() => cb.call(this));
        }
    }
    else {
        this.__isUpdating = true;
        rafBatch(() => {
            if(this.isMounted()) {
                this.__isUpdating = false;
                const prevRootNode = this.__rootNode;

                this.patch(this.attrs, this.children, this.context, false);

                if(cb) {
                    cb.call(this);
                }

                if(IS_DEBUG) {
                    globalHook.emit('replace', prevRootNode, this.__rootNode);
                }
            }
        });
    }
}

function getComponentRootNode() {
    return this.__rootNode === null?
        this.__rootNode = this.render() :
        this.__rootNode;
}

function isComponentMounted() {
    return this.__isMounted;
}

function onComponentRefRequest() {
    return this;
}

function buildComponentAttrs(attrs) {
    if(attrs === this.attrs) {
        return attrs;
    }

    const { defaultAttrs } = this.constructor,
        hasDefaultAttrs = defaultAttrs != null,
        res = attrs === emptyObj?
            hasDefaultAttrs? defaultAttrs : attrs :
            hasDefaultAttrs? merge(defaultAttrs, attrs) : attrs;

    if(IS_DEBUG) {
        Object.freeze(res);
    }

    return res;
}

function createComponent(props, staticProps) {
    const res = function(attrs, children, ctx) {
            if(IS_DEBUG) {
                restrictObjProp(this, 'attrs');
                restrictObjProp(this, 'children');
                restrictObjProp(this, 'state');
                restrictObjProp(this, 'context');

                this.__isFrozen = false;
            }

            this.attrs = this.__buildAttrs(attrs);
            this.children = children;
            this.state = emptyObj;
            this.context = ctx;

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

            this.__isMounted = false;
            this.__isUpdating = false;

            this.__rootNode = null;

            this.onInit();

            this.__prevAttrs = this.attrs;
            this.__prevChildren = this.children;
            this.__prevState = this.state;
            this.__prevContext = this.context;
        },
        ptp = {
            constructor : res,
            onInit : noOp,
            mount : mountComponent,
            unmount : unmountComponent,
            onMount : noOp,
            onUnmount : noOp,
            onAttrsReceive : noOp,
            onChildrenReceive : noOp,
            onContextReceive : noOp,
            shouldRerender : shouldComponentRerender,
            onRender : onComponentRender,
            onUpdate : noOp,
            isMounted : isComponentMounted,
            setState : setComponentState,
            renderToDom : renderComponentToDom,
            renderToString : renderComponentToString,
            adoptDom : adoptComponentDom,
            getDomNode : getComponentDomNode,
            getRootNode : getComponentRootNode,
            render : renderComponent,
            update : updateComponent,
            patch : patchComponent,
            onChildContextRequest : requestChildContext,
            onRefRequest : onComponentRefRequest,
            __buildAttrs : buildComponentAttrs
        };

    for(const i in props) {
        ptp[i] = props[i];
    }

    res.prototype = ptp;

    for(const i in staticProps) {
        res[i] = staticProps[i];
    }

    res['__vidom__component__'] = true;

    return res;
}

export default createComponent;
<|endoftext|>


<commit_before>// Copyright (c) 2013 M-Way Solutions GmbH
// http://github.com/mwaylabs/The-M-Project/blob/absinthe/MIT-LICENSE.txt

/**
 * The Bikini.Collection can be used like a Backbone Collection,
 *
 * but there are some enhancements to fetch, save and delete the
 * contained models from or to other "data stores".
 *
 * see LocalStorageStore, WebSqlStore or BikiniStore for examples
 *
 * @module Bikini.Collection
 *
 * @type {*}
 * @extends Backbone.Collection
 *
 */
Bikini.Collection = Backbone.Collection.extend({

    constructor: function (options) {
        this.init(options);
        Backbone.Collection.apply(this, arguments);
    }
});

Bikini.Collection.create = Bikini.create;
Bikini.Collection.design = Bikini.design;

_.extend(Bikini.Collection.prototype, Bikini.Object, {

    _type: 'Bikini.Collection',

    isCollection: YES,

    model: Bikini.Model,

    entity: null,

    options: null,

    logon: Bikini.Security.logon,

    init: function (options) {
        options = options || {};
        this.store = options.store || this.store || (this.model ? this.model.prototype.store : null);
        this.entity = options.entity || this.entity || (this.model ? this.model.prototype.entity : null);
        this.options = options.options || this.options;

        var entity = this.entity || this.entityFromUrl(this.url);
        if (entity) {
            this.entity = Bikini.Entity.from(entity, { model: this.model, typeMapping: options.typeMapping });
        }
        this._updateUrl();

        if (this.store && _.isFunction(this.store.initCollection)) {
            this.store.initCollection(this, options);
        }
    },

    entityFromUrl: function (url) {
        if (url) {
            // extract last path part as entity name
            var parts = Bikini.Request.getLocation(this.url).pathname.match(/([^\/]+)\/?$/);
            if (parts && parts.length > 1) {
                return parts[1];
            }
        }
    },

    sort: function (options) {
        if (_.isObject(options && options.sort)) {
            this.comparator = Bikini.DataSelector.compileSort(options.sort);
        }
        Backbone.Collection.prototype.sort.apply(this, arguments);
    },

    select: function (options) {
        var selector = options && options.query ? Bikini.DataSelector.create(options.query) : null;
        var collection = Bikini.Collection.create(null, { model: this.model });

        if (options && options.sort) {
            collection.comparator = Bikini.DataSelector.compileSort(options.sort);
        }

        this.each(function (model) {
            if (!selector || selector.matches(model.attributes)) {
                collection.add(model);
            }
        });
        return collection;
    },

    destroy: function (options) {
        options = options || {};
        var success = options.success;
        if (this.length > 0) {
            options.success = function () {
                if (this.length === 0 && success) {
                    success();
                }
            };
            var model;
            while ((model = this.first())) {
                this.sync('delete', model, options);
                this.remove(model);
            }
        } else if (success) {
            success();
        }
    },

    sync: function (method, model, options) {
        options = options || {};
        options.credentials = options.credentials || this.credentials;
        var store = (options.store ? options.store : null) || this.store;
        var that = this;
        var args = arguments;

        this.logon(options, function (result) {
            if (store && _.isFunction(store.sync)) {
                return store.sync.apply(that, args);
            } else {
                return Backbone.sync.apply(that, args);
            }
        });
    },

    /**
     * save all containing models
     */
    save: function() {
        this.each(function(model) {
            model.save();
        });
    },

    getUrlParams: function (url) {
        url = url || this.getUrl();
        var m = url.match(/\?([^#]*)/);
        var params = {};
        if (m && m.length > 1) {
            _.each(m[1].split('&'), function (p) {
                var a = p.split('=');
                params[a[0]] = a[1];
            });
        }
        return params;
    },

    getUrl: function (collection) {
        return (_.isFunction(this.url) ? this.url() : this.url) || '';
    },

    getUrlRoot: function () {
        var url = this.getUrl();
        return url ? ( url.indexOf('?') >= 0 ? url.substr(0, url.indexOf('?')) : url) : '';
    },

    applyFilter: function (callback) {
        this.trigger('filter', this.filter(callback));
    },

    _updateUrl: function () {
        var params = this.getUrlParams();
        if (this.options) {
            this.url = this.getUrlRoot();
            if (this.options.query) {
                params.query = encodeURIComponent(JSON.stringify(this.options.query));
            }
            if (this.options.fields) {
                params.fields = encodeURIComponent(JSON.stringify(this.options.fields));
            }
            if (this.options.sort) {
                params.sort = encodeURIComponent(JSON.stringify(this.options.sort));
            }
            if (!_.isEmpty(params)) {
                this.url += '?';
                var a = [];
                for (var k in params) {
                    a.push(k + (params[k] ? '=' + params[k] : ''));
                }
                this.url += a.join('&');
            }
        }
    }

});
<commit_msg>add destroyLocal function to collection<commit_after>// Copyright (c) 2013 M-Way Solutions GmbH
// http://github.com/mwaylabs/The-M-Project/blob/absinthe/MIT-LICENSE.txt

/**
 * The Bikini.Collection can be used like a Backbone Collection,
 *
 * but there are some enhancements to fetch, save and delete the
 * contained models from or to other "data stores".
 *
 * see LocalStorageStore, WebSqlStore or BikiniStore for examples
 *
 * @module Bikini.Collection
 *
 * @type {*}
 * @extends Backbone.Collection
 *
 */
Bikini.Collection = Backbone.Collection.extend({

    constructor: function (options) {
        this.init(options);
        Backbone.Collection.apply(this, arguments);
    }
});

Bikini.Collection.create = Bikini.create;
Bikini.Collection.design = Bikini.design;

_.extend(Bikini.Collection.prototype, Bikini.Object, {

    _type: 'Bikini.Collection',

    isCollection: YES,

    model: Bikini.Model,

    entity: null,

    options: null,

    logon: Bikini.Security.logon,

    init: function (options) {
        options = options || {};
        this.store = options.store || this.store || (this.model ? this.model.prototype.store : null);
        this.entity = options.entity || this.entity || (this.model ? this.model.prototype.entity : null);
        this.options = options.options || this.options;

        var entity = this.entity || this.entityFromUrl(this.url);
        if (entity) {
            this.entity = Bikini.Entity.from(entity, { model: this.model, typeMapping: options.typeMapping });
        }
        this._updateUrl();

        if (this.store && _.isFunction(this.store.initCollection)) {
            this.store.initCollection(this, options);
        }
    },

    entityFromUrl: function (url) {
        if (url) {
            // extract last path part as entity name
            var parts = Bikini.Request.getLocation(this.url).pathname.match(/([^\/]+)\/?$/);
            if (parts && parts.length > 1) {
                return parts[1];
            }
        }
    },

    sort: function (options) {
        if (_.isObject(options && options.sort)) {
            this.comparator = Bikini.DataSelector.compileSort(options.sort);
        }
        Backbone.Collection.prototype.sort.apply(this, arguments);
    },

    select: function (options) {
        var selector = options && options.query ? Bikini.DataSelector.create(options.query) : null;
        var collection = Bikini.Collection.create(null, { model: this.model });

        if (options && options.sort) {
            collection.comparator = Bikini.DataSelector.compileSort(options.sort);
        }

        this.each(function (model) {
            if (!selector || selector.matches(model.attributes)) {
                collection.add(model);
            }
        });
        return collection;
    },

    destroy: function (options) {
        options = options || {};
        var success = options.success;
        if (this.length > 0) {
            options.success = function () {
                if (this.length === 0 && success) {
                    success();
                }
            };
            var model;
            while ((model = this.first())) {
                this.sync('delete', model, options);
                this.remove(model);
            }
        } else if (success) {
            success();
        }
    },

    destroyLocal: function(){
        var store = this.endpoint.localStore;
        var that = this;
        // DROP TABLE
        store.drop(store.entities.Approval);
        // RESET localStorage-entry
        localStorage.setItem('__' + this.channel + 'last_msg_time', '');
        this.store.endpoints = {};
        this.reset();
    },

    sync: function (method, model, options) {
        options = options || {};
        options.credentials = options.credentials || this.credentials;
        var store = (options.store ? options.store : null) || this.store;
        var that = this;
        var args = arguments;

        this.logon(options, function (result) {
            if (store && _.isFunction(store.sync)) {
                return store.sync.apply(that, args);
            } else {
                return Backbone.sync.apply(that, args);
            }
        });
    },

    /**
     * save all containing models
     */
    save: function() {
        this.each(function(model) {
            model.save();
        });
    },

    getUrlParams: function (url) {
        url = url || this.getUrl();
        var m = url.match(/\?([^#]*)/);
        var params = {};
        if (m && m.length > 1) {
            _.each(m[1].split('&'), function (p) {
                var a = p.split('=');
                params[a[0]] = a[1];
            });
        }
        return params;
    },

    getUrl: function (collection) {
        return (_.isFunction(this.url) ? this.url() : this.url) || '';
    },

    getUrlRoot: function () {
        var url = this.getUrl();
        return url ? ( url.indexOf('?') >= 0 ? url.substr(0, url.indexOf('?')) : url) : '';
    },

    applyFilter: function (callback) {
        this.trigger('filter', this.filter(callback));
    },

    _updateUrl: function () {
        var params = this.getUrlParams();
        if (this.options) {
            this.url = this.getUrlRoot();
            if (this.options.query) {
                params.query = encodeURIComponent(JSON.stringify(this.options.query));
            }
            if (this.options.fields) {
                params.fields = encodeURIComponent(JSON.stringify(this.options.fields));
            }
            if (this.options.sort) {
                params.sort = encodeURIComponent(JSON.stringify(this.options.sort));
            }
            if (!_.isEmpty(params)) {
                this.url += '?';
                var a = [];
                for (var k in params) {
                    a.push(k + (params[k] ? '=' + params[k] : ''));
                }
                this.url += a.join('&');
            }
        }
    }

});
<|endoftext|>


<commit_before>// ************************************
// A variety of validation routines
//
//  All routines return true or false
//
// checkDate -- checks if valid date
// checkDigit -- checks if character provided is a single digit
// checkNotEmpty  -- checks if empty
// checkEmail -- check if valid email
// checkNumber -- check if number
// checkNumberLessThan -- check if number is less than a provided number
// checkNumberGreaterThan -- check if number is greater than a provided number
// checkPhone -- checks if a 10 digit phone number
// checkCreditCardNumber -- checks if valid card number using Luhn's formula
// checkCreditCardType -- checks if the credit card type is valid based on the credit card number
//                         Master Card, Visa, American Express
// ************************************

/*
    Checks if the string is a valid date formatted as...
    mm dd yyyy, mm/dd/yyyy, mm.dd.yyyy, mm-dd-yyyy

    http://codylindley.com/blogstuff/js/validation/
*/
function checkDate(str){
	var re = /^(\d{1,2})[\s\.\/-](\d{1,2})[\s\.\/-](\d{4})$/
	if (!re.test(str)) return false;
	var result = str.match(re);
	var m = parseInt(result[1]);
	var d = parseInt(result[2]);
	var y = parseInt(result[3]);
	if(m < 1 || m > 12 || y < 1900 || y > 2100) return false;
	if(m == 2){
		var days = ((y % 4) == 0) ? 29 : 28;
	}else if(m == 4 || m == 6 || m == 9 || m == 11){
		var days = 30;
	}else{
		var days = 31;
	}
	return (d >= 1 && d <= days);
}

/*
 Check if character supplied is a digit
*/
function checkDigit(c) {
    if (c.length != 1) return false;
    var strAllowed = "1234567890";
    return (strAllowed.indexOf (c) != -1);
}

/*
 Check for empty string, return true if empty, false otherwise
*/
function checkNotEmpty(strng) {
    return (strng != "");
}

/*
 Email checking-- comes from Apple's example validation code
 http://developer.apple.com/internet/webcontent/examples/validate_source.html
*/
function checkEmail(strng) {
    if (strng == "") {
        return false;
    }
    // test email for an @ followed by characters and a .
    var emailFilter=/^.+@.+\..{2,3}$/;
    if (!(emailFilter.test(strng))) {
        return false;
    }
    else {
        //test email for illegal characters
        var illegalChars= /[\(\)\<\>\,\;\:\\\"\[\]]/
        if (strng.match(illegalChars)) {
            return false;
        }
    }
    return true;
}

/*
 Check if this is a number
 */
function checkNumber(num) {
    return (!(isNaN(parseInt(num))));
}

function checkNumberGreaterThan(num, compareNum) {
    if (!checkNumber(num)) return false;
    return (num > compareNum);
}

function checkNumberLessThan(num, compareNum) {
    if (!checkNumber(num)) return false;
    return (num < compareNum);
}

/*
 phone number - strip out delimiters and check for 10 digits -- also from Apple
*/
function checkPhone(strng) {
    if (strng == "") {
        return false;
    }
    // check that phone number doesn't contain illegal chars
    var stripped = strng.replace(/[\(\)\.\-\ ]/g, ''); //strip out acceptable non-numeric characters
    if (isNaN(parseInt(stripped))) {
        return false;
    }
    // check length of phone number
    if (!(stripped.length == 10)) {
        return false;
    }
    return true;
}

/*
 Check if this credit card number is valid
*/
function checkCreditCardNumber (strNum) {
    var nCheck = 0;
    var bEven = false;

    for (n = strNum.length - 1; n >= 0; n--) {
        var cDigit = strNum.charAt (n);
        if (isDigit (cDigit)) {
            var nDigit = parseInt(cDigit, 10);
            if (bEven) {
                if ((nDigit *= 2) > 9)
                    nDigit -= 9;
            }
            nCheck += nDigit;
            bEven = ! bEven;
        } else if (cDigit != ' ' && cDigit != '.' && cDigit != '-') {
            return false;
        }
    }
    return (nCheck % 10) == 0;
}

/*
 Check if this credit card type is valid
*/
function checkCreditCardType(strNum, type) {
    var nLen = 0;
    for (n = 0; n < strNum.length; n++) {
        if (isDigit (strNum.substring (n,n+1)))
            ++nLen;
    }
    if (type == 'Visa')
        return ((strNum.substring(0,1) == '4') && (nLen == 13 || nLen == 16));
    else if (type == 'Amex')
        return ((strNum.substring(0,2) == '34' || strNum.substring(0,2) == '37') && (nLen == 15));
    else if (type == 'Master Card')
        return ((strNum.substring(0,2) == '51' || strNum.substring(0,2) == '52'
                || strNum.substring(0,2) == '53' || strNum.substring(0,2) == '54'
                || strNum.substring(0,2) == '55') && (nLen == 16));
    else
        return false;

}

function validate( myform ) {
    var inputFields = document.getElementById(myform.id).getElementsByTagName("input");
    var valid = true;
    var checkFunc = "";
    var message = "";
    for (i = 0; i < inputFields.length; i++) {
        var checkFuncStr = inputFields[i].className;
        var startIdx = checkFuncStr.indexOf('check')
        if (startIdx >= 0) {
            var lastIdx = checkFuncStr.indexOf('#');
            if (lastIdx > 0) {
                checkFunc = checkFuncStr.substring(startIdx, lastIdx);
                var myfunc = checkFunc + "('" + inputFields[i].value + "')";
                valid = eval(myfunc);
                if (!valid) {
                    message = inputFields[i+1].value;
                    displayError( myform, message);
                    return false;
                }
            }
        }
    }
}

function displayError( myform, message) {
    var msgDiv = null;
    var form = document.getElementById(myform.id);
    var divs = form.getElementsByTagName("div");
    for (i = 0; i < divs.length; i++) {
        var errorDiv = divs[i].className;
        if (errorDiv == "ui-messagebox-portlet-msg-error") {
            msgDiv = divs[i];
            msgDiv.childNodes[0].textContent = message;
        }
    }
    if (!msgDiv) {
        msgDiv = document.createElement("div");
        msgDiv.className = "ui-messagebox-portlet-msg-error";
        var msgSpan = document.createElement("span");
        msgSpan.className = "portlet-msg-error";
        var txt = document.createTextNode(message);
        msgSpan.appendChild(txt);
        msgDiv.appendChild(msgSpan);
        form.insertBefore(msgDiv, form.childNodes[0]);
    }
}<commit_msg>loop thru class attribute for validators<commit_after>// ************************************
// A variety of validation routines
//
//  All routines return true or false
//
// checkDate -- checks if valid date
// checkDigit -- checks if character provided is a single digit
// checkNotEmpty  -- checks if empty
// checkEmail -- check if valid email
// checkNumber -- check if number
// checkNumberLessThan -- check if number is less than a provided number
// checkNumberGreaterThan -- check if number is greater than a provided number
// checkPhone -- checks if a 10 digit phone number
// checkCreditCardNumber -- checks if valid card number using Luhn's formula
// checkCreditCardType -- checks if the credit card type is valid based on the credit card number
//                         Master Card, Visa, American Express
// ************************************

/*
    Checks if the string is a valid date formatted as...
    mm dd yyyy, mm/dd/yyyy, mm.dd.yyyy, mm-dd-yyyy

    http://codylindley.com/blogstuff/js/validation/
*/
function checkDate(str){
	var re = /^(\d{1,2})[\s\.\/-](\d{1,2})[\s\.\/-](\d{4})$/
	if (!re.test(str)) return false;
	var result = str.match(re);
	var m = parseInt(result[1]);
	var d = parseInt(result[2]);
	var y = parseInt(result[3]);
	if(m < 1 || m > 12 || y < 1900 || y > 2100) return false;
	if(m == 2){
		var days = ((y % 4) == 0) ? 29 : 28;
	}else if(m == 4 || m == 6 || m == 9 || m == 11){
		var days = 30;
	}else{
		var days = 31;
	}
	return (d >= 1 && d <= days);
}

/*
 Check if character supplied is a digit
*/
function checkDigit(c) {
    if (c.length != 1) return false;
    var strAllowed = "1234567890";
    return (strAllowed.indexOf (c) != -1);
}

/*
 Check for empty string, return true if empty, false otherwise
*/
function checkNotEmpty(strng) {
    return (strng != "");
}

/*
 Email checking-- comes from Apple's example validation code
 http://developer.apple.com/internet/webcontent/examples/validate_source.html
*/
function checkEmail(strng) {
    if (strng == "") {
        return false;
    }
    // test email for an @ followed by characters and a .
    var emailFilter=/^.+@.+\..{2,3}$/;
    if (!(emailFilter.test(strng))) {
        return false;
    }
    else {
        //test email for illegal characters
        var illegalChars= /[\(\)\<\>\,\;\:\\\"\[\]]/
        if (strng.match(illegalChars)) {
            return false;
        }
    }
    return true;
}

/*
 Check if this is a number
 */
function checkNumber(num) {
    return (!(isNaN(parseInt(num))));
}

function checkNumberGreaterThan(num, compareNum) {
    if (!checkNumber(num)) return false;
    return (num > compareNum);
}

function checkNumberLessThan(num, compareNum) {
    if (!checkNumber(num)) return false;
    return (num < compareNum);
}

/*
 phone number - strip out delimiters and check for 10 digits -- also from Apple
*/
function checkPhone(strng) {
    if (strng == "") {
        return false;
    }
    // check that phone number doesn't contain illegal chars
    var stripped = strng.replace(/[\(\)\.\-\ ]/g, ''); //strip out acceptable non-numeric characters
    if (isNaN(parseInt(stripped))) {
        return false;
    }
    // check length of phone number
    if (!(stripped.length == 10)) {
        return false;
    }
    return true;
}

/*
 Check if this credit card number is valid
*/
function checkCreditCardNumber (strNum) {
    var nCheck = 0;
    var bEven = false;

    for (n = strNum.length - 1; n >= 0; n--) {
        var cDigit = strNum.charAt (n);
        if (isDigit (cDigit)) {
            var nDigit = parseInt(cDigit, 10);
            if (bEven) {
                if ((nDigit *= 2) > 9)
                    nDigit -= 9;
            }
            nCheck += nDigit;
            bEven = ! bEven;
        } else if (cDigit != ' ' && cDigit != '.' && cDigit != '-') {
            return false;
        }
    }
    return (nCheck % 10) == 0;
}

/*
 Check if this credit card type is valid
*/
function checkCreditCardType(strNum, type) {
    var nLen = 0;
    for (n = 0; n < strNum.length; n++) {
        if (isDigit (strNum.substring (n,n+1)))
            ++nLen;
    }
    if (type == 'Visa')
        return ((strNum.substring(0,1) == '4') && (nLen == 13 || nLen == 16));
    else if (type == 'Amex')
        return ((strNum.substring(0,2) == '34' || strNum.substring(0,2) == '37') && (nLen == 15));
    else if (type == 'Master Card')
        return ((strNum.substring(0,2) == '51' || strNum.substring(0,2) == '52'
                || strNum.substring(0,2) == '53' || strNum.substring(0,2) == '54'
                || strNum.substring(0,2) == '55') && (nLen == 16));
    else
        return false;

}

function validate( myform ) {
    var inputFields = document.getElementById(myform.id).getElementsByTagName("input");
    var valid = true;
    var checkFunc = "";
    var message = "";
    for (i = 0; i < inputFields.length; i++) {
        var checkFuncStr = inputFields[i].className;
        var startIdx = 0;
        var endIdx = checkFuncStr.length;
        var done = false;
        do {
            startIdx = checkFuncStr.indexOf('check', startIdx);
            if (startIdx >= 0) {
                var lastIdx = checkFuncStr.indexOf('#', startIdx);
                if (lastIdx > 0) {
                    checkFunc = checkFuncStr.substring(startIdx, lastIdx);
                    startIdx = lastIdx;
                    var myfunc = checkFunc + "('" + inputFields[i].value + "')";
                    valid = eval(myfunc);
                    if (!valid) {
                        var validateName = inputFields[i].name + "#" + checkFunc;
                        var hiddenField = document.getElementById(myform.id).elements[validateName];
                        message = hiddenField.value;
                        displayError( myform, message);
                        return false;
                    }
                }
            } else {
                done = true;
            }
            if (startIdx >= endIdx - 5) done = true;
        } while (!done)
    }
}

function displayError( myform, message) {
    var msgDiv = null;
    var form = document.getElementById(myform.id);
    var divs = form.getElementsByTagName("div");
    for (i = 0; i < divs.length; i++) {
        var errorDiv = divs[i].className;
        if (errorDiv == "ui-messagebox-portlet-msg-error") {
            msgDiv = divs[i];
            msgDiv.childNodes[0].textContent = message;
        }
    }
    if (!msgDiv) {
        msgDiv = document.createElement("div");
        msgDiv.className = "ui-messagebox-portlet-msg-error";
        var msgSpan = document.createElement("span");
        msgSpan.className = "portlet-msg-error";
        var txt = document.createTextNode(message);
        msgSpan.appendChild(txt);
        msgDiv.appendChild(msgSpan);
        form.insertBefore(msgDiv, form.childNodes[0]);
    }
}<|endoftext|>


<commit_before>var Controller = null;
var PointZero = new Point(0, 0);
var SizeZero = new Size(0, 0);
var AnimationSheets = {};

atom.declare("Game.Controller",
{
	initialize: function()
	{
		atom.ImagePreloader.run(
		{
			ship1: "Textures/ship1.png",
			part1: "Textures/part1.png",
			triangle: "Textures/triangle.png",
			point: "Textures/point.png",
			animation1: "Textures/animation1.png",
			ship2: "Textures/ship2.png",
			part2: "Textures/part2.png",
			part2_broken: "Textures/part2_broken.png",
			explosion1: "Textures/explosion1.png",
			bullet: "Textures/bullet.png",
			bulletExplosion: "Textures/bulletExplosion.png",
			engine1: "Textures/engine1.png",
			engine1_broken: "Textures/engine1_broken.png",
			ship_explosion: "Textures/ship_explosion.png",
			ship3: "Textures/ship3.png",
			engine2: "Textures/engine2.png",
			engine2_broken: "Textures/engine2_broken.png",
			ship3_broken: "Textures/ship3_broken.png",
			ship2_broken: "Textures/ship2_broken.png",
			debris1: "Textures/debris/d1.png",
			debris2: "Textures/debris/d2.png",
			debris3: "Textures/debris/d3.png",
			debris4: "Textures/debris/d4.png",
			debris5: "Textures/debris/d5.png",
			debris6: "Textures/debris/d6.png",
			debris7: "Textures/debris/d7.png",
			debris8: "Textures/debris/d8.png",
			ship4: "Textures/ship4.png",
			ship4_broken: "Textures/ship4_broken.png"
		}, this.run, this);
	},

	run: function(images)
	{
		Controller = this;

		var div_CanvasSize = document.getElementById("div_CanvasSize");
		this.fieldSize = new Size(div_CanvasSize.clientWidth, div_CanvasSize.clientHeight);
		var app = new App({size: this.fieldSize});
		app.resources.set("images", images);
		this.images = images;
		this.Aim = new Game.Aim();
		this.translatedOffset = new Point(0, 0);
		this.cruiseControll_left = false;
		this.cruiseControll_right = false;
		this.playerColor = "#FFD800";

		this.mapSize = new Size(8000, 7000);
		this.mapSizeStopShips = new Size(this.mapSize.x - 500, this.mapSize.y - 500);
		this.mapRect = new Rectangle({center: PointZero, size: this.mapSizeStopShips});

		var mapAspect = this.mapSize.x / this.mapSize.y;
		var miniMapWidth = this.fieldSize.x / 5;
		this.miniMapSize = new Size(miniMapWidth, miniMapWidth / mapAspect);

		this.mouse = new Mouse(app.container.bounds);
		this.mouse.events.add('click', this.mouseClick);

		this.teams = new Game.Teams();

		this.keyboard = new atom.Keyboard();

		this.layerBackground = app.createLayer("background");
		this.layerShips = app.createLayer({name: "ships", invoke: true, intersection: 'all'});
		this.layerMinimap = app.createLayer({name: "minimap", invoke: true});
		this.layerMinimap.ctx.size = new Size(this.miniMapSize.x, this.miniMapSize.y);

		var Minimap = new Game.Minimap(this.layerMinimap, {});

		this.zIndexMapObjects = 0;
		this.drawBackground(this.layerBackground.ctx);

		this.GUImanager = new Game.GUImanager();
		this.GUImanager.PatchController();

		this.sound = new Game.SoundPlayer({});

		this.ships = [];
		this.zIndexCounter = 1000;
		var spawnPlayer = 1; //1 fighter_1, 2 cruiser_tesla, 3 fighter_bat
		var fighterCount = 5;
		var cruiserCount = 1;
		var batCount = 1;
		this.PlayerController = new Game.PlayerController();
		var spawnArea = this.mapSizeStopShips;

		for (var i=0; i<cruiserCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 2 && i==cruiserCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_cruiser_tesla(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_cruiser_tesla(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		for (var i=0; i<fighterCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 1 && i==fighterCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_fighter_1(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_fighter_1(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		for (var i=0; i<batCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 3 && i==batCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_fighter_bat(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_fighter_bat(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter_bat(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		this.translatedOffset = new Point(this.fieldSize.x/2, this.fieldSize.y/2);
		if (this.PlayerController.ship != null)
		{
			var playerCener = this.PlayerController.ship.shape.center;
			this.translatedOffset = new Point(-playerCener.x + this.fieldSize.x/2 , -playerCener.y + this.fieldSize.y/2);
		}
		this.layerShips.dom.canvas.ctx.translate(this.translatedOffset);

		this.fpsMeter();

		document.getElementById("btn_controll_left").onclick = function()
		{
			Controller.cruiseControll_left = !Controller.cruiseControll_left;
			Controller.updateCruiseButtons();
		};

		document.getElementById("btn_controll_right").onclick = function()
		{
			Controller.cruiseControll_right = !Controller.cruiseControll_right;
			Controller.updateCruiseButtons();
		};
	},

	updateCruiseButtons: function()
	{
		var spriteLeft = "url(textures/btnGreen.png)";
		var spriteRight = "url(textures/btnGreen.png)";

		if (Controller.cruiseControll_left)
			spriteLeft = "url(textures/btnGreenPress.png)";

		if (Controller.cruiseControll_right)
			spriteRight = "url(textures/btnGreenPress.png)";

		document.getElementById("btn_controll_left").style.backgroundImage = spriteLeft;
		document.getElementById("btn_controll_right").style.backgroundImage = spriteRight;
	},

	addLayersTranslate: function(point)
	{
		this.translatedOffset = new Point(this.translatedOffset.x - point.x, this.translatedOffset.y - point.y);
		this.layerShips.dom.canvas.ctx.translate(point, true);
	},

	killShip: function(ship)
	{
		var indx = -1;
		for (var i = 0; i<this.ships.length; i++)
		{
			if (this.ships[i] == ship)
			{
				indx = i;
				break;
			}
		}

		if (indx == -1)
		{
			console.warn("Ship not found to splice " + JSON.stringify(ship));
			return;
		}

		this.ships.splice(i, 1);
	},

	// Context not saved
	mouseClick: function()
	{
		//return;

		var point = Controller.mouse.point.clone();

		point = new Point(point.x - Controller.translatedOffset.x, point.y - Controller.translatedOffset.y);

		new Game.Bullet(Controller.layerShips,
			{
				position: point,
				angle: -2,
				speed: 0.1,
				team: "yellow"
			});
	},

	drawBackground: function(ctx)
	{
		ctx.fillAll(
			ctx.createGradient(
			new Circle(this.fieldSize.x/2, this.fieldSize.y/2, this.fieldSize.x / 10),
			new Circle(this.fieldSize.x/2, this.fieldSize.y/2, this.fieldSize.x / 2), {
				'0.0': '#0C0038',
				'0.5': '#080028',
				'1.0': '#050019'
			})
		);

		new Game.GradientCircle(Controller.layerShips,
		{
			position: new Point(0, 0),
			radius: 500
		});
	},

	fpsMeter: function ()
	{
		var fps = atom.trace(), time = [], last = Date.now();

		atom.frame.add(function ()
		{
			if (time.length > 5) time.shift();

			time.push(Date.now() - last);
			last = Date.now();

			fps.value = Math.ceil(1000 / time.average()) + " FPS";
		});
	}
});<commit_msg>No gui on load<commit_after>var Controller = null;
var PointZero = new Point(0, 0);
var SizeZero = new Size(0, 0);
var AnimationSheets = {};

atom.declare("Game.Controller",
{
	initialize: function()
	{
		document.getElementById("shield_online").style.display = "none";
		document.getElementById("shield_offline").style.display = "none";
		document.getElementById("shield_charging").style.display = "none";

		atom.ImagePreloader.run(
		{
			ship1: "Textures/ship1.png",
			part1: "Textures/part1.png",
			triangle: "Textures/triangle.png",
			point: "Textures/point.png",
			animation1: "Textures/animation1.png",
			ship2: "Textures/ship2.png",
			part2: "Textures/part2.png",
			part2_broken: "Textures/part2_broken.png",
			explosion1: "Textures/explosion1.png",
			bullet: "Textures/bullet.png",
			bulletExplosion: "Textures/bulletExplosion.png",
			engine1: "Textures/engine1.png",
			engine1_broken: "Textures/engine1_broken.png",
			ship_explosion: "Textures/ship_explosion.png",
			ship3: "Textures/ship3.png",
			engine2: "Textures/engine2.png",
			engine2_broken: "Textures/engine2_broken.png",
			ship3_broken: "Textures/ship3_broken.png",
			ship2_broken: "Textures/ship2_broken.png",
			debris1: "Textures/debris/d1.png",
			debris2: "Textures/debris/d2.png",
			debris3: "Textures/debris/d3.png",
			debris4: "Textures/debris/d4.png",
			debris5: "Textures/debris/d5.png",
			debris6: "Textures/debris/d6.png",
			debris7: "Textures/debris/d7.png",
			debris8: "Textures/debris/d8.png",
			ship4: "Textures/ship4.png",
			ship4_broken: "Textures/ship4_broken.png"
		}, this.run, this);
	},

	run: function(images)
	{
		Controller = this;

		var div_CanvasSize = document.getElementById("div_CanvasSize");
		this.fieldSize = new Size(div_CanvasSize.clientWidth, div_CanvasSize.clientHeight);
		var app = new App({size: this.fieldSize});
		app.resources.set("images", images);
		this.images = images;
		this.Aim = new Game.Aim();
		this.translatedOffset = new Point(0, 0);
		this.cruiseControll_left = false;
		this.cruiseControll_right = false;
		this.playerColor = "#FFD800";

		this.mapSize = new Size(8000, 7000);
		this.mapSizeStopShips = new Size(this.mapSize.x - 500, this.mapSize.y - 500);
		this.mapRect = new Rectangle({center: PointZero, size: this.mapSizeStopShips});

		var mapAspect = this.mapSize.x / this.mapSize.y;
		var miniMapWidth = this.fieldSize.x / 5;
		this.miniMapSize = new Size(miniMapWidth, miniMapWidth / mapAspect);

		this.mouse = new Mouse(app.container.bounds);
		this.mouse.events.add('click', this.mouseClick);

		this.teams = new Game.Teams();

		this.keyboard = new atom.Keyboard();

		this.layerBackground = app.createLayer("background");
		this.layerShips = app.createLayer({name: "ships", invoke: true, intersection: 'all'});
		this.layerMinimap = app.createLayer({name: "minimap", invoke: true});
		this.layerMinimap.ctx.size = new Size(this.miniMapSize.x, this.miniMapSize.y);

		var Minimap = new Game.Minimap(this.layerMinimap, {});

		this.zIndexMapObjects = 0;
		this.drawBackground(this.layerBackground.ctx);

		this.GUImanager = new Game.GUImanager();
		this.GUImanager.PatchController();

		this.sound = new Game.SoundPlayer({});

		this.ships = [];
		this.zIndexCounter = 1000;
		var spawnPlayer = 1; //1 fighter_1, 2 cruiser_tesla, 3 fighter_bat
		var fighterCount = 5;
		var cruiserCount = 1;
		var batCount = 1;
		this.PlayerController = new Game.PlayerController();
		var spawnArea = this.mapSizeStopShips;

		for (var i=0; i<cruiserCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 2 && i==cruiserCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_cruiser_tesla(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_cruiser_tesla(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		for (var i=0; i<fighterCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 1 && i==fighterCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_fighter_1(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_fighter_1(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		for (var i=0; i<batCount; i++)
		{
			var controller = new Game.AI_fighter();
			if (spawnPlayer == 3 && i==batCount - 1)
				controller = this.PlayerController;

			var Ship2 = new Game.Ship_fighter_bat(this.layerShips,
			{
				position: new Point(-spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: controller,
				team: "red"
			});
			this.ships.push(Ship2);

			var Ship3 = new Game.Ship_fighter_bat(this.layerShips,
			{
				position: new Point(+spawnArea.x/2 * Math.random(), spawnArea.y * (Math.random() - 0.5)),
				angle: 1,
				controller: new Game.AI_fighter_bat(),
				team: "blue"
			});
			this.ships.push(Ship3);
		}

		this.translatedOffset = new Point(this.fieldSize.x/2, this.fieldSize.y/2);
		if (this.PlayerController.ship != null)
		{
			var playerCener = this.PlayerController.ship.shape.center;
			this.translatedOffset = new Point(-playerCener.x + this.fieldSize.x/2 , -playerCener.y + this.fieldSize.y/2);
		}
		this.layerShips.dom.canvas.ctx.translate(this.translatedOffset);

		this.fpsMeter();

		document.getElementById("btn_controll_left").onclick = function()
		{
			Controller.cruiseControll_left = !Controller.cruiseControll_left;
			Controller.updateCruiseButtons();
		};

		document.getElementById("btn_controll_right").onclick = function()
		{
			Controller.cruiseControll_right = !Controller.cruiseControll_right;
			Controller.updateCruiseButtons();
		};
	},

	updateCruiseButtons: function()
	{
		var spriteLeft = "url(textures/btnGreen.png)";
		var spriteRight = "url(textures/btnGreen.png)";

		if (Controller.cruiseControll_left)
			spriteLeft = "url(textures/btnGreenPress.png)";

		if (Controller.cruiseControll_right)
			spriteRight = "url(textures/btnGreenPress.png)";

		document.getElementById("btn_controll_left").style.backgroundImage = spriteLeft;
		document.getElementById("btn_controll_right").style.backgroundImage = spriteRight;
	},

	addLayersTranslate: function(point)
	{
		this.translatedOffset = new Point(this.translatedOffset.x - point.x, this.translatedOffset.y - point.y);
		this.layerShips.dom.canvas.ctx.translate(point, true);
	},

	killShip: function(ship)
	{
		var indx = -1;
		for (var i = 0; i<this.ships.length; i++)
		{
			if (this.ships[i] == ship)
			{
				indx = i;
				break;
			}
		}

		if (indx == -1)
		{
			console.warn("Ship not found to splice " + JSON.stringify(ship));
			return;
		}

		this.ships.splice(i, 1);
	},

	// Context not saved
	mouseClick: function()
	{
		// debug bullet
		return;

		var point = Controller.mouse.point.clone();

		point = new Point(point.x - Controller.translatedOffset.x, point.y - Controller.translatedOffset.y);

		new Game.Bullet(Controller.layerShips,
			{
				position: point,
				angle: -2,
				speed: 0.1,
				team: "yellow"
			});
	},

	drawBackground: function(ctx)
	{
		ctx.fillAll(
			ctx.createGradient(
			new Circle(this.fieldSize.x/2, this.fieldSize.y/2, this.fieldSize.x / 10),
			new Circle(this.fieldSize.x/2, this.fieldSize.y/2, this.fieldSize.x / 2), {
				'0.0': '#0C0038',
				'0.5': '#080028',
				'1.0': '#050019'
			})
		);

		new Game.GradientCircle(Controller.layerShips,
		{
			position: new Point(0, 0),
			radius: 500
		});
	},

	fpsMeter: function ()
	{
		var fps = atom.trace(), time = [], last = Date.now();

		atom.frame.add(function ()
		{
			if (time.length > 5) time.shift();

			time.push(Date.now() - last);
			last = Date.now();

			fps.value = Math.ceil(1000 / time.average()) + " FPS";
		});
	}
});<|endoftext|>


<commit_before>/**
 *
 * weatherunderground adapter
 *
 * Adapter loading the json forecast of weatherunderground
 *
 * note: you need an account and an api key to get the forecast. This is free for non excess usage: 500 requests/d
 * see: http://www.wunderground.com/weather/api/d/pricing
 *
 * register for a key:
 * http://www.wunderground.com/weather/api/d/questionnaire.html?plan=a&level=0&history=undefined
 *
 * see http://www.wunderground.com/weather/api/d/docs?d=data/hourly
 * for reference of the possible values from hourly WU forecast
 *
 */

"use strict";

var utils = require(__dirname + '/lib/utils'); // Get common adapter utils

var request = require('request');

var adapter = utils.adapter({
    name: 'weatherunderground',

    unload: function (callback) {
        adapter.log.info("adapter weatherunderground is unloading");
    },
    discover: function (callback) {
    },
    install: function (callback) {
        adapter.log.info("adapter weatherunderground installed");
    },
    uninstall: function (callback) {
        adapter.log.info("adapter weatherunderground UN-installed");
    },
    objectChange: function (id, obj) {
        adapter.log.info('objectChange ' + id + ' ' + JSON.stringify(obj));
    },
    stateChange: function (id, state) {
        adapter.log.info('stateChange ' + id + ' ' + JSON.stringify(state));
    },
    ready: function () {
        adapter.log.info("Adapter weatherunderground got 'Ready' Signal - starting scheduler to look for forecasts");
        checkWeatherVariables();
        getWuForecastData();
    },
    message: function (obj) {
    }
});

function getWuForecastData() {

    //debug

    var url = "http://api.wunderground.com/api/" + adapter.config.apikey + "/hourly/q/" + adapter.config.location + ".json";

    request({url: url, json: true}, function(error, response, body) {
        if (!error && response.statusCode === 200) {
            var qpf_sum = 0;
            var pop_max = 0;
            var uvi_sum = 0;

            for (var i = 0; i < 24; i++) {
                try {
                    //adapter.log.info("WU-Response Body: " + JSON.stringify(body.hourly_forecast[0].FCTTIME)); // Print the json response
                    //var forecast = JSON.parse(body.jsonData);
                    //adapter.log.info("version: " + body.response.version);
                    // see http://www.wunderground.com/weather/api/d/docs?d=resources/phrase-glossary for infos about properties and codes
                    adapter.setState("forecast." + i + "h.time", {ack: true, val: body.hourly_forecast[i].FCTTIME.pretty});
                    adapter.setState("forecast." + i + "h.temp", {ack: true, val: body.hourly_forecast[i].temp.metric});
                    adapter.setState("forecast." + i + "h.fctcode", {ack: true, val: body.hourly_forecast[i].fctcode}); //forecast description number -> see link above
                    adapter.setState("forecast." + i + "h.sky", {ack: true, val: body.hourly_forecast[i].sky}); //?
                    adapter.setState("forecast." + i + "h.wspd", {ack: true, val: body.hourly_forecast[i].wspd.metric}); // windspeed in kmh
                    adapter.setState("forecast." + i + "h.wdir", {ack: true, val: body.hourly_forecast[i].wdir.degrees}); //wind dir in degrees
                    adapter.setState("forecast." + i + "h.uvi", {ack: true, val: body.hourly_forecast[i].uvi}); //UV Index -> wikipedia
                    adapter.setState("forecast." + i + "h.humidity", {ack: true, val: body.hourly_forecast[i].humidity});
                    adapter.setState("forecast." + i + "h.heatindex", {ack: true, val: body.hourly_forecast[i].heatindex.metric}); // -> wikipedia
                    adapter.setState("forecast." + i + "h.feelslike", {ack: true, val: body.hourly_forecast[i].feelslike.metric}); // -> wikipedia
                    adapter.setState("forecast." + i + "h.qpf", {ack: true, val: body.hourly_forecast[i].qpf.metric}); // Quantitative precipitation forecast
                    adapter.setState("forecast." + i + "h.snow", {ack: true, val: body.hourly_forecast[i].snow.metric});
                    adapter.setState("forecast." + i + "h.pop", {ack: true, val: body.hourly_forecast[i].pop}); // probability of Precipitation
                    adapter.setState("forecast." + i + "h.mslp", {ack: true, val: body.hourly_forecast[i].mslp.metric}); // mean sea level pressure

                    qpf_sum += Number(body.hourly_forecast[i].qpf.metric);
                    uvi_sum += Number(body.hourly_forecast[i].uvi);
                    if (Number(body.hourly_forecast[i].uvi) > pop_max) {
                        pop_max = Number(body.hourly_forecast[i].uvi);
                    }

                    // 6h
                    if (i == 5) {
                        adapter.setState("forecast.6h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.6h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.6h.sum.uvi", {ack: true, val: uvi_sum/6});
                    }
                    // 12h
                    if (i == 11) {
                        adapter.setState("forecast.12h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.12h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.12h.sum.uvi", {ack: true, val: uvi_sum/12});
                    }
                    // 24h
                    if (i == 23) {
                        adapter.setState("forecast.24h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.24h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.24h.sum.uvi", {ack: true, val: uvi_sum/24});
                    }
                } catch (error) {
                    adapter.log.error("Could not parse Forecast-Data: " + error);
                }
            }
            adapter.log.info("all forecast values set");
        } else
        {
            // ERROR
            adapter.log.error("Wunderground reported an error: " + error);
        }
    });
}

function checkWeatherVariables() {
    adapter.log.info("init forecast variables", 'info');

    ['time','temp','fctcode','sky','wspd','wdir','uvi','humidity','heatindex','feelslike','qpf','snow','pop','mslp'].map( function(v) {
        for (var i = 0; i < 24; i++) {
            var name = "forecast." + i + "h." + v;
            if (adapter.getState(name) === null) {
                var obj = {
                    type: 'state',
                    common: {name: v, read: true, write: true, type: 'number'},
                    native: {id: name}
                };
                adapter.setObjectNotExists(name, obj);
            }
        }
    });
    ['forecast.6h.sum.qpf','forecast.12h.sum.qpf','forecast.24h.sum.qpf',
        'forecast.6h.sum.pop', 'forecast.12h.sum.pop', 'forecast.24h.sum.pop',
        'forecast.6h.sum.uvi','forecast.12h.sum.uvi','forecast.24h.sum.uvi'].map( function(name) {
            if (adapter.getState(name) === null) {
                var obj = {
                    type: 'state',
                    common: {name: name, read: true, write: true, type: 'number'},
                    native: {id: name}
                };
                adapter.setObjectNotExists(name, obj);
            }
        });
}

<commit_msg>initial version<commit_after>/**
 *
 * weatherunderground adapter
 *
 * Adapter loading the json forecast of weatherunderground
 *
 * note: you need an account and an api key to get the forecast. This is free for non excess usage: 500 requests/d
 * see: http://www.wunderground.com/weather/api/d/pricing
 *
 * register for a key:
 * http://www.wunderground.com/weather/api/d/questionnaire.html?plan=a&level=0&history=undefined
 *
 * see http://www.wunderground.com/weather/api/d/docs?d=data/hourly
 * for reference of the possible values from hourly WU forecast
 *
 */

"use strict";

var utils = require(__dirname + '/lib/utils'); // Get common adapter utils

var request = require('request');

var adapter = utils.adapter({
    name: 'weatherunderground',

    unload: function (callback) {
        adapter.log.info("adapter weatherunderground is unloading");
    },
    discover: function (callback) {
    },
    install: function (callback) {
        adapter.log.info("adapter weatherunderground installed");
    },
    uninstall: function (callback) {
        adapter.log.info("adapter weatherunderground UN-installed");
    },
    objectChange: function (id, obj) {
        adapter.log.info('objectChange ' + id + ' ' + JSON.stringify(obj));
    },
    stateChange: function (id, state) {
        adapter.log.info('stateChange ' + id + ' ' + JSON.stringify(state));
    },
    ready: function () {
        adapter.log.info("Adapter weatherunderground got 'Ready' Signal - starting scheduler to look for forecasts");
        checkWeatherVariables();
        getWuForecastData();
    },
    message: function (obj) {
    }
});

function getWuForecastData() {

    //debug

    var url = "http://api.wunderground.com/api/" + adapter.config.apikey + "/hourly/q/" + adapter.config.location + ".json";

    request({url: url, json: true}, function(error, response, body) {
        if (!error && response.statusCode === 200) {
            var qpf_sum = 0;
            var pop_max = 0;
            var uvi_sum = 0;

            for (var i = 0; i < 24; i++) {
                try {
                    //adapter.log.info("WU-Response Body: " + JSON.stringify(body.hourly_forecast[0].FCTTIME)); // Print the json response
                    //var forecast = JSON.parse(body.jsonData);
                    //adapter.log.info("version: " + body.response.version);
                    // see http://www.wunderground.com/weather/api/d/docs?d=resources/phrase-glossary for infos about properties and codes
                    adapter.setState("forecast." + i + "h.time", {ack: true, val: body.hourly_forecast[i].FCTTIME.pretty});
                    adapter.setState("forecast." + i + "h.temp", {ack: true, val: body.hourly_forecast[i].temp.metric});
                    adapter.setState("forecast." + i + "h.fctcode", {ack: true, val: body.hourly_forecast[i].fctcode}); //forecast description number -> see link above
                    adapter.setState("forecast." + i + "h.sky", {ack: true, val: body.hourly_forecast[i].sky}); //?
                    adapter.setState("forecast." + i + "h.wspd", {ack: true, val: body.hourly_forecast[i].wspd.metric}); // windspeed in kmh
                    adapter.setState("forecast." + i + "h.wdir", {ack: true, val: body.hourly_forecast[i].wdir.degrees}); //wind dir in degrees
                    adapter.setState("forecast." + i + "h.uvi", {ack: true, val: body.hourly_forecast[i].uvi}); //UV Index -> wikipedia
                    adapter.setState("forecast." + i + "h.humidity", {ack: true, val: body.hourly_forecast[i].humidity});
                    adapter.setState("forecast." + i + "h.heatindex", {ack: true, val: body.hourly_forecast[i].heatindex.metric}); // -> wikipedia
                    adapter.setState("forecast." + i + "h.feelslike", {ack: true, val: body.hourly_forecast[i].feelslike.metric}); // -> wikipedia
                    adapter.setState("forecast." + i + "h.qpf", {ack: true, val: body.hourly_forecast[i].qpf.metric}); // Quantitative precipitation forecast
                    adapter.setState("forecast." + i + "h.snow", {ack: true, val: body.hourly_forecast[i].snow.metric});
                    adapter.setState("forecast." + i + "h.pop", {ack: true, val: body.hourly_forecast[i].pop}); // probability of Precipitation
                    adapter.setState("forecast." + i + "h.mslp", {ack: true, val: body.hourly_forecast[i].mslp.metric}); // mean sea level pressure

                    qpf_sum += Number(body.hourly_forecast[i].qpf.metric);
                    uvi_sum += Number(body.hourly_forecast[i].uvi);
                    if (Number(body.hourly_forecast[i].uvi) > pop_max) {
                        pop_max = Number(body.hourly_forecast[i].uvi);
                    }

                    // 6h
                    if (i == 5) {
                        adapter.setState("forecast.6h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.6h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.6h.sum.uvi", {ack: true, val: uvi_sum/6});
                    }
                    // 12h
                    if (i == 11) {
                        adapter.setState("forecast.12h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.12h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.12h.sum.uvi", {ack: true, val: uvi_sum/12});
                    }
                    // 24h
                    if (i == 23) {
                        adapter.setState("forecast.24h.sum.qpf", {ack: true, val: qpf_sum});
                        adapter.setState("forecast.24h.sum.pop", {ack: true, val: pop_max});
                        adapter.setState("forecast.24h.sum.uvi", {ack: true, val: uvi_sum/24});
                    }
                } catch (error) {
                    adapter.log.error("Could not parse Forecast-Data: " + error);
                }
            }
            adapter.log.info("all forecast values set");
        } else
        {
            // ERROR
            adapter.log.error("Wunderground reported an error: " + error);
        }
    });
}

function checkWeatherVariables() {
    adapter.log.info("init forecast variables", 'info');

    ['time','temp','fctcode','sky','wspd','wdir','uvi','humidity','heatindex','feelslike','qpf','snow','pop','mslp'].map( function(v) {
        for (var i = 0; i < 24; i++) {
            var name = "forecast." + i + "h." + v;
            if (adapter.getState(name) === null) {
                var obj = {
                    type: 'state',
                    common: {name: v, read: true, write: true, type: 'number'},
                    native: {id: name}
                };
                adapter.setObjectNotExists(name, obj);
                adapter.log.info("created object: " + name);
            }
        }
    });
    ['forecast.6h.sum.qpf','forecast.12h.sum.qpf','forecast.24h.sum.qpf',
        'forecast.6h.sum.pop', 'forecast.12h.sum.pop', 'forecast.24h.sum.pop',
        'forecast.6h.sum.uvi','forecast.12h.sum.uvi','forecast.24h.sum.uvi'].map( function(name) {
            if (adapter.getState(name) === null) {
                var obj = {
                    type: 'state',
                    common: {name: name, read: true, write: true, type: 'number'},
                    native: {id: name}
                };
                adapter.setObjectNotExists(name, obj);
            }
        });
}

<|endoftext|>


<commit_before>/**
 * Insight search plugin
 * @author PPOffice { @link https://github.com/ppoffice }
 */
(function ($, CONFIG) {
    var $main = $('.ins-search');
    var $input = $main.find('.ins-search-input');
    var $wrapper = $main.find('.ins-section-wrapper');
    var $container = $main.find('.ins-section-container');
    $main.parent().remove('.ins-search');
    $('body').append($main);

    function section (title) {
        return $('<section>').addClass('ins-section')
            .append($('<header>').addClass('ins-section-header').text(title));
    }

    function searchItem (icon, title, slug, preview, url) {
        return $('<div>').addClass('ins-selectable').addClass('ins-search-item')
            .append($('<header>').append($('<i>').addClass('fa').addClass('fa-' + icon)).append(title != null && title != '' ? title : CONFIG.TRANSLATION['UNTITLED'])
                .append(slug ? $('<span>').addClass('ins-slug').text(slug) : null))
            .append(preview ? $('<p>').addClass('ins-search-preview').text(preview) : null)
            .attr('data-url', url);
    }

    function sectionFactory (type, array) {
        var sectionTitle;
        var $searchItems;
        if (array.length === 0) return null;
        sectionTitle = CONFIG.TRANSLATION[type];
        switch (type) {
            case 'POSTS':
            case 'PAGES':
                $searchItems = array.map(function (item) {
                    // Use config.root instead of permalink to fix url issue
                    return searchItem('file', item.title, null, item.text.slice(0, 150), CONFIG.ROOT_URL + item.path);
                });
                break;
            case 'CATEGORIES':
            case 'TAGS':
                $searchItems = array.map(function (item) {
                    return searchItem(type === 'CATEGORIES' ? 'folder' : 'tag', item.name, item.slug, null, item.permalink);
                });
                break;
            default:
                return null;
        }
        return section(sectionTitle).append($searchItems);
    }

    function extractToSet (json, key) {
        var values = {};
        var entries = json.pages.concat(json.posts);
        entries.forEach(function (entry) {
            if (entry[key]) {
                entry[key].forEach(function (value) {
                    values[value.name] = value;
                });
            }
        });
        var result = [];
        for (var key in values) {
            result.push(values[key]);
        }
        return result;
    }

    function parseKeywords (keywords) {
        return keywords.split(' ').filter(function (keyword) {
            return !!keyword;
        }).map(function (keyword) {
            return keyword.toUpperCase();
        });
    }

    /**
     * Judge if a given post/page/category/tag contains all of the keywords.
     * @param Object            obj     Object to be weighted
     * @param Array<String>     fields  Object's fields to find matches
     */
    function filter (keywords, obj, fields) {
        var result = false;
        var keywordArray = parseKeywords(keywords);
        var containKeywords = keywordArray.filter(function (keyword) {
            var containFields = fields.filter(function (field) {
                if (!obj.hasOwnProperty(field))
                    return false;
                if (obj[field].toUpperCase().indexOf(keyword) > -1)
                    return true;
            });
            if (containFields.length > 0)
                return true;
            return false;
        });
        return containKeywords.length === keywordArray.length;
    }

    function filterFactory (keywords) {
        return {
            POST: function (obj) {
                return filter(keywords, obj, ['title', 'text']);
            },
            PAGE: function (obj) {
                return filter(keywords, obj, ['title', 'text']);
            },
            CATEGORY: function (obj) {
                return filter(keywords, obj, ['name', 'slug']);
            },
            TAG: function (obj) {
                return filter(keywords, obj, ['name', 'slug']);
            }
        };
    }

    /**
     * Calculate the weight of a matched post/page/category/tag.
     * @param Object            obj     Object to be weighted
     * @param Array<String>     fields  Object's fields to find matches
     * @param Array<Integer>    weights Weight of every field
     */
    function weight (keywords, obj, fields, weights) {
        var value = 0;
        parseKeywords(keywords).forEach(function (keyword) {
            var pattern = new RegExp(keyword, 'img'); // Global, Multi-line, Case-insensitive
            fields.forEach(function (field, index) {
                if (obj.hasOwnProperty(field)) {
                    var matches = obj[field].match(pattern);
                    value += matches ? matches.length * weights[index] : 0;
                }
            });
        });
        return value;
    }

    function weightFactory (keywords) {
        return {
            POST: function (obj) {
                return weight(keywords, obj, ['title', 'text'], [3, 1]);
            },
            PAGE: function (obj) {
                return weight(keywords, obj, ['title', 'text'], [3, 1]);
            },
            CATEGORY: function (obj) {
                return weight(keywords, obj, ['name', 'slug'], [1, 1]);
            },
            TAG: function (obj) {
                return weight(keywords, obj, ['name', 'slug'], [1, 1]);
            }
        };
    }

    function search (json, keywords) {
        var WEIGHTS = weightFactory(keywords);
        var FILTERS = filterFactory(keywords);
        var posts = json.posts;
        var pages = json.pages;
        var tags = extractToSet(json, 'tags');
        var categories = extractToSet(json, 'categories');
        return {
            posts: posts.filter(FILTERS.POST).sort(function (a, b) { return WEIGHTS.POST(b) - WEIGHTS.POST(a); }).slice(0, 5),
            pages: pages.filter(FILTERS.PAGE).sort(function (a, b) { return WEIGHTS.PAGE(b) - WEIGHTS.PAGE(a); }).slice(0, 5),
            categories: categories.filter(FILTERS.CATEGORY).sort(function (a, b) { return WEIGHTS.CATEGORY(b) - WEIGHTS.CATEGORY(a); }).slice(0, 5),
            tags: tags.filter(FILTERS.TAG).sort(function (a, b) { return WEIGHTS.TAG(b) - WEIGHTS.TAG(a); }).slice(0, 5)
        };
    }

    function searchResultToDOM (searchResult) {
        $container.empty();
        for (var key in searchResult) {
            $container.append(sectionFactory(key.toUpperCase(), searchResult[key]));
        }
    }

    function scrollTo ($item) {
        if ($item.length === 0) return;
        var wrapperHeight = $wrapper[0].clientHeight;
        var itemTop = $item.position().top - $wrapper.scrollTop();
        var itemBottom = $item[0].clientHeight + $item.position().top;
        if (itemBottom > wrapperHeight + $wrapper.scrollTop()) {
            $wrapper.scrollTop(itemBottom - $wrapper[0].clientHeight);
        }
        if (itemTop < 0) {
            $wrapper.scrollTop($item.position().top);
        }
    }

    function selectItemByDiff (value) {
        var $items = $.makeArray($container.find('.ins-selectable'));
        var prevPosition = -1;
        $items.forEach(function (item, index) {
            if ($(item).hasClass('active')) {
                prevPosition = index;
                return;
            }
        });
        var nextPosition = ($items.length + prevPosition + value) % $items.length;
        $($items[prevPosition]).removeClass('active');
        $($items[nextPosition]).addClass('active');
        scrollTo($($items[nextPosition]));
    }

    function gotoLink ($item) {
        if ($item && $item.length) {
            location.href = $item.attr('data-url');
        }
    }

    $.getJSON(CONFIG.CONTENT_URL, function (json) {
        if (location.hash.trim() === '#ins-search') {
            $main.addClass('show');
        }
        $input.on('input', function () {
            var keywords = $(this).val();
            searchResultToDOM(search(json, keywords));
        });
        $input.trigger('input');
    });

    $(document).on('click focus', '.search-form-input', function () {
        $main.addClass('show');
        $main.find('.ins-search-input').focus();
    }).on('click', '.ins-search-item', function () {
        gotoLink($(this));
    }).on('click', '.ins-close', function () {
        $main.removeClass('show');
    }).on('keydown', function (e) {
        if (!$main.hasClass('show')) return;
        switch (e.keyCode) {
            case 27: // ESC
                $main.removeClass('show'); break;
            case 38: // UP
                selectItemByDiff(-1); break;
            case 40: // DOWN
                selectItemByDiff(1); break;
            case 13: //ENTER
                gotoLink($container.find('.ins-selectable.active').eq(0)); break;
        }
    });
})(jQuery, window.INSIGHT_CONFIG);<commit_msg>fix(search): html entity does not display correctly in insight search items<commit_after>/**
 * Insight search plugin
 * @author PPOffice { @link https://github.com/ppoffice }
 */
(function ($, CONFIG) {
    var $main = $('.ins-search');
    var $input = $main.find('.ins-search-input');
    var $wrapper = $main.find('.ins-section-wrapper');
    var $container = $main.find('.ins-section-container');
    $main.parent().remove('.ins-search');
    $('body').append($main);

    // https://stackoverflow.com/questions/1147359/how-to-decode-html-entities-using-jquery#answer-1395954
    function decodeEntities(encodedString) {
        var textArea = document.createElement('textarea');
        textArea.innerHTML = encodedString;
        return textArea.value;
    }

    function section (title) {
        return $('<section>').addClass('ins-section')
            .append($('<header>').addClass('ins-section-header').text(title));
    }

    function searchItem (icon, title, slug, preview, url) {
        return $('<div>').addClass('ins-selectable').addClass('ins-search-item')
            .append($('<header>').append($('<i>').addClass('fa').addClass('fa-' + icon)).append(title != null && title != '' ? title : CONFIG.TRANSLATION['UNTITLED'])
                .append(slug ? $('<span>').addClass('ins-slug').text(slug) : null))
            .append(preview ? $('<p>').addClass('ins-search-preview').text(decodeEntities(preview)) : null)
            .attr('data-url', url);
    }

    function sectionFactory (type, array) {
        var sectionTitle;
        var $searchItems;
        if (array.length === 0) return null;
        sectionTitle = CONFIG.TRANSLATION[type];
        switch (type) {
            case 'POSTS':
            case 'PAGES':
                $searchItems = array.map(function (item) {
                    // Use config.root instead of permalink to fix url issue
                    return searchItem('file', item.title, null, item.text.slice(0, 150), CONFIG.ROOT_URL + item.path);
                });
                break;
            case 'CATEGORIES':
            case 'TAGS':
                $searchItems = array.map(function (item) {
                    return searchItem(type === 'CATEGORIES' ? 'folder' : 'tag', item.name, item.slug, null, item.permalink);
                });
                break;
            default:
                return null;
        }
        return section(sectionTitle).append($searchItems);
    }

    function extractToSet (json, key) {
        var values = {};
        var entries = json.pages.concat(json.posts);
        entries.forEach(function (entry) {
            if (entry[key]) {
                entry[key].forEach(function (value) {
                    values[value.name] = value;
                });
            }
        });
        var result = [];
        for (var key in values) {
            result.push(values[key]);
        }
        return result;
    }

    function parseKeywords (keywords) {
        return keywords.split(' ').filter(function (keyword) {
            return !!keyword;
        }).map(function (keyword) {
            return keyword.toUpperCase();
        });
    }

    /**
     * Judge if a given post/page/category/tag contains all of the keywords.
     * @param Object            obj     Object to be weighted
     * @param Array<String>     fields  Object's fields to find matches
     */
    function filter (keywords, obj, fields) {
        var result = false;
        var keywordArray = parseKeywords(keywords);
        var containKeywords = keywordArray.filter(function (keyword) {
            var containFields = fields.filter(function (field) {
                if (!obj.hasOwnProperty(field))
                    return false;
                if (obj[field].toUpperCase().indexOf(keyword) > -1)
                    return true;
            });
            if (containFields.length > 0)
                return true;
            return false;
        });
        return containKeywords.length === keywordArray.length;
    }

    function filterFactory (keywords) {
        return {
            POST: function (obj) {
                return filter(keywords, obj, ['title', 'text']);
            },
            PAGE: function (obj) {
                return filter(keywords, obj, ['title', 'text']);
            },
            CATEGORY: function (obj) {
                return filter(keywords, obj, ['name', 'slug']);
            },
            TAG: function (obj) {
                return filter(keywords, obj, ['name', 'slug']);
            }
        };
    }

    /**
     * Calculate the weight of a matched post/page/category/tag.
     * @param Object            obj     Object to be weighted
     * @param Array<String>     fields  Object's fields to find matches
     * @param Array<Integer>    weights Weight of every field
     */
    function weight (keywords, obj, fields, weights) {
        var value = 0;
        parseKeywords(keywords).forEach(function (keyword) {
            var pattern = new RegExp(keyword, 'img'); // Global, Multi-line, Case-insensitive
            fields.forEach(function (field, index) {
                if (obj.hasOwnProperty(field)) {
                    var matches = obj[field].match(pattern);
                    value += matches ? matches.length * weights[index] : 0;
                }
            });
        });
        return value;
    }

    function weightFactory (keywords) {
        return {
            POST: function (obj) {
                return weight(keywords, obj, ['title', 'text'], [3, 1]);
            },
            PAGE: function (obj) {
                return weight(keywords, obj, ['title', 'text'], [3, 1]);
            },
            CATEGORY: function (obj) {
                return weight(keywords, obj, ['name', 'slug'], [1, 1]);
            },
            TAG: function (obj) {
                return weight(keywords, obj, ['name', 'slug'], [1, 1]);
            }
        };
    }

    function search (json, keywords) {
        var WEIGHTS = weightFactory(keywords);
        var FILTERS = filterFactory(keywords);
        var posts = json.posts;
        var pages = json.pages;
        var tags = extractToSet(json, 'tags');
        var categories = extractToSet(json, 'categories');
        return {
            posts: posts.filter(FILTERS.POST).sort(function (a, b) { return WEIGHTS.POST(b) - WEIGHTS.POST(a); }).slice(0, 5),
            pages: pages.filter(FILTERS.PAGE).sort(function (a, b) { return WEIGHTS.PAGE(b) - WEIGHTS.PAGE(a); }).slice(0, 5),
            categories: categories.filter(FILTERS.CATEGORY).sort(function (a, b) { return WEIGHTS.CATEGORY(b) - WEIGHTS.CATEGORY(a); }).slice(0, 5),
            tags: tags.filter(FILTERS.TAG).sort(function (a, b) { return WEIGHTS.TAG(b) - WEIGHTS.TAG(a); }).slice(0, 5)
        };
    }

    function searchResultToDOM (searchResult) {
        $container.empty();
        for (var key in searchResult) {
            $container.append(sectionFactory(key.toUpperCase(), searchResult[key]));
        }
    }

    function scrollTo ($item) {
        if ($item.length === 0) return;
        var wrapperHeight = $wrapper[0].clientHeight;
        var itemTop = $item.position().top - $wrapper.scrollTop();
        var itemBottom = $item[0].clientHeight + $item.position().top;
        if (itemBottom > wrapperHeight + $wrapper.scrollTop()) {
            $wrapper.scrollTop(itemBottom - $wrapper[0].clientHeight);
        }
        if (itemTop < 0) {
            $wrapper.scrollTop($item.position().top);
        }
    }

    function selectItemByDiff (value) {
        var $items = $.makeArray($container.find('.ins-selectable'));
        var prevPosition = -1;
        $items.forEach(function (item, index) {
            if ($(item).hasClass('active')) {
                prevPosition = index;
                return;
            }
        });
        var nextPosition = ($items.length + prevPosition + value) % $items.length;
        $($items[prevPosition]).removeClass('active');
        $($items[nextPosition]).addClass('active');
        scrollTo($($items[nextPosition]));
    }

    function gotoLink ($item) {
        if ($item && $item.length) {
            location.href = $item.attr('data-url');
        }
    }

    $.getJSON(CONFIG.CONTENT_URL, function (json) {
        if (location.hash.trim() === '#ins-search') {
            $main.addClass('show');
        }
        $input.on('input', function () {
            var keywords = $(this).val();
            searchResultToDOM(search(json, keywords));
        });
        $input.trigger('input');
    });

    $(document).on('click focus', '.search-form-input', function () {
        $main.addClass('show');
        $main.find('.ins-search-input').focus();
    }).on('click', '.ins-search-item', function () {
        gotoLink($(this));
    }).on('click', '.ins-close', function () {
        $main.removeClass('show');
    }).on('keydown', function (e) {
        if (!$main.hasClass('show')) return;
        switch (e.keyCode) {
            case 27: // ESC
                $main.removeClass('show'); break;
            case 38: // UP
                selectItemByDiff(-1); break;
            case 40: // DOWN
                selectItemByDiff(1); break;
            case 13: //ENTER
                gotoLink($container.find('.ins-selectable.active').eq(0)); break;
        }
    });
})(jQuery, window.INSIGHT_CONFIG);<|endoftext|>


<commit_before>const { Knorm } = require('@knorm/knorm');

class KnormTimestamps {
  constructor({ createdAt = {}, updatedAt = {}, name = 'timestamps' } = {}) {
    this.name = name;

    this.fields = {};
    this.fields[createdAt.name || 'createdAt'] = {
      type: 'dateTime',
      column: createdAt.column || 'created_at',
      default: () => new Date(),
      updated: false
    };
    this.updatedAtFieldName = updatedAt.name || 'updatedAt';
    this.fields[this.updatedAtFieldName] = {
      type: 'dateTime',
      column: updatedAt.column || 'updated_at',
      default: () => new Date()
    };
  }

  updateModel(knorm) {
    knorm.Model = class TimestampsModel extends knorm.Model {};
    knorm.Model.fields = this.fields;
  }

  updateQuery(knorm) {
    const { updatedAtFieldName } = this;
    class TimestampsQuery extends knorm.Query {
      async update(data, options) {
        if (data) {
          (Array.isArray(data) ? data : [data]).forEach(data => {
            data[updatedAtFieldName] = new Date();
          });
        }
        return super.update(data, options);
      }
    }
    knorm.Model.Query = knorm.Query = TimestampsQuery;
  }

  init(knorm) {
    if (!knorm) {
      throw new this.constructor.KnormTimestampsError(
        'no Knorm instance provided'
      );
    }

    if (!(knorm instanceof Knorm)) {
      throw new this.constructor.KnormTimestampsError(
        'invalid Knorm instance provided'
      );
    }

    this.updateModel(knorm);
    this.updateQuery(knorm);
  }
}

KnormTimestamps.KnormTimestampsError = class KnormTimestampsError extends Knorm.KnormError {};

module.exports = KnormTimestamps;
<commit_msg>refactor: use knorm helpers to update classes<commit_after>const { Knorm } = require('@knorm/knorm');

class KnormTimestamps {
  constructor({ createdAt = {}, updatedAt = {}, name = 'timestamps' } = {}) {
    this.name = name;

    this.fields = {};
    this.fields[createdAt.name || 'createdAt'] = {
      type: 'dateTime',
      column: createdAt.column || 'created_at',
      default: () => new Date(),
      updated: false
    };
    this.updatedAtFieldName = updatedAt.name || 'updatedAt';
    this.fields[this.updatedAtFieldName] = {
      type: 'dateTime',
      column: updatedAt.column || 'updated_at',
      default: () => new Date()
    };
  }

  updateModel(knorm) {
    class TimestampsModel extends knorm.Model {}

    TimestampsModel.fields = this.fields;

    knorm.updateModel(TimestampsModel);
  }

  updateQuery(knorm) {
    const { updatedAtFieldName } = this;

    class TimestampsQuery extends knorm.Query {
      async update(data, options) {
        if (data) {
          (Array.isArray(data) ? data : [data]).forEach(data => {
            data[updatedAtFieldName] = new Date();
          });
        }
        return super.update(data, options);
      }
    }

    knorm.updateQuery(TimestampsQuery);
  }

  init(knorm) {
    if (!knorm) {
      throw new this.constructor.KnormTimestampsError(
        'no Knorm instance provided'
      );
    }

    if (!(knorm instanceof Knorm)) {
      throw new this.constructor.KnormTimestampsError(
        'invalid Knorm instance provided'
      );
    }

    this.updateModel(knorm);
    this.updateQuery(knorm);
  }
}

KnormTimestamps.KnormTimestampsError = class KnormTimestampsError extends Knorm.KnormError {};

module.exports = KnormTimestamps;
<|endoftext|>