<commit_before>'use strict';

var THREE = require("three");

var parsedPoints = [],
    parsedTags = [],
    tagColors = new Map(),
    total = 0;

var Data = module.exports = {
    pointSize: 2,
    pointSizeMultiplier: 1,
    cloudSize2D: 1.5,

    loadData: function(data) {
        parsedPoints = [];
        parsedTags = [];
        total = data.length;

        var i;
        for (i = 0; i < data.length; i++) {
            var dataPoint = new THREE.Vector3(data[i][1], data[i][2], data[i][3]);
            dataPoint.url = "audio/" + data[i][4];
            dataPoint.meta = this.parseTags(data[i][5], i);
            dataPoint.color = new THREE.Color(data[i][6]);
            this.parseTagColors(dataPoint, 'phonem');
            parsedPoints.push(dataPoint);
        }
        this.sortTagValues();
    },

    /**
     * Parses tag JSON into tag objects.
     * @param {array} tags - array of {key: foo, value: bar} objects
     * @param {number} pointIndex - index of current dataPoint
     * @returns {array} Array that includes tag information for a point {key: foor, values: []}
     */
    parseTags: function(tags, pointIndex) {
        var meta = [],
            tagKey,
            tagVal,
            tagIndex,
            values,
            valueIndex;

        for (var i = 0; i < tags.length; i++) {
            tagKey = tags[i].key;
            tagVal = tags[i].val;

            // Parse tag for a point object
            tagIndex = this.addTwoPropertyObject(meta, 'key', tagKey, 'values', new Array());
            meta[tagIndex].values.push(tagVal);

            // Parse tag for parsedTag array
            tagIndex = this.addTwoPropertyObject(parsedTags, 'key', tagKey, 'values', new Array());
            values = parsedTags[tagIndex].values;
            valueIndex = this.addTwoPropertyObject(values, 'value', tagVal, 'points', new Array());
            values[valueIndex].points.push(pointIndex);
        }
        // Returns array of tag objects for use as a property of a point object
        return meta;
    },

    /**
     * Function that maps the color to the correct tag value. Wanted tag is usually the one
     * that was used to compute the color og the point.
     * @param {any} dataPoint - data point object
     * @param {any} tagKey - key value of tag that was used to determine color of the point
     */

    parseTagColors: function(dataPoint, tagKey) {
        var metaData = dataPoint.meta,
            value,
            tag;

        for (var i = 0; i < metaData.length; i++) {
            tag = metaData[i];
            if (tag.key === tagKey) {
                value = tag.values[0];
            }
        }

        if (!tagColors.has(value)) {
            tagColors.set(value, dataPoint.color);
        }
    },

    /**
     * Computes color for every datapoint and sets the color of each point.
     * Used when no color information is provided in data JSON
     * @param {JSON} data - data in JSON format
     */
    computeColorInformation: function(data) {
        var maxEuc = 0,
            minEuc = Number.MAX_VALUE,
            maxZ = 0,
            hueOffset = 20,
            hues = [];

        for (i = 0; i < data.length; i++) {
            var x = Math.pow(parsedPoints[i].x, 2);
            var y = Math.pow(parsedPoints[i].y, 2);
            var z = Math.pow(parsedPoints[i].z, 2);
            var hue = Math.sqrt(x + y + z);
            hues.push(hue);

            maxZ = Math.max(maxZ, z);
            maxEuc = Math.max(maxEuc, hue);
            minEuc = Math.min(minEuc, hue);
        }
        for (i = 0; i < data.length; i++) {
            var color = new THREE.Color();
            var lightness = parsedPoints[i].z / (2 * maxZ);
            color.setHSL((hues[i] - minEuc + hueOffset) / (maxEuc - minEuc), 1, lightness + 0.5);
            parsedPoints[i].color = color;

        }
    },

    /**
     * Adds an object with two properties to an array, if it doesnt exist, and returns index of that object.
     * @param {array} array - array to wich object will be added
     * @param {string} firstKey - name (key) of the first property
     * @param {any} firstValue - value of the first property
     * @param {string} secondKey - name (key) of the second property
     * @param {any} secondValue - value of the second property
     * @returns {number} Index of the object
     */
    addTwoPropertyObject: function(array, firstKey, firstValue, secondKey, secondValue) {
        var valueIndex = this.getObjectIndex(array, firstKey, firstValue);
        if (valueIndex === -1) {
            var metaTag = {};
            metaTag[firstKey] = firstValue;
            metaTag[secondKey] = secondValue;
            array.push(metaTag);
            return array.length - 1;
        }
        return valueIndex;
    },

    /**
     * Returns index of an object with desired value of a property
     * @param {array} array - array that will be searched
     * @param {string} propertyName - name of the attribute that will be compared
     * @param {any} value - wanted value of the attribute
     * @returns {number} Index of an object
     */
    getObjectIndex: function(array, propertyName, value) {
        for (var i = 0; i < array.length; i++) {
            var object = array[i];
            if (array[i][propertyName] === value) {
                return i;
            }
        }
        return -1;
    },

    /**
     * Sorts tag values alphabetically
     */
    sortTagValues: function() {
        for (var i = 0; i < parsedTags.length; i++) {
            var values = parsedTags[i].values;
            values.sort(function(a, b) {
                if (a.value < b.value) {
                    return -1
                }
                if (a.value > b.value) {
                    return 1;
                }
                return 0;
            })
        }
    },

    getTag: function(key) {
        var index = this.getObjectIndex(parsedTags, 'key', key)
        if (index === -1) {
            return undefined;
        }
        return parsedTags[index];
    },

    getTotalPoints: function() {
        return total;
    },

    getUrl: function(index) {
        return parsedPoints[index].url;
    },

    getPoint: function(index) {
        return parsedPoints[index];
    },

    getColor: function(index) {
        return parsedPoints[index].color;
    },

    getTags: function() {
        return parsedTags;
    },

    getTagColor: function(tag) {
        return tagColors.get(tag);
    }

};

<commit_msg>added map structure to Data.js for filtering<commit_after>'use strict';

var THREE = require("three");

var parsedPoints = [],
    parsedTags = [],
    tagMap = new Map(),
    tagColors = new Map(),
    total = 0;

var Data = module.exports = {
    pointSize: 2,
    pointSizeMultiplier: 1,
    cloudSize2D: 1.5,

    loadData: function(data) {
        parsedPoints = [];
        parsedTags = [];
        total = data.length;

        var i;
        for (i = 0; i < data.length; i++) {
            var dataPoint = new THREE.Vector3(data[i][1], data[i][2], data[i][3]);
            dataPoint.url = "audio/" + data[i][4];
            dataPoint.meta = this.parseTags(data[i][5], i);
            dataPoint.color = new THREE.Color(data[i][6]);
            this.parseTagColors(dataPoint, 'phonem');
            parsedPoints.push(dataPoint);
        }
        this.sortTagValues();
        console.log(tagMap);
    },

    /**
     * Parses tag JSON into tag objects.
     * @param {array} tags - array of {key: foo, value: bar} objects
     * @param {number} pointIndex - index of current dataPoint
     * @returns {array} Array that includes tag information for a point {key: foor, values: []}
     */
    parseTags: function(tags, pointIndex) {
        var meta = [],
            tagKey,
            tagVal,
            tagIndex,
            values,
            valueIndex;

        for (var i = 0; i < tags.length; i++) {
            tagKey = tags[i].key;
            tagVal = tags[i].val;

            // Parse tag for a point object
            tagIndex = this.addTwoPropertyObject(meta, 'key', tagKey, 'values', new Array());
            meta[tagIndex].values.push(tagVal);

            // Parse tag for parsedTag array
            if(!tagMap.has(tagKey)){
                tagMap.set(tagKey, new Object);
            }

            if(tagMap.get(tagKey)[tagVal] === undefined){
                tagMap.get(tagKey)[tagVal] = [];
            }

            tagMap.get(tagKey)[tagVal].push(pointIndex);

            tagIndex = this.addTwoPropertyObject(parsedTags, 'key', tagKey, 'values', new Array());
            values = parsedTags[tagIndex].values;
            valueIndex = this.addTwoPropertyObject(values, 'value', tagVal, 'points', new Array());
            values[valueIndex].points.push(pointIndex);
        }
        // Returns array of tag objects for use as a property of a point object
        return meta;
    },

    /**
     * Function that maps the color to the correct tag value. Wanted tag is usually the one
     * that was used to compute the color og the point.
     * @param {any} dataPoint - data point object
     * @param {any} tagKey - key value of tag that was used to determine color of the point
     */

    parseTagColors: function(dataPoint, tagKey) {
        var metaData = dataPoint.meta,
            value,
            tag;

        for (var i = 0; i < metaData.length; i++) {
            tag = metaData[i];
            if (tag.key === tagKey) {
                value = tag.values[0];
            }
        }

        if (!tagColors.has(value)) {
            tagColors.set(value, dataPoint.color);
        }
    },

    /**
     * Computes color for every datapoint and sets the color of each point.
     * Used when no color information is provided in data JSON
     * @param {JSON} data - data in JSON format
     */
    computeColorInformation: function(data) {
        var maxEuc = 0,
            minEuc = Number.MAX_VALUE,
            maxZ = 0,
            hueOffset = 20,
            hues = [];

        for (i = 0; i < data.length; i++) {
            var x = Math.pow(parsedPoints[i].x, 2);
            var y = Math.pow(parsedPoints[i].y, 2);
            var z = Math.pow(parsedPoints[i].z, 2);
            var hue = Math.sqrt(x + y + z);
            hues.push(hue);

            maxZ = Math.max(maxZ, z);
            maxEuc = Math.max(maxEuc, hue);
            minEuc = Math.min(minEuc, hue);
        }
        for (i = 0; i < data.length; i++) {
            var color = new THREE.Color();
            var lightness = parsedPoints[i].z / (2 * maxZ);
            color.setHSL((hues[i] - minEuc + hueOffset) / (maxEuc - minEuc), 1, lightness + 0.5);
            parsedPoints[i].color = color;

        }
    },

    /**
     * Adds an object with two properties to an array, if it doesnt exist, and returns index of that object.
     * @param {array} array - array to wich object will be added
     * @param {string} firstKey - name (key) of the first property
     * @param {any} firstValue - value of the first property
     * @param {string} secondKey - name (key) of the second property
     * @param {any} secondValue - value of the second property
     * @returns {number} Index of the object
     */
    addTwoPropertyObject: function(array, firstKey, firstValue, secondKey, secondValue) {
        var valueIndex = this.getObjectIndex(array, firstKey, firstValue);
        if (valueIndex === -1) {
            var metaTag = {};
            metaTag[firstKey] = firstValue;
            metaTag[secondKey] = secondValue;
            array.push(metaTag);
            return array.length - 1;
        }
        return valueIndex;
    },

    /**
     * Returns index of an object with desired value of a property
     * @param {array} array - array that will be searched
     * @param {string} propertyName - name of the attribute that will be compared
     * @param {any} value - wanted value of the attribute
     * @returns {number} Index of an object
     */
    getObjectIndex: function(array, propertyName, value) {
        for (var i = 0; i < array.length; i++) {
            var object = array[i];
            if (array[i][propertyName] === value) {
                return i;
            }
        }
        return -1;
    },

    /**
     * Sorts tag values alphabetically
     */
    sortTagValues: function() {
        for (var i = 0; i < parsedTags.length; i++) {
            var values = parsedTags[i].values;
            values.sort(function(a, b) {
                if (a.value < b.value) {
                    return -1
                }
                if (a.value > b.value) {
                    return 1;
                }
                return 0;
            })
        }
    },

    getTag: function(key) {
        var index = this.getObjectIndex(parsedTags, 'key', key)
        if (index === -1) {
            return undefined;
        }
        return parsedTags[index];
    },

    getTotalPoints: function() {
        return total;
    },

    getUrl: function(index) {
        return parsedPoints[index].url;
    },

    getPoint: function(index) {
        return parsedPoints[index];
    },

    getColor: function(index) {
        return parsedPoints[index].color;
    },

    getTags: function() {
        return parsedTags;
    },

    getTagColor: function(tag) {
        return tagColors.get(tag);
    },

    getTagMap: function(){
        return tagMap;
    }

};

