<commit_before>const $ = require('jquery');
const co = require('co');

const constants = require('../common/constants.js');
const bg = require('../common/background.js');
const ga = require('../common/ga.js');

bg.messageListener(function*(req, sender) {
    if (req.action == 'setSession')
        return yield* setSession(req, sender);
    if (req.action == 'getUser')
        return yield* bg.getUser();
    if (req.action == 'getCampaignDataRange')
        return yield* getCampaignDataRange(req.campaignId, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getAdGroupDataRange')
        return yield* getAdGroupDataRange(req.campaignId, req.adGroupId, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getAdDataRangeByAsin')
        return yield* getAdDataRangeByAsin(req.campaignId, req.adGroupId, req.asin, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getKeywordDataRange')
        return yield* getKeywordDataRange(req.campaignId, req.adGroupId, req.startTimestamp, req.endTimestamp);
    throw new Error('unknown action');
});

function* synchronizeCampaignData() {
    console.log('synchronizeCampaignData start at', new Date());

    try {
        const ranges = yield* getMissingRanges();
        for (const range of ranges) {
            const campaignIds = yield* requestCampaignDataRange(range.start, range.end);

            for (const campaignId of campaignIds) {
                const adGroupIds = yield* requestAdGroupDataRange(campaignId, range.start, range.end);

                // This innermost loop we can parallelize for speed without
                // blowing things up too much, hopefully
                const promises = [];

                for (const adGroupId of adGroupIds) {
                    promises.push(co(requestAdDataRange(campaignId, adGroupId, range.start, range.end)));
                    promises.push(co(requestKeywordDataRange(campaignId, adGroupId, range.start, range.end)));
                }

                yield Promise.all(promises);
            }
        }
    }
    catch (ex) {
        ga.mex(ex, false);
    }
    finally {
        console.log('synchronizeCampaignData finish at', new Date());
    }
}

function* setSession(req, sender) {
    chrome.pageAction.show(sender.tab.id);
    yield* synchronizeCampaignData();
}

function* requestAllPages(getCurrentPage) {
    const pageSize = 50;
    let currentPage = 0;
    let totalRecords = 0;
    let data = null;

    do {
        data = yield* getCurrentPage(pageSize, currentPage * pageSize);
        totalRecords = data.iTotalRecords;
        currentPage++;
    }
    while (currentPage * pageSize < totalRecords);

    return data;
}

function* requestSellerDataRange(subRoute, filters, startTimestamp, endTimestamp, dataCallback) {
    return yield* requestAllPages(function*(pageSize, currentRecord) {
        const requestParams = {
            sEcho: 1,
            parentCreationDate: 0,
            iDisplayStart: currentRecord,
            iDisplayLength: pageSize,
            statisticsPeriod: 'CUSTOMIZED',
            aggregates: true,
            startDate: startTimestamp,
            endDate: endTimestamp,
            statusFilter: 'ENABLED',
        };
        if (filters) {
            if (filters.statusFilter) {
                requestParams.statusFilter = filters.statusFilter;
                delete filters.statusFilter;
            }
            requestParams.filters = JSON.stringify(filters);
        }

        const data = yield $.ajax(`https://sellercentral.amazon.com/hz/cm/${subRoute}/fetch`, {
            method: 'GET',
            data: requestParams,
            dataType: 'json',
        });

        yield* dataCallback(data);
        return data;
    });
}

function dataIdsWithImpressions(data) {
    const idIndex = data.columnNames.indexOf('id');
    const impressionsIndex = data.columnNames.indexOf('impressions');
    return data.aaData.filter(x => x[idIndex] && x[impressionsIndex]).map(x => x[idIndex]);
}

function* requestCampaignDataRange(startTimestamp, endTimestamp) {
    const campaignIds = new Set();
    console.log('requesting campaign data in range', startTimestamp, endTimestamp);

    yield* requestSellerDataRange('campaign', null, startTimestamp, endTimestamp, function*(data) {
        // We always store campaign data ranges, because that acts as a signal
        // that we've synced data for this range.
        yield* storeCampaignDataRange(data, startTimestamp, endTimestamp);

        // Don't bother doing anything else if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        // Gather the IDs of the campaigns discovered in this data range which
        // have non-zero impressions
        dataIdsWithImpressions(data).forEach(x => campaignIds.add(x));
    });

    return Array.from(campaignIds);
}

function* requestAdGroupDataRange(campaignId, startTimestamp, endTimestamp) {
    const adGroupIds = new Set();
    console.log('requesting adGroupData data in range', startTimestamp, endTimestamp, 'campaignId', campaignId);

    const filters = {campaign: { id: { eq: [campaignId] } } };
    yield* requestSellerDataRange('adgroup', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeAdGroupDataRange(data, startTimestamp, endTimestamp);

        // Gather the adGroupIds of the ad groups discovered in this data range
        dataIdsWithImpressions(data).forEach(x => adGroupIds.add(x));
    });

    return Array.from(adGroupIds);
}

function* requestAdDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    console.log('requesting ad data in range', startTimestamp, endTimestamp, 'campaignId', campaignId, 'adGroupId', adGroupId);
    const filters = {campaign: { id: { eq: [campaignId] } }, adGroup: { id: { eq: [adGroupId] } } };
    return yield* requestSellerDataRange('ad', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeAdDataRange(data, startTimestamp, endTimestamp);
    });
}

function* requestKeywordDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    console.log('requesting keyword data in range', startTimestamp, endTimestamp, 'campaignId', campaignId, 'adGroupId', adGroupId);
    const filters = {
        statusFilter: 'ENABLED|PAUSED',
        matchType: { eq: ["broad", "phrase", "exact"] },
        campaign: { id: { eq: [campaignId] } },
        adGroup: { id: { eq: [adGroupId] } }
    };
    return yield* requestSellerDataRange('keyword', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeKeywordDataRange(data, startTimestamp, endTimestamp);
    });
}

function* getMissingRanges() {
    return yield $.ajax(`https://${constants.hostname}/api/seller/campaignData/missingRanges`, {
        method: 'GET',
        dataType: 'json',
    });
}

function* storeSellerDataRange(subRoute, data, startTimestamp, endTimestamp) {
    return yield $.ajax(`https://${constants.hostname}/api/seller/${subRoute}/${startTimestamp}-${endTimestamp}`, {
        method: 'PUT',
        data: JSON.stringify(data),
        contentType: 'application/json',
    });
}

function* getSellerDataRange(subRoute, startTimestamp, endTimestamp) {
    return yield $.ajax(`https://${constants.hostname}/api/seller/${subRoute}/${startTimestamp}-${endTimestamp}`, {
        method: 'GET',
        dataType: 'json'
    });
}

function* storeCampaignDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('campaignData', data, startTimestamp, endTimestamp);
}

function* getCampaignDataRange(campaignId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`campaignData/${campaignId}`, startTimestamp, endTimestamp);
}

function* storeAdGroupDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('adGroupData', data, startTimestamp, endTimestamp);
}

function* getAdGroupDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`adGroupData/${campaignId}/${adGroupId}`, startTimestamp, endTimestamp);
}

function* storeAdDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('adData', data, startTimestamp, endTimestamp);
}

function* getAdDataRangeByAsin(campaignId, adGroupId, asin, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`adData/${campaignId}/${adGroupId}/asin=${asin}`, startTimestamp, endTimestamp);
}

function* storeKeywordDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('keywordData', data, startTimestamp, endTimestamp);
}

function* getKeywordDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`keywordData/${campaignId}/${adGroupId}`, startTimestamp, endTimestamp);
}
<commit_msg>changed all seller calls to use the bg ajax call<commit_after>const co = require('co');

const constants = require('../common/constants.js');
const bg = require('../common/background.js');
const ga = require('../common/ga.js');

bg.messageListener(function*(req, sender) {
    if (req.action == 'setSession')
        return yield* setSession(req, sender);
    if (req.action == 'getUser')
        return yield* bg.getUser();
    if (req.action == 'getCampaignDataRange')
        return yield* getCampaignDataRange(req.campaignId, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getAdGroupDataRange')
        return yield* getAdGroupDataRange(req.campaignId, req.adGroupId, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getAdDataRangeByAsin')
        return yield* getAdDataRangeByAsin(req.campaignId, req.adGroupId, req.asin, req.startTimestamp, req.endTimestamp);
    if (req.action == 'getKeywordDataRange')
        return yield* getKeywordDataRange(req.campaignId, req.adGroupId, req.startTimestamp, req.endTimestamp);
    throw new Error('unknown action');
});

function* synchronizeCampaignData() {
    console.log('synchronizeCampaignData start at', new Date());

    try {
        const ranges = yield* getMissingRanges();
        for (const range of ranges) {
            const campaignIds = yield* requestCampaignDataRange(range.start, range.end);

            for (const campaignId of campaignIds) {
                const adGroupIds = yield* requestAdGroupDataRange(campaignId, range.start, range.end);

                // This innermost loop we can parallelize for speed without
                // blowing things up too much, hopefully
                const promises = [];

                for (const adGroupId of adGroupIds) {
                    promises.push(co(requestAdDataRange(campaignId, adGroupId, range.start, range.end)));
                    promises.push(co(requestKeywordDataRange(campaignId, adGroupId, range.start, range.end)));
                }

                yield Promise.all(promises);
            }
        }
    }
    catch (ex) {
        ga.mex(ex, false);
    }
    finally {
        console.log('synchronizeCampaignData finish at', new Date());
    }
}

function* setSession(req, sender) {
    chrome.pageAction.show(sender.tab.id);
    yield* synchronizeCampaignData();
}

function* requestAllPages(getCurrentPage) {
    const pageSize = 50;
    let currentPage = 0;
    let totalRecords = 0;
    let data = null;

    do {
        data = yield* getCurrentPage(pageSize, currentPage * pageSize);
        totalRecords = data.iTotalRecords;
        currentPage++;
    }
    while (currentPage * pageSize < totalRecords);

    return data;
}

function* requestSellerDataRange(subRoute, filters, startTimestamp, endTimestamp, dataCallback) {
    return yield* requestAllPages(function*(pageSize, currentRecord) {
        const requestParams = {
            sEcho: 1,
            parentCreationDate: 0,
            iDisplayStart: currentRecord,
            iDisplayLength: pageSize,
            statisticsPeriod: 'CUSTOMIZED',
            aggregates: true,
            startDate: startTimestamp,
            endDate: endTimestamp,
            statusFilter: 'ENABLED',
        };
        if (filters) {
            if (filters.statusFilter) {
                requestParams.statusFilter = filters.statusFilter;
                delete filters.statusFilter;
            }
            requestParams.filters = JSON.stringify(filters);
        }

        const data = yield bg.ajax(`https://sellercentral.amazon.com/hz/cm/${subRoute}/fetch`, {
            method: 'GET',
            data: requestParams,
            dataType: 'json',
        });

        yield* dataCallback(data);
        return data;
    });
}

function dataIdsWithImpressions(data) {
    const idIndex = data.columnNames.indexOf('id');
    const impressionsIndex = data.columnNames.indexOf('impressions');
    return data.aaData.filter(x => x[idIndex] && x[impressionsIndex]).map(x => x[idIndex]);
}

function* requestCampaignDataRange(startTimestamp, endTimestamp) {
    const campaignIds = new Set();
    console.log('requesting campaign data in range', startTimestamp, endTimestamp);

    yield* requestSellerDataRange('campaign', null, startTimestamp, endTimestamp, function*(data) {
        // We always store campaign data ranges, because that acts as a signal
        // that we've synced data for this range.
        yield* storeCampaignDataRange(data, startTimestamp, endTimestamp);

        // Don't bother doing anything else if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        // Gather the IDs of the campaigns discovered in this data range which
        // have non-zero impressions
        dataIdsWithImpressions(data).forEach(x => campaignIds.add(x));
    });

    return Array.from(campaignIds);
}

function* requestAdGroupDataRange(campaignId, startTimestamp, endTimestamp) {
    const adGroupIds = new Set();
    console.log('requesting adGroupData data in range', startTimestamp, endTimestamp, 'campaignId', campaignId);

    const filters = {campaign: { id: { eq: [campaignId] } } };
    yield* requestSellerDataRange('adgroup', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeAdGroupDataRange(data, startTimestamp, endTimestamp);

        // Gather the adGroupIds of the ad groups discovered in this data range
        dataIdsWithImpressions(data).forEach(x => adGroupIds.add(x));
    });

    return Array.from(adGroupIds);
}

function* requestAdDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    console.log('requesting ad data in range', startTimestamp, endTimestamp, 'campaignId', campaignId, 'adGroupId', adGroupId);
    const filters = {campaign: { id: { eq: [campaignId] } }, adGroup: { id: { eq: [adGroupId] } } };
    return yield* requestSellerDataRange('ad', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeAdDataRange(data, startTimestamp, endTimestamp);
    });
}

function* requestKeywordDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    console.log('requesting keyword data in range', startTimestamp, endTimestamp, 'campaignId', campaignId, 'adGroupId', adGroupId);
    const filters = {
        statusFilter: 'ENABLED|PAUSED',
        matchType: { eq: ["broad", "phrase", "exact"] },
        campaign: { id: { eq: [campaignId] } },
        adGroup: { id: { eq: [adGroupId] } }
    };
    return yield* requestSellerDataRange('keyword', filters, startTimestamp, endTimestamp, function*(data) {
        // Don't bother storing if nothing happened in this range
        if (!data.aggrStatData.impressions)
            return;

        yield* storeKeywordDataRange(data, startTimestamp, endTimestamp);
    });
}

function* getMissingRanges() {
    return yield bg.ajax(`https://${constants.hostname}/api/seller/campaignData/missingRanges`, {
        method: 'GET',
        dataType: 'json',
    });
}

function* storeSellerDataRange(subRoute, data, startTimestamp, endTimestamp) {
    return yield bg.ajax(`https://${constants.hostname}/api/seller/${subRoute}/${startTimestamp}-${endTimestamp}`, {
        method: 'PUT',
        data: JSON.stringify(data),
        contentType: 'application/json',
    });
}

function* getSellerDataRange(subRoute, startTimestamp, endTimestamp) {
    return yield bg.ajax(`https://${constants.hostname}/api/seller/${subRoute}/${startTimestamp}-${endTimestamp}`, {
        method: 'GET',
        dataType: 'json'
    });
}

function* storeCampaignDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('campaignData', data, startTimestamp, endTimestamp);
}

function* getCampaignDataRange(campaignId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`campaignData/${campaignId}`, startTimestamp, endTimestamp);
}

function* storeAdGroupDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('adGroupData', data, startTimestamp, endTimestamp);
}

function* getAdGroupDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`adGroupData/${campaignId}/${adGroupId}`, startTimestamp, endTimestamp);
}

function* storeAdDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('adData', data, startTimestamp, endTimestamp);
}

function* getAdDataRangeByAsin(campaignId, adGroupId, asin, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`adData/${campaignId}/${adGroupId}/asin=${asin}`, startTimestamp, endTimestamp);
}

function* storeKeywordDataRange(data, startTimestamp, endTimestamp) {
    return yield* storeSellerDataRange('keywordData', data, startTimestamp, endTimestamp);
}

function* getKeywordDataRange(campaignId, adGroupId, startTimestamp, endTimestamp) {
    return yield* getSellerDataRange(`keywordData/${campaignId}/${adGroupId}`, startTimestamp, endTimestamp);
}
<|endoftext|>


<commit_before>//= require ../store
//= require ../dispatcher

(function () {

"use strict";

var JobsStream = Dashboard.Stores.JobsStream = Dashboard.Store.createClass({
	displayName: "Stores.JobOutput",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = {
			appId: this.id.appId,
		};
		this.url = Dashboard.config.endpoints.cluster_controller + "/apps/"+ this.props.appId +"/jobs?key="+ encodeURIComponent(Dashboard.config.user.controller_key);
	},

	didBecomeActive: function () {
		this.__openEventStream();
	},

	didBecomeInactive: function () {
		return this.constructor.__super__.didBecomeInactive.apply(this, arguments).then(function () {
			if (this.__eventSource) {
				this.__eventSource.close();
			}
		}.bind(this));
	},

	getInitialState: function () {
		return {};
	},

	__openEventStream: function () {
		if ( !window.hasOwnProperty('EventSource') ) {
			return;
		}

		var url = this.url;
		var eventSource;
		eventSource = new window.EventSource(url, {withCredentials: true});
		eventSource.addEventListener("close", function () {
			this.__eventSource = null;
		});
		eventSource.addEventListener("message", function (e) {
			var evnt = JSON.parse(e.data || "");
			Dashboard.Dispatcher.handleAppEvent({
				name: "JOB_STATE_CHANGE",
				appId: this.props.appId,
				jobId: evnt.job_id,
				state: evnt.state
			});
		}.bind(this), false);

		this.__eventSource = eventSource;
	}

});

JobsStream.isValidId = function (id) {
	return id.appId;
};

})();
<commit_msg>dashboard: Fix job events stream<commit_after>//= require ../store
//= require ../dispatcher

(function () {

"use strict";

var JobsStream = Dashboard.Stores.JobsStream = Dashboard.Store.createClass({
	displayName: "Stores.JobOutput",

	getState: function () {
		return this.state;
	},

	willInitialize: function () {
		this.props = {
			appId: this.id.appId,
		};
		this.url = Dashboard.config.endpoints.cluster_controller +'/apps/'+ this.props.appId +'/events';
		this.url = this.url + Marbles.QueryParams.serializeParams([{
			key: Dashboard.config.user.controller_key,
			object_type: 'job',
			past: 'true'
		}]);
	},

	didBecomeActive: function () {
		this.__openEventStream();
	},

	didBecomeInactive: function () {
		return this.constructor.__super__.didBecomeInactive.apply(this, arguments).then(function () {
			if (this.__eventSource) {
				this.__eventSource.close();
			}
		}.bind(this));
	},

	getInitialState: function () {
		return {};
	},

	__openEventStream: function () {
		if ( !window.hasOwnProperty('EventSource') ) {
			return;
		}

		var url = this.url;
		var eventSource;
		eventSource = new window.EventSource(url, {withCredentials: true});
		eventSource.addEventListener("close", function () {
			this.__eventSource = null;
		});
		eventSource.addEventListener("message", function (e) {
			var res = JSON.parse(e.data || "");
			var evnt = res.data;
			Dashboard.Dispatcher.handleAppEvent({
				name: "JOB_STATE_CHANGE",
				appId: this.props.appId,
				jobId: evnt.job_id,
				state: evnt.state
			});
		}.bind(this), false);

		this.__eventSource = eventSource;
	}

});

JobsStream.isValidId = function (id) {
	return id.appId;
};

})();
<|endoftext|>


<commit_before>epeek.genome.tooltip = function() {
    "use strict";
    var path = epeek.scriptPath("ePeek.js");

    // Style options
    var bgColor;
    var fgColor;

    var tooltip = function(gene) {
	var drag = d3.behavior.drag()
	    .origin(function(){
		return {x:parseInt(d3.select(this).style("left")),
			y:parseInt(d3.select(this).style("top"))
		       }
	    })
	    .on("drag", function() {
		d3.select(this)
		    .style("left", d3.event.x + "px")
		    .style("top", d3.event.y + "px")
	    });

	var sel = d3.select(".ePeek_groupDiv")
	    .append("div")
	    .attr("class", "ePeek_gene_info")
 	    .classed("ePeek_gene_info_active", true)
	    .call(drag);
	sel
	    .style("left", d3.mouse(this)[0] + "px")
	    .style("top", d3.mouse(this)[1] + "px");

	var gene_info_table = sel
	    .append("table")
	    .attr("class", "ePeek_zmenu")
	    .style("border-color", fgColor)
	gene_info_table
	    .append("tr")
	    .attr("class", "ePeek_gene_info_header")
	    .append("th")
	    .style("background-color", fgColor)
	    .style("color", bgColor)
	    .attr("colspan", 2)
	    .text("HGNC Symbol: " + gene.external_name);
	var gene_tr = gene_info_table
	    .append("tr")
	gene_tr
	    .append("th")
	    .style("border-color", fgColor)
	    .text("Gene");
	gene_tr
	    .append("td")
	    .append("a")
	    .attr("href", "kk")
	    .text(gene.ID);
	var type_tr = gene_info_table
	    .append("tr");
	type_tr
	    .append("th")
	    .text("Gene Type");
	type_tr
	    .append("td")
	    .text(gene.biotype);
	var location_tr = gene_info_table
	    .append("tr");
	location_tr
	    .append("th")
	    .text("Location");
	location_tr
	    .append("td")
	    .append("a")
	    .attr("href", "kk")
	    .text(gene.seq_region_name + ":" + gene.start + "-" + gene.end);
	var strand_tr = gene_info_table
	    .append("tr")
	strand_tr
	    .append("th")
	    .text("Strand")
	strand_tr
	    .append("td")
	    .text(function(){return gene.strand === 1 ? "Forward" : "Reverse"});
	var description_tr = gene_info_table
	    .append("tr")
	description_tr
	    .append("th")
	    .text("Description")
	description_tr
	    .append("td")
	    .text(gene.description);

	// Close
	sel.append("span")
	    .style("position", "absolute")
	    .style("right", "-10px")
	    .style("top", "-10px")
	    .append("img")
	    .attr("src", path + "lib/close.png")
	    .attr("width", "20px")
	    .attr("height", "20px")
	    .on("click", function() {d3.select(this).node().parentNode.parentNode.remove();});
//     sel.classed("ePeek_gene_info_active", false)});

    };

    tooltip.background_color = function(color) {
	if (!arguments.length) {
	    return bgColor;
	}
	bgColor = color;
	return tooltip;
    };

    tooltip.foreground_color = function(color) {
	if (!arguments.length) {
	    return fgColor;
	}
	fgColor = color;
	return tooltip;
    };

    return tooltip;
};
<commit_msg>moved to lib/tooltip/tooltip.js<commit_after><|endoftext|>


<commit_before>/*!
 * ${copyright}
 */

