<commit_before>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');
const Actor = require('../../../client/src/actor.js');

describe('Rogue.Actor', () => {

    it('has name, stats and inventory', () => {
        const actor = new Actor.Rogue('testRogue');
        expect(actor.getName()).to.equal('testRogue');

        const wp = actor.getWillpower();
        expect(wp).to.equal(5);

        const missile = actor.getMissile();
        expect(missile).to.be.null;

    });

    it('Acts like Locatable', () => {
        const actor = new Actor.Rogue(true);
        actor.setXY(2, 10);
        expect(actor.getX()).to.equal(2);
        expect(actor.getY()).to.equal(10);

        expect(actor.getXY()).to.deep.equal([2, 10]);

        expect(actor.isAtXY(2, 10)).to.equal(true);
        expect(actor.isAtXY(5, 11)).to.equal(false);
    });

    it('can be a player actor', () => {
        const actor = new Actor.Rogue('player hero');
        actor.setIsPlayer(true);
        expect(actor.isPlayer()).to.equal(true);

        RG.suppressErrorMessages = true;
        actor.setIsPlayer(false);
        expect(actor.isPlayer()).to.equal(true);
        RG.suppressErrorMessages = false;

        actor.setName('renamed');
        expect(actor.getName()).to.equal('renamed');

    });

    it('can be serialized to JSON', () => {
        const actor = new Actor.Rogue('player hero');
        actor.setIsPlayer(true);

        const hunger = new RG.Component.Hunger();
        actor.add('Hunger', hunger);

        const actorJSON = actor.toJSON();
        expect(actorJSON.name).to.equal('player hero');

        expect(actorJSON).to.have.property('components');

        const hungerJSON = Object.values(actorJSON.components).find(
            c => c.setType === 'Hunger'
        );
        expect(hungerJSON).to.exist;

    });

    it('has different stats', () => {
        const actor = new Actor.Rogue('player hero');

        const prot = actor.getProtection();
        expect(prot).to.equal(0);

        const str = actor.getStrength();
        expect(str).to.equal(5);

        const dmg = actor.getDamage();
        expect(dmg > 0, 'More than 0 damage').to.equal(true);

    });

    it('has methods for getting combat damage', () => {
        const actor = new Actor.Rogue('fighter');
        const sword = new RG.Item.Weapon('sword');
        sword.setDamageDie('10d1 + 3');
        actor.getInvEq().addItem(sword);
        actor.getInvEq().equipItem(sword);
        const dmg = actor.getDamage();
        expect(dmg).to.be.at.least(13);

        const meat = new RG.Item.Food('meat');
        actor.getInvEq().addItem(meat);
        expect(actor.getInvEq().unequipItem('hand', 1)).to.be.true;
        expect(actor.getInvEq().equipItem(meat)).to.be.true;

        const dmgFood = actor.getDamage();
        expect(dmgFood).to.be.at.least(1);
    });

    it('can have CombatMods added', () => {
        const mob = new Actor.Rogue('mob');
        const combatMods = new RG.Component.CombatMods();

        const attack = mob.getAttack();
        combatMods.setAttack(5);
        mob.add('CombatMods', combatMods);
        const newAttack = mob.getAttack();
        expect(newAttack).to.equal(attack + 5);

        combatMods.setDamage(5);
        const mobDamage = mob.getDamage();
        expect(mobDamage >= 6).to.equal(true);

        const mobDefense = mob.getDefense();
        combatMods.setDefense(7);
        const mobNewDefense = mob.getDefense();
        expect(mobNewDefense).to.equal(mobDefense + 7);
    });

    it('can have StatsMods added', () => {
        const mob = new Actor.Rogue('mob');
        const statMods = new RG.Component.StatsMods();
        mob.add('StatsMods', statMods);

        const oldWp = mob.getWillpower();
        statMods.setWillpower(5);
        const newWp = mob.getWillpower();
        expect(newWp).to.equal(oldWp + 5);

        const oldStr = mob.getStrength();
        statMods.setStrength(-3);
        const newStr = mob.getStrength();
        expect(newStr).to.equal(oldStr - 3);

        const oldAcc = mob.getAccuracy();
        statMods.setAccuracy(10);
        const newAcc = mob.getAccuracy();
        expect(newAcc).to.equal(oldAcc + 10);

        const oldAgi = mob.getAgility();
        statMods.setAgility(10);
        const newAgi = mob.getAgility();
        expect(newAgi).to.equal(oldAgi + 10);
    });

    it('can have an actor class', () => {
        const archer = new RG.Actor.Rogue('archer');
        const actorClass = new RG.Component.ActorClass();
        actorClass.setClassName('Marksman');
        archer.add(actorClass);
        RG.levelUpActor(archer, 2);
    });
});
<commit_msg>Removed 2nd arg to add().<commit_after>
const expect = require('chai').expect;
const RG = require('../../../client/src/battles');
const Actor = require('../../../client/src/actor.js');

describe('Rogue.Actor', () => {

    it('has name, stats and inventory', () => {
        const actor = new Actor.Rogue('testRogue');
        expect(actor.getName()).to.equal('testRogue');

        const wp = actor.getWillpower();
        expect(wp).to.equal(5);

        const missile = actor.getMissile();
        expect(missile).to.be.null;

    });

    it('Acts like Locatable', () => {
        const actor = new Actor.Rogue(true);
        actor.setXY(2, 10);
        expect(actor.getX()).to.equal(2);
        expect(actor.getY()).to.equal(10);

        expect(actor.getXY()).to.deep.equal([2, 10]);

        expect(actor.isAtXY(2, 10)).to.equal(true);
        expect(actor.isAtXY(5, 11)).to.equal(false);
    });

    it('can be a player actor', () => {
        const actor = new Actor.Rogue('player hero');
        actor.setIsPlayer(true);
        expect(actor.isPlayer()).to.equal(true);

        RG.suppressErrorMessages = true;
        actor.setIsPlayer(false);
        expect(actor.isPlayer()).to.equal(true);
        RG.suppressErrorMessages = false;

        actor.setName('renamed');
        expect(actor.getName()).to.equal('renamed');

    });

    it('can be serialized to JSON', () => {
        const actor = new Actor.Rogue('player hero');
        actor.setIsPlayer(true);

        const hunger = new RG.Component.Hunger();
        actor.add('Hunger', hunger);

        const actorJSON = actor.toJSON();
        expect(actorJSON.name).to.equal('player hero');

        expect(actorJSON).to.have.property('components');

        const hungerJSON = Object.values(actorJSON.components).find(
            c => c.setType === 'Hunger'
        );
        expect(hungerJSON).to.exist;

    });

    it('has different stats', () => {
        const actor = new Actor.Rogue('player hero');

        const prot = actor.getProtection();
        expect(prot).to.equal(0);

        const str = actor.getStrength();
        expect(str).to.equal(5);

        const dmg = actor.getDamage();
        expect(dmg > 0, 'More than 0 damage').to.equal(true);

    });

    it('has methods for getting combat damage', () => {
        const actor = new Actor.Rogue('fighter');
        const sword = new RG.Item.Weapon('sword');
        sword.setDamageDie('10d1 + 3');
        actor.getInvEq().addItem(sword);
        actor.getInvEq().equipItem(sword);
        const dmg = actor.getDamage();
        expect(dmg).to.be.at.least(13);

        const meat = new RG.Item.Food('meat');
        actor.getInvEq().addItem(meat);
        expect(actor.getInvEq().unequipItem('hand', 1)).to.be.true;
        expect(actor.getInvEq().equipItem(meat)).to.be.true;

        const dmgFood = actor.getDamage();
        expect(dmgFood).to.be.at.least(1);
    });

    it('can have CombatMods added', () => {
        const mob = new Actor.Rogue('mob');
        const combatMods = new RG.Component.CombatMods();

        const attack = mob.getAttack();
        combatMods.setAttack(5);
        mob.add(combatMods);
        const newAttack = mob.getAttack();
        expect(newAttack).to.equal(attack + 5);

        combatMods.setDamage(5);
        const mobDamage = mob.getDamage();
        expect(mobDamage >= 6).to.equal(true);

        const mobDefense = mob.getDefense();
        combatMods.setDefense(7);
        const mobNewDefense = mob.getDefense();
        expect(mobNewDefense).to.equal(mobDefense + 7);
    });

    it('can have StatsMods added', () => {
        const mob = new Actor.Rogue('mob');
        const statMods = new RG.Component.StatsMods();
        mob.add('StatsMods', statMods);

        const oldWp = mob.getWillpower();
        statMods.setWillpower(5);
        const newWp = mob.getWillpower();
        expect(newWp).to.equal(oldWp + 5);

        const oldStr = mob.getStrength();
        statMods.setStrength(-3);
        const newStr = mob.getStrength();
        expect(newStr).to.equal(oldStr - 3);

        const oldAcc = mob.getAccuracy();
        statMods.setAccuracy(10);
        const newAcc = mob.getAccuracy();
        expect(newAcc).to.equal(oldAcc + 10);

        const oldAgi = mob.getAgility();
        statMods.setAgility(10);
        const newAgi = mob.getAgility();
        expect(newAgi).to.equal(oldAgi + 10);
    });

    it('can have an actor class', () => {
        const archer = new RG.Actor.Rogue('archer');
        const actorClass = new RG.Component.ActorClass();
        actorClass.setClassName('Marksman');
        archer.add(actorClass);
        RG.levelUpActor(archer, 2);
    });
});
<|endoftext|>


<commit_before>/* -----------------------------------------------------------------------------
 * VARS
 * -------------------------------------------------------------------------- */

// Project base paths
// -----------------------------------------------------------------------------
var basePaths = {
	src:  'Source/',
	dest: 'Compiled Size Packs/'
},

// Paths for file assets
// -----------------------------------------------------------------------------
paths = {
	img: {
		src:  basePaths.src,
		dest: basePaths.dest
	}
},
// custom plugin settings
// -----------------------------------------------------------------------------
settings = {
	imagemin: {
		// Default is 3 (16 trials)
		optimizationLevel: 3
	}
},

// watched filename patterns
// -----------------------------------------------------------------------------
watchedPatterns = {
	img: paths.img.src + '**/*.png'
}

// Patch name!
// -----------------------------------------------------------------
patchName = 'NoPatchName';

/* -----------------------------------------------------------------------------
 * GULP PLUGINS
 * -------------------------------------------------------------------------- */
var gulp = require('gulp'),
	$ = require('gulp-load-plugins')({
		pattern: '*',
		camelize: true
	});

/* -----------------------------------------------------------------------------
 * Global Functions
 * -------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
 * TASKS
 * -------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
 * Task - optimise
 * -------------------------------------------------------------------------- */