<|endoftext|>


<commit_before>let objBrowser = chrome ? chrome : browser;

class EtherAddressLookup {

    constructor()
    {
        console.log("Init EAL");

        this.ethereumAddressRegex = new RegExp(/(^|\s|:|-)((?:0x)[0-9a-fA-F]{40})(?:\s|$)/gi, "gi");
        this.ENSAddressRegex = new RegExp(/(^|\s|:|-)(\S+(?:\.eth))(?:\s|$)/gi, "gi");

        this.setDefaultExtensionSettings();
        this.init();
    }

    setDefaultExtensionSettings()
    {
        this.blHighlight = false;
        this.strBlockchainExplorer = "https://etherscan.io/address";

        this.intSettingsCount = 0;
        this.intSettingsTotalCount = 2;
    }

    //Gets extension settings and then converts addresses to links
    init()
    {
        let objBrowser = chrome ? chrome : browser;
        //Get the highlight option for the user
        objBrowser.runtime.sendMessage({func: "highlight_option"}, function(objResponse) {
            if(objResponse && objResponse.hasOwnProperty("resp")) {
                this.blHighlight = (objResponse.resp == 1 ? true : false);
            }
            ++this.intSettingsCount;
        }.bind(this));

        //Get the blockchain explorer for the user
        objBrowser.runtime.sendMessage({func: "blockchain_explorer"}, function(objResponse) {
            this.strBlockchainExplorer = objResponse.resp;
            ++this.intSettingsCount;
        }.bind(this));

        //Update the DOM once all settings have been received...
        setTimeout(function() {
            if(true || this.intSettingsCount === this.intSettingsTotalCount) {
                if(this.blBlacklistDomains) {
                    this.blacklistedDomainCheck();
                }
                this.convertAddressToLink();
            }
        }.bind(this), 10)
    }

    //Finds Ethereum addresses and converts to a link to a block explorer
    convertAddressToLink()
    {
        var arrWhitelistedTags = ["code", "span", "p", "td", "li", "em", "i", "b", "strong", "small"];

        //Get the whitelisted nodes
        for(var i=0; i<arrWhitelistedTags.length; i++) {
            var objNodes = document.getElementsByTagName(arrWhitelistedTags[i]);
            //Loop through the whitelisted content
            for(var x=0; x<objNodes.length; x++) {

                this.convertEthereumAddress(objNodes, x);
                this.convertENSAddress(objNodes, x);

            }
        }

        if(this.blHighlight) {
            this.addHighlightStyle();
        }
    }

    convertEthereumAddress(objNodes, index)
    {
        this.convertAddress(objNodes, index, /((?:0x)[0-9a-fA-F]{40})/gi, this.ethereumAddressRegex);
    }

    convertENSAddress(objNodes, index)
    {
        this.convertAddress(objNodes, index, this.ENSAddressRegex, this.ENSAddressRegex);
    }

    convertAddress(objNodes, index, checkRegex, replaceRegex)
    {
        //Put the blockchain explorer into a so we can parse it.
        var objBlockchainExplorer = document.createElement("a");
        objBlockchainExplorer.href = this.strBlockchainExplorer;

        var strContent = objNodes[index].innerHTML;
        if( checkRegex.exec(strContent) !== null) {
            objNodes[index].innerHTML = strContent.replace(
                replaceRegex,
                '$1$2'
            );
        }
    }

    //Removes the highlight style from Ethereum addresses
    removeHighlightStyle()
    {
        var objEtherAddresses = document.getElementsByClassName("ext-etheraddresslookup-link");
        for (var i = 0; i < objEtherAddresses.length; i++) {
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-no_highlight");
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-highlight");
        }
        return false;
    }

    //Adds the highlight style
    addHighlightStyle()
    {
        var objEtherAddresses = document.getElementsByClassName("ext-etheraddresslookup-link");
        for (var i = 0; i < objEtherAddresses.length; i++) {
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-highlight");
            objEtherAddresses[i].classList.remove("ext-etheraddresslookup-link-no_highlight");
        }
        return false;
    }
}

window.addEventListener("load", function() {
    let objEtherAddressLookup = new EtherAddressLookup();
});

//Send message from the extension to here.
objBrowser.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        let objEtherAddressLookup = new EtherAddressLookup();
        if(typeof request.func !== "undefined") {
            if(typeof objEtherAddressLookup[request.func] == "function") {
                objEtherAddressLookup[request.func]();
                sendResponse({status: "ok"});
                return true;
            }
        }
        sendResponse({status: "fail"});
    }
);
<commit_msg>Adjustment to RegEx to give better matches<commit_after>let objBrowser = chrome ? chrome : browser;

class EtherAddressLookup {

    constructor()
    {
        console.log("Init EAL");

        this.setDefaultExtensionSettings();
        this.setSearchAndReplaceSettings();
        this.init();
    }

    setDefaultExtensionSettings()
    {
        this.blHighlight = false;
        this.strBlockchainExplorer = "https://etherscan.io/address";

        this.intSettingsCount = 0;
        this.intSettingsTotalCount = 2;
    }

