<commit_before>// Includes file dependencies
define([
    "backbone",
    "marionette",
    "text!../templates/player_options.html",
    "../helpers/PromiseFailReport",
    "parse"
], function( Backbone, Marionette, player_options_html, PromiseFailReport, Parse) {

    var RoleView = Marionette.ItemView.extend({
        template: function (serialized_model) {
            var id = serialized_model.attributes.name;
            id = id.split('_');
            id = id[1];
            serialized_model.troupe_id = id;
            return _.template("<a class='ui-btn' href='#troupe/<%= troupe_id %>/characters/all'><%= attributes.name %>")(serialized_model);
        }
    });

    var RolesView = Marionette.CollectionView.extend({
        tagName: 'div',
        childView: RoleView
    });

    var View = Marionette.LayoutView.extend( {
        template: _.template(player_options_html),
        regions: {
            troupcharactersquickaccess: "#troupe-characters-quick-access",
        },
        initialize: function(options) {
            var self = this;
            self.options = options || {};
            self.roles = new Backbone.Collection();
            _.bindAll(this, "setup", "update_roles");
        },
        update_roles: function() {
            var self = this;
            self._updateRoleWrapper = self._updateRoleWrapper || Parse.Promise.as();
            self._updateRoleWrapper = self._updateRoleWrapper.always(function () {
                var q = new Parse.Query(Parse.Role);
                q.each(function (role) {
                    var users_relation = role.getUsers();
                    var uq = users_relation.query();
                    uq.equalTo("objectId", Parse.User.current().id);
                    return uq.each(function (user) {
                        self.roles.add(role);
                    }).fail(function (error) {
                        console.log("Failed in promise for " + role.get("name"));
                    });
                }).fail(PromiseFailReport);
            });
            return self._updateRoleWrapper;
        },
        setup: function() {
            var self = this;
            var options = self.options || {};
            self.render();

            var is_st = Parse.User.current().get("storytellerinterface");
            var is_ad = Parse.User.current().get("admininterface");

            // Don't try to display the troupe characters quick access if we don't think they have any special roles
            if (!is_ad && !is_st)
                return self;

            self.showChildView('troupcharactersquickaccess', new RolesView({
                collection: self.roles
            }), options);
            self.update_roles();

            return self;
        },
    } );

    return View;
} );
<commit_msg>Display a loading message when we have no troupes yet<commit_after>// Includes file dependencies
define([
    "backbone",
    "marionette",
    "text!../templates/player_options.html",
    "../helpers/PromiseFailReport",
    "parse"
], function( Backbone, Marionette, player_options_html, PromiseFailReport, Parse) {

    var NoRolesView = Marionette.ItemView.extend({
        template: _.template("Loading Available Troupes...")
    });

    var RoleView = Marionette.ItemView.extend({
        template: function (serialized_model) {
            var id = serialized_model.attributes.name;
            id = id.split('_');
            id = id[1];
            serialized_model.troupe_id = id;
            return _.template("<a class='ui-btn' href='#troupe/<%= troupe_id %>/characters/all'><%= attributes.name %>")(serialized_model);
        }
    });

    var RolesView = Marionette.CollectionView.extend({
        tagName: 'div',
        childView: RoleView,
        emptyView: NoRolesView
    });

    var View = Marionette.LayoutView.extend( {
        template: _.template(player_options_html),
        regions: {
            troupcharactersquickaccess: "#troupe-characters-quick-access",
        },
        initialize: function(options) {
            var self = this;
            self.options = options || {};
            self.roles = new Backbone.Collection();
            _.bindAll(this, "setup", "update_roles");
        },
        update_roles: function() {
            var self = this;
            self._updateRoleWrapper = self._updateRoleWrapper || Parse.Promise.as();
            self._updateRoleWrapper = self._updateRoleWrapper.always(function () {
                var q = new Parse.Query(Parse.Role);
                q.each(function (role) {
                    var users_relation = role.getUsers();
                    var uq = users_relation.query();
                    uq.equalTo("objectId", Parse.User.current().id);
                    return uq.each(function (user) {
                        self.roles.add(role);
                    }).fail(function (error) {
                        console.log("Failed in promise for " + role.get("name"));
                    });
                }).fail(PromiseFailReport);
            });
            return self._updateRoleWrapper;
        },
        setup: function() {
            var self = this;
            var options = self.options || {};
            self.render();

            var is_st = Parse.User.current().get("storytellerinterface");
            var is_ad = Parse.User.current().get("admininterface");

            // Don't try to display the troupe characters quick access if we don't think they have any special roles
            if (!is_ad && !is_st)
                return self;

            self.showChildView('troupcharactersquickaccess', new RolesView({
                collection: self.roles
            }), options);
            self.update_roles();

            return self;
        },
    } );

    return View;
} );
<|endoftext|>


<commit_before>/* global module:true, process:true */

(function() {
  'use strict';

  var fs = require('fs'),
      less = require('less'),
      extend = require('extend'),
      path = require('path'),
      appDir = process.cwd(),
      karmaConstants = require(appDir + '/node_modules/karma/lib/constants'),
      MockupGrunt = function (requirejsOptions) { this.init(requirejsOptions); },
      BROWSERS = process.env.BROWSERS;

  if (BROWSERS) {
    BROWSERS = BROWSERS.split(',');
  } else {
    BROWSERS = [ 'SL_Chrome', 'SL_Firefox' ];
  }

  MockupGrunt.prototype = {

    sections: {
      requirejs: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.requirejs = this.gruntConfig.requirejs || {};
          this.gruntConfig.requirejs[name] = this.gruntConfig.requirejs[name] || {};
          this.gruntConfig.requirejs[name].options = this.gruntConfig.requirejs[name].options || {};

          this.gruntConfig.requirejs[name].options = {
            name: 'node_modules/requirejs/require.js',
            include: ['mockup-bundles-' + name].concat(bundleOptions.extraInclude || []),
            exclude: bundleOptions.exclude || [],
            insertRequire: ['mockup-bundles-' + name],
            out: bundleOptions.path + name + '.js'
          };
        }
      },
      uglify: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.uglify = this.gruntConfig.uglify || {};
          this.gruntConfig.uglify[name] = this.gruntConfig.uglify[name] || {};
          this.gruntConfig.uglify[name].files = this.gruntConfig.uglify[name].files || {};
          this.gruntConfig.uglify[name].options = {
            mangle: false,
            sourceMap: true,
            sourceMapName: bundleOptions.path + name + '.min.js.map'
          };
          this.gruntConfig.uglify[name].files[bundleOptions.path + name + '.min.js'] = [
            bundleOptions.path + name + '.js'
          ];
        }
      },
      less: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          var gruntConfig = this.gruntConfig;

          gruntConfig.less = gruntConfig.less || {};
          gruntConfig.less[name] = gruntConfig.less[name] || {};
          gruntConfig.less[name].files = gruntConfig.less[name].files || {};
          gruntConfig.less[name].files[bundleOptions.path + name + '.min.css'] = 'less/' + name + '.less';
          gruntConfig.less[name].options = {
            sourceMap: true,
            sourceMapFilename: bundleOptions.path + name + '.min.css.map'
          };

          gruntConfig.watch = gruntConfig.watch || {};
          gruntConfig.watch['less-' + name] = gruntConfig.watch['less-' + name] || {
            files: [ 'less/' + name + '.less' ],
            tasks: [ 'less:' + name ]
          };

          var parser = new(less.Parser)({ syncImport: true, paths: ['less'], filename: name + '.less' }),
              bundleFile = fs.readFileSync('less/' + name + '.less', { encoding: 'utf-8' });

          parser.parse(bundleFile, function() {
            for(var file in parser.imports.files) {
              gruntConfig.watch['less-' + name].files.push(file);
            }
          });
        }
      },
      copy: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.copy = this.gruntConfig.copy || {};
          this.gruntConfig.copy[name] = this.gruntConfig.copy[name] || {};
          this.gruntConfig.copy[name].files = this.gruntConfig.copy[name].files || [];
          this.gruntConfig.copy[name].files = this.gruntConfig.copy[name].files.concat([
            {
              expand: true, cwd: 'bower_components/bootstrap/dist/fonts/', src: 'glyphicons-halflings-regular.*', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-bootstrap-' + src; }
            }, {
              expand: true, cwd: 'bower_components/jqtree/', src: 'jqtree-circle.png', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-jqtree-' + src; }
            }, {
              expand: true, cwd: 'bower_components/select2/', src: 'select2*.png', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-select2-' + src; }
            }, {
              expand: true, cwd: 'bower_components/select2/', src: 'select2*.gif', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-select2-' + src; }
            }, {
              expand: true, cwd: 'bower_components/dropzone/downloads/images/', src: 'spritemap*', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-dropzone-' + src; }
            }
          ]);
        }
      },
      sed: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.sed = this.gruntConfig.sed || {};
          // source maps
          this.gruntConfig.sed[name + '.min.css.map'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'sourceMappingURL=' + bundleOptions.path + name + '.min.css.map',
            replacement: 'sourceMappingURL=' + bundleOptions.url + '.min.css.map',
          };
          this.gruntConfig.sed[name + '.min.js.map'] = {
            path: bundleOptions.path + name + '.min.js',
            pattern: 'sourceMappingURL=' + name + '.min.js.map',
            replacement: 'sourceMappingURL=' + bundleOptions.url + '.min.js.map',
          };
          // pattern resources
          this.gruntConfig.sed[name + '-bootstrap-glyphicons'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(\'../bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular',
            replacement: 'url(\'' + bundleOptions.url + '-bootstrap-glyphicons-halflings-regular'
          };
          this.gruntConfig.sed[name + '-dropzone-spritemap'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\("../images/spritemap',
            replacement: 'url(\'' + bundleOptions.url + '-dropzone-spritemap'
          };
          this.gruntConfig.sed[name + '-select2-images'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(\'select2',
            replacement: 'url(\'' + bundleOptions.url + '-select2-select2'
          };
          this.gruntConfig.sed[name + '-jqtree-circle'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(jqtree-circle.png',
            replacement: 'url(\'' + bundleOptions.url + '-jqtree-jqtree-circle.png\''
          };
        }
      }

    },
    init: function(requirejsOptions) {
      this.requirejsOptions = requirejsOptions;
      this.patterns = [];
      this.bundles = {};
      this.gruntConfig = {};
      this.files = [
        /*
        * include initial framework (mocha and requirejs) with html5
        * shims/shams/polyfills
        */
        'bower_components/selectivizr/selectivizr.js',
        'bower_components/es5-shim/es5-shim.js',
        'bower_components/es5-shim/es5-sham.js',
        'bower_components/console-polyfill/index.js',
        'node_modules/mocha/mocha.js',
        'node_modules/karma-mocha/lib/adapter.js',
        'node_modules/requirejs/require.js',
        'node_modules/karma-requirejs/lib/adapter.js',

        /*
        * include requirejs configuration
        */
        'js/config.js',

        /*
        * include karma requirejs configuration
        */
        'tests/config.js',
      ];

      /*
      * provide (but not include) all scripts defined in requirejs's
      * configuration
      *
      * also at the same time create a list of all patterns to be loaded with
      * docs bundle
      */
      var path;
      for (var key in this.requirejsOptions.paths) {
        path = this.requirejsOptions.paths[key];
        if (path.indexOf('.md') !== path.length - 3) {
          this.files.push({ pattern: path + '.js', included: false });
        }
        if (key.indexOf('mockup-patterns-') === 0) {
          this.patterns.push(key);
        }
      }

      /*
      * provide (but not include) all files in "tests/" and "js/" folder
      * those files will be loaded by requirejs at later points
      *
      * TODO: simplify the pattern to include everything inside js/ and
      * tests/ folders.
      */
      this.files = this.files.concat([
        {pattern: 'tests/**/*', included: false},
        {pattern: 'js/**/*', included: false},
        {pattern: 'patterns/**/*', included: false}
      ]);

    },
    registerBundle: function(name, customGruntConfig, bundleOptions, sections) {

      /*
       * TODO: add description
       */
      extend(true, this.gruntConfig, customGruntConfig || {});

      /*
       * TODO: add description
       */
      bundleOptions = extend(true, {
        path: 'build/',
        url: '++resource++plone.app.' + name,
        insertExtraRequires: []
      }, bundleOptions || {});

      /*
       * TODO: add description
       */
      sections = sections || ['requirejs', 'uglify', 'less', 'copy', 'sed'];

      /*
       * TODO: add description
       */
      for (var i = 0; i < sections.length; i = i + 1) {
        if (this.sections[sections[i]]) {
          this.sections[sections[i]].registerBundle.apply(
            this,
            [ name, customGruntConfig, bundleOptions, sections ]
          );
        }
      }

      /*
       * TODO: add description
       */
      var bundleTasks = [];
      for (var j = 0; j < sections.length; j = j + 1) {
        if (this.gruntConfig[sections[j]][name] !== {} && sections[j] !== 'sed') {
          bundleTasks.push(sections[j] + ':' + name);
        } else if (sections[j] === 'sed') {
          for (var sedSection in this.gruntConfig.sed) {
            if (this.gruntConfig.sed.hasOwnProperty(sedSection) && sedSection.indexOf(name) === 0) {
              bundleTasks.push('sed:' + sedSection);
            }
          }
        }
      }
      this.bundles[name] = bundleTasks;
    },
    initGrunt: function(grunt, customGruntConfig) {
      extend(true, this.gruntConfig, customGruntConfig || {});

      /*
       * TODO: add description
       */
      var bundles = [];
      for (var name in this.bundles) {
        bundles.push('bundle-' + name);
        grunt.registerTask('bundle-' + name, this.bundles[name]);
      }
      grunt.registerTask('test', [ 'jshint', 'karma:test' ]);
      grunt.registerTask('test_once', [ 'jshint', 'karma:testOnce' ]);
      grunt.registerTask('test_dev', [ 'karma:testDev' ]);
      grunt.registerTask('test_ci', [ 'jshint', 'karma:testCI'].concat(bundles));

      /*
       * TODO: add description
       */
      grunt.initConfig(extend(true, {
        jshint: { options: { jshintrc: '.jshintrc' }, all: ['Gruntfile.js', 'js/**/*.js', 'tests/*.js'] },
        karma: {
          options: {
            basePath: './',
            frameworks: [],
            files: this.files,
            preprocessors: { 'js/**/*.js': 'coverage' },
            reporters: ['dots', 'progress', 'coverage', 'spec'],
            coverageReporter: { type : 'lcov', dir : 'coverage/' },
            port: 9876,
            colors: true,
            // logLevel: karmaConstants.LOG_DEBUG,
            logLevel: karmaConstants.LOG_INFO,
            browserNoActivityTimeout: 200000,
            autoWatch: true,
            captureTimeout: 60000,
            plugins: [
              'karma-mocha',
              'karma-coverage',
              'karma-requirejs',
              'karma-sauce-launcher',
              'karma-chrome-launcher',
              'karma-phantomjs-launcher',
              'karma-junit-reporter',
              'karma-spec-reporter'

            ]
          },
          test: {
            browsers: ['PhantomJS']
          },
          testOnce: {
            singleRun: true,
            browsers: ['PhantomJS']
          },
          testDev: {
            browsers: ['Chrome'],
            preprocessors: {},
            reporters: ['dots', 'progress'],
            plugins: [
              'karma-mocha',
              'karma-requirejs',
              'karma-chrome-launcher',
            ]
          },
          testCI: {
            singleRun: true,
            port: 8080,
            recordVideo: true,
            reporters: ['junit', 'coverage', 'saucelabs'],
            junitReporter: { outputFile: 'test-results.xml' },
            sauceLabs: { testName: 'Mockup', startConnect: true },
            browsers: BROWSERS,
            customLaunchers: {
              'SL_Chrome': { base: 'SauceLabs', browserName: 'chrome', platform: 'Windows 8.1', version: '38' },
              'SL_Firefox': { base: 'SauceLabs', browserName: 'firefox', platform: 'Windows 8.1', version: '33' },
              'SL_Opera': { base: 'SauceLabs', browserName: 'opera', platform: 'Windows 8.1', version: '25' },
              'SL_Safari': { base: 'SauceLabs', browserName: 'safari', platform: 'Mac 10.9', version: '7.1' },
              'SL_IE_8': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '8' },
              'SL_IE_9': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '9' },
              'SL_IE_10': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '10' },
              'SL_IE_11': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' },
              'SL_IPhone': { base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.9', version: '7.1' },
              'SL_IPad': { base: 'SauceLabs', browserName: 'ipad', platform: 'OS X 10.9', version: '7.1' },
              'SL_Android': { base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.3' }
            }
          }
        },
        requirejs: {
          options: this.requirejsOptions
        },
        less: {
          options: {
            compress: true,
            cleancss: false,
            ieCompat: true,
            paths: ['less']
          }
        },
        sed: {
          'bootstrap': {
            path: 'node_modules/lcov-result-merger/index.js',
            pattern: 'throw new Error\\(\'Unknown Prefix ',
            replacement: '//throw// new Error(\'Unknown Prefix '
          }
        }
      }, this.gruntConfig));

      /*
       * TODO: add description
       */
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.loadNpmTasks('grunt-contrib-jshint');
      grunt.loadNpmTasks('grunt-contrib-less');
      grunt.loadNpmTasks('grunt-contrib-requirejs');
      grunt.loadNpmTasks('grunt-contrib-uglify');
      grunt.loadNpmTasks('grunt-contrib-watch');
      grunt.loadNpmTasks('grunt-karma');
      grunt.loadNpmTasks('grunt-sed');

    }
  };

  module.exports = MockupGrunt;

})();
<commit_msg>Add a new test runner which starts a webserver.<commit_after>/* global module:true, process:true */