gulp.task('optimise', function() {
		var pctScale = (size / initialSize * 100).toString() + '%',
			customDirname = size.toString() + suff,
			zipName = '[' + customDirname + '] Sphax Patch - ' + patchName + '.zip',
			ignoreStuff = $.ignore('**/*.{psb,psd}'),
			filterPNG = $.filter(['**/*.png'], { restore: true }),
			filterResizeables = $.filter([
				'**/*.png',
				'!**/pack.png'
			], { restore: true }),
			// If there are images that need their transparency preserved, define them here, e.g.:
			// filterThresholdable = $.filter(['**/*.png', '!**/items/icons/**/*.png'], { restore: true });
			filterThresholdable = $.filter([
				'**/*.png'
			], { restore: true });

		return stream
			.pipe(ignoreStuff)
			.pipe($.clone())
			.pipe($.rename(function (path) {
				// { dirname: 'Example Project 2',
				//   basename: 'test1',
				//   extname: '.png' }
				path.dirname = customDirname + '/' + path.dirname;
			}))
			.pipe($.newer(paths.img.dest))
			// Cache everything past this point, name the cache using dirname
			.pipe($.cached(customDirname))
			// Do the following steps to PNGs only( i.e. no .txt, .mcmeta files)
			.pipe(filterPNG)
				// Do the following to ONLY resizeables
				.pipe(filterResizeables)
					// Use gulp-gm to resize images
					.pipe($.gm(function (imageFile) {
						return imageFile
							// Ensure 8-bit RGB
							.bitdepth(8)
							// Bilinear
							.filter('Triangle')
							// Resize to % scale
							.resize(pctScale, '%');
					}))
				.pipe(filterResizeables.restore)
				// Use gulp-gm to  apply threshold to (remove partial transparency from) images
				// Apply only to images we want to remove transparency from
				.pipe(filterThresholdable)
					.pipe($.gm(function (imageFile) {
						return imageFile
							// Ensure no transparent edges on all PNGs
							.operator('Opacity', 'Threshold', 50, '%');
					}))
				.pipe(filterThresholdable.restore)
				// pass all images through gulp-imagemin
				.pipe($.imagemin(settings.imagemin))
			// Restore non-PNG files to stream
			.pipe(filterPNG.restore)
			.pipe(gulp.dest(paths.img.dest))
			// zip everything up
			.pipe($.zip(zipName))
			.pipe(gulp.dest(paths.img.dest));
	});

// default task
// -----------------------------------------------------------------------------
gulp.task('default', function () {
	console.log('\nWatching for changes:\n');
	// Watch Images
	// -------------------------------------------------------------------------
	console.log('- IMG Files: ' + watchedPatterns.img);
	gulp.watch(watchedPatterns.img, ['optimise']);

	console.log('\n');
}); // /default
<commit_msg>Let's not break everything<commit_after>/* -----------------------------------------------------------------------------
 * VARS
 * -------------------------------------------------------------------------- */

// Project base paths
// -----------------------------------------------------------------------------
var basePaths = {
	src:  'Source/',
	dest: 'Compiled Size Packs/'
},

// Paths for file assets
// -----------------------------------------------------------------------------
paths = {
	img: {
		src:  basePaths.src,
		dest: basePaths.dest
	}
},
// custom plugin settings
// -----------------------------------------------------------------------------
settings = {
	imagemin: {
		// Default is 3 (16 trials)
		optimizationLevel: 3
	}
},

// watched filename patterns
// -----------------------------------------------------------------------------
watchedPatterns = {
	img: paths.img.src + '**/*.png'
},

// Patch name!
// -----------------------------------------------------------------
patchName = 'NoPatchName';

/* -----------------------------------------------------------------------------
 * GULP PLUGINS
 * -------------------------------------------------------------------------- */
var gulp = require('gulp'),
	$ = require('gulp-load-plugins')({
		pattern: '*',
		camelize: true
	});

/* -----------------------------------------------------------------------------
 * Global Functions
 * -------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
 * TASKS
 * -------------------------------------------------------------------------- */
/* -----------------------------------------------------------------------------
 * Task - optimise
 * -------------------------------------------------------------------------- */
gulp.task('optimise', function() {
		var pctScale = (size / initialSize * 100).toString() + '%',
			customDirname = size.toString() + suff,
			zipName = '[' + customDirname + '] Sphax Patch - ' + patchName + '.zip',
			ignoreStuff = $.ignore('**/*.{psb,psd}'),
			filterPNG = $.filter(['**/*.png'], { restore: true }),
			filterResizeables = $.filter([
				'**/*.png',
				'!**/pack.png'
			], { restore: true }),
			// If there are images that need their transparency preserved, define them here, e.g.:
			// filterThresholdable = $.filter(['**/*.png', '!**/items/icons/**/*.png'], { restore: true });
			filterThresholdable = $.filter([
				'**/*.png'
			], { restore: true });

		return stream
			.pipe(ignoreStuff)
			.pipe($.clone())
			.pipe($.rename(function (path) {
				// { dirname: 'Example Project 2',
				//   basename: 'test1',
				//   extname: '.png' }
				path.dirname = customDirname + '/' + path.dirname;
			}))
			.pipe($.newer(paths.img.dest))
			// Cache everything past this point, name the cache using dirname
			.pipe($.cached(customDirname))
			// Do the following steps to PNGs only( i.e. no .txt, .mcmeta files)
			.pipe(filterPNG)
				// Do the following to ONLY resizeables
				.pipe(filterResizeables)
					// Use gulp-gm to resize images
					.pipe($.gm(function (imageFile) {
						return imageFile
							// Ensure 8-bit RGB
							.bitdepth(8)
							// Bilinear
							.filter('Triangle')
							// Resize to % scale
							.resize(pctScale, '%');
					}))
				.pipe(filterResizeables.restore)
				// Use gulp-gm to  apply threshold to (remove partial transparency from) images
				// Apply only to images we want to remove transparency from
				.pipe(filterThresholdable)
					.pipe($.gm(function (imageFile) {
						return imageFile
							// Ensure no transparent edges on all PNGs
							.operator('Opacity', 'Threshold', 50, '%');
					}))
				.pipe(filterThresholdable.restore)
				// pass all images through gulp-imagemin
				.pipe($.imagemin(settings.imagemin))
			// Restore non-PNG files to stream
			.pipe(filterPNG.restore)
			.pipe(gulp.dest(paths.img.dest))
			// zip everything up
			.pipe($.zip(zipName))
			.pipe(gulp.dest(paths.img.dest));
	});

// default task
// -----------------------------------------------------------------------------
gulp.task('default', function () {
	console.log('\nWatching for changes:\n');
	// Watch Images
	// -------------------------------------------------------------------------
	console.log('- IMG Files: ' + watchedPatterns.img);
	gulp.watch(watchedPatterns.img, ['optimise']);

	console.log('\n');
}); // /default
<|endoftext|>


<commit_before>function register_onload(func) {
  var old_event = window.onload;
  if (typeof window.onload != 'function') { window.onload = func; }
  else { window.onload = function() { old_event(); func(); }; }
}

function show_dates_as_local_time() {
  var spans = document.getElementsByTagName('span');
  for (var i=0; i<spans.length; i++) {
    if (spans[i].className.match(/\btypo_date\b/i)) {
      spans[i].innerHTML = get_local_time_for_date(spans[i].title);
    }
  }
}

function get_local_time_for_date(time) {
  system_date = new Date(time);
  user_date = new Date();
  delta_minutes = Math.round((user_date - system_date) / (60 * 1000));
  if (Math.abs(delta_minutes) <= (8*7*24*60)) { // eight weeks... I'm lazy to count days for longer than that
    distance = distance_of_time_in_words(delta_minutes);
    if (delta_minutes < 0) {
      return distance + ' from now';
    } else {
      return distance + ' ago';
    }
  } else {
    return 'on ' + system_date.toLocaleDateString();
  }
}

// a vague copy of rails' inbuilt function,
// but a bit more friendly with the hours.
function distance_of_time_in_words(minutes) {
  if (minutes.isNaN) return "";
  minutes = Math.abs(minutes);
  if (minutes < 1) return ('less than a minute');
  if (minutes < 50) return (minutes + ' minutes');
  if (minutes < 90) return ('about one hour');
  if (minutes < 1080) return (Math.round(minutes / 60) + ' hours');
  if (minutes < 1440) return ('one day');
  if (minutes < 2880) return ('about one day');
  else return (Math.round(minutes / 1440) + ' days')
}

function commentAdded(request) {
  new Effect.BlindDown($('commentList').lastChild);
  $('commentform').elements[3].value = '';
  $('commentform').elements[3].focus();
}

function failure(request) {
  $('errors').innerHTML = request.responseText;
  new Effect.Highlight('errors');
}

function loading() {
  $('form-submit-button').disabled = true;
  Element.show('comment_loading');
}

function complete(request) {
  Element.hide('comment_loading');
  Element.show('commentform');
  $('form-submit-button').disabled = false;

  if (request.status == 200) { commentAdded() };
}

register_onload(function() {
  if ($('commentform')) {
    $('commentform').elements['comment[author]'].value = getCookie('author');
    $('commentform').elements['comment[url]'].value = getCookie('url');

    if ($('commentform').elements['comment[url]'].value != ''
        || $('commentform').elements['comment[email]'].value != '') {
      Element.show('guest_url'); Element.show('guest_email');
    }
  }
})
register_onload(function() { if ($('q')) {$('q').setAttribute('autocomplete', 'off');} })<commit_msg>Fix date display bug.  (closes #269)<commit_after>function register_onload(func) {
  var old_event = window.onload;
  if (typeof window.onload != 'function') { window.onload = func; }
  else { window.onload = function() { old_event(); func(); }; }
}

function show_dates_as_local_time() {
  var spans = document.getElementsByTagName('span');
  for (var i=0; i<spans.length; i++) {
    if (spans[i].className.match(/\btypo_date\b/i)) {
      spans[i].innerHTML = get_local_time_for_date(spans[i].title);
    }
  }
}

function get_local_time_for_date(time) {
  system_date = new Date(time);
  user_date = new Date();
  delta_minutes = Math.floor((user_date - system_date) / (60 * 1000));
  if (Math.abs(delta_minutes) <= (8*7*24*60)) { // eight weeks... I'm lazy to count days for longer than that
    distance = distance_of_time_in_words(delta_minutes);
    if (delta_minutes < 0) {
      return distance + ' from now';
    } else {
      return distance + ' ago';
    }
  } else {
    return 'on ' + system_date.toLocaleDateString();
  }
}

// a vague copy of rails' inbuilt function,
// but a bit more friendly with the hours.
function distance_of_time_in_words(minutes) {
  if (minutes.isNaN) return "";
  minutes = Math.abs(minutes);
  if (minutes < 1) return ('less than a minute');
  if (minutes < 50) return (minutes + ' minute' + (minutes == 1 ? '' : 's'));
  if (minutes < 90) return ('about one hour');
  if (minutes < 1080) return (Math.round(minutes / 60) + ' hours');
  if (minutes < 1440) return ('one day');
  if (minutes < 2880) return ('about one day');
  else return (Math.round(minutes / 1440) + ' days')
}

function commentAdded(request) {
  new Effect.BlindDown($('commentList').lastChild);
  $('commentform').elements[3].value = '';
  $('commentform').elements[3].focus();
}

function failure(request) {
  $('errors').innerHTML = request.responseText;
  new Effect.Highlight('errors');
}

function loading() {
  $('form-submit-button').disabled = true;
  Element.show('comment_loading');
}

function complete(request) {
  Element.hide('comment_loading');
  Element.show('commentform');
  $('form-submit-button').disabled = false;

  if (request.status == 200) { commentAdded() };
}

