<commit_before>var config = {
	isCustomConfiguration:false
};

(function(){

// TOD how can we embed this into the synchronous loading process to fill the config??
	//function _findValidAddressBookItemId(callback){
	//	try{
	//		var pim = Widget.PIM;
	//		var addr = new pim.AddressBookItem();
	//		addr.setAttributeValue("fullName", "*");
	//		Widget.PIM.onAddressBookItemsFound = function(items){
	//			if (items.length>0){
	//				callback(items[0].addressBookItemId);
	//			}
	//		}
	//		pim.findAddressBookItems(addr, 0, 1);
	//		delete pim.onAddressBookItemsFound;
	//	}catch(e){
	//		callback(null);
	//	}
	//}

	var defaults = {
		// summary: This configuration defines the features of the phone.
		// description: It maybe used to determine if a test is viable
		// 		and shall be added or not. E.g. if a phone has a certain hardware
		// 		feature or not, like a clamshell.
		hasAccelerometer:true,
		hasClipboard:false,
		hasClamshell:false,
		hasKeypadLight:false,

		supportsOrientationLandscape:true,
		supportsMultipleEmailAccounts:true,
		supportsDeleteEmailAccounts:true,

		unsupportedApis:[],

		// Some devices/platforms don't support certain features and they normally need to return UNSUPPORTED
		// exception, but to run the correct tests (those testing for the exception) we need to configure
		// the platforms. That is done here.
		// The list below ONLY lists those features that need to be turned off for a certain platform
		// if there is one missing add it, by default the features are all expected to be supported (default value is true).
		supports:{
			// On the first the module (=test file) is given.
			Messaging:{
				moveMessage:true, // moveToFolder()
				editFolder:true, // If createFolder(), moveFolder(), deleteFolder() are NOT supported set this to false.
				multipleEmailAccounts:true
			}
		},

		// Set this to true if the device can open multiple applications.
		// E.g. we can only test Widget.onRestore when the device allows to put the
		// application in the background.
		canDoMultitasking:true,

		validAddressBookItemId:"1",
		validCalendarItemId:"1", // The first contact filled in an H2 really has the ID "1".

		// Various file system settings that will be used for testing, etc.
		// NOTE: Paths must always end with the directorySeparator
		// (just to have less hazzle when just adding a filename in the test).
		fileSystem:{
			directorySeparator:"/",

			// A path where we can read a file from, do directory listing or something alike.
			readablePath:"/virtual/photos/",
			// Specify a file name here for a file that is readable.
			// E.g. for testing methods like getFile().
			readableFile:"/virtual/photos/test-photo/test.txt",
			emptyReadableDirectory:"/virtual/photos/test-photo/testdir",

			// Writeable file or path.
			writeablePath:"/virtual/photos/",
			writeableFile:"/virtual/photos/test-photo/test-write.txt",

			// The root path of the widget, where we can e.g. read out all the
			// files provided with the widget (like audio or video files).
			widgetPath:"",
			playableAudioFiles:{
				inWidget:{
					songWav:"test-audio/wav/music.wav",
					songMp3:"test-audio/mp3/music.mp3",
					loopWav:"test-audio/wav/loop.wav",
					loopMp3:"test-audio/mp3/loop.mp3"
				},
				onDevice:{
					songWav:"/virtual/music/test-audio/wav/music.wav",
					songMp3:"/virtual/music/test-audio/mp3/music.mp3",
					loopWav:"/virtual/music/test-audio/wav/loop.wav",
					loopMp3:"/virtual/music/test-audio/mp3/loop.mp3"
				}
			},
			playableVideoFiles:{
				//viaHttp:"http://...",
				//viaHttps:"https://...",
				//viaRtsp:"rtsp://...",
				//viaFile:"file:///", // ??? shall this be the virtual FS or the real FS (=device specific)???
				avc:{
					inWidget:"test-video/avc/AVC_AAC_48K_30F_QVGA.mp4",
					onDevice:"/virtual/videos/test-video/avc/AVC_AAC_48K_30F_QVGA.mp4"
				},
				h263:{
					inWidget:"test-video/h263/H263_148K_QCIF_15_plus_MP4AAC_22_1.3gp",
					onDevice:"/virtual/videos/test-video/h263/H263_148K_QCIF_15_plus_MP4AAC_22_1.3gp"
				},
				h264:{
					inWidget:"test-video/h264/H264_256K_QVGA_15_plus_AAC_22_2.mp4",
					onDevice:"/virtual/videos/test-video/h264/H264_256K_QVGA_15_plus_AAC_22_2.mp4",
					inWidget1:"test-video/h264/HMC_boa_320_240.MP4",
					onDevice1:"/virtual/videos/test-video/h264/HMC_boa_320_240.MP4"
				},
				mp4:{
					inWidget:"test-video/mp4/MP4V_508K_QVGA_15_plus_MP4AAC_32_2.mp4",
					onDevice:"/virtual/videos/test-video/mp4/MP4V_508K_QVGA_15_plus_MP4AAC_32_2.mp4"
				}
			},
			imageFile:""
		},

		events:{
			invalidRecurrenceTypes:[] // By default all are valid, just list those here that are in the spec but not valid.
		},

		geolocation:{
			supportsAgps:true,
			supportsCellId:true,
			supportsGps:true,
			timeouts:{
				gps:180 * 1000,
				agps:5 * 1000,
				cellId:15 * 1000
			}
		}
	};

	//
	//	Configure your stuff here!!!!!!!!!!!!!!
	//
	var configs = {
		//
		//	Vodafone 360 Devices, H1/M1
		//
		"regexp:^WidgetManager;\\sSAMSUNG-GT-I8320-Vodafone;AppleWebKit.*":function(){
			// Figure out the widget's root directory by making a filesystem
			// function throw an error and reading the "sourceURL" property of this error.
			// It returns the filename for this config.js file.
			var readableFile = "";
			try{
				Widget.Device.getDirectoryFileNames("doesn't exist anyway!");
			}catch(e){
				if (e.sourceURL){
					readableFile = e.sourceURL;
				}
			}
			// Replace multiple trailing slashes, explicitly (just to be sure).
			var widgetPath = readableFile.replace(/\/js\/config\.js$/, "").replace(/\/+$/, "")+"/";

			var ret = {
				canDoMultitasking:false
				// Add the device's configuration, different from the default here!
			};
			return ret;
		},
		//
		//	Vodafone 360 Devices, H2 (I8330), M2 (I6420)
		//
		"regexp:^WidgetManager;\\sSAMSUNG-GT-I\\d{4}-Vodafone;AppleWebKit.*":function(){
			var ret = {
				// AGPS==GPS so set the timeout to the same on the H2
				geolocation:{
					timeouts: {
						agps: defaults.geolocation.timeouts.gps
					}
				},
				events: {
					invalidRecurrenceTypes: ['EVERY_WEEKDAY', 'MONTHLY_ON_DAY']
				},
				supports: {
					Messaging:{
						moveMessage: false,
						editFolder: false,
						multipleEmailAccounts: false
					}
				}
			};
			return ret;
		},
		//
		//	Opera Widget Runtime for Vodafone for Android
		//
		"regexp:^WidgetManager;.*\\(Android.*Opera.*Widgets.*":function(){
			var ret = {
				unsupportedApis:[
					"Widget.RadioInfo.radioSignalSource",
					"Widget.RadioInfo.radioSignalStrengthPercent",
					"Widget.RadioInfo.onSignalSourceChange",
					"Widget.DataNetworkInfo.onNetworkConnectionChanged",
					"Widget.DataNetworkInfo.getNetworkConnectionName",
					"Widget.DataNetworkInfo.networkConnectionType",
					"Widget.Device.clipboardString",
					"Widget.Device.copyFile",
					"Widget.Device.deleteFile",
					"Widget.Device.findFiles",
					"Widget.Device.getFileSystemRoots",
					"Widget.Device.getFileSystemSize",
					"Widget.Device.moveFile",
					"Widget.Device.onFilesFound",
					"Widget.Device.setRingtone",
					"Widget.Device.vibrate",
					"Widget.Device.PowerInfo",
					"Widget.DeviceInfo.totalMemory",
					"Widget.DeviceStateInfo.backLightOn",
					"Widget.DeviceStateInfo.keypadLightOn",
					"Widget.DeviceStateInfo.onScreenChangeDimensions",
					"Widget.DeviceStateInfo.Config",
					"Widget.PositionInfo.altitudeAccuracy",
					"Widget.PositionInfo.cellID",
					"Widget.PIM.deleteAddressBookItem",
					"Widget.Multimedia.isVideoPlaying",
					"Widget.VideoPlayer.*",
					"Widget.PIM.addCalendarItem",
					"Widget.PIM.deleteCalendarItem",
					"Widget.PIM.exportAsVCard",
					"Widget.PIM.findCalendarItems",
					"Widget.PIM.getCalendarItem",
					"Widget.PIM.getCalendarItems",
					"Widget.PIM.onCalendarItemAlert",
					"Widget.PIM.onCalendarItemsFound",
					"Widget.Calendar*",
					"Widget.EventRecurrenceTypes",
					"Widget.Device.AccountInfo.phoneMSISDN",
					"Widget.Device.AccountInfo.userSubscriptionType",
					"Widget.Device.AccountInfo.userAccountBalance",
					"Widget.Telephony*",
					"Widget.CallRecord*",
					"Widget.Messag*", // includes Message, Messaging, etc.
					"Widget.Attachment",
					"Widget.Account",
					"Widget.Config",
					"Widget.PowerInfo",
				]
			};
			return ret;
		},
		//
		//	PC, Opera Widget Runtime
		//
		"regexp:Opera\\/9\\.64(.*)Presto\\/2\\.1\\.1":function(){
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		},
		//
		//	Opera Widgets 10.00 (Emulator, maybe also when running on a device)
		//
		"regexp:Opera\\/9\\.80(.*)Presto\\/2\\.4\\.18":function(){
		},
		//
		//	Firefox on PC
		//
		// e.g. "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6"
		"regexp:Mozilla.*Gecko\/\\d+\\sFirefox.*":function(){
// using only "AppleWebkit" here would also be found on the H2
		//"regexp:(.*AppleWebKit.*)|(Mozilla.*Gecko\/\\d+\\sFirefox.*)":function(){
			var ret = {
				hasClipboard:true,
				hasClamshell:false,
				geolocation:{
					timeouts: {
						agps: defaults.geolocation.timeouts.gps
					}
				},
				events: {
					invalidRecurrenceTypes: ['EVERY_WEEKDAY', 'MONTHLY_ON_DAY']
				},
				supports: {
					Messaging:{
						moveMessage: false,
						editFolder: false,
						multipleEmailAccounts: false
					}
				}
			};
			return ret;
		},
		//
		// Chrome, Ripple
		//
		//"regexp:Mozilla.*Chrome":function(){
		//	var ret = {
		//	};
		//	return ret;
		//},

		// Made for UAs
		// 		WidgetManager; Nokia N96....
		// 		WidgetManager; Nokia 5800...
		"regexp:^WidgetManager;\\sNokia\\s(N)?\\d+;\\sOpera.*":function(){
			var widgetPath = (""+window.location).replace("widget://localhost/", "").replace(/index.html$/, "");
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		},
		"WidgetManager; NOKIA E52-1; Opera/9.5 (S60; Symbian OS; U; de; Opera Mobile/1109)":function(){
			var widgetPath = (""+window.location).replace("widget://localhost/", "").replace(/index.html$/, "");
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		}
	};
	//
	//	END of the configuring stuff.
	//

	//
	// Find the config we have to mixin.
	//
	var ua = window.navigator.userAgent;
	var configToMixin = null;
//var ua = "WidgetManager; SAMSUNG-GT-I8320-Vodafone;AppleWebKit/528.5+(X11;U;Linux;en;i8329BUIH8)";
	for (var key in configs){
		var c = configs[key];
		if (key.indexOf("regexp:")===0){
			if (ua.match(new RegExp(key.substr(7)))){
				configToMixin = c();
				break;
			}
		} else if(key===ua){
			configToMixin = c();
			break;
		}
	}
	if (configToMixin===null){
		configToMixin = doh.util.mixin({}, defaults);
	} else {
		configToMixin.isCustomConfiguration = true;
	}

	// config is still empty at this point, just contains key "isCustomConfiguration".
	doh.util.mixin(config, defaults);
	// Mixin the additional config params.
	// Mixin recursively so objects don't have to declare each key again!
	function _mixin(base, overrider){
		// summary:
		// 		Recursive object mixin.
		// description:
		// 		base is the initial object, overrider contains values that
		// 		override the according values in base.
		var ret = doh.util.mixin({}, base); // clone base
		for (var key in overrider){
			var v = overrider[key];
			if (!doh.util.isArray(v) && typeof v=="object"){
				ret[key] = _mixin(ret[key], v);
			} else {
				ret[key] = v;
			}
		}
		return ret;
	}
	for (var key in configToMixin){
		var v = configToMixin[key];
		if (typeof v=="object" && !doh.util.isArray(v)){
			config[key] = _mixin(config[key], v);
		} else {
			config[key] = v;
		}
	}
})();
<commit_msg>fixed opera config, now signed widgets can be tested<commit_after>var config = {
	isCustomConfiguration:false
};

