<commit_before>/**
 * @module menu
 */

modules.define(
    'menu',
    ['i-bem__dom', 'control', 'keyboard__codes', 'menu-item'],
    function(provide, BEMDOM, Control, keyCodes) {

/** @const Number */
var TIMEOUT_KEYBOARD_SEARCH = 1500;

/**
 * @exports
 * @class menu
 * @augments control
 * @bem
 */
provide(BEMDOM.decl({ block : this.name, baseBlock : Control }, /** @lends menu.prototype */{
    onSetMod : {
        'js' : {
            'inited' : function() {
                this.__base.apply(this, arguments);
                this._hoveredItem = null;
                this._items = null;

                this._lastTyping = {
                    char : '',
                    text : '',
                    index : 0,
                    time : 0
                };

                this.hasMod('focused') && this.bindToDoc('keydown', this._onKeyDown);
            }
        },

        'focused' : {
            'true' : function() {
                this.__base.apply(this, arguments);
                this
                    .bindToDoc('keydown', this._onKeyDown) // NOTE: should be called after __base
                    .bindToDoc('keypress', this._onKeyPress);
            },

            '' : function() {
                this
                    .unbindFromDoc('keydown', this._onKeyDown)
                    .unbindFromDoc('keypress', this._onKeyPress)
                    .__base.apply(this, arguments);
                this._hoveredItem && this._hoveredItem.delMod('hovered');
            }
        },

        'disabled' : function(modName, modVal) {
            this.getItems().forEach(function(menuItem){
                menuItem.setMod(modName, modVal);
            });
        }
    },

    /**
     * Returns items
     * @returns {menu-item[]}
     */
    getItems : function() {
        return this._items || (this._items = this.findBlocksInside('menu-item'));
    },

    /**
     * Sets content
     * @param {String|jQuery} content
     * @returns {menu} this
     */
    setContent : function(content) {
        BEMDOM.update(this.domElem, content);
        this._hoveredItem = null;
        this._items = null;
        return this;
    },

    /**
     * Search menu item by keyboard event
     * @param {jQuery.Event} e
     * @returns {menu-item}
     */
    searchItemByKeyboardEvent : function(e) {
        var currentTime = +new Date(),
            charCode = e.charCode,
            char = String.fromCharCode(charCode).toLowerCase(),
            lastTyping = this._lastTyping,
            index = lastTyping.index,
            isSameChar = char === lastTyping.char && lastTyping.text.length === 1,
            items = this.getItems();

        if(charCode <= keyCodes.SPACE || e.ctrlKey || e.altKey || e.metaKey) {
            lastTyping.time = currentTime;
            return null;
        }

        if(currentTime - lastTyping.time > TIMEOUT_KEYBOARD_SEARCH || isSameChar) {
            lastTyping.text = char;
        } else {
            lastTyping.text += char;
        }

        lastTyping.char = char;
        lastTyping.time = currentTime;

        // If key is pressed again, then continue to search to next menu item
        if(isSameChar && items[index].getText().search(lastTyping.char) === 0) {
            index = index >= items.length - 1? 0 : index + 1;
        }

        // 2 passes: from index to items.length and from 0 to index.
        var i = index, len = items.length;
        while(i < len) {
            if(this._doesItemMatchText(items[i], lastTyping.text)) {
                lastTyping.index = i;
                return items[i];
            }

            i++;

            if(i === items.length) {
                i = 0;
                len = index;
            }
        }

        return null;
    },

    _onItemHover : function(item) {
        if(item.hasMod('hovered')) {
            this._hoveredItem && this._hoveredItem.delMod('hovered');
            this._scrollToItem(this._hoveredItem = item);
        } else if(this._hoveredItem === item) {
            this._hoveredItem = null;
        }
    },

    _scrollToItem : function(item) {
        var domElemOffsetTop = this.domElem.offset().top,
            itemDomElemOffsetTop = item.domElem.offset().top,
            relativeScroll;

        if((relativeScroll = itemDomElemOffsetTop - domElemOffsetTop) < 0 ||
            (relativeScroll =
                itemDomElemOffsetTop +
                item.domElem.outerHeight() -
                domElemOffsetTop -
                this.domElem.outerHeight()) > 0) {
            this.domElem.scrollTop(this.domElem.scrollTop() + relativeScroll);
        }
    },

    _onItemClick : function(item, data) {
        this.emit('item-click', { item : item, source : data.source });
    },

    _onKeyDown : function(e) {
        var keyCode = e.keyCode,
            isArrow = keyCode === keyCodes.UP || keyCode === keyCodes.DOWN;

        if(isArrow && !e.shiftKey) {
            e.preventDefault();

            var dir = keyCode - 39, // using the features of key codes for "up"/"down" ;-)
                items = this.getItems(),
                len = items.length,
                hoveredIdx = items.indexOf(this._hoveredItem),
                nextIdx = hoveredIdx,
                i = 0;

            do {
                nextIdx += dir;
                nextIdx = nextIdx < 0? len - 1 : nextIdx >= len? 0 : nextIdx;
                if(++i === len) return; // if we have no next item to hover
            } while(items[nextIdx].hasMod('disabled'));

            this._lastTyping.index = nextIdx;

            items[nextIdx].setMod('hovered');
        }
    },

    _onKeyPress : function(e) {
        var item = this.searchItemByKeyboardEvent(e);
        item && item.setMod('hovered');
    },

    _doesItemMatchText : function(item, text) {
        return !item.hasMod('disabled') &&
            item.getText().toLowerCase().search(text) === 0;
    }
}, /** @lends menu */{
    live : function() {
        this
            .liveInitOnBlockInsideEvent({ modName : 'hovered', modVal : '*' }, 'menu-item', function(e) {
                this._onItemHover(e.target);
            })
            .liveInitOnBlockInsideEvent('click', 'menu-item', function(e, data) {
                this._onItemClick(e.target, data);
            });

        return this.__base.apply(this, arguments);
    }
}));

});
<commit_msg>menu: two _onKeyDown handler binds if block is inited on focus (close #1381)<commit_after>/**
 * @module menu
 */

modules.define(
    'menu',
    ['i-bem__dom', 'control', 'keyboard__codes', 'menu-item'],
    function(provide, BEMDOM, Control, keyCodes) {

/** @const Number */
var TIMEOUT_KEYBOARD_SEARCH = 1500;

/**
 * @exports
 * @class menu
 * @augments control
 * @bem
 */
provide(BEMDOM.decl({ block : this.name, baseBlock : Control }, /** @lends menu.prototype */{
    onSetMod : {
        'js' : {
            'inited' : function() {
                this.__base.apply(this, arguments);
                this._hoveredItem = null;
                this._items = null;

                this._lastTyping = {
                    char : '',
                    text : '',
                    index : 0,
                    time : 0
                };
            }
        },

        'disabled' : function(modName, modVal) {
            this.getItems().forEach(function(menuItem){
                menuItem.setMod(modName, modVal);
            });
        }
    },

    /**
     * Returns items
     * @returns {menu-item[]}
     */
    getItems : function() {
        return this._items || (this._items = this.findBlocksInside('menu-item'));
    },

    /**
     * Sets content
     * @param {String|jQuery} content
     * @returns {menu} this
     */
    setContent : function(content) {
        BEMDOM.update(this.domElem, content);
        this._hoveredItem = null;
        this._items = null;
        return this;
    },

    /**
     * Search menu item by keyboard event
     * @param {jQuery.Event} e
     * @returns {menu-item}
     */
    searchItemByKeyboardEvent : function(e) {
        var currentTime = +new Date(),
            charCode = e.charCode,
            char = String.fromCharCode(charCode).toLowerCase(),
            lastTyping = this._lastTyping,
            index = lastTyping.index,
            isSameChar = char === lastTyping.char && lastTyping.text.length === 1,
            items = this.getItems();

        if(charCode <= keyCodes.SPACE || e.ctrlKey || e.altKey || e.metaKey) {
            lastTyping.time = currentTime;
            return null;
        }

        if(currentTime - lastTyping.time > TIMEOUT_KEYBOARD_SEARCH || isSameChar) {
            lastTyping.text = char;
        } else {
            lastTyping.text += char;
        }

        lastTyping.char = char;
        lastTyping.time = currentTime;

        // If key is pressed again, then continue to search to next menu item
        if(isSameChar && items[index].getText().search(lastTyping.char) === 0) {
            index = index >= items.length - 1? 0 : index + 1;
        }

        // 2 passes: from index to items.length and from 0 to index.
        var i = index, len = items.length;
        while(i < len) {
            if(this._doesItemMatchText(items[i], lastTyping.text)) {
                lastTyping.index = i;
                return items[i];
            }

            i++;

            if(i === items.length) {
                i = 0;
                len = index;
            }
        }

        return null;
    },

    /** @override **/
    _onFocus : function() {
        this.__base.apply(this, arguments);
        this
            .bindToDoc('keydown', this._onKeyDown) // NOTE: should be called after __base
            .bindToDoc('keypress', this._onKeyPress);
    },

    /** @override **/
    _onBlur : function() {
        this
            .unbindFromDoc('keydown', this._onKeyDown)
            .unbindFromDoc('keypress', this._onKeyPress)
            .__base.apply(this, arguments);
        this._hoveredItem && this._hoveredItem.delMod('hovered');
    },

    _onItemHover : function(item) {
        if(item.hasMod('hovered')) {
            this._hoveredItem && this._hoveredItem.delMod('hovered');
            this._scrollToItem(this._hoveredItem = item);
        } else if(this._hoveredItem === item) {
            this._hoveredItem = null;
        }
    },

    _scrollToItem : function(item) {
        var domElemOffsetTop = this.domElem.offset().top,
            itemDomElemOffsetTop = item.domElem.offset().top,
            relativeScroll;

        if((relativeScroll = itemDomElemOffsetTop - domElemOffsetTop) < 0 ||
            (relativeScroll =
                itemDomElemOffsetTop +
                item.domElem.outerHeight() -
                domElemOffsetTop -
                this.domElem.outerHeight()) > 0) {
            this.domElem.scrollTop(this.domElem.scrollTop() + relativeScroll);
        }
    },

    _onItemClick : function(item, data) {
        this.emit('item-click', { item : item, source : data.source });
    },

    _onKeyDown : function(e) {
        var keyCode = e.keyCode,
            isArrow = keyCode === keyCodes.UP || keyCode === keyCodes.DOWN;

        if(isArrow && !e.shiftKey) {
            e.preventDefault();

            var dir = keyCode - 39, // using the features of key codes for "up"/"down" ;-)
                items = this.getItems(),
                len = items.length,
                hoveredIdx = items.indexOf(this._hoveredItem),
                nextIdx = hoveredIdx,
                i = 0;

            do {
                nextIdx += dir;
                nextIdx = nextIdx < 0? len - 1 : nextIdx >= len? 0 : nextIdx;
                if(++i === len) return; // if we have no next item to hover
            } while(items[nextIdx].hasMod('disabled'));

            this._lastTyping.index = nextIdx;

            items[nextIdx].setMod('hovered');
        }
    },

    _onKeyPress : function(e) {
        var item = this.searchItemByKeyboardEvent(e);
        item && item.setMod('hovered');
    },

    _doesItemMatchText : function(item, text) {
        return !item.hasMod('disabled') &&
            item.getText().toLowerCase().search(text) === 0;
    }
}, /** @lends menu */{
    live : function() {
        this
            .liveInitOnBlockInsideEvent({ modName : 'hovered', modVal : '*' }, 'menu-item', function(e) {
                this._onItemHover(e.target);
            })
            .liveInitOnBlockInsideEvent('click', 'menu-item', function(e, data) {
                this._onItemClick(e.target, data);
            });

        return this.__base.apply(this, arguments);
    }
}));

});
<|endoftext|>


<commit_before>/**
 *  \details © 2011  Open Ximdex Evolution SL [http://www.ximdex.org]
 *
 *  Ximdex a Semantic Content Management System (CMS)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  See the Affero GNU General Public License for more details.
 *  You should have received a copy of the Affero GNU General Public License
 *  version 3 along with Ximdex (see LICENSE file).
 *
 *  If not, visit http://gnu.org/licenses/agpl-3.0.html.
 *
 *  @author Ximdex DevTeam <dev@ximdex.com>
 *  @version $Revision$
 */

angular.module('ximdex.common.service')
    .factory('xMenu', ['$window', '$rootScope', function($window, $rootScope) {

    	var createButton = function(options) {
			options = $.extend({
				text: '',
				title: '',
				value: '',
				data: {},
				className: '',
				click: function() {},
				icon: null,
				container: null
			}, options);

			var b = $('<button></button>')
				.addClass('window-toolbar-button '+options.className + ' ' +options.value)
				//.html($('').html(options.text))
				.val(options.value)
				.data('data', options.data)
//				.attr('title', options.title)
				.click(options.click);

			$(b)
				.append($('Icono'))
				.append($('').html(options.text));

			if (!Object.isEmpty(options.icon)) {

				var icon = options.icon.substr(0, options.icon.length-4);
				b.addClass('icon-'+icon);
			}

			if (options.container !== null) {
				b.appendTo(options.container);
			}
			$(b).wrap('
');
			return b;
		}

    	var createButtonList = function(options) {
    	    options = $.extend({
    	        text: '',
    	        title: '',
    	        value: '',
    	        data: {},
    	        className: '',
    	        click: function() {},
    	        icon: null,
    	        container: null
    	    }, options);

    	    var ndiv = $('
').addClass('button-container-list');
    	    var ndiv = $('
').addClass('button-container-list icon').addClass(options.value).html(options.text);
    	    ndiv.data('data',options.data).click(options.click);

    	    /*if (!Object.isEmpty(options.icon)) {

    	        var icon = options.icon.substr(0, options.icon.length-4);
    	        ndiv.append($('').addClass(options.value).addClass('list-icon').html("Icono"));
    	    }

    	    ndiv.append($('').addClass('button-text icon').addClass(options.value).html(options.text));*/

    	    if (options.container !== null) {
    	        ndiv.appendTo(options.container);
    	    }

    	    return ndiv;
    	}
    	var createFloatMenu = function(params) {
    	    var nodeid = params.data.nodeid.value;
    	    var cmenu = $('div.xim-actions-menu').unbind().empty();
    	    var show = true;

    	    if (cmenu.length == 0) {

    	        cmenu = $('

')
    	            .addClass('xim-actions-menu destroy-on-click')
    	            .attr('id', 'cmenu-'+nodeid);

    	    } else if ($(cmenu).attr('id') == 'cmenu-'+nodeid) {
    	        show = false;
    	    }

    	    show = show & (params.actions.length > 0);

    	    if (!show) {
    	        $(cmenu).unbind().remove();
    	        return;
    	    }

    	    if (Object.isFunction(params.actions.each)) {

    	        params.actions.each(function(index, item) {
    	            item.params = item.params.replace('%3D', '=');
    	            createButton({
    	                text: item.name,
    	                title: item.name,
    	                value: item.command,
    	                data: {
    	                    action: item,
    	                    nodes: params.nodes,
    	                    ids: params.ids
    	                },
    	                className: 'view-action',
    	                icon: item.icon,
    	                click: function(e) {
    	                    var data = $(e.currentTarget).data('data');
    	                    params.result(data.action, params.ids);
    	                }.bind(this),
    	                container: cmenu
    	            });
    	        });

    	        cmenu
    	            .css({
    	                position: 'absolute',
    	                left: params.menuPos.x,
    	                top: params.menuPos.y
    	            })
    	            .appendTo('body');

    	    }
    	}
    	var createFloatMenuList = function(params) {
			var nodeid = params.data.nodeid.value;
			var cmenu = $('div.xim-actions-menu').unbind().empty();
			var show = true;

			if (cmenu.length == 0) {

				cmenu = $('

')
					.addClass('xim-actions-menu xim-actions-menu-list destroy-on-click')
					.attr('id', 'cmenu-'+nodeid);

			} else if ($(cmenu).attr('id') == 'cmenu-'+nodeid) {
				show = false;
			}

			show = show & (params.actions.length > 0);

			if (!show) {
				$(cmenu).unbind().remove();
				return;
			}

			if (Object.isFunction(params.actions.each)) {

				params.actions.each(function(index, item) {
					item.params = item.params.replace('%3D', '=');
					createButtonList({
						text: item.name,
						title: item.name,
						value: item.command,
						data: {
							action: item,
							nodes: params.nodes,
							ids: params.ids
						},
						className: 'view-action',
						icon: item.icon,
						click: function(e) {
							var data = $(e.currentTarget).data('data');
							params.result(data.action, params.ids);
						}.bind(this),
						container: cmenu
					});
				});

				cmenu
					.css({
						position: 'absolute',
						left: params.menuPos.x,
						top: params.menuPos.y
					})
					.appendTo('body');

				//Detect End Page Collision
				var windowY = window.innerHeight;
				var menuY = $(cmenu).height();
				var finY  = menuY + params.menuPos.y;

				if(finY > windowY){
					params.menuPos.y = windowY - menuY - 20;
					$(cmenu).css({
						top: params.menuPos.y
					});
				}

			}
		}
        return {
            legacyOpen: function(params) {
            	if (params.inline) {
            		createFloatMenu(params);
            	} else {
            		createFloatMenuList(params);
            	}
            }
        }
    }]);<commit_msg>Minor issue<commit_after>/**
 *  \details © 2011  Open Ximdex Evolution SL [http://www.ximdex.org]
 *
 *  Ximdex a Semantic Content Management System (CMS)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  See the Affero GNU General Public License for more details.
 *  You should have received a copy of the Affero GNU General Public License
 *  version 3 along with Ximdex (see LICENSE file).
 *
 *  If not, visit http://gnu.org/licenses/agpl-3.0.html.
 *
 *  @author Ximdex DevTeam <dev@ximdex.com>
 *  @version $Revision$
 */

angular.module('ximdex.common.service')
    .factory('xMenu', ['$window', '$rootScope', function($window, $rootScope) {

    	var createButton = function(options) {
			options = $.extend({
				text: '',
				title: '',
				value: '',
				data: {},
				className: '',
				click: function() {},
				icon: null,
				container: null
			}, options);

			var b = $('<button></button>')
				.addClass('window-toolbar-button '+options.className + ' ' +options.value)
				//.html($('').html(options.text))
				.val(options.value)
				.data('data', options.data)
//				.attr('title', options.title)
				.click(options.click);

			$(b)
				.append($('Icono'))
				.append($('').html(options.text));

			if (!Object.isEmpty(options.icon)) {

				var icon = options.icon.substr(0, options.icon.length-4);
				b.addClass('icon-'+icon);
			}

			if (options.container !== null) {
				b.appendTo(options.container);
			}
			$(b).wrap('
');
			return b;
		}

    	var createButtonList = function(options) {
    	    options = $.extend({
    	        text: '',
    	        title: '',
    	        value: '',
    	        data: {},
    	        className: '',
    	        click: function() {},
    	        icon: null,
    	        container: null
    	    }, options);

    	    var ndiv = $('
').addClass('button-container-list');
    	    var ndiv = $('
').addClass('button-container-list icon').addClass(options.value).html(options.text);
    	    ndiv.data('data',options.data).click(options.click);

    	    if (options.container !== null) {
    	        ndiv.appendTo(options.container);
    	    }

    	    return ndiv;
    	}
    	var createFloatMenu = function(params) {
    	    var nodeid = params.data.nodeid.value;
    	    var cmenu = $('div.xim-actions-menu').unbind().empty();
    	    var show = true;

    	    if (cmenu.length == 0) {

    	        cmenu = $('

')
    	            .addClass('xim-actions-menu destroy-on-click')
    	            .attr('id', 'cmenu-'+nodeid);

    	    } else if ($(cmenu).attr('id') == 'cmenu-'+nodeid) {
    	        show = false;
    	    }

    	    show = show & (params.actions.length > 0);

    	    if (!show) {
    	        $(cmenu).unbind().remove();
    	        return;
    	    }

    	    if (Object.isFunction(params.actions.each)) {

    	        params.actions.each(function(index, item) {
    	            item.params = item.params.replace('%3D', '=');
    	            createButton({
    	                text: item.name,
    	                title: item.name,
    	                value: item.command,
    	                data: {
    	                    action: item,
    	                    nodes: params.nodes,
    	                    ids: params.ids
    	                },
    	                className: 'view-action',
    	                icon: item.icon,
    	                click: function(e) {
    	                    var data = $(e.currentTarget).data('data');
    	                    params.result(data.action, params.ids);
    	                }.bind(this),
    	                container: cmenu
    	            });
    	        });

    	        cmenu
    	            .css({
    	                position: 'absolute',
    	                left: params.menuPos.x,
    	                top: params.menuPos.y
    	            })
    	            .appendTo('body');

    	    }
    	}
    	var createFloatMenuList = function(params) {
			var nodeid = params.data.nodeid.value;
			var cmenu = $('div.xim-actions-menu').unbind().empty();
			var show = true;

			if (cmenu.length == 0) {

				cmenu = $('

')
					.addClass('xim-actions-menu xim-actions-menu-list destroy-on-click')
					.attr('id', 'cmenu-'+nodeid);

			} else if ($(cmenu).attr('id') == 'cmenu-'+nodeid) {
				show = false;
			}

			show = show & (params.actions.length > 0);

			if (!show) {
				$(cmenu).unbind().remove();
				return;
			}

			if (Object.isFunction(params.actions.each)) {

				params.actions.each(function(index, item) {
					item.params = item.params.replace('%3D', '=');
					createButtonList({
						text: item.name,
						title: item.name,
						value: item.command,
						data: {
							action: item,
							nodes: params.nodes,
							ids: params.ids
						},
						className: 'view-action',
						icon: item.icon,
						click: function(e) {
							var data = $(e.currentTarget).data('data');
							params.result(data.action, params.ids);
						}.bind(this),
						container: cmenu
					});
				});

				cmenu
					.css({
						position: 'absolute',
						left: params.menuPos.x,
						top: params.menuPos.y
					})
					.appendTo('body');

				//Detect End Page Collision
				var windowY = window.innerHeight;
				var menuY = $(cmenu).height();
				var finY  = menuY + params.menuPos.y;

				if(finY > windowY){
					params.menuPos.y = windowY - menuY - 20;
					$(cmenu).css({
						top: params.menuPos.y
					});
				}

			}
		}
        return {
            legacyOpen: function(params) {
            	if (params.inline) {
            		createFloatMenu(params);
            	} else {
            		createFloatMenuList(params);
            	}
            }
        }
    }]);<|endoftext|>


<commit_before>const fs     = require('fs')
const path   = require('path')
const script = require('../assets/nexrender.jsx')

/* helpers */

const selectLayers = ({ composition, layerName, layerIndex }, callbackString) => {
    const method = layerName ? 'selectLayersByName' : 'selectLayersByIndex';
    const compo  = composition === undefined ? 'null' : `'${composition}'`;
    const value  = layerName ? `'${layerName}'` : layerIndex;

    return (`nexrender.${method}(${compo}, ${value}, ${callbackString});`);
}

const renderIf = (value, string, encode) => {
    const encoded = !encode ? value : typeof value == 'string' ? `'${value}'` : JSON.stringify(value);
    return value === undefined ? '' : string.replace('$value', encoded);
}

/* scripting wrappers */

const wrapFootage = ({ dest, ...asset }) => (`(function() {
    ${selectLayers(asset, `function(layer) {
        nexrender.replaceFootage(layer, '${dest.replace(/\\/g, "\\\\")}')
    }`)}
})();\n`)

const wrapData = ({ property, value, expression, ...asset }) => (`(function() {
    ${selectLayers(asset, `function(layer) {
        var property = layer.property('${property}');
        if (!property) { return false; }

        ${renderIf(value, `property.setValue($value);`, 1)}
        ${renderIf(expression, `property.expression = '$value;'`, 0)}

        return true;
    }`)}
})();\n`)

const wrapScript = ({ dest }) => (`(function() {
    ${fs.readFileSync(dest, 'utf8')}
})();\n`)

module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] running script assemble...`);

    const data = [];
    const base = job.workpath;

    job.assets.map(asset => {
        switch (asset.type) {
            case 'video':
            case 'audio':
            case 'image':
                data.push(wrapFootage(asset));
                break;

            case 'data':
                data.push(wrapData(asset));
                break;

            case 'script':
                data.push(wrapScript(asset));
                break;
        }
    });

    /* write out assembled custom script file in the workpath */
    job.scriptfile = path.join(base, `nexrender-${job.uid}-script.jsx`);
    fs.writeFileSync(job.scriptfile, script
        .replace('/*COMPOSITION*/', job.template.composition)
        .replace('/*USERSCRIPT*/', data.join('\n'))
    );

    return Promise.resolve(job)
}
<commit_msg>added script string escaping<commit_after>const fs     = require('fs')
const path   = require('path')
const script = require('../assets/nexrender.jsx')

/* helpers */

const escape = string => `'${string.replace(/\'/g, '\\\'')}'`

const selectLayers = ({ composition, layerName, layerIndex }, callbackString) => {
    const method = layerName ? 'selectLayersByName' : 'selectLayersByIndex';
    const compo  = composition === undefined ? 'null' : escape(composition);
    const value  = layerName ? escape(layerName) : layerIndex;

    return (`nexrender.${method}(${compo}, ${value}, ${callbackString});`);
}

const renderIf = (value, string) => {
    const encoded = typeof value == 'string' ? escape(value) : JSON.stringify(value);
    return value === undefined ? '' : string.replace('$value', encoded);
}

/* scripting wrappers */

const wrapFootage = ({ dest, ...asset }) => (`(function() {
    ${selectLayers(asset, `function(layer) {
        nexrender.replaceFootage(layer, '${dest.replace(/\\/g, "\\\\")}')
    }`)}
})();\n`)

const wrapData = ({ property, value, expression, ...asset }) => (`(function() {
    ${selectLayers(asset, `function(layer) {
        var property = layer.property('${property}');
        if (!property) { return false; }

        ${renderIf(value, `property.setValue($value);`)}
        ${renderIf(expression, `property.expression = $value;`)}

        return true;
    }`)}
})();\n`)

const wrapScript = ({ dest }) => (`(function() {
    ${fs.readFileSync(dest, 'utf8')}
})();\n`)

module.exports = (job, settings) => {
    settings.logger.log(`[${job.uid}] running script assemble...`);

    const data = [];
    const base = job.workpath;

    job.assets.map(asset => {
        switch (asset.type) {
            case 'video':
            case 'audio':
            case 'image':
                data.push(wrapFootage(asset));
                break;

            case 'data':
                data.push(wrapData(asset));
                break;

            case 'script':
                data.push(wrapScript(asset));
                break;
        }
    });

    /* write out assembled custom script file in the workpath */
    job.scriptfile = path.join(base, `nexrender-${job.uid}-script.jsx`);
    fs.writeFileSync(job.scriptfile, script
        .replace('/*COMPOSITION*/', job.template.composition)
        .replace('/*USERSCRIPT*/', data.join('\n'))
    );

    return Promise.resolve(job)
}
<|endoftext|>


<commit_before>var scale, gridX, gridY, player;
var playerVector, playerDestination;
var offsetVector, offsetDestination;
var allPaths = new Array();
var customLayerPaths = new Array();
var customLayerObjects = {};
var customLayerSvg = {};
var layers = new Array();
var maxLayer = 3;
var currentLayer = 0;
var offset = new Point(0, 0);
var symbols = new Object();

for (var i = -maxLayer; i <= maxLayer; i++) {
    var layer = new Layer();
    layers.push(project.activeLayer);
}

var customLayer = new Layer();
var customLayerOffset = new Point(0, 0);
customLayer.visible = false;

function activateLayer(index) {
    showCustomLayer(false);
    layers[getLayerIndex(index)].activate();
    layers[getLayerIndex(index)].opacity = 1;
    if (currentLayer != index) {
        layers[getLayerIndex(currentLayer)].opacity = 0.2;
        currentLayer = index;
    }
}

function getLayerIndex(index) {
    if (index < -maxLayer || index > maxLayer) {
        alert("Layer out of bounds. Current layer range: -" + maxLayer + " to " + maxLayer);
    }
    // layers array represents z-indexes from -maxLayer to maxLayer
    return index + maxLayer;
}

activateLayer(currentLayer);

gridApi.setScale = function(newScale) {
    scale = newScale;
    gridX = new Point(scale, 0);
    gridY = new Point(0, scale);
};

gridApi.setZoom = function(zoom) {
    paper.view.zoom = zoom;
};

gridApi.zoomIn = function(amount) {
    paper.view.zoom = paper.view.zoom * (Math.pow(1.1, amount));
};

function onMouseDrag(event) {
    updateOffset(event.delta);
}

function onMouseUp(event) {
    var x = getGridSquareX(event.point);
    var y = getGridSquareY(event.point);
    ASLEvent("JS_GridSquareClick", x + ";" + y);
}

function updateOffset(delta) {
    setOffset(getOffset() + delta);
    var paths;
    if (project.activeLayer == customLayer) {
        paths = customLayerPaths;
    }
    else {
        paths = allPaths;
    }
    for (var i = 0; i < paths.length; i++) {
        paths[i].position += delta;
    }
    if (playerDestination && project.activeLayer != customLayer) {
        playerDestination += delta;
    }
}

function getOffset() {
    if (project.activeLayer == customLayer) {
        return customLayerOffset;
    }
    return offset;
}

function setOffset(value) {
    if (project.activeLayer == customLayer) {
        customLayerOffset = value;
    }
    else {
        offset = value;
    }
}

function onFrame(event) {
    if (playerVector) {
        var distance = player.position - playerDestination;
        if (distance.length > playerVector.length) {
            player.position += playerVector;
        }
        else {
            player.position = playerDestination;
            playerVector = null;
            playerDestination = null;

            var playerPositionAbsolute = player.position - offset;
            offsetDestination = paper.view.center - playerPositionAbsolute;

            offsetVector = (offsetDestination-offset) / 10;
        }
    }
    if (offsetVector) {
        var distance = offset - offsetDestination;
        if (distance.length > offsetVector.length) {
            updateOffset(offsetVector);
        }
        else {
            updateOffset(offsetDestination-offset);
            offsetVector = null;
            offsetDestination = null;
        }
    }
}

gridApi.drawGrid = function(minX, minY, maxX, maxY, border) {

    function gridLine(start, end) {
        var path = new Path();
        path.strokeColor = border;
        path.add(start, end);
        addPathToCurrentLayerList(path);
    }

    // draw the vertical lines
    for (var x = minX; x <= maxX; x++) {
        var start = gridPoint(x, minY);
        var end = gridPoint(x, maxY);
        gridLine(start, end);
    }

    // draw the horizontal lines
    for (var y = minY; y <= maxY; y++) {
        var start = gridPoint(minX, y);
        var end = gridPoint(maxX, y);
        gridLine(start, end);
    }
};

function gridPoint(x, y) {
    return (gridX * x) + (gridY * y) + getOffset();
}

function getGridSquareX(point) {
    return Math.floor(((point - getOffset()) / gridX).x);
}

function getGridSquareY(point) {
    return Math.floor(((point - getOffset()) / gridY).y);
}

function gridPointNudge(x, y, nudgeX, nudgeY) {
    var result = gridPoint(x, y);
    result.x += nudgeX;
    result.y += nudgeY;
    return result;
}

var firstBox = true;

gridApi.drawBox = function(x, y, z, width, height, border, borderWidth, fill, sides) {
    activateLayer(z);
    // if this is the very first room, centre the canvas by updating the offset
    if (firstBox) {
        var centrePoint = gridPoint(x + width / 2, y + height / 2);
        var offsetX = paper.view.center.x - centrePoint.x;
        var offsetY = paper.view.center.y - centrePoint.y;
        updateOffset(new Point(offsetX, offsetY));
        firstBox = false;
    }
    var path = null;
    var points = [gridPoint(x, y), gridPoint(x + width, y), gridPoint(x + width, y + height), gridPoint(x, y + height)];
    // sides is encoded with bits to represent NESW
    var draw = [sides & 8, sides & 4, sides & 2, sides & 1];
    for (var i = 0; i < 4; i++) {
        var next = (i + 1) % 4;
        if (draw[i]) {
            if (path == null) {
                path = new Path();
                allPaths.push(path);
                if (borderWidth > 0) {
                    path.strokeColor = border;
                    path.strokeWidth = borderWidth;
                }
                path.add(points[i]);
            }
            path.add(points[next]);
        } else {
            path = null;
        }
    }
    var fillPath;
    if (sides == 15) {
        fillPath = path;
    } else {
        fillPath = new Path();
        fillPath.add(points[0], points[1], points[2], points[3]);
        allPaths.push(fillPath);
    }
    fillPath.fillColor = fill;
    fillPath.closed = true;
};

gridApi.drawLine = function(x1, y1, x2, y2, border, borderWidth) {
    var path = new Path;
    path.strokeColor = border;
    path.strokeWidth = borderWidth;
    path.add(gridPoint(x1, y1));
    path.add(gridPoint(x2, y2));
    addPathToCurrentLayerList(path);
};

gridApi.drawArrow = function (id, x1, y1, x2, y2, border, borderWidth) {
    clearExistingObject(id);

    var linePath = new Path;
    var start = gridPoint(x1, y1);
    var end = gridPoint(x2, y2);
    linePath.strokeColor = border;
    linePath.strokeWidth = borderWidth;
    linePath.add(start);
    linePath.add(end);
    addPathToCurrentLayerList(linePath);

    var vector = end - start;
    var arrowVector = vector.normalize(10);
    var arrowheadPath = new Path([
        end + arrowVector.rotate(150),
        end,
        end + arrowVector.rotate(-150)
    ]);
    arrowheadPath.strokeColor = border;
    arrowheadPath.strokeWidth = borderWidth;
    addPathToCurrentLayerList(arrowheadPath);

    customLayerObjects[id] = [linePath, arrowheadPath];
};

function addPathToCurrentLayerList(path) {
    if (project.activeLayer == customLayer) {
        customLayerPaths.push(path);
    }
    else {
        allPaths.push(path);
    }
}

gridApi.drawPlayer = function(x, y, z, radius, border, borderWidth, fill) {
    activateLayer(z);
    if (!player) {
        player = new Path.Circle(gridPoint(x, y), radius);
        player.strokeColor = border;
        player.strokeWidth = borderWidth;
        player.fillColor = fill;
        player.fillColor = fill;
        allPaths.push(player);

        var playerPositionAbsolute = player.position - offset;
        var offsetDestinationX = paper.view.center.x - playerPositionAbsolute.x;
        var offsetDestinationY = paper.view.center.y - playerPositionAbsolute.y;

        offsetDestination = new Point(offsetDestinationX, offsetDestinationY);
        offsetVector = (offsetDestination - offset);
    } else {
        playerDestination = gridPoint(x, y);
        playerVector = (playerDestination - player.position) / 10;
        // move player to the end of the activeLayer so it gets drawn on top
        project.activeLayer.addChild(player);
    }
};

gridApi.drawLabel = function(x, y, z, text) {
    activateLayer(z);
    var pointText = new PointText(gridPoint(x, y));
    pointText.justification = "center";
    pointText.fillColor = "black";
    pointText.content = text;
    allPaths.push(pointText);
};

function showCustomLayer(visible) {
    if (visible != customLayer.visible) {
        customLayer.visible = visible;
        for (var idx = 0; idx < layers.length; idx++) {
            layers[idx].visible = !visible;
        }
        if (visible) {
            customLayer.activate();
        }
        else {
            layers[getLayerIndex(currentLayer)].activate();
        }
    }
}

gridApi.showCustomLayer = function(visible) {
    showCustomLayer(visible);
};

gridApi.clearCustomLayer = function() {
    customLayer.removeChildren();
};

gridApi.clearAllLayers = function () {
    player = null;
    $.each(layers, function(idx, layer) {
        layer.removeChildren();
    });
};

gridApi.setCentre = function(x, y) {
    var centrePoint = gridPoint(x, y);
    var offsetX = paper.view.center.x - centrePoint.x;
    var offsetY = paper.view.center.y - centrePoint.y;
    var curOffset = getOffset();
    updateOffset(new Point(offsetX, offsetY));
};

gridApi.drawCustomLayerSquare = function(id, x, y, width, height, text, fill) {
    var points = [];
    points.push(gridPointNudge(x, y, 1, 1));
    points.push(gridPointNudge(x + width, y, -1, 1));
    points.push(gridPointNudge(x + width, y + height, -1, -1));
    points.push(gridPointNudge(x, y + height, 1, -1));

    var textPoint = gridPoint(x + width / 2, y + height / 2);
    gridApi.drawCustomLayerObject(id, points, text, textPoint, fill, fill);
};

function clearExistingObject(id) {
    var existing = customLayerObjects[id];
    if (existing) {
        for (var idx in existing) {
            var path = existing[idx];
            // TO DO: Should remove path from layer and layerlist array
            path.visible = false;
        }
    }
}

gridApi.drawCustomLayerObject = function (id, points, text, textPoint, border, fill) {
    clearExistingObject(id);

    var paths = new Array();
    path = new Path();
    path.strokeColor = border;
    $.each(points, function(index, value) {
        path.add(value);
    });
    path.fillColor = fill;
    path.closed = true;
    addPathToCurrentLayerList(path);
    paths.push(path);

    if (text) {
        var pointText = new PointText(textPoint);
        pointText.justification = "center";
        pointText.fillColor = "black";
        pointText.content = text;
        addPathToCurrentLayerList(pointText);
        paths.push(pointText);
    }

    customLayerObjects[id] = paths;
};

gridApi.loadSvg = function (data, id) {
    var svg = paper.project.importSVG(data);
    if (svg) {
        symbols[id] = new Symbol(svg);
    }
};

gridApi.drawCustomLayerSvg = function (id, symbolId, x, y, width, height) {
    if (symbolId in symbols) {
        var existing = customLayerSvg[id];
        var placedSymbol = existing ? existing : symbols[symbolId].place();
        placedSymbol.scale(gridX.x * width / placedSymbol.bounds.width, gridY.y * height / placedSymbol.bounds.height);
        placedSymbol.position = gridPoint(x, y) + placedSymbol.bounds.size / 2;
        addPathToCurrentLayerList(placedSymbol);
        customLayerSvg[id] = placedSymbol;
    }
};

gridApi.onLoad();<commit_msg>Can pass an opacity into gridApi.drawCustomLayerObject<commit_after>var scale, gridX, gridY, player;
var playerVector, playerDestination;
var offsetVector, offsetDestination;
var allPaths = new Array();
var customLayerPaths = new Array();
var customLayerObjects = {};
var customLayerSvg = {};
var layers = new Array();
var maxLayer = 3;
var currentLayer = 0;
var offset = new Point(0, 0);
var symbols = new Object();

for (var i = -maxLayer; i <= maxLayer; i++) {
    var layer = new Layer();
    layers.push(project.activeLayer);
}

var customLayer = new Layer();
var customLayerOffset = new Point(0, 0);
customLayer.visible = false;

function activateLayer(index) {
    showCustomLayer(false);
    layers[getLayerIndex(index)].activate();
    layers[getLayerIndex(index)].opacity = 1;
    if (currentLayer != index) {
        layers[getLayerIndex(currentLayer)].opacity = 0.2;
        currentLayer = index;
    }
}

function getLayerIndex(index) {
    if (index < -maxLayer || index > maxLayer) {
        alert("Layer out of bounds. Current layer range: -" + maxLayer + " to " + maxLayer);
    }
    // layers array represents z-indexes from -maxLayer to maxLayer
    return index + maxLayer;
}

activateLayer(currentLayer);

gridApi.setScale = function(newScale) {
    scale = newScale;
    gridX = new Point(scale, 0);
    gridY = new Point(0, scale);
};

gridApi.setZoom = function(zoom) {
    paper.view.zoom = zoom;
};

gridApi.zoomIn = function(amount) {
    paper.view.zoom = paper.view.zoom * (Math.pow(1.1, amount));
};

function onMouseDrag(event) {
    updateOffset(event.delta);
}

function onMouseUp(event) {
    var x = getGridSquareX(event.point);
    var y = getGridSquareY(event.point);
    ASLEvent("JS_GridSquareClick", x + ";" + y);
}

function updateOffset(delta) {
    setOffset(getOffset() + delta);
    var paths;
    if (project.activeLayer == customLayer) {
        paths = customLayerPaths;
    }
    else {
        paths = allPaths;
    }
    for (var i = 0; i < paths.length; i++) {
        paths[i].position += delta;
    }
    if (playerDestination && project.activeLayer != customLayer) {
        playerDestination += delta;
    }
}

function getOffset() {
    if (project.activeLayer == customLayer) {
        return customLayerOffset;
    }
    return offset;
}

function setOffset(value) {
    if (project.activeLayer == customLayer) {
        customLayerOffset = value;
    }
    else {
        offset = value;
    }
}

function onFrame(event) {
    if (playerVector) {
        var distance = player.position - playerDestination;
        if (distance.length > playerVector.length) {
            player.position += playerVector;
        }
        else {
            player.position = playerDestination;
            playerVector = null;
            playerDestination = null;

            var playerPositionAbsolute = player.position - offset;
            offsetDestination = paper.view.center - playerPositionAbsolute;

            offsetVector = (offsetDestination-offset) / 10;
        }
    }
    if (offsetVector) {
        var distance = offset - offsetDestination;
        if (distance.length > offsetVector.length) {
            updateOffset(offsetVector);
        }
        else {
            updateOffset(offsetDestination-offset);
            offsetVector = null;
            offsetDestination = null;
        }
    }
}

gridApi.drawGrid = function(minX, minY, maxX, maxY, border) {

    function gridLine(start, end) {
        var path = new Path();
        path.strokeColor = border;
        path.add(start, end);
        addPathToCurrentLayerList(path);
    }

    // draw the vertical lines
    for (var x = minX; x <= maxX; x++) {
        var start = gridPoint(x, minY);
        var end = gridPoint(x, maxY);
        gridLine(start, end);
    }

    // draw the horizontal lines
    for (var y = minY; y <= maxY; y++) {
        var start = gridPoint(minX, y);
        var end = gridPoint(maxX, y);
        gridLine(start, end);
    }
};

function gridPoint(x, y) {
    return (gridX * x) + (gridY * y) + getOffset();
}

function getGridSquareX(point) {
    return Math.floor(((point - getOffset()) / gridX).x);
}

function getGridSquareY(point) {
    return Math.floor(((point - getOffset()) / gridY).y);
}

function gridPointNudge(x, y, nudgeX, nudgeY) {
    var result = gridPoint(x, y);
    result.x += nudgeX;
    result.y += nudgeY;
    return result;
}

var firstBox = true;

gridApi.drawBox = function(x, y, z, width, height, border, borderWidth, fill, sides) {
    activateLayer(z);
    // if this is the very first room, centre the canvas by updating the offset
    if (firstBox) {
        var centrePoint = gridPoint(x + width / 2, y + height / 2);
        var offsetX = paper.view.center.x - centrePoint.x;
        var offsetY = paper.view.center.y - centrePoint.y;
        updateOffset(new Point(offsetX, offsetY));
        firstBox = false;
    }
    var path = null;
    var points = [gridPoint(x, y), gridPoint(x + width, y), gridPoint(x + width, y + height), gridPoint(x, y + height)];
    // sides is encoded with bits to represent NESW
    var draw = [sides & 8, sides & 4, sides & 2, sides & 1];
    for (var i = 0; i < 4; i++) {
        var next = (i + 1) % 4;
        if (draw[i]) {
            if (path == null) {
                path = new Path();
                allPaths.push(path);
                if (borderWidth > 0) {
                    path.strokeColor = border;
                    path.strokeWidth = borderWidth;
                }
                path.add(points[i]);
            }
            path.add(points[next]);
        } else {
            path = null;
        }
    }
    var fillPath;
    if (sides == 15) {
        fillPath = path;
    } else {
        fillPath = new Path();
        fillPath.add(points[0], points[1], points[2], points[3]);
        allPaths.push(fillPath);
    }
    fillPath.fillColor = fill;
    fillPath.closed = true;
};

gridApi.drawLine = function(x1, y1, x2, y2, border, borderWidth) {
    var path = new Path;
    path.strokeColor = border;
    path.strokeWidth = borderWidth;
    path.add(gridPoint(x1, y1));
    path.add(gridPoint(x2, y2));
    addPathToCurrentLayerList(path);
};

gridApi.drawArrow = function (id, x1, y1, x2, y2, border, borderWidth) {
    clearExistingObject(id);

    var linePath = new Path;
    var start = gridPoint(x1, y1);
    var end = gridPoint(x2, y2);
    linePath.strokeColor = border;
    linePath.strokeWidth = borderWidth;
    linePath.add(start);
    linePath.add(end);
    addPathToCurrentLayerList(linePath);

    var vector = end - start;
    var arrowVector = vector.normalize(10);
    var arrowheadPath = new Path([
        end + arrowVector.rotate(150),
        end,
        end + arrowVector.rotate(-150)
    ]);
    arrowheadPath.strokeColor = border;
    arrowheadPath.strokeWidth = borderWidth;
    addPathToCurrentLayerList(arrowheadPath);

    customLayerObjects[id] = [linePath, arrowheadPath];
};

function addPathToCurrentLayerList(path) {
    if (project.activeLayer == customLayer) {
        customLayerPaths.push(path);
    }
    else {
        allPaths.push(path);
    }
}

gridApi.drawPlayer = function(x, y, z, radius, border, borderWidth, fill) {
    activateLayer(z);
    if (!player) {
        player = new Path.Circle(gridPoint(x, y), radius);
        player.strokeColor = border;
        player.strokeWidth = borderWidth;
        player.fillColor = fill;
        player.fillColor = fill;
        allPaths.push(player);

        var playerPositionAbsolute = player.position - offset;
        var offsetDestinationX = paper.view.center.x - playerPositionAbsolute.x;
        var offsetDestinationY = paper.view.center.y - playerPositionAbsolute.y;

        offsetDestination = new Point(offsetDestinationX, offsetDestinationY);
        offsetVector = (offsetDestination - offset);
    } else {
        playerDestination = gridPoint(x, y);
        playerVector = (playerDestination - player.position) / 10;
        // move player to the end of the activeLayer so it gets drawn on top
        project.activeLayer.addChild(player);
    }
};

gridApi.drawLabel = function(x, y, z, text) {
    activateLayer(z);
    var pointText = new PointText(gridPoint(x, y));
    pointText.justification = "center";
    pointText.fillColor = "black";
    pointText.content = text;
    allPaths.push(pointText);
};

function showCustomLayer(visible) {
    if (visible != customLayer.visible) {
        customLayer.visible = visible;
        for (var idx = 0; idx < layers.length; idx++) {
            layers[idx].visible = !visible;
        }
        if (visible) {
            customLayer.activate();
        }
        else {
            layers[getLayerIndex(currentLayer)].activate();
        }
    }
}

gridApi.showCustomLayer = function(visible) {
    showCustomLayer(visible);
};

gridApi.clearCustomLayer = function() {
    customLayer.removeChildren();
};

gridApi.clearAllLayers = function () {
    player = null;
    $.each(layers, function(idx, layer) {
        layer.removeChildren();
    });
};

gridApi.setCentre = function(x, y) {
    var centrePoint = gridPoint(x, y);
    var offsetX = paper.view.center.x - centrePoint.x;
    var offsetY = paper.view.center.y - centrePoint.y;
    var curOffset = getOffset();
    updateOffset(new Point(offsetX, offsetY));
};

gridApi.drawCustomLayerSquare = function(id, x, y, width, height, text, fill) {
    var points = [];
    points.push(gridPointNudge(x, y, 1, 1));
    points.push(gridPointNudge(x + width, y, -1, 1));
    points.push(gridPointNudge(x + width, y + height, -1, -1));
    points.push(gridPointNudge(x, y + height, 1, -1));

    var textPoint = gridPoint(x + width / 2, y + height / 2);
    gridApi.drawCustomLayerObject(id, points, text, textPoint, fill, fill);
};

function clearExistingObject(id) {
    var existing = customLayerObjects[id];
    if (existing) {
        for (var idx in existing) {
            var path = existing[idx];
            // TO DO: Should remove path from layer and layerlist array
            path.visible = false;
        }
    }
}

gridApi.drawCustomLayerObject = function (id, points, text, textPoint, border, fill, opacity) {
    clearExistingObject(id);

    var paths = new Array();
    path = new Path();
    path.strokeColor = border;
    $.each(points, function(index, value) {
        path.add(value);
    });
    path.fillColor = fill;
    path.closed = true;
    if (typeof opacity != "undefined") {
        path.opacity = opacity;
    }
    addPathToCurrentLayerList(path);
    paths.push(path);

    if (text) {
        var pointText = new PointText(textPoint);
        pointText.justification = "center";
        pointText.fillColor = "black";
        pointText.content = text;
        if (typeof opacity != "undefined") {
            pointText.opacity = opacity;
        }
        addPathToCurrentLayerList(pointText);
        paths.push(pointText);
    }

    customLayerObjects[id] = paths;
};

gridApi.loadSvg = function (data, id) {
    var svg = paper.project.importSVG(data);
    if (svg) {
        symbols[id] = new Symbol(svg);
    }
};

gridApi.drawCustomLayerSvg = function (id, symbolId, x, y, width, height) {
    if (symbolId in symbols) {
        var existing = customLayerSvg[id];
        var placedSymbol = existing ? existing : symbols[symbolId].place();
        placedSymbol.scale(gridX.x * width / placedSymbol.bounds.width, gridY.y * height / placedSymbol.bounds.height);
        placedSymbol.position = gridPoint(x, y) + placedSymbol.bounds.size / 2;
        addPathToCurrentLayerList(placedSymbol);
        customLayerSvg[id] = placedSymbol;
    }
};

gridApi.onLoad();<|endoftext|>


<commit_before>/* jshint browser:true, devel:true */
/* global Mithril */

Mithril.$wAttrList = [];

Mithril.withAttr = (function (original) {
	return function () {
		console.log('withAttr', arguments[0], arguments[1].toString());
		var result = original.apply(this, arguments);
		Mithril.$wAttrList.push({
			attr: arguments[0],
			fn: arguments[1],
			wrap: result
		});
		return result;
	};

})(Mithril.withAttr);

Mithril.$reviver = function (cellCache, root, cell, controller) {

	var nextEl = function (node) {
		if (node === null) return null;
		while (node.nodeName == "#text" && node.nodeValue.trim().length === 0) node = node.nextSibling;
		return node;
	};
	var inController = function (fn) {
		for (var m in controller) {
			if (controller[m] == fn) {
				return m;
			}
		}
	};
	var reviveFn = function (node, attr, fn) {
		var m; //, obj;

		if (attr == 'config' && fn == Mithril.route) {
			node.removeEventListener("click", Mithril.$routeUnobtrusive);
			node.addEventListener("click", Mithril.$routeUnobtrusive);
			return fn;
		}
		for (m in Mithril) {
			if (Mithril[m] == fn) {
				return '* Mithril: ' + m;
			}
		}

		for (m = 0; m < Mithril.$wAttrList.length; m++) {
			var entry = Mithril.$wAttrList[m];
			if (entry.wrap == fn) {
				m = inController(entry.fn);
				node[attr] = Mithril.$autoRedraw(Mithril.withAttr(entry.attr, controller[m]));
				return;
			}
		}

		m = inController(fn);
		if (m) {
			node[attr] = Mithril.$autoRedraw(controller[m]);
			return;
		}

		return fn.toString();
	};

	var revive = function (cell, parentNode) {
		var i, cache, node = parentNode && nextEl(parentNode.firstChild);
		if (typeof cell == 'string') {
			cell = new ''.constructor(cell);
			cell.nodes = [node];
			return cell;
		}
		var copy = function (cell) {
			if (typeof cell == 'string') {
				cell = new ''.constructor(cell);
				cell.nodes = [node];
				return cell;
			}
			var prop, value, attrs = {}, attrN, attrV, ret = {};
			for (prop in cell) {
				value = cell[prop];
				switch (prop) {
				case 'children':
					if (value) ret.children = revive(value, node);
					break;
				case 'attrs':
					for (attrN in value) {
						attrV = value[attrN];
						if (typeof attrV == 'function') {
							attrV = reviveFn(node, attrN, attrV);
						}
						attrs[attrN] = attrV;
					}
					ret.attrs = attrs;
					break;
				default:
					ret[prop] = value;
				}
			}
			ret.nodes = [node];
			node = node && nextEl(node.nextSibling);
			return ret;
		};
		if (Array.isArray(cell)) {
			cache = cell.map(copy);
			if (!cache.nodes) {
				cache.nodes = cache.map(function (cell) {
					return cell.nodes[0];
				});
			}
		} else {
			cache = copy(cell);
		}
		return cache;
	};
	var c = revive(cell, root);
	cellCache[0] = c;
//	console.log('\n\nvar cellCacheR = ', JSON.stringify(c, function (key, value) {
//		if (key == 'nodes') value = value.length + ' [' + value.map(function (node) {
//			return (node ? node.nodeName || node.nodeValue : 'null*node');
//		}) + ']';
//		return value;
//	}));
};<commit_msg>Fixed handling of string contents<commit_after>/* jshint browser:true, devel:true */
/* global Mithril */

Mithril.$wAttrList = [];

Mithril.withAttr = (function (original) {
	return function () {
		console.log('withAttr', arguments[0], arguments[1].toString());
		var result = original.apply(this, arguments);
		Mithril.$wAttrList.push({
			attr: arguments[0],
			fn: arguments[1],
			wrap: result
		});
		return result;
	};

})(Mithril.withAttr);

Mithril.$reviver = function (cellCache, root, cell, controller) {

	var nextEl = function (node) {
		if (node === null) return null;
		while (node.nodeName == "#text" && node.nodeValue.trim().length === 0) node = node.nextSibling;
		return node;
	};
	var inController = function (fn) {
		for (var m in controller) {
			if (controller[m] == fn) {
				return m;
			}
		}
	};
	var reviveFn = function (node, attr, fn) {
		var m; //, obj;

		if (attr == 'config' && fn == Mithril.route) {
			node.removeEventListener("click", Mithril.$routeUnobtrusive);
			node.addEventListener("click", Mithril.$routeUnobtrusive);
			return fn;
		}
		for (m in Mithril) {
			if (Mithril[m] == fn) {
				return '* Mithril: ' + m;
			}
		}

		for (m = 0; m < Mithril.$wAttrList.length; m++) {
			var entry = Mithril.$wAttrList[m];
			if (entry.wrap == fn) {
				m = inController(entry.fn);
				node[attr] = Mithril.$autoRedraw(Mithril.withAttr(entry.attr, controller[m]));
				return;
			}
		}

		m = inController(fn);
		if (m) {
			node[attr] = Mithril.$autoRedraw(controller[m]);
			return;
		}

		return fn.toString();
	};

	var revive = function (cell, parentNode) {
		var i, cache, node = parentNode && nextEl(parentNode.firstChild);
		if (typeof cell == 'string') {
			cell = new ''.constructor(cell);
			cell.nodes = [node];
			return cell;
		}
		var copy = function (cell) {
			var prop, value, attrs = {}, attrN, attrV, ret = {};
			if (typeof cell == 'string') {
				ret = new ''.constructor(cell);
			} else {
				for (prop in cell) {
					value = cell[prop];
					switch (prop) {
					case 'children':
						if (value) ret.children = revive(value, node);
						break;
					case 'attrs':
						for (attrN in value) {
							attrV = value[attrN];
							if (typeof attrV == 'function') {
								attrV = reviveFn(node, attrN, attrV);
							}
							attrs[attrN] = attrV;
						}
						ret.attrs = attrs;
						break;
					default:
						ret[prop] = value;
					}
				}
			}
			ret.nodes = [node];
			node = node && nextEl(node.nextSibling);
			return ret;
		};
		if (Array.isArray(cell)) {
			cache = cell.map(copy);
			if (!cache.nodes) {
				cache.nodes = cache.map(function (cell) {
					return cell.nodes[0];
				});
			}
		} else {
			cache = copy(cell);
		}
		return cache;
	};
	var c = revive(cell, root);
	cellCache[0] = c;
//	console.log('\n\nvar cellCacheR = ', JSON.stringify(c, function (key, value) {
//		if (key == 'nodes') value = value.length + ' [' + value.map(function (node) {
//			return (node ? node.nodeName || node.nodeValue : 'null*node');
//		}) + ']';
//		return value;
//	}));
};<|endoftext|>


<commit_before>import { UPDATE_QUERY, UPDATE_QUERY_COLLECTION_LOOKUP_INFO, UPDATE_QUERY_SOURCE_LOOKUP_INFO, ADD_CUSTOM_QUERY, SELECT_SEARCH_BY_ID, SAVE_PARSED_QUERIES, MARK_AS_DELETED_QUERY, RESET_QUERIES, REMOVE_DELETED_QUERIES, COPY_AND_REPLACE_QUERY_FIELD, REMOVE_NEW_STATUS, SWAP_SORT_QUERIES } from '../../../actions/explorerActions';
import { autoMagicQueryLabel } from '../../../lib/explorerUtil';

const INITIAL_STATE = [];

function shiftSortPositions(state, position) {
  const updatedState = [...state];
  updatedState.map((q, index) => {
    if (index >= position) {
      updatedState[index].sortPosition += 1;
    }
    return updatedState[index];
  });
  return updatedState;
}
function swapSortPositions(state, fromQuery, toPosition) {
  const updatedState = [...state];
  const highestPosition = updatedState.reduce((a, b) => (a.sortPosition > b.sortPosition ? a : b)).sortPosition;
  const fromQueryIndex = state.findIndex(q => q.uid !== null && q.uid === fromQuery.uid);
  updatedState.map((q, index) => {
    if (q.sortPosition === toPosition) {
      updatedState[index].sortPosition = fromQuery.sortPosition;
    }
    return q;
  });
  updatedState[fromQueryIndex].sortPosition = toPosition > highestPosition ? highestPosition : toPosition; // prevent inflation at end of list
  return updatedState;
}

function queries(state = INITIAL_STATE, action) {
  let updatedState = null;
  let queryIndex = -1;
  switch (action.type) {
    case ADD_CUSTOM_QUERY:
      updatedState = [...state];
      updatedState = shiftSortPositions(state, action.payload.sortPosition); // increment sortPosition for all queries 'behind' new query
      updatedState.push(action.payload);
      return updatedState;
    case UPDATE_QUERY:
      if (action.payload.query) { // update entire query object versus field at a time like in selected reducer
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.query.uid);
        // we may not have an id if this is a custom query, use index. -- update we may not even use ID... TBD
        queryIndex = queryIndex > -1 ? queryIndex : action.payload.query.uid;
        updatedState[queryIndex] = action.payload.query;
        if (updatedState[queryIndex].autoNaming) {
          updatedState[queryIndex].label = autoMagicQueryLabel(updatedState[queryIndex]);
        }
        if (updatedState[queryIndex].q === '*' || updatedState[queryIndex].q === '') {
          updatedState[queryIndex].autoNaming = true;
        }
        return updatedState;
      }
      return null;
    case COPY_AND_REPLACE_QUERY_FIELD: // replace property

      if (action.payload.uid !== undefined && action.payload.field) {
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        updatedState = [...state];
        updatedState[queryIndex] = Object.assign({}, updatedState[queryIndex], action.payload.newValues);
        return updatedState;
      }
      return null;
    case UPDATE_QUERY_SOURCE_LOOKUP_INFO:
      if (action.payload && state && state.length > 0) { // just for safety
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        if (queryIndex === -1) {
          // we didn't fine the query uid we are looking for, so this is an error
          // so swallow the error for now with no updates
          return state;
        }
        queryIndex = queryIndex > -1 ? queryIndex : action.payload.uid;
        updatedState[queryIndex].sources = action.payload.sources.results;
        return updatedState;
      }
      return null;
    case UPDATE_QUERY_COLLECTION_LOOKUP_INFO:
      if (action.payload && state && state.length > 0) { // just for safety
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        if (queryIndex === -1) {
          // we didn't fine the query uid we are looking for, so this is an error
          // so swallow the error for now with no updates
          return state;
        }
        updatedState[queryIndex].collections = action.payload.collections.results;
        return updatedState;
      }
      return null;
    case SELECT_SEARCH_BY_ID:
      if (action.payload) { // make sure searchId is set if present in return results. use uid to differentiate queries.
        const queryData = action.payload.queries.map(q => Object.assign({}, q, { searchId: action.payload.id, id: action.payload.uid, uid: action.payload.uid }));
        updatedState = queryData;
        return updatedState;
      }
      return state;
    case SAVE_PARSED_QUERIES: // select this set of queries as passed in by URL
      updatedState = action.payload.map(q => Object.assign({}, q, { autoNaming: q.q === '*' || q.q === '' ? true : q.autoNaming }));
      return updatedState;
    case MARK_AS_DELETED_QUERY:
      if (action.payload) {
        updatedState = [...state];
        if (updatedState.length === 1) return updatedState; // they can't delete all the queries
        queryIndex = updatedState.findIndex(q => q.uid !== null && q.uid === action.payload.uid);

        updatedState[queryIndex].deleted = true;
        return updatedState;
      }
      return state;
    case REMOVE_NEW_STATUS:
      const queryData = [...state.map(q => Object.assign({}, q, { new: false }))];
      updatedState = queryData;
      return updatedState;
    case REMOVE_DELETED_QUERIES:
      return state.filter(q => !q.deleted);
    case SWAP_SORT_QUERIES:
      updatedState = [...state];
      return swapSortPositions(state, action.payload.from, action.payload.to);
    case RESET_QUERIES:
      return INITIAL_STATE;
    default:
      return state;
  }
}

export default queries;
<commit_msg>Fix parsing of collections for demo query #1460<commit_after>import { UPDATE_QUERY, UPDATE_QUERY_COLLECTION_LOOKUP_INFO, UPDATE_QUERY_SOURCE_LOOKUP_INFO, ADD_CUSTOM_QUERY, SELECT_SEARCH_BY_ID, SAVE_PARSED_QUERIES, MARK_AS_DELETED_QUERY, RESET_QUERIES, REMOVE_DELETED_QUERIES, COPY_AND_REPLACE_QUERY_FIELD, REMOVE_NEW_STATUS, SWAP_SORT_QUERIES } from '../../../actions/explorerActions';
import { autoMagicQueryLabel } from '../../../lib/explorerUtil';

const INITIAL_STATE = [];

function shiftSortPositions(state, position) {
  const updatedState = [...state];
  updatedState.map((q, index) => {
    if (index >= position) {
      updatedState[index].sortPosition += 1;
    }
    return updatedState[index];
  });
  return updatedState;
}
function swapSortPositions(state, fromQuery, toPosition) {
  const updatedState = [...state];
  const highestPosition = updatedState.reduce((a, b) => (a.sortPosition > b.sortPosition ? a : b)).sortPosition;
  const fromQueryIndex = state.findIndex(q => q.uid !== null && q.uid === fromQuery.uid);
  updatedState.map((q, index) => {
    if (q.sortPosition === toPosition) {
      updatedState[index].sortPosition = fromQuery.sortPosition;
    }
    return q;
  });
  updatedState[fromQueryIndex].sortPosition = toPosition > highestPosition ? highestPosition : toPosition; // prevent inflation at end of list
  return updatedState;
}

function queries(state = INITIAL_STATE, action) {
  let updatedState = null;
  let queryIndex = -1;
  switch (action.type) {
    case ADD_CUSTOM_QUERY:
      updatedState = [...state];
      updatedState = shiftSortPositions(state, action.payload.sortPosition); // increment sortPosition for all queries 'behind' new query
      updatedState.push(action.payload);
      return updatedState;
    case UPDATE_QUERY:
      if (action.payload.query) { // update entire query object versus field at a time like in selected reducer
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.query.uid);
        // we may not have an id if this is a custom query, use index. -- update we may not even use ID... TBD
        queryIndex = queryIndex > -1 ? queryIndex : action.payload.query.uid;
        updatedState[queryIndex] = action.payload.query;
        if (updatedState[queryIndex].autoNaming) {
          updatedState[queryIndex].label = autoMagicQueryLabel(updatedState[queryIndex]);
        }
        if (updatedState[queryIndex].q === '*' || updatedState[queryIndex].q === '') {
          updatedState[queryIndex].autoNaming = true;
        }
        return updatedState;
      }
      return null;
    case COPY_AND_REPLACE_QUERY_FIELD: // replace property

      if (action.payload.uid !== undefined && action.payload.field) {
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        updatedState = [...state];
        updatedState[queryIndex] = Object.assign({}, updatedState[queryIndex], action.payload.newValues);
        return updatedState;
      }
      return null;
    case UPDATE_QUERY_SOURCE_LOOKUP_INFO:
      if (action.payload && state && state.length > 0) { // just for safety
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        if (queryIndex === -1) {
          // we didn't fine the query uid we are looking for, so this is an error
          // so swallow the error for now with no updates
          return state;
        }
        queryIndex = queryIndex > -1 ? queryIndex : action.payload.uid;
        updatedState[queryIndex].sources = action.payload.sources.results;
        return updatedState;
      }
      return null;
    case UPDATE_QUERY_COLLECTION_LOOKUP_INFO:
      if (action.payload && state && state.length > 0) { // just for safety
        updatedState = [...state];
        queryIndex = state.findIndex(q => q.uid !== null && q.uid === action.payload.uid);
        if (queryIndex === -1) {
          // we didn't fine the query uid we are looking for, so this is an error
          // so swallow the error for now with no updates
          return state;
        }
        updatedState[queryIndex].collections = action.payload.collections;
        return updatedState;
      }
      return null;
    case SELECT_SEARCH_BY_ID:
      if (action.payload) { // make sure searchId is set if present in return results. use uid to differentiate queries.
        const queryData = action.payload.queries.map(q => Object.assign({}, q, { searchId: action.payload.id, id: action.payload.uid, uid: action.payload.uid }));
        updatedState = queryData;
        return updatedState;
      }
      return state;
    case SAVE_PARSED_QUERIES: // select this set of queries as passed in by URL
      updatedState = action.payload.map(q => Object.assign({}, q, { autoNaming: q.q === '*' || q.q === '' ? true : q.autoNaming }));
      return updatedState;
    case MARK_AS_DELETED_QUERY:
      if (action.payload) {
        updatedState = [...state];
        if (updatedState.length === 1) return updatedState; // they can't delete all the queries
        queryIndex = updatedState.findIndex(q => q.uid !== null && q.uid === action.payload.uid);

        updatedState[queryIndex].deleted = true;
        return updatedState;
      }
      return state;
    case REMOVE_NEW_STATUS:
      const queryData = [...state.map(q => Object.assign({}, q, { new: false }))];
      updatedState = queryData;
      return updatedState;
    case REMOVE_DELETED_QUERIES:
      return state.filter(q => !q.deleted);
    case SWAP_SORT_QUERIES:
      updatedState = [...state];
      return swapSortPositions(state, action.payload.from, action.payload.to);
    case RESET_QUERIES:
      return INITIAL_STATE;
    default:
      return state;
  }
}

export default queries;
<|endoftext|>


<commit_before>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 15/02/12
 * Time: 17:21
 * To change this template use File | Settings | File Templates.
 */
var util = require('util');
// Authentication

var jest = require('jest'),
    cron = require('../cron').cron,
    models = require('../models'),
    fs = require('fs'),
    path = require('path'),
    async = require('async');

var knox;
try
{
    knox = require('knox');
}
catch(e)
{
}

var ACTION_PRICE = 2;

var user_public_fields = exports.user_public_fields = {
    id:null,
    first_name:null,
    last_name:null,
    avatar_url:null,
    score: null,
    num_of_given_mandates: null,
    num_of_proxies_i_represent: null
};

var SessionAuthentication = exports.SessionAuthentication = jest.Authentication.extend({
    is_authenticated : function(req, callback){

        var is_auth = req.isAuthenticated();
        if(is_auth)
        {
            var user_id = req.session.user_id;
            if(!user_id){
                callback({message: "no user id"}, null);
            }else{
                models.User.findById(user_id, function(err,user)
                {
                    if(err)
                        callback(err);
                    else
                    {
                        if(!user) {
                            if(req.method != 'GET')
                                callback(null,false);
                            else
                                callback(null,true);
                            return;
                        }
                        req.user = user;
                        // save user last visit
                        // to avoid many updates to the db, don't save if the difference is less than 2 minutes
                        if( !user.last_visit || (new Date() - user.last_visit  > 1000*60*2))
                            models.User.update({_id:user._id},{$set:{last_visit: new Date()}},function(err) {
                                if(err) {
                                    console.error('failed setting last visit',err);
                                }
                                else
                                    console.log('saved last visit');
                            });
                        var is_activated = user.is_activated;
                        if(is_activated || req.method == 'GET')
                            callback(null, true);
                        else {
                            callback({code:401,message:'not_activated'});
                        }
                    }
                });
            }
        }
        else
        {
            if(req.method != 'GET')
                callback(null,false);
            else
                callback(null,true);
        }

    }
});

var TokenAuthorization = exports.TokenAuthorization = jest.Authorization.extend({
    init:function(token_price)
    {
        this.token_price = token_price;
    },

    edit_object : function(req,object,callback){

        if (this.token_price || req.token_price)
        {
            if(req.user.tokens >= (this.token_price || req.token_price)){
                 callback(null, object);
            }else{
                callback({message:"Error: Unauthorized - there is not enought tokens",code:401}, null);
            }
        }
        else
            callback(null,object);
    }
});

var isArgIsInList = exports.isArgIsInList = function(arg_id, collection_list){
    var flag = false;
    for (var i = 0; i < collection_list.length; i++){
        arg_id = arg_id || arg_id.id;
        if (arg_id == collection_list[i].id){
            flag = true;
            break;
        }
    }
    return flag;
};

var score = {};
score.grade = 1;
score.vote = 1;
//score.post = 20;
//score.suggestion = 20;
//score.discussion = 30;

//
//function approve_item (item,item_type,user,callback)
//{
//    update_user_gamification(null,'approved_' + item_type,user,0,callback);
//}

function update_user_gamification(req, game_type, user, price, callback)
{
    var inc_user_gamification ={};
    var inc_user_gamification_score ={};
    inc_user_gamification['gamification.'+game_type] = 1;
    inc_user_gamification['score'] = score[game_type] || 0;

    if(price)
        inc_user_gamification['tokens'] = -price;

        user.gamification = user.gamification || {};
        user.gamification[game_type] = user.gamification[game_type] || 0;
        user.gamification[game_type] += 1;
        user.score += score[game_type];
        if(price)
            user.tokens -= price;
        models.User.update({_id:user.id},{$inc:inc_user_gamification},function(err,num)
        {
            if(err)
                callback(err);
            else
            {
//                async.parallel([
//                    function(cbk){
//                        set_passive_user_updates(req, cbk);
//                    },
//
//                    function(cbk){
//                        check_gamification_rewards(user, cbk);
//
//                    }
//                ], function(err, args){
//                    console.log('user gamification saved');
//                    callback(err, args[1]);
//                })

//                check_gamification_rewards(user, callback);
                callback(err, 0);//TODO change it
                console.log('user gamification saved');

            }
        });
}

/*

//    בזבוז של כל הטוקנים במשך X ימים
function check_user_runout_of_tokens_time(user, callback){

    var X_DAYS_TIME = 1000*60*60*24* 3;
    var date = new Date();
    if(user.tokens == 0 && (date.getTime() - user.runout_of_tokens_time > ) ){
        cron.addTokensToUserByEventAndSetGamificationBonus(user._id, "", event_bonus, callback)
    }
}
*/
function set_passive_user_updates(req, callback){

//    req.update_type = req.update_type || {};
    if(req.update_type){

    }else{
        callback(null, 0);
    }
}

function check_gamification_rewards(user,callback)
{
    //if rewards reurn it
    //+ if perminant reward (king or something) insert to data base the new status

    callback(null,/*reward*/null);
}

function gamification_deserilize(self,base,req,res,obj,status)
{
    if(status == 201 || status == 202 && self.gamification_type || req.gamification_type)
    {
        update_user_gamification(req, self.gamification_type || req.gamification_type, req.user, self.token_price || req.token_price,function(err,rewards)
        {
            if(rewards)
                obj['rewards'] = rewards;

            if (obj)
                obj.updated_user_tokens = req.user.tokens;
            else
            {
                var temp_obj = {}
                    temp_obj.updated_user_tokens = req.user.tokens;
            }
            req.session.user = req.user;
            base(req,res,obj || temp_obj,status);
        });
    }else{
        base(req,res,obj,status);
    }
}

var GamificationResource = exports.GamificationResource  = jest.Resource.extend({
    init:function(type,price)
    {
        this.gamification_type = type;
        this._super();
        this.authorization = new TokenAuthorization(price || 0);
        this.token_price = price;
    },
    deserialize:function(req, res,obj,status)
    {
        gamification_deserilize(this,this._super,req,res,obj,status);
    }
});

var GamificationMongooseResource = exports.GamificationMongooseResource = jest.MongooseResource.extend({
    init:function(model,type,price)
    {
        this.gamification_type = type;
        this._super(model);
        this.authorization = new TokenAuthorization(price || 0);
        this.token_price = price;
    },
    deserialize:function(req, res, obj, status)
    {
        gamification_deserilize(this, this._super, req, res, obj, status);
    }
});

var token_prices = {};
function load_token_prices(){
    models.GamificationTokens.findOne({},function(err,doc)
    {
        if(doc)
            token_prices = doc._doc;
        if(err)
            console.error(err);
    });
};

load_token_prices();

models.GamificationTokens.schema.pre('save',function(next)
{
    setTimeout(load_token_prices, 1000);
    next();
});

exports.getGamificationTokenPrice = function(type)
{
    return token_prices[type] || 0;
};

var threshold_calc_variables = {};
function load_threshold_calc_variables(){
    models.ThresholdCalcVariables.findOne({},function(err,doc)
    {
        if(doc)
            threshold_calc_variables = doc._doc;
        if(err)
            console.error(err);
    });
};

load_threshold_calc_variables();

models.ThresholdCalcVariables.schema.pre('save',function(next)
{
    setTimeout(load_threshold_calc_variables, 1000);
    next();
});

exports.getThresholdCalcVariables = function(type)
{
    return threshold_calc_variables[type] || 0;
};

var create_filename = function(filename)
{
    var parts = filename.split('.');
    var filename = parts.length > 1 ? parts.slice(0,parts.length-1).join('.') : parts[0];
    filename = filename.replace(/\s\-/g,'_');
    var ext = parts.length > 1 ? '.' + parts[parts.length-1] : '';
    ext = ext.replace(/\s\-/g,'_');
    return '/' + filename + '_' + (Date.now()%1000) + ext;
};

var uploadHandler = exports.uploadHandler = function(req,callback) {
    var knoxClient = require('j-forms').fields.getKnoxClient();

    var fName = req.header('x-file-name');
    var fType = req.header('x-file-type');

    if(!fName && !fType){
        callback({code:404,message:'bad file upload'});
        return;
    }

    var filename = create_filename(fName);

    function writeToFile(callback){
        var os = fs.createWriteStream(path.join(__dirname,'..','deliver','public','cdn') + filename);

        stream.on('data',function(data) {
            os.write(data);
        });

        stream.on('end',function() {
            os.end();
            var value = {path:filename,url:'/cdn/' + filename};
            callback(null,value);
        });

        stream.resume();
    }

    var stream = req.queueStream || req;

    if(knox&&knoxClient)
    {

        writeToFile(function(err,value) {

            if(err) {
                callback(err);
                return;
            }

            setTimeout(function() {

                var file = path.join(__dirname,'..','deliver','public','cdn',value.path);
                stream = fs.createReadStream(file);

                knoxClient.putStream(stream, '/' + filename, function(err, res){
                    if(err)
                        callback(err);
                    else {
                        fs.unlink(file);
                        var value = {
                            path:res.socket._httpMessage.url,
                            url:res.socket._httpMessage.url
                        };
                        callback(null,value);
                    }
                });
            },200);
        });
    }
    else
        writeToFile(callback);
};<commit_msg>user_public_fields - has_voted<commit_after>/**
 * Created by JetBrains WebStorm.
 * User: saar
 * Date: 15/02/12
 * Time: 17:21
 * To change this template use File | Settings | File Templates.
 */
var util = require('util');
// Authentication

var jest = require('jest'),
    cron = require('../cron').cron,
    models = require('../models'),
    fs = require('fs'),
    path = require('path'),
    async = require('async');

var knox;
try
{
    knox = require('knox');
}
catch(e)
{
}

var ACTION_PRICE = 2;

var user_public_fields = exports.user_public_fields = {
    id:null,
    first_name:null,
    last_name:null,
    avatar_url:null,
    score: null,
    num_of_given_mandates: null,
    num_of_proxies_i_represent: null,
    has_voted: null
};

var SessionAuthentication = exports.SessionAuthentication = jest.Authentication.extend({
    is_authenticated : function(req, callback){

        var is_auth = req.isAuthenticated();
        if(is_auth)
        {
            var user_id = req.session.user_id;
            if(!user_id){
                callback({message: "no user id"}, null);
            }else{
                models.User.findById(user_id, function(err,user)
                {
                    if(err)
                        callback(err);
                    else
                    {
                        if(!user) {
                            if(req.method != 'GET')
                                callback(null,false);
                            else
                                callback(null,true);
                            return;
                        }
                        req.user = user;
                        // save user last visit
                        // to avoid many updates to the db, don't save if the difference is less than 2 minutes
                        if( !user.last_visit || (new Date() - user.last_visit  > 1000*60*2))
                            models.User.update({_id:user._id},{$set:{last_visit: new Date()}},function(err) {
                                if(err) {
                                    console.error('failed setting last visit',err);
                                }
                                else
                                    console.log('saved last visit');
                            });
                        var is_activated = user.is_activated;
                        if(is_activated || req.method == 'GET')
                            callback(null, true);
                        else {
                            callback({code:401,message:'not_activated'});
                        }
                    }
                });
            }
        }
        else
        {
            if(req.method != 'GET')
                callback(null,false);
            else
                callback(null,true);
        }

    }
});

var TokenAuthorization = exports.TokenAuthorization = jest.Authorization.extend({
    init:function(token_price)
    {
        this.token_price = token_price;
    },

    edit_object : function(req,object,callback){

        if (this.token_price || req.token_price)
        {
            if(req.user.tokens >= (this.token_price || req.token_price)){
                 callback(null, object);
            }else{
                callback({message:"Error: Unauthorized - there is not enought tokens",code:401}, null);
            }
        }
        else
            callback(null,object);
    }
});

var isArgIsInList = exports.isArgIsInList = function(arg_id, collection_list){
    var flag = false;
    for (var i = 0; i < collection_list.length; i++){
        arg_id = arg_id || arg_id.id;
        if (arg_id == collection_list[i].id){
            flag = true;
            break;
        }
    }
    return flag;
};

var score = {};
score.grade = 1;
score.vote = 1;
//score.post = 20;
//score.suggestion = 20;
//score.discussion = 30;

//
//function approve_item (item,item_type,user,callback)
//{
//    update_user_gamification(null,'approved_' + item_type,user,0,callback);
//}

function update_user_gamification(req, game_type, user, price, callback)
{
    var inc_user_gamification ={};
    var inc_user_gamification_score ={};
    inc_user_gamification['gamification.'+game_type] = 1;
    inc_user_gamification['score'] = score[game_type] || 0;

    if(price)
        inc_user_gamification['tokens'] = -price;

        user.gamification = user.gamification || {};
        user.gamification[game_type] = user.gamification[game_type] || 0;
        user.gamification[game_type] += 1;
        user.score += score[game_type];
        if(price)
            user.tokens -= price;
        models.User.update({_id:user.id},{$inc:inc_user_gamification},function(err,num)
        {
            if(err)
                callback(err);
            else
            {
//                async.parallel([
//                    function(cbk){
//                        set_passive_user_updates(req, cbk);
//                    },
//
//                    function(cbk){
//                        check_gamification_rewards(user, cbk);
//
//                    }
//                ], function(err, args){
//                    console.log('user gamification saved');
//                    callback(err, args[1]);
//                })

//                check_gamification_rewards(user, callback);
                callback(err, 0);//TODO change it
                console.log('user gamification saved');

            }
        });
}

/*

//    בזבוז של כל הטוקנים במשך X ימים
function check_user_runout_of_tokens_time(user, callback){

    var X_DAYS_TIME = 1000*60*60*24* 3;
    var date = new Date();
    if(user.tokens == 0 && (date.getTime() - user.runout_of_tokens_time > ) ){
        cron.addTokensToUserByEventAndSetGamificationBonus(user._id, "", event_bonus, callback)
    }
}
*/
function set_passive_user_updates(req, callback){

//    req.update_type = req.update_type || {};
    if(req.update_type){

    }else{
        callback(null, 0);
    }
}

function check_gamification_rewards(user,callback)
{
    //if rewards reurn it
    //+ if perminant reward (king or something) insert to data base the new status

    callback(null,/*reward*/null);
}

function gamification_deserilize(self,base,req,res,obj,status)
{
    if(status == 201 || status == 202 && self.gamification_type || req.gamification_type)
    {
        update_user_gamification(req, self.gamification_type || req.gamification_type, req.user, self.token_price || req.token_price,function(err,rewards)
        {
            if(rewards)
                obj['rewards'] = rewards;

            if (obj)
                obj.updated_user_tokens = req.user.tokens;
            else
            {
                var temp_obj = {}
                    temp_obj.updated_user_tokens = req.user.tokens;
            }
            req.session.user = req.user;
            base(req,res,obj || temp_obj,status);
        });
    }else{
        base(req,res,obj,status);
    }
}

var GamificationResource = exports.GamificationResource  = jest.Resource.extend({
    init:function(type,price)
    {
        this.gamification_type = type;
        this._super();
        this.authorization = new TokenAuthorization(price || 0);
        this.token_price = price;
    },
    deserialize:function(req, res,obj,status)
    {
        gamification_deserilize(this,this._super,req,res,obj,status);
    }
});

var GamificationMongooseResource = exports.GamificationMongooseResource = jest.MongooseResource.extend({
    init:function(model,type,price)
    {
        this.gamification_type = type;
        this._super(model);
        this.authorization = new TokenAuthorization(price || 0);
        this.token_price = price;
    },
    deserialize:function(req, res, obj, status)
    {
        gamification_deserilize(this, this._super, req, res, obj, status);
    }
});

var token_prices = {};
function load_token_prices(){
    models.GamificationTokens.findOne({},function(err,doc)
    {
        if(doc)
            token_prices = doc._doc;
        if(err)
            console.error(err);
    });
};

load_token_prices();

models.GamificationTokens.schema.pre('save',function(next)
{
    setTimeout(load_token_prices, 1000);
    next();
});

exports.getGamificationTokenPrice = function(type)
{
    return token_prices[type] || 0;
};

var threshold_calc_variables = {};
function load_threshold_calc_variables(){
    models.ThresholdCalcVariables.findOne({},function(err,doc)
    {
        if(doc)
            threshold_calc_variables = doc._doc;
        if(err)
            console.error(err);
    });
};

load_threshold_calc_variables();

models.ThresholdCalcVariables.schema.pre('save',function(next)
{
    setTimeout(load_threshold_calc_variables, 1000);
    next();
});

exports.getThresholdCalcVariables = function(type)
{
    return threshold_calc_variables[type] || 0;
};

var create_filename = function(filename)
{
    var parts = filename.split('.');
    var filename = parts.length > 1 ? parts.slice(0,parts.length-1).join('.') : parts[0];
    filename = filename.replace(/\s\-/g,'_');
    var ext = parts.length > 1 ? '.' + parts[parts.length-1] : '';
    ext = ext.replace(/\s\-/g,'_');
    return '/' + filename + '_' + (Date.now()%1000) + ext;
};

var uploadHandler = exports.uploadHandler = function(req,callback) {
    var knoxClient = require('j-forms').fields.getKnoxClient();

    var fName = req.header('x-file-name');
    var fType = req.header('x-file-type');

    if(!fName && !fType){
        callback({code:404,message:'bad file upload'});
        return;
    }

    var filename = create_filename(fName);

    function writeToFile(callback){
        var os = fs.createWriteStream(path.join(__dirname,'..','deliver','public','cdn') + filename);

        stream.on('data',function(data) {
            os.write(data);
        });

        stream.on('end',function() {
            os.end();
            var value = {path:filename,url:'/cdn/' + filename};
            callback(null,value);
        });

        stream.resume();
    }

    var stream = req.queueStream || req;

    if(knox&&knoxClient)
    {

        writeToFile(function(err,value) {

            if(err) {
                callback(err);
                return;
            }

            setTimeout(function() {

                var file = path.join(__dirname,'..','deliver','public','cdn',value.path);
                stream = fs.createReadStream(file);

                knoxClient.putStream(stream, '/' + filename, function(err, res){
                    if(err)
                        callback(err);
                    else {
                        fs.unlink(file);
                        var value = {
                            path:res.socket._httpMessage.url,
                            url:res.socket._httpMessage.url
                        };
                        callback(null,value);
                    }
                });
            },200);
        });
    }
    else
        writeToFile(callback);
};<|endoftext|>


<commit_before>const chai = require('chai');
const expect = chai.expect;
const chaiAsPromised = require("chai-as-promised");
const progress = require("@progress/jsdo-core").progress;
const DataSource = require("../../build/progress.data.node").DataSource;

chai.use(chaiAsPromised);

// This bug relates to ADAS-7282
// This removes the functionality from the DataSource of count always being used
// if there was a count functionality present in the catalog, which is bad.

//First describe
describe('ADAS-7282: DataSource invokes count operation bug', function () {
    //options all the info required for creating a jsdo session
    const options = {
        serviceURI: "https://oemobiledemo.progress.com/OEMobileDemoServices",
        catalogURI: "https://oemobiledemo.progress.com/OEMobileDemoServices/static/SportsService3.json",
        resourceName: "SalesRep",
        authenticationModel: "anonymous",
        tableRef: "ttSalesRep"
    };

    //define your variables required for the tests below
    let session,
        jsdo,
        dataSource;

    //before: getSession
    before(function (done) {
        progress.data.getSession(options).then((object) => {
            session = object.jsdosession;
        }).then(() => done(), () => done());
    });

    //after: Logout of the session after we are done
    after((done) => {
        session.invalidate().then(() => done());
    });

    //Second describe for CRUD tests
    describe('JSDO Instantiation Tests', function () {
        it('should successfully create a JSDO', function () {
            jsdo = new progress.data.JSDO({ name: options.resourceName });
            expect(jsdo).to.be.an.instanceof(progress.data.JSDO);
            dataSource = new DataSource({
                jsdo: jsdo,
                tableRef: "ttSalesrep"
            });
        });
    });

    //1st Read without parameters
    describe('read() without params', function () {
        let data;

        //1st it ()
        it('should successfully call read()', function (done) {
            let read = dataSource.read().toPromise()
                .then((mydata) => {
                    return true;
                }, (error) => {
                    return expect.fail(null, null, 'read({}) did not succeed: ' + error);

                });

            expect(read).to.eventually.be.true.notify(done);
        });

        //2nd it ()
        it('should successfully call read({})', function (done) {
            let read = dataSource.read({}).toPromise()
                .then((mydata) => {
                    data = mydata.data;
                    return true;
                }, (error) => {
                    return expect.fail(null, null, 'read({}) did not succeed: ' + error);
                });

            expect(read).to.eventually.be.true.notify(done);
        });

        it('should have a read() that successfully grabs data', function () {
            expect(data).to.be.an.instanceOf(Array);
        });
    });

});
<commit_msg>Updated service to use Docker container service<commit_after>const chai = require('chai');
const expect = chai.expect;
const chaiAsPromised = require("chai-as-promised");
const progress = require("@progress/jsdo-core").progress;
const DataSource = require("../../build/progress.data.node").DataSource;

chai.use(chaiAsPromised);

// This bug relates to ADAS-7282
// This removes the functionality from the DataSource of count always being used
// if there was a count functionality present in the catalog, which is bad.

//First describe
describe('ADAS-7282: DataSource invokes count operation bug', function () {
    //options all the info required for creating a jsdo session
    const options = {
        serviceURI: "http://172.29.18.125:8894/OEMobileDemoServices",
        catalogURI: "http://172.29.18.125:8894/OEMobileDemoServices/static/SportsService.json",
        resourceName: "SalesRep",
        authenticationModel: "anonymous",
        tableRef: "ttSalesRep"
    };

    //define your variables required for the tests below
    let session,
        jsdo,
        dataSource;

    //before: getSession
    before(function (done) {
        progress.data.getSession(options).then((object) => {
            session = object.jsdosession;
        }).then(() => done(), () => done());
    });

    //after: Logout of the session after we are done
    after((done) => {
        session.invalidate().then(() => done());
    });

    //Second describe for CRUD tests
    describe('JSDO Instantiation Tests', function () {
        it('should successfully create a JSDO', function () {
            jsdo = new progress.data.JSDO({ name: options.resourceName });
            expect(jsdo).to.be.an.instanceof(progress.data.JSDO);
            dataSource = new DataSource({
                jsdo: jsdo,
                tableRef: "ttSalesrep"
            });
        });
    });

    //1st Read without parameters
    describe('read() without params', function () {
        let data;

        //1st it ()
        it('should successfully call read()', function (done) {
            let read = dataSource.read().toPromise()
                .then((mydata) => {
                    return true;
                }, (error) => {
                    return expect.fail(null, null, 'read({}) did not succeed: ' + error);

                });

            expect(read).to.eventually.be.true.notify(done);
        });

        //2nd it ()
        it('should successfully call read({})', function (done) {
            let read = dataSource.read({}).toPromise()
                .then((mydata) => {
                    data = mydata.data;
                    return true;
                }, (error) => {
                    return expect.fail(null, null, 'read({}) did not succeed: ' + error);
                });

            expect(read).to.eventually.be.true.notify(done);
        });

        it('should have a read() that successfully grabs data', function () {
            expect(data).to.be.an.instanceOf(Array);
        });
    });

});
<|endoftext|>