<commit_before>var autoprefixer = require('autoprefixer-core');
var GittyCache = require('./tasks/utils/gitty-cache');

module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({});
  grunt.loadTasks('tasks');
  grunt.loadTasks('backbone.marionette/tasks');

  GittyCache.setReleaseTag(grunt.option('TAG'));

  grunt.config.merge({
    'gitty:releaseTag': {
      marionette: {
        options: {
          repo: 'backbone.marionette'
        }
      }
    },
    'gitty:checkoutTag': {
      marionette: {
        options: {
          repo: 'backbone.marionette'
        }
      }
    },
    critical: {
        test: {
            options: {
                base: './',
                css: [
                    'dist/styles/marionette.css'
                ],
                width: 1200,
                height: 800
            },
            src: 'dist/index.html',
            dest: 'dist/index.html'
        }
    },
    concat: {
      options: {
        separator: '\n',
      },
      dist: {
        src: [
          'bower_components/jquery/dist/jquery.min.js',
          'bower_components/jQuery.equalHeights/jquery.equalheights.min.js',
          'bower_components/google-code-prettify/bin/prettify.min.js',
          'bower_components/jquery-unveil/jquery.unveil.min.js',
          'bower_components/snabbt.js/snabbt.min.js',
          'src/js/script.js',
          'src/js/github.js',
          'src/js/inspector-comment.js',
          'bower_components/underscore/underscore.js',
          'bower_components/backbone/backbone.js',
          'backbone.marionette/lib/backbone.marionette.js'
        ],
        dest: 'dist/js/build.js'
      }
    },

    docco: {
      build: {
        src: ['backbone.marionette/lib/backbone.marionette.js'],
        options: {
          output: 'dist/annotated-src/'
        }
      }
    },

    clean: {
      dist: ['dist']
    },

    connect: {
      server: {
        options: {
          base: 'dist',
          port: 8000
        }
      }
    },

    copy: {
      assets: {
        files: [
          {
            expand: true,
            cwd: 'src/',
            src: ['images/**/*','!images/**/*.{png,jpg,gif,ico}'],
            dest: 'dist/'
          },
          {
            expand: true,
            src: ['bower_components/**/*'],
            dest: 'dist/'
          },
          {
            cwd: 'src/',
            expand: true,
            src: ['js/docs.js'],
            dest: 'dist'
          },
          {
            expand: true,
            cwd: 'bower_components/jquery/dist',
            src: ['jquery.min.map'],
            dest: 'dist/js'
          }
        ]
      },
      main: {
        files: [
          {
            cwd: 'src/',
            expand: true,
            src: ['robots.txt'],
            dest: 'dist/'
          },
          {
            cwd: 'src/images/',
            expand: true,
            src: ['favicon.ico'],
            dest: 'dist/'
          },
        ]
      }
    },

    imagemin: {
      dynamic: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['images/**/*.{png,jpg,gif}'],
          dest: 'dist/'
        }]
      }
    },

    svgstore: {
      options: {},
      default : {
        files: {
          'src/images/svg-sprite.svg': ['src/svg-icons/*.svg']
        }
      }
    },

    sass: {
      options:{
        outputStyle: 'compressed'
      },
      dist: {
        files: {
          'dist/styles/marionette.css': 'src/stylesheets/marionette.scss',
          'dist/styles/inspector.css': 'src/stylesheets/inspector/index.scss',
          'dist/styles/api.css': 'src/stylesheets/api.scss',
          'dist/styles/docs.css': 'src/stylesheets/docs.scss'
        }
      },
      dev: {
        options:{
          outputStyle: 'nested',
          sourceMap: true
        },
        files: {
          'dist/styles/marionette.css': 'src/stylesheets/marionette.scss',
          'dist/styles/inspector.css': 'src/stylesheets/inspector/index.scss',
          'dist/styles/api.css': 'src/stylesheets/api.scss',
          'dist/styles/docs.css': 'src/stylesheets/docs.scss'
        }
      }
    },

    postcss: {
      options: {
        processors: [
          autoprefixer({ browsers: ['last 2 version'] }).postcss
        ]
      },
      dev: {
        options: {
          map: true
        },
        src: 'dist/styles/*.css'
      },
      dist: {
        src: 'dist/styles/*.css'
      }
    },

    watch: {
      options: {
        atBegin: true
      },
      svg: {
        files: 'src/svg-icons/*.svg',
        tasks: ['svgstore', 'sass:dev']
      },
      styles: {
        files: 'src/stylesheets/**/*.scss',
        tasks: ['notify:preCSS', 'sass:dev', 'postcss:dev', 'notify:postCSS']
      },
      scripts: {
        files: 'src/js/**/*',
        tasks: ['notify:preHTML', 'concat', 'copy', 'notify:postHTML']
      },
      assets: {
        files: 'src/images/**/*',
        tasks: ['imagemin', 'copy']
      },
      data: {
        files: 'src/data/*.json',
        tasks: ['notify:preHTML', 'compile-templates', 'notify:postHTML']
      },
      pages: {
        files: 'src/**/*.jade',
        tasks: ['notify:preHTML', 'compile-templates', 'notify:postHTML']
      }
    },

    jade: {
      compile : {
        files: {
          'dist/index.html': 'src/index.jade',
          'dist/inspector/index.html': 'src/inspector/index.jade',
          'dist/download/index.html': 'src/download/index.jade'

        },
        options: {
          data: function(){
            return {
              VERSION: GittyCache.releaseTag || 'v.X.X.X',
              books: grunt.file.readJSON('src/data/books.json'),
              videos: grunt.file.readJSON('src/data/videos.json')
            };
          }
        }
      }
    },

    notify: {
      watch: {
        options: {
          message: 'Watching for changes...'
        }
      },

      data: {
        options: {
          messages: 'Data .json files changed ...'
        }
      },

      preHTML: {
        options: {
          message: 'Compiling HTML files...'
        }
      },
      postHTML: {
        options: {
          message: 'HTML files compiled.'
        }
      },

      preCSS: {
        options: {
          message: 'Compiling CSS files...'
        }
      },
      postCSS: {
        options: {
          message: 'CSS files compiled.'
        }
      }
    },

    compileDocs: {
      marionette: {
        options: {
          repo      : 'backbone.marionette',
          template  : 'src/docs/template.html',
          indexTemplate  : 'src/docs/index.html',
          svgIcons  : 'src/images/svg-sprite.svg'
        },
        src  : 'backbone.marionette/docs',
        dest : 'dist/docs'
      }
    },

    compileApi: {
      marionette: {
        options: {
          repo : 'backbone.marionette'
        },
        src  : 'src/api',
        dest : 'dist/api'
      }
    }
  });

  grunt.registerTask('dev', [
    'clean:dist',
    'connect',
    'notify:watch',
    'watch'
  ]);

  grunt.registerTask('compile-site', [
    'svgstore',
    'sass:dist',
    'concat',
    'copy',
    'imagemin',
    'compile-templates',
    'postcss:dist',
    'critical'
  ]);

  grunt.registerTask('compile-templates', [
    'gitty:releaseTag',
    'jade'
  ]);

  grunt.registerTask('compile-docs', [
    'gitty:releaseTag',
    'compileDocs',
    'sass:dist',
    'gitty:checkoutTag'
  ]);

  grunt.registerTask('compile-api', [
    'compileApi',
    'sass:dist'
  ]);

  grunt.registerTask('compile-docco', [
    'gitty:checkoutTag:marionette',
    'docco:build'
  ]);

  grunt.registerTask('compile-downloads', [
    'compileDownloads'
  ]);

  grunt.registerTask('compile-all', [
    'compile-site',
    'compile-docs',
    'compile-docco',
    'compile-downloads'
  ]);
};
<commit_msg>Add source map generation for main build js<commit_after>var autoprefixer = require('autoprefixer-core');
var GittyCache = require('./tasks/utils/gitty-cache');