(function(){

// TOD how can we embed this into the synchronous loading process to fill the config??
	//function _findValidAddressBookItemId(callback){
	//	try{
	//		var pim = Widget.PIM;
	//		var addr = new pim.AddressBookItem();
	//		addr.setAttributeValue("fullName", "*");
	//		Widget.PIM.onAddressBookItemsFound = function(items){
	//			if (items.length>0){
	//				callback(items[0].addressBookItemId);
	//			}
	//		}
	//		pim.findAddressBookItems(addr, 0, 1);
	//		delete pim.onAddressBookItemsFound;
	//	}catch(e){
	//		callback(null);
	//	}
	//}

	var defaults = {
		// summary: This configuration defines the features of the phone.
		// description: It maybe used to determine if a test is viable
		// 		and shall be added or not. E.g. if a phone has a certain hardware
		// 		feature or not, like a clamshell.
		hasAccelerometer:true,
		hasClipboard:false,
		hasClamshell:false,
		hasKeypadLight:false,

		supportsOrientationLandscape:true,
		supportsMultipleEmailAccounts:true,
		supportsDeleteEmailAccounts:true,

		unsupportedApis:[],

		// Some devices/platforms don't support certain features and they normally need to return UNSUPPORTED
		// exception, but to run the correct tests (those testing for the exception) we need to configure
		// the platforms. That is done here.
		// The list below ONLY lists those features that need to be turned off for a certain platform
		// if there is one missing add it, by default the features are all expected to be supported (default value is true).
		supports:{
			// On the first the module (=test file) is given.
			Messaging:{
				moveMessage:true, // moveToFolder()
				editFolder:true, // If createFolder(), moveFolder(), deleteFolder() are NOT supported set this to false.
				multipleEmailAccounts:true
			}
		},

		// Set this to true if the device can open multiple applications.
		// E.g. we can only test Widget.onRestore when the device allows to put the
		// application in the background.
		canDoMultitasking:true,

		validAddressBookItemId:"1",
		validCalendarItemId:"1", // The first contact filled in an H2 really has the ID "1".

		// Various file system settings that will be used for testing, etc.
		// NOTE: Paths must always end with the directorySeparator
		// (just to have less hazzle when just adding a filename in the test).
		fileSystem:{
			directorySeparator:"/",

			// A path where we can read a file from, do directory listing or something alike.
			readablePath:"/virtual/photos/",
			// Specify a file name here for a file that is readable.
			// E.g. for testing methods like getFile().
			readableFile:"/virtual/photos/test-photo/test.txt",
			emptyReadableDirectory:"/virtual/photos/test-photo/testdir",

			// Writeable file or path.
			writeablePath:"/virtual/photos/",
			writeableFile:"/virtual/photos/test-photo/test-write.txt",

			// The root path of the widget, where we can e.g. read out all the
			// files provided with the widget (like audio or video files).
			widgetPath:"",
			playableAudioFiles:{
				inWidget:{
					songWav:"test-audio/wav/music.wav",
					songMp3:"test-audio/mp3/music.mp3",
					loopWav:"test-audio/wav/loop.wav",
					loopMp3:"test-audio/mp3/loop.mp3"
				},
				onDevice:{
					songWav:"/virtual/music/test-audio/wav/music.wav",
					songMp3:"/virtual/music/test-audio/mp3/music.mp3",
					loopWav:"/virtual/music/test-audio/wav/loop.wav",
					loopMp3:"/virtual/music/test-audio/mp3/loop.mp3"
				}
			},
			playableVideoFiles:{
				//viaHttp:"http://...",
				//viaHttps:"https://...",
				//viaRtsp:"rtsp://...",
				//viaFile:"file:///", // ??? shall this be the virtual FS or the real FS (=device specific)???
				avc:{
					inWidget:"test-video/avc/AVC_AAC_48K_30F_QVGA.mp4",
					onDevice:"/virtual/videos/test-video/avc/AVC_AAC_48K_30F_QVGA.mp4"
				},
				h263:{
					inWidget:"test-video/h263/H263_148K_QCIF_15_plus_MP4AAC_22_1.3gp",
					onDevice:"/virtual/videos/test-video/h263/H263_148K_QCIF_15_plus_MP4AAC_22_1.3gp"
				},
				h264:{
					inWidget:"test-video/h264/H264_256K_QVGA_15_plus_AAC_22_2.mp4",
					onDevice:"/virtual/videos/test-video/h264/H264_256K_QVGA_15_plus_AAC_22_2.mp4",
					inWidget1:"test-video/h264/HMC_boa_320_240.MP4",
					onDevice1:"/virtual/videos/test-video/h264/HMC_boa_320_240.MP4"
				},
				mp4:{
					inWidget:"test-video/mp4/MP4V_508K_QVGA_15_plus_MP4AAC_32_2.mp4",
					onDevice:"/virtual/videos/test-video/mp4/MP4V_508K_QVGA_15_plus_MP4AAC_32_2.mp4"
				}
			},
			imageFile:""
		},

		events:{
			invalidRecurrenceTypes:[] // By default all are valid, just list those here that are in the spec but not valid.
		},

		geolocation:{
			supportsAgps:true,
			supportsCellId:true,
			supportsGps:true,
			timeouts:{
				gps:180 * 1000,
				agps:5 * 1000,
				cellId:15 * 1000
			}
		}
	};

	//
	//	Configure your stuff here!!!!!!!!!!!!!!
	//
	var configs = {
		//
		//	Vodafone 360 Devices, H1/M1
		//
		"regexp:^WidgetManager;\\sSAMSUNG-GT-I8320-Vodafone;AppleWebKit.*":function(){
			// Figure out the widget's root directory by making a filesystem
			// function throw an error and reading the "sourceURL" property of this error.
			// It returns the filename for this config.js file.
			var readableFile = "";
			try{
				Widget.Device.getDirectoryFileNames("doesn't exist anyway!");
			}catch(e){
				if (e.sourceURL){
					readableFile = e.sourceURL;
				}
			}
			// Replace multiple trailing slashes, explicitly (just to be sure).
			var widgetPath = readableFile.replace(/\/js\/config\.js$/, "").replace(/\/+$/, "")+"/";

			var ret = {
				canDoMultitasking:false
				// Add the device's configuration, different from the default here!
			};
			return ret;
		},
		//
		//	Vodafone 360 Devices, H2 (I8330), M2 (I6420)
		//
		"regexp:^WidgetManager;\\sSAMSUNG-GT-I\\d{4}-Vodafone;AppleWebKit.*":function(){
			var ret = {
				// AGPS==GPS so set the timeout to the same on the H2
				geolocation:{
					timeouts: {
						agps: defaults.geolocation.timeouts.gps
					}
				},
				events: {
					invalidRecurrenceTypes: ['EVERY_WEEKDAY', 'MONTHLY_ON_DAY']
				},
				supports: {
					Messaging:{
						moveMessage: false,
						editFolder: false,
						multipleEmailAccounts: false
					}
				}
			};
			return ret;
		},
		//
		//	Opera Widget Runtime for Vodafone for Android
		//
		"regexp:^WidgetManager;.*\\(Android.*Opera.*Widgets.*":function(){
			var ret = {
				fileSystem:{
					readablePath:"/sdcard",
					readableFile:"/sdcard/test-audio/mp3/loop.mp3",
					playableAudioFiles:{
						onDevice:{
							// Hope we soon wont need it and opera builds the virtual fs
							songWav:"file:///sdcard/test-audio/wav/music.wav",
							songMp3:"file:///sdcard/test-audio/mp3/music.mp3",
							loopWav:"file:///sdcard/test-audio/wav/loop.wav",
							loopMp3:"file:///sdcard/test-audio/mp3/loop.mp3"
						}
					}
				},
				unsupportedApis:[
					"Widget.Device.RadioInfo.radioSignalSource",
					"Widget.Device.RadioInfo.radioSignalStrengthPercent",
					"Widget.Device.RadioInfo.onSignalSourceChange",
					"Widget.Device.DataNetworkInfo.onNetworkConnectionChanged",
					"Widget.Device.DataNetworkInfo.getNetworkConnectionName",
					"Widget.Device.DataNetworkInfo.networkConnectionType",
					"Widget.Device.clipboardString",
					"Widget.Device.copyFile",
					"Widget.Device.deleteFile",
					"Widget.Device.findFiles",
					"Widget.Device.getFileSystemRoots",
					"Widget.Device.getFileSystemSize",
					"Widget.Device.moveFile",
					"Widget.Device.onFilesFound",
					"Widget.Device.setRingtone",
					"Widget.Device.vibrate",
					"Widget.Device.PowerInfo",
					"Widget.Device.DeviceInfo.totalMemory",
					"Widget.Device.DeviceStateInfo.backLightOn",
					"Widget.Device.DeviceStateInfo.keypadLightOn",
					"Widget.Device.DeviceStateInfo.onScreenChangeDimensions",
					"Widget.Device.DeviceStateInfo.Config",
					"Widget.Device.PositionInfo.altitudeAccuracy",
					"Widget.Device.PositionInfo.cellID",
					"Widget.PIM.deleteAddressBookItem",
					"Widget.Multimedia.isVideoPlaying",
					"Widget.Multimedia.VideoPlayer.*",
					"Widget.PIM.addCalendarItem",
					"Widget.PIM.deleteCalendarItem",
					"Widget.PIM.exportAsVCard",
					"Widget.PIM.findCalendarItems",
					"Widget.PIM.getCalendarItem",
					"Widget.PIM.getCalendarItems",
					"Widget.PIM.onCalendarItemAlert",
					"Widget.PIM.onCalendarItemsFound",
					"Widget.PIM.Calendar*",
					"Widget.PIM.EventRecurrenceTypes",
					"Widget.Device.AccountInfo.phoneMSISDN",
					"Widget.Device.AccountInfo.userSubscriptionType",
					"Widget.Device.AccountInfo.userAccountBalance",
					"Widget.Telephony*",
					"Widget.CallRecord*",
					"Widget.Messag*", // includes Message, Messaging, etc.
					"Widget.Attachment",
					"Widget.Account",
					"Widget.Config"
				]
			};
			return ret;
		},
		//
		//	PC, Opera Widget Runtime
		//
		"regexp:Opera\\/9\\.64(.*)Presto\\/2\\.1\\.1":function(){
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		},
		//
		//	Opera Widgets 10.00 (Emulator, maybe also when running on a device)
		//
		"regexp:Opera\\/9\\.80(.*)Presto\\/2\\.4\\.18":function(){
		},
		//
		//	Firefox on PC
		//
		// e.g. "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-GB; rv:1.9.2) Gecko/20100115 Firefox/3.6"
		"regexp:Mozilla.*Gecko\/\\d+\\sFirefox.*":function(){
// using only "AppleWebkit" here would also be found on the H2
		//"regexp:(.*AppleWebKit.*)|(Mozilla.*Gecko\/\\d+\\sFirefox.*)":function(){
			var ret = {
				hasClipboard:true,
				hasClamshell:false,
				geolocation:{
					timeouts: {
						agps: defaults.geolocation.timeouts.gps
					}
				},
				events: {
					invalidRecurrenceTypes: ['EVERY_WEEKDAY', 'MONTHLY_ON_DAY']
				},
				supports: {
					Messaging:{
						moveMessage: false,
						editFolder: false,
						multipleEmailAccounts: false
					}
				}
			};
			return ret;
		},
		//
		// Chrome, Ripple
		//
		//"regexp:Mozilla.*Chrome":function(){
		//	var ret = {
		//	};
		//	return ret;
		//},

		// Made for UAs
		// 		WidgetManager; Nokia N96....
		// 		WidgetManager; Nokia 5800...
		"regexp:^WidgetManager;\\sNokia\\s(N)?\\d+;\\sOpera.*":function(){
			var widgetPath = (""+window.location).replace("widget://localhost/", "").replace(/index.html$/, "");
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		},
		"WidgetManager; NOKIA E52-1; Opera/9.5 (S60; Symbian OS; U; de; Opera Mobile/1109)":function(){
			var widgetPath = (""+window.location).replace("widget://localhost/", "").replace(/index.html$/, "");
			var ret = {
				hasClipboard:true,
				hasClamshell:false
			};
			return ret;
		}
	};
	//
	//	END of the configuring stuff.
	//

	//
	// Find the config we have to mixin.
	//
	var ua = window.navigator.userAgent;
	var configToMixin = null;
//var ua = "WidgetManager; SAMSUNG-GT-I8320-Vodafone;AppleWebKit/528.5+(X11;U;Linux;en;i8329BUIH8)";
	for (var key in configs){
		var c = configs[key];
		if (key.indexOf("regexp:")===0){
			if (ua.match(new RegExp(key.substr(7)))){
				configToMixin = c();
				break;
			}
		} else if(key===ua){
			configToMixin = c();
			break;
		}
	}
	if (configToMixin===null){
		configToMixin = doh.util.mixin({}, defaults);
	} else {
		configToMixin.isCustomConfiguration = true;
	}

	// config is still empty at this point, just contains key "isCustomConfiguration".
	doh.util.mixin(config, defaults);
	// Mixin the additional config params.
	// Mixin recursively so objects don't have to declare each key again!
	function _mixin(base, overrider){
		// summary:
		// 		Recursive object mixin.
		// description:
		// 		base is the initial object, overrider contains values that
		// 		override the according values in base.
		var ret = doh.util.mixin({}, base); // clone base
		for (var key in overrider){
			var v = overrider[key];
			if (!doh.util.isArray(v) && typeof v=="object"){
				ret[key] = _mixin(ret[key], v);
			} else {
				ret[key] = v;
			}
		}
		return ret;
	}
	for (var key in configToMixin){
		var v = configToMixin[key];
		if (typeof v=="object" && !doh.util.isArray(v)){
			config[key] = _mixin(config[key], v);
		} else {
			config[key] = v;
		}
	}
})();
<|endoftext|>