register_onload(function() {
  if ($('commentform')) {
    $('commentform').elements['comment[author]'].value = getCookie('author');
    $('commentform').elements['comment[url]'].value = getCookie('url');

    if ($('commentform').elements['comment[url]'].value != ''
        || $('commentform').elements['comment[email]'].value != '') {
      Element.show('guest_url'); Element.show('guest_email');
    }
  }
})
register_onload(function() { if ($('q')) {$('q').setAttribute('autocomplete', 'off');} })<|endoftext|>


<commit_before>'use strict';
var fs = require('fs');
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');

var MeanGenerator = yeoman.generators.Base.extend({
	constructor: function(args, options) {
		yeoman.generators.Base.apply(this, arguments);

		this.pkg = require('../package.json');

		this.argument('appname', { type: String, required: false });
		this.argument('no-hooks', { type: Boolean, required: false });
		this.appname = this.appname || path.basename(process.cwd());
		this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

		// __NOTE:__ This implementation of the `appPath`
		// configuration is something that is not standard for the
		// Angular.js and Backbone.js Yeoman Generators. In order for
		// the generators to be able to interface with this
		// generator, we need to do a little bit of trickery with the
		// `.yo-rc.json` file and the `bower.json` config file.

		if (typeof this.env.options.appPath === 'undefined') {
			try {
				this.env.options.appPath = require(path.join(process.cwd(), 'bower.json')).appPath;
			} catch (e) {}
			if(!this.env.options.appPath) {
				this.env.options.appPath = this.options.appPath || 'public';
			}
		}

		this.config.set('appPath', this.env.options.appPath);
		this.appPath = this.env.options.appPath;

		args = ['main'];

		if(!this.arguments['no-hooks']) {
			this.hookFor('mean:boilerplate', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('angular:main', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('angular:controller', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('mean:server', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});
		}

		this.on('end', function() {
			this.invoke('karma:app', {
				options: {
					cwd: this.destinationRoot(),
					coffee: this.options.coffee,
					travis: false,
					'skip-install': this.options['skip-install'],
					components: [
						'angular/angular.js',
						'angular-mocks/angular-mocks.js',
						'angular-resource/angular-resource.js',
						'angular-cookies/angular-cookies.js',
						'angular-sanitize/angular-sanitize.js',
						'angular-route/angular-route.js'
					]
				}
			});

			if (!this.options['skip-install']) {
				this.installDependencies({
					callback: function() {

						this.spawnCommand('gulp', ['wire-dependencies']);

						if(!this.options['no-git']) {
							this.spawnCommand('grunt', ['git-init']);
						}
					}.bind(this)
				});
			}
		});

	},

	welcome: function() {
		// have Yeoman greet the user
		this.log(this.yeoman);

		this.log(chalk.red('---- MEAN GENERATOR ----'));
		this.log(
			'The MEAN generator is modular, and made to be used with \
			other existing Yeoman generators*. Either run the base \
			MEAN generator, or call each generator independently.\n\n',
			'*Compatibility with angular and backbone generators \
			using the \'--appPath=\"public\"\' option.\n'
			);

		this.log('Generators included:');
		this.log(chalk.green('- app'), chalk.grey(': copies hidden/dot files, git, npm, and bower files to project directory'));
		this.log(chalk.green('- boilerplate'), chalk.grey(': fetches HTML5 Boilerplate and copies some common files'));
		this.log(chalk.green('- server'), chalk.grey(': sets up Express server with MongoDB support'), '\n\n');
	},

	askFor: function() {
		// var done = this.async();

		// var prompts = [{
		// 	name: 'githubUser',
		// 	message: 'What is your GitHub user name?'
		// }, {
		// 	name: 'name',
		// 	message: 'What is the name of your project?',
		// 	default: path.basename(process.cwd())
		// }, {
		// 	name: 'description',
		// 	message: 'Description'
		// }];

		// this.prompt(prompts, function(props) {
		// 	this.githubUser = props.githubUser;

		// 	this.name = this._.slugify(props.name);
		// 	this.description = props.description;

		// 	this.repoUrl = 'https://github.com/' + props.githubUser + '/' + this.name + '.git';
		// 	this.repoLink = 'git@github.com:' + props.githubUser + '/' + this.name + '.git';

		// 	done();
		// }.bind(this));

		this.githubUser = 'ajthor';
		this.name = 'mean-test';
		this.description = '';
		this.repoUrl = 'https://github.com/' + this.githubUser + '/' + this.name + '.git';
		this.repoLink = 'git@github.com:' + this.githubUser + '/' + this.name + '.git';

	},

	directories: function() {
		this.dest.mkdir('public');
		this.dest.mkdir('public/scripts');
		this.dest.mkdir('public/scripts/vendor');
	},

	projectFiles: function() {
		this.template('_package.json', 'package.json');
		this.template('_bower.json', 'bower.json');

		this.template("_Gruntfile.js", "Gruntfile.js");
		this.template("_gulpfile.js", "gulpfile.js");
	},

	rootFiles: function() {
		this.expandFiles('*', {
			cwd: path.join(this.src._base, '/root'),
			dot: true
		}).forEach(function(file) {
			this.copy(path.join(this.src._base, '/root', file), file);
		}.bind(this));
	}

});

module.exports = MeanGenerator;

<commit_msg>prettify welcome message<commit_after>'use strict';
var fs = require('fs');
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');

var MeanGenerator = yeoman.generators.Base.extend({
	constructor: function(args, options) {
		yeoman.generators.Base.apply(this, arguments);

		this.pkg = require('../package.json');

		this.argument('appname', { type: String, required: false });
		this.argument('no-hooks', { type: Boolean, required: false });
		this.appname = this.appname || path.basename(process.cwd());
		this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

		// __NOTE:__ This implementation of the `appPath`
		// configuration is something that is not standard for the
		// Angular.js and Backbone.js Yeoman Generators. In order for
		// the generators to be able to interface with this
		// generator, we need to do a little bit of trickery with the
		// `.yo-rc.json` file and the `bower.json` config file.

		if (typeof this.env.options.appPath === 'undefined') {
			try {
				this.env.options.appPath = require(path.join(process.cwd(), 'bower.json')).appPath;
			} catch (e) {}
			if(!this.env.options.appPath) {
				this.env.options.appPath = this.options.appPath || 'public';
			}
		}

		this.config.set('appPath', this.env.options.appPath);
		this.appPath = this.env.options.appPath;

		args = ['main'];

		if(!this.arguments['no-hooks']) {
			this.hookFor('mean:boilerplate', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('angular:main', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('angular:controller', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});

			this.hookFor('mean:server', {
				args: args,
				options: {
					options: {
						'appPath': 'public'
					}
				}
			});
		}

		this.on('end', function() {
			this.invoke('karma:app', {
				options: {
					cwd: this.destinationRoot(),
					coffee: this.options.coffee,
					travis: false,
					'skip-install': this.options['skip-install'],
					components: [
						'angular/angular.js',
						'angular-mocks/angular-mocks.js',
						'angular-resource/angular-resource.js',
						'angular-cookies/angular-cookies.js',
						'angular-sanitize/angular-sanitize.js',
						'angular-route/angular-route.js'
					]
				}
			});

			if (!this.options['skip-install']) {
				this.installDependencies({
					callback: function() {

						this.spawnCommand('gulp', ['wire-dependencies']);

						if(!this.options['no-git']) {
							this.spawnCommand('grunt', ['git-init']);
						}
					}.bind(this)
				});
			}
		});

	},

	welcome: function() {
		// have Yeoman greet the user
		this.log(this.yeoman);

		this.log(chalk.red('---- MEAN GENERATOR ----'));
		this.log(
			'The MEAN generator is modular, and made to be used with other existing Yeoman generators*. Either run the base MEAN generator, or call each generator independently.\n\n',
			'*Compatibility with angular and backbone generators using the \'', chalk.red('--appPath=\"public\"'), '\' option.\n'
			);

		this.log('Generators included:');
		this.log(chalk.green('- app'), chalk.grey(': copies hidden/dot files, git, npm, and bower files to project directory'));
		this.log(chalk.green('- boilerplate'), chalk.grey(': fetches HTML5 Boilerplate and copies some common files'));
		this.log(chalk.green('- server'), chalk.grey(': sets up Express server with MongoDB support'), '\n\n');
	},

	askFor: function() {
		// var done = this.async();

		// var prompts = [{
		// 	name: 'githubUser',
		// 	message: 'What is your GitHub user name?'
		// }, {
		// 	name: 'name',
		// 	message: 'What is the name of your project?',
		// 	default: path.basename(process.cwd())
		// }, {
		// 	name: 'description',
		// 	message: 'Description'
		// }];

		// this.prompt(prompts, function(props) {
		// 	this.githubUser = props.githubUser;

		// 	this.name = this._.slugify(props.name);
		// 	this.description = props.description;

		// 	this.repoUrl = 'https://github.com/' + props.githubUser + '/' + this.name + '.git';
		// 	this.repoLink = 'git@github.com:' + props.githubUser + '/' + this.name + '.git';

		// 	done();
		// }.bind(this));

		this.githubUser = 'ajthor';
		this.name = 'mean-test';
		this.description = '';
		this.repoUrl = 'https://github.com/' + this.githubUser + '/' + this.name + '.git';
		this.repoLink = 'git@github.com:' + this.githubUser + '/' + this.name + '.git';

	},

	directories: function() {
		this.dest.mkdir('public');
		this.dest.mkdir('public/scripts');
		this.dest.mkdir('public/scripts/vendor');
	},

	projectFiles: function() {
		this.template('_package.json', 'package.json');
		this.template('_bower.json', 'bower.json');

		this.template("_Gruntfile.js", "Gruntfile.js");
		this.template("_gulpfile.js", "gulpfile.js");
	},

	rootFiles: function() {
		this.expandFiles('*', {
			cwd: path.join(this.src._base, '/root'),
			dot: true
		}).forEach(function(file) {
			this.copy(path.join(this.src._base, '/root', file), file);
		}.bind(this));
	}

});

module.exports = MeanGenerator;

<|endoftext|>


<commit_before>var gulp = require('gulp')
var coffee = require('gulp-coffee')
var concat = require('gulp-concat')
var prepend = require('gulp-insert').prepend
var shell = require('gulp-shell')
var uglify = require('gulp-uglify')
var rename = require('gulp-rename')
var fs = require('fs')

gulp.task('build', function() {
  // Order here is important.
  files = [
    './src/setup.coffee',
    './src/assert.coffee',
    './src/id_factory.coffee',
    './src/action.coffee',
    './src/dispatcher.coffee',
    './src/deferred_task.coffee',
    './src/store.coffee',
    './src/export.coffee'
  ]

  gulp.src(files)
      .pipe(concat('hippodrome.js'))
      .pipe(coffee())
      .pipe(gulp.dest('./dist'))
      .pipe(uglify())
      .pipe(rename('hippodrome.min.js'))
      .pipe(gulp.dest('./dist'))
});

gulp.task('test', ['build'], shell.task([
  'npm run test'
]))

gulp.task('watch', ['test'], function() {
  gulp.watch('src/**/*.coffee', ['test']);
})

gulp.task('set-npm-version', function() {
  version = require('./package.json').version;
  pkg = fs.readFileSync('./npm/package.json')
  pkgJson = JSON.parse(pkg)
  pkgJson.version = version
  fs.writeFileSync('./npm/package.json', JSON.stringify(pkgJson, null, 2))
})

gulp.task('copy-npm-javascript', function() {
  gulp.src('dist/*.js')
      .pipe(gulp.dest('./npm'))
})

gulp.task('prepare-npm', ['set-npm-version', 'copy-npm-javascript'])

gulp.task('set-gem-version', function() {
  version = require('./package.json').version
  gemVersionModule = 'module Hippodrome\n  VERSION = \'' + version + '\'\nend'
  fs.writeFileSync('./rails/lib/hippodrome/version.rb', gemVersionModule)
})

gulp.task('copy-gem-javascript', function() {
  gulp.src('dist/*/js')
      .pipe(prepend('//= require lodash\n\n')) // Sprockets directive for rails.
      .pipe(gulp.dest('./rails/app/assets/javascripts'))
})

gulp.task('prepare-gem', ['set-gem-version', 'copy-gem-javascript'])
<commit_msg>Gulp task to commit version number changes.<commit_after>var gulp = require('gulp')
var coffee = require('gulp-coffee')
var concat = require('gulp-concat')
var prepend = require('gulp-insert').prepend
var shell = require('gulp-shell')
var uglify = require('gulp-uglify')
var rename = require('gulp-rename')
var fs = require('fs')

gulp.task('build', function() {
  // Order here is important.
  files = [
    './src/setup.coffee',
    './src/assert.coffee',
    './src/id_factory.coffee',
    './src/action.coffee',
    './src/dispatcher.coffee',
    './src/deferred_task.coffee',
    './src/store.coffee',
    './src/export.coffee'
  ]

  gulp.src(files)
      .pipe(concat('hippodrome.js'))
      .pipe(coffee())
      .pipe(gulp.dest('./dist'))
      .pipe(uglify())
      .pipe(rename('hippodrome.min.js'))
      .pipe(gulp.dest('./dist'))
});

gulp.task('test', ['build'], shell.task([
  'npm run test'
]))

gulp.task('watch', ['test'], function() {
  gulp.watch('src/**/*.coffee', ['test']);
})

gulp.task('set-npm-version', function() {
  version = require('./package.json').version;
  pkg = fs.readFileSync('./npm/package.json')
  pkgJson = JSON.parse(pkg)
  pkgJson.version = version
  fs.writeFileSync('./npm/package.json', JSON.stringify(pkgJson, null, 2))
})

gulp.task('copy-npm-javascript', function() {
  gulp.src('dist/*.js')
      .pipe(gulp.dest('./npm'))
})

gulp.task('prepare-npm', ['set-npm-version', 'copy-npm-javascript'])

gulp.task('set-gem-version', function() {
  version = require('./package.json').version;
  gemVersionModule = 'module Hippodrome\n  VERSION = \'' + version + '\'\nend'
  fs.writeFileSync('./rails/lib/hippodrome/version.rb', gemVersionModule)
})

gulp.task('copy-gem-javascript', function() {
  gulp.src('dist/*/js')
      .pipe(prepend('//= require lodash\n\n')) // Sprockets directive for rails.
      .pipe(gulp.dest('./rails/app/assets/javascripts'))
})

gulp.task('prepare-gem', ['set-gem-version', 'copy-gem-javascript'])

gulp.task('commit-version-changes', ['prepare-gem', 'prepare-npm'], function() {
  version = require('./package.json').version;

  gulp.src('')
      .pipe(shell([
        'git add npm/package.json rails/lib/hippodrome/version.rb',
        'git commit -m "Build version ' + version + ' of hippodrome."'
      ]))
})

gulp.task('publish', ['commit-version-changes'])
<|endoftext|>


<commit_before>/**
 * Nomads Basic Mobile and Desktop Client
 */

ANIMATION_OFFSET = 50;

INTERFACE_CIRCLE_RAD = 110;
INTERFACE_CIRCLE0_X = 250 + ANIMATION_OFFSET;
INTERFACE_CIRCLE0_Y = 129 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_X = 370 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_Y = 215 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_X = 330 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_Y = 360 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_X = 176 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_Y = 375 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_X = 134 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_Y = 215 + ANIMATION_OFFSET;

GRAPHICS_W = 600;
GRAPHICS_H = 600;

var client;
var currentZone;
var currentX;
var currentY;
var canvas;
var context;
var clientAnimation;
var x, y;
var allClientThoughts = []; //by instantiating this here, users will get a clean slate as they enter the fray. will start populating globally as new messages appear.

$(document).ready(function(){
  client = new NomadsMobileClient(initCallback);

  client.geolocate();

  $('#namefield').focus();
  canvas = document.getElementById('mainui');

  // setup animation
  clientAnimation = new NomadsMobileClientAnimation();

  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  //hide entry div until user selects a zone.
  $("#phrase-entry").hide();

  //Listeners

  $('#login-form').submit(login);

  $('#phrase-form').submit(submitPhrase);
  $('#cancel_phrase').hide();
  $('#cancel_phrase').click(cancelPhrase);

  canvas.addEventListener('mousedown', zoneClick);

  //Load sounds
  $('.sounds').load();
  $("html, body").animate({ scrollTop: 0 }, "slow");

});

pointInCircle = function (center_x, center_y, radius, x, y){
  var dist = (center_x - x)*(center_x - x) + (center_y - y)*(center_y - y);
  if(dist < radius*radius){
    return true;
  }else{
    return false;
  }
}

zoneClick = function(evt){
  var rect = canvas.getBoundingClientRect();

  x = currentX = evt.clientX - rect.left;
  y = currentY = evt.clientY - rect.top;

  //tests!
  if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 0
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else{
      console.log("zone 0");
      zoneSelect(0);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 1
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else{
      console.log("zone 2");
      zoneSelect(2);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 2
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else{
      console.log("zone 4");
      zoneSelect(4);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 3
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7")
      zoneSelect(7);
    }else{
      console.log("zone 6");
      zoneSelect(6);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 4
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7");
      zoneSelect(7);
    }else
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else{
      console.log("zone 8");
      zoneSelect(8);
    }
  }

  console.log("mouse down "+x + ' ' + y);
}

initCallback = function(){
  $('#loader').hide();
}

login = function(e){
  //cancel form submission
  e.preventDefault();

  if($('#namefield').val()==""){
    //must submit phrase
    return;
  }

  client.login($('#namefield').val(), loginComplete);
}

loginComplete = function(){
  $('#login').fadeOut();
}

zoneSelect = function(cz){
  $("#phrase-entry").show();
  $('#enter_phrase').prop('disabled', false);
  $('#cancel_phrase').prop('disabled', false);
  $('#phrasefield').prop('disabled', false);
  $('#phrasefield').focus();

  currentZone = cz;//$(this).attr("data-location");
  return false;
}

submitPhrase = function(e){
  //cancel form submission
  e.preventDefault();
  var text = $('#phrasefield').val();
  if(text==""){
    //must submit phrase
    //tell the user to submit something?
    return;
  }

  client.sendMessage(text, currentZone, x, y, 'textMessage');

  //error with this function. won't play anything else below. doesn't exist?
  //clientAnimation.sendMessage();

  //create new clientThought, push to allClientThoughts[]
  //see NomadsMobileClientAnimation.js for display on canvas.
  //this only displays a single Client's thoughts on his/her canvas.
  allClientThoughts.push({
    "thought":text,
    "x":x,
    "y":y,
    "life":20,
    "size":18,
    "alpha":1.0
  });

  $('#phrasefield').val('');
  //Play sound
  var i = Math.floor(Math.random()*14);
  console.log("playing sound "+i);
  $('#sound'+i)[0].play();
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $("#phrasefield").blur();
  //jump user screen back up to top of page.
  //$("body, html").scrollTop($("#mainui").offset().top);
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();

  });

}

cancelPhrase = function(e){
  //cancel form submission
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $('#phrasefield').val('');

  //jump user back to top after cancel.
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();
  });
}
<commit_msg>styling login form<commit_after>/**
 * Nomads Basic Mobile and Desktop Client
 */

