<commit_before>/**
 * Iterates over a list of elements, yielding each in turn to an iterate function.
 */

//var arr = ['a','b','c'];
//
//each(arr, function(item, index, list) {
//    console.log('VAL >', item, index, list);
//});
//
//each(arr, {name: "John"}, function(item, index, list, params, next) {
//    console.log('ITEM >', item, index, list, params)
//    next();
//}, function(err){
//    if(err) {
//        console.log('err', err);
//        return;
//    }
//    console.log('done');
//});
define('each', function () {

    var regex = /([^\s,]+)/g;

    function getParamNames(fn) {
        var funStr = fn.toString();
        return funStr.slice(funStr.indexOf('(') + 1, funStr.indexOf(')')).match(regex);
    }

    function each(list) {
        var params, handler, done, progress;
        if(typeof arguments[1] === 'function') {
            handler = arguments[1];
            done = arguments[2];
            progress = arguments[2];
        } else {
            params = arguments[1] === null || arguments[1] === undefined ? {} : arguments[1];
            handler = arguments[2];
            done = arguments[3];
            progress = arguments[4];
        }

        if (!list) {
            if (done) {
                done(undefined, list, params);// we complete immediately if there is no list.
            }
            return;
        }

        // var fnDesc = handler.toString();
        var next;
        var index = 0;
        var returnVal;
        var paramNames = getParamNames(handler);
        var keys;
        var len;

        if (list.length === undefined) {
            keys = Object.keys(list);
            len = keys.length;
        }

        // allow params to modify the loop directly if they have a = in front of them.
        // start the loop part way through or so on.
        // Future feature: to have it set the starting index.
        //if (params && params['=index']) {
        //    index = params['=index'];
        //}

        var iterate = function () {
            // use list length. in case they remove or add items.
            len = keys ? len : list.length;
            if (index < len) {
                try {
                    if(params) {
                        returnVal = handler(keys ? list[keys[index]] : list[index], keys ? keys[index] : index, list, params, next);
                    } else {
                        returnVal = handler(keys ? list[keys[index]] : list[index], keys ? keys[index] : index, list, next);
                    }
                } catch(e) {
                    if (done) {
                        done(e, list, params);
                    } else {
                        throw e;// non async methods need to show the error.
                    }
                }
                // if return true then exit the loop.
                if (returnVal !== undefined) {
                    iterate = null;
                    if (done) {
                        done(returnVal, list, params);
                        return;
                    }
                    return returnVal;
                }
                if (!next) {
                    index += 1;// only if synchronous increment here.
                    iterate();
                }
            } else if (typeof done === 'function') {
                iterate = null;
                done(null, list, params);
            }
        };

        var now = Date.now();
        var limitIndex = 0;
        /**
         * Allow to process withing a ms threshold.
         * Example would be iterate as many as possible within a 10ms threshold.
         * This makes the async loop faster than 1 frame wait for each item with a 0 timeout.
         * @param {Number=} threshold
         * @param {Number=} max number of items to process before coming up for air.
         */
        function iter(threshold, limit) {
            var current;
            index += 1;// if asynchronous increment here.
            if (threshold || limit) {
                limit = limit || 500;
                current = Date.now();
                if (current < now + threshold && (!limit || index - limitIndex > limit)) {
                    limitIndex = index;
                    iterate();
                    return;
                }
                if (progress) {
                    progress(index, len);
                }
                now = current;
            }
            setTimeout(iterate, 0);
        }

        if(params) {
            if(paramNames && paramNames.length === 5) {
                next = iter;
            }
        } else {
            if(paramNames && paramNames.length === 4) {
                next = iter;
            }
        }

        var syncReturnVal = iterate();
        if (syncReturnVal !== undefined) {
            return syncReturnVal;
        }
        if (!done && params) {
            return params;
        }
    }

    return each;
});
<commit_msg>fix limit on each it was not working correctly.<commit_after>/**
 * Iterates over a list of elements, yielding each in turn to an iterate function.
 */

//var arr = ['a','b','c'];
//
//each(arr, function(item, index, list) {
//    console.log('VAL >', item, index, list);
//});
//
//each(arr, {name: "John"}, function(item, index, list, params, next) {
//    console.log('ITEM >', item, index, list, params)
//    next();
//}, function(err){
//    if(err) {
//        console.log('err', err);
//        return;
//    }
//    console.log('done');
//});
define('each', function () {

    var regex = /([^\s,]+)/g;

    function getParamNames(fn) {
        var funStr = fn.toString();
        return funStr.slice(funStr.indexOf('(') + 1, funStr.indexOf(')')).match(regex);
    }

    function each(list) {
        var params, handler, done, progress;
        if(typeof arguments[1] === 'function') {
            handler = arguments[1];
            done = arguments[2];
            progress = arguments[2];
        } else {
            params = arguments[1] === null || arguments[1] === undefined ? {} : arguments[1];
            handler = arguments[2];
            done = arguments[3];
            progress = arguments[4];
        }

        if (!list) {
            if (done) {
                done(undefined, list, params);// we complete immediately if there is no list.
            }
            return;
        }

        // var fnDesc = handler.toString();
        var next;
        var index = 0;
        var returnVal;
        var paramNames = getParamNames(handler);
        var keys;
        var len;

        if (list.length === undefined) {
            keys = Object.keys(list);
            len = keys.length;
        }

        // allow params to modify the loop directly if they have a = in front of them.
        // start the loop part way through or so on.
        // Future feature: to have it set the starting index.
        //if (params && params['=index']) {
        //    index = params['=index'];
        //}

        var iterate = function () {
            // use list length. in case they remove or add items.
            len = keys ? len : list.length;
            if (index < len) {
                try {
                    if(params) {
                        returnVal = handler(keys ? list[keys[index]] : list[index], keys ? keys[index] : index, list, params, next);
                    } else {
                        returnVal = handler(keys ? list[keys[index]] : list[index], keys ? keys[index] : index, list, next);
                    }
                } catch(e) {
                    if (done) {
                        done(e, list, params);
                    } else {
                        throw e;// non async methods need to show the error.
                    }
                }
                // if return true then exit the loop.
                if (returnVal !== undefined) {
                    iterate = null;
                    if (done) {
                        done(returnVal, list, params);
                        return;
                    }
                    return returnVal;
                }
                if (!next) {
                    index += 1;// only if synchronous increment here.
                    iterate();
                }
            } else if (typeof done === 'function') {
                iterate = null;
                done(null, list, params);
            }
        };

        var now = Date.now();
        var limitIndex = 0;
        /**
         * Allow to process withing a ms threshold.
         * Example would be iterate as many as possible within a 10ms threshold.
         * This makes the async loop faster than 1 frame wait for each item with a 0 timeout.
         * @param {Number=} threshold
         * @param {Number=} max number of items to process before coming up for air.
         */
        function iter(threshold, limit) {
            var current;
            index += 1;// if asynchronous increment here.
            if (threshold || limit) {
                limit = limit || 500;
                current = Date.now();
                if (current < now + threshold && (!limit || index - limitIndex < limit)) {
                    iterate();
                    return;
                }
                if (progress) {
                    progress(index, len);
                }
                limitIndex = index;
                now = current;
            }
            setTimeout(iterate, 0);
        }

        if(params) {
            if(paramNames && paramNames.length === 5) {
                next = iter;
            }
        } else {
            if(paramNames && paramNames.length === 4) {
                next = iter;
            }
        }

        var syncReturnVal = iterate();
        if (syncReturnVal !== undefined) {
            return syncReturnVal;
        }
        if (!done && params) {
            return params;
        }
    }

    return each;
});
<|endoftext|>


<commit_before>import { createStore } from 'redux';

import prog from './prog';

const deconstruct = function(root) {
    if (root === null || root === undefined) {
        return null;
    }
    var nodes = [];
    var index = 0;
    var traverse = function (obj, parent = -1) {
        const id = index++;
        const result = { parent };

        Object.keys(obj).forEach(key => {
            const val = obj[key];

            if (val == null) {
                result[key] = val;
            } else if (typeof val === "object") {
                if (Array.isArray(val)) {
                    result[key] = val.map(item => traverse(item, id));
                } else {
                    result[key] = traverse(val, id);
                }
            } else if (typeof val === "function") {
                result[key] = "[function]";
            } else {
                result[key] = val;
            }
        });

        nodes[id] = result;
        return id;
    };

    traverse(root);
    return nodes;
};

const nodes = deconstruct(prog);

const defaultState = {
    nodes: nodes,
    selection: null,
};

const getValue = function(node) {
    if (node.type === 'NumberLiteral') {
        return node.value;
    } else if (node.type === 'StringLiteral') {
        return `"${node.value}"`;
    } else if (node.type === 'Identifier') {
        return node.name;
    }
};

