<commit_before>/*
 * Spreed WebRTC.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed WebRTC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
define(['underscore', 'jquery', 'modernizr', 'sjcl'], function(underscore, $, Modernizr, sjcl) {

	var Database = function(name) {
		this.version = 3;
		this.ready = false;
		this.db = null;
		this.name = name;
		this.e = $({});
		var request = indexedDB.open(this.name, this.version);
		var that = this;
		request.onupgradeneeded = function(event) {
			var db = event.target.result;
			var transaction = event.target.transaction;
			transaction.onerror = _.bind(that.onerror, that);
			that.init(db);
			console.log("Created contacts database.")
		};
		request.onsuccess = _.bind(that.onsuccess, that);
	};
	Database.prototype.init = function(db) {
		var createOrUpdateStore = function(name, obj) {
			if (db.objectStoreNames.contains(name)) {
				// TODO(longsleep): Migrate data.
				db.deleteObjectStore(name);
			}
			db.createObjectStore(name, obj);
		}
		// Create our object stores.
		createOrUpdateStore("contacts", {
			// We use id field as our unique identifier.
			keyPath: "id"
		});
	};
	Database.prototype.onerror = function(event) {
		console.log("IndexDB database error", event);
	};
	Database.prototype.onsuccess = function(event) {
		this.db = event.target.result;
		this.ready = true;
		console.log("Openend database", this.db);
		this.e.triggerHandler("ready");
	};
	Database.prototype.put = function(storename, data, successCallback, errorCallback) {
		var transaction = this.db.transaction(storename, "readwrite");
		var store = transaction.objectStore(storename);
		var request = store.put(data);
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = request.onerror = errorCallback;
		if (successCallback) {
			request.onsuccess = successCallback;
		}
		return request;
	};
	Database.prototype.delete = function(storename, id, successCallback, errorCallback) {
		var transaction = this.db.transaction(storename, "readwrite");
		var store = transaction.objectStore(storename);
		var request = store.delete(id);
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = request.onerror = errorCallback;
		if (successCallback) {
			request.onsuccess = successCallback;
		}
		return request;
	};
	Database.prototype.all = function(storename, iteratorCallback, errorCallback) {
		var transaction = this.db.transaction(storename);
		var store = transaction.objectStore(storename);
		var keyRange = IDBKeyRange.lowerBound(0);
		var cursorRequest = store.openCursor(keyRange);
		cursorRequest.onsuccess = function(event) {
			var result = event.target.result;
			if (!result) {
				return;
			}
			//console.log("read data idb", result, event);
			iteratorCallback(result.value);
			result.continue();
		};
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = cursorRequest.onerror = errorCallback;
		return cursorRequest;
	};
	Database.prototype.close = function() {
		// TODO(longsleep): Database close.
		this.e.off();
		if (this.db) {
			this.db.close();
			this.db = null;
			this.ready = false;
		}
		_.defer(_.bind(function() {
			this.e.triggerHandler("closed");
		}, this));
	};

	// contacts
	return ["appData", "contactData", "mediaStream", function(appData, contactData, mediaStream) {

		var Contacts = function() {

			this.e = $({});
			this.userid = null;
			this.key = null;
			this.database = null;

			appData.e.on("authenticationChanged", _.bind(function(event, userid, suserid) {
				var database = this.open(userid, suserid);
				if (database && userid) {
					// TODO(longsleep): This needs to be delayed util self has ha userid.
					if (database.ready) {
						_.defer(_.bind(function() {
							if (this.database === database) {
								this.load();
							}
						}, this));
					} else {
						database.e.one("ready", _.bind(function() {
							if (this.database === database) {
								this.load();
							}
						}, this));
					}
				}
			}, this));

		};

		Contacts.prototype.open = function(userid, suserid) {

			if (this.database && (!userid || this.userid !== userid)) {
				// Unload existing contacts.
				this.unload();
				// Close existing database.
				this.database.close();
				this.database = null;
			}
			if (userid) {
				if (!Modernizr.indexeddb) {
					return;
				}
				// Create secure key for hashing and encryption.
				this.key = sjcl.codec.base64.fromBits(sjcl.hash.sha256.hash(suserid+mediaStream.config.Token));
				// Create database name for user which.
				var id = "mediastream-" + this.id(userid);
				console.log("Open of database:", id);
				var database = this.database = new Database(id);
				return database;
			} else {
				this.database = null;
				return null;
			}

		};

		Contacts.prototype.id = function(userid) {

			var hmac = new sjcl.misc.hmac(this.key);
			return sjcl.codec.base64.fromBits(hmac.encrypt(userid));

		};

		Contacts.prototype.encrypt = function(data) {

			return sjcl.encrypt(this.key, JSON.stringify(data));

		};

		Contacts.prototype.decrypt = function(data) {

			var result;
			try {
				var s = sjcl.decrypt(this.key, data);
				result = JSON.parse(s);
			} catch(err) {
				console.error("Failed to decrypt contact data", err);
			}
			return result;

		};

		Contacts.prototype.load = function() {
			if (this.database) {
				console.log("Load contacts from storage", this);
				var remove = [];
				this.database.all("contacts", _.bind(function(data) {
					var d = this.decrypt(data.contact);
					if (d) {
						var contact = contactData.addByData(d);
						// TODO(longsleep): Convert buddyImage string to Blob.
						this.e.triggerHandler("contactadded", d);
					} else {
						// Remove empty or invalid entries automatically.
						remove.push(data.id);
					}
				}, this));
				// Remove marked entries.
				if (remove.length) {
					_.each(remove, _.bind(function(id) {
						this.database.delete("contacts", id);
					}, this));
				}
			}
		};

		Contacts.prototype.unload = function() {
			contactData.clear(_.bind(function(contact) {
				this.e.triggerHandler("contactremoved", contact);
			}, this));
		};

		Contacts.prototype.add = function(request, status) {
			var contact = contactData.addByRequest(request, status);
			this.e.triggerHandler("contactadded", contact);
			if (this.database) {
				this.database.put("contacts", {
					id: this.id(contact.Userid),
					contact: this.encrypt(contact)
				})
			}
		};

		Contacts.prototype.remove = function(userid) {
			var contact = contactData.get(userid);
			console.log("contacts remove", userid, contact);
			if (contact) {
				contactData.remove(userid);
				if (this.database) {
					this.database.delete("contacts", this.id(userid));
				}
				this.e.triggerHandler("contactremoved", contact);
			}
		};

		return new Contacts();

	}];

});
<commit_msg>Cleanups.<commit_after>/*
 * Spreed WebRTC.
 * Copyright (C) 2013-2014 struktur AG
 *
 * This file is part of Spreed WebRTC.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
define(['underscore', 'jquery', 'modernizr', 'sjcl'], function(underscore, $, Modernizr, sjcl) {

	var Database = function(name) {
		this.version = 3;
		this.ready = false;
		this.db = null;
		this.name = name;
		this.e = $({});
		var request = indexedDB.open(this.name, this.version);
		var that = this;
		request.onupgradeneeded = function(event) {
			var db = event.target.result;
			var transaction = event.target.transaction;
			transaction.onerror = _.bind(that.onerror, that);
			that.init(db);
			console.log("Created contacts database.")
		};
		request.onsuccess = _.bind(that.onsuccess, that);
	};
	Database.prototype.init = function(db) {
		var createOrUpdateStore = function(name, obj) {
			if (db.objectStoreNames.contains(name)) {
				// TODO(longsleep): Migrate data.
				db.deleteObjectStore(name);
			}
			db.createObjectStore(name, obj);
		}
		// Create our object stores.
		createOrUpdateStore("contacts", {
			// We use id field as our unique identifier.
			keyPath: "id"
		});
	};
	Database.prototype.onerror = function(event) {
		console.log("IndexDB database error", event);
	};
	Database.prototype.onsuccess = function(event) {
		this.db = event.target.result;
		this.ready = true;
		console.log("Openend database", this.db);
		this.e.triggerHandler("ready");
	};
	Database.prototype.put = function(storename, data, successCallback, errorCallback) {
		var transaction = this.db.transaction(storename, "readwrite");
		var store = transaction.objectStore(storename);
		var request = store.put(data);
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = request.onerror = errorCallback;
		if (successCallback) {
			request.onsuccess = successCallback;
		}
		return request;
	};
	Database.prototype.delete = function(storename, id, successCallback, errorCallback) {
		var transaction = this.db.transaction(storename, "readwrite");
		var store = transaction.objectStore(storename);
		var request = store.delete(id);
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = request.onerror = errorCallback;
		if (successCallback) {
			request.onsuccess = successCallback;
		}
		return request;
	};
	Database.prototype.all = function(storename, iteratorCallback, errorCallback) {
		var transaction = this.db.transaction(storename);
		var store = transaction.objectStore(storename);
		var keyRange = IDBKeyRange.lowerBound(0);
		var cursorRequest = store.openCursor(keyRange);
		cursorRequest.onsuccess = function(event) {
			var result = event.target.result;
			if (!result) {
				return;
			}
			//console.log("read data idb", result, event);
			iteratorCallback(result.value);
			result.continue();
		};
		if (!errorCallback) {
			errorCallback = _.bind(this.onerror, this);
		}
		transaction.onerror = cursorRequest.onerror = errorCallback;
		return cursorRequest;
	};
	Database.prototype.close = function() {
		// TODO(longsleep): Database close.
		this.e.off();
		if (this.db) {
			this.db.close();
			this.db = null;
			this.ready = false;
		}
		_.defer(_.bind(function() {
			this.e.triggerHandler("closed");
		}, this));
	};

	// contacts
	return ["appData", "contactData", "mediaStream", function(appData, contactData, mediaStream) {

		var Contacts = function() {

			this.e = $({});
			this.userid = null;
			this.key = null;
			this.database = null;

			appData.e.on("authenticationChanged", _.bind(function(event, userid, suserid) {
				// TODO(longsleep): Avoid creating empty databases. Create db on store only.
				var database = this.open(userid, suserid);
				if (database && userid) {
					// Load when database is ready and userid is available.
					if (database.ready) {
						_.defer(_.bind(function() {
							if (this.database === database) {
								this.load();
							}
						}, this));
					} else {
						database.e.one("ready", _.bind(function() {
							if (this.database === database) {
								this.load();
							}
						}, this));
					}
				}
			}, this));

		};

		Contacts.prototype.open = function(userid, suserid) {

			if (this.database && (!userid || this.userid !== userid)) {
				// Unload existing contacts.
				this.unload();
				// Close existing database.
				this.database.close();
				this.database = null;
			}
			if (userid) {
				if (!Modernizr.indexeddb) {
					return;
				}
				// Create secure key for hashing and encryption.
				this.key = sjcl.codec.base64.fromBits(sjcl.hash.sha256.hash(suserid+mediaStream.config.Token));
				// Create database name for user which.
				var id = "mediastream-" + this.id(userid);
				console.log("Open of database:", id);
				var database = this.database = new Database(id);
				return database;
			} else {
				this.database = null;
				return null;
			}

		};

		Contacts.prototype.id = function(userid) {

			var hmac = new sjcl.misc.hmac(this.key);
			return sjcl.codec.base64.fromBits(hmac.encrypt(userid));

		};

		Contacts.prototype.encrypt = function(data) {

			return sjcl.encrypt(this.key, JSON.stringify(data));

		};

		Contacts.prototype.decrypt = function(data) {

			var result;
			try {
				var s = sjcl.decrypt(this.key, data);
				result = JSON.parse(s);
			} catch(err) {
				console.error("Failed to decrypt contact data", err);
			}
			return result;

		};

		Contacts.prototype.load = function() {
			if (this.database) {
				console.log("Load contacts from storage", this);
				var remove = [];
				this.database.all("contacts", _.bind(function(data) {
					var d = this.decrypt(data.contact);
					if (d) {
						var contact = contactData.addByData(d);
						// TODO(longsleep): Convert buddyImage string to Blob.
						this.e.triggerHandler("contactadded", d);
					} else {
						// Remove empty or invalid entries automatically.
						remove.push(data.id);
					}
				}, this));
				// Remove marked entries.
				if (remove.length) {
					_.each(remove, _.bind(function(id) {
						this.database.delete("contacts", id);
					}, this));
				}
			}
		};

		Contacts.prototype.unload = function() {
			contactData.clear(_.bind(function(contact) {
				this.e.triggerHandler("contactremoved", contact);
			}, this));
		};

		Contacts.prototype.add = function(request, status) {
			var contact = contactData.addByRequest(request, status);
			this.e.triggerHandler("contactadded", contact);
			if (this.database) {
				this.database.put("contacts", {
					id: this.id(contact.Userid),
					contact: this.encrypt(contact)
				})
			}
		};

		Contacts.prototype.remove = function(userid) {
			var contact = contactData.get(userid);
			console.log("contacts remove", userid, contact);
			if (contact) {
				contactData.remove(userid);
				if (this.database) {
					this.database.delete("contacts", this.id(userid));
				}
				this.e.triggerHandler("contactremoved", contact);
			}
		};

		return new Contacts();

	}];

});
<|endoftext|>


<commit_before>FAN_URL="/fan/"
PARACHUTE_URL="/parachute/"
WATERSPLASHER_URL = "/watersplasher/"
EVENT_URL="/events/"
JUMP_STATE_URL="/jumpState/"

do_nothing = function() {}

default_error = function (jqXHR) {
			console.log("ajax error " + jqXHR.status);
			serverDown = true;
}

log = function(msg) {
	time = new Date().timeNow();
	$('#log').prepend('
'+ time + ' - '+ msg + '
');
}

ajax_json = function(uri, method, request_data, is_async, success_callback, error_callback) {
	var request = {
		url: uri,
		type: method,
		contentType: "application/json",
		accepts: "application/json",
		cache: false,
		dataType: 'json',
		async: is_async,
		success: function(data) {
			serverDown = false;
			success_callback(data);
		},
		error: function(jqXHR) {
			default_error(jqXHR);
			error_callback();
		}
	};

	if (request_data != null)
		request.data = JSON.stringify(request_data);

	return $.ajax(request);
}

UiSwitch = function(id, onStateChanged) {
	var self = this;
	self.id = id;
	self.uiSwitch = $(id);

	self.setSwitchState = function(state) {
		self.uiSwitch.bootstrapSwitch('state', state, true);
	}

	self.uiSwitch.bootstrapSwitch('state', false, true);
	self.uiSwitch.on('switchChange.bootstrapSwitch', function(event, state) {
		onStateChanged(event, state);
	});

	return self;
}

VjControlAPI = function() {
	var self = this;

	self.setFanSpeed = function(speed_percentage) {
		eventSocket.emit('unityFanSpeedEvent', speed_percentage);
	}

	self.getFanSpeed = function() {
		ajax_json(FAN_URL, "GET", null, true, do_nothing, do_nothing).done(function(data) { self.setSlider(data.speed); });
	}

	self.getParachuteState = function() {
		ajax_json(PARACHUTE_URL, "GET", null, true, function(data) { parachuteSwitch.setSwitchState(data.parachute); });
	}

	self.getWatersplasherState = function() {
		ajax_json(WATERSPLASHER_URL, "GET", null, true, function(data) { watersplasherSwitch.setSwitchState(data.watersplasher); });
	}

	self.getJumpState = function() {
		ajax_json(JUMP_STATE_URL, "GET", null, true, function(data) { jumpStateSwitch.setSwitchState(data.jumpStarted); });
	}

	return self;
}

FanSlider = function(vjAPI) {
	var self = this;
	self.onChangeCallbackEnabled = true;

	self.initSlider = function () {
		ajax_json(FAN_URL, "GET", null, false, do_nothing, do_nothing).done(function(data) {
			// Initilaize slider with value
			$( "#slider" ).slider({
				value: data.speed,
				step: 10
			});

			// Set speed with slider
			$( "#slider" ).on( "slidechange", function( event, ui ) {
				if (self.onChangeCallbackEnabled)
					vjAPI.setFanSpeed($( "#slider" ).slider( "value" ));
			});
		});
	}

	self.setSlider = function(speed) {
		self.onChangeCallbackEnabled = false;
		$( "#slider" ).slider( "option", "value", speed);
		$("#slider_value").text(speed + "%");
		self.onChangeCallbackEnabled = true;
	}

	self.initSlider();

	return self;
}

EventSocket = function(){
	var ret = io.connect('http://' + document.domain + ':' + location.port + '/events');

	var self = this;
	self.previousFanSpeed = -1;

	ret.on('connect', function(msg) {
		log('[INFO] Socket connected.');
		serverConnectedStateSwitch.setSwitchState(true);
		vjAPI.getFanSpeed();
		vjAPI.getParachuteState();
		vjAPI.getWatersplasherState();
		vjAPI.getJumpState();
	});

	ret.on('disconnect', function(msg) {
		log('[ERROR] Socket disconnected!');
		serverConnectedStateSwitch.setSwitchState(false);
	});

	// Receive fan event from server
	ret.on('raspiFanEvent', function(msg) {
		fanSlider.setSlider(msg);
		if (previousFanSpeed != msg) {
			log('[DEBUG] Set fan slider to ' + msg);
			previousFanSpeed = msg;
		}
	});

	// Watersplasher switched on
	ret.on('raspiWaterSplasherOnEvent', function(msg) {
		log('[DEBUG] Watersplasher: On');
		watersplasherSwitch.setSwitchState(true);
	});

	// Watersplasher switched off
	ret.on('raspiWaterSplasherOffEvent', function(msg) {
		log('[DEBUG] Watersplasher: Off');
		watersplasherSwitch.setSwitchState(false);
	});

	// Parachute opened
	ret.on('raspiParachuteOpenEvent', function(msg) {
		log('[DEBUG] Parachute opened');
		parachuteSwitch.setSwitchState(true);
	});

	// Parachute closed
	ret.on('raspiParachuteCloseEvent', function(msg) {
		log('[DEBUG] Parachute closed');
		parachuteSwitch.setSwitchState(false);
		jumpStateSwitch.setSwitchState(false);
	});

	// Ready to jump
	ret.on('raspiUnityReadyEvent', function(msg) {
		log('[DEBUG] Unity is ready');
		readyStateSwitch.setSwitchState(true);
	});

	// Start jump
	ret.on('raspiJumpStartedEvent', function(msg) {
		log('[DEBUG] Player jumped');
		jumpStateSwitch.setSwitchState(true);
		readyStateSwitch.setSwitchState(false);
		myWatch.reset();
		myWatch.start();
	});

	// Landing
	ret.on('raspiLandingEvent', function(msg) {
		log('[DEBUG] Player landed');
		jumpStateSwitch.setSwitchState(false);

		myWatch.stop();
	});

	return ret;
}

vjAPI = VjControlAPI();
fanSlider = FanSlider(vjAPI);
eventSocket = EventSocket(vjAPI);

readyStateSwitch = new UiSwitch('input#ready-state', function(event, state) {if (state) eventSocket.emit('unityReadyEvent', '[DEBUG] Unity ready!'); else eventSocket.emit('unityResetLevel', '[DEBUG] Reset level');});
jumpStateSwitch = new UiSwitch('input#jump-state', function(event, state) {if (state) eventSocket.emit('unityJumpStartedEvent', '[DEBUG] Start Jump'); else eventSocket.emit('unityLandingEvent', '[DEBUG] Player landed');});
serverConnectedStateSwitch = new UiSwitch('input#server-connection-state', do_nothing);

watersplasherSwitch = new UiSwitch('input#watersplasher-state', function(event, state) {if (state) eventSocket.emit('unityWaterSplasherOnEvent', '[DEBUG] Switch on Watersplasher'); else eventSocket.emit('unityWaterSplasherOffEvent', '[DEBUG] Switch off Watersplasher');});
parachuteSwitch = new UiSwitch('input#parachute-state', function(event, state) {if (state) eventSocket.emit('unityParachuteOpenEvent', '[DEBUG] Open parachute'); else eventSocket.emit('unityResetLevel', '[DEBUG] Reset level');});

updateWatch = function (watch) {
	$('#watchdisplay').text(watch.toString());
	console.log("Updating watch");
};
myWatch = new Stopwatch(updateWatch, 100);

// For the time now
Date.prototype.timeNow = function () {
	return ((this.getHours() < 10)?"0":"") + this.getHours() +":"+ ((this.getMinutes() < 10)?"0":"") + this.getMinutes() +":"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds();
}
<commit_msg>[JS] Removed event sending from switches - was for debug.<commit_after>FAN_URL="/fan/"
PARACHUTE_URL="/parachute/"
WATERSPLASHER_URL = "/watersplasher/"
EVENT_URL="/events/"
JUMP_STATE_URL="/jumpState/"

do_nothing = function() {}

default_error = function (jqXHR) {
			console.log("ajax error " + jqXHR.status);
			serverDown = true;
}

log = function(msg) {
	time = new Date().timeNow();
	$('#log').prepend('
'+ time + ' - '+ msg + '
');
}

ajax_json = function(uri, method, request_data, is_async, success_callback, error_callback) {
	var request = {
		url: uri,
		type: method,
		contentType: "application/json",
		accepts: "application/json",
		cache: false,
		dataType: 'json',
		async: is_async,
		success: function(data) {
			serverDown = false;
			success_callback(data);
		},
		error: function(jqXHR) {
			default_error(jqXHR);
			error_callback();
		}
	};

	if (request_data != null)
		request.data = JSON.stringify(request_data);

	return $.ajax(request);
}

UiSwitch = function(id, onStateChanged) {
	var self = this;
	self.id = id;
	self.uiSwitch = $(id);

	self.setSwitchState = function(state) {
		self.uiSwitch.bootstrapSwitch('state', state, true);
	}

	self.uiSwitch.bootstrapSwitch('state', false, true);
	self.uiSwitch.on('switchChange.bootstrapSwitch', function(event, state) {
		onStateChanged(event, state);
	});

	return self;
}

VjControlAPI = function() {
	var self = this;

	self.setFanSpeed = function(speed_percentage) {
		eventSocket.emit('unityFanSpeedEvent', speed_percentage);
	}

	self.getFanSpeed = function() {
		ajax_json(FAN_URL, "GET", null, true, do_nothing, do_nothing).done(function(data) { self.setSlider(data.speed); });
	}

	self.getParachuteState = function() {
		ajax_json(PARACHUTE_URL, "GET", null, true, function(data) { parachuteSwitch.setSwitchState(data.parachute); });
	}

	self.getWatersplasherState = function() {
		ajax_json(WATERSPLASHER_URL, "GET", null, true, function(data) { watersplasherSwitch.setSwitchState(data.watersplasher); });
	}

	self.getJumpState = function() {
		ajax_json(JUMP_STATE_URL, "GET", null, true, function(data) { jumpStateSwitch.setSwitchState(data.jumpStarted); });
	}

	return self;
}

FanSlider = function(vjAPI) {
	var self = this;
	self.onChangeCallbackEnabled = true;

	self.initSlider = function () {
		ajax_json(FAN_URL, "GET", null, false, do_nothing, do_nothing).done(function(data) {
			// Initilaize slider with value
			$( "#slider" ).slider({
				value: data.speed,
				step: 10
			});

			// Set speed with slider
			$( "#slider" ).on( "slidechange", function( event, ui ) {
				if (self.onChangeCallbackEnabled)
					vjAPI.setFanSpeed($( "#slider" ).slider( "value" ));
			});
		});
	}

	self.setSlider = function(speed) {
		self.onChangeCallbackEnabled = false;
		$( "#slider" ).slider( "option", "value", speed);
		$("#slider_value").text(speed + "%");
		self.onChangeCallbackEnabled = true;
	}

	self.initSlider();

	return self;
}

EventSocket = function(){
	var ret = io.connect('http://' + document.domain + ':' + location.port + '/events');

	var self = this;
	self.previousFanSpeed = -1;

	ret.on('connect', function(msg) {
		log('[INFO] Socket connected.');
		serverConnectedStateSwitch.setSwitchState(true);
		vjAPI.getFanSpeed();
		vjAPI.getParachuteState();
		vjAPI.getWatersplasherState();
		vjAPI.getJumpState();
	});

	ret.on('disconnect', function(msg) {
		log('[ERROR] Socket disconnected!');
		serverConnectedStateSwitch.setSwitchState(false);
	});

	// Receive fan event from server
	ret.on('raspiFanEvent', function(msg) {
		fanSlider.setSlider(msg);
		if (previousFanSpeed != msg) {
			log('[DEBUG] Set fan slider to ' + msg);
			previousFanSpeed = msg;
		}
	});

	// Watersplasher switched on
	ret.on('raspiWaterSplasherOnEvent', function(msg) {
		log('[DEBUG] Watersplasher: On');
		watersplasherSwitch.setSwitchState(true);
	});

	// Watersplasher switched off
	ret.on('raspiWaterSplasherOffEvent', function(msg) {
		log('[DEBUG] Watersplasher: Off');
		watersplasherSwitch.setSwitchState(false);
	});

	// Parachute opened
	ret.on('raspiParachuteOpenEvent', function(msg) {
		log('[DEBUG] Parachute opened');
		parachuteSwitch.setSwitchState(true);
	});

	// Parachute closed
	ret.on('raspiParachuteCloseEvent', function(msg) {
		log('[DEBUG] Parachute closed');
		parachuteSwitch.setSwitchState(false);
		jumpStateSwitch.setSwitchState(false);
	});

	// Ready to jump
	ret.on('raspiUnityReadyEvent', function(msg) {
		log('[DEBUG] Unity is ready');
		readyStateSwitch.setSwitchState(true);
	});

	// Start jump
	ret.on('raspiJumpStartedEvent', function(msg) {
		log('[DEBUG] Player jumped');
		jumpStateSwitch.setSwitchState(true);
		readyStateSwitch.setSwitchState(false);
		myWatch.reset();
		myWatch.start();
	});

	// Landing
	ret.on('raspiLandingEvent', function(msg) {
		log('[DEBUG] Player landed');
		jumpStateSwitch.setSwitchState(false);

		myWatch.stop();
	});

	return ret;
}

vjAPI = VjControlAPI();
fanSlider = FanSlider(vjAPI);
eventSocket = EventSocket(vjAPI);

readyStateSwitch = new UiSwitch('input#ready-state', function(event, state) {if (state) eventSocket.emit('unityReadyEvent', '[DEBUG] Unity ready!'); else eventSocket.emit('unityResetLevel', '[DEBUG] Reset level');});
jumpStateSwitch = new UiSwitch('input#jump-state', do_nothing);
serverConnectedStateSwitch = new UiSwitch('input#server-connection-state', do_nothing);

watersplasherSwitch = new UiSwitch('input#watersplasher-state', do_nothing);
parachuteSwitch = new UiSwitch('input#parachute-state', do_nothing);

updateWatch = function (watch) {
	$('#watchdisplay').text(watch.toString());
	console.log("Updating watch");
};
myWatch = new Stopwatch(updateWatch, 100);

// For the time now
Date.prototype.timeNow = function () {
	return ((this.getHours() < 10)?"0":"") + this.getHours() +":"+ ((this.getMinutes() < 10)?"0":"") + this.getMinutes() +":"+ ((this.getSeconds() < 10)?"0":"") + this.getSeconds();
}
<|endoftext|>


<commit_before>'use strict';

// Libraries
import React, {PropTypes} from 'react';

// Components
import CoverImage from '../CoverImage/CoverImageContainer.component';
import OrderButton from '../Order/OrderButton/OrderButton.component';
import LikeContainer from '../LikeDislike/LikeContainer.component.js';
import DislikeContainer from '../LikeDislike/DislikeContainer.component.js';
import WorkRecommendation from './WorkRecommendation.component';

// Actions
import RecommendationActions from '../../actions/Recommendations.actions.js';

// Stores
import ProfileStore from '../../stores/Profile.store';
import RecommendationsStore from '../../stores/Recommendations.store.js';

export default class WorkLayout extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      profile: ProfileStore.getState(),
      recommendations: RecommendationsStore.getInitialState()
    };

    this.unsubscribe = [
      ProfileStore.listen(() => {
        this.setState({
          profile: ProfileStore.getState()
        });

        this.getRecommendationState();
      }),

      RecommendationsStore.listen(() => this.setState({
        recommendations: RecommendationsStore.store
      }))
    ];
  }

  componentDidMount() {
    this.getRecommendationState();
  }

  componentWillUnmount() {
    this.unsubscribe.forEach(
      (unsubscriber) => {
        unsubscriber();
      }
    );
  }

  getRecommendationState() {
    const likes = this.state.profile.profile.likes;
    RecommendationActions.getRecommendations({
      work: this.props.id,
      likes: likes.map((like) => {
        return like.item_id;
      }),
      dislikes: []
    });
  }

  getLikeDislikeContainers(id) {
    return (

          <LikeContainer objectId={id} />

          <DislikeContainer objectId={id} />

    );
  }

  render() {
    const profile = this.state.profile;
    // Fake profile to look like old one until refactor!
    // TODO: REFACTOR!
    let orderButtonComponent = '';
    if (profile.userIsLoggedIn && profile.profile.agencyid) {
      const orderProfile = {
        userIsLoggedIn: profile.userIsLoggedIn,
        favoriteLibraries: [{
          libraryID: profile.profile.agencyid,
          agencyID: profile.pickup_agency ? profile.pickup_agency : profile.profile.agencyid,
          borrowerID: typeof window !== 'undefined' && window.BORROWER_ID ? window.BORROWER_ID : ''
        }]
      };

      orderButtonComponent = (
        <OrderButton
          favoriteLibraries={orderProfile.favoriteLibraries}
          manifestations={this.props.specifics}
          profile={orderProfile}
          relations={this.props.work.result.relations}
        />
      );
    }

    const personalRecommendations = profile.userIsLoggedIn ? (
      <WorkRecommendation
        recommendations={this.state.recommendations.recommendations.personal}
        type='personal' />
    ) : '';

    const genericRecommendations = (
      <WorkRecommendation
        recommendations={this.state.recommendations.recommendations.generic}
        type='generic' />
    );

    const likeContainers = profile.userIsLoggedIn ? this.getLikeDislikeContainers(this.props.id) : ' ';

    return (

            <CoverImage noCoverUrl='/covers/no-cover-image-book.png' pids={[this.props.id, this.props.work.result.pid]} prefSize='detail_500' />

            {orderButtonComponent}

            {likeContainers}

{this.props.work.result.title}

                  {this.props.work.result.creator}

{this.props.work.result.abstract}

                {this.props.work.result.isbns.length > 0 ? 'ISBN: ' + this.props.work.result.isbns[0] : ''}

{this.props.work.result.extent}

                  {this.props.work.result.actors.length > 0 ? 'Medvirkende: ' : ''}
                  {this.props.work.result.actors.map((actor, index) => {
                    return (

                          {actor}

                      );
                  })}

                {this.props.work.result.series}

                {this.props.work.result.subjects.length > 0 ? 'Emner: ' : ''}
                {this.props.work.result.subjects.map((subject, index, array) => {
                  const notLast = (array.length - 1) !== index;
                  return (

                       {notLast ? subject + ', ' : subject}

                  );
                })}

                {this.props.work.result.dk5s.length > 0 ? 'Opstilling: ' : ''}
                {this.props.work.result.dk5s.map((dk5, index) => {
                  return (

                      {dk5.text}

                  );
                })}

{this.props.work.result.audience.age.join(', ')}

{this.props.work.result.audience.pegi}

{this.props.work.result.audience.medieraad}

                {this.props.work.result.tracks.length > 0 ? 'Trackliste: ' : ''}
                {this.props.work.result.tracks.map((track, index) => {
                  return (

{track}
);
                })}

                {this.props.work.result.languages.length > 0 ? 'Sprog: ' : ''}
                {this.props.work.result.languages.join(', ')}

              {this.props.specifics.map((specific, index) => {
                return (
                  {specific.type} ({specific.dates.join('; ')})
                );
              })}

              {this.props.editions.length > 0 ? 'Udgaver:' : ''}
              {this.props.editions}

Noget der ligner

          {personalRecommendations}
          {genericRecommendations}

    );
  }
}

WorkLayout.displayName = 'WorkLayout';
WorkLayout.propTypes = {
  editions: PropTypes.array,
  id: PropTypes.string,
  specifics: PropTypes.array,
  work: PropTypes.object
};
<commit_msg>Remove workRecommedations component when no recommendations are available<commit_after>'use strict';

// Libraries
import React, {PropTypes} from 'react';
import {isEmpty} from 'lodash';

// Components
import CoverImage from '../CoverImage/CoverImageContainer.component';
import OrderButton from '../Order/OrderButton/OrderButton.component';
import LikeContainer from '../LikeDislike/LikeContainer.component.js';
import DislikeContainer from '../LikeDislike/DislikeContainer.component.js';
import WorkRecommendation from './WorkRecommendation.component';

// Actions
import RecommendationActions from '../../actions/Recommendations.actions.js';

// Stores
import ProfileStore from '../../stores/Profile.store';
import RecommendationsStore from '../../stores/Recommendations.store.js';

export default class WorkLayout extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      profile: ProfileStore.getState(),
      recommendations: RecommendationsStore.getInitialState()
    };

    this.unsubscribe = [
      ProfileStore.listen(() => {
        this.setState({
          profile: ProfileStore.getState()
        });

        this.getRecommendationState();
      }),

      RecommendationsStore.listen(() => this.setState({
        recommendations: RecommendationsStore.store
      }))
    ];
  }

  componentDidMount() {
    this.getRecommendationState();
  }

  componentWillUnmount() {
    this.unsubscribe.forEach(
      (unsubscriber) => {
        unsubscriber();
      }
    );
  }

  getRecommendationState() {
    const likes = this.state.profile.profile.likes;
    RecommendationActions.getRecommendations({
      work: this.props.id,
      likes: likes.map((like) => {
        return like.item_id;
      }),
      dislikes: []
    });
  }

  getLikeDislikeContainers(id) {
    return (

          <LikeContainer objectId={id} />

          <DislikeContainer objectId={id} />

    );
  }

  render() {
    const profile = this.state.profile;
    // Fake profile to look like old one until refactor!
    // TODO: REFACTOR!
    let orderButtonComponent = '';
    if (profile.userIsLoggedIn && profile.profile.agencyid) {
      const orderProfile = {
        userIsLoggedIn: profile.userIsLoggedIn,
        favoriteLibraries: [{
          libraryID: profile.profile.agencyid,
          agencyID: profile.pickup_agency ? profile.pickup_agency : profile.profile.agencyid,
          borrowerID: typeof window !== 'undefined' && window.BORROWER_ID ? window.BORROWER_ID : ''
        }]
      };

      orderButtonComponent = (
        <OrderButton
          favoriteLibraries={orderProfile.favoriteLibraries}
          manifestations={this.props.specifics}
          profile={orderProfile}
          relations={this.props.work.result.relations}
        />
      );
    }

    let workRecommendations = null;

    if (!isEmpty(this.state.recommendations.recommendations.personal) || !isEmpty(this.state.recommendations.recommendations.generic)) {

      const personalRecommendations = profile.userIsLoggedIn ? (
        <WorkRecommendation
          recommendations={this.state.recommendations.recommendations.personal}
          type='personal' />
      ) : '';

      const genericRecommendations = (
        <WorkRecommendation
          recommendations={this.state.recommendations.recommendations.generic}
          type='generic' />
      );

      workRecommendations = (

Noget der ligner

          {personalRecommendations}
          {genericRecommendations}

      );
    }

    const likeContainers = profile.userIsLoggedIn ? this.getLikeDislikeContainers(this.props.id) : ' ';

    return (

            <CoverImage noCoverUrl='/covers/no-cover-image-book.png' pids={[this.props.id, this.props.work.result.pid]} prefSize='detail_500' />

            {orderButtonComponent}

            {likeContainers}

{this.props.work.result.title}

                  {this.props.work.result.creator}

{this.props.work.result.abstract}

                {this.props.work.result.isbns.length > 0 ? 'ISBN: ' + this.props.work.result.isbns[0] : ''}

{this.props.work.result.extent}

                  {this.props.work.result.actors.length > 0 ? 'Medvirkende: ' : ''}
                  {this.props.work.result.actors.map((actor, index) => {
                    return (

                          {actor}

                      );
                  })}

                {this.props.work.result.series}

                {this.props.work.result.subjects.length > 0 ? 'Emner: ' : ''}
                {this.props.work.result.subjects.map((subject, index, array) => {
                  const notLast = (array.length - 1) !== index;
                  return (

                       {notLast ? subject + ', ' : subject}

                  );
                })}

                {this.props.work.result.dk5s.length > 0 ? 'Opstilling: ' : ''}
                {this.props.work.result.dk5s.map((dk5, index) => {
                  return (

                      {dk5.text}

                  );
                })}

{this.props.work.result.audience.age.join(', ')}

{this.props.work.result.audience.pegi}

{this.props.work.result.audience.medieraad}

                {this.props.work.result.tracks.length > 0 ? 'Trackliste: ' : ''}
                {this.props.work.result.tracks.map((track, index) => {
                  return (

{track}
);
                })}

                {this.props.work.result.languages.length > 0 ? 'Sprog: ' : ''}
                {this.props.work.result.languages.join(', ')}

              {this.props.specifics.map((specific, index) => {
                return (
                  {specific.type} ({specific.dates.join('; ')})
                );
              })}

              {this.props.editions.length > 0 ? 'Udgaver:' : ''}
              {this.props.editions}

        {workRecommendations}

    );
  }
}

WorkLayout.displayName = 'WorkLayout';
WorkLayout.propTypes = {
  editions: PropTypes.array,
  id: PropTypes.string,
  specifics: PropTypes.array,
  work: PropTypes.object
};
<|endoftext|>


<commit_before>
'use strict';

this.R = (function () {
    var topOfDependencyStack;

    function relLog(stuff) {
        //relLog(stuff);
    }

    function funcIfString(f) {
        if (typeof f === 'string' || f instanceof String)
            f = new Function('return ' + f + ';');
        return f;
    }

    function R(arg1, arg2, getter, setter) {
        if (arg1 instanceof Function)        // enable R(() => o.c = o.a + o.b);
            return R.maintain(arg1, arg2);      // arg1 called in detector, arg 2 as a callback afterward
        else if (getter)
            return R.relative(arg1, arg2, getter, setter);      // arg 1 object, arg2 name of property
        else
            return R.alerter(arg1, arg2);
    };

    R.alerter = function alerter(obj, name) {
        var cachedValue = obj[name];
        var dependents = {};
        Object.defineProperty(obj, name, {
            get: function () {
                if (topOfDependencyStack)
                    dependents[topOfDependencyStack._id] = topOfDependencyStack;
                return cachedValue;
            },
            set: function (value) {
                if (!(cachedValue === value)) {
                    cachedValue = value;
                    for (var d in dependents)
                        dependents[d].invalidate();
                    dependents = {};    // clears every time so abandoned relative values make it to garbage collector
                }
                return cachedValue;

            }
        });
    };

    // uses an id system to prevent the creation of duplicate dependencies
    var relativeIdCounter = 1;
    function getNewId() {
        //return Symbol();
        return relativeIdCounter++;
    }

    // declares a relative value dependent upon alerter values and/or other relative values
    R.relative = function relative(obj, name, getter, setter) {
        getter = funcIfString(getter);
        setter = funcIfString(setter);
        var _id = getNewId();
        var cachedValue;
        if (!setter)
            setter = function (value) {
                throw new Error(name + ' is an unassignable relative value');
            };

        var s = {
            _id: _id,
            inputs: {},
            invalidate: function () {
                if (this.parent && cachedValue)
                    this.parent.invalidate();
                cachedValue = null;
                relLog(name + ' invalidated!');
            }
        };

        Object.defineProperty(obj, name, {
            enumerable: true,
            get: function () {
                if (!cachedValue) {
                    // provide cached value invalidator to values that are called by the getter

                    if (topOfDependencyStack)
                        s.parent = topOfDependencyStack;
                    var priorTop = topOfDependencyStack;
                    topOfDependencyStack = s

                    // retrieve the value
                    cachedValue = { value: getter() };

                    // return parent to top of stack
                    topOfDependencyStack = priorTop;
                }
                return cachedValue.value;
            },
            set: setter
        });

        return s;
    };

    R.bind = function bind(getter, obj, name) {
        getter = funcIfString(getter);
        function setupBinding() {
            R.onValueChange(getter, function () {
                obj[name] = 'asdf o.c = ' + o.c;
                setupBinding();
            });
        }
        setupBinding();
    };

    R.maintain = function maintain(func, tailCallback) {
        var cont = true;
        var out = { cancel: function () { cont = false; } };
        function setupBinding() {
            R.onValueChange(func, function () {
                if (cont) {
                    setupBinding();
                if (tailCallback)
                    tailCallback();
                }
            });
        }
        setupBinding();
        return out;
    };

    /*R.maintain = function maintain(func, tailCallback) {
        var cont = true;
        var out = { cancel: function () { cont = false; } };
        function setupBinding() {
            R.onValueChange(func, function () {
                if (cont) {
                    func();
                    setupBinding();
                }
            });       // testing immediate
            if (tailCallback)
                tailCallback();
        }
        setupBinding();
        return out;
    };*/

    // when the getter value changes, the callback will execute
    R.onValueChange = function onValueChange(getter, callback, immediate) {
        getter = funcIfString(getter);
        var callingBack = false;
        var s = {
            _id: getNewId(),
            inputs: {},
            invalidate: function () {
                relLog('value change triggered!');
                if (!callingBack) {
                    callingBack = true;
                    function func() {
                        callback();
                        callingBack = false;
                    }
                    if (immediate)
                        func();
                    else
                        setTimeout(func);   // todo: remove (seems to not handle multiple calls without)
                }
            }
        };

        if (topOfDependencyStack) {
            topOfDependencyStack.inputs[s._id] = s;
            s.parent = topOfDependencyStack;
        }
        var priorTop = topOfDependencyStack;
        topOfDependencyStack = s

        // trigger getter to establish dependencies
        var g = getter();

        // return parent to top of stack
        topOfDependencyStack = priorTop;

        // provide a cancellation mechanism
        var out = {
            cancel: function () {
                callback = function () { };
            }
        };
        return out;
    }

    return R;
})();

