<commit_before>/*
 * create.js: Titanium Mobile CLI create command
 *
 * Copyright (c) 2012-2013, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

var appc = require('node-appc'),
	async = require('async'),
	fields = require('fields'),
	fs = require('fs'),
	i18n = appc.i18n(__dirname),
	path = require('path'),
	ti = require('titanium-sdk'),
	wrench = require('wrench'),
	__ = i18n.__,
	__n = i18n.__n;

exports.cliVersion = '>=3.2.1';
exports.desc = __('creates a new mobile application'); // or module

exports.config = function config(logger, config, cli) {
	return function (finished) {
		cli.createHook('create.config', function (callback) {
			var conf,
				idPrefix = config.get('app.idprefix'),
				workspaceDir = config.app.workspace ? appc.fs.resolvePath(config.app.workspace) : null,
				availablePlatforms = {},
				validPlatforms = {};

			workspaceDir && !fs.existsSync(workspaceDir) && (workspaceDir = null);

			// build list of all valid platforms
			ti.platforms.forEach(function (p) {
				if (/^iphone|ios|ipad$/.test(p)) {
					validPlatforms['iphone'] = availablePlatforms['iphone'] = 1;
					validPlatforms['ipad'] = availablePlatforms['ipad'] = 1;
					validPlatforms['ios'] = 1;
				} else {
					validPlatforms[p] = availablePlatforms[p] = 1;
				}
			});

			// add "all"
			validPlatforms['all'] = 1;
			availablePlatforms = ['all'].concat(Object.keys(availablePlatforms));

			conf = {
				flags: {
					force: {
						abbr: 'f',
						desc: __('force project creation even if path already exists')
					}
				},
				options: appc.util.mix({
					id: {
						desc: __("the App ID in the format 'com.companyname.appname'"),
						order: 150,
						prompt: function (callback) {
							callback(fields.text({
								default: idPrefix ? idPrefix.replace(/\.$/, '') + '.' + cli.argv.name.replace(/[ -]/g, '_').replace(/[^a-zA-Z0-9_]/g, '').replace(/_+/g, '_') : undefined,
								promptLabel: __('App ID'),
								validate: conf.options.id.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							if (!value) {
								logger.error(__('Please specify an App ID') + '\n');
								return callback(true);
							}

							// general app id validation
							if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_-]*(\.[a-zA-Z0-9_-]*)*)$/.test(value)) {
								logger.error(__('Invalid App ID "%s"', value));
								logger.error(__('The App ID must consist of letters, numbers, dashes, and underscores.'));
								logger.error(__('Note: Android does not allow dashes and iOS does not allow underscores.'));
								logger.error(__('The first character must be a letter or underscore.'));
								logger.error(__("Usually the App ID is your company's reversed Internet domain name. (i.e. com.example.myapp)") + '\n');
								return callback(true);
							}

							if (cli.argv.platforms.indexOf('android') != -1) {
								if (value.indexOf('-') != -1) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Dashes are not allowed in the App ID when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}

								if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_]*(\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)*)$/.test(value)) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Numbers are not allowed directly after periods when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}

								if (!ti.validAppId(value)) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('The app must not contain Java reserved words when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}
							} else {
								// android is not in the list of platforms
								var counter = 0;

								if (value.indexOf('-') != -1) {
									logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow dashes in the App ID.'));
									counter++;
								}

								if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_]*(\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)*)$/.test(value)) {
									counter || logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow numbers directly following periods in the App ID.'));
									counter++;
								}

								if (!ti.validAppId(value)) {
									counter || logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow Java reserved words in the App ID.'));
									counter++;
								}

								counter && logger.warn(__('If you wish to add Android support, you will need to fix the <id> in the tiapp.xml.') + '\n');
							}

							if (value.indexOf('_') != -1) {
								if (cli.argv.platforms.indexOf('ios') != -1 || cli.argv.platforms.indexOf('iphone') != -1 || cli.argv.platforms.indexOf('ipad') != -1) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Underscores are not allowed in the App ID when targeting %s.', 'iOS'.cyan) + '\n');
									return callback(true);
								} else {
									logger.warn(__('The specified App ID is not compatible with the iOS platform.'));
									logger.warn(__('iOS does not allow underscores in the App ID.'));
									logger.warn(__('If you wish to add iOS support, you will need to fix the <id> in the tiapp.xml.') + '\n');
								}
							}

							callback(null, value);
						}
					},
					name: {
						abbr: 'n',
						desc: __('the name of the project'),
						order: 140,
						prompt: function (callback) {
							callback(fields.text({
								promptLabel: __('Project name'),
								validate: conf.options.name.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							if (!value) {
								logger.error(__('Please specify a project name') + '\n');
								return callback(true);
							}

							if (cli.argv.platforms.indexOf('android') != -1 && value.indexOf('&') != -1) {
								if (config.get('android.allowAppNameAmpersands', false)) {
									logger.warn(__('The project name contains an ampersand (&) which will most likely cause problems.'));
									logger.warn(__('It is recommended that you change the app name in the tiapp.xml or define the app name using i18n strings.'));
									logger.warn(__('Refer to %s for more information.', 'http://appcelerator.com/i18n-app-name'.cyan));
								} else {
									logger.error(__('The project name contains an ampersand (&) which will most likely cause problems.'));
									logger.error(__('It is recommended that you change the app name in the tiapp.xml or define the app name using i18n strings.'));
									logger.error(__('Refer to %s for more information.', 'http://appcelerator.com/i18n-app-name'));
									logger.error(__('To allow ampersands in the app name, run:'));
									logger.error('    ti config android.allowAppNameAmpersands true\n');
									return callback(true);
								}
							}

							if (!/^[a-zA-Z]/.test(value)) {
								logger.error(__('The first character of the project name must be a letter.') + '\n');
								return callback(true);
							}

							callback(null, value);
						}
					},
					platforms: {
						abbr: 'p',
						default: !cli.argv.prompt && 'all' || undefined, // if we're prompting, then force the platforms to be prompted for, otherwise force 'all'
						desc: __('the target build platform'),
						order: 120,
						prompt: function (callback) {
							callback(fields.text({
								promptLabel: __('Target platform (%s)', availablePlatforms.join('|')),
								default: 'all',
								validate: conf.options.platforms.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							var goodValues = {},
								badValues = {};

							// just in case they set -p without a value
							if (value === true) {
								value = 'all';
							}

							value.trim().toLowerCase().split(',').forEach(function (s) {
								if (s = s.trim()) {
									if (validPlatforms[s]) {
										goodValues[s] = 1;
									} else {
										badValues[s] = 1;
									}
								}
							});

							var badLen = Object.keys(badValues).length;
							if (badLen) {
								logger.error(__n('Invalid platform: %%s', 'Invalid platforms: %%s', badLen, Object.keys(badValues).join(', ')) + '\n');
								return callback(true);
							}

							if (goodValues.ios) {
								goodValues.iphone = 1;
								goodValues.ipad = 1;
								delete goodValues.ios;
							}

							if (goodValues.all) {
								goodValues = {};
								availablePlatforms.forEach(function (p) {
									if (p != 'all') {
										goodValues[p] = 1;
									}
								});
							}

							callback(null, Object.keys(goodValues).join(','));
						}
					},
					template: {
						desc: __('the name of the project template to use'),
						default: 'default',
						order: 110,
						required: true
					},
					type: {
						abbr: 't',
						default: 'app',
						desc: __('the type of project to create'),
						order: 100,
						skipValueCheck: true,
						validate: function (value, callback) {
							callback(/^app|module$/.test(value) ? null : new Error(__('Invalid project type "%s"', value)), value);
						},
						values: ['app'] // , 'module']
					},
					url: {
						abbr: 'u',
						default: !cli.argv.prompt && config.get('app.url') || undefined,
						desc: __('your company/personal URL'),
						order: 160,
						prompt: function (callback) {
							callback(fields.text({
								default: config.get('app.url'),
								promptLabel: __('Your company/personal URL')
							}));
						},
						required: !!cli.argv.prompt,
						validate: function (value, callback) {
							callback(null, value);
						}
					},
					'workspace-dir': {
						abbr: 'd',
						default: !cli.argv.prompt && workspaceDir || undefined,
						desc: __('the directory to place the project in'),
						order: 170,
						prompt: function (callback) {
							callback(fields.file({
								complete: true,
								default: workspaceDir || undefined,
								ignoreDirs: new RegExp(config.get('cli.ignoreDirs')),
								ignoreFiles: new RegExp(config.get('cli.ignoreFiles')),
								promptLabel: __('Directory to place project'),
								showHidden: true,
								validate: conf.options['workspace-dir'].validate
							}));
						},
						required: true,
						validate: function (dir, callback) {
							if (!dir) {
								logger.error(__('Please specify the workspace directory') + '\n');
								return callback(true);
							}

							dir = appc.fs.resolvePath(dir);

							// check if the directory is writable
							var prev = null,
								curr = dir;
							while (curr != prev) {
								if (fs.existsSync(curr)) {
									if (appc.fs.isDirWritable(curr)) {
										break;
									} else {
										logger.error(__('Directory "%s" is not writable', curr) + '\n');
										return callback(true);
									}
								}

								prev = curr;
								curr = path.dirname(curr);
							}

							callback(null, dir);
						}
					}
				}, ti.commonOptions(logger, config))
			};
			callback(null, conf);
		})(function (err, result) {
			finished(result);
		});
	};
};

exports.validate = function validate(logger, config, cli) {
	// check if the project already exists
	if (cli.argv.name && !cli.argv.force) {
		var projectDir = path.join(cli.argv['workspace-dir'], cli.argv.name);
		if (fs.existsSync(projectDir)) {
			logger.error(__('Project already exists: %s', projectDir));
			logger.error(__('Either change the project name, workspace directory, or re-run this command with the --force flag.') + '\n');
			process.exit(1);
		}
	}
};

exports.run = function run(logger, config, cli, finished) {
	var projectName = cli.argv.name,
		projectDir = appc.fs.resolvePath(cli.argv['workspace-dir'], projectName),
		type = cli.argv.type;

	var creator;
	if (type == 'app') {
		creator = new (require('../lib/app-creator'))(logger, config, cli);
	} else if (type == 'module') {
		creator = new (require('../lib/module-creator'))(logger, config, cli);
	}

	if (!creator) {
		logger.error(__('Failed to initialize "%s" creator.', type));
		return finished();
	}

	cli.emit('create.pre', creator, function () {
		fs.existsSync(projectDir) || wrench.mkdirSyncRecursive(projectDir);

		creator.run(function (err) {
			if (err) {
				cli.emit('create.finalize', creator, function () {
					logger.error(__("Failed to create project '%s' in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
					finished(err);
				});
			} else {
				async.series(creator.platforms.scrubbed.map(function (platform) {
					return function (next) {
						cli.emit('create.pre.platform.' + platform, creator, function (err) {
							if (err) {
								next(err);
							} else {
								var p = appc.fs.resolvePath(path.dirname(module.filename), '..', '..', platform, 'cli', 'commands', '_create.js');
								if (fs.existsSync(p)) {
									logger.info(__('Copying "%s" platform resources', platform));
									require(p).run(logger, config, cli, creator.projectConfig);
								}
								cli.emit('create.post.platform.' + platform, creator, next);
							}
						});
					};
				}), function (err) {
					cli.emit('create.post', creator, function () {
						cli.emit('create.finalize', creator, function () {
							if (err) {
								logger.error(__("Failed to create project '%s' in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
							} else {
								logger.info(__("Project '%s' created successfully in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
							}
							finished(err);
						});
					});
				});
			}
		});
	});
};

<commit_msg>[TIMOB-16683] Specifying 'ti create -p' no longer defaults to 'all' and now prompts for the platform.<commit_after>/*
 * create.js: Titanium Mobile CLI create command
 *
 * Copyright (c) 2012-2013, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

var appc = require('node-appc'),
	async = require('async'),
	fields = require('fields'),
	fs = require('fs'),
	i18n = appc.i18n(__dirname),
	path = require('path'),
	ti = require('titanium-sdk'),
	wrench = require('wrench'),
	__ = i18n.__,
	__n = i18n.__n;

exports.cliVersion = '>=3.2.1';
exports.desc = __('creates a new mobile application'); // or module

exports.config = function config(logger, config, cli) {
	return function (finished) {
		cli.createHook('create.config', function (callback) {
			var conf,
				idPrefix = config.get('app.idprefix'),
				workspaceDir = config.app.workspace ? appc.fs.resolvePath(config.app.workspace) : null,
				availablePlatforms = {},
				validPlatforms = {};

			workspaceDir && !fs.existsSync(workspaceDir) && (workspaceDir = null);

			// build list of all valid platforms
			ti.platforms.forEach(function (p) {
				if (/^iphone|ios|ipad$/.test(p)) {
					validPlatforms['iphone'] = availablePlatforms['iphone'] = 1;
					validPlatforms['ipad'] = availablePlatforms['ipad'] = 1;
					validPlatforms['ios'] = 1;
				} else {
					validPlatforms[p] = availablePlatforms[p] = 1;
				}
			});

			// add "all"
			validPlatforms['all'] = 1;
			availablePlatforms = ['all'].concat(Object.keys(availablePlatforms));

			conf = {
				flags: {
					force: {
						abbr: 'f',
						desc: __('force project creation even if path already exists')
					}
				},
				options: appc.util.mix({
					id: {
						desc: __("the App ID in the format 'com.companyname.appname'"),
						order: 150,
						prompt: function (callback) {
							callback(fields.text({
								default: idPrefix ? idPrefix.replace(/\.$/, '') + '.' + cli.argv.name.replace(/[ -]/g, '_').replace(/[^a-zA-Z0-9_]/g, '').replace(/_+/g, '_') : undefined,
								promptLabel: __('App ID'),
								validate: conf.options.id.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							if (!value) {
								logger.error(__('Please specify an App ID') + '\n');
								return callback(true);
							}

							// general app id validation
							if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_-]*(\.[a-zA-Z0-9_-]*)*)$/.test(value)) {
								logger.error(__('Invalid App ID "%s"', value));
								logger.error(__('The App ID must consist of letters, numbers, dashes, and underscores.'));
								logger.error(__('Note: Android does not allow dashes and iOS does not allow underscores.'));
								logger.error(__('The first character must be a letter or underscore.'));
								logger.error(__("Usually the App ID is your company's reversed Internet domain name. (i.e. com.example.myapp)") + '\n');
								return callback(true);
							}

							if (cli.argv.platforms.indexOf('android') != -1) {
								if (value.indexOf('-') != -1) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Dashes are not allowed in the App ID when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}

								if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_]*(\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)*)$/.test(value)) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Numbers are not allowed directly after periods when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}

								if (!ti.validAppId(value)) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('The app must not contain Java reserved words when targeting %s.', 'Android'.cyan) + '\n');
									return callback(true);
								}
							} else {
								// android is not in the list of platforms
								var counter = 0;

								if (value.indexOf('-') != -1) {
									logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow dashes in the App ID.'));
									counter++;
								}

								if (!/^([a-zA-Z_]{1}[a-zA-Z0-9_]*(\.[a-zA-Z_]{1}[a-zA-Z0-9_]*)*)$/.test(value)) {
									counter || logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow numbers directly following periods in the App ID.'));
									counter++;
								}

								if (!ti.validAppId(value)) {
									counter || logger.warn(__('The specified App ID is not compatible with the Android platform.'));
									logger.warn(__('Android does not allow Java reserved words in the App ID.'));
									counter++;
								}

								counter && logger.warn(__('If you wish to add Android support, you will need to fix the <id> in the tiapp.xml.') + '\n');
							}

							if (value.indexOf('_') != -1) {
								if (cli.argv.platforms.indexOf('ios') != -1 || cli.argv.platforms.indexOf('iphone') != -1 || cli.argv.platforms.indexOf('ipad') != -1) {
									logger.error(__('Invalid App ID "%s"', value));
									logger.error(__('Underscores are not allowed in the App ID when targeting %s.', 'iOS'.cyan) + '\n');
									return callback(true);
								} else {
									logger.warn(__('The specified App ID is not compatible with the iOS platform.'));
									logger.warn(__('iOS does not allow underscores in the App ID.'));
									logger.warn(__('If you wish to add iOS support, you will need to fix the <id> in the tiapp.xml.') + '\n');
								}
							}

							callback(null, value);
						}
					},
					name: {
						abbr: 'n',
						desc: __('the name of the project'),
						order: 140,
						prompt: function (callback) {
							callback(fields.text({
								promptLabel: __('Project name'),
								validate: conf.options.name.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							if (!value) {
								logger.error(__('Please specify a project name') + '\n');
								return callback(true);
							}

							if (cli.argv.platforms.indexOf('android') != -1 && value.indexOf('&') != -1) {
								if (config.get('android.allowAppNameAmpersands', false)) {
									logger.warn(__('The project name contains an ampersand (&) which will most likely cause problems.'));
									logger.warn(__('It is recommended that you change the app name in the tiapp.xml or define the app name using i18n strings.'));
									logger.warn(__('Refer to %s for more information.', 'http://appcelerator.com/i18n-app-name'.cyan));
								} else {
									logger.error(__('The project name contains an ampersand (&) which will most likely cause problems.'));
									logger.error(__('It is recommended that you change the app name in the tiapp.xml or define the app name using i18n strings.'));
									logger.error(__('Refer to %s for more information.', 'http://appcelerator.com/i18n-app-name'));
									logger.error(__('To allow ampersands in the app name, run:'));
									logger.error('    ti config android.allowAppNameAmpersands true\n');
									return callback(true);
								}
							}

							if (!/^[a-zA-Z]/.test(value)) {
								logger.error(__('The first character of the project name must be a letter.') + '\n');
								return callback(true);
							}

							callback(null, value);
						}
					},
					platforms: {
						abbr: 'p',
						default: !cli.argv.prompt && 'all' || undefined, // if we're prompting, then force the platforms to be prompted for, otherwise force 'all'
						desc: __('the target build platform'),
						order: 120,
						prompt: function (callback) {
							callback(fields.text({
								promptLabel: __('Target platform (%s)', availablePlatforms.join('|')),
								default: 'all',
								validate: conf.options.platforms.validate
							}));
						},
						required: true,
						validate: function (value, callback) {
							var goodValues = {},
								badValues = {};

							// just in case they set -p without a value
							if (value === true) {
								return callback(true);
							}

							value.trim().toLowerCase().split(',').forEach(function (s) {
								if (s = s.trim()) {
									if (validPlatforms[s]) {
										goodValues[s] = 1;
									} else {
										badValues[s] = 1;
									}
								}
							});

							var badLen = Object.keys(badValues).length;
							if (badLen) {
								logger.error(__n('Invalid platform: %%s', 'Invalid platforms: %%s', badLen, Object.keys(badValues).join(', ')) + '\n');
								return callback(true);
							}

							if (goodValues.ios) {
								goodValues.iphone = 1;
								goodValues.ipad = 1;
								delete goodValues.ios;
							}

							if (goodValues.all) {
								goodValues = {};
								availablePlatforms.forEach(function (p) {
									if (p != 'all') {
										goodValues[p] = 1;
									}
								});
							}

							callback(null, Object.keys(goodValues).join(','));
						}
					},
					template: {
						desc: __('the name of the project template to use'),
						default: 'default',
						order: 110,
						required: true
					},
					type: {
						abbr: 't',
						default: 'app',
						desc: __('the type of project to create'),
						order: 100,
						skipValueCheck: true,
						validate: function (value, callback) {
							callback(/^app|module$/.test(value) ? null : new Error(__('Invalid project type "%s"', value)), value);
						},
						values: ['app'] // , 'module']
					},
					url: {
						abbr: 'u',
						default: !cli.argv.prompt && config.get('app.url') || undefined,
						desc: __('your company/personal URL'),
						order: 160,
						prompt: function (callback) {
							callback(fields.text({
								default: config.get('app.url'),
								promptLabel: __('Your company/personal URL')
							}));
						},
						required: !!cli.argv.prompt,
						validate: function (value, callback) {
							callback(null, value);
						}
					},
					'workspace-dir': {
						abbr: 'd',
						default: !cli.argv.prompt && workspaceDir || undefined,
						desc: __('the directory to place the project in'),
						order: 170,
						prompt: function (callback) {
							callback(fields.file({
								complete: true,
								default: workspaceDir || undefined,
								ignoreDirs: new RegExp(config.get('cli.ignoreDirs')),
								ignoreFiles: new RegExp(config.get('cli.ignoreFiles')),
								promptLabel: __('Directory to place project'),
								showHidden: true,
								validate: conf.options['workspace-dir'].validate
							}));
						},
						required: true,
						validate: function (dir, callback) {
							if (!dir) {
								logger.error(__('Please specify the workspace directory') + '\n');
								return callback(true);
							}

							dir = appc.fs.resolvePath(dir);

							// check if the directory is writable
							var prev = null,
								curr = dir;
							while (curr != prev) {
								if (fs.existsSync(curr)) {
									if (appc.fs.isDirWritable(curr)) {
										break;
									} else {
										logger.error(__('Directory "%s" is not writable', curr) + '\n');
										return callback(true);
									}
								}

								prev = curr;
								curr = path.dirname(curr);
							}

							callback(null, dir);
						}
					}
				}, ti.commonOptions(logger, config))
			};
			callback(null, conf);
		})(function (err, result) {
			finished(result);
		});
	};
};

exports.validate = function validate(logger, config, cli) {
	// check if the project already exists
	if (cli.argv.name && !cli.argv.force) {
		var projectDir = path.join(cli.argv['workspace-dir'], cli.argv.name);
		if (fs.existsSync(projectDir)) {
			logger.error(__('Project already exists: %s', projectDir));
			logger.error(__('Either change the project name, workspace directory, or re-run this command with the --force flag.') + '\n');
			process.exit(1);
		}
	}
};

exports.run = function run(logger, config, cli, finished) {
	var projectName = cli.argv.name,
		projectDir = appc.fs.resolvePath(cli.argv['workspace-dir'], projectName),
		type = cli.argv.type;

	var creator;
	if (type == 'app') {
		creator = new (require('../lib/app-creator'))(logger, config, cli);
	} else if (type == 'module') {
		creator = new (require('../lib/module-creator'))(logger, config, cli);
	}

	if (!creator) {
		logger.error(__('Failed to initialize "%s" creator.', type));
		return finished();
	}

	cli.emit('create.pre', creator, function () {
		fs.existsSync(projectDir) || wrench.mkdirSyncRecursive(projectDir);

		creator.run(function (err) {
			if (err) {
				cli.emit('create.finalize', creator, function () {
					logger.error(__("Failed to create project '%s' in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
					finished(err);
				});
			} else {
				async.series(creator.platforms.scrubbed.map(function (platform) {
					return function (next) {
						cli.emit('create.pre.platform.' + platform, creator, function (err) {
							if (err) {
								next(err);
							} else {
								var p = appc.fs.resolvePath(path.dirname(module.filename), '..', '..', platform, 'cli', 'commands', '_create.js');
								if (fs.existsSync(p)) {
									logger.info(__('Copying "%s" platform resources', platform));
									require(p).run(logger, config, cli, creator.projectConfig);
								}
								cli.emit('create.post.platform.' + platform, creator, next);
							}
						});
					};
				}), function (err) {
					cli.emit('create.post', creator, function () {
						cli.emit('create.finalize', creator, function () {
							if (err) {
								logger.error(__("Failed to create project '%s' in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
							} else {
								logger.info(__("Project '%s' created successfully in %s", creator.projectName.cyan, appc.time.prettyDiff(cli.startTime, Date.now())) + '\n');
							}
							finished(err);
						});
					});
				});
			}
		});
	});
};

<|endoftext|>


<commit_before>var SQ = SQ || {};

SQ.Screen = function Screen (canvas, settings) {
	this.canvas = canvas;
	this.ctx = canvas.getContext("2d");
	this.settings = settings;

	if (settings.fullScreen) {
		window.addEventListener("resize", this.resizeHandler.bind(this));
		this.canvas.width = window.innerWidth;
		this.canvas.height = window.innerHeight;
	}
};

SQ.Screen.prototype.drawLayer = function drawLayer (startX, startY, layerdata, layerdatawidth, tileWidth, tileHeight, tiles, targetCtx) {
	if (!targetCtx) {
		targetCtx = this.ctx;
	}
	var maxX = Math.floor((startX + targetCtx.canvas.width) / tileWidth),
		maxY = Math.ceil((startY + targetCtx.canvas.height) / tileHeight);
	for (var x = Math.floor(startX / tileWidth); x < maxX; x++) {
		for (var y = Math.floor(startY / tileHeight); y < maxY; y++) {
			var tileNumber = Math.max(x, 0) + Math.max(y, 0) * layerdatawidth;
			if (!tiles[layerdata[tileNumber]]) {
				continue;
			}
			targetCtx.drawImage(tiles[layerdata[tileNumber]], startX + x * tileWidth, startY + y * tileHeight);
		}
	}
};

SQ.Screen.prototype.resizeHandler = function resizeHandler () {
	if (this.settings.fullScreen) {
		this.canvas.width = window.innerWidth;
		this.canvas.height = window.innerHeight;
	}
};<commit_msg>Shorter default targetCtx + added drawEntity<commit_after>var SQ = SQ || {};

SQ.Screen = function Screen (canvas, settings) {
	this.canvas = canvas;
	this.ctx = canvas.getContext("2d");
	this.settings = settings;

	if (settings.fullScreen) {
		window.addEventListener("resize", this.resizeHandler.bind(this));
		this.canvas.width = window.innerWidth;
		this.canvas.height = window.innerHeight;
	}
};

SQ.Screen.prototype.drawLayer = function drawLayer (startX, startY, layerdata, layerdatawidth, tileWidth, tileHeight, tiles, targetCtx) {
	targetCtx = targetCtx || this.ctx;
	var maxX = Math.floor((startX + targetCtx.canvas.width) / tileWidth),
		maxY = Math.ceil((startY + targetCtx.canvas.height) / tileHeight);
	for (var x = Math.floor(startX / tileWidth); x < maxX; x++) {
		for (var y = Math.floor(startY / tileHeight); y < maxY; y++) {
			var tileNumber = Math.max(x, 0) + Math.max(y, 0) * layerdatawidth;
			if (!tiles[layerdata[tileNumber]]) {
				continue;
			}
			targetCtx.drawImage(tiles[layerdata[tileNumber]], startX + x * tileWidth, startY + y * tileHeight);
		}
	}
};

SQ.Screen.prototype.drawEntitys = function drawEntitys (entityList, targetCtx) {
	targetCtx = targetCtx || this.ctx;

};

SQ.Screen.prototype.resizeHandler = function resizeHandler () {
	if (this.settings.fullScreen) {
		this.canvas.width = window.innerWidth;
		this.canvas.height = window.innerHeight;
	}
};<|endoftext|>


<commit_before>var StylesheetTools = Backbone.View.extend({
    id: 'stylesheet-tools',
    className: 'view',
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function(){
        $(this.el).html(ich.StylesheetTools);
    },
    events: {
        'click .show-fonts' : 'showFonts',
        'click .show-colors' : 'showColors'
    },
    showFonts: function(){
        $('a.show-colors').removeClass('active').addClass('inactive');
        var self = $('a.show-fonts', this.el);
        if(self.hasClass('inactive')){
            self.removeClass('inactive')
                .addClass('active');
            $('#colors', this.el).hide();
            $('#fonts', this.el).show();
        }
        return false;
    },
    showColors: function(){
        $('a.show-fonts').removeClass('active').addClass('inactive');
        var self = $('a.show-colors', this.el);
        if(self.hasClass('inactive')){
            self.removeClass('inactive')
                .addClass('active');
            $('#fonts', this.el).hide();
            $('#colors', this.el).show();
        }
        return false;
    }
});

var ColorPickerToolView = Backbone.View.extend({
    id: 'color-picker',
    initialize: function(options) {
        _.bindAll(this, 'activate', 'pickerChange', 'pickerShow', 'pickerHide');
        this.colorChanged = false;
        this.project = options.project;
        this.render();
        window.app.bind('ready', this.activate);
    },
    render: function() {
        $(this.el).html(ich.ColorPickerToolView);
    },
    activate: function() {
        var that = this,
            visible = false;
        this.colorpicker = $('a', this.el).ColorPicker({
            eventName: 'toggle',
            onChange: that.pickerChange,
            onShow: that.pickerShow,
            onHide: that.pickerHide
        }).bind('click', function() {
            if (!visible) {
                $(this).trigger('toggle');
                visible = true;
            }
            else {
                visible = false;
            }
            return false;
        });
        $(document).bind('click', function() {
            visible = false;
        });
    },
    pickerChange: function(hsb, hex, rgb) {
        this.colorChanged = hex;
    },
    pickerShow: function() {
        var selection = this.project.view.stylesheets.activeTab.codemirror.selection();
        if (selection.match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g)) {
            $(this.colorpicker).ColorPickerSetColor(
                selection.substring(1, selection.length));
        }
        else if (selection.match(/[A-Fa-f0-9]{6}\b|[A-Fa-f0-9]{3}\b/g)) {
            $(this.colorpicker).ColorPickerSetColor(selection);
        }
    },
    pickerHide: function(hsb, hex, rgb) {
        if (this.colorChanged) {
            var mirror = this.project.view.stylesheets.activeTab.codemirror;
            if (mirror.selection().match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g)) {
                mirror.replaceSelection('#' + this.colorChanged);
            }
            else if (mirror.selection().match(/^[A-Fa-f0-9]{6}\b|^[A-Fa-f0-9]{3}\b/g)) {
                mirror.replaceSelection(this.colorChanged);
            }
            this.colorChanged = false;
        }
    }
});

var ColorSwatch = Backbone.Model.extend({
    initialize: function() {
        this.set({ hsl: this.RGBToHSL(this.unpack(this.get('hex'))) });
    },
    /**
     * From farbtastic.
     */
    RGBToHSL: function (rgb) {
      var r = rgb[0], g = rgb[1], b = rgb[2],
          min = Math.min(r, g, b),
          max = Math.max(r, g, b),
          delta = max - min,
          h = 0,
          s = 0,
          l = (min + max) / 2;
      if (l > 0 && l < 1) {
        s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
      }
      if (delta > 0) {
        if (max == r && max != g) h += (g - b) / delta;
        if (max == g && max != b) h += (2 + (b - r) / delta);
        if (max == b && max != r) h += (4 + (r - g) / delta);
        h /= 6;
      }
      return [h, s, l];
    },
    unpack: function (color) {
      if (color.length == 7) {
        function x(i) {
          return parseInt(color.substring(i, i + 2), 16) / 255;
        }
        return [ x(1), x(3), x(5) ];
      }
      else if (color.length == 4) {
        function x(i) {
          return parseInt(color.substring(i, i + 1), 16) / 15;
        }
        return [ x(1), x(2), x(3) ];
      }
    }
});