const reducer = function(state = defaultState, action) {
    const { selection, nodes } = state;

    switch(action.type) {
        case 'MOVE_LEFT':
            if (selection && selection.pos != null) {
                let pos = selection.pos;
                let id = selection.id;

                const node = state.nodes[selection.id];

                if (pos === 0) {
                    const parent = state.nodes[node.parent];
                    if (parent.type === 'CallExpression') {
                        let index = parent.arguments.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.arguments[index];
                            pos = getValue(nodes[id]).length;
                        }
                    } else if (parent.type === 'ArrayExpression') {
                        let index = parent.elements.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.elements[index];
                            pos = getValue(nodes[id]).length;
                        }
                    } else if (parent.type === 'FunctionExpression') {
                        let index = parent.params.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.params[index];
                            pos = getValue(nodes[id]).length;
                        }
                    }
                } else {
                    pos = pos - 1;
                }

                return {
                    ...state,
                    selection: {
                        id,
                        pos,
                    },
                };
            }

            return state;
        case 'MOVE_RIGHT':
            if (selection && selection.pos != null) {
                let pos = selection.pos;
                let id = selection.id;

                const node = state.nodes[selection.id];
                const value = getValue(node);

                if (pos === value.length) {
                    const parent = state.nodes[node.parent];
                    if (parent.type === 'CallExpression') {
                        const count = parent.arguments.length;
                        let index = parent.arguments.indexOf(id);
                        if (index !== -1 && index + 1 < count) {
                            index = index + 1;
                            id = parent.arguments[index];
                            pos = 0;
                        }
                    } else if (parent.type === 'ArrayExpression') {
                        const count = parent.elements.length;
                        let index = parent.elements.indexOf(id);
                        if (index !== -1 && index + 1 < count) {
                            index = index + 1;
                            id = parent.elements[index];
                            pos = 0;
                        }
                    } else if (parent.type === 'FunctionExpression') {
                        const count = parent.params.length;
                        let index = parent.params.indexOf(id);
                        if (index !== -1 && index + 1 < count ) {
                            index = index + 1;
                            id = parent.params[index];
                            pos = 0;
                        }
                    }
                } else {
                    pos = pos + 1;
                }

                return {
                    ...state,
                    selection: {
                        id,
                        pos,
                    },
                };
            }

            return state;
        case 'INSERT':
            if (selection && selection.id) {
                const node = state.nodes[selection.id];
                const parent = node.parent;

                let pos = selection.pos;

                if (node.type === 'StringLiteral') {
                    if (pos > 0 && pos < node.value.length + 2) {
                        const left = node.value.substring(0, pos - 1);
                        const right = node.value.substring(pos - 1);
                        const value = left + action.char + right;
                        pos += 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    }
                } else if (node.type === 'NumberLiteral') {
                    if (/[0-9\.]/.test(action.char)) {
                        if (action.char === '.' && node.value.includes('.')) {
                            return state;
                        }
                        const left = node.value.substring(0, pos);
                        const right = node.value.substring(pos);
                        const value = left + action.char + right;
                        pos += 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    }
                } else if (node.type === 'Placeholder') {
                    if (action.char === '"') {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'StringLiteral',
                                    value: '',
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: 1
                            },
                        };
                    } else if (/[0-9\.]/.test(action.char)) {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'NumberLiteral',
                                    value: action.char,
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: 1
                            },
                        };
                    }
                }
            }
            return state;
        case 'DELETE':
            if (selection && selection.id) {
                const node = state.nodes[selection.id];
                const parent = node.parent;
                let pos = selection.pos;

                if (node.type === 'StringLiteral') {
                    if (pos > 1 && pos < node.value.length + 2) {
                        const left = node.value.substring(0, pos - 2);
                        const right = node.value.substring(pos - 1);
                        const value = left + right;
                        pos -= 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    } else if (node.value.length === 0) {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'Placeholder',
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: undefined,
                            },
                        };
                    }
                } else if (node.type === 'NumberLiteral') {
                    if (pos > 0) {
                        const left = node.value.substring(0, pos - 1);
                        const right = node.value.substring(pos);
                        const value = left + right;
                        pos -= 1;

                        if (value === '') {
                            return {
                                ...state,
                                nodes: {
                                    ...nodes,
                                    [selection.id]: {
                                        type: 'Placeholder',
                                        parent,
                                    },
                                },
                                selection: {
                                    ...selection,
                                    pos: undefined,
                                },
                            };
                        } else {
                            return {
                                ...state,
                                nodes: {
                                    ...nodes,
                                    [selection.id]: {
                                        ...node,
                                        value,
                                    },
                                },
                                selection: {
                                    ...selection,
                                    pos: pos
                                },
                            };
                        }
                    }
                }
            }
            return state;
        case 'SELECT':
            if (selection && selection.id === action.id && selection.pos === action.pos) {
                return {
                    ...state,
                    selection: null,
                };
            } else {
                return {
                    ...state,
                    selection: {
                        id: action.id,
                        pos: action.pos,
                    },
                };
            }
        default:
            return state;
    }
};

const store = createStore(reducer);

export default store;
<commit_msg>implement deleting a placeholder arg in a CallExpression<commit_after>import { createStore } from 'redux';

import prog from './prog';

const deconstruct = function(root) {
    if (root === null || root === undefined) {
        return null;
    }
    var nodes = [];
    var index = 0;
    var traverse = function (obj, parent = -1) {
        const id = index++;
        const result = { parent };

        Object.keys(obj).forEach(key => {
            const val = obj[key];

            if (val == null) {
                result[key] = val;
            } else if (typeof val === "object") {
                if (Array.isArray(val)) {
                    result[key] = val.map(item => traverse(item, id));
                } else {
                    result[key] = traverse(val, id);
                }
            } else if (typeof val === "function") {
                result[key] = "[function]";
            } else {
                result[key] = val;
            }
        });

        nodes[id] = result;
        return id;
    };

    traverse(root);
    return nodes;
};

const nodes = deconstruct(prog);

const defaultState = {
    nodes: nodes,
    selection: null,
};

const getValue = function(node) {
    if (node.type === 'NumberLiteral') {
        return node.value;
    } else if (node.type === 'StringLiteral') {
        return `"${node.value}"`;
    } else if (node.type === 'Identifier') {
        return node.name;
    }
};

const reducer = function(state = defaultState, action) {
    const { selection, nodes } = state;

    switch(action.type) {
        case 'MOVE_LEFT':
            if (selection && selection.pos != null) {
                let pos = selection.pos;
                let id = selection.id;

                const node = state.nodes[selection.id];

                if (pos === 0) {
                    const parent = state.nodes[node.parent];
                    if (parent.type === 'CallExpression') {
                        let index = parent.arguments.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.arguments[index];
                            pos = getValue(nodes[id]).length;
                        }
                    } else if (parent.type === 'ArrayExpression') {
                        let index = parent.elements.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.elements[index];
                            pos = getValue(nodes[id]).length;
                        }
                    } else if (parent.type === 'FunctionExpression') {
                        let index = parent.params.indexOf(id);
                        if (index > 0) {
                            index = Math.max(0, index - 1);
                            id = parent.params[index];
                            pos = getValue(nodes[id]).length;
                        }
                    }
                } else {
                    pos = pos - 1;
                }

                return {
                    ...state,
                    selection: {
                        id,
                        pos,
                    },
                };
            }

            return state;
        case 'MOVE_RIGHT':
            if (selection && selection.pos != null) {
                let pos = selection.pos;
                let id = selection.id;

                const node = state.nodes[selection.id];
                const value = getValue(node);

                if (pos === value.length) {
                    const parent = state.nodes[node.parent];
                    if (parent.type === 'CallExpression') {
                        const count = parent.arguments.length;
                        let index = parent.arguments.indexOf(id);
                        if (index !== -1 && index + 1 < count) {
                            index = index + 1;
                            id = parent.arguments[index];
                            pos = 0;
                        }
                    } else if (parent.type === 'ArrayExpression') {
                        const count = parent.elements.length;
                        let index = parent.elements.indexOf(id);
                        if (index !== -1 && index + 1 < count) {
                            index = index + 1;
                            id = parent.elements[index];
                            pos = 0;
                        }
                    } else if (parent.type === 'FunctionExpression') {
                        const count = parent.params.length;
                        let index = parent.params.indexOf(id);
                        if (index !== -1 && index + 1 < count ) {
                            index = index + 1;
                            id = parent.params[index];
                            pos = 0;
                        }
                    }
                } else {
                    pos = pos + 1;
                }

                return {
                    ...state,
                    selection: {
                        id,
                        pos,
                    },
                };
            }

            return state;
        case 'INSERT':
            if (selection && selection.id) {
                const node = state.nodes[selection.id];
                const parent = node.parent;

                let pos = selection.pos;

                if (node.type === 'StringLiteral') {
                    if (pos > 0 && pos < node.value.length + 2) {
                        const left = node.value.substring(0, pos - 1);
                        const right = node.value.substring(pos - 1);
                        const value = left + action.char + right;
                        pos += 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    }
                } else if (node.type === 'NumberLiteral') {
                    if (/[0-9\.]/.test(action.char)) {
                        if (action.char === '.' && node.value.includes('.')) {
                            return state;
                        }
                        const left = node.value.substring(0, pos);
                        const right = node.value.substring(pos);
                        const value = left + action.char + right;
                        pos += 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    }
                } else if (node.type === 'Placeholder') {
                    if (action.char === '"') {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'StringLiteral',
                                    value: '',
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: 1
                            },
                        };
                    } else if (/[0-9\.]/.test(action.char)) {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'NumberLiteral',
                                    value: action.char,
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: 1
                            },
                        };
                    }
                }
            }
            return state;
        case 'DELETE':
            if (selection && selection.id) {
                const node = state.nodes[selection.id];
                const parent = node.parent;
                let pos = selection.pos;

                if (node.type === 'StringLiteral') {
                    if (pos > 1 && pos < node.value.length + 2) {
                        const left = node.value.substring(0, pos - 2);
                        const right = node.value.substring(pos - 1);
                        const value = left + right;
                        pos -= 1;

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    ...node,
                                    value,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: pos
                            },
                        };
                    } else if (node.value.length === 0) {
                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [selection.id]: {
                                    type: 'Placeholder',
                                    parent,
                                },
                            },
                            selection: {
                                ...selection,
                                pos: undefined,
                            },
                        };
                    }
                } else if (node.type === 'NumberLiteral') {
                    if (pos > 0) {
                        const left = node.value.substring(0, pos - 1);
                        const right = node.value.substring(pos);
                        const value = left + right;
                        pos -= 1;

                        if (value === '') {
                            return {
                                ...state,
                                nodes: {
                                    ...nodes,
                                    [selection.id]: {
                                        type: 'Placeholder',
                                        parent,
                                    },
                                },
                                selection: {
                                    ...selection,
                                    pos: undefined,
                                },
                            };
                        } else {
                            return {
                                ...state,
                                nodes: {
                                    ...nodes,
                                    [selection.id]: {
                                        ...node,
                                        value,
                                    },
                                },
                                selection: {
                                    ...selection,
                                    pos: pos
                                },
                            };
                        }
                    }
                } else if (node.type === 'Placeholder') {
                    const parentNode = nodes[parent];

                    if (parentNode.type === 'CallExpression' && parentNode.arguments.includes(selection.id)) {
                        const args = parentNode.arguments;
                        const prevArg = args[args.indexOf(selection.id) - 1];

                        return {
                            ...state,
                            nodes: {
                                ...nodes,
                                [parent]: {
                                    ...parentNode,
                                    arguments: args.filter(arg => arg !== selection.id),
                                }
                            },
                            selection: {
                                id: prevArg,
                                pos: getValue(nodes[prevArg]).length,
                            },
                        };
                    }
                }
            }
            return state;
        case 'SELECT':
            if (selection && selection.id === action.id && selection.pos === action.pos) {
                return {
                    ...state,
                    selection: null,
                };
            } else {
                return {
                    ...state,
                    selection: {
                        id: action.id,
                        pos: action.pos,
                    },
                };
            }
        default:
            return state;
    }
};