module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({});
  grunt.loadTasks('tasks');
  grunt.loadTasks('backbone.marionette/tasks');

  GittyCache.setReleaseTag(grunt.option('TAG'));

  grunt.config.merge({
    'gitty:releaseTag': {
      marionette: {
        options: {
          repo: 'backbone.marionette'
        }
      }
    },
    'gitty:checkoutTag': {
      marionette: {
        options: {
          repo: 'backbone.marionette'
        }
      }
    },
    critical: {
        test: {
            options: {
                base: './',
                css: [
                    'dist/styles/marionette.css'
                ],
                width: 1200,
                height: 800
            },
            src: 'dist/index.html',
            dest: 'dist/index.html'
        }
    },
    concat: {
      options: {
        separator: '\n',
        sourceMap: true
      },
      dist: {
        src: [
          'bower_components/jquery/dist/jquery.min.js',
          'bower_components/jQuery.equalHeights/jquery.equalheights.min.js',
          'bower_components/google-code-prettify/bin/prettify.min.js',
          'bower_components/jquery-unveil/jquery.unveil.min.js',
          'bower_components/snabbt.js/snabbt.min.js',
          'src/js/script.js',
          'src/js/github.js',
          'src/js/inspector-comment.js',
          'bower_components/underscore/underscore.js',
          'bower_components/backbone/backbone.js',
          'backbone.marionette/lib/backbone.marionette.js'
        ],
        dest: 'dist/js/build.js',
      }
    },

    docco: {
      build: {
        src: ['backbone.marionette/lib/backbone.marionette.js'],
        options: {
          output: 'dist/annotated-src/'
        }
      }
    },

    clean: {
      dist: ['dist']
    },

    connect: {
      server: {
        options: {
          base: 'dist',
          port: 8000
        }
      }
    },

    copy: {
      assets: {
        files: [
          {
            expand: true,
            cwd: 'src/',
            src: ['images/**/*','!images/**/*.{png,jpg,gif,ico}'],
            dest: 'dist/'
          },
          {
            expand: true,
            src: ['bower_components/**/*'],
            dest: 'dist/'
          },
          {
            cwd: 'src/',
            expand: true,
            src: ['js/docs.js'],
            dest: 'dist'
          },
          {
            expand: true,
            cwd: 'bower_components/jquery/dist',
            src: ['jquery.min.map'],
            dest: 'dist/js'
          }
        ]
      },
      main: {
        files: [
          {
            cwd: 'src/',
            expand: true,
            src: ['robots.txt'],
            dest: 'dist/'
          },
          {
            cwd: 'src/images/',
            expand: true,
            src: ['favicon.ico'],
            dest: 'dist/'
          },
        ]
      }
    },

    imagemin: {
      dynamic: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['images/**/*.{png,jpg,gif}'],
          dest: 'dist/'
        }]
      }
    },

    svgstore: {
      options: {},
      default : {
        files: {
          'src/images/svg-sprite.svg': ['src/svg-icons/*.svg']
        }
      }
    },

    sass: {
      options:{
        outputStyle: 'compressed'
      },
      dist: {
        files: {
          'dist/styles/marionette.css': 'src/stylesheets/marionette.scss',
          'dist/styles/inspector.css': 'src/stylesheets/inspector/index.scss',
          'dist/styles/api.css': 'src/stylesheets/api.scss',
          'dist/styles/docs.css': 'src/stylesheets/docs.scss'
        }
      },
      dev: {
        options:{
          outputStyle: 'nested',
          sourceMap: true
        },
        files: {
          'dist/styles/marionette.css': 'src/stylesheets/marionette.scss',
          'dist/styles/inspector.css': 'src/stylesheets/inspector/index.scss',
          'dist/styles/api.css': 'src/stylesheets/api.scss',
          'dist/styles/docs.css': 'src/stylesheets/docs.scss'
        }
      }
    },

    postcss: {
      options: {
        processors: [
          autoprefixer({ browsers: ['last 2 version'] }).postcss
        ]
      },
      dev: {
        options: {
          map: true
        },
        src: 'dist/styles/*.css'
      },
      dist: {
        src: 'dist/styles/*.css'
      }
    },

    watch: {
      options: {
        atBegin: true
      },
      svg: {
        files: 'src/svg-icons/*.svg',
        tasks: ['svgstore', 'sass:dev']
      },
      styles: {
        files: 'src/stylesheets/**/*.scss',
        tasks: ['notify:preCSS', 'sass:dev', 'postcss:dev', 'notify:postCSS']
      },
      scripts: {
        files: 'src/js/**/*',
        tasks: ['notify:preHTML', 'concat', 'copy', 'notify:postHTML']
      },
      assets: {
        files: 'src/images/**/*',
        tasks: ['imagemin', 'copy']
      },
      data: {
        files: 'src/data/*.json',
        tasks: ['notify:preHTML', 'compile-templates', 'notify:postHTML']
      },
      pages: {
        files: 'src/**/*.jade',
        tasks: ['notify:preHTML', 'compile-templates', 'notify:postHTML']
      }
    },

    jade: {
      compile : {
        files: {
          'dist/index.html': 'src/index.jade',
          'dist/inspector/index.html': 'src/inspector/index.jade',
          'dist/download/index.html': 'src/download/index.jade'

        },
        options: {
          data: function(){
            return {
              VERSION: GittyCache.releaseTag || 'v.X.X.X',
              books: grunt.file.readJSON('src/data/books.json'),
              videos: grunt.file.readJSON('src/data/videos.json')
            };
          }
        }
      }
    },

    notify: {
      watch: {
        options: {
          message: 'Watching for changes...'
        }
      },

      data: {
        options: {
          messages: 'Data .json files changed ...'
        }
      },

      preHTML: {
        options: {
          message: 'Compiling HTML files...'
        }
      },
      postHTML: {
        options: {
          message: 'HTML files compiled.'
        }
      },

      preCSS: {
        options: {
          message: 'Compiling CSS files...'
        }
      },
      postCSS: {
        options: {
          message: 'CSS files compiled.'
        }
      }
    },

    compileDocs: {
      marionette: {
        options: {
          repo      : 'backbone.marionette',
          template  : 'src/docs/template.html',
          indexTemplate  : 'src/docs/index.html',
          svgIcons  : 'src/images/svg-sprite.svg'
        },
        src  : 'backbone.marionette/docs',
        dest : 'dist/docs'
      }
    },

    compileApi: {
      marionette: {
        options: {
          repo : 'backbone.marionette'
        },
        src  : 'src/api',
        dest : 'dist/api'
      }
    }
  });

  grunt.registerTask('dev', [
    'clean:dist',
    'connect',
    'notify:watch',
    'watch'
  ]);

  grunt.registerTask('compile-site', [
    'svgstore',
    'sass:dist',
    'concat',
    'copy',
    'imagemin',
    'compile-templates',
    'postcss:dist',
    'critical'
  ]);

  grunt.registerTask('compile-templates', [
    'gitty:releaseTag',
    'jade'
  ]);

  grunt.registerTask('compile-docs', [
    'gitty:releaseTag',
    'compileDocs',
    'sass:dist',
    'gitty:checkoutTag'
  ]);

  grunt.registerTask('compile-api', [
    'compileApi',
    'sass:dist'
  ]);

  grunt.registerTask('compile-docco', [
    'gitty:checkoutTag:marionette',
    'docco:build'
  ]);

  grunt.registerTask('compile-downloads', [
    'compileDownloads'
  ]);

  grunt.registerTask('compile-all', [
    'compile-site',
    'compile-docs',
    'compile-docco',
    'compile-downloads'
  ]);
};
<|endoftext|>


<commit_before>var guiStatus;

function setupGUI() {
  guiStatus =  new GuiStatus();
  resizeGUI();

  var fiberSelector = document.getElementById("fiberSelector");
  var regionSelector = document.getElementById("regionSelector");
  // Empty them - this function might be called for GUIupdating
  fiberSelector.innerHTML = "";
  regionSelector.innerHTML = "";

  if (phantom.fibers.source.length > 0) {
    // Add *none* option
    var option = document.createElement("option");
    option.text = '*none*'
    option.selected = true;
    // If any fiber is being edited, move to non-edit mode
    option.onclick = function() {
      if (guiStatus.editingRegion === undefined) {
        guiStatus.unediting();
        guiStatus.retrieve();
      };
      resizeGUI();
    };
    fiberSelector.options.add(option);
    fiberSelector.disabled = false;

    // Add the rest of the options
    phantom.fibers.source.forEach( function(fiber, index) {
      var backgroundColor = fiber.color;

      var option = document.createElement("option");
      var selectColorSpan = document.createElement("span");
      var selectTextSpan = document.createElement("span");
      selectColorSpan.style.color = backgroundColor.getStyle();
      selectColorSpan.innerHTML = '■ ';

      selectTextSpan.innerHTML = fiber.controlPoints.length.toString() + " points";

      option.appendChild(selectColorSpan);
      option.appendChild(selectTextSpan);

      option.onmouseover = function() {phantom.fiberHighlight(index);};
      option.onclick = function() {fiberSelectClick(index);};
      fiberSelector.options.add(option);
    });
  } else {
    fiberSelector.disabled = true;
  }

  if (phantom.isotropicRegions.source.length > 0) {
    // Add *none* option
    var option = document.createElement("option");
    option.text = '*none*'
    option.selected = true;
    // If any fiber is being edited, move to non-edit mode
    option.onclick = function() {
      if (guiStatus.editingFiber === undefined) {
        guiStatus.unediting();
        guiStatus.retrieve();
      };
      resizeGUI();
    };
    regionSelector.options.add(option);
    regionSelector.disabled = false;

    // Add the rest of the options
    phantom.isotropicRegions.source.forEach( function(region, index) {
      var backgroundColor = region.color;

      var option = document.createElement("option");
      var selectColorSpan = document.createElement("span");
      var selectTextSpan = document.createElement("span");
      selectColorSpan.style.color = backgroundColor.getStyle();
      selectColorSpan.innerHTML = '■ ';

      selectTextSpan.innerHTML = "radius " + region.radius.toString();

      option.appendChild(selectColorSpan);
      option.appendChild(selectTextSpan);

      option.onmouseover = function() {phantom.regionHighlight(index);};
      option.onclick = function() {regionSelectClick(index);};
      regionSelector.options.add(option);
    });
  } else {
    regionSelector.disabled = true;
  }

  editExit();
}

// Add element buttons are only available when no element is being edited
function editExit() {
  var editGUI = document.getElementById('editGUI');
  editGUI.innerHTML = ""

  var newfiberbutton = document.createElement("BUTTON");
  var newregionbutton = document.createElement("BUTTON");
  editGUI.appendChild(newfiberbutton);
  editGUI.appendChild(newregionbutton);

  newfiberbutton.innerHTML = "New Fiber";
  newfiberbutton.onclick = function() { newFiberClick() };

  newregionbutton.innerHTML = "New Region";
  newregionbutton.onclick = function() { newIsotropicRegionClick() };
}
<commit_msg>New element buttons styled for right align<commit_after>var guiStatus;

function setupGUI() {
  guiStatus =  new GuiStatus();
  resizeGUI();

  var fiberSelector = document.getElementById("fiberSelector");
  var regionSelector = document.getElementById("regionSelector");
  // Empty them - this function might be called for GUIupdating
  fiberSelector.innerHTML = "";
  regionSelector.innerHTML = "";

  if (phantom.fibers.source.length > 0) {
    // Add *none* option
    var option = document.createElement("option");
    option.text = '*none*'
    option.selected = true;
    // If any fiber is being edited, move to non-edit mode
    option.onclick = function() {
      if (guiStatus.editingRegion === undefined) {
        guiStatus.unediting();
        guiStatus.retrieve();
      };
      resizeGUI();
    };
    fiberSelector.options.add(option);
    fiberSelector.disabled = false;

    // Add the rest of the options
    phantom.fibers.source.forEach( function(fiber, index) {
      var backgroundColor = fiber.color;

      var option = document.createElement("option");
      var selectColorSpan = document.createElement("span");
      var selectTextSpan = document.createElement("span");
      selectColorSpan.style.color = backgroundColor.getStyle();
      selectColorSpan.innerHTML = '■ ';

      selectTextSpan.innerHTML = fiber.controlPoints.length.toString() + " points";

      option.appendChild(selectColorSpan);
      option.appendChild(selectTextSpan);

      option.onmouseover = function() {phantom.fiberHighlight(index);};
      option.onclick = function() {fiberSelectClick(index);};
      fiberSelector.options.add(option);
    });
  } else {
    fiberSelector.disabled = true;
  }

  if (phantom.isotropicRegions.source.length > 0) {
    // Add *none* option
    var option = document.createElement("option");
    option.text = '*none*'
    option.selected = true;
    // If any fiber is being edited, move to non-edit mode
    option.onclick = function() {
      if (guiStatus.editingFiber === undefined) {
        guiStatus.unediting();
        guiStatus.retrieve();
      };
      resizeGUI();
    };
    regionSelector.options.add(option);
    regionSelector.disabled = false;

    // Add the rest of the options
    phantom.isotropicRegions.source.forEach( function(region, index) {
      var backgroundColor = region.color;

      var option = document.createElement("option");
      var selectColorSpan = document.createElement("span");
      var selectTextSpan = document.createElement("span");
      selectColorSpan.style.color = backgroundColor.getStyle();
      selectColorSpan.innerHTML = '■ ';

      selectTextSpan.innerHTML = "radius " + region.radius.toString();

      option.appendChild(selectColorSpan);
      option.appendChild(selectTextSpan);

      option.onmouseover = function() {phantom.regionHighlight(index);};
      option.onclick = function() {regionSelectClick(index);};
      regionSelector.options.add(option);
    });
  } else {
    regionSelector.disabled = true;
  }

  editExit();
}