R.selfTest = function() {

    var sequence = [];

    function ensure(message) {
        if (!sequence[0])
            throw Error('Message when none expected: ' + message);
        else {
            var m = sequence.shift();
            if (m != message)
                throw Error('Unexpected message: ' + message + '. Expected message was: ' + m);
        }
    }

    var test = {};
    R(test, 'v1');
    R(test, 'v2');
    R(test, 'v3', () => test.v1 + test.v2);
    test.v1 = 9;
    test.v2 = 8;

    // value change
    sequence = ['v1 evaluated: 9'];
    var change = R.onValueChange(function() {
        ensure('v1 evaluated: ' + test.v1);
    }, function() {
        ensure('v1 callback triggered: ' + test.v1);
    });
    sequence = ['v3 get 17'];
    var change2 = R.onValueChange(function() {
        ensure('v3 get ' + test.v3)
    }, function () {
        ensure('v3 cb ' + test.v3);
    });
    sequence = ['v1 callback triggered: 10', 'v3 cb 18'];
    test.v1 = 10;
    test.v1 = 11;
    change.cancel();
    change2.cancel();

    // maintain
    sequence = ['v1 evaluated: 11', 'v1 callback triggered: 11'];
    var maint = R(function() {
        ensure('v1 evaluated: ' + test.v1);
    }, function() {
        ensure('v1 callback triggered: ' + test.v1);
    });
    sequence = ['v1 evaluated: 8', 'v1 callback triggered: 8'];
    test.v1 = 8;
    sequence = ['v1 evaluated: 7', 'v1 callback triggered: 7'];
    test.v1 = 7;

    sequence = ['v3 get 15', 'v1 evaluated: 6', 'v1 callback triggered: 6', 'v3 cb 14'];
    var maint2 = R(() => ensure('v3 get ' + test.v3), () => ensure('v3 cb ' + test.v3));
    test.v1 = 6;
    maint.cancel();
    maint2.cancel();

};

