<commit_before>/* eslint-env mocha */
/* eslint no-console:0 */
'use strict';

require('babel-core/register')({sourceMaps: 'inline'});

let Cache = require('../lib/Cache'),
	assert = require('assert');

describe('should insert a single entity', function () {
	let cache, room;

	beforeEach(() => {
		cache = new Cache();
		room = {
			id: 'numix',
			type: 'room',
			description: 'GTK+ and Gnome Shell themes.'
		};
	});

	it('checking if the insert was successful', function() {
		cache.put({ entities: { numix: room }});
		assert.deepEqual(cache.entities, { numix: room });
		assert.deepEqual(cache.getEntity('numix'), room);
	});

	it('checking if callback of getEntity is fired if entity doesnt exist', function(done) {

		cache.onChange(function(changes) {
			if (
				changes.queries && changes.queries.entities &&
				changes.queries.entities.alice === true
			) {
				cache.put({ entities: { alice: null } });
			}
		});

		assert.deepEqual(
			cache.getEntity('alice', function(err, entity) {
				assert(!err, 'threw an error');
				assert(!entity, 'entity doesnt exist');
				done();
			}),
			{ type: 'loading' }
		);

		assert.deepEqual(cache.queries, { entities: { alice: true } });
	});

	it('checking if callback of getEntity is fired if entity is added later', function(done) {
		let callbackFired = false;

		cache.onChange(function(changes) {
			if (
				changes.queries && changes.queries.entities &&
				changes.queries.entities.alice === true
			) {
				cache.put({ entities: { alice: {
					id: 'alice',
					createTime: 140000000,
					description: 'stupid day dreamer'
				} } });
			}
		});

		cache.getEntity('alice', function(err, entity) {
			assert(!callbackFired, 'callback fired twice');
			callbackFired = true;
			assert(!err, 'threw an error');
			assert.deepEqual(entity, {
				id: 'alice',
				createTime: 140000000,
				description: 'stupid day dreamer'
			});
			cache.put({ entities: { alice: null } });
			setTimeout(done, 100);
		});
	});
});

describe('should insert a new range and query it', function () {
	let cache = new Cache();
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7 ] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'numix', updateTime: 1 },
			{ id: 'scrollback', updateTime: 3 },
			{ id: 'bangalore', updateTime: 6 }
		] }
	});

	it('simple query', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 5 ]);

		assert.equal(res.get().length, 2, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
	});

	it('query with loading at the end', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 9 ]);
		assert.equal(res.get().length, 4, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
		assert.equal(res.get(2).updateTime, 6, 'incorrect item');
		assert.equal(res.get(3).updateTime, 7, 'incorrect item');
		assert.equal(res.get(3).type, 'loading', 'incorrect item');
	});

	it('query with 3 property ranges with after only single item', function() {
		let res = cache.query('room:updateTime!(:)', [ 3, 0, 1 ]);
		assert.equal(res.get().length, 1, 'incorrect results');
		assert.equal(res.get(0).updateTime, 3, 'incorrect item');
	});

	it('query with 3 property ranges with after only: multiple items with no loading', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 0, 3 ]);
		assert.equal(res.get().length, 3, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
		assert.equal(res.get(2).updateTime, 6, 'incorrect item');
	});

	it('Cache.query should fire callback on geting data', function(done) {
		cache.onChange(function() {
			cache.put({
				knowledge: {
					'room:createTime': [ 1, 5 ]
				},
				indexes: {
					'room:createTime': [
						{
							createTime: 1,
							type: 'text',
							body: 'hi'
						},
						{
							createTime: 2,
							type: 'text',
							body: 'hi'
						},
						{
							createTime: 3,
							type: 'text',
							body: 'hi'
						}
					]
				}
			});
		});
		cache.query(cache.sliceToKey({ type: 'text', order: 'createTime'}), [ 1, 0, 50 ], function(err, data) {
			assert(!err, 'Error thrown');
			assert.equal(data.length, 3, 'callback fired with new items');
			done();
		});
	});
});

describe('query for cache with infinity in the end', function() {
	let cache = new Cache({
		is: (entity, type) => { return type === 'relation'; }
	});
	cache.put({
		knowledge: { 'relation:roleTime!(:)': [ [ 0, +Infinity ] ] },
		indexes: { 'relation:roleTime!(:)': [
			{ id: 'harish_numix', roleTime: 1 },
			{ id: 'satya_numix', roleTime: 3 },
			{ id: 'aravind_numix', roleTime: 6 }
		] }
	});

	it('query with 2 prop ranges', function () {
		let res = cache.query('relation:roleTime!(:)', [ 1, 9 ]);
		assert.equal(res.get(0).roleTime, 1, 'incorrect item');
		assert.equal(res.get(1).roleTime, 3, 'incorrect item');
		assert.equal(res.get(2).roleTime, 6, 'incorrect item');
	});

	it("query with 3 prop ranges: shouldn't return loading at the end.", function () {
		let res = cache.query('relation:roleTime!(:)', [ 3, 0, 3 ]);
		assert.equal(res.get().length, 2, 'incorrect results');
		assert.equal(res.get(0).roleTime, 3, 'incorrect item');
		assert.equal(res.get(1).roleTime, 6, 'incorrect item');
	});
	it('query with 3 prop ranges: should give loading in the beginning and add a query.', function () {
		let res = cache.query('relation:roleTime!(:)', [ 3, 2, 3 ]);

		assert.equal(res.get().length, 4, 'length not correct on ');
		assert.equal(res.get(0).type, 'loading', 'incorrect item');
		assert.equal(res.get(1).roleTime, 1, 'incorrect item');
		assert.equal(res.get(2).roleTime, 3, 'incorrect item');
		assert.equal(res.get(3).roleTime, 6, 'incorrect item');
		assert(Object.keys(cache.queries).length, 'no queries added');
	});
});

describe('should index entities when adding knowledge: ', function () {
	let cache = new Cache({
		is: (entity, type) => { return type === 'relation'; }
	});
	cache.put({
		entities: {
			harish_numix: { id: 'harish_numix', roleTime: 1 },
			aravind_numix: { id: 'aravind_numix', roleTime: 3 },
			satya_numix: { id: 'satya_numix', roleTime: 6 }
		}
	});
	cache.put({
		knowledge: { 'relation:roleTime!(:)': [ [ 0, +Infinity ] ] }
	});
	it('adding knowledge should add the indexes', function() {
		assert(Object.keys(cache.indexes).length, 'no index added');
	});
});

describe('deleting an item which is part of an index: ', function () {
	let cache = new Cache();
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7 ] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'numix', type: 'room', updateTime: 1 },
			{ id: 'scrollback', type: 'room', updateTime: 3 },
			{ id: 'bangalore', type: 'room', updateTime: 6 }
		] }
	});

	cache.put({
		entities: {
			numix: null
		}
	});

	it('item should be deleted', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 9 ]);
		assert(res.get(0).id !== 'numix', 'didnt delete');
	});
});

it("getEntity callback fired when indexes are put", (done) => {
	let cache = new Cache();
	cache.getEntity("test123", (err, entity) => {
		assert.deepEqual(entity, {id: 'test123', type: 'room', updateTime: 3});
		done();
	});
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'test123', type: 'room', updateTime: 3 }
		] }
	});
});

/*
	TODO:
	Existing entities should be indexed when adding knowledge.
	Queries should be added to cache.queries
	Cache._recentQueries should be updated
*/
<commit_msg>Modified the test<commit_after>/* eslint-env mocha */
/* eslint no-console:0 */
'use strict';

require('babel-core/register')({sourceMaps: 'inline'});

let Cache = require('../lib/Cache'),
	assert = require('assert');

describe('should insert a single entity', function () {
	let cache, room;

	beforeEach(() => {
		cache = new Cache();
		room = {
			id: 'numix',
			type: 'room',
			description: 'GTK+ and Gnome Shell themes.'
		};
	});

	it('checking if the insert was successful', function() {
		cache.put({ entities: { numix: room }});
		assert.deepEqual(cache.entities, { numix: room });
		assert.deepEqual(cache.getEntity('numix'), room);
	});

	it('checking if callback of getEntity is fired if entity doesnt exist', function(done) {

		cache.onChange(function(changes) {
			if (
				changes.queries && changes.queries.entities &&
				changes.queries.entities.alice === true
			) {
				cache.put({ entities: { alice: null } });
			}
		});

		assert.deepEqual(
			cache.getEntity('alice', function(err, entity) {
				assert(!err, 'threw an error');
				assert(!entity, 'entity doesnt exist');
				done();
			}),
			{ type: 'loading' }
		);

		assert.deepEqual(cache.queries, { entities: { alice: true } });
	});

	it('checking if callback of getEntity is fired if entity is added later', function(done) {
		let callbackFired = false;

		cache.onChange(function(changes) {
			if (
				changes.queries && changes.queries.entities &&
				changes.queries.entities.alice === true
			) {
				cache.put({ entities: { alice: {
					id: 'alice',
					createTime: 140000000,
					description: 'stupid day dreamer'
				} } });
			}
		});

		cache.getEntity('alice', function(err, entity) {
			assert(!callbackFired, 'callback fired twice');
			callbackFired = true;
			assert(!err, 'threw an error');
			assert.deepEqual(entity, {
				id: 'alice',
				createTime: 140000000,
				description: 'stupid day dreamer'
			});
			cache.put({ entities: { alice: null } });
			setTimeout(done, 100);
		});
	});
});

describe('should insert a new range and query it', function () {
	let cache = new Cache();
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7 ] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'numix', updateTime: 1 },
			{ id: 'scrollback', updateTime: 3 },
			{ id: 'bangalore', updateTime: 6 }
		] }
	});

	it('simple query', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 5 ]);

		assert.equal(res.get().length, 2, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
	});

	it('query with loading at the end', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 9 ]);
		assert.equal(res.get().length, 4, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
		assert.equal(res.get(2).updateTime, 6, 'incorrect item');
		assert.equal(res.get(3).updateTime, 7, 'incorrect item');
		assert.equal(res.get(3).type, 'loading', 'incorrect item');
	});

	it('query with 3 property ranges with after only single item', function() {
		let res = cache.query('room:updateTime!(:)', [ 3, 0, 1 ]);
		assert.equal(res.get().length, 1, 'incorrect results');
		assert.equal(res.get(0).updateTime, 3, 'incorrect item');
	});

	it('query with 3 property ranges with after only: multiple items with no loading', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 0, 3 ]);
		assert.equal(res.get().length, 3, 'incorrect results');
		assert.equal(res.get(0).updateTime, 1, 'incorrect item');
		assert.equal(res.get(1).updateTime, 3, 'incorrect item');
		assert.equal(res.get(2).updateTime, 6, 'incorrect item');
	});

	it('Cache.query should fire callback on geting data', function(done) {
		cache.onChange(function() {
			cache.put({
				knowledge: {
					'text:createTime': [ 1, 5 ]
				},
				indexes: {
					'text:createTime': [
						{
							createTime: 1,
							type: 'text',
							body: 'hi'
						},
						{
							createTime: 2,
							type: 'text',
							body: 'hi'
						},
						{
							createTime: 3,
							type: 'text',
							body: 'hi'
						}
					]
				}
			});
		});
		cache.query(cache.sliceToKey({ type: 'text', order: 'createTime'}), [ 1, 3 ], function(err, data) {
			assert(!err, 'Error thrown');
			assert.equal(data.length, 3, 'callback fired with new items');
			done();
		});
	});
});