// Add element buttons are only available when no element is being edited
function editExit() {
  var editGUI = document.getElementById('editGUI');
  editGUI.innerHTML = ""

  var newfiberbutton = document.createElement("BUTTON");
  newfiberbutton.style.float = "right";
  newfiberbutton.innerHTML = "New Fiber";
  newfiberbutton.onclick = function() { newFiberClick() };

  var newregionbutton = document.createElement("BUTTON");
  newregionbutton.style.float = "right";
  newregionbutton.innerHTML = "New Region";
  newregionbutton.onclick = function() { newIsotropicRegionClick() };

  // As style is float, must be appended from right to left
  editGUI.appendChild(newregionbutton);
  editGUI.appendChild(newfiberbutton);
}
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp'),
  gulpLoadPlugins = require('gulp-load-plugins'),
  request = require('request'),
  karmaServer = require('karma').Server,
  _ = require('lodash'),
  fs = require('fs'),
  assets = require('../config/assets.json');
var plugins = gulpLoadPlugins();

process.env.NODE_ENV = 'test';

gulp.task('test', ['startServer', 'stopServer']);
gulp.task('startServer', function(done) {
  var promise = require('../server.js');

  promise.then(function(app){done();});
});
gulp.task('stopServer', ['runKarma'], function() {
  process.exit();
});
gulp.task('runMocha', ['startServer'], function () {
  return gulp.src('./packages/**/server/tests/**/*.spec.js', {read: false})
    .pipe(plugins.mocha({
      reporter: 'spec'
    }))
    .on('error', function(error){
      console.error(error);
      this.emit('end');
    });
});
gulp.task('runKarma', ['runMocha'], function (done) {
  request('http://localhost:3001/api/aggregatedassets', function(error, response, body) {
    var aggregatedassets = JSON.parse(body);
    aggregatedassets = processIncludes(aggregatedassets.footer.js);

    var karma = new karmaServer({
      configFile: __dirname + '/../karma.conf.js',
      singleRun: true,
      files: aggregatedassets.concat(['packages/**/public/tests/**/*.js', 'packages/**/public/**/*.html'])
    }, function () {
      done();
    });

    karma.start();
  });
});

function processIncludes(aggregatedAssets) {
  for(var i = 0; i < aggregatedAssets.length; ++i) {
    aggregatedAssets[i] = aggregatedAssets[i].slice(1);
    if(aggregatedAssets[i].indexOf('bower_components/') === -1) {
      var index = aggregatedAssets[i].indexOf('/') + 1;
      aggregatedAssets[i] = aggregatedAssets[i].substring(0, index) + "public/" + aggregatedAssets[i].substring(index);
    }
    try {
      fs.lstatSync(__dirname + '/../packages/core/' + aggregatedAssets[i]);
      aggregatedAssets[i] = 'packages/core/' + aggregatedAssets[i];
      continue;
    } catch(e) {
      // Not a file
    }
    try {
      fs.lstatSync(__dirname + '/../packages/custom/' + aggregatedAssets[i]);
      aggregatedAssets[i] = 'packages/custom/' + aggregatedAssets[i];
    } catch (e) {
      // Not a file
    }
  }
  return aggregatedAssets;
}<commit_msg>lodash and assets never used<commit_after>'use strict';

var gulp = require('gulp'),
  gulpLoadPlugins = require('gulp-load-plugins'),
  request = require('request'),
  karmaServer = require('karma').Server,
  fs = require('fs');
var plugins = gulpLoadPlugins();

process.env.NODE_ENV = 'test';

gulp.task('test', ['startServer', 'stopServer']);
gulp.task('startServer', function(done) {
  var promise = require('../server.js');

  promise.then(function(app){done();});
});
gulp.task('stopServer', ['runKarma'], function() {
  process.exit();
});
gulp.task('runMocha', ['startServer'], function () {
  return gulp.src('./packages/**/server/tests/**/*.spec.js', {read: false})
    .pipe(plugins.mocha({
      reporter: 'spec'
    }))
    .on('error', function(error){
      console.error(error);
      this.emit('end');
    });
});
gulp.task('runKarma', ['runMocha'], function (done) {
  request('http://localhost:3001/api/aggregatedassets', function(error, response, body) {
    var aggregatedassets = JSON.parse(body);
    aggregatedassets = processIncludes(aggregatedassets.footer.js);

    var karma = new karmaServer({
      configFile: __dirname + '/../karma.conf.js',
      singleRun: true,
      files: aggregatedassets.concat(['packages/**/public/tests/**/*.js', 'packages/**/public/**/*.html'])
    }, function () {
      done();
    });

    karma.start();
  });
});

function processIncludes(aggregatedAssets) {
  for(var i = 0; i < aggregatedAssets.length; ++i) {
    aggregatedAssets[i] = aggregatedAssets[i].slice(1);
    if(aggregatedAssets[i].indexOf('bower_components/') === -1) {
      var index = aggregatedAssets[i].indexOf('/') + 1;
      aggregatedAssets[i] = aggregatedAssets[i].substring(0, index) + "public/" + aggregatedAssets[i].substring(index);
    }
    try {
      fs.lstatSync(__dirname + '/../packages/core/' + aggregatedAssets[i]);
      aggregatedAssets[i] = 'packages/core/' + aggregatedAssets[i];
      continue;
    } catch(e) {
      // Not a file
    }
    try {
      fs.lstatSync(__dirname + '/../packages/custom/' + aggregatedAssets[i]);
      aggregatedAssets[i] = 'packages/custom/' + aggregatedAssets[i];
    } catch (e) {
      // Not a file
    }
  }
  return aggregatedAssets;
}<|endoftext|>


<commit_before>module.exports = (GULP, PLUGINS, NODE_MODULES, PATHS, REVISION) => {
    return function (callback) {
        var twig_options = {
            base: PATHS.src,
            errorLogToConsole: true
        }

        var src = GULP.src([
            PATHS.src + '/**/*.twig',
            '!' + PATHS.src + '/**/assets/**/*.twig',
            '!' + PATHS.src + '/**/layouts/**/*.twig',
            '!' + PATHS.src + '/**/partials/*.twig',
        ], {
            nodir: true
        })
        .pipe(PLUGINS.plumber())
        .pipe(PLUGINS.twig(twig_options))
        .pipe(PLUGINS.faker())
        .pipe(GULP.dest(PATHS.dest));

        var modules = GULP.src([
            PATHS.modules + '/**/*.twig'
        ], {
            nodir: true
        })
        .pipe(PLUGINS.plumber())
        .pipe(PLUGINS.twig(twig_options))
        .pipe(PLUGINS.faker())
        .pipe(GULP.dest(PATHS.dest + '/submodules' ));

        return NODE_MODULES.merge(src, modules);
    }
}<commit_msg>Twig generator<commit_after>module.exports = (GULP, PLUGINS, NODE_MODULES, PATHS, REVISION) => {
    return function (callback) {
        var sources = [
            {
                input: [
                    PATHS.src + '/**/*.twig',
                    '!' + PATHS.src + '/**/assets/**/*.twig',
                    '!' + PATHS.src + '/**/layouts/**/*.twig',
                    '!' + PATHS.src + '/**/partials/*.twig',
                ],
                output: ''
            },
            {
                input: [
                    PATHS.packages + '/**/*.twig'
                ],
                output: '/submodules'
            }
        ];

        var streams = [];

        sources.forEach(function(source) {
            var stream = GULP.src(source.input, {
                nodir: true
            })
            .pipe(PLUGINS.plumber())
            .pipe(PLUGINS.twig({
                base: PATHS.src,
                errorLogToConsole: true
            }))
            .pipe(PLUGINS.faker())
            .pipe(GULP.dest(PATHS.dest + source.output));

            streams.push(stream);
        }, this);

        return NODE_MODULES.merge(streams);
    }
}<|endoftext|>


<commit_before>import Class from 'lowclass'
import {Camera as ThreeCamera, Object3D} from 'three'
import Mixin from './Mixin'
import ElementOperations from './ElementOperations'
import Transformable from './Transformable'
import Node from './Node'
import Scene from './Scene'
import Motor from './Motor'
import {isInstanceof} from './Utility'
import {CSS3DObjectNested} from '../lib/three/CSS3DRendererNested'
import {disposeObject} from '../utils/three'
import {Events} from './Events'

window.addEventListener('error', (event) => {
    const error = event.error
    if (/Illegal constructor/i.test(error.message)) {
        console.error(`
            One of the reasons the following error can happen is if a Custom
            Element is called with 'new' before being defined.
            For other reasons, see: https://www.google.com/search?q=chrome%20illegal%20constructor
        `)
    }
})

let three = null
let domPlane = null

// We explicitly use `var` instead of `let` here because it is hoisted for the
// Node and Scene modules. This, along with the following initImperativeBase
// function, allows the circular dependency between this module and the Node and
// Scene modules to work. For details on why, see
// https://esdiscuss.org/topic/how-to-solve-this-basic-es6-module-circular-dependency-problem.
var ImperativeBase

