<commit_before>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2013 Sebastian Werner
--------------------------------------------------------------------------------------------------
  Based on ES5-Shim
  https://github.com/kriskowal/es5-shim
  Copyright 2009-2012 by contributors, MIT License
==================================================================================================
*/

"use strict";

(function()
{
  // ES5 15.9.5.43
  // http://es5.github.com/#x15.9.5.43
  // This function returns a String value represent the instance in time
  // represented by this Date object. The format of the String is the Date Time
  // string format defined in 15.9.1.15. All fields are present in the String.
  // The time zone is always UTC, denoted by the suffix Z. If the time value of
  // this object is not a finite Number a RangeError exception is thrown.
  var negativeDate = -62198755200000;
  var negativeYearString = "-000001";

  if (!Date.prototype.toISOString || (new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1))
  {
    core.Main.addMembers("Date",
    {
      toISOString : function()
      {
        var self = this;
        var result, length, value, year, month;
        if (!isFinite(self)) {
          throw new RangeError("Date.prototype.toISOString called on non-finite value.");
        }

        year = self.getUTCFullYear();
        month = self.getUTCMonth();

        // see https://github.com/kriskowal/es5-shim/issues/111
        year += Math.floor(month / 12);
        month = (month % 12 + 12) % 12;

        // the date time string format is specified in 15.9.1.15.
        result = [month + 1, self.getUTCDate(), self.getUTCHours(), self.getUTCMinutes(), self.getUTCSeconds()];

        year = (
          (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
          ("00000" + Math.abs(year))
          .slice(0 <= year && year <= 9999 ? -4 : -6)
        );

        length = result.length;
        while (length--)
        {
          value = result[length];

          // pad months, days, hours, minutes, and seconds to have two digits.
          if (value < 10) {
            result[length] = "0" + value;
          }
        }

        // pad milliseconds to have three digits.
        return (
          year + "-" + result.slice(0, 2).join("-") +
          "T" + result.slice(2).join(":") + "." +
          ("000" + self.getUTCMilliseconds()).slice(-3) + "Z"
        );
      }
    }, true);
  }
})();
<commit_msg>Added minor doc<commit_after>/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2013 Sebastian Werner
--------------------------------------------------------------------------------------------------
  Based on ES5-Shim
  https://github.com/kriskowal/es5-shim
  Copyright 2009-2012 by contributors, MIT License
==================================================================================================
*/

"use strict";

/**
 * Adds or fixes `Date.prototype.toISOString`.
 *
 * See also: http://kangax.github.io/es5-compat-table/
 */
(function()
{
  // ES5 15.9.5.43
  // http://es5.github.com/#x15.9.5.43
  // This function returns a String value represent the instance in time
  // represented by this Date object. The format of the String is the Date Time
  // string format defined in 15.9.1.15. All fields are present in the String.
  // The time zone is always UTC, denoted by the suffix Z. If the time value of
  // this object is not a finite Number a RangeError exception is thrown.
  var negativeDate = -62198755200000;
  var negativeYearString = "-000001";

  if (!Date.prototype.toISOString || (new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1))
  {
    core.Main.addMembers("Date",
    {
      toISOString : function()
      {
        var self = this;
        var result, length, value, year, month;
        if (!isFinite(self)) {
          throw new RangeError("Date.prototype.toISOString called on non-finite value.");
        }

        year = self.getUTCFullYear();
        month = self.getUTCMonth();

        // see https://github.com/kriskowal/es5-shim/issues/111
        year += Math.floor(month / 12);
        month = (month % 12 + 12) % 12;

        // the date time string format is specified in 15.9.1.15.
        result = [month + 1, self.getUTCDate(), self.getUTCHours(), self.getUTCMinutes(), self.getUTCSeconds()];

        year = (
          (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
          ("00000" + Math.abs(year))
          .slice(0 <= year && year <= 9999 ? -4 : -6)
        );

        length = result.length;
        while (length--)
        {
          value = result[length];

          // pad months, days, hours, minutes, and seconds to have two digits.
          if (value < 10) {
            result[length] = "0" + value;
          }
        }

        // pad milliseconds to have three digits.
        return (
          year + "-" + result.slice(0, 2).join("-") +
          "T" + result.slice(2).join(":") + "." +
          ("000" + self.getUTCMilliseconds()).slice(-3) + "Z"
        );
      }
    }, true);
  }
})();
<|endoftext|>


<commit_before>(function () {
  'use strict';

  var colors         = require('colors');
  var strip          = require('cli-color/strip');
  var fs             = require('fs');
  var prompt         = require('prompt-sync');
  var child_process  = require('child_process');
  var pkg            = require('./package.json');
  var oldVersion     = pkg.version;
  var abortCmds      = [ 'git checkout master', 'rm abort push' ];
  var pushCmds       = [ 'rm abort push'];
  var cleanupCmds    = [];
  var defaultOptions = { encoding: 'utf-8' };
  var origin         = 'https://github.com/angular/material.git';
  var lineWidth      = 65;
  var newVersion;

  if (validate()) {
    newVersion = getNewVersion();

    line();

    checkoutVersionBranch();
    updateVersion();
    createChangelog();
    commitChanges();
    tagRelease();
    cloneRepo('bower-material');
    updateBowerVersion();
    cloneRepo('code.material.angularjs.org');
    updateSite();
    updateMaster();
    writeScript('abort', abortCmds.concat(cleanupCmds));
    writeScript('push', pushCmds.concat(cleanupCmds));

    line();
    log('Your repo is ready to be pushed.');
    log('Please look over {{"CHANGELOG.md".cyan}} and make any changes.');
    log('When you are ready, please run "{{"./push".cyan}}" to finish the process.');
    log('If you would like to cancel this release, please run "./abort"');
  }

  //-- utility methods

  function validate () {
    if (exec('npm whoami') !== 'angularcore') {
      err('You must be authenticated with npm as "angularcore" to perform a release.');
    } else if (exec('git rev-parse --abbrev-ref HEAD') !== 'master') {
      err('Releases can only performed from master at this time.');
    } else if (exec('git pull -q --rebase {{origin}} master 2> /dev/null') instanceof Error) {
      err('Please make sure your local branch is synced with origin/master.');
    } else {
      return true;
    }
    function err (msg) {
      var str = 'Error: ' + msg;
      err(str.red);
    }
  }

  function checkoutVersionBranch () {
    exec('git checkout -q -b release/{{newVersion}}');
    abortCmds.push('git branch -D release/{{newVersion}}');
  }

  function updateVersion () {
    start('Updating {{"package.json".cyan}} version from {{oldVersion.cyan}} to {{newVersion.cyan}}...');
    pkg.version = newVersion;
    fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
    done();
    abortCmds.push('git checkout package.json');
    pushCmds.push('git add package.json');
  }

  function createChangelog () {
    start('Generating changelog from {{oldVersion.cyan}} to {{newVersion.cyan}}...');
    exec('gulp changelog --sha=$(git merge-base v{{oldVersion}} HEAD)');
    done();
    abortCmds.push('git checkout CHANGELOG.md');
    pushCmds.push('git add CHANGELOG.md');
  }

  function clear () {
    write("\u001b[2J\u001b[0;0H");
  }

  function getNewVersion () {
    clear();
    var options = getVersionOptions(oldVersion), key, type, version;
    log('The current version is {{oldVersion.cyan}}.');
    log('');
    log('What type of release is this?');
    for (key in options) { log((+key + 1) + ') ' + options[key].cyan); }
    log('');
    write('Please select a new version: ');
    type = prompt();

    if (options[type - 1]) version = options[type - 1];
    else if (type.match(/^\d+\.\d+\.\d+(-rc\d+)?$/)) version = type;
    else throw new Error('Your entry was invalid.');

    if (version.indexOf('rc') < 0) {
      log('');
      write('Is this a release candidate? {{"[yes/no]".cyan}} ');
      if (prompt() === 'yes') version += '-rc1';
    }

    log('');
    log('The new version will be ' + version.cyan + '.');
    write('Is this correct? {{"[yes/no]".cyan}} ');
    return prompt() === 'yes' ? version : getNewVersion();

    function getVersionOptions (version) {
      return version.match(/-rc\d+$/)
          ? [ increment(version, 'rc'),
              increment(version, 'minor') ]
          : [ increment(version, 'patch'),
              increment(version, 'minor'),
              increment(version, 'major') ];

      function increment (versionString, type) {
        var version = parseVersion(versionString);
        if (version.rc) {
          switch (type) {
            case 'minor': version.rc = 0; break;
            case 'rc': version.rc++; break;
          }
        } else {
          version[type]++;
          //-- reset any version numbers lower than the one changed
          switch (type) {
            case 'major': version.minor = 0;
            case 'minor': version.patch = 0;
            case 'patch': version.rc = 0;
          }
        }
        return getVersionString(version);

        function parseVersion (version) {
          var parts = version.split(/\.|\-rc/g);
          return { string: version, major: parts[0], minor: parts[1], patch: parts[2], rc: parts[3] || 0 };
        }

        function getVersionString(version) {
          var str = version.major + '.' + version.minor + '.' + version.patch;
          if (version.rc) str += '-rc' + version.rc;
          return str;
        }
      }
    }
  }

  function tagRelease () {
    start('Tagging release...');
    exec('git tag v{{newVersion}}');
    done();
    abortCmds.push('git tag -d v{{newVersion}}');
    pushCmds.push(
        'git push {{origin}} HEAD',
        'git push --tags'
    );
  }

  function commitChanges () {
    start('Committing changes...');
    exec('git commit -am "release: version {{newVersion}}"');
    done();
    pushCmds.push('git commit --amend --no-edit');
  }

  function cloneRepo (repo) {
    start('Cloning ' + repo.cyan + ' from Github...');
    exec('git clone https://github.com/angular/' + repo + '.git --depth=1 2> /dev/null');
    done();
    cleanupCmds.push('rm -rf ' + repo);
  }

  function fill(str) {
    return str.replace(/\{\{[^\}]+\}\}/g, function (match) {
      return eval(match.substr(2, match.length - 4));
    });
  }

  function writeScript (name, cmds) {
    fs.writeFileSync(name, '#!/usr/bin/env bash\n\n' + fill(cmds.join('\n')));
    exec('chmod +x ' + name);
  }

  function updateBowerVersion () {
    start('Updating bower version...');
    var options = { cwd: './bower-material' },
        bower = require(options.cwd + '/bower.json'),
        pkg = require(options.cwd + '/package.json');
    //-- update versions in config files
    bower.version = pkg.version = newVersion;
    fs.writeFileSync(options.cwd + '/package.json', JSON.stringify(pkg, null, 2));
    fs.writeFileSync(options.cwd + '/bower.json', JSON.stringify(bower, null, 2));
    done();
    start('Building bower files...');
    //-- build files for bower
    exec([
      'rm -rf dist',
      'gulp build',
      'gulp build-all-modules --mode=default',
      'gulp build-all-modules --mode=closure',
      'rm -rf dist/demos'
    ]);
    done();
    start('Copy files into bower repo...');
    //-- copy files over to bower repo
    exec([
      'cp -Rf ../dist/* ./',
      'git add -A',
      'git commit -m "release: version {{newVersion}}"',
      'git tag -f v{{newVersion}}',
      'rm -rf ../dist'
    ], options);
    done();
    //-- add steps to push script
    pushCmds.push(
        comment('push to bower (master and tag) and publish to npm'),
        'cd ' + options.cwd,
        'cp ../CHANGELOG.md .',
        'git add CHANGELOG.md',
        'git commit --amend --no-edit',
        'git push',
        'git push --tags',
        'npm publish',
        'cd ..'
    );
  }

  function updateSite () {
    start('Adding new version of the docs site...');
    var options = { cwd: './code.material.angularjs.org' },
        config  = require(options.cwd + '/docs.json');
    config.versions.unshift(newVersion);
    config.latest = newVersion;
    fs.writeFileSync(options.cwd + '/docs.json', JSON.stringify(config, null, 2));
    //-- build files for bower
    exec([
      'rm -rf dist',
      'gulp docs'
    ]);
    //-- copy files over to site repo
    exec([
      'rm -rf latest',
      'cp -Rf ../dist/docs {{newVersion}}',
      'cp -Rf ../dist/docs latest',
      'git add -A',
      'git commit -m "release: version {{newVersion}}"',
      'rm -rf ../dist'
    ], options);
    done();
    //-- add steps to push script
    pushCmds.push(
        comment('push the site'),
        'cd ' + options.cwd,
        'git push',
        'cd ..'
    );
  }

  function updateMaster () {
    pushCmds.push(
        comment('update package.json in master'),
        'git co master',
        'git pull --rebase {{origin}} master',
        'node -e "' + stringifyFunction(buildCommand) + '"',
        'git add package.json',
        'git commit -m "update version number in package.json to {{newVersion}}"',
        'git push'
    );
    function buildCommand () {
      require('fs').writeFileSync('package.json', JSON.stringify(getUpdatedJson(), null, 2));
      function getUpdatedJson () {
        var json = require('./package.json');
        json.version = '{{newVersion}}';
        return json;
      }
    }
    function stringifyFunction (method) {
      return method
          .toString()
          .split('\n')
          .slice(1, -1)
          .map(function (line) { return line.trim(); })
          .join(' ')
          .replace(/\"/g, '\\\"');
    }
  }

  function done () {
    log('done'.green);
  }

  function exec (cmd, userOptions) {
    if (cmd instanceof Array) {
      return cmd.forEach(function (cmd) { exec(cmd, userOptions); });
    }
    try {
      var options = Object.create(defaultOptions);
      for (var key in userOptions) options[key] = userOptions[key];
      return child_process.execSync(fill(cmd), options).trim();
    } catch (err) {
      return err;
    }
  }

  function comment (msg) {
    return '\n# ' + msg + '\n';
  }

  function start (msg) {
    var parsedMsg = fill(msg),
        msgLength = strip(parsedMsg).length,
        diff = lineWidth - 4 - msgLength;
    write(parsedMsg + Array(diff + 1).join(' '));
  }

  function log (msg) {
    console.log(fill(msg));
  }

  function write (msg) {
    process.stdout.write(fill(msg));
  }

  function line () {
    log(Array(lineWidth + 1).join('-'));
  }
})();
<commit_msg>fix(build): fixes issue where release tag doesn't match release branch<commit_after>(function () {
  'use strict';

  var colors         = require('colors');
  var strip          = require('cli-color/strip');
  var fs             = require('fs');
  var prompt         = require('prompt-sync');
  var child_process  = require('child_process');
  var pkg            = require('./package.json');
  var oldVersion     = pkg.version;
  var abortCmds      = [ 'git checkout master', 'rm abort push' ];
  var pushCmds       = [ 'rm abort push'];
  var cleanupCmds    = [];
  var defaultOptions = { encoding: 'utf-8' };
  var origin         = 'https://github.com/angular/material.git';
  var lineWidth      = 65;
  var newVersion;

  if (validate()) {
    newVersion = getNewVersion();

    line();

    checkoutVersionBranch();
    updateVersion();
    createChangelog();
    commitChanges();
    tagRelease();
    cloneRepo('bower-material');
    updateBowerVersion();
    cloneRepo('code.material.angularjs.org');
    updateSite();
    updateMaster();
    writeScript('abort', abortCmds.concat(cleanupCmds));
    writeScript('push', pushCmds.concat(cleanupCmds));

    line();
    log('Your repo is ready to be pushed.');
    log('Please look over {{"CHANGELOG.md".cyan}} and make any changes.');
    log('When you are ready, please run "{{"./push".cyan}}" to finish the process.');
    log('If you would like to cancel this release, please run "./abort"');
  }

  //-- utility methods

  function validate () {
    if (exec('npm whoami') !== 'angularcore') {
      err('You must be authenticated with npm as "angularcore" to perform a release.');
    } else if (exec('git rev-parse --abbrev-ref HEAD') !== 'master') {
      err('Releases can only performed from master at this time.');
    } else if (exec('git pull -q --rebase {{origin}} master 2> /dev/null') instanceof Error) {
      err('Please make sure your local branch is synced with origin/master.');
    } else {
      return true;
    }
    function err (msg) {
      var str = 'Error: ' + msg;
      err(str.red);
    }
  }

  function checkoutVersionBranch () {
    exec('git checkout -q -b release/{{newVersion}}');
    abortCmds.push('git branch -D release/{{newVersion}}');
  }

  function updateVersion () {
    start('Updating {{"package.json".cyan}} version from {{oldVersion.cyan}} to {{newVersion.cyan}}...');
    pkg.version = newVersion;
    fs.writeFileSync('./package.json', JSON.stringify(pkg, null, 2));
    done();
    abortCmds.push('git checkout package.json');
    pushCmds.push('git add package.json');
  }

  function createChangelog () {
    start('Generating changelog from {{oldVersion.cyan}} to {{newVersion.cyan}}...');
    exec('gulp changelog --sha=$(git merge-base v{{oldVersion}} HEAD)');
    done();
    abortCmds.push('git checkout CHANGELOG.md');
    pushCmds.push('git add CHANGELOG.md');
  }

  function clear () {
    write("\u001b[2J\u001b[0;0H");
  }

  function getNewVersion () {
    clear();
    var options = getVersionOptions(oldVersion), key, type, version;
    log('The current version is {{oldVersion.cyan}}.');
    log('');
    log('What type of release is this?');
    for (key in options) { log((+key + 1) + ') ' + options[key].cyan); }
    log('');
    write('Please select a new version: ');
    type = prompt();

    if (options[type - 1]) version = options[type - 1];
    else if (type.match(/^\d+\.\d+\.\d+(-rc\d+)?$/)) version = type;
    else throw new Error('Your entry was invalid.');

    if (version.indexOf('rc') < 0) {
      log('');
      write('Is this a release candidate? {{"[yes/no]".cyan}} ');
      if (prompt() === 'yes') version += '-rc1';
    }

    log('');
    log('The new version will be ' + version.cyan + '.');
    write('Is this correct? {{"[yes/no]".cyan}} ');
    return prompt() === 'yes' ? version : getNewVersion();

    function getVersionOptions (version) {
      return version.match(/-rc\d+$/)
          ? [ increment(version, 'rc'),
              increment(version, 'minor') ]
          : [ increment(version, 'patch'),
              increment(version, 'minor'),
              increment(version, 'major') ];

      function increment (versionString, type) {
        var version = parseVersion(versionString);
        if (version.rc) {
          switch (type) {
            case 'minor': version.rc = 0; break;
            case 'rc': version.rc++; break;
          }
        } else {
          version[type]++;
          //-- reset any version numbers lower than the one changed
          switch (type) {
            case 'major': version.minor = 0;
            case 'minor': version.patch = 0;
            case 'patch': version.rc = 0;
          }
        }
        return getVersionString(version);

        function parseVersion (version) {
          var parts = version.split(/\.|\-rc/g);
          return { string: version, major: parts[0], minor: parts[1], patch: parts[2], rc: parts[3] || 0 };
        }

        function getVersionString(version) {
          var str = version.major + '.' + version.minor + '.' + version.patch;
          if (version.rc) str += '-rc' + version.rc;
          return str;
        }
      }
    }
  }

  function tagRelease () {
    pushCmds.push(
        'git tag v{{newVersion}}',
        'git push {{origin}} HEAD',
        'git push --tags'
    );
  }

  function commitChanges () {
    start('Committing changes...');
    exec('git commit -am "release: version {{newVersion}}"');
    done();
    pushCmds.push('git commit --amend --no-edit');
  }

  function cloneRepo (repo) {
    start('Cloning ' + repo.cyan + ' from Github...');
    exec('git clone https://github.com/angular/' + repo + '.git --depth=1 2> /dev/null');
    done();
    cleanupCmds.push('rm -rf ' + repo);
  }

  function fill(str) {
    return str.replace(/\{\{[^\}]+\}\}/g, function (match) {
      return eval(match.substr(2, match.length - 4));
    });
  }

  function writeScript (name, cmds) {
    fs.writeFileSync(name, '#!/usr/bin/env bash\n\n' + fill(cmds.join('\n')));
    exec('chmod +x ' + name);
  }

  function updateBowerVersion () {
    start('Updating bower version...');
    var options = { cwd: './bower-material' },
        bower = require(options.cwd + '/bower.json'),
        pkg = require(options.cwd + '/package.json');
    //-- update versions in config files
    bower.version = pkg.version = newVersion;
    fs.writeFileSync(options.cwd + '/package.json', JSON.stringify(pkg, null, 2));
    fs.writeFileSync(options.cwd + '/bower.json', JSON.stringify(bower, null, 2));
    done();
    start('Building bower files...');
    //-- build files for bower
    exec([
      'rm -rf dist',
      'gulp build',
      'gulp build-all-modules --mode=default',
      'gulp build-all-modules --mode=closure',
      'rm -rf dist/demos'
    ]);
    done();
    start('Copy files into bower repo...');
    //-- copy files over to bower repo
    exec([
      'cp -Rf ../dist/* ./',
      'git add -A',
      'git commit -m "release: version {{newVersion}}"',
      'rm -rf ../dist'
    ], options);
    done();
    //-- add steps to push script
    pushCmds.push(
        comment('push to bower (master and tag) and publish to npm'),
        'cd ' + options.cwd,
        'cp ../CHANGELOG.md .',
        'git add CHANGELOG.md',
        'git commit --amend --no-edit',
        'git tag -f v{{newVersion}}',
        'git push',
        'git push --tags',
        'npm publish',
        'cd ..'
    );
  }

  function updateSite () {
    start('Adding new version of the docs site...');
    var options = { cwd: './code.material.angularjs.org' },
        config  = require(options.cwd + '/docs.json');
    config.versions.unshift(newVersion);
    config.latest = newVersion;
    fs.writeFileSync(options.cwd + '/docs.json', JSON.stringify(config, null, 2));
    //-- build files for bower
    exec([
      'rm -rf dist',
      'gulp docs'
    ]);
    //-- copy files over to site repo
    exec([
      'rm -rf latest',
      'cp -Rf ../dist/docs {{newVersion}}',
      'cp -Rf ../dist/docs latest',
      'git add -A',
      'git commit -m "release: version {{newVersion}}"',
      'rm -rf ../dist'
    ], options);
    done();
    //-- add steps to push script
    pushCmds.push(
        comment('push the site'),
        'cd ' + options.cwd,
        'git push',
        'cd ..'
    );
  }

  function updateMaster () {
    pushCmds.push(
        comment('update package.json in master'),
        'git co master',
        'git pull --rebase {{origin}} master',
        'node -e "' + stringifyFunction(buildCommand) + '"',
        'git add package.json',
        'git commit -m "update version number in package.json to {{newVersion}}"',
        'git push'
    );
    function buildCommand () {
      require('fs').writeFileSync('package.json', JSON.stringify(getUpdatedJson(), null, 2));
      function getUpdatedJson () {
        var json = require('./package.json');
        json.version = '{{newVersion}}';
        return json;
      }
    }
    function stringifyFunction (method) {
      return method
          .toString()
          .split('\n')
          .slice(1, -1)
          .map(function (line) { return line.trim(); })
          .join(' ')
          .replace(/\"/g, '\\\"');
    }
  }

  function done () {
    log('done'.green);
  }

  function exec (cmd, userOptions) {
    if (cmd instanceof Array) {
      return cmd.forEach(function (cmd) { exec(cmd, userOptions); });
    }
    try {
      var options = Object.create(defaultOptions);
      for (var key in userOptions) options[key] = userOptions[key];
      return child_process.execSync(fill(cmd), options).trim();
    } catch (err) {
      return err;
    }
  }

  function comment (msg) {
    return '\n# ' + msg + '\n';
  }

  function start (msg) {
    var parsedMsg = fill(msg),
        msgLength = strip(parsedMsg).length,
        diff = lineWidth - 4 - msgLength;
    write(parsedMsg + Array(diff + 1).join(' '));
  }

  function log (msg) {
    console.log(fill(msg));
  }

  function write (msg) {
    process.stdout.write(fill(msg));
  }

  function line () {
    log(Array(lineWidth + 1).join('-'));
  }
})();
<|endoftext|>