// Provides class sap.ui.rta.plugin.Selection.
sap.ui.define([
	'sap/ui/rta/plugin/Plugin',
	'sap/ui/rta/Utils',
	'sap/ui/fl/Utils'
],
function(Plugin, Utils, FlexUtils) {
	"use strict";

	/**
	 * Constructor for a new Selection plugin.
	 *
	 * @param {string} [sId] id for the new object, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new object
	 * @class The Selection plugin allows you to select or focus overlays with mouse or keyboard and navigate to others.
	 * @extends sap.ui.rta.plugin.Plugin
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @private
	 * @since 1.34
	 * @alias sap.ui.rta.plugin.Selection
	 * @experimental Since 1.34. This class is experimental and provides only limited functionality. Also the API might be changed in future.
	 */
	var Selection = Plugin.extend("sap.ui.rta.plugin.Selection", /** @lends sap.ui.dt.Plugin.prototype */
	{
		metadata: {
			// ---- object ----

			// ---- control specific ----
			library: "sap.ui.rta",
			properties: {
				multiSelectionRequiredPlugins : {
					type : "string[]"
				}
			},
			associations: {},
			events: {
				elementEditableChange: {
					parameters: {
						editable: {
							type: "boolean"
						}
					}
				}
			}
		}
	});

	/**
	 * @param {sap.ui.dt.ElementOverlay} oOverlay overlay to be checked for developer mode
	 * @returns {boolean} true if it's in developer mode
	 * @private
	 */
	Selection.prototype._checkDeveloperMode = function(oOverlay) {
		if (oOverlay.getDesignTimeMetadata()) {
			var bDeveloperMode = this.getCommandFactory().getFlexSettings().developerMode;
			if (bDeveloperMode && this.hasStableId(oOverlay)) {
				oOverlay.setEditable(true);
				oOverlay.setSelectable(true);
				this.fireElementEditableChange({
					editable: true
				});
				return true;
			}
		}
		return false;
	};

	/**
	 * Register an overlay
	 *
	 * @param {sap.ui.dt.Overlay} oOverlay overlay object
	 * @override
	 */
	Selection.prototype.registerElementOverlay = function(oOverlay) {
		if (!this._checkDeveloperMode(oOverlay)) {
			oOverlay.attachEditableChange(this._onEditableChange, this);
			this._adaptSelectable(oOverlay);
		}

		oOverlay.attachBrowserEvent("click", this._selectOverlay, this);
		oOverlay.attachBrowserEvent("keydown", this._onKeyDown, this);
		oOverlay.attachBrowserEvent("mousedown", this._onMouseDown, this);
	};

	Selection.prototype._onEditableChange = function(oEvent) {
		var oOverlay = oEvent.getSource();
		this._adaptSelectable(oOverlay);
	};

	Selection.prototype._adaptSelectable = function(oOverlay) {
		var bSelectable = oOverlay.getEditable();
		if (oOverlay.getSelectable() !== bSelectable) {
			oOverlay.setSelectable(bSelectable);
			this.fireElementEditableChange({
				editable: bSelectable
			});
		}
	};

	/**
	 * Additionally to super->deregisterOverlay this method detatches the browser events
	 *
	 * @param {sap.ui.dt.Overlay} oOverlay overlay object
	 * @override
	 */
	Selection.prototype.deregisterElementOverlay = function(oOverlay) {
		oOverlay.detachBrowserEvent("click", this._selectOverlay, this);
		oOverlay.detachBrowserEvent("keydown", this._onKeyDown, this);
		oOverlay.detachBrowserEvent("mousedown", this._onMouseDown, this);

		oOverlay.detachEditableChange(this._onEditableChange, this);
	};

	Selection.prototype._setFocusOnOverlay = function(oOverlay, oEvent) {
		if (oOverlay && oOverlay.getSelectable()) {
			oOverlay.focus();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handle keydown event
	 *
	 * @param {sap.ui.base.Event} oEvent event object
	 * @private
	 */
	Selection.prototype._onKeyDown = function(oEvent) {
		var oOverlay = Utils.getFocusedOverlay();
		if (oEvent.keyCode === jQuery.sap.KeyCodes.ENTER) {
			this._selectOverlay(oEvent);
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_UP && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oParentOverlay = Utils.getFocusableParentOverlay(oOverlay);
				this._setFocusOnOverlay(oParentOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_DOWN && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oFirstChildOverlay = Utils.getFirstFocusableDescendantOverlay(oOverlay);
				this._setFocusOnOverlay(oFirstChildOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_LEFT && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oPrevSiblingOverlay = Utils.getPreviousFocusableSiblingOverlay(oOverlay);
				this._setFocusOnOverlay(oPrevSiblingOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_RIGHT && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oNextSiblingOverlay = Utils.getNextFocusableSiblingOverlay(oOverlay);
				this._setFocusOnOverlay(oNextSiblingOverlay, oEvent);
				oEvent.preventDefault();
			}
		}
	};

	Selection.prototype._selectOverlay = function (oEvent) {
		var oOverlay = sap.ui.getCore().byId(oEvent.currentTarget.id);
		var bMultiSelection = oEvent.metaKey || oEvent.ctrlKey;
		var oTargetClasses = oEvent.target.className;

		if (oOverlay.getSelectable() && oTargetClasses.indexOf("sapUiDtOverlay") > -1) {
			if (bMultiSelection) {
				this.getDesignTime().setSelectionMode(sap.ui.dt.SelectionMode.Multi);
			}

			oOverlay.setSelected(!oOverlay.getSelected());

			if (bMultiSelection) {
				this.getDesignTime().setSelectionMode(sap.ui.dt.SelectionMode.Single);
			}

			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handle MouseDown event
	 *
	 * @param {sap.ui.base.Event} oEvent event object
	 * @private
	 */
	Selection.prototype._onMouseDown = function(oEvent) {
		if (sap.ui.Device.browser.name == "ie"){
			var oOverlay = sap.ui.getCore().byId(oEvent.currentTarget.id);
			if (oOverlay.getSelectable()){
				oOverlay.focus();
				oEvent.stopPropagation();
			} else {
				oOverlay.getDomRef().blur();
			}
		}
	};

	/**
	 * @override
	 */
	Selection.prototype.setDesignTime = function(oDesignTime) {
		//detach from listener from old DesignTime instance
		if (this.getDesignTime()) {
			this.getDesignTime().detachSelectionChange(this._onDesignTimeSelectionChange, this);
		}

		//set new DesignTime instance in parent class
		Plugin.prototype.setDesignTime.apply(this, arguments);

		//attach listener back to the new DesignTime instance
		if (this.getDesignTime()) {
			this.getDesignTime().attachSelectionChange(this._onDesignTimeSelectionChange, this);
		}
	};

	Selection.prototype._onDesignTimeSelectionChange = function(oEvent) {
		if (this.getDesignTime().getSelectionMode() === sap.ui.dt.SelectionMode.Single) {
			return;
		}

		var oCurrentSelectedOverlay = oEvent.getParameter("selection")[oEvent.getParameter("selection").length - 1];
		var aSelections = this.getDesignTime().getSelection();
		if (aSelections && aSelections.length === 1) {
			oCurrentSelectedOverlay.setSelected(true);
			return;
		}
		if (!oCurrentSelectedOverlay || this.getDesignTime().getSelectionMode() === sap.ui.dt.SelectionMode.Single) {
			return;
		}

		//shared relevant container?
		var bMultiSelectisValid = _hasSharedMultiSelectionPlugins(aSelections, this.getMultiSelectionRequiredPlugins())
			&& _hasSharedRelevantContainer(aSelections);
		oCurrentSelectedOverlay.setSelected(bMultiSelectisValid);
	};

	function _hasSharedMultiSelectionPlugins(aSelections, aMultiSelectionRequiredPlugins){
		var aSharedMultiSelectionPlugins = aMultiSelectionRequiredPlugins;
		aSelections.forEach(function(oSelecedOverlay) {
			var aEditableByPlugins = oSelecedOverlay.getEditableByPlugins();
			aSharedMultiSelectionPlugins = aSharedMultiSelectionPlugins.reduce(function(aSharedPlugins, sPluginName){
				if (aEditableByPlugins.indexOf(sPluginName) !== -1){
					aSharedPlugins.push(sPluginName);
				}
				return aSharedPlugins;
			}, []);
		});
		return aSharedMultiSelectionPlugins.length > 0;
	}

	function _hasSharedRelevantContainer(aSelections){
		var oCurrentSelectedOverlay = aSelections[aSelections.length - 1];
		var oPreviousSelectedOverlay = aSelections[aSelections.length - 2];

		var oCurrentRelevantContainer = oCurrentSelectedOverlay.getRelevantContainer();
		var oPreviousRelevantContainer = oPreviousSelectedOverlay.getRelevantContainer();

		return oCurrentRelevantContainer === oPreviousRelevantContainer;
	}

	return Selection;
}, /* bExport= */true);
<commit_msg>[INTERNAL] sap.ui.rta: fix selection issue in IE<commit_after>/*!
 * ${copyright}
 */

// Provides class sap.ui.rta.plugin.Selection.
sap.ui.define([
	'sap/ui/rta/plugin/Plugin',
	'sap/ui/rta/Utils',
	'sap/ui/fl/Utils'
],
function(Plugin, Utils, FlexUtils) {
	"use strict";

	/**
	 * Constructor for a new Selection plugin.
	 *
	 * @param {string} [sId] id for the new object, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new object
	 * @class The Selection plugin allows you to select or focus overlays with mouse or keyboard and navigate to others.
	 * @extends sap.ui.rta.plugin.Plugin
	 * @author SAP SE
	 * @version ${version}
	 * @constructor
	 * @private
	 * @since 1.34
	 * @alias sap.ui.rta.plugin.Selection
	 * @experimental Since 1.34. This class is experimental and provides only limited functionality. Also the API might be changed in future.
	 */
	var Selection = Plugin.extend("sap.ui.rta.plugin.Selection", /** @lends sap.ui.dt.Plugin.prototype */
	{
		metadata: {
			// ---- object ----

			// ---- control specific ----
			library: "sap.ui.rta",
			properties: {
				multiSelectionRequiredPlugins : {
					type : "string[]"
				}
			},
			associations: {},
			events: {
				elementEditableChange: {
					parameters: {
						editable: {
							type: "boolean"
						}
					}
				}
			}
		}
	});

	/**
	 * @param {sap.ui.dt.ElementOverlay} oOverlay overlay to be checked for developer mode
	 * @returns {boolean} true if it's in developer mode
	 * @private
	 */
	Selection.prototype._checkDeveloperMode = function(oOverlay) {
		if (oOverlay.getDesignTimeMetadata()) {
			var bDeveloperMode = this.getCommandFactory().getFlexSettings().developerMode;
			if (bDeveloperMode && this.hasStableId(oOverlay)) {
				oOverlay.setEditable(true);
				oOverlay.setSelectable(true);
				this.fireElementEditableChange({
					editable: true
				});
				return true;
			}
		}
		return false;
	};

	/**
	 * Register an overlay
	 *
	 * @param {sap.ui.dt.Overlay} oOverlay overlay object
	 * @override
	 */
	Selection.prototype.registerElementOverlay = function(oOverlay) {
		if (!this._checkDeveloperMode(oOverlay)) {
			oOverlay.attachEditableChange(this._onEditableChange, this);
			this._adaptSelectable(oOverlay);
		}

		oOverlay.attachBrowserEvent("click", this._selectOverlay, this);
		oOverlay.attachBrowserEvent("keydown", this._onKeyDown, this);
		oOverlay.attachBrowserEvent("mousedown", this._onMouseDown, this);
	};

	Selection.prototype._onEditableChange = function(oEvent) {
		var oOverlay = oEvent.getSource();
		this._adaptSelectable(oOverlay);
	};

	Selection.prototype._adaptSelectable = function(oOverlay) {
		var bSelectable = oOverlay.getEditable();
		if (oOverlay.getSelectable() !== bSelectable) {
			oOverlay.setSelectable(bSelectable);
			this.fireElementEditableChange({
				editable: bSelectable
			});
		}
	};

	/**
	 * Additionally to super->deregisterOverlay this method detatches the browser events
	 *
	 * @param {sap.ui.dt.Overlay} oOverlay overlay object
	 * @override
	 */
	Selection.prototype.deregisterElementOverlay = function(oOverlay) {
		oOverlay.detachBrowserEvent("click", this._selectOverlay, this);
		oOverlay.detachBrowserEvent("keydown", this._onKeyDown, this);
		oOverlay.detachBrowserEvent("mousedown", this._onMouseDown, this);

		oOverlay.detachEditableChange(this._onEditableChange, this);
	};

	Selection.prototype._setFocusOnOverlay = function(oOverlay, oEvent) {
		if (oOverlay && oOverlay.getSelectable()) {
			oOverlay.focus();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handle keydown event
	 *
	 * @param {sap.ui.base.Event} oEvent event object
	 * @private
	 */
	Selection.prototype._onKeyDown = function(oEvent) {
		var oOverlay = Utils.getFocusedOverlay();
		if (oEvent.keyCode === jQuery.sap.KeyCodes.ENTER) {
			this._selectOverlay(oEvent);
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_UP && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oParentOverlay = Utils.getFocusableParentOverlay(oOverlay);
				this._setFocusOnOverlay(oParentOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_DOWN && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oFirstChildOverlay = Utils.getFirstFocusableDescendantOverlay(oOverlay);
				this._setFocusOnOverlay(oFirstChildOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_LEFT && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oPrevSiblingOverlay = Utils.getPreviousFocusableSiblingOverlay(oOverlay);
				this._setFocusOnOverlay(oPrevSiblingOverlay, oEvent);
				oEvent.preventDefault();
			}
		} else if (oEvent.keyCode === jQuery.sap.KeyCodes.ARROW_RIGHT && oEvent.shiftKey === false && oEvent.altKey === false) {
			if (oOverlay) {
				var oNextSiblingOverlay = Utils.getNextFocusableSiblingOverlay(oOverlay);
				this._setFocusOnOverlay(oNextSiblingOverlay, oEvent);
				oEvent.preventDefault();
			}
		}
	};

	Selection.prototype._selectOverlay = function (oEvent) {
		var oOverlay = sap.ui.getCore().byId(oEvent.currentTarget.id);
		var bMultiSelection = oEvent.metaKey || oEvent.ctrlKey;
		var oTargetClasses = oEvent.target.className;

		if (oOverlay.getSelectable() && oTargetClasses.indexOf("sapUiDtOverlay") > -1) {
			if (bMultiSelection) {
				this.getDesignTime().setSelectionMode(sap.ui.dt.SelectionMode.Multi);
			}

			oOverlay.setSelected(!oOverlay.getSelected());

			if (bMultiSelection) {
				this.getDesignTime().setSelectionMode(sap.ui.dt.SelectionMode.Single);
			}

			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	/**
	 * Handle MouseDown event
	 *
	 * @param {sap.ui.base.Event} oEvent event object
	 * @private
	 */
	Selection.prototype._onMouseDown = function(oEvent) {
		// set focus after clicking, needed only for internet explorer
		if (sap.ui.Device.browser.name == "ie"){
			// when the EasyAdd Button is clicked, we don't want to focus/stopPropagation.
			// but when the OverlayScrollContainer is the target, we want it to behave like a click on an overlay
			var oTarget = sap.ui.getCore().byId(oEvent.target.id);
			var bTargetIsScrollContainer = oEvent.target.className === "sapUiDtOverlayScrollContainer";
			var oOverlay = sap.ui.getCore().byId(oEvent.currentTarget.id);
			if ((bTargetIsScrollContainer || oTarget instanceof sap.ui.dt.Overlay) && oOverlay instanceof sap.ui.dt.Overlay) {
				if (oOverlay.getSelectable()){
					oOverlay.focus();
					oEvent.stopPropagation();
				} else {
					oOverlay.getDomRef().blur();
				}
			}
		}
	};

	/**
	 * @override
	 */
	Selection.prototype.setDesignTime = function(oDesignTime) {
		//detach from listener from old DesignTime instance
		if (this.getDesignTime()) {
			this.getDesignTime().detachSelectionChange(this._onDesignTimeSelectionChange, this);
		}

		//set new DesignTime instance in parent class
		Plugin.prototype.setDesignTime.apply(this, arguments);

		//attach listener back to the new DesignTime instance
		if (this.getDesignTime()) {
			this.getDesignTime().attachSelectionChange(this._onDesignTimeSelectionChange, this);
		}
	};

	Selection.prototype._onDesignTimeSelectionChange = function(oEvent) {
		if (this.getDesignTime().getSelectionMode() === sap.ui.dt.SelectionMode.Single) {
			return;
		}

		var oCurrentSelectedOverlay = oEvent.getParameter("selection")[oEvent.getParameter("selection").length - 1];
		var aSelections = this.getDesignTime().getSelection();
		if (aSelections && aSelections.length === 1) {
			oCurrentSelectedOverlay.setSelected(true);
			return;
		}
		if (!oCurrentSelectedOverlay || this.getDesignTime().getSelectionMode() === sap.ui.dt.SelectionMode.Single) {
			return;
		}

		//shared relevant container?
		var bMultiSelectisValid = _hasSharedMultiSelectionPlugins(aSelections, this.getMultiSelectionRequiredPlugins())
			&& _hasSharedRelevantContainer(aSelections);
		oCurrentSelectedOverlay.setSelected(bMultiSelectisValid);
	};

	function _hasSharedMultiSelectionPlugins(aSelections, aMultiSelectionRequiredPlugins){
		var aSharedMultiSelectionPlugins = aMultiSelectionRequiredPlugins;
		aSelections.forEach(function(oSelecedOverlay) {
			var aEditableByPlugins = oSelecedOverlay.getEditableByPlugins();
			aSharedMultiSelectionPlugins = aSharedMultiSelectionPlugins.reduce(function(aSharedPlugins, sPluginName){
				if (aEditableByPlugins.indexOf(sPluginName) !== -1){
					aSharedPlugins.push(sPluginName);
				}
				return aSharedPlugins;
			}, []);
		});
		return aSharedMultiSelectionPlugins.length > 0;
	}

	function _hasSharedRelevantContainer(aSelections){
		var oCurrentSelectedOverlay = aSelections[aSelections.length - 1];
		var oPreviousSelectedOverlay = aSelections[aSelections.length - 2];

		var oCurrentRelevantContainer = oCurrentSelectedOverlay.getRelevantContainer();
		var oPreviousRelevantContainer = oPreviousSelectedOverlay.getRelevantContainer();

		return oCurrentRelevantContainer === oPreviousRelevantContainer;
	}

	return Selection;
}, /* bExport= */true);
<|endoftext|>


<commit_before>/*-
 * Copyright 2014 Square Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

JoseJWE.Utils = {};
var Utils = {};

/**
 * Converts the output from `openssl x509 -text` or `openssl rsa -text` into a
 * CryptoKey which can then be used with RSA-OAEP. Also accepts (and validates)
 * JWK keys.
 *
 * TODO: this code probably belongs in the webcryptographer.
 *
 * @param rsa_key  public RSA key in json format. Parameters can be base64
 *                 encoded, strings or number (for 'e').
 * @param alg      String, name of the algorithm
 * @return Promise<CryptoKey>
 */
JoseJWE.Utils.importRsaPublicKey = function(rsa_key, alg) {
  var jwk,
    config = null,
    rk,
    usage;

  alg = alg || "RSA-OAEP";

  usage = getKeyUsageByAlg(alg);

  if (usage.publicKey == "wrapKey") {
    jwk = Utils.convertRsaKey(rsa_key, ["n", "e"]);
    config = getCryptoConfig(alg);
  } else {
    rk = {};
    for (var name in rsa_key) {
      if(rsa_key.hasOwnProperty(name)) {
        rk[name] = rsa_key[name];
      }
    }
    config = getSignConfig(alg);
    if (!rk.alg && alg) {
      rk.alg = alg;
    }
    jwk = Utils.convertRsaKey(rk, ["n", "e"]);
    jwk.ext = true;
  }
  return crypto.subtle.importKey("jwk", jwk, config.id, false, [usage.publicKey]);
};

/**
 * Converts the output from `openssl x509 -text` or `openssl rsa -text` into a
 * CryptoKey which can then be used with RSA-OAEP and RSA. Also accepts (and validates)
 * JWK keys.
 *
 * TODO: this code probably belongs in the webcryptographer.
 *
 * @param rsa_key  private RSA key in json format. Parameters can be base64
 *                 encoded, strings or number (for 'e').
 * @param alg      String, name of the algorithm
 * @return Promise<CryptoKey>
 */
JoseJWE.Utils.importRsaPrivateKey = function(rsa_key, alg) {
  var jwk,
    config,
    rk,
    usage;

  alg = alg || "RSA-OAEP";

  usage = getKeyUsageByAlg(alg);

  if (usage.privateKey == "unwrapKey") {
    jwk = Utils.convertRsaKey(rsa_key, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]);
    config = getCryptoConfig("RSA-OAEP");
  } else {
    rk = {};
    for (var name in rsa_key) {
      if(rsa_key.hasOwnProperty(name)) {
        rk[name] = rsa_key[name];
      }
    }
    config = getSignConfig(alg);
    if (!rk.alg && alg) {
      rk.alg = alg;
    }
    jwk = Utils.convertRsaKey(rk, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]);
    jwk.ext = true;
  }
  return crypto.subtle.importKey("jwk", jwk, config.id, false, [usage.privateKey]);
};

// Private functions

Utils.isString = function(str) {
  return ((typeof(str) == "string") || (str instanceof String));
};

/**
 * Takes an arrayish (an array, ArrayBuffer or Uint8Array)
 * and returns an array or a Uint8Array.
 *
 * @param arr  arrayish
 * @return array or Uint8Array
 */
Utils.arrayish = function(arr) {
  if (arr instanceof Array) {
    return arr;
  }
  if (arr instanceof Uint8Array) {
    return arr;
  }
  if (arr instanceof ArrayBuffer) {
    return new Uint8Array(arr);
  }
  Jose.assert(false, "arrayish: invalid input");
};

/**
 * Checks if an RSA key contains all the expected parameters. Also checks their
 * types. Converts hex encoded strings (or numbers) to base64.
 *
 * @param rsa_key     RSA key in json format. Parameters can be base64 encoded,
 *                    strings or number (for 'e').
 * @param parameters  array<string>
 * @return json
 */
Utils.convertRsaKey = function(rsa_key, parameters) {
  var r = {};

  // Check that we have all the parameters
  var missing = [];
  parameters.map(function(p) {
    if (rsa_key[p] === undefined) {
      missing.push(p);
    }
  });

  if (missing.length > 0) {
    Jose.assert(false, "convertRsaKey: Was expecting " + missing.join());
  }

  // kty is either missing or is set to "RSA"
  if (rsa_key.kty !== undefined) {
    Jose.assert(rsa_key.kty == "RSA", "convertRsaKey: expecting rsa_key['kty'] to be 'RSA'");
  }
  r.kty = "RSA";

  // alg is either missing or is set to "RSA-OAEP"
  if (rsa_key.alg !== undefined) {
    // Jose.assert(rsa_key.alg == "RSA-OAEP" || rsa_key.alg == "RS256", "convertRsaKey: expecting rsa_key['alg'] to be 'RSA-OAEP'");
    r.alg = rsa_key.alg;
  } else {
    r.alg = "RSA-OAEP";
  }

  // note: we punt on checking key_ops

  var intFromHex = function(e) {
    return parseInt(e, 16);
  };
  for (var i = 0; i < parameters.length; i++) {
    var p = parameters[i];
    var v = rsa_key[p];
    if (p == "e") {
      if (typeof(v) == "number") {
        v = Utils.Base64Url.encodeArray(Utils.stripLeadingZeros(Utils.arrayFromInt32(v)));
      }
    } else if (/^([0-9a-fA-F]{2}:)+[0-9a-fA-F]{2}$/.test(v)) {
      var arr = v.split(":").map(intFromHex);
      v = Utils.Base64Url.encodeArray(Utils.stripLeadingZeros(arr));
    } else if (typeof(v) != "string") {
      Jose.assert(false, "convertRsaKey: expecting rsa_key['" + p + "'] to be a string");
    }
    r[p] = v;
  }

  return r;
};

/**
 * Converts a string into an array of ascii codes.
 *
 * @param str  string
 * @return Uint8Array
 */
Utils.arrayFromString = function(str) {
  Jose.assert(Utils.isString(str), "arrayFromString: invalid input");
  var arr = str.split('').map(function(c) {
    return c.charCodeAt(0);
  });
  return new Uint8Array(arr);
};

/**
 * Converts an array of ascii codes into a string.
 *
 * @param arr  ArrayBuffer
 * @return string
 */
Utils.stringFromArray = function(arr) {
  Jose.assert(arr instanceof ArrayBuffer, "stringFromArray: invalid input");
  arr = new Uint8Array(arr);
  r = '';
  for (var i = 0; i < arr.length; i++) {
    r += String.fromCharCode(arr[i]);
  }
  return r;
};

/**
 * Strips leading zero in an array.
 *
 * @param arr  arrayish
 * @return array
 */
Utils.stripLeadingZeros = function(arr) {
  if (arr instanceof ArrayBuffer) {
    arr = new Uint8Array(arr);
  }
  var is_leading_zero = true;
  var r = [];
  for (var i = 0; i < arr.length; i++) {
    if (is_leading_zero && arr[i] === 0) {
      continue;
    }
    is_leading_zero = false;
    r.push(arr[i]);
  }
  return r;
};

/**
 * Converts a number into an array of 4 bytes (big endian).
 *
 * @param i  number
 * @return ArrayBuffer
 */
Utils.arrayFromInt32 = function(i) {
  Jose.assert(typeof(i) == "number", "arrayFromInt32: invalid input");
  Jose.assert(i == i | 0, "arrayFromInt32: out of range");

  var buf = new Uint8Array(new Uint32Array([i]).buffer);
  var r = new Uint8Array(4);
  for (var j = 0; j < 4; j++) {
    r[j] = buf[3 - j];
  }
  return r.buffer;
};

/**
 * Concatenates arrayishes.
 *
 * @param arguments two or more arrayishes
 * @return Uint8Array
 */
Utils.arrayBufferConcat = function(/* ... */) {
  // Compute total size
  var args = [];
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    args.push(Utils.arrayish(arguments[i]));
    total += args[i].length;
  }
  var r = new Uint8Array(total);
  var offset = 0;
  for (i = 0; i < arguments.length; i++) {
    for (var j = 0; j < args[i].length; j++) {
      r[offset++] = args[i][j];
    }
  }
  Jose.assert(offset == total, "arrayBufferConcat: unexpected offset");
  return r;
};

Utils.Base64Url = {};

/**
 * Base64Url encodes a string (no trailing '=')
 *
 * @param str  string
 * @return string
 */
Utils.Base64Url.encode = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.encode: invalid input");
  return btoa(str)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
};

/**
 * Base64Url encodes an array
 *
 * @param arr array or ArrayBuffer
 * @return string
 */
Utils.Base64Url.encodeArray = function(arr) {
  arr = Utils.arrayish(arr);
  var r = "";
  for (i = 0; i < arr.length; i++) {
    r += String.fromCharCode(arr[i]);
  }
  return Utils.Base64Url.encode(r);
};

/**
 * Base64Url decodes a string
 *
 * @param str  string
 * @return string
 */
Utils.Base64Url.decode = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.decode: invalid input");
  // atob is nice and ignores missing '='
  return atob(str.replace(/-/g, "+").replace(/_/g, "/"));
};

Utils.Base64Url.decodeArray = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.decodeArray: invalid input");
  return Utils.arrayFromString(Utils.Base64Url.decode(str));
};
<commit_msg>fixed some implicit globals<commit_after>/*-
 * Copyright 2014 Square Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

JoseJWE.Utils = {};
var Utils = {};

/**
 * Converts the output from `openssl x509 -text` or `openssl rsa -text` into a
 * CryptoKey which can then be used with RSA-OAEP. Also accepts (and validates)
 * JWK keys.
 *
 * TODO: this code probably belongs in the webcryptographer.
 *
 * @param rsa_key  public RSA key in json format. Parameters can be base64
 *                 encoded, strings or number (for 'e').
 * @param alg      String, name of the algorithm
 * @return Promise<CryptoKey>
 */
JoseJWE.Utils.importRsaPublicKey = function(rsa_key, alg) {
  var jwk,
    config = null,
    rk,
    usage;

  alg = alg || "RSA-OAEP";

  usage = getKeyUsageByAlg(alg);

  if (usage.publicKey == "wrapKey") {
    jwk = Utils.convertRsaKey(rsa_key, ["n", "e"]);
    config = getCryptoConfig(alg);
  } else {
    rk = {};
    for (var name in rsa_key) {
      if(rsa_key.hasOwnProperty(name)) {
        rk[name] = rsa_key[name];
      }
    }
    config = getSignConfig(alg);
    if (!rk.alg && alg) {
      rk.alg = alg;
    }
    jwk = Utils.convertRsaKey(rk, ["n", "e"]);
    jwk.ext = true;
  }
  return crypto.subtle.importKey("jwk", jwk, config.id, false, [usage.publicKey]);
};

/**
 * Converts the output from `openssl x509 -text` or `openssl rsa -text` into a
 * CryptoKey which can then be used with RSA-OAEP and RSA. Also accepts (and validates)
 * JWK keys.
 *
 * TODO: this code probably belongs in the webcryptographer.
 *
 * @param rsa_key  private RSA key in json format. Parameters can be base64
 *                 encoded, strings or number (for 'e').
 * @param alg      String, name of the algorithm
 * @return Promise<CryptoKey>
 */
JoseJWE.Utils.importRsaPrivateKey = function(rsa_key, alg) {
  var jwk,
    config,
    rk,
    usage;

  alg = alg || "RSA-OAEP";

  usage = getKeyUsageByAlg(alg);

  if (usage.privateKey == "unwrapKey") {
    jwk = Utils.convertRsaKey(rsa_key, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]);
    config = getCryptoConfig("RSA-OAEP");
  } else {
    rk = {};
    for (var name in rsa_key) {
      if(rsa_key.hasOwnProperty(name)) {
        rk[name] = rsa_key[name];
      }
    }
    config = getSignConfig(alg);
    if (!rk.alg && alg) {
      rk.alg = alg;
    }
    jwk = Utils.convertRsaKey(rk, ["n", "e", "d", "p", "q", "dp", "dq", "qi"]);
    jwk.ext = true;
  }
  return crypto.subtle.importKey("jwk", jwk, config.id, false, [usage.privateKey]);
};

// Private functions

Utils.isString = function(str) {
  return ((typeof(str) == "string") || (str instanceof String));
};

/**
 * Takes an arrayish (an array, ArrayBuffer or Uint8Array)
 * and returns an array or a Uint8Array.
 *
 * @param arr  arrayish
 * @return array or Uint8Array
 */
Utils.arrayish = function(arr) {
  if (arr instanceof Array) {
    return arr;
  }
  if (arr instanceof Uint8Array) {
    return arr;
  }
  if (arr instanceof ArrayBuffer) {
    return new Uint8Array(arr);
  }
  Jose.assert(false, "arrayish: invalid input");
};

/**
 * Checks if an RSA key contains all the expected parameters. Also checks their
 * types. Converts hex encoded strings (or numbers) to base64.
 *
 * @param rsa_key     RSA key in json format. Parameters can be base64 encoded,
 *                    strings or number (for 'e').
 * @param parameters  array<string>
 * @return json
 */
Utils.convertRsaKey = function(rsa_key, parameters) {
  var r = {};

  // Check that we have all the parameters
  var missing = [];
  parameters.map(function(p) {
    if (rsa_key[p] === undefined) {
      missing.push(p);
    }
  });

  if (missing.length > 0) {
    Jose.assert(false, "convertRsaKey: Was expecting " + missing.join());
  }

  // kty is either missing or is set to "RSA"
  if (rsa_key.kty !== undefined) {
    Jose.assert(rsa_key.kty == "RSA", "convertRsaKey: expecting rsa_key['kty'] to be 'RSA'");
  }
  r.kty = "RSA";

  // alg is either missing or is set to "RSA-OAEP"
  if (rsa_key.alg !== undefined) {
    // Jose.assert(rsa_key.alg == "RSA-OAEP" || rsa_key.alg == "RS256", "convertRsaKey: expecting rsa_key['alg'] to be 'RSA-OAEP'");
    r.alg = rsa_key.alg;
  } else {
    r.alg = "RSA-OAEP";
  }

  // note: we punt on checking key_ops

  var intFromHex = function(e) {
    return parseInt(e, 16);
  };
  for (var i = 0; i < parameters.length; i++) {
    var p = parameters[i];
    var v = rsa_key[p];
    if (p == "e") {
      if (typeof(v) == "number") {
        v = Utils.Base64Url.encodeArray(Utils.stripLeadingZeros(Utils.arrayFromInt32(v)));
      }
    } else if (/^([0-9a-fA-F]{2}:)+[0-9a-fA-F]{2}$/.test(v)) {
      var arr = v.split(":").map(intFromHex);
      v = Utils.Base64Url.encodeArray(Utils.stripLeadingZeros(arr));
    } else if (typeof(v) != "string") {
      Jose.assert(false, "convertRsaKey: expecting rsa_key['" + p + "'] to be a string");
    }
    r[p] = v;
  }

  return r;
};

/**
 * Converts a string into an array of ascii codes.
 *
 * @param str  string
 * @return Uint8Array
 */
Utils.arrayFromString = function(str) {
  Jose.assert(Utils.isString(str), "arrayFromString: invalid input");
  var arr = str.split('').map(function(c) {
    return c.charCodeAt(0);
  });
  return new Uint8Array(arr);
};

/**
 * Converts an array of ascii codes into a string.
 *
 * @param arr  ArrayBuffer
 * @return string
 */
Utils.stringFromArray = function(arr) {
  Jose.assert(arr instanceof ArrayBuffer, "stringFromArray: invalid input");
  arr = new Uint8Array(arr);
  var r = '';
  for (var i = 0; i < arr.length; i++) {
    r += String.fromCharCode(arr[i]);
  }
  return r;
};

/**
 * Strips leading zero in an array.
 *
 * @param arr  arrayish
 * @return array
 */
Utils.stripLeadingZeros = function(arr) {
  if (arr instanceof ArrayBuffer) {
    arr = new Uint8Array(arr);
  }
  var is_leading_zero = true;
  var r = [];
  for (var i = 0; i < arr.length; i++) {
    if (is_leading_zero && arr[i] === 0) {
      continue;
    }
    is_leading_zero = false;
    r.push(arr[i]);
  }
  return r;
};

/**
 * Converts a number into an array of 4 bytes (big endian).
 *
 * @param i  number
 * @return ArrayBuffer
 */
Utils.arrayFromInt32 = function(i) {
  Jose.assert(typeof(i) == "number", "arrayFromInt32: invalid input");
  Jose.assert(i == i | 0, "arrayFromInt32: out of range");

  var buf = new Uint8Array(new Uint32Array([i]).buffer);
  var r = new Uint8Array(4);
  for (var j = 0; j < 4; j++) {
    r[j] = buf[3 - j];
  }
  return r.buffer;
};

/**
 * Concatenates arrayishes.
 *
 * @param arguments two or more arrayishes
 * @return Uint8Array
 */
Utils.arrayBufferConcat = function(/* ... */) {
  // Compute total size
  var args = [];
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    args.push(Utils.arrayish(arguments[i]));
    total += args[i].length;
  }
  var r = new Uint8Array(total);
  var offset = 0;
  for (i = 0; i < arguments.length; i++) {
    for (var j = 0; j < args[i].length; j++) {
      r[offset++] = args[i][j];
    }
  }
  Jose.assert(offset == total, "arrayBufferConcat: unexpected offset");
  return r;
};

Utils.Base64Url = {};

/**
 * Base64Url encodes a string (no trailing '=')
 *
 * @param str  string
 * @return string
 */
Utils.Base64Url.encode = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.encode: invalid input");
  return btoa(str)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/, "");
};

/**
 * Base64Url encodes an array
 *
 * @param arr array or ArrayBuffer
 * @return string
 */
Utils.Base64Url.encodeArray = function(arr) {
  arr = Utils.arrayish(arr);
  var r = "";
  for (var i = 0; i < arr.length; i++) {
    r += String.fromCharCode(arr[i]);
  }
  return Utils.Base64Url.encode(r);
};

/**
 * Base64Url decodes a string
 *
 * @param str  string
 * @return string
 */
Utils.Base64Url.decode = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.decode: invalid input");
  // atob is nice and ignores missing '='
  return atob(str.replace(/-/g, "+").replace(/_/g, "/"));
};