(function() {
  'use strict';

  var fs = require('fs'),
      less = require('less'),
      extend = require('extend'),
      path = require('path'),
      appDir = process.cwd(),
      karmaConstants = require(appDir + '/node_modules/karma/lib/constants'),
      MockupGrunt = function (requirejsOptions) { this.init(requirejsOptions); },
      BROWSERS = process.env.BROWSERS;

  if (BROWSERS) {
    BROWSERS = BROWSERS.split(',');
  } else {
    BROWSERS = [ 'SL_Chrome', 'SL_Firefox' ];
  }

  MockupGrunt.prototype = {

    sections: {
      requirejs: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.requirejs = this.gruntConfig.requirejs || {};
          this.gruntConfig.requirejs[name] = this.gruntConfig.requirejs[name] || {};
          this.gruntConfig.requirejs[name].options = this.gruntConfig.requirejs[name].options || {};

          this.gruntConfig.requirejs[name].options = {
            name: 'node_modules/requirejs/require.js',
            include: ['mockup-bundles-' + name].concat(bundleOptions.extraInclude || []),
            exclude: bundleOptions.exclude || [],
            insertRequire: ['mockup-bundles-' + name],
            out: bundleOptions.path + name + '.js'
          };
        }
      },
      uglify: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.uglify = this.gruntConfig.uglify || {};
          this.gruntConfig.uglify[name] = this.gruntConfig.uglify[name] || {};
          this.gruntConfig.uglify[name].files = this.gruntConfig.uglify[name].files || {};
          this.gruntConfig.uglify[name].options = {
            mangle: false,
            sourceMap: true,
            sourceMapName: bundleOptions.path + name + '.min.js.map'
          };
          this.gruntConfig.uglify[name].files[bundleOptions.path + name + '.min.js'] = [
            bundleOptions.path + name + '.js'
          ];
        }
      },
      less: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          var gruntConfig = this.gruntConfig;

          gruntConfig.less = gruntConfig.less || {};
          gruntConfig.less[name] = gruntConfig.less[name] || {};
          gruntConfig.less[name].files = gruntConfig.less[name].files || {};
          gruntConfig.less[name].files[bundleOptions.path + name + '.min.css'] = 'less/' + name + '.less';
          gruntConfig.less[name].options = {
            sourceMap: true,
            sourceMapFilename: bundleOptions.path + name + '.min.css.map'
          };

          gruntConfig.watch = gruntConfig.watch || {};
          gruntConfig.watch['less-' + name] = gruntConfig.watch['less-' + name] || {
            files: [ 'less/' + name + '.less' ],
            tasks: [ 'less:' + name ]
          };

          var parser = new(less.Parser)({ syncImport: true, paths: ['less'], filename: name + '.less' }),
              bundleFile = fs.readFileSync('less/' + name + '.less', { encoding: 'utf-8' });

          parser.parse(bundleFile, function() {
            for(var file in parser.imports.files) {
              gruntConfig.watch['less-' + name].files.push(file);
            }
          });
        }
      },
      copy: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.copy = this.gruntConfig.copy || {};
          this.gruntConfig.copy[name] = this.gruntConfig.copy[name] || {};
          this.gruntConfig.copy[name].files = this.gruntConfig.copy[name].files || [];
          this.gruntConfig.copy[name].files = this.gruntConfig.copy[name].files.concat([
            {
              expand: true, cwd: 'bower_components/bootstrap/dist/fonts/', src: 'glyphicons-halflings-regular.*', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-bootstrap-' + src; }
            }, {
              expand: true, cwd: 'bower_components/jqtree/', src: 'jqtree-circle.png', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-jqtree-' + src; }
            }, {
              expand: true, cwd: 'bower_components/select2/', src: 'select2*.png', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-select2-' + src; }
            }, {
              expand: true, cwd: 'bower_components/select2/', src: 'select2*.gif', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-select2-' + src; }
            }, {
              expand: true, cwd: 'bower_components/dropzone/downloads/images/', src: 'spritemap*', dest: bundleOptions.path,
              rename: function(dest, src) { return dest + name + '-dropzone-' + src; }
            }
          ]);
        }
      },
      sed: {
        registerBundle: function(name, customGruntConfig, bundleOptions, sections) {
          this.gruntConfig.sed = this.gruntConfig.sed || {};
          // source maps
          this.gruntConfig.sed[name + '.min.css.map'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'sourceMappingURL=' + bundleOptions.path + name + '.min.css.map',
            replacement: 'sourceMappingURL=' + bundleOptions.url + '.min.css.map',
          };
          this.gruntConfig.sed[name + '.min.js.map'] = {
            path: bundleOptions.path + name + '.min.js',
            pattern: 'sourceMappingURL=' + name + '.min.js.map',
            replacement: 'sourceMappingURL=' + bundleOptions.url + '.min.js.map',
          };
          // pattern resources
          this.gruntConfig.sed[name + '-bootstrap-glyphicons'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(\'../bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular',
            replacement: 'url(\'' + bundleOptions.url + '-bootstrap-glyphicons-halflings-regular'
          };
          this.gruntConfig.sed[name + '-dropzone-spritemap'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\("../images/spritemap',
            replacement: 'url(\'' + bundleOptions.url + '-dropzone-spritemap'
          };
          this.gruntConfig.sed[name + '-select2-images'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(\'select2',
            replacement: 'url(\'' + bundleOptions.url + '-select2-select2'
          };
          this.gruntConfig.sed[name + '-jqtree-circle'] = {
            path: bundleOptions.path + name + '.min.css',
            pattern: 'url\\(jqtree-circle.png',
            replacement: 'url(\'' + bundleOptions.url + '-jqtree-jqtree-circle.png\''
          };
        }
      }

    },
    init: function(requirejsOptions) {
      this.requirejsOptions = requirejsOptions;
      this.patterns = [];
      this.bundles = {};
      this.gruntConfig = {};
      this.files = [
        /*
        * include initial framework (mocha and requirejs) with html5
        * shims/shams/polyfills
        */
        'bower_components/selectivizr/selectivizr.js',
        'bower_components/es5-shim/es5-shim.js',
        'bower_components/es5-shim/es5-sham.js',
        'bower_components/console-polyfill/index.js',
        'node_modules/mocha/mocha.js',
        'node_modules/karma-mocha/lib/adapter.js',
        'node_modules/requirejs/require.js',
        'node_modules/karma-requirejs/lib/adapter.js',

        /*
        * include requirejs configuration
        */
        'js/config.js',

        /*
        * include karma requirejs configuration
        */
        'tests/config.js',
      ];

      /*
      * provide (but not include) all scripts defined in requirejs's
      * configuration
      *
      * also at the same time create a list of all patterns to be loaded with
      * docs bundle
      */
      var path;
      for (var key in this.requirejsOptions.paths) {
        path = this.requirejsOptions.paths[key];
        if (path.indexOf('.md') !== path.length - 3) {
          this.files.push({ pattern: path + '.js', included: false });
        }
        if (key.indexOf('mockup-patterns-') === 0) {
          this.patterns.push(key);
        }
      }

      /*
      * provide (but not include) all files in "tests/" and "js/" folder
      * those files will be loaded by requirejs at later points
      *
      * TODO: simplify the pattern to include everything inside js/ and
      * tests/ folders.
      */
      this.files = this.files.concat([
        {pattern: 'tests/**/*', included: false},
        {pattern: 'js/**/*', included: false},
        {pattern: 'patterns/**/*', included: false}
      ]);

    },
    registerBundle: function(name, customGruntConfig, bundleOptions, sections) {

      /*
       * TODO: add description
       */
      extend(true, this.gruntConfig, customGruntConfig || {});

      /*
       * TODO: add description
       */
      bundleOptions = extend(true, {
        path: 'build/',
        url: '++resource++plone.app.' + name,
        insertExtraRequires: []
      }, bundleOptions || {});

      /*
       * TODO: add description
       */
      sections = sections || ['requirejs', 'uglify', 'less', 'copy', 'sed'];

      /*
       * TODO: add description
       */
      for (var i = 0; i < sections.length; i = i + 1) {
        if (this.sections[sections[i]]) {
          this.sections[sections[i]].registerBundle.apply(
            this,
            [ name, customGruntConfig, bundleOptions, sections ]
          );
        }
      }

      /*
       * TODO: add description
       */
      var bundleTasks = [];
      for (var j = 0; j < sections.length; j = j + 1) {
        if (this.gruntConfig[sections[j]][name] !== {} && sections[j] !== 'sed') {
          bundleTasks.push(sections[j] + ':' + name);
        } else if (sections[j] === 'sed') {
          for (var sedSection in this.gruntConfig.sed) {
            if (this.gruntConfig.sed.hasOwnProperty(sedSection) && sedSection.indexOf(name) === 0) {
              bundleTasks.push('sed:' + sedSection);
            }
          }
        }
      }
      this.bundles[name] = bundleTasks;
    },
    initGrunt: function(grunt, customGruntConfig) {
      extend(true, this.gruntConfig, customGruntConfig || {});

      /*
       * Register different test runners
       */
      var bundles = [];
      for (var name in this.bundles) {
        bundles.push('bundle-' + name);
        grunt.registerTask('bundle-' + name, this.bundles[name]);
      }
      grunt.registerTask('test', [ 'jshint', 'karma:test' ]);
      grunt.registerTask('test_once', [ 'jshint', 'karma:testOnce' ]);
      grunt.registerTask('test_dev', [ 'karma:testDev' ]);
      grunt.registerTask('test_serve', [ 'karma:testServe' ]);
      grunt.registerTask('test_ci', [ 'jshint', 'karma:testCI'].concat(bundles));

      /*
       * TODO: add description
       */
      grunt.initConfig(extend(true, {
        jshint: { options: { jshintrc: '.jshintrc' }, all: ['Gruntfile.js', 'js/**/*.js', 'tests/*.js'] },
        karma: {
          options: {
            basePath: './',
            frameworks: [],
            files: this.files,
            preprocessors: { 'js/**/*.js': 'coverage' },
            reporters: ['dots', 'progress', 'coverage', 'spec'],
            coverageReporter: { type : 'lcov', dir : 'coverage/' },
            port: 9876,
            colors: true,
            // logLevel: karmaConstants.LOG_DEBUG,
            logLevel: karmaConstants.LOG_INFO,
            browserNoActivityTimeout: 200000,
            autoWatch: true,
            captureTimeout: 60000,
            plugins: [
              'karma-mocha',
              'karma-coverage',
              'karma-requirejs',
              'karma-sauce-launcher',
              'karma-chrome-launcher',
              'karma-phantomjs-launcher',
              'karma-junit-reporter',
              'karma-spec-reporter'

            ]
          },
          test: {
            browsers: ['PhantomJS']
          },
          testOnce: {
            singleRun: true,
            browsers: ['PhantomJS']
          },
          testDev: {
            browsers: ['Chrome'],
            preprocessors: {},
            reporters: ['dots', 'progress'],
            plugins: [
              'karma-mocha',
              'karma-requirejs',
              'karma-chrome-launcher'
            ]
          },
          testServe: {
            preprocessors: {},
            reporters: ['dots', 'progress'],
            plugins: [
              'karma-mocha',
              'karma-requirejs'
            ]
          },
          testCI: {
            singleRun: true,
            port: 8080,
            recordVideo: true,
            reporters: ['junit', 'coverage', 'saucelabs'],
            junitReporter: { outputFile: 'test-results.xml' },
            sauceLabs: { testName: 'Mockup', startConnect: true },
            browsers: BROWSERS,
            customLaunchers: {
              'SL_Chrome': { base: 'SauceLabs', browserName: 'chrome', platform: 'Windows 8.1', version: '38' },
              'SL_Firefox': { base: 'SauceLabs', browserName: 'firefox', platform: 'Windows 8.1', version: '33' },
              'SL_Opera': { base: 'SauceLabs', browserName: 'opera', platform: 'Windows 8.1', version: '25' },
              'SL_Safari': { base: 'SauceLabs', browserName: 'safari', platform: 'Mac 10.9', version: '7.1' },
              'SL_IE_8': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '8' },
              'SL_IE_9': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '9' },
              'SL_IE_10': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 7', version: '10' },
              'SL_IE_11': { base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' },
              'SL_IPhone': { base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.9', version: '7.1' },
              'SL_IPad': { base: 'SauceLabs', browserName: 'ipad', platform: 'OS X 10.9', version: '7.1' },
              'SL_Android': { base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.3' }
            }
          }
        },
        requirejs: {
          options: this.requirejsOptions
        },
        less: {
          options: {
            compress: true,
            cleancss: false,
            ieCompat: true,
            paths: ['less']
          }
        },
        sed: {
          'bootstrap': {
            path: 'node_modules/lcov-result-merger/index.js',
            pattern: 'throw new Error\\(\'Unknown Prefix ',
            replacement: '//throw// new Error(\'Unknown Prefix '
          }
        }
      }, this.gruntConfig));

      /*
       * TODO: add description
       */
      grunt.loadNpmTasks('grunt-contrib-copy');
      grunt.loadNpmTasks('grunt-contrib-jshint');
      grunt.loadNpmTasks('grunt-contrib-less');
      grunt.loadNpmTasks('grunt-contrib-requirejs');
      grunt.loadNpmTasks('grunt-contrib-uglify');
      grunt.loadNpmTasks('grunt-contrib-watch');
      grunt.loadNpmTasks('grunt-karma');
      grunt.loadNpmTasks('grunt-sed');
    }
  };
  module.exports = MockupGrunt;
})();
<|endoftext|>