ANIMATION_OFFSET = 50;

INTERFACE_CIRCLE_RAD = 110;
INTERFACE_CIRCLE0_X = 250 + ANIMATION_OFFSET;
INTERFACE_CIRCLE0_Y = 129 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_X = 370 + ANIMATION_OFFSET;
INTERFACE_CIRCLE1_Y = 215 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_X = 330 + ANIMATION_OFFSET;
INTERFACE_CIRCLE2_Y = 360 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_X = 176 + ANIMATION_OFFSET;
INTERFACE_CIRCLE3_Y = 375 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_X = 134 + ANIMATION_OFFSET;
INTERFACE_CIRCLE4_Y = 215 + ANIMATION_OFFSET;

GRAPHICS_W = 600;
GRAPHICS_H = 600;

var client;
var currentZone;
var currentX;
var currentY;
var canvas;
var context;
var clientAnimation;
var x, y;
var allClientThoughts = []; //by instantiating this here, users will get a clean slate as they enter the fray. will start populating globally as new messages appear.

$(document).ready(function(){
  client = new NomadsMobileClient(initCallback);

  client.geolocate();

  $('#namefield').focus();
  canvas = document.getElementById('mainui');

  // setup animation
  clientAnimation = new NomadsMobileClientAnimation();

  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  //hide entry div until user selects a zone.
  $("#phrase-entry").hide();

  //Listeners

  $('#login-form').submit(login);

  $('#phrase-form').submit(submitPhrase);
  $('#cancel_phrase').hide();
  $('#cancel_phrase').click(cancelPhrase);

  canvas.addEventListener('mousedown', zoneClick);

  //Load sounds
  $('.sounds').load();
  $("html, body").animate({ scrollTop: 0 }, "slow");

});

pointInCircle = function (center_x, center_y, radius, x, y){
  var dist = (center_x - x)*(center_x - x) + (center_y - y)*(center_y - y);
  if(dist < radius*radius){
    return true;
  }else{
    return false;
  }
}