<commit_before>// Backbone.D3View.js 0.1.0
// ---------------

//     (c) 2014 Adam Krebs
//     Backbone.D3View may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/akre54/Backbone.D3View

(function (factory) {
  if (typeof define === 'function' && define.amd) { define(['backbone', 'd3'], factory);
  } else if (typeof exports === 'object') { factory(require('backbone'), require('d3'));
  } else { factory(Backbone, d3); }
}(function (Backbone, d3) {

  // Cached regex to match an opening '<' of an HTML tag, possibly left-padded
  // with whitespace.
  var paddedLt = /^\s*</;

  // Cache array methods for later use.
  var slice = [].slice;

  // Events need a unique id for attaching multiple events of the same type.
  var uniqueId = 0;

  // Cache Backbone.View for use in `constructor`.
  var BBView = Backbone.View;

  Backbone.D3ViewMixin = {

    // Store eventsMap for undelegation
    _eventsMap: null,

    // A reference to the d3 selection backing the view
    d3el: null,

    constructor: function() {
      this._eventsMap = {};
      BBView.apply(this, arguments);
    },

    $: function(selector) {
      return this.d3el.selectAll(selector)[0];
    },

    _removeElement: function() {
      this.undelegateEvents();
      this.d3el.remove();
    },

    _setElement: function(element) {
      if (typeof element == 'string') {
        if (paddedLt.test(element)) {
          var el = document.createElement('div');
          el.innerHTML = element;
          this.el = el.firstChild;
        } else {
          this.el = document.querySelector(element);
        }
      } else {
        this.el = element;
      }

      this.d3el = d3.select(this.el);
    },

    _setAttributes: function(attributes) {
      this.d3el.attr(attributes);
    },

    // `delegate` supports two- and three-arg forms. The `selector` is optional.
    delegate: function(eventName, selector, listener) {
      var el;

      if (typeof selector === 'string') {
        el = selector === '' ? this.d3el : this.d3el.selectAll(selector);
      } else {
        el = this.d3el;
        listener = selector;
        selector = null;
      }

      // d3 needs `uniqueId` to delegate more than one listener per event type.
      var namespace = '.' + uniqueId++;

      (this._eventsMap[eventName] || (this._eventsMap[eventName] = [])).push({
        selector: selector,
        listener: listener,
        namespace: namespace
      });

      // The `event` object is stored in `d3.event` but Backbone expects it as
      // the first argument to the listener.
      el.on(eventName + namespace, function() {
        var args = slice.call(arguments);
        args.unshift(d3.event)
        listener.apply(this, args);
      });
      return this;
    },

    undelegate: function(eventName, selector, listener) {
      if (typeof selector !== 'string') {
        listener = selector;
        selector = null;
      }

      var handlers = this._eventsMap[eventName];

      _(handlers).chain()
        .filter(function(item) {
          return (listener ? item.listener === listener : true) &&
            (selector ? item.selector === selector : true);
        })
        .forEach(function(item) {
          var el = (selector || (!selector && item.selector)) ? this.d3el.selectAll(selector || item.selector) : this.d3el;
          el.on(eventName + item.namespace, null);
          handlers.splice(_.indexOf(handlers, item), 1);
        }, this);
    },

    undelegateEvents: function() {
      if (!this.d3el) return;

      _.each(this._eventsMap, function(handlers, eventName) {
        _.each(handlers, function(item) {
          this.undelegate(eventName, item.selector)
        }, this);
      }, this);
      this._eventsMap = {};
      return this;
    }
  };

  Backbone.D3View = Backbone.View.extend(Backbone.D3ViewMixin);

  return Backbone.D3View;
}));
<commit_msg>Avoid a costly loop through handlers for `undelegateEvents` and cleanup some logic<commit_after>// Backbone.D3View.js 0.1.0
// ---------------