R.selfTest();
<commit_msg>Delete relativity.js<commit_after><|endoftext|>


<commit_before>/* renderTmpl
 * version 0.1
 * http://github.com/stevenmtwhunt/rendertmpl */

(function(global, jQuery, undefined) {

	var _tmplCount = 0;
	var _renderTmplTypes = new Array();

	//used to handle xml http requests.
	var xhr = function(url, callback) {

	  	var http_request = false;
		if (window.XMLHttpRequest) { // Mozilla, Safari,...
	       http_request = new XMLHttpRequest();
	       if (http_request.overrideMimeType)
	           http_request.overrideMimeType('text/xml');
	   }
	   else if (window.ActiveXObject) { // IE
	       try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); }
		   catch(e) {
		       try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); }
			   catch (e) { }
	       }
	   }

	   if (!http_request)
	       return false;

	   http_request.onreadystatechange = function() {
	       if (http_request.readyState == 4) {
	           if (http_request.status == 200)
					callback(http_request.responseText);
			   else return http_request.status + ')';
	       }
	   };

	   http_request.open('GET', url, true);
	   http_request.send(null);

	};

	//used to render templates based on name and data.
	var renderTmpl = function(tmpl, data) {
		var render = onRender(_renderTmplTypes[tmpl]);
		return render(tmpl, data);
	};

	//loads templates from associated files.
	var load = function() {

		var todo = new Array();
		var rels = new Array();

		//get all link tags.
		var links = document.getElementsByTagName('link');

		for (var i = 0; i < links.length; i++) {

			//find the ones that are templates.
			var rel = ""+links[i].rel;
			rel = rel.substr(0, rel.indexOf('/')+1);

			if (rel === 'template/') {

				//increment template count; used to determine when to call ready().
				_tmplCount++;
				todo.push(links[i]);

				//get the template type from REL and push it to a list.
				rel = ""+links[i].rel;
				rel = rel.substr(rel.lastIndexOf('/')+1);
				rels.push(rel);
			}
		}

		//closure function that handles callback from ajax file load.
		var handleLoadFile = function(file, rel) {
			return function(data) {

				var name = file.substring(file.lastIndexOf("/")+1, file.indexOf('.', file.lastIndexOf("/")+1));

				//build array that remembers which type the template is.
				_renderTmplTypes[name] = rel;

				//register template by name.
				var reg = onRegister(rel);
				reg(name, data);

				//subtract counter.
				if (--_tmplCount == 0) {
					_tmplCount = -1;
					ready();
				}
			}
		}

		for (var i = 0; i < todo.length; i++) {
			var file = todo[i].href;

			//get the contents of the linked file.
			xhr(file, handleLoadFile(file, rels[i]));
		}
	};

	//manages lambdas to call when templates are ready.
	var _renderTmplReady = new Array();
	var ready = function(lambda) {
		if (lambda === undefined) {
			for (var i = 0; i < _renderTmplReady.length; i++) {
				var fn = _renderTmplReady[i];
				fn();
			}
		}
		else
			_renderTmplReady.push(lambda);
	};

	//generic lambda handler
	var lambdaHandler = function(arr, name, lambda) {

		//if the name provided is already in the array...
		if (name in arr) {
			//if no lambda is provided, return the lambda in the array.
			if (lambda === undefined)
				return arr[name];
			//if the value provided is null, remove the item from the array.
			else if (lambda == null) {
				delete arr[name];
				return;
			}
		}
		//if the name is undefined, then return the entire array.
		else if (name === undefined)
			return arr;
		//if the name is not in the array, and the lambda is not valid, return.
		else if (lambda === undefined || typeof lambda != 'function')
			return NULL;

		//if the name is not in the array, or the name is in the array but none of the other conditions matched, add/update the value.
		arr[name] = lambda;
	};

	//on render lambda handler.
	var _renderTmplOnRender = new Array();
	var onRender = function(name, lambda) {
		return lambdaHandler(_renderTmplOnRender, name, lambda);
	};

	//on register lambda handler.
	var _renderTmplOnRegister = new Array();
	var onRegister = function(name, lambda) {
		return lambdaHandler(_renderTmplOnRegister, name, lambda);
	};

	var engines = {
		jsrender: function(name) {
			//use default name if no name is given.
			var alias = (name === undefined ? "x-jsrender" : name);

			onRender(alias, function(tmpl, data) {
				return $.templates[tmpl].render(data);
			});

			onRegister(alias, function(tmpl, data) {
				return $.templates(tmpl, data);
			});
		}
	};

	//register jQuery extensions.
	var lib = jQuery;
	lib.renderTmpl = renderTmpl;
	lib.renderTmpl.load = load;
	lib.renderTmpl.ready = ready;
	lib.renderTmpl.onRender = onRender;
	lib.renderTmpl.onRegister = onRegister;
	lib.renderTmpl.engines = engines;

})(this, this.jQuery);<commit_msg>added additional functionality<commit_after>/* renderTmpl
 * version 0.1
 * http://github.com/stevenmtwhunt/rendertmpl */