zoneClick = function(evt){
  var rect = canvas.getBoundingClientRect();

  x = currentX = evt.clientX - rect.left;
  y = currentY = evt.clientY - rect.top;

  //tests!
  if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 0
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else{
      console.log("zone 0");
      zoneSelect(0);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 1
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 1");
      zoneSelect(1);
    }else
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else{
      console.log("zone 2");
      zoneSelect(2);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 2
    if(pointInCircle(INTERFACE_CIRCLE1_X, INTERFACE_CIRCLE1_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 3");
      zoneSelect(3);
    }else
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else{
      console.log("zone 4");
      zoneSelect(4);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 3
    if(pointInCircle(INTERFACE_CIRCLE2_X, INTERFACE_CIRCLE2_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 5");
      zoneSelect(5);
    }else
    if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7")
      zoneSelect(7);
    }else{
      console.log("zone 6");
      zoneSelect(6);
    }
  }else
  if(pointInCircle(INTERFACE_CIRCLE4_X, INTERFACE_CIRCLE4_Y, INTERFACE_CIRCLE_RAD, x, y)){
    //circle 4
    if(pointInCircle(INTERFACE_CIRCLE3_X, INTERFACE_CIRCLE3_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 7");
      zoneSelect(7);
    }else
    if(pointInCircle(INTERFACE_CIRCLE0_X, INTERFACE_CIRCLE0_Y, INTERFACE_CIRCLE_RAD, x, y)){
      console.log("zone 9");
      zoneSelect(9);
    }else{
      console.log("zone 8");
      zoneSelect(8);
    }
  }

  console.log("mouse down "+x + ' ' + y);
}

initCallback = function(){
  $('#loader').hide();
}

login = function(e){
  //cancel form submission
  e.preventDefault();

  if($('#namefield').val()==""){
    //must submit phrase
    return;
  }

  client.login($('#namefield').val(), loginComplete);
}

loginComplete = function(){
  $("#namefield").blur();
  $('#login').fadeOut();
}

zoneSelect = function(cz){
  $("#phrase-entry").show();
  $('#enter_phrase').prop('disabled', false);
  $('#cancel_phrase').prop('disabled', false);
  $('#phrasefield').prop('disabled', false);
  $('#phrasefield').focus();

  currentZone = cz;//$(this).attr("data-location");
  return false;
}

submitPhrase = function(e){
  //cancel form submission
  e.preventDefault();
  var text = $('#phrasefield').val();
  if(text==""){
    //must submit phrase
    //tell the user to submit something?
    return;
  }

  client.sendMessage(text, currentZone, x, y, 'textMessage');

  //error with this function. won't play anything else below. doesn't exist?
  //clientAnimation.sendMessage();

  //create new clientThought, push to allClientThoughts[]
  //see NomadsMobileClientAnimation.js for display on canvas.
  //this only displays a single Client's thoughts on his/her canvas.
  allClientThoughts.push({
    "thought":text,
    "x":x,
    "y":y,
    "life":20,
    "size":18,
    "alpha":1.0
  });

  $('#phrasefield').val('');
  //Play sound
  var i = Math.floor(Math.random()*14);
  console.log("playing sound "+i);
  $('#sound'+i)[0].play();
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $("#phrasefield").blur();
  //jump user screen back up to top of page.
  //$("body, html").scrollTop($("#mainui").offset().top);
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();

  });

}

cancelPhrase = function(e){
  //cancel form submission
  $('#enter_phrase').prop('disabled', true);
  $('#cancel_phrase').prop('disabled', true);
  $('#phrasefield').prop('disabled', true);
  $('#phrasefield').val('');

  //jump user back to top after cancel.
  $("body, html").animate({
    scrollTop: $("#mainui").offset().top
  }, 600, function() {
    // Animation complete.
    $("#phrase-entry").hide();
  });
}
<|endoftext|>


<commit_before>import React from 'react'
import ReactDOM from 'react-dom'

import * as Alerts from 'pui-react-alerts'
import * as Alignment from 'pui-css-alignment'
import * as Autocomplete from 'pui-react-autocomplete'
import * as Top from 'pui-react-back-to-top'
import * as Bootstrap from 'pui-css-bootstrap'
import * as Buttons from 'pui-react-buttons'
import * as Checkbox from 'pui-react-checkbox'
import * as Collapse from 'pui-react-collapse'
import * as Clipboard from 'pui-react-copy-to-clipboard'
import * as Dividers from 'pui-react-dividers'
import * as DraggableList from 'pui-react-draggable-list'
import * as Ellipsis from 'pui-css-ellipsis'
import * as Dropdowns from 'pui-react-dropdowns'
import * as Expander from 'pui-react-expander'
import * as Grids from 'pui-react-grids'
import * as Hoverable from 'pui-css-hoverable'
import * as Iconography from 'pui-react-iconography'
import * as Images from 'pui-react-images'
import * as Inputs from 'pui-react-inputs'
import * as Labels from 'pui-react-labels'
import * as Lists from 'pui-react-lists'
import * as Media from 'pui-react-media'
import * as Modals from 'pui-react-modals'
import * as Notifications from 'pui-react-notifications'
import * as Trigger from 'pui-react-overlay-trigger'
import * as Pagination from 'pui-react-pagination'
import * as Panels from 'pui-react-panels'
import * as Panes from 'pui-react-panes'
import * as Portals from 'pui-react-portals'
import * as Radio from 'pui-react-radio'
import * as Ribbons from 'pui-react-ribbons'
import * as Table from 'pui-react-table'
import * as Select from 'pui-react-select'
import * as StreamList from 'pui-react-stream-list'
import * as Svg from 'pui-react-svg'
import * as Tabs from 'pui-react-tabs'
import * as Layout from 'pui-react-tile-layout'
import * as Toggle from 'pui-react-toggle'
import * as Tooltip from 'pui-react-tooltip'

const attachToWindow = pakage => { // package is a reserved word
  Object.keys(pakage).forEach(key => {
    window[key] = pakage[key]
  })
}

export default () => {
  window.React = React
  window.ReactDOM = ReactDOM

  const packages = [
    Alerts,
    Alignment,
    Autocomplete,
    Top,
    Bootstrap,
    Buttons,
    Checkbox,
    Collapse,
    Clipboard,
    Dividers,
    DraggableList,
    Ellipsis,
    Dropdowns,
    Expander,
    Grids,
    Hoverable,
    Iconography,
    Images,
    Inputs,
    Labels,
    Lists,
    Media,
    Modals,
    Notifications,
    Trigger,
    Pagination,
    Panels,
    Panes,
    Portals,
    Radio,
    Ribbons,
    Table,
    Select,
    StreamList,
    Svg,
    Tabs,
    Layout,
    Toggle,
    Tooltip,
  ]
  packages.forEach(attachToWindow)
}<commit_msg>Removed broken import<commit_after>import React from 'react'
import ReactDOM from 'react-dom'

import * as Alerts from 'pui-react-alerts'
import * as Alignment from 'pui-css-alignment'
import * as Autocomplete from 'pui-react-autocomplete'
import * as Top from 'pui-react-back-to-top'
import * as Bootstrap from 'pui-css-bootstrap'
import * as Buttons from 'pui-react-buttons'
import * as Checkbox from 'pui-react-checkbox'
import * as Collapse from 'pui-react-collapse'
import * as Clipboard from 'pui-react-copy-to-clipboard'
import * as Dividers from 'pui-react-dividers'
import * as DraggableList from 'pui-react-draggable-list'
import * as Ellipsis from 'pui-css-ellipsis'
import * as Dropdowns from 'pui-react-dropdowns'
import * as Expander from 'pui-react-expander'
import * as Grids from 'pui-react-grids'
import * as Hoverable from 'pui-css-hoverable'
import * as Iconography from 'pui-react-iconography'
import * as Images from 'pui-react-images'
import * as Inputs from 'pui-react-inputs'
import * as Labels from 'pui-react-labels'
import * as Lists from 'pui-react-lists'
import * as Media from 'pui-react-media'
import * as Modals from 'pui-react-modals'
import * as Notifications from 'pui-react-notifications'
import * as Trigger from 'pui-react-overlay-trigger'
import * as Pagination from 'pui-react-pagination'
import * as Panels from 'pui-react-panels'
import * as Panes from 'pui-react-panes'
import * as Portals from 'pui-react-portals'
import * as Radio from 'pui-react-radio'
import * as Table from 'pui-react-table'
import * as Select from 'pui-react-select'
import * as StreamList from 'pui-react-stream-list'
import * as Svg from 'pui-react-svg'
import * as Tabs from 'pui-react-tabs'
import * as Layout from 'pui-react-tile-layout'
import * as Toggle from 'pui-react-toggle'
import * as Tooltip from 'pui-react-tooltip'

const attachToWindow = pakage => { // package is a reserved word
  Object.keys(pakage).forEach(key => {
    window[key] = pakage[key]
  })
}

export default () => {
  window.React = React
  window.ReactDOM = ReactDOM

  const packages = [
    Alerts,
    Alignment,
    Autocomplete,
    Top,
    Bootstrap,
    Buttons,
    Checkbox,
    Collapse,
    Clipboard,
    Dividers,
    DraggableList,
    Ellipsis,
    Dropdowns,
    Expander,
    Grids,
    Hoverable,
    Iconography,
    Images,
    Inputs,
    Labels,
    Lists,
    Media,
    Modals,
    Notifications,
    Trigger,
    Pagination,
    Panels,
    Panes,
    Portals,
    Radio,
    Ribbons,
    Table,
    Select,
    StreamList,
    Svg,
    Tabs,
    Layout,
    Toggle,
    Tooltip,
  ]
  packages.forEach(attachToWindow)
}<|endoftext|>


<commit_before>'use strict';

var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var path = require('path');
var _ = require('lodash');

var gadget = require('../lib/util');

var options = {};

module.exports = yeoman.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json');

    if (!this.options.skipWelcome) {
      this.log(yosay(
        'Welcome to ' + chalk.red.bold('Gadget ' + this.pkg.version)
        + ', the gnarly generator for Grunt Drupal Tasks!'
      ));
    }
  },

  prompting: function () {
    var self = this;
    var done = this.async();

    if (this.options.hasOwnProperty('drupalDistro') && typeof this.options.drupalDistro === 'string') {
      var distros = require('../app/distros');
      this.options.drupalDistro = distros[this.options.drupalDistro];
    }

    var prompts = require('../lib/prompts');
    prompts = _.filter(prompts, function (item) {
      return _.isUndefined(self.options[item.name]);
    });

    this.prompt(prompts, function (props) {
      options = _.assign(props, this.options);
      if (!options['cacheInternal']) {
        options.cacheInternal = 'database';
      }
      this.log("\nOk, I'm going to start assembling this project...");
      done();
    }.bind(this));
  },

  configuring: {
    // Determine the latest stable release for the requested Drupal core version.
    getDistroRelease: function () {
      // Provide a fallback value in case the request fails.
      options.drupalDistroRelease = options.drupalDistroVersion;

      // Handle version used by updates.drupal.org for 8.x.x releases.
      options.majorVersionForUpdateSystem = options.drupalDistroVersion;
      if (options.majorVersionForUpdateSystem.match(/^8\.\d+\.x$/)) {
        options.majorVersionForUpdateSystem = '8.x';
      }

      // Find the latest stable release for the Drupal distro version.
      var done = this.async();
      options.drupalDistro.releaseVersion(options.majorVersionForUpdateSystem, done, function(err, version, done) {
        if (err) {
          this.log.error(err);
          return done(err);
        }
        options.drupalDistroRelease = version;
        done();
      }.bind(this));
    },

    cacheVersion: function() {
      if (options.cacheInternal != 'database') {
        var done = this.async();
        require('../lib/drupalProjectVersion')
          // the other options for cache are redis and memcache, which happen
          // to be the names of the contrib modules that integrate with them.
          .latestRelease(options.cacheInternal, options.majorVersionForUpdateSystem, done, function(err, version, done) {
            if (err) {
              this.log.error(err);
              return done(err);
            }
            options.cacheVersion = version.substr(4);
            done();
          }.bind(this)
        );
      }
    },

    gdtBase: function() {
      this.fs.copy(
        path.resolve(this.templatePath('gdt'), '**', '*'),
        this.destinationRoot(),
        {
          globOptions: { dot: true }
        }
      );
    }
  },

  writing: {
    distroAdditions: function () {
      var srcFiles = path.resolve(
        this.templatePath('drupal'),
        options.drupalDistro.id,
        options.drupalDistroVersion
      );

      if (gadget.fsExistsSync(srcFiles)) {
        this.fs.copy(
          path.resolve(srcFiles),
          this.destinationRoot(),
          {
            globOptions: { dot: true }
          }
        );
      }
    },

    projectResources: function () {
      this.fs.copy(
        this.templatePath('project/gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copy(
        this.templatePath('project/editorconfig'),
        this.destinationPath('.editorconfig')
      );
    },

    packageJson: function () {
      var pkg = this.fs.readJSON('package.json');

      // Inject grunt-drupal-tasks into the dependency list.
      pkg.dependencies['grunt-drupal-tasks'] = gadget.npmVersion(
        'grunt-drupal-tasks',
        '//github.com/phase2/grunt-drupal-tasks.git',
        this.options['use-master']
      );

      pkg.name = options.projectName;
      pkg.description = options.projectDescription;

      if (!pkg['scripts'] && options['themePath']) {
        pkg.scripts = {};
      }
      if (!pkg.scripts['postinstall'] && options['themePath']) {
        pkg.scripts['postinstall'] = 'cd ' + options.themePath + ' && npm install';
      }

      this.fs.writeJSON('package.json', pkg);
    },

    composerJson: function () {
      var composer = this.fs.readJSON('composer.json');
      composer.name = options.projectName;
      composer.description = options.projectDescription;
      this.fs.writeJSON('composer.json', composer);
    },

    gruntConfig: function () {
      var gcfg = this.fs.readJSON('Gruntconfig.json')

      if (!gcfg) {
        //TODO: throw error
      }

      // Process theme options and insert into Gruntconfig.json.
      if (options.themeName && options.themePath) {
        var themeOpts = {
          path: "<%= config.srcPaths.drupal %>/themes/" + options.themeName
        };

        if (options.themeType === 'compass') {
          themeOpts.compass = true;
        }
        else if (options.themeType === 'grunt' && options.themeGruntTask) {
          themeOpts.grunt = true;
          themeOpts.gruntTask = options.themeGruntTask;
        }

        if (options.themeScripts) {
          themeOpts.scripts = options.themeScripts;
        }

        if (!gcfg.hasOwnProperty('themes')) {
          gcfg.themes = {};
        }
        gcfg.themes[options.themeName] = themeOpts;
      }

      gcfg.project = { 'profile': options.drupalDistro.profile };
      gcfg.generated = { name: this.pkg.name, version: this.pkg.version };

      this.fs.writeJSON('Gruntconfig.json', gcfg);
    },

    readme: function () {
      if (!options['skip-readme']) {
        this.fs.copyTpl(
          this.templatePath('README.md'),
          this.destinationPath('README.md'),
          // Extracted to facilitate parallel README generation by a parent.
          gadget.tokens(options)
        );
      }
    },

    drushMakefile: function () {
      this.log('Setting up Drush makefile to install Drupal Distribution '
        + options.drupalDistro.option.name + ' version '
        + chalk.red(options.drupalDistroRelease) + '.\n');
      var done = this.async();
      options.drupalDistro.drushMakeFile(this, options, done);
    }
  },

  install: function () {
    if (!options['skip-install']) {
      this.npmInstall();
    }
  },

  end: function () {
    if (!options['skipGoodbye']) {
      this.log('\nGadget has ' + chalk.red('finished')
        + ' setting up the Drupal project scaffold with Grunt Drupal Tasks!\n');
      this.log('Run `' + chalk.red('grunt')
        + '` to start the first build of this project.\n');
    }
  }
});
<commit_msg>Fixing undefined error by ensuring that pkg.scripts is created in all cases.<commit_after>'use strict';