<commit_before>/**
 * Performs treeshake on JS files
 */
exports.run = function (grunt, wrap, filename, data) {

    var buildPathJS = data.build + '/' + filename + '.js';

    if (data.scripts) {

        var files = {};
        files[buildPathJS] = [
            'node_modules/hbjs/src/**/**.js',
            '.tmp_templates/*.js'
        ];

        var treeshake = {
            options: {
                wrap: wrap,
                minify: true,
                match: function (searchText) {
                    var camelCase = function (str) {
                        return str.replace(/-([a-z])/g, function (g) {
                            return g[1].toUpperCase();
                        });
                    };

                    var results = searchText.match(/(\w+-)+\w+/gim);
                    //console.log('--RESULTS--', results);

                    for (var e in results) {
                        //if (results[e].indexOf('hb-') === 0) {
                        //    results[e] = 'hbd.' + camelCase(results[e].replace('hb-', ''));
                        //} else {
                            results[e] = camelCase(results[e]);
                        //}
                    }
                    //console.log('----', results);
                    return results;
                },
                ignore: [],
                inspect: ['.tmp_templates/*.js'],
                export: [],
                exclude: [],
                import: [],
                report: 'verbose',
                log: 'logs/' + filename + '.log'
            },
            files: files
        }

        var scripts = data.scripts;
        var options = treeshake.options;
        if (scripts.inspect) {
            options.inspect = options.inspect.concat(scripts.inspect);
        }
        if (scripts.ignore) {
            options.ignore = options.ignore.concat(scripts.ignore);
        }
        if (scripts.import) {
            options.import = options.import.concat(scripts.import);
        }
        if (scripts.exclude) {
            options.exclude = options.exclude.concat(scripts.exclude);
        }
        if (scripts.export) {
            options.export = options.export.concat(scripts.export);
        }
        if (scripts.src) {
            files[buildPathJS] = files[buildPathJS].concat(scripts.src);
        }

        var config = grunt.config.get('treeshake') || {};
        config['hummingbird_treeshake'] = treeshake;
        grunt.config.set('treeshake', config);
        grunt.task.run('treeshake:hummingbird_treeshake');
    }
};<commit_msg>removing comments.<commit_after>/**
 * Performs treeshake on JS files
 */