    setSearchAndReplaceSettings()
    {
        // Check user is on their favourite block explorer
        // If we are on our favourite blockchain explorer, don't target blank.
        this.onBlockchainExplorer = this.onBlockchainExplorer();
        this.target = (this.onBlockchainExplorer ? '_self' : '_blank');

        // Set RegExs
        this.ethereumAddressRegex = new RegExp(/(^|\s|:|-)((?:0x)[0-9a-fA-F]{40})(?:\s|$)/gi, "gi");
        this.ENSAddressRegex = new RegExp(/(\s|^|\.|\"|\'|\>)([a-z0-9][a-z0-9-\.]+[a-z0-9](?:.eth))(\s|$|\.|\"|\'|\<)/gim, "gim");

        // Set string substitutions
        this.ethereumAddressReplace = '$1$2';
        this.ENSAddressReplace = '$1$2$3';
    }

    //Gets extension settings and then converts addresses to links
    init()
    {
        let objBrowser = chrome ? chrome : browser;
        //Get the highlight option for the user
        objBrowser.runtime.sendMessage({func: "highlight_option"}, function(objResponse) {
            if(objResponse && objResponse.hasOwnProperty("resp")) {
                this.blHighlight = (objResponse.resp == 1 ? true : false);
            }
            ++this.intSettingsCount;
        }.bind(this));

        //Get the blockchain explorer for the user
        objBrowser.runtime.sendMessage({func: "blockchain_explorer"}, function(objResponse) {
            this.strBlockchainExplorer = objResponse.resp;
            ++this.intSettingsCount;
        }.bind(this));

        //Update the DOM once all settings have been received...
        setTimeout(function() {
            if(true || this.intSettingsCount === this.intSettingsTotalCount) {
                if(this.blBlacklistDomains) {
                    this.blacklistedDomainCheck();
                }
                this.convertAddressToLink();
            }
        }.bind(this), 10)
    }

    //Finds Ethereum addresses and converts to a link to a block explorer
    convertAddressToLink()
    {
        var arrWhitelistedTags = ["code", "span", "p", "td", "li", "em", "i", "b", "strong", "small"];

        //Get the whitelisted nodes
        for(var i=0; i<arrWhitelistedTags.length; i++) {
            var objNodes = document.getElementsByTagName(arrWhitelistedTags[i]);
            //Loop through the whitelisted content
            for(var x=0; x<objNodes.length; x++) {

                this.convertEthereumAddress(objNodes, x);
                this.convertENSAddress(objNodes, x);

            }
        }

        if(this.blHighlight) {
            this.addHighlightStyle();
        }
    }

    convertEthereumAddress(objNodes, index)
    {
        this.convertAddress(
            objNodes, index, /((?:0x)[0-9a-fA-F]{40})/gi, this.ethereumAddressRegex, this.ethereumAddressReplace
        );
    }

    convertENSAddress(objNodes, index)
    {
        this.convertAddress(
            objNodes, index, this.ENSAddressRegex, this.ENSAddressRegex, this.ENSAddressReplace
        );
    }

    convertAddress(objNodes, index, checkRegex, replaceRegex, replacePattern)
    {
        var strContent = objNodes[index].innerHTML;
        if( checkRegex.exec(strContent) !== null) {
            objNodes[index].innerHTML = strContent.replace(replaceRegex, replacePattern);
        }
    }

    onBlockchainExplorer()
    {
        var objBlockchainExplorer = document.createElement("a");
        objBlockchainExplorer.href = this.strBlockchainExplorer;
        return objBlockchainExplorer.hostname === window.location.hostname;
    }

    //Removes the highlight style from Ethereum addresses
    removeHighlightStyle()
    {
        var objEtherAddresses = document.getElementsByClassName("ext-etheraddresslookup-link");
        for (var i = 0; i < objEtherAddresses.length; i++) {
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-no_highlight");
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-highlight");
        }
        return false;
    }

    //Adds the highlight style
    addHighlightStyle()
    {
        var objEtherAddresses = document.getElementsByClassName("ext-etheraddresslookup-link");
        for (var i = 0; i < objEtherAddresses.length; i++) {
            objEtherAddresses[i].classList.add("ext-etheraddresslookup-link-highlight");
            objEtherAddresses[i].classList.remove("ext-etheraddresslookup-link-no_highlight");
        }
        return false;
    }
}

window.addEventListener("load", function() {
    let objEtherAddressLookup = new EtherAddressLookup();
});

//Send message from the extension to here.
objBrowser.runtime.onMessage.addListener(
    function(request, sender, sendResponse) {
        let objEtherAddressLookup = new EtherAddressLookup();
        if(typeof request.func !== "undefined") {
            if(typeof objEtherAddressLookup[request.func] == "function") {
                objEtherAddressLookup[request.func]();
                sendResponse({status: "ok"});
                return true;
            }
        }
        sendResponse({status: "fail"});
    }
);
<|endoftext|>


<commit_before>Node.FindNodeType = function(nodeText,returnKey)
{
	if( typeof(returnKey) === "undefined") returnKey = false;
	for (var key in Node.NodeTypes) {
		if (Node.NodeTypes.hasOwnProperty(key)) {
			var element = Node.NodeTypes[key];
			if(element.name === nodeText)
			{
				if(returnKey)
					return key;
				else
					return Node.NodeTypes[key];
			}
			else continue;
		}
	}
}

Node.onSelectedFunctionChange = function()
{
	var e = document.getElementById("nodeFunctionSelect");
	var selectedFunction = e.options[e.selectedIndex].text;
	selectedFunction = Node.FindNodeType(selectedFunction);
	e = document.getElementById("additionalContent");
	e.innerHTML = "";

	for (var i = 0; i < selectedFunction.params.length; i++) {
		var element = selectedFunction.params[i];
		e.innerHTML += ''+ element.name +'<input class="nodeItem" type="'+ element.type +'" id="'+ element.name.hashCode() +'"></input>
';
	}
}

onEditNode = function(nodeData, callback)
{
	Node._createNodeModal(function()
	{
		Node._editNodeData(nodeData,callback);
		gl.aceEditor.setValue(nodeData.SCRIPT_TXT);
		Node.UpdateNodeChildren();
	},
	function()
	{
		var e = document.getElementById("nodeFunctionSelect");
		var i = 0;
		for (var key in Node.NodeTypes) {
			if (Node.NodeTypes.hasOwnProperty(key)) {
				var element = Node.NodeTypes[key];
				if(element.name === nodeData.nodeType.name)
				{
					e.selectedIndex = i;
					break;
				}
				else i++;
			}
		}
		Node.onSelectedFunctionChange();
		Node._populateNodeModalParameters(nodeData);
	});
}

onEditEdge = function(edgeData, callback)
{
	callback(edgeData);
	Node.UpdateNodeChildren();
}

Node._createNodeModal = function(callback,createCallback)
{
	var list = '';
	for (var key in Node.NodeTypes) {
		if (Node.NodeTypes.hasOwnProperty(key)) {
			var element = Node.NodeTypes[key];
			list += '<option value="'+ key +'">'+ element.name +'</option>';
		}
	}
	ModalManager.createModal('<select id="nodeFunctionSelect" selectedIndex=0 onchange="Node.onSelectedFunctionChange()">'+ list +'</select>

</div<',callback,createCallback);
}

Node._populateNodeModalParameters = function(nodeData)
{
	var inputs = document.getElementById('additionalContent').getElementsByTagName('input');
	var labels = document.getElementById('additionalContent').getElementsByTagName('label');

	for (var i = 0; i < labels.length; i++) {
		var e = labels[i];

		switch(inputs[i].type)
		{
			case 'checkbox':
				inputs[i].checked = nodeData.m22metadata[e.innerHTML];
				break;
			default:
				inputs[i].value = nodeData.m22metadata[e.innerHTML];
				break;
		}
	}
}

Node.UpdateNodeChildren = function()
{
	console.log("Updating node children");

	for (var nKey in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(nKey)) {
			gl.nodesDataset._data[nKey].children = [];
			gl.nodesDataset._data[nKey].parents = [];
			for (var eKey in gl.edgesDataset._data) {
				if (gl.edgesDataset._data.hasOwnProperty(eKey)) {
					if(gl.edgesDataset._data[eKey].from === gl.nodesDataset._data[nKey].id)
					{
						gl.nodesDataset._data[nKey].children.push(gl.edgesDataset._data[eKey]);
					}

					if(gl.edgesDataset._data[eKey].to === gl.nodesDataset._data[nKey].id)
					{
						gl.nodesDataset._data[nKey].parents.push(gl.edgesDataset._data[eKey]);
					}
				}
			}
		}
	}
}

Node._editNodeData = function(nodeData,callback)
{
	var e = document.getElementById("nodeFunctionSelect");
	var selectedFunction = Node.FindNodeType(e.options[e.selectedIndex].text);
	var selectedFunctionKey = Node.FindNodeType(e.options[e.selectedIndex].text, true)

	var inputs = document.getElementById('additionalContent').getElementsByTagName('input');
	var labels = document.getElementById('additionalContent').getElementsByTagName('label');

	if(selectedFunctionKey !== 'narrative')
		nodeData.SCRIPT_TXT = selectedFunctionKey;
	else
		nodeData.SCRIPT_TXT = "";
	nodeData.label = selectedFunctionKey;
	nodeData.level = !nodeData.level ? GetHighestNodeLevel() + 1 : nodeData.level;
	nodeData.startOfNode = '';
	nodeData.endOfNode = '';
	for (var k in selectedFunction.nodeProps) {
		if (selectedFunction.nodeProps.hasOwnProperty(k)) {
			nodeData[k] = selectedFunction.nodeProps[k];
		}
	}

	nodeData.m22metadata = {};
	for (var i = 0; i < labels.length; i++) {
		switch(inputs[i].type)
		{
			case 'checkbox':
				nodeData.m22metadata[labels[i].innerHTML] = inputs[i].checked;
				if(inputs[i].checked === true)
					nodeData.SCRIPT_TXT += " " + inputs[i].checked;
				break;
			default:
				nodeData.m22metadata[labels[i].innerHTML] = inputs[i].value;
				nodeData.SCRIPT_TXT += " " + inputs[i].value;
				break;
		}
	}

	if(selectedFunctionKey === 'narrative')
		nodeData.SCRIPT_TXT = nodeData.SCRIPT_TXT.substr(1);

	switch(selectedFunction)
	{
		case Node.NodeTypes.narrative:
			nodeData.label = 'NewNode';
			nodeData.color = { background: '#D2E5FF'};
		break;
		case Node.NodeTypes.nullop:
			nodeData = null;
		break;
		default:
		break;
	}

	if(nodeData)
	{
		nodeData.shadow = { enabled: false };
		nodeData.nodeType = selectedFunction;
	}

	callback(nodeData);
}

onAddNode = function(nodeData, callback)
{
	Node._createNodeModal(function(){Node._editNodeData(nodeData, function(){ callback(nodeData); Node.UpdateNodeChildren(); })});
}

onDeleteNode = function(nodeData,callback)
{
	gl.aceEditor.setValue("");
	callback(nodeData);
	Node.UpdateNodeChildren();
}

onDeleteEdge = function(edgeData,callback)
{
	var fromNode = gl.edgesDataset._data[edgeData.edges[0]].from;
	var toNode = gl.edgesDataset._data[edgeData.edges[0]].to;
	fromNode = gl.nodesDataset._data[fromNode];
	toNode = gl.nodesDataset._data[toNode];

	fromNode.endOfNode = "";
	toNode.startOfNode = "";

	callback(edgeData);
	Node.UpdateNodeChildren();
}

onAddEdge = function(edgeData,callback)
{
	if (edgeData.from === edgeData.to)
	{
		alert("You can't connect a node to itself!");
		callback(edgeData);
		return;
	}

	var fromNode = gl.nodesDataset._data[edgeData.from];
	var toNode = gl.nodesDataset._data[edgeData.to];

	if(gl.selectedNode != null)
	{
		gl.aceEditor.setValue("");
		gl.selectedNode = null;
		for(n = 0; n < gl.nodeInfoBoxes.length; n++)
		{
			if(gl.nodeInfoBoxes[n])
				gl.nodeInfoBoxes[n].value = "";
		}
	}
	edgeData.arrows = 'to';
	if(gl.nodesDataset === undefined)
		gl.nodesDataset = gl.network.body.data.nodes;

	fromNode.endOfNode = "\n\nGoto " + edgeData.to;
	toNode.startOfNode = "--" + edgeData.to + "\n\n";

	UpdateSelectedNode();
	callback(edgeData);
	Node.UpdateNodeChildren();
}

function destroy()
{
	if (gl.network !== null) {
		gl.network.destroy();
		gl.network = null;
	}
}

function draw()
{
	destroy();
	Node.UpdateNodeChildren();

	var data = {
		edges: gl.edgesDataset,
		nodes: gl.nodesDataset
	}

	for (var key in data.edges._data) {
		if (data.edges._data.hasOwnProperty(key)) {
			data.edges._data[key].title = key;
		}
	}

	// create a network
	var container = document.getElementById('mynetwork');
	gl.events.onAddEdge = onAddEdge;
	gl.events.onAddNode = onAddNode;
	gl.events.onDeleteEdge = onDeleteEdge;
	gl.events.onDeleteNode = onDeleteNode;
	gl.events.onEditEdge = onEditEdge;
	gl.events.onEditNode = onEditNode;
	gl.options =
	{
	    layout:
		{
	        hierarchical:
			{
	            direction: "LR",
	            sortMethod: "directed",
	            nodeSpacing: 250
	        }
	    },
	    interaction:
		{
			dragNodes: true,
			navigationButtons: true,
	    },
	    manipulation:
		{
	        enabled: true,
			addNode: gl.events.onAddNode,
			deleteNode: gl.events.onDeleteNode,
			deleteEdge: gl.events.onDeleteEdge,
			addEdge: gl.events.onAddEdge,
			editEdge: false,
			editNode: gl.events.onEditNode,
	    },
	    physics:
		{
	        enabled: false
	    }
	};

	gl.network = new vis.Network(container, data, gl.options);

	// add event listeners
	gl.network.on('select', function (params) {
	    if (params.nodes[0] != undefined)
		{
			if(typeof(gl.selectedNode) != undefined && gl.selectedNode != null)
			{
				gl.selectedNode.SCRIPT_TXT = gl.aceEditor.getValue();
			}
			for (var property in gl.network.body.data.nodes._data)
			{
				if (property == params.nodes[0])
				{
					gl.selectedNode = gl.network.body.data.nodes._data[property];
					break;
				}
			}
			try
			{
				gl.aceEditor.setValue(gl.selectedNode.SCRIPT_TXT);
				if(gl.selectedNode.nodeType !== Node.NodeTypes.narrative) gl.aceEditor.setReadOnly(true);
				else gl.aceEditor.setReadOnly(false);
				gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Name].value = gl.selectedNode.label;
				if(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.ID])
					gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.ID].value = gl.selectedNode.id;
				gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value = gl.selectedNode.level;
			}
			catch(err)
			{
				alert("Failed to find node data!");
				console.log(err);
				console.log(params);
			}
	    }
		else
		{
			if(typeof(gl.selectedNode) != undefined && gl.selectedNode != null)
			{
				gl.selectedNode.SCRIPT_TXT = gl.aceEditor.getValue();
			}
	        gl.aceEditor.setValue("");
			gl.selectedNode = null;
			for(n = 0; n < gl.nodeInfoBoxes.length; n++)
			{
				if(gl.nodeInfoBoxes[n])
					gl.nodeInfoBoxes[n].value = "";
			}
		}
	});
}