var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var path = require('path');
var _ = require('lodash');

var gadget = require('../lib/util');

var options = {};

module.exports = yeoman.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json');

    if (!this.options.skipWelcome) {
      this.log(yosay(
        'Welcome to ' + chalk.red.bold('Gadget ' + this.pkg.version)
        + ', the gnarly generator for Grunt Drupal Tasks!'
      ));
    }
  },

  prompting: function () {
    var self = this;
    var done = this.async();

    if (this.options.hasOwnProperty('drupalDistro') && typeof this.options.drupalDistro === 'string') {
      var distros = require('../app/distros');
      this.options.drupalDistro = distros[this.options.drupalDistro];
    }

    var prompts = require('../lib/prompts');
    prompts = _.filter(prompts, function (item) {
      return _.isUndefined(self.options[item.name]);
    });

    this.prompt(prompts, function (props) {
      options = _.assign(props, this.options);
      if (!options['cacheInternal']) {
        options.cacheInternal = 'database';
      }
      this.log("\nOk, I'm going to start assembling this project...");
      done();
    }.bind(this));
  },

  configuring: {
    // Determine the latest stable release for the requested Drupal core version.
    getDistroRelease: function () {
      // Provide a fallback value in case the request fails.
      options.drupalDistroRelease = options.drupalDistroVersion;

      // Handle version used by updates.drupal.org for 8.x.x releases.
      options.majorVersionForUpdateSystem = options.drupalDistroVersion;
      if (options.majorVersionForUpdateSystem.match(/^8\.\d+\.x$/)) {
        options.majorVersionForUpdateSystem = '8.x';
      }

      // Find the latest stable release for the Drupal distro version.
      var done = this.async();
      options.drupalDistro.releaseVersion(options.majorVersionForUpdateSystem, done, function(err, version, done) {
        if (err) {
          this.log.error(err);
          return done(err);
        }
        options.drupalDistroRelease = version;
        done();
      }.bind(this));
    },

    cacheVersion: function() {
      if (options.cacheInternal != 'database') {
        var done = this.async();
        require('../lib/drupalProjectVersion')
          // the other options for cache are redis and memcache, which happen
          // to be the names of the contrib modules that integrate with them.
          .latestRelease(options.cacheInternal, options.majorVersionForUpdateSystem, done, function(err, version, done) {
            if (err) {
              this.log.error(err);
              return done(err);
            }
            options.cacheVersion = version.substr(4);
            done();
          }.bind(this)
        );
      }
    },

    gdtBase: function() {
      this.fs.copy(
        path.resolve(this.templatePath('gdt'), '**', '*'),
        this.destinationRoot(),
        {
          globOptions: { dot: true }
        }
      );
    }
  },

  writing: {
    distroAdditions: function () {
      var srcFiles = path.resolve(
        this.templatePath('drupal'),
        options.drupalDistro.id,
        options.drupalDistroVersion
      );

      if (gadget.fsExistsSync(srcFiles)) {
        this.fs.copy(
          path.resolve(srcFiles),
          this.destinationRoot(),
          {
            globOptions: { dot: true }
          }
        );
      }
    },

    projectResources: function () {
      this.fs.copy(
        this.templatePath('project/gitignore'),
        this.destinationPath('.gitignore')
      );
      this.fs.copy(
        this.templatePath('project/editorconfig'),
        this.destinationPath('.editorconfig')
      );
    },

    packageJson: function () {
      var pkg = this.fs.readJSON('package.json');

      // Inject grunt-drupal-tasks into the dependency list.
      pkg.dependencies['grunt-drupal-tasks'] = gadget.npmVersion(
        'grunt-drupal-tasks',
        '//github.com/phase2/grunt-drupal-tasks.git',
        this.options['use-master']
      );

      pkg.name = options.projectName;
      pkg.description = options.projectDescription;

      if (!pkg['scripts']) {
        pkg.scripts = {};
      }
      if (!pkg.scripts['postinstall'] && options['themePath']) {
        pkg.scripts['postinstall'] = 'cd ' + options.themePath + ' && npm install';
      }

      this.fs.writeJSON('package.json', pkg);
    },

    composerJson: function () {
      var composer = this.fs.readJSON('composer.json');
      composer.name = options.projectName;
      composer.description = options.projectDescription;
      this.fs.writeJSON('composer.json', composer);
    },

    gruntConfig: function () {
      var gcfg = this.fs.readJSON('Gruntconfig.json')

      if (!gcfg) {
        //TODO: throw error
      }

      // Process theme options and insert into Gruntconfig.json.
      if (options.themeName && options.themePath) {
        var themeOpts = {
          path: "<%= config.srcPaths.drupal %>/themes/" + options.themeName
        };

        if (options.themeType === 'compass') {
          themeOpts.compass = true;
        }
        else if (options.themeType === 'grunt' && options.themeGruntTask) {
          themeOpts.grunt = true;
          themeOpts.gruntTask = options.themeGruntTask;
        }

        if (options.themeScripts) {
          themeOpts.scripts = options.themeScripts;
        }

        if (!gcfg.hasOwnProperty('themes')) {
          gcfg.themes = {};
        }
        gcfg.themes[options.themeName] = themeOpts;
      }

      gcfg.project = { 'profile': options.drupalDistro.profile };
      gcfg.generated = { name: this.pkg.name, version: this.pkg.version };

      this.fs.writeJSON('Gruntconfig.json', gcfg);
    },

    readme: function () {
      if (!options['skip-readme']) {
        this.fs.copyTpl(
          this.templatePath('README.md'),
          this.destinationPath('README.md'),
          // Extracted to facilitate parallel README generation by a parent.
          gadget.tokens(options)
        );
      }
    },

    drushMakefile: function () {
      this.log('Setting up Drush makefile to install Drupal Distribution '
        + options.drupalDistro.option.name + ' version '
        + chalk.red(options.drupalDistroRelease) + '.\n');
      var done = this.async();
      options.drupalDistro.drushMakeFile(this, options, done);
    }
  },

  install: function () {
    if (!options['skip-install']) {
      this.npmInstall();
    }
  },

  end: function () {
    if (!options['skipGoodbye']) {
      this.log('\nGadget has ' + chalk.red('finished')
        + ' setting up the Drupal project scaffold with Grunt Drupal Tasks!\n');
      this.log('Run `' + chalk.red('grunt')
        + '` to start the first build of this project.\n');
    }
  }
});
<|endoftext|>


<commit_before>/**
 * WordPress dependencies
 */
import { addFilter } from '@wordpress/hooks';
import { compose } from '@wordpress/compose';
import domReady from '@wordpress/dom-ready';
import { setDefaultBlockName } from '@wordpress/blocks';
import { select, subscribe } from '@wordpress/data';
const { getSelectedBlockClientId } = select( 'core/editor' );
/**
 * Internal dependencies
 */
import { withAttributes, withBlockName, withHasSelectedInnerblock, withAmpStorySettings } from './components';
import { ALLOWED_BLOCKS, BLOCK_TAG_MAPPING } from './helpers';

// Ensure that the default block is page when no block is selected.
domReady( () => {
	setDefaultBlockName( 'amp/amp-story-page' );
} );
subscribe( () => {
	setDefaultBlockName( getSelectedBlockClientId() ? 'core/paragraph' : 'amp/amp-story-page' );
} );

/**
 * Add AMP attributes to every allowed AMP Story block.
 *
 * @param {Object} settings Settings.
 * @param {string} name Block name.
 * @return {Object} Settings.
 */