(function(global, jQuery, undefined) {

	var _tmplCount = 0;
	var _renderTmplTypes = new Array();

	//used to handle xml http requests.
	var xhr = function(url, callback) {

	  	var http_request = false;
		if (window.XMLHttpRequest) { // Mozilla, Safari,...
	       http_request = new XMLHttpRequest();
	       if (http_request.overrideMimeType)
	           http_request.overrideMimeType('text/xml');
	   }
	   else if (window.ActiveXObject) { // IE
	       try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); }
		   catch(e) {
		       try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); }
			   catch (e) { }
	       }
	   }

	   if (!http_request)
	       return false;

	   http_request.onreadystatechange = function() {
	       if (http_request.readyState == 4) {
	           if (http_request.status == 200)
					callback(http_request.responseText);
			   else return http_request.status;
	       }
	   };

	   http_request.open('GET', url, true);
	   http_request.send(null);

	};

	//used to render templates based on name and data.
	var renderTmpl = function(tmpl, data) {
		var render = onRender(_renderTmplTypes[tmpl]);
		return render(tmpl, data);
	};

	var _renderTmplLoaded = false;

	//loads templates from associated files.
	var load = function() {

		//only load once per request.
		if (_renderTmplLoaded)
			return;

		_renderTmplLoaded = true;

		//register all configured engines.
		for (var key in engines) {
			if (key != 'register') {
				engines[key]();
			}
		}

		var todo = new Array();
		var rels = new Array();

		//get all link tags.
		var links = document.getElementsByTagName('link');

		for (var i = 0; i < links.length; i++) {

			//find the ones that are templates.
			var rel = ""+links[i].rel;
			rel = rel.substr(0, rel.indexOf('/')+1);

			if (rel === 'template/') {

				//increment template count; used to determine when to call ready().
				_tmplCount++;
				todo.push(links[i]);

				//get the template type from REL and push it to a list.
				rel = ""+links[i].rel;
				rel = rel.substr(rel.lastIndexOf('/')+1);
				rels.push(rel);
			}
		}

		//closure function that handles callback from ajax file load.
		var handleLoadFile = function(file, rel) {
			return function(data) {

				var name = file.substring(file.lastIndexOf("/")+1, file.indexOf('.', file.lastIndexOf("/")+1));

				//build array that remembers which type the template is.
				_renderTmplTypes[name] = rel;

				//register template by name.
				var reg = onRegister(rel);
				reg(name, data);

				//subtract counter.
				if (--_tmplCount == 0) {
					_tmplCount = -1;
					ready();
				}
			}
		}

		for (var i = 0; i < todo.length; i++) {
			var file = todo[i].href;

			//get the contents of the linked file.
			xhr(file, handleLoadFile(file, rels[i]));
		}
	};

	var reload = function() {

		if (_renderTmplLoaded) {
			for (var i = 0; i < _renderTmplOnReset.length; i++) {
				var reset = _renderTmplOnReset[i];
				reset();
			}
			_renderTmplLoaded = false;
		}

		load();
	}

	//resets the templates.
	var reset = function() {

		for (var i = 0; i < _renderTmplOnReset.length; i++) {
			var reset = _renderTmplOnReset[i];
			reset();
		}

		_renderTmplOnRender = new Array();
		_renderTmplOnRegister = new Array();
		_renderTmplOnReset = new Array();
	}

	//manages lambdas to call when templates are ready.
	var _renderTmplReady = new Array();
	var ready = function(lambda) {
		if (lambda === undefined) {
			for (var i = 0; i < _renderTmplReady.length; i++) {
				var fn = _renderTmplReady[i];
				fn();
			}
		}
		else
			_renderTmplReady.push(lambda);
	};

	//generic lambda handler
	var lambdaHandler = function(arr, name, lambda) {

		//if the name provided is already in the array...
		if (name in arr) {
			//if no lambda is provided, return the lambda in the array.
			if (lambda === undefined)
				return arr[name];
			//if the value provided is null, remove the item from the array.
			else if (lambda == null) {
				delete arr[name];
				return;
			}
		}
		//if the name is undefined, then return the entire array.
		else if (name === undefined)
			return arr;
		//if the name is not in the array, and the lambda is not valid, return.
		else if (lambda === undefined || typeof lambda != 'function')
			return NULL;

		//if the name is not in the array, or the name is in the array but none of the other conditions matched, add/update the value.
		arr[name] = lambda;
	};

	//on render lambda handler.
	var _renderTmplOnRender = new Array();
	var onRender = function(name, lambda) {
		return lambdaHandler(_renderTmplOnRender, name, lambda);
	};

	//on register lambda handler.
	var _renderTmplOnRegister = new Array();
	var onRegister = function(name, lambda) {
		return lambdaHandler(_renderTmplOnRegister, name, lambda);
	};

	//on reset lambda handler.
	var _renderTmplOnReset = new Array();
	var onReset = function(name, lambda) {
		return lambdaHandler(_renderTmplOnReset, name, lambda);
	};

	var engines = {

		jsrender: function(name) {
			//use default name if no name is given.
			var alias = (name === undefined ? "x-jsrender" : name);

			onRender(alias, function(tmpl, data) {
				return $.templates[tmpl].render(data);
			});

			onRegister(alias, function(tmpl, data) {
				return $.templates(tmpl, data);
			});

			onReset(alias, function() {
				$.templates = {};
			});
		},

		register: function(name, callbacks) {
			onRender(name, callbacks.render);
			onRegister(name, callbacks.register);
			onReset(name, callbacks.reset);
		}
	};

	//register jQuery extensions.
	var lib = jQuery;
	lib.renderTmpl = renderTmpl;
	lib.renderTmpl.reset = reset;
	lib.renderTmpl.reload = reload;
	lib.renderTmpl.ready = ready;
	lib.renderTmpl.engines = engines;

	$(window).load(function() {
		if (_renderTmplLoaded === false)
			load();
	});

})(this, this.jQuery);<|endoftext|>