describe('query for cache with infinity in the end', function() {
	let cache = new Cache({
		is: (entity, type) => { return type === 'relation'; }
	});
	cache.put({
		knowledge: { 'relation:roleTime!(:)': [ [ 0, +Infinity ] ] },
		indexes: { 'relation:roleTime!(:)': [
			{ id: 'harish_numix', roleTime: 1 },
			{ id: 'satya_numix', roleTime: 3 },
			{ id: 'aravind_numix', roleTime: 6 }
		] }
	});

	it('query with 2 prop ranges', function () {
		let res = cache.query('relation:roleTime!(:)', [ 1, 9 ]);
		assert.equal(res.get(0).roleTime, 1, 'incorrect item');
		assert.equal(res.get(1).roleTime, 3, 'incorrect item');
		assert.equal(res.get(2).roleTime, 6, 'incorrect item');
	});

	it("query with 3 prop ranges: shouldn't return loading at the end.", function () {
		let res = cache.query('relation:roleTime!(:)', [ 3, 0, 3 ]);
		assert.equal(res.get().length, 2, 'incorrect results');
		assert.equal(res.get(0).roleTime, 3, 'incorrect item');
		assert.equal(res.get(1).roleTime, 6, 'incorrect item');
	});
	it('query with 3 prop ranges: should give loading in the beginning and add a query.', function () {
		let res = cache.query('relation:roleTime!(:)', [ 3, 2, 3 ]);

		assert.equal(res.get().length, 4, 'length not correct on ');
		assert.equal(res.get(0).type, 'loading', 'incorrect item');
		assert.equal(res.get(1).roleTime, 1, 'incorrect item');
		assert.equal(res.get(2).roleTime, 3, 'incorrect item');
		assert.equal(res.get(3).roleTime, 6, 'incorrect item');
		assert(Object.keys(cache.queries).length, 'no queries added');
	});
});

describe('should index entities when adding knowledge: ', function () {
	let cache = new Cache({
		is: (entity, type) => { return type === 'relation'; }
	});
	cache.put({
		entities: {
			harish_numix: { id: 'harish_numix', roleTime: 1 },
			aravind_numix: { id: 'aravind_numix', roleTime: 3 },
			satya_numix: { id: 'satya_numix', roleTime: 6 }
		}
	});
	cache.put({
		knowledge: { 'relation:roleTime!(:)': [ [ 0, +Infinity ] ] }
	});
	it('adding knowledge should add the indexes', function() {
		assert(Object.keys(cache.indexes).length, 'no index added');
	});
});

describe('deleting an item which is part of an index: ', function () {
	let cache = new Cache();
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7 ] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'numix', type: 'room', updateTime: 1 },
			{ id: 'scrollback', type: 'room', updateTime: 3 },
			{ id: 'bangalore', type: 'room', updateTime: 6 }
		] }
	});

	cache.put({
		entities: {
			numix: null
		}
	});

	it('item should be deleted', function() {
		let res = cache.query('room:updateTime!(:)', [ 1, 9 ]);
		assert(res.get(0).id !== 'numix', 'didnt delete');
	});
});

it("getEntity callback fired when indexes are put", (done) => {
	let cache = new Cache();
	cache.getEntity("test123", (err, entity) => {
		assert.deepEqual(entity, {id: 'test123', type: 'room', updateTime: 3});
		done();
	});
	cache.put({
		knowledge: { 'room:updateTime!(:)': [ [ 0, 7] ] },
		indexes: { 'room:updateTime!(:)': [
			{ id: 'test123', type: 'room', updateTime: 3 }
		] }
	});
});

/*
	TODO:
	Existing entities should be indexed when adding knowledge.
	Queries should be added to cache.queries
	Cache._recentQueries should be updated
*/
<|endoftext|>


<commit_before>const {LayerController} = require("../components/layerController");

const globalMap = {};
global.L = {DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({addTo: (map) => {globalMap[raster] = coordinates}, remove: (map) => {delete globalMap[raster]}, bringToFront: () => {}, bringToBack: () => {}})};

const controllers = require("../components/Controller.js");

var testDisplay = {};
jest.mock('../components/Controller.js', () => ({
    currentDomain: ({
        subscribe: () => {}
    }),
    current_display: ({
        getValue: () => ({}),
        setValue: jest.fn()
    }),
    currentSimulation: ({
        getValue: () => "test",
    }),
    currentDomain: ({
        getValue: () => 1,
        subscribe: () => {}
    }),
    sorted_timestamps: ({
        getValue: () => ["2020"]
    }),
    raster_base: ({
        getValue: () => "test_base"
    }),
    current_timestamp: ({
        getValue: () => ["2020"]
    }),
    rasters: ({
        getValue: () => ({
            1: {
                "2020": {"raster": {raster: "raster test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                       "overlay": {raster: "overlay test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            }
        })
    }),
    organization: ({
        getValue: () => "SJSU"
    })
}));

const utils = require("../util.js");
jest.mock('../util.js', () => ({
    baseLayerDict: {},
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn()
    },
    dragElement: jest.fn(),
    overlay_list: ['overlay']
}));

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        testDisplay = {};
        controllers.current_display.getValue = () => testDisplay;
        const div = document.createElement("div");
        div.id = "raster-colorbar";
        await document.body.appendChild(div);
        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect("raster" in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect("overlay" in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        const rasterDict = layerController.rasterDict;
        layerController.handleOverlayadd("raster", rasterDict["raster"]);
        expect("test_baseraster test" in globalMap).toEqual(true);
        expect("raster" in controllers.current_display.getValue()).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        const rasterDict = layerController.rasterDict;
        layerController.handleOverlayadd("raster", rasterDict["raster"]);
        layerController.handleOverlayRemove("raster", rasterDict["raster"]);
        expect("raster" in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        testDisplay = {"raster": { addTo: (map) => {},
                                   bringToFront: () => {},
                                   bringToBack: () => {},
                                   remove: (map) => {}
                                 }
                      };
        layerController.domainSwitch();
        expect("raster" in controllers.current_display.getValue()).toEqual(true);
    });
});<commit_msg>Updated domain switching so that the domain is taken into account<commit_after>const {LayerController} = require("../components/layerController");

const globalMap = {};
global.L = {DomEvent: {disableClickPropagation: jest.fn(), disableScrollPropagation: jest.fn()},
            imageOverlay: (raster, coordinates, settings) => ({addTo: (map) => {globalMap[raster] = coordinates}, remove: (map) => {delete globalMap[raster]}, bringToFront: () => {}, bringToBack: () => {}})};

const controllers = require("../components/Controller.js");