function GetHighestNodeLevel()
{
	var highest = false;
	for (var key in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(key)) {
			if(typeof(highest) === 'boolean' || gl.nodesDataset._data[key].level > highest)
			{
				highest = gl.nodesDataset._data[key].level;
			}
		}
	}
	if(highest === false) return 0;
	else return highest;
}

function GetLowestNodeLevel()
{
	var lowest = false;
	for (var key in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(key)) {
			if(typeof(lowest) === 'boolean' || gl.nodesDataset._data[key].level < lowest)
			{
				lowest = gl.nodesDataset._data[key].level;
			}
		}
	}
	if(lowest === false) return 0;
	else return lowest;
}

function UpdateSelectedNode()
{
	if(gl.selectedNode != null)
	{
		var temp = gl.selectedNode.level;
		if(gl.nodesDataset == null)
			gl.nodesDataset = gl.network.body.data.nodes;
		if(gl.edgesDataset == null)
		{
			gl.edgesDataset = gl.network.body.data.edges;
			draw();
		}

		gl.nodesDataset.update([ {
			id: gl.selectedNode.id,
			label: gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Name].value,
			//title: gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.File].value,
			level: parseInt(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value),
			SCRIPT_TXT: gl.aceEditor.getValue()
		} ]);

		if(parseInt(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value) != temp)
		{
			draw();
		}
	}
}
<commit_msg>Fix critical bug blocking narrative node editing<commit_after>Node.FindNodeType = function(nodeText,returnKey)
{
	if( typeof(returnKey) === "undefined") returnKey = false;
	for (var key in Node.NodeTypes) {
		if (Node.NodeTypes.hasOwnProperty(key)) {
			var element = Node.NodeTypes[key];
			if(element.name === nodeText)
			{
				if(returnKey)
					return key;
				else
					return Node.NodeTypes[key];
			}
			else continue;
		}
	}
}

Node.onSelectedFunctionChange = function()
{
	var e = document.getElementById("nodeFunctionSelect");
	var selectedFunction = e.options[e.selectedIndex].text;
	selectedFunction = Node.FindNodeType(selectedFunction);
	e = document.getElementById("additionalContent");
	e.innerHTML = "";

	for (var i = 0; i < selectedFunction.params.length; i++) {
		var element = selectedFunction.params[i];
		e.innerHTML += ''+ element.name +'<input class="nodeItem" type="'+ element.type +'" id="'+ element.name.hashCode() +'"></input>
';
	}
}

onEditNode = function(nodeData, callback)
{
	Node._createNodeModal(function()
	{
		Node._editNodeData(nodeData,callback);
		gl.aceEditor.setValue(nodeData.SCRIPT_TXT);
		Node.UpdateNodeChildren();
	},
	function()
	{
		var e = document.getElementById("nodeFunctionSelect");
		var i = 0;
		for (var key in Node.NodeTypes) {
			if (Node.NodeTypes.hasOwnProperty(key)) {
				var element = Node.NodeTypes[key];
				if(element.name === nodeData.nodeType.name)
				{
					e.selectedIndex = i;
					break;
				}
				else i++;
			}
		}
		Node.onSelectedFunctionChange();
		Node._populateNodeModalParameters(nodeData);
	});
}

onEditEdge = function(edgeData, callback)
{
	callback(edgeData);
	Node.UpdateNodeChildren();
}

Node._createNodeModal = function(callback,createCallback)
{
	var list = '';
	for (var key in Node.NodeTypes) {
		if (Node.NodeTypes.hasOwnProperty(key)) {
			var element = Node.NodeTypes[key];
			list += '<option value="'+ key +'">'+ element.name +'</option>';
		}
	}
	ModalManager.createModal('<select id="nodeFunctionSelect" selectedIndex=0 onchange="Node.onSelectedFunctionChange()">'+ list +'</select>

</div<',callback,createCallback);
}

Node._populateNodeModalParameters = function(nodeData)
{
	var inputs = document.getElementById('additionalContent').getElementsByTagName('input');
	var labels = document.getElementById('additionalContent').getElementsByTagName('label');

	for (var i = 0; i < labels.length; i++) {
		var e = labels[i];

		switch(inputs[i].type)
		{
			case 'checkbox':
				inputs[i].checked = nodeData.m22metadata[e.innerHTML];
				break;
			default:
				inputs[i].value = nodeData.m22metadata[e.innerHTML];
				break;
		}
	}
}

Node.UpdateNodeChildren = function()
{
	console.log("Updating node children");

	for (var nKey in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(nKey)) {
			gl.nodesDataset._data[nKey].children = [];
			gl.nodesDataset._data[nKey].parents = [];
			for (var eKey in gl.edgesDataset._data) {
				if (gl.edgesDataset._data.hasOwnProperty(eKey)) {
					if(gl.edgesDataset._data[eKey].from === gl.nodesDataset._data[nKey].id)
					{
						gl.nodesDataset._data[nKey].children.push(gl.edgesDataset._data[eKey]);
					}

					if(gl.edgesDataset._data[eKey].to === gl.nodesDataset._data[nKey].id)
					{
						gl.nodesDataset._data[nKey].parents.push(gl.edgesDataset._data[eKey]);
					}
				}
			}
		}
	}
}