<commit_before>
var masterEntities = {};

function handleEntities(entitiesList) {
    cleanToolTips();
      for (var i in entitiesList) {
          var entity = entitiesList[i];
          if (entity.hasId()) {
              var idString = '' + entity.getId();
              if (masterEntities[idString] == undefined) {
                  if (entity.hasDelete() && entity.getDelete()) {
                      // do not add new entity that is marked as delete
                  }
                  else {
            masterEntities[idString] = entity;
            copyMapsIntoUpdateablePosition(entity)
                  }
              }
              else {
                  if (entity.hasDelete() && entity.getDelete()) {
                      delete masterEntities[idString];
                  }
                  else {
                      var masterEntity = masterEntities[idString];
                      updateMasterEntity(masterEntity, entity);
                  }
              }
          }
          else {
              console.log('-----ERROR----- no entity ID on entity');
          }
      }
      renderState(gameboard_ctx, gameboard_canvas, masterEntities, gameScaleFactor, 0, 0, shapePositionMapForContext["game"]);
      // disable zoom box for now
      //drawZoomBox(gameboard_ctx, gameboard_canvas, zoomBoxOriginX, zoomBoxOriginY, zoomFactor);
      //renderState(gameboard_zoom_ctx, gameboard_zoom_canvas, masterEntities, zoomFactor, zoomBoxOriginX, zoomBoxOriginY, shapePositionMapForContext["zoom"]);
}