var ColorSwatchesList = Backbone.Collection.extend({
    model: ColorSwatch,
    initialize: function(models, options) {
        _.bindAll(this, 'reload');
        this.project = options.project;
        this.project.bind('codeMirrorChange', this.reload);
        this.project.bind('ready', this.reload);
    },
    reload: function() {
        var matches = this.project.get('Stylesheet').pluck('data')
            .join('\n').match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g);
        if (!matches) {
            matches = [];
        }
        matches = _.uniq(matches);

        var hexMap = {}
        this.each(function(swatch) { hexMap[swatch.get('hex')]  = swatch; });

        // Get list of models to remove.
        var remove = _.without.apply(this, [this.pluck('hex')].concat(matches));
        var that = this;
        _.each(remove, function(hex) {
            that.remove(hexMap[hex]);
        })

        for (var i = 0; i < matches.length; i++) {
            var pass = false;
            this.forEach(function(color) {
                if (color.get('hex') == matches[i]) {
                    pass = true;
                }
            });
            if (!pass) {
                this.add(new ColorSwatch({hex: matches[i]}));
            }
        }
        // Trigger the deferred add event
        this.trigger('add');
    },
    /**
     * Sort swatches by lightness.
     */
    comparator: function(swatch) {
        return swatch.get('hsl')[2];
    }
});