// Here we wrap the definition of the ImperativeBase class with this function in
// order to solve the circular depdendency problem caused by the
// Node<->ImperativeBase and Scene<->ImperativeBase circles. The Node and Scene
// modules call initImperativeBase to ensure that the ImperativeBase declaration
// happens first, and then those modules can use the live binding in their
// declarations.
initImperativeBase()
export function initImperativeBase() {
    if (ImperativeBase) return

    /**
     * The ImperativeBase class is the base class for the Imperative version of the
     * API, for people who chose to take the all-JavaScript approach and who will
     * not use the HTML-based API (infamous/motor-html).
     *
     * In the future when there is an option to disable the HTML-DOM rendering (and
     * render only WebGL, for example) then the imperative API will be the only API
     * available since the HTML API will be turned off as a result of disabling
     * HTML rendering. Disabling both WebGL and HTML won't make sense, as we'll need
     * at least one of those to render with.
     */
    ImperativeBase = Mixin(Base =>

        Class('ImperativeBase').extends( Transformable.mixin( Base ), ({ Super, Public, Private, Protected }) => ({
            constructor(options = {}) {
                const self = Super(this).constructor(options)

                // we don't need this, keep for backward compatibility (mainly
                // all my demos at trusktr.io).
                self.imperativeCounterpart = self

                self._willBeRendered = false

                // Here we create the DOM HTMLElement associated with this
                // Imperative-API Node.
                self._elementOperations = new ElementOperations(self)

                // stores a ref to this Node's root Scene when/if this Node is
                // in a scene.
                self._scene = null

                // See Transformable/Sizeable propertychange event.
                // TODO: defer size calculation to render task
                self.on('propertychange', self._onPropertyChange, self)

                return self
            },

            get glLoaded() {
                return Protected(this).__glLoaded
            },

            get cssLoaded() {
                return Protected(this).__cssLoaded
            },

            get three() {
                // if (!(this.scene && this.scene.experimentalWebgl)) return null

                if (!Private(this).__three) {
                    const three = Private(this).__three = this.makeThreeObject3d()
                    three.pivot = new THREE.Vector3
                }

                return Private(this).__three
            },

            get threeCSS() {
                // if (!(this.scene && !this.scene.disableCss)) return null

                if (!Private(this).__threeCSS) {
                    const threeCSS = Private(this).__threeCSS = this.makeThreeCSSObject()
                    threeCSS.pivot = new THREE.Vector3
                }

                return Private(this).__threeCSS
            },

            connectedCallback() {
                Super(this).connectedCallback()
            },

            _onPropertyChange(prop) {
                if ( prop == 'sizeMode' || prop == 'size' ) {
                    this._calcSize()
                }

                this._needsToBeRendered()
            },

            loadGL() {
                if (!(this.scene && this.scene.experimentalWebgl)) return

                if (Protected(this).__glLoaded) return
                Protected(this).__glLoaded = true

                // we don't let Three update local matrices automatically, we do
                // it ourselves in Transformable._calculateMatrix and
                // Transformable._calculateWorldMatricesInSubtree
                this.three.matrixAutoUpdate = false

                // NOTE, this.parent works here because loadGL is called by
                // childConnectedCallback at which point a child is already
                // upgraded and thus has this.parent API ready.
                this.parent && this.parent.three.add(this.three)

                // If a subclass needs to initialize values in its Three.js
                // object, it will have the passInitialValuesToThree method for
                // that.
                //
                // TODO we shouldn't need to define passInitialValuesToThree in
                // sub classes, the default values of the props should
                // automatically be in place.
                this.passInitialValuesToThree && this.passInitialValuesToThree()

                this._needsToBeRendered()
            },

            unloadGL() {
                if (!Protected(this).__glLoaded) return
                Protected(this).__glLoaded = false

                disposeObject(Private(this).__three)
                Private(this).__three = null

                this._needsToBeRendered()
            },

            makeThreeObject3d() {
                return new Object3D
            },

            loadCSS() {
                if (!(this.scene && !this.scene.disableCss)) return

                if (Protected(this).__cssLoaded) return
                Protected(this).__cssLoaded = true

                // we don't let Three update local matrices automatically, we do
                // it ourselves in Transformable._calculateMatrix and
                // Transformable._calculateWorldMatricesInSubtree
                this.threeCSS.matrixAutoUpdate = false

                // NOTE, this.parent works here because loadCSS is called by
                // childConnectedCallback at which point a child is already
                // upgraded and thus has this.parent API ready.
                this.parent && this.parent.threeCSS.add(this.threeCSS)

                this._needsToBeRendered()
            },

            unloadCSS() {
                if (!Protected(this).__cssLoaded) return
                Protected(this).__cssLoaded = false

                disposeObject(Private(this).__threeCSS)
                Private(this).__threeCSS = null

                this._needsToBeRendered()
            },

            makeThreeCSSObject() {
                return new CSS3DObjectNested(this)
            },

            childConnectedCallback(child) {
                Super(this).childConnectedCallback(child)

                // children can be non-lib DOM nodes (f.e. div, h1, etc)
                if (isInstanceof(child, Node)) {
                    child.__loadGL()
                    child.__loadCSS()
                }
            },

            childDisconnectedCallback(child) {
                Super(this).childDisconnectedCallback(child)

                // children can be non-lib DOM nodes (f.e. div, h1, etc)
                if (isInstanceof(child, Node)) {
                    child.__unloadGL()
                    child.__unloadCSS()
                }
            },

            /**
             * Subclasses are required to override this. It should return the HTML-API
             * counterpart for this Imperative-API instance. See Node or Scene classes
             * for example.
             *
             * @private
             */
            _makeElement() {
                throw new Error('Subclasses need to override ImperativeBase#_makeElement.')
            },

            /**
             * Get the Scene that this Node is in, null if no Scene. This traverses up recursively
             * at first, then the value is cached.
             *
             * @readonly
             */
            get scene() {
                // NOTE: this._scene is initally null, created in the constructor.

                // if already cached, return it. Or if no parent, return it (it'll be null).
                // Additionally, Scenes have this._scene already set to themselves.
                if (this._scene || !this.parent) return this._scene

                // if the parent node already has a ref to the scene, use that.
                if (this.parent._scene) {
                    this._scene = this.parent._scene
                }
                else if (this.parent instanceof Scene) {
                    this._scene = this.parent
                }
                // otherwise call the scene getter on the parent, which triggers
                // traversal up the scene graph in order to find the root scene (null
                // if none).
                else {
                    this._scene = this.parent.scene
                }

                return this._scene
            },

            /**
             * @override
             */
            add(childNode) {
                if (!isInstanceof(childNode, ImperativeBase)) return

                // We cannot add Scenes to Nodes, for now.
                if (childNode instanceof Scene) {
                    throw new Error(`
                        A Scene cannot be added to another Node or Scene (at
                        least for now). To place a Scene in a Node, just mount
                        a new Scene onto a MotorHTMLNode with Scene.mount().
                    `)
                }

                Super(this).add(childNode)

                // Calculate sizing because proportional size might depend on
                // the new parent.
                childNode._calcSize()
                childNode._needsToBeRendered()

                // child should watch the parent for size changes.
                this.on('sizechange', childNode._onParentSizeChange)

                this._elementOperations.connectChildElement(childNode)

                return this
            },

            remove(childNode, /* private */__leaveInDom) {
                if (!(childNode instanceof Node)) return

                Super(this).remove(childNode)

                this.off('sizechange', childNode._onParentSizeChange)

                if (!__leaveInDom)
                    this._elementOperations.disconnectChildElement(childNode)
            },

            _needsToBeRendered() {
                // we don't need to render until we're connected into a tree with a scene.
                if (!this.scene || !this.isConnected) return
                // TODO make sure we render when connected into a tree with a scene

                this._willBeRendered = true
                Motor.setNodeToBeRendered(this)
            },

            // This method is used by Motor._renderNodes().
            _getNearestAncestorThatShouldBeRendered() {
                let parent = this.parent

                while (parent) {
                    if (parent._willBeRendered) return parent
                    parent = parent.parent
                }

                return false
            },

            _render(timestamp) {
                if ( Super(this)._render ) Super(this)._render()

                this._elementOperations.applyImperativeNodeProperties(this)
            },

            // TODO make a classes prop?
            // set properties(properties = {}) {
            //     Super(this).properties = properties
            //
            //     if (properties.classes)
            //         this._elementOperations.setClasses(...properties.classes);
            // },

            protected: {
                __glLoaded: false,
                __cssLoaded: false,
            },

            private: {
                __three: null,
                __threeCSS: null,
            },

            // FIXME, these should be protected, but the use of Mixin breaks the
            // access helper. We'll fix this in lowclass.
            // protected: {
                __loadGL() {
                    Public(this).loadGL()
                    Public(this).emit(Events.BEHAVIOR_GL_LOAD, Public(this))
                    Promise.resolve().then(() => {
                        Public(this).emit(Events.GL_LOAD, Public(this))
                    })
                },

                __unloadGL() {
                    Public(this).unloadGL()
                    Public(this).emit(Events.BEHAVIOR_GL_UNLOAD, Public(this))
                    Promise.resolve().then(() => {
                        Public(this).emit(Events.GL_UNLOAD, Public(this))
                    })
                },

                __loadCSS() {
                    Public(this).loadCSS()
                    Public(this).emit(Events.CSS_LOAD, Public(this))
                },

                __unloadCSS() {
                    Public(this).unloadCSS()
                    Public(this).emit(Events.CSS_UNLOAD, Public(this))
                },
            // }
        }))

    )

}

export {ImperativeBase as default}
<commit_msg>remove empty ImperativeBase method<commit_after>import Class from 'lowclass'
import {Camera as ThreeCamera, Object3D} from 'three'
import Mixin from './Mixin'
import ElementOperations from './ElementOperations'
import Transformable from './Transformable'
import Node from './Node'
import Scene from './Scene'
import Motor from './Motor'
import {isInstanceof} from './Utility'
import {CSS3DObjectNested} from '../lib/three/CSS3DRendererNested'
import {disposeObject} from '../utils/three'
import {Events} from './Events'

window.addEventListener('error', (event) => {
    const error = event.error
    if (/Illegal constructor/i.test(error.message)) {
        console.error(`
            One of the reasons the following error can happen is if a Custom
            Element is called with 'new' before being defined.
            For other reasons, see: https://www.google.com/search?q=chrome%20illegal%20constructor
        `)
    }
})

let three = null
let domPlane = null

// We explicitly use `var` instead of `let` here because it is hoisted for the
// Node and Scene modules. This, along with the following initImperativeBase
// function, allows the circular dependency between this module and the Node and
// Scene modules to work. For details on why, see
// https://esdiscuss.org/topic/how-to-solve-this-basic-es6-module-circular-dependency-problem.
var ImperativeBase