//     (c) 2014 Adam Krebs
//     Backbone.D3View may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/akre54/Backbone.D3View

(function (factory) {
  if (typeof define === 'function' && define.amd) { define(['backbone', 'd3'], factory);
  } else if (typeof exports === 'object') { factory(require('backbone'), require('d3'));
  } else { factory(Backbone, d3); }
}(function (Backbone, d3) {

  // Cached regex to match an opening '<' of an HTML tag, possibly left-padded
  // with whitespace.
  var paddedLt = /^\s*</;

  // Cache array methods for later use.
  var slice = [].slice;

  // Events need a unique id for attaching multiple events of the same type.
  var uniqueId = 0;

  // Cache Backbone.View for use in `constructor`.
  var BBView = Backbone.View;

  Backbone.D3ViewMixin = {

    // Store eventsMap for undelegation
    _eventsMap: null,

    // A reference to the d3 selection backing the view
    d3el: null,

    constructor: function() {
      this._eventsMap = {};
      BBView.apply(this, arguments);
    },

    $: function(selector) {
      return this.d3el.selectAll(selector)[0];
    },

    _removeElement: function() {
      this.undelegateEvents();
      this.d3el.remove();
    },

    _setElement: function(element) {
      if (typeof element == 'string') {
        if (paddedLt.test(element)) {
          var el = document.createElement('div');
          el.innerHTML = element;
          this.el = el.firstChild;
        } else {
          this.el = document.querySelector(element);
        }
      } else {
        this.el = element;
      }

      this.d3el = d3.select(this.el);
    },

    _setAttributes: function(attributes) {
      this.d3el.attr(attributes);
    },

    // `delegate` supports two- and three-arg forms. The `selector` is optional.
    delegate: function(eventName, selector, listener) {
      var el;

      if (typeof selector === 'string') {
        el = selector === '' ? this.d3el : this.d3el.selectAll(selector);
      } else {
        el = this.d3el;
        listener = selector;
        selector = null;
      }

      // d3 needs `uniqueId` to delegate more than one listener per event type.
      var namespace = '.' + uniqueId++;

      (this._eventsMap[eventName] || (this._eventsMap[eventName] = [])).push({
        selector: selector,
        listener: listener,
        namespace: namespace
      });

      // The `event` object is stored in `d3.event` but Backbone expects it as
      // the first argument to the listener.
      el.on(eventName + namespace, function() {
        var args = slice.call(arguments);
        args.unshift(d3.event)
        listener.apply(this, args);
      });
      return this;
    },

    undelegate: function(eventName, selector, listener) {
      if (typeof selector !== 'string') {
        listener = selector;
        selector = null;
      }

      var handlers = this._eventsMap[eventName];

      _(handlers).chain()
        .filter(function(item) {
          return (listener ? item.listener === listener : true) &&
            (selector ? item.selector === selector : true);
        })
        .forEach(function(item) {
          removeEvent(this.d3el, eventName, selector || item.selector, item.namespace);
          handlers.splice(_.indexOf(handlers, item), 1);
        }, this);
    },

    undelegateEvents: function() {
      if (!this.d3el) return;

      for (var eventName in this._eventsMap) {
        var handlers = this._eventsMap[eventName];
        for (var i = 0, len = handlers.length; i < len; i++) {
          var item = handlers[i];
          removeEvent(this.d3el, eventName, item.selector, item.namespace);
        }
      }

      this._eventsMap = {};
      return this;
    }
  };

  // Avoid a costly loop through handlers for `undelegateEvents`
  var removeEvent = function(d3el, eventName, selector, namespace) {
    var el = selector ? d3el.selectAll(selector) : d3el;
    el.on(eventName + namespace, null);
  }

  Backbone.D3View = Backbone.View.extend(Backbone.D3ViewMixin);

  return Backbone.D3View;
}));
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//  Copyright (C) 2008-2012  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Utilities
//============================================================================
IPython.namespace('IPython.utils');