Node._editNodeData = function(nodeData,callback)
{
	var e = document.getElementById("nodeFunctionSelect");
	var selectedFunction = Node.FindNodeType(e.options[e.selectedIndex].text);
	var selectedFunctionKey = Node.FindNodeType(e.options[e.selectedIndex].text, true)

	var inputs = document.getElementById('additionalContent').getElementsByTagName('input');
	var labels = document.getElementById('additionalContent').getElementsByTagName('label');

	if(selectedFunctionKey !== 'narrative')
		nodeData.SCRIPT_TXT = selectedFunctionKey;
	else
		nodeData.SCRIPT_TXT = "";
	nodeData.label = selectedFunctionKey;
	nodeData.level = !nodeData.level ? GetHighestNodeLevel() + 1 : nodeData.level;
	nodeData.startOfNode = '';
	nodeData.endOfNode = '';
	for (var k in selectedFunction.nodeProps) {
		if (selectedFunction.nodeProps.hasOwnProperty(k)) {
			nodeData[k] = selectedFunction.nodeProps[k];
		}
	}

	nodeData.m22metadata = {};
	for (var i = 0; i < labels.length; i++) {
		switch(inputs[i].type)
		{
			case 'checkbox':
				nodeData.m22metadata[labels[i].innerHTML] = inputs[i].checked;
				if(inputs[i].checked === true)
					nodeData.SCRIPT_TXT += " " + inputs[i].checked;
				break;
			default:
				nodeData.m22metadata[labels[i].innerHTML] = inputs[i].value;
				nodeData.SCRIPT_TXT += " " + inputs[i].value;
				break;
		}
	}

	if(selectedFunctionKey === 'narrative')
		nodeData.SCRIPT_TXT = nodeData.SCRIPT_TXT.substr(1);

	switch(selectedFunction)
	{
		case Node.NodeTypes.narrative:
			nodeData.label = 'NewNode';
			nodeData.color = { background: '#D2E5FF'};
		break;
		case Node.NodeTypes.nullop:
			nodeData = null;
		break;
		default:
		break;
	}

	if(nodeData)
	{
		nodeData.shadow = { enabled: false };
		nodeData.nodeType = selectedFunction;
	}

	callback(nodeData);
}

onAddNode = function(nodeData, callback)
{
	Node._createNodeModal(function(){Node._editNodeData(nodeData, function(){ callback(nodeData); Node.UpdateNodeChildren(); })});
}

onDeleteNode = function(nodeData,callback)
{
	gl.aceEditor.setValue("");
	callback(nodeData);
	Node.UpdateNodeChildren();
}

onDeleteEdge = function(edgeData,callback)
{
	var fromNode = gl.edgesDataset._data[edgeData.edges[0]].from;
	var toNode = gl.edgesDataset._data[edgeData.edges[0]].to;
	fromNode = gl.nodesDataset._data[fromNode];
	toNode = gl.nodesDataset._data[toNode];

	fromNode.endOfNode = "";
	toNode.startOfNode = "";

	callback(edgeData);
	Node.UpdateNodeChildren();
}

onAddEdge = function(edgeData,callback)
{
	if (edgeData.from === edgeData.to)
	{
		alert("You can't connect a node to itself!");
		callback(edgeData);
		return;
	}

	var fromNode = gl.nodesDataset._data[edgeData.from];
	var toNode = gl.nodesDataset._data[edgeData.to];

	if(gl.selectedNode != null)
	{
		gl.aceEditor.setValue("");
		gl.selectedNode = null;
		for(n = 0; n < gl.nodeInfoBoxes.length; n++)
		{
			if(gl.nodeInfoBoxes[n])
				gl.nodeInfoBoxes[n].value = "";
		}
	}
	edgeData.arrows = 'to';
	if(gl.nodesDataset === undefined)
		gl.nodesDataset = gl.network.body.data.nodes;

	fromNode.endOfNode = "\n\nGoto " + edgeData.to;
	toNode.startOfNode = "--" + edgeData.to + "\n\n";

	UpdateSelectedNode();
	callback(edgeData);
	Node.UpdateNodeChildren();
}

function destroy()
{
	if (gl.network !== null) {
		gl.network.destroy();
		gl.network = null;
	}
}

function draw()
{
	destroy();
	Node.UpdateNodeChildren();

	var data = {
		edges: gl.edgesDataset,
		nodes: gl.nodesDataset
	}

	for (var key in data.edges._data) {
		if (data.edges._data.hasOwnProperty(key)) {
			data.edges._data[key].title = key;
		}
	}

	// create a network
	var container = document.getElementById('mynetwork');
	gl.events.onAddEdge = onAddEdge;
	gl.events.onAddNode = onAddNode;
	gl.events.onDeleteEdge = onDeleteEdge;
	gl.events.onDeleteNode = onDeleteNode;
	gl.events.onEditEdge = onEditEdge;
	gl.events.onEditNode = onEditNode;
	gl.options =
	{
	    layout:
		{
	        hierarchical:
			{
	            direction: "LR",
	            sortMethod: "directed",
	            nodeSpacing: 250
	        }
	    },
	    interaction:
		{
			dragNodes: true,
			navigationButtons: true,
	    },
	    manipulation:
		{
	        enabled: true,
			addNode: gl.events.onAddNode,
			deleteNode: gl.events.onDeleteNode,
			deleteEdge: gl.events.onDeleteEdge,
			addEdge: gl.events.onAddEdge,
			editEdge: false,
			editNode: gl.events.onEditNode,
	    },
	    physics:
		{
	        enabled: false
	    }
	};

	gl.network = new vis.Network(container, data, gl.options);

	// add event listeners
	gl.network.on('select', function (params) {
	    if (params.nodes[0] != undefined)
		{
			if(typeof(gl.selectedNode) != undefined && gl.selectedNode != null)
			{
				gl.selectedNode.SCRIPT_TXT = gl.aceEditor.getValue();
			}
			for (var property in gl.network.body.data.nodes._data)
			{
				if (property == params.nodes[0])
				{
					gl.selectedNode = gl.network.body.data.nodes._data[property];
					break;
				}
			}
			try
			{
				gl.aceEditor.setValue(gl.selectedNode.SCRIPT_TXT);
				if(gl.selectedNode.nodeType.name != Node.NodeTypes.narrative.name) gl.aceEditor.setReadOnly(true);
				else gl.aceEditor.setReadOnly(false);
				gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Name].value = gl.selectedNode.label;
				if(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.ID])
					gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.ID].value = gl.selectedNode.id;
				gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value = gl.selectedNode.level;
			}
			catch(err)
			{
				alert("Failed to find node data!");
				console.log(err);
				console.log(params);
			}
	    }
		else
		{
			if(typeof(gl.selectedNode) != undefined && gl.selectedNode != null)
			{
				gl.selectedNode.SCRIPT_TXT = gl.aceEditor.getValue();
			}
	        gl.aceEditor.setValue("");
			gl.selectedNode = null;
			for(n = 0; n < gl.nodeInfoBoxes.length; n++)
			{
				if(gl.nodeInfoBoxes[n])
					gl.nodeInfoBoxes[n].value = "";
			}
		}
	});
}

function GetHighestNodeLevel()
{
	var highest = false;
	for (var key in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(key)) {
			if(typeof(highest) === 'boolean' || gl.nodesDataset._data[key].level > highest)
			{
				highest = gl.nodesDataset._data[key].level;
			}
		}
	}
	if(highest === false) return 0;
	else return highest;
}

function GetLowestNodeLevel()
{
	var lowest = false;
	for (var key in gl.nodesDataset._data) {
		if (gl.nodesDataset._data.hasOwnProperty(key)) {
			if(typeof(lowest) === 'boolean' || gl.nodesDataset._data[key].level < lowest)
			{
				lowest = gl.nodesDataset._data[key].level;
			}
		}
	}
	if(lowest === false) return 0;
	else return lowest;
}

function UpdateSelectedNode()
{
	if(gl.selectedNode != null)
	{
		var temp = gl.selectedNode.level;
		if(gl.nodesDataset == null)
			gl.nodesDataset = gl.network.body.data.nodes;
		if(gl.edgesDataset == null)
		{
			gl.edgesDataset = gl.network.body.data.edges;
			draw();
		}

		gl.nodesDataset.update([ {
			id: gl.selectedNode.id,
			label: gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Name].value,
			//title: gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.File].value,
			level: parseInt(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value),
			SCRIPT_TXT: gl.aceEditor.getValue()
		} ]);

		if(parseInt(gl.nodeInfoBoxes[gl.nodeInfoBoxesIndex.Level].value) != temp)
		{
			draw();
		}
	}
}
<|endoftext|>


<commit_before>var path    = require('path')
var debug   = require('debug')('app:' + path.basename(__filename).replace('.js', ''))
var request = require('request')
var async   = require('async')
var op      = require('object-path')
var fs      = require('fs')

var entu    = require('../helpers/entu')

debug('Maintenance Started at ' + Date().toString())

fs.readdir('./pagecache', function(error, files) {
    if (error) {
        debug('0', error)
    }
    files.forEach(function(file) {
        if (path.extname(file) === '.json') {
            debug('Read from cache: ' + path.basename(file, '.json'))
            SDC.set(path.basename(file, '.json'), require(path.join('../pagecache', file)))
        }
    })
})

SDC.set('calendar.min_date', new Date().toLocaleDateString())
SDC.set('calendar.max_date', new Date().toLocaleDateString())

var cacheRoot = function cacheRoot() {
    debug('Caching root')
    SDC.set(['__', 'season'], (new Date().getFullYear()-2000+(Math.sign(new Date().getMonth()-7.5)-1)/2) + '/' + (new Date().getFullYear()-2000+(Math.sign(new Date().getMonth()-5.5)-1)/2+1))
    entu.get_entity(id=APP_ENTU_ROOT, null, null, CB=function(error, institution) {
        if (error) {
            debug('Cant cache institution entity', error)
        }
        SDC.set(['__', 'main_color'], institution.get(['properties', 'main-color', 'value']))
        SDC.set(['__', 'secondary_color'], institution.get(['properties', 'secondary-color', 'value']))
        fs.createWriteStream('./pagecache/root.json').write(JSON.stringify(SDC.get('__'), null, '  '))
        debug('Root cached')
        setTimeout(cacheRoot, APP_ROOT_REFRESH_MS)
    })
}
cacheRoot()