// Here we wrap the definition of the ImperativeBase class with this function in
// order to solve the circular depdendency problem caused by the
// Node<->ImperativeBase and Scene<->ImperativeBase circles. The Node and Scene
// modules call initImperativeBase to ensure that the ImperativeBase declaration
// happens first, and then those modules can use the live binding in their
// declarations.
initImperativeBase()
export function initImperativeBase() {
    if (ImperativeBase) return

    /**
     * The ImperativeBase class is the base class for the Imperative version of the
     * API, for people who chose to take the all-JavaScript approach and who will
     * not use the HTML-based API (infamous/motor-html).
     *
     * In the future when there is an option to disable the HTML-DOM rendering (and
     * render only WebGL, for example) then the imperative API will be the only API
     * available since the HTML API will be turned off as a result of disabling
     * HTML rendering. Disabling both WebGL and HTML won't make sense, as we'll need
     * at least one of those to render with.
     */
    ImperativeBase = Mixin(Base =>

        Class('ImperativeBase').extends( Transformable.mixin( Base ), ({ Super, Public, Private, Protected }) => ({
            constructor(options = {}) {
                const self = Super(this).constructor(options)

                // we don't need this, keep for backward compatibility (mainly
                // all my demos at trusktr.io).
                self.imperativeCounterpart = self

                self._willBeRendered = false

                // Here we create the DOM HTMLElement associated with this
                // Imperative-API Node.
                self._elementOperations = new ElementOperations(self)

                // stores a ref to this Node's root Scene when/if this Node is
                // in a scene.
                self._scene = null

                // See Transformable/Sizeable propertychange event.
                // TODO: defer size calculation to render task
                self.on('propertychange', self._onPropertyChange, self)

                return self
            },

            get glLoaded() {
                return Protected(this).__glLoaded
            },

            get cssLoaded() {
                return Protected(this).__cssLoaded
            },

            get three() {
                // if (!(this.scene && this.scene.experimentalWebgl)) return null

                if (!Private(this).__three) {
                    const three = Private(this).__three = this.makeThreeObject3d()
                    three.pivot = new THREE.Vector3
                }

                return Private(this).__three
            },

            get threeCSS() {
                // if (!(this.scene && !this.scene.disableCss)) return null

                if (!Private(this).__threeCSS) {
                    const threeCSS = Private(this).__threeCSS = this.makeThreeCSSObject()
                    threeCSS.pivot = new THREE.Vector3
                }

                return Private(this).__threeCSS
            },

            _onPropertyChange(prop) {
                if ( prop == 'sizeMode' || prop == 'size' ) {
                    this._calcSize()
                }

                this._needsToBeRendered()
            },

            loadGL() {
                if (!(this.scene && this.scene.experimentalWebgl)) return

                if (Protected(this).__glLoaded) return
                Protected(this).__glLoaded = true

                // we don't let Three update local matrices automatically, we do
                // it ourselves in Transformable._calculateMatrix and
                // Transformable._calculateWorldMatricesInSubtree
                this.three.matrixAutoUpdate = false

                // NOTE, this.parent works here because loadGL is called by
                // childConnectedCallback at which point a child is already
                // upgraded and thus has this.parent API ready.
                this.parent && this.parent.three.add(this.three)

                // If a subclass needs to initialize values in its Three.js
                // object, it will have the passInitialValuesToThree method for
                // that.
                //
                // TODO we shouldn't need to define passInitialValuesToThree in
                // sub classes, the default values of the props should
                // automatically be in place.
                this.passInitialValuesToThree && this.passInitialValuesToThree()

                this._needsToBeRendered()
            },

            unloadGL() {
                if (!Protected(this).__glLoaded) return
                Protected(this).__glLoaded = false

                disposeObject(Private(this).__three)
                Private(this).__three = null

                this._needsToBeRendered()
            },

            makeThreeObject3d() {
                return new Object3D
            },

            loadCSS() {
                if (!(this.scene && !this.scene.disableCss)) return

                if (Protected(this).__cssLoaded) return
                Protected(this).__cssLoaded = true

                // we don't let Three update local matrices automatically, we do
                // it ourselves in Transformable._calculateMatrix and
                // Transformable._calculateWorldMatricesInSubtree
                this.threeCSS.matrixAutoUpdate = false

                // NOTE, this.parent works here because loadCSS is called by
                // childConnectedCallback at which point a child is already
                // upgraded and thus has this.parent API ready.
                this.parent && this.parent.threeCSS.add(this.threeCSS)

                this._needsToBeRendered()
            },

            unloadCSS() {
                if (!Protected(this).__cssLoaded) return
                Protected(this).__cssLoaded = false

                disposeObject(Private(this).__threeCSS)
                Private(this).__threeCSS = null

                this._needsToBeRendered()
            },

            makeThreeCSSObject() {
                return new CSS3DObjectNested(this)
            },

            childConnectedCallback(child) {
                Super(this).childConnectedCallback(child)

                // children can be non-lib DOM nodes (f.e. div, h1, etc)
                if (isInstanceof(child, Node)) {
                    child.__loadGL()
                    child.__loadCSS()
                }
            },

            childDisconnectedCallback(child) {
                Super(this).childDisconnectedCallback(child)

                // children can be non-lib DOM nodes (f.e. div, h1, etc)
                if (isInstanceof(child, Node)) {
                    child.__unloadGL()
                    child.__unloadCSS()
                }
            },

            /**
             * Subclasses are required to override this. It should return the HTML-API
             * counterpart for this Imperative-API instance. See Node or Scene classes
             * for example.
             *
             * @private
             */
            _makeElement() {
                throw new Error('Subclasses need to override ImperativeBase#_makeElement.')
            },

            /**
             * Get the Scene that this Node is in, null if no Scene. This traverses up recursively
             * at first, then the value is cached.
             *
             * @readonly
             */
            get scene() {
                // NOTE: this._scene is initally null, created in the constructor.

                // if already cached, return it. Or if no parent, return it (it'll be null).
                // Additionally, Scenes have this._scene already set to themselves.
                if (this._scene || !this.parent) return this._scene

                // if the parent node already has a ref to the scene, use that.
                if (this.parent._scene) {
                    this._scene = this.parent._scene
                }
                else if (this.parent instanceof Scene) {
                    this._scene = this.parent
                }
                // otherwise call the scene getter on the parent, which triggers
                // traversal up the scene graph in order to find the root scene (null
                // if none).
                else {
                    this._scene = this.parent.scene
                }

                return this._scene
            },

            /**
             * @override
             */
            add(childNode) {
                if (!isInstanceof(childNode, ImperativeBase)) return

                // We cannot add Scenes to Nodes, for now.
                if (childNode instanceof Scene) {
                    throw new Error(`
                        A Scene cannot be added to another Node or Scene (at
                        least for now). To place a Scene in a Node, just mount
                        a new Scene onto a MotorHTMLNode with Scene.mount().
                    `)
                }

                Super(this).add(childNode)

                // Calculate sizing because proportional size might depend on
                // the new parent.
                childNode._calcSize()
                childNode._needsToBeRendered()

                // child should watch the parent for size changes.
                this.on('sizechange', childNode._onParentSizeChange)

                this._elementOperations.connectChildElement(childNode)

                return this
            },

            remove(childNode, /* private */__leaveInDom) {
                if (!(childNode instanceof Node)) return

                Super(this).remove(childNode)

                this.off('sizechange', childNode._onParentSizeChange)

                if (!__leaveInDom)
                    this._elementOperations.disconnectChildElement(childNode)
            },

            _needsToBeRendered() {
                // we don't need to render until we're connected into a tree with a scene.
                if (!this.scene || !this.isConnected) return
                // TODO make sure we render when connected into a tree with a scene

                this._willBeRendered = true
                Motor.setNodeToBeRendered(this)
            },

            // This method is used by Motor._renderNodes().
            _getNearestAncestorThatShouldBeRendered() {
                let parent = this.parent

                while (parent) {
                    if (parent._willBeRendered) return parent
                    parent = parent.parent
                }

                return false
            },

            _render(timestamp) {
                if ( Super(this)._render ) Super(this)._render()

                this._elementOperations.applyImperativeNodeProperties(this)
            },

            // TODO make a classes prop?
            // set properties(properties = {}) {
            //     Super(this).properties = properties
            //
            //     if (properties.classes)
            //         this._elementOperations.setClasses(...properties.classes);
            // },

            protected: {
                __glLoaded: false,
                __cssLoaded: false,
            },

            private: {
                __three: null,
                __threeCSS: null,
            },

            // FIXME, these should be protected, but the use of Mixin breaks the
            // access helper. We'll fix this in lowclass.
            // protected: {
                __loadGL() {
                    Public(this).loadGL()
                    Public(this).emit(Events.BEHAVIOR_GL_LOAD, Public(this))
                    Promise.resolve().then(() => {
                        Public(this).emit(Events.GL_LOAD, Public(this))
                    })
                },

                __unloadGL() {
                    Public(this).unloadGL()
                    Public(this).emit(Events.BEHAVIOR_GL_UNLOAD, Public(this))
                    Promise.resolve().then(() => {
                        Public(this).emit(Events.GL_UNLOAD, Public(this))
                    })
                },

                __loadCSS() {
                    Public(this).loadCSS()
                    Public(this).emit(Events.CSS_LOAD, Public(this))
                },

                __unloadCSS() {
                    Public(this).unloadCSS()
                    Public(this).emit(Events.CSS_UNLOAD, Public(this))
                },
            // }
        }))

    )

}

export {ImperativeBase as default}
<|endoftext|>


<commit_before>function require(path, parent){
  var m, realpath;

  if(parent)
    realpath = require.mods[parent].aliases[path];
  else
    realpath = path;

  if(!realpath)
    realpath = require.virtual( path );

  if(!(m = require.mods[realpath]))
  {
    console.error('Module not found: ', path);
    return null
  }

  if(!m.init)
  {
    m.factory.call(this, require.local(realpath), m.module, m.module.exports);
    m.init = true;
  }

  return m.module.exports;
}

require.mods = {}

require.local = function( path ){
  return function( id ) { return require( id, path ); }
}

require.register = function(path, mod, aliases){
  require.mods[path] = {
    factory: mod,
    aliases: aliases,
    module: {exports:{}}
  };
}

require.virtual = function(path) {
  for(var virtual in require.virtual.conf)
    if(path.indexOf(virtual) == 0)
      return require.virtual.conf[virtual] + path.match(/\/(.+)/)[0];
  return null;
}

require.virtual.conf = ~VIRTUAL;<commit_msg>Optimize browser-require<commit_after>function require(path, parent){
  var m, realpath;

  if(parent)
  {
    realpath = require.mods[parent].aliases[path];
    if(!realpath) realpath = require.virtual( path );
  }
  else
    realpath = path;

  if(!(m = require.mods[realpath]))
    return console.error('Module not found: ', path);

  if(!m.init)
  {
    m.factory.call(this, require.local(realpath), m.module, m.module.exports);
    m.init = true;
  }

  return m.module.exports;
}

require.mods = {}

require.local = function( path ){
  return function( id ) { return require( id, path ); }
}

require.register = function(path, mod, aliases){
  require.mods[path] = {
    factory: mod,
    aliases: aliases,
    module: {exports:{}}
  };
}

require.virtual = function(path) {
  for(var virtual in require.virtual.conf)
    if(path.indexOf(virtual) == 0)
      return require.virtual.conf[virtual] + path.match(/\/(.+)/)[0];
  return null;
}

require.virtual.conf = ~VIRTUAL;<|endoftext|>


<commit_before>var ls = require('ls-r')
var fs = require('graceful-fs')

var relative = require('path').relative

var crypto = require('crypto')
var through = require('through')

function hashStream (alg, encoding) {
  var hash = crypto.createHash(alg || 'sha1')
  return through(function (data) {
    hash.update(data)
  }, function () {
    this.queue(hash.digest(encoding || 'hex'))
    this.queue(null)
  })
}

function hashTree (dir, cb) {

  ls(dir, function (err, _, files) {
    if (err) return cb(err)

    var n = files.length
    var hashes = {}, streams = []

    files.forEach(function (file) {
      if(file.isDirectory())
        return next()

      var rs = fs.createReadStream(file.path)
      streams.push(rs)

      rs.pipe(hashStream())
        .once('data', function (hash) {

          hashes[relative(dir, file.path)] = hash
          next()
        })
    })

    function next(err) {
      if(err) {
        while(streams) streams.shift().destroy()
        return cb(err)
      }
      if(--n) return
      //sort the keys, so that it's possible to consistently hash
      //the hashes object
      var _hashes = {}
      Object.keys(hashes).sort().forEach(function (k) {
        _hashes[k] = hashes[k]
      })
      cb(null, _hashes)
    }
  })
}

exports = module.exports = hashTree
exports.hashStream = hashStream