IPython.utils = (function (IPython) {

    //============================================================================
    // Cross-browser RegEx Split
    //============================================================================

    // This code has been MODIFIED from the code licensed below to not replace the
    // default browser split.  The license is reproduced here.

    // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
    /*!
     * Cross-Browser Split 1.1.1
     * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
     * Available under the MIT License
     * ECMAScript compliant, uniform cross-browser split method
     */

    /**
     * Splits a string into an array of strings using a regex or string
     * separator. Matches of the separator are not included in the result array.
     * However, if `separator` is a regex that contains capturing groups,
     * backreferences are spliced into the result each time `separator` is
     * matched. Fixes browser bugs compared to the native
     * `String.prototype.split` and can be used reliably cross-browser.
     * @param {String} str String to split.
     * @param {RegExp|String} separator Regex or string to use for separating
     *     the string.
     * @param {Number} [limit] Maximum number of items to include in the result
     *     array.
     * @returns {Array} Array of substrings.
     * @example
     *
     * // Basic use
     * regex_split('a b c d', ' ');
     * // -> ['a', 'b', 'c', 'd']
     *
     * // With limit
     * regex_split('a b c d', ' ', 2);
     * // -> ['a', 'b']
     *
     * // Backreferences in result array
     * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
     * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
     */
    var regex_split = function (str, separator, limit) {
        // If `separator` is not a regex, use `split`
        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
            return split.call(str, separator, limit);
        }
        var output = [],
            flags = (separator.ignoreCase ? "i" : "") +
                    (separator.multiline  ? "m" : "") +
                    (separator.extended   ? "x" : "") + // Proposed for ES6
                    (separator.sticky     ? "y" : ""), // Firefox 3+
            lastLastIndex = 0,
            // Make `global` and avoid `lastIndex` issues by working with a copy
            separator = new RegExp(separator.source, flags + "g"),
            separator2, match, lastIndex, lastLength;
        str += ""; // Type-convert

        var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
        if (!compliantExecNpcg) {
            // Doesn't need flags gy, but they don't hurt
            separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
        }
        /* Values for `limit`, per the spec:
         * If undefined: 4294967295 // Math.pow(2, 32) - 1
         * If 0, Infinity, or NaN: 0
         * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
         * If negative number: 4294967296 - Math.floor(Math.abs(limit))
         * If other: Type-convert, then use the above rules
         */
        limit = typeof(limit) === "undefined" ?
            -1 >>> 0 : // Math.pow(2, 32) - 1
            limit >>> 0; // ToUint32(limit)
        while (match = separator.exec(str)) {
            // `separator.lastIndex` is not reliable cross-browser
            lastIndex = match.index + match[0].length;
            if (lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));
                // Fix browsers whose `exec` methods don't consistently return `undefined` for
                // nonparticipating capturing groups
                if (!compliantExecNpcg && match.length > 1) {
                    match[0].replace(separator2, function () {
                        for (var i = 1; i < arguments.length - 2; i++) {
                            if (typeof(arguments[i]) === "undefined") {
                                match[i] = undefined;
                            }
                        }
                    });
                }
                if (match.length > 1 && match.index < str.length) {
                    Array.prototype.push.apply(output, match.slice(1));
                }
                lastLength = match[0].length;
                lastLastIndex = lastIndex;
                if (output.length >= limit) {
                    break;
                }
            }
            if (separator.lastIndex === match.index) {
                separator.lastIndex++; // Avoid an infinite loop
            }
        }
        if (lastLastIndex === str.length) {
            if (lastLength || !separator.test("")) {
                output.push("");
            }
        } else {
            output.push(str.slice(lastLastIndex));
        }
        return output.length > limit ? output.slice(0, limit) : output;
    };

    //============================================================================
    // End contributed Cross-browser RegEx Split
    //============================================================================

    var uuid = function () {
        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789ABCDEF";
        for (var i = 0; i < 32; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[12] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
        s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01

        var uuid = s.join("");
        return uuid;
    };

    //Fix raw text to parse correctly in crazy XML
    function xmlencode(string) {
        return string.replace(/\&/g,'&'+'amp;')
            .replace(/</g,'&'+'lt;')
            .replace(/>/g,'&'+'gt;')
            .replace(/\'/g,'&'+'apos;')
            .replace(/\"/g,'&'+'quot;')
            .replace(/`/g,'&'+'#96;');
    }

    //Map from terminal commands to CSS classes
    var ansi_colormap = {
        "01":"ansibold",

        "30":"ansiblack",
        "31":"ansired",
        "32":"ansigreen",
        "33":"ansiyellow",
        "34":"ansiblue",
        "35":"ansipurple",
        "36":"ansicyan",
        "37":"ansigray",

        "40":"ansibgblack",
        "41":"ansibgred",
        "42":"ansibggreen",
        "44":"ansibgyellow",
        "44":"ansibgblue",
        "45":"ansibgpurple",
        "46":"ansibgcyan",
        "47":"ansibggray"
    };

    function _process_numbers(attrs, numbers) {
        // process ansi escapes
        var n = numbers.shift();
        if (ansi_colormap[n]) {
            if ( ! attrs["class"] ) {
                attrs["class"] = ansi_colormap[n];
            } else {
                attrs["class"] += " " + ansi_colormap[n];
            }
        } else if (n == "38" || n == "48") {
            // VT100 256 color or 24 bit RGB
            if (numbers.length < 2) {
                console.log("Not enough fields for VT100 color", numbers);
                return;
            }

            var index_or_rgb = numbers.shift();
            var r,g,b;
            if (index_or_rgb == "5") {
                // 256 color
                var idx = parseInt(numbers.shift());
                if (idx < 16) {
                    // indexed ANSI
                    // ignore bright / non-bright distinction
                    idx = idx % 8;
                    var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
                    if ( ! attrs["class"] ) {
                        attrs["class"] = ansiclass;
                    } else {
                        attrs["class"] += " " + ansiclass;
                    }
                    return;
                } else if (idx < 232) {
                    // 216 color 6x6x6 RGB
                    idx = idx - 16;
                    b = idx % 6;
                    g = Math.floor(idx / 6) % 6;
                    r = Math.floor(idx / 36) % 6;
                    // convert to rgb
                    r = (r * 51);
                    g = (g * 51);
                    b = (b * 51);
                } else {
                    // grayscale
                    idx = idx - 231;
                    // it's 1-24 and should *not* include black or white,
                    // so a 26 point scale
                    r = g = b = Math.floor(idx * 256 / 26);
                }
            } else if (index_or_rgb == "2") {
                // Simple 24 bit RGB
                if (numbers.length > 3) {
                    console.log("Not enough fields for RGB", numbers);
                    return;
                }
                r = numbers.shift();
                g = numbers.shift();
                b = numbers.shift();
            } else {
                console.log("unrecognized control", numbers);
                return;
            }
            if (r !== undefined) {
                // apply the rgb color
                var line;
                if (n == "38") {
                    line = "color: ";
                } else {
                    line = "background-color: ";
                }
                line = line + "rgb(" + r + "," + g + "," + b + ");"
                if ( !attrs["style"] ) {
                    attrs["style"] = line;
                } else {
                    attrs["style"] += " " + line;
                }
            }
        }
    }

    function ansispan(str) {
        // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
        // regular ansi escapes (using the table above)
        return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
            if (!pattern) {
                // [(01|22|39|)m close spans
                return "";
            }
            // consume sequence of color escapes
            var numbers = pattern.match(/\d+/g);
            var attrs = {};
            while (numbers.length > 0) {
                _process_numbers(attrs, numbers);
            }

            var span = "";
        });
    };

    // Transform ANSI color escape codes into HTML  tags with css
    // classes listed in the above ansi_colormap object. The actual color used
    // are set in the css file.
    function fixConsole(txt) {
        txt = xmlencode(txt);
        var re = /\033\[([\dA-Fa-f;]*?)m/;
        var opened = false;
        var cmds = [];
        var opener = "";
        var closer = "";

        // Strip all ANSI codes that are not color related.  Matches
        // all ANSI codes that do not end with "m".
        var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
        txt = txt.replace(ignored_re, "");

        // color ansi codes
        txt = ansispan(txt);
        return txt;
    }

    // Remove chunks that should be overridden by the effect of
    // carriage return characters
    function fixCarriageReturn(txt) {
        var tmp = txt;
        do {
            txt = tmp;
            tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
            tmp = tmp.replace(/^.*\r+/gm, '');  // Other \r --> clear line
        } while (tmp.length < txt.length);
        return txt;
    }

    // Locate any URLs and convert them to a anchor tag
    function autoLinkUrls(txt) {
        return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
            "$1$2$3");
    }

    // some keycodes that seem to be platform/browser independent
    var keycodes = {
                BACKSPACE:  8,
                TAB      :  9,
                ENTER    : 13,
                SHIFT    : 16,
                CTRL     : 17,
                CONTROL  : 17,
                ALT      : 18,
                CAPS_LOCK: 20,
                ESC      : 27,
                SPACE    : 32,
                PGUP     : 33,
                PGDOWN   : 34,
                END      : 35,
                HOME     : 36,
                LEFT_ARROW: 37,
                LEFTARROW: 37,
                LEFT     : 37,
                UP_ARROW : 38,
                UPARROW  : 38,
                UP       : 38,
                RIGHT_ARROW:39,
                RIGHTARROW:39,
                RIGHT    : 39,
                DOWN_ARROW: 40,
                DOWNARROW: 40,
                DOWN     : 40,
                // all three of these keys may be COMMAND on OS X:
                LEFT_SUPER : 91,
                RIGHT_SUPER : 92,
                COMMAND  : 93,
    };

    var points_to_pixels = function (points) {
        // A reasonably good way of converting between points and pixels.
        var test = $('

');
        $(body).append(test);
        var pixel_per_point = test.width()/10000;
        test.remove();
        return Math.floor(points*pixel_per_point);
    };

    // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
    browser = (function() {
        var N= navigator.appName, ua= navigator.userAgent, tem;
        var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
        if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
        M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
        return M;
    })();

    return {
        regex_split : regex_split,
        uuid : uuid,
        fixConsole : fixConsole,
        keycodes : keycodes,
        fixCarriageReturn : fixCarriageReturn,
        autoLinkUrls : autoLinkUrls,
        points_to_pixels : points_to_pixels,
        browser : browser
    };

}(IPython));

<commit_msg>Fix ansi color code for background yellow<commit_after>//----------------------------------------------------------------------------
//  Copyright (C) 2008-2012  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// Utilities
//============================================================================
IPython.namespace('IPython.utils');

IPython.utils = (function (IPython) {

    //============================================================================
    // Cross-browser RegEx Split
    //============================================================================

    // This code has been MODIFIED from the code licensed below to not replace the
    // default browser split.  The license is reproduced here.

    // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
    /*!
     * Cross-Browser Split 1.1.1
     * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
     * Available under the MIT License
     * ECMAScript compliant, uniform cross-browser split method
     */

    /**
     * Splits a string into an array of strings using a regex or string
     * separator. Matches of the separator are not included in the result array.
     * However, if `separator` is a regex that contains capturing groups,
     * backreferences are spliced into the result each time `separator` is
     * matched. Fixes browser bugs compared to the native
     * `String.prototype.split` and can be used reliably cross-browser.
     * @param {String} str String to split.
     * @param {RegExp|String} separator Regex or string to use for separating
     *     the string.
     * @param {Number} [limit] Maximum number of items to include in the result
     *     array.
     * @returns {Array} Array of substrings.
     * @example
     *
     * // Basic use
     * regex_split('a b c d', ' ');
     * // -> ['a', 'b', 'c', 'd']
     *
     * // With limit
     * regex_split('a b c d', ' ', 2);
     * // -> ['a', 'b']
     *
     * // Backreferences in result array
     * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
     * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
     */
    var regex_split = function (str, separator, limit) {
        // If `separator` is not a regex, use `split`
        if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
            return split.call(str, separator, limit);
        }
        var output = [],
            flags = (separator.ignoreCase ? "i" : "") +
                    (separator.multiline  ? "m" : "") +
                    (separator.extended   ? "x" : "") + // Proposed for ES6
                    (separator.sticky     ? "y" : ""), // Firefox 3+
            lastLastIndex = 0,
            // Make `global` and avoid `lastIndex` issues by working with a copy
            separator = new RegExp(separator.source, flags + "g"),
            separator2, match, lastIndex, lastLength;
        str += ""; // Type-convert

        var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
        if (!compliantExecNpcg) {
            // Doesn't need flags gy, but they don't hurt
            separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
        }
        /* Values for `limit`, per the spec:
         * If undefined: 4294967295 // Math.pow(2, 32) - 1
         * If 0, Infinity, or NaN: 0
         * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
         * If negative number: 4294967296 - Math.floor(Math.abs(limit))
         * If other: Type-convert, then use the above rules
         */
        limit = typeof(limit) === "undefined" ?
            -1 >>> 0 : // Math.pow(2, 32) - 1
            limit >>> 0; // ToUint32(limit)
        while (match = separator.exec(str)) {
            // `separator.lastIndex` is not reliable cross-browser
            lastIndex = match.index + match[0].length;
            if (lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));
                // Fix browsers whose `exec` methods don't consistently return `undefined` for
                // nonparticipating capturing groups
                if (!compliantExecNpcg && match.length > 1) {
                    match[0].replace(separator2, function () {
                        for (var i = 1; i < arguments.length - 2; i++) {
                            if (typeof(arguments[i]) === "undefined") {
                                match[i] = undefined;
                            }
                        }
                    });
                }
                if (match.length > 1 && match.index < str.length) {
                    Array.prototype.push.apply(output, match.slice(1));
                }
                lastLength = match[0].length;
                lastLastIndex = lastIndex;
                if (output.length >= limit) {
                    break;
                }
            }
            if (separator.lastIndex === match.index) {
                separator.lastIndex++; // Avoid an infinite loop
            }
        }
        if (lastLastIndex === str.length) {
            if (lastLength || !separator.test("")) {
                output.push("");
            }
        } else {
            output.push(str.slice(lastLastIndex));
        }
        return output.length > limit ? output.slice(0, limit) : output;
    };

    //============================================================================
    // End contributed Cross-browser RegEx Split
    //============================================================================

    var uuid = function () {
        // http://www.ietf.org/rfc/rfc4122.txt
        var s = [];
        var hexDigits = "0123456789ABCDEF";
        for (var i = 0; i < 32; i++) {
            s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
        }
        s[12] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
        s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01

        var uuid = s.join("");
        return uuid;
    };

    //Fix raw text to parse correctly in crazy XML
    function xmlencode(string) {
        return string.replace(/\&/g,'&'+'amp;')
            .replace(/</g,'&'+'lt;')
            .replace(/>/g,'&'+'gt;')
            .replace(/\'/g,'&'+'apos;')
            .replace(/\"/g,'&'+'quot;')
            .replace(/`/g,'&'+'#96;');
    }

    //Map from terminal commands to CSS classes
    var ansi_colormap = {
        "01":"ansibold",

        "30":"ansiblack",
        "31":"ansired",
        "32":"ansigreen",
        "33":"ansiyellow",
        "34":"ansiblue",
        "35":"ansipurple",
        "36":"ansicyan",
        "37":"ansigray",

        "40":"ansibgblack",
        "41":"ansibgred",
        "42":"ansibggreen",
        "43":"ansibgyellow",
        "44":"ansibgblue",
        "45":"ansibgpurple",
        "46":"ansibgcyan",
        "47":"ansibggray"
    };

    function _process_numbers(attrs, numbers) {
        // process ansi escapes
        var n = numbers.shift();
        if (ansi_colormap[n]) {
            if ( ! attrs["class"] ) {
                attrs["class"] = ansi_colormap[n];
            } else {
                attrs["class"] += " " + ansi_colormap[n];
            }
        } else if (n == "38" || n == "48") {
            // VT100 256 color or 24 bit RGB
            if (numbers.length < 2) {
                console.log("Not enough fields for VT100 color", numbers);
                return;
            }

            var index_or_rgb = numbers.shift();
            var r,g,b;
            if (index_or_rgb == "5") {
                // 256 color
                var idx = parseInt(numbers.shift());
                if (idx < 16) {
                    // indexed ANSI
                    // ignore bright / non-bright distinction
                    idx = idx % 8;
                    var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
                    if ( ! attrs["class"] ) {
                        attrs["class"] = ansiclass;
                    } else {
                        attrs["class"] += " " + ansiclass;
                    }
                    return;
                } else if (idx < 232) {
                    // 216 color 6x6x6 RGB
                    idx = idx - 16;
                    b = idx % 6;
                    g = Math.floor(idx / 6) % 6;
                    r = Math.floor(idx / 36) % 6;
                    // convert to rgb
                    r = (r * 51);
                    g = (g * 51);
                    b = (b * 51);
                } else {
                    // grayscale
                    idx = idx - 231;
                    // it's 1-24 and should *not* include black or white,
                    // so a 26 point scale
                    r = g = b = Math.floor(idx * 256 / 26);
                }
            } else if (index_or_rgb == "2") {
                // Simple 24 bit RGB
                if (numbers.length > 3) {
                    console.log("Not enough fields for RGB", numbers);
                    return;
                }
                r = numbers.shift();
                g = numbers.shift();
                b = numbers.shift();
            } else {
                console.log("unrecognized control", numbers);
                return;
            }
            if (r !== undefined) {
                // apply the rgb color
                var line;
                if (n == "38") {
                    line = "color: ";
                } else {
                    line = "background-color: ";
                }
                line = line + "rgb(" + r + "," + g + "," + b + ");"
                if ( !attrs["style"] ) {
                    attrs["style"] = line;
                } else {
                    attrs["style"] += " " + line;
                }
            }
        }
    }

    function ansispan(str) {
        // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
        // regular ansi escapes (using the table above)
        return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
            if (!pattern) {
                // [(01|22|39|)m close spans
                return "";
            }
            // consume sequence of color escapes
            var numbers = pattern.match(/\d+/g);
            var attrs = {};
            while (numbers.length > 0) {
                _process_numbers(attrs, numbers);
            }

            var span = "";
        });
    };

    // Transform ANSI color escape codes into HTML  tags with css
    // classes listed in the above ansi_colormap object. The actual color used
    // are set in the css file.
    function fixConsole(txt) {
        txt = xmlencode(txt);
        var re = /\033\[([\dA-Fa-f;]*?)m/;
        var opened = false;
        var cmds = [];
        var opener = "";
        var closer = "";

        // Strip all ANSI codes that are not color related.  Matches
        // all ANSI codes that do not end with "m".
        var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
        txt = txt.replace(ignored_re, "");

        // color ansi codes
        txt = ansispan(txt);
        return txt;
    }

    // Remove chunks that should be overridden by the effect of
    // carriage return characters
    function fixCarriageReturn(txt) {
        var tmp = txt;
        do {
            txt = tmp;
            tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
            tmp = tmp.replace(/^.*\r+/gm, '');  // Other \r --> clear line
        } while (tmp.length < txt.length);
        return txt;
    }

    // Locate any URLs and convert them to a anchor tag
    function autoLinkUrls(txt) {
        return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
            "$1$2$3");
    }

    // some keycodes that seem to be platform/browser independent
    var keycodes = {
                BACKSPACE:  8,
                TAB      :  9,
                ENTER    : 13,
                SHIFT    : 16,
                CTRL     : 17,
                CONTROL  : 17,
                ALT      : 18,
                CAPS_LOCK: 20,
                ESC      : 27,
                SPACE    : 32,
                PGUP     : 33,
                PGDOWN   : 34,
                END      : 35,
                HOME     : 36,
                LEFT_ARROW: 37,
                LEFTARROW: 37,
                LEFT     : 37,
                UP_ARROW : 38,
                UPARROW  : 38,
                UP       : 38,
                RIGHT_ARROW:39,
                RIGHTARROW:39,
                RIGHT    : 39,
                DOWN_ARROW: 40,
                DOWNARROW: 40,
                DOWN     : 40,
                // all three of these keys may be COMMAND on OS X:
                LEFT_SUPER : 91,
                RIGHT_SUPER : 92,
                COMMAND  : 93,
    };

    var points_to_pixels = function (points) {
        // A reasonably good way of converting between points and pixels.
        var test = $('

');
        $(body).append(test);
        var pixel_per_point = test.width()/10000;
        test.remove();
        return Math.floor(points*pixel_per_point);
    };

    // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
    browser = (function() {
        var N= navigator.appName, ua= navigator.userAgent, tem;
        var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
        if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
        M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
        return M;
    })();

    return {
        regex_split : regex_split,
        uuid : uuid,
        fixConsole : fixConsole,
        keycodes : keycodes,
        fixCarriageReturn : fixCarriageReturn,
        autoLinkUrls : autoLinkUrls,
        points_to_pixels : points_to_pixels,
        browser : browser
    };

}(IPython));