Utils.Base64Url.decodeArray = function(str) {
  Jose.assert(Utils.isString(str), "Base64Url.decodeArray: invalid input");
  return Utils.arrayFromString(Utils.Base64Url.decode(str));
};
<|endoftext|>


<commit_before>/* $This file is distributed under the terms of the license in /doc/license.txt$ */
function delete_photo(passUrl)  {

	var delete_photo_answer = confirm ("Are you sure you want to delete your photo?");

		if (delete_photo_answer){
			window.open(passUrl);
			}

		else{
			return false;
			}
}

<commit_msg>Fix js for photo deletion. When the user chooses “Cancel”, he doesn't see anymore a page with the word “false” on it.<commit_after>/* $This file is distributed under the terms of the license in /doc/license.txt$ */
function delete_photo(passUrl)  {

	var delete_photo_answer = confirm ("Are you sure you want to delete your photo?");

		if (delete_photo_answer){
			window.open(passUrl);
			}
}

<|endoftext|>


<commit_before>/**
 * @class A scene node that applies a model-space billboard transform to the nodes within its subgraph.
 * @extends SceneJS.Node
 *
Example

A billboard to orient a flattened cube towards the lookat:

 * var billboard = new SceneJS.Billboard(
 *     new SceneJS.Scale({
 *       x: 5.0,
 *       y: 5.0,
 *       z: 0.1
 *   },
 *      new SceneJS.Cube()))
 *

 * @constructor
 * Create a new SceneJS.Billboard
 * @param {Object} config  Config object followed by zero or more child nodes
 */
