<commit_before>process.traceDeprecation = true;

const path = require('path');
const webpack = require('webpack');
const pkg = require('./package.json');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const commandLineArgs = require('command-line-args');

const argOptions = [
	{ name: 'debug', alias: 'd', type: Boolean },
	{ name: 'verbose', alias: 'v', type: Boolean },
	{ name: 'publicPath', alias: 'p', type: String, defaultOption: '' },
];
const args = commandLineArgs(argOptions);

const isDebug = args.debug;
const isVerbose = args.verbose;
const useHMR = false; //!!global.HMR; // Hot Module Replacement (HMR)
const babelConfig = {
	...pkg.babel,
	babelrc: true,
	cacheDirectory: useHMR
};

// Webpack configuration (main.js => dist/main.{hash}.js)
// http://webpack.github.io/docs/configuration.html
const config = {
	node: {
		fs: 'empty'
	},
	mode: isDebug ? 'development' : 'production',

	// The base directory for resolving the entry option
	context: path.resolve(__dirname),

	entry: [ './src/main.js' ],

	output: {
		path: path.resolve(__dirname, 'dist'),
		publicPath: isDebug ? '' : args.publicPath, // where bundled files are uploaded on server
		filename: '[name].[hash].js',
		chunkFilename: '[id].[chunkhash].js',
	},

	// Switch loaders to debug or release mode
	// Developer tool to enhance debugging, source maps
	// http://webpack.github.io/docs/configuration.html#devtool
	devtool: isDebug ? 'eval-source-map' : false,

	// What information should be printed to the console
	stats: {
		colors: true,
		reasons: isDebug,
		hash: isVerbose,
		version: isVerbose,
		timings: true,
		chunks: isVerbose,
		chunkModules: isVerbose,
		cached: isVerbose,
		cachedAssets: isVerbose
	},

	// Options affecting the normal modules
	module: {
		rules: [
			{
				test: /\.jsx?$/,
				exclude: [new RegExp('jsPsych'), /node_modules/],
				use: [
					{
						loader: 'babel-loader',
						options: babelConfig
					}
				]
			},
			{
				test: /\.css/,
				use: [
					{
						loader: 'style-loader'
					},
					{
						loader: 'css-loader',
						options: {
							sourceMap: isDebug,
							// CSS Modules https://github.com/css-modules/css-modules
							modules: true,
							localIdentName: isDebug
							? '[name]_[local]_[hash:base64:3]'
							: '[hash:base64:4]',
							// CSS Nano http://cssnano.co/options/
							minimize: !isDebug
						}
					}
				]
			},
			{
				test: /\.scss$/, // sass
				use: [
					{ loader: 'style-loader' },
					{
						loader: 'css-loader',
						options: {
							sourceMap: isDebug,
							// CSS Modules https://github.com/css-modules/css-modules
							modules: true,
							localIdentName: isDebug
							? '[name]_[local]_[hash:base64:3]'
							: '[hash:base64:4]',
							// CSS Nano http://cssnano.co/options/
							minimize: !isDebug
						}
					},
					{ loader: 'sass-loader' }
				]
			},
			{
				test: /\.json$/,
				exclude: [path.resolve(__dirname, './routes.json')],
				loader: 'json-loader'
			},
			{
				test: /\.json$/,
				include: [path.resolve(__dirname, './routes.json')],
				loaders: [
					`babel-loader?${JSON.stringify(babelConfig)}`,
					path.resolve(__dirname, './utils/routes-loader.js')
				]
			},
			{
				test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ico)$/,
				use: [
					{
						loader: 'file-loader',
						options: {
							limit: 10000
						}
					}
				]
			},
			{
				test: /\.(eot|ttf|wav|mp3|mp4)$/,
				use: 'file-loader'
			}
		]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: './src/index.html',
			title: 'Games With Words',
//			template: 'src/index.ejs',
//			inject: 'body',
			options: {
				debug: isDebug,
				trackingID: process.env.GOOGLE_ANALYTICS_SITE_ID,
			}
		}),
		...(isDebug ? [] : [new webpack.optimize.AggressiveMergingPlugin()])
	],
	optimization: {
		minimize: !isDebug
	}
};

// Hot Module Replacement (HMR) + React Hot Reload
if (isDebug && useHMR) {
	babelConfig.plugins.unshift('react-hot-loader/babel');
	config.entry.unshift(
		'react-hot-loader/patch',
		'webpack-hot-middleware/client'
	);
	config.plugins.push(new webpack.HotModuleReplacementPlugin());
	config.plugins.push(new webpack.NoEmitOnErrorsPlugin());
}

module.exports = config;
<commit_msg>cleaned<commit_after>process.traceDeprecation = true;

const path = require('path');
const webpack = require('webpack');
const pkg = require('./package.json');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const commandLineArgs = require('command-line-args');

const argOptions = [
	{ name: 'debug', alias: 'd', type: Boolean },
	{ name: 'verbose', alias: 'v', type: Boolean },
	{ name: 'hmr', alias: 'h', type: Boolean },
	{ name: 'google_analytics_site_id', alias: 'g', type: String, defaultOption: '' },
	{ name: 'publicPath', alias: 'p', type: String, defaultOption: '' },
];
const args = commandLineArgs(argOptions);

const babelConfig = {
	...pkg.babel,
	babelrc: true,
	cacheDirectory: args.hmr,
	plugins: [
		...(args.debug && args.hmr ? ['react-hot-loader/babel'] : [])
	]
};

// Webpack configuration (main.js => dist/main.{hash}.js)
// http://webpack.github.io/docs/configuration.html
const config = {
	node: { fs: 'empty' },
	mode: args.debug ? 'development' : 'production',

	context: path.resolve(__dirname), // The base directory for resolving the entry option

	entry: [
		'./src/main.js',
		...(args.debug && args.hmr ?  ['react-hot-loader/patch', 'webpack-host-middleware/client'] : [])
	],

	output: {
		path: path.resolve(__dirname, 'dist'),
		publicPath: args.debug ? '' : args.publicPath, // where bundled files are uploaded on server
		filename: '[name].[hash].js',
		chunkFilename: '[id].[chunkhash].js',
	},

	// Switch loaders to debug or release mode
	// Developer tool to enhance debugging, source maps
	// http://webpack.github.io/docs/configuration.html#devtool
	devtool: args.debug ? 'eval-source-map' : false,

	// What information should be printed to the console
	stats: {
		colors: true,
		reasons: args.debug,
		hash: args.verbose,
		version: args.verbose,
		timings: true,
		chunks: args.verbose,
		chunkModules: args.verbose,
		cached: args.verbose,
		cachedAssets: args.verbose
	},

	// Options affecting the normal modules
	module: {
		rules: [
			{
				test: /\.jsx?$/,
				exclude: [new RegExp('jsPsych'), /node_modules/],
				use: [ { loader: 'babel-loader', options: babelConfig } ]
			},
			{
				test: /\.css/,
				use: [ { loader: 'style-loader' },
					{
						loader: 'css-loader',
						options: {
							sourceMap: args.debug,
							modules: true, // CSS Modules https://github.com/css-modules/css-modules
							localIdentName: args.debug
							? '[name]_[local]_[hash:base64:3]'
							: '[hash:base64:4]',
							// CSS Nano http://cssnano.co/options/
							minimize: !args.debug
						}
					}
				]
			},
			{
				test: /\.scss$/, // sass
				use: [
					{ loader: 'style-loader' },
					{
						loader: 'css-loader',
						options: {
							sourceMap: args.debug,
							// CSS Modules https://github.com/css-modules/css-modules
							modules: true,
							localIdentName: args.debug ? '[name]_[local]_[hash:base64:3]' : '[hash:base64:4]',
							minimize: !args.debug // CSS Nano http://cssnano.co/options/
						}
					},
					{ loader: 'sass-loader' }
				]
			},
			{
				test: /\.json$/,
				exclude: [path.resolve(__dirname, './routes.json')],
				loader: 'json-loader'
			},
			{
				test: /\.json$/,
				include: [path.resolve(__dirname, './routes.json')],
				loaders: [
					`babel-loader?${JSON.stringify(babelConfig)}`,
					path.resolve(__dirname, './utils/routes-loader.js')
				]
			},
			{
				test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ico)$/,
				use: [ { loader: 'file-loader', options: { limit: 10000 } } ]
			},
			{
				test: /\.(eot|ttf|wav|mp3|mp4)$/,
				use: 'file-loader'
			}
		]
	},
	plugins: [
		new HtmlWebpackPlugin({
			template: './src/index.html',
			title: 'Games With Words',
			options: {
				debug: args.debug,
				trackingID: args.google_analytics_site_id,
			}
		}),
		...(args.debug ? [] : [new webpack.optimize.AggressiveMergingPlugin()]),
		...(args.debug && args.hmr ? [
			new webpack.HotModuleReplacementPlugin(),
			new webpack.NoEmitOnErrorsPlugin()
		] : [])
	],
	optimization: {
		minimize: !args.debug
	}
};