<|endoftext|>


<commit_before>import { action } from '@ember/object';
import { tagName } from '@ember-decorators/component';
import Component from '@ember/component';
import listenTo from 'ember-bootstrap/utils/cp/listen-to';
import defaultValue from 'ember-bootstrap/utils/default-decorator';
import deprecateSubclassing from 'ember-bootstrap/utils/deprecate-subclassing';

/**
  Bootstrap-style [accordion group](http://getbootstrap.com/javascript/#collapse-example-accordion),
  with collapsible/expandable items.

  ### Usage

  Use as a block level component with any number of yielded [Components.AccordionItem](Components.AccordionItem.html)
  components as children:

  ```handlebars
  <BsAccordion as |Acc|>
    <Acc.item @value={{1}} @title="First item">
      <p>Lorem ipsum...</p>
      <button onclick={{action acc.change 2}}>Next</button>
    </Acc.item>
    <Acc.item @value={{2}} @title="Second item">
      <p>Lorem ipsum...</p>
    </Acc.item>
    <Acc.item @value={{3}} @title="Third item">
      <p>Lorem ipsum...</p>
    </Acc.item>
  </BsAccordion>
  ```

  In the example above the first accordion item utilizes the yielded `change` action to add some custom behaviour.

  *Note that only invoking the component in a template as shown above is considered part of its public API. Extending from it (subclassing) is generally not supported, and may break at any time.*

  @class Accordion
  @namespace Components
  @extends Ember.Component
  @public
*/
@tagName('')
@deprecateSubclassing
export default class Accordion extends Component {
  /**
   * The value of the currently selected accordion item. Set this to change selection programmatically.
   *
   * When the selection is changed by user interaction this property will not update by using two-way bindings in order
   * to follow DDAU best practices. If you want to react to such changes, subscribe to the `onChange` action
   *
   * @property selected
   * @public
   */
  @defaultValue
  selected = null;