exports.run = function (grunt, wrap, filename, data) {

    var buildPathJS = data.build + '/' + filename + '.js';

    if (data.scripts) {

        var files = {};
        files[buildPathJS] = [
            'node_modules/hbjs/src/**/**.js',
            '.tmp_templates/*.js'
        ];

        var treeshake = {
            options: {
                wrap: wrap,
                minify: true,
                match: function (searchText) {
                    var camelCase = function (str) {
                        return str.replace(/-([a-z])/g, function (g) {
                            return g[1].toUpperCase();
                        });
                    };

                    var results = searchText.match(/(\w+-)+\w+/gim);
                    //console.log('--RESULTS--', results);

                    for (var e in results) {
                        results[e] = camelCase(results[e]);
                    }
                    //console.log('----', results);
                    return results;
                },
                ignore: [],
                inspect: ['.tmp_templates/*.js'],
                export: [],
                exclude: [],
                import: [],
                report: 'verbose',
                log: 'logs/' + filename + '.log'
            },
            files: files
        }

        var scripts = data.scripts;
        var options = treeshake.options;
        if (scripts.inspect) {
            options.inspect = options.inspect.concat(scripts.inspect);
        }
        if (scripts.ignore) {
            options.ignore = options.ignore.concat(scripts.ignore);
        }
        if (scripts.import) {
            options.import = options.import.concat(scripts.import);
        }
        if (scripts.exclude) {
            options.exclude = options.exclude.concat(scripts.exclude);
        }
        if (scripts.export) {
            options.export = options.export.concat(scripts.export);
        }
        if (scripts.src) {
            files[buildPathJS] = files[buildPathJS].concat(scripts.src);
        }

        var config = grunt.config.get('treeshake') || {};
        config['hummingbird_treeshake'] = treeshake;
        grunt.config.set('treeshake', config);
        grunt.task.run('treeshake:hummingbird_treeshake');
    }
};<|endoftext|>


<commit_before>let express = require('express')
let router = express.Router()
let User = require('../../models/user')
let CurrentlyReading = require('../../models/currentlyReading')
const requireAuth = require('passport').authenticate('jwt', {session: false})

/**
 * @swagger
 * definition:
 *  CurrentlyReading:
 *    properties:
 *      book:
 *        type: "string"
 *      chapterTrail:
 *        type: "array"
 *        items:
 *          type: "string"
 */

/**
 * @swagger
 * definition:
 *  User:
 *    properties:
 *      fullName:
 *        type: "string"
 *      email:
 *        type: "string"
 *      password:
 *        type: "string"
 *      created:
 *        type: "Date"
 *      currentlyReading:
 *        type: "array"
 *        items:
 *          type: "CurrentlyReading"
 *      resetPasswordToken:
 *        type: "string"
 *      resetPasswordExpires:
 *        type: "Date"
 */

/**
 * @swagger
 * /users/currentlyreading/{bookId}:
 *   get:
 *     tags:
 *       - currentlyreading user
 *     description:
 *       - Returns the currently-reading object from the logged in user
 *         with the specified bookid
 *     produces:
 *       - application/json
 *     parameters:
 *      -
 *        name: "bookId"
 *        in: "path"
 *        description: "Book Id"
 *        required: true
 *        type: "string"
 *     responses:
 *      200:
 *        description: A currently-reading object
 *        schema:
 *          $ref: '#/definitions/CurrentlyReading'
 *
 */
router.get('/currentlyreading/:bookId', requireAuth, (req, res) => {
  User.findOne(
    {
      '_id': req.user._id, 'currentlyReading.book': req.params.bookId,
    },
    {
      currentlyReading: {$elemMatch: {book: req.params.bookId}},
    },
    (err, user) => {
      if (err) {
        res.sendStatus(500)
      } else {
        if (user && user.currentlyReading.length) {
          res.send(user.currentlyReading[0])
        } else {
          res.sendStatus(204)
        }
      }
    })
})

/**
 * @swagger
 * /users/currentlyreading:
 *   get:
 *     tags:
 *       - currentlyreading
 *     description:
 *       - Returns all the currently-reading objects from the logged in user
 *     produces:
 *       - application/json
 *     responses:
 *      200:
 *        description: An array of currently-reading objects
 *        schema:
 *          $ref: '#/definitions/CurrentlyReading'
 *
 */
router.get('/currentlyreading', requireAuth, (req, res) => {
  User.findOne(
    {
      _id: req.user._id,
    },
    (err, user) => {
      if (err) {
        res.status(500).send({})
      } else {
        if (user && user.currentlyReading) {
          res.send(user.currentlyReading)
        } else {
          res.sendStatus(204)
        }
      }
    })
})

/**
 * @swagger
 * /users/{id}:
 *   get:
 *     tags:
 *       - user
 *     description:
 *       - Returns the user with the specified ID
 *     produces:
 *       - application/json
 *     parameters:
 *       -
 *        name: "id"
 *        in: "path"
 *        description: "User Id"
 *        required: true
 *        type: "string"
 *     responses:
 *      200:
 *        description: A user object
 *        schema:
 *          $ref: '#/definitions/User'
 *
 */
router.get('/:id', (req, res) => {
  User.findOne(
    {
      _id: req.params['id'],
    },
    '-currentlyReading',
    (err, user) => {
      if (err) {
        res.status(500).send({})
      } else {
        res.send(user)
      }
    })
})

/**
 * @swagger
 * /currentlyreading:
 *   put:
 *    tags:
 *      - CurrentlyReading
 *    description:
 *      - "Receives a currently reading object and adds
 *         it to the currently reading array of the user logged in. If it already
 *         exists it gets updated"
 *    produces:
 *      - application/json
 *    responses:
 *      200:
 *        description: "20 when successfully updated"
 *      500:
 *        description: "500 when there was an error"
 */
router.put('/currentlyreading', requireAuth, (req, res) => {
  let currentlyReading = new CurrentlyReading(req.body)
  User.findOneAndUpdate(
    {
      '_id': req.user._id,
      'currentlyReading.book': currentlyReading.book,
    },
    {
      '$set': {
        'currentlyReading.$': currentlyReading,
      },
    },
    {
      upsert: true,
    },
    (err, user) => {
      if (err) {
        User.findOne({_id: req.user._id}, (err, user) => {
          if (err) {
            res.sendStatus(500)
          } else {
            user.currentlyReading.push(currentlyReading)
            user.save()
            res.sendStatus(200)
          }
        })
      } else {
        res.sendStatus(200)
      }
    })
})

module.exports = router
<commit_msg>Updated swagger schema to not include currenlyReading in User<commit_after>let express = require('express')
let router = express.Router()
let User = require('../../models/user')
let CurrentlyReading = require('../../models/currentlyReading')
const requireAuth = require('passport').authenticate('jwt', {session: false})

/**
 * @swagger
 * definition:
 *  CurrentlyReading:
 *    properties:
 *      book:
 *        type: "string"
 *      chapterTrail:
 *        type: "array"
 *        items:
 *          type: "string"
 */

/**
 * @swagger
 * definition:
 *  User:
 *    properties:
 *      fullName:
 *        type: "string"
 *      email:
 *        type: "string"
 *      password:
 *        type: "string"
 *      created:
 *        type: "Date"
 *      resetPasswordToken:
 *        type: "string"
 *      resetPasswordExpires:
 *        type: "Date"
 */

/**
 * @swagger
 * /users/currentlyreading/{bookId}:
 *   get:
 *     tags:
 *       - currentlyreading user
 *     description:
 *       - Returns the currently-reading object from the logged in user
 *         with the specified bookid
 *     produces:
 *       - application/json
 *     parameters:
 *      -
 *        name: "bookId"
 *        in: "path"
 *        description: "Book Id"
 *        required: true
 *        type: "string"
 *     responses:
 *      200:
 *        description: A currently-reading object
 *        schema:
 *          $ref: '#/definitions/CurrentlyReading'
 *
 */
router.get('/currentlyreading/:bookId', requireAuth, (req, res) => {
  User.findOne(
    {
      '_id': req.user._id, 'currentlyReading.book': req.params.bookId,
    },
    {
      currentlyReading: {$elemMatch: {book: req.params.bookId}},
    },
    (err, user) => {
      if (err) {
        res.sendStatus(500)
      } else {
        if (user && user.currentlyReading.length) {
          res.send(user.currentlyReading[0])
        } else {
          res.sendStatus(204)
        }
      }
    })
})

/**
 * @swagger
 * /users/currentlyreading:
 *   get:
 *     tags:
 *       - currentlyreading
 *     description:
 *       - Returns all the currently-reading objects from the logged in user
 *     produces:
 *       - application/json
 *     responses:
 *      200:
 *        description: An array of currently-reading objects
 *        schema:
 *          $ref: '#/definitions/CurrentlyReading'
 *
 */
router.get('/currentlyreading', requireAuth, (req, res) => {
  User.findOne(
    {
      _id: req.user._id,
    },
    (err, user) => {
      if (err) {
        res.status(500).send({})
      } else {
        if (user && user.currentlyReading) {
          res.send(user.currentlyReading)
        } else {
          res.sendStatus(204)
        }
      }
    })
})

/**
 * @swagger
 * /users/{id}:
 *   get:
 *     tags:
 *       - user
 *     description:
 *       - Returns the user with the specified ID
 *     produces:
 *       - application/json
 *     parameters:
 *       -
 *        name: "id"
 *        in: "path"
 *        description: "User Id"
 *        required: true
 *        type: "string"
 *     responses:
 *      200:
 *        description: A user object
 *        schema:
 *          $ref: '#/definitions/User'
 *
 */
router.get('/:id', (req, res) => {
  User.findOne(
    {
      _id: req.params['id'],
    },
    '-currentlyReading',
    (err, user) => {
      if (err) {
        res.status(500).send({})
      } else {
        res.send(user)
      }
    })
})

/**
 * @swagger
 * /currentlyreading:
 *   put:
 *    tags:
 *      - CurrentlyReading
 *    description:
 *      - "Receives a currently reading object and adds
 *         it to the currently reading array of the user logged in. If it already
 *         exists it gets updated"
 *    produces:
 *      - application/json
 *    responses:
 *      200:
 *        description: "20 when successfully updated"
 *      500:
 *        description: "500 when there was an error"
 */
router.put('/currentlyreading', requireAuth, (req, res) => {
  let currentlyReading = new CurrentlyReading(req.body)
  User.findOneAndUpdate(
    {
      '_id': req.user._id,
      'currentlyReading.book': currentlyReading.book,
    },
    {
      '$set': {
        'currentlyReading.$': currentlyReading,
      },
    },
    {
      upsert: true,
    },
    (err, user) => {
      if (err) {
        User.findOne({_id: req.user._id}, (err, user) => {
          if (err) {
            res.sendStatus(500)
          } else {
            user.currentlyReading.push(currentlyReading)
            user.save()
            res.sendStatus(200)
          }
        })
      } else {
        res.sendStatus(200)
      }
    })
})

module.exports = router
<|endoftext|>


<commit_before>import React, { Component } from 'react'

export default class TextEditor extends Component {
  constructor(props){
    super(props);
    this.keepInputIme = false;
  }

  onKeyDown(e){
    // keyDown時のkeyCode
    // Firefox[0],IE,Chrome,Safari[229]の時はIME入力中
    if (e.keyCode === 0 || e.keyCode === 229) {
      this.keepInputIme = true;
    }
  }

  onKeyUp(e){
    if (!this.keepInputIme && e.key === "Enter") {
      this.props.onPressEnterKey(e);
    }
    this.keepInputIme = false;
  }

  onChange(e){
    this.props.onChange(e.target.value);
  }