const store = createStore(reducer);

export default store;
<|endoftext|>


<commit_before>import { update } from "./renderer"

const tuple = {
	data: null,
	key: null,
	parentKey: null,
	watchers: null
}

function Proxy(key, func) {
	this.key = key
	this.func = func
}

function WatcherBuffer() {
	this.funcs = []
	this.buffer = null
}

class Store
{
	constructor()
	{
		this.data = {}
		this.proxies = []
		this.emitting = false

		this.watchers = new WatcherBuffer()
		this.watchers.buffer = {}
	}

	set(key, value)
	{
		this.dispatch({
			action: "SET",
			key,
			value
		})
	}

	add(key, value)
	{
		this.dispatch({
			action: "ADD",
			key,
			value
		})
	}

	remove(key, value)
	{
		this.dispatch({
			action: "REMOVE",
			key
		})
	}

	dispatch(data)
	{
		for(let n = 0; n < this.proxies.length; n++) {
			const proxy = this.proxies[n]
			if(data.key.indexOf(proxy.key) === 0) {
				if(proxy.func(data)) {
					return
				}
			}
		}

		if(this.globalProxy) {
			this.globalProxy(data)
		}
		else {
			this.handle(data)
		}
	}

	performSet(payload)
	{
		if(!this.getData(payload.key, payload.force)) { return }

		if(payload.key)
		{
			tuple.data[tuple.key] = payload.value
			this.emit({
				action: "SET",
				key: tuple.parentKey,
				value: tuple.data
			}, tuple.watchers, tuple.key, payload.value)
		}
		else
		{
			this.data = payload.value
			this.emitWatchers({
				action: "SET",
				key: "",
				value: payload.value
			}, this.watchers)
		}
	}

	performAdd(payload)
	{
		if(!this.getData(payload.key)) { return }

		let array = tuple.data[tuple.key]
		if(!array) {
			array = [ payload.value ]
			tuple.data[tuple.key] = array
		}
		else if(!Array.isArray(array)) {
			console.warn("(store) Data at key '${payload.key}' is not an Array")
			return
		}
		else {
			array.push(payload.value)
		}

		const watchers = tuple.watchers.buffer ? tuple.watchers.buffer[tuple.key] : null
		if(!watchers) { return }

		const funcs = watchers.funcs
		if(funcs)
		{
			const payload = {
				action: "SET",
				key: tuple.key,
				value: array
			}

			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}
	}

	performRemove(payload)
	{
		if(!this.getData(payload.key)) { return }

		const data = tuple.data
		if(Array.isArray(data)) {
			data.splice(parseInt(tuple.key), 1)
		}
		else {
			delete data[tuple.key]
		}

		this.emit({
			action: "SET",
			key: tuple.parentKey,
			value: tuple.data
		}, tuple.watchers, tuple.key, null)
	}

	handle(data)
	{
		switch(data.action) {
			case "SET":
				this.performSet(data)
				break
			case "ADD":
				this.performAdd(data)
				break
			case "REMOVE":
				this.performRemove(data)
				break
		}
	}

	watch(path, func)
	{
		let watchers = this.watchers

		const keys = path.split("/")
		for(let n = 0; n < keys.length; n++)
		{
			const key = keys[n]
			const buffer = watchers.buffer

			if(buffer)
			{
				const nextWatchers = buffer[key]
				if(!nextWatchers) {
					const newWatchers = new WatcherBuffer()
					watchers.buffer[key] = newWatchers
					watchers = this.fillWatchers(newWatchers, keys, n + 1)
					break
				}
				else {
					watchers = nextWatchers
				}
			}
			else {
				watchers = this.fillWatchers(watchers, keys, n)
				break
			}
		}

		watchers.funcs.push(func)
	}

	fillWatchers(watchers, keys, index)
	{
		for(let n = index; n < keys.length; n++) {
			const newWatcher = new WatcherBuffer()
			watchers.buffer = {}
			watchers.buffer[keys[n]] = newWatcher
			watchers = newWatcher
		}

		return watchers
	}

	// TODO: Remove empty watcher objects
	unwatch(path, func)
	{
		if(!path) { return }

		let watchers = this.watchers

		const keys = path.split("/")
		for(let n = 0; n < keys.length; n++) {
			if(!watchers.buffer) {
				console.warn("(store.unwatch) Watcher can not be found for:", path)
				return
			}
			watchers = watchers.buffer[keys[n]]
		}

		const funcs = watchers.funcs
		const index = funcs.indexOf(func)
		if(index === -1) {
			console.warn("(store.unwatch) Watcher can not be found for:", path)
			return
		}

		if(this.emitting) {
			funcs.splice(index, 1)
		}
		else {
			funcs[index] = funcs[funcs.length - 1]
			funcs.pop()
		}
	}

	emit(payload, watchers, key, value)
	{
		if(!watchers) { return }

		this.emitting = true

		const funcs = watchers.funcs
		if(funcs) {
			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}

		watchers = watchers.buffer ? watchers.buffer[key] : null
		if(watchers) {
			payload.key = key
			payload.value = value
			this.emitWatchers(payload, watchers)
		}

		this.emitting = false
	}

	emitWatchers(payload, watchers)
	{
		const funcs = watchers.funcs
		if(funcs) {
			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}

		const buffer = watchers.buffer
		if(buffer)
		{
			const value = payload.value
			if(value && typeof value === "object")
			{
				for(let key in buffer) {
					payload.key = key
					payload.value = value[key] || null
					this.emitWatchers(payload, buffer[key])
				}
			}
			else
			{
				payload.value = null
				for(let key in buffer) {
					payload.key = key
					this.emitWatchers(payload, buffer[key])
				}
			}
		}
	}

	get(key)
	{
		if(!key)
		{
			if(key === undefined) {
				return ""
			}

			return this.data
		}

		const buffer = key.split("/")
		let data = this.data

		for(let n = 0; n < buffer.length; n++)
		{
			const id = buffer[n]
			if(id === "@") {
				return buffer[n - 1]
			}
			else {
				data = data[id]
			}

			if(data === undefined) {
				return null
			}
		}

		return data
	}

	getData(path)
	{
		if(!path) {
			tuple.data = this.data
			tuple.key = null
			tuple.parentKey = null
			tuple.watchers = null
			return tuple
		}

		const keys = path.split("/")
		const num = keys.length - 1;
		if(num === 0) {
			tuple.data = this.data
			tuple.key = keys[0]
			tuple.parentKey = null
			tuple.watchers = this.watchers
		}
		else
		{
			let data = this.data
			let watchers = this.watchers

			for(let n = 0; n < num; n++)
			{
				const key = keys[n]
				const newData = data[key]
				if(!newData) {
					console.warn(`(store.getData) No data available with key: [${keys[n]}] with path: [${path}]`)
					return null
				}

				data = newData
				if(watchers) {
					watchers = watchers.buffer ? watchers.buffer[key] : null
				}
			}

			tuple.data = data
			tuple.key = keys[num]
			tuple.parentKey = keys[num - 1]
			tuple.watchers = watchers
		}

		return tuple
	}

	addProxy(key, func)
	{
		if(key === "")
		{
			if(this.globalProxy) {
				console.warn("(wabi.proxy) There is already global proxy declared")
				return
			}

			this.globalProxy = func
		}
		else
		{
			for(let n = 0; n < this.proxies.length; n++) {
				const proxy = this.proxies[n]
				if(proxy.key === key && proxy.func === func) {
					console.warn("(wabi.proxy) There is already a proxy declared with key:", key)
					return
				}
			}

			const proxy = new Proxy(key, func)
			this.proxies.push(proxy)
		}
	}

	removeProxy(key, func)
	{
		if(key === "")
		{
			if(this.globalProxy !== func) {
				console.warn("(wabi.proxy) Global proxy functions don`t match")
				return
			}

			this.globalProxy = null
		}
		else
		{
			for(let n = 0; n < this.proxies.length; n++) {
				const proxy = this.proxies[n]
				if(proxy.key === key && proxy.func === func) {
					this.proxies[n] = this.proxies[this.proxies.length - 1]
					this.proxies.pop()
					return
				}
			}
		}
	}

	toJSON() {
		return this.data
	}
}

const store = new Store()

const lastSegment = function(str)
{
	const index = str.lastIndexOf("/")
	if(index === -1) { return null }

	return str.slice(index + 1)
}

export {
	store, lastSegment
}
<commit_msg>Fix remove emit action<commit_after>import { update } from "./renderer"

const tuple = {
	data: null,
	key: null,
	parentKey: null,
	watchers: null
}

function Proxy(key, func) {
	this.key = key
	this.func = func
}

function WatcherBuffer() {
	this.funcs = []
	this.buffer = null
}