var ColorSwatchesToolView = Backbone.View.extend({
    id: 'colors',
    className: 'view',
    initialize: function(options) {
        _.bindAll(this, 'render', 'createSwatchView');
        this.collection.bind('add', this.render);
        this.collection.bind('remove', this.del);
        this.project = options.project;
        $(this.el).html(ich.ColorSwatchesToolView());
    },
    render: function() {
        var that = this;
        var pointer = null;
        this.collection.each(function(swatch) {
            if (!swatch.view) {
                swatch.view = new ColorSwatchView({
                    model: swatch,
                    project:that.project
                });
                if (!pointer) {
                    self.$('.swatches').prepend(swatch.view.el);
                }
                else {
                    $(pointer).after(swatch.view.el);
                }
            }
            pointer = swatch.view.el;
        });
    },
    del: function(swatch) {
        swatch.view.remove();
    }
});

var ColorSwatchView = Backbone.View.extend({
    events: {
        'click': 'insertHex'
    },
    initialize: function(options) {
        _.bindAll(this, 'render', 'insertHex');
        this.project = options.project;
        this.render();
    },
    render: function() {
       $(this.el).html(ich.ColorSwatchView({color: this.model.get('hex')}));
       return this;
    },
    insertHex: function() {
        var mirror = this.project.view.stylesheets.activeTab.codemirror;
        var pos = mirror.cursorPosition();
        var hex = this.model.get('hex');
        if (mirror.lineContent(pos.line).charAt(pos.character-1) == '#') {
            mirror.replaceSelection(hex.slice(1));
        }
        else {
            mirror.replaceSelection(hex);
        }
        $(mirror).focus();
        return false;
    }
});