  render() {
    if (this.props.multiline) {
      return (
        <textarea
          name={this.props.name}
          rows={this.props.rows}
          cols={this.props.cols}
          placeholder={this.props.placeholder}
          onChange={(e) => this.onChange(e)}
          onKeyDown={(e) => this.onKeyDown(e)}
          onKeyUp={(e) => this.onKeyUp(e)}
        >
          {this.props.value}
        </textarea>
      )
    } else {
      return (
        <input
          type="text"
          name={this.props.name}
          value={this.props.value}
          placeholder={this.props.placeholder}
          onChange={(e) => this.onChange(e)}
          onKeyDown={(e) => this.onKeyDown(e)}
          onKeyUp={(e) => this.onKeyUp(e)}
        />
      )
    }
  }
}<commit_msg>テキストエリアもテキストフィールドと同じようにvalue属性に値を指定する必要がある<commit_after>import React, { Component } from 'react'

export default class TextEditor extends Component {
  constructor(props){
    super(props);
    this.keepInputIme = false;
  }

  onKeyDown(e){
    // keyDown時のkeyCode
    // Firefox[0],IE,Chrome,Safari[229]の時はIME入力中
    if (e.keyCode === 0 || e.keyCode === 229) {
      this.keepInputIme = true;
    }
  }

  onKeyUp(e){
    if (!this.keepInputIme && e.key === "Enter") {
      this.props.onPressEnterKey(e);
    }
    this.keepInputIme = false;
  }

  onChange(e){
    this.props.onChange(e.target.value);
  }

  render() {
    if (this.props.multiline) {
      return (
        <textarea
          name={this.props.name}
          value={this.props.value}
          rows={this.props.rows}
          cols={this.props.cols}
          placeholder={this.props.placeholder}
          onChange={(e) => this.onChange(e)}
          onKeyDown={(e) => this.onKeyDown(e)}
          onKeyUp={(e) => this.onKeyUp(e)}
        />
      )
    } else {
      return (
        <input
          type="text"
          name={this.props.name}
          placeholder={this.props.placeholder}
          onChange={(e) => this.onChange(e)}
          onKeyDown={(e) => this.onKeyDown(e)}
          onKeyUp={(e) => this.onKeyUp(e)}
        />
      )
    }
  }
}<|endoftext|>


<commit_before>router('/test', function()
{
    document.getElementById('targetText').innerHTML +="
Welcome to the test page!
";
    console.log('This is a functional test call!');
});

router = function (uri, callback)
{
    var regex = new RegExp(uri + '$');
    var match = regex.exec(location.pathname);

    if (match)
    {
        document.addEventListener('DOMContentLoaded', function()
        {
            callback.apply(callback, match.splice(1));
        });
    }
};<commit_msg>routes are ALIVE!<commit_after>route('/', function ()
{
    alert('welcome!');
});

route('/test', 'template1', function ()
{
    document.getElementById('targetText').innerHTML +="
Welcome to the test page!
";
    console.log('This is a functional test call!');
});

// https://gist.github.com/joakimbeng/7918297<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp'),
    changed = require('gulp-changed'),
    csso = require('gulp-csso'),
    autoprefixer = require('gulp-autoprefixer'),
    browserify = require('browserify'),
    watchify = require('watchify'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    reactify = require('reactify'),
    del = require('del'),
    notify = require('gulp-notify'),
    browserSync = require('browser-sync'),
    reload = browserSync.reload,
    p = {
      jsx: ['./lib/scripts/app.jsx'],
      css: ['lib/styles/main.css', 'lib/styles/bootstrap.min.css'],
      bundle: 'app.js',
      distJs: 'dist/js',
      distCss: 'dist/css'
    };

gulp.task('clean', function(cb) {
  del(['dist'], cb);
});

gulp.task('browserSync', function() {
  browserSync({
    server: {
      baseDir: './'
    }
  })
});

gulp.task('watchify', function() {
  var bundler = watchify(browserify(p.jsx, watchify.args));

  function rebundle() {
    return bundler
      .bundle()
      .on('error', notify.onError())
      .pipe(source(p.bundle))
      .pipe(gulp.dest(p.distJs))
      .pipe(reload({stream: true}));
  }

  bundler.transform(reactify)
  .on('update', rebundle);
  return rebundle();
});

gulp.task('browserify', function() {
  browserify(p.jsx)
    .transform(reactify)
    .bundle()
    .pipe(source(p.bundle))
    .pipe(buffer())
    .pipe(gulp.dest(p.distJs));
});

gulp.task('styles', function() {
  gulp.watch('lib/styles/**/*.css', function () {
    return gulp.src(p.css)
      .pipe(changed(p.distCss))
      .pipe(autoprefixer('last 1 version'))
      .pipe(csso())
      .pipe(gulp.dest(p.distCss))
      .pipe(reload({stream: true}));
    });
});

gulp.task('watchTask', function() {
  gulp.watch(p.scss, ['styles']);
});

gulp.task('watch', ['clean'], function() {
  gulp.start(['browserSync', 'watchify']);
});

gulp.task('build', ['clean'], function() {
  process.env.NODE_ENV = 'production';
  gulp.start(['browserify', 'styles']);
});

gulp.task('default', ['build', 'watch']);
<commit_msg>fix tasks for styles<commit_after>'use strict';

var gulp = require('gulp'),
    changed = require('gulp-changed'),
    csso = require('gulp-csso'),
    autoprefixer = require('gulp-autoprefixer'),
    browserify = require('browserify'),
    watchify = require('watchify'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    reactify = require('reactify'),
    del = require('del'),
    notify = require('gulp-notify'),
    browserSync = require('browser-sync'),
    reload = browserSync.reload,
    p = {
      jsx: ['./lib/scripts/app.jsx'],
      css: ['lib/styles/main.css', 'lib/styles/bootstrap.min.css'],
      bundle: 'app.js',
      distJs: 'dist/js',
      distCss: 'dist/css'
    };

gulp.task('clean', function(cb) {
  del(['dist'], cb);
});

gulp.task('browserSync', function() {
  browserSync({
    server: {
      baseDir: './'
    }
  })
});

gulp.task('watchify', function() {
  var bundler = watchify(browserify(p.jsx, watchify.args));

  function rebundle() {
    return bundler
      .bundle()
      .on('error', notify.onError())
      .pipe(source(p.bundle))
      .pipe(gulp.dest(p.distJs))
      .pipe(reload({stream: true}));
  }

  bundler.transform(reactify)
  .on('update', rebundle);
  return rebundle();
});

gulp.task('browserify', function() {
  browserify(p.jsx)
    .transform(reactify)
    .bundle()
    .pipe(source(p.bundle))
    .pipe(buffer())
    .pipe(gulp.dest(p.distJs));
});

gulp.task('styles', function() {
  return gulp.src(p.css)
    .pipe(changed(p.distCss))
    .pipe(autoprefixer('last 1 version'))
    .pipe(csso())
    .pipe(gulp.dest(p.distCss))
    .pipe(reload({stream: true}));
});

gulp.task('watchTask', function() {
  gulp.watch(p.css, ['styles']);
});

gulp.task('watch', ['clean'], function() {
  gulp.start(['browserSync', 'watchTask', 'watchify', 'styles']);
});

gulp.task('build', ['clean'], function() {
  process.env.NODE_ENV = 'production';
  gulp.start(['browserify', 'styles']);
});

gulp.task('default', ['build', 'watch']);
<|endoftext|>


<commit_before>/**
 * Common interface for tab menu access.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2015 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLab/WCF/Ui/TabMenu
 */
define(['Dictionary', 'Dom/ChangeListener', 'Dom/Util', './TabMenu/Simple'], function(Dictionary, DomChangeListener, DomUtil, SimpleTabMenu) {
	"use strict";

	var _tabMenus = new Dictionary();

	/**
	 * @exports	WoltLab/WCF/Ui/TabMenu
	 */
	var UiTabMenu = {
		/**
		 * Sets up tab menus and binds listeners.
		 */
		setup: function() {
			this._init();
			this._selectErroneousTabs();

			DomChangeListener.add('WoltLab/WCF/Ui/TabMenu', this._init.bind(this));
		},

		/**
		 * Initializes available tab menus.
		 */
		_init: function() {
			var tabMenus = document.querySelectorAll('.tabMenuContainer:not(.staticTabMenuContainer)');
			for (var i = 0, length = tabMenus.length; i < length; i++) {
				var container = tabMenus[i];
				var containerId = DomUtil.identify(container);

				if (_tabMenus.has(containerId)) {
					continue;
				}

				var tabMenu = new SimpleTabMenu(container), returnValue;
				if (tabMenu.validate()) {
					returnValue = tabMenu.init();

					_tabMenus.set(containerId, tabMenu);

					if (returnValue instanceof Element) {
						tabMenu = this.getTabMenu(returnValue.parentNode.id);
						tabMenu.select(returnValue.id, null, true);
					}
				}
			}
		},

		/**
		 * Selects the first tab containing an element with class `formError`.
		 */
		_selectErroneousTabs: function() {
			_tabMenus.forEach(function(tabMenu) {
				var foundError = false;
				tabMenu.getContainers().forEach(function(container) {
					if (!foundError && container.getElementsByClassName('formError').length) {
						foundError = true;

						tabMenu.select(container.id);
					}
				});
			});
		},

		/**
		 * Returns a SimpleTabMenu instance for given container id.
		 *
		 * @param	{string}	containerId	tab menu container id
		 * @return	{(SimpleTabMenu|undefined)}	tab menu object
		 */
		getTabMenu: function(containerId) {
			return _tabMenus.get(containerId);
		}
	};

	return UiTabMenu;
});
<commit_msg>Some minor optimizations<commit_after>/**
 * Common interface for tab menu access.
 *
 * @author	Alexander Ebert
 * @copyright	2001-2015 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @module	WoltLab/WCF/Ui/TabMenu
 */
define(['Dictionary', 'Dom/ChangeListener', 'Dom/Util', './TabMenu/Simple'], function(Dictionary, DomChangeListener, DomUtil, SimpleTabMenu) {
	"use strict";

	var _tabMenus = new Dictionary();

	/**
	 * @exports	WoltLab/WCF/Ui/TabMenu
	 */
	var UiTabMenu = {
		/**
		 * Sets up tab menus and binds listeners.
		 */
		setup: function() {
			this._init();
			this._selectErroneousTabs();

			DomChangeListener.add('WoltLab/WCF/Ui/TabMenu', this._init.bind(this));
		},

		/**
		 * Initializes available tab menus.
		 */
		_init: function() {
			var container, containerId, returnValue, tabMenu, tabMenus = document.querySelectorAll('.tabMenuContainer:not(.staticTabMenuContainer)');
			for (var i = 0, length = tabMenus.length; i < length; i++) {
				container = tabMenus[i];
				containerId = DomUtil.identify(container);

				if (_tabMenus.has(containerId)) {
					continue;
				}

				tabMenu = new SimpleTabMenu(container);
				if (tabMenu.validate()) {
					returnValue = tabMenu.init();

					_tabMenus.set(containerId, tabMenu);

					if (returnValue instanceof Element) {
						tabMenu = this.getTabMenu(returnValue.parentNode.id);
						tabMenu.select(returnValue.id, null, true);
					}
				}
			}
		},

		/**
		 * Selects the first tab containing an element with class `formError`.
		 */
		_selectErroneousTabs: function() {
			_tabMenus.forEach(function(tabMenu) {
				var foundError = false;
				tabMenu.getContainers().forEach(function(container) {
					if (!foundError && container.getElementsByClassName('formError').length) {
						foundError = true;

						tabMenu.select(container.id);
					}
				});
			});
		},

		/**
		 * Returns a SimpleTabMenu instance for given container id.
		 *
		 * @param	{string}	containerId	tab menu container id
		 * @return	{(SimpleTabMenu|undefined)}	tab menu object
		 */
		getTabMenu: function(containerId) {
			return _tabMenus.get(containerId);
		}
	};

	return UiTabMenu;
});
<|endoftext|>


<commit_before>import { app, Menu, Tray } from 'electron';
import path from 'path';

import { showDesktopSettings } from './desktopSettings';

let appIcon = null;
const mainWindow = WindowManager.getAll('main')[0];

let audioDeviceMenu = [
  {
    label: 'Loading Devices...',
    enabled: false,
  },
];

if (process.platform === 'darwin') {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/macTemplate.png`));
} else {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/main_tray.png`));
}