  /**
   * @property itemComponent
   * @type {String}
   * @private
   */
  @defaultValue
  itemComponent = 'bs-accordion/item';

  /**
   * The value of the currently selected accordion item
   *
   * @property isSelected
   * @private
   */
  @listenTo('selected')
  isSelected;

  /**
   * Action when the selected accordion item is about to be changed.
   *
   * You can return false to prevent changing the active item, and do that in your action by
   * setting the `selected` accordingly.
   *
   * @event onChange
   * @param newValue
   * @param oldValue
   * @public
   */
  onChange(newValue, oldValue) {} // eslint-disable-line no-unused-vars

  @action
  doChange(newValue) {
    let oldValue = this.isSelected;
    if (oldValue === newValue) {
      newValue = null;
    }
    if (this.onChange(newValue, oldValue) !== false) {
      this.set('isSelected', newValue);
    }
  }
}
<commit_msg>fix usage example in accordion docs<commit_after>import { action } from '@ember/object';
import { tagName } from '@ember-decorators/component';
import Component from '@ember/component';
import listenTo from 'ember-bootstrap/utils/cp/listen-to';
import defaultValue from 'ember-bootstrap/utils/default-decorator';
import deprecateSubclassing from 'ember-bootstrap/utils/deprecate-subclassing';