var testDisplay = {};
jest.mock('../components/Controller.js', () => ({
    currentDomain: ({
        getValue: () => 1,
        subscribe: () => {}
    }),
    current_display: ({
        getValue: () => ({}),
        setValue: jest.fn()
    }),
    currentSimulation: ({
        getValue: () => "test",
    }),
    currentDomain: ({
        getValue: () => 1,
        subscribe: () => {}
    }),
    sorted_timestamps: ({
        getValue: () => ["2020"]
    }),
    raster_base: ({
        getValue: () => "test_base"
    }),
    current_timestamp: ({
        getValue: () => ["2020"]
    }),
    rasters: ({
        getValue: () => ({
            1: {
                "2020": {"raster": {raster: "raster test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                       "overlay": {raster: "overlay test", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            },
            2: {
                "2020": {"raster": {raster: "raster test 2", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]}},
                       "overlay": {raster: "overlay test 2", coords: {0: [0, 0], 1: [0, 1], 2: [1, 0], 3: [1, 1]} }}
            }
        })
    }),
    organization: ({
        getValue: () => "SJSU"
    })
}));

const utils = require("../util.js");
jest.mock('../util.js', () => ({
    baseLayerDict: {},
    map: {
        addTo: jest.fn(),
        fitBounds: jest.fn()
    },
    dragElement: jest.fn(),
    overlay_list: ['overlay']
}));

describe('Tests for adding layers to menu and selecting layers', () => {
    var layerController;

    beforeEach(async () => {
        testDisplay = {};
        controllers.current_display.getValue = () => testDisplay;
        const div = document.createElement("div");
        div.id = "raster-colorbar";
        await document.body.appendChild(div);
        layerController = await document.body.appendChild(new LayerController());
        layerController.domainSwitch();
    });

    test('Layer Controller should populate its raster and overlay layers correctly', () => {
        const rasterDict = layerController.rasterDict;
        const overlayDict = layerController.overlayDict;
        expect(Object.entries(rasterDict).length).toEqual(1);
        expect("raster" in rasterDict).toEqual(true);
        expect(Object.entries(overlayDict).length).toEqual(1);
        expect("overlay" in overlayDict).toEqual(true);
    });

    test('Layers should be correctly added to the map when selected', () => {
        const rasterDict = layerController.rasterDict;
        layerController.handleOverlayadd("raster", rasterDict["raster"]);
        expect("test_baseraster test" in globalMap).toEqual(true);
        expect("raster" in controllers.current_display.getValue()).toEqual(true);
    });

    test('Layers should be correctly removed from the map when selected', () => {
        const rasterDict = layerController.rasterDict;
        layerController.handleOverlayadd("raster", rasterDict["raster"]);
        layerController.handleOverlayRemove("raster", rasterDict["raster"]);
        expect("test_baseraster test" in globalMap).toEqual(false);
    });

    test('Layer Controller should preserve previous selected layers when domain is switched on the same simulation', () => {
        const rasterDict = layerController.rasterDict;
        layerController.handleOverlayadd("raster", rasterDict["raster"]);
        controllers.currentDomain.getValue = () => 2;
        layerController.domainSwitch();
        expect("raster" in controllers.current_display.getValue()).toEqual(true);
        expect("test_baseraster test 2" in globalMap).toEqual(true);
        expect("test_baseraster test" in globalMap).toEqual(false);
    });

    test('Layer Controller should clear selected layers when domain is switched to new simulation', () => {

    });
});<|endoftext|>


<commit_before>var log = require('tinylogger');
var crypt = require('./crypt.js');
var misc = require('./misc.js');
var conf = require('../enode.config.js').config;
var hexDump = require('hexy').hexy;
require('./buffer.js');

/*
* Keycreation Client <-> Server:
    * Client A (Outgoing connection client -> server):
        Sendkey:    Md5(<BaseKey 4><MagicValueClientServer 1><RandomKeyPartClientA 2>)  7
    * Client B (Incomming connection):
        Receivekey: Md5(<BaseKey 4><MagicValueServerClient 1><RandomKeyPartClientA 2>)  7
    * Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to safe CPU time

* Handshake
    * The handshake is encrypted (except otherwise noted) by the Keys created above
    * Padding is currently not used for UDP meaning that PaddingLen will be 0, using PaddingLengths
      up to 16 Bytes is acceptable however.

    Client A: <SemiRandomNotProtocolMarker 1[Unencrypted]><RandomKeyPart 2[Unencrypted]>
        <MagicValue 4><PaddingLen 1><RandomBytes PaddingLen%16>

* Overhead: 8 Bytes per UDP Packet

* Security for Basic Obfuscation:
    * Random looking packets, very limited protection against passive eavesdropping single packets

* Additional Comments:
    * For obvious reasons the UDP handshake is actually no handshake. If a different Encryption
      method (or better a different Key) is to be used this has to be negotiated in a TCP
      connection.
    * SemiRandomNotProtocolMarker is a Byte which has a value unequal any Protocol header byte.
      This is a compromiss, turning in complete randomness (and nice design) but gaining a lower
      CPU usage.

*/

var MAGICVALUE_UDP_SERVERCLIENT = 0xA5;
var MAGICVALUE_UDP_CLIENTSERVER = 0x6B;
var MAGICVALUE_UDP_SYNC_CLIENT  = 0x395F2EC1;
var MAGICVALUE_UDP_SYNC_SERVER  = 0x13EF24D5;

var recvKeys = new Buffer(0xffffff);
var sendKeys = new Buffer(0xffffff);

(function() { // Precalculate all possible keys (2*0xffff different 256B keys = 32MB).
    log.info('UDP crypt keys init. Server key: '+
        conf.udp.serverKey+' (0x'+conf.udp.serverKey.toString(16)+')');
    log.info('UDP crypt keys init');
    var sendBuf = new Buffer(7);
    var recvBuf = new Buffer(7);
    sendBuf.putUInt32LE(conf.udp.serverKey).putUInt8(MAGICVALUE_UDP_SERVERCLIENT);
    recvBuf.putUInt32LE(conf.udp.serverKey).putUInt8(MAGICVALUE_UDP_CLIENTSERVER);
    for (var i=0; i<0x10000; i++) {
        sendBuf.pos(5).putUInt16LE(i);
        recvBuf.pos(5).putUInt16LE(i);
        sendKeys.putBuffer(crypt.RC4CreateKey(crypt.md5(sendBuf), false).state);
        recvKeys.putBuffer(crypt.RC4CreateKey(crypt.md5(recvBuf), false).state);
    }
})();

/**
 * @class Crypt for UDP
 * @constructor
 * @property {Integer} status
 */
var udpCrypt = function() {
    this.status = conf.supportCrypt ? CS_ENCRYPTING : CS_NONE;
};

/**
 * @description Decrypt buffer when needed
 * @param {Buffer} buffer Input data
 * @param {Buffer} info Input data
 * @returns {Buffer} Decrypted data
 */
udpCrypt.prototype.decrypt = function(buffer, info) {
    switch (this.status) {

        case CS_ENCRYPTING:
            var protocol = buffer.getUInt8();
            if ((protocol != PR_ED2K) && (protocol != PR_EMULE) && (protocol != PR_ZLIB)) {
                log.trace('udpCrypt: decrypting data from '+info.address);
                var clientKey = buffer.getUInt16LE();
                var b = buffer.get();
                var RC4Key = { x: 0, y: 0, state: recvKeys.pos(clientKey).get(256) };
                b = crypt.RC4Crypt(b, b.length, RC4Key);
                if (b.getUInt32LE() == MAGICVALUE_UDP_SYNC_SERVER) {
                    var padLength = b.getUInt8();
                    b.get(padLength); // Skip padding
                    return b.get(); // The rest of the packet is the decrypted data
                }
                else {
                    log.warn('Error decrypting UDP packet');
                }
            }

        case CS_NONE:
        default:
            buffer.pos(0);
            return buffer;
    }
};

/**
 * @description Encrypts an UDP packet
 * @param {Buffer} buffer Input data
 * @return {Buffer} Encrypted data
 */
udpCrypt.prototype.encrypt = function(buffer) {
    var randomKey = crypt.rand(0xffff);
    // crypted part
    var enc = new Buffer(buffer.length + 5);
    enc.putUInt32LE(MAGICVALUE_UDP_SYNC_SERVER).putUInt8(0).putBuffer(buffer);
    var RC4Key = { x: 0, y: 0, state: sendKeys.pos(clientKey).get(256) };
    enc = crypt.RC4Crypt(enc, enc.length, sendKeys[RC4Key]);
    // return buffer
    var ret = new Buffer(buffer.length + 8);
    return ret.putUInt8(crypt.randProtocol()).putUInt16LE(randomKey).putBuffer(enc);
}

exports.udpCrypt = udpCrypt;
<commit_msg>Bug solved reading keys from the pool<commit_after>var log = require('tinylogger');
var crypt = require('./crypt.js');
var misc = require('./misc.js');
var conf = require('../enode.config.js').config;
var hexDump = require('hexy').hexy;
require('./buffer.js');

/*
* Keycreation Client <-> Server:
    * Client A (Outgoing connection client -> server):
        Sendkey:    Md5(<BaseKey 4><MagicValueClientServer 1><RandomKeyPartClientA 2>)  7
    * Client B (Incomming connection):
        Receivekey: Md5(<BaseKey 4><MagicValueServerClient 1><RandomKeyPartClientA 2>)  7
    * Note: The first 1024 Bytes will be _NOT_ discarded for UDP keys to safe CPU time

* Handshake
    * The handshake is encrypted (except otherwise noted) by the Keys created above
    * Padding is currently not used for UDP meaning that PaddingLen will be 0, using PaddingLengths
      up to 16 Bytes is acceptable however.

    Client A: <SemiRandomNotProtocolMarker 1[Unencrypted]><RandomKeyPart 2[Unencrypted]>
        <MagicValue 4><PaddingLen 1><RandomBytes PaddingLen%16>

* Overhead: 8 Bytes per UDP Packet

* Security for Basic Obfuscation:
    * Random looking packets, very limited protection against passive eavesdropping single packets

* Additional Comments:
    * For obvious reasons the UDP handshake is actually no handshake. If a different Encryption
      method (or better a different Key) is to be used this has to be negotiated in a TCP
      connection.
    * SemiRandomNotProtocolMarker is a Byte which has a value unequal any Protocol header byte.
      This is a compromiss, turning in complete randomness (and nice design) but gaining a lower
      CPU usage.

*/

var MAGICVALUE_UDP_SERVERCLIENT = 0xA5;
var MAGICVALUE_UDP_CLIENTSERVER = 0x6B;
var MAGICVALUE_UDP_SYNC_CLIENT  = 0x395F2EC1;
var MAGICVALUE_UDP_SYNC_SERVER  = 0x13EF24D5;

var sendKeys = new Buffer(0xffffff);
var recvKeys = new Buffer(0xffffff);

(function() { // Precalculate all possible keys (2*0xffff different 256B keys = 32MB).
    log.info('UDP crypt keys init. Server key: '+
        conf.udp.serverKey+' (0x'+conf.udp.serverKey.toString(16)+')');
    log.info('UDP crypt keys init');
    var sendBuf = new Buffer(7);
    var recvBuf = new Buffer(7);
    sendBuf.putUInt32LE(conf.udp.serverKey).putUInt8(MAGICVALUE_UDP_SERVERCLIENT);
    recvBuf.putUInt32LE(conf.udp.serverKey).putUInt8(MAGICVALUE_UDP_CLIENTSERVER);
    for (var i=0; i<0x10000; i++) {
        sendBuf.pos(5).putUInt16LE(i);
        recvBuf.pos(5).putUInt16LE(i);
        sendKeys.putBuffer(crypt.RC4CreateKey(crypt.md5(sendBuf), false).state);
        recvKeys.putBuffer(crypt.RC4CreateKey(crypt.md5(recvBuf), false).state);
    }
})();

var getKey = function(pool, index) {
    var buf = new Buffer(256);
    var start = index<<8;
    pool.copy(buf, 0, start, start+256);
    return { x: 0, y: 0, state: buf };
};

/**
 * @class Crypt for UDP
 * @constructor
 * @property {Integer} status
 */
var udpCrypt = function() {
    this.status = conf.supportCrypt ? CS_ENCRYPTING : CS_NONE;
};

/**
 * @description Decrypt buffer when needed
 * @param {Buffer} buffer Input data
 * @param {Buffer} info Input data
 * @returns {Buffer} Decrypted data
 */
udpCrypt.prototype.decrypt = function(buffer, info) {
    switch (this.status) {

        case CS_ENCRYPTING:
            var protocol = buffer.getUInt8();
            if ((protocol != PR_ED2K) && (protocol != PR_EMULE) && (protocol != PR_ZLIB)) {
                log.trace('udpCrypt: decrypting data from '+info.address);
                var clientKey = buffer.getUInt16LE();
                var b = buffer.get();
                b = crypt.RC4Crypt(b, b.length, getKey(recvKeys, clientKey));
                if (b.getUInt32LE() == MAGICVALUE_UDP_SYNC_SERVER) {
                    var padLength = b.getUInt8();
                    b.get(padLength); // Skip padding
                    return b.get(); // The rest of the packet is the decrypted data
                }
                else {
                    log.warn('Error decrypting UDP packet');
                }
            }

        case CS_NONE:
        default:
            buffer.pos(0);
            return buffer;
    }
};

/**
 * @description Encrypts an UDP packet
 * @param {Buffer} buffer Input data
 * @return {Buffer} Encrypted data
 */
udpCrypt.prototype.encrypt = function(buffer) {
    var randomKey = crypt.rand(0xffff);
    // crypted part
    var enc = new Buffer(buffer.length + 5);
    enc.putUInt32LE(MAGICVALUE_UDP_SYNC_SERVER).putUInt8(0).putBuffer(buffer);
    enc = crypt.RC4Crypt(enc, enc.length, getKey(sendKeys, randomKey));
    // return buffer
    var ret = new Buffer(buffer.length + 8);
    return ret.putUInt8(crypt.randProtocol()).putUInt16LE(randomKey).putBuffer(enc);
}

exports.udpCrypt = udpCrypt;
<|endoftext|>


<commit_before>//Commenting from popups
function commentClick(uniqID) {
    var locationLat;
    var locationLng;
    $(markersArray).each(function () {
        if (this.myData.id === uniqID) {
            locationLat = Math.round(this.getLatLng().lat);
            locationLng = Math.round(this.getLatLng().lng);
        }
    })
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": $(".popup-textarea").val(),
        "Lat": locationLat,
        "Lng": locationLng,
        "ParentId": null
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),

            success: function () {
                $(".leaflet-popup-content").fadeOut();
                markerX = markersArray[markersArray.findIndex(x => parseInt(x.myData.id) === parseInt(uniqID))];
                markerX.closePopup();
                reloadMarkers();
                $(".leaflet-popup-content").fadeIn();
                $("#comment-section").load(window.location.href + " #comment-section > * ");
                $("#comment-textarea").val("");

            }

        });

};