const setContextMenu = () => {
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Show',
      click: () => {
        mainWindow.setSkipTaskbar(false);
        mainWindow.show();
      },
    },
    {
      label: 'Audio Device',
      submenu: audioDeviceMenu,
    },
    { label: 'Settings', click: () => { showDesktopSettings(); } },
    { type: 'separator' },
    { label: 'Quit', click: () => { global.quiting = true; app.quit(); } },
  ]);
  appIcon.setContextMenu(contextMenu);
};
setContextMenu();

/**
 * Toggle the main window (on tray click).
 * If in background, bring to foreground.
 */
function toggleMainWindow() {
  // the mainWindow variable will be GC'd
  // we must find the window ourselves
  const win = WindowManager.getAll('main')[0];

  if (process.platform === 'darwin') { // OS-X - Not tested!
    if (!win.isVisible()) {
      // Show
      win.setSkipTaskbar(false);
      win.show();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.hide();
      }
    }
  } else { // Windows, Linux
    const wasMinimized = win.isMinimized();

    if (wasMinimized || !win.isFocused()) {
      win.setSkipTaskbar(false);
      win.show();

      win.focus(); // if not minimized, try to focus it

      if (!wasMinimized && !win.isFocused()) {
        // Failed to focus the window !

        // The window is in a weird glitch state caused
        // by "closing" it with the cross button

        // Since we can't give it focus, assume it's in the
        // foreground and user actually wanted to hide it.
        if (Settings.get('minToTray', true)) {
          win.minimize();
          win.setSkipTaskbar(true);
        }
      }

    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.minimize();
        win.setSkipTaskbar(true);
      }
    }
  }
}

appIcon.setToolTip('Google Play Music');
appIcon.on('click', toggleMainWindow);

/* does not work if the 'click' handler is present */
//appIcon.on('double-click', toggleMainWindow);

// DEV: Keep the icon in the global scope or it gets garbage collected........
global.appIcon = appIcon;

app.on('before-quit', () => {
  appIcon.destroy();
  delete global.appIcon;
  appIcon = null;
});

Emitter.on('audiooutput:list', (event, devices) => {
  audioDeviceMenu = [];
  devices.forEach((device) => {
    if (device.kind === 'audiooutput') {
      let label = device.label;
      if (!label) {
        switch (device.deviceId) {
          case 'default':
            label = 'System Default';
            break;
          case 'communications':
            label = 'System Default Communications';
            break;
          default:
            label = 'Unknown Device';
            break;
        }
      }
      audioDeviceMenu.push({
        label,
        type: 'radio',
        click: () => {
          Emitter.sendToGooglePlayMusic('audiooutput:set', device.deviceId);
          Settings.set('audiooutput', label);
        },
        checked: (label === Settings.get('audiooutput')),
      });
    }
  });
  setContextMenu();
});

Emitter.sendToGooglePlayMusic('audiooutput:fetch');
Emitter.on('audiooutput:set', () => Emitter.sendToGooglePlayMusic('audiooutput:fetch'));
<commit_msg>Do not try to focus if in background, works around the focus glitch<commit_after>import { app, Menu, Tray } from 'electron';
import path from 'path';

import { showDesktopSettings } from './desktopSettings';

let appIcon = null;
const mainWindow = WindowManager.getAll('main')[0];

let audioDeviceMenu = [
  {
    label: 'Loading Devices...',
    enabled: false,
  },
];