<commit_before>$(document).ready(function() {

	var tpl = {
		detailTou : '<div data-uid="<%=detail.uid%>">'+
                        '
'+
                            '<img src="<%=detail.photo%>">'+
                        '
'+
                        '
<%=detail.count%>
'+
                        '
<%=detail.name%>
'+
                        '
'+
                            '<%=detail.company%>'+
                            '<%=detail.worker%>'+
                        '
'+
                        '
<%=detail.intro%>
'+
                    '
',
        detailChuang : '<div data-uid="<%=detail.uid%>">'+
                        '
'+
                            '<img src="<%=detail.photo%>">'+
                        '
'+
                        '
<%=detail.count%>
'+
                        '
<%=detail.name%>/第<%=detail.session_number%>届
'+
                        '
'+
                            '<%=detail.project%>'+
                        '
'+
                        '
<%=detail.intro%>
'+
                    '
'
	};

	// 创业者事件
	var chuang = {
		init : function() {
			this.piaoStatus = true;
			this.$backHome = $('.back-home');
			this.$otherPerson = $('.other-person');
			this.$touPiao = $('.tou-piao');
			this.$bangPiao = $('.bang-piao');
			this.$piaoCount = $('.piao-count');
			this.$share = $('.share');
			// 投过之后就不再进行投票了
			if(this.$touPiao.data('status') == 1) {
				this.$touPiao.css({
					'background' : '#ccc'
				}).html('已投票');
				this.piaoStatus = false;
			}
			var url = window.location.href;
			if(url.indexOf('tou') > 0) {
				this.getDetailTou();
			}else if(url.indexOf('chuang') > 0) {
				this.getDetailChuang();
			}
		},

		getDetailTou : function() {
			var _this = this;

			// var data = {

			// };

			// $.ajax({
		 //        url : '/home/banner',
		 //        type : 'get',
		 //        data : data,
		 //        dataType : 'json',
		 //        success : function(msg) {
		 //            if (msg.code != '0000') {
		 //                return;
		 //            }
		 //            var first = template.compile(tpl.firstPage),
   //              	html = render({data : msg.data[0]});

   //              	var other = template.compile(tpl.otherPage),
   //              	html = render({data : msg.data[0]});
		 //            $('.head-time').append(html);

		 //            _this.bind();
		 //        }
		 	//    });
			var data = {
			    "message": "",
			    "code": 200,
			    "data": {
			        "count": 0,
			        "is_vote": false,
			        "session_number": 1,
			        "uid": 2,
			        "photo": "http://7xpr29.com1.z0.glb.clouddn.com/liuchuanjun.jpg",
			        "project": "美菜",
			        "intro": "中国科学院空间物理学硕士，前窝窝团联合创始人，期望用互联网的方式来改变农业、农村和农民。",
			        "name": "刘传军"
			    }
			};
			var render = template.compile(tpl.detailChuang),
	            html = render({
	            	detail : data.data
	            });
	        $('.content').html(html);
	        _this.bind();
		},

		getDetailChuang : function() {
			var _this = this;

			var data = {
			    "message": "",
			    "code": 200,
			    "data": {
			        "count": 0,
			        "uid": 2,
			        "photo": "http://7xpr29.com1.z0.glb.clouddn.com/chenxin.jpg",
			        "company": "红杉资本",
			        "worker": "投资经理",
			        "is_vote": false,
			        "intro": "关注交易平台、互联网房产及蓝领服务，负责杭州地区，投资项目包括房产销冠、觅食、窝客等。",
			        "name": "陈新"
			    }
			};
			var render = template.compile(tpl.detailTou),
	            html = render({
	            	detail : data.data
	            });
	        $('.content').html(html);
	        _this.bind();
		},

		postTouVote : function(data) {
			var _this = this;

			var data = {
				vote : data
			};
			$.ajax({
		        url : '/home/banner',
		        type : 'post',
		        data : data,
		        dataType : 'json',
		        success : function(msg) {
		            window.reload();
		        }
		 	});
		},

		postChuangVote : function(data) {
			var _this = this;

			var data = {
				vote : data
			};
			$.ajax({
		        url : '/home/banner',
		        type : 'post',
		        data : data,
		        dataType : 'json',
		        success : function(msg) {
		            window.reload();
		        }
		 	});
		},

		bind : function() {
			var _this = this;

		    // 点击投票
		    _this.$touPiao.on('click', function() {
		    	if(_this.piaoStatus == false) {
		    		return;
		    	}else{
		    		var count = Number(_this.$piaoCount.text());
		    		var url = window.location.href;
			    	count++;
			    	_this.$piaoCount.html(count);
			    	if(url.indexOf('tou') > 0) {
						_this.postTouVote(count);
					}else if(url.indexOf('chuang') > 0) {
						_this.postChuangVote(count);
					}
			    	$(this).css({
						'background' : '#ccc'
					}).html('已投票');
					_this.piaoStatus = false;
		    	}
		    });

		    // 帮忙拉票
		    _this.$bangPiao.on('click', function(event) {
		    	event.preventDefault();
		    	event.stopPropagation();
		    	_this.$share.show();
		    });

		    // 取消分享mask
		    $(document).on('click', function() {
		    	_this.$share.hide();
		    });

		    // 返回首页
		    _this.$backHome.on('click', function() {
		    	window.location.href="../../index.html";
		    });

		    // 查看其它人
		    _this.$otherPerson.on('click', function() {
		    	window.location.href="list.html";
		    });
		}
	}

	chuang.init();
});<commit_msg>false<commit_after>$(document).ready(function() {

	var tpl = {
		detailTou : '<div data-uid="<%=detail.uid%>">'+
                        '
'+
                            '<img src="<%=detail.photo%>">'+
                        '
'+
                        '
<%=detail.count%>
'+
                        '
<%=detail.name%>
'+
                        '
'+
                            '<%=detail.company%>'+
                            '<%=detail.worker%>'+
                        '
'+
                        '
<%=detail.intro%>
'+
                    '
',
        detailChuang : '<div data-uid="<%=detail.uid%>">'+
                        '
'+
                            '<img src="<%=detail.photo%>">'+
                        '
'+
                        '
<%=detail.count%>
'+
                        '
<%=detail.name%>/第<%=detail.session_number%>届
'+
                        '
'+
                            '<%=detail.project%>'+
                        '
'+
                        '
<%=detail.intro%>
'+
                    '
'
	};

	// 创业者事件
	var chuang = {
		init : function() {
			this.piaoStatus = true;

			var url = window.location.href;
			if(url.indexOf('tou') > 0) {
				this.getDetailTou();
			}else if(url.indexOf('chuang') > 0) {
				this.getDetailChuang();
			}
		},

		getDetailTou : function() {
			var _this = this;

			// var data = {

			// };

			// $.ajax({
		 //        url : '/home/banner',
		 //        type : 'get',
		 //        data : data,
		 //        dataType : 'json',
		 //        success : function(msg) {
		 //            if (msg.code != '0000') {
		 //                return;
		 //            }
		 //            var first = template.compile(tpl.firstPage),
   //              	html = render({data : msg.data[0]});

   //              	var other = template.compile(tpl.otherPage),
   //              	html = render({data : msg.data[0]});
		 //            $('.head-time').append(html);

		 //            _this.bind();
		 //        }
		 	//    });
			var data = {
			    "message": "",
			    "code": 200,
			    "data": {
			        "count": 0,
			        "is_vote": false,
			        "session_number": 1,
			        "uid": 2,
			        "photo": "http://7xpr29.com1.z0.glb.clouddn.com/liuchuanjun.jpg",
			        "project": "美菜",
			        "intro": "中国科学院空间物理学硕士，前窝窝团联合创始人，期望用互联网的方式来改变农业、农村和农民。",
			        "name": "刘传军"
			    }
			};
			var render = template.compile(tpl.detailChuang),
	            html = render({
	            	detail : data.data
	            });
	        $('.content').html(html);
	        // 投过之后就不再进行投票了
			if(this.$('.tou-piao').data('status') == 1) {
				this.$('.tou-piao').css({
					'background' : '#ccc'
				}).html('已投票');
				this.piaoStatus = false;
			}
	        _this.bind();
		},

		getDetailChuang : function() {
			var _this = this;

			var data = {
			    "message": "",
			    "code": 200,
			    "data": {
			        "count": 0,
			        "uid": 2,
			        "photo": "http://7xpr29.com1.z0.glb.clouddn.com/chenxin.jpg",
			        "company": "红杉资本",
			        "worker": "投资经理",
			        "is_vote": false,
			        "intro": "关注交易平台、互联网房产及蓝领服务，负责杭州地区，投资项目包括房产销冠、觅食、窝客等。",
			        "name": "陈新"
			    }
			};
			var render = template.compile(tpl.detailTou),
	            html = render({
	            	detail : data.data
	            });
	        $('.content').html(html);
	        // 投过之后就不再进行投票了
			if(this.$('.tou-piao').data('status') == 1) {
				this.$('.tou-piao').css({
					'background' : '#ccc'
				}).html('已投票');
				this.piaoStatus = false;
			}
	        _this.bind();
		},

		postTouVote : function(data) {
			var _this = this;

			var data = {
				vote : data
			};
			$.ajax({
		        url : '/home/banner',
		        type : 'post',
		        data : data,
		        dataType : 'json',
		        success : function(msg) {
		            window.reload();
		        }
		 	});
		},

		postChuangVote : function(data) {
			var _this = this;

			var data = {
				vote : data
			};
			$.ajax({
		        url : '/home/banner',
		        type : 'post',
		        data : data,
		        dataType : 'json',
		        success : function(msg) {
		            window.reload();
		        }
		 	});
		},

		bind : function() {
			var _this = this;

		    // 点击投票
		    _this.$('.tou-piao').on('click', function() {
		    	if(_this.piaoStatus == false) {
		    		return;
		    	}else{
		    		var count = Number(_this.$('.piao-count').text());
		    		var url = window.location.href;
			    	count++;
			    	_this.$('.piao-count').html(count);
			    	if(url.indexOf('tou') > 0) {
						_this.postTouVote(count);
					}else if(url.indexOf('chuang') > 0) {
						_this.postChuangVote(count);
					}
			    	$(this).css({
						'background' : '#ccc'
					}).html('已投票');
					_this.piaoStatus = false;
		    	}
		    });

		    // 帮忙拉票
		    _this.$('.bang-piao').on('click', function(event) {
		    	event.preventDefault();
		    	event.stopPropagation();
		    	_this.$('.share').show();
		    });

		    // 取消分享mask
		    $(document).on('click', function() {
		    	_this.$('.share').hide();
		    });

		    // 返回首页
		    _this.$('.back-home').on('click', function() {
		    	window.location.href="../../index.html";
		    });

		    // 查看其它人
		    _this.$('.other-person').on('click', function() {
		    	window.location.href="list.html";
		    });
		}
	}

	chuang.init();
});<|endoftext|>