//Commenting from main comment section
function commentClickMain() {
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": $("#comment-textarea").val(),
        "Lat": null,
        "Lng": null,
        "ParentId": null
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),
            success: function () {
                $("#comment-section").load(window.location.href + " #comment-section > * ");

                $("#comment-textarea").val("");
            }
        });

};

//Adding live listeners to the reply buttons, will do the same for the main comment buttons
$(document).ready(function () {
    reloadMarkers();
    $(document).on("keypress", ".reply-textarea", function (e) {
        if (e.which === 13) {
            var parent = $(this).attr("id").slice(5);
            $("#button-" + parent).click();
            // prevent duplicate submission
            alert(parent);
            return false;
        }
    })
    $(document).on("keypress", "#comment-textarea", function (e) {
        if (e.which === 13) {
            $('#submit-comment').click();
            // prevent duplicate submission
            return false;
        }
    })
    $(document).on("click", ".reply-button", function () {
        var area;
        var parent = $(this).data("parent");
        if ($(this).hasClass("popup-btn")) {
            area = $(".popup-textarea");
        }
        else {
            area = $("#text-" + parent);
        }
        replyComment(parent, area);

    })
});

function replyComment(parent, area) {
    var element = " #replies-" + parent;
    try {
        var loc = $("#loc-" + parent).data("location").split(" ");
        var lat = loc[0];
        var lng = loc[2];
    }
    catch (err) {
        var loc = null;
    }
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": area.val(),
        "Lat": lat,
        "Lng": lng,
        "ParentId": parent
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),
            success: function () {

                $(element).fadeOut();

                $("#comment-section #replies-" + parent + " .comment-container").load(window.location.href + " #comment-section #replies-" + parent + " .comment-container>*");
                if (loc !== null) {
                    if ($(area).hasClass("popup-textarea")) {
                        var uniqID = $(area).attr("id").slice(9);
                        createCommentRow($("span.main-user").html(), $(".popup-textarea").val(), uniqID, parent);
                    }
                    else {
                        {
                            $(markersArray).each(function () {
                                this.getPopup().setContent("");
                            })
                            reloadMarkers();
                        }

                    }
                }
                $(area).val("");
                $(element).fadeIn();
            }
        });
}

//Get new comments for markers
function reloadMarkers() {

    var id = $("#ImageId").val()
    $.ajax(
        {
            type: "GET", //HTTP GET Method
            url: "../GetComments", // Controller/View
            contentType: "application/json;",
            dataType: "json",
            data: {
                id: id
            },
            success: function (data) {
                $(data).each(function () {

                    var parent;
                    if (this.comment.parentId === undefined) {
                        parent = this.comment.commentId;
                    }

                    else {
                        parent = this.comment.parentId;
                    }
                    createMarkers(this.comment.message, this.posterProfileName, this.comment.lat, this.comment.lng, parent, true);

                })
            }
        });
}<commit_msg>File did not save properly<commit_after>//Commenting from popups
function commentClick(uniqID) {
    var locationLat;
    var locationLng;
    $(markersArray).each(function () {
        if (this.myData.id === uniqID) {
            locationLat = Math.round(this.getLatLng().lat);
            locationLng = Math.round(this.getLatLng().lng);
        }
    })
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": $(".popup-textarea").val(),
        "Lat": locationLat,
        "Lng": locationLng,
        "ParentId": null
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),

            success: function () {
                $(".leaflet-popup-content").fadeOut();
                markerX = markersArray[markersArray.findIndex(x => parseInt(x.myData.id) === parseInt(uniqID))];
                markerX.closePopup();
                reloadMarkers();
                $(".leaflet-popup-content").fadeIn();
                $("#comment-section").load(window.location.href + " #comment-section > * ");
                $("#comment-textarea").val("");

            }

        });

};

//Commenting from main comment section
function commentClickMain() {
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": $("#comment-textarea").val(),
        "Lat": null,
        "Lng": null,
        "ParentId": null
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),
            success: function () {
                $("#comment-section").load(window.location.href + " #comment-section > * ");

                $("#comment-textarea").val("");
            }
        });

};

//Adding live listeners to the reply buttons
$(document).ready(function () {
    reloadMarkers();
    $(document).on("keypress", ".reply-textarea", function (e) {
        if (e.which === 13) {
            var parent = $(this).attr("id").slice(5);
            $("#button-" + parent).click();
            // prevent duplicate submission
            return false;
        }
    })
    $(document).on("keypress", "#comment-textarea", function (e) {
        if (e.which === 13) {
            $('#submit-comment').click();
            // prevent duplicate submission
            return false;
        }
    })
    $(document).on("click", ".reply-button", function () {
        var area;
        var parent = $(this).data("parent");
        if ($(this).hasClass("popup-btn")) {
            area = $(".popup-textarea");
        }
        else {
            area = $("#text-" + parent);
        }
        replyComment(parent, area);

    })
});

function replyComment(parent, area) {
    var element = " #replies-" + parent;
    try {
        var loc = $("#loc-" + parent).data("location").split(" ");
        var lat = loc[0];
        var lng = loc[2];
    }
    catch (err) {
        var loc = null;
    }
    var DataFromBody = {
        "ImageId": $("#ImageId").val(),
        "Message": area.val(),
        "Lat": lat,
        "Lng": lng,
        "ParentId": parent
    }
    $.ajax(
        {
            type: "POST", //HTTP POST Method
            url: "../Comment", // Controller/View
            contentType: "application/json;",
            dataType: "text",
            data: JSON.stringify(DataFromBody),
            success: function () {

                $(element).fadeOut();

                $("#comment-section #replies-" + parent + " .comment-container").load(window.location.href + " #comment-section #replies-" + parent + " .comment-container>*");
                if (loc !== null) {
                    if ($(area).hasClass("popup-textarea")) {
                        var uniqID = $(area).attr("id").slice(9);
                        createCommentRow($("span.main-user").html(), $(".popup-textarea").val(), uniqID, parent);
                    }
                    else {
                        {
                            $(markersArray).each(function () {
                                this.getPopup().setContent("");
                            })
                            reloadMarkers();
                        }

                    }
                }
                $(area).val("");
                $(element).fadeIn();
            }
        });
}