class Store
{
	constructor()
	{
		this.data = {}
		this.proxies = []
		this.emitting = false

		this.watchers = new WatcherBuffer()
		this.watchers.buffer = {}
	}

	set(key, value)
	{
		this.dispatch({
			action: "SET",
			key,
			value
		})
	}

	add(key, value)
	{
		this.dispatch({
			action: "ADD",
			key,
			value
		})
	}

	remove(key, value)
	{
		this.dispatch({
			action: "REMOVE",
			key
		})
	}

	dispatch(data)
	{
		for(let n = 0; n < this.proxies.length; n++) {
			const proxy = this.proxies[n]
			if(data.key.indexOf(proxy.key) === 0) {
				if(proxy.func(data)) {
					return
				}
			}
		}

		if(this.globalProxy) {
			this.globalProxy(data)
		}
		else {
			this.handle(data)
		}
	}

	performSet(payload)
	{
		if(!this.getData(payload.key, payload.force)) { return }

		if(payload.key)
		{
			tuple.data[tuple.key] = payload.value
			this.emit({
				action: "SET",
				key: tuple.parentKey,
				value: tuple.data
			}, tuple.watchers, "SET", tuple.key, payload.value)
		}
		else
		{
			this.data = payload.value
			this.emitWatchers({
				action: "SET",
				key: "",
				value: payload.value
			}, this.watchers)
		}
	}

	performAdd(payload)
	{
		if(!this.getData(payload.key)) { return }

		let array = tuple.data[tuple.key]
		if(!array) {
			array = [ payload.value ]
			tuple.data[tuple.key] = array
		}
		else if(!Array.isArray(array)) {
			console.warn("(store) Data at key '${payload.key}' is not an Array")
			return
		}
		else {
			array.push(payload.value)
		}

		const watchers = tuple.watchers.buffer ? tuple.watchers.buffer[tuple.key] : null
		if(!watchers) { return }

		const funcs = watchers.funcs
		if(funcs)
		{
			const payload = {
				action: "SET",
				key: tuple.key,
				value: array
			}

			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}
	}

	performRemove(payload)
	{
		if(!this.getData(payload.key)) { return }

		const data = tuple.data
		if(Array.isArray(data)) {
			data.splice(parseInt(tuple.key), 1)
		}
		else {
			delete data[tuple.key]
		}

		this.emit({
			action: "SET",
			key: tuple.parentKey,
			value: tuple.data
		}, tuple.watchers, "REMOVE", tuple.key, null)
	}

	handle(data)
	{
		switch(data.action) {
			case "SET":
				this.performSet(data)
				break
			case "ADD":
				this.performAdd(data)
				break
			case "REMOVE":
				this.performRemove(data)
				break
		}
	}

	watch(path, func)
	{
		let watchers = this.watchers

		const keys = path.split("/")
		for(let n = 0; n < keys.length; n++)
		{
			const key = keys[n]
			const buffer = watchers.buffer

			if(buffer)
			{
				const nextWatchers = buffer[key]
				if(!nextWatchers) {
					const newWatchers = new WatcherBuffer()
					watchers.buffer[key] = newWatchers
					watchers = this.fillWatchers(newWatchers, keys, n + 1)
					break
				}
				else {
					watchers = nextWatchers
				}
			}
			else {
				watchers = this.fillWatchers(watchers, keys, n)
				break
			}
		}

		watchers.funcs.push(func)
	}

	fillWatchers(watchers, keys, index)
	{
		for(let n = index; n < keys.length; n++) {
			const newWatcher = new WatcherBuffer()
			watchers.buffer = {}
			watchers.buffer[keys[n]] = newWatcher
			watchers = newWatcher
		}

		return watchers
	}

	// TODO: Remove empty watcher objects
	unwatch(path, func)
	{
		if(!path) { return }

		let watchers = this.watchers

		const keys = path.split("/")
		for(let n = 0; n < keys.length; n++) {
			if(!watchers.buffer) {
				console.warn("(store.unwatch) Watcher can not be found for:", path)
				return
			}
			watchers = watchers.buffer[keys[n]]
		}

		const funcs = watchers.funcs
		const index = funcs.indexOf(func)
		if(index === -1) {
			console.warn("(store.unwatch) Watcher can not be found for:", path)
			return
		}

		if(this.emitting) {
			funcs.splice(index, 1)
		}
		else {
			funcs[index] = funcs[funcs.length - 1]
			funcs.pop()
		}
	}

	emit(payload, watchers, action, key, value)
	{
		if(!watchers) { return }

		this.emitting = true

		const funcs = watchers.funcs
		if(funcs) {
			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}

		watchers = watchers.buffer ? watchers.buffer[key] : null
		if(watchers) {
			payload.action = action
			payload.key = key
			payload.value = value
			this.emitWatchers(payload, watchers)
		}

		this.emitting = false
	}

	emitWatchers(payload, watchers)
	{
		const funcs = watchers.funcs
		if(funcs) {
			for(let n = 0; n < funcs.length; n++) {
				funcs[n](payload)
			}
		}

		const buffer = watchers.buffer
		if(buffer)
		{
			const value = payload.value
			if(value && typeof value === "object")
			{
				for(let key in buffer) {
					payload.key = key
					payload.value = value[key] || null
					this.emitWatchers(payload, buffer[key])
				}
			}
			else
			{
				payload.value = null
				for(let key in buffer) {
					payload.key = key
					this.emitWatchers(payload, buffer[key])
				}
			}
		}
	}

	get(key)
	{
		if(!key)
		{
			if(key === undefined) {
				return ""
			}

			return this.data
		}

		const buffer = key.split("/")
		let data = this.data

		for(let n = 0; n < buffer.length; n++)
		{
			const id = buffer[n]
			if(id === "@") {
				return buffer[n - 1]
			}
			else {
				data = data[id]
			}

			if(data === undefined) {
				return null
			}
		}

		return data
	}

	getData(path)
	{
		if(!path) {
			tuple.data = this.data
			tuple.key = null
			tuple.parentKey = null
			tuple.watchers = null
			return tuple
		}

		const keys = path.split("/")
		const num = keys.length - 1;
		if(num === 0) {
			tuple.data = this.data
			tuple.key = keys[0]
			tuple.parentKey = null
			tuple.watchers = this.watchers
		}
		else
		{
			let data = this.data
			let watchers = this.watchers

			for(let n = 0; n < num; n++)
			{
				const key = keys[n]
				const newData = data[key]
				if(!newData) {
					console.warn(`(store.getData) No data available with key: [${keys[n]}] with path: [${path}]`)
					return null
				}

				data = newData
				if(watchers) {
					watchers = watchers.buffer ? watchers.buffer[key] : null
				}
			}

			tuple.data = data
			tuple.key = keys[num]
			tuple.parentKey = keys[num - 1]
			tuple.watchers = watchers
		}

		return tuple
	}

	addProxy(key, func)
	{
		if(key === "")
		{
			if(this.globalProxy) {
				console.warn("(wabi.proxy) There is already global proxy declared")
				return
			}

			this.globalProxy = func
		}
		else
		{
			for(let n = 0; n < this.proxies.length; n++) {
				const proxy = this.proxies[n]
				if(proxy.key === key && proxy.func === func) {
					console.warn("(wabi.proxy) There is already a proxy declared with key:", key)
					return
				}
			}

			const proxy = new Proxy(key, func)
			this.proxies.push(proxy)
		}
	}

	removeProxy(key, func)
	{
		if(key === "")
		{
			if(this.globalProxy !== func) {
				console.warn("(wabi.proxy) Global proxy functions don`t match")
				return
			}

			this.globalProxy = null
		}
		else
		{
			for(let n = 0; n < this.proxies.length; n++) {
				const proxy = this.proxies[n]
				if(proxy.key === key && proxy.func === func) {
					this.proxies[n] = this.proxies[this.proxies.length - 1]
					this.proxies.pop()
					return
				}
			}
		}
	}

	toJSON() {
		return this.data
	}
}

const store = new Store()

const lastSegment = function(str)
{
	const index = str.lastIndexOf("/")
	if(index === -1) { return null }

	return str.slice(index + 1)
}

export {
	store, lastSegment
}
<|endoftext|>


<commit_before>import sortedObject from './sortedObject';
import {createStore} from 'redux';
import {reducer} from './reducer';

const Store = {
  ...createStore(reducer),

  getDefaultParams() {
    return this.getState().defaultParams;
  },

  getCleanQuery() {
    const cleanQuery = {...this.getState().query};

    Object.keys(this.getDefaultParams()).forEach(key => {
      if (cleanQuery[key] === this.getDefaultParams()[key]) {
        delete cleanQuery[key];
      }
    });
    return sortedObject(cleanQuery);
  },

  getQuery() {
    return this.getState().query;
  },

  getType() {
    return this.getState().type;
  }
};

export default Store;
<commit_msg>Remove all extras from store<commit_after>import {createStore} from 'redux';
import {componentRouter} from './reducer';

export const store = createStore(componentRouter);
<|endoftext|>


<commit_before>import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

import { baseURL, getCall, postCall } from './rest'

Vue.use(Vuex)

export const mutations = {
  setItem(state, newItem) {
    state.item = newItem
  },
  setRecipe(state, newRecipe) {
    state.recipe = newRecipe
  },
  addCharacter(state, newChar) {
    Vue.set(state.characters, newChar.name, newChar)
  },
  deleteCharacter(state, char) {
    Vue.delete(state.characters, char)
  },
  setPrice(state, payload) {
    Vue.set(state.prices, payload.item, payload.price)
  },
  deletePrice(state, item) {
    Vue.delete(state.prices, item)
  }
}