<commit_before>"use strict";

function Player() {
  GameObject(this); //extend from game object.

  this.position = {x: 0, y: 0};
  this.dimension = {w: 32, h: 32};
  this.velocity = 5;
  this.moving = false;
  this.expanding = false;
  this.arming = false;
  this.exploding = false;
  this.colliding = false;
  this.timer = 0;
  this.moveTo = {x: 0, y: 0};
  this.rotateTo = 0;
  this.angle = 0;
  this.life = 100;

  this.bubble = {
    w: 0,
    h: 0,
    vel: 1,
    armed: {
      w: 0,
      h: 0
    }
  };

  var that = this;

  if (('ontouchstart' in window) ||
       (navigator.maxTouchPoints > 0) ||
       (navigator.msMaxTouchPoints > 0)) {

  } else {

  }

  this.addListener("touchmove", function(e){
    var touches = e.changedTouches;

    that.moveTo.x = touches[0].pageX;
    that.moveTo.y = touches[0].pageY;
    that.moving = true;

    if (!that.exploding && !that.arming) {
      that.exploding = false;
      that.arming = false;
      that.expanding = true;
    }
    e.preventDefault();
  });

  this.addListener("touchstart", function(e){
    var touches = e.changedTouches;

    if (that.arming) {
      that.moveTo.x = touches[0].pageX;
      that.moveTo.y = touches[0].pageY;
      that.moving = true;
    }

    that.expanding = true;
  });

  this.addListener("touchend", function(e){
    if (that.bubble.h > 32) {
      that.expanding = false;
      this.exploding = false;
      that.arming = true;
      that.timer = 0;
      that.bubble.armed.w = that.bubble.w;
      that.bubble.armed.h = that.bubble.h;
    } else {
      that.timer = 0;
      that.expanding = false;
      this.exploding = false;
      that.arming = false;
      that.bubble.armed.w = 0;
      that.bubble.w = 0;
      that.bubble.armed.h = 0;
      that.bubble.h = 0;

    }
  });

  this.addListener('update', function(dt){
    that.colliding = false;

    if (that.moving) {
      var xDistance = that.moveTo.x - that.position.x;
      var yDistance = that.moveTo.y - that.position.y;
      var distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
      if (distance > 1) {
          that.position.x += xDistance * (dt * that.velocity);
          that.position.y += yDistance * (dt * that.velocity);
      } else {
        that.moving = false;
      }

      that.angle = Math.atan2(yDistance,xDistance) * (180/Math.PI);
    }

    if (that.expanding && that.bubble.h < 100) {
      that.bubble.w += 32 * (dt * that.bubble.vel);
      that.bubble.h += 32 * (dt * that.bubble.vel);
    }

    if (that.arming) {
      if (that.dimension.w <= 64) {
        that.dimension.w += 64 * (dt * that.bubble.vel);
        that.dimension.h += 64 * (dt * that.bubble.vel);

        that.bubble.w += 32 * (dt * that.bubble.vel);
        that.bubble.h += 32 * (dt * that.bubble.vel);
      }

      that.timer += dt * that.bubble.vel * 2;

      if (that.timer > 1) {
        that.timer = 0;
        that.arming = false;
        that.exploding = true;
      }
    }

    if (that.exploding) {
      that.dimension.w = 32;
      that.dimension.h = 32;
      that.bubble.w = that.bubble.armed.w;
      that.bubble.h = that.bubble.armed.h;

      that.timer += dt * that.bubble.vel * 2;

      if (that.timer > 1) {
        that.timer = 0;
        that.exploding = false;
        that.bubble.w = 0;
        that.bubble.h = 0;
      }
    }

  });

  this.addListener('render', function(){
    var ctx = that.parent.parent.ctx;

    ctx.save();
    ctx.translate(that.position.x,that.position.y);
    //ctx.rotate(45 * Math.PI / 180);
    ctx.rotate(that.angle * Math.PI / 180);
    ctx.translate(-that.dimension.w/2,-that.dimension.h/2); // before we draw the sprite lets set the anchor point to its center.
    ctx.beginPath();
    //ctx.rect(that.position.x, that.position.y, that.dimension.w, that.dimension.h);
    ctx.rect(0, 0, that.dimension.w, that.dimension.h);
    //ctx.rect(that.position.x - (that.dimension.w / 2), that.position.y - (that.dimension.h / 2), that.dimension.w, that.dimension.h);
    ctx.fillStyle = that.colliding?'red':'white';
    ctx.fill();
    ctx.restore();

    if (that.expanding) {
      ctx.globalAlpha = 0.5;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#00CCFF';
      ctx.fill();
      //ctx.stroke();
      ctx.globalAlpha = 1;

      // if (that.bubble.h < 100) {
      //   ctx.beginPath();
      //   ctx.strokeStyle = '#FFFFFF';
      //   ctx.lineWidth = 5;
      //   ctx.arc(that.position.x, that.position.y, that.bubble.w, that.bubble.w / 2, that.bubble.w / 2 + (Math.PI));
      //   ctx.stroke();
      // }
    }

    if (that.arming || that.expanding) {
      ctx.globalCompositeOperation = "overlay";
      for (var i = 0; i < 10; i++) {
        ctx.globalAlpha = 1;
        ctx.beginPath();
        ctx.strokeStyle = '#FFFFFF';
        ctx.lineWidth = 10;
        var bubbleRad = that.bubble.w - Math.random() * that.bubble.w;
        ctx.arc(that.position.x, that.position.y, bubbleRad, bubbleRad / 2, bubbleRad / 2 + (Math.PI));
        ctx.stroke();
        ctx.globalAlpha = 1;
      }
      ctx.globalCompositeOperation = "source-over";
    }

    if (that.arming) {
      ctx.globalAlpha = parseInt(that.timer * 10) % 2 == 0?0.5:0;//0.5;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#00CCFF';
      ctx.fill();
      //ctx.stroke();
      ctx.globalAlpha = 1;
    }

    if (that.exploding) {
      ctx.globalAlpha = 1 - that.timer;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#FFFFFF';
      ctx.fill();

      ctx.beginPath();
      ctx.strokeStyle = '#FFFFFF';
      ctx.lineWidth = 10;
      ctx.arc(that.position.x, that.position.y, that.bubble.w + that.timer * 100, 0, 2 * Math.PI);
      ctx.stroke();

      //ctx.stroke();
      ctx.globalAlpha = 1;
    }

  });

}

Player.prototype = Object.create(GameObject.prototype);
Player.prototype.constructor = Player;

Player.prototype.die = function(){
  //console.log('DIE!', this);
  this.dying = true;
};