SceneJS.Billboard = SceneJS.createNodeType("billboard");

SceneJS.Billboard.prototype._renderOLD = function(traversalContext) {

    var superViewXForm = SceneJS._viewTransformModule.getTransform();
    var superModelXForm = SceneJS._modelTransformModule.getTransform();

    /* 1. Get world-space billboard center
     */
    var pos = SceneJS._math_transformPoint3(superModelXForm.matrix, [0,0,0]);

    /* 2. Get world-space vector from eye to billboard center
     */
    var eye = superViewXForm.lookAt.eye;
    var look = SceneJS._math_normalizeVec3(SceneJS._math_subVec3([eye.x, eye.y, eye.z], pos));

    var up = superViewXForm.lookAt.up;
    up = SceneJS._math_normalizeVec3([up.x, up.y, up.z]);

    var right = SceneJS._math_mat4();
    SceneJS._math_cross3Vec3(look, up, right);
    SceneJS._math_cross3Vec3(right, look, up);

    var r1 = right[0], r2 = right[1], r3 = right[2],
            u1 = up[0], u2 = up[1], u3 = up[2],
            l1 = look[0], l2 = look[1], l3 = look[2],
            px = pos[0], py = pos[1], pz = pos[2];

    var mat = [
        r1,    u1,    l1,    px,
        r2,    u2,    l2,    py,
        r3,    u3,    l3,    pz,
        0,    0,    0,    1
    ];

    //var modelMat = SceneJS._math_translationMat4v(pos);
    var modelMat = SceneJS._math_identityMat4();
    var viewMat = SceneJS._math_mat4();
    SceneJS._math_mulMat4(superViewXForm.matrix, mat, viewMat);

    SceneJS._viewTransformModule.setTransform({ matrix: viewMat });
    SceneJS._modelTransformModule.setTransform({ matrix: modelMat});

    this._renderNodes(traversalContext);

    SceneJS._modelTransformModule.setTransform(superModelXForm);
    SceneJS._viewTransformModule.setTransform(superViewXForm);
};

