<commit_before>/**
 * JavaScript for the BucketList FieldFrame field type.
 *
 * @package		BucketList
 * @author 		Stephen Lewis (http://eepro.co.uk/)
 * @copyright 	Copyright (c) 2009, Stephen Lewis
 * @link 		http://eepro.co.uk/bucketlist/
 */

jQuery.noConflict();
jQuery(document).ready(function($) {

	// Is the downloads status bar visible?
	statusActive = false;

	/**
	 * Controls the display of the status bar.
	 *
	 * @access	private
	 * @param 	bool	showStatus		Show or hide the status bar (default true).
	 * @return 	void
	 */
	function displayStatusBar(showStatus) {

		// Enough with the typing.
		$statusBar = $('#bucketload-status');

		// Where are we heading to?
		targetBottom = (showStatus === false) ? -$statusBar.outerHeight(true) * 1.5 : 0;

		// Animate!
		$statusBar.stop(true, false).animate({bottom : targetBottom}, 500, function() {
			statusActive = (showStatus !== false);
		});
	}

	/**
	 * Removes an upload item from the list.
	 *
	 * @access	private
	 * @param 	string		uploadId		The upload ID of the item to remove.
	 * @return 	void.
	 */
	function removeUpload(uploadId) {

		// Shorthand.
		$item = $('#bucketload-status-' + uploadId);

		// Hide the item.
		$item.animate({width : 'hide', opacity : 0}, 500, function() {
			// If this is the last item, hide the bar.
			if ($(this).siblings().length == 0) {
				displayStatusBar(false);
			}

			// Remove this item.
			$(this).remove();
		});
	}

	/**
	 * Notifies the user of a successful upload.
	 *
	 * @access	private
	 * @param 	object		params		listItem, message, status, uploadId.
	 */
	function uploadSuccess(params) {
		$('li#bucketload-status-' + params['uploadId'])
			.removeClass('active')
			.addClass('complete')
			.html(params.message);

		setTimeout('removeUpload("' + params.uploadId + '")', 1500);
	}

	/**
	 * Notifies the user of a failed upload.
	 *
	 * @access	private
	 * @param	object		params		listItem, message, status, uploadId.
	 */
	function uploadFailure(params) {
		if (params.message == '' || params.message == 'undefined') {
			params.message = languageStrings.uploadFailureGeneric;
		}

		$('#bucketload-status li#bucketload-status-' + params.uploadId)
			.removeClass('active')
			.addClass('error')
			.html(params.message);
	}

	/**
	 * Notifies the user that the upload has started, by adding an item
	 * to the upload list.
	 *
	 * @access	private
	 * @param	object		params		fileName, uploadId.
	 */
	function uploadStart(params) {
		// Stupid IE has to be different, and include some nonsense path with the file name.
		fileName = params.fileName.replace(/.*(\/|\\)/, '');

		// Create the new item, append it to the list, and fade it in.
		$li = $('
' + fileName + '
');
		$li.appendTo('#bucketload-status ul').hide().fadeIn('fast');

		// If the status bar is currently hidden, show it.
		if (statusActive == false) {
			displayStatusBar(true);
		}
	}

	/**
	 * Alerts the user to in-progress uploads when he attempts to save, preview, or quick save
	 * the page. If there are no in-progress uploads, we let him proceed without question.
	 *
	 * @access	public
	 * @param 	object		e		jQuery event object.
	 */
	function handleSubmit(e) {
		pendingUploads = $('#bucketload-status li').length;

		if (typeof(pendingUploads) == 'number' && pendingUploads > 0) {
			return confirm(languageStrings.confirmExit);
		}
	}

	/**
	 * Alerts the user to in-progress uploads when he attempts to navigate away from
	 * the page, or close the window. If there are no in-progress uploads, we let him
	 * proceed without question.
	 *
	 * @access	public
	 * @param 	object		e		Native browser event object (event not bound using jQuery)
	 */
	function handleNavigate(e) {
		pendingUploads = $('#bucketload-status li').length;

		if (typeof(pendingUploads) == 'number' && pendingUploads > 0) {
			return languageStrings.confirmExit;
		}
	}

	/**
	 * ------------------------------------------------------------------
	 * Initialisation.
	 * ------------------------------------------------------------------
	 */

	selector = 'input[type="submit"][name="preview"], input[type="submit"][name="save"], input[type="submit"][name="submit"]';

	$(selector).bind('click', handleSubmit);
	window.onbeforeunload = handleNavigate;		// Do it the old-fashioned way. The jQuery event seems rather flakey.

	/**
	 * We post any AJAX requests back to the current URL, to be handled by
	 * the sessions_start hook.
	 *
	 * The advantages of doing it this way are two-fold:
	 * 1. We know for certain that the FieldFrame extension will be instantiated
	 * for this page, so all the FF-dependent gumpf in the BucketList fieldtype
	 * will work as expected.
	 *
	 * 2. Everything will work in the CP, and in a SAEF. Spiffing.
	 */

	// Create the upload status bar.
	$('body').append('

');

	// Hide the status bar, in case it isn't already.
	displayStatusBar(false);

	targetURL = document.location.href;

	$.fn.bucketlist.defaults.ajaxScriptURL 		= targetURL;
	$.fn.bucketlist.defaults.uploadFormAction	= targetURL;
	$.fn.bucketlist.defaults.onUploadFailure 	= uploadFailure;
	$.fn.bucketlist.defaults.onUploadStart		= uploadStart;
	$.fn.bucketlist.defaults.onUploadSuccess	= uploadSuccess;

	// Initialise non-matrix file trees.
	$('.ff-ft > .eepro-co-uk > .bucketlist-ui').each(function() {
		$(this).bucketlist({initialFile : $(this).next(':hidden').val()});
	});

	// Initialise matrix file trees.
	if (typeof $.fn.ffMatrix != 'undefined') {

		/**
		 * Initialise matrix file trees. Also handles new table cells as
		 * they are created.
		 *
		 * This is the only way of doing this at present, but by Brandon's
		 * own admission it's a trifle flakey, and has a habit of running
		 * twice.
		 *
		 * I tried checking for the presence of the BucketList file tree,
		 * but that wasn't working. Setting a class 'flag' on the td
		 * works fine though.
		 *
		 * Of course, we're screwed if FF Matrix ever fails to trigger
		 * this method.
		 */

		$.fn.ffMatrix.onDisplayCell.bucketlist = function(td, matrix) {
			$td = $(td);

			if ($td.hasClass('.bucketlist-ready') == false) {
				$td.addClass('bucketlist-ready').find('.bucketlist-ui').each(function() {
					$(this).bucketlist({
						initialFile : $(this).parents('.eepro-co-uk').find('input:hidden').val()
					});
				});
			}
		}
	}
});<commit_msg>Fixed bug introduced by use of JS closure in v1.0.3, with the cunning use of an JS closure.<commit_after>/**
 * JavaScript for the BucketList FieldFrame field type.
 *
 * @package		BucketList
 * @author 		Stephen Lewis (http://eepro.co.uk/)
 * @copyright 	Copyright (c) 2009, Stephen Lewis
 * @link 		http://eepro.co.uk/bucketlist/
 */

jQuery.noConflict();
jQuery(document).ready(function($) {

	// Is the downloads status bar visible?
	statusActive = false;

	/**
	 * Controls the display of the status bar.
	 *
	 * @access	private
	 * @param 	bool	showStatus		Show or hide the status bar (default true).
	 * @return 	void
	 */
	function displayStatusBar(showStatus) {

		// Enough with the typing.
		$statusBar = $('#bucketload-status');

		// Where are we heading to?
		targetBottom = (showStatus === false) ? -$statusBar.outerHeight(true) * 1.5 : 0;

		// Animate!
		$statusBar.stop(true, false).animate({bottom : targetBottom}, 500, function() {
			statusActive = (showStatus !== false);
		});
	}

	/**
	 * Notifies the user of a successful upload.
	 *
	 * @access	private
	 * @param 	object		params		listItem, message, status, uploadId.
	 */
	function uploadSuccess(params) {
		$('li#bucketload-status-' + params['uploadId'])
			.removeClass('active')
			.addClass('complete')
			.html(params.message);

		setTimeout(removeUpload, 1500);

		// Removes the uploaded item from the status bar.
		function removeUpload() {
			$item = $('#bucketload-status-' + params['uploadId']);

			// Hide the item.
			$item.animate({width : 'hide', opacity : 0}, 500, function() {
				// If this is the last item, hide the bar.
				if ($(this).siblings().length == 0) {
					displayStatusBar(false);
				}

				// Remove this item.
				$(this).remove();
			});
		}
	}

	/**
	 * Notifies the user of a failed upload.
	 *
	 * @access	private
	 * @param	object		params		listItem, message, status, uploadId.
	 */
	function uploadFailure(params) {
		if (params.message == '' || params.message == 'undefined') {
			params.message = languageStrings.uploadFailureGeneric;
		}

		$('#bucketload-status li#bucketload-status-' + params.uploadId)
			.removeClass('active')
			.addClass('error')
			.html(params.message);
	}

	/**
	 * Notifies the user that the upload has started, by adding an item
	 * to the upload list.
	 *
	 * @access	private
	 * @param	object		params		fileName, uploadId.
	 */
	function uploadStart(params) {
		// Stupid IE has to be different, and include some nonsense path with the file name.
		fileName = params.fileName.replace(/.*(\/|\\)/, '');

		// Create the new item, append it to the list, and fade it in.
		$li = $('
' + fileName + '
');
		$li.appendTo('#bucketload-status ul').hide().fadeIn('fast');

		// If the status bar is currently hidden, show it.
		if (statusActive == false) {
			displayStatusBar(true);
		}
	}

	/**
	 * Alerts the user to in-progress uploads when he attempts to save, preview, or quick save
	 * the page. If there are no in-progress uploads, we let him proceed without question.
	 *
	 * @access	public
	 * @param 	object		e		jQuery event object.
	 */
	function handleSubmit(e) {
		pendingUploads = $('#bucketload-status li').length;

		if (typeof(pendingUploads) == 'number' && pendingUploads > 0) {
			return confirm(languageStrings.confirmExit);
		}
	}

	/**
	 * Alerts the user to in-progress uploads when he attempts to navigate away from
	 * the page, or close the window. If there are no in-progress uploads, we let him
	 * proceed without question.
	 *
	 * @access	public
	 * @param 	object		e		Native browser event object (event not bound using jQuery)
	 */
	function handleNavigate(e) {
		pendingUploads = $('#bucketload-status li').length;

		if (typeof(pendingUploads) == 'number' && pendingUploads > 0) {
			return languageStrings.confirmExit;
		}
	}

	/**
	 * ------------------------------------------------------------------
	 * Initialisation.
	 * ------------------------------------------------------------------
	 */

	selector = 'input[type="submit"][name="preview"], input[type="submit"][name="save"], input[type="submit"][name="submit"]';

	$(selector).bind('click', handleSubmit);
	window.onbeforeunload = handleNavigate;		// Do it the old-fashioned way. The jQuery event seems rather flakey.

	/**
	 * We post any AJAX requests back to the current URL, to be handled by
	 * the sessions_start hook.
	 *
	 * The advantages of doing it this way are two-fold:
	 * 1. We know for certain that the FieldFrame extension will be instantiated
	 * for this page, so all the FF-dependent gumpf in the BucketList fieldtype
	 * will work as expected.
	 *
	 * 2. Everything will work in the CP, and in a SAEF. Spiffing.
	 */

	// Create the upload status bar.
	$('body').append('

');

	// Hide the status bar, in case it isn't already.
	displayStatusBar(false);

	targetURL = document.location.href;

	$.fn.bucketlist.defaults.ajaxScriptURL 		= targetURL;
	$.fn.bucketlist.defaults.uploadFormAction	= targetURL;
	$.fn.bucketlist.defaults.onUploadFailure 	= uploadFailure;
	$.fn.bucketlist.defaults.onUploadStart		= uploadStart;
	$.fn.bucketlist.defaults.onUploadSuccess	= uploadSuccess;

	// Initialise non-matrix file trees.
	$('.ff-ft > .eepro-co-uk > .bucketlist-ui').each(function() {
		$(this).bucketlist({initialFile : $(this).next(':hidden').val()});
	});

	// Initialise matrix file trees.
	if (typeof $.fn.ffMatrix != 'undefined') {

		/**
		 * Initialise matrix file trees. Also handles new table cells as
		 * they are created.
		 *
		 * This is the only way of doing this at present, but by Brandon's
		 * own admission it's a trifle flakey, and has a habit of running
		 * twice.
		 *
		 * I tried checking for the presence of the BucketList file tree,
		 * but that wasn't working. Setting a class 'flag' on the td
		 * works fine though.
		 *
		 * Of course, we're screwed if FF Matrix ever fails to trigger
		 * this method.
		 */

		$.fn.ffMatrix.onDisplayCell.bucketlist = function(td, matrix) {
			$td = $(td);

			if ($td.hasClass('.bucketlist-ready') == false) {
				$td.addClass('bucketlist-ready').find('.bucketlist-ui').each(function() {
					$(this).bucketlist({
						initialFile : $(this).parents('.eepro-co-uk').find('input:hidden').val()
					});
				});
			}
		}
	}
});<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var cordova = require('cordova-lib').cordova.raw; // get the promise version of all methdos
var wiredep = require('wiredep');

var GulpIonicGenerator = yeoman.generators.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json'); // get package.json content
    // TODO: check if .yo-rc.json exists: options: call subgenerator? update project structure? select subgenerator?
    // retrieve config for templating
    this.answers = this.config.getAll().answers;
    this.update = this.answers ? true : false;
  },

  prompting: function () {
    if (this.update) {
      return;
    }
    // say hello
    this.log(yosay(
      'Welcome to the polished M generator!'
    ));

    // tell yeoman we're doing asynchronous stuff here
    // so it can wait with subsequent tasks
    var done = this.async();

    var prompts = [
      // appName
      {
        type: 'input',
        name: 'appName',
        message: 'state the name of your project (the name that will be displayed below the app icon)',
        validate: function (value) {
          return value ? true : 'Please enter a name ';
        }
      },
      // appId
      {
        type: 'input',
        name: 'appId',
        message: 'state the id of your project (e.g. com.company.project)',
        validate: function (value) {
          var splits = value.split('.').filter(function (element) {
            return element.length;
          });
          return splits.length >= 3 ? true : 'Please enter a valid id! E.g. com.company.project';
        }
      },
      // bower packages
      {
        type: 'checkbox',
        name: 'bowerPackages',
        message: 'Choose all bower packages in addition to angular, ionic, angular-ui-router, cordova and ngCordova:',
        choices: [
          {
            value: 'angular-dynamic-locale#~0.1.17',
            name: 'angular-dynamic-locale#~0.1.17',
            checked: true
          },
          {
            value: 'angular-localForage#~0.2.10',
            name: 'angular-localForage#~0.2.10',
            checked: true
          },
          {
            value: 'angular-touch#~1.2.25',
            name: 'angular-touch#~1.2.25',
            checked: true
          },
          {
            value: 'angular-translate#~2.4.0',
            name: 'angular-translate#~2.4.0',
            checked: true
          },
          {
            value: 'angular-translate-loader-static-files#~2.4.0',
            name: 'angular-translate-loader-static-files#~2.4.0',
            checked: true
          },
          {
            value: 'angular-ui-bootstrap-bower#~0.11.0',
            name: 'angular-ui-bootstrap-bower#~0.11.0',
            checked: true
          },
          {
            value: 'fastclick#~1.0.3',
            name: 'fastclick#~1.0.3',
            checked: true
          },
          {
            value: 'ratchet#~2.0.2',
            name: 'ratchet#~2.0.2',
            checked: false
          },
          {
            value: 'restangular#~1.4.0',
            name: 'restangular#~1.4.0',
            checked: true
          }
        ]
      },
      // stableVersions
      {
        type: 'list',
        name: 'ionicSass',
        message: 'Do you want to use the sass version of ionic\'s css?',
        choices: [
          {
            value: true,
            name: 'yes (more flexible)',
            default: true
          },
          {
            value: false,
            name: 'not (faster)',
          }
        ]
      },
      // stableVersions
      {
        type: 'list',
        name: 'stableVersions',
        message: 'Do you want to use components (bower & npm) we deem stable or the latest ones?',
        choices: [
          {
            value: true,
            name: 'stable (recommended)',
            default: true
          },
          {
            value: false,
            name: 'latest (experienced)',
          }
        ]
      },
      // select platforms
      {
        type: 'checkbox',
        name: 'platforms',
        message: 'Select all platforms you want to support:',
        choices: [
          {
            value: 'ios',
            name: 'iOS',
            checked: true
          },
          {
            value: 'android',
            name: 'Android',
            checked: true
          }
        ]
      },
      // select plugins
      {
        type: 'checkbox',
        name: 'plugins',
        message: 'Select all cordova plugins you want to install',
        choices: [
          new yeoman.inquirer.Separator(),
          {
            value: 'org.apache.cordova.device',
            name: 'Device - org.apache.cordova.device',
            checked: true
          },
          {
            value: 'org.apache.cordova.dialogs',
            name: 'Dialogs - org.apache.cordova.dialogs'
          },
          {
            value: 'org.apache.cordova.network-information',
            name: 'Network - org.apache.cordova.network-information'
          },
          {
            value: 'org.apache.cordova.splashscreen',
            name: 'Splashscreen - org.apache.cordova.splashscreen'
          },
          {
            value: 'https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git',
            name: 'Toast - https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git'
          },
          {
            value: 'org.apache.cordova.vibration',
            name: 'Vibration - org.apache.cordova.vibration'
          },
        ]
      },
    ];

    // prompt and save results in this.answers
    this.prompt(prompts, function (answers) {
      this.answers = answers;
      answers.includeSass = true; // set to true for now

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

  configuring: function () {

    // TODO: remove debugging
    // debugging
    this.log(chalk.inverse(JSON.stringify(this.answers, null, '  ')));
    // this.answers = {
    //   'appName': 'asdf',
    //   'appId': 'com.company.project',
    //   'bowerPackages': [
    //     'angular-dynamic-locale#~0.1.17',
    //     'angular-localForage#~0.2.10',
    //     'angular-touch#~1.2.25',
    //     'angular-translate#~2.4.0',
    //     'angular-translate-loader-static-files#~2.4.0',
    //     'angular-ui-bootstrap-bower#~0.11.0',
    //     'fastclick#~1.0.3',
    //     'restangular#~1.4.0'
    //   ],
    //   'ionicSass': true,
    //   'stableVersions': true,
    //   'platforms': [
    //     'ios',
    //     'android'
    //   ],
    //   'plugins': [
    //     'org.apache.cordova.device',
    //     'org.apache.cordova.dialogs'
    //   ],
    //   'includeSass': true
    // };

    // store config in .yo-rc.json
    this.config.set('answers', this.answers);
  },

  writing: {

    cordova: function () {
      if (this.update) {
        return true;
      }

      var done = this.async(); // wait with subsequent tasks since cordova needs an empty folder
      // cordova project
      cordova.create('.', this.answers.appId, this.answers.appName)
      // add platforms
      .then(function () {
        this.log(chalk.green('Created cordova project'));
        return cordova.platform('add', this.answers.platforms);
      }.bind(this))
      // add plugins
      .then(function () {
        this.log(chalk.green('Added platforms: ' + this.answers.platforms.join(', ')));
        return cordova.plugins('add', this.answers.plugins);
      }.bind(this))
      // all
      .then(function () {
        this.log(chalk.green('Added plugins: ' + this.answers.plugins.join(', ')));
        this.log(chalk.green('Cordova project was set up successfully! Project Name: '), chalk.bgGreen(this.answers.appId));
        done();
      }.bind(this))
      .catch(function (err) {
        this.log(chalk.red('Couldn\'t finish generator: \n' + err));
        // halts because done will not be called!
      }.bind(this));
    },

    app: function () {
      // prepare bower.json
      var bower = this.bower = {
        dependencies: {
          'ionic': 'v1.0.0-beta.12',
          'angular': '~1.3.0-rc.2',
          'angular-ui-router': '~0.2.10',
          'ngCordova': '~0.1.4-alpha',
          'cordova': '~3.4.0'
        },
        devDependencies: {

        },
        resolutions: {
          'angular': '~1.3.0-rc.2'
        }
      };
      // include selected packages
      for (var i = 0, bowerPackage; (bowerPackage = this.answers.bowerPackages[i]); i++) {
        bowerPackage = bowerPackage.split('#');
        this.bower.dependencies[bowerPackage[0]] = bowerPackage[1];
      }
      // set all deps to latest?
      if (!this.answers.stableVersions) {
        for (var topKey in bower) {
          for (var key in bower[topKey]) {
            bower[topKey][key] = 'latest';
          }
        }
      }
      // add other properties
      bower.name = this.answers.appName;
      bower.private = true;

      // prepare index
      var indexFile = this.readFileAsString(path.join(this.sourceRoot(), '_index.html'));
      indexFile = this.engine(indexFile, this); // create template with data from 'this'

      // app  files
      this.copy('_app.js', 'app/scripts/app.js');
      this.write('bower.json', JSON.stringify(bower, null, 2));
      this.template('_gulpfile.js', 'gulpfile.js');
      this.write('app/index.html', indexFile);

      var css = 'main.' + (this.answers.includeSass ? 's' : '') + 'css';
      this.copy(css, 'app/styles/' + css);
    },

    projectfiles: function () {

      this.template('_package.json', 'package.json');
      this.copy('bowerrc', '.bowerrc');
      this.copy('editorconfig', '.editorconfig');
      this.copy('gitattributes', '.gitattributes');
      this.copy('gitignore', '.gitignore');
      this.copy('jscsrc', '.jscsrc');
      this.copy('jshintrc', '.jshintrc');
      this.copy('jshintignore', '.jshintignore');
      this.copy('jshintrc', '.jshintrc');
      this.copy('README.md', 'README.md');
    },

    subgenerators: function () {
      this.composeWith('m:service', {arguments: 'start', options: {sample: 'start'}});
      this.composeWith('m:controller', {arguments: 'start', options: {sample: 'start'}});
      this.composeWith('m:partial', {arguments: 'start', options: {sample: 'start'}});
    }
  },

  install: function () {
    this.installDependencies({
      skipInstall: this.options['skip-install'],
      callback: function () {
        if (!this.options['skip-install']) {
          // inject bower dependencies and app js files
          var done = this.async();
          this.spawnCommand('gulp', ['wiredep', 'fonts'])
          .on('exit', function () {
            // TODO: better gulp task wiring/dependencies
            // https://github.com/gulpjs/gulp/blob/master/docs/API.md#async-task-support
            // https://github.com/klei/gulp-inject#injecting-files-from-multiple-source-streams
            // https://github.com/klei/gulp-inject#injecting-some-files-into-head-and-some-into-body
            this.spawnCommand('gulp', ['inject']);
            done();
          }.bind(this));
        }
      }.bind(this)
    });
  },

  end: function () {

  }
});

module.exports = GulpIonicGenerator;
<commit_msg>don't print answers<commit_after>'use strict';

var path = require('path');
var yeoman = require('yeoman-generator');
var yosay = require('yosay');
var chalk = require('chalk');
var cordova = require('cordova-lib').cordova.raw; // get the promise version of all methdos
var wiredep = require('wiredep');

var GulpIonicGenerator = yeoman.generators.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json'); // get package.json content
    // TODO: check if .yo-rc.json exists: options: call subgenerator? update project structure? select subgenerator?
    // retrieve config for templating
    this.answers = this.config.getAll().answers;
    this.update = this.answers ? true : false;
  },

  prompting: function () {
    if (this.update) {
      return;
    }
    // say hello
    this.log(yosay(
      'Welcome to the polished M generator!'
    ));

    // tell yeoman we're doing asynchronous stuff here
    // so it can wait with subsequent tasks
    var done = this.async();

    var prompts = [
      // appName
      {
        type: 'input',
        name: 'appName',
        message: 'state the name of your project (the name that will be displayed below the app icon)',
        validate: function (value) {
          return value ? true : 'Please enter a name ';
        }
      },
      // appId
      {
        type: 'input',
        name: 'appId',
        message: 'state the id of your project (e.g. com.company.project)',
        validate: function (value) {
          var splits = value.split('.').filter(function (element) {
            return element.length;
          });
          return splits.length >= 3 ? true : 'Please enter a valid id! E.g. com.company.project';
        }
      },
      // bower packages
      {
        type: 'checkbox',
        name: 'bowerPackages',
        message: 'Choose all bower packages in addition to angular, ionic, angular-ui-router, cordova and ngCordova:',
        choices: [
          {
            value: 'angular-dynamic-locale#~0.1.17',
            name: 'angular-dynamic-locale#~0.1.17',
            checked: true
          },
          {
            value: 'angular-localForage#~0.2.10',
            name: 'angular-localForage#~0.2.10',
            checked: true
          },
          {
            value: 'angular-touch#~1.2.25',
            name: 'angular-touch#~1.2.25',
            checked: true
          },
          {
            value: 'angular-translate#~2.4.0',
            name: 'angular-translate#~2.4.0',
            checked: true
          },
          {
            value: 'angular-translate-loader-static-files#~2.4.0',
            name: 'angular-translate-loader-static-files#~2.4.0',
            checked: true
          },
          {
            value: 'angular-ui-bootstrap-bower#~0.11.0',
            name: 'angular-ui-bootstrap-bower#~0.11.0',
            checked: true
          },
          {
            value: 'fastclick#~1.0.3',
            name: 'fastclick#~1.0.3',
            checked: true
          },
          {
            value: 'ratchet#~2.0.2',
            name: 'ratchet#~2.0.2',
            checked: false
          },
          {
            value: 'restangular#~1.4.0',
            name: 'restangular#~1.4.0',
            checked: true
          }
        ]
      },
      // stableVersions
      {
        type: 'list',
        name: 'ionicSass',
        message: 'Do you want to use the sass version of ionic\'s css?',
        choices: [
          {
            value: true,
            name: 'yes (more flexible)',
            default: true
          },
          {
            value: false,
            name: 'not (faster)',
          }
        ]
      },
      // stableVersions
      {
        type: 'list',
        name: 'stableVersions',
        message: 'Do you want to use components (bower & npm) we deem stable or the latest ones?',
        choices: [
          {
            value: true,
            name: 'stable (recommended)',
            default: true
          },
          {
            value: false,
            name: 'latest (experienced)',
          }
        ]
      },
      // select platforms
      {
        type: 'checkbox',
        name: 'platforms',
        message: 'Select all platforms you want to support:',
        choices: [
          {
            value: 'ios',
            name: 'iOS',
            checked: true
          },
          {
            value: 'android',
            name: 'Android',
            checked: true
          }
        ]
      },
      // select plugins
      {
        type: 'checkbox',
        name: 'plugins',
        message: 'Select all cordova plugins you want to install',
        choices: [
          new yeoman.inquirer.Separator(),
          {
            value: 'org.apache.cordova.device',
            name: 'Device - org.apache.cordova.device',
            checked: true
          },
          {
            value: 'org.apache.cordova.dialogs',
            name: 'Dialogs - org.apache.cordova.dialogs'
          },
          {
            value: 'org.apache.cordova.network-information',
            name: 'Network - org.apache.cordova.network-information'
          },
          {
            value: 'org.apache.cordova.splashscreen',
            name: 'Splashscreen - org.apache.cordova.splashscreen'
          },
          {
            value: 'https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git',
            name: 'Toast - https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git'
          },
          {
            value: 'org.apache.cordova.vibration',
            name: 'Vibration - org.apache.cordova.vibration'
          },
        ]
      },
    ];

    // prompt and save results in this.answers
    this.prompt(prompts, function (answers) {
      this.answers = answers;
      answers.includeSass = true; // set to true for now

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

  configuring: function () {

    // TODO: remove debugging
    // debugging
    // this.log(chalk.inverse(JSON.stringify(this.answers, null, '  ')));
    // this.answers = {
    //   'appName': 'asdf',
    //   'appId': 'com.company.project',
    //   'bowerPackages': [
    //     'angular-dynamic-locale#~0.1.17',
    //     'angular-localForage#~0.2.10',
    //     'angular-touch#~1.2.25',
    //     'angular-translate#~2.4.0',
    //     'angular-translate-loader-static-files#~2.4.0',
    //     'angular-ui-bootstrap-bower#~0.11.0',
    //     'fastclick#~1.0.3',
    //     'restangular#~1.4.0'
    //   ],
    //   'ionicSass': true,
    //   'stableVersions': true,
    //   'platforms': [
    //     'ios',
    //     'android'
    //   ],
    //   'plugins': [
    //     'org.apache.cordova.device',
    //     'org.apache.cordova.dialogs'
    //   ],
    //   'includeSass': true
    // };

    // store config in .yo-rc.json
    this.config.set('answers', this.answers);
  },

  writing: {

    cordova: function () {
      if (this.update) {
        return true;
      }

      var done = this.async(); // wait with subsequent tasks since cordova needs an empty folder
      // cordova project
      cordova.create('.', this.answers.appId, this.answers.appName)
      // add platforms
      .then(function () {
        this.log(chalk.green('Created cordova project'));
        return cordova.platform('add', this.answers.platforms);
      }.bind(this))
      // add plugins
      .then(function () {
        this.log(chalk.green('Added platforms: ' + this.answers.platforms.join(', ')));
        return cordova.plugins('add', this.answers.plugins);
      }.bind(this))
      // all
      .then(function () {
        this.log(chalk.green('Added plugins: ' + this.answers.plugins.join(', ')));
        this.log(chalk.green('Cordova project was set up successfully! Project Name: '), chalk.bgGreen(this.answers.appId));
        done();
      }.bind(this))
      .catch(function (err) {
        this.log(chalk.red('Couldn\'t finish generator: \n' + err));
        // halts because done will not be called!
      }.bind(this));
    },

    app: function () {
      // prepare bower.json
      var bower = this.bower = {
        dependencies: {
          'ionic': 'v1.0.0-beta.12',
          'angular': '~1.3.0-rc.2',
          'angular-ui-router': '~0.2.10',
          'ngCordova': '~0.1.4-alpha',
          'cordova': '~3.4.0'
        },
        devDependencies: {

        },
        resolutions: {
          'angular': '~1.3.0-rc.2'
        }
      };
      // include selected packages
      for (var i = 0, bowerPackage; (bowerPackage = this.answers.bowerPackages[i]); i++) {
        bowerPackage = bowerPackage.split('#');
        this.bower.dependencies[bowerPackage[0]] = bowerPackage[1];
      }
      // set all deps to latest?
      if (!this.answers.stableVersions) {
        for (var topKey in bower) {
          for (var key in bower[topKey]) {
            bower[topKey][key] = 'latest';
          }
        }
      }
      // add other properties
      bower.name = this.answers.appName;
      bower.private = true;

      // prepare index
      var indexFile = this.readFileAsString(path.join(this.sourceRoot(), '_index.html'));
      indexFile = this.engine(indexFile, this); // create template with data from 'this'

      // app  files
      this.copy('_app.js', 'app/scripts/app.js');
      this.write('bower.json', JSON.stringify(bower, null, 2));
      this.template('_gulpfile.js', 'gulpfile.js');
      this.write('app/index.html', indexFile);

      var css = 'main.' + (this.answers.includeSass ? 's' : '') + 'css';
      this.copy(css, 'app/styles/' + css);
    },

    projectfiles: function () {

      this.template('_package.json', 'package.json');
      this.copy('bowerrc', '.bowerrc');
      this.copy('editorconfig', '.editorconfig');
      this.copy('gitattributes', '.gitattributes');
      this.copy('gitignore', '.gitignore');
      this.copy('jscsrc', '.jscsrc');
      this.copy('jshintrc', '.jshintrc');
      this.copy('jshintignore', '.jshintignore');
      this.copy('jshintrc', '.jshintrc');
      this.copy('README.md', 'README.md');
    },

    subgenerators: function () {
      this.composeWith('m:service', {arguments: 'start', options: {sample: 'start'}});
      this.composeWith('m:controller', {arguments: 'start', options: {sample: 'start'}});
      this.composeWith('m:partial', {arguments: 'start', options: {sample: 'start'}});
    }
  },

  install: function () {
    this.installDependencies({
      skipInstall: this.options['skip-install'],
      callback: function () {
        if (!this.options['skip-install']) {
          // inject bower dependencies and app js files
          var done = this.async();
          this.spawnCommand('gulp', ['wiredep', 'fonts'])
          .on('exit', function () {
            // TODO: better gulp task wiring/dependencies
            // https://github.com/gulpjs/gulp/blob/master/docs/API.md#async-task-support
            // https://github.com/klei/gulp-inject#injecting-files-from-multiple-source-streams
            // https://github.com/klei/gulp-inject#injecting-some-files-into-head-and-some-into-body
            this.spawnCommand('gulp', ['inject']);
            done();
          }.bind(this));
        }
      }.bind(this)
    });
  },

  end: function () {

  }
});

module.exports = GulpIonicGenerator;
<|endoftext|>


<commit_before>chipsterWeb.controller('SessionCtrl', function($scope, $routeParams, $q,
		TemplateService, SessionRestangular, AuthenticationService,$websocket) {

	//SessionRestangular is a restangular object with configured baseUrl and
	//authorization header

	$scope.sessionUrl = SessionRestangular.one('sessions',
			$routeParams.sessionId);

	// creating a websocket object and start listening for the events
	var ws=$websocket.$new({
		url:'ws://localhost:8000/'+"sessiondbevents/"+"events/" + $routeParams.sessionId + "?token=" + AuthenticationService.getToken(),
		protocols: []
	});

	 ws.$on('$open', function () {
		 	console.log('connected through web socket');
		  })
		  .$on('$message', function(event) { // it listens for 'incoming event'
		    console.log(event);
		    $scope.event=event;
		  })
		  .$on('$close',function(){
			console.log('Connection to web socket is closing');
		  });

	// creating a session model object
	$scope.session = {
		sessionId : $routeParams.sessionId,
		sessionName : "",
		sessionDetail : "",
		workflowData : {}
	};

	//For view manipulation
	$scope.item=1;
	$scope.setItem = function(value) {
		$scope.item=value;
	};

	$scope.isSet = function(value) {
		return $scope.item === value;
	};

	//Dataset and tool for posting jobs
	$scope.selectedDatasetId = [];
	$scope.selectedToolId = null;
	$scope.selectedToolIndex = -1;
	$scope.istoolselected = false;

	//Dataset Detail showing
	$scope.dataNode=null;
	$scope.isDataNodeSelected=false;

	$scope.d3Data={nodes:[],links:[]};

	$scope.getSessionDetail = function() {
		//get session detail
		var promises = [ $scope.sessionUrl.get(),
		                 $scope.sessionUrl.all('datasets').getList(),
		                 $scope.sessionUrl.all('jobs').getList() ];

		$q.all(promises).then(
				function(res) {
					$scope.session.sessionName=res[0].data.name;
					$scope.session.sessionDetail=res[0].data.notes;

					//craete the workflow
					var datasets = res[1].data;
					var jobs = res[2].data;

					// create dicts
					var datasetDict = {};
					datasets.forEach(function(dataset) {
						datasetDict[dataset.datasetId] = dataset;
					});

					var jobDict = {};
					jobs.forEach(function(job) {
						jobDict[job.jobId] = job;
					});

					// assign indexes to datasets
					angular.forEach(datasets, function(dataset, index) {
						dataset.index = index;
					});

					// create links
					var links = [];
					datasets.forEach(function(targetDataset) {
						if (!targetDataset.sourceJob) {
							return; // continue
						}
						if (!(targetDataset.sourceJob in jobDict)) {
							//console.log("source job of dataset " + targetDataset.name + " isn't found");
							return; // continue
						}
						var sourceJob = jobDict[targetDataset.sourceJob];
						// iterate over the inputs of the source job
						sourceJob.inputs.forEach(function(input) {
							var sourceDataset = datasetDict[input.datasetId];
							links.push({
								source : sourceDataset.index,
								target : targetDataset.index,
								value : 4
							});
							console.log("link created: " + sourceDataset.name+ "->" + targetDataset.name);
						});
					});

					// set groups and levels
					angular.forEach(datasets, function(elem, index) {
						elem.group = 1;
						elem.c_id = 0;
						elem.level = index;

					});
					// we are done
					$scope.d3Data = {
						nodes : datasets,
						links : links
					};

				$scope.jobs=jobs;

				});
	};

	$scope.editSession = function() {
		var sessionObj = TemplateService.getSessionTemplate();

		sessionObj.sessionId = $scope.session.sessionId;
		sessionObj.name = $scope.session.sessionName;
		sessionObj.notes = $scope.session.sessionDetail;
		$scope.sessionUrl.customPUT(sessionObj).then(function(res){
			console.log(res);
		});

	};

	$scope.getDataSets = function() {
		$scope.datalist = $scope.sessionUrl.all('datasets').getList();
	};

	$scope.addDataset = function() {
		var newDataset = TemplateService.getDatasetTemplate();
		newDataset.x=TemplateService.getrandomX();
		newDataset.y=TemplateService.getrandomY();
		console.log(newDataset);
		var datasetUrl = $scope.sessionUrl.one('datasets');
		datasetUrl.customPOST(newDataset).then(function(response) {
			alert("Dataset has been added");
			$scope.d3Data.nodes.push(newDataset);

			//Refresh the session page
			//$scope.getSessionDetail();
		})
	};

	$scope.deleteDataset=function(datasetObj){

		//changing the file Id first
		var datasetUrl=$scope.sessionUrl.one('datasets').one(datasetObj.datasetId);
		datasetObj.fileId=TemplateService.getRandomFileID();

		console.log(datasetObj);
		//after that attempting to delete
		datasetUrl.customPUT(datasetObj).then(function(res){
			datasetUrl.remove().then(function(res){
				console.log(res);
			});

		});

	};

	$scope.getJobs = function() {
		$scope.sessionUrl.getList('jobs').then(function(res){

		});
	};

	$scope.runJob = function() {

		if ($scope.selectedDatasetId.length < 1) {
			alert("No dataset selected");
			return;
		}
		var newJob = TemplateService.getJobTemplate();

		if (!$scope.selectedToolId) {
			alert("No tool selected");
			return;
		}
		//edit the fields with selected parameter
		newJob.toolId = $scope.selectedToolId.tool;
		newJob.toolName = $scope.selectedToolId.name;

		angular.forEach($scope.selectedDatasetId, function(selectedDataId,
				index) {
			newJob.inputs[index].datasetId = selectedDataId;
		});

		console.log(newJob);

		var postJobUrl = $scope.sessionUrl.one('jobs');
		postJobUrl.customPOST(newJob).then(function(response) {
			alert("Job Submitted to server");

		});

	};

	// Binding datasetId from workflow graph directive
	this.setDatasetId = function(datasetId) {
		$scope.selectedDatasetId.push(datasetId);
		console.log($scope.selectedDatasetId);
	};

	this.cancelDatasetSelection = function(datasetId) {
		var index = $scope.selectedDatasetId.indexOf(datasetId);
		$scope.selectedDatasetId.splice(index, 1);
	};

	$scope.selectedTool = function(tool, $index) {
		$scope.selectedToolId = tool;
		$scope.selectedToolIndex = $index;
		$scope.istoolselected = true;
	};

	$scope.showToolDescription = function() {
		return $scope.istoolselected;
	};

	$scope.toggleToolSelection = function() {
		$scope.istoolselected = false;
		$scope.selectedToolIndex = 0;
	};

	//implementing right click options for data nodes
	this.renameDataset=function(datasetObj,name){
		var datasetUrl=$scope.sessionUrl.one('datasets').one(datasetObj.datasetId);
		var renamedObj=angular.copy(datasetObj);
		renamedObj.name=name;

		//console.log(datasetObj);
		datasetUrl.customPUT(renamedObj).then(function(res){
			var index = $scope.d3Data.nodes.indexOf(datasetObj);
			console.log(index);
			$scope.d3Data.nodes.splice(index, 1,renamedObj);
			//$scope.getSessionDetail();

		});
	};

	this.getSelectedDataNode=function(dataNode){
		$scope.dataNode=dataNode;
		console.log($scope.dataNode.name);
		$scope.isDataNodeSelected=true;

	};

	$scope.showDatasetDetail=function(){
		return $scope.isDataNodeSelected;
	};

});
<commit_msg>Upload files<commit_after>chipsterWeb.controller('SessionCtrl', function($scope, $routeParams, $q,
		TemplateService, SessionRestangular, AuthenticationService,$websocket) {

	//SessionRestangular is a restangular object with configured baseUrl and
	//authorization header

	$scope.sessionUrl = SessionRestangular.one('sessions',
			$routeParams.sessionId);

	// creating a websocket object and start listening for the events
	var ws=$websocket.$new({
		url:'ws://localhost:8000/'+"sessiondbevents/"+"events/" + $routeParams.sessionId + "?token=" + AuthenticationService.getToken(),
		protocols: []
	});

	 ws.$on('$open', function () {
		 	console.log('connected through web socket');
		  })
		  .$on('$message', function(event) { // it listens for 'incoming event'
		    console.log(event);
		    $scope.event=event;
		  })
		  .$on('$close',function(){
			console.log('Connection to web socket is closing');
		  });

	// creating a session model object
	$scope.session = {
		sessionId : $routeParams.sessionId,
		sessionName : "",
		sessionDetail : "",
		workflowData : {}
	};

	//For view manipulation
	$scope.item=1;
	$scope.setItem = function(value) {
		$scope.item=value;
	};

	$scope.isSet = function(value) {
		return $scope.item === value;
	};

	//Dataset and tool for posting jobs
	$scope.selectedDatasetId = [];
	$scope.selectedToolId = null;
	$scope.selectedToolIndex = -1;
	$scope.istoolselected = false;

	//Dataset Detail showing
	$scope.dataNode=null;
	$scope.isDataNodeSelected=false;

	$scope.d3Data={nodes:[],links:[]};

	$scope.getSessionDetail = function() {
		//get session detail
		var promises = [ $scope.sessionUrl.get(),
		                 $scope.sessionUrl.all('datasets').getList(),
		                 $scope.sessionUrl.all('jobs').getList() ];

		$q.all(promises).then(
				function(res) {
					$scope.session.sessionName=res[0].data.name;
					$scope.session.sessionDetail=res[0].data.notes;

					//craete the workflow
					var datasets = res[1].data;
					var jobs = res[2].data;

					// create dicts
					var datasetDict = {};
					datasets.forEach(function(dataset) {
						datasetDict[dataset.datasetId] = dataset;
					});

					var jobDict = {};
					jobs.forEach(function(job) {
						jobDict[job.jobId] = job;
					});

					// assign indexes to datasets
					angular.forEach(datasets, function(dataset, index) {
						dataset.index = index;
					});

					// create links
					var links = [];
					datasets.forEach(function(targetDataset) {
						if (!targetDataset.sourceJob) {
							return; // continue
						}
						if (!(targetDataset.sourceJob in jobDict)) {
							//console.log("source job of dataset " + targetDataset.name + " isn't found");
							return; // continue
						}
						var sourceJob = jobDict[targetDataset.sourceJob];
						// iterate over the inputs of the source job
						sourceJob.inputs.forEach(function(input) {
							var sourceDataset = datasetDict[input.datasetId];
							links.push({
								source : sourceDataset.index,
								target : targetDataset.index,
								value : 4
							});
							console.log("link created: " + sourceDataset.name+ "->" + targetDataset.name);
						});
					});

					// set groups and levels
					angular.forEach(datasets, function(elem, index) {
						elem.group = 1;
						elem.c_id = 0;
						elem.level = index;

					});
					// we are done
					$scope.d3Data = {
						nodes : datasets,
						links : links
					};

				$scope.jobs=jobs;

				});
	};

	$scope.editSession = function() {
		var sessionObj = TemplateService.getSessionTemplate();

		sessionObj.sessionId = $scope.session.sessionId;
		sessionObj.name = $scope.session.sessionName;
		sessionObj.notes = $scope.session.sessionDetail;
		$scope.sessionUrl.customPUT(sessionObj).then(function(res){
			console.log(res);
		});

	};

	$scope.getDataSets = function() {
		$scope.datalist = $scope.sessionUrl.all('datasets').getList();
	};

	$scope.flowFileAdded = function(file, event, flow) {

		// get a separate target for each file
		flow.opts.target = function(file, chunk, isTest) {
			return file.chipsterTarget;
		};

		$scope.createDataset(file.name).then(function (dataset) {
			// create an own target for each file
			file.chipsterTarget = 'http://localhost:8000/'+"filebroker/"+"sessions/" + $routeParams.sessionId + "/datasets/" + dataset.datasetId + "?token=" + AuthenticationService.getToken();
			file.resume();
		});
		// wait for dataset to be created
		file.pause();
	};

	$scope.flowFileSuccess = function ( file, message, flow ) {
		// remove completed files from the list
		file.cancel();
	};

	$scope.createDataset = function(name) {

		var d = TemplateService.getDatasetTemplate();

		d.datasetId=null;
		d.name=name;
		d.x=TemplateService.getrandomX();
		d.y=TemplateService.getrandomY();
		d.sourceJob=null;

		return new Promise(function(resolve, reject) {
			var datasetUrl = $scope.sessionUrl.one('datasets');
			datasetUrl.customPOST(d).then(function(response) {
				var location = response.headers('Location');
				d.datasetId = location.substr(location.lastIndexOf('/') + 1);
				$scope.d3Data.nodes.push(d);
				resolve(d);
			});
		});
	};

	$scope.deleteDataset=function(datasetObj){

		//changing the file Id first
		var datasetUrl=$scope.sessionUrl.one('datasets').one(datasetObj.datasetId);
		datasetObj.fileId=TemplateService.getRandomFileID();

		console.log(datasetObj);
		//after that attempting to delete
		datasetUrl.customPUT(datasetObj).then(function(res){
			datasetUrl.remove().then(function(res){
				console.log(res);
			});

		});

	};

	$scope.getJobs = function() {
		$scope.sessionUrl.getList('jobs').then(function(res){

		});
	};

	$scope.runJob = function() {

		if ($scope.selectedDatasetId.length < 1) {
			alert("No dataset selected");
			return;
		}
		var newJob = TemplateService.getJobTemplate();

		if (!$scope.selectedToolId) {
			alert("No tool selected");
			return;
		}
		//edit the fields with selected parameter
		newJob.toolId = $scope.selectedToolId.tool;
		newJob.toolName = $scope.selectedToolId.name;

		angular.forEach($scope.selectedDatasetId, function(selectedDataId,
				index) {
			newJob.inputs[index].datasetId = selectedDataId;
		});

		console.log(newJob);

		var postJobUrl = $scope.sessionUrl.one('jobs');
		postJobUrl.customPOST(newJob).then(function(response) {
			alert("Job Submitted to server");

		});

	};

	// Binding datasetId from workflow graph directive
	this.setDatasetId = function(datasetId) {
		$scope.selectedDatasetId.push(datasetId);
		console.log($scope.selectedDatasetId);
	};

	this.cancelDatasetSelection = function(datasetId) {
		var index = $scope.selectedDatasetId.indexOf(datasetId);
		$scope.selectedDatasetId.splice(index, 1);
	};

	$scope.selectedTool = function(tool, $index) {
		$scope.selectedToolId = tool;
		$scope.selectedToolIndex = $index;
		$scope.istoolselected = true;
	};

	$scope.showToolDescription = function() {
		return $scope.istoolselected;
	};

	$scope.toggleToolSelection = function() {
		$scope.istoolselected = false;
		$scope.selectedToolIndex = 0;
	};

	//implementing right click options for data nodes
	this.renameDataset=function(datasetObj,name){
		var datasetUrl=$scope.sessionUrl.one('datasets').one(datasetObj.datasetId);
		var renamedObj=angular.copy(datasetObj);
		renamedObj.name=name;

		//console.log(datasetObj);
		datasetUrl.customPUT(renamedObj).then(function(res){
			var index = $scope.d3Data.nodes.indexOf(datasetObj);
			console.log(index);
			$scope.d3Data.nodes.splice(index, 1,renamedObj);
			//$scope.getSessionDetail();

		});
	};

	this.getSelectedDataNode=function(dataNode){
		$scope.dataNode=dataNode;
		console.log($scope.dataNode.name);
		$scope.isDataNodeSelected=true;

	};

	$scope.showDatasetDetail=function(){
		return $scope.isDataNodeSelected;
	};

});
<|endoftext|>


<commit_before>const React = require('react');
const T = require('prop-types');
const { spring } = require('react-motion');
const Utils = require('./utils');
const _merge = require('lodash/merge');

module.exports = class StrangeMotion extends React.PureComponent {

    static propTypes = {
        model: T.array,
        animConfig: T.shape({
            start: T.object,
            beforeEnter: T.object,
            enter: T.object.isRequired,
            leave: T.object
        }),
        animPlugins: T.array,

        // Left off implementing animPlugins for the motion blur plugin.

        children: T.any.isRequired,
        animWrapperComponent: T.any,
        animWrapperComponentRef: T.func,
        animWrapperProps: T.func,
        childWrapperComponent: T.any,
        childWrapperProps: T.func,
        childProps: T.func
    }

    static defaultSpring = {
        stiffness: 170,
        damping: 26,
        precision: 0.01
    }

    constructor(props) {

        super();

        let animConfig;
        if (!props.animConfig) {
            animConfig = this._getDefaultAnimConfig();
        }
        else {
            animConfig = this.processInitAnimConfig(props.animConfig);
        }

        let model;
        let childIsFunc;

        if (props.model) {
            model = props.model;
        }

        if (typeof props.children === 'function') {

            childIsFunc = true;
            if (!props.model) {
                throw new Error('StrangeMotion: Must pass in model if children is a function');
            }
            model = props.model;
        }
        else {
            childIsFunc = false;
            if (props.model) {
                throw new Error('StrangeMotion: Must pass function as child if model is provided in props');
            }
            model = Utils.getElementsFromChildren(props.children);
        }

        this.state = {
            animConfig,
            model,
            childIsFunc,
            childWrapperComponent: props.childWrapperComponent,
            childWrapperProps: props.childWrapperProps
        };

        this.willEnter = this._willEnter.bind(this);
        this.willLeave = this._willLeave.bind(this);
        this.getStyles = this._getStyles.bind(this);
        this.getDefaultStyles = this._getDefaultStyles.bind(this);
        this.applyInterpolatedStyles = this._applyInterpolatedStyles.bind(this);
        this.genId = this._genId.bind(this);
    }

    getChildren(interpolatedStyles) {

        const {
            animWrapperComponent,
            animWrapperProps,
            childWrapperComponent,
            childWrapperProps,
            childProps,
            model
        } = this.state;

        const interpolatedAsArray = [].concat(interpolatedStyles);

        if (typeof interpolatedStyles === 'object' &&
            !Array.isArray(interpolatedStyles)) {

            // it's a Motion object

            const interpolatedChild = interpolatedAsArray
            .map((style) => {

                let newChildPropsVal = {};
                if (childProps) {
                    newChildPropsVal = childProps(style);
                }

                // Use model right here
                const newChild = Array.isArray(model) ? model[0] : model;

                return this.applyInterpolatedStyles({
                    style,
                    child: newChild,
                    childWrapperComponent,
                    childWrapperProps,
                    newChildPropsVal
                });
            })[0]; // Grab the first and only item here

            if (!animWrapperComponent && !animWrapperProps) {
                return interpolatedChild;
            }

            if (animWrapperComponent) {
                return React.createElement(
                    animWrapperComponent,
                    animWrapperProps && animWrapperProps(interpolatedStyles) || {},
                    interpolatedChild
                );
            }
            else {
                return React.cloneElement(
                    interpolatedChild,
                    animWrapperProps && animWrapperProps(interpolatedStyles) || {}
                );
            }
        }

        // Apply new styles to children

        const interpolatedChildren = interpolatedAsArray
        .map(({ style, data, key }) => {

            let newChildPropsVal = {};
            if (childProps) {
                newChildPropsVal = childProps({ style, data, key });
            }

            return this.applyInterpolatedStyles({
                style,
                child: data,
                key,
                childWrapperComponent,
                childWrapperProps,
                newChildPropsVal,
            });
        });

        return React.createElement(
            animWrapperComponent || 'div',
            animWrapperProps && animWrapperProps(interpolatedStyles) || {},
            interpolatedChildren
        );
    };

    _applyInterpolatedStyles({
        style,
        child,
        key,
        childWrapperComponent,
        childWrapperProps,
        newChildPropsVal
    }) {

        if (!key) {
            key = this.genId();
        }

        const { children } = this.props;
        const childStyle = child.props && child.props.style;

        let newStyle = style;

        newStyle = _merge(
            {},
            childStyle || {},
            style
        );

        let newChild;

        const newChildProps = newChildPropsVal;

        if (this.state.childIsFunc && !childWrapperComponent) {

            newChild = React.cloneElement(
                children({ style: newStyle, child, key }),
                { ...newChildProps, style }
            );
        }
        else if (this.state.childIsFunc && childWrapperComponent) {

            newChild = React.cloneElement(
                children({ style: childStyle, child, key }),
                newChildProps
            );
        }

        if (!this.state.childIsFunc && !childWrapperComponent) {

            newChild = React.cloneElement(
                child,
                { ...newChildProps, style }
            );
        }
        else if (!this.state.childIsFunc && childWrapperComponent) {

            newChild = React.cloneElement(
                child,
                newChildProps
            );
        }

        if (childWrapperComponent) {

            let childWrapperPropsVal = {};

            if (typeof childWrapperProps === 'function') {
                childWrapperPropsVal = childWrapperProps(
                    { child, key }
                );
            }
            else if (childWrapperProps) {
                childWrapperPropsVal = childWrapperProps;
            }

            newChild = React.createElement(
                childWrapperComponent,
                { key, ...childWrapperPropsVal },
                newChild
            );
        }

        return newChild;
    }

    _getDefaultAnimConfig() {

        return {
            start: {},
            beforeEnter: {},
            enter: {},
            leave: {}
        };
    }

    processInitAnimConfig(animConfig) {

        const animConfigWithDefaults = Utils.assignDefaultsToAnimConfig(animConfig);

        const self = this;

        const {
            assignedAnimConfig,
            delays
        } = Utils.assignAnimConfig({
            beginAnimConfig: self.state && self.state.animConfig,
            newAnimConfig: animConfigWithDefaults
        });

        if (delays) {
            this.waitingDelays = delays;
        }

        return assignedAnimConfig;
    }

    // Why do I have newAnimConfig here if nobody is using it?
    // it's for documentation to make sure you know what you're passing in.

    assignAnimConfig({ newAnimConfig: passedInAnimConfig }, setStateCb) {

        let newAnimConfig = passedInAnimConfig;

        if (passedInAnimConfig.enter &&
            passedInAnimConfig.enter.$delay) {

            const { $delay: $enterDelay, ...enterWithoutDelay } = passedInAnimConfig.enter;

            // setup the $delay

            setTimeout(() => {

                const newAnimConfigClone = JSON.parse(JSON.stringify(newAnimConfig));

                this.assignAnimConfig({
                    newAnimConfig: { enter: enterWithoutDelay }
                }, this._setNewAnimConfig(passedInAnimConfig, newAnimConfigClone));
            }, $enterDelay);

            const { enter, ...rest } = passedInAnimConfig;
            if (Object.keys(rest).length !== 0) {
                newAnimConfig = rest;
            }
        }

        this._setNewAnimConfig(passedInAnimConfig, newAnimConfig, setStateCb)();
    }

    _setNewAnimConfig(passedInAnimConfig, newAnimConfig, setStateCb) {

        const reactMotion = this.reactMotion;

        let beginAnimConfig = this.state.animConfig;

        return () => {

            newAnimConfig = Object.keys(newAnimConfig)
            .reduce((collector, animType) => {

                const currentAnimType = passedInAnimConfig[animType];

                const newAnimType = Object.keys(currentAnimType)
                .reduce((collector, cssPropName) => {

                    const cssPropVal = currentAnimType[cssPropName];

                    if (cssPropVal === 'getLastIdealStyle') {

                        const delayPropVal = reactMotion.props.defaultStyle[cssPropName].val;

                        collector[cssPropName] = { val: delayPropVal };
                    }
                    else if (cssPropVal === 'getBeginEnterVal') {

                        const delayPropVal = beginAnimConfig.enter[cssPropName].val;
                        collector[cssPropName] = { val: delayPropVal };
                    }
                    else {
                        collector[cssPropName] = cssPropVal;
                    }

                    return collector;
                }, {});

                collector[animType] = newAnimType;

                return collector;
            }, {});

            //

            const {
                assignedAnimConfig,
                delays
            } = Utils.assignAnimConfig({
                beginAnimConfig,
                newAnimConfig,
                reactMotion
            });

            if (newAnimConfig.start) {

                return this.setState({
                    animConfig: {
                        ...assignedAnimConfig,
                        enter: newAnimConfig.start
                    }
                }, () => {

                    this.setState({
                        animConfig: assignedAnimConfig
                    }, () => {

                        if (typeof setStateCb === 'function') {
                            setStateCb();
                        }

                        this.handleDelays(delays);
                    });
                });
            }

            this.setState({
                animConfig: assignedAnimConfig
            }, () => {

                if (typeof setStateCb === 'function') {
                    setStateCb();
                }

                this.handleDelays(delays);
            });
        }
    }

    handleDelays(delays) {

        // if there weren't any delays, '$delay' will be set to undefined
        // from Utils.assignAnimConfig
        if (delays) {
            /*
                Delays object is organized by its delay times. ex:
                {
                    400: [{ enter: { top: 100, left: 100 } }],
                    10000: [{ enter: { top: 500, left: 300 }] }
                }
            }
            */

            Object.keys(delays).forEach((delay) => {

                setTimeout(() => {

                    [].concat(delays[delay]).forEach((currentDelay) => {

                        this.assignAnimConfig({
                            newAnimConfig: currentDelay
                        });
                    })

                }, delay);
            });
        };
    }

    componentDidMount() {

        const { waitingDelays } = this;

        if (waitingDelays) {

            Object.keys(waitingDelays).forEach(($delay) => {

                setTimeout(() => {

                    this.assignAnimConfig({ newAnimConfig: waitingDelays[$delay] });
                }, $delay);
            });
        }
    }

    componentWillReceiveProps(nextProps) {

        const {
            children,
            model,
            animConfig
        } = nextProps;

        if (children && typeof children !== 'function') {

            this.setState({
                model: Utils.getElementsFromChildren(children)
            });
        }

        if (model) {
            this.setState({ model });
        }

        // Thanks to React, we won't have to worry
        // about the same animConfig being passed in twice,
        // so we can safely assume that whatever animConfig
        // props the user assigns via the `animController` will
        // take precedence in `getStyles()`, and won't be
        // immediately overwritten with styles here.

        // NOTE: This does mean that any animations defined with
        // the animController will be overwritten with this one.
        // Of course they can be changed again via the animController
        // which will take over. This is basically now an alias of
        // animController.mergeAnimConfig()

        if (animConfig) {
            this.assignAnimConfig({ newAnimConfig: animConfig });
        }
    }

    filterChildrenForType(children) {

        return children;
    }

    _genId() {

        return Math.random().toString(16).slice(2);
    }

    // Only used with TransitionMotion
    _willEnter() {

        const { animConfig } = this.state;
        return animConfig.beforeEnter;
    }

    // Only used with TransitionMotion
    _willLeave() {

        const { animConfig } = this.state;
        return animConfig.leave;
    }

    _getDefaultStyles() {

        const defaultStyles = this.getStyles('start')
        .map((interpolatedStyle) => {

            const newCssVals = interpolatedStyle.style;

            const newInterpolatedStyle = _merge(
                {},
                interpolatedStyle,
                { style: newCssVals }
            );

            return newInterpolatedStyle;
        });

        return defaultStyles;
    }

    _getStyles(animConfigKey) {

        const { model, animConfig } = this.state;

        let mergedAnimConfig = animConfig;

        if (this.animController && this.animControllerAnimConfig) {
            mergedAnimConfig = Object.assign({},
                animConfig,
                this.animControllerAnimConfig
            );
        };

        let filteredModel;
        if (this.props.model) {
            filteredModel = model;
        }
        else {
            // TODO This doesn't make any sense, it's only here for the toggle-motion
            filteredModel = this.filterChildrenForType(model);
        }

        const newStyles = filteredModel.map((child, i) => {

            const { key, id: itemId, name } = child;

            let newKey = key || '';

            if (!key) {
                if (itemId) {
                    newKey += itemId;
                }

                if (name) {
                    newKey += name + i;
                }
            }

            if (newKey === '') {
                newKey = this._genId();
            }

            let newStyle = animConfigKey ? mergedAnimConfig[animConfigKey] : mergedAnimConfig.enter;

            return {
                data: child,
                style: newStyle,
                key: String(newKey)
            };
        });

        return newStyles;
    }
};
<commit_msg>Add plugin support<commit_after>const React = require('react');
const T = require('prop-types');
const { spring } = require('react-motion');
const Utils = require('./utils');
const _merge = require('lodash/merge');

module.exports = class StrangeMotion extends React.PureComponent {

    static propTypes = {
        model: T.array,
        animConfig: T.shape({
            start: T.object,
            beforeEnter: T.object,
            enter: T.object.isRequired,
            leave: T.object
        }),
        animPlugins: T.array,

        // Left off implementing animPlugins for the motion blur plugin.

        children: T.any.isRequired,
        animWrapperComponent: T.any,
        animWrapperComponentRef: T.func,
        animWrapperProps: T.func,
        childWrapperComponent: T.any,
        childWrapperProps: T.func,
        childProps: T.func
    }

    static defaultSpring = {
        stiffness: 170,
        damping: 26,
        precision: 0.01
    }

    constructor(props) {

        super();

        let animConfig;
        if (!props.animConfig) {
            animConfig = this._getDefaultAnimConfig();
        }
        else {
            animConfig = this.processInitAnimConfig(props.animConfig);
        }

        let model;
        let childIsFunc;

        if (props.model) {
            model = props.model;
        }

        if (typeof props.children === 'function') {

            childIsFunc = true;
            if (!props.model) {
                throw new Error('StrangeMotion: Must pass in model if children is a function');
            }
            model = props.model;
        }
        else {
            childIsFunc = false;
            if (props.model) {
                throw new Error('StrangeMotion: Must pass function as child if model is provided in props');
            }
            model = Utils.getElementsFromChildren(props.children);
        }

        this.state = {
            animConfig,
            model,
            childIsFunc,
            childWrapperComponent: props.childWrapperComponent,
            childWrapperProps: props.childWrapperProps
        };

        this.willEnter = this._willEnter.bind(this);
        this.willLeave = this._willLeave.bind(this);
        this.getStyles = this._getStyles.bind(this);
        this.getDefaultStyles = this._getDefaultStyles.bind(this);
        this.applyInterpolatedStyles = this._applyInterpolatedStyles.bind(this);
        this.genId = this._genId.bind(this);
        this.applyPlugins = this._applyPlugins.bind(this);
    }

    getChildren(interpolatedStyles) {

        const {
            animWrapperComponent,
            animWrapperProps,
            childWrapperComponent,
            childWrapperProps,
            childProps,
            model
        } = this.state;

        const interpolatedAsArray = [].concat(interpolatedStyles);

        if (typeof interpolatedStyles === 'object' &&
            !Array.isArray(interpolatedStyles)) {

            // it's a Motion object

            const interpolatedChild = interpolatedAsArray
            .map((style) => {

                let newChildPropsVal = {};
                if (childProps) {
                    newChildPropsVal = childProps(style);
                }

                // Use model right here
                const newChild = Array.isArray(model) ? model[0] : model;

                return this.applyInterpolatedStyles({
                    style,
                    child: newChild,
                    childWrapperComponent,
                    childWrapperProps,
                    newChildPropsVal
                });
            })[0]; // Grab the first and only item here

            if (!animWrapperComponent && !animWrapperProps) {
                return interpolatedChild;
            }

            if (animWrapperComponent) {
                return React.createElement(
                    animWrapperComponent,
                    animWrapperProps && animWrapperProps(interpolatedStyles) || {},
                    interpolatedChild
                );
            }
            else {
                return React.cloneElement(
                    interpolatedChild,
                    animWrapperProps && animWrapperProps(interpolatedStyles) || {}
                );
            }
        }

        // Apply new styles to children

        const interpolatedChildren = interpolatedAsArray
        .map(({ style, data, key }) => {

            let newChildPropsVal = {};
            if (childProps) {
                newChildPropsVal = childProps({ style, data, key });
            }

            return this.applyInterpolatedStyles({
                style,
                child: data,
                key,
                childWrapperComponent,
                childWrapperProps,
                newChildPropsVal,
            });
        });

        return React.createElement(
            animWrapperComponent || 'div',
            animWrapperProps && animWrapperProps(interpolatedStyles) || {},
            interpolatedChildren
        );
    };

    _applyInterpolatedStyles({
        style,
        child,
        key,
        childWrapperComponent,
        childWrapperProps,
        newChildPropsVal
    }) {

        const stylePluginsApplied = this.applyPlugins({
           pluginFunc: 'toCss',
           applyTo: style
        });

        if (!key) {
            key = this.genId();
        }

        const { children } = this.props;
        const childStyle = child.props && child.props.style;

        let newStyle = stylePluginsApplied;

        newStyle = _merge(
            {},
            childStyle || {},
            stylePluginsApplied
        );

        let newChild;

        const newChildProps = newChildPropsVal;

        if (this.state.childIsFunc && !childWrapperComponent) {

            newChild = React.cloneElement(
                children({ style: newStyle, child, key }),
                { ...newChildProps, style }
            );
        }
        else if (this.state.childIsFunc && childWrapperComponent) {

            newChild = React.cloneElement(
                children({ style: newStyle, child, key }),
                newChildProps
            );
        }

        if (!this.state.childIsFunc && !childWrapperComponent) {

            newChild = React.cloneElement(
                child,
                { ...newChildProps, style: newStyle }
            );
        }
        else if (!this.state.childIsFunc && childWrapperComponent) {

            newChild = React.cloneElement(
                child,
                newChildProps
            );
        }

        if (childWrapperComponent) {

            let childWrapperPropsVal = {};

            if (typeof childWrapperProps === 'function') {
                childWrapperPropsVal = childWrapperProps(
                    { child, key }
                );
            }
            else if (childWrapperProps) {
                childWrapperPropsVal = childWrapperProps;
            }

            newChild = React.createElement(
                childWrapperComponent,
                { key, ...childWrapperPropsVal },
                newChild
            );
        }

        return newChild;
    }

    _getDefaultAnimConfig() {

        return {
            start: {},
            beforeEnter: {},
            enter: {},
            leave: {}
        };
    }

    processInitAnimConfig(animConfig) {

        const animConfigWithDefaults = Utils.assignDefaultsToAnimConfig(animConfig);

        const self = this;

        // Should call `applyPlugins` here and set animConfigPluginsApplied
        // const animConfigPluginsApplied = animConfigWithDefaults

        const animConfigPluginsApplied = this._applyPlugins({
            pluginFunc: 'assignNewAnimConfig',
            applyTo: animConfigWithDefaults
        });

        const {
            assignedAnimConfig,
            delays
        } = Utils.assignAnimConfig({
            beginAnimConfig: self.state && self.state.animConfig,
            newAnimConfig: animConfigPluginsApplied
        });

        if (delays) {
            this.waitingDelays = delays;
        }

        return assignedAnimConfig;
    }

    _applyPlugins({ pluginFunc, applyTo }) {

        if (!this.props) {
            return applyTo;
        }

        const { animPlugins } = this.props;

        const filteredAnimPlugins = [].concat(animPlugins).filter((plugin) => plugin ? true : false);

        let pluginsApplied = applyTo;

        // TODO implement Topo sorting for plugins

        filteredAnimPlugins.forEach((plugin) => {

            if (plugin[pluginFunc]) {
                pluginsApplied = plugin[pluginFunc](applyTo);
            }
        });

        return pluginsApplied;
    }

    // Why do I have newAnimConfig here if nobody is using it?
    // it's for documentation to make sure you know what you're passing in.

    assignAnimConfig({ newAnimConfig: passedInAnimConfig }, setStateCb) {

        let newAnimConfig = JSON.parse(JSON.stringify(passedInAnimConfig));

        if (passedInAnimConfig.enter &&
            passedInAnimConfig.enter.$delay) {

            const { $delay: $enterDelay, ...enterWithoutDelay } = passedInAnimConfig.enter;

            // setup the $delay

            setTimeout(() => {

                const newAnimConfigClone = JSON.parse(JSON.stringify(newAnimConfig));

                this.assignAnimConfig({
                    newAnimConfig: { enter: enterWithoutDelay }
                }, this._setNewAnimConfig(passedInAnimConfig, newAnimConfigClone));
            }, $enterDelay);

            const { enter, ...rest } = passedInAnimConfig;
            if (Object.keys(rest).length !== 0) {
                newAnimConfig = rest;
            }
        }

        this._setNewAnimConfig(passedInAnimConfig, newAnimConfig, setStateCb)();
    }

    _setNewAnimConfig(passedInAnimConfig, newAnimConfig, setStateCb) {

        const reactMotion = this.reactMotion;

        let beginAnimConfig = this.state.animConfig;

        return () => {

            newAnimConfig = Object.keys(newAnimConfig)
            .reduce((collector, animType) => {

                const currentAnimType = passedInAnimConfig[animType];

                const newAnimType = Object.keys(currentAnimType)
                .reduce((collector, cssPropName) => {

                    const cssPropVal = currentAnimType[cssPropName];

                    // console.log('cssPropName', cssPropName);
                    // console.warn('BEFORE cssPropVal', cssPropVal);

                    if (cssPropVal === 'getLastIdealStyle') {

                        // console.log('reactMotion', reactMotion);
                        const delayProp = reactMotion.state.lastIdealStyle[cssPropName];

                        collector[cssPropName] = typeof delayProp.val === 'undefined' ? delayProp : delayProp.val;
                    }
                    else {
                        collector[cssPropName] = cssPropVal;
                    }

                    return collector;
                }, {});

                collector[animType] = newAnimType;

                return collector;
            }, {});

            //

            const animConfigPluginsApplied = this.applyPlugins({
                pluginFunc: 'assignNewAnimConfig',
                applyTo: newAnimConfig
            });

            const {
                assignedAnimConfig,
                delays
            } = Utils.assignAnimConfig({
                beginAnimConfig,
                newAnimConfig: animConfigPluginsApplied,
                reactMotion
            });

            if (newAnimConfig.start) {

                return this.setState({
                    animConfig: {
                        ...assignedAnimConfig,
                        enter: newAnimConfig.start
                    }
                }, () => {

                    this.setState({
                        animConfig: assignedAnimConfig
                    }, () => {

                        if (typeof setStateCb === 'function') {
                            setStateCb();
                        }

                        this.handleDelays(delays);
                    });
                });
            }

            this.setState({
                animConfig: assignedAnimConfig
            }, () => {

                if (typeof setStateCb === 'function') {
                    setStateCb();
                }

                this.handleDelays(delays);
            });
        }
    };

    handleDelays(delays) {

        // if there weren't any delays, '$delay' will be set to undefined
        // from Utils.assignAnimConfig
        if (delays) {
            /*
                Delays object is organized by its delay times. ex:
                {
                    400: [{ enter: { top: 100, left: 100 } }],
                    10000: [{ enter: { top: 500, left: 300 }] }
                }
            }
            */

            Object.keys(delays).forEach((delay) => {

                setTimeout(() => {

                    [].concat(delays[delay]).forEach((currentDelay) => {

                        this.assignAnimConfig({
                            newAnimConfig: currentDelay
                        });
                    })

                }, delay);
            });
        };
    };

    componentDidMount() {

        const { waitingDelays } = this;

        if (waitingDelays) {

            Object.keys(waitingDelays).forEach(($delay) => {

                setTimeout(() => {

                    this.assignAnimConfig({ newAnimConfig: waitingDelays[$delay] });
                }, $delay);
            });
        }
    };

    componentWillReceiveProps(nextProps) {

        const {
            children,
            model,
            animConfig
        } = nextProps;

        if (children && typeof children !== 'function') {

            this.setState({
                model: Utils.getElementsFromChildren(children)
            });
        }

        if (model) {
            this.setState({ model });
        }

        // Thanks to React, we won't have to worry
        // about the same animConfig being passed in twice,
        // so we can safely assume that whatever animConfig
        // props the user assigns via the `animController` will
        // take precedence in `getStyles()`, and won't be
        // immediately overwritten with styles here.

        // NOTE: This does mean that any animations defined with
        // the animController will be overwritten with this one.
        // Of course they can be changed again via the animController
        // which will take over. This is basically now an alias of
        // animController.mergeAnimConfig()

        if (animConfig) {
            this.assignAnimConfig({ newAnimConfig: animConfig });
        }
    };

    filterChildrenForType(children) {

        return children;
    };

    _genId() {

        return Math.random().toString(16).slice(2);
    };

    // Only used with TransitionMotion
    _willEnter() {

        const { animConfig } = this.state;
        return animConfig.beforeEnter;
    };

    // Only used with TransitionMotion
    _willLeave() {

        const { animConfig } = this.state;
        return animConfig.leave;
    };

    _getDefaultStyles() {

        const defaultStyles = this.getStyles('start')
        .map((interpolatedStyle) => {

            const newCssVals = this.applyPlugins({
                pluginFunc: 'getStyles',
                applyTo: interpolatedStyle.style
            });

            const newInterpolatedStyle = _merge(
                {},
                interpolatedStyle,
                { style: newCssVals }
            );

            return newInterpolatedStyle;
        });

        return defaultStyles;
    };

    _getStyles(animConfigKey) {

        const { model, animConfig } = this.state;

        let mergedAnimConfig = animConfig;

        if (this.animController && this.animControllerAnimConfig) {
            mergedAnimConfig = Object.assign({},
                animConfig,
                this.animControllerAnimConfig
            );
        };

        let filteredModel;
        if (this.props.model) {
            filteredModel = model;
        }
        else {
            // TODO This doesn't make any sense, it's only here for the toggle-motion
            filteredModel = this.filterChildrenForType(model);
        }

        const newStyles = filteredModel.map((child, i) => {

            const { key, id: itemId, name } = child;

            let newKey = key || '';

            if (!key) {
                if (itemId) {
                    newKey += itemId;
                }

                if (name) {
                    newKey += name + i;
                }
            }

            if (newKey === '') {
                newKey = this._genId();
            }

            const newCssVals = this.applyPlugins({
                pluginFunc: 'getStyles',
                applyTo: animConfigKey ? mergedAnimConfig[animConfigKey] : mergedAnimConfig.enter
            });

            return {
                data: child,
                style: newCssVals,
                key: String(newKey)
            };
        });

        return newStyles;
    };
};
<|endoftext|>