export const actions = {
  setItem({ commit, state }, newItem) {
    postCall(baseURL+newItem.詳細, { "調達価格": state.prices }, (xhr) => {
      if (xhr.readyState==4 && xhr.status==200) {
        commit('setItem', JSON.parse(xhr.response))
      } else if (xhr.status==404) {
        commit('setItem', {
          アイテム名: newItem.アイテム名,
          英名: "",
          info: "",
          重さ: 0.0,
          NPC売却価格: 0,
          参考価格: 0,
          特殊条件: [],
          ペットアイテム: { 種別: '不明' },
          レシピ: [],
          備考: "細かいことは\nわかりません(´・ω・`)",
        })
      }
    })
  },
  setRecipe({ commit }, newRecipe) {
    getCall(baseURL+newRecipe.詳細, (xhr) => {
      if (xhr.readyState==4 && xhr.status==200) {
        commit('setRecipe', JSON.parse(xhr.response))
      } else if (xhr.status==404) {
        commit('setRecipe', {
          レシピ名: this.recipe.レシピ名,
          テクニック: ['わからん'],
          必要スキル: { 'わからん': 0 },
          収録バインダー: [{バインダー名: 'わからん'}],
          レシピ必須: false,
          材料: { 'わからん': 0 },
          生成物: { 'わからん': 0 },
          備考: '細かいことは\nわかりません(´・ω・`)',
        })
      }
    })
  },
  setPrice({ commit }, payload) {
    commit('setPrice', payload)
  },
  deletePrice({ commit }, item) {
    commit('deletePrice', item)
  },
}

export default new Vuex.Store({
  state: {
    item: {
      アイテム名: '',
      特殊条件: [],
      ペットアイテム: { 種別: '不明' },
      レシピ: [],
      info: '',
      備考: '',
    },
    recipe: {
      レシピ名: '',
      テクニック: ['わからん'],
      必要スキル: { 'わからん': 0 },
      収録バインダー: [{バインダー名: 'わからん'}],
      レシピ必須: false,
      材料: { 'わからん': 0 },
      生成物: { 'わからん': 0 },
      備考: 'よくわからん(´・ω・`)',
    },
    characters: {
      しらたま: { name: 'しらたま' },
    },
    prices: {
    },
  },
  mutations: mutations,
  actions: actions,
  plugins: [createPersistedState()]
})
<commit_msg>試験的に async を使用するようにした<commit_after>import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

import { baseURL, getCall, postCall } from './rest'

Vue.use(Vuex)

export const mutations = {
  setItem(state, newItem) {
    state.item = newItem
  },
  setRecipe(state, newRecipe) {
    state.recipe = newRecipe
  },
  addCharacter(state, newChar) {
    Vue.set(state.characters, newChar.name, newChar)
  },
  deleteCharacter(state, char) {
    Vue.delete(state.characters, char)
  },
  setPrice(state, payload) {
    Vue.set(state.prices, payload.item, payload.price)
  },
  deletePrice(state, item) {
    Vue.delete(state.prices, item)
  }
}

export const actions = {
  async setItem({ commit, state }, newItem) {
    postCall(baseURL+newItem.詳細, { "調達価格": state.prices }, (xhr) => {
      if (xhr.readyState==4 && xhr.status==200) {
        commit('setItem', JSON.parse(xhr.response))
      } else if (xhr.status==404) {
        commit('setItem', {
          アイテム名: newItem.アイテム名,
          英名: "",
          info: "",
          重さ: 0.0,
          NPC売却価格: 0,
          参考価格: 0,
          特殊条件: [],
          ペットアイテム: { 種別: '不明' },
          レシピ: [],
          備考: "細かいことは\nわかりません(´・ω・`)",
        })
      }
    })
  },
  async setRecipe({ commit }, newRecipe) {
    getCall(baseURL+newRecipe.詳細, (xhr) => {
      if (xhr.readyState==4 && xhr.status==200) {
        commit('setRecipe', JSON.parse(xhr.response))
      } else if (xhr.status==404) {
        commit('setRecipe', {
          レシピ名: this.recipe.レシピ名,
          テクニック: ['わからん'],
          必要スキル: { 'わからん': 0 },
          収録バインダー: [{バインダー名: 'わからん'}],
          レシピ必須: false,
          材料: { 'わからん': 0 },
          生成物: { 'わからん': 0 },
          備考: '細かいことは\nわかりません(´・ω・`)',
        })
      }
    })
  },
  async setPrice({ commit }, payload) {
    commit('setPrice', payload)
  },
  async deletePrice({ commit }, item) {
    commit('deletePrice', item)
  },
}

export default new Vuex.Store({
  state: {
    item: {
      アイテム名: '',
      特殊条件: [],
      ペットアイテム: { 種別: '不明' },
      レシピ: [],
      info: '',
      備考: '',
    },
    recipe: {
      レシピ名: '',
      テクニック: ['わからん'],
      必要スキル: { 'わからん': 0 },
      収録バインダー: [{バインダー名: 'わからん'}],
      レシピ必須: false,
      材料: { 'わからん': 0 },
      生成物: { 'わからん': 0 },
      備考: 'よくわからん(´・ω・`)',
    },
    characters: {
      しらたま: { name: 'しらたま' },
    },
    prices: {
    },
  },
  mutations: mutations,
  actions: actions,
  plugins: [createPersistedState()]
})
<|endoftext|>


<commit_before>// mostly taken from http://www.codinginsight.com/angularjs-and-pickadate/

angular.module('angular-datepicker', [])
	.directive('pickADate', function () {
	    return {
	        restrict: "A",
	        scope: {
	            pickADate: '=',
	            minDate: '=',
	            maxDate: '='
	        },
	        link: function (scope, element, attrs) {
	            element.pickadate({
	                onSet: function (e) {
	                    if (scope.$$phase || scope.$root.$$phase) // we are coming from $watch or link setup
	                        return;
	                    var select = element.pickadate('picker').get('select'); // selected date
	                    scope.$apply(function () {
	                        if (e.hasOwnProperty('clear')) {
	                            scope.pickADate = null;
	                            return;
	                        }
	                        if (!scope.pickADate || typeof scope.pickADate === 'string')
	                            scope.pickADate = new Date(0);
	                        scope.pickADate.setYear(select.obj.getYear() + 1900); // hello Y2K...
	                        // It took me half a day to figure out that javascript Date object's getYear
	                        // function returns the years since 1900. Ironically setYear() accepts the actual year A.D.
	                        // So as I got the $#%^ 114 and set it, guess what, I was transported to ancient Rome 114 A.D.
	                        // That's it I'm done being a programmer, I'd rather go serve Emperor Trajan as a sex slave.
	                        scope.pickADate.setMonth(select.obj.getMonth());
	                        scope.pickADate.setDate(select.obj.getDate());
	                    });
	                },
	                onClose: function () {
						if (!cordova || !cordova.plugins || !cordova.plugins.Keyboard) {
							return;
						}

						var keyboardShowCallback = function () {
							cordova.plugins.Keyboard.close();
							window.removeEventListener('native.keyboardshow', this);
						};

						window.addEventListener('native.keyboardshow', keyboardShowCallback);

						setTimeout(function () {
							window.removeEventListener('native.keyboardshow', keyboardShowCallback);
						}, 500);
	                },
					container: document.body
	            });

				setTimeout(function() {
					if (scope.pickADate) {
						element.pickadate('picker').set('select', scope.pickADate);
					}
				}, 1000);
	        }
	    };
	})
	.directive('pickATime', function () {
	    return {
	        restrict: "A",
	        scope: {
	            pickATime: '='
	        },
	        link: function (scope, element, attrs) {
	            element.pickatime({
	                onSet: function (e) {
	                    if (scope.$$phase || scope.$root.$$phase) // we are coming from $watch or link setup
	                        return;
	                    var select = element.pickatime('picker').get('select'); // selected date
	                    scope.$apply(function () {
	                        if (e.hasOwnProperty('clear')) {
	                            scope.pickATime = null;
	                            return;
	                        }
	                        if (!scope.pickATime || typeof scope.pickATime === 'string')
	                            scope.pickATime = new Date();

	                        scope.pickATime.setHours(select.hour);
	                        scope.pickATime.setMinutes(select.mins);
	                        scope.pickATime.setSeconds(0);
	                        scope.pickATime.setMilliseconds(0);
	                    });
	                },
	                onClose: function () {
						if (!cordova || !cordova.plugins || !cordova.plugins.Keyboard) {
							return;
						}

						var keyboardShowCallback = function () {
							cordova.plugins.Keyboard.close();
							window.removeEventListener('native.keyboardshow', this);
						};

						window.addEventListener('native.keyboardshow', keyboardShowCallback);

						setTimeout(function () {
							window.removeEventListener('native.keyboardshow', keyboardShowCallback);
						}, 500);
	                },
					container: document.body
	            });

				setTimeout(function() {
					if (scope.pickATime) {
						element.pickatime('picker').set('select', scope.pickATime);
					}
				}, 1000);
	        }
	    };
	});	<commit_msg>safely check if cordova is 'undefined'<commit_after>// mostly taken from http://www.codinginsight.com/angularjs-and-pickadate/