module.exports = config;
<|endoftext|>


<commit_before>var Path = require('path');
var Fs = require('fire-fs');
var FireUrl = require('fire-url');

var sysRequire = require;
var builtinClassIds;
var builtinClassNames;
var builtinComponentMenus;
var builtinCustomAssetMenus;

var initialized = false;
var loadedScriptNodes = [];

function init () {
    //sandbox.globalVarsChecker = new GlobalVarsChecker().record();
    builtinClassIds = Fire.JS._registeredClassIds;
    builtinClassNames = Fire.JS._registeredClassNames;
    //builtinComponentMenus = Fire._componentMenuItems.slice();
    //builtinCustomAssetMenus = Fire._customAssetMenuItems.slice();
}

function reset () {
    // clear
    Fire.FObject._deferredDestroy();
    //// reset menus
    //Fire._componentMenuItems = builtinComponentMenus.slice();
    //Fire._customAssetMenuItems = builtinCustomAssetMenus.slice();
    //// Editor.MainMenu.reset();
    // remove user classes
    Fire.JS._registeredClassIds = builtinClassIds;
    Fire.JS._registeredClassNames = builtinClassNames;
    ////
    Fire.LoadManager.reset();
    // 清除 browserify 声明的 require 后，除非用户另外找地方存了原来的 require，否则之前的脚本都将会被垃圾回收
    require = sysRequire;
    Fire._RFreset();
}

var sandbox = {
    reload: function (compiled) {
        this.compiled = compiled;
        Editor.stashScene(function (err, json) {
            // reload connected browser
            Editor.sendToCore('app:reload-on-device');

            //
            reset();

            // reload
            Editor.initScene();
        });
    },

    loadCompiledScript: function (next) {
        if ( Editor.remote.Compiler.state !== 'idle' ) {
            setTimeout( function () {
                sandbox.loadCompiledScript(next);
            }, 50 );
            return;
        }

        if (!initialized) {
            initialized = true;
            init();
        }

        function doLoad (src, cb) {
            var script = document.createElement('script');
            script.onload = function () {
                console.timeEnd('load ' + src);
                cb();
            };
            script.onerror = function () {
                console.timeEnd('load ' + src);
                if (loadedScriptNodes.length > 0) {
                    loader.unloadAll();
                }
                console.error('Failed to load %s', src);
                cb(new Error('Failed to load ' + src));
            };
            script.setAttribute('type','text/javascript');
            script.setAttribute('charset', 'utf-8');
            script.setAttribute('src', FireUrl.addRandomQuery(src));
            console.time('load ' + src);
            document.head.appendChild(script);
            loadedScriptNodes.push(script);
        }
        var scriptPath = Path.join(Editor.libraryPath, 'bundle.project.js');
        Fs.exists(scriptPath, function (exists) {
            if (exists) {
                doLoad(scriptPath, next);
            }
            else {
                next();
            }
        });
    },

    unloadCompiledScript: function (next) {
        // remove script element
        for (var i = 0; i < loadedScriptNodes.length; i++) {
            var node = loadedScriptNodes[i];
            node.remove();
        }
        loadedScriptNodes.length = 0;
    },

    compiled: false
};

Editor.Sandbox = sandbox;