if (process.platform === 'darwin') {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/macTemplate.png`));
} else {
  appIcon = new Tray(path.resolve(`${__dirname}/../../../assets/img/main_tray.png`));
}

const setContextMenu = () => {
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Show',
      click: () => {
        mainWindow.setSkipTaskbar(false);
        mainWindow.show();
      },
    },
    {
      label: 'Audio Device',
      submenu: audioDeviceMenu,
    },
    { label: 'Settings', click: () => { showDesktopSettings(); } },
    { type: 'separator' },
    { label: 'Quit', click: () => { global.quiting = true; app.quit(); } },
  ]);
  appIcon.setContextMenu(contextMenu);
};
setContextMenu();

/**
 * Toggle the main window (on tray click).
 * If in background, bring to foreground.
 */
function toggleMainWindow() {
  // the mainWindow variable will be GC'd
  // we must find the window ourselves
  const win = WindowManager.getAll('main')[0];

  if (process.platform === 'darwin') { // OS-X - Not tested!
    if (!win.isVisible()) {
      // Show
      win.setSkipTaskbar(false);
      win.show();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.hide();
      }
    }
  } else { // Windows, Linux
    if (win.isMinimized()) {
      win.setSkipTaskbar(false);
      win.restore();
    } else {
      // Hide to tray, if configured
      if (Settings.get('minToTray', true)) {
        win.minimize();
        win.setSkipTaskbar(true);
      }
    }
  }
}

appIcon.setToolTip('Google Play Music');
//appIcon.on('double-click', toggleMainWindow);
appIcon.on('click', toggleMainWindow);

// DEV: Keep the icon in the global scope or it gets garbage collected........
global.appIcon = appIcon;

app.on('before-quit', () => {
  appIcon.destroy();
  delete global.appIcon;
  appIcon = null;
});

Emitter.on('audiooutput:list', (event, devices) => {
  audioDeviceMenu = [];
  devices.forEach((device) => {
    if (device.kind === 'audiooutput') {
      let label = device.label;
      if (!label) {
        switch (device.deviceId) {
          case 'default':
            label = 'System Default';
            break;
          case 'communications':
            label = 'System Default Communications';
            break;
          default:
            label = 'Unknown Device';
            break;
        }
      }
      audioDeviceMenu.push({
        label,
        type: 'radio',
        click: () => {
          Emitter.sendToGooglePlayMusic('audiooutput:set', device.deviceId);
          Settings.set('audiooutput', label);
        },
        checked: (label === Settings.get('audiooutput')),
      });
    }
  });
  setContextMenu();
});

Emitter.sendToGooglePlayMusic('audiooutput:fetch');
Emitter.on('audiooutput:set', () => Emitter.sendToGooglePlayMusic('audiooutput:fetch'));
<|endoftext|>


<commit_before>
<commit_msg>removing abandoned file<commit_after><|endoftext|>


<commit_before>const normalize = (fields) => {
  if (Array.isArray(fields)) {
    return fields.reduce((prev, curr) => {
      if (~curr.indexOf('.')) {
        prev[curr.split('.')[1]] = curr;
      } else {
        prev[curr] = curr;
      }

      return prev;
    }, {});
  }

  return fields;
};

/**
 * Maps fields to computed functions.
 *
 * @param {Array|Object} fields
 */
const mapFields = (fields) => {
  const normalized = normalize(fields);
  return Object.keys(normalized).reduce((prev, curr) => {
    const field = normalized[curr];
    prev[curr] = function mappedField () {
      // if field exists
      if (this.$validator.flags[field]) {
        return this.$validator.flags[field];
      }

      // if it has a scope defined
      const index = field.indexOf('.');
      if (index <= 0) {
        return {};
      }

      let [scope, ...name] = field.split('.');
      scope = this.$validator.flags[`$${scope}`];
      name = name.join('.');

      if (scope && scope[name]) {
        return scope[name];
      }

      return {};
    };

    return prev;
  }, {});
};

export default mapFields;
<commit_msg>add flow to helpers.js<commit_after>// @flow

const normalize = (fields: Array<any> | Object): Object => {
  if (Array.isArray(fields)) {
    return fields.reduce((prev, curr) => {
      if (~curr.indexOf('.')) {
        prev[curr.split('.')[1]] = curr;
      } else {
        prev[curr] = curr;
      }

      return prev;
    }, {});
  }

  return fields;
};

/**
 * Maps fields to computed functions.
 */
const mapFields = (fields: Array<any> | Object): Object => {
  const normalized = normalize(fields);
  return Object.keys(normalized).reduce((prev, curr) => {
    const field = normalized[curr];
    prev[curr] = function mappedField () {
      // if field exists
      if (this.$validator.flags[field]) {
        return this.$validator.flags[field];
      }

      // if it has a scope defined
      const index = field.indexOf('.');
      if (index <= 0) {
        return {};
      }

      let [scope, ...name] = field.split('.');
      scope = this.$validator.flags[`$${scope}`];
      name = name.join('.');

      if (scope && scope[name]) {
        return scope[name];
      }

      return {};
    };

    return prev;
  }, {});
};

export default mapFields;
<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * This class aims to have the same interface as ArrowNode and support the same API but to do it by transforming shapes where
 * possible instead of creating new shapes, in order to improve performance, see https://github.com/phetsims/scenery-phet/issues/28
 *
 * TODO: Add support for "collar" stroke and shrunken arrowheads.
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // Imports
  var inherit = require( 'PHET_CORE/inherit' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var Matrix3 = require( 'DOT/Matrix3' );
  var Shape = require( 'KITE/Shape' );
  var Vector2 = require( 'DOT/Vector2' );
  var ArrowNode = require( 'SCENERY_PHET/ArrowNode' );
  var ArrowShape = require( 'SCENERY_PHET/ArrowShape' );

  /*
   * @param {number} tailX
   * @param {number} tailY
   * @param {number} tipX
   * @param {number} tipY
   * @param {Object} options
   * @constructor
   */
  function MutableArrowNode( tailX, tailY, tipX, tipY, options ) {

    // default options
    options = _.extend( {
      headHeight: 10,
      headWidth: 10,
      tailWidth: 5,
      doubleHead: false, // true puts heads on both ends of the arrow, false puts a head at the tip
      fill: 'black',
      stroke: 'black',
      lineWidth: 1
    }, options );

    // things you're likely to mess up, add more as needed
    assert && assert( options.headWidth > options.tailWidth );

    //The tail of the Arrow is a
    Node.call( this, options );

    //Intermediate parent for setting the rotation of the node
    this.parent = new Node();

    //Rectangle for body and stripes along the sides for stroke
    this.body = new Node( {
      children: [
        new Rectangle( 0, 0, options.tailWidth, 1, {fill: options.fill} ),
        new Rectangle( -options.lineWidth / 2, 0, options.lineWidth, 1, {fill: options.stroke} ),
        new Rectangle( options.tailWidth - options.lineWidth / 2, 0, options.lineWidth, 1, {fill: options.stroke} )
      ]} );

    //Head shape.  Don't close so the stroke can be used for the angled parts, but not the flat part (the "collar").
    var headShape = new Shape().moveTo( -options.headWidth / 2, 0 ).lineTo( 0, options.headHeight ).lineTo( options.headWidth / 2, 0 );
    this.head = new Path( headShape, {fill: options.fill, stroke: options.stroke, lineWidth: options.lineWidth} );

    this.tailEdgeStroke = new Rectangle( 0, -options.lineWidth / 2, options.tailWidth, options.lineWidth, {fill: 'black'} );

    this.parent.addChild( this.head );
    this.parent.addChild( this.body );
    this.parent.addChild( this.tailEdgeStroke );

    this.addChild( this.parent );
    this.options = options;

    //Fall back to ArrowNode when arrowhead is small
    this.arrowNode = new ArrowNode( 0, 0, 0, 0, options );
    this.arrowNode.visible = false;
    this.addChild( this.arrowNode );

    this.optimized = true;
    this.setTailAndTip( tailX, tailY, tipX, tipY );
  }

  return inherit( Node, MutableArrowNode, {
    getMatrix: function( x, y, angle, sx, sy, originX, originY ) {

      //Translate to the desired location
      var matrix = Matrix3.translation( x, y );

      //Rotation and translation can happen in any order
      matrix = matrix.multiplyMatrix( Matrix3.rotation2( angle ) );

      //Update scale if not 1
      if ( originX !== 1 || originY !== 1 ) {
        matrix = matrix.multiplyMatrix( Matrix3.scaling( sx, sy ) );
      }

      //Update origin if non-zero
      if ( originX !== 0 || originY !== 0 ) {

        //Think of it as a multiplying the Vector2 to the right, so this step happens first actually.  Use it to center the registration point
        matrix = matrix.multiplyMatrix( Matrix3.translation( -originX, -originY ) );
      }

      return matrix;
    },
    setTailAndTip: function( tailX, tailY, tipX, tipY ) {
      if ( this.tailX !== tailX || this.tailY !== tailY || this.tipX !== tipX || this.tipY !== tipY ) {
        var dx = tipX - tailX;
        var dy = tipY - tailY;

        var bodyDistance = Math.sqrt( dx * dx + dy * dy ) - this.options.headHeight;

        var willBeOptimized = bodyDistance > this.options.headHeight;

        if ( willBeOptimized ) {

          if ( !this.optimized ) {
            this.body.visible = true;
            this.head.visible = true;
            this.tailEdgeStroke.visible = true;
            this.arrowNode.visible = false;
          }

          var angle = Math.atan2( dy, dx );

          var bodyTipX = bodyDistance * Math.cos( angle ) + tailX;
          var bodyTipY = bodyDistance * Math.sin( angle ) + tailY;

          //Overlap a bit so it looks like a solid piece
          var overlap = 2E-1;

          this.body.setMatrix( this.getMatrix( tailX, tailY, angle - Math.PI / 2, 1, bodyDistance + overlap, this.options.tailWidth / 2, 0 ) );
          this.head.setMatrix( this.getMatrix( bodyTipX, bodyTipY, angle - Math.PI / 2, 1, 1, 0, 0 ) );
          this.tailEdgeStroke.setMatrix( this.getMatrix( tailX, tailY, angle - Math.PI / 2, 1, 1, this.options.tailWidth / 2, 0 ) );
        }
        else {
          if ( this.optimized ) {
            this.body.visible = false;
            this.head.visible = false;
            this.tailEdgeStroke.visible = false;
            this.arrowNode.visible = true;
          }
          this.arrowNode.setShape( new ArrowShape( tailX, tailY, tipX, tipY, this.options ) );
        }

        this.optimized = willBeOptimized;
        this.tailX = tailX;
        this.tailY = tailY;
        this.tipX = tipX;
        this.tipY = tipY;
      }
    },
    setShape: function() {
      console.log( 'set shape called on MutableArrowNode.' );
    }
  } );
} );
<commit_msg>added docs<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * This class aims to have the same interface as ArrowNode and support the same API but to do it by transforming shapes where
 * possible instead of creating new shapes, in order to improve performance, see https://github.com/phetsims/scenery-phet/issues/28
 *
 * TODO: Add support for "collar" stroke and shrunken arrowheads.
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // Imports
  var inherit = require( 'PHET_CORE/inherit' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var Matrix3 = require( 'DOT/Matrix3' );
  var Shape = require( 'KITE/Shape' );
  var Vector2 = require( 'DOT/Vector2' );
  var ArrowNode = require( 'SCENERY_PHET/ArrowNode' );
  var ArrowShape = require( 'SCENERY_PHET/ArrowShape' );

  /*
   * @param {number} tailX
   * @param {number} tailY
   * @param {number} tipX
   * @param {number} tipY
   * @param {Object} options
   * @constructor
   */
  function MutableArrowNode( tailX, tailY, tipX, tipY, options ) {

    // default options
    options = _.extend( {
      headHeight: 10,
      headWidth: 10,
      tailWidth: 5,
      doubleHead: false, // true puts heads on both ends of the arrow, false puts a head at the tip
      fill: 'black',
      stroke: 'black',
      lineWidth: 1
    }, options );

    // things you're likely to mess up, add more as needed
    assert && assert( options.headWidth > options.tailWidth );

    //The tail of the Arrow is a
    Node.call( this, options );

    //Intermediate parent for setting the rotation of the node
    this.parent = new Node();

    //Rectangle for body and stripes along the sides for stroke
    this.body = new Node( {
      children: [
        new Rectangle( 0, 0, options.tailWidth, 1, {fill: options.fill} ),
        new Rectangle( -options.lineWidth / 2, 0, options.lineWidth, 1, {fill: options.stroke} ),
        new Rectangle( options.tailWidth - options.lineWidth / 2, 0, options.lineWidth, 1, {fill: options.stroke} )
      ]} );

    //Head shape.  Don't close so the stroke can be used for the angled parts, but not the flat part (the "collar").
    var headShape = new Shape().moveTo( -options.headWidth / 2, 0 ).lineTo( 0, options.headHeight ).lineTo( options.headWidth / 2, 0 );
    this.head = new Path( headShape, {fill: options.fill, stroke: options.stroke, lineWidth: options.lineWidth} );

    this.tailEdgeStroke = new Rectangle( 0, -options.lineWidth / 2, options.tailWidth, options.lineWidth, {fill: 'black'} );

    this.parent.addChild( this.head );
    this.parent.addChild( this.body );
    this.parent.addChild( this.tailEdgeStroke );

    this.addChild( this.parent );
    this.options = options;

    //Fall back to ArrowNode when arrowhead is small
    //TODO: We could replace this with optimized shrunken arrowhead and arrow tip too
    this.arrowNode = new ArrowNode( 0, 0, 0, 0, options );
    this.arrowNode.visible = false;
    this.addChild( this.arrowNode );

    this.optimized = true;
    this.setTailAndTip( tailX, tailY, tipX, tipY );
  }

  return inherit( Node, MutableArrowNode, {
    getMatrix: function( x, y, angle, sx, sy, originX, originY ) {

      //Translate to the desired location
      var matrix = Matrix3.translation( x, y );

      //Rotation and translation can happen in any order
      matrix = matrix.multiplyMatrix( Matrix3.rotation2( angle ) );

      //Update scale if not 1
      if ( originX !== 1 || originY !== 1 ) {
        matrix = matrix.multiplyMatrix( Matrix3.scaling( sx, sy ) );
      }

      //Update origin if non-zero
      if ( originX !== 0 || originY !== 0 ) {

        //Think of it as a multiplying the Vector2 to the right, so this step happens first actually.  Use it to center the registration point
        matrix = matrix.multiplyMatrix( Matrix3.translation( -originX, -originY ) );
      }

      return matrix;
    },
    setTailAndTip: function( tailX, tailY, tipX, tipY ) {
      if ( this.tailX !== tailX || this.tailY !== tailY || this.tipX !== tipX || this.tipY !== tipY ) {
        var dx = tipX - tailX;
        var dy = tipY - tailY;

        var bodyDistance = Math.sqrt( dx * dx + dy * dy ) - this.options.headHeight;

        var willBeOptimized = bodyDistance > this.options.headHeight;

        if ( willBeOptimized ) {

          if ( !this.optimized ) {
            this.body.visible = true;
            this.head.visible = true;
            this.tailEdgeStroke.visible = true;
            this.arrowNode.visible = false;
          }

          var angle = Math.atan2( dy, dx );

          var bodyTipX = bodyDistance * Math.cos( angle ) + tailX;
          var bodyTipY = bodyDistance * Math.sin( angle ) + tailY;

          //Overlap a bit so it looks like a solid piece
          var overlap = 2E-1;

          this.body.setMatrix( this.getMatrix( tailX, tailY, angle - Math.PI / 2, 1, bodyDistance + overlap, this.options.tailWidth / 2, 0 ) );
          this.head.setMatrix( this.getMatrix( bodyTipX, bodyTipY, angle - Math.PI / 2, 1, 1, 0, 0 ) );
          this.tailEdgeStroke.setMatrix( this.getMatrix( tailX, tailY, angle - Math.PI / 2, 1, 1, this.options.tailWidth / 2, 0 ) );
        }
        else {
          if ( this.optimized ) {
            this.body.visible = false;
            this.head.visible = false;
            this.tailEdgeStroke.visible = false;
            this.arrowNode.visible = true;
          }
          this.arrowNode.setShape( new ArrowShape( tailX, tailY, tipX, tipY, this.options ) );
        }

        this.optimized = willBeOptimized;
        this.tailX = tailX;
        this.tailY = tailY;
        this.tipX = tipX;
        this.tipY = tipY;
      }
    },
    setShape: function() {
      console.log( 'set shape called on MutableArrowNode.' );
    }
  } );
} );
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { pickBoxProps } from '../box';
import Button from './Button';
import ButtonGroup from './ButtonGroup';
import { Menu } from '../menu';
import Popover from '../popover';
import { IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import pick from 'lodash.pick';

class SplitButton extends PureComponent {
  firstChild = pick(this.props.children[0].props, ['label']);

  state = {
    buttonLabel: this.firstChild.label,
    popoverActive: false,
    popoverAnchorEl: null,
  };

  handleMainButtonClick = event => {
    this.props.onButtonClick(event);
  };

  handleSecondaryButtonClick = event => {
    this.setState({ popoverActive: true, popoverAnchorEl: event.currentTarget });
  };

  handleMenuItemClick = child => {
    const childProps = child.props;
    this.setState({
      popoverActive: false,
    });
    childProps.onClick(childProps.label);
  };

  handleCloseClick = () => {
    this.setState({ popoverActive: false });
  };

  render() {
    const { children, level, size, disabled, ...others } = this.props;
    const { buttonLabel, popoverActive, popoverAnchorEl } = this.state;
    const boxProps = pickBoxProps(others);
    return (
      <Box display="flex" justifyContent="center" {...boxProps} data-teamleader-ui="split-menu">
        <ButtonGroup segmented>
          <Button
            label={buttonLabel}
            level={level}
            size={size}
            disabled={disabled}
            onClick={this.handleMainButtonClick}
          />
          <Button
            icon={<IconChevronDownSmallOutline />}
            level={level}
            size={size}
            disabled={disabled}
            onClick={this.handleSecondaryButtonClick}
          />
        </ButtonGroup>
        <Popover
          active={popoverActive}
          anchorEl={popoverAnchorEl}
          backdrop="transparent"
          onEscKeyDown={this.handleCloseClick}
          onOverlayClick={this.handleCloseClick}
          position="start"
        >
          <Menu>
            {React.Children.map(children, child => {
              if (child.props.label !== buttonLabel) {
                return React.cloneElement(child, {
                  onClick: () => this.handleMenuItemClick(child),
                });
              }
            })}
          </Menu>
        </Popover>
      </Box>
    );
  }
}

SplitButton.defaultProps = {
  level: 'primary',
  size: 'medium',
};

SplitButton.propTypes = {
  /** The MenuItems we pass to our component. */
  children: PropTypes.node.isRequired,
  /** Determines which kind of button to be rendered. */
  level: PropTypes.oneOf(['primary', 'secondary', 'destructive']),
  /** Size of the button. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** The function executed, when we click on the main button. */
  onButtonClick: PropTypes.func.isRequired,
  /** If true, component will be disabled. */
  disabled: PropTypes.bool,
};

export default SplitButton;
<commit_msg>:boom: Pass event to menuItem onClick instead of label<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { pickBoxProps } from '../box';
import Button from './Button';
import ButtonGroup from './ButtonGroup';
import { Menu } from '../menu';
import Popover from '../popover';
import { IconChevronDownSmallOutline } from '@teamleader/ui-icons';
import pick from 'lodash.pick';

class SplitButton extends PureComponent {
  firstChild = pick(this.props.children[0].props, ['label']);

  state = {
    buttonLabel: this.firstChild.label,
    popoverActive: false,
    popoverAnchorEl: null,
  };

  handleMainButtonClick = event => {
    this.props.onButtonClick(event);
  };

  handleSecondaryButtonClick = event => {
    this.setState({ popoverActive: true, popoverAnchorEl: event.currentTarget });
  };

  handleMenuItemClick = (child, event) => {
    const childProps = child.props;
    this.setState({
      popoverActive: false,
    });
    childProps.onClick(event);
  };

  handleCloseClick = () => {
    this.setState({ popoverActive: false });
  };

  render() {
    const { children, level, size, disabled, ...others } = this.props;
    const { buttonLabel, popoverActive, popoverAnchorEl } = this.state;
    const boxProps = pickBoxProps(others);
    return (
      <Box display="flex" justifyContent="center" {...boxProps} data-teamleader-ui="split-menu">
        <ButtonGroup segmented>
          <Button
            label={buttonLabel}
            level={level}
            size={size}
            disabled={disabled}
            onClick={this.handleMainButtonClick}
          />
          <Button
            icon={<IconChevronDownSmallOutline />}
            level={level}
            size={size}
            disabled={disabled}
            onClick={this.handleSecondaryButtonClick}
          />
        </ButtonGroup>
        <Popover
          active={popoverActive}
          anchorEl={popoverAnchorEl}
          backdrop="transparent"
          onEscKeyDown={this.handleCloseClick}
          onOverlayClick={this.handleCloseClick}
          position="start"
        >
          <Menu>
            {React.Children.map(children, child => {
              if (child.props.label !== buttonLabel) {
                return React.cloneElement(child, {
                  onClick: event => this.handleMenuItemClick(child, event),
                });
              }
            })}
          </Menu>
        </Popover>
      </Box>
    );
  }
}

SplitButton.defaultProps = {
  level: 'primary',
  size: 'medium',
};

SplitButton.propTypes = {
  /** The MenuItems we pass to our component. */
  children: PropTypes.node.isRequired,
  /** Determines which kind of button to be rendered. */
  level: PropTypes.oneOf(['primary', 'secondary', 'destructive']),
  /** Size of the button. */
  size: PropTypes.oneOf(['small', 'medium', 'large']),
  /** The function executed, when we click on the main button. */
  onButtonClick: PropTypes.func.isRequired,
  /** If true, component will be disabled. */
  disabled: PropTypes.bool,
};

export default SplitButton;
<|endoftext|>


<commit_before>var jQuery = (function (doc) {
  'use strict';

  var fn = function (selector) {
    var i, nodes, results = [];
    if (selector instanceof fn) {
      return selector;
    }
    this.element = selector;
    if (typeof selector === 'string') {
      if (selector.indexOf('#') === 0) {
        this.element = document.getElementById(selector.slice(1));
      }
      if (selector.indexOf('.') === 0) {
        nodes = doc.getElementsByClassName(selector.slice(1));
        for (i = 0; i < nodes.length; i += 1) {
          results.push(new fn(nodes[i]));
        }
        return results;
      }
      if (selector.indexOf('<') === 0) {
        selector = selector.slice(1, -1);
        nodes = doc.getElementsByTagName(selector);
        for (i = 0; i < nodes.length; i += 1) {
          results.push(new fn(nodes[i]));
        }
        return results;
      }
    }
    return this;
  },

  root = function (selector) {
    return new fn(selector);
  };

  root.fromPoint = function (x, y) {
    return root(doc.elementFromPoint(x, y));
  };

  fn.prototype.html = function (value) {
    if (this.element) {
      if (value === undefined) {
        return this.element.innerHTML;
      }
      this.element.innerHTML = value;
    }
    return this;
  };

  fn.prototype.int = function () {
    return parseInt(this.html(), 10);
  };

  fn.prototype.top = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.style.top, 10);
      }
      this.element.style.top = value + 'px';
    }
  };

  fn.prototype.left = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.style.left, 10);
      }
      this.element.style.left = value + 'px';
    }
  };

  fn.prototype.display = function (value) {
    if (this.element) {
      this.element.style.display = value;
    }
  };

  fn.prototype.add = function (klass) {
    if (this.element) {
      klass = ' ' + klass;
      if (this.element.className.indexOf(klass) < 0) {
        this.element.className += klass;
      }
    }
  };

  fn.prototype.remove = function (klass) {
    if (this.element) {
      var regex = new RegExp('(\\s+)?' + klass, 'g');
      this.element.className = this.element.className.replace(regex, '');
    }
  };

  fn.prototype.listen = function (message, callback) {
    if (this.element) {
      this.element.addEventListener(message, callback, false);
    }
  };

  fn.prototype.ignore = function (message, callback) {
    if (this.element) {
      this.element.removeEventListener(message, callback, false);
    }
  };

  fn.prototype.center = function () {
    var e = this.element, x = 0, y = 0;
    if (e) {
      x = e.offsetWidth / 2;
      y = e.offsetHeight / 2;
    }
    while (e && !isNaN(e.offsetLeft) && !isNaN(e.offsetTop)) {
      x += e.offsetLeft - e.scrollLeft;
      y += e.offsetTop - e.scrollTop;
      e = e.offsetParent;
    }
    return { x: x, y: y };
  };

  fn.prototype.animate = function (klass, callback) {
    var self = this;
    if (this.element) {
      var wrapper = function () {
        self.ignore('webkitTransitionEnd', wrapper);
        self.ignore('otransitionend', wrapper);
        self.remove(klass);
        if (callback) {
          callback();
        }
      };
      this.listen('webkitTransitionEnd', wrapper);
      this.listen('otransitionend', wrapper);
      this.add(klass);
    }
  };

  fn.prototype.name = function () {
    if (this.element) {
      return this.element.nodeName;
    }
    return '';
  };

  fn.prototype.data = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.getAttribute('data-value'), 10);
      }
      this.element.setAttribute('data-value', value);
    }
    return '';
  };

  fn.prototype.klass = function () {
    if (this.element) {
      return this.element.className;
    }
    return '';
  };

  fn.prototype.vanish = function () {
    if (this.element) {
      this.element.parentNode.removeChild(this.element);
    }
  };

  fn.prototype.kids = function (value) {
    if (this.element) {
      return this.element.getElementsByTagName(value);
    }
    return [];
  };

  fn.prototype.unwrap = function () {
    return this.element;
  };

  return root;
}(document));
<commit_msg>Fixes my jQuery library so it passes JSLint.<commit_after>var jQuery = (function (doc) {
  'use strict';

  var Fn = function (selector) {
    var i, nodes, results = [];
    if (selector instanceof Fn) {
      return selector;
    }
    this.element = selector;
    if (typeof selector === 'string') {
      if (selector.indexOf('#') === 0) {
        this.element = document.getElementById(selector.slice(1));
      }
      if (selector.indexOf('.') === 0) {
        nodes = doc.getElementsByClassName(selector.slice(1));
        for (i = 0; i < nodes.length; i += 1) {
          results.push(new Fn(nodes[i]));
        }
        return results;
      }
      if (selector.indexOf('<') === 0) {
        selector = selector.slice(1, -1);
        nodes = doc.getElementsByTagName(selector);
        for (i = 0; i < nodes.length; i += 1) {
          results.push(new Fn(nodes[i]));
        }
        return results;
      }
    }
    return this;
  },

  root = function (selector) {
    return new Fn(selector);
  };

  root.fromPoint = function (x, y) {
    return root(doc.elementFromPoint(x, y));
  };

  Fn.prototype.html = function (value) {
    if (this.element) {
      if (value === undefined) {
        return this.element.innerHTML;
      }
      this.element.innerHTML = value;
    }
    return this;
  };

  Fn.prototype.int = function () {
    return parseInt(this.html(), 10);
  };

  Fn.prototype.top = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.style.top, 10);
      }
      this.element.style.top = value + 'px';
    }
  };

  Fn.prototype.left = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.style.left, 10);
      }
      this.element.style.left = value + 'px';
    }
  };

  Fn.prototype.display = function (value) {
    if (this.element) {
      this.element.style.display = value;
    }
  };

  Fn.prototype.add = function (klass) {
    if (this.element) {
      klass = ' ' + klass;
      if (this.element.className.indexOf(klass) < 0) {
        this.element.className += klass;
      }
    }
  };

  Fn.prototype.remove = function (klass) {
    if (this.element) {
      var regex = new RegExp('(\\s+)?' + klass, 'g');
      this.element.className = this.element.className.replace(regex, '');
    }
  };

  Fn.prototype.listen = function (message, callback) {
    if (this.element) {
      this.element.addEventListener(message, callback, false);
    }
  };

  Fn.prototype.ignore = function (message, callback) {
    if (this.element) {
      this.element.removeEventListener(message, callback, false);
    }
  };

  Fn.prototype.center = function () {
    var e = this.element, x = 0, y = 0;
    if (e) {
      x = e.offsetWidth / 2;
      y = e.offsetHeight / 2;
    }
    while (e && !isNaN(e.offsetLeft) && !isNaN(e.offsetTop)) {
      x += e.offsetLeft - e.scrollLeft;
      y += e.offsetTop - e.scrollTop;
      e = e.offsetParent;
    }
    return { x: x, y: y };
  };

  Fn.prototype.animate = function (klass, callback) {
    var wrapper, self = this;
    if (this.element) {
      wrapper = function () {
        self.ignore('webkitTransitionEnd', wrapper);
        self.ignore('otransitionend', wrapper);
        self.remove(klass);
        if (callback) {
          callback();
        }
      };
      this.listen('webkitTransitionEnd', wrapper);
      this.listen('otransitionend', wrapper);
      this.add(klass);
    }
  };

  Fn.prototype.name = function () {
    if (this.element) {
      return this.element.nodeName;
    }
    return '';
  };

  Fn.prototype.data = function (value) {
    if (this.element) {
      if (value === undefined) {
        return parseInt(this.element.getAttribute('data-value'), 10);
      }
      this.element.setAttribute('data-value', value);
    }
    return '';
  };

  Fn.prototype.klass = function () {
    if (this.element) {
      return this.element.className;
    }
    return '';
  };

  Fn.prototype.vanish = function () {
    if (this.element) {
      this.element.parentNode.removeChild(this.element);
    }
  };

  Fn.prototype.kids = function (value) {
    if (this.element) {
      return this.element.getElementsByTagName(value);
    }
    return [];
  };

  Fn.prototype.unwrap = function () {
    return this.element;
  };

  return root;
}(document));
<|endoftext|>