var FontPickerToolView = Backbone.View.extend({
    id: 'font-picker',
    events: {
        'change #fonts': 'insertFont'
    },
    initialize: function(options) {
        _.bindAll(this, 'render', 'insertFont');
        this.project = options.project;
        this.model.fetch({
            success: this.render,
            error: this.render
        });
    },
    //@TODO Having Some trouble here - will work on this in the morning :(
    render: function() {
        var fonts = this.model.get('fonts'),
            console.log(fonts);

        _.each(fonts, function(i){
            fontList = '
' + fonts + '
';
        })

        $(this.el).html(ich.FontPickerToolView({
            fonts: fontList
        }));

        var $input = $('input', this.el),
            $list = $('font-list'),
            formTitle = $input.attr('title');

        // Returns a case-insensitive contains()
        jQuery.expr[':'].Contains = function(a,i,m){
            return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
        };
        $input.change( function () {
            var filter = $input.val();
            if(filter) {
                $list.find('a:not(:Contains(' + filter + '))').parent().slideUp();
                $list.find('a:Contains(' + filter + ')').parent().slideDown();
            } else {
                $list.find('li').slideDown();
            }
            return false;
        })
        .keyup( function () {
            $(this).change();
        });

        function remove() {
          if ($input.val() === formTitle) {
            $input.val('');
          }
        }
        $input.blur(function () {
          $input.val(formTitle);
        }).focus(remove).blur();
        //Also remove if ..
        $input.submit(remove);
        $(window).unload(remove); // For Firefox
    },
    insertFont: function() {
        var mirror = this.project.view.stylesheets.activeTab.codemirror;
        var value = this.$('input').val();
      if(value !== 'Filter list' && value !== '') {
        mirror.replaceSelection('"' + this.$('input').val() + '"');
        $(mirror).focus();
        this.$('input').val('');
      }
    }
});
<commit_msg>Made unexpected token change to app.tools<commit_after>var StylesheetTools = Backbone.View.extend({
    id: 'stylesheet-tools',
    className: 'view',
    initialize: function(options) {
        _.bindAll(this, 'render');
        this.render();
    },
    render: function(){
        $(this.el).html(ich.StylesheetTools);
    },
    events: {
        'click .show-fonts' : 'showFonts',
        'click .show-colors' : 'showColors'
    },
    showFonts: function(){
        $('a.show-colors').removeClass('active').addClass('inactive');
        var self = $('a.show-fonts', this.el);
        if(self.hasClass('inactive')){
            self.removeClass('inactive')
                .addClass('active');
            $('#colors', this.el).hide();
            $('#fonts', this.el).show();
        }
        return false;
    },
    showColors: function(){
        $('a.show-fonts').removeClass('active').addClass('inactive');
        var self = $('a.show-colors', this.el);
        if(self.hasClass('inactive')){
            self.removeClass('inactive')
                .addClass('active');
            $('#fonts', this.el).hide();
            $('#colors', this.el).show();
        }
        return false;
    }
});

var ColorPickerToolView = Backbone.View.extend({
    id: 'color-picker',
    initialize: function(options) {
        _.bindAll(this, 'activate', 'pickerChange', 'pickerShow', 'pickerHide');
        this.colorChanged = false;
        this.project = options.project;
        this.render();
        window.app.bind('ready', this.activate);
    },
    render: function() {
        $(this.el).html(ich.ColorPickerToolView);
    },
    activate: function() {
        var that = this,
            visible = false;
        this.colorpicker = $('a', this.el).ColorPicker({
            eventName: 'toggle',
            onChange: that.pickerChange,
            onShow: that.pickerShow,
            onHide: that.pickerHide
        }).bind('click', function() {
            if (!visible) {
                $(this).trigger('toggle');
                visible = true;
            }
            else {
                visible = false;
            }
            return false;
        });
        $(document).bind('click', function() {
            visible = false;
        });
    },
    pickerChange: function(hsb, hex, rgb) {
        this.colorChanged = hex;
    },
    pickerShow: function() {
        var selection = this.project.view.stylesheets.activeTab.codemirror.selection();
        if (selection.match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g)) {
            $(this.colorpicker).ColorPickerSetColor(
                selection.substring(1, selection.length));
        }
        else if (selection.match(/[A-Fa-f0-9]{6}\b|[A-Fa-f0-9]{3}\b/g)) {
            $(this.colorpicker).ColorPickerSetColor(selection);
        }
    },
    pickerHide: function(hsb, hex, rgb) {
        if (this.colorChanged) {
            var mirror = this.project.view.stylesheets.activeTab.codemirror;
            if (mirror.selection().match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g)) {
                mirror.replaceSelection('#' + this.colorChanged);
            }
            else if (mirror.selection().match(/^[A-Fa-f0-9]{6}\b|^[A-Fa-f0-9]{3}\b/g)) {
                mirror.replaceSelection(this.colorChanged);
            }
            this.colorChanged = false;
        }
    }
});

var ColorSwatch = Backbone.Model.extend({
    initialize: function() {
        this.set({ hsl: this.RGBToHSL(this.unpack(this.get('hex'))) });
    },
    /**
     * From farbtastic.
     */
    RGBToHSL: function (rgb) {
      var r = rgb[0], g = rgb[1], b = rgb[2],
          min = Math.min(r, g, b),
          max = Math.max(r, g, b),
          delta = max - min,
          h = 0,
          s = 0,
          l = (min + max) / 2;
      if (l > 0 && l < 1) {
        s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
      }
      if (delta > 0) {
        if (max == r && max != g) h += (g - b) / delta;
        if (max == g && max != b) h += (2 + (b - r) / delta);
        if (max == b && max != r) h += (4 + (r - g) / delta);
        h /= 6;
      }
      return [h, s, l];
    },
    unpack: function (color) {
      if (color.length == 7) {
        function x(i) {
          return parseInt(color.substring(i, i + 2), 16) / 255;
        }
        return [ x(1), x(3), x(5) ];
      }
      else if (color.length == 4) {
        function x(i) {
          return parseInt(color.substring(i, i + 1), 16) / 15;
        }
        return [ x(1), x(2), x(3) ];
      }
    }
});