const addAMPAttributes = ( settings, name ) => {
	if ( -1 === ALLOWED_BLOCKS.indexOf( name ) ) {
		return settings;
	}

	const addedAttributes = {};

	// Define selector according to mappings.
	if ( BLOCK_TAG_MAPPING[ name ] ) {
		addedAttributes.ampAnimationType = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in',
		};
		addedAttributes.ampAnimationDelay = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-delay',
			default: '0ms',
		};
		addedAttributes.ampAnimationDuration = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-duration',
		};
		addedAttributes.ampAnimationAfter = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-after',
		};
	} else if ( 'core/list' === name ) {
		addedAttributes.ampAnimationType = {
			type: 'string',
		};
		addedAttributes.ampAnimationDelay = {
			type: 'number',
			default: 0,
		};
		addedAttributes.ampAnimationDuration = {
			type: 'number',
			default: 0,
		};
		addedAttributes.ampAnimationAfter = {
			type: 'string',
		};
	}

	// Lets add font family to the text blocks.
	if ( 'core/paragraph' === name || 'core/heading' === name ) {
		addedAttributes.ampFontFamily = {
			type: 'string',
		};
	}

	if ( 'core/image' === name ) {
		addedAttributes.ampShowImageCaption = {
			type: 'boolean',
			default: false,
		};
	}

	settings.attributes = settings.attributes || {};
	settings.attributes = {
		...settings.attributes,
		...addedAttributes,
	};

	return settings;
};

/**
 * Add extra attributes to save to DB.
 *
 * @param {Object} props Properties.
 * @param {Object} blockType Block type.
 * @param {Object} attributes Attributes.
 * @return {Object} Props.
 */
const addAMPExtraProps = ( props, blockType, attributes ) => {
	const ampAttributes = {};

	if ( -1 === ALLOWED_BLOCKS.indexOf( blockType.name ) ) {
		return props;
	}

	if ( attributes.ampAnimationType ) {
		ampAttributes[ 'animate-in' ] = attributes.ampAnimationType;

		if ( attributes.ampAnimationDelay ) {
			ampAttributes[ 'animate-in-delay' ] = attributes.ampAnimationDelay;
		}

		if ( attributes.ampAnimationDuration ) {
			ampAttributes[ 'animate-in-duration' ] = attributes.ampAnimationDuration;
		}

		if ( attributes.ampAnimationAfter ) {
			ampAttributes[ 'animate-in-after' ] = attributes.ampAnimationAfter;
		}
	}

	if ( attributes.ampFontFamily ) {
		ampAttributes[ 'data-font-family' ] = attributes.ampFontFamily;
	}

	return {
		...props,
		...ampAttributes,
	};
};

/**
 * Filter layer properties to define the parent block.
 *
 * @param {Object} props Block properties.
 * @return {Object} Properties.
 */
const setBlockParent = ( props ) => {
	const { name } = props;
	if ( -1 !== ALLOWED_BLOCKS.indexOf( name ) ) {
		// Only amp/amp-story-page blocks can be on the top level.
		return {
			...props,
			parent: [ 'amp/amp-story-page' ],
		};
	}

	if ( -1 === name.indexOf( 'amp/amp-story-page' ) ) {
		// Do not allow inserting any of the blocks if they're not AMP Story blocks.
		return {
			...props,
			parent: [ '' ],
		};
	}

	return props;
};

const wrapperWithSelect = compose(
	withAttributes,
	withBlockName,
	withHasSelectedInnerblock
);

/**
 * Add wrapper props to the blocks.
 *
 * @param {Object} BlockListBlock BlockListBlock element.
 * @return {Function} Handler.
 */
const addWrapperProps = ( BlockListBlock ) => {
	return wrapperWithSelect( ( props ) => {
		const { blockName, hasSelectedInnerBlock, attributes } = props;

		// If it's not an allowed block then lets return original;
		if ( -1 === ALLOWED_BLOCKS.indexOf( blockName ) ) {
			return <BlockListBlock { ...props } />;
		}

		let wrapperProps;

		// If we have an inner block selected let's add 'data-amp-selected=parent' to the wrapper.
		if (
			hasSelectedInnerBlock &&
			(
				'amp/amp-story-page' === blockName
			)
		) {
			wrapperProps = Object.assign( {}, props.wrapperProps, { 'data-amp-selected': 'parent' } );
		} else {
			// If we have image caption or font-family set, add these to wrapper properties.
			wrapperProps = Object.assign( {}, props.wrapperProps, {
				'data-amp-image-caption': ( 'core/image' === blockName && ! attributes.ampShowImageCaption ) ? 'noCaption' : undefined,
				'data-font-family': attributes.ampFontFamily || undefined,
			} );
		}

		return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />;
	} );
};

// These do not reliably work at domReady.
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/setBlockParent', setBlockParent );
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/addAttributes', addAMPAttributes );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/filterEdit', withAmpStorySettings );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/addWrapperProps', addWrapperProps );
addFilter( 'blocks.getSaveContent.extraProps', 'ampStoryEditorBlocks/addExtraAttributes', addAMPExtraProps );
<commit_msg>Use object spread instead of Object.assing for wrapper props<commit_after>/**
 * WordPress dependencies
 */
import { addFilter } from '@wordpress/hooks';
import { compose } from '@wordpress/compose';
import domReady from '@wordpress/dom-ready';
import { setDefaultBlockName } from '@wordpress/blocks';
import { select, subscribe } from '@wordpress/data';
const { getSelectedBlockClientId } = select( 'core/editor' );
/**
 * Internal dependencies
 */
import { withAttributes, withBlockName, withHasSelectedInnerblock, withAmpStorySettings } from './components';
import { ALLOWED_BLOCKS, BLOCK_TAG_MAPPING } from './helpers';

// Ensure that the default block is page when no block is selected.
domReady( () => {
	setDefaultBlockName( 'amp/amp-story-page' );
} );
subscribe( () => {
	setDefaultBlockName( getSelectedBlockClientId() ? 'core/paragraph' : 'amp/amp-story-page' );
} );

/**
 * Add AMP attributes to every allowed AMP Story block.
 *
 * @param {Object} settings Settings.
 * @param {string} name Block name.
 * @return {Object} Settings.
 */
const addAMPAttributes = ( settings, name ) => {
	if ( -1 === ALLOWED_BLOCKS.indexOf( name ) ) {
		return settings;
	}

	const addedAttributes = {};

	// Define selector according to mappings.
	if ( BLOCK_TAG_MAPPING[ name ] ) {
		addedAttributes.ampAnimationType = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in',
		};
		addedAttributes.ampAnimationDelay = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-delay',
			default: '0ms',
		};
		addedAttributes.ampAnimationDuration = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-duration',
		};
		addedAttributes.ampAnimationAfter = {
			source: 'attribute',
			selector: BLOCK_TAG_MAPPING[ name ],
			attribute: 'animate-in-after',
		};
	} else if ( 'core/list' === name ) {
		addedAttributes.ampAnimationType = {
			type: 'string',
		};
		addedAttributes.ampAnimationDelay = {
			type: 'number',
			default: 0,
		};
		addedAttributes.ampAnimationDuration = {
			type: 'number',
			default: 0,
		};
		addedAttributes.ampAnimationAfter = {
			type: 'string',
		};
	}

	// Lets add font family to the text blocks.
	if ( 'core/paragraph' === name || 'core/heading' === name ) {
		addedAttributes.ampFontFamily = {
			type: 'string',
		};
	}

	if ( 'core/image' === name ) {
		addedAttributes.ampShowImageCaption = {
			type: 'boolean',
			default: false,
		};
	}

	settings.attributes = settings.attributes || {};
	settings.attributes = {
		...settings.attributes,
		...addedAttributes,
	};

	return settings;
};

/**
 * Add extra attributes to save to DB.
 *
 * @param {Object} props Properties.
 * @param {Object} blockType Block type.
 * @param {Object} attributes Attributes.
 * @return {Object} Props.
 */
const addAMPExtraProps = ( props, blockType, attributes ) => {
	const ampAttributes = {};

	if ( -1 === ALLOWED_BLOCKS.indexOf( blockType.name ) ) {
		return props;
	}

	if ( attributes.ampAnimationType ) {
		ampAttributes[ 'animate-in' ] = attributes.ampAnimationType;

		if ( attributes.ampAnimationDelay ) {
			ampAttributes[ 'animate-in-delay' ] = attributes.ampAnimationDelay;
		}

		if ( attributes.ampAnimationDuration ) {
			ampAttributes[ 'animate-in-duration' ] = attributes.ampAnimationDuration;
		}

		if ( attributes.ampAnimationAfter ) {
			ampAttributes[ 'animate-in-after' ] = attributes.ampAnimationAfter;
		}
	}

	if ( attributes.ampFontFamily ) {
		ampAttributes[ 'data-font-family' ] = attributes.ampFontFamily;
	}

	return {
		...props,
		...ampAttributes,
	};
};

/**
 * Filter layer properties to define the parent block.
 *
 * @param {Object} props Block properties.
 * @return {Object} Properties.
 */
const setBlockParent = ( props ) => {
	const { name } = props;
	if ( -1 !== ALLOWED_BLOCKS.indexOf( name ) ) {
		// Only amp/amp-story-page blocks can be on the top level.
		return {
			...props,
			parent: [ 'amp/amp-story-page' ],
		};
	}

	if ( -1 === name.indexOf( 'amp/amp-story-page' ) ) {
		// Do not allow inserting any of the blocks if they're not AMP Story blocks.
		return {
			...props,
			parent: [ '' ],
		};
	}

	return props;
};

const wrapperWithSelect = compose(
	withAttributes,
	withBlockName,
	withHasSelectedInnerblock
);

/**
 * Add wrapper props to the blocks.
 *
 * @param {Object} BlockListBlock BlockListBlock element.
 * @return {Function} Handler.
 */
const addWrapperProps = ( BlockListBlock ) => {
	return wrapperWithSelect( ( props ) => {
		const { blockName, hasSelectedInnerBlock, attributes } = props;

		// If it's not an allowed block then lets return original;
		if ( -1 === ALLOWED_BLOCKS.indexOf( blockName ) ) {
			return <BlockListBlock { ...props } />;
		}

		let wrapperProps;

		// If we have an inner block selected let's add 'data-amp-selected=parent' to the wrapper.
		if (
			hasSelectedInnerBlock &&
			(
				'amp/amp-story-page' === blockName
			)
		) {
			wrapperProps = {
				...props.wrapperProps,
				'data-amp-selected': 'parent',
			};

			return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />;
		}

		// If we have image caption or font-family set, add these to wrapper properties.
		wrapperProps = {
			...props.wrapperProps,
			'data-amp-image-caption': ( 'core/image' === blockName && ! attributes.ampShowImageCaption ) ? 'noCaption' : undefined,
			'data-font-family': attributes.ampFontFamily || undefined,
		};

		return <BlockListBlock { ...props } wrapperProps={ wrapperProps } />;
	} );
};

// These do not reliably work at domReady.
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/setBlockParent', setBlockParent );
addFilter( 'blocks.registerBlockType', 'ampStoryEditorBlocks/addAttributes', addAMPAttributes );
addFilter( 'editor.BlockEdit', 'ampStoryEditorBlocks/filterEdit', withAmpStorySettings );
addFilter( 'editor.BlockListBlock', 'ampStoryEditorBlocks/addWrapperProps', addWrapperProps );
addFilter( 'blocks.getSaveContent.extraProps', 'ampStoryEditorBlocks/addExtraAttributes', addAMPExtraProps );
<|endoftext|>