//Get new comments for markers
function reloadMarkers() {

    var id = $("#ImageId").val()
    $.ajax(
        {
            type: "GET", //HTTP GET Method
            url: "../GetComments", // Controller/View
            contentType: "application/json;",
            dataType: "json",
            data: {
                id: id
            },
            success: function (data) {
                $(data).each(function () {

                    var parent;
                    if (this.comment.parentId === undefined) {
                        parent = this.comment.commentId;
                    }

                    else {
                        parent = this.comment.parentId;
                    }
                    createMarkers(this.comment.message, this.posterProfileName, this.comment.lat, this.comment.lng, parent, true);

                })
            }
        });
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { createStyleSheet } from 'stylishly';
import Text from 'material-ui/Text';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import { throttle } from 'material-ui/utils/helpers';
import addEventListener from 'material-ui/utils/addEventListener';

import AppDrawer from './AppDrawer';

export const styleSheet = createStyleSheet('AppFrame', (theme) => {
  const { palette, transitions, typography } = theme;
  return {
    '@raw html': { boxSizing: 'border-box' },
    '@raw *, @raw *:before, @raw *:after': { boxSizing: 'inherit' },
    '@raw body': {
      margin: 0,
      background: palette.background.default,
      fontFamily: typography.fontFamily,
      color: palette.text.primary,
      lineHeight: '1.2',
      overflowX: 'hidden',
    },
    '@raw a': {
      color: palette.accent.A400,
      textDecoration: 'none',
      '&:hover': {
        textDecoration: 'underline',
      },
    },
    '@raw p': {
      lineHeight: '1.6',
    },
    root: {
      display: 'flex',
      alignItems: 'stretch',
      minHeight: '100vh',
      width: '100vw',
      appBarHome: {
        backgroundColor: 'transparent',
        boxShadow: 'none',
      },
    },
    navIcon: {
      marginLeft: -12,
    },
    grow: {
      flex: '1 1 100%',
    },
    toggleShade: {
      marginRight: -12,
    },
    title: {
      marginLeft: 24,
      flex: '0 0 auto',
    },
    appBar: {
      left: 'auto',
      right: 0,
      transition: transitions.create('width'),
    },
    [theme.breakpoints.up('lg')]: {
      appBarShift: {
        width: 'calc(100% - 250px)',
      },
      navIconHide: {
        display: 'none',
      },
    },
  };
});

class AppFrame extends Component {
  static propTypes = {
    children: PropTypes.node,
    dispatch: PropTypes.func,
    routes: PropTypes.array,
  };

  static contextTypes = {
    theme: PropTypes.object.isRequired,
    styleManager: PropTypes.object.isRequired,
  };

  state = {
    drawerDocked: false,
    drawerOpen: false,
  };

  componentWillMount() {
    this.resizeListener = addEventListener(window, 'resize', this.handleResize);
  }

  componentDidMount() {
    this.mounted = true;
    this.checkWindowSize();
  }

  componentWillUnmount() {
    this.mounted = false;

    if (this.resizeListener) {
      this.resizeListener.remove();
    }
  }

  checkWindowSize = () => {
    if (!this.mounted) {
      return;
    }

    const breakpoint = this.context.theme.breakpoints.getWidth('lg');

    if (this.state.drawerDocked && window.innerWidth < breakpoint) {
      this.setState({ drawerDocked: false });
    } else if (!this.state.drawerDocked && window.innerWidth >= breakpoint) {
      this.setState({ drawerDocked: true });
    }
  };

  handleResize = throttle(this.checkWindowSize, 100);

  handleDrawerOpen = () => this.setState({ drawerOpen: true });
  handleDrawerClose = () => this.setState({ drawerOpen: false });
  handleDrawerToggle = () => this.setState({ drawerOpen: !this.state.drawerOpen });

  handleToggleShade = () => this.props.dispatch({ type: 'TOGGLE_THEME_SHADE' });

  getTitle() {
    const { routes } = this.props;
    for (let i = routes.length - 1; i >= 0; i--) {
      if (routes[i].hasOwnProperty('title')) {
        return routes[i].title;
      }
    }
    return null;
  }

  getCurrentPath() {
    const { routes } = this.props;
    for (let i = routes.length - 1; i >= 0; i--) {
      if (routes[i].hasOwnProperty('path')) {
        return routes[i].path;
      }
    }
    return null;
  }

  render() {
    const classes = this.context.styleManager.render(styleSheet);
    const title = this.getTitle();

    let drawerDocked = this.state.drawerDocked;
    let navIconClassName = classes.navIcon;
    let appBarClassName = classes.appBar;

    if (title === null) { // home route, don't shift app bar or dock drawer
      drawerDocked = false;
      appBarClassName += ` ${classes.appBarHome}`;
    } else {
      navIconClassName += ` ${classes.navIconHide}`;
      appBarClassName += ` ${classes.appBarShift}`;
    }

    return (

        <AppBar className={appBarClassName}>
          <Toolbar>
            <IconButton onClick={this.handleDrawerToggle} className={navIconClassName}>
              menu
            </IconButton>
            <Text className={classes.title} type="title">{title}</Text>

            <IconButton onClick={this.handleToggleShade} className={classes.toggleShade}>
              lightbulb_outline
            </IconButton>
          </Toolbar>
        </AppBar>
        <AppDrawer
          docked={drawerDocked}
          routes={this.props.routes}
          onRequestClose={this.handleDrawerClose}
          open={this.state.drawerOpen}
        />
        {this.props.children}

    );
  }
}

function mapStateToProps(state) {
  return {
    dark: state.dark,
  };
}

export default connect(mapStateToProps)(AppFrame);
<commit_msg>Fix box sizing raw selector<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { createStyleSheet } from 'stylishly';
import Text from 'material-ui/Text';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import IconButton from 'material-ui/IconButton';
import { throttle } from 'material-ui/utils/helpers';
import addEventListener from 'material-ui/utils/addEventListener';

import AppDrawer from './AppDrawer';

export const styleSheet = createStyleSheet('AppFrame', (theme) => {
  const { palette, transitions, typography } = theme;
  return {
    '@raw html': { boxSizing: 'border-box' },
    '@raw *, *:before, *:after': { boxSizing: 'inherit' },
    '@raw body': {
      margin: 0,
      background: palette.background.default,
      fontFamily: typography.fontFamily,
      color: palette.text.primary,
      lineHeight: '1.2',
      overflowX: 'hidden',
    },
    '@raw a': {
      color: palette.accent.A400,
      textDecoration: 'none',
      '&:hover': {
        textDecoration: 'underline',
      },
    },
    '@raw p': {
      lineHeight: '1.6',
    },
    root: {
      display: 'flex',
      alignItems: 'stretch',
      minHeight: '100vh',
      width: '100vw',
      appBarHome: {
        backgroundColor: 'transparent',
        boxShadow: 'none',
      },
    },
    navIcon: {
      marginLeft: -12,
    },
    grow: {
      flex: '1 1 100%',
    },
    toggleShade: {
      marginRight: -12,
    },
    title: {
      marginLeft: 24,
      flex: '0 0 auto',
    },
    appBar: {
      left: 'auto',
      right: 0,
      transition: transitions.create('width'),
    },
    [theme.breakpoints.up('lg')]: {
      appBarShift: {
        width: 'calc(100% - 250px)',
      },
      navIconHide: {
        display: 'none',
      },
    },
  };
});

class AppFrame extends Component {
  static propTypes = {
    children: PropTypes.node,
    dispatch: PropTypes.func,
    routes: PropTypes.array,
  };

  static contextTypes = {
    theme: PropTypes.object.isRequired,
    styleManager: PropTypes.object.isRequired,
  };

  state = {
    drawerDocked: false,
    drawerOpen: false,
  };

  componentWillMount() {
    this.resizeListener = addEventListener(window, 'resize', this.handleResize);
  }

  componentDidMount() {
    this.mounted = true;
    this.checkWindowSize();
  }

  componentWillUnmount() {
    this.mounted = false;

    if (this.resizeListener) {
      this.resizeListener.remove();
    }
  }

  checkWindowSize = () => {
    if (!this.mounted) {
      return;
    }

    const breakpoint = this.context.theme.breakpoints.getWidth('lg');

    if (this.state.drawerDocked && window.innerWidth < breakpoint) {
      this.setState({ drawerDocked: false });
    } else if (!this.state.drawerDocked && window.innerWidth >= breakpoint) {
      this.setState({ drawerDocked: true });
    }
  };

  handleResize = throttle(this.checkWindowSize, 100);

  handleDrawerOpen = () => this.setState({ drawerOpen: true });
  handleDrawerClose = () => this.setState({ drawerOpen: false });
  handleDrawerToggle = () => this.setState({ drawerOpen: !this.state.drawerOpen });

  handleToggleShade = () => this.props.dispatch({ type: 'TOGGLE_THEME_SHADE' });

  getTitle() {
    const { routes } = this.props;
    for (let i = routes.length - 1; i >= 0; i--) {
      if (routes[i].hasOwnProperty('title')) {
        return routes[i].title;
      }
    }
    return null;
  }

  getCurrentPath() {
    const { routes } = this.props;
    for (let i = routes.length - 1; i >= 0; i--) {
      if (routes[i].hasOwnProperty('path')) {
        return routes[i].path;
      }
    }
    return null;
  }

  render() {
    const classes = this.context.styleManager.render(styleSheet);
    const title = this.getTitle();

    let drawerDocked = this.state.drawerDocked;
    let navIconClassName = classes.navIcon;
    let appBarClassName = classes.appBar;

    if (title === null) { // home route, don't shift app bar or dock drawer
      drawerDocked = false;
      appBarClassName += ` ${classes.appBarHome}`;
    } else {
      navIconClassName += ` ${classes.navIconHide}`;
      appBarClassName += ` ${classes.appBarShift}`;
    }

    return (

        <AppBar className={appBarClassName}>
          <Toolbar>
            <IconButton onClick={this.handleDrawerToggle} className={navIconClassName}>
              menu
            </IconButton>
            <Text className={classes.title} type="title">{title}</Text>

            <IconButton onClick={this.handleToggleShade} className={classes.toggleShade}>
              lightbulb_outline
            </IconButton>
          </Toolbar>
        </AppBar>
        <AppDrawer
          docked={drawerDocked}
          routes={this.props.routes}
          onRequestClose={this.handleDrawerClose}
          open={this.state.drawerOpen}
        />
        {this.props.children}

    );
  }
}

function mapStateToProps(state) {
  return {
    dark: state.dark,
  };
}

export default connect(mapStateToProps)(AppFrame);
<|endoftext|>


<commit_before>/*global _spPageContextInfo */
/*global document,console,clearTimeout,setTimeout,window,XMLHttpRequest,$ */
/*jshint -W043*/

/**
 * Protect window.console method calls, e.g. console is not defined on IE
 * unless dev tools are open, and IE doesn't define console.debug
 *
 * Chrome 41.0.2272.118: debug,error,info,log,warn,dir,dirxml,table,trace,assert,count,markTimeline,profile,profileEnd,time,timeEnd,timeStamp,timeline,timelineEnd,group,groupCollapsed,groupEnd,clear
 * Firefox 37.0.1: log,info,warn,error,exception,debug,table,trace,dir,group,groupCollapsed,groupEnd,time,timeEnd,profile,profileEnd,assert,count
 * Internet Explorer 11: select,log,info,warn,error,debug,assert,time,timeEnd,timeStamp,group,groupCollapsed,groupEnd,trace,clear,dir,dirxml,count,countReset,cd
 * Safari 6.2.4: debug,error,log,info,warn,clear,dir,dirxml,table,trace,assert,count,profile,profileEnd,time,timeEnd,timeStamp,group,groupCollapsed,groupEnd
 * Opera 28.0.1750.48: debug,error,info,log,warn,dir,dirxml,table,trace,assert,count,markTimeline,profile,profileEnd,time,timeEnd,timeStamp,timeline,timelineEnd,group,groupCollapsed,groupEnd,clear
 */
(function () {
	// Union of Chrome, Firefox, IE, Opera, and Safari console methods
	var methods = ["assert", "assert", "cd", "clear", "count", "countReset",
    "debug", "dir", "dirxml", "dirxml", "dirxml", "error", "error", "exception",
    "group", "group", "groupCollapsed", "groupCollapsed", "groupEnd", "info",
    "info", "log", "log", "markTimeline", "profile", "profileEnd", "profileEnd",
    "select", "table", "table", "time", "time", "timeEnd", "timeEnd", "timeEnd",
    "timeEnd", "timeEnd", "timeStamp", "timeline", "timelineEnd", "trace",
    "trace", "trace", "trace", "trace", "warn"];
	var length = methods.length;
	var console = (window.console = window.console || {});
	var method;
	var noop = function () {};
	while (length--) {
		method = methods[length];
		// define undefined methods as noops to prevent errors
		if (!console[method])
			console[method] = noop;
	}
})();

/* Global functions */
var VM365_CalcMaster = { //global obect for easier debugging
	//global settings
	comma: _spPageContextInfo.currentLanguage === 1033 ? ',' : ';', //SharePoint function separator
	layouts: _spPageContextInfo.layoutsUrl,
	saveID: 0,
	//initialize CalcMaster
	initialize: function () {
		//get references to DOM elements
		VM365_CalcMaster.columnList = document.getElementById('onetidIOCalcFields1');
		VM365_CalcMaster.textarea = document.getElementById('onetidIODefTextValue1');
		//adjust layout of textarea and column list
		VM365_CalcMaster.columnList.style.height = VM365_CalcMaster.textarea.style.height = '300px';
		VM365_CalcMaster.textarea.style.width = '500px';
		//Highlight the Number datatype for HTML output
		VM365_CalcMaster.setDOMelement('Number (outputs HTML/JavaScript)', 0, 'L_onetidTypeNumber1', 'lightGreen');
		//add CalcMaster UI elements for Toolbar and Save Formula Reporting, remember the MIT license
		VM365_CalcMaster.setDOMelement(
			"CalcMaster \
			powered by 365Coach.nl \

MIT sourcecode on GitHub \

\

See SharePoint Calculated Column Functions & Syntax List\

The \
				 \
					Drag-Drop View Editor is a cool bookmarklet also\

\
				 \

 \

", 0, 'onetidIODefText0');
		VM365_CalcMaster.addFunctionlist();
		VM365_CalcMaster.setDOMelement('Update your Formula and I will check if the Formula is correct', 2);
		//add event to the existing textarea
		VM365_CalcMaster.textarea.onkeyup = function (event) {
			if ([37, 38, 39, 40].indexOf(event.keyCode) === -1) { //ignore arrow keys
				clearTimeout(VM365_CalcMaster.saveID);
				VM365_CalcMaster.saveID = setTimeout(function () {
					VM365_CalcMaster.updateFormula(event);
				}, 300);//do not save while typing
			}
		};
	},
	//supporting functions
	setDOMelement: function (txt, color, id, bgcolor) {
		var element = document.getElementById(id || 'calcmasterSave');
		element.innerHTML = txt;
		element.style.color = ['black', 'red', 'green', 'darkorange'][color];
		if (bgcolor) element.style.backgroundColor = bgcolor;
	},
	setFormulaInTextarea: function (Formula) {
		if (Formula.indexOf('\n') === -1) { //if no newlines exist reformat to multiple lines
			Formula = Formula.replace(/&\"/gi, '\n  &\"'); //replace & before quote
			Formula = Formula.replace(/\"&/gi, '"\n  &'); //replace & after quote
			Formula = Formula.replace(/\";/gi, '\"\n;'); //replace & before quote
			Formula = Formula.replace(/IF/g, '\nIF'); //replace & before quote
		}
		VM365_CalcMaster.textarea.value = Formula;
	},
	sanitizeFormulaBeforeWritingToSP: function (Formula) {
		//the original Grand CalcMaster does a lot more, left the code in as a reminder to self
		//Formula = Formula.replace(/'/g, "'");
		//Formula = Formula.replace(/'/g, "\\'");
		//Formula = Formula.replace(/'/g, '"&CHAR(39)&"');
		Formula = Formula.replace(/`/g, "'"); //replace backticks with single quote
		return (Formula);
	},
	//additional button functions in CalcMaster editor
	functionConvertToICC: function (Formula) {
		Formula = Formula || VM365_CalcMaster.textarea.value;
		if (Formula[0] !== '=') { //if Formula is NOT a SharePoint formula, it is javascript code
			Formula.replace(/'/g, '`'); //replace original single quotes with backticks (used in Grand CalcMaster)
			if (Formula.indexOf('onload') === -1 && Formula.indexOf('onclick') === -1) {
				//wrap in IMG onload tag and quoted SharePoint formula strings
				Formula = '=""';
			}
			VM365_CalcMaster.setFormulaInTextarea(Formula);
			VM365_CalcMaster.updateFormula();
		} else {
			VM365_CalcMaster.setDOMelement('textarea does not contain plain JavaScript', 1);
		}
	},
	updateFormula: function (event) {
		//current selected Formula output datatype
		var selectedType = Array.prototype.filter.call(document.getElementsByName('ResultType'), function (r) {
			if (r.checked) return (r);
		});
		//document.getElementById('onetidSaveItem').style.display = 'none'; //hide OK button
		var Formula = VM365_CalcMaster.textarea.value;
		VM365_CalcMaster.setFormulaInTextarea(Formula);
		VM365_CalcMaster.updateCalculatedColumn({
			Title: document.getElementById('idColName').value,
			Description: document.getElementById('idDesc').value,
			Formula: Formula,
			type: selectedType[0].value //Text or Number or DateTime or Currency or Boolean
		});
		//reporting of Formula analysis
		var calcmasterHint = [];
		if (Formula.split('"').length % 2 === 0) calcmasterHint.push("unmatched double quotes");
		if (Formula.split("'").length % 2 === 0) calcmasterHint.push("unmatched single quotes");
		if (Formula.split('(').length !== Formula.split(')').length) calcmasterHint.push("unmatched () brackets");
		VM365_CalcMaster.setDOMelement(calcmasterHint.join('
'), 3, 'calcmasterHint');
	},
	updateCalculatedColumn: function (column,formula,list,field) {
		VM365_CalcMaster.setDOMelement('Trying to save Formula ' + column.Title + '....', 2);
		column.list = "Lists(guid'" + _spPageContextInfo.pageListId.replace(/[{}]/g, '') + "')";
		column.field = "Fields/getbytitle('" + column.Title + "')";
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.onreadystatechange = function () {
			console.info(xmlhttp.status,xmlhttp);
			if (xmlhttp.readyState == XMLHttpRequest.DONE) {
				if (xmlhttp.status == 500) {
					console.info(xmlhttp.status, xmlhttp.statusText,JSON.parse(xmlhttp.responseText).error.message.value);
					VM365_CalcMaster.setDOMelement(JSON.parse(xmlhttp.responseText).error.message.value, 1);
				} else {
					VM365_CalcMaster.setDOMelement('Formula ' + column.Title + ' saved!');
				}
			}
		};
		console.info('saving',column.Title,column.Formula);
		xmlhttp.open("POST", _spPageContextInfo.webAbsoluteUrl + "/_api/Web/ " + column.list + "/" + column.field, true);
		xmlhttp.setRequestHeader("X-HTTP-Method", "MERGE");
		xmlhttp.setRequestHeader("X-RequestDigest", document.getElementById('__REQUESTDIGEST').value);
		xmlhttp.setRequestHeader("accept", "application/json;odata=verbose");
		xmlhttp.setRequestHeader("content-type", "application/json;odata=verbose");
		xmlhttp.send(
			JSON.stringify({
				'Title': column.Title,
				'Formula': VM365_CalcMaster.sanitizeFormulaBeforeWritingToSP(column.Formula),
				'__metadata': {
					'type': 'SP.FieldCalculated'
				},
				'Description': column.Description,
				'OutputType': ({
					Text: 2,
					Number: 9,
					Currency: 10,
					DateTime: 4,
					Boolean: 8
				})[column.type]
			})
		);
	},
	//leaving jQuery ajax call in here, I use it my CalcMaster Pro version
	JQ_updateCalculatedColumn: function (column) {
		VM365_CalcMaster.setDOMelement('Updating Formula ' + column.Title + '... (this may take a minute)', 2);
		column.list = "Lists(guid'" + _spPageContextInfo.pageListId.replace(/[{}]/g, '') + "')";
		column.field = "Fields/getbytitle('" + column.Title + "')";
		$.ajax({
			url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/ " + column.list + "/" + column.field,
			success: function (data) {
				VM365_CalcMaster.setDOMelement('Formula ' + column.Title + ' saved succesfully');
			},
			error: function (data) {
				VM365_CalcMaster.setDOMelement(data.responseJSON.error.message.value, 1);
			},
			type: "POST",
			headers: {
				"X-HTTP-Method": "MERGE",
				"X-RequestDigest": document.getElementById('__REQUESTDIGEST').value,
				"accept": "application/json;odata=verbose",
				"content-type": "application/json;odata=verbose"
			},
			data: JSON.stringify({
				'Title': column.Title,
				'Formula': VM365_CalcMaster.sanitizeFormulaBeforeWritingToSP(column.Formula),
				'__metadata': {
					'type': 'SP.FieldCalculated'
				},
				'Description': column.Description,
				'OutputType': ({
					Text: 2,
					Number: 9,
					Currency: 10,
					DateTime: 4,
					Boolean: 8
				})[column.type]
			})
		}); //ajax call
	},
	addFunctionlist:function(){
		var F=document.getElementById('onetidIODefText0').parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.cells[1];
		F.style.verticalAlign='top';
		F.style.width='inherit';
		F.innerHTML="";
	}
};
VM365_CalcMaster.initialize();
<commit_msg>better feedback on formula saving<commit_after>/*global _spPageContextInfo */
/*global document,console,clearTimeout,setTimeout,window,XMLHttpRequest,$ */
/*jshint -W043*/

/**
 * Protect window.console method calls, e.g. console is not defined on IE
 * unless dev tools are open, and IE doesn't define console.debug
 *
 * Chrome 41.0.2272.118: debug,error,info,log,warn,dir,dirxml,table,trace,assert,count,markTimeline,profile,profileEnd,time,timeEnd,timeStamp,timeline,timelineEnd,group,groupCollapsed,groupEnd,clear
 * Firefox 37.0.1: log,info,warn,error,exception,debug,table,trace,dir,group,groupCollapsed,groupEnd,time,timeEnd,profile,profileEnd,assert,count
 * Internet Explorer 11: select,log,info,warn,error,debug,assert,time,timeEnd,timeStamp,group,groupCollapsed,groupEnd,trace,clear,dir,dirxml,count,countReset,cd
 * Safari 6.2.4: debug,error,log,info,warn,clear,dir,dirxml,table,trace,assert,count,profile,profileEnd,time,timeEnd,timeStamp,group,groupCollapsed,groupEnd
 * Opera 28.0.1750.48: debug,error,info,log,warn,dir,dirxml,table,trace,assert,count,markTimeline,profile,profileEnd,time,timeEnd,timeStamp,timeline,timelineEnd,group,groupCollapsed,groupEnd,clear
 */
(function () {
	// Union of Chrome, Firefox, IE, Opera, and Safari console methods
	var methods = ["assert", "assert", "cd", "clear", "count", "countReset",
    "debug", "dir", "dirxml", "dirxml", "dirxml", "error", "error", "exception",
    "group", "group", "groupCollapsed", "groupCollapsed", "groupEnd", "info",
    "info", "log", "log", "markTimeline", "profile", "profileEnd", "profileEnd",
    "select", "table", "table", "time", "time", "timeEnd", "timeEnd", "timeEnd",
    "timeEnd", "timeEnd", "timeStamp", "timeline", "timelineEnd", "trace",
    "trace", "trace", "trace", "trace", "warn"];
	var length = methods.length;
	var console = (window.console = window.console || {});
	var method;
	var noop = function () {};
	while (length--) {
		method = methods[length];
		// define undefined methods as noops to prevent errors
		if (!console[method])
			console[method] = noop;
	}
})();

/* Global functions */
var VM365_CalcMaster = { //global obect for easier debugging
	//global settings
	comma: _spPageContextInfo.currentLanguage === 1033 ? ',' : ';', //SharePoint function separator
	layouts: _spPageContextInfo.layoutsUrl,
	saveID: 0,
	//initialize CalcMaster
	initialize: function () {
		//get references to DOM elements
		VM365_CalcMaster.columnList = document.getElementById('onetidIOCalcFields1');
		VM365_CalcMaster.textarea = document.getElementById('onetidIODefTextValue1');
		//adjust layout of textarea and column list
		VM365_CalcMaster.columnList.style.height = VM365_CalcMaster.textarea.style.height = '300px';
		VM365_CalcMaster.textarea.style.width = '500px';
		//Highlight the Number datatype for HTML output
		VM365_CalcMaster.setDOMelement('Number (outputs HTML/JavaScript)', 0, 'L_onetidTypeNumber1', 'lightGreen');
		//add CalcMaster UI elements for Toolbar and Save Formula Reporting, remember the MIT license
		VM365_CalcMaster.setDOMelement(
			"CalcMaster \
			powered by 365Coach.nl \

MIT sourcecode on GitHub \

\

See SharePoint Calculated Column Functions & Syntax List\

The \
				 \
					Drag-Drop View Editor is a cool bookmarklet also\

\
				 \

 \

", 0, 'onetidIODefText0');
		VM365_CalcMaster.addFunctionlist();
		VM365_CalcMaster.setDOMelement('Update your Formula and I will check if the Formula is correct', 2);
		//add event to the existing textarea
		VM365_CalcMaster.textarea.onkeyup = function (event) {
			if ([37, 38, 39, 40].indexOf(event.keyCode) === -1) { //ignore arrow keys
				clearTimeout(VM365_CalcMaster.saveID);
				VM365_CalcMaster.saveID = setTimeout(function () {
					VM365_CalcMaster.updateFormula(event);
				}, 300);//do not save while typing
			}
		};
	},
	//supporting functions
	setDOMelement: function (txt, color, id, bgcolor) {
		var element = document.getElementById(id || 'calcmasterSave');
		element.innerHTML = txt;
		element.style.color = ['black', 'red', 'green', 'darkorange'][color];
		if (bgcolor) element.style.backgroundColor = bgcolor;
	},
	setFormulaInTextarea: function (Formula) {
		if (Formula.indexOf('\n') === -1) { //if no newlines exist reformat to multiple lines
			Formula = Formula.replace(/&\"/gi, '\n  &\"'); //replace & before quote
			Formula = Formula.replace(/\"&/gi, '"\n  &'); //replace & after quote
			Formula = Formula.replace(/\";/gi, '\"\n;'); //replace & before quote
			Formula = Formula.replace(/IF/g, '\nIF'); //replace & before quote
		}
		VM365_CalcMaster.textarea.value = Formula;
	},
	sanitizeFormulaBeforeWritingToSP: function (Formula) {
		//the original Grand CalcMaster does a lot more, left the code in as a reminder to self
		//Formula = Formula.replace(/'/g, "'");
		//Formula = Formula.replace(/'/g, "\\'");
		//Formula = Formula.replace(/'/g, '"&CHAR(39)&"');
		Formula = Formula.replace(/`/g, "'"); //replace backticks with single quote
		return (Formula);
	},
	//additional button functions in CalcMaster editor
	functionConvertToICC: function (Formula) {
		Formula = Formula || VM365_CalcMaster.textarea.value;
		if (Formula[0] !== '=') { //if Formula is NOT a SharePoint formula, it is javascript code
			Formula.replace(/'/g, '`'); //replace original single quotes with backticks (used in Grand CalcMaster)
			if (Formula.indexOf('onload') === -1 && Formula.indexOf('onclick') === -1) {
				//wrap in IMG onload tag and quoted SharePoint formula strings
				Formula = '=""';
			}
			VM365_CalcMaster.setFormulaInTextarea(Formula);
			VM365_CalcMaster.updateFormula();
		} else {
			VM365_CalcMaster.setDOMelement('textarea does not contain plain JavaScript', 1);
		}
	},
	updateFormula: function (event) {
		//current selected Formula output datatype
		var selectedType = Array.prototype.filter.call(document.getElementsByName('ResultType'), function (r) {
			if (r.checked) return (r);
		});
		//document.getElementById('onetidSaveItem').style.display = 'none'; //hide OK button
		var Formula = VM365_CalcMaster.textarea.value;
		VM365_CalcMaster.setFormulaInTextarea(Formula);
		VM365_CalcMaster.updateCalculatedColumn({
			Title: document.getElementById('idColName').value,
			Description: document.getElementById('idDesc').value,
			Formula: Formula,
			type: selectedType[0].value //Text or Number or DateTime or Currency or Boolean
		});
		//reporting of Formula analysis
		var calcmasterHint = [];
		if (Formula.split('"').length % 2 === 0) calcmasterHint.push("unmatched double quotes");
		if (Formula.split("'").length % 2 === 0) calcmasterHint.push("unmatched single quotes");
		if (Formula.split('(').length !== Formula.split(')').length) calcmasterHint.push("unmatched () brackets");
		VM365_CalcMaster.setDOMelement(calcmasterHint.join('
'), 3, 'calcmasterHint');
	},
	updateCalculatedColumn: function (column,formula,list,field) {
		VM365_CalcMaster.setDOMelement("Updating Formula " + column.Title + "... (this may take a minute)", 2);
		column.list = "Lists(guid'" + _spPageContextInfo.pageListId.replace(/[{}]/g, '') + "')";
		column.field = "Fields/getbytitle('" + column.Title + "')";
		var xmlhttp = new XMLHttpRequest();
		xmlhttp.onreadystatechange = function () {
			console.info(xmlhttp.status,xmlhttp);
			VM365_CalcMaster.setDOMelement('Updating all List Items...');
			if (xmlhttp.readyState == XMLHttpRequest.DONE) {
				if (xmlhttp.status == 500) {
					console.info(xmlhttp.status, xmlhttp.statusText,JSON.parse(xmlhttp.responseText).error.message.value);
					VM365_CalcMaster.setDOMelement(JSON.parse(xmlhttp.responseText).error.message.value, 1);
				} else {
					VM365_CalcMaster.setDOMelement('Formula ' + column.Title + ' saved!');
				}
			}
		};
		console.info('saving',column.Title,column.Formula);
		xmlhttp.open("POST", _spPageContextInfo.webAbsoluteUrl + "/_api/Web/ " + column.list + "/" + column.field, true);
		xmlhttp.setRequestHeader("X-HTTP-Method", "MERGE");
		xmlhttp.setRequestHeader("X-RequestDigest", document.getElementById('__REQUESTDIGEST').value);
		xmlhttp.setRequestHeader("accept", "application/json;odata=verbose");
		xmlhttp.setRequestHeader("content-type", "application/json;odata=verbose");
		xmlhttp.send(
			JSON.stringify({
				'Title': column.Title,
				'Formula': VM365_CalcMaster.sanitizeFormulaBeforeWritingToSP(column.Formula),
				'__metadata': {
					'type': 'SP.FieldCalculated'
				},
				'Description': column.Description,
				'OutputType': ({
					Text: 2,
					Number: 9,
					Currency: 10,
					DateTime: 4,
					Boolean: 8
				})[column.type]
			})
		);
	},
	//leaving jQuery ajax call in here, I use it my CalcMaster Pro version
	JQ_updateCalculatedColumn: function (column) {
		VM365_CalcMaster.setDOMelement("Updating Formula " + column.Title + "... (this may take a minute)", 2);
		column.list = "Lists(guid'" + _spPageContextInfo.pageListId.replace(/[{}]/g, '') + "')";
		column.field = "Fields/getbytitle('" + column.Title + "')";
		$.ajax({
			url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/ " + column.list + "/" + column.field,
			success: function (data) {
				VM365_CalcMaster.setDOMelement('Formula ' + column.Title + ' saved succesfully');
			},
			error: function (data) {
				VM365_CalcMaster.setDOMelement(data.responseJSON.error.message.value, 1);
			},
			type: "POST",
			headers: {
				"X-HTTP-Method": "MERGE",
				"X-RequestDigest": document.getElementById('__REQUESTDIGEST').value,
				"accept": "application/json;odata=verbose",
				"content-type": "application/json;odata=verbose"
			},
			data: JSON.stringify({
				'Title': column.Title,
				'Formula': VM365_CalcMaster.sanitizeFormulaBeforeWritingToSP(column.Formula),
				'__metadata': {
					'type': 'SP.FieldCalculated'
				},
				'Description': column.Description,
				'OutputType': ({
					Text: 2,
					Number: 9,
					Currency: 10,
					DateTime: 4,
					Boolean: 8
				})[column.type]
			})
		}); //ajax call
	},
	addFunctionlist:function(){
		var F=document.getElementById('onetidIODefText0').parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.cells[1];
		F.style.verticalAlign='top';
		F.style.width='inherit';
		F.innerHTML="";
	}
};
VM365_CalcMaster.initialize();
<|endoftext|>


<commit_before>describe('traffic', function() {
  beforeEach(function() {
    window.matrix.settings = {
      profileId: ''
    };
    subject =  window.matrix.search;
    sandbox = sinon.sandbox.create();
    server = sinon.fakeServer.create();
  });
  afterEach(function() {
    sandbox.restore();
    server.restore();
  });
  describe('#init', function() {
    beforeEach(function() {
      $('body').append('

');
      sandbox.stub(Handlebars, 'compile');
    });
    it("calls reload", function() {
      mock = sandbox.mock(subject).expects("reload").once();
      subject.init();
      mock.verify();
    });
    it("calls reload with interval of 1 minute", function() {
      clock = sinon.useFakeTimers(Date.now());
      mock = sandbox.mock(subject).expects("reload").twice();
      subject.init();
      clock.tick(60000);
      mock.verify();
      clock.restore();
    });
  });
  describe('#reload', function() {
    it("calls endpoint", function() {
      sandbox.stub(xhr, "json");
      mock = sandbox.mock(subject).expects("endpoint").once();
      subject.reload();
      mock.verify();
    });
    context('json returned', function(){
      beforeEach(function() {
        stub = sandbox.stub(xhr, 'json');
      });
      it("calls parseResponse", function() {
        mock = sandbox.mock(subject).expects("parseResponse").once();
        subject.reload();
        stub.callArgWith(1, {}, {});
        mock.verify();
      });
    });
  });
  describe('#parseResponse', function() {
    context("error parsing json", function() {
      it("returns withpout parsing", function() {
        mock = sandbox.mock(subject).expects("parseData").never();
        subject.parseResponse({}, null);
        mock.verify();
      });
      it("does not refresh the results", function() {
        mock = sandbox.mock(subject).expects("refreshResults").never();
        subject.parseResponse({}, null);
        mock.verify();
      });
    });
    context("no error parsing json", function() {
      context("has data from GA", function() {
        it("calls parseData", function() {
          sandbox.stub(subject, 'refreshResults');
          mock = sandbox.mock(subject).expects("parseData").once();
          subject.parseResponse(null, {rows: []});
          mock.verify();
        });
        it("refreshes the results", function() {
          mock = sandbox.mock(subject).expects("refreshResults").once();
          subject.parseResponse(null, {rows: []});
          mock.verify();
        });
      });
      context("no rows (no data from GA)", function() {
        it("does not call parseData", function() {
          mock = sandbox.mock(subject).expects("parseData").never();
          subject.parseResponse(null, {});
          mock.verify();
        });
      });
    });
  });
  describe('#parseData', function() {
    beforeEach(function() {
      data = { rows: [ ["url1", "keyword 1", "00", "DESKTOP", "1"],["url1", "keyword 2", "01", "DESKTOP", "1"],["url1", "keyword 3", "01", "DESKTOP", "1"],["url1", "keyowrd 4", "02", "DESKTOP", "1"]]};
    });
    it("calls addTerm for every row less than two minutes ago", function() {
      mock = sandbox.mock(subject).expects("addTerm").thrice();
      subject.parseData(data);
      mock.verify();
    });
    it("calls addTerm for every row", function() {
      data = { rows: [ ["url1", "keyword", "00", "DESKTOP", "1"]]};
      mock = sandbox.mock(subject).expects("addTerm").withArgs("keyword", 1, "url1");
      subject.parseData(data);
      mock.verify();
    });
    context('Search Term', function() {
      beforeEach(function(){
      data = { rows: [ ["url1", "Search", "00", "DESKTOP", "1"]]};
      });
      it("does not call addTerm for the row", function() {
        mock = sandbox.mock(subject).expects("addTerm").never();
        subject.parseData(data);
        mock.verify();
      });
    });
  });
  describe('#addTerm', function() {
    beforeEach(function() {
      subject.terms = [];
    });
    it("adds new items to terms", function() {
      result = { term: 'Test', total: 1, url: 'url', deviceCategory: 'desktop' }
      subject.addTerm("Test", 1, "url", "desktop");
      expect(subject.terms[0]).to.eql(result);
    });
  });
  describe('#refreshResults', function() {
    beforeEach(function() {
      subject.terms = [{ term: 'Test', total: 1, url: 'url', source: 'source' }];
    });
    it("shows all terms", function() {
    });
    it("calls handlebars template", function() {
    });
  });
  describe('#endpoint', function() {
    it('returns the path to the servers realtime endpoint', function() {
      var result = '/realtime?ids=ga:&'+
        'metrics=rt:pageViews&'+
        'dimensions=rt:pagePath,rt:keyword,rt:minutesAgo,rt:deviceCategory&'+
        'sort=rt:minutesAgo&max-results=10000';
      expect(subject.endpoint()).to.eql(result);
    });
    context('with profileId', function() {
      beforeEach(function() {
        window.matrix.settings = {
          profileId: 'Test'
        };
      });
      it('returns correct profile Id in the endpoint path', function() {
      var result = '/realtime?ids=ga:Test&'+
        'metrics=rt:pageViews&'+
        'dimensions=rt:pagePath,rt:keyword,rt:minutesAgo,rt:deviceCategory&'+
        'sort=rt:minutesAgo&max-results=10000';
      expect(subject.endpoint()).to.eql(result);
      });
    });
  });
  describe("safeTerm", function() {
    context("email address", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("iw@jwi.de")).to.eq(false);
      });
    });
    context("just numbers", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("432913")).to.eq(false);
      });
    });
    context("no search term", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("(not set)")).to.eq(false);
      });
    });
    context("search term secured by google", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("(not provided)")).to.eq(false);
      });
    });
    context("503 request", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("Sorry, we are experiencing technical difficulties (503 error)")).to.eq(false);
      });
    });
  });
});
<commit_msg>Add test for template call<commit_after>describe('traffic', function() {
  beforeEach(function() {
    window.matrix.settings = {
      profileId: ''
    };
    subject =  window.matrix.search;
    sandbox = sinon.sandbox.create();
    server = sinon.fakeServer.create();
  });
  afterEach(function() {
    sandbox.restore();
    server.restore();
  });
  describe('#init', function() {
    beforeEach(function() {
      $('body').append('

');
      sandbox.stub(Handlebars, 'compile');
    });
    it("calls reload", function() {
      mock = sandbox.mock(subject).expects("reload").once();
      subject.init();
      mock.verify();
    });
    it("calls reload with interval of 1 minute", function() {
      clock = sinon.useFakeTimers(Date.now());
      mock = sandbox.mock(subject).expects("reload").twice();
      subject.init();
      clock.tick(60000);
      mock.verify();
      clock.restore();
    });
  });
  describe('#reload', function() {
    it("calls endpoint", function() {
      sandbox.stub(xhr, "json");
      mock = sandbox.mock(subject).expects("endpoint").once();
      subject.reload();
      mock.verify();
    });
    context('json returned', function(){
      beforeEach(function() {
        stub = sandbox.stub(xhr, 'json');
      });
      it("calls parseResponse", function() {
        mock = sandbox.mock(subject).expects("parseResponse").once();
        subject.reload();
        stub.callArgWith(1, {}, {});
        mock.verify();
      });
    });
  });
  describe('#parseResponse', function() {
    context("error parsing json", function() {
      it("returns withpout parsing", function() {
        mock = sandbox.mock(subject).expects("parseData").never();
        subject.parseResponse({}, null);
        mock.verify();
      });
      it("does not refresh the results", function() {
        mock = sandbox.mock(subject).expects("refreshResults").never();
        subject.parseResponse({}, null);
        mock.verify();
      });
    });
    context("no error parsing json", function() {
      context("has data from GA", function() {
        it("calls parseData", function() {
          sandbox.stub(subject, 'refreshResults');
          mock = sandbox.mock(subject).expects("parseData").once();
          subject.parseResponse(null, {rows: []});
          mock.verify();
        });
        it("refreshes the results", function() {
          mock = sandbox.mock(subject).expects("refreshResults").once();
          subject.parseResponse(null, {rows: []});
          mock.verify();
        });
      });
      context("no rows (no data from GA)", function() {
        it("does not call parseData", function() {
          mock = sandbox.mock(subject).expects("parseData").never();
          subject.parseResponse(null, {});
          mock.verify();
        });
      });
    });
  });
  describe('#parseData', function() {
    beforeEach(function() {
      data = { rows: [ ["url1", "keyword 1", "00", "DESKTOP", "1"],["url1", "keyword 2", "01", "DESKTOP", "1"],["url1", "keyword 3", "01", "DESKTOP", "1"],["url1", "keyowrd 4", "02", "DESKTOP", "1"]]};
    });
    it("calls addTerm for every row less than two minutes ago", function() {
      mock = sandbox.mock(subject).expects("addTerm").thrice();
      subject.parseData(data);
      mock.verify();
    });
    it("calls addTerm for every row", function() {
      data = { rows: [ ["url1", "keyword", "00", "DESKTOP", "1"]]};
      mock = sandbox.mock(subject).expects("addTerm").withArgs("keyword", 1, "url1");
      subject.parseData(data);
      mock.verify();
    });
    context('Search Term', function() {
      beforeEach(function(){
      data = { rows: [ ["url1", "Search", "00", "DESKTOP", "1"]]};
      });
      it("does not call addTerm for the row", function() {
        mock = sandbox.mock(subject).expects("addTerm").never();
        subject.parseData(data);
        mock.verify();
      });
    });
  });
  describe('#addTerm', function() {
    beforeEach(function() {
      subject.terms = [];
    });
    it("adds new items to terms", function() {
      result = { term: 'Test', total: 1, url: 'url', deviceCategory: 'desktop' }
      subject.addTerm("Test", 1, "url", "desktop");
      expect(subject.terms[0]).to.eql(result);
    });
  });
  describe('#refreshResults', function() {
    beforeEach(function() {
      subject.terms = [{ term: 'Test', total: 1, url: 'url', source: 'source' }];
    });
    it("shows all terms", function() {
    });
    it("calls handlebars template", function() {
      mock = sandbox.mock(templateHelper).expects("prependTemplate").once();
      subject.refreshResults();
      mock.verify();
    });
  });
  describe('#endpoint', function() {
    it('returns the path to the servers realtime endpoint', function() {
      var result = '/realtime?ids=ga:&'+
        'metrics=rt:pageViews&'+
        'dimensions=rt:pagePath,rt:keyword,rt:minutesAgo,rt:deviceCategory&'+
        'sort=rt:minutesAgo&max-results=10000';
      expect(subject.endpoint()).to.eql(result);
    });
    context('with profileId', function() {
      beforeEach(function() {
        window.matrix.settings = {
          profileId: 'Test'
        };
      });
      it('returns correct profile Id in the endpoint path', function() {
      var result = '/realtime?ids=ga:Test&'+
        'metrics=rt:pageViews&'+
        'dimensions=rt:pagePath,rt:keyword,rt:minutesAgo,rt:deviceCategory&'+
        'sort=rt:minutesAgo&max-results=10000';
      expect(subject.endpoint()).to.eql(result);
      });
    });
  });
  describe("safeTerm", function() {
    context("email address", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("iw@jwi.de")).to.eq(false);
      });
    });
    context("just numbers", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("432913")).to.eq(false);
      });
    });
    context("no search term", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("(not set)")).to.eq(false);
      });
    });
    context("search term secured by google", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("(not provided)")).to.eq(false);
      });
    });
    context("503 request", function() {
      it("is not safe", function() {
        expect(subject.safeTerm("Sorry, we are experiencing technical difficulties (503 error)")).to.eq(false);
      });
    });
  });
});
<|endoftext|>