var ColorSwatchesList = Backbone.Collection.extend({
    model: ColorSwatch,
    initialize: function(models, options) {
        _.bindAll(this, 'reload');
        this.project = options.project;
        this.project.bind('codeMirrorChange', this.reload);
        this.project.bind('ready', this.reload);
    },
    reload: function() {
        var matches = this.project.get('Stylesheet').pluck('data')
            .join('\n').match(/\#[A-Fa-f0-9]{6}\b|\#[A-Fa-f0-9]{3}\b/g);
        if (!matches) {
            matches = [];
        }
        matches = _.uniq(matches);

        var hexMap = {}
        this.each(function(swatch) { hexMap[swatch.get('hex')]  = swatch; });

        // Get list of models to remove.
        var remove = _.without.apply(this, [this.pluck('hex')].concat(matches));
        var that = this;
        _.each(remove, function(hex) {
            that.remove(hexMap[hex]);
        })

        for (var i = 0; i < matches.length; i++) {
            var pass = false;
            this.forEach(function(color) {
                if (color.get('hex') == matches[i]) {
                    pass = true;
                }
            });
            if (!pass) {
                this.add(new ColorSwatch({hex: matches[i]}));
            }
        }
        // Trigger the deferred add event
        this.trigger('add');
    },
    /**
     * Sort swatches by lightness.
     */
    comparator: function(swatch) {
        return swatch.get('hsl')[2];
    }
});

var ColorSwatchesToolView = Backbone.View.extend({
    id: 'colors',
    className: 'view',
    initialize: function(options) {
        _.bindAll(this, 'render', 'createSwatchView');
        this.collection.bind('add', this.render);
        this.collection.bind('remove', this.del);
        this.project = options.project;
        $(this.el).html(ich.ColorSwatchesToolView());
    },
    render: function() {
        var that = this;
        var pointer = null;
        this.collection.each(function(swatch) {
            if (!swatch.view) {
                swatch.view = new ColorSwatchView({
                    model: swatch,
                    project:that.project
                });
                if (!pointer) {
                    self.$('.swatches').prepend(swatch.view.el);
                }
                else {
                    $(pointer).after(swatch.view.el);
                }
            }
            pointer = swatch.view.el;
        });
    },
    del: function(swatch) {
        swatch.view.remove();
    }
});

var ColorSwatchView = Backbone.View.extend({
    events: {
        'click': 'insertHex'
    },
    initialize: function(options) {
        _.bindAll(this, 'render', 'insertHex');
        this.project = options.project;
        this.render();
    },
    render: function() {
       $(this.el).html(ich.ColorSwatchView({color: this.model.get('hex')}));
       return this;
    },
    insertHex: function() {
        var mirror = this.project.view.stylesheets.activeTab.codemirror;
        var pos = mirror.cursorPosition();
        var hex = this.model.get('hex');
        if (mirror.lineContent(pos.line).charAt(pos.character-1) == '#') {
            mirror.replaceSelection(hex.slice(1));
        }
        else {
            mirror.replaceSelection(hex);
        }
        $(mirror).focus();
        return false;
    }
});

var FontPickerToolView = Backbone.View.extend({
    id: 'font-picker',
    events: {
        'change #fonts': 'insertFont'
    },
    initialize: function(options) {
        _.bindAll(this, 'render', 'insertFont');
        this.project = options.project;
        this.model.fetch({
            success: this.render,
            error: this.render
        });
    },
    //@TODO Having Some trouble here - will work on this in the morning :(
    render: function() {
        var fonts = this.model.get('fonts');

        _.each(fonts, function(i){
            fontList = '
' + fonts + '
';
        });

        $(this.el).html(ich.FontPickerToolView({
            fonts: fontList
        }));

        var $input = $('input', this.el),
            $list = $('font-list'),
            formTitle = $input.attr('title');

        // Returns a case-insensitive contains()
        jQuery.expr[':'].Contains = function(a,i,m){
            return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;
        };
        $input.change( function () {
            var filter = $input.val();
            if(filter) {
                $list.find('a:not(:Contains(' + filter + '))').parent().slideUp();
                $list.find('a:Contains(' + filter + ')').parent().slideDown();
            } else {
                $list.find('li').slideDown();
            }
            return false;
        })
        .keyup( function () {
            $(this).change();
        });

        function remove() {
          if ($input.val() === formTitle) {
            $input.val('');
          }
        }
        $input.blur(function () {
          $input.val(formTitle);
        }).focus(remove).blur();
        //Also remove if ..
        $input.submit(remove);
        $(window).unload(remove); // For Firefox
    },
    insertFont: function() {
        var mirror = this.project.view.stylesheets.activeTab.codemirror;
        var value = this.$('input').val();
      if(value !== 'Filter list' && value !== '') {
        mirror.replaceSelection('"' + this.$('input').val() + '"');
        $(mirror).focus();
        this.$('input').val('');
      }
    }
});
<|endoftext|>


<commit_before>var _ = require('underscore');
var backbone = require('backbone');
var registry = require('./components/datapackage-registry');

// WARN Used just for demo purposes
var VALID_DESCRIPTOR = {
  'name': 'my-dataset',

  'resources': [{
    'path': 'data.csv',

    'schema': {
      'fields': [
        {'name': 'var1', 'type': 'string'},
        {'name': 'var2', 'type': 'integer'},
        {'name': 'var3', 'type': 'number'}
      ]
    }
  }]
};

// Application state changed here
module.exports = backbone.Router.extend({
  routes: {
    '(/)': 'index'
  },

  /**
   * Turn off all UI views except navigation bar which is part of base layout
   */
  deactivateAll: function() {
    _.chain(_.omit(window.APP.layout, ['navbar']))
      .values()
      .invoke('deactivate');

    return this;
  },

  index: function() {
    this.deactivateAll();
    window.APP.layout.navbar.toggleBadge(true);

    window.APP.layout.descriptorEdit
      .activate();

    // WARN Process registry errors here
    registry.get().then(function(D) {
      window.APP.layout.descriptorEdit.layout.registryList
        .reset(new backbone.Collection(D))
        .activate();
    });
  }
});<commit_msg>Download button should be visible no matter there are no non-empty data for download (#26)<commit_after>var _ = require('underscore');
var backbone = require('backbone');
var registry = require('./components/datapackage-registry');

// WARN Used just for demo purposes
var VALID_DESCRIPTOR = {
  'name': 'my-dataset',

  'resources': [{
    'path': 'data.csv',

    'schema': {
      'fields': [
        {'name': 'var1', 'type': 'string'},
        {'name': 'var2', 'type': 'integer'},
        {'name': 'var3', 'type': 'number'}
      ]
    }
  }]
};

// Application state changed here
module.exports = backbone.Router.extend({
  routes: {
    '(/)': 'index'
  },

  /**
   * Turn off all UI views except navigation bar which is part of base layout
   */
  deactivateAll: function() {
    _.chain(_.omit(window.APP.layout, ['navbar']))
      .values()
      .invoke('deactivate');

    return this;
  },

  index: function() {
    this.deactivateAll();
    window.APP.layout.navbar.toggleBadge(true);
    window.APP.layout.download.activate();

    window.APP.layout.descriptorEdit
      .activate();

    // WARN Process registry errors here
    registry.get().then(function(D) {
      window.APP.layout.descriptorEdit.layout.registryList
        .reset(new backbone.Collection(D))
        .activate();
    });
  }
});<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash')
  , raf = require('raf/polyfill')
  , Ribcage
  , extendView;

Ribcage = {
  initialize: function (opts){

    opts = opts || {};

    // if we need to load data before rendering, do it
    if (typeof this.loadData === 'function') {
      this._dataLoaded = false
    }
    // otherwise, assume we have the data already
    else {
      this._dataLoaded = true
    }

    this._nukeOnRender = opts._nukeOnRender
    delete opts._nukeOnRender

    // backbone 1.1+ doesn't auto-set this.options
    this.options = opts

    if(this.beforeInit) {
      this.beforeInit(opts);
    }

    this.template = this.template || opts.template;

    if (!this.template) {
      this.template = function () { return ''; };
    }

    if (this.afterInit) {
      this.afterInit(opts);
    }

    this.render();
  }

, context: function () {
    return _.extend({}, this.options, this.model);
  }

, render: function () {
    var self = this
      , model = this.model;

    if(typeof this.bindEvents === 'function') {
      this.bindEvents()
    }

    if (!this._dataLoaded && typeof this.loadData === 'function') {
      return this.loadData(function () {
        self._dataLoaded = true
        self.render()
      })
    }

    if (this.beforeRender) {
      this.beforeRender();
    }

    // Maintainers of legacy code might want to use this
    // but certainly not YOU, young grasshopper!
    if (this._nukeOnRender) {
      this.closeSubviews();
      this.$el.empty();
    }

    if (this.beforeTemplating) {
      model = this.beforeTemplating();
    }

    if (this.context) {
      model = this.context();
    }

    this.$el.html(this.template(model));

    // As soon as the view is bound to DOM, we need to delegate events and re-render all
    // subviews to keep events intact. -cstumph
    this.delegateEvents()
    this.eachSubview( function eachSubviewInRender (view){
      view.render()
    })

    // I'm not happy deferring here, but backbone's
    // event system is based on the DOM, so my hands
    // are tied. - Daniel
    _.defer(function () {
      self.trigger('afterRender')
    });

    if (this.afterRender) {
      this.afterRender();
    }

    return this;
  }

, proxy: function (name, view){
    this.listenTo(view, name, function proxiedEventCallback(){
      var args = Array.prototype.slice.call(arguments, 0);
      args.splice(0, 0, name);
      this.trigger.apply(this, args);
    })
  }

, eachSubview: function (iterator, context){
    _.each(this.subviews, iterator, context || this);
  }

, _attachSubView: function (view){
    this.subviews = this.subviews || {};
    this.subviewByModelId = this.subviewByModelId || {};

    this.subviews[view.cid] = view;
    if (view.model) {
      if (!this.subviewByModelId[view.model.id]) this.subviewByModelId[view.model.id] = [];
      this.subviewByModelId[view.model.id].push(view);
    }

    return view;
  }

, appendSubview: function (view, el){
    el || (el = this.$el);

    this._attachSubView(view);

    if (view.options.render) view.render()
    el.append(view.el);

    _.defer(function (){
      view.trigger('afterAppend', view);
    });

    if (view.afterAppend) {
      view.afterAppend();
    }
  }

, prependSubview: function (view, el){
    el || (el = this.$el);

    this._attachSubView(view);

    if (view.options.renderOnAppend) view.render()
    el.prepend(view.el);

    _.defer(function () {
      view.trigger('afterPrepend', view);
    });

    if (view.afterPrepend) {
      view.afterPrepend();
    }
  }

, appendSubviews: function (views, el, callback){
    el || (el = this.$el);

    var fragment = document.createDocumentFragment();

    _.each(views, function(view){
      this._attachSubView(view);

      if (view.options.renderOnAppend) view.render()
      fragment.appendChild(view.el);

      _.defer(function () {
        view.trigger('afterAppend', view);
      });

      if (view.afterAppend) {
        view.afterAppend();
      }
    }, this);

    raf.call(window, function(){
      el[0].appendChild(fragment);
      if (_.isFunction(callback)) callback(views);
    });
  }

, batchAppendSubviews: function (views, el, batchCount, batchCallback, callback){
    var self = this
      , batches = _(views)
                  .groupBy( function (view, index){
                    return Math.floor(index / batchCount);
                  })
                  .toArray()
                  .valueOf();

    function appendNextBatch () {
      if(!batches.length && typeof callback === 'function') {
        return callback();
      }

      var viewBatch = batches.shift();

      self.appendSubviews(viewBatch, el, function (){
        if (typeof batchCallback === 'function') {
          batchCallback(viewBatch);
        }

        appendNextBatch();
      });
    }

    appendNextBatch();
  }

, close: function close(options, callback) {
    options || (options = {})

    if (this.beforeClose) {
      this.beforeClose();
    }

    this.closeSubviews({keepDom: true}, _.bind(function onSubviewsClosed(){
      this.stopListening();

      // when the subviews are closed, close the parent
      // keep the DOM elements, b/c it's save to assume that all child DOM
      // is containted by the parent DOM container. This allows us to reduce
      // many DOM removal calls to just one.
      if (!options.keepDom) {
        raf.call(window, function closeRequestAnimationFrame(){
          // remove the from the DOM
          if (this.$el) this.$el.remove()
          // destroy our reference to the DOM node
          this.$el = null
          this.el = null
          if (_.isFunction(callback)) callback()
        }.bind(this))
      }
      else if (_.isFunction(callback)) callback()
    }, this));
  }

, closeSubviews: function (options, callback){
    var subviewCount = _.size(this.subviews)
      , done

    if (_.isFunction(callback)){
      // if there are no subviews to close, just call the callback
      if (!subviewCount) return void callback()
      else done = _.after(subviewCount, callback)
    }

    this.eachSubview( function (subview){
      subview.close(options, done);
    });

    this.subviews = {};
  }

, detachSubview: function (view){
    var msg

    if (this.subviews) {

      if (view && !this.subviews[view.cid]) {
        msg = 'View not found in ' + this.className + '\'s subviews: ' + view.className

        if(view.model)
          msg += '\n\n'+ view.model.toJSON()

        throw new Error(msg)
      }

      delete this.subviews[view.cid];
    }

    view.$el.detach();
  }

, _removeSubviewByModel: function _removeSubviewByModel(model, method){
    var id = model.id
    if (this.subviewByModelId){
      if (!id || !this.subviewByModelId[id]){
        throw new Error('No views with ' + id + ' model id found in ' + this.className + ' subviews');
      }

      _.each(this.subviewByModelId[id], function(view){
        method(view);
      }, this);

      delete this.subviewByModelId[id];
    }

  }

, closeSubviewsByModel: function closeSubviewsByModel(model){
    this._removeSubviewByModel(model, this.close)
  }

, detachSubviewByModel: function detachSubviewByModel(model){
    this._removeSubviewByModel(model, this.detachSubview)
  }

};//end Ribcage{}

extendView = function (view){
  return view.extend(Ribcage);
};

module.exports = extendView;
<commit_msg>Memory leak fix on subview closing<commit_after>'use strict';

var _ = require('lodash')
  , raf = require('raf/polyfill')
  , Ribcage
  , extendView;

Ribcage = {
  initialize: function (opts){

    opts = opts || {};

    // if we need to load data before rendering, do it
    if (typeof this.loadData === 'function') {
      this._dataLoaded = false
    }
    // otherwise, assume we have the data already
    else {
      this._dataLoaded = true
    }

    this._nukeOnRender = opts._nukeOnRender
    delete opts._nukeOnRender

    // backbone 1.1+ doesn't auto-set this.options
    this.options = opts

    if(this.beforeInit) {
      this.beforeInit(opts);
    }

    this.template = this.template || opts.template;

    if (!this.template) {
      this.template = function () { return ''; };
    }

    if (this.afterInit) {
      this.afterInit(opts);
    }

    this.render();
  }

, context: function () {
    return _.extend({}, this.options, this.model);
  }

, render: function () {
    var self = this
      , model = this.model;

    if(typeof this.bindEvents === 'function') {
      this.bindEvents()
    }

    if (!this._dataLoaded && typeof this.loadData === 'function') {
      return this.loadData(function () {
        self._dataLoaded = true
        self.render()
      })
    }

    if (this.beforeRender) {
      this.beforeRender();
    }

    // Maintainers of legacy code might want to use this
    // but certainly not YOU, young grasshopper!
    if (this._nukeOnRender) {
      this.closeSubviews();
      this.$el.empty();
    }

    if (this.beforeTemplating) {
      model = this.beforeTemplating();
    }

    if (this.context) {
      model = this.context();
    }

    this.$el.html(this.template(model));

    // As soon as the view is bound to DOM, we need to delegate events and re-render all
    // subviews to keep events intact. -cstumph
    this.delegateEvents()
    this.eachSubview( function eachSubviewInRender (view){
      view.render()
    })

    // I'm not happy deferring here, but backbone's
    // event system is based on the DOM, so my hands
    // are tied. - Daniel
    _.defer(function () {
      self.trigger('afterRender')
    });

    if (this.afterRender) {
      this.afterRender();
    }

    return this;
  }

, proxy: function (name, view){
    this.listenTo(view, name, function proxiedEventCallback(){
      var args = Array.prototype.slice.call(arguments, 0);
      args.splice(0, 0, name);
      this.trigger.apply(this, args);
    })
  }

, eachSubview: function (iterator, context){
    _.each(this.subviews, iterator, context || this);
  }

, _attachSubView: function (view){
    this.subviews = this.subviews || {};
    this.subviewByModelId = this.subviewByModelId || {};

    this.subviews[view.cid] = view;
    if (view.model) {
      if (!this.subviewByModelId[view.model.id]) this.subviewByModelId[view.model.id] = [];
      this.subviewByModelId[view.model.id].push(view);
    }

    return view;
  }

, appendSubview: function (view, el){
    el || (el = this.$el);

    this._attachSubView(view);

    if (view.options.render) view.render()
    el.append(view.el);

    _.defer(function (){
      view.trigger('afterAppend', view);
    });

    if (view.afterAppend) {
      view.afterAppend();
    }
  }

, prependSubview: function (view, el){
    el || (el = this.$el);

    this._attachSubView(view);

    if (view.options.renderOnAppend) view.render()
    el.prepend(view.el);

    _.defer(function () {
      view.trigger('afterPrepend', view);
    });

    if (view.afterPrepend) {
      view.afterPrepend();
    }
  }

, appendSubviews: function (views, el, callback){
    el || (el = this.$el);

    var fragment = document.createDocumentFragment();

    _.each(views, function(view){
      this._attachSubView(view);

      if (view.options.renderOnAppend) view.render()
      fragment.appendChild(view.el);

      _.defer(function () {
        view.trigger('afterAppend', view);
      });

      if (view.afterAppend) {
        view.afterAppend();
      }
    }, this);

    raf.call(window, function(){
      el[0].appendChild(fragment);
      if (_.isFunction(callback)) callback(views);
    });
  }

, batchAppendSubviews: function (views, el, batchCount, batchCallback, callback){
    var self = this
      , batches = _(views)
                  .groupBy( function (view, index){
                    return Math.floor(index / batchCount);
                  })
                  .toArray()
                  .valueOf();

    function appendNextBatch () {
      if(!batches.length && typeof callback === 'function') {
        return callback();
      }

      var viewBatch = batches.shift();

      self.appendSubviews(viewBatch, el, function (){
        if (typeof batchCallback === 'function') {
          batchCallback(viewBatch);
        }

        appendNextBatch();
      });
    }

    appendNextBatch();
  }

, close: function close(options, callback) {
    options || (options = {})

    if (this.beforeClose) {
      this.beforeClose();
    }

    this.closeSubviews({keepDom: true}, _.bind(function onSubviewsClosed(){
      this.stopListening();

      // when the subviews are closed, close the parent
      // keep the DOM elements, b/c it's save to assume that all child DOM
      // is containted by the parent DOM container. This allows us to reduce
      // many DOM removal calls to just one.
      if (!options.keepDom) {
        raf.call(window, function closeRequestAnimationFrame(){
          // remove the from the DOM
          if (this.$el) this.$el.remove()
          // destroy our reference to the DOM node
          this.$el = null
          this.el = null
          if (_.isFunction(callback)) callback()
        }.bind(this))
      }
      else if (_.isFunction(callback)) callback()
    }, this));
  }

, closeSubviews: function (options, callback){
    var subviewCount = _.size(this.subviews)
      , done

    if (_.isFunction(callback)){
      // if there are no subviews to close, just call the callback
      if (!subviewCount) return void callback()
      else done = _.after(subviewCount, callback)
    }

    this.eachSubview( function (subview){
      subview.close(options, done);
    });

    // empty out our lists of subviews
    this.subviews = {}
    this.subviewByModelId = {}
  }

, detachSubview: function (view){
    var msg

    if (this.subviews) {

      if (view && !this.subviews[view.cid]) {
        msg = 'View not found in ' + this.className + '\'s subviews: ' + view.className

        if(view.model)
          msg += '\n\n'+ view.model.toJSON()

        throw new Error(msg)
      }

      delete this.subviews[view.cid];
    }

    view.$el.detach();
  }

, _removeSubviewByModel: function _removeSubviewByModel(model, method){
    var id = model.id
    if (this.subviewByModelId){
      if (!id || !this.subviewByModelId[id]){
        throw new Error('No views with ' + id + ' model id found in ' + this.className + ' subviews');
      }

      _.each(this.subviewByModelId[id], function(view){
        method(view);
      }, this);

      delete this.subviewByModelId[id];
    }

  }

, closeSubviewsByModel: function closeSubviewsByModel(model){
    this._removeSubviewByModel(model, this.close)
  }

, detachSubviewByModel: function detachSubviewByModel(model){
    this._removeSubviewByModel(model, this.detachSubview)
  }

};//end Ribcage{}

extendView = function (view){
  return view.extend(Ribcage);
};

module.exports = extendView;
<|endoftext|>


<commit_before>/**
 * Cf. JavaScript Ninja, pp. 145ff.
 * http://ejohn.org/blog/simple-javascript-inheritance
 *
 * My version differs from the book in 3 ways:
 * 1) It doesn't check for whether the corresponding
 *    _super method is called by the overriding subclass method.
 * 2) No functionality is added directly to the built-in
 *    JavaScript Object.
 * 3) The reference to arguments.callee (likely to be
 *    deprecated) is eliminated.
 */

(function () {
    var initializing = false;

    // generic base class
    this.Base = function() {};

    Base.extend = function extend(properties) {
        var _super = this.prototype,
            proto,
            name;

        initializing = true;
        proto = new this();
        initializing = false;

        // leaving out check for presence of "_super" string
        for (name in properties) {
            proto[name] = typeof properties[name] === "function" &&
                typeof _super[name] === "function" ? (function (name, fn) {
                    return function () {
                        var tmp = this._super,
                            ret;

                        this._super = _super[name];
                        ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(name, properties[name]) : properties[name];
        }

        function Class() {
            if (!initializing && this.init) {
                this.init.apply(this, arguments);
            }
        }

        Class.prototype = proto;
        Class.constructor = Class;
        Class.extend = extend;
        return Class;
    };
})();
<commit_msg>Improve description and add copyright<commit_after>/**
 * extend.js
 * Copyright (c) 2013 Marshall Farrier
 * http://www.opensource.org/licenses/mit-license.php
 *
 * For background to this script
 * cf. John Resig, Secrets of the JavaScript Ninja, pp. 145ff.
 * http://ejohn.org/blog/simple-javascript-inheritance
 *
 * My version differs from Resig's in 3 ways:
 * 1) It doesn't check for whether the corresponding
 *    _super method is called by the overriding subclass method.
 *    (seems to me like too much overhead since the if-condition
 *    is only met if the superclass already has the given method)
 * 2) No functionality is added directly to the built-in
 *    JavaScript Object.
 * 3) The reference to arguments.callee (likely to be
 *    deprecated) is eliminated.
 */

(function () {
    var initializing = false;

    // generic base class
    this.Base = function() {};

    Base.extend = function extend(properties) {
        var _super = this.prototype,
            proto,
            name;

        initializing = true;
        proto = new this();
        initializing = false;

        // leaving out check for presence of "_super" string
        for (name in properties) {
            proto[name] = typeof properties[name] === "function" &&
                typeof _super[name] === "function" ? (function (name, fn) {
                    return function () {
                        var tmp = this._super,
                            ret;

                        this._super = _super[name];
                        ret = fn.apply(this, arguments);
                        this._super = tmp;
                        return ret;
                    };
                })(name, properties[name]) : properties[name];
        }

        function Class() {
            if (!initializing && this.init) {
                this.init.apply(this, arguments);
            }
        }

        Class.prototype = proto;
        Class.constructor = Class;
        Class.extend = extend;
        return Class;
    };
})();
<|endoftext|>


<commit_before>(function( $ ) {

    $.fn.fanoos = function(options) {

      var settings = $.extend({ // These are the defaults.
        animationClass: 'animated', // css animation univetsal class
        duration: 1000, // css animation duration (ms)
        offset: 0, // offset form top of the image
        delay: 0 // delay on playing animation
      }, options );

      var elementList = []; // a global list of fanoos elements

      function init() { // init function: gets all elements who need fanoos to animate them

        var elementNumber = 0; // start point of list

        $('.fanoos').each(function() { // for all fanoos element

          var tempSettings = { // These are the unique settings
            duration: settings.duration, // TEMP css animation duration (ms)
            offset: settings.offset, // TEMP offset form top of the image
            delay: settings.delay // TEMP delay on playing animation
          }

          if ( $(this).attr('data-fanoos-id') == null || $(this).attr('data-fanoos-id').length == 0) { // if element didn't have a data-fanoos-id
            var fanoosId = 'fanoosElement' + elementNumber; // create a fanoos ID
            $(this).attr('data-fanoos-id', 'fanoosElement' + elementNumber); // and add it to data-fanoos-id
          } else {
            var fanoosId = $(this).attr('data-fanoos-id'); // or just use the one it has
          };

          if ( typeof $(this).attr('data-fanoos-offset') !== typeof undefined && $(this).attr('data-fanoos-offset') !== false ) { // if element had a data-fanoos-offset
            tempSettings.offset = parseInt( $(this).attr('data-fanoos-offset') ); // update settings
          };

          if ( typeof $(this).attr('data-fanoos-delay') !== typeof undefined && $(this).attr('data-fanoos-offset') !== false ) { // if element had a data-fanoos-delay
            tempSettings.delay = parseInt( Math.abs($(this).attr('data-fanoos-delay')) ); // update settings
          };

          if ( typeof $(this).attr('data-fanoos-duration') !== typeof undefined && $(this).attr('data-fanoos-duration') !== false ) { // if element had a data-fanoos-duration
            tempSettings.duration = parseInt( Math.abs($(this).attr('data-fanoos-duration')) ); // update settings
          };

          $(this).addClass(settings.animationClass).css({
            'animation-play-state': 'paused',
            'animation-duration': tempSettings.duration + 'ms',
            'animation-delay': tempSettings.delay + 'ms',
          }); // add animation class but don't let it play

          var element = { // create a fannos element
            'fanoosID' : fanoosId, // ID
            'offsetTop'  : Math.ceil($(this).offset().top) + tempSettings.offset // position from top
          }

          elementList.push(element); // add elment to list

          elementNumber++; // go for next elment
        });

      }

      function run(element) { // run function: play element's css animation
        element.css("animation-play-state", "running"); // play the animation
      }

      function action(){ // action function: connect run funtion to real world

        var resultList = $.grep(elementList, function(e){ // a list of fanoos elements that should be played
          return e.offsetTop <= ($(window).scrollTop() + $(window).height()); // just when bottom of window reached element
        });

        if (resultList.length > 0) { // if result list had any elements in it
          for (var i = 0; i < resultList.length; i++) {
            run( $('[data-fanoos-id="' + resultList[i].fanoosID + '"]') ); // play them one by one
          }
        }

      }

      init(); // initiate fanoos

      $(window).scroll(function(){ // do action when scrolling
        action();
      });

      $( document ).ready(function(){ // do action when document is loaded
        action();
      });

    }
}( jQuery ));
<commit_msg>Added workOnMobile Option<commit_after>(function( $ ) {

    $.fn.fanoos = function(options) {

      var settings = $.extend({ // These are the defaults.
        animationClass: 'animated', // css animation univetsal class
        duration: 1000, // css animation duration (ms)
        offset: 0, // offset form top of the image (px)
        delay: 0, // delay on playing animation (ms)
        workOnMobile: false, // whether work on mobile or not
        mobileWidth: 768 // Mobile max Width (px)
      }, options );

      var elementList = []; // a global list of fanoos elements
      var windowWidth = $(window).outerWidth(); // width of window (to check for responsiveness)

      function init() { // init function: gets all elements who need fanoos to animate them

        var elementNumber = 0; // start point of list

        $('.fanoos').each(function() { // for all fanoos element

          var tempSettings = { // These are the unique settings
            duration: settings.duration, // TEMP css animation duration (ms)
            offset: settings.offset, // TEMP offset form top of the image
            delay: settings.delay, // TEMP delay on playing animation
            workOnMobile: settings.workOnMobile // whether work on mobile or not
          }

          if ( $(this).attr('data-fanoos-id') == null || $(this).attr('data-fanoos-id').length == 0) { // if element didn't have a data-fanoos-id
            var fanoosId = 'fanoosElement' + elementNumber; // create a fanoos ID
            $(this).attr('data-fanoos-id', 'fanoosElement' + elementNumber); // and add it to data-fanoos-id
          } else {
            var fanoosId = $(this).attr('data-fanoos-id'); // or just use the one it has
          };

          if ( typeof $(this).attr('data-fanoos-offset') !== typeof undefined && $(this).attr('data-fanoos-offset') !== false ) { // if element had a data-fanoos-offset
            tempSettings.offset = parseInt( $(this).attr('data-fanoos-offset') ); // update settings
          };

          if ( typeof $(this).attr('data-fanoos-delay') !== typeof undefined && $(this).attr('data-fanoos-offset') !== false ) { // if element had a data-fanoos-delay
            tempSettings.delay = parseInt( Math.abs($(this).attr('data-fanoos-delay')) ); // update settings
          };

          if ( typeof $(this).attr('data-fanoos-duration') !== typeof undefined && $(this).attr('data-fanoos-duration') !== false ) { // if element had a data-fanoos-duration
            tempSettings.duration = parseInt( Math.abs($(this).attr('data-fanoos-duration')) ); // update settings
          };

          if ( typeof $(this).attr('data-fanoos-workOnMobile') !== typeof undefined ) { // if element had a data-fanoos-workOnMobile
            tempSettings.workOnMobile = $(this).attr('data-fanoos-workOnMobile'); // update settings
          };

          if ( windowWidth < settings.mobileWidth && tempSettings.workOnMobile ) {
            addElement($(this)); // add element to list and do stuff
          } else if ( windowWidth >= settings.mobileWidth ) {
            addElement($(this)); // add element to list and do stuff
          }

          function addElement(thisElement){

            thisElement.addClass(settings.animationClass).css({
              'animation-play-state': 'paused',
              'animation-duration': tempSettings.duration + 'ms',
              'animation-delay': tempSettings.delay + 'ms',
            }); // add animation class but don't let it play

            var element = { // create a fannos element
              'fanoosID' : fanoosId, // ID
              'offsetTop'  : Math.ceil(thisElement.offset().top) + tempSettings.offset // position from top
            }

            elementList.push(element); // add elment to list

            elementNumber++; // go for next elment

          }

        });

      }

      function run(element) { // run function: play element's css animation
        element.css("animation-play-state", "running"); // play the animation
      }

      function action(){ // action function: connect run funtion to real world

        var resultList = $.grep(elementList, function(e){ // a list of fanoos elements that should be played
          return e.offsetTop <= ($(window).scrollTop() + $(window).height()); // just when bottom of window reached element
        });

        if (resultList.length > 0) { // if result list had any elements in it
          for (var i = 0; i < resultList.length; i++) {
            run( $('[data-fanoos-id="' + resultList[i].fanoosID + '"]') ); // play them one by one
          }
        }

      }

      init(); // initiate fanoos

      $(window).scroll(function(){ // do action when scrolling
        action();
      });

      $( document ).ready(function(){ // do action when document is loaded
        action();
      });

    }
}( jQuery ));
<|endoftext|>


<commit_before>"use strict";function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}function genUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=16*Math.random()|0,v="x"==c?r:3&r|8;return v.toString(16)})}var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||!1,descriptor.configurable=!0,"value"in descriptor&&(descriptor.writable=!0),Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){return protoProps&&defineProperties(Constructor.prototype,protoProps),staticProps&&defineProperties(Constructor,staticProps),Constructor}}();"undefined"==typeof window&&(global.window=global);var Pathname=function(){function Pathname(input){_classCallCheck(this,Pathname),this.input=input,this.clean=this.cleanf(),this.chop=this.chopf(),this.name=this.namef(),this.basename=this.basenamef(),this.parent=this.parentf(),this.extentions=this.extentionsf(),this.segment=this.segmentf()}return _createClass(Pathname,[{key:"cleanf",value:function(){var clean=[],pathArray=this.input.match(/[^\/]+/g);for(var i in pathArray){var name=pathArray[i];"."===name||(".."===name?clean.pop():clean.push(name))}return"/"+clean.join("/")}},{key:"chopf",value:function(){var segments=this.clean.match(/[^\/]+/g);return null===segments?["/"]:segments}},{key:"namef",value:function(){return this.chop[this.chop.length-1]}},{key:"basenamef",value:function(){var name=this.name;if(""===name)return name;var base=name.match(/^[^\.]+/);return null!==base?base[0]:""}},{key:"parentf",value:function(){if("/"===this.name)return null;var parentLen=this.clean.length-this.name.length;return this.clean.slice(0,parentLen)}},{key:"extentionsf",value:function(){return this.name.match(/\.[^\.]+/g)}},{key:"segmentf",value:function(){var pathArray=this.chop,segments=[];if("/"===this.name)segments=["/"];else for(var i=0;i<=pathArray.length;i++){var matchPath=pathArray.slice(0,i);segments.push("/"+matchPath.join("/"))}return segments}}]),Pathname}(),Inode=function Inode(){var config=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};_classCallCheck(this,Inode),this.links=0,Object.assign(this,config)},Disk=function(){function Disk(){_classCallCheck(this,Disk),this.uuid=genUUID(),this.inodes=[new Inode({links:1,id:0,type:"d",files:{".":0,"..":0}})]}return _createClass(Disk,[{key:"addInode",value:function(type){var name=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,parentInode=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(name.match("/"))return console.warn("No '/' allowed in a name"),-1;var id=this.inodes.length;return this.inodes[id]=new Inode({links:1,type:type,id:id}),parentInode instanceof Inode&&"d"===parentInode.type&&(parentInode.files[name]=id),this.inodes[id]}},{key:"mkFile",value:function(name,parentInode){var inode=this.addInode("f",name,parentInode);return inode<0?-1:(inode.data="",inode)}},{key:"mkDir",value:function(name,parentInode){var inode=this.addInode("d",name,parentInode);return inode<0?-1:(inode.files={".":inode.id,"..":parentInode.id},inode)}},{key:"mkLink",value:function(name,parentInode,targetInode){return name.match("/")?(console.warn("No '/' allowed in a name"),-1):(parentInode.files[name]=targetInode.id,targetInode)}},{key:"mkSymLink",value:function(name,parentInode,targetPath){var inode=this.addInode("sl",name,parentInode);if(inode<0)return-1;var path=new Pathname(targetPath).clean;return inode.redirect=path,inode}}]),Disk}(),VFS=function(){function VFS(rootDisk){_classCallCheck(this,VFS),this.mounts={"/":rootDisk}}return _createClass(VFS,[{key:"mount",value:function(disk,mountPoint){return this.mounts[mountPoint]=disk}},{key:"unmount",value:function(mountPoint){return delete this.mounts[mountPoint]}},{key:"unmountByUUID",value:function(uuid){var mountPoints=Object.keys(box.fs.mounts);for(var i in mountPoints){var mountPoint=mountPoints[i];if(this.mounts[mountPoint].uuid===uuid)return delete this.mounts[mountPoint]}}},{key:"mountPoint",value:function mountPoint(path){var pathname=new Pathname(path),segments=pathname.segment,mounts=Object.keys(this.mounts),resolves=[];for(var i in mounts){var mount=new Pathname(mounts[i]).clean;for(var _i in segments)segments[_i]===mount&&resolves.push(mount)}var mountPoint=resolves.pop();return mountPoint}},{key:"resolveHard",value:function(path){var inode=0,trace=[inode],pathname=new Pathname(path),mountPoint=this.mountPoint(pathname.clean),disk=this.mounts[mountPoint],diskLocalPath=pathname.clean.substring(mountPoint.length);if(""===diskLocalPath)return disk.inodes[inode];var pathArray=new Pathname(diskLocalPath).chop;for(var i in pathArray){var name=pathArray[i],inodeObj=disk.inodes[inode];if(void 0===inodeObj.files)return console.warn("Could not resolve path to inodes completely, stopping at inode : "+inode),console.warn(trace),-1;if(inode=inodeObj.files[name],void 0===inode)return console.warn("Could not find end inode, failed at segment name : "+name),console.warn(trace),-1;trace.push(inode)}return disk.inodes[trace.pop()]}},{key:"resolve",value:function(path){var redirectCount=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;if(redirectCount>=50)return console.warn("Max symbolic link redirect count reached (50) at "+path),-1;var inode=this.resolveHard(path);return inode<0?(console.warn("Error on hard resolve"),-1):"sl"===inode.type?(redirectCount++,this.resolve(inode.redirect,redirectCount)):inode}},{key:"rm",value:function(path){var pathname=new Pathname(path),parent=pathname.parent,parentInode=this.resolve(parent),name=pathname.name;return parentInode<0?(console.warn("Parent directory, "+parent+" not resolved"),-1):delete parentInode.files[name]}},{key:"mkPath",value:function(type,path){var target=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,pathname=new Pathname(path),parent=pathname.parent,parentInode=this.resolve(parent),name=pathname.name,mountPoint=this.mountPoint(pathname.clean),disk=this.mounts[mountPoint];if(parentInode<0)return console.warn("Parent directory, "+parent+" not resolved"),-1;var addedInode=-1;if("f"===type)addedInode=disk.mkFile(name,parentInode);else if("d"===type)addedInode=disk.mkDir(name,parentInode);else if("l"===type&&null!==target){var targetInode=this.resolve(target);if(targetInode<0)return console.warn("Target inode to hard link not resolved"),-1;addedInode=disk.mkLink(name,parentInode,targetInode)}else{if("sl"!==type||null===target)return console.warn("Unknown type : "+type),-1;addedInode=disk.mkSymLink(name,parentInode,target)}return addedInode<0?(console.warn("Inode addition error"),-1):addedInode}},{key:"touch",value:function(path){return this.mkPath("f",path)}},{key:"mkdir",value:function(path){return this.mkPath("d",path)}},{key:"ln",value:function(path,targetPath){return this.mkPath("l",path,targetPath)}},{key:"lns",value:function(path,targetPath){return this.mkPath("sl",path,targetPath)}}]),VFS}(),Computer=function Computer(name){_classCallCheck(this,Computer),this.name=name,this.fs=new VFS(new Disk)};window.box=new Computer("fauxOS");<commit_msg>built latest<commit_after>"use strict";function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor))throw new TypeError("Cannot call a class as a function")}function genUUID(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=16*Math.random()|0,v="x"==c?r:3&r|8;return v.toString(16)})}var _createClass=function(){function defineProperties(target,props){for(var i=0;i<props.length;i++){var descriptor=props[i];descriptor.enumerable=descriptor.enumerable||!1,descriptor.configurable=!0,"value"in descriptor&&(descriptor.writable=!0),Object.defineProperty(target,descriptor.key,descriptor)}}return function(Constructor,protoProps,staticProps){return protoProps&&defineProperties(Constructor.prototype,protoProps),staticProps&&defineProperties(Constructor,staticProps),Constructor}}();"undefined"==typeof window&&(global.window=global);var Pathname=function(){function Pathname(input){_classCallCheck(this,Pathname),this.input=input,this.clean=this.cleanf(),this.chop=this.chopf(),this.name=this.namef(),this.basename=this.basenamef(),this.parent=this.parentf(),this.extentions=this.extentionsf(),this.segment=this.segmentf()}return _createClass(Pathname,[{key:"cleanf",value:function(){var clean=[],pathArray=this.input.match(/[^\/]+/g);for(var i in pathArray){var name=pathArray[i];"."===name||(".."===name?clean.pop():clean.push(name))}return"/"+clean.join("/")}},{key:"chopf",value:function(){var segments=this.clean.match(/[^\/]+/g);return null===segments?["/"]:segments}},{key:"namef",value:function(){return this.chop[this.chop.length-1]}},{key:"basenamef",value:function(){var name=this.name;if(""===name)return name;var base=name.match(/^[^\.]+/);return null!==base?base[0]:""}},{key:"parentf",value:function(){if("/"===this.name)return null;var parentLen=this.clean.length-this.name.length;return this.clean.slice(0,parentLen)}},{key:"extentionsf",value:function(){return this.name.match(/\.[^\.]+/g)}},{key:"segmentf",value:function(){var pathArray=this.chop,segments=[];if("/"===this.name)segments=["/"];else for(var i=0;i<=pathArray.length;i++){var matchPath=pathArray.slice(0,i);segments.push("/"+matchPath.join("/"))}return segments}}]),Pathname}(),Inode=function Inode(){var config=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};_classCallCheck(this,Inode),this.links=0,Object.assign(this,config)},Disk=function(){function Disk(){_classCallCheck(this,Disk),this.uuid=genUUID(),this.inodes=[new Inode({links:1,id:0,type:"d",files:{".":0,"..":0}})]}return _createClass(Disk,[{key:"addInode",value:function(type){var name=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,parentInode=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null;if(name.match("/"))return-1;var id=this.inodes.length;return this.inodes[id]=new Inode({links:1,type:type,id:id}),parentInode instanceof Inode&&"d"===parentInode.type&&(parentInode.files[name]=id),this.inodes[id]}},{key:"mkFile",value:function(name,parentInode){var inode=this.addInode("f",name,parentInode);return inode<0?-1:(inode.data="",inode)}},{key:"mkDir",value:function(name,parentInode){var inode=this.addInode("d",name,parentInode);return inode<0?-1:(inode.files={".":inode.id,"..":parentInode.id},inode)}},{key:"mkLink",value:function(name,parentInode,targetInode){return name.match("/")?-1:(parentInode.files[name]=targetInode.id,targetInode)}},{key:"mkSymLink",value:function(name,parentInode,targetPath){var inode=this.addInode("sl",name,parentInode);if(inode<0)return-1;var path=new Pathname(targetPath).clean;return inode.redirect=path,inode}}]),Disk}(),VFS=function(){function VFS(rootDisk){_classCallCheck(this,VFS),this.mounts={"/":rootDisk},this.opened={}}return _createClass(VFS,[{key:"mount",value:function(disk,mountPoint){return this.mounts[mountPoint]=disk}},{key:"unmount",value:function(mountPoint){return delete this.mounts[mountPoint]}},{key:"unmountByUUID",value:function(uuid){var mountPoints=Object.keys(box.fs.mounts);for(var i in mountPoints){var mountPoint=mountPoints[i];if(this.mounts[mountPoint].uuid===uuid)return delete this.mounts[mountPoint]}}},{key:"mountPoint",value:function mountPoint(path){var pathname=new Pathname(path),segments=pathname.segment,mounts=Object.keys(this.mounts),resolves=[];for(var i in mounts){var mount=new Pathname(mounts[i]).clean;for(var _i in segments)segments[_i]===mount&&resolves.push(mount)}var mountPoint=resolves.pop();return mountPoint}},{key:"resolveHard",value:function(path){var inode=0,trace=[inode],pathname=new Pathname(path),mountPoint=this.mountPoint(pathname.clean),disk=this.mounts[mountPoint],diskLocalPath=pathname.clean.substring(mountPoint.length);if(""===diskLocalPath)return disk.inodes[inode];var pathArray=new Pathname(diskLocalPath).chop;for(var i in pathArray){var name=pathArray[i],inodeObj=disk.inodes[inode];if(void 0===inodeObj.files)return-1;if(inode=inodeObj.files[name],void 0===inode)return-1;trace.push(inode)}return disk.inodes[trace.pop()]}},{key:"resolve",value:function(path){var redirectCount=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;if(redirectCount>=50)return-1;var inode=this.resolveHard(path);return inode<0?-1:"sl"===inode.type?(redirectCount++,this.resolve(inode.redirect,redirectCount)):inode}},{key:"rm",value:function(path){var pathname=new Pathname(path),parent=pathname.parent,parentInode=this.resolve(parent),name=pathname.name;return parentInode<0?-1:delete parentInode.files[name]}},{key:"mkPath",value:function(type,path){var target=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,pathname=new Pathname(path),parent=pathname.parent,parentInode=this.resolve(parent),name=pathname.name,mountPoint=this.mountPoint(pathname.clean),disk=this.mounts[mountPoint];if(parentInode<0)return-1;var addedInode=-1;if("f"===type)addedInode=disk.mkFile(name,parentInode);else if("d"===type)addedInode=disk.mkDir(name,parentInode);else if("l"===type&&null!==target){var targetInode=this.resolve(target);if(targetInode<0)return-1;addedInode=disk.mkLink(name,parentInode,targetInode)}else{if("sl"!==type||null===target)return-1;addedInode=disk.mkSymLink(name,parentInode,target)}return addedInode<0?-1:addedInode}},{key:"touch",value:function(path){return this.mkPath("f",path)}},{key:"mkdir",value:function(path){return this.mkPath("d",path)}},{key:"ln",value:function(path,targetPath){return this.mkPath("l",path,targetPath)}},{key:"lns",value:function(path,targetPath){return this.mkPath("sl",path,targetPath)}}]),VFS}(),FileDesc=function FileDesc(path){var fs=arguments.length>1&&void 0!==arguments[1]?arguments[1]:window.box.fs;_classCallCheck(this,FileDesc),this.path=path,this.inode=fs.resolve(this.path)},Process=function(){function Process(){var computer=arguments.length>0&&void 0!==arguments[0]?arguments[0]:window.box;_classCallCheck(this,Process),this.fs=computer.fs,this.fds=[]}return _createClass(Process,[{key:"open",value:function(path){var fd=new FileDesc(path,this.fs);return this.fds.push(fd),this.fds.length-1}},{key:"read",value:function(fdID){var fd=this.fds[fdID];return void 0!==fd.inode.data?fd.inode.data:-1}},{key:"write",value:function(fdID,data){var fd=this.fds[fdID];return void 0!==fd.inode.data?fd.inode.data=data:-1}}]),Process}(),Computer=function Computer(name){_classCallCheck(this,Computer),this.name=name,this.fs=new VFS(new Disk)};window.box=new Computer("fauxOS");<|endoftext|>