Player.prototype.stopExpanding = function(){
  this.timer = 0;
  this.expanding = false;
  this.moving = false;
  this.exploding = false;
  this.arming = false;
  this.bubble.h = 0;
  this.bubble.w = 0;
};
<commit_msg>Add spawning phase to player.<commit_after>"use strict";

function Player() {
  GameObject(this); //extend from game object.

  this.position = {x: 0, y: 0};
  this.dimension = {w: 32, h: 32};
  this.velocity = 5;
  this.moving = false;
  this.expanding = false;
  this.arming = false;
  this.exploding = false;
  this.colliding = false;
  this.spawning = false;
  this.spawningTimer = 0;
  this.dying = false;
  this.timer = 0;
  this.moveTo = {x: 0, y: 0};
  this.rotateTo = 0;
  this.angle = 0;
  this.lives = 3;

  this.bubble = {
    w: 0,
    h: 0,
    vel: 1,
    armed: {
      w: 0,
      h: 0
    }
  };

  var that = this;

  if (('ontouchstart' in window) ||
       (navigator.maxTouchPoints > 0) ||
       (navigator.msMaxTouchPoints > 0)) {

  } else {

  }

  this.addListener("touchmove", function(e){
    var touches = e.changedTouches;

    that.moveTo.x = touches[0].pageX;
    that.moveTo.y = touches[0].pageY;
    that.moving = true;

    if (!that.exploding && !that.arming) {
      that.exploding = false;
      that.arming = false;
      that.expanding = true;
    }
    e.preventDefault();
  });

  this.addListener("touchstart", function(e){
    var touches = e.changedTouches;

    if (that.arming) {
      that.moveTo.x = touches[0].pageX;
      that.moveTo.y = touches[0].pageY;
      that.moving = true;
    }

    that.expanding = true;
  });

  this.addListener("touchend", function(e){
    if (that.bubble.h > 32) {
      that.expanding = false;
      this.exploding = false;
      that.arming = true;
      that.timer = 0;
      that.bubble.armed.w = that.bubble.w;
      that.bubble.armed.h = that.bubble.h;
    } else {
      that.timer = 0;
      that.expanding = false;
      this.exploding = false;
      that.arming = false;
      that.bubble.armed.w = 0;
      that.bubble.w = 0;
      that.bubble.armed.h = 0;
      that.bubble.h = 0;

    }
  });

  this.addListener('update', function(dt){
    that.colliding = false;

    if (that.moving) {
      var xDistance = that.moveTo.x - that.position.x;
      var yDistance = that.moveTo.y - that.position.y;
      var distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance);
      if (distance > 1) {
          that.position.x += xDistance * (dt * that.velocity);
          that.position.y += yDistance * (dt * that.velocity);
      } else {
        that.moving = false;
      }

      that.angle = Math.atan2(yDistance,xDistance) * (180/Math.PI);
    }

    if (that.expanding && that.bubble.h < 300) {
      that.bubble.w += 32 * (dt * that.bubble.vel);
      that.bubble.h += 32 * (dt * that.bubble.vel);
    }

    if (that.spawning) {
      that.spawningTimer += dt * that.velocity * 2;
      console.log(that.spawningTimer);
    }

    if (that.spawningTimer > 15) {
      that.spawningTimer = 0;
      that.spawning = false;
    }

    if (that.arming) {
      if (that.dimension.w <= 64) {
        that.dimension.w += 64 * (dt * that.bubble.vel);
        that.dimension.h += 64 * (dt * that.bubble.vel);

        that.bubble.w += 32 * (dt * that.bubble.vel);
        that.bubble.h += 32 * (dt * that.bubble.vel);
      }

      that.timer += dt * that.bubble.vel * 2;

      if (that.timer > 1) {
        that.timer = 0;
        that.arming = false;
        that.exploding = true;
        that.triggerListeners('start-explosion', that);
      }
    }

    if (that.exploding) {
      that.dimension.w = 32;
      that.dimension.h = 32;
      that.bubble.w = that.bubble.armed.w;
      that.bubble.h = that.bubble.armed.h;

      that.timer += dt * that.bubble.vel * 2;

      if (that.timer > 1) {
        that.timer = 0;
        that.exploding = false;
        that.bubble.w = 0;
        that.bubble.h = 0;
        that.triggerListeners('end-explosion', that);
      }
    }

  });

  this.addListener('render', function(){
    var ctx = that.parent.parent.ctx;

    ctx.save();
    ctx.translate(that.position.x,that.position.y);
    //ctx.rotate(45 * Math.PI / 180);
    ctx.rotate(that.angle * Math.PI / 180);
    ctx.translate(-that.dimension.w/2,-that.dimension.h/2); // before we draw the sprite lets set the anchor point to its center.
    ctx.beginPath();
    //ctx.rect(that.position.x, that.position.y, that.dimension.w, that.dimension.h);
    ctx.rect(0, 0, that.dimension.w, that.dimension.h);
    //ctx.rect(that.position.x - (that.dimension.w / 2), that.position.y - (that.dimension.h / 2), that.dimension.w, that.dimension.h);
    ctx.fillStyle = that.colliding?'red':'white';
    ctx.fill();
    ctx.restore();

    if (that.expanding) {
      ctx.globalAlpha = 0.5;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#00CCFF';
      ctx.fill();
      //ctx.stroke();
      ctx.globalAlpha = 1;

      // if (that.bubble.h < 100) {
      //   ctx.beginPath();
      //   ctx.strokeStyle = '#FFFFFF';
      //   ctx.lineWidth = 5;
      //   ctx.arc(that.position.x, that.position.y, that.bubble.w, that.bubble.w / 2, that.bubble.w / 2 + (Math.PI));
      //   ctx.stroke();
      // }
    }

    if (that.arming || that.expanding) {
      ctx.globalCompositeOperation = "overlay";
      for (var i = 0; i < 10; i++) {
        ctx.globalAlpha = 1;
        ctx.beginPath();
        ctx.strokeStyle = '#FFFFFF';
        ctx.lineWidth = 10;
        var bubbleRad = that.bubble.w - Math.random() * that.bubble.w;
        ctx.arc(that.position.x, that.position.y, bubbleRad, bubbleRad / 2, bubbleRad / 2 + (Math.PI));
        ctx.stroke();
        ctx.globalAlpha = 1;
      }
      ctx.globalCompositeOperation = "source-over";
    }

    if (that.arming) {
      ctx.globalAlpha = parseInt(that.timer * 10) % 2 == 0?0.5:0;//0.5;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#00CCFF';
      ctx.fill();
      //ctx.stroke();
      ctx.globalAlpha = 1;
    }

    if (that.exploding) {
      ctx.globalAlpha = 1 - that.timer;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, that.bubble.w, 0, 2 * Math.PI);
      ctx.fillStyle = '#FFFFFF';
      ctx.fill();

      ctx.globalAlpha = 1 - that.timer * 5;
      ctx.beginPath();
      ctx.strokeStyle = '#FFFFFF';
      ctx.lineWidth = 10;
      ctx.arc(that.position.x, that.position.y, that.bubble.w + that.timer * 100, 0, 2 * Math.PI);
      ctx.stroke();

      //ctx.stroke();
      ctx.globalAlpha = 1;
    }

    if (that.spawning) {
      ctx.globalAlpha = parseInt(that.spawningTimer * 10) % 2 == 0?0.5:0;//0.5;
      ctx.beginPath();
      ctx.arc(that.position.x, that.position.y, 64, 0, 2 * Math.PI);
      ctx.fillStyle = '#FFFFFF';
      ctx.fill();
      //ctx.stroke();
      ctx.globalAlpha = 1;
    }

  });

}

Player.prototype = Object.create(GameObject.prototype);
Player.prototype.constructor = Player;

Player.prototype.die = function(){
  console.log('DIE!', this);
  this.lives--;
  this.spawning = true;
  this.triggerListeners('die', this);
};

Player.prototype.stopExpanding = function(){
  this.timer = 0;
  this.expanding = false;
  this.moving = false;
  this.exploding = false;
  this.arming = false;
  this.bubble.h = 0;
  this.bubble.w = 0;
};
<|endoftext|>


<commit_before>/*global
 define
 */
/*jslint
 browser: true,
 white: true
 */

/**
 * A route path ParamComponent
 *
 * @typedef {Object} RoutePathComponent
 * @property {string} type - the type of the component, either 'param' or 'path'
 * @property {string} name - type name of the component. For param, it is the name of the query variable and of the resulting property in the param object; for path it is literal text of the path component.
 *
 */

/**
 * A definition of path and parameters which may match a route, and a payload.
 *
 * @typedef {Object} RouteSpecification
 * @property {Array.<String|RoutePathComponent>} path - an array of path elements, either literal strings or path component objects
 * @property {Object} params - an object whose properties are parameters may be present in a query string
 * @property {Object} payload - an arbitrary object which represents the state associated with the route path.
 */

/**
 * A simple hash-path router service.
 *
 * @module router
 *
 *
 * @returns {unresolved}
 */
define([], function () {
    'use strict';
    var factory = function () {
        // Routing
        var routes = [];
        function addRoute(pathSpec) {
            /*
             * The path spec is an array of elements. Each element is either a
             * string, in which case it is a literal path component,
             * regular expression, which case it is matched on a path component,
             * object with type:param
             */
            /* TODO: do something on overlapping routes */
            /* TODO: better mapping method for routes. */
            /* still, with a relatively short list of routes, this is far from a performance issue. */
            routes.push(pathSpec);
        }

        var defaultRoute = null;
        function setDefaultRoute(routeSpec) {
            defaultRoute = routeSpec;
        }

        function parseQueryString(s) {
            var fields = s.split(/[\?\&]/),
                params = {};
            fields.forEach(function(field) {
                if (field.length > 0) {
                    var pair = field.split('=');
                    if (pair[0].length > 0) {
                        params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
                    }
                }
            });
            return params;
        }

        function getCurrentRequest() {
            var path = [],
                query = {};

            // The path is (for now) from the hash component.
            if (window.location.hash && window.location.hash.length > 1) {
                var hash = window.location.hash.substr(1),
                    pathQuery = hash.split('?', 2);

                if (pathQuery.length === 2) {
                    query = parseQueryString(pathQuery[1]);
                }
                path = pathQuery[0].split('/').filter(function (x) {
                    return (x.length > 0);
                });
            }

            return {
                path: path,
                query: query
            };
        }

        function findCurrentRoute() {
            var req = getCurrentRequest();
            return findRoute(req);
        }

        function findRoute(req) {
            var foundRoute;
            for (var i = 0; i < routes.length; i += 1) {
                var route = routes[i];
                if (route.path.length !== req.path.length) {
                    continue;
                }
                var params = {}, found = true;
                for (var j = 0; j < req.path.length; j += 1) {
                    var elValue = route.path[j],
                        elType = typeof elValue;
                    if (elType === 'string' && elValue !== req.path[j]) {
                        found = false;
                        break;
                    } else if (elType === 'object' && elValue.type === 'param') {
                        params[elValue.name] = req.path[j];
                    }
                }
                if (found) {
                    foundRoute = {
                        params: params,
                        route: route
                    };
                    break;
                }
            }
            // The total params is the path params and query params
            if (foundRoute) {
                var allowableParams = foundRoute.route.queryParams || {};
                Object.keys(req.query).forEach(function(key) {
                    var paramDef = allowableParams[key];
                    /* TODO: implement the param def for conversion, validation, etc. */
                    if (paramDef) {
                        foundRoute.params[key] = req.query[key];
                    }
                });
            } else {
                return {
                    params: {},
                    route: defaultRoute
                };
            }
            return foundRoute;
        }

        function listRoutes() {
            return routes.map(function(route) {
                return route.path;
            });
        };

        return {
            addRoute: addRoute,
            listRoutes: listRoutes,
            findCurrentRoute: findCurrentRoute,
            getCurrentRequest: getCurrentRequest,
            findRoute: findRoute,
            setDefaultRoute: setDefaultRoute
        };
    };

    return {
        make: function() {
            return factory();
        }
    };
});<commit_msg>code cleanup for router.<commit_after>/*global
 define
 */