<commit_before>$(function(){
    setupEvents();

    $.ajax({
        url: "/getConfig",
        type: "get",
        success: function(data){
            if (typeof data.ssh != 'undefined') {
                buildConfigForm(data.ssh, 'SSH', 'ssh');
            }

            if (typeof data.db != 'undefined') {
                buildConfigForm(data.db, 'MySQL', 'db');
            }
        }
    });

    $.ajax({
        url: "/getSshConfig",
        type: "get",
        success: function(data) {
            var sshConfigData = data;
        }
    });

    function setupEvents() {
        $('#config-save').on('click', function(){
            var data = $('#config-form').find(':input').serialize();
            $.ajax({
                url: '/setConfig',
                type: 'post',
                data: data
            });
        });
    }

    function buildConfigForm(data, label, group) {
        var container = $('<fieldset>

</fieldset>').appendTo('#config-inputs');
        container.attr('name', group.toLowerCase()).attr('form', 'config-form');
        container.find('h3').text(label + ' Settings');

        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                var e = $('

<input type="text" class="form-control" id="" />

');
                var id = label + key;
                e.find('label').attr('for', id).text(label + " " + key);
                e.find('input').attr('id', id).attr('name', group + "[" + key + "]").val(data[key]);
                container.append(e);
            }
        }
    }
});<commit_msg>Refactoring configuration frontend js<commit_after>var config;
$(function(){

    function Configuration() {
        this.setupEvents();
        this.buildConfig();
    }

    Configuration.prototype.buildConfig = function() {
        var successCallback = function(data) {
            if (typeof data.ssh != 'undefined') {
                this.buildConfigForm(data.ssh, 'SSH', 'ssh');
            }

            if (typeof data.db != 'undefined') {
                this.buildConfigForm(data.db, 'MySQL', 'db');
            }
        }.bind(this);

        this.getConfig(successCallback);
    };

    Configuration.prototype.getConfig = function (successCallback) {
        $.ajax({
            url: "/getConfig",
            type: "get",
            success: successCallback
        });
    };

    Configuration.prototype.setupEvents = function() {
        $('#config-save').on('click', function(){
            var data = $('#config-form').find(':input').serialize();
            $.ajax({
                url: '/setConfig',
                type: 'post',
                data: data
            });
        });
    };

    Configuration.prototype.buildConfigForm = function(data, label, group) {
        var container = $('<fieldset>

</fieldset>').appendTo('#config-inputs');
        container.attr('name', group.toLowerCase()).attr('form', 'config-form');
        container.find('h3').text(label + ' Settings');

        for (var key in data) {
            if (data.hasOwnProperty(key)) {
                var e = $('

<input type="text" class="form-control" id="" />

');
                var id = label + key;
                e.find('label').attr('for', id).text(label + " " + key);
                e.find('input').attr('id', id).attr('name', group + "[" + key + "]").val(data[key]);
                container.append(e);
            }
        }
    };

    Configuration.prototype.getSshConfig = function() {
        $.ajax({
            url: "/getSshConfig",
            type: "get",
            success: function(data) {
                var sshConfigData = data;
            }
        });
    };

    config = new Configuration();

});<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

function generateGUID() {
  /* jshint bitwise:false */
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

function bundleIdFromName(props) {
  return "com." + _.slugify(props.author) + "." + _.slugify(props.appname);
}

function notBlank(val) {
  return val && val !== "";
}

function notSpecifiedFilter(val) {
  return val === "" ? "not specified" : val;
}

var CliTitaniumProjectGenerator = module.exports = function CliTitaniumProjectGenerator(args, options, config) {
  /* jshint unused:false */
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(CliTitaniumProjectGenerator, yeoman.generators.Base);

CliTitaniumProjectGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    type:    'input',
    name:    'author',
    message: 'Your name please:'
  }, {
    type:     'input',
    name:     'appname',
    message:  'What will you call your app?',
    validate: notBlank
  }, {
    type:     'input',
    name:     'bundle_id',
    message:  'What is the bundle ID?',
    default:  bundleIdFromName,
    validate: notBlank
  }, {
    type:     'input',
    name:     'version',
    message:  'What version would you like to start with?',
    default:  '0.0.0',
    validate: notBlank
  }, {
    type:    'input',
    name:    'description',
    message: 'Provide a short description for your app:',
    filter:  notSpecifiedFilter
  }, {
    type:    'input',
    name:    'url',
    message: 'What is the URL for the project wenpage (if any)'
  }, {
    type:    'checkbox',
    name:    'options',
    message: 'Extras:',
    choices: [{
      name:    'Include Alloy',
      value:   'use_alloy',
      checked: true
    }, {
      name:    'Include a testing framework (mocha, chai, sinon, mockti)',
      value:   'use_tests',
      checked: true
    }, {
      name:    'Use an express server for local (offline) development',
      value:   'use_server',
      checked: false
    }]
  }];

  this.prompt(prompts, function (props) {
    /* jshint camelcase:false */
    this.author      = props.author;
    this.appname     = props.appname;
    this.bundle_id   = props.bundle_id;
    this.description = props.description;
    this.url         = props.url;
    this.version     = props.version;
    this.use_alloy   = props.options.indexOf('use_alloy') !== -1;
    this.use_tests   = props.options.indexOf('use_tests') !== -1;
    this.use_server  = props.options.indexOf('use_server') !== -1;
    this.guid        = generateGUID();
    this.copyright   = new Date().getFullYear() + (this.author ? " " + this.author : "");

    cb();
  }.bind(this));
};

CliTitaniumProjectGenerator.prototype.app = function app() {
  this.template('_package.json', 'package.json');
  this.template('tiapp.xml', 'tiapp.xml');
};

CliTitaniumProjectGenerator.prototype.projectfiles = function projectfiles() {
  this.template('launcher', 'launcher');
  this.copy('jshintrc', '.jshintrc');
};

CliTitaniumProjectGenerator.prototype.serverFiles = function projectfiles() {
  this.mkdir('dev_server');
  this.copy('server.coffee', 'dev_server/server.coffee');
};

CliTitaniumProjectGenerator.prototype.testFiles = function projectfiles() {
};
<commit_msg>Fix bundleID prompt<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

function generateGUID() {
  /* jshint bitwise:false */
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

function extractBundleId(_, props) {
  return "com." + _.slugify(props.author) + "." + _.slugify(props.appname);
}

function notBlank(val) {
  return val && val !== "";
}

function notSpecifiedFilter(val) {
  return val === "" ? "not specified" : val;
}

var CliTitaniumProjectGenerator = module.exports = function CliTitaniumProjectGenerator(args, options, config) {
  /* jshint unused:false */
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(CliTitaniumProjectGenerator, yeoman.generators.Base);

CliTitaniumProjectGenerator.prototype.askFor = function askFor() {
  var cb = this.async();
  var bundleIdFromName = this._.partial(extractBundleId, this._);

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    type:    'input',
    name:    'author',
    message: 'Your name please:'
  }, {
    type:     'input',
    name:     'appname',
    message:  'What will you call your app?',
    default:  this.appname,
    validate: notBlank
  }, {
    type:     'input',
    name:     'bundle_id',
    message:  'What is the bundle ID?',
    default:  bundleIdFromName,
    validate: notBlank
  }, {
    type:     'input',
    name:     'version',
    message:  'What version would you like to start with?',
    default:  '0.0.0',
    validate: notBlank
  }, {
    type:    'input',
    name:    'description',
    message: 'Provide a short description for your app:',
    filter:  notSpecifiedFilter
  }, {
    type:    'input',
    name:    'url',
    message: 'What is the URL for the project wenpage (if any)'
  }, {
    type:    'checkbox',
    name:    'options',
    message: 'Extras:',
    choices: [{
      name:    'Include Alloy',
      value:   'use_alloy',
      checked: true
    }, {
      name:    'Include a testing framework (mocha, chai, sinon, mockti)',
      value:   'use_tests',
      checked: true
    }, {
      name:    'Use an express server for local (offline) development',
      value:   'use_server',
      checked: false
    }]
  }];

  this.prompt(prompts, function (props) {
    /* jshint camelcase:false */
    this.author      = props.author;
    this.appname     = props.appname;
    this.bundle_id   = props.bundle_id;
    this.description = props.description;
    this.url         = props.url;
    this.version     = props.version;
    this.use_alloy   = props.options.indexOf('use_alloy') !== -1;
    this.use_tests   = props.options.indexOf('use_tests') !== -1;
    this.use_server  = props.options.indexOf('use_server') !== -1;
    this.guid        = generateGUID();
    this.copyright   = new Date().getFullYear() + (this.author ? " " + this.author : "");

    cb();
  }.bind(this));
};

CliTitaniumProjectGenerator.prototype.app = function app() {
  this.template('_package.json', 'package.json');
  this.template('tiapp.xml', 'tiapp.xml');
};

CliTitaniumProjectGenerator.prototype.projectfiles = function projectfiles() {
  this.template('launcher', 'launcher');
  this.copy('jshintrc', '.jshintrc');
};

CliTitaniumProjectGenerator.prototype.serverFiles = function projectfiles() {
  this.mkdir('dev_server');
  this.copy('server.coffee', 'dev_server/server.coffee');
};

CliTitaniumProjectGenerator.prototype.testFiles = function projectfiles() {
};
<|endoftext|>


<commit_before>const editTextarea = {
  init() {
    // get all textarea elements with a maxlength attr
    const textAreaEls = document.querySelectorAll("textarea[data-max-length]");

    if (textAreaEls.length < 1) return;

    textAreaEls.forEach(el => {
      const limit = el.getAttribute("data-max-length");

      // create and insert counter element
      const counterEl = document.createElement("div");
      counterEl.innerText = `0/${limit}`;
      counterEl.className = "textarea-counter";
      el.insertAdjacentElement("afterend", counterEl);

      // update count on every character change
      el.addEventListener("keyup", e => {
        const count = e.target.value.length;
        counterEl.innerText = `${count}/${limit}`;
        if (count > limit) {
          counterEl.classList.add("textarea-counter-over-limit");
        } else {
          counterEl.classList.remove("textarea-counter-over-limit");
        }
      });
    });
  },
};

export default editTextarea;
<commit_msg>display character count on page load in edit article...brief de Brief Description field<commit_after>const editTextarea = {
  init() {
    // get all textarea elements with a maxlength attr
    const textAreaEls = document.querySelectorAll("textarea[data-max-length]");

    if (textAreaEls.length < 1) return;

    textAreaEls.forEach(el => {
      const limit = el.getAttribute("data-max-length");

      // create and insert counter element
      const counterEl = document.createElement("div");
      counterEl.innerText = `${el.innerHTML.length}/${limit}`;
      counterEl.className = "textarea-counter";
      el.insertAdjacentElement("afterend", counterEl);

      // update count on every character change
      el.addEventListener("keyup", e => {
        const count = e.target.value.length;
        counterEl.innerText = `${count}/${limit}`;
        if (count > limit) {
          counterEl.classList.add("textarea-counter-over-limit");
        } else {
          counterEl.classList.remove("textarea-counter-over-limit");
        }
      });
    });
  },
};

export default editTextarea;
<|endoftext|>