SceneJS.Billboard.prototype._render = function(traversalContext) {

    var superViewXForm = SceneJS._viewTransformModule.getTransform();
    var superModelXForm = SceneJS._modelTransformModule.getTransform();

    /* 1. Get world-space billboard center
     */
    var pos = SceneJS._math_transformPoint3(superModelXForm.matrix, [0,0,0]);

    /* 2. Get world-space vector from eye to billboard center
     */
    var eye = superViewXForm.lookAt.eye;
    var look = SceneJS._math_normalizeVec3(SceneJS._math_subVec3([eye.x, eye.y, eye.z], pos));

    var viewMat = superViewXForm.matrix;

    var viewUp = SceneJS._math_normalizeVec3([
        viewMat[0 * 4 + 1],
        viewMat[1 * 4 + 1],
        viewMat[2 * 4 + 1]
    ]);

    /*var viewRight = SceneJS._math_normalizeVec3([
        viewMat[0 * 4 + 0],
        viewMat[1 * 4 + 0],
        viewMat[2 * 4 + 0]
    ]);

    var viewLook = SceneJS._math_normalizeVec3([
        viewMat[0 * 4 + 2],
        viewMat[1 * 4 + 2],
        viewMat[2 * 4 + 2]
    ]);*/

    var xx = Array(3);
    var yy = viewUp;
    var zz = look;
    SceneJS._math_cross3Vec3(zz, yy, xx);
    xx = SceneJS._math_normalizeVec3(xx);
    SceneJS._math_cross3Vec3(xx, zz, yy);

    var mat = [
        xx[0],    xx[1],    xx[2],    0,
        yy[0],    yy[1],    yy[2],    0,
        zz[0],    zz[1],    zz[2],    0,
        -pos[0],  -pos[1],  -pos[2],    1
    ];

    //SceneJS._viewTransformModule.setTransform({ matrix: superViewXForm.matrix });
    SceneJS._modelTransformModule.setTransform({ matrix: mat});

    this._renderNodes(traversalContext);

    SceneJS._modelTransformModule.setTransform(superModelXForm);
    SceneJS._viewTransformModule.setTransform(superViewXForm);
};
<commit_msg>Cleanup the billboard code and went back to the original naming style<commit_after>/**
 * @class A scene node that applies a model-space billboard transform to the nodes within its subgraph.
 * @extends SceneJS.Node
 *
Example

A billboard to orient a flattened cube towards the lookat:

 * var billboard = new SceneJS.Billboard(
 *     new SceneJS.Scale({
 *       x: 5.0,
 *       y: 5.0,
 *       z: 0.1
 *   },
 *      new SceneJS.Cube()))
 *

 * @constructor
 * Create a new SceneJS.Billboard
 * @param {Object} config  Config object followed by zero or more child nodes
 */
SceneJS.Billboard = SceneJS.createNodeType("billboard");

SceneJS.Billboard.prototype._renderOLD = function(traversalContext) {

    var superViewXForm = SceneJS._viewTransformModule.getTransform();
    var superModelXForm = SceneJS._modelTransformModule.getTransform();

    /* 1. Get world-space billboard center
     */
    var pos = SceneJS._math_transformPoint3(superModelXForm.matrix, [0,0,0]);

    /* 2. Get world-space vector from eye to billboard center
     */
    var eye = superViewXForm.lookAt.eye;
    var look = SceneJS._math_normalizeVec3(SceneJS._math_subVec3([eye.x, eye.y, eye.z], pos));

    var up = superViewXForm.lookAt.up;
    up = SceneJS._math_normalizeVec3([up.x, up.y, up.z]);

    var right = SceneJS._math_mat4();
    SceneJS._math_cross3Vec3(look, up, right);
    SceneJS._math_cross3Vec3(right, look, up);

    var r1 = right[0], r2 = right[1], r3 = right[2],
            u1 = up[0], u2 = up[1], u3 = up[2],
            l1 = look[0], l2 = look[1], l3 = look[2],
            px = pos[0], py = pos[1], pz = pos[2];

    var mat = [
        r1,    u1,    l1,    px,
        r2,    u2,    l2,    py,
        r3,    u3,    l3,    pz,
        0,    0,    0,    1
    ];

    //var modelMat = SceneJS._math_translationMat4v(pos);
    var modelMat = SceneJS._math_identityMat4();
    var viewMat = SceneJS._math_mat4();
    SceneJS._math_mulMat4(superViewXForm.matrix, mat, viewMat);

    SceneJS._viewTransformModule.setTransform({ matrix: viewMat });
    SceneJS._modelTransformModule.setTransform({ matrix: modelMat});

    this._renderNodes(traversalContext);

    SceneJS._modelTransformModule.setTransform(superModelXForm);
    SceneJS._viewTransformModule.setTransform(superViewXForm);
};