/*jslint
 browser: true,
 white: true
 */

/**
 * A route path ParamComponent
 *
 * @typedef {Object} RoutePathComponent
 * @property {string} type - the type of the component, either 'param' or 'path'
 * @property {string} name - type name of the component. For param, it is the name of the query variable and of the resulting property in the param object; for path it is literal text of the path component.
 *
 */

/**
 * A definition of path and parameters which may match a route, and a payload.
 *
 * @typedef {Object} RouteSpecification
 * @property {Array.<String|RoutePathComponent>} path - an array of path elements, either literal strings or path component objects
 * @property {Object} params - an object whose properties are parameters may be present in a query string
 * @property {Object} payload - an arbitrary object which represents the state associated with the route path.
 */

/**
 * A simple hash-path router service.
 *
 * @module router
 *
 *
 * @returns {unresolved}
 */
define([], function () {
    'use strict';
    function factory () {
        // Routing
        var routes = [],
            defaultRoute = null;
        function addRoute(pathSpec) {
            /*
             * The path spec is an array of elements. Each element is either a
             * string, in which case it is a literal path component,
             * regular expression, which case it is matched on a path component,
             * object with type:param
             */
            /* TODO: do something on overlapping routes */
            /* TODO: better mapping method for routes. */
            /* still, with a relatively short list of routes, this is far from a performance issue. */
            routes.push(pathSpec);
        }

        function setDefaultRoute(routeSpec) {
            defaultRoute = routeSpec;
        }

        function parseQueryString(s) {
            var fields = s.split(/[\?\&]/),
                params = {};
            fields.forEach(function(field) {
                if (field.length > 0) {
                    var pair = field.split('=');
                    if (pair[0].length > 0) {
                        params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
                    }
                }
            });
            return params;
        }

        function getCurrentRequest() {
            var path = [],
                query = {},
                hash, pathQuery;

            // The path is (for now) from the hash component.
            if (window.location.hash && window.location.hash.length > 1) {
                hash = window.location.hash.substr(1);
                pathQuery = hash.split('?', 2);

                if (pathQuery.length === 2) {
                    query = parseQueryString(pathQuery[1]);
                }
                path = pathQuery[0].split('/').filter(function (x) {
                    return (x.length > 0);
                });
            }

            return {
                path: path,
                query: query
            };
        }

        function findRoute(req) {
            var foundRoute, i, j, route, params, found, elValue, elType, allowableParams;
            for (i = 0; i < routes.length; i += 1) {
                route = routes[i];
                if (route.path.length !== req.path.length) {
                    continue;
                }
                params = {};
                found = true;
                for (j = 0; j < req.path.length; j += 1) {
                    elValue = route.path[j];
                    elType = typeof elValue;
                    if (elType === 'string' && elValue !== req.path[j]) {
                        found = false;
                        break;
                    }
                    if (elType === 'object' && elValue.type === 'param') {
                        params[elValue.name] = req.path[j];
                    }
                }
                if (found) {
                    foundRoute = {
                        params: params,
                        route: route
                    };
                    break;
                }
            }
            // The total params is the path params and query params
            if (foundRoute) {
                allowableParams = foundRoute.route.queryParams || {};
                Object.keys(req.query).forEach(function(key) {
                    var paramDef = allowableParams[key];
                    /* TODO: implement the param def for conversion, validation, etc. */
                    if (paramDef) {
                        foundRoute.params[key] = req.query[key];
                    }
                });
            } else {
                return {
                    params: {},
                    route: defaultRoute
                };
            }
            return foundRoute;
        }
         function findCurrentRoute() {
            var req = getCurrentRequest();
            return findRoute(req);
        }

        function listRoutes() {
            return routes.map(function(route) {
                return route.path;
            });
        }

        return {
            addRoute: addRoute,
            listRoutes: listRoutes,
            findCurrentRoute: findCurrentRoute,
            getCurrentRequest: getCurrentRequest,
            findRoute: findRoute,
            setDefaultRoute: setDefaultRoute
        };
    }

    return {
        make: function() {
            return factory();
        }
    };
});<|endoftext|>