var cacheEntities = function cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f) {
    debug('Caching ' + name)
    var callback = function(error, entities) {
        if (error) {
            if (error.code == 'ENOTFOUND') {
                debug('Retry in 5 sec', error)
                setTimeout(function() {cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f)}, 5*1000)
                return
            }
        }
        var marked_entities_1 = {}
        var marked_entities_2 = {}
        async.each(entities, function(one_entity, callback) {
            var markers = []
            manipulator_f(one_entity, function(error, processed_entity) {
                if (error) {
                    debug('4', error)
                }
                one_entity = processed_entity
                markers = marker_f(one_entity)
                if (markers.length == 0) {
                    markers.push('_')
                }
                markers.forEach(function(marker) {
                    if (!marked_entities_1[marker]) {
                        marked_entities_1[marker] = []
                    }
                    marked_entities_1[marker].push(one_entity.get())
                    // op.push(marked_entities, marker, one_entity.get())
                })
                callback()
            })
        }, function (error) {
            if (error) {
                debug('2', error)
            }
            Object.keys(marked_entities_1).sort().forEach(function(marker) {
                // debug('pushing to ' + marker, JSON.stringify(marked_entities_1[marker], null, '  '))
                op.set(marked_entities_2, marker, marked_entities_1[marker])
            })

            for (marker in marked_entities_2) {
                debug('Writing ' + name + '.' + marker + ' to cache.')
                var ws = fs.createWriteStream('./pagecache/' + name + '_' + marker + '.json')
                ws.write(JSON.stringify(marked_entities_2[marker], null, '  '))
                SDC.set(name + '_' + marker, marked_entities_2[marker])
            }
            if (delay_ms) {
                setTimeout(function() {cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f)}, delay_ms)
            }
            debug('Caching ' + name + ' done. Next check in ' + delay_ms/1000 + ' sec.')
        })
    }
    if (parent) {
        entu.get_childs(parent=parent, definition=definition, auth_id=null, auth_token=null, callback=callback)
    } else {
        entu.get_entities(definition=definition, limit=null, auth_id=null, auth_token=null, callback=callback)
    }
}

var event_manipulator = function manipulator_f(entity_in, callback) {
    var entity_out = op({})
    entity_out.set('id', entity_in.get('id'))
    entity_out.set('category', entity_in.get('properties.category'))
    entity_out.set('name', entity_in.get('properties.name.value'))
    entity_out.set('description', entity_in.get('properties.description.md'))
    entity_out.set('photo', entity_in.get('properties.photo.0'))
    entity_out.set('photos', entity_in.get('properties.photo'))
    entity_out.set('video', entity_in.get('properties.video.value'))
    entity_out.set('location', entity_in.get('properties.location.value'))
    entity_out.set('price', entity_in.get('properties.price.value'))
    entity_out.set('ticket-api', entity_in.get('properties.ticket-api.value'))
    entity_out.set('technical-information', entity_in.get('properties.technical-information.md'))

    entity_in.get('properties.start-time', []).forEach(function(starttime) {
        entity_out.push('start-times', starttime.value)
    })

    if (entity_in.get('properties.performance.reference')) {
        // debug('fetch performance')
        entu.get_entity(id=entity_in.get('properties.performance.reference'), null, null, performanceCB=function(error, performance) {
            if (error) {
                debug('Event manipulator performance reference', error)
            }
            entity_out.set('performance', performance_manipulator(performance).get())
            // debug(entity_out.get('performance'))
            callback(null, entity_out)
        })
    } else {
        // debug('no performance')
        callback(null, entity_out)
    }
}

var performance_manipulator = function manipulator_f(entity_in) {
    var entity_out = op({})
    entity_out.set('id', entity_in.get('id'))
    entity_out.set('category', entity_in.get('properties.category'))
    entity_out.set('name', entity_in.get('properties.name.value'))
    entity_out.set('description', entity_in.get('properties.description.md'))
    entity_out.set('photo', entity_in.get('properties.photo.0'))
    entity_out.set('photos', entity_in.get('properties.photo'))
    entity_out.set('video', entity_in.get('properties.video.value'))
    entity_out.set('technical-information', entity_in.get('properties.technical-information.md'))
    return entity_out
}