if(!module.parent)
  hashTree(process.cwd(), console.log)
<commit_msg>filter files to track<commit_after>var ls = require('ls-r')
var fs = require('graceful-fs')

var relative = require('path').relative

var crypto = require('crypto')
var through = require('through')

function hashStream (alg, encoding) {
  var hash = crypto.createHash(alg || 'sha1')
  return through(function (data) {
    hash.update(data)
  }, function () {
    this.queue(hash.digest(encoding || 'hex'))
    this.queue(null)
  })
}

function hashTree (dir, filter, cb) {
  if(!cb)
    cb = filter, filter = null

  ls(dir, function (err, _, files) {
    if (err) return cb(err)

    var n = files.length
    var hashes = {}, streams = []

    files.forEach(function (file) {
      if(file.isDirectory())
        return next()
      var name = relative(dir, file.path)
      if(filter && !filter(name, file))
        return next()
      var rs = fs.createReadStream(file.path)
      streams.push(rs)

      rs.pipe(hashStream())
        .once('data', function (hash) {

          hashes[name] = hash
          next()
        })
    })

    function next(err) {
      if(err) {
        while(streams) streams.shift().destroy()
        return cb(err)
      }
      if(--n) return
      //sort the keys, so that it's possible to consistently hash
      //the hashes object
      var _hashes = {}
      Object.keys(hashes).sort().forEach(function (k) {
        _hashes[k] = hashes[k]
      })
      cb(null, _hashes)
    }
  })
}

exports = module.exports = hashTree
exports.hashStream = hashStream

if(!module.parent)
  hashTree(process.cwd(), console.log)
<|endoftext|>


<commit_before>// Number of pixels to scroll up and down
var LINE = 40;

// Number of pixels to scroll left and right
var COLUMN = 20;

// Lots of pixels jump to the top or bottom of a page
var BIG = 10000000000;

// Modifier Keys
var META = "meta";
var CTRL = "ctrl";
var ALT = "alt";
var SHIFT = "shift";

// Return a ctrl keyboard shortcut
var ctrl = function(a) {
    return CTRL + "+" + a;
}

// Return a meta keyboard shortcut
var meta = function(a) {
    return META + "+" + a;
}

// Return a shift keyboard shortcut
var shift = function(a) {
    return SHIFT + "+" + a;
}

// Module to hold all the keybindings
// I wrote this a while ago, not sure how it works
var hotkeys = function() {
    var matched = false;
    var current = "";
    var combo = "";
    var partialKeyMap = {};
    var fullKeyMap = {};
    var keyMap = {};
    var unrecognized = function(){};

    var keyPress = function() {
	if (partialKeyMap[combo]) {
	    current = combo;
	    matched = true;
	} else if (fullKeyMap[combo]) {
	    matched = true;
	    current = "";
	    fullKeyMap[combo]();
	}
    };

    var keyFn = function(kk){
	return function() {
	    combo = current + kk;
	    keyPress();
	}
    };

    $(document).keydown(function() {
	matched = false;
	command = false;
    });

    $(document).keyup(function() {
	if(!matched) {
	    unrecognized();
	    current = "";
	}
    });

    // Return the hotkeys object
    return {
	setUnrecognized: function(fn){ unrecognized = fn; },
	add: function(k, fn){

	    var keys = k.toLowerCase().split(" ");
	    var seq = "";

	    for ( var i = 0, l = keys.length; i < l; i++ ) {

		//Create a partial mapping
		seq += keys[i];
		if (i < (l - 1)) {
		    partialKeyMap[seq] = true;
		} else {
		    fullKeyMap[seq] = fn;
		}

		//Only maps keys we haven't seen before
		if (!keyMap[ keys[i] ]) {
		    keyMap[ keys[i] ] = true;
		    $(document).bind('keydown', keys[i], keyFn(keys[i]));
		}
	    }
	}
    }
}();

hotkeys.setUnrecognized(function(){});

// HTML Selectors for ConkerChrome elements
var selectors = {
    "conker": "#conkerchrome",
    "commandbar": "#commandbar",
    "commandinput": "#conkerchrome input",
    "number": ".conkerchrome_number"
}

// CSS Selectors for ConkerChrome elements
var css = {
    "highlight": "conkerchrome_highlight",
    "selected": "conkerchrome_selected",
    "number": "conkerchrome_number"
}

var baseMode = {
    "enter": function(){},
    "leave": function(){},
    "update": function(e, bar){}
}

// Current command
var currentMode  = baseMode;