module.exports = sandbox;
<commit_msg>clear cached uuid so that the scene can be reload correctly (fireball-x/fireball#198)<commit_after>var Path = require('path');
var Fs = require('fire-fs');
var FireUrl = require('fire-url');

var sysRequire = require;
var builtinClassIds;
var builtinClassNames;
var builtinComponentMenus;
var builtinCustomAssetMenus;

var initialized = false;
var loadedScriptNodes = [];

function init () {
    //sandbox.globalVarsChecker = new GlobalVarsChecker().record();
    builtinClassIds = Fire.JS._registeredClassIds;
    builtinClassNames = Fire.JS._registeredClassNames;
    //builtinComponentMenus = Fire._componentMenuItems.slice();
    //builtinCustomAssetMenus = Fire._customAssetMenuItems.slice();
}

function reset () {
    // clear
    Fire.FObject._deferredDestroy();
    //// reset menus
    //Fire._componentMenuItems = builtinComponentMenus.slice();
    //Fire._customAssetMenuItems = builtinCustomAssetMenus.slice();
    //// Editor.MainMenu.reset();
    // remove user classes
    Fire.JS._registeredClassIds = builtinClassIds;
    Fire.JS._registeredClassNames = builtinClassNames;
    ////
    Fire.LoadManager.reset();
    // 清除 browserify 声明的 require 后，除非用户另外找地方存了原来的 require，否则之前的脚本都将会被垃圾回收
    require = sysRequire;

    Fire._RFreset();
    Editor.clearUrlToUuidCache();
}

var sandbox = {
    reload: function (compiled) {
        this.compiled = compiled;
        Editor.stashScene(function (err, json) {
            // reload connected browser
            Editor.sendToCore('app:reload-on-device');

            //
            reset();

            // reload
            Editor.initScene();
        });
    },

    loadCompiledScript: function (next) {
        if ( Editor.remote.Compiler.state !== 'idle' ) {
            setTimeout( function () {
                sandbox.loadCompiledScript(next);
            }, 50 );
            return;
        }

        if (!initialized) {
            initialized = true;
            init();
        }

        function doLoad (src, cb) {
            var script = document.createElement('script');
            script.onload = function () {
                console.timeEnd('load ' + src);
                cb();
            };
            script.onerror = function () {
                console.timeEnd('load ' + src);
                if (loadedScriptNodes.length > 0) {
                    loader.unloadAll();
                }
                console.error('Failed to load %s', src);
                cb(new Error('Failed to load ' + src));
            };
            script.setAttribute('type','text/javascript');
            script.setAttribute('charset', 'utf-8');
            script.setAttribute('src', FireUrl.addRandomQuery(src));
            console.time('load ' + src);
            document.head.appendChild(script);
            loadedScriptNodes.push(script);
        }
        var scriptPath = Path.join(Editor.libraryPath, 'bundle.project.js');
        Fs.exists(scriptPath, function (exists) {
            if (exists) {
                doLoad(scriptPath, next);
            }
            else {
                next();
            }
        });
    },

    unloadCompiledScript: function (next) {
        // remove script element
        for (var i = 0; i < loadedScriptNodes.length; i++) {
            var node = loadedScriptNodes[i];
            node.remove();
        }
        loadedScriptNodes.length = 0;
    },

    compiled: false
};

Editor.Sandbox = sandbox;

module.exports = sandbox;
<|endoftext|>


<commit_before>module.exports = function (grunt) {

    grunt.initConfig({

        // Read tagenvy.json so we can access the config
        tagenvy: grunt.file.readJSON('tagenvy.json'),

        // Task to concatenate bower components
        bower_concat: {
            all: {
                dest: 'dist/_bower.js'
            }
        }
    });

    grunt.loadNpmTasks('grunt-bower-concat');

    grunt.registerTask('default', ['bower_concat']);
    grunt.registerTask('build', []);
};<commit_msg>Updated default and build tasks<commit_after>module.exports = function (grunt) {

    grunt.initConfig({

        // Read tagenvy.json so we can access the config
        tagenvy: grunt.file.readJSON('tagenvy.json'),

        // Task to concatenate bower components
        bower_concat: {
            all: {
                dest: 'dist/_bower.js'
            }
        }
    });

    grunt.loadNpmTasks('grunt-bower-concat');

    grunt.registerTask('default', ['build']);
    grunt.registerTask('build', ['bower_concat']);
};<|endoftext|>


<commit_before>module.exports = function (grunt) {

    grunt.initConfig({

        // Read tagenvy.json so we can access the config
        tagenvy: grunt.file.readJSON('tagenvy.json'),

        // Concatenate bower components
        bower_concat: {
            all: {
                dest: 'src/bower.js'
            }
        },

        // Concatenate tagenvy.js and _bower.js
        concat: {
            options: {
                separator: ';\n\n'
            },
            tagenvy: {
                src: ['src/bower.js', 'src/tagenvy.js'],
                dest: 'dist/tagenvy.js'
            }
        },

        // Check JavaScript code
        jshint: {
            afterConcat: {
                options: {
                    '-W032': true // Ignore warning 'W032: Unnecessary semicolon'
                },
                src: [
                    '<%%= concat.tagenvy.dest %>'
                ]
            },
            options: {
                // options here to override JSHint defaults
                globals: {
                    jQuery: true,
                    console: true,
                    module: true,
                    document: true,
                    angular: true
                },
                globalstrict: false
            }
        }
    });

    grunt.loadNpmTasks('grunt-bower-concat');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-jshint');

    grunt.registerTask('default', ['build']);
    grunt.registerTask('test', ['jshint']);
    grunt.registerTask('build', ['bower_concat', 'concat']);
};<commit_msg>Added additional tasks for testing JavaScript before concatenation and after concatenation<commit_after>module.exports = function (grunt) {

    grunt.initConfig({

        // Read tagenvy.json so we can access the config
        tagenvy: grunt.file.readJSON('tagenvy.json'),

        // Concatenate bower components
        bower_concat: {
            all: {
                dest: 'src/bower.js'
            }
        },

        // Concatenate tagenvy.js and _bower.js
        concat: {
            options: {
                separator: ';\n\n'
            },
            tagenvy: {
                src: ['src/bower.js', 'src/tagenvy.js'],
                dest: 'dist/tagenvy.js'
            }
        },

        // Check JavaScript code
        jshint: {
            beforeConcat: {
                options: {
                    '-W032': true // Ignore warning 'W032: Unnecessary semicolon'
                },
                src: [
                    '<%%= concat.tagenvy.src %>'
                ]
            },
            afterConcat: {
                options: {
                    '-W032': true // Ignore warning 'W032: Unnecessary semicolon'
                },
                src: [
                    '<%%= concat.tagenvy.dest %>'
                ]
            },
            options: {
                // options here to override JSHint defaults
                globals: {
                    jQuery: true,
                    console: true,
                    module: true,
                    document: true,
                    angular: true
                },
                globalstrict: false
            }
        }
    });

    grunt.loadNpmTasks('grunt-bower-concat');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-jshint');

    grunt.registerTask('default', ['jshint:beforeConcat', 'build', 'jshint:afterConcat']);
    grunt.registerTask('test', ['jshint:beforeConcat']);
    grunt.registerTask('build', ['bower_concat', 'concat']);
};<|endoftext|>


<commit_before>module.exports = function(grunt) {

  'use strict';

<% if (ProjectServer) { %>
  var fileExists = require('file-exists'),
  fs = require('fs'),
  key = function() {
    if (fileExists('clientConfig.json')) {
      key = fs.readFileSync((require('userhome')(grunt.file.readJSON('clientConfig.json').keyPath)));
    } else {
      var idrsa = require('userhome')('.ssh/id_rsa');
      key = fileExists(idrsa) ? fs.readFileSync(idrsa) : '';
    }
  },

  passphraseConfig = function() {
    if (fileExists('clientConfig.json')) {
      passphraseConfig = grunt.file.readJSON('clientConfig.json').passphrase;
    } else {
      passphraseConfig = '';
    }
  };

  key();
  passphraseConfig();
<% } %>

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    auto_install: {
      local: {
        options: {
          failOnError: true,
          bower: false
        }
      }
    },
<% if (ProjectServer) { %>
    environments: {
      options: {
        local_path: './build',
      },
      preview: {
        options: {
          username: grunt.file.readJSON('hostConfig.json').username,
          host: grunt.file.readJSON('hostConfig.json').hostServer,
          deploy_path: grunt.file.readJSON('hostConfig.json').deployPath,
          current_symlink: 'web',
          releases_to_keep: 2,
          passphrase: passphraseConfig,
          privateKey: key
        }
      }
    },<% } %>

    watch: {
      options: {
        spawn: false
      },

      // Styling
      scss: {
        files: 'components/**/*.scss',
        tasks: ['sync:webfonts', 'imagemin', 'compass:development', 'modernizr']
      },

      // Scripting
      js: {
        files: ['components/*.js', 'components/app/**/*.js', '!components/app/_deferred/**/*.js'],
        tasks: ['requirejs:development', 'modernizr'],
      },
      js_deferred: {
        files: ['components/app/_deferred/**/*.js'],
        tasks: ['uglify:deferred_development', 'modernizr'],
      },
      js_bower: {
        files: ['components/bower/**/*.js'],
        tasks: ['uglify:external', 'requirejs:development'],
      },
      json: {
        options: { livereload: true },
        files: ['components/app/**/*.json'],
        tasks: ['sync:json'],
      },

      // HTML
      html: {
        options: { livereload: true },
        files: ['*.html','components/app/**/*.html' , '!components/bower/**/*.html', '!build/**/*.html'],
        tasks: ['replace'],
      },

      // SVG
      svg: {
        options: { livereload: true },
        files: ['components/app/_svg/*.svg' , 'components/app/_svg/**/*.svg'],
        tasks: ['replace'],
      },

      // Images
      img_content: {
        options: { livereload: true },
        files: 'img/**/*.{png,gif,jpg,svg}',
        tasks: ['imagemin:content'],
      },
      img_background: {
        options: { livereload: true },
        files: ['components/**/*.{png,gif,jpg,svg,ico}', '!_svg/**/*.svg', '!_svg/*.svg'],
        tasks: ['clean:css', 'imagemin:backgrounds' , 'compass:development'],
      },
      img_inline_svg: {
        options: { livereload: true },
        files: ['components/app/_svg/**/*.svg', 'components/app/_svg/*.svg'],
        tasks: ['clean:css', 'imagemin:inline_svg' , 'compass:development'],
      },

      // websocket support
      livereload: {
        options: { livereload: true },
        files: ['build/**/*.{css,js}']
      }
    },

    compass: {
      options: {
        asset_cache_buster: false,
        bundleExec: true,
        cssDir: 'build/assets/css',
        httpFontsPath: '/assets/font',
        httpImagesPath: '/assets/img',
        imagesDir: 'build/assets/img',
        noLineComments: false,
        require: 'sass-css-importer',
        sassDir: 'components',
        specify: ['components/*.scss', 'components/app/_deferred/**/*.scss']
      },
      development: {
        options: {
          environment: 'development',
          sourcemap: true
        }
      },
      <% if (ProjectServer) { %>
      preview: {
        options: {
          environment: 'development',
          sourcemap: false,
        }
      },
      <% } %>
      live: {
        options: {
          environment: 'production',
          noLineComments: true,
          sourcemap: true,
          httpPath: '/' // . = relative
        }
      }
    },

    replace: {
      modules: {
        options: {
          excludeBuiltins: true,
          patterns: [
            {
              match: /{(app|deferred):{([\w|\-]*)}}/g,
              replacement: function (match, type, file) {

                // use regular file

                // add app folder to deferred component
                type = type === 'deferred' ? 'app/_' + type : type;

                // get file for replacement
                return grunt.file.read('components/' + type + '/' + file + '/' + file + '.html');
              }
            },
            {
              match: /{(app|deferred):{(.+):{(.+)}}}/g,
              replacement: function (match, type, component, alt_file) {

                // use alternate file

                // add app folder to deferred component
                type = type === 'deferred' ? 'app/_' + type : type;

                // get file for replacement
                return grunt.file.read('components/' + type + '/' + component + '/' + alt_file + '.html');
              }
            },
            {
              match: /{(svg):{([\w|\-]*)}}/g,
              replacement: function (match, type, file) {

                // use regular svg file without folder

                // get file for replacement
                return grunt.file.read('components/app/_svg/' + file + '.svg');
              }
            },
            {
              match: /{(svg):{(.+):{(.+)}}}/g,
              replacement: function (match, type, component, alt_file) {

                // use regular svg file that is nested in a folder

                // get file for replacement
                return grunt.file.read('components/app/_svg/' + component + '/' + alt_file + '.svg');
              }
            }
          ]
        },
        files: [
          {
            expand: true,
            flatten: true,
            src: ['*.html'],
            dest: 'build/'
          }
        ]
      }
    },

    requirejs: {
      options: {
        mainConfigFile: 'components/<%= ProjectName %>.js',
        name: '<%= ProjectName %>',
        out: 'build/assets/js/<%= ProjectName %>.js',
        useStrict: true
      },
      development: {
        options: {
          generateSourceMaps: true,
          optimize: 'none'
        }
      },
      <% if (ProjectServer) { %>
      preview: {
        options: {
          generateSourceMaps: false,
          optimize: 'none'
        }
      },
      <% } %>
      live: {
        options: {
          generateSourceMaps: false,
          optimize: 'uglify'
        }
      }
    },

    uglify: {
      deferred_development: {
        options: {
          sourceMap: true
        },
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      <% if (ProjectServer) { %>
      deferred_preview: {
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      <% } %>
      deferred_live: {
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      external: {
        files: {
          'build/assets/js/libs/require.js': ['components/libs/requirejs/require.js']
        }
      }
    },

    imagemin: {
      content: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'img',
          src: ['**/*.{gif,ico,jpg,png,svg}'],
          dest: 'build/img'
        }]
      },
      backgrounds: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/*.{gif,jpg,png,svg,ico}', '!_svg/**/*.svg', '!_svg/*.svg'],
          dest: 'build/assets/img'
        }]
      },
      inline_svg: {
        files: [{
          flatten: false,
          expand: true,
          cwd: 'components/app/_svg',
          src: ['**/*.svg','*.svg'],
          dest: 'build/assets/img/inline-svg'
        }]
      }
    },

    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: ['components/app/**/*.js']
    },

    csslint: {
      options: {
        csslintrc: '.csslintrc',
        import: false
      },
      lax: {
        src: ['build/assets/css/**/*.css']
      }
    },

    accessibility: {
      options : {
        accessibilityLevel: 'WCAG2<%= WCAG2 %>',
        accessibilityrc: true,
        domElement: true,
        reportLevels: {
          notice: false,
          warning: true,
          error: true
        }
      },
      development : {
        files: [{
          expand  : true,
          cwd     : 'build/',
          src     : ['*.html']
        }]
      }
    },

    clean: {
      css: {
        src: ['build/assets/css/**/*.css']
      },
      build: {
        src: ['build']
      }
    },

    qunit: {
      all: {
        options: {
          urls: [
            'http://localhost:10000/qunit/qunit-test-suite.html'
          ]
        }
      }
    },

    connect: {
      server: {
        options: {
          port: 10000,
          base: '.'
        }
      }
    },

    sync: {
      webfonts: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/font/*.{ttf,eot,woff,svg}'],
          dest: 'build/assets/font'
        }],
        verbose: true
      },
      json: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/*.json'],
          dest: 'build/assets/json'
        }],
        verbose: true
      }
    },

    modernizr: {
      dist: {
        'devFile' : 'components/libs/modernizr/modernizr.js',
        'outputFile' : 'build/assets/js/libs/modernizr.js',
        'extra' : {
          'shiv' : <% if (oldIE) { %>true<% } else { %>false<% } %>,
          'printshiv' : <% if (oldIE) { %>true<% } else { %>false<% } %>,
          'load' : false,
          'mq' : false,
          'cssclasses' : true
        },
        'files' : {
          'src': ['components/app/**/*.js', 'build/**/*.css']
        }
      }
    },

    jsdoc : {
      dist : {
        src: ['components/app/**/*.js'],
        options: {
          destination: 'documentation'
        }
      }
    },

    scsslint: {
      options: {
        bundleExec: true,
        colorizeOutput: true,
        compact: true,
        config: '.scsslintrc',
        reporterOutput: null
      },
      scss: [
        'components/app/**/*.scss',
      ]
    }

  });

  grunt.loadNpmTasks('grunt-auto-install');
  grunt.loadNpmTasks('grunt-accessibility');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-csslint');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-jsdoc');
  grunt.loadNpmTasks('grunt-modernizr');
  grunt.loadNpmTasks('grunt-newer');
  grunt.loadNpmTasks('grunt-replace');
  grunt.loadNpmTasks('grunt-scss-lint');
  grunt.loadNpmTasks('grunt-sync');
  <% if (ProjectServer) { %>grunt.loadNpmTasks('grunt-ssh-deploy');<% } %>

  grunt.registerTask('default', [
    'auto_install',
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:development',
    'requirejs:development',
    'uglify:deferred_development',
    'uglify:external',
    'modernizr'
  ]);

  grunt.registerTask('live', [
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:live',
    'requirejs:live',
    'uglify:deferred_live',
    'uglify:external',
    'modernizr'
  ]);
  <% if (ProjectServer) { %>
  grunt.registerTask('preview', [
    'auto_install',
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:preview',
    'requirejs:preview',
    'uglify:deferred_preview',
    'uglify:external',
    'modernizr',
    'ssh_deploy:preview'
  ]);<% } %>

  grunt.registerTask('test', [
    'csslint',
    'scsslint',
    'jshint',
    'accessibility',
    'connect',
    'qunit:all'
  ]);

  grunt.registerTask('doc', [
    'jsdoc'
  ]);

};
<commit_msg>[FEATURE] refactoring svg replace<commit_after>module.exports = function(grunt) {

  'use strict';

<% if (ProjectServer) { %>
  var fileExists = require('file-exists'),
  fs = require('fs'),
  key = function() {
    if (fileExists('clientConfig.json')) {
      key = fs.readFileSync((require('userhome')(grunt.file.readJSON('clientConfig.json').keyPath)));
    } else {
      var idrsa = require('userhome')('.ssh/id_rsa');
      key = fileExists(idrsa) ? fs.readFileSync(idrsa) : '';
    }
  },

  passphraseConfig = function() {
    if (fileExists('clientConfig.json')) {
      passphraseConfig = grunt.file.readJSON('clientConfig.json').passphrase;
    } else {
      passphraseConfig = '';
    }
  };

  key();
  passphraseConfig();
<% } %>

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    auto_install: {
      local: {
        options: {
          failOnError: true,
          bower: false
        }
      }
    },
<% if (ProjectServer) { %>
    environments: {
      options: {
        local_path: './build',
      },
      preview: {
        options: {
          username: grunt.file.readJSON('hostConfig.json').username,
          host: grunt.file.readJSON('hostConfig.json').hostServer,
          deploy_path: grunt.file.readJSON('hostConfig.json').deployPath,
          current_symlink: 'web',
          releases_to_keep: 2,
          passphrase: passphraseConfig,
          privateKey: key
        }
      }
    },<% } %>

    watch: {
      options: {
        spawn: false
      },

      // Styling
      scss: {
        files: 'components/**/*.scss',
        tasks: ['sync:webfonts', 'imagemin', 'compass:development', 'modernizr']
      },

      // Scripting
      js: {
        files: ['components/*.js', 'components/app/**/*.js', '!components/app/_deferred/**/*.js'],
        tasks: ['requirejs:development', 'modernizr'],
      },
      js_deferred: {
        files: ['components/app/_deferred/**/*.js'],
        tasks: ['uglify:deferred_development', 'modernizr'],
      },
      js_bower: {
        files: ['components/bower/**/*.js'],
        tasks: ['uglify:external', 'requirejs:development'],
      },
      json: {
        options: { livereload: true },
        files: ['components/app/**/*.json'],
        tasks: ['sync:json'],
      },

      // HTML
      html: {
        options: { livereload: true },
        files: ['*.html','components/app/**/*.html' , '!components/bower/**/*.html', '!build/**/*.html'],
        tasks: ['replace'],
      },

      // SVG
      svg: {
        options: { livereload: true },
        files: ['components/app/_svg/*.svg' , 'components/app/_svg/**/*.svg'],
        tasks: ['replace'],
      },

      // Images
      img_content: {
        options: { livereload: true },
        files: 'img/**/*.{png,gif,jpg,svg}',
        tasks: ['imagemin:content'],
      },
      img_background: {
        options: { livereload: true },
        files: ['components/**/*.{png,gif,jpg,svg,ico}', '!_svg/**/*.svg', '!_svg/*.svg'],
        tasks: ['clean:css', 'imagemin:backgrounds' , 'compass:development'],
      },
      img_inline_svg: {
        options: { livereload: true },
        files: ['components/app/_svg/**/*.svg', 'components/app/_svg/*.svg'],
        tasks: ['clean:css', 'imagemin:inline_svg' , 'compass:development'],
      },

      // websocket support
      livereload: {
        options: { livereload: true },
        files: ['build/**/*.{css,js}']
      }
    },

    compass: {
      options: {
        asset_cache_buster: false,
        bundleExec: true,
        cssDir: 'build/assets/css',
        httpFontsPath: '/assets/font',
        httpImagesPath: '/assets/img',
        imagesDir: 'build/assets/img',
        noLineComments: false,
        require: 'sass-css-importer',
        sassDir: 'components',
        specify: ['components/*.scss', 'components/app/_deferred/**/*.scss']
      },
      development: {
        options: {
          environment: 'development',
          sourcemap: true
        }
      },
      <% if (ProjectServer) { %>
      preview: {
        options: {
          environment: 'development',
          sourcemap: false,
        }
      },
      <% } %>
      live: {
        options: {
          environment: 'production',
          noLineComments: true,
          sourcemap: true,
          httpPath: '/' // . = relative
        }
      }
    },

    replace: {
      modules: {
        options: {
          excludeBuiltins: true,
          patterns: [
            {
              match: /{(app|deferred|svg):{([\w|\-]*)}}/g,
              replacement: function (match, type, file) {

                var is_svg = type === 'svg' ? true : false,
                    extension = is_svg ? '.svg' : '.html',
                    path = '',
                    start = '',
                    end = '';

                // use regular file

                // add app folder to deferred component
                type = type !== 'app' ? 'app/_' + type : type;

                // set path to file
                path = 'components/' + type + '/' + file + '/' + file + extension;

                if (is_svg) {
                  start = '<!-- START ' + path + ' -->\n';
                  end = '<!-- END ' + path + ' -->\n';
                }

                // var output = start + grunt.file.read(path) + end;
                // get file for replacement
                return start + grunt.file.read(path) + end;
                // return output;
              }
            },
            {
              match: /{(app|deferred|svg):{(.+):{(.+)}}}/g,
              replacement: function (match, type, component, alt_file) {

                var is_svg = type === 'svg' ? true : false,
                    extension = is_svg ? '.svg' : '.html',
                    path = '',
                    start = '',
                    end = '';

                // use alternate file

                // add app folder to deferred component
                type = type !== 'app' ? 'app/_' + type : type;

                // set path to file
                path = 'components/' + type + '/' + component + '/' + alt_file + extension;

                if (is_svg) {
                  start = '<!-- START ' + path + ' -->\n';
                  end = '<!-- END ' + path + ' -->\n';
                }

                // get file for replacement
                return start + grunt.file.read(path) + end;
              }
            },
          ]
        },
        files: [
          {
            expand: true,
            flatten: true,
            src: ['*.html'],
            dest: 'build/'
          }
        ]
      }
    },

    requirejs: {
      options: {
        mainConfigFile: 'components/<%= ProjectName %>.js',
        name: '<%= ProjectName %>',
        out: 'build/assets/js/<%= ProjectName %>.js',
        useStrict: true
      },
      development: {
        options: {
          generateSourceMaps: true,
          optimize: 'none'
        }
      },
      <% if (ProjectServer) { %>
      preview: {
        options: {
          generateSourceMaps: false,
          optimize: 'none'
        }
      },
      <% } %>
      live: {
        options: {
          generateSourceMaps: false,
          optimize: 'uglify'
        }
      }
    },

    uglify: {
      deferred_development: {
        options: {
          sourceMap: true
        },
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      <% if (ProjectServer) { %>
      deferred_preview: {
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      <% } %>
      deferred_live: {
        files: [{
          expand: true,
          flatten: true,
          cwd: 'components/app/_deferred',
          src: ['**/*.js', '!**/test-*.js'],
          dest: 'build/assets/js/deferred'
        }]
      },
      external: {
        files: {
          'build/assets/js/libs/require.js': ['components/libs/requirejs/require.js']
        }
      }
    },

    imagemin: {
      content: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'img',
          src: ['**/*.{gif,ico,jpg,png,svg}'],
          dest: 'build/img'
        }]
      },
      backgrounds: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/*.{gif,jpg,png,svg,ico}', '!_svg/**/*.svg', '!_svg/*.svg'],
          dest: 'build/assets/img'
        }]
      },
      inline_svg: {
        files: [{
          flatten: false,
          expand: true,
          cwd: 'components/app/_svg',
          src: ['**/*.svg','*.svg'],
          dest: 'build/assets/img/inline-svg'
        }]
      }
    },

    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: ['components/app/**/*.js']
    },

    csslint: {
      options: {
        csslintrc: '.csslintrc',
        import: false
      },
      lax: {
        src: ['build/assets/css/**/*.css']
      }
    },

    accessibility: {
      options : {
        accessibilityLevel: 'WCAG2<%= WCAG2 %>',
        accessibilityrc: true,
        domElement: true,
        reportLevels: {
          notice: false,
          warning: true,
          error: true
        }
      },
      development : {
        files: [{
          expand  : true,
          cwd     : 'build/',
          src     : ['*.html']
        }]
      }
    },

    clean: {
      css: {
        src: ['build/assets/css/**/*.css']
      },
      build: {
        src: ['build']
      }
    },

    qunit: {
      all: {
        options: {
          urls: [
            'http://localhost:10000/qunit/qunit-test-suite.html'
          ]
        }
      }
    },

    connect: {
      server: {
        options: {
          port: 10000,
          base: '.'
        }
      }
    },

    sync: {
      webfonts: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/font/*.{ttf,eot,woff,svg}'],
          dest: 'build/assets/font'
        }],
        verbose: true
      },
      json: {
        files: [{
          flatten: true,
          expand: true,
          cwd: 'components/app',
          src: ['**/*.json'],
          dest: 'build/assets/json'
        }],
        verbose: true
      }
    },

    modernizr: {
      dist: {
        'devFile' : 'components/libs/modernizr/modernizr.js',
        'outputFile' : 'build/assets/js/libs/modernizr.js',
        'extra' : {
          'shiv' : <% if (oldIE) { %>true<% } else { %>false<% } %>,
          'printshiv' : <% if (oldIE) { %>true<% } else { %>false<% } %>,
          'load' : false,
          'mq' : false,
          'cssclasses' : true
        },
        'files' : {
          'src': ['components/app/**/*.js', 'build/**/*.css']
        }
      }
    },

    jsdoc : {
      dist : {
        src: ['components/app/**/*.js'],
        options: {
          destination: 'documentation'
        }
      }
    },

    scsslint: {
      options: {
        bundleExec: true,
        colorizeOutput: true,
        compact: true,
        config: '.scsslintrc',
        reporterOutput: null
      },
      scss: [
        'components/app/**/*.scss',
      ]
    }

  });

  grunt.loadNpmTasks('grunt-auto-install');
  grunt.loadNpmTasks('grunt-accessibility');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-csslint');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-jsdoc');
  grunt.loadNpmTasks('grunt-modernizr');
  grunt.loadNpmTasks('grunt-newer');
  grunt.loadNpmTasks('grunt-replace');
  grunt.loadNpmTasks('grunt-scss-lint');
  grunt.loadNpmTasks('grunt-sync');
  <% if (ProjectServer) { %>grunt.loadNpmTasks('grunt-ssh-deploy');<% } %>

  grunt.registerTask('default', [
    'auto_install',
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:development',
    'requirejs:development',
    'uglify:deferred_development',
    'uglify:external',
    'modernizr'
  ]);

  grunt.registerTask('live', [
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:live',
    'requirejs:live',
    'uglify:deferred_live',
    'uglify:external',
    'modernizr'
  ]);
  <% if (ProjectServer) { %>
  grunt.registerTask('preview', [
    'auto_install',
    'clean:build',
    'replace',
    'imagemin',
    'sync',
    'compass:preview',
    'requirejs:preview',
    'uglify:deferred_preview',
    'uglify:external',
    'modernizr',
    'ssh_deploy:preview'
  ]);<% } %>

  grunt.registerTask('test', [
    'csslint',
    'scsslint',
    'jshint',
    'accessibility',
    'connect',
    'qunit:all'
  ]);

  grunt.registerTask('doc', [
    'jsdoc'
  ]);

};
<|endoftext|>