// Split events into past and future and group by time
cacheEntities(
    name = 'program',
    definition = 'event',
    parent = 597,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 15 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under SAAL Biennaal and group by time
cacheEntities(
    name = 'SAAL_Biennaal',
    definition = 'event',
    parent = 1932,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under NU Performance and group by time
cacheEntities(
    name = 'NU_Performance',
    definition = 'event',
    parent = 1933,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under Tours and group by time
cacheEntities(
    name = 'tours',
    definition = 'event',
    parent = 1929,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under Residency and group by time
cacheEntities(
    name = 'Residency',
    definition = 'event',
    parent = 1931,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Split news into old and new and group by time
cacheEntities(
    name = 'news',
    definition = 'news',
    parent = 597,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 10 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var news_time = entity.get(['properties','time','value'])
        var markers = []
        var ms = Date.parse(news_time)
        var news_date = news_time.slice(0,10)
        // var news_date = (new Date(ms)).toJSON().slice(0,10)
        if (ms < Date.now()) {
            markers.push('past.' + news_date)
        } else if (ms >= Date.now()) {
            markers.push('upcoming.' + news_date)
        }
        return markers
    },
    manipulator_f = function manipulator_f(entity) {
        return entity
    }
)

// Example markers on person
cacheEntities(
    name = 'users',
    definition = 'person',
    parent = null,
    reset_markers = ['entusiastid', 'others'],
    delay_ms = 60 * 60 * 1000,
    marker_f = function marker_f(entity) {
        if (entity.get('name') == 'Mihkel-Mikelis Putrinš')
            return ['entusiastid.mihkel']
        else if (entity.get('name') == 'Argo Roots')
            return ['entusiastid.argo']
        else
            return ['others']
    },
    manipulator_f = function manipulator_f(entity_in) {
        var entity_out = op({})
        entity_out.set('id', entity_in.get('id'))
        entity_out.set('name', entity_in.get('displayname'))
        entity_out.set('entity', entity_in.get())
        return entity_out
    }
)<commit_msg>deal with calendar later<commit_after>var path    = require('path')
var debug   = require('debug')('app:' + path.basename(__filename).replace('.js', ''))
var request = require('request')
var async   = require('async')
var op      = require('object-path')
var fs      = require('fs')

var entu    = require('../helpers/entu')

debug('Maintenance Started at ' + Date().toString())

fs.readdir('./pagecache', function(error, files) {
    if (error) {
        debug('0', error)
    }
    files.forEach(function(file) {
        if (path.extname(file) === '.json') {
            debug('Read from cache: ' + path.basename(file, '.json'))
            SDC.set(path.basename(file, '.json'), require(path.join('../pagecache', file)))
        }
    })
})

SDC.set('calendar.min_date', new Date().toLocaleDateString())
SDC.set('calendar.max_date', new Date().toLocaleDateString())

var cacheRoot = function cacheRoot() {
    debug('Caching root')
    SDC.set(['__', 'season'], (new Date().getFullYear()-2000+(Math.sign(new Date().getMonth()-7.5)-1)/2) + '/' + (new Date().getFullYear()-2000+(Math.sign(new Date().getMonth()-5.5)-1)/2+1))
    entu.get_entity(id=APP_ENTU_ROOT, null, null, CB=function(error, institution) {
        if (error) {
            debug('Cant cache institution entity', error)
        }
        SDC.set(['__', 'main_color'], institution.get(['properties', 'main-color', 'value']))
        SDC.set(['__', 'secondary_color'], institution.get(['properties', 'secondary-color', 'value']))
        fs.createWriteStream('./pagecache/root.json').write(JSON.stringify(SDC.get('__'), null, '  '))
        debug('Root cached')
        setTimeout(cacheRoot, APP_ROOT_REFRESH_MS)
    })
}
cacheRoot()

var cacheEntities = function cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f) {
    debug('Caching ' + name)
    var callback = function(error, entities) {
        if (error) {
            if (error.code == 'ENOTFOUND') {
                debug('Retry in 5 sec', error)
                setTimeout(function() {cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f)}, 5*1000)
                return
            }
        }
        var marked_entities_1 = {}
        var marked_entities_2 = {}
        async.each(entities, function(one_entity, callback) {
            var markers = []
            manipulator_f(one_entity, function(error, processed_entity) {
                if (error) {
                    debug('4', error)
                }
                one_entity = processed_entity
                markers = marker_f(one_entity)
                if (markers.length == 0) {
                    markers.push('_')
                }
                markers.forEach(function(marker) {
                    if (!marked_entities_1[marker]) {
                        marked_entities_1[marker] = []
                    }
                    marked_entities_1[marker].push(one_entity.get())
                    // op.push(marked_entities, marker, one_entity.get())
                })
                callback()
            })
        }, function (error) {
            if (error) {
                debug('2', error)
            }
            Object.keys(marked_entities_1).sort().forEach(function(marker) {
                // debug('pushing to ' + marker, JSON.stringify(marked_entities_1[marker], null, '  '))
                op.set(marked_entities_2, marker, marked_entities_1[marker])
            })

            for (marker in marked_entities_2) {
                debug('Writing ' + name + '.' + marker + ' to cache.')
                var ws = fs.createWriteStream('./pagecache/' + name + '_' + marker + '.json')
                ws.write(JSON.stringify(marked_entities_2[marker], null, '  '))
                SDC.set(name + '_' + marker, marked_entities_2[marker])
            }
            if (delay_ms) {
                setTimeout(function() {cacheEntities(name, definition, parent, reset_markers, delay_ms, marker_f, manipulator_f)}, delay_ms)
            }
            // fs.createWriteStream('./pagecache/calendar.json').write(JSON.stringify(SDC.get('calendar'), null, '  '))
            debug('Caching ' + name + ' done. Next check in ' + delay_ms/1000 + ' sec.')
        })
    }
    if (parent) {
        entu.get_childs(parent=parent, definition=definition, auth_id=null, auth_token=null, callback=callback)
    } else {
        entu.get_entities(definition=definition, limit=null, auth_id=null, auth_token=null, callback=callback)
    }
}

var event_manipulator = function manipulator_f(entity_in, callback) {
    var entity_out = op({})
    entity_out.set('id', entity_in.get('id'))
    entity_out.set('category', entity_in.get('properties.category'))
    entity_out.set('name', entity_in.get('properties.name.value'))
    entity_out.set('description', entity_in.get('properties.description.md'))
    entity_out.set('photo', entity_in.get('properties.photo.0'))
    entity_out.set('photos', entity_in.get('properties.photo'))
    entity_out.set('video', entity_in.get('properties.video.value'))
    entity_out.set('location', entity_in.get('properties.location.value'))
    entity_out.set('price', entity_in.get('properties.price.value'))
    entity_out.set('ticket-api', entity_in.get('properties.ticket-api.value'))
    entity_out.set('technical-information', entity_in.get('properties.technical-information.md'))

    entity_in.get('properties.start-time', []).forEach(function(starttime) {
        entity_out.push('start-times', starttime.value)
        // SDC.set(['calendar', 'dates', new Date(starttime.value).toLocaleDateString(), entity_out.get('id')], entity_out.get())
    })

    if (entity_in.get('properties.performance.reference')) {
        // debug('fetch performance')
        entu.get_entity(id=entity_in.get('properties.performance.reference'), null, null, performanceCB=function(error, performance) {
            if (error) {
                debug('Event manipulator performance reference', error)
            }
            entity_out.set('performance', performance_manipulator(performance).get())
            // debug(entity_out.get('performance'))
            callback(null, entity_out)
        })
    } else {
        // debug('no performance')
        callback(null, entity_out)
    }
}

var performance_manipulator = function manipulator_f(entity_in) {
    var entity_out = op({})
    entity_out.set('id', entity_in.get('id'))
    entity_out.set('category', entity_in.get('properties.category'))
    entity_out.set('name', entity_in.get('properties.name.value'))
    entity_out.set('description', entity_in.get('properties.description.md'))
    entity_out.set('photo', entity_in.get('properties.photo.0'))
    entity_out.set('photos', entity_in.get('properties.photo'))
    entity_out.set('video', entity_in.get('properties.video.value'))
    entity_out.set('technical-information', entity_in.get('properties.technical-information.md'))
    return entity_out
}

// Split events into past and future and group by time
cacheEntities(
    name = 'program',
    definition = 'event',
    parent = 597,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 15 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under SAAL Biennaal and group by time
cacheEntities(
    name = 'SAAL_Biennaal',
    definition = 'event',
    parent = 1932,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under NU Performance and group by time
cacheEntities(
    name = 'NU_Performance',
    definition = 'event',
    parent = 1933,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under Tours and group by time
cacheEntities(
    name = 'tours',
    definition = 'event',
    parent = 1929,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Fetch events from under Residency and group by time
cacheEntities(
    name = 'Residency',
    definition = 'event',
    parent = 1931,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 30 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var event_times = entity.get('start-times')
        var markers = []
        if (!event_times || !Array.isArray(event_times) || event_times.length == 0) {
            markers.push('no_date')
        } else {
            for (i in event_times.sort()) {
                var ms = Date.parse(event_times[i])
                var event_date = (event_times[i]).slice(0,10)
                var event_time = (event_times[i]).slice(11,16)
                // var event_date = (new Date(ms)).toJSON().slice(0,10)
                if (ms < Date.now()) {
                    markers.push('past.' + event_date + '.' + event_time)
                } else if (ms >= Date.now()) {
                    markers.push('upcoming.' + event_date + '.' + event_time)
                }
            }
        }
        return markers
    },
    manipulator_f = event_manipulator
)

// Split news into old and new and group by time
cacheEntities(
    name = 'news',
    definition = 'news',
    parent = 597,
    reset_markers = ['no_date', 'past', 'upcoming'],
    delay_ms = 10 * 60 * 1000,
    marker_f = function marker_f(entity) {
        var news_time = entity.get(['properties','time','value'])
        var markers = []
        var ms = Date.parse(news_time)
        var news_date = news_time.slice(0,10)
        // var news_date = (new Date(ms)).toJSON().slice(0,10)
        if (ms < Date.now()) {
            markers.push('past.' + news_date)
        } else if (ms >= Date.now()) {
            markers.push('upcoming.' + news_date)
        }
        return markers
    },
    manipulator_f = function manipulator_f(entity) {
        return entity
    }
)

// Example markers on person
cacheEntities(
    name = 'users',
    definition = 'person',
    parent = null,
    reset_markers = ['entusiastid', 'others'],
    delay_ms = 60 * 60 * 1000,
    marker_f = function marker_f(entity) {
        if (entity.get('name') == 'Mihkel-Mikelis Putrinš')
            return ['entusiastid.mihkel']
        else if (entity.get('name') == 'Argo Roots')
            return ['entusiastid.argo']
        else
            return ['others']
    },
    manipulator_f = function manipulator_f(entity_in) {
        var entity_out = op({})
        entity_out.set('id', entity_in.get('id'))
        entity_out.set('name', entity_in.get('displayname'))
        entity_out.set('entity', entity_in.get())
        return entity_out
    }
)<|endoftext|>


<commit_before>/**
 * @file
 * JS Integration between CiviCRM & Stripe.
 */
(function($, CRM) {

  var $form, $submit, buttonText;
  var isWebform = false;

  // Response from Stripe.createToken.
  function stripeResponseHandler(status, response) {
    if (response.error) {
      $('html, body').animate({scrollTop: 0}, 300);
      // Show the errors on the form.
      if ($(".messages.crm-error.stripe-message").length > 0) {
        $(".messages.crm-error.stripe-message").slideUp();
        $(".messages.crm-error.stripe-message:first").remove();
      }
      $form.prepend('
'
      + 'Payment Error Response:'
      + '
'
      + '
Error: ' + response.error.message + '
'
      + '
'
      + '
');

      $submit.removeAttr('disabled').attr('value', buttonText);

    }
    else {
      var token = response['id'];
      // Update form with the token & submit.
      $form.find("input#stripe-token").val(token);
      $form.find("input#credit_card_number").removeAttr('name');
      $form.find("input#cvv2").removeAttr('name');
      $submit.prop('disabled', false);
      window.onbeforeunload = null;
      $form.get(0).submit();
    }
  }

  // Prepare the form.
  $(document).ready(function() {
    $.getScript('https://js.stripe.com/v2/', function () {
      Stripe.setPublishableKey($('#stripe-pub-key').val());
    });

    if ($('.webform-client-form').length) {
      isWebform = true;
      $('form.webform-client-form').addClass('stripe-payment-form');
    }
    else {
      if (!($('.stripe-payment-form').length)) {
        $('#crm-container > form').addClass('stripe-payment-form');
      }
    }
    $form   = $('form.stripe-payment-form');
    if (isWebform) {
      $submit = $form.find('.button-primary');
    }
    else {
      $submit = $form.find('input[type="submit"][formnovalidate!="1"]');

      // If CiviDiscount button or field is submitted, flag the form.
      $form.data('cividiscount-dont-handle', '0');
      $form.find('input[type="submit"][formnovalidate="1"]').click( function() {
        $form.data('cividiscount-dont-handle', 1);
      });
      $form.find('input#discountcode').keypress( function(e) {
        if (e.which == 13) {
          $form.data('cividiscount-dont-handle', 1);
        }
      });
      $submit;
    }

    // For CiviCRM Webforms.
    if (isWebform) {
      if (!($('#action').length)) {
        $form.append('<input type="hidden" name="op" id="action" />');
      }
      $(document).keypress(function(event) {
        if (event.which == 13) {
          event.preventDefault();
          $submit.click();
        }
      });
      $(":submit").click(function() {
        $('#action').val(this.value);
      });
      $('#billingcheckbox:input').hide();
      $('label[for="billingcheckbox"]').hide();

      var webformPrevious = $('input.webform-previous').first().val();
    }
    else {
      // This is native civicrm form - check for existing token.
      if ($form.find("input#stripe-token").val()) {
        $('.credit_card_info-group').hide();
        $('#billing-payment-block').append('<input type="button" value="Edit CC details" id="ccButton" />');
        $('#ccButton').click(function() {
          $('.credit_card_info-group').show();
          $('#ccButton').hide();
          $form.find('input#stripe-token').val('');
        });
      }
    }

    $submit.removeAttr('onclick');

    $form.unbind('submit');

    // Intercept form submission.
    $form.submit(function (event) {
      // Don't handle submits generated by the CiviDiscount button.
      if ($form.data('cividiscount-dont-handle') == 1) {
        return true;
      }
      if (isWebform) {
        var $processorFields = $('.civicrm-enabled[name$="civicrm_1_contribution_1_contribution_payment_processor_id]"]');

        if ($('#action').attr('value') == webformPrevious) {
          return true;
        }
        if ($('#wf-crm-billing-total').length) {
          if ($('#wf-crm-billing-total').data('data-amount') == '0') {
            return true;
          }
        }
        if ($processorFields.length) {
          if ($processorFields.filter(':checked').val() == '0') {
            return true;
          }
          if (!($form.find('input[name="stripe_token"]').length)) {
            return true;
          }
        }
      }
      // Disable the submit button to prevent repeated clicks, cache button text, restore if Stripe returns error
      buttonText = $submit.attr('value');
      $submit.prop('disabled', true).attr('value', 'Processing');

      // Hide payment if total is 0 and no more participants.
      if ($('#priceset').length) {
        additionalParticipants = cj("#additional_participants").val();
        // The currentTotal is already being calculated in Form/Contribution/Main.tpl.
        if(typeof currentTotal !== 'undefined') {
          if (currentTotal == 0 && !additionalParticipants) {
            // This is also hit when "Going back", but we already have stripe_token.
            return true;
          }
        }
      }

      // Handle multiple payment options and Stripe not being chosen.
      if ($form.find(".crm-section.payment_processor-section").length > 0) {
        if ($form.find('input[name="payment_processor_id"]:checked').length) {
          processorId=$form.find('input[name="payment_processor_id"]:checked').val();
          if (!($form.find('input[name="stripe_token"]').length) || ($('#stripe-id').length && $('#stripe-id').val() != processorId)) {
            return true;
          }
        }
        else {
          // No payment processor is checked.
          return true;
        }
      }

      // Handle pay later (option value '0' in payment_processor radio group).
      if ($form.find('input[name="payment_processor_id"]:checked').length && !parseInt($form.find('input[name="payment_processor_id"]:checked').val())) {
        return true;
      }

      // Handle reuse of existing token
      if ($form.find("input#stripe-token").val()) {
        $form.find("input#credit_card_number").removeAttr('name');
        $form.find("input#cvv2").removeAttr('name');
        return true;
      }

      // If there's no credit card field, no use in continuing (probably wrong
      // context anyway)
      if (!$form.find('#credit_card_number').length) {
        return true;
      }

      event.preventDefault();
      event.stopPropagation();

      // Handle changes introduced in CiviCRM 4.3.
      if ($form.find('#credit_card_exp_date_M').length > 0) {
        var cc_month = $form.find('#credit_card_exp_date_M').val();
        var cc_year = $form.find('#credit_card_exp_date_Y').val();
      }
      else {
        var cc_month = $form.find('#credit_card_exp_date\\[M\\]').val();
        var cc_year = $form.find('#credit_card_exp_date\\[Y\\]').val();
      }
      Stripe.card.createToken({
        name:        $form.find('#billing_first_name').val() + ' ' + $form.find('#billing_last_name').val(),
        address_zip: $form.find('#billing_postal_code-5').val(),
        number:      $form.find('#credit_card_number').val(),
        cvc:         $form.find('#cvv2').val(),
        exp_month:   cc_month,
        exp_year:    cc_year
      }, stripeResponseHandler);

      return false;
    });
  });
}(cj, CRM));
<commit_msg>Don't submit if the back button is clicked<commit_after>/**
 * @file
 * JS Integration between CiviCRM & Stripe.
 */
(function($, CRM) {

  var $form, $submit, buttonText;
  var isWebform = false;

  // Response from Stripe.createToken.
  function stripeResponseHandler(status, response) {
    if (response.error) {
      $('html, body').animate({scrollTop: 0}, 300);
      // Show the errors on the form.
      if ($(".messages.crm-error.stripe-message").length > 0) {
        $(".messages.crm-error.stripe-message").slideUp();
        $(".messages.crm-error.stripe-message:first").remove();
      }
      $form.prepend('
'
      + 'Payment Error Response:'
      + '
'
      + '
Error: ' + response.error.message + '
'
      + '
'
      + '
');

      $submit.removeAttr('disabled').attr('value', buttonText);

    }
    else {
      var token = response['id'];
      // Update form with the token & submit.
      $form.find("input#stripe-token").val(token);
      $form.find("input#credit_card_number").removeAttr('name');
      $form.find("input#cvv2").removeAttr('name');
      $submit.prop('disabled', false);
      window.onbeforeunload = null;
      $form.get(0).submit();
    }
  }

  // Prepare the form.
  $(document).ready(function() {
    $.getScript('https://js.stripe.com/v2/', function () {
      Stripe.setPublishableKey($('#stripe-pub-key').val());
    });

    if ($('.webform-client-form').length) {
      isWebform = true;
      $('form.webform-client-form').addClass('stripe-payment-form');
    }
    else {
      if (!($('.stripe-payment-form').length)) {
        $('#crm-container > form').addClass('stripe-payment-form');
      }
    }
    $form   = $('form.stripe-payment-form');
    if (isWebform) {
      $submit = $form.find('.button-primary');
    }
    else {
      $submit = $form.find('input[type="submit"][formnovalidate!="1"]');

      // If CiviDiscount button or field is submitted, flag the form.
      $form.data('cividiscount-dont-handle', '0');
      // This is an ugly hack. Really, the code should positively identify the
      // "real" submit button(s) and only respond to them.  Otherwise, we're
      // chasing down a potentially endless number of exceptions.  The problem
      // is that it's unclear if CiviCRM consistently names its submit buttons.
      $form.find('input[type="submit"][formnovalidate="1"], input[type="submit"].cancel').click( function() {
        $form.data('cividiscount-dont-handle', 1);
      });
      $form.find('input#discountcode').keypress( function(e) {
        if (e.which == 13) {
          $form.data('cividiscount-dont-handle', 1);
        }
      });
      $submit;
    }

    // For CiviCRM Webforms.
    if (isWebform) {
      if (!($('#action').length)) {
        $form.append('<input type="hidden" name="op" id="action" />');
      }
      $(document).keypress(function(event) {
        if (event.which == 13) {
          event.preventDefault();
          $submit.click();
        }
      });
      $(":submit").click(function() {
        $('#action').val(this.value);
      });
      $('#billingcheckbox:input').hide();
      $('label[for="billingcheckbox"]').hide();

      var webformPrevious = $('input.webform-previous').first().val();
    }
    else {
      // This is native civicrm form - check for existing token.
      if ($form.find("input#stripe-token").val()) {
        $('.credit_card_info-group').hide();
        $('#billing-payment-block').append('<input type="button" value="Edit CC details" id="ccButton" />');
        $('#ccButton').click(function() {
          $('.credit_card_info-group').show();
          $('#ccButton').hide();
          $form.find('input#stripe-token').val('');
        });
      }
    }

    $submit.removeAttr('onclick');

    $form.unbind('submit');

    // Intercept form submission.
    $form.submit(function (event) {
      // Don't handle submits generated by the CiviDiscount button.
      if ($form.data('cividiscount-dont-handle') == 1) {
        return true;
      }
      if (isWebform) {
        var $processorFields = $('.civicrm-enabled[name$="civicrm_1_contribution_1_contribution_payment_processor_id]"]');

        if ($('#action').attr('value') == webformPrevious) {
          return true;
        }
        if ($('#wf-crm-billing-total').length) {
          if ($('#wf-crm-billing-total').data('data-amount') == '0') {
            return true;
          }
        }
        if ($processorFields.length) {
          if ($processorFields.filter(':checked').val() == '0') {
            return true;
          }
          if (!($form.find('input[name="stripe_token"]').length)) {
            return true;
          }
        }
      }
      // Disable the submit button to prevent repeated clicks, cache button text, restore if Stripe returns error
      buttonText = $submit.attr('value');
      $submit.prop('disabled', true).attr('value', 'Processing');

      // Hide payment if total is 0 and no more participants.
      if ($('#priceset').length) {
        additionalParticipants = cj("#additional_participants").val();
        // The currentTotal is already being calculated in Form/Contribution/Main.tpl.
        if(typeof currentTotal !== 'undefined') {
          if (currentTotal == 0 && !additionalParticipants) {
            // This is also hit when "Going back", but we already have stripe_token.
            return true;
          }
        }
      }

      // Handle multiple payment options and Stripe not being chosen.
      if ($form.find(".crm-section.payment_processor-section").length > 0) {
        if ($form.find('input[name="payment_processor_id"]:checked').length) {
          processorId=$form.find('input[name="payment_processor_id"]:checked').val();
          if (!($form.find('input[name="stripe_token"]').length) || ($('#stripe-id').length && $('#stripe-id').val() != processorId)) {
            return true;
          }
        }
        else {
          // No payment processor is checked.
          return true;
        }
      }

      // Handle pay later (option value '0' in payment_processor radio group).
      if ($form.find('input[name="payment_processor_id"]:checked').length && !parseInt($form.find('input[name="payment_processor_id"]:checked').val())) {
        return true;
      }

      // Handle reuse of existing token
      if ($form.find("input#stripe-token").val()) {
        $form.find("input#credit_card_number").removeAttr('name');
        $form.find("input#cvv2").removeAttr('name');
        return true;
      }

      // If there's no credit card field, no use in continuing (probably wrong
      // context anyway)
      if (!$form.find('#credit_card_number').length) {
        return true;
      }

      event.preventDefault();
      event.stopPropagation();

      // Handle changes introduced in CiviCRM 4.3.
      if ($form.find('#credit_card_exp_date_M').length > 0) {
        var cc_month = $form.find('#credit_card_exp_date_M').val();
        var cc_year = $form.find('#credit_card_exp_date_Y').val();
      }
      else {
        var cc_month = $form.find('#credit_card_exp_date\\[M\\]').val();
        var cc_year = $form.find('#credit_card_exp_date\\[Y\\]').val();
      }
      Stripe.card.createToken({
        name:        $form.find('#billing_first_name').val() + ' ' + $form.find('#billing_last_name').val(),
        address_zip: $form.find('#billing_postal_code-5').val(),
        number:      $form.find('#credit_card_number').val(),
        cvc:         $form.find('#cvv2').val(),
        exp_month:   cc_month,
        exp_year:    cc_year
      }, stripeResponseHandler);

      return false;
    });
  });
}(cj, CRM));
<|endoftext|>