// Create conkerbar
var conkerChrome = function(){

    jQuery(document.body).append("

<input type=\"text\">
");
    var bar = jQuery(selectors.conker);
    var title = jQuery(selectors.commandbar);
    var input = jQuery(selectors.commandinput);

    jQuery('#conkerchrome input').keyup(function(e) {
	var bar = jQuery(e.target);
	if(e.keyCode == 71 && e.ctrlKey){
	    bar.blur();
	    cancel();
	}
	currentMode.update(e, bar);
    });

    return {
	"hide": function(){ bar.hide(); input.val("");},
	"show": function(text){
	    title.text(text);
	    bar.show();
	    input.css({"left": title.width() + 10}).focus();
	}
    };
}();

function showConkerChrome(){
    jQuery(selectors.conker).show();
}

function hideConkerChrome(){
    jQuery(selectors.conker).hide();
}

// Keyboard shortcuts
var cancel = function(){
    conkerChrome.hide();
    currentMode.leave();
    currentMode = baseMode;
};

// Unfocus selected area (such as a textbox)
hotkeys.add("esc", function(){
    $(":focus").blur();
});

// Cancel current command
hotkeys.add(ctrl('g'), cancel);

// Move back one page in the history
hotkeys.add(shift('b'), function() {
    window.history.back();
});

// Move forward one page in the history
hotkeys.add(shift('f'), function() {
    window.history.forward();
});

// Reload the current page
hotkeys.add(ctrl('r'), function() {
    window.location.reload(true);
});

// Movement around the page

// Scroll the page all the way to the right
hotkeys.add(ctrl('a'), function(){
    window.scrollBy(-BIG, 0);
});

// Scroll the page all the way to the left
hotkeys.add(ctrl('e'), function(){
    window.scrollBy(BIG, 0);
});

// Scroll the page forward a column
hotkeys.add(ctrl('f'), function(){
    window.scrollBy(COLUMN, 0);
});

// Scroll the page back a column
hotkeys.add(ctrl('b'), function(){
    window.scrollBy(-COLUMN, 0);
});

// Scroll the page down a line
hotkeys.add(ctrl('n'), function(){
    window.scrollBy(0, LINE);
});

// Scroll the page up a line
hotkeys.add(ctrl('p'), function(){
    window.scrollBy(0, -LINE);
});

// Jump down a page length
hotkeys.add(ctrl('v'), function(){
    window.scrollBy(0, window.innerHeight - LINE);
});

// Jump up a page length
hotkeys.add(meta('v'), function(){
    window.scrollBy(0, -(window.innerHeight - LINE));
});

// Jump to the end of the page
hotkeys.add(meta(shift('.')), function(){
    window.scrollBy(0, BIG);
});

// Jump to the top of the page
hotkeys.add(meta(shift(',')), function(){
    window.scrollBy(0, -BIG);
});

// Open a url
// TODO: Make this work
hotkeys.add('ctrl+x ctrl+f', function() {
    conkerChrome.show();
});

// Close the current tab
hotkeys.add('ctrl+x k', function() {
    chrome.extension.sendRequest({action: "close-tab"});
});

hotkeys.add('f', function (evt){
    followMode.enter();
    currentMode = followMode;
});

// Follow a link on the page
// TODO: Make this work
var followMode = {
    enter: function(){
	jQuery("a").each(function(i, elem){
	    jQuery(this).append(jQuery("
", {"class": css.number, "text": i}))
		.addClass(css.highlight);
	});
	conkerChrome.show("Enter Link ID");
    },
    update: function(e, bar) {
	// Get the selected link or return
	var v = bar.val();
	if (!v) return;
	link = jQuery("a:eq(" + v + ")");
	// If the return was pressed,
	if (e.keyCode == 13) {
	    if (link && link.attr("href")) {
		// If shift+return, open new tab
		if (e.shiftKey) {
		    chrome.extension.sendRequest({
			action: "new-tab",
			url: link.attr("href")
		    });
	    	} else {
		    window.location.href = link.attr("href");
		}
	    }
	} else {
	    jQuery("a." + css.selected).removeClass(css.selected);
	    if (link.hasClass(css.selected))
		return;
	    link.addClass(css.selected);
	}
    },
    leave: function(){
	jQuery("a").removeClass(css.highlight)
	    .removeClass(css.selected);
	jQuery(selectors.number).remove();
    }
}
<commit_msg>Blur bar on cancel, make the code look pretty<commit_after>// Create the ConkerChrome object
var ConkerC = function(opts) {

    // Default options
    var defaults = {
	line: 40,        // Number of pixels to scroll up and down
	column: 20,      // Number of pixels to scroll left and right
	ctrl: "ctrl",    // Default key mappings
	meta: "meta",    // Users can change these
	shift: "shift"   // If they want
    };

    // Load the user provided options
    var options = jQuery.extend({}, defaults, opts);

    // Lots of pixels jump to the top or bottom of a page
    // The user shouldn't be able to set this
    var BIG = 10000000000;

    // HTML Selectors for ConkerChrome elements
    var selectors = {
	conker: "#conkerchrome",
	commandbar: "#commandbar",
	commandinput: "#conkerchrome input",
	number: ".conkerchrome_number"
    }

    // CSS Selectors for ConkerChrome elements
    var css = {
	highlight: "conkerchrome_highlight",
	selected: "conkerchrome_selected",
	number: "conkerchrome_number"
    }

    var baseMode = {
	enter: function(){},
	leave: function(){},
	update: function(e, bar){}
    }

    // Module to hold all the keybindings
    // I wrote this a while ago, not sure how it works
    var hotkeys = function() {
	var matched = false;
	var current = "";
	var combo = "";
	var partialKeyMap = {};
	var fullKeyMap = {};
	var keyMap = {};
	var unrecognized = function(){};

	var keyPress = function() {
	    if (partialKeyMap[combo]) {
		current = combo;
		matched = true;
	    } else if (fullKeyMap[combo]) {
		matched = true;
		current = "";
		fullKeyMap[combo]();
	    }
	};

	var keyFn = function(kk){
	    return function() {
		combo = current + kk;
		keyPress();
	    }
	};

	jQuery(document).keydown(function() {
	    matched = false;
	    command = false;
	});

	jQuery(document).keyup(function() {
	    if(!matched) {
		unrecognized();
		current = "";
	    }
	});

	// Return the hotkeys object
	return {
	    setUnrecognized: function(fn){ unrecognized = fn; },
	    add: function(k, fn){

		var keys = k.toLowerCase().split(" ");
		var seq = "";

		for ( var i = 0, l = keys.length; i < l; i++ ) {

		    //Create a partial mapping
		    seq += keys[i];
		    if (i < (l - 1)) {
			partialKeyMap[seq] = true;
		    } else {
			fullKeyMap[seq] = fn;
		    }

		    //Only maps keys we haven't seen before
		    if (!keyMap[ keys[i] ]) {
			keyMap[ keys[i] ] = true;
			$(document).bind('keydown', keys[i], keyFn(keys[i]));
		    }
		}
	    }
	}
    }();

    // Call this function when an unknown command is entered
    hotkeys.setUnrecognized(function(){});

    // Current mode
    var currentMode  = baseMode;

    // Create conkerbar
    var conkerBar = function(){

	jQuery(document.body).append("

<input type=\"text\">
");
	var bar = jQuery(selectors.conker);
	var title = jQuery(selectors.commandbar);
	var input = jQuery(selectors.commandinput);

	input.keyup(function(e) {
	    if(e.keyCode == 71 && e.ctrlKey){
		cancel();
	    }
	    currentMode.update(e, bar);
	});

	return {
	    hide: function(){ bar.hide(); input.val("").blur();},
	    show: function(text){
		title.text(text);
		bar.show();
		input.css({"left": title.width() + 10}).focus();
	    }
	};
    }();

    // Exit out of the current mode
    var cancel = function(){
	conkerBar.hide();
	currentMode.leave();
	currentMode = baseMode;
    };

    // Unfocus selected area (such as a textbox)
    hotkeys.add("esc", function(){
	$(":focus").blur();
    });

    // Cancel current command
    hotkeys.add("ctrl+g", cancel);

    // Move back one page in the history
    hotkeys.add("shift+b", function() {
	window.history.back();
    });

    // Move forward one page in the history
    hotkeys.add("shift+f", function() {
	window.history.forward();
    });

    // Reload the current page
    hotkeys.add("ctrl+r", function() {
	window.location.reload(true);
    });

    // Movement around the page

    // Scroll the page all the way to the right
    hotkeys.add("ctrl+a", function(){
	window.scrollBy(-BIG, 0);
    });

    // Scroll the page all the way to the left
    hotkeys.add("ctrl+e", function(){
	window.scrollBy(BIG, 0);
    });

    // Scroll the page forward a column
    hotkeys.add("ctrl+f", function(){
	window.scrollBy(options.column, 0);
    });

    // Scroll the page back a column
    hotkeys.add("ctrl+b", function(){
	window.scrollBy(-options.column, 0);
    });

    // Scroll the page down a line
    hotkeys.add("ctrl+n", function(){
	window.scrollBy(0, options.line);
    });

    // Scroll the page up a line
    hotkeys.add("ctrl+p", function(){
	window.scrollBy(0, -options.line);
    });

    // Jump down a page length
    hotkeys.add("ctrl+v", function(){
	window.scrollBy(0, window.innerHeight - options.line);
    });

    // Jump up a page length
    hotkeys.add("meta+v", function(){
	window.scrollBy(0, -(window.innerHeight - options.line));
    });

    // Jump to the end of the page
    hotkeys.add("meta+shift+.", function(){
	window.scrollBy(0, BIG);
    });

    // Jump to the top of the page
    hotkeys.add("meta+shift+,", function(){
	window.scrollBy(0, -BIG);
    });

    // Open a url
    // TODO: Make this work
    hotkeys.add('ctrl+x ctrl+f', function() {
	conkerBar.show();
    });

    // Close the current tab
    hotkeys.add('ctrl+x k', function() {
	chrome.extension.sendRequest({action: "close-tab"});
    });

    hotkeys.add('f', function (evt){
	followMode.enter();
	currentMode = followMode;
    });

    // Follow a link on the page
    var followMode = {
	enter: function(){
	    jQuery("a").each(function(i, elem){
		jQuery(this).append(jQuery("
", {"class": css.number, "text": i}))
		    .addClass(css.highlight);
	    });
	    conkerBar.show("Enter Link ID");
	},
	update: function(e, bar) {
	    // Get the selected link or return
	    var v = bar.val();
	    if (!v) return;
	    link = jQuery("a:eq(" + v + ")");
	    // If the return was pressed,
	    if (e.keyCode == 13) {
		if (link && link.attr("href")) {
		    // If shift+return, open new tab
		    if (e.shiftKey) {
			chrome.extension.sendRequest({
			    action: "new-tab",
			    url: link.attr("href")
			});
	    	    } else {
			window.location.href = link.attr("href");
		    }
		}
	    } else {
		jQuery("a." + css.selected).removeClass(css.selected);
		if (link.hasClass(css.selected))
		    return;
		link.addClass(css.selected);
	    }
	},
	leave: function(){
	    jQuery("a").removeClass(css.highlight)
		.removeClass(css.selected);
	    jQuery(selectors.number).remove();
	}
    }
}({}); //This object will later be a user stored settings file<|endoftext|>


<commit_before>(function(window) {

  var TRANSITION_EVENT = 'transitionend';

  var transitionable = (function() {
    var b = document.body || document.documentElement,
        s = b.style,
        p = 'transition';

    if (typeof s[p] === 'string') {
      return true;
    }

    var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];
    p = p.charAt(0).toUpperCase() + p.substr(1);

    for (var i = 0; i < v.length; i++) {
      if (typeof s[v[i] + p] === 'string') {
        TRANSITION_EVENT = v[i] + p + 'End';
        return true;
      }
    }

    return false;
  }());

  function findTransitionProperties(els) {
    var props = [];
    for (var i = 0; i < els.length; i++) {
      var prop = window.getComputedStyle(els[i])['transition-property'];
      if (prop) {
        prop = prop.split(',').map(function(s) { return s.replace(/\s+/, ''); });
        for (var j = 0; j < prop.length; j++) {
          if (props.indexOf(prop[j]) === -1) {
            props.push(prop[j]);
          }
        }
      }
    }
    return props;
  }

  function cleanArray(arr) {
    var newarr = [];
    for (var i = 0; i < arr.length; i++) {
      if (arr[i].indexOf('-') === -1) {
        newarr.push(arr[i]);
      }
    }
    return newarr;
  }

  function isInArray(arr1, arr2) {
    for (var i = 0; i < arr1.length; i++) {
      if (arr2.indexOf(arr1[i]) === -1) {
        return false;
      }
    }
    return true;
  }

  function intoArray(thing) {
    if (typeof thing === 'undefined') {
      thing = [];
    }
    if (thing instanceof NodeList) {
      thing = Array.prototype.slice.call(thing);
    } else if (!(thing instanceof Array)) {
      thing = [thing];
    }
    return thing;
  }

  function parentAt(el, level) {
    for (var i = 0; i < level; i++) {
      if (!el.parentNode || el === document.body) {
        break;
      }
      el = el.parentNode;
    }
    return el;
  }

  function hasCommonParent(el, level, common) {
    return (parentAt(el, level) === common);
  }

  function findCommonParent(els) {
    var lastParent,
        level = 1;
    for (var i = 0; i < els.length; i++) {
      if (!lastParent) {
        lastParent = parentAt(els[i], level);
        continue;
      }
      if (lastParent && !hasCommonParent(els[i], level, lastParent)) {
        lastParent = null;
        level++;
        i = 0;
      }
    }
    return lastParent || document.body;
  }

  function EventContainer(opts) {
    this.nextRun = opts.nextRun;
    this.waitForContinue = false;
  }

  EventContainer.prototype.continue = function() {
    this.waitForContinue = false;
    return this.nextRun();
  };

  EventContainer.prototype.wait = function() {
    this.waitForContinue = true;
  };

  function Root(els) {
    this.processElements(els);
    this.classes = [];
    this.callbacks = [];
    this.timings = [];
    return this;
  }

  Root.prototype.processElements = function(els) {
    if (typeof els === 'string') {
      var found = document.querySelectorAll(els);
      if (found.length === 0) {
        this.els = [];
        if ((typeof this.deferredEls === 'undefined')) {
          this.deferredEls = els;
        } else {
          this.deferredEls = null;
        }
      } else {
        this.els = intoArray(found);
      }
    } else {
      this.els = intoArray(els);
    }
    this.parent = findCommonParent(this.els);
  };

  Root.prototype.alter = function(cls) {
    if (arguments.length > 1) {
      this.classes.push(Array.prototype.slice.call(arguments));
    } else {
      this.classes.push(intoArray(cls));
    }
    return this;
  };

  Root.prototype.then = function(fn) {
    if (arguments.length > 1) {
      this.callbacks.push(Array.prototype.slice.call(arguments));
    } else {
      this.callbacks.push(intoArray(fn));
    }
    return this;
  };

  Root.prototype.stagger = function(ms, buff) {
    this.timings.push([(ms || 0), (buff || 0)]);
    return this;
  };

  Root.prototype.run = function(current) {

    if (this.deferredEls) {
      this.processElements(this.deferredEls);
    }

    current = current || 0;

    var total = this.classes.length,
        parent = this.parent,
        callbacks = this.callbacks[current] || [],
        classes = this.classes[current] || [],
        timing = this.timings[current] || [0, 0],
        els = this.els,
        len = this.els.length,
        transitionsToFulfill = findTransitionProperties(els),
        self = this;

    var nextRun = function() {
      if (current + 1 < total) {
        self.run(current + 1);
      } else {
        flushCallbacks(current + 1);
      }
    };

    var eventContainer = new EventContainer({
      nextRun: nextRun
    });

    var flushCallbacks = function(start) {
      for (var i = start; i < self.callbacks.length; i++) {
        for (var j = 0; j < self.callbacks[i].length; j++) {
          self.callbacks[i][j](eventContainer, els);
        }
      }
    };

    var runCallbacks = function() {
      for (var i = 0; i < callbacks.length; i++) {
        callbacks[i](eventContainer, els);
      }
      if (!eventContainer.waitForContinue) {
        nextRun();
      }
    };

    var hasFulfilledAllTransitions = function(e) {
      if (!e.target.fulfilledTransitions) {
        e.target.fulfilledTransitions = [];
      }
      if (e.target.fulfilledTransitions.indexOf(e.propertyName) === -1) {
        e.target.fulfilledTransitions.push(e.propertyName);
      }
      if (e.target.fulfilledTransitions.length === transitionsToFulfill.length) {
        e.target.fulfilledTransitions = [];
        return true;
      } else {
        return false;
      }
    };

    var transitionCallback = function(e) {
      if (els.indexOf(e.target) !== -1 &&
          isInArray(cleanArray(classes), Array.prototype.slice.call(e.target.classList)) &&
          hasFulfilledAllTransitions(e)) {
        len--;
        if (len <= 0) {
          parent.removeEventListener(TRANSITION_EVENT, transitionCallback);
          runCallbacks();
        }
      }
    };

    var alterClasses = function() {
      for (var i = 0; i < els.length; i++) {
        window.setTimeout(function(el) {
          return function() {
            for (var j = 0; j < classes.length; j++) {
              if (classes[j].indexOf('-') === 0) {
                el.classList.remove(classes[j].slice(1));
              } else {
                el.classList.add(classes[j]);
              }
            }
          };
        }(els[i]), timing[1] + (i * timing[0]));
      }
    };

    if (transitionable) {
      parent.addEventListener(TRANSITION_EVENT, transitionCallback);
      window.setTimeout(alterClasses, 15);
    } else {
      alterClasses();
      runCallbacks();
    }

    return null;

  };

  function Preloader(src) {
    this.src = src;
    this.callbacks = [];
  }

  Preloader.prototype.then = function(fn) {
    this.callbacks.push(fn);
  };

  Preloader.prototype.run = function() {
    this.img = new window.Image();

    var self = this;

    var runCallbacks = function() {
      for (var i = 0; i < self.callbacks.length; i++) {
        self.callbacks[i](this);
      }
    };

    this.img.onload = this.img.onerror = runCallbacks;

    this.img.src = this.src;
  };

  function RootWrapper(els) {
    this.chain = [];
    if (els) {
      this.on(els);
    }
    return this;
  };

  RootWrapper.prototype.preload = function(src) {
    this.chain.push(new Preloader(src));
    return this;
  };

  RootWrapper.prototype.on = function(els) {
    this.chain.push(new Root(els));
    return this;
  };
  RootWrapper.prototype.thenOn = RootWrapper.prototype.on;

  RootWrapper.prototype.currentRoot = function() {
    return this.chain[this.chain.length - 1];
  };

  RootWrapper.prototype.alter = function() {
    this.currentRoot().alter.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.stagger = function() {
    this.currentRoot().stagger.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.then = function() {
    this.currentRoot().then.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.run = function(current) {
    current = current || 0;

    var total = this.chain.length,
        self = this;

    var nextRun = function() {
      if (current + 1 < total) {
        self.run(current + 1);
      }
    };

    this.chain[current].then(nextRun);
    this.chain[current].run();
  };

  window.converge = {
    preload: function(src) {
      var wrapper = new RootWrapper();
      return wrapper.preload(src);
    },
    on: function(els) {
      return new RootWrapper(els);
    }
  };

}(window));
<commit_msg>attach transitions to fulfill to individual elements<commit_after>(function(window) {

  var TRANSITION_EVENT = 'transitionend';

  var transitionable = (function() {
    var b = document.body || document.documentElement,
        s = b.style,
        p = 'transition';

    if (typeof s[p] === 'string') {
      return true;
    }

    var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];
    p = p.charAt(0).toUpperCase() + p.substr(1);

    for (var i = 0; i < v.length; i++) {
      if (typeof s[v[i] + p] === 'string') {
        TRANSITION_EVENT = v[i] + p + 'End';
        return true;
      }
    }

    return false;
  }());

  function findTransitionProperties(el) {
    var prop = window.getComputedStyle(el)['transition-property'];
    if (prop) {
      prop = prop.split(',').map(function(s) { return s.replace(/\s+/, ''); });
    }
    return prop || [];
  }

  function findAllTransitionProperties(els) {
    var props = [];
    for (var i = 0; i < els.length; i++) {
      var prop = findTransitionProperties(els[i]);
      for (var j = 0; j < prop.length; j++) {
        if (props.indexOf(prop[j]) === -1) {
          props.push(prop[j]);
        }
      }
    }
    return props;
  }

  function cleanArray(arr) {
    var newarr = [];
    for (var i = 0; i < arr.length; i++) {
      if (arr[i].indexOf('-') === -1) {
        newarr.push(arr[i]);
      }
    }
    return newarr;
  }

  function isInArray(arr1, arr2) {
    for (var i = 0; i < arr1.length; i++) {
      if (arr2.indexOf(arr1[i]) === -1) {
        return false;
      }
    }
    return true;
  }

  function intoArray(thing) {
    if (typeof thing === 'undefined') {
      thing = [];
    }
    if (thing instanceof NodeList) {
      thing = Array.prototype.slice.call(thing);
    } else if (!(thing instanceof Array)) {
      thing = [thing];
    }
    return thing;
  }

  function parentAt(el, level) {
    for (var i = 0; i < level; i++) {
      if (!el.parentNode || el === document.body) {
        break;
      }
      el = el.parentNode;
    }
    return el;
  }

  function hasCommonParent(el, level, common) {
    return (parentAt(el, level) === common);
  }

  function findCommonParent(els) {
    var lastParent,
        level = 1;
    for (var i = 0; i < els.length; i++) {
      if (!lastParent) {
        lastParent = parentAt(els[i], level);
        continue;
      }
      if (lastParent && !hasCommonParent(els[i], level, lastParent)) {
        lastParent = null;
        level++;
        i = 0;
      }
    }
    return lastParent || document.body;
  }

  function EventContainer(opts) {
    this.nextRun = opts.nextRun;
    this.waitForContinue = false;
  }

  EventContainer.prototype.continue = function() {
    this.waitForContinue = false;
    return this.nextRun();
  };

  EventContainer.prototype.wait = function() {
    this.waitForContinue = true;
  };

  function Root(els) {
    this.processElements(els);
    this.classes = [];
    this.callbacks = [];
    this.timings = [];
    return this;
  }

  Root.prototype.processElements = function(els) {
    if (typeof els === 'string') {
      var found = document.querySelectorAll(els);
      if (found.length === 0) {
        this.els = [];
        if ((typeof this.deferredEls === 'undefined')) {
          this.deferredEls = els;
        } else {
          this.deferredEls = null;
        }
      } else {
        this.els = intoArray(found);
      }
    } else {
      this.els = intoArray(els);
    }
    this.parent = findCommonParent(this.els);
  };

  Root.prototype.alter = function(cls) {
    if (arguments.length > 1) {
      this.classes.push(Array.prototype.slice.call(arguments));
    } else {
      this.classes.push(intoArray(cls));
    }
    return this;
  };

  Root.prototype.then = function(fn) {
    if (arguments.length > 1) {
      this.callbacks.push(Array.prototype.slice.call(arguments));
    } else {
      this.callbacks.push(intoArray(fn));
    }
    return this;
  };

  Root.prototype.stagger = function(ms, buff) {
    this.timings.push([(ms || 0), (buff || 0)]);
    return this;
  };

  Root.prototype.run = function(current) {

    if (this.deferredEls) {
      this.processElements(this.deferredEls);
    }

    current = current || 0;

    var total = this.classes.length,
        parent = this.parent,
        callbacks = this.callbacks[current] || [],
        classes = this.classes[current] || [],
        timing = this.timings[current] || [0, 0],
        els = this.els,
        len = this.els.length,
        self = this;

    var nextRun = function() {
      if (current + 1 < total) {
        self.run(current + 1);
      } else {
        flushCallbacks(current + 1);
      }
    };

    var eventContainer = new EventContainer({
      nextRun: nextRun
    });

    var flushCallbacks = function(start) {
      for (var i = start; i < self.callbacks.length; i++) {
        for (var j = 0; j < self.callbacks[i].length; j++) {
          self.callbacks[i][j](eventContainer, els);
        }
      }
    };

    var runCallbacks = function() {
      for (var i = 0; i < callbacks.length; i++) {
        callbacks[i](eventContainer, els);
      }
      if (!eventContainer.waitForContinue) {
        nextRun();
      }
    };

    var hasFulfilledAllTransitions = function(e) {
      if (!e.target.fulfilledTransitions) {
        e.target.fulfilledTransitions = [];
        e.target.transitionsToFulfill = findTransitionProperties(e.target);
      }
      if (e.target.fulfilledTransitions.indexOf(e.propertyName) === -1) {
        e.target.fulfilledTransitions.push(e.propertyName);
      }
      if (e.target.fulfilledTransitions.length === e.target.transitionsToFulfill.length) {
        e.target.fulfilledTransitions = [];
        return true;
      } else {
        return false;
      }
    };

    var transitionCallback = function(e) {
      if (els.indexOf(e.target) !== -1 &&
          isInArray(cleanArray(classes), Array.prototype.slice.call(e.target.classList)) &&
          hasFulfilledAllTransitions(e)) {
        len--;
        if (len <= 0) {
          parent.removeEventListener(TRANSITION_EVENT, transitionCallback);
          runCallbacks();
        }
      }
    };

    var alterClasses = function() {
      for (var i = 0; i < els.length; i++) {
        window.setTimeout(function(el) {
          return function() {
            for (var j = 0; j < classes.length; j++) {
              if (classes[j].indexOf('-') === 0) {
                el.classList.remove(classes[j].slice(1));
              } else {
                el.classList.add(classes[j]);
              }
            }
          };
        }(els[i]), timing[1] + (i * timing[0]));
      }
    };

    if (transitionable) {
      parent.addEventListener(TRANSITION_EVENT, transitionCallback);
      window.setTimeout(alterClasses, 15);
    } else {
      alterClasses();
      runCallbacks();
    }

    return null;

  };

  function Preloader(src) {
    this.src = src;
    this.callbacks = [];
  }

  Preloader.prototype.then = function(fn) {
    this.callbacks.push(fn);
  };

  Preloader.prototype.run = function() {
    this.img = new window.Image();

    var self = this;

    var runCallbacks = function() {
      for (var i = 0; i < self.callbacks.length; i++) {
        self.callbacks[i](this);
      }
    };

    this.img.onload = this.img.onerror = runCallbacks;

    this.img.src = this.src;
  };

  function RootWrapper(els) {
    this.chain = [];
    if (els) {
      this.on(els);
    }
    return this;
  };

  RootWrapper.prototype.preload = function(src) {
    this.chain.push(new Preloader(src));
    return this;
  };

  RootWrapper.prototype.on = function(els) {
    this.chain.push(new Root(els));
    return this;
  };
  RootWrapper.prototype.thenOn = RootWrapper.prototype.on;

  RootWrapper.prototype.currentRoot = function() {
    return this.chain[this.chain.length - 1];
  };

  RootWrapper.prototype.alter = function() {
    this.currentRoot().alter.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.stagger = function() {
    this.currentRoot().stagger.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.then = function() {
    this.currentRoot().then.apply(this.currentRoot(),
      Array.prototype.slice.call(arguments)
    );
    return this;
  };

  RootWrapper.prototype.run = function(current) {
    current = current || 0;

    var total = this.chain.length,
        self = this;

    var nextRun = function() {
      if (current + 1 < total) {
        self.run(current + 1);
      }
    };

    this.chain[current].then(nextRun);
    this.chain[current].run();
  };

  window.converge = {
    preload: function(src) {
      var wrapper = new RootWrapper();
      return wrapper.preload(src);
    },
    on: function(els) {
      return new RootWrapper(els);
    }
  };

}(window));
<|endoftext|>