<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

describe('ReactDefaultPerf', function() {
  var React;
  var ReactDOM;
  var ReactDefaultPerf;
  var ReactTestUtils;
  var ReactDefaultPerfAnalysis;

  var App;
  var Box;
  var Div;

  beforeEach(function() {
    var now = 0;
    jest.setMock('fbjs/lib/performanceNow', function() {
      return now++;
    });

    if (typeof console.table !== 'function') {
      console.table = () => {};
      console.table.isFake = true;
    }

    React = require('React');
    ReactDOM = require('ReactDOM');
    ReactDefaultPerf = require('ReactDefaultPerf');
    ReactTestUtils = require('ReactTestUtils');
    ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');

    App = React.createClass({
      render: function() {
        return
<Box /><Box flip={this.props.flipSecond} />
;
      },
    });

    Box = React.createClass({
      render: function() {
        return
<input />
;
      },
    });

    // ReactPerf only measures composites, so we put everything in one.
    Div = React.createClass({
      render: function() {
        return
;
      },
    });
  });

  afterEach(function() {
    if (console.table.isFake) {
      delete console.table;
    }
  });

  function measure(fn) {
    ReactDefaultPerf.start();
    fn();
    ReactDefaultPerf.stop();
    return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change;
  }

  it('should count no-op update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(<App />, container);
    var measurements = measure(() => {
      ReactDOM.render(<App />, container);
    });

    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary.length).toBe(2);

    /*eslint-disable dot-notation */

    expect(summary[0]['Owner > component']).toBe('<root> > App');
    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
    expect(summary[0]['Instances']).toBe(1);

    expect(summary[1]['Owner > component']).toBe('App > Box');
    expect(summary[1]['Wasted time (ms)']).not.toBe(0);
    expect(summary[1]['Instances']).toBe(2);

    /*eslint-enable dot-notation */
  });

  it('should count no-op update in child as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(<App />, container);

    // Here, we add a Box -- two of the <Box /> updates are wasted time (but the
    // addition of the third is not)
    var measurements = measure(() => {
      ReactDOM.render(<App flipSecond={true} />, container);
    });

    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary.length).toBe(1);

    /*eslint-disable dot-notation */

    expect(summary[0]['Owner > component']).toBe('App > Box');
    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
    expect(summary[0]['Instances']).toBe(1);

    /*eslint-enable dot-notation */
  });

  function expectNoWaste(fn) {
    var measurements = measure(fn);
    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary).toEqual([]);
  }

  it('should not count initial render as waste', function() {
    expectNoWaste(() => {
      ReactTestUtils.renderIntoDocument(<App />);
    });
  });

  it('should not count unmount as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hello
, container);
    expectNoWaste(() => {
      ReactDOM.unmountComponentAtNode(container);
    });
  });

  it('should not count content update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hello
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hello world
, container);
    });
  });

  it('should not count child addition as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count child removal as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count property update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count style update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count property removal as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count raw HTML update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

,
      container
    );
    expectNoWaste(() => {
      ReactDOM.render(

,
        container
      );
    });
  });

  it('should not count child reordering as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count text update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
{'hello'}{'world'}
, container);
    expectNoWaste(() => {
      ReactDOM.render(
{'hello'}{'friend'}
, container);
    });
  });

  it('putListener should not be instrumented', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });

    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
    expect(summary).toEqual([]);
  });

  it('deleteListener should not be instrumented', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });

    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
    expect(summary).toEqual([]);
  });

  it('should print a table after calling printOperations', function() {
    var container = document.createElement('div');
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });
    spyOn(console, 'table');
    ReactDefaultPerf.printOperations(measurements);
    expect(console.table.calls.length).toBe(1);
    expect(console.table.argsForCall[0][0]).toEqual([{
      'data-reactid': '',
      type: 'set innerHTML',
      args: '{"node":"<not serializable>","children":[],"html":null,"text":null}',
    }]);
  });

  it('warns once when using getMeasurementsSummaryMap', function() {
    var measurements = measure(() => {});
    spyOn(console, 'error');
    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
    expect(console.error.calls.length).toBe(1);
    expect(console.error.argsForCall[0][0]).toContain(
      '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
      '`ReactPerf.getWasted(...)` instead.'
    );

    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
    expect(console.error.calls.length).toBe(1);
  });

  it('warns once when using printDOM', function() {
    var measurements = measure(() => {});
    spyOn(console, 'error');
    ReactDefaultPerf.printDOM(measurements);
    expect(console.error.calls.length).toBe(1);
    expect(console.error.argsForCall[0][0]).toContain(
      '`ReactPerf.printDOM(...)` is deprecated. Use ' +
      '`ReactPerf.printOperations(...)` instead.'
    );

    ReactDefaultPerf.printDOM(measurements);
    expect(console.error.calls.length).toBe(1);
  });

});
<commit_msg>Fix ReactPerf.printOperations() test to work with createElement = false<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @emails react-core
 */