SceneJS.Billboard.prototype._render = function(traversalContext) {

    var superViewXForm = SceneJS._viewTransformModule.getTransform();
    var superModelXForm = SceneJS._modelTransformModule.getTransform();

    /* 1. Get world-space billboard center
     */
    var pos = SceneJS._math_transformPoint3(superModelXForm.matrix, [0,0,0]);

    /* 2. Get world-space vector from eye to billboard center
     */
    var eye = superViewXForm.lookAt.eye;
    var look = SceneJS._math_normalizeVec3(SceneJS._math_subVec3([eye.x, eye.y, eye.z], pos));

    /* 3. Get the world space up vector of the camera
     */
    var up = SceneJS._math_normalizeVec3([
        superViewXForm.matrix[0 * 4 + 1],
        superViewXForm.matrix[1 * 4 + 1],
        superViewXForm.matrix[2 * 4 + 1]
    ]);

    /* 4. Calculate a new coordinate basis for the billboard using the
     *    camera up vector and the look-at vector.
     */
    var right = Array(3);
    SceneJS._math_cross3Vec3(look, up, right);
    right = SceneJS._math_normalizeVec3(right);
    SceneJS._math_cross3Vec3(right, look, up);

    var mat = [
        right[0], right[1], right[2],   0,
        up[0],    up[1],    up[2],      0,
        look[0],  look[1],  look[2],    0,
        -pos[0],  -pos[1],  -pos[2],    1
    ];

    //SceneJS._viewTransformModule.setTransform({ matrix: superViewXForm.matrix });
    SceneJS._modelTransformModule.setTransform({ matrix: mat});

    this._renderNodes(traversalContext);

    SceneJS._modelTransformModule.setTransform(superModelXForm);
    SceneJS._viewTransformModule.setTransform(superViewXForm);
};
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { UIDatabase } from '../../database';

import { sortDataBy } from '../../utilities';
import { recordKeyExtractor } from './utilities';
import getColumns from './getColumns';
import getPageInfoColumns from './getPageInfoColumns';
import { getIndicatorData } from './getIndicatorTableData';

import { ROUTES } from '../../navigation/constants';

/**
 * Gets data for initialising a customer invoice page from an associated transaction.
 *
 * @param    {Transaction}  transaction
 * @returns  {object}
 */
export const customerInvoiceInitialiser = transaction => {
  const { items: backingData } = transaction;

  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: transaction,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    hasSelection: false,
    route: ROUTES.CUSTOMER_INVOICE,
    columns: getColumns(ROUTES.CUSTOMER_INVOICE),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICE),
  };
};

/**
 * Gets data for initialising a customer invoices page.
 * Invoices shown initially are unfinalised and sorted by serial number.
 *
 * @returns  {object}
 */
export const customerInvoicesInitialiser = () => {
  const backingData = UIDatabase.objects('CustomerInvoice');
  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['otherParty.name'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.CUSTOMER_INVOICES,
    columns: getColumns(ROUTES.CUSTOMER_INVOICES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICES),
  };
};

/**
 * Gets data for initialising a customer requisition page from an associated requisition.
 *
 * @param    {Requisition}  requisition
 * @returns  {object}
 */
const customerRequisitionInitialiser = requisition => {
  const { items: backingData } = requisition;
  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: requisition,
    backingData: requisition.items,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route: ROUTES.CUSTOMER_REQUISITION,
    columns: getColumns(ROUTES.CUSTOMER_REQUISITION),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_REQUISITION),
  };
};

/**
 * Gets data for initialising a customer requisitions page.
 *
 * @returns  {object}
 */
const customerRequisitionsInitialiser = () => {
  const backingData = UIDatabase.objects('ResponseRequisition');

  const filteredData = backingData.filtered('status != $0', 'finalised');
  const sortedData = sortDataBy(filteredData.slice(), 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    route: ROUTES.CUSTOMER_REQUISITIONS,
    columns: getColumns(ROUTES.CUSTOMER_REQUISITIONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_REQUISITIONS),
  };
};

/**
 * Gets data for initialising a stock page.
 *
 * @returns  {object}
 */
const stockInitialiser = () => {
  const backingData = UIDatabase.objects('Item').sorted('name');

  return {
    backingData,
    data: backingData.slice(),
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'code'],
    sortKey: 'name',
    isAscending: true,
    selectedRow: null,
    route: ROUTES.STOCK,
    columns: getColumns(ROUTES.STOCK),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCK),
  };
};

/**
 * Gets data for initialising a stocktakes page.
 * Initial data is unfinalised stocktakes, sorted by creation date.
 *
 * @returns  {object}
 */
const stocktakesInitialiser = () => {
  const backingData = UIDatabase.objects('Stocktake');

  const filteredData = backingData.filtered('status != $0', 'finalised');
  const sortedData = filteredData.sorted('createdDate', true).slice();

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'serialNumber'],
    sortKey: 'createdDate',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.STOCKTAKES,
    columns: getColumns(ROUTES.STOCKTAKES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKES),
  };
};

/**
 * Gets data for initialising a stocktake batch page from an associated stocktake item.
 *
 * @param    {StocktakeItem}  stocktakeItem
 * @returns  {object}
 */
const stocktakeBatchInitialiser = stocktakeItem => ({
  pageObject: stocktakeItem,
  backingData: stocktakeItem.batches,
  data: stocktakeItem.batches.slice(),
  keyExtractor: recordKeyExtractor,
  dataState: new Map(),
  sortKey: 'itemName',
  isAscending: true,
  modalKey: '',
  modalValue: null,
  columns: getColumns(ROUTES.CUSTOMER_INVOICE),
  getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICE),
});

/**
 * Gets data for initialising a manage stocktake page from an associated stocktake item.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeManagerInitialiser = stocktake => {
  const backingData = UIDatabase.objects('Item');

  return {
    stocktake,
    backingData,
    data: backingData.sorted('name').slice(),
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'code'],
    name: stocktake ? stocktake.name : '',
    sortKey: 'name',
    isAscending: true,
    hasSelection: false,
    allSelected: false,
    showAll: true,
    route: ROUTES.STOCKTAKE_MANAGER,
    columns: getColumns(ROUTES.STOCKTAKE_MANAGER),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKE_MANAGER),
  };
};

/**
 * Gets data for initialising an edit stocktake page from an associated stocktake item.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeEditorInitialiser = stocktake => {
  const { items: backingData } = stocktake;
  const sortedData = backingData.sorted('item.name').slice();

  const hasNegativeAdjustmentReasons = UIDatabase.objects('NegativeAdjustmentReason').length > 0;
  const hasPositiveAdjustmentReasons = UIDatabase.objects('PositiveAdjustmentReason').length > 0;
  const usesReasons = hasNegativeAdjustmentReasons && hasPositiveAdjustmentReasons;

  const route = usesReasons ? ROUTES.STOCKTAKE_EDITOR_WITH_REASONS : ROUTES.STOCKTAKE_EDITOR;

  return {
    pageObject: stocktake,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route,
    columns: getColumns(route),
    getPageInfoColumns: getPageInfoColumns(route),
  };
};

/**
 * Gets data for initialising an edit stocktake page when reasons
 * are defined from an associated stocktake.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeEditorWithReasonsInitialiser = stocktake => {
  const { items: backingData } = stocktake;
  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: stocktake,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route: ROUTES.STOCKTAKE_EDITOR_WITH_REASONS,
    columns: getColumns(ROUTES.STOCKTAKE_EDITOR_WITH_REASONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKE_EDITOR_WITH_REASONS),
  };
};

/**
 * Gets data for initialising a supplier invoice page from an associated transaction item.
 *
 * @param    {Transaction}  transaction
 * @returns  {object}
 */
const supplierInvoiceInitialiser = transaction => {
  const backingData = transaction.getTransactionBatches(UIDatabase);

  const sortedData = backingData.sorted('itemName').slice();

  return {
    pageObject: transaction,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['itemName'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    hasSelection: false,
    route: ROUTES.SUPPLIER_INVOICE,
    columns: getColumns(ROUTES.SUPPLIER_INVOICE),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_INVOICE),
  };
};

/**
 * Gets data for initialising a supplier invoices page.
 * Data is initially unfinalised and sorted by serial number.
 *
 * @returns  {object}
 */
const supplierInvoicesInitialiser = () => {
  const backingData = UIDatabase.objects('SupplierInvoice');

  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.SUPPLIER_INVOICES,
    columns: getColumns(ROUTES.SUPPLIER_INVOICES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_INVOICES),
  };
};

/**
 * Gets data for initialising a supplier requisition page from an associated requisition.
 *
 * @param    {Requisition}  requisition
 * @returns  {object}
 */
const supplierRequisitionInitialiser = requisition => {
  const { isFinalised, program, period, items: backingData, indicators } = requisition;

  const usingPrograms = !!program;
  const route = program ? ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM : ROUTES.SUPPLIER_REQUISITION;

  const sortedData = backingData.sorted('item.name').slice();
  const filteredData =
    !usingPrograms || isFinalised
      ? sortedData
      : sortedData.filter(item => item.isLessThanThresholdMOS);

  const usingIndicators = !!indicators.length;

  const [selectedIndicator] = indicators;
  const { columns: indicatorColumns, rows: indicatorRows } = usingIndicators
    ? getIndicatorData(selectedIndicator, period)
    : {};
  // ?
  // : {};

  return {
    pageObject: requisition,
    backingData,
    data: filteredData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    hasSelection: false,
    modalValue: null,
    usingIndicators,
    showIndicators: false,
    selectedIndicator,
    indicatorColumns,
    indicatorRows,
    indicators,
    showAll: !usingPrograms || isFinalised,
    route: ROUTES.SUPPLIER_REQUISITION,
    columns: getColumns(route),
    getPageInfoColumns: getPageInfoColumns(route),
  };
};

/**
 * Gets data for initialising a supplier requisitions page.
 * Initial data are unfinalised requisitions, sorted by serial number.
 *
 * @returns  {object}
 */
const supplierRequisitionsInitialiser = () => {
  const backingData = UIDatabase.objects('RequestRequisition');

  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.SUPPLIER_REQUISITIONS,
    columns: getColumns(ROUTES.SUPPLIER_REQUISITIONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_REQUISITIONS),
  };
};

const pageInitialisers = {
  customerInvoice: customerInvoiceInitialiser,
  customerInvoices: customerInvoicesInitialiser,
  customerRequisition: customerRequisitionInitialiser,
  customerRequisitions: customerRequisitionsInitialiser,
  stock: stockInitialiser,
  stocktakeBatchEditModal: stocktakeBatchInitialiser,
  stocktakeBatchEditModalWithReasons: stocktakeBatchInitialiser,
  stocktakeEditor: stocktakeEditorInitialiser,
  stocktakeEditorWithReasons: stocktakeEditorWithReasonsInitialiser,
  stocktakeManager: stocktakeManagerInitialiser,
  stocktakes: stocktakesInitialiser,
  supplierInvoice: supplierInvoiceInitialiser,
  supplierInvoices: supplierInvoicesInitialiser,
  supplierRequisition: supplierRequisitionInitialiser,
  supplierRequisitions: supplierRequisitionsInitialiser,
};