angular.module('angular-datepicker', [])
	.directive('pickADate', function () {
	    return {
	        restrict: "A",
	        scope: {
	            pickADate: '=',
	            minDate: '=',
	            maxDate: '='
	        },
	        link: function (scope, element, attrs) {
	            element.pickadate({
	                onSet: function (e) {
	                    if (scope.$$phase || scope.$root.$$phase) // we are coming from $watch or link setup
	                        return;
	                    var select = element.pickadate('picker').get('select'); // selected date
	                    scope.$apply(function () {
	                        if (e.hasOwnProperty('clear')) {
	                            scope.pickADate = null;
	                            return;
	                        }
	                        if (!scope.pickADate || typeof scope.pickADate === 'string')
	                            scope.pickADate = new Date(0);
	                        scope.pickADate.setYear(select.obj.getYear() + 1900); // hello Y2K...
	                        // It took me half a day to figure out that javascript Date object's getYear
	                        // function returns the years since 1900. Ironically setYear() accepts the actual year A.D.
	                        // So as I got the $#%^ 114 and set it, guess what, I was transported to ancient Rome 114 A.D.
	                        // That's it I'm done being a programmer, I'd rather go serve Emperor Trajan as a sex slave.
	                        scope.pickADate.setMonth(select.obj.getMonth());
	                        scope.pickADate.setDate(select.obj.getDate());
	                    });
	                },
	                onClose: function () {
						if (typeof cordova === 'undefined' || !cordova.plugins || !cordova.plugins.Keyboard) {
							return;
						}

						var keyboardShowCallback = function () {
							cordova.plugins.Keyboard.close();
							window.removeEventListener('native.keyboardshow', this);
						};

						window.addEventListener('native.keyboardshow', keyboardShowCallback);

						setTimeout(function () {
							window.removeEventListener('native.keyboardshow', keyboardShowCallback);
						}, 500);
	                },
					container: document.body
	            });

				setTimeout(function() {
					if (scope.pickADate) {
						element.pickadate('picker').set('select', scope.pickADate);
					}
				}, 1000);
	        }
	    };
	})
	.directive('pickATime', function () {
	    return {
	        restrict: "A",
	        scope: {
	            pickATime: '='
	        },
	        link: function (scope, element, attrs) {
	            element.pickatime({
	                onSet: function (e) {
	                    if (scope.$$phase || scope.$root.$$phase) // we are coming from $watch or link setup
	                        return;
	                    var select = element.pickatime('picker').get('select'); // selected date
	                    scope.$apply(function () {
	                        if (e.hasOwnProperty('clear')) {
	                            scope.pickATime = null;
	                            return;
	                        }
	                        if (!scope.pickATime || typeof scope.pickATime === 'string')
	                            scope.pickATime = new Date();

	                        scope.pickATime.setHours(select.hour);
	                        scope.pickATime.setMinutes(select.mins);
	                        scope.pickATime.setSeconds(0);
	                        scope.pickATime.setMilliseconds(0);
	                    });
	                },
	                onClose: function () {
						if (typeof cordova ==='undefined' || !cordova.plugins || !cordova.plugins.Keyboard) {
							return;
						}

						var keyboardShowCallback = function () {
							cordova.plugins.Keyboard.close();
							window.removeEventListener('native.keyboardshow', this);
						};

						window.addEventListener('native.keyboardshow', keyboardShowCallback);

						setTimeout(function () {
							window.removeEventListener('native.keyboardshow', keyboardShowCallback);
						}, 500);
	                },
					container: document.body
	            });

				setTimeout(function() {
					if (scope.pickATime) {
						element.pickatime('picker').set('select', scope.pickATime);
					}
				}, 1000);
	        }
	    };
	});	<|endoftext|>


<commit_before>import DEFAULT_SHELL   from 'default-shell'
import { observable }  from 'mobx'
import { remote }      from 'electron'

import Config          from './config'
import { Colors }      from './defaults/colors'
import { mergeArrays } from './utils/arrays'

export default new class Store {
  // Empty or falsy values
  @observable tabs        = []
  @observable props       = []
  @observable plugins     = []
  @observable selectedTab = 0
  @observable rows        = 0
  @observable cols        = 0
  @observable isMaximized = false
  @observable isFocused   = false

  // Config based values
  // DEFAULTS
  @observable config         = {}
  @observable elements       = {}
  @observable shellArguments = []
  @observable customCss      = ''
  @observable terminalColors = Colors
  @observable shell          = DEFAULT_SHELL

  async init() {
    // Setup window title based on selected tab
    document.onload = () =>
      window.title = this.tabs[this.selectedTab].title || ''

    // Setup event listeners
    remote.getCurrentWindow().on('focus', () => this.isFocused = true )
    remote.getCurrentWindow().on('blur',  () => this.isFocused = false)

    // Retrive from the Config class
    // if there was an error in the loading process
    const isError = await Config.isError()

    // If there is this error
    if(isError)
      // Set the Store `isError` value to the error
      this.isError = Config.error
    else
      // If everything is Hunky Dory we can proceed
      // and fill in all config-based values
      this.config = await Config.get()

      // Then setup all the other values
      if(this.config.elements)
        this.elements       = this.config.elements

      if(this.config.shell)
        this.shell          = this.config.shell

      if(this.config.shellArguments)
        this.shellArguments = this.config.shellArguments

      if(this.config.customCss)
        this.shellArguments = this.config.css

      if(this.config.colors)
        this.terminalColors = mergeArrays(Colors, this.config.colors)

      if(this.config.plugins)
        this.plugins = this.config.plugins
  }
}
<commit_msg>:pencil: Organize store<commit_after>import DEFAULT_SHELL   from 'default-shell'
import { observable }  from 'mobx'
import { remote }      from 'electron'

import Config          from './config'
import { Colors }      from './defaults/colors'
import { mergeArrays } from './utils/arrays'

export default new class Store {
  // Empty or falsy values
  @observable tabs           = []
  @observable selectedTab    = 0
  @observable rows           = 0
  @observable cols           = 0
  @observable isMaximized    = false
  @observable isFocused      = false

  // Config based values
  // DEFAULTS
  @observable config         = {}
  @observable elements       = {}
  @observable styles         = {}
  @observable props          = []
  @observable plugins        = []
  @observable shellArguments = []
  @observable customCss      = ''
  @observable terminalColors = Colors
  @observable shell          = DEFAULT_SHELL

  async init() {
    // Setup window title based on selected tab
    document.onload = () =>
      window.title = this.tabs[this.selectedTab].title || ''

    // Setup event listeners
    remote.getCurrentWindow().on('focus', () => this.isFocused = true )
    remote.getCurrentWindow().on('blur',  () => this.isFocused = false)

    // Retrive from the Config class
    // if there was an error in the loading process
    const isError = await Config.isError()

    // If there is this error
    if(isError)
      // Set the Store `isError` value to the error
      this.isError = Config.error
    else
      // If everything is Hunky Dory we can proceed
      // and fill in all config-based values
      this.config = await Config.get()

      // Then setup all the other values
      if(this.config.elements)
        this.elements       = this.config.elements

      if(this.config.shell)
        this.shell          = this.config.shell

      if(this.config.shellArguments)
        this.shellArguments = this.config.shellArguments

      if(this.config.customCss)
        this.shellArguments = this.config.css

      if(this.config.colors)
        this.terminalColors = mergeArrays(Colors, this.config.colors)

      if(this.config.plugins)
        this.plugins = this.config.plugins
  }
}
<|endoftext|>


<commit_before>import runloop from '../../global/runloop';
import { warnIfDebug } from '../../utils/log';
import { ANCHOR, ATTRIBUTE, BINDING_FLAG, COMPONENT, DECORATOR, EVENT, TRANSITION, YIELDER } from '../../config/types';
import Item from './shared/Item';
import ConditionalAttribute from './element/ConditionalAttribute';
import construct from '../../Ractive/construct';
import initialise from '../../Ractive/initialise';
import render from '../../Ractive/render';
import { create, extend } from '../../utils/object';
import { createDocumentFragment } from '../../utils/dom';
import createItem from './createItem';
import { removeFromArray } from '../../utils/array';
import { bind, cancel, render as callRender, unbind, unrender, update } from '../../shared/methodCallers';
import Hook from '../../events/Hook';
import EventDirective from './shared/EventDirective';
import RactiveEvent from './component/RactiveEvent';
import updateLiveQueries from './component/updateLiveQueries';
import { updateAnchors } from '../../shared/anchors';

function makeDirty ( query ) {
	query.makeDirty();
}

const teardownHook = new Hook( 'teardown' );

export default class Component extends Item {
	constructor ( options, ComponentConstructor ) {
		super( options );
		this.isAnchor = this.template.t === ANCHOR;
		this.type = this.isAnchor ? ANCHOR : COMPONENT; // override ELEMENT from super

		const partials = options.template.p || {};
		if ( !( 'content' in partials ) ) partials.content = options.template.f || [];
		this._partials = partials; // TEMP

		if ( this.isAnchor ) {
			this.name = options.template.n;

			this.addChild = addChild;
			this.removeChild = removeChild;
		} else {
			const instance = create( ComponentConstructor.prototype );

			this.instance = instance;
			this.name = options.template.e;

			if ( instance.el ) {
				warnIfDebug( `The <${this.name}> component has a default 'el' property; it has been disregarded` );
			}

			this.liveQueries = [];

			// find container
			let fragment = options.parentFragment;
			let container;
			while ( fragment ) {
				if ( fragment.owner.type === YIELDER ) {
					container = fragment.owner.container;
					break;
				}

				fragment = fragment.parent;
			}

			// add component-instance-specific properties
			instance.parent = this.parentFragment.ractive;
			instance.container = container || null;
			instance.root = instance.parent.root;
			instance.component = this;

			construct( this.instance, { partials });

			// for hackability, this could be an open option
			// for any ractive instance, but for now, just
			// for components and just for ractive...
			instance._inlinePartials = partials;
		}

		this.attributeByName = {};

		this.attributes = [];
		const leftovers = [];
		( this.template.m || [] ).forEach( template => {
			switch ( template.t ) {
				case ATTRIBUTE:
				case EVENT:
					this.attributes.push( createItem({
						owner: this,
						parentFragment: this.parentFragment,
						template
					}) );
					break;

				case TRANSITION:
				case BINDING_FLAG:
				case DECORATOR:
					break;

				default:
					leftovers.push( template );
					break;
			}
		});

		this.attributes.push( new ConditionalAttribute({
			owner: this,
			parentFragment: this.parentFragment,
			template: leftovers
		}) );

		this.eventHandlers = [];
	}

	bind () {
		if ( !this.isAnchor ) {
			this.attributes.forEach( bind );

			initialise( this.instance, {
				partials: this._partials
			}, {
				cssIds: this.parentFragment.cssIds
			});

			this.eventHandlers.forEach( bind );

			this.bound = true;
		}
	}