function renderState(ctx, canvas, entities, zoom_factor, xOffset, yOffset, shapePositionMap) {
    clearGameBoard(ctx, canvas);
    for (var i in entities) {
        var entity = entities[i];
        if (entity != undefined) {
            if (entity.hasPos()) {
                var pos = entity.getPos();
                if (pos.hasX() && pos.hasY()) {
                    var x = pos.getX();
                    var y = pos.getY();
                    layoutEntityAtPosition(Number(i), ctx, x , y , entity, zoom_factor, xOffset, yOffset, shapePositionMap);
                }
            }
        }
    }
    var si = {};
    si.x = 100;
    si.y = 200;
    si.radius = 50;
    var shape = {};
    shape.
    renderCircle(si, shape);
}

function layoutEntityAtPosition(entityIndex, ctx, x, y, entity, zoom_factor, xOffset, yOffset, shapePositionMap) {
    var entityX = zoom(x - xOffset);
    var entityY = zoom(y - yOffset);
    var shapesList = entity.getShapesList();
    for (var j in shapesList) {
        var shape = shapesList[j];
        var shapeInfo = {}; // so we remember what this is
        var si = shapeInfo;
        //
        si.entity = entity;
        si.shapePositionMap = shapePositionMap;
        si.ctx = ctx;
        si.entityIndex = entityIndex;
        si.entityX = entityX;
        si.entityY = entityY;
        si.zoom_factor = zoom_factor;
        si.shapeId = getShapeId(entity, shape);
        setRelativePosition(si, shape);
        setAbsolutePosition(si);
        si.rotation_in_radians = shape.getRotation();
        setHitPointsInfo(si, entity);

        //console.log('entity had hp ' + hitPoints);
        if (shape.hasRect()) {
            renderRectangle(si, shape);
            si.tooltipX = si.x - si.width/2 - 10;
            si.tooltipY = si.y - si.height/2 - 10;
        }
        else if (shape.hasTriangle()) {
            renderTriangle(si, shape);
            si.tooltipX = si.x - (si.baseLen + 6)/2 - 10;
            si.tooltipY = si.y - (si.baseLen + 6)/2 - 10;
        }
        else if (shape.hasKite()) {
            renderKite(si, shape);
            si.tooltipX = si.x - (si.baseLen + 6)/2 - 10;
            si.tooltipY = si.y - (si.baseLen + 6)/2 - 10;
        }
        else if (shape.hasCircle()) {
            renderCircle(si, shape);
            si.tooltipX = si.x - (si.radius + 6)/2 - 10;
            si.tooltipY = si.y - (si.radius + 6)/2 - 10;
        }
        else if (shape.hasOctagon()) {
            renderOctagon(si, shape);
            si.tooltipX = si.x - 10;
            si.tooltipY = si.y - (getOctagonHeight(si) + 6)/2 - 10;
        }
        createToolTips(si);
    }
}