'use strict';

describe('ReactDefaultPerf', function() {
  var React;
  var ReactDOM;
  var ReactDOMFeatureFlags;
  var ReactDefaultPerf;
  var ReactTestUtils;
  var ReactDefaultPerfAnalysis;

  var App;
  var Box;
  var Div;

  beforeEach(function() {
    var now = 0;
    jest.setMock('fbjs/lib/performanceNow', function() {
      return now++;
    });

    if (typeof console.table !== 'function') {
      console.table = () => {};
      console.table.isFake = true;
    }

    React = require('React');
    ReactDOM = require('ReactDOM');
    ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
    ReactDefaultPerf = require('ReactDefaultPerf');
    ReactTestUtils = require('ReactTestUtils');
    ReactDefaultPerfAnalysis = require('ReactDefaultPerfAnalysis');

    App = React.createClass({
      render: function() {
        return
<Box /><Box flip={this.props.flipSecond} />
;
      },
    });

    Box = React.createClass({
      render: function() {
        return
<input />
;
      },
    });

    // ReactPerf only measures composites, so we put everything in one.
    Div = React.createClass({
      render: function() {
        return
;
      },
    });
  });

  afterEach(function() {
    if (console.table.isFake) {
      delete console.table;
    }
  });

  function measure(fn) {
    ReactDefaultPerf.start();
    fn();
    ReactDefaultPerf.stop();
    return ReactDefaultPerf.getLastMeasurements().__unstable_this_format_will_change;
  }

  it('should count no-op update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(<App />, container);
    var measurements = measure(() => {
      ReactDOM.render(<App />, container);
    });

    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary.length).toBe(2);

    /*eslint-disable dot-notation */

    expect(summary[0]['Owner > component']).toBe('<root> > App');
    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
    expect(summary[0]['Instances']).toBe(1);

    expect(summary[1]['Owner > component']).toBe('App > Box');
    expect(summary[1]['Wasted time (ms)']).not.toBe(0);
    expect(summary[1]['Instances']).toBe(2);

    /*eslint-enable dot-notation */
  });

  it('should count no-op update in child as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(<App />, container);

    // Here, we add a Box -- two of the <Box /> updates are wasted time (but the
    // addition of the third is not)
    var measurements = measure(() => {
      ReactDOM.render(<App flipSecond={true} />, container);
    });

    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary.length).toBe(1);

    /*eslint-disable dot-notation */

    expect(summary[0]['Owner > component']).toBe('App > Box');
    expect(summary[0]['Wasted time (ms)']).not.toBe(0);
    expect(summary[0]['Instances']).toBe(1);

    /*eslint-enable dot-notation */
  });

  function expectNoWaste(fn) {
    var measurements = measure(fn);
    var summary = ReactDefaultPerf.getWasted(measurements);
    expect(summary).toEqual([]);
  }

  it('should not count initial render as waste', function() {
    expectNoWaste(() => {
      ReactTestUtils.renderIntoDocument(<App />);
    });
  });

  it('should not count unmount as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hello
, container);
    expectNoWaste(() => {
      ReactDOM.unmountComponentAtNode(container);
    });
  });

  it('should not count content update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hello
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hello world
, container);
    });
  });

  it('should not count child addition as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count child removal as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count property update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count style update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count property removal as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    expectNoWaste(() => {
      ReactDOM.render(
hey
, container);
    });
  });

  it('should not count raw HTML update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

,
      container
    );
    expectNoWaste(() => {
      ReactDOM.render(

,
        container
      );
    });
  });

  it('should not count child reordering as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(

, container);
    expectNoWaste(() => {
      ReactDOM.render(

, container);
    });
  });

  it('should not count text update as waste', function() {
    var container = document.createElement('div');
    ReactDOM.render(
{'hello'}{'world'}
, container);
    expectNoWaste(() => {
      ReactDOM.render(
{'hello'}{'friend'}
, container);
    });
  });

  it('putListener should not be instrumented', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });

    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
    expect(summary).toEqual([]);
  });

  it('deleteListener should not be instrumented', function() {
    var container = document.createElement('div');
    ReactDOM.render(
hey
, container);
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });

    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
    expect(summary).toEqual([]);
  });

  it('should print a table after calling printOperations', function() {
    var container = document.createElement('div');
    var measurements = measure(() => {
      ReactDOM.render(
hey
, container);
    });
    spyOn(console, 'table');
    ReactDefaultPerf.printOperations(measurements);
    expect(console.table.calls.length).toBe(1);
    expect(console.table.argsForCall[0][0]).toEqual([{
      'data-reactid': '',
      type: 'set innerHTML',
      args: ReactDOMFeatureFlags.useCreateElement ?
        '{"node":"<not serializable>","children":[],"html":null,"text":null}' :
        '"
hey
"',
    }]);
  });

  it('warns once when using getMeasurementsSummaryMap', function() {
    var measurements = measure(() => {});
    spyOn(console, 'error');
    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
    expect(console.error.calls.length).toBe(1);
    expect(console.error.argsForCall[0][0]).toContain(
      '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' +
      '`ReactPerf.getWasted(...)` instead.'
    );

    ReactDefaultPerf.getMeasurementsSummaryMap(measurements);
    expect(console.error.calls.length).toBe(1);
  });

  it('warns once when using printDOM', function() {
    var measurements = measure(() => {});
    spyOn(console, 'error');
    ReactDefaultPerf.printDOM(measurements);
    expect(console.error.calls.length).toBe(1);
    expect(console.error.argsForCall[0][0]).toContain(
      '`ReactPerf.printDOM(...)` is deprecated. Use ' +
      '`ReactPerf.printOperations(...)` instead.'
    );

    ReactDefaultPerf.printDOM(measurements);
    expect(console.error.calls.length).toBe(1);
  });

});
<|endoftext|>