	bubble () {
		if ( !this.isAnchor && !this.dirty ) {
			this.dirty = true;
			this.parentFragment.bubble();
		}
	}

	destroyed () {
		if ( !this.isAnchor && this.instance.fragment ) this.instance.fragment.destroyed();
	}

	detach () {
		if ( this.isAnchor ) {
			if ( this.instance ) return this.instance.fragment.detach();
			return createDocumentFragment()
		}

		return this.instance.fragment.detach();
	}

	find ( selector, options ) {
		if ( this.instance ) return this.instance.fragment.find( selector, options );
	}

	findAll ( selector, query ) {
		if ( this.instance ) this.instance.fragment.findAll( selector, query );
	}

	findComponent ( name, options ) {
		if ( !name || this.name === name ) return this.instance;

		if ( this.instance.fragment ) {
			return this.instance.fragment.findComponent( name, options );
		}
	}

	findAllComponents ( name, query ) {
		if ( this.instance && query.test( this ) ) {
			query.add( this.instance );

			if ( query.live ) {
				this.liveQueries.push( query );
			}
		}

		if ( this.instance ) this.instance.findAllComponents( name, { _query: query } );
	}

	firstNode ( skipParent ) {
		if ( this.instance ) return this.instance.fragment.firstNode( skipParent );
	}

	removeFromQuery ( query ) {
		if ( this.instance ) query.remove( this.instance );
		removeFromArray( this.liveQueries, query );
	}

	render ( target, occupants ) {
		if ( this.isAnchor ) {
			this.target = target;
			if ( !checking.length ) {
				checking.push( this.ractive );
				runloop.scheduleTask( checkAnchors, true );
			}
		} else {
			render( this.instance, target, null, occupants );

			this.checkYielders();
			this.attributes.forEach( callRender );
			this.eventHandlers.forEach( callRender );
			updateLiveQueries( this );
		}
		this.rendered = true;
	}

	shuffled () {
		if ( this.instance ) this.liveQueries.forEach( makeDirty );
		super.shuffled();
	}

	toString () {
		if ( this.instance ) return this.instance.toHTML();
	}

	unbind () {
		if ( !this.isAnchor ) {
			this.bound = false;

			this.attributes.forEach( unbind );

			const instance = this.instance;
			instance.viewmodel.teardown();
			instance.fragment.unbind();
			instance._observers.forEach( cancel );

			if ( instance.fragment.rendered && instance.el.__ractive_instances__ ) {
				removeFromArray( instance.el.__ractive_instances__, instance );
			}

			teardownHook.fire( instance );
		}
	}

	unrender ( shouldDestroy ) {
		this.shouldDestroy = shouldDestroy;

		if ( this.isAnchor ) {
			if ( this.item ) unrenderItem( this, this.item );
			this.target = null;
			if ( !checking.length ) {
				checking.push( this.ractive );
				runloop.scheduleTask( checkAnchors, true );
			}
		} else {
			this.instance.unrender();
			this.instance.el = null;
			this.attributes.forEach( unrender );
			this.eventHandlers.forEach( unrender );

			this.liveQueries.forEach( query => query.remove( this.instance ) );
			this.liveQueries = [];
		}

		this.rendered = false;
	}

	update () {
		this.dirty = false;
		if ( this.instance ) this.instance.fragment.update();
		if ( !this.isAnchor ) {
			this.checkYielders();
			this.attributes.forEach( update );
			this.eventHandlers.forEach( update );
		}
	}
}

function addChild ( meta ) {
	if ( this.item ) this.removeChild( this.item );

	const child = meta.instance;
	meta.anchor = this;

	meta.parentFragment = this.parentFragment;
	meta.name = meta.nameOption || this.name;
	this.name = meta.name;

	if ( !child.isolated ) child.viewmodel.attached( this.parentFragment );

	// render as necessary
	if ( this.rendered ) {
		renderItem( this, meta );
	}
}

function removeChild ( meta ) {
	// unrender as necessary
	if ( this.item === meta ) {
		unrenderItem( this, meta );
		this.name = this.template.n;
	}
}

function renderItem ( anchor, meta ) {
	if ( !anchor.rendered ) return;

	meta.shouldDestroy = false;
	meta.parentFragment = anchor.parentFragment;

	anchor.item = meta;
	anchor.instance = meta.instance;
	anchor.liveQueries = meta.liveQueries;
	const nextNode = anchor.parentFragment.findNextNode( anchor );

	if ( meta.instance.fragment.rendered ) {
		meta.instance.unrender();
	}

	meta.partials = meta.instance.partials;
	meta.instance.partials = extend( {}, meta.partials, anchor._partials );

	meta.instance.fragment.unbind();
	meta.instance.fragment.bind( meta.instance.viewmodel );

	anchor.attributes.forEach( bind );
	anchor.eventHandlers.forEach( bind );
	anchor.attributes.forEach( callRender );
	anchor.eventHandlers.forEach( callRender );

	const target = anchor.parentFragment.findParentNode();
	render( meta.instance, target, target.contains( nextNode ) ? nextNode : null );

	if ( meta.lastBound !== anchor ) {
		meta.lastBound = anchor;
	}

	updateLiveQueries( meta );
}

function unrenderItem ( anchor, meta ) {
	if ( !anchor.rendered ) return;

	meta.shouldDestroy = true;
	meta.instance.unrender();

	anchor.eventHandlers.forEach( unrender );
	anchor.attributes.forEach( unrender );
	anchor.eventHandlers.forEach( unbind );
	anchor.attributes.forEach( unbind );

	meta.instance.el = meta.instance.anchor = null;
	meta.parentFragment = null;
	meta.anchor = null;
	anchor.item = null;
	anchor.instance = null;

	meta.liveQueries.forEach( q => q.remove( meta.instance ) );
	meta.liveQueries = [];
	anchor.liveQueries = null;
}

var checking = [];
export function checkAnchors () {
	const list = checking;
	checking = [];

	list.forEach( updateAnchors );
}
<commit_msg>don't create a conditional attribute for component if there's nothing to put in it<commit_after>import runloop from '../../global/runloop';
import { warnIfDebug } from '../../utils/log';
import { ANCHOR, ATTRIBUTE, BINDING_FLAG, COMPONENT, DECORATOR, EVENT, TRANSITION, YIELDER } from '../../config/types';
import Item from './shared/Item';
import ConditionalAttribute from './element/ConditionalAttribute';
import construct from '../../Ractive/construct';
import initialise from '../../Ractive/initialise';
import render from '../../Ractive/render';
import { create, extend } from '../../utils/object';
import { createDocumentFragment } from '../../utils/dom';
import createItem from './createItem';
import { removeFromArray } from '../../utils/array';
import { bind, cancel, render as callRender, unbind, unrender, update } from '../../shared/methodCallers';
import Hook from '../../events/Hook';
import EventDirective from './shared/EventDirective';
import RactiveEvent from './component/RactiveEvent';
import updateLiveQueries from './component/updateLiveQueries';
import { updateAnchors } from '../../shared/anchors';

function makeDirty ( query ) {
	query.makeDirty();
}

const teardownHook = new Hook( 'teardown' );

export default class Component extends Item {
	constructor ( options, ComponentConstructor ) {
		super( options );
		this.isAnchor = this.template.t === ANCHOR;
		this.type = this.isAnchor ? ANCHOR : COMPONENT; // override ELEMENT from super

		const partials = options.template.p || {};
		if ( !( 'content' in partials ) ) partials.content = options.template.f || [];
		this._partials = partials; // TEMP

		if ( this.isAnchor ) {
			this.name = options.template.n;

			this.addChild = addChild;
			this.removeChild = removeChild;
		} else {
			const instance = create( ComponentConstructor.prototype );

			this.instance = instance;
			this.name = options.template.e;

			if ( instance.el ) {
				warnIfDebug( `The <${this.name}> component has a default 'el' property; it has been disregarded` );
			}

			this.liveQueries = [];

			// find container
			let fragment = options.parentFragment;
			let container;
			while ( fragment ) {
				if ( fragment.owner.type === YIELDER ) {
					container = fragment.owner.container;
					break;
				}

				fragment = fragment.parent;
			}

			// add component-instance-specific properties
			instance.parent = this.parentFragment.ractive;
			instance.container = container || null;
			instance.root = instance.parent.root;
			instance.component = this;

			construct( this.instance, { partials });

			// for hackability, this could be an open option
			// for any ractive instance, but for now, just
			// for components and just for ractive...
			instance._inlinePartials = partials;
		}

		this.attributeByName = {};

		this.attributes = [];
		const leftovers = [];
		( this.template.m || [] ).forEach( template => {
			switch ( template.t ) {
				case ATTRIBUTE:
				case EVENT:
					this.attributes.push( createItem({
						owner: this,
						parentFragment: this.parentFragment,
						template
					}) );
					break;

				case TRANSITION:
				case BINDING_FLAG:
				case DECORATOR:
					break;

				default:
					leftovers.push( template );
					break;
			}
		});

		if ( leftovers.length ) {
			this.attributes.push( new ConditionalAttribute({
				owner: this,
				parentFragment: this.parentFragment,
				template: leftovers
			}) );
		}

		this.eventHandlers = [];
	}

	bind () {
		if ( !this.isAnchor ) {
			this.attributes.forEach( bind );

			initialise( this.instance, {
				partials: this._partials
			}, {
				cssIds: this.parentFragment.cssIds
			});

			this.eventHandlers.forEach( bind );

			this.bound = true;
		}
	}

	bubble () {
		if ( !this.isAnchor && !this.dirty ) {
			this.dirty = true;
			this.parentFragment.bubble();
		}
	}

	destroyed () {
		if ( !this.isAnchor && this.instance.fragment ) this.instance.fragment.destroyed();
	}