function renderCircle(si, shape) {
    var circ = shape.getCircle();
    si.radius = zoom(40);
    if (circ.hasRadius()) {
      si.radius = zoom(rect.getRadius());
    }

    var shapePoints = getShapePoints(si.x,si.y,si.radius + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawCircle(si);
}

function renderRectangle(si, shape) {
    var rect = shape.getRect();
    si.width = zoom(40);
    si.height = zoom(30);
    if (rect.hasWidth()) {
      si.width = zoom(rect.getWidth());
    }
    if (rect.hasHeight()) {
      si.height = zoom(rect.getHeight());
    }
    var shapePoints = getShapePoints(si.x,si.y,Math.max(si.width, si.height ) + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawRect(si);
}

function renderOctagon(si, shape) {
    var oct = shape.getOctagon();
    si.edgeTop = zoom(40);
    si.edgeCorner = zoom(40);
    si.edgeLeft = zoom(40);
    if (oct.hasEdgeTop()) {
      si.edgeTop = zoom(oct.getEdgeTop());
    }
    if (oct.hasEdgeLeft()) {
      si.edgeLeft = zoom(oct.getEdgeLeft());
    }
    if (oct.hasEdgeCorner()) {
      si.edgeCorner = zoom(oct.getEdgeCorner());
    }
    var shapePoints = getShapePoints(si.x,si.y,Math.max(getOctagonHeight(si), getOctagonWidth(si)) + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawOctagon(si);
}

function renderTriangle(shapeInfo, shape) {
    var si = shapeInfo;
    var triangle = shape.getTriangle();
    si.baseLen = zoom(triangle.getBaseLen());
    var shapePoints = getShapePoints(si.x,si.y,si.baseLen + 6, si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    //drawTriangle(ctx, x, y, baseLen, orientation, colorRGBA);
    drawTriangle(si);
}

function renderKite(shapeInfo, shape) {
    var si = shapeInfo;
    var kite = shape.getKite();
    si.length = zoom(kite.getLength());
    si.width = zoom(kite.getWidth());
    var shapePoints = getShapePoints(si.x,si.y,Math.max(si.width, si.length), si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawKite(si);
}

function drawCircle(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    ctx.beginPath();
    ctx.arc(0,0,si.radius,0,2*Math.PI);
    ctx.stroke();
    ctx.fill();
    ctx.restore();
}

function drawRect(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var x1 = x - (si.height / 2);
    //if (x1 < 0) {
    //  x1 = 0;
    //}
    var y1 = y - (si.width / 2);
    //if (y1 < 0) {
    //  y1 = 0;
    //}
    var x2 = x + (si.height / 2);
    var y2 = y + (si.width / 2);
    ctx.beginPath();

    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.strokeRect(x1, y1, si.height, si.width);
    ctx.fillStyle = si.colorRGBA;
    //ctx.fillStyle = colorRGBA;
    ctx.fillRect(x1, y1, si.height, si.width);
    ctx.restore();
}

function drawRectWithGradient(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var x1 = x - (si.height / 2);
    //if (x1 < 0) {
    //  x1 = 0;
    //}
    var y1 = y - (si.width / 2);
    //if (y1 < 0) {
    //  y1 = 0;
    //}
    var x2 = x + (si.height / 2);
    var y2 = y + (si.width / 2);

    var gradient = ctx.createLinearGradient(x1, si.y, x2, si.y);
    gradient.addColorStop(0, si.colorRGBA);
    gradient.addColorStop(1, 'white');
    ctx.beginPath();

    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
        ctx.strokeStyle = si.colorRGBA;
    }
    ctx.strokeRect(x1, y1, height, width);
    ctx.fillStyle = gradient;
    //ctx.fillStyle = colorRGBA;
    ctx.fillRect(x1, y1, height, width);
    ctx.restore();
}

function drawTriangle(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var radians = 60 * Math.PI / 180;
    var height = (Math.tan(radians) * si.baseLen) / 2;
    var yTip = y - height / 2;
    var yBottom = y + height / 2;
    var xTip = x;
    var xBottomLeft = x - si.baseLen / 2;
    var xBottomRight = x + si.baseLen / 2;
    ctx.beginPath();
    ctx.moveTo(xTip, yTip);
    ctx.lineTo(xBottomRight, yBottom);
    ctx.lineTo(xBottomLeft, yBottom);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    ctx.fillStyle = si.colorRGBA;
    ctx.fill();
    ctx.restore();
}

function drawKite(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var yTip = y;
    var yBottom = y;
    var xTip = x + si.width / 2;
    var xBottom = x - si.width / 2;
    var xLeftWing = x - si.width / 4;
    var yLeftWing = y - si.length / 3;
    var xRightWing = x - si.width / 4;
    var yRightWing = y + si.length / 3;

    var gradient = ctx.createLinearGradient(xBottom, yBottom, xTip, yTip);
    gradient.addColorStop(0, si.colorRGBA);
    gradient.addColorStop(1, 'white');

    ctx.beginPath();
    ctx.moveTo(xTip, yTip);
    ctx.lineTo(xLeftWing, yLeftWing);
    ctx.lineTo(xBottom, yBottom);
    ctx.lineTo(xRightWing, yRightWing);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    //ctx.fillStyle = colorRGBA;
    ctx.fillStyle = gradient;
    ctx.fill();
    ctx.restore();
}

function drawOctagon(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    var x1 = si.x - si.edgeTop/2;
    var y1 = si.y - getOctagonHeight(si)/2;
    var x2 = si.x + si.edgeTop/2;
    var y2 = y1;

    var x3 = si.x + getOctagonWidth(si)/2;
    var y3 = si.y - si.edgeLeft/2;
    var x4 = x3;
    var y4 = si.y + si.edgeLeft/2;

    var x5 = x2;
    var y5 = si.y + getOctagonHeight(si)/2;
    var x6 = x1;
    var y6 = y5;

    var x7 = si.x - getOctagonWidth(si)/2;
    var y7 = y4;
    var x8 = x7;
    var y8 = y3;

    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.lineTo(x3, y3);
    ctx.lineTo(x4, y4);
    ctx.lineTo(x5, y5);
    ctx.lineTo(x6, y6);
    ctx.lineTo(x7, y7);
    ctx.lineTo(x8, y8);
    ctx.lineTo(x1, y1);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    ctx.fillStyle = si.colorRGBA;
    ctx.fill();
    ctx.restore();
}

<commit_msg>add arrow rendering<commit_after>
var masterEntities = {};

function handleEntities(entitiesList) {
    cleanToolTips();
      for (var i in entitiesList) {
          var entity = entitiesList[i];
          if (entity.hasId()) {
              var idString = '' + entity.getId();
              if (masterEntities[idString] == undefined) {
                  if (entity.hasDelete() && entity.getDelete()) {
                      // do not add new entity that is marked as delete
                  }
                  else {
            masterEntities[idString] = entity;
            copyMapsIntoUpdateablePosition(entity)
                  }
              }
              else {
                  if (entity.hasDelete() && entity.getDelete()) {
                      delete masterEntities[idString];
                  }
                  else {
                      var masterEntity = masterEntities[idString];
                      updateMasterEntity(masterEntity, entity);
                  }
              }
          }
          else {
              console.log('-----ERROR----- no entity ID on entity');
          }
      }
      renderState(gameboard_ctx, gameboard_canvas, masterEntities, gameScaleFactor, 0, 0, shapePositionMapForContext["game"]);
      // disable zoom box for now
      //drawZoomBox(gameboard_ctx, gameboard_canvas, zoomBoxOriginX, zoomBoxOriginY, zoomFactor);
      //renderState(gameboard_zoom_ctx, gameboard_zoom_canvas, masterEntities, zoomFactor, zoomBoxOriginX, zoomBoxOriginY, shapePositionMapForContext["zoom"]);
}

function renderState(ctx, canvas, entities, zoom_factor, xOffset, yOffset, shapePositionMap) {
    clearGameBoard(ctx, canvas);
    for (var i in entities) {
        var entity = entities[i];
        if (entity != undefined) {
            if (entity.hasPos()) {
                var pos = entity.getPos();
                if (pos.hasX() && pos.hasY()) {
                    var x = pos.getX();
                    var y = pos.getY();
                    layoutEntityAtPosition(Number(i), ctx, x , y , entity, zoom_factor, xOffset, yOffset, shapePositionMap);
                }
            }
        }
    }
}

function layoutEntityAtPosition(entityIndex, ctx, x, y, entity, zoom_factor, xOffset, yOffset, shapePositionMap) {
    var entityX = zoom(x - xOffset);
    var entityY = zoom(y - yOffset);
    var shapesList = entity.getShapesList();
    for (var j in shapesList) {
        var shape = shapesList[j];
        var shapeInfo = {}; // so we remember what this is
        var si = shapeInfo;
        //
        si.entity = entity;
        si.shapePositionMap = shapePositionMap;
        si.ctx = ctx;
        si.entityIndex = entityIndex;
        si.entityX = entityX;
        si.entityY = entityY;
        si.zoom_factor = zoom_factor;
        si.shapeId = getShapeId(entity, shape);
        setRelativePosition(si, shape);
        setAbsolutePosition(si);
        si.rotation_in_radians = shape.getRotation();
        setHitPointsInfo(si, entity);

        //console.log('entity had hp ' + hitPoints);
        if (shape.hasRect()) {
            renderRectangle(si, shape);
            si.tooltipX = si.x - si.width/2 - 10;
            si.tooltipY = si.y - si.height/2 - 10;
        }
        else if (shape.hasTriangle()) {
            renderTriangle(si, shape);
            si.tooltipX = si.x - (si.baseLen + 6)/2 - 10;
            si.tooltipY = si.y - (si.baseLen + 6)/2 - 10;
        }
        else if (shape.hasKite()) {
            renderKite(si, shape);
            si.tooltipX = si.x - (si.baseLen + 6)/2 - 10;
            si.tooltipY = si.y - (si.baseLen + 6)/2 - 10;
        }
        else if (shape.hasCircle()) {
            renderCircle(si, shape);
            si.tooltipX = si.x - (si.radius + 6)/2 - 10;
            si.tooltipY = si.y - (si.radius + 6)/2 - 10;
        }
        else if (shape.hasOctagon()) {
            renderOctagon(si, shape);
            si.tooltipX = si.x - 10;
            si.tooltipY = si.y - (getOctagonHeight(si) + 6)/2 - 10;
        }

        else if (shape.hasArrow()) {
            renderArrow(si, shape);
            si.tooltipX = undefined;
            si.tooltipY = undefined;
        }
        if (si.tooltipX != undefined) {
            createToolTips(si);
        }
    }
}

function renderArrow(si, shape) {
    var arrow = shape.getArrow();
    if (!arrow.hasTargetPos()) {
        return;
    }
    var targetPos = arrow.getTargetPos();
    if (!pos.hasX() || !pos.hasY()) {
       return;
    }
    si.targetX = targetPos.getX();
    si.targetY = targetPos.getY();
    si.thickness = 2;
    si.headlength = 6;
    si.headwidth = 2;
    if (arrow.hasThickness()) {
        si.thickness = arrow.getThickness();
    }
    if (arrow.hasHeadLength()) {
        si.headlength = arrow.getHeadLength();
    }
    if (arrow.hasHeadWidth()) {
        si.headwidth = arrow.getHeadWidth();
    }

    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawArrow(si);
}

function renderCircle(si, shape) {
    var circ = shape.getCircle();
    si.radius = zoom(40);
    if (circ.hasRadius()) {
      si.radius = zoom(rect.getRadius());
    }

    var shapePoints = getShapePoints(si.x,si.y,si.radius + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawCircle(si);
}

function renderRectangle(si, shape) {
    var rect = shape.getRect();
    si.width = zoom(40);
    si.height = zoom(30);
    if (rect.hasWidth()) {
      si.width = zoom(rect.getWidth());
    }
    if (rect.hasHeight()) {
      si.height = zoom(rect.getHeight());
    }
    var shapePoints = getShapePoints(si.x,si.y,Math.max(si.width, si.height ) + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawRect(si);
}

function renderOctagon(si, shape) {
    var oct = shape.getOctagon();
    si.edgeTop = zoom(40);
    si.edgeCorner = zoom(40);
    si.edgeLeft = zoom(40);
    if (oct.hasEdgeTop()) {
      si.edgeTop = zoom(oct.getEdgeTop());
    }
    if (oct.hasEdgeLeft()) {
      si.edgeLeft = zoom(oct.getEdgeLeft());
    }
    if (oct.hasEdgeCorner()) {
      si.edgeCorner = zoom(oct.getEdgeCorner());
    }
    var shapePoints = getShapePoints(si.x,si.y,Math.max(getOctagonHeight(si), getOctagonWidth(si)) + 6 , si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawOctagon(si);
}

function renderTriangle(shapeInfo, shape) {
    var si = shapeInfo;
    var triangle = shape.getTriangle();
    si.baseLen = zoom(triangle.getBaseLen());
    var shapePoints = getShapePoints(si.x,si.y,si.baseLen + 6, si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    //drawTriangle(ctx, x, y, baseLen, orientation, colorRGBA);
    drawTriangle(si);
}

function renderKite(shapeInfo, shape) {
    var si = shapeInfo;
    var kite = shape.getKite();
    si.length = zoom(kite.getLength());
    si.width = zoom(kite.getWidth());
    var shapePoints = getShapePoints(si.x,si.y,Math.max(si.width, si.length), si.shapeId) ;
    si.shapePositionMap[si.shapeId] = shapePoints;
    //	highlightShape(ctx,shapeId,shapePositionMap);
    si.colorRGBA = loadShapeColorAsRGBAString(shape);
    drawKite(si);
}

function drawCircle(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    ctx.beginPath();
    ctx.arc(0,0,si.radius,0,2*Math.PI);
    ctx.stroke();
    ctx.fill();
    ctx.restore();
}

function drawRect(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var x1 = x - (si.height / 2);
    //if (x1 < 0) {
    //  x1 = 0;
    //}
    var y1 = y - (si.width / 2);
    //if (y1 < 0) {
    //  y1 = 0;
    //}
    var x2 = x + (si.height / 2);
    var y2 = y + (si.width / 2);
    ctx.beginPath();

    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.strokeRect(x1, y1, si.height, si.width);
    ctx.fillStyle = si.colorRGBA;
    //ctx.fillStyle = colorRGBA;
    ctx.fillRect(x1, y1, si.height, si.width);
    ctx.restore();
}

function drawRectWithGradient(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var x1 = x - (si.height / 2);
    //if (x1 < 0) {
    //  x1 = 0;
    //}
    var y1 = y - (si.width / 2);
    //if (y1 < 0) {
    //  y1 = 0;
    //}
    var x2 = x + (si.height / 2);
    var y2 = y + (si.width / 2);

    var gradient = ctx.createLinearGradient(x1, si.y, x2, si.y);
    gradient.addColorStop(0, si.colorRGBA);
    gradient.addColorStop(1, 'white');
    ctx.beginPath();

    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
        ctx.strokeStyle = si.colorRGBA;
    }
    ctx.strokeRect(x1, y1, height, width);
    ctx.fillStyle = gradient;
    //ctx.fillStyle = colorRGBA;
    ctx.fillRect(x1, y1, height, width);
    ctx.restore();
}

function drawTriangle(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var radians = 60 * Math.PI / 180;
    var height = (Math.tan(radians) * si.baseLen) / 2;
    var yTip = y - height / 2;
    var yBottom = y + height / 2;
    var xTip = x;
    var xBottomLeft = x - si.baseLen / 2;
    var xBottomRight = x + si.baseLen / 2;
    ctx.beginPath();
    ctx.moveTo(xTip, yTip);
    ctx.lineTo(xBottomRight, yBottom);
    ctx.lineTo(xBottomLeft, yBottom);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    ctx.fillStyle = si.colorRGBA;
    ctx.fill();
    ctx.restore();
}

function drawKite(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    x = 0;
    y = 0;
    var yTip = y;
    var yBottom = y;
    var xTip = x + si.width / 2;
    var xBottom = x - si.width / 2;
    var xLeftWing = x - si.width / 4;
    var yLeftWing = y - si.length / 3;
    var xRightWing = x - si.width / 4;
    var yRightWing = y + si.length / 3;

    var gradient = ctx.createLinearGradient(xBottom, yBottom, xTip, yTip);
    gradient.addColorStop(0, si.colorRGBA);
    gradient.addColorStop(1, 'white');

    ctx.beginPath();
    ctx.moveTo(xTip, yTip);
    ctx.lineTo(xLeftWing, yLeftWing);
    ctx.lineTo(xBottom, yBottom);
    ctx.lineTo(xRightWing, yRightWing);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    //ctx.fillStyle = colorRGBA;
    ctx.fillStyle = gradient;
    ctx.fill();
    ctx.restore();
}

function drawOctagon(shapeInfo) {
    var si = shapeInfo;
    var ctx = si.ctx;
    ctx.save();
    ctx.translate(si.x,si.y);
    ctx.rotate(si.rotation_in_radians);
    var x1 = si.x - si.edgeTop/2;
    var y1 = si.y - getOctagonHeight(si)/2;
    var x2 = si.x + si.edgeTop/2;
    var y2 = y1;

    var x3 = si.x + getOctagonWidth(si)/2;
    var y3 = si.y - si.edgeLeft/2;
    var x4 = x3;
    var y4 = si.y + si.edgeLeft/2;

    var x5 = x2;
    var y5 = si.y + getOctagonHeight(si)/2;
    var x6 = x1;
    var y6 = y5;

    var x7 = si.x - getOctagonWidth(si)/2;
    var y7 = y4;
    var x8 = x7;
    var y8 = y3;

    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.lineTo(x3, y3);
    ctx.lineTo(x4, y4);
    ctx.lineTo(x5, y5);
    ctx.lineTo(x6, y6);
    ctx.lineTo(x7, y7);
    ctx.lineTo(x8, y8);
    ctx.lineTo(x1, y1);
    ctx.closePath();

    // the outline
    ctx.lineWidth = shape_outline_width;
    ctx.strokeStyle = shape_outline_color;
    if (use_shape_color_for_outline) {
      ctx.strokeStyle = si.colorRGBA;
    }
    ctx.stroke();

    // the fill color
    ctx.fillStyle = si.colorRGBA;
    ctx.fill();
    ctx.restore();
}

function drawArrow(shapeInfo){
    var si = shapeInfo;
    var fromx = si.x;
    var fromy = si.y;
    var tox = si.targetX;
    var toy = si.targetY;
    //variables to be used when creating the arrow

    var ctx = si.ctx;
    var headlen = si.headlength;

    var angle = Math.atan2(toy-fromy,tox-fromx);
    ctx.save();
    //starting path of the arrow from the start square to the end square and drawing the stroke
    ctx.beginPath();
    ctx.moveTo(fromx, fromy);
    ctx.lineTo(tox, toy);
    ctx.strokeStyle = si.colorRGBA;
    ctx.lineWidth = si.thickness;
    ctx.stroke();

    //starting a new path from the head of the arrow to one of the sides of the point
    ctx.beginPath();
    ctx.moveTo(tox, toy);
    ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));

    //path from the side point of the arrow, to the other side point
    ctx.lineTo(tox-headlen*Math.cos(angle+Math.PI/7),toy-headlen*Math.sin(angle+Math.PI/7));

    //path from the side point back to the tip of the arrow, and then again to the opposite side point
    ctx.lineTo(tox, toy);
    ctx.lineTo(tox-headlen*Math.cos(angle-Math.PI/7),toy-headlen*Math.sin(angle-Math.PI/7));

    //draws the paths created above
    ctx.strokeStyle = si.colorRGBA;
    ctx.lineWidth = si.thickness;
    ctx.stroke();
    ctx.fillStyle = si.colorRGBA;
    ctx.fill();
    ctx.restore();
}<|endoftext|>


<commit_before>var React = require('react');

var MessagesSection = require('./dialog/MessagesSection.react');
var ComposeSection = require('./dialog/ComposeSection.react');

var DialogStore = require('../stores/DialogStore');
var MessageStore = require('../stores/MessageStore');

var getStateFromStore = function() {
  return({
    dialog: DialogStore.getSelectedDialog(),
    messages: MessageStore.getAll()
  });
};

var DialogSection = React.createClass({
  getInitialState: function() {
    return(getStateFromStore());
  },

  componentDidMount: function() {
    DialogStore.addSelectListener(this._onChange);
    MessageStore.addChangeListener(this._onChange);
    MessageStore.addChangeListener(this._scrollToBottom);
  },

  componentWillUnmount: function() {
    MessageStore.removeChangeListener(this._onChange);
    DialogStore.removeSelectListener(this._onChange);
  },

  render: function() {
    return(

        <MessagesSection messages={this.state.messages} ref="MessagesSection"/>
        <ComposeSection dialog={this.state.dialog}/>

    )
  },

  _scrollToBottom: function() {
    var ul = this.refs.MessagesSection.getDOMNode();
    ul.scrollTop = ul.scrollHeight;
  },

  _onChange: function() {
    this.setState(getStateFromStore());
    setTimeout(this._scrollToBottom, 0);
  }
});

module.exports = DialogSection;
<commit_msg>refactor(web): fix warning<commit_after>var React = require('react');

var MessagesSection = require('./dialog/MessagesSection.react');
var ComposeSection = require('./dialog/ComposeSection.react');

var DialogStore = require('../stores/DialogStore');
var MessageStore = require('../stores/MessageStore');

var getStateFromStore = function() {
  return({
    dialog: DialogStore.getSelectedDialog(),
    messages: MessageStore.getAll()
  });
};

var DialogSection = React.createClass({
  getInitialState: function() {
    return(getStateFromStore());
  },

  componentDidMount: function() {
    DialogStore.addSelectListener(this._onChange);
    MessageStore.addChangeListener(this._onChange);
    MessageStore.addChangeListener(this._scrollToBottom);
  },

  componentWillUnmount: function() {
    MessageStore.removeChangeListener(this._onChange);
    DialogStore.removeSelectListener(this._onChange);
  },

  render: function() {
    return(

        <MessagesSection messages={this.state.messages} ref="MessagesSection"/>
        <ComposeSection dialog={this.state.dialog}/>

    )
  },

  _scrollToBottom: function() {
    var ul = this.refs.MessagesSection.getDOMNode();
    ul.scrollTop = ul.scrollHeight;
  },

  _onChange: function() {
    this.setState(getStateFromStore());
    setTimeout(function() { this._scrollToBottom() }, 0);
  }
});

module.exports = DialogSection;
<|endoftext|>


<commit_before>import React from 'react';
import {shallow} from 'enzyme';
import assert from 'assert';

import DisplayManage from '../DisplayManage';

describe('DisplayManage', () => {
  let wrapper;
  let displaySize;
  let imageDatas;
  let widthInput;
  let heightInput;
  beforeEach(() => {
    displaySize = {width: null, height: null};
    imageDatas = [
      {data: 'foo', width: 20, height: 10},
      {data: 'foo', width: 50, height: 30},
      {data: 'foo', width: 30, height: 40},
    ];
    wrapper = shallow(
      <DisplayManage
        updateDisplaySize={(width, height) => {
          displaySize = {width, height};
        }}
        displayedImageDatas={imageDatas}
        display={{width: 10, height: 10}}
      />
    );
    const inputs = wrapper.find('input');
    widthInput = inputs.at(0);
    heightInput = inputs.at(1);
  });
  describe('fitMaxViewLayer', () => {
    it('ボタンを押すと、 imageDatas の中のwidthとheightの最大値を updateDisplaySize に渡して呼び出す', () => {
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="fit-max-view-layer"]').simulate('click');
      assert(displaySize.width === 50 && displaySize.height === 40);
    });
    it('imageDatas が空の場合は、何もしない', () => {
      imageDatas = [];
      wrapper = shallow(
        <DisplayManage
          updateDisplaySize={(width, height) => {
            displaySize = {width, height};
          }}
          displayedImageDatas={imageDatas}
          display={{width: 10, height: 10}}
        />
      );
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="fit-max-view-layer"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
  });
  describe('specifyDisplaySize', () => {
    it('ボタンを押すと、テキストボックスの値を updateDisplaySize に渡して呼び出す', () => {
      widthInput.simulate('change', {currentTarget: {value: '33'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === 33 && displaySize.height === 22);
    });
    it('テキストボックスの値が0以下のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '-33'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
    it('テキストボックスの値が10,000以上のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '33'}});
      heightInput.simulate('change', {currentTarget: {value: '10000'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
    it('テキストボックスの値が数値以外のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '33a'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
  });
  describe('state', () => {
    it('widthString と widthHeight の初期値は、 display を文字列変換した値になる', () => {
      const {width, height} = wrapper.instance().props.display;
      assert(
        String(width) === wrapper.state('widthString') &&
          String(height) === wrapper.state('widthString')
      );
    });
    it('テキストボックスへの onChange によって、 widthString と widthHeight が変化する', () => {
      assert(wrapper.state('widthString') !== '987');
      widthInput.simulate('change', {currentTarget: {value: '987'}});
      assert(wrapper.state('widthString') === '987');
    });
    it('テキストボックスの値が適切でない状態で specifyDisplaySize ボタンを押した場合、 error が true になる', () => {
      assert(wrapper.state('error') === false);
      widthInput.simulate('change', {currentTarget: {value: 'hoge'}});
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(wrapper.state('error') === true);
    });
    it('テキストボックスへの onChange によって、 error が false になる', () => {
      assert(wrapper.state('error') === false);
      widthInput.simulate('change', {currentTarget: {value: 'hoge'}});
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(wrapper.state('error') === true);
      widthInput.simulate('change', {currentTarget: {value: '1'}});
      assert(wrapper.state('error') === false);
    });
  });
});
<commit_msg>境界値をテストするように変えた。<commit_after>import React from 'react';
import {shallow} from 'enzyme';
import assert from 'assert';

import DisplayManage from '../DisplayManage';

describe('DisplayManage', () => {
  let wrapper;
  let displaySize;
  let imageDatas;
  let widthInput;
  let heightInput;
  beforeEach(() => {
    displaySize = {width: null, height: null};
    imageDatas = [
      {data: 'foo', width: 20, height: 10},
      {data: 'foo', width: 50, height: 30},
      {data: 'foo', width: 30, height: 40},
    ];
    wrapper = shallow(
      <DisplayManage
        updateDisplaySize={(width, height) => {
          displaySize = {width, height};
        }}
        displayedImageDatas={imageDatas}
        display={{width: 10, height: 10}}
      />
    );
    const inputs = wrapper.find('input');
    widthInput = inputs.at(0);
    heightInput = inputs.at(1);
  });
  describe('fitMaxViewLayer', () => {
    it('ボタンを押すと、 imageDatas の中のwidthとheightの最大値を updateDisplaySize に渡して呼び出す', () => {
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="fit-max-view-layer"]').simulate('click');
      assert(displaySize.width === 50 && displaySize.height === 40);
    });
    it('imageDatas が空の場合は、何もしない', () => {
      imageDatas = [];
      wrapper = shallow(
        <DisplayManage
          updateDisplaySize={(width, height) => {
            displaySize = {width, height};
          }}
          displayedImageDatas={imageDatas}
          display={{width: 10, height: 10}}
        />
      );
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="fit-max-view-layer"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
  });
  describe('specifyDisplaySize', () => {
    it('ボタンを押すと、テキストボックスの値を updateDisplaySize に渡して呼び出す', () => {
      widthInput.simulate('change', {currentTarget: {value: '33'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === 33 && displaySize.height === 22);
    });
    it('テキストボックスの値が0以下のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '0'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
    it('テキストボックスの値が10,000以上のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '33'}});
      heightInput.simulate('change', {currentTarget: {value: '10000'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
    it('テキストボックスの値が数値以外のときは updateDisplaySize を呼び出さない', () => {
      widthInput.simulate('change', {currentTarget: {value: '33a'}});
      heightInput.simulate('change', {currentTarget: {value: '22'}});
      assert(displaySize.width === null && displaySize.height === null);
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(displaySize.width === null && displaySize.height === null);
    });
  });
  describe('state', () => {
    it('widthString と widthHeight の初期値は、 display を文字列変換した値になる', () => {
      const {width, height} = wrapper.instance().props.display;
      assert(
        String(width) === wrapper.state('widthString') &&
          String(height) === wrapper.state('widthString')
      );
    });
    it('テキストボックスへの onChange によって、 widthString と widthHeight が変化する', () => {
      assert(wrapper.state('widthString') !== '987');
      widthInput.simulate('change', {currentTarget: {value: '987'}});
      assert(wrapper.state('widthString') === '987');
    });
    it('テキストボックスの値が適切でない状態で specifyDisplaySize ボタンを押した場合、 error が true になる', () => {
      assert(wrapper.state('error') === false);
      widthInput.simulate('change', {currentTarget: {value: 'hoge'}});
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(wrapper.state('error') === true);
    });
    it('テキストボックスへの onChange によって、 error が false になる', () => {
      assert(wrapper.state('error') === false);
      widthInput.simulate('change', {currentTarget: {value: 'hoge'}});
      wrapper.find('[data-test="specify-display-size"]').simulate('click');
      assert(wrapper.state('error') === true);
      widthInput.simulate('change', {currentTarget: {value: '1'}});
      assert(wrapper.state('error') === false);
    });
  });
});
<|endoftext|>