/**
  Bootstrap-style [accordion group](http://getbootstrap.com/javascript/#collapse-example-accordion),
  with collapsible/expandable items.

  ### Usage

  Use as a block level component with any number of yielded [Components.AccordionItem](Components.AccordionItem.html)
  components as children:

  ```handlebars
  <BsAccordion as |acc|>
    <acc.item @value={{1}} @title="First item">
      <p>Lorem ipsum...</p>
      <button {{on "click" (fn acc.change 2)}}>
        Next
      </button>
    </acc.item>
    <acc.item @value={{2}} @title="Second item">
      <p>Lorem ipsum...</p>
    </acc.item>
    <acc.item @value={{3}} @title="Third item">
      <p>Lorem ipsum...</p>
    </acc.item>
  </BsAccordion>
  ```

  In the example above the first accordion item utilizes the yielded `change` action to add some custom behaviour.

  *Note that only invoking the component in a template as shown above is considered part of its public API. Extending from it (subclassing) is generally not supported, and may break at any time.*

  @class Accordion
  @namespace Components
  @extends Ember.Component
  @public
*/
@tagName('')
@deprecateSubclassing
export default class Accordion extends Component {
  /**
   * The value of the currently selected accordion item. Set this to change selection programmatically.
   *
   * When the selection is changed by user interaction this property will not update by using two-way bindings in order
   * to follow DDAU best practices. If you want to react to such changes, subscribe to the `onChange` action
   *
   * @property selected
   * @public
   */
  @defaultValue
  selected = null;

  /**
   * @property itemComponent
   * @type {String}
   * @private
   */
  @defaultValue
  itemComponent = 'bs-accordion/item';

  /**
   * The value of the currently selected accordion item
   *
   * @property isSelected
   * @private
   */
  @listenTo('selected')
  isSelected;

  /**
   * Action when the selected accordion item is about to be changed.
   *
   * You can return false to prevent changing the active item, and do that in your action by
   * setting the `selected` accordingly.
   *
   * @event onChange
   * @param newValue
   * @param oldValue
   * @public
   */
  onChange(newValue, oldValue) {} // eslint-disable-line no-unused-vars

  @action
  doChange(newValue) {
    let oldValue = this.isSelected;
    if (oldValue === newValue) {
      newValue = null;
    }
    if (this.onChange(newValue, oldValue) !== false) {
      this.set('isSelected', newValue);
    }
  }
}
<|endoftext|>


<commit_before>var dom           = require('./dom')('')
var ReactDatalist = require('../react-datalist')
var assert        = require('assert')
var _             = require('lodash')
var React         = require('react')
var nanodom       = require('nanodom')
var ReactAddons   = require('react/addons')

var ReactTestUtils = React.addons.TestUtils

/** VARIABLES **/

var filterSetter;
var setFilter    = function(fn) { filterSetter = fn }
var options      = ['apple','orange','pear','pineapple','melon']
var defaultProps = {options:options, list:'fruit', forcePoly:true, setFilter:setFilter}

/** HELPER FUNCTIONS **/

function render(props, callback) {
    return React.renderComponent(ReactDatalist(_.merge(defaultProps, props)), document.body, function() {
        if (typeof callback === 'function') setTimeout(callback)
    })
}
function setInputValue(datalist, value) {
     var __input   = nanodom('.react-datalist-input')[0]
     var _input    = ReactTestUtils.findRenderedDOMComponentWithTag(datalist, 'input')
     __input.value = value
    ReactTestUtils.Simulate.change(_input)
}
function clickOption(datalist, index) {
    var _options = ReactTestUtils.scryRenderedDOMComponentsWithClass(datalist, 'react-datalist-option')
    ReactTestUtils.Simulate.click(_options[index])
}

/** TESTS **/

describe('DATALIST', function() {

    afterEach(function(done) {
        React.unmountComponentAtNode(document.body)
        document.body.innerHTML = ""
        setTimeout(done)
    })

    it('Should render a container, an input and a datalist', function(done) {
        render({},function() {
            var __datalist = nanodom('.react-datalist')
            assert(__datalist.length == 1)
            var __container = nanodom('.react-datalist-container')
            assert(__container.length == 1)
            var __input = nanodom('.react-datalist-input')
            assert(__input.length == 1)
            done()
        })
    })

    it('Should be able to filter options', function(done) {
        var _datalist = render({},function() {
            var filtered = _datalist.filterOptions(options, null)
            assert(filtered.length === options.length)
            filtered = _datalist.filterOptions(options)
            assert(filtered.length === options.length)
            filtered = _datalist.filterOptions(options, "p")
            assert(filtered.length === 3)
            filtered = _datalist.filterOptions(options, "lon")
            assert(filtered.length === 1)
            done()
        })
    })

    it('Should support setting initial input value throught initialFilter property', function(done) {
        render({initialFilter : 'meh'}, function() {
            var __input = nanodom('.react-datalist-input')[0]
            assert(__input.value === 'meh')
            done()
        })
    })

    it('Should render a datalist with the passed options', function(done) {
        var _datalist = render({}, function() {
            setInputValue(_datalist, '')
            var domlist = nanodom('.react-datalist')
            assert(domlist.length == 1)
            assert(domlist[0].childNodes.length == options.length)
            assert(domlist[0].id == 'fruit')
            done()
        })
    })

    it('Filter options should change when the input value changes', function(done) {
        var _datalist = render({}, function() {
            var __datalist = nanodom('.react-datalist')[0]
            setInputValue(_datalist, '')
            assert(__datalist.childNodes.length == options.length)
            setInputValue(_datalist, 'melon')
            assert(__datalist.childNodes.length == 1)
            done()
        })
    })

    it('Should call its callback', function(done) {
        var onInputChange = function(event) {
            assert(true)
            done()
        }
        var _datalist = render({ onInputChange : onInputChange }, function() {
            setInputValue(_datalist, 'p')
        })
    })

    // it('Can navigate options with arrow keys', function() {
    //     setInputValue('')
    //     var __datalist = nanodom('.react-datalist')[0]
    //     var __input    = nanodom('.react-datalist-input')[0]
    //     var _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     assert(__datalist.childNodes.length == options.length)
    //     // Down to first item
    //     ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
    //     var __option = nanodom('.react-datalist-option-selected')
    //     assert(__option.length == 1)
    //     assert(__option[0].innerHTML == options[0])
    //     // Down to second item
    //     ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
    //     var __option = nanodom('.react-datalist-option-selected')
    //     assert(__option.length == 1)
    //     assert(__option[0].innerHTML == options[1])
    //     // Up to first item
    //     ReactTestUtils.Simulate.keyDown(_input, {which: 38, type: "keydown"})
    //     var __option = nanodom('.react-datalist-option-selected')
    //     assert(__option.length == 1)
    //     assert(__option[0].innerHTML == options[0])
    // })

    // it('Can select an option by hitting enter', function(done) {
    //     var onOptionSelected = function(option) {
    //         assert(option == options[0])
    //         render(defaultOptions, function() {
    //             done()
    //         })
    //     }
    //     var opts = merge(defaultOptions, {onOptionSelected:onOptionSelected})
    //     render(opts, function() {
    //         setInputValue('')
    //         var __datalist = nanodom('.react-datalist')[0]
    //         var __input    = nanodom('.react-datalist-input')[0]
    //         var _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //         assert(__datalist.childNodes.length == options.length)
    //         // Down to an item
    //         ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
    //         var __option = nanodom('.react-datalist-option-selected')
    //         assert(__option.length == 1)
    //         // Enter to select it
    //         ReactTestUtils.Simulate.keyDown(_input, {which: 13, type: "keydown"})
    //     })
    // })

    // it('Can hide the options by pressing ESC', function(done) {
    //     setInputValue('p')
    //     var __datalist, __input, _input;
    //     _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.change(_input)
    //     __datalist = nanodom('.react-datalist')[0]
    //     assert(__datalist.childNodes.length == 3)
    //     // ESC to hide the options
    //     ReactTestUtils.Simulate.keyUp(_input, {which: 27, type: "keyup"})
    //     __datalist = nanodom('.react-datalist')[0]
    //     __input    = nanodom('.react-datalist-input')[0]
    //     assert(__datalist.style._values.display === 'none')
    //     assert(__input.value === 'p')
    //     // ESC again to clear filter
    //     ReactTestUtils.Simulate.keyUp(_input, {which: 27, type: "keyup"})
    //     __datalist = nanodom('.react-datalist')[0]
    //     __input    = nanodom('.react-datalist-input')[0]
    //     assert(__datalist.style._values.display === 'none')
    //     assert(__input.value === '')
    //     done()
    // })

    // it('Will select an option if you click it', function(done) {
    //     var onOptionSelected = function(option) {
    //         assert(option == options[3])
    //         render(defaultOptions, function() {
    //             done()
    //         })
    //     }
    //     var opts = merge(defaultOptions, {filter:'', onOptionSelected:onOptionSelected})
    //     render(opts, function() {
    //         clickOption(3)
    //     })
    // })

    // it('Will releveal the available options if the input field is clicked', function() {
    //     clickOption(0)
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.style._values.display === 'none')
    //     var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.click(_input)
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.style._values.display === 'block')
    // })

    // it('Will hide the options on input blur', function(done) {
    //     setInputValue('melon')
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.childNodes.length == 1)
    //     assert(domlist.style._values.display === 'block')
    //     var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.blur(_input)
    //     // The options hang for 10ms so that click works properly
    //     setTimeout(function() {
    //         var domlist = nanodom('.react-datalist')[0]
    //         assert(domlist.childNodes.length == 1)
    //         assert(domlist.style._values.display === 'none')
    //         done()
    //     },120)
    // })

    // it('Will expose the input blur event', function(done) {
    //     var blur = function(event) {
    //         assert(true)
    //         render(defaultOptions, function() {
    //             done()
    //         })
    //     }
    //     var opts = merge(defaultOptions, { onInputBlur : blur })
    //     render(opts, function() {
    //         var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //         ReactTestUtils.Simulate.blur(_input)
    //     })
    // })

    // it('Can autoposition itself', function() {
    //     setInputValue('p')
    //     var domlist  = nanodom('.react-datalist')[0]
    //     var style    = window.getComputedStyle(domlist)
    //     var position = style.getPropertyValue('position')
    //     assert(position == 'absolute')
    // })

    // it('Can take a placeholder property for the input', function() {
    //     var __input = nanodom('.react-datalist-input')[0]
    //     assert(__input.attributes.placeholder.value === 'Choose project')
    // })

    // it('Has facitilies for controlling the input state externally', function() {
    //     var __input = nanodom('.react-datalist-input')[0]
    //     assert(__input.value != 'poop')
    //     filterSetter('poop')
    //     assert(__input.value == 'poop')
    // })

})<commit_msg>More tests reworked<commit_after>var dom           = require('./dom')('')
var ReactDatalist = require('../react-datalist')
var assert        = require('assert')
var _             = require('lodash')
var React         = require('react')
var nanodom       = require('nanodom')
var ReactAddons   = require('react/addons')