<commit_before>$(window).load(function () {

  $(document).on('change', '.btn-file :file', function () {
    var input = $(this)
    var numFiles = input.get(0).files ? input.get(0).files.length : 1
    var label = input.val().replace(/\\/g, '/').replace(/.*\//, '')

    input.trigger('fileselect', [numFiles, label])
  })

  $(document).ready(function () {
    $('.btn-file :file').on('fileselect', function (event, numFiles, label) {
      //console.log(numFiles)
      //console.log(label)
    })
  })

  $('[data-toggle="tooltip"]').tooltip()

})

$(function () {
  if ($('#srch-term').length > 0 && $('#srch-term').val() === '') {
    setSearchFormState()
    doTrigger()
  }

  // Open links in-app instead of new window //
  $('.open-in-app a').click(function (event) {
    event.preventDefault()
    if ($(this).attr('href') !== undefined) {
      window.location = $(this).attr('href')
    }
  })

  // Menu toggle //
  $('.toggle-dropdown').on('click', function () {
    var parent = $(this).parent() // Select parent of clicked element
    if (parent.hasClass('active')) {
      parent.removeClass('active')
    } else {
      $('li.active').removeClass('active') // Reset active class
      parent.addClass('active') // Set class 'active' to parent's child
    }
  })

  // Searchform //

  $('.searchForm').on('focus', function () {
    $('#heroSearch').addClass('contracted')
    $('html, body').animate({ scrollTop: 0 }, 'fast')
  })

  $('.searchForm').keyup(setSearchFormState).blur(function () {
    if (this.value === '') {
      $('#heroSearch')
        .removeClass('contracted')
        .addClass('transition')
    }
  })

  function setSearchFormState() {
    if ($('.searchForm').val() === '') {
      $('#searchForm-btn-default').html('')
      $('#results').hide()
    } else {
      $('#searchForm-btn-default').html('')
    }
  }

  var typingTimer
  $('.searchForm').on('keyup', function () {
    clearTimeout(typingTimer)
    typingTimer = setTimeout(doTrigger, 150)
  })

  $('.searchForm').on('keydown', function () {
    clearTimeout(typingTimer)
  })

  setTimeout(function () {
    var searchParam = window.location.search
    if (searchParam.length > 0) { //Search query is entered in URL
      setSearchFormState()
      doTrigger()
    }
  }, 0)

  // Search results //
  function doTrigger() {
    if ($('.searchForm').val().length > 2) {
      $('#searchResultsContainer').html('')
      $.getJSON('/ajax/search/?s=' + $('.searchForm').val(), function (data) {
        if (data[0] !== undefined) {
          if ($('#searchEngine-noResults').css('display') === 'block') {
            $('#searchEngine-noResults').show()
          }
          $('#searchFor').html('
Resultat för ' + $('.searchForm').val() + '
')
          $('#results').show()
          $('#searchResult').append('

')

          $('#searchResultsContainer').show('fast')

          for (var i = 0, result = data; i < result.length; i++) {
            var id = result[i]._id
            var content = '
'
            content += '
'
            content += '

'
            content += '

'
            content += '
' + result[i].title + '
'
            content += '
' + result[i].post.content.substring(0, 115) + '...

'
            content += '

 0
'
            content += '
'
            content += 'Läs mer

'
            $('#searchResultsContainer').append(content)
            $('#searchResult-' + id).show()
            $('#searchForm-btn-default').html('')
            $('#searchEngine-noResults').hide()
          }
        } else { // No results
          $('#searchForm-btn-default').html('')
          $('#searchEngine-noResults').show()
          $('#results').show()
          $('#searchFor').html('')
          $('#searchResultsContainer').show()
        }
      })
    }
  }
})<commit_msg>Add veg_type to products in search result<commit_after>$(window).load(function () {

  $(document).on('change', '.btn-file :file', function () {
    var input = $(this)
    var numFiles = input.get(0).files ? input.get(0).files.length : 1
    var label = input.val().replace(/\\/g, '/').replace(/.*\//, '')

    input.trigger('fileselect', [numFiles, label])
  })

  $(document).ready(function () {
    $('.btn-file :file').on('fileselect', function (event, numFiles, label) {
      //console.log(numFiles)
      //console.log(label)
    })
  })

  $('[data-toggle="tooltip"]').tooltip()

})

$(function () {
  if ($('#srch-term').length > 0 && $('#srch-term').val() === '') {
    setSearchFormState()
    doTrigger()
  }

  // Open links in-app instead of new window //
  $('.open-in-app a').click(function (event) {
    event.preventDefault()
    if ($(this).attr('href') !== undefined) {
      window.location = $(this).attr('href')
    }
  })

  // Menu toggle //
  $('.toggle-dropdown').on('click', function () {
    var parent = $(this).parent() // Select parent of clicked element
    if (parent.hasClass('active')) {
      parent.removeClass('active')
    } else {
      $('li.active').removeClass('active') // Reset active class
      parent.addClass('active') // Set class 'active' to parent's child
    }
  })

  // Searchform //

  $('.searchForm').on('focus', function () {
    $('#heroSearch').addClass('contracted')
    $('html, body').animate({ scrollTop: 0 }, 'fast')
  })

  $('.searchForm').keyup(setSearchFormState).blur(function () {
    if (this.value === '') {
      $('#heroSearch')
        .removeClass('contracted')
        .addClass('transition')
    }
  })

  function setSearchFormState() {
    if ($('.searchForm').val() === '') {
      $('#searchForm-btn-default').html('')
      $('#results').hide()
    } else {
      $('#searchForm-btn-default').html('')
    }
  }

  var typingTimer
  $('.searchForm').on('keyup', function () {
    clearTimeout(typingTimer)
    typingTimer = setTimeout(doTrigger, 150)
  })

  $('.searchForm').on('keydown', function () {
    clearTimeout(typingTimer)
  })

  setTimeout(function () {
    var searchParam = window.location.search
    if (searchParam.length > 0) { //Search query is entered in URL
      setSearchFormState()
      doTrigger()
    }
  }, 0)

  // Search results //
  function doTrigger() {
    if ($('.searchForm').val().length > 2) {
      $('#searchResultsContainer').html('')
      $.getJSON('/ajax/search/?s=' + $('.searchForm').val(), function (data) {
        if (data[0] !== undefined) {
          if ($('#searchEngine-noResults').css('display') === 'block') {
            $('#searchEngine-noResults').show()
          }
          $('#searchFor').html('
Resultat för ' + $('.searchForm').val() + '
')
          $('#results').show()
          $('#searchResult').append('

')

          $('#searchResultsContainer').show('fast')

          var veg_types = {
            vegan: {
              name: 'Veganskt',
              className: 'text-success'
            },
            lacto_ovo: {
              name: 'Lakto-ovo vegetariskt',
              className: 'text-warning'
            },
            animal: {
              name: 'Animaliskt',
              className: 'text-danger'
            }
          }

          for (var i = 0, result = data; i < result.length; i++) {
            var id = result[i]._id
            var content = '
'
            content += '
'
            content += '

'
            content += '

'
            content += '
' + result[i].title + '
'
            content += '
'
            if (result[i].type === '4') {
              content += '' + veg_types[result[i].post.veg_type].name + ' '
            }
            content += result[i].post.content.substring(0, 115) + '...

'
            content += '

 0
'
            content += '
'
            content += 'Läs mer

'
            $('#searchResultsContainer').append(content)
            $('#searchResult-' + id).show()
            $('#searchForm-btn-default').html('')
            $('#searchEngine-noResults').hide()
          }
        } else { // No results
          $('#searchForm-btn-default').html('')
          $('#searchEngine-noResults').show()
          $('#results').show()
          $('#searchFor').html('')
          $('#searchResultsContainer').show()
        }
      })
    }
  }
})<|endoftext|>


<commit_before>(function($) {
  'use strict';
  var slice = Array.prototype.slice;

  /**
  *
  */
  function PjaxTableSearch(el, options) {
    this._$el = $(el);
    this._$searchFilter = this._$el.find('input[type="search"]');

    this._init();
  }

  PjaxTableSearch.prototype._init = function() {
    this._$el.find('.ui-search').click(this._onClickSearch.bind(this));
    this._$el.find('.ui-close').click(this._onClickClose.bind(this));
    this._$searchFilter.keyup(this._onInputKeyup.bind(this));
  };

  PjaxTableSearch.prototype._onClickSearch = function(e) {
    this._$el.trigger('search:submit', $searchFilter.val());
  };

  PjaxTableSearch.prototype._onInputKeyup = function(e) {
    this._$el.find('.ui-close').removeClass('hidden');
    if (e.which === 13) {          //enter / return
      this._$el.trigger('search:submit', $(e.currentTarget).val());
    } else if (e.which == 27) {    //escape
      this._clearSearch();
    }
  };

  PjaxTableSearch.prototype._onClickClose = function(e) {
    this._clearSearch();
  };

  PjaxTableSearch.prototype._clearSearch = function(e) {
    this._$searchFilter.val('');
    this._$el.trigger('search:clear');
    this._$el.find('.ui-close').addClass('hidden');
  };

  $.fn.pjaxTableSearch = function(options) {
    var args = slice.call(arguments);
    var values = []; // return values

    $(this).each(function() {
      // get the current instance or create a new one
      var $el = $(this);
      var widget = $el.data('pjaxTableSearch');
      var methodReturn;

      if (!widget) {
        widget = $el.data('pjaxTableSearch', new PjaxTableSearch(this, options)).data('pjaxTableSearch');
      }

      // execute methods and return the method return or this element for chaining
      if (typeof options === 'string') {
        // special case for resetting widgets, cleanup and reset
        if (options === 'destroy') {
          if (typeof widget.destroy === 'function') {
            widget.destroy();
          }
          delete $el.data().pjaxTableSearch;
        } else if (typeof widget[options] === 'function' && options.charAt(0) !== '_') {
          methodReturn = widget[options].apply(widget, args.slice(1, args.length));
          values.push(methodReturn);
        } else {
          throw new Error('Invalid method: ' + options);
        }
      } else {
        values.push(widget);
      }
    });

    // return only 1 value if possible
    return values.length > 1 ? values : values[0];
  };

  $(function() { $('[data-pjax-table-search][data-auto-init="true"]').pjaxTableSearch({}); });
})(jQuery);
<commit_msg>Fixes incorrect refeference to  in _onClickSearch method<commit_after>(function($) {
  'use strict';
  var slice = Array.prototype.slice;

  /**
  *
  */
  function PjaxTableSearch(el, options) {
    this._$el = $(el);
    this._$searchFilter = this._$el.find('input[type="search"]');

    this._init();
  }

  PjaxTableSearch.prototype._init = function() {
    this._$el.find('.ui-search').click(this._onClickSearch.bind(this));
    this._$el.find('.ui-close').click(this._onClickClose.bind(this));
    this._$searchFilter.keyup(this._onInputKeyup.bind(this));
  };

  PjaxTableSearch.prototype._onClickSearch = function(e) {
    this._$el.trigger('search:submit', this._$searchFilter.val());
  };

  PjaxTableSearch.prototype._onInputKeyup = function(e) {
    this._$el.find('.ui-close').removeClass('hidden');
    if (e.which === 13) {          //enter / return
      this._$el.trigger('search:submit', $(e.currentTarget).val());
    } else if (e.which == 27) {    //escape
      this._clearSearch();
    }
  };

  PjaxTableSearch.prototype._onClickClose = function(e) {
    this._clearSearch();
  };

  PjaxTableSearch.prototype._clearSearch = function(e) {
    this._$searchFilter.val('');
    this._$el.trigger('search:clear');
    this._$el.find('.ui-close').addClass('hidden');
  };

  $.fn.pjaxTableSearch = function(options) {
    var args = slice.call(arguments);
    var values = []; // return values

    $(this).each(function() {
      // get the current instance or create a new one
      var $el = $(this);
      var widget = $el.data('pjaxTableSearch');
      var methodReturn;

      if (!widget) {
        widget = $el.data('pjaxTableSearch', new PjaxTableSearch(this, options)).data('pjaxTableSearch');
      }

      // execute methods and return the method return or this element for chaining
      if (typeof options === 'string') {
        // special case for resetting widgets, cleanup and reset
        if (options === 'destroy') {
          if (typeof widget.destroy === 'function') {
            widget.destroy();
          }
          delete $el.data().pjaxTableSearch;
        } else if (typeof widget[options] === 'function' && options.charAt(0) !== '_') {
          methodReturn = widget[options].apply(widget, args.slice(1, args.length));
          values.push(methodReturn);
        } else {
          throw new Error('Invalid method: ' + options);
        }
      } else {
        values.push(widget);
      }
    });

    // return only 1 value if possible
    return values.length > 1 ? values : values[0];
  };

  $(function() { $('[data-pjax-table-search][data-auto-init="true"]').pjaxTableSearch({}); });
})(jQuery);
<|endoftext|>


<commit_before>function Shape(id) {
    this.id = id;
    this.paper_shape = undefined;

    this.fill_color = undefined;
    this.stroke_color = undefined;
    this.stroke_width = undefined;

    this._configJSON = function() {
        var fill_color_json = ColorsAdapter.paperColorToHex(this.fill_color);
        var stroke_color_json = ColorsAdapter.paperColorToHex(this.stroke_color);
        return {
            'shape_id': this.id,
            'fill_color': fill_color_json.hex_color,
            'fill_alpha': fill_color_json.alpha,
            'stroke_color': stroke_color_json.hex_color,
            'stroke_alpha': stroke_color_json.alpha,
            'stroke_width': this.stroke_width
        }
    };

    this.getCenter = function() {
        if (typeof this.paper_shape !== 'undefined') {
            var bbox = this.paper_shape.bounds;
            return {
                'x': bbox.center.x,
                'y': bbox.center.y
            }
        } else {
            console.info('Shape not initialized');
        }
    };

    this.getBoundingBoxDimensions = function() {
        if (typeof this.paper_shape !== 'undefined') {
            var bbox = this.paper_shape.bounds;
            return {
                'width': bbox.width,
                'height': bbox.height
            };
        } else {
            console.info('Shape not initialized');
        }
    };

    this.contains = function(point_x, point_y) {
        var point_obj = new paper.Point(point_x, point_y);
        if (typeof this.paper_shape !== 'undefined')
            return this.paper_shape.contains(point_obj);
        else
            console.warn('Paper.js shape not initialized');
    };

    this.configure = function(shape_config) {
        if (typeof this.paper_shape !== 'undefined') {
            this.fill_color = ColorsAdapter.hexToPaperColor(shape_config.fill_color, shape_config.fill_alpha);
            this.paper_shape.setFillColor(this.fill_color);
            this.stroke_color = ColorsAdapter.hexToPaperColor(shape_config.stroke_color, shape_config.stroke_alpha);
            this.paper_shape.setStrokeColor(this.stroke_color);
            this.stroke_width = shape_config.stroke_width;
            this.paper_shape.setStrokeWidth(this.stroke_width);
        }
    };

    this.enableEvents = function(events_list) {
        if (typeof events_list === 'undefined') {
            for (var ev in this.default_events) {
                this.paper_shape[this.default_events[ev]] = true;
            }
        } else {
            for (var ev in events_list) {
                if (this.default_events.indexOf(events_list[ev]) !== -1) {
                    this.paper_shape[events_list[ev]] = true;
                } else {
                    console.warn('Unknown event ' + events_list[ev]);
                }
            }
        }
    };

    this.disableEvents = function(events_list) {
        if (typeof events_list === 'undefined') {
            for (var ev in this.default_events) {
                this.paper_shape[this.default_events[ev]] = false;
            }
        } else {
            for (var ev in events_list) {
                if (this.default_events.indexOf(events_list[ev]) !== -1) {
                    this.paper_shape[events_list[ev]] = false;
                } else {
                    console.warn('Unknown event ' + events_list[ev]);
                }
            }
        }
    };

    this._buildEvents = function() {
        this.paper_shape.on({
            mousedrag: function(event) {
                if (this[Shape.MOUSE_DRAG_EVENT] === true) {
                    document.body.style.cursor = 'move';
                    this.position = new paper.Point(
                        this.position.x + event.delta.x,
                        this.position.y + event.delta.y
                    );
                }
            },
            mouseup:  function(event) {
                document.body.style.cursor = 'auto';
            }
        });
    };

    this.initializeEvents = function(activate_events) {
        var activate = (typeof activate_events === 'undefined') ? false : activate_events;
        this._buildEvents();
        if (activate) {
            this.enableEvents();
        } else {
            this.disableEvents();
        }
    };

    this.select = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setSelected(true);
        }
    };

    this.deselect = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setSelected(false);
        }
    };

    this.isSelected = function() {
        if (typeof this.paper_shape !== 'undefined') {
            return this.paper_shape.selected;
        } else {
            return undefined;
        }
    };

    this.show = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setVisible(true);
        }
    };

    this.hide = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setVisible(false);
        }
    };

    this.delete = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.remove();
        }
    };
}

Shape.MOUSE_DRAG_EVENT = 'mouse_drag_event';
Shape.prototype.default_events = [
    Shape.MOUSE_DRAG_EVENT
];

function Rectangle(id, origin_x, origin_y, width, height) {
    Shape.call(this, id);

    this.origin_x = origin_x;
    this.origin_y = origin_y;
    this.width = width;
    this.height = height;

    this.toPaperShape = function(activate_events) {
        var rect = new paper.Shape.Rectangle({
            point: [this.origin_x, this.origin_y],
            size: [this.width, this.height]
        });
        this.paper_shape = rect;
        this.initializeEvents(activate_events);
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'origin_x': this.origin_x + x_offset,
                'origin_y': this.origin_y + y_offset,
                'width': this.width,
                'height': this.height,
                'type': 'rectangle'
            });
        return shape_json;
    };
}