/**
 * A wrapper for mapping pages to initialisation functions.
 *
 * @param    {object}    A mapper from page names to initialisation functions.
 * @returns  {Function}  A lookup function for retrieving page initialisers.
 */
const getPageInitialiser = pageToInitialiser => page => pageToInitialiser[page];

export default getPageInitialiser(pageInitialisers);
<commit_msg>Add indicator revert<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { UIDatabase } from '../../database';

import { sortDataBy } from '../../utilities';
import { recordKeyExtractor } from './utilities';
import getColumns from './getColumns';
import getPageInfoColumns from './getPageInfoColumns';
import { getIndicatorData } from './getIndicatorTableData';

import { ROUTES } from '../../navigation/constants';

/**
 * Gets data for initialising a customer invoice page from an associated transaction.
 *
 * @param    {Transaction}  transaction
 * @returns  {object}
 */
export const customerInvoiceInitialiser = transaction => {
  const { items: backingData } = transaction;

  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: transaction,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    hasSelection: false,
    route: ROUTES.CUSTOMER_INVOICE,
    columns: getColumns(ROUTES.CUSTOMER_INVOICE),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICE),
  };
};

/**
 * Gets data for initialising a customer invoices page.
 * Invoices shown initially are unfinalised and sorted by serial number.
 *
 * @returns  {object}
 */
export const customerInvoicesInitialiser = () => {
  const backingData = UIDatabase.objects('CustomerInvoice');
  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['otherParty.name'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.CUSTOMER_INVOICES,
    columns: getColumns(ROUTES.CUSTOMER_INVOICES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICES),
  };
};

/**
 * Gets data for initialising a customer requisition page from an associated requisition.
 *
 * @param    {Requisition}  requisition
 * @returns  {object}
 */
const customerRequisitionInitialiser = requisition => {
  const { items: backingData } = requisition;
  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: requisition,
    backingData: requisition.items,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route: ROUTES.CUSTOMER_REQUISITION,
    columns: getColumns(ROUTES.CUSTOMER_REQUISITION),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_REQUISITION),
  };
};

/**
 * Gets data for initialising a customer requisitions page.
 *
 * @returns  {object}
 */
const customerRequisitionsInitialiser = () => {
  const backingData = UIDatabase.objects('ResponseRequisition');

  const filteredData = backingData.filtered('status != $0', 'finalised');
  const sortedData = sortDataBy(filteredData.slice(), 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    route: ROUTES.CUSTOMER_REQUISITIONS,
    columns: getColumns(ROUTES.CUSTOMER_REQUISITIONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_REQUISITIONS),
  };
};

/**
 * Gets data for initialising a stock page.
 *
 * @returns  {object}
 */
const stockInitialiser = () => {
  const backingData = UIDatabase.objects('Item').sorted('name');

  return {
    backingData,
    data: backingData.slice(),
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'code'],
    sortKey: 'name',
    isAscending: true,
    selectedRow: null,
    route: ROUTES.STOCK,
    columns: getColumns(ROUTES.STOCK),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCK),
  };
};

/**
 * Gets data for initialising a stocktakes page.
 * Initial data is unfinalised stocktakes, sorted by creation date.
 *
 * @returns  {object}
 */
const stocktakesInitialiser = () => {
  const backingData = UIDatabase.objects('Stocktake');

  const filteredData = backingData.filtered('status != $0', 'finalised');
  const sortedData = filteredData.sorted('createdDate', true).slice();

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'serialNumber'],
    sortKey: 'createdDate',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.STOCKTAKES,
    columns: getColumns(ROUTES.STOCKTAKES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKES),
  };
};

/**
 * Gets data for initialising a stocktake batch page from an associated stocktake item.
 *
 * @param    {StocktakeItem}  stocktakeItem
 * @returns  {object}
 */
const stocktakeBatchInitialiser = stocktakeItem => ({
  pageObject: stocktakeItem,
  backingData: stocktakeItem.batches,
  data: stocktakeItem.batches.slice(),
  keyExtractor: recordKeyExtractor,
  dataState: new Map(),
  sortKey: 'itemName',
  isAscending: true,
  modalKey: '',
  modalValue: null,
  columns: getColumns(ROUTES.CUSTOMER_INVOICE),
  getPageInfoColumns: getPageInfoColumns(ROUTES.CUSTOMER_INVOICE),
});

/**
 * Gets data for initialising a manage stocktake page from an associated stocktake item.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeManagerInitialiser = stocktake => {
  const backingData = UIDatabase.objects('Item');

  return {
    stocktake,
    backingData,
    data: backingData.sorted('name').slice(),
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['name', 'code'],
    name: stocktake ? stocktake.name : '',
    sortKey: 'name',
    isAscending: true,
    hasSelection: false,
    allSelected: false,
    showAll: true,
    route: ROUTES.STOCKTAKE_MANAGER,
    columns: getColumns(ROUTES.STOCKTAKE_MANAGER),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKE_MANAGER),
  };
};

/**
 * Gets data for initialising an edit stocktake page from an associated stocktake item.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeEditorInitialiser = stocktake => {
  const { items: backingData } = stocktake;
  const sortedData = backingData.sorted('item.name').slice();

  const hasNegativeAdjustmentReasons = UIDatabase.objects('NegativeAdjustmentReason').length > 0;
  const hasPositiveAdjustmentReasons = UIDatabase.objects('PositiveAdjustmentReason').length > 0;
  const usesReasons = hasNegativeAdjustmentReasons && hasPositiveAdjustmentReasons;

  const route = usesReasons ? ROUTES.STOCKTAKE_EDITOR_WITH_REASONS : ROUTES.STOCKTAKE_EDITOR;

  return {
    pageObject: stocktake,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route,
    columns: getColumns(route),
    getPageInfoColumns: getPageInfoColumns(route),
  };
};

/**
 * Gets data for initialising an edit stocktake page when reasons
 * are defined from an associated stocktake.
 *
 * @param    {Stocktake}  stocktake
 * @returns  {object}
 */
const stocktakeEditorWithReasonsInitialiser = stocktake => {
  const { items: backingData } = stocktake;
  const sortedData = backingData.sorted('item.name').slice();

  return {
    pageObject: stocktake,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    route: ROUTES.STOCKTAKE_EDITOR_WITH_REASONS,
    columns: getColumns(ROUTES.STOCKTAKE_EDITOR_WITH_REASONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.STOCKTAKE_EDITOR_WITH_REASONS),
  };
};

/**
 * Gets data for initialising a supplier invoice page from an associated transaction item.
 *
 * @param    {Transaction}  transaction
 * @returns  {object}
 */
const supplierInvoiceInitialiser = transaction => {
  const backingData = transaction.getTransactionBatches(UIDatabase);

  const sortedData = backingData.sorted('itemName').slice();

  return {
    pageObject: transaction,
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['itemName'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    modalValue: null,
    hasSelection: false,
    route: ROUTES.SUPPLIER_INVOICE,
    columns: getColumns(ROUTES.SUPPLIER_INVOICE),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_INVOICE),
  };
};

/**
 * Gets data for initialising a supplier invoices page.
 * Data is initially unfinalised and sorted by serial number.
 *
 * @returns  {object}
 */
const supplierInvoicesInitialiser = () => {
  const backingData = UIDatabase.objects('SupplierInvoice');

  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.SUPPLIER_INVOICES,
    columns: getColumns(ROUTES.SUPPLIER_INVOICES),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_INVOICES),
  };
};

/**
 * Gets data for initialising a supplier requisition page from an associated requisition.
 *
 * @param    {Requisition}  requisition
 * @returns  {object}
 */
const supplierRequisitionInitialiser = requisition => {
  const { isFinalised, program, period, items: backingData, indicators } = requisition;

  const usingPrograms = !!program;
  const route = program ? ROUTES.SUPPLIER_REQUISITION_WITH_PROGRAM : ROUTES.SUPPLIER_REQUISITION;

  const sortedData = backingData.sorted('item.name').slice();
  const filteredData =
    !usingPrograms || isFinalised
      ? sortedData
      : sortedData.filter(item => item.isLessThanThresholdMOS);

  const usingIndicators = !!indicators.length;

  const [selectedIndicator] = indicators;
  const { columns: indicatorColumns, rows: indicatorRows } = getIndicatorData(
    selectedIndicator,
    period
  );

  return {
    pageObject: requisition,
    backingData,
    data: filteredData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['item.name', 'item.code'],
    sortKey: 'itemName',
    isAscending: true,
    modalKey: '',
    hasSelection: false,
    modalValue: null,
    usingIndicators,
    showIndicators: false,
    selectedIndicator,
    indicatorColumns,
    indicatorRows,
    indicators,
    showAll: !usingPrograms || isFinalised,
    route: ROUTES.SUPPLIER_REQUISITION,
    columns: getColumns(route),
    getPageInfoColumns: getPageInfoColumns(route),
  };
};

/**
 * Gets data for initialising a supplier requisitions page.
 * Initial data are unfinalised requisitions, sorted by serial number.
 *
 * @returns  {object}
 */
const supplierRequisitionsInitialiser = () => {
  const backingData = UIDatabase.objects('RequestRequisition');

  const filteredData = backingData.filtered('status != $0', 'finalised').slice();
  const sortedData = sortDataBy(filteredData, 'serialNumber', false);

  return {
    backingData,
    data: sortedData,
    keyExtractor: recordKeyExtractor,
    dataState: new Map(),
    searchTerm: '',
    filterDataKeys: ['serialNumber'],
    sortKey: 'serialNumber',
    isAscending: false,
    modalKey: '',
    hasSelection: false,
    route: ROUTES.SUPPLIER_REQUISITIONS,
    columns: getColumns(ROUTES.SUPPLIER_REQUISITIONS),
    getPageInfoColumns: getPageInfoColumns(ROUTES.SUPPLIER_REQUISITIONS),
  };
};

const pageInitialisers = {
  customerInvoice: customerInvoiceInitialiser,
  customerInvoices: customerInvoicesInitialiser,
  customerRequisition: customerRequisitionInitialiser,
  customerRequisitions: customerRequisitionsInitialiser,
  stock: stockInitialiser,
  stocktakeBatchEditModal: stocktakeBatchInitialiser,
  stocktakeBatchEditModalWithReasons: stocktakeBatchInitialiser,
  stocktakeEditor: stocktakeEditorInitialiser,
  stocktakeEditorWithReasons: stocktakeEditorWithReasonsInitialiser,
  stocktakeManager: stocktakeManagerInitialiser,
  stocktakes: stocktakesInitialiser,
  supplierInvoice: supplierInvoiceInitialiser,
  supplierInvoices: supplierInvoicesInitialiser,
  supplierRequisition: supplierRequisitionInitialiser,
  supplierRequisitions: supplierRequisitionsInitialiser,
};

/**
 * A wrapper for mapping pages to initialisation functions.
 *
 * @param    {object}    A mapper from page names to initialisation functions.
 * @returns  {Function}  A lookup function for retrieving page initialisers.
 */
const getPageInitialiser = pageToInitialiser => page => pageToInitialiser[page];

export default getPageInitialiser(pageInitialisers);
<|endoftext|>