var ReactTestUtils = React.addons.TestUtils

/** VARIABLES **/

var filterSetter;
var setFilter    = function(fn) { filterSetter = fn }
var options      = ['apple','orange','pear','pineapple','melon']
var defaultProps = {options:options, list:'fruit', forcePoly:true, setFilter:setFilter}

/** HELPER FUNCTIONS **/

function render(props, callback) {
    return React.renderComponent(ReactDatalist(_({}).merge(defaultProps).merge(props).__wrapped__), document.body, function() {
        if (typeof callback === 'function') setTimeout(callback)
    })
}
function setInputValue(datalist, value) {
     var __input   = nanodom('.react-datalist-input')[0]
     var _input    = ReactTestUtils.findRenderedDOMComponentWithTag(datalist, 'input')
     __input.value = value
    ReactTestUtils.Simulate.change(_input)
}
function clickOption(datalist, index) {
    var _options = ReactTestUtils.scryRenderedDOMComponentsWithClass(datalist, 'react-datalist-option')
    ReactTestUtils.Simulate.click(_options[index])
}

/** TESTS **/

describe('DATALIST', function() {

    afterEach(function(done) {
        React.unmountComponentAtNode(document.body)
        document.body.innerHTML = ""
        setTimeout(done)
    })

    it('Should render a container, an input and a datalist', function(done) {
        render({},function() {
            var __datalist = nanodom('.react-datalist')
            assert(__datalist.length == 1)
            var __container = nanodom('.react-datalist-container')
            assert(__container.length == 1)
            var __input = nanodom('.react-datalist-input')
            assert(__input.length == 1)
            done()
        })
    })

    it('Should be able to filter options', function(done) {
        var _datalist = render({},function() {
            var filtered = _datalist.filterOptions(options, null)
            assert(filtered.length === options.length)
            filtered = _datalist.filterOptions(options)
            assert(filtered.length === options.length)
            filtered = _datalist.filterOptions(options, "p")
            assert(filtered.length === 3)
            filtered = _datalist.filterOptions(options, "lon")
            assert(filtered.length === 1)
            done()
        })
    })

    it('Should support setting initial input value throught initialFilter property', function(done) {
        render({initialFilter : 'meh'}, function() {
            var __input = nanodom('.react-datalist-input')[0]
            assert(__input.value === 'meh')
            done()
        })
    })

    it('Should render a datalist with the passed options', function(done) {
        var _datalist = render({}, function() {
            setInputValue(_datalist, '')
            var domlist = nanodom('.react-datalist')
            assert(domlist.length == 1)
            assert(domlist[0].childNodes.length == options.length)
            assert(domlist[0].id == 'fruit')
            done()
        })
    })

    it('Filter options should change when the input value changes', function(done) {
        var _datalist = render({}, function() {
            var __datalist = nanodom('.react-datalist')[0]
            setInputValue(_datalist, '')
            assert(__datalist.childNodes.length == options.length)
            setInputValue(_datalist, 'melon')
            assert(__datalist.childNodes.length == 1)
            done()
        })
    })

    it('Should call its callback', function(done) {
        var onInputChange = function(event) {
            assert(true)
            done()
        }
        var _datalist = render({ onInputChange : onInputChange }, function() {
            setInputValue(_datalist, 'p')
        })
    })

    it('Can navigate options with arrow keys', function(done) {
        var _datalist = render({}, function() {
            setInputValue(_datalist, '')
            var __datalist = nanodom('.react-datalist')[0]
            var __input    = nanodom('.react-datalist-input')[0]
            var _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
            assert(__datalist.childNodes.length == options.length)
            // Down to first item
            ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
            var __option = nanodom('.react-datalist-option-selected')
            assert(__option.length == 1)
            assert(__option[0].innerHTML == options[0])
            // Down to second item
            ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
            var __option = nanodom('.react-datalist-option-selected')
            assert(__option.length == 1)
            assert(__option[0].innerHTML == options[1])
            // Up to first item
            ReactTestUtils.Simulate.keyDown(_input, {which: 38, type: "keydown"})
            var __option = nanodom('.react-datalist-option-selected')
            assert(__option.length == 1)
            assert(__option[0].innerHTML == options[0])
            done()
        })
    })

    it('Can select an option by hitting enter', function(done) {
        var onOptionSelected = function(option) {
            assert(option == options[0])
            done()
        }
        var _datalist = render({ onOptionSelected : onOptionSelected }, function() {
            setInputValue(_datalist, '')
            var __datalist = nanodom('.react-datalist')[0]
            var __input    = nanodom('.react-datalist-input')[0]
            var _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
            assert(__datalist.childNodes.length == options.length)
            // Down to an item
            ReactTestUtils.Simulate.keyDown(_input, {which: 40, type: "keydown"})
            var __option = nanodom('.react-datalist-option-selected')
            assert(__option.length == 1)
            // Enter to select it
            ReactTestUtils.Simulate.keyDown(_input, {which: 13, type: "keydown"})
        })
    })

    // it('Can hide the options by pressing ESC', function(done) {
    //     setInputValue('p')
    //     var __datalist, __input, _input;
    //     _input     = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.change(_input)
    //     __datalist = nanodom('.react-datalist')[0]
    //     assert(__datalist.childNodes.length == 3)
    //     // ESC to hide the options
    //     ReactTestUtils.Simulate.keyUp(_input, {which: 27, type: "keyup"})
    //     __datalist = nanodom('.react-datalist')[0]
    //     __input    = nanodom('.react-datalist-input')[0]
    //     assert(__datalist.style._values.display === 'none')
    //     assert(__input.value === 'p')
    //     // ESC again to clear filter
    //     ReactTestUtils.Simulate.keyUp(_input, {which: 27, type: "keyup"})
    //     __datalist = nanodom('.react-datalist')[0]
    //     __input    = nanodom('.react-datalist-input')[0]
    //     assert(__datalist.style._values.display === 'none')
    //     assert(__input.value === '')
    //     done()
    // })

    // it('Will select an option if you click it', function(done) {
    //     var onOptionSelected = function(option) {
    //         assert(option == options[3])
    //         render(defaultOptions, function() {
    //             done()
    //         })
    //     }
    //     var opts = merge(defaultOptions, {filter:'', onOptionSelected:onOptionSelected})
    //     render(opts, function() {
    //         clickOption(3)
    //     })
    // })

    // it('Will releveal the available options if the input field is clicked', function() {
    //     clickOption(0)
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.style._values.display === 'none')
    //     var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.click(_input)
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.style._values.display === 'block')
    // })

    // it('Will hide the options on input blur', function(done) {
    //     setInputValue('melon')
    //     var domlist = nanodom('.react-datalist')[0]
    //     assert(domlist.childNodes.length == 1)
    //     assert(domlist.style._values.display === 'block')
    //     var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //     ReactTestUtils.Simulate.blur(_input)
    //     // The options hang for 10ms so that click works properly
    //     setTimeout(function() {
    //         var domlist = nanodom('.react-datalist')[0]
    //         assert(domlist.childNodes.length == 1)
    //         assert(domlist.style._values.display === 'none')
    //         done()
    //     },120)
    // })

    // it('Will expose the input blur event', function(done) {
    //     var blur = function(event) {
    //         assert(true)
    //         render(defaultOptions, function() {
    //             done()
    //         })
    //     }
    //     var opts = merge(defaultOptions, { onInputBlur : blur })
    //     render(opts, function() {
    //         var _input = ReactTestUtils.findRenderedDOMComponentWithTag(_datalist, 'input')
    //         ReactTestUtils.Simulate.blur(_input)
    //     })
    // })

    // it('Can autoposition itself', function() {
    //     setInputValue('p')
    //     var domlist  = nanodom('.react-datalist')[0]
    //     var style    = window.getComputedStyle(domlist)
    //     var position = style.getPropertyValue('position')
    //     assert(position == 'absolute')
    // })

    // it('Can take a placeholder property for the input', function() {
    //     var __input = nanodom('.react-datalist-input')[0]
    //     assert(__input.attributes.placeholder.value === 'Choose project')
    // })

    // it('Has facitilies for controlling the input state externally', function() {
    //     var __input = nanodom('.react-datalist-input')[0]
    //     assert(__input.value != 'poop')
    //     filterSetter('poop')
    //     assert(__input.value == 'poop')
    // })

})<|endoftext|>