Rectangle.prototype = new Shape();

function Ellipse(id, center_x, center_y, radius_x, radius_y) {
    Shape.call(this, id);

    this.center_x = center_x;
    this.center_y = center_y;
    this.radius_x = radius_x;
    this.radius_y = radius_y;

    this.toPaperShape = function(activate_events) {
        var ellipse = new paper.Shape.Ellipse({
            center: [this.center_x, this.center_y],
            radius: [this.radius_x, this.radius_y]
        });
        this.paper_shape = ellipse;
        this.initializeEvents(activate_events);
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'center_x': this.center_x + x_offset,
                'center_y': this.center_y + y_offset,
                'radius_x': this.radius_x,
                'radius_y': this.radius_y,
                'type': 'ellipse'
            });
        return shape_json;
    };
}

Ellipse.prototype = new Shape();

function Circle(id, center_x, center_y, radius) {
    Shape.call(this, id);

    this.center_x = center_x;
    this.center_y = center_y;
    this.radius = radius;

    this.toPaperShape = function(activate_events) {
        var circle = new paper.Shape.Circle({
            center: [this.center_x, this.center_y],
            radius: this.radius
        });
        this.paper_shape = circle;
        this.initializeEvents(activate_events);
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'center_x': this.center_x + x_offset,
                'center_y': this.center_y + y_offset,
                'radius': this.radius,
                'type': 'circle'
            });
        return shape_json;
    };
}

Circle.prototype = new Shape();

function Line(id, from_x, from_y, to_x, to_y) {
    Shape.call(this, id);

    this.from_x = from_x;
    this.from_y = from_y;
    this.to_x = to_x;
    this.to_y = to_y;

    this.toPaperShape = function(activate_events) {
        var line = new paper.Path.Line({
            from: [this.from_x, this.from_y],
            to: [this.to_x, this.to_y]
        });
        this.paper_shape = line;
        this.initializeEvents(activate_events);
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'from_x': this.from_x + x_offset,
                'from_y': this.from_y + y_offset,
                'to_x': this.to_x + x_offset,
                'to_y': this.to_y + y_offset,
                'type': 'line'
            });
        return shape_json;
    };
}

Line.prototype = new Shape();<commit_msg>release v0.3.3<commit_after>function Shape(id) {
    this.id = id;
    this.paper_shape = undefined;

    this.fill_color = undefined;
    this.stroke_color = undefined;
    this.stroke_width = undefined;

    this._configJSON = function() {
        var fill_color_json = ColorsAdapter.paperColorToHex(this.fill_color);
        var stroke_color_json = ColorsAdapter.paperColorToHex(this.stroke_color);
        return {
            'shape_id': this.id,
            'fill_color': fill_color_json.hex_color,
            'fill_alpha': fill_color_json.alpha,
            'stroke_color': stroke_color_json.hex_color,
            'stroke_alpha': stroke_color_json.alpha,
            'stroke_width': this.stroke_width
        }
    };

    this._bindWrapper = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.shape_wrapper = this;
        }
    };

    this.updateShapeDetails = function() {
        console.log('Using default updateShapeDetails method');
    };

    this.getCenter = function() {
        if (typeof this.paper_shape !== 'undefined') {
            var bbox = this.paper_shape.bounds;
            return {
                'x': bbox.center.x,
                'y': bbox.center.y
            }
        } else {
            console.info('Shape not initialized');
        }
    };

    this.getBoundingBoxDimensions = function() {
        if (typeof this.paper_shape !== 'undefined') {
            var bbox = this.paper_shape.bounds;
            return {
                'width': bbox.width,
                'height': bbox.height
            };
        } else {
            console.info('Shape not initialized');
        }
    };

    this.contains = function(point_x, point_y) {
        var point_obj = new paper.Point(point_x, point_y);
        if (typeof this.paper_shape !== 'undefined')
            return this.paper_shape.contains(point_obj);
        else
            console.warn('Paper.js shape not initialized');
    };

    this.configure = function(shape_config) {
        if (typeof this.paper_shape !== 'undefined') {
            this.fill_color = ColorsAdapter.hexToPaperColor(shape_config.fill_color, shape_config.fill_alpha);
            this.paper_shape.setFillColor(this.fill_color);
            this.stroke_color = ColorsAdapter.hexToPaperColor(shape_config.stroke_color, shape_config.stroke_alpha);
            this.paper_shape.setStrokeColor(this.stroke_color);
            this.stroke_width = shape_config.stroke_width;
            this.paper_shape.setStrokeWidth(this.stroke_width);
        }
    };

    this.enableEvents = function(events_list) {
        if (typeof events_list === 'undefined') {
            for (var ev in this.default_events) {
                this.paper_shape[this.default_events[ev]] = true;
            }
        } else {
            for (var ev in events_list) {
                if (this.default_events.indexOf(events_list[ev]) !== -1) {
                    this.paper_shape[events_list[ev]] = true;
                } else {
                    console.warn('Unknown event ' + events_list[ev]);
                }
            }
        }
    };

    this.disableEvents = function(events_list) {
        if (typeof events_list === 'undefined') {
            for (var ev in this.default_events) {
                this.paper_shape[this.default_events[ev]] = false;
            }
        } else {
            for (var ev in events_list) {
                if (this.default_events.indexOf(events_list[ev]) !== -1) {
                    this.paper_shape[events_list[ev]] = false;
                } else {
                    console.warn('Unknown event ' + events_list[ev]);
                }
            }
        }
    };

    this._buildEvents = function() {
        this.paper_shape.on({
            mousedrag: function(event) {
                if (this[Shape.MOUSE_DRAG_EVENT] === true) {
                    document.body.style.cursor = 'move';
                    this.position = new paper.Point(
                        this.position.x + event.delta.x,
                        this.position.y + event.delta.y
                    );
                }
            },
            mouseup:  function(event) {
                this.shape_wrapper.updateShapeDetails();
                document.body.style.cursor = 'auto';
            }
        });
    };

    this.initializeEvents = function(activate_events) {
        var activate = (typeof activate_events === 'undefined') ? false : activate_events;
        this._buildEvents();
        if (activate) {
            this.enableEvents();
        } else {
            this.disableEvents();
        }
    };

    this.select = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setSelected(true);
        }
    };

    this.deselect = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setSelected(false);
        }
    };

    this.isSelected = function() {
        if (typeof this.paper_shape !== 'undefined') {
            return this.paper_shape.selected;
        } else {
            return undefined;
        }
    };

    this.show = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setVisible(true);
        }
    };

    this.hide = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.setVisible(false);
        }
    };

    this.delete = function() {
        if (typeof this.paper_shape !== 'undefined') {
            this.paper_shape.remove();
        }
    };
}

Shape.MOUSE_DRAG_EVENT = 'mouse_drag_event';
Shape.prototype.default_events = [
    Shape.MOUSE_DRAG_EVENT
];

function Rectangle(id, origin_x, origin_y, width, height) {
    Shape.call(this, id);

    this.origin_x = origin_x;
    this.origin_y = origin_y;
    this.width = width;
    this.height = height;

    this.toPaperShape = function(activate_events) {
        var rect = new paper.Shape.Rectangle({
            point: [this.origin_x, this.origin_y],
            size: [this.width, this.height]
        });
        this.paper_shape = rect;
        this._bindWrapper();
        this.initializeEvents(activate_events);
    };

    this.updateShapeDetails = function() {
        this.origin_x = this.paper_shape.point.x;
        this.origin_y = this.paper_shape.point.y;
        this.width = this.paper_shape.size.width;
        this.height = this.paper_shape.size.height;
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'origin_x': this.origin_x + x_offset,
                'origin_y': this.origin_y + y_offset,
                'width': this.width,
                'height': this.height,
                'type': 'rectangle'
            });
        return shape_json;
    };
}

Rectangle.prototype = new Shape();

function Ellipse(id, center_x, center_y, radius_x, radius_y) {
    Shape.call(this, id);

    this.center_x = center_x;
    this.center_y = center_y;
    this.radius_x = radius_x;
    this.radius_y = radius_y;

    this.toPaperShape = function(activate_events) {
        var ellipse = new paper.Shape.Ellipse({
            center: [this.center_x, this.center_y],
            radius: [this.radius_x, this.radius_y]
        });
        this.paper_shape = ellipse;
        this._bindWrapper();
        this.initializeEvents(activate_events);
    };

    this.updateShapeDetails = function() {
        this.center_x = this.paper_shape.position.x;
        this.center_y = this.paper_shape.position.y;
        this.radius_x = this.paper_shape.radius.width;
        this.radius_y = this.paper_shape.radius.height;
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'center_x': this.center_x + x_offset,
                'center_y': this.center_y + y_offset,
                'radius_x': this.radius_x,
                'radius_y': this.radius_y,
                'type': 'ellipse'
            });
        return shape_json;
    };
}

Ellipse.prototype = new Shape();

function Circle(id, center_x, center_y, radius) {
    Shape.call(this, id);

    this.center_x = center_x;
    this.center_y = center_y;
    this.radius = radius;

    this.toPaperShape = function(activate_events) {
        var circle = new paper.Shape.Circle({
            center: [this.center_x, this.center_y],
            radius: this.radius
        });
        this.paper_shape = circle;
        this._bindWrapper();
        this.initializeEvents(activate_events);
    };

    this.updateShapeDetails = function() {
        this.center_x = this.paper_shape.position.x;
        this.center_y = this.paper_shape.position.y;
        this.radius = this.paper_shape.radius;
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'center_x': this.center_x + x_offset,
                'center_y': this.center_y + y_offset,
                'radius': this.radius,
                'type': 'circle'
            });
        return shape_json;
    };
}

Circle.prototype = new Shape();

function Line(id, from_x, from_y, to_x, to_y) {
    Shape.call(this, id);

    this.from_x = from_x;
    this.from_y = from_y;
    this.to_x = to_x;
    this.to_y = to_y;

    this.toPaperShape = function(activate_events) {
        var line = new paper.Path.Line({
            from: [this.from_x, this.from_y],
            to: [this.to_x, this.to_y]
        });
        this.paper_shape = line;
        this._bindWrapper();
        this.initializeEvents(activate_events);
    };

    this.updateShapeDetails = function() {
        this.from_x = this.paper_shape.segments[0].point.x;
        this.from_y = this.paper_shape.segments[0].point.y;
        this.to_x = this.paper_shape.segments[1].point.x;
        this.to_y = this.paper_shape.segments[1].point.y;
    };

    this.toJSON = function(x_offset, y_offset) {
        var shape_json = this._configJSON();
        $.extend(
            shape_json,
            {
                'from_x': this.from_x + x_offset,
                'from_y': this.from_y + y_offset,
                'to_x': this.to_x + x_offset,
                'to_y': this.to_y + y_offset,
                'type': 'line'
            });
        return shape_json;
    };
}

Line.prototype = new Shape();<|endoftext|>