	detach () {
		if ( this.isAnchor ) {
			if ( this.instance ) return this.instance.fragment.detach();
			return createDocumentFragment()
		}

		return this.instance.fragment.detach();
	}

	find ( selector, options ) {
		if ( this.instance ) return this.instance.fragment.find( selector, options );
	}

	findAll ( selector, query ) {
		if ( this.instance ) this.instance.fragment.findAll( selector, query );
	}

	findComponent ( name, options ) {
		if ( !name || this.name === name ) return this.instance;

		if ( this.instance.fragment ) {
			return this.instance.fragment.findComponent( name, options );
		}
	}

	findAllComponents ( name, query ) {
		if ( this.instance && query.test( this ) ) {
			query.add( this.instance );

			if ( query.live ) {
				this.liveQueries.push( query );
			}
		}

		if ( this.instance ) this.instance.findAllComponents( name, { _query: query } );
	}

	firstNode ( skipParent ) {
		if ( this.instance ) return this.instance.fragment.firstNode( skipParent );
	}

	removeFromQuery ( query ) {
		if ( this.instance ) query.remove( this.instance );
		removeFromArray( this.liveQueries, query );
	}

	render ( target, occupants ) {
		if ( this.isAnchor ) {
			this.target = target;
			if ( !checking.length ) {
				checking.push( this.ractive );
				runloop.scheduleTask( checkAnchors, true );
			}
		} else {
			render( this.instance, target, null, occupants );

			this.checkYielders();
			this.attributes.forEach( callRender );
			this.eventHandlers.forEach( callRender );
			updateLiveQueries( this );
		}
		this.rendered = true;
	}

	shuffled () {
		if ( this.instance ) this.liveQueries.forEach( makeDirty );
		super.shuffled();
	}

	toString () {
		if ( this.instance ) return this.instance.toHTML();
	}

	unbind () {
		if ( !this.isAnchor ) {
			this.bound = false;

			this.attributes.forEach( unbind );

			const instance = this.instance;
			instance.viewmodel.teardown();
			instance.fragment.unbind();
			instance._observers.forEach( cancel );

			if ( instance.fragment.rendered && instance.el.__ractive_instances__ ) {
				removeFromArray( instance.el.__ractive_instances__, instance );
			}

			teardownHook.fire( instance );
		}
	}

	unrender ( shouldDestroy ) {
		this.shouldDestroy = shouldDestroy;

		if ( this.isAnchor ) {
			if ( this.item ) unrenderItem( this, this.item );
			this.target = null;
			if ( !checking.length ) {
				checking.push( this.ractive );
				runloop.scheduleTask( checkAnchors, true );
			}
		} else {
			this.instance.unrender();
			this.instance.el = null;
			this.attributes.forEach( unrender );
			this.eventHandlers.forEach( unrender );

			this.liveQueries.forEach( query => query.remove( this.instance ) );
			this.liveQueries = [];
		}

		this.rendered = false;
	}

	update () {
		this.dirty = false;
		if ( this.instance ) this.instance.fragment.update();
		if ( !this.isAnchor ) {
			this.checkYielders();
			this.attributes.forEach( update );
			this.eventHandlers.forEach( update );
		}
	}
}

function addChild ( meta ) {
	if ( this.item ) this.removeChild( this.item );

	const child = meta.instance;
	meta.anchor = this;

	meta.parentFragment = this.parentFragment;
	meta.name = meta.nameOption || this.name;
	this.name = meta.name;

	if ( !child.isolated ) child.viewmodel.attached( this.parentFragment );

	// render as necessary
	if ( this.rendered ) {
		renderItem( this, meta );
	}
}

function removeChild ( meta ) {
	// unrender as necessary
	if ( this.item === meta ) {
		unrenderItem( this, meta );
		this.name = this.template.n;
	}
}

function renderItem ( anchor, meta ) {
	if ( !anchor.rendered ) return;

	meta.shouldDestroy = false;
	meta.parentFragment = anchor.parentFragment;

	anchor.item = meta;
	anchor.instance = meta.instance;
	anchor.liveQueries = meta.liveQueries;
	const nextNode = anchor.parentFragment.findNextNode( anchor );

	if ( meta.instance.fragment.rendered ) {
		meta.instance.unrender();
	}

	meta.partials = meta.instance.partials;
	meta.instance.partials = extend( {}, meta.partials, anchor._partials );

	meta.instance.fragment.unbind();
	meta.instance.fragment.bind( meta.instance.viewmodel );

	anchor.attributes.forEach( bind );
	anchor.eventHandlers.forEach( bind );
	anchor.attributes.forEach( callRender );
	anchor.eventHandlers.forEach( callRender );

	const target = anchor.parentFragment.findParentNode();
	render( meta.instance, target, target.contains( nextNode ) ? nextNode : null );

	if ( meta.lastBound !== anchor ) {
		meta.lastBound = anchor;
	}

	updateLiveQueries( meta );
}

function unrenderItem ( anchor, meta ) {
	if ( !anchor.rendered ) return;

	meta.shouldDestroy = true;
	meta.instance.unrender();

	anchor.eventHandlers.forEach( unrender );
	anchor.attributes.forEach( unrender );
	anchor.eventHandlers.forEach( unbind );
	anchor.attributes.forEach( unbind );

	meta.instance.el = meta.instance.anchor = null;
	meta.parentFragment = null;
	meta.anchor = null;
	anchor.item = null;
	anchor.instance = null;

	meta.liveQueries.forEach( q => q.remove( meta.instance ) );
	meta.liveQueries = [];
	anchor.liveQueries = null;
}

var checking = [];
export function checkAnchors () {
	const list = checking;
	checking = [];

	list.forEach( updateAnchors );
}
<|endoftext|>


<commit_before>/**
 * @depends ../core/AudioletNode.js
 */

var CrossFade = new Class({
    Extends: AudioletNode,
    initialize: function(audiolet, position) {
        AudioletNode.prototype.initialize.apply(this, [audiolet, 3, 1]);
        this.linkNumberOfOutputChannels(0, 0);
        this.position = new AudioletParameter(this, 2, position || 0.5);
    },

    generate: function(inputBuffers, outputBuffers) {
        var inputBufferA = inputBuffers[0];
        var inputBufferB = inputBuffers[1];
        var outputBuffer = outputBuffers[0];

        var inputChannelsA = inputBufferA.channels;
        var inputChannelsB = inputBufferB.channels;
        var outputChannels = outputBuffer.channels;

        if (inputBufferA.isEmpty || inputBufferB.isEmpty) {
            outputBuffer.isEmpty = true;
            return;
        }

        // Local processing variables
        var positionParameter = this.position;
        var position, positionChannel;
        if (positionParameter.isStatic()) {
            position = positionParameter.getValue();
        }
        else {
            positionChannel = positionParameter.getChannel();
        }

        var bufferLength = outputBuffer.length;
        for (var i = 0; i < bufferLength; i++) {
            if (positionChannel) {
                position = positionChannel[i];
            }
            var scaledPosition = position * Math.PI / 2;
            // TODO: Use sine/cos tables?
            var gainA = Math.cos(scaledPosition);
            var gainB = Math.sin(scaledPosition);

            var numberOfChannels = inputBufferA.numberOfChannels;
            for (var j = 0; j < numberOfChannels; j++) {
                var inputChannelA = inputChannelsA[j];
                var inputChannelB = inputChannelsB[j];
                var outputChannel = outputChannels[j];

                outputChannel[i] = inputChannelA[i] * gainA +
                                   inputChannelB[i] * gainB;
            }
        }
    },

    toString: function() {
        return 'Cross Fader';
    }
});
<commit_msg>Make crossfade handle the situation where one buffer is empty, but the other isn't.<commit_after>/**
 * @depends ../core/AudioletNode.js
 */

var CrossFade = new Class({
    Extends: AudioletNode,
    initialize: function(audiolet, position) {
        AudioletNode.prototype.initialize.apply(this, [audiolet, 3, 1]);
        this.linkNumberOfOutputChannels(0, 0);
        this.position = new AudioletParameter(this, 2, position || 0.5);
    },

    generate: function(inputBuffers, outputBuffers) {
        var inputBufferA = inputBuffers[0];
        var inputBufferB = inputBuffers[1];
        var outputBuffer = outputBuffers[0];

        var inputChannelsA = inputBufferA.channels;
        var inputChannelsB = inputBufferB.channels;
        var outputChannels = outputBuffer.channels;

        if (inputBufferA.isEmpty && inputBufferB.isEmpty) {
            outputBuffer.isEmpty = true;
            return;
        }

        // Local processing variables
        var positionParameter = this.position;
        var position, positionChannel;
        if (positionParameter.isStatic()) {
            position = positionParameter.getValue();
        }
        else {
            positionChannel = positionParameter.getChannel();
        }

        var bufferLength = outputBuffer.length;
        for (var i = 0; i < bufferLength; i++) {
            if (positionChannel) {
                position = positionChannel[i];
            }
            var scaledPosition = position * Math.PI / 2;
            // TODO: Use sine/cos tables?
            var gainA = Math.cos(scaledPosition);
            var gainB = Math.sin(scaledPosition);

            var numberOfChannels = inputBufferA.numberOfChannels;
            for (var j = 0; j < numberOfChannels; j++) {
                var inputChannelA = inputChannelsA[j];
                var inputChannelB = inputChannelsB[j];
                var outputChannel = outputChannels[j];

                var valueA, valueB;
                if (!inputBufferA.isEmpty) {
                    valueA = inputChannelA[i];
                }
                else {
                    valueA = 0;
                }

                if (!inputBufferB.isEmpty) {
                    valueB = inputChannelB[i];
                }
                else {
                    valueB = 0;
                }
                outputChannel[i] = valueA * gainA +
                                   valueB * gainB;
            }
        }
    },

    toString: function() {
        return 'Cross Fader';
    }
});
<|endoftext|>