<commit_before>/*
 *  This file is part of Wirecloud.
 *  Copyright (C) 2015  CoNWeT Lab., Universidad Politécnica de Madrid
 *
 *  Wirecloud is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  License, or (at your option) any later version.
 *
 *  Wirecloud is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with Wirecloud.  If not, see <http://www.gnu.org/licenses/>.
 */

/*global StyledElements, Wirecloud */

Wirecloud.ui.WiringEditor.Behaviour = (function () {

    "use strict";

    /**
     * Create a new instance of class Behaviour.
     * @class
     *
     * @param {Object.<String, *>} data
     * @param {Number} index
     * @param {Object.<String, *>} [options]
     */
    var Behaviour = function Behaviour(data, index, options) {
        var countersElement;

        StyledElements.EventManagerMixin.call(this, Behaviour.events);
        data = Behaviour.normalize(data, index);

        this.wrapperElement = document.createElement('div');
        this.wrapperElement.className = "behaviour";

        this.bodyElement = document.createElement('div');
        this.bodyElement.className = "behaviour-body";
        this.wrapperElement.appendChild(this.bodyElement);

        this.title = data.title;
        this.description = data.description;

        this.titleElement = document.createElement('span');
        this.titleElement.className = "behaviour-title";
        this.titleElement.textContent = this.title;
        this.bodyElement.appendChild(this.titleElement);

        this.descriptionElement = document.createElement('span');
        this.descriptionElement.className = "behaviour-description";
        this.descriptionElement.textContent = this.description;
        this.bodyElement.appendChild(this.descriptionElement);

        countersElement = document.createElement('div');
        countersElement.className = "behaviour-elements";
        this.bodyElement.appendChild(this.countersElement);

        this.components = data.components;
        this.connections = data.connections;

        this.connectionsElement = document.createElement('div');
        this.connectionsElement.className = "badge badge-connections";
        countersElement.appendChild(this.connectionsElement);

        this.operatorsElement = document.createElement('div');
        this.operatorsElement.className = "badge badge-operators";
        countersElement.appendChild(this.operatorsElement);

        this.widgetsElement = document.createElement('div');
        this.widgetsElement.className = "badge badge-widgets";
        countersElement.appendChild(this.widgetsElement);

        this.headingElement = document.createElement('div');
        this.headingElement.className = "behaviour-heading";
        this.wrapperElement.appendChild(this.headingElement);

        Object.defineProperty(this, 'active', {
            'get': function get() {
                return this.wrapperElement.classList.contains('active');
            },
            'set': function set(value) {
                if (value) {
                    this.wrapperElement.classList.add('active');
                } else {
                    this.wrapperElement.classList.remove('active');
                }
            }
        });

        this.active = data.active;
        updateCounterList.call(this);
    };

    StyledElements.Utils.inherit(Behaviour, null, StyledElements.EventManagerMixin);

    Behaviour.events = ['click', 'info.click'];

    Behaviour.normalize = function normalize(data, index) {
        if (typeof data !== 'object') {
            data = {
                active: false,
                title: "New behaviour " + index,
                description: "No description provided.",
                components: {
                    operator: {},
                    widget: {}
                },
                connections: []
            };
        }

        if (typeof data.active !== 'boolean') {
            data.active = false;
        }

        if (typeof data.title !== 'string' || !data.title.length) {
            data.title = "New behaviour " + index;
        }

        if (typeof data.description !== 'string' || !data.description.length) {
            data.description = "No description provided.";
        }

        if (typeof data.components !== 'object') {
            data.components = {
                operator: {},
                widget: {}
            };
        }

        if (!Array.isArray(data.connections)) {
            data.connections = [];
        }

        return data;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Boolean} If the component given is saved.
     */
    Behaviour.prototype.containsComponent = function containsComponent(componentType, componentId) {
        return componentId in this.components[componentType];
    };

    /**
     * @public
     * @function
     *
     * @param {Behaviour} behaviour
     * @returns {Boolean} If the behaviour given is the same behaviour saved.
     */
    Behaviour.prototype.equals = function equals(behaviour) {
        return (behaviour instanceof Behaviour) && Object.is(this, behaviour);
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Boolean} If the component given has view registered.
     */
    Behaviour.prototype.hasComponentView = function hasComponentView(componentType, componentId) {
        return Object.keys(this.components[componentType][componentId]).length;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Object.<String, *>} The current view of the component given.
     */
    Behaviour.prototype.getComponentView = function getComponentView(componentType, componentId) {
        return this.components[componentType][componentId];
    };

    /**
     * @public
     * @function
     *
     * @param {String} connectionId
     * @returns {Object.<String, *>} The current view of the component given.
     */
    Behaviour.prototype.getConnectionView = function getConnectionView(connectionId) {
        var connectionView, found, i;

        for (found = false, i = 0; !found && i < this.connections.length; i++) {
            if (this.connections[i].id == connectionId) {
                connectionView = this.connections[i];
                found = true;
            }
        }

        return connectionView;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.removeComponent = function removeComponent(componentType, componentId) {
        delete this.components[componentType][componentId];
        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {String} connectionId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.removeConnection = function removeConnection(connectionId) {
        var index;

        if ((index=this.connections.indexOf(connectionId)) != -1) {
            this.connections.splice(index, 1);
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @returns {Object.<String, *>} The current information saved.
     */
    Behaviour.prototype.serialize = function serialize() {
        var data = {
            active: this.active,
            title: this.title,
            description: this.description,
            components: this.components,
            connections: this.connections
        };

        return StyledElements.Utils.cloneObject(data);
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @param {Object.<String, *>} componentView
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateComponent = function updateComponent(componentType, componentId, componentView) {
        if (typeof componentView === 'undefined') {
            if (!this.containsComponent(componentType, componentId)) {
                this.components[componentType][componentId] = {};
            }
        } else {
            this.components[componentType][componentId] = componentView;
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateConnection = function updateConnection(connectionId) {
        var index;

        if ((index=this.connections.indexOf(componentId)) == -1) {
            this.connections.push(connectionId);
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {Object.<String, *>} data
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateInfo = function updateInfo(data) {
        var prop;

        if (typeof data.title === 'string' && data.title.length) {
            this.title = data.title;
            this.titleElement.textContent = data.title;
        }

        if (typeof data.description === 'string' && data.description.length) {
            this.description = data.description;
            this.descriptionElement.textContent = data.description;
        }

        return this;
    };

    /**
     * @private
     * @function
     *
     * @returns {Behaviour} The instance on which this function was called.
     */
    var updateCounterList = function updateCounterList() {
        this.connectionsElement.textContent = this.connections.length;
        this.operatorsElement.textContent = Object.keys(this.components.operator).length;
        this.widgetsElement.textContent = Object.keys(this.components.widget).length;

        return this;
    };

    return Behaviour;

})();
<commit_msg>Added an icon to the behaviour's heading<commit_after>/*
 *  This file is part of Wirecloud.
 *  Copyright (C) 2015  CoNWeT Lab., Universidad Politécnica de Madrid
 *
 *  Wirecloud is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  License, or (at your option) any later version.
 *
 *  Wirecloud is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with Wirecloud.  If not, see <http://www.gnu.org/licenses/>.
 */

/*global StyledElements, Wirecloud */

Wirecloud.ui.WiringEditor.Behaviour = (function () {

    "use strict";

    /**
     * Create a new instance of class Behaviour.
     * @class
     *
     * @param {Object.<String, *>} data
     * @param {Number} index
     * @param {Object.<String, *>} [options]
     */
    var Behaviour = function Behaviour(data, index, options) {
        var iconDisplay, countersElement;

        StyledElements.EventManagerMixin.call(this, Behaviour.events);
        data = Behaviour.normalize(data, index);

        this.wrapperElement = document.createElement('div');
        this.wrapperElement.className = "behaviour";

        this.bodyElement = document.createElement('div');
        this.bodyElement.className = "behaviour-body";
        this.wrapperElement.appendChild(this.bodyElement);

        this.title = data.title;
        this.description = data.description;

        this.titleElement = document.createElement('span');
        this.titleElement.className = "behaviour-title";
        this.titleElement.textContent = this.title;
        this.bodyElement.appendChild(this.titleElement);

        this.descriptionElement = document.createElement('span');
        this.descriptionElement.className = "behaviour-description";
        this.descriptionElement.textContent = this.description;
        this.bodyElement.appendChild(this.descriptionElement);

        countersElement = document.createElement('div');
        countersElement.className = "behaviour-elements";
        this.bodyElement.appendChild(countersElement);

        this.components = data.components;
        this.connections = data.connections;

        this.connectionsElement = document.createElement('div');
        this.connectionsElement.className = "badge badge-connections";
        countersElement.appendChild(this.connectionsElement);

        this.operatorsElement = document.createElement('div');
        this.operatorsElement.className = "badge badge-operators";
        countersElement.appendChild(this.operatorsElement);

        this.widgetsElement = document.createElement('div');
        this.widgetsElement.className = "badge badge-widgets";
        countersElement.appendChild(this.widgetsElement);

        this.headingElement = document.createElement('div');
        this.headingElement.className = "behaviour-heading";
        this.wrapperElement.appendChild(this.headingElement);

        iconDisplay = document.createElement('span');
        iconDisplay.className = "btn-display icon-eye-open";
        this.headingElement.appendChild(iconDisplay);

        Object.defineProperty(this, 'active', {
            'get': function get() {
                return this.wrapperElement.classList.contains('active');
            },
            'set': function set(value) {
                if (value) {
                    this.wrapperElement.classList.add('active');
                } else {
                    this.wrapperElement.classList.remove('active');
                }
            }
        });

        this.active = data.active;
        updateCounterList.call(this);
    };

    StyledElements.Utils.inherit(Behaviour, null, StyledElements.EventManagerMixin);

    Behaviour.events = ['click', 'info.click'];

    Behaviour.normalize = function normalize(data, index) {
        if (typeof data !== 'object') {
            data = {
                active: false,
                title: "New behaviour " + index,
                description: "No description provided.",
                components: {
                    operator: {},
                    widget: {}
                },
                connections: []
            };
        }

        if (typeof data.active !== 'boolean') {
            data.active = false;
        }

        if (typeof data.title !== 'string' || !data.title.length) {
            data.title = "New behaviour " + index;
        }

        if (typeof data.description !== 'string' || !data.description.length) {
            data.description = "No description provided.";
        }

        if (typeof data.components !== 'object') {
            data.components = {
                operator: {},
                widget: {}
            };
        }

        if (!Array.isArray(data.connections)) {
            data.connections = [];
        }

        return data;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Boolean} If the component given is saved.
     */
    Behaviour.prototype.containsComponent = function containsComponent(componentType, componentId) {
        return componentId in this.components[componentType];
    };

    /**
     * @public
     * @function
     *
     * @param {Behaviour} behaviour
     * @returns {Boolean} If the behaviour given is the same behaviour saved.
     */
    Behaviour.prototype.equals = function equals(behaviour) {
        return (behaviour instanceof Behaviour) && Object.is(this, behaviour);
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Boolean} If the component given has view registered.
     */
    Behaviour.prototype.hasComponentView = function hasComponentView(componentType, componentId) {
        return Object.keys(this.components[componentType][componentId]).length;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Object.<String, *>} The current view of the component given.
     */
    Behaviour.prototype.getComponentView = function getComponentView(componentType, componentId) {
        return this.components[componentType][componentId];
    };

    /**
     * @public
     * @function
     *
     * @param {String} connectionId
     * @returns {Object.<String, *>} The current view of the component given.
     */
    Behaviour.prototype.getConnectionView = function getConnectionView(connectionId) {
        var connectionView, found, i;

        for (found = false, i = 0; !found && i < this.connections.length; i++) {
            if (this.connections[i].id == connectionId) {
                connectionView = this.connections[i];
                found = true;
            }
        }

        return connectionView;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.removeComponent = function removeComponent(componentType, componentId) {
        delete this.components[componentType][componentId];
        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {String} connectionId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.removeConnection = function removeConnection(connectionId) {
        var index;

        if ((index=this.connections.indexOf(connectionId)) != -1) {
            this.connections.splice(index, 1);
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @returns {Object.<String, *>} The current information saved.
     */
    Behaviour.prototype.serialize = function serialize() {
        var data = {
            active: this.active,
            title: this.title,
            description: this.description,
            components: this.components,
            connections: this.connections
        };

        return StyledElements.Utils.cloneObject(data);
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentType
     * @param {String} componentId
     * @param {Object.<String, *>} componentView
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateComponent = function updateComponent(componentType, componentId, componentView) {
        if (typeof componentView === 'undefined') {
            if (!this.containsComponent(componentType, componentId)) {
                this.components[componentType][componentId] = {};
            }
        } else {
            this.components[componentType][componentId] = componentView;
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {String} componentId
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateConnection = function updateConnection(connectionId) {
        var index;

        if ((index=this.connections.indexOf(componentId)) == -1) {
            this.connections.push(connectionId);
        }

        updateCounterList.call(this);

        return this;
    };

    /**
     * @public
     * @function
     *
     * @param {Object.<String, *>} data
     * @returns {Behaviour} The instance on which this function was called.
     */
    Behaviour.prototype.updateInfo = function updateInfo(data) {
        var prop;

        if (typeof data.title === 'string' && data.title.length) {
            this.title = data.title;
            this.titleElement.textContent = data.title;
        }

        if (typeof data.description === 'string' && data.description.length) {
            this.description = data.description;
            this.descriptionElement.textContent = data.description;
        }

        return this;
    };

    /**
     * @private
     * @function
     *
     * @returns {Behaviour} The instance on which this function was called.
     */
    var updateCounterList = function updateCounterList() {
        this.connectionsElement.textContent = this.connections.length;
        this.operatorsElement.textContent = Object.keys(this.components.operator).length;
        this.widgetsElement.textContent = Object.keys(this.components.widget).length;

        return this;
    };

    return Behaviour;

})();
<|endoftext|>


<commit_before>import Ember from 'ember';
import Suggester from '../utils/suggester';

export default Ember.View.extend({
  classNames: ["story"],

  templateName: function() {
    if (this.get('content.model.isDeleted')) {
      return "story/deleted";
    }
    return "story/" + this.get('content.model.type');
  }.property('content.model.type', 'content.model.isDeleted'),

  rerenderOnDeletion: function() {
    this.rerender();
  }.observes('content.model.isDeleted'),

  truncateLongComments: function() {
    var commentEl = this.$(".comment-text")[0];
    if (commentEl && commentEl.offsetHeight < commentEl.scrollHeight - 1) {
      this.controller.set('overflowing', true);
    }
  },

  hideSpoilers: function() {
    if (this.get('content.model.type') === "comment") {
      Ember.run.scheduleOnce('afterRender', this, function() {
        this.$(".spoiler").spoilerAlert();
      });
    }
  }.on('didInsertElement').observes('content.showAll', 'content.loadingAll'),

  didInsertElement: function() {
    var storyType = this.get('content.model.type');
    if (storyType === "comment") {
      this.truncateLongComments();
      this.$("img").load(() => {
        this.truncateLongComments();
      });

      Suggester(this.$('textarea'));
    }
  }
});
<commit_msg>:memo: fix story view issue<commit_after>import Ember from 'ember';
import Suggester from '../utils/suggester';

export default Ember.View.extend({
  classNames: ["story"],

  templateName: function() {
    if (this.get('content.model.isDeleted')) {
      return "story/deleted";
    }
    return "story/" + this.get('content.model.type');
  }.property('content.model.type', 'content.model.isDeleted'),

  rerenderOnDeletion: function() {
    this.rerender();
  }.observes('content.model.isDeleted'),

  truncateLongComments: function() {
    var commentEl = this.$(".comment-text")[0];
    if (commentEl && commentEl.offsetHeight < commentEl.scrollHeight - 1) {
      this.get('controller').set('overflowing', true);
    }
  },

  hideSpoilers: function() {
    if (this.get('content.model.type') === "comment") {
      Ember.run.scheduleOnce('afterRender', this, function() {
        this.$(".spoiler").spoilerAlert();
      });
    }
  }.on('didInsertElement').observes('content.showAll', 'content.loadingAll'),

  didInsertElement: function() {
    var storyType = this.get('content.model.type');
    if (storyType === "comment") {
      this.truncateLongComments();
      this.$("img").load(() => {
        this.truncateLongComments();
      });

      Suggester(this.$('textarea'));
    }
  }
});
<|endoftext|>