<commit_before>(function () {

  var
    ONERROR   = window.onerror,
    COUNT     = 0,
    TYPES     = {},

    T_CONTROLS =
      '
' +
        '<button class="run btn large primary">Run</button>' +
      '
',
    T_EDITOR = '

',
    T_SOURCE = '

',
    T_ERRORS = '

',
    T_RENDER = '

',
    T_IFRAME = '';

  // Javascript type:
  TYPES.javascript = function Javascript (o) {
    this.onerror = o.onerror;
  };
  TYPES.javascript.prototype = {
    codeMirrorType : 'javascript',
    example : function (o) {

      var
        example = o.example,
        render = o.render,
        renderId = $(render).attr('id'),
        args = o.args ? ',' + o.args.toString() : '';

      return '(' + example + ')(document.getElementById("' + renderId+ '")' +
          args + ');';
    },
    render : function (o) {
      eval(o.example);
    }
  };

  // HTML Type:
  TYPES.html = function Html (o) {
    this.onerror = o.onerror;
  };
  TYPES.html.prototype = {
    codeMirrorType : 'htmlmixed',
    example : function (o) {
      return $.trim(o.example);
    },
    render : function (o) {

      var
        example = o.example,
        render = o.render,
        iframe = $(T_IFRAME),
        that = this,
        win, doc;

      render.html(iframe);

      win = iframe[0].contentWindow;

      doc = win.document;
      doc.open();

      // Error
      win.onerror = iframe.onerror = function () {
        that.onerror.apply(null, arguments);
      }

      doc.write(example);
      doc.close();
    }
  };

  // Editor
  function Editor (container, o) {

    var
      type      = o.type || 'javascript',
      example   = o.example || '',
      noRun     = o.noRun || false,
      teardown  = o.teardown || false,
      controls  = $(T_CONTROLS),
      render    = $(T_RENDER),
      errors    = $(T_ERRORS),
      source    = $(T_SOURCE),
      node      = $(T_EDITOR),
      renderId  = 'editor-render-' + COUNT,
      api,
      render,
      codeMirror;

    api = new TYPES[type]({
      onerror : onerror
    });
    if (!api) throw 'Invalid type: API not found for type `' + type + '`.';

    render
      .attr('id', renderId);

    errors
      .hide();

    node
      .append(render)
      .append(controls)
      .append(source)
      .addClass(type)
      .addClass(noRun ? 'no-run' : '');

    container = $(container);
    container
      .append(node);

    source
      .append(errors)

    example = api.example({
      args : o.args,
      example : example,
      render : render
    });

    codeMirror = CodeMirror(source[0], {
      value : example,
      readOnly : noRun,
      lineNumbers : true,
      mode : api.codeMirrorType
    });

    if (!noRun) {
      controls.delegate('.run', 'click', function () {
        example = codeMirror.getValue();
        execute();
      });

      execute();
    }

    // Error handling:
    window.onerror = function (message, url, line) {

      onerror(message, url, line);
      console.log(message);

      if (ONERROR && $.isFunction(ONERROR)) {
        return ONERROR(message, url, line);
      } else {
        return false;
      }
    }

    // Helpers

    function execute () {
      errors.hide();
      if (teardown) {
        teardown.call();
      }
      api.render({
        example : example,
        render : render
      });
    }

    function onerror (message, url, line) {
      // @TODO Find some js error normalizing lib

      var
        doThatSexyThang = false,
        html = 'Error: ',
        error, stack;

      /*
      // Native error type handling:
      if (typeof (message) !== 'string') {
        error = message;
        message = error.message;
        stack = error.stack;

        //if (stack) {
          console.log(stack);
        //}

        //console.log(message);

      }

      */

      html += '' + message + '';
      if (typeof (line) !== "undefined") {
        html += '';
        html += 'Line ' + line + '';
        console.log(url);
        if (url) {
          html += ' of ';
          if (url == window.location) {
            html += 'script';
            if (doThatSexyThang) {
              //codeMirror.setMarker(line, '•');
            }
          } else {
            html += '' + url + '';
          }
        }
        html += '.';
      }

      errors.show();
      errors.html(html);
    }

    COUNT++;

    this.setExample = function (source, args) {
      example = api.example({
        args : args,
        example : source,
        render : render
      });
      codeMirror.setValue(example);
      codeMirror.refresh();
      execute();
    }
  }

  if (typeof Flotr.Examples === 'undefined') Flotr.Examples = {};
  Flotr.Examples.Editor = Editor;
})();
<commit_msg>Integration with js-fiddle.  Add fiddle button.<commit_after>(function () {

  var
    ONERROR   = window.onerror,
    COUNT     = 0,
    TYPES     = {},

    T_CONTROLS =
      '
' +
        '<button class="fiddle btn large primary">Fiddle</button>' +
        '<button class="run btn large primary">Run</button>' +
      '
',
    T_EDITOR = '

',
    T_SOURCE = '

',
    T_ERRORS = '

',
    T_RENDER = '

',
    T_IFRAME = '';

  // Javascript type:
  TYPES.javascript = function Javascript (o) {
    this.onerror = o.onerror;
  };
  TYPES.javascript.prototype = {
    codeMirrorType : 'javascript',
    example : function (o) {

      var
        example = o.example,
        render = o.render,
        renderId = $(render).attr('id'),
        args = o.args ? ',' + o.args.toString() : '';

      return '(' + example + ')(document.getElementById("' + renderId+ '")' +
          args + ');';
    },
    render : function (o) {
      eval(o.example);
    }
  };

  // HTML Type:
  TYPES.html = function Html (o) {
    this.onerror = o.onerror;
  };
  TYPES.html.prototype = {
    codeMirrorType : 'htmlmixed',
    example : function (o) {
      return $.trim(o.example);
    },
    render : function (o) {

      var
        example = o.example,
        render = o.render,
        iframe = $(T_IFRAME),
        that = this,
        win, doc;

      render.html(iframe);

      win = iframe[0].contentWindow;

      doc = win.document;
      doc.open();

      // Error
      win.onerror = iframe.onerror = function () {
        that.onerror.apply(null, arguments);
      }

      doc.write(example);
      doc.close();
    }
  };

  // Editor
  function Editor (container, o) {

    var
      type      = o.type || 'javascript',
      example   = o.example || '',
      noRun     = o.noRun || false,
      teardown  = o.teardown || false,
      controls  = $(T_CONTROLS),
      render    = $(T_RENDER),
      errors    = $(T_ERRORS),
      source    = $(T_SOURCE),
      node      = $(T_EDITOR),
      renderId  = 'editor-render-' + COUNT,
      api,
      render,
      codeMirror;

    api = new TYPES[type]({
      onerror : onerror
    });
    if (!api) throw 'Invalid type: API not found for type `' + type + '`.';

    render
      .attr('id', renderId);

    errors
      .hide();

    node
      .append(render)
      .append(controls)
      .append(source)
      .addClass(type)
      .addClass(noRun ? 'no-run' : '');

    container = $(container);
    container
      .append(node);

    source
      .append(errors)

    example = api.example({
      args : o.args,
      example : example,
      render : render
    });

    codeMirror = CodeMirror(source[0], {
      value : example,
      readOnly : noRun,
      lineNumbers : true,
      mode : api.codeMirrorType
    });

    if (!noRun) {
      controls.delegate('.run', 'click', function () {
        example = codeMirror.getValue();
        execute();
      });

      execute();
    }

    controls.delegate('.fiddle', 'click', function () {
      fiddle();
    });

    // Error handling:
    window.onerror = function (message, url, line) {

      onerror(message, url, line);
      console.log(message);

      if (ONERROR && $.isFunction(ONERROR)) {
        return ONERROR(message, url, line);
      } else {
        return false;
      }
    }

    // Helpers

    function execute () {
      errors.hide();
      if (teardown) {
        teardown.call();
      }
      api.render({
        example : example,
        render : render
      });
    }

    function onerror (message, url, line) {
      // @TODO Find some js error normalizing lib

      var
        doThatSexyThang = false,
        html = 'Error: ',
        error, stack;

      /*
      // Native error type handling:
      if (typeof (message) !== 'string') {
        error = message;
        message = error.message;
        stack = error.stack;

        //if (stack) {
          console.log(stack);
        //}

        //console.log(message);

      }

      */

      html += '' + message + '';
      if (typeof (line) !== "undefined") {
        html += '';
        html += 'Line ' + line + '';
        console.log(url);
        if (url) {
          html += ' of ';
          if (url == window.location) {
            html += 'script';
            if (doThatSexyThang) {
              //codeMirror.setMarker(line, '•');
            }
          } else {
            html += '' + url + '';
          }
        }
        html += '.';
      }

      errors.show();
      errors.html(html);
    }

    function fiddle () {
      var
        url = 'http://jsfiddle.net/api/post/jquery/1.7/',
        form = $('<form method="post" action="' + url + '" target="_blank"></form>'),
        input;

      // Resources
      resources = [
        'https://raw.github.com/HumbleSoftware/Flotr2/master/flotr2.min.js',
        'https://raw.github.com/HumbleSoftware/Flotr2/master/examples/examples.css'
      ];
      input = $('<input type="hidden" name="resources">')
        .attr('value', resources.join(','));
      form.append(input);

      // HTML
      input = $('<input type="hidden" name="html">')
        .attr('value', '

');
      form.append(input);

      // CSS
      input = $('<input type="hidden" name="normalize_css" value="no">')
      form.append(input);
      input = $('<input type="hidden" name="css">')
        .attr('value',
          '#'+renderId+' {\n  width: 340px;\n  height: 220px;' +
          '\n  margin: 24px auto;\n}'
        );
      form.append(input);

      // JS
      input = $('<input type="hidden" name="js">')
        .attr('value', '$(function () {\n' + example + '\n});');

      form.append(input);

      // Submit
      form.append(input);
      $(document.body).append(form);
      form.submit();
    }

    COUNT++;

    this.setExample = function (source, args) {
      example = api.example({
        args : args,
        example : source,
        render : render
      });
      codeMirror.setValue(example);
      codeMirror.refresh();
      execute();
    }
  }

  if (typeof Flotr.Examples === 'undefined') Flotr.Examples = {};
  Flotr.Examples.Editor = Editor;
})();
<|endoftext|>


<commit_before>/*!
 * ui.js
 * Copyright Mathias Bynens <http://mths.be/>
 * Modified by John-David Dalton <http://allyoucanleet.com/>
 * Available under MIT license <http://mths.be/mit>
 */

(function(window, document) {

  /** CSS class name used for error styles */
  var ERROR_CLASS = 'error',

   /** CSS clasName used for `js enabled` styles */
   JS_CLASS = 'js',

   /** CSS class name used to display error-info */
   SHOW_CLASS = 'show',

   /** CSS class name used to reset result styles */
   RESULTS_CLASS = 'results',

   /** Google Analytics account id */
   GA_ACCOUNT_ID = 'UA-6065217-40',

   /** Benchmark results element id prefix (e.g. `results-1`) */
   RESULTS_PREFIX = 'results-',

   /** Inner text for the various run button states */
   RUN_TEXT = {
     'READY': 'Run tests',
     'READY_AGAIN': 'Run again',
     'RUNNING': 'Stop running'
   },

   /** Common status values */
   STATUS_TEXT = {
     'READY': 'Ready to run.',
     'READY_AGAIN': 'Done. Ready to run again.'
   },

   /** Cache of error messages */
   cache = {
     'errors': []
   },

   each = Benchmark.each,

   formatNumber = Benchmark.formatNumber,

   indexOf = Benchmark.indexOf,

   invoke = Benchmark.invoke,

   isArray = Benchmark.isArray;

  /*--------------------------------------------------------------------------*/

  /**
   * Shortcut for document.getElementById().
   * @private
   * @param {String|Object} id The id of the element to retrieve.
   * @returns {Object} The element, if found, or null.
   */
  function $(id) {
    return typeof id == 'string' ? document.getElementById(id) : id;
  }

  /**
   * Adds a css class name to an element's className property.
   * @private
   * @param {Object} element The element.
   * @param {String} className The class name.
   */
  function addClass(element, className) {
    if (!hasClass(element = $(element), className)) {
      element.className += (element.className ? ' ' : '') + className;
    }
  }

  /**
   * Registers an event listener on an element.
   * @private
   * @param {Object} element The element.
   * @param {String} eventName The name of the event to listen to.
   * @param {Function} handler The event handler.
   */
  function addListener(element, eventName, handler) {
    if (typeof element.addEventListener != 'undefined') {
      element.addEventListener(eventName, handler, false);
    } else if (element.attachEvent != 'undefined') {
      element.attachEvent('on' + eventName, handler);
    }
  }

  /**
   * Appends to an element's innerHTML property.
   * @private
   * @param {Object} element The element.
   * @param {String} html The HTML to append.
   */
  function appendHTML(element, html) {
    html != null && ($(element).innerHTML += html);
  }

  /**
   * Shortcut for document.createElement().
   * @private
   * @param {String} tag The tag name of the element to create.
   * @returns {Object} A new of the given tag name element.
   */
  function createElement(tagName) {
    return document.createElement(tagName);
  }

  /**
   * Checks if an element is assigned the given class name.
   * @private
   * @param {Object} element The element.
   * @param {String} className The class name.
   * @returns {Boolean} If assigned the class name return true, else false.
   */
  function hasClass(element, className) {
    return (' ' + $(element).className + ' ').indexOf(' ' + className + ' ') > -1;
  }

  /**
   * Appends to or clears the error log.
   * @private
   * @param {String|Boolean} text The the text to append or false to clear.
   */
  function logError(text) {
    var elTable,
        elDiv = $('error-info');

    if (!elDiv) {
      elTable = $('test-table');
      elDiv = createElement('div');
      elDiv.id = 'error-info';
      elTable.parentNode.insertBefore(elDiv, elTable.nextSibling);
    }
    if (text === false) {
      elDiv.className = elDiv.innerHTML = '';
      cache.errors.length = 0;
    }
    else {
      if (indexOf(cache.errors, text) < 0) {
        cache.errors.push(text);
        addClass(elDiv, SHOW_CLASS);
        appendHTML(elDiv, text);
      }
    }
  }

  /**
   * Set an element's innerHTML property.
   * @private
   * @param {Object} element The element.
   * @param {String} html The HTML to set.
   */
  function setHTML(element, html) {
    $(element).innerHTML = html == null ? '' : html;
  }

  /**
   * Sets the status text.
   * @private
   * @param {String} text The text write to the status.
   */
  function setStatus(text) {
    setHTML('status', text);
  }

  /*--------------------------------------------------------------------------*/

  /**
   * The title table cell click event handler used to run the corresponding benchmark.
   * @private
   */
  function onClick(e) {
    e || (e = window.event);
    var id = (e.target || e.srcElement).id.split('-')[1];

    each(ui.benchmarks, function(benchmark) {
      if (benchmark.id == id) {
        ui.run(benchmark);
        return false;
      }
    });
  }

  /**
   * The onComplete callback assigned to new benchmarks.
   * @private
   * @param {Object} benchmark The benchmark.
   */
  function onComplete(benchmark) {
    setStatus(STATUS_TEXT.READY_AGAIN);
    ui.render(benchmark);
  }

  /**
   * The onCycle callback, used for onStart as well, assigned to new benchmarks.
   * @private
   * @param {Object} benchmark The benchmark.
   */
  function onCycle(benchmark) {
    if (!benchmark.aborted) {
      setStatus(benchmark.name + ' × ' +
                formatNumber(benchmark.count) + ' (' +
                benchmark.cycles + ' cycles)');
    }
  }

  /**
   * The window hashchange event handler supported by Chrome 5+, Firefox 3.6+, and IE8+.
   * @private
   */
  function onHashChange() {
    ui.parseHash();
    if (typeof window.init == 'function') {
      init();
    }
  }

  /**
   * The title cell keyup event handler used to simulate a mouse click when hitting the ENTER key.
   * @private
   */
  function onKeyUp(e) {
    if (13 == (e || window.event).keyCode) {
      onClick.call(this);
    }
  }

  /**
   * The window load event handler used to initialize the UI.
   * @private
   */
  function onLoad() {
    $('run').onclick = onRun;
    $('question').value = 'no';

    addClass('run', 'show');
    setHTML('run', RUN_TEXT.READY);
    setHTML('user-agent', Benchmark.platform);
    setStatus(STATUS_TEXT.READY);

    // show warning when Firebug is enabled
    if (typeof window.console != 'undefined' && typeof console.firebug == 'string') {
      addClass('firebug', 'show');
    }
    // call user provided init() function
    if (typeof window.init == 'function') {
      init();
    }
    // auto-run benchmarks when the URL has #run
    if ('run' == location.hash.slice(1, 4)) {
      onRun();
    }
  }

  /**
   * The callback fired when the run queue is complete.
   * @private
   */
  function onQueueComplete() {
    var first,
        last,
        result = [];

    // populate result array (skipping unrun and errored benchmarks)
    each(ui.benchmarks, function(benchmark) {
      if (benchmark.cycles) {
        result.push({ 'id': benchmark.id, 'hz': benchmark.hz });
      }
    });

    if (result.length > 1) {
      // sort descending by hz (highest hz / fastest first)
      result.sort(function(a, b) { return b.hz - a.hz; });
      first = result[0];
      last  = result[result.length - 1];

      // print contextual information
      each(result, function(benchmark) {
        var percent,
            text = 'fastest',
            elResult = $(RESULTS_PREFIX + benchmark.id),
            elSpan = elResult.getElementsByTagName('span')[0];

        if (benchmark.hz == first.hz) {
          // mark fastest
          addClass(elResult, text);
        }
        else {
          percent = Math.floor((1 - benchmark.hz / first.hz) * 100);
          text = percent + '% slower';

          // mark slowest
          if (benchmark.hz == last.hz) {
            addClass(elResult, 'slowest');
          }
        }
        if (elSpan) {
          setHTML(elSpan, text);
        } else {
          appendHTML(elResult, '<span>' + text + '<\/span>');
        }
      });

      // post results to Browserscope
      ui.browserscope.post();
    }

    // all benchmarks are finished
    ui.running = false;
    setHTML('run', RUN_TEXT.READY_AGAIN);
  }

  /**
   * The "run" button click event handler used to run or abort the benchmarks.
   * @private
   */
  function onRun(e) {
    var benchmarks = ui.benchmarks,
        run = $('run').innerHTML != RUN_TEXT.RUNNING;

    ui.abort();
    if (run) {
      logError(false);
      invoke(Benchmark.CALIBRATIONS, 'reset');
      ui.run((e || window.event).shiftKey ? benchmarks.slice(0).reverse() : benchmarks);
    }
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Aborts any running benchmarks, clears the run queue, and renders results.
   * @static
   * @member ui
   */
  function abort() {
    var me = this,
        benchmarks = me.benchmarks;

    me.queue.length = 0;
    me.render(benchmarks);
    invoke(benchmarks.concat(Benchmark.CALIBRATIONS), 'abort');
    setHTML('run', RUN_TEXT.READY);
  }

  /**
   * Adds a benchmark the the collection.
   * @static
   * @member ui
   * @param {String} name The name assigned to the benchmark.
   * @param {String} id The id assigned to the benchmark.
   * @param {Function} fn The function to benchmark.
   */
  function addTest(name, id, fn) {
    var me = this,
        elTitle = $('title-' + id),
        benchmark = new Benchmark(fn, {
          'id': id,
          'name': name,
          'onStart': onCycle,
          'onCycle': onCycle,
          'onComplete': onComplete
        });

    elTitle.tabIndex = 0;
    elTitle.title = 'Click to run this test again.';

    addListener(elTitle, 'click', onClick);
    addListener(elTitle, 'keyup', onKeyUp);

    me.benchmarks.push(benchmark);
    me.elResults.push($(RESULTS_PREFIX + id));
    me.render(benchmark);
  }

  /**
   * Parses the window.location.hash value into an object assigned to `ui.params`.
   * @static
   * @member ui
   */
  function parseHash() {
    var hashes = location.hash.slice(1).split('&'),
        params = this.params = { };

    each(hashes[0] && hashes, function(hash) {
      var pair = hashes[length].split('=');
      params[pair[0]] = pair[1];
    });
  }

  /**
   * Renders the results table cell of the corresponding benchmark(s).
   * @static
   * @member ui
   * @param {Array|Object} [benchmarks=ui.benchmarks] One or an array of benchmarks.
   */
  function render(benchmarks) {
    var me = this;
    if (!isArray(benchmarks)) {
      benchmarks = benchmarks ? [benchmarks] : me.benchmarks;
    }
    each(benchmarks, function(benchmark) {
      var cell = $(RESULTS_PREFIX + benchmark.id),
          error = benchmark.error,
          hz = benchmark.hz;

      cell.title = '';

      // status: error
      if (error) {
        setHTML(cell, 'Error');
        if (!hasClass(cell, ERROR_CLASS)) {
          addClass(cell, ERROR_CLASS);
        }
        logError('<p>' + error + '.<\/p><ul><li>' +
          Benchmark.join(error, '<\/li><li>') + '<\/li><\/ul>');
      }
      else {
        // status: running
        if (benchmark.running) {
          setHTML(cell, 'running…');
        }
        // status: finished
        else if (benchmark.cycles) {
          setHTML(cell, formatNumber(hz));
          cell.title = 'Ran ' + formatNumber(benchmark.count) + ' times in ' +
                       benchmark.times.cycle.toFixed(2) + ' seconds.' +
                       (hz == Infinity ? '' : ' (' +
                       benchmark.RME.toFixed(2) + '% margin of error)');
        }
        // status: pending
        else if (indexOf(me.queue, benchmark) > -1) {
          setHTML(cell, 'pending…');
        }
        // status: ready
        else {
          setHTML(cell, 'ready');
        }
      }
    });
  }

  /**
   * Adds given benchmark(s) to the queue and runs.
   * @static
   * @member ui
   * @param {Array|Object} [benchmarks=ui.benchmarks] One or an array of benchmarks.
   */
  function run(benchmarks) {
    var added,
        me = this,
        queue = me.queue;

    if (!isArray(benchmarks)) {
      benchmarks = benchmarks ? [benchmarks] : me.benchmarks;
    }
    each(benchmarks, function(benchmark) {
      if (!benchmark.error && indexOf(queue, benchmark) < 0) {
        // reset before (re)running so the previous run's results are
        // not re-recorded if the operation is aborted mid queue
        benchmark.reset();
        queue.push(benchmark);
        me.render(benchmark);
        added = true;

        if (!me.running) {
          me.running = true;
          setHTML('run', RUN_TEXT.RUNNING);
          invoke(queue, {
            'async': true,
            'methodName': 'run',
            'queued': true,
            'onComplete': onQueueComplete
          });
        }
      }
    });

    // reset result classNames
    if (added) {
      each(me.elResults, function(elResult) {
        if (!hasClass(elResult, ERROR_CLASS)) {
          elResult.className = RESULTS_CLASS;
        }
      });
    }
  }

  /*--------------------------------------------------------------------------*/

  // expose
  window.ui = {

    /**
     * An array of table cells used to display benchmark results.
     * @member ui
     */
    'elResults': [],

    /**
     * The parsed query parameters of the pages url hash.
     * @member ui
     */
    'params': {},

    /**
     * The queue of benchmarks to run.
     * @member ui
     */
    'queue': [],

    /**
     * A flag to indicate if the benchmarks are running.
     * @member ui
     */
    'running': false,

    /**
     * An array of benchmarks created from test cases.
     * @member ui
     */
    'benchmarks': [],

    // abort, dequeue, and render results
    'abort': abort,

    // create a new benchmark from a test case
    'addTest': addTest,

    // parse query params into ui.params[] hash
    'parseHash': parseHash,

    // (re)render the results of one or more benchmarks
    'render': render,

    // add one or more benchmarks to the queue and run
    'run': run
  };

  /*--------------------------------------------------------------------------*/

  // signal JavaScript detected
  addClass(document.documentElement, JS_CLASS);

  // don't let users alert, confirm, prompt, or open new windows
  window.alert = window.confirm = window.prompt = window.open = Benchmark.noop;

  // re-parse hash query params when it changes
  addListener(window, 'hashchange', onHashChange);

  // bootstrap onload
  addListener(window, 'load', onLoad);

  // parse location hash string
  ui.parseHash();

  // force benchmark methods to run asynchronously for a more responsive UI
  Benchmark.prototype.DEFAULT_ASYNC = true;

  // customize calibration benchmarks
  each(Benchmark.CALIBRATIONS, function(cal) {
    cal.name = 'Calibrating';
    cal.onCycle = cal.onStart = onCycle;
  });

  // optimized asynchronous Google Analytics snippet based on
  // http://mathiasbynens.be/notes/async-analytics-snippet
  (function(tag) {
    var script = createElement(tag),
        sibling = document.getElementsByTagName(tag)[0];

    window._gaq = [['_setAccount', GA_ACCOUNT_ID], ['_trackPageview']];
    script.async = 1;
    script.src = '//www.google-analytics.com/ga.js';
    sibling.parentNode.insertBefore(script, sibling);
  }('script'));

}(this, document));<commit_msg>benchmark: Remove Google Analytics id from the plugin. [jddalton]<commit_after>/*!
 * ui.js
 * Copyright Mathias Bynens <http://mths.be/>
 * Modified by John-David Dalton <http://allyoucanleet.com/>
 * Available under MIT license <http://mths.be/mit>
 */

(function(window, document) {

  /** CSS class name used for error styles */
  var ERROR_CLASS = 'error',

   /** CSS clasName used for `js enabled` styles */
   JS_CLASS = 'js',

   /** CSS class name used to display error-info */
   SHOW_CLASS = 'show',

   /** CSS class name used to reset result styles */
   RESULTS_CLASS = 'results',

   /** Google Analytics account id */
   GA_ACCOUNT_ID = '',

   /** Benchmark results element id prefix (e.g. `results-1`) */
   RESULTS_PREFIX = 'results-',

   /** Inner text for the various run button states */
   RUN_TEXT = {
     'READY': 'Run tests',
     'READY_AGAIN': 'Run again',
     'RUNNING': 'Stop running'
   },

   /** Common status values */
   STATUS_TEXT = {
     'READY': 'Ready to run.',
     'READY_AGAIN': 'Done. Ready to run again.'
   },

   /** Cache of error messages */
   cache = {
     'errors': []
   },

   each = Benchmark.each,

   formatNumber = Benchmark.formatNumber,

   indexOf = Benchmark.indexOf,

   invoke = Benchmark.invoke,

   isArray = Benchmark.isArray;

  /*--------------------------------------------------------------------------*/

  /**
   * Shortcut for document.getElementById().
   * @private
   * @param {String|Object} id The id of the element to retrieve.
   * @returns {Object} The element, if found, or null.
   */
  function $(id) {
    return typeof id == 'string' ? document.getElementById(id) : id;
  }

  /**
   * Adds a css class name to an element's className property.
   * @private
   * @param {Object} element The element.
   * @param {String} className The class name.
   */
  function addClass(element, className) {
    if (!hasClass(element = $(element), className)) {
      element.className += (element.className ? ' ' : '') + className;
    }
  }

  /**
   * Registers an event listener on an element.
   * @private
   * @param {Object} element The element.
   * @param {String} eventName The name of the event to listen to.
   * @param {Function} handler The event handler.
   */
  function addListener(element, eventName, handler) {
    if (typeof element.addEventListener != 'undefined') {
      element.addEventListener(eventName, handler, false);
    } else if (element.attachEvent != 'undefined') {
      element.attachEvent('on' + eventName, handler);
    }
  }

  /**
   * Appends to an element's innerHTML property.
   * @private
   * @param {Object} element The element.
   * @param {String} html The HTML to append.
   */
  function appendHTML(element, html) {
    html != null && ($(element).innerHTML += html);
  }

  /**
   * Shortcut for document.createElement().
   * @private
   * @param {String} tag The tag name of the element to create.
   * @returns {Object} A new of the given tag name element.
   */
  function createElement(tagName) {
    return document.createElement(tagName);
  }

  /**
   * Checks if an element is assigned the given class name.
   * @private
   * @param {Object} element The element.
   * @param {String} className The class name.
   * @returns {Boolean} If assigned the class name return true, else false.
   */
  function hasClass(element, className) {
    return (' ' + $(element).className + ' ').indexOf(' ' + className + ' ') > -1;
  }

  /**
   * Appends to or clears the error log.
   * @private
   * @param {String|Boolean} text The the text to append or false to clear.
   */
  function logError(text) {
    var elTable,
        elDiv = $('error-info');

    if (!elDiv) {
      elTable = $('test-table');
      elDiv = createElement('div');
      elDiv.id = 'error-info';
      elTable.parentNode.insertBefore(elDiv, elTable.nextSibling);
    }
    if (text === false) {
      elDiv.className = elDiv.innerHTML = '';
      cache.errors.length = 0;
    }
    else {
      if (indexOf(cache.errors, text) < 0) {
        cache.errors.push(text);
        addClass(elDiv, SHOW_CLASS);
        appendHTML(elDiv, text);
      }
    }
  }

  /**
   * Set an element's innerHTML property.
   * @private
   * @param {Object} element The element.
   * @param {String} html The HTML to set.
   */
  function setHTML(element, html) {
    $(element).innerHTML = html == null ? '' : html;
  }

  /**
   * Sets the status text.
   * @private
   * @param {String} text The text write to the status.
   */
  function setStatus(text) {
    setHTML('status', text);
  }

  /*--------------------------------------------------------------------------*/

  /**
   * The title table cell click event handler used to run the corresponding benchmark.
   * @private
   */
  function onClick(e) {
    e || (e = window.event);
    var id = (e.target || e.srcElement).id.split('-')[1];

    each(ui.benchmarks, function(benchmark) {
      if (benchmark.id == id) {
        ui.run(benchmark);
        return false;
      }
    });
  }

  /**
   * The onComplete callback assigned to new benchmarks.
   * @private
   * @param {Object} benchmark The benchmark.
   */
  function onComplete(benchmark) {
    setStatus(STATUS_TEXT.READY_AGAIN);
    ui.render(benchmark);
  }

  /**
   * The onCycle callback, used for onStart as well, assigned to new benchmarks.
   * @private
   * @param {Object} benchmark The benchmark.
   */
  function onCycle(benchmark) {
    if (!benchmark.aborted) {
      setStatus(benchmark.name + ' × ' +
                formatNumber(benchmark.count) + ' (' +
                benchmark.cycles + ' cycles)');
    }
  }

  /**
   * The window hashchange event handler supported by Chrome 5+, Firefox 3.6+, and IE8+.
   * @private
   */
  function onHashChange() {
    ui.parseHash();
    if (typeof window.init == 'function') {
      init();
    }
  }

  /**
   * The title cell keyup event handler used to simulate a mouse click when hitting the ENTER key.
   * @private
   */
  function onKeyUp(e) {
    if (13 == (e || window.event).keyCode) {
      onClick.call(this);
    }
  }

  /**
   * The window load event handler used to initialize the UI.
   * @private
   */
  function onLoad() {
    $('run').onclick = onRun;
    $('question').value = 'no';

    addClass('run', 'show');
    setHTML('run', RUN_TEXT.READY);
    setHTML('user-agent', Benchmark.platform);
    setStatus(STATUS_TEXT.READY);

    // show warning when Firebug is enabled
    if (typeof window.console != 'undefined' && typeof console.firebug == 'string') {
      addClass('firebug', 'show');
    }
    // call user provided init() function
    if (typeof window.init == 'function') {
      init();
    }
    // auto-run benchmarks when the URL has #run
    if ('run' == location.hash.slice(1, 4)) {
      onRun();
    }
  }

  /**
   * The callback fired when the run queue is complete.
   * @private
   */
  function onQueueComplete() {
    var first,
        last,
        result = [];

    // populate result array (skipping unrun and errored benchmarks)
    each(ui.benchmarks, function(benchmark) {
      if (benchmark.cycles) {
        result.push({ 'id': benchmark.id, 'hz': benchmark.hz });
      }
    });

    if (result.length > 1) {
      // sort descending by hz (highest hz / fastest first)
      result.sort(function(a, b) { return b.hz - a.hz; });
      first = result[0];
      last  = result[result.length - 1];

      // print contextual information
      each(result, function(benchmark) {
        var percent,
            text = 'fastest',
            elResult = $(RESULTS_PREFIX + benchmark.id),
            elSpan = elResult.getElementsByTagName('span')[0];

        if (benchmark.hz == first.hz) {
          // mark fastest
          addClass(elResult, text);
        }
        else {
          percent = Math.floor((1 - benchmark.hz / first.hz) * 100);
          text = percent + '% slower';

          // mark slowest
          if (benchmark.hz == last.hz) {
            addClass(elResult, 'slowest');
          }
        }
        if (elSpan) {
          setHTML(elSpan, text);
        } else {
          appendHTML(elResult, '<span>' + text + '<\/span>');
        }
      });

      // post results to Browserscope
      ui.browserscope.post();
    }

    // all benchmarks are finished
    ui.running = false;
    setHTML('run', RUN_TEXT.READY_AGAIN);
  }

  /**
   * The "run" button click event handler used to run or abort the benchmarks.
   * @private
   */
  function onRun(e) {
    var benchmarks = ui.benchmarks,
        run = $('run').innerHTML != RUN_TEXT.RUNNING;

    ui.abort();
    if (run) {
      logError(false);
      invoke(Benchmark.CALIBRATIONS, 'reset');
      ui.run((e || window.event).shiftKey ? benchmarks.slice(0).reverse() : benchmarks);
    }
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Aborts any running benchmarks, clears the run queue, and renders results.
   * @static
   * @member ui
   */
  function abort() {
    var me = this,
        benchmarks = me.benchmarks;

    me.queue.length = 0;
    me.render(benchmarks);
    invoke(benchmarks.concat(Benchmark.CALIBRATIONS), 'abort');
    setHTML('run', RUN_TEXT.READY);
  }

  /**
   * Adds a benchmark the the collection.
   * @static
   * @member ui
   * @param {String} name The name assigned to the benchmark.
   * @param {String} id The id assigned to the benchmark.
   * @param {Function} fn The function to benchmark.
   */
  function addTest(name, id, fn) {
    var me = this,
        elTitle = $('title-' + id),
        benchmark = new Benchmark(fn, {
          'id': id,
          'name': name,
          'onStart': onCycle,
          'onCycle': onCycle,
          'onComplete': onComplete
        });

    elTitle.tabIndex = 0;
    elTitle.title = 'Click to run this test again.';

    addListener(elTitle, 'click', onClick);
    addListener(elTitle, 'keyup', onKeyUp);

    me.benchmarks.push(benchmark);
    me.elResults.push($(RESULTS_PREFIX + id));
    me.render(benchmark);
  }

  /**
   * Parses the window.location.hash value into an object assigned to `ui.params`.
   * @static
   * @member ui
   */
  function parseHash() {
    var hashes = location.hash.slice(1).split('&'),
        params = this.params = { };

    each(hashes[0] && hashes, function(hash) {
      var pair = hashes[length].split('=');
      params[pair[0]] = pair[1];
    });
  }

  /**
   * Renders the results table cell of the corresponding benchmark(s).
   * @static
   * @member ui
   * @param {Array|Object} [benchmarks=ui.benchmarks] One or an array of benchmarks.
   */
  function render(benchmarks) {
    var me = this;
    if (!isArray(benchmarks)) {
      benchmarks = benchmarks ? [benchmarks] : me.benchmarks;
    }
    each(benchmarks, function(benchmark) {
      var cell = $(RESULTS_PREFIX + benchmark.id),
          error = benchmark.error,
          hz = benchmark.hz;

      cell.title = '';

      // status: error
      if (error) {
        setHTML(cell, 'Error');
        if (!hasClass(cell, ERROR_CLASS)) {
          addClass(cell, ERROR_CLASS);
        }
        logError('<p>' + error + '.<\/p><ul><li>' +
          Benchmark.join(error, '<\/li><li>') + '<\/li><\/ul>');
      }
      else {
        // status: running
        if (benchmark.running) {
          setHTML(cell, 'running…');
        }
        // status: finished
        else if (benchmark.cycles) {
          setHTML(cell, formatNumber(hz));
          cell.title = 'Ran ' + formatNumber(benchmark.count) + ' times in ' +
                       benchmark.times.cycle.toFixed(2) + ' seconds.' +
                       (hz == Infinity ? '' : ' (' +
                       benchmark.RME.toFixed(2) + '% margin of error)');
        }
        // status: pending
        else if (indexOf(me.queue, benchmark) > -1) {
          setHTML(cell, 'pending…');
        }
        // status: ready
        else {
          setHTML(cell, 'ready');
        }
      }
    });
  }

  /**
   * Adds given benchmark(s) to the queue and runs.
   * @static
   * @member ui
   * @param {Array|Object} [benchmarks=ui.benchmarks] One or an array of benchmarks.
   */
  function run(benchmarks) {
    var added,
        me = this,
        queue = me.queue;

    if (!isArray(benchmarks)) {
      benchmarks = benchmarks ? [benchmarks] : me.benchmarks;
    }
    each(benchmarks, function(benchmark) {
      if (!benchmark.error && indexOf(queue, benchmark) < 0) {
        // reset before (re)running so the previous run's results are
        // not re-recorded if the operation is aborted mid queue
        benchmark.reset();
        queue.push(benchmark);
        me.render(benchmark);
        added = true;

        if (!me.running) {
          me.running = true;
          setHTML('run', RUN_TEXT.RUNNING);
          invoke(queue, {
            'async': true,
            'methodName': 'run',
            'queued': true,
            'onComplete': onQueueComplete
          });
        }
      }
    });

    // reset result classNames
    if (added) {
      each(me.elResults, function(elResult) {
        if (!hasClass(elResult, ERROR_CLASS)) {
          elResult.className = RESULTS_CLASS;
        }
      });
    }
  }

  /*--------------------------------------------------------------------------*/

  // expose
  window.ui = {

    /**
     * An array of table cells used to display benchmark results.
     * @member ui
     */
    'elResults': [],

    /**
     * The parsed query parameters of the pages url hash.
     * @member ui
     */
    'params': {},

    /**
     * The queue of benchmarks to run.
     * @member ui
     */
    'queue': [],

    /**
     * A flag to indicate if the benchmarks are running.
     * @member ui
     */
    'running': false,

    /**
     * An array of benchmarks created from test cases.
     * @member ui
     */
    'benchmarks': [],

    // abort, dequeue, and render results
    'abort': abort,

    // create a new benchmark from a test case
    'addTest': addTest,

    // parse query params into ui.params[] hash
    'parseHash': parseHash,

    // (re)render the results of one or more benchmarks
    'render': render,

    // add one or more benchmarks to the queue and run
    'run': run
  };

  /*--------------------------------------------------------------------------*/

  // signal JavaScript detected
  addClass(document.documentElement, JS_CLASS);

  // don't let users alert, confirm, prompt, or open new windows
  window.alert = window.confirm = window.prompt = window.open = Benchmark.noop;

  // re-parse hash query params when it changes
  addListener(window, 'hashchange', onHashChange);

  // bootstrap onload
  addListener(window, 'load', onLoad);

  // parse location hash string
  ui.parseHash();

  // force benchmark methods to run asynchronously for a more responsive UI
  Benchmark.prototype.DEFAULT_ASYNC = true;

  // customize calibration benchmarks
  each(Benchmark.CALIBRATIONS, function(cal) {
    cal.name = 'Calibrating';
    cal.onCycle = cal.onStart = onCycle;
  });

  // optimized asynchronous Google Analytics snippet based on
  // http://mathiasbynens.be/notes/async-analytics-snippet
  if (GA_ACCOUNT_ID) {
    (function() {
      var tag = 'script',
          script = createElement(tag),
          sibling = document.getElementsByTagName(tag)[0];

      window._gaq = [['_setAccount', GA_ACCOUNT_ID], ['_trackPageview']];
      script.async = 1;
      script.src = '//www.google-analytics.com/ga.js';
      sibling.parentNode.insertBefore(script, sibling);
    }());
  }
}(this, document));<|endoftext|>


<commit_before>var DEMO = (function( $ ) {
  'use strict';

  var $grid = $('#grid'),
      $filterOptions = $('.filter-options'),
      $sizer = $grid.find('.shuffle__sizer'),

  init = function() {

    // Display initial items
    displayItems();

    // None of these need to be executed synchronously
    setTimeout(function() {
      listen();
      setupFilters();
      setupSorting();
      setupSearching();
    }, 100);

    // You can subscribe to custom events.
    // shrink, shrunk, filter, filtered, sorted, load, done
    $grid.on('loading.shuffle done.shuffle layout.shuffle', function(evt, shuffle) {
      // Make sure the browser has a console
      if ( window.console && window.console.log && typeof window.console.log === 'function' ) {
        console.log( 'Shuffle:', evt.type );
      }
    });

    // instantiate the plugin
    $grid.shuffle({
      itemSelector: '.picture-item',
      sizer: $sizer
    });

    // Destroy it! o_O
    // $grid.shuffle('destroy');
  },

  getRandomInt = function(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  },

  displayItems = function() {
    // Creating random elements. You could use an
    // ajax request or clone elements instead
    var itemsToCreate = 5,
        frag = document.createDocumentFragment(),
        items = [],
        $items,
        classes = ['w2', 'h2', 'w3'],
        box, i, random, randomClass;

    for (i = 0; i < itemsToCreate; i++) {
      random = Math.random();
      box = document.createElement('div');
      box.className = 'box';
      box.setAttribute('created', getRandomInt(1, 150));

      // Randomly add a class
      if ( random > 0.8 ) {
        randomClass = Math.floor( Math.random() * 3 );
        box.className = box.className + ' ' + classes[ randomClass ];
      }

      box.innerHTML = "Box "+i;
      items.push( box );
      frag.appendChild( box );
    }

    $items = $(items);

    // Insert items in the grid
    $grid.append(frag);

    // Tell shuffle items have been appended.
    // It expects a jQuery object as the parameter.
    $grid.shuffle('appended', $items );
  },

  // Set up button clicks
  setupFilters = function() {
    var $btns = $filterOptions.children();
    $btns.on('click', function() {
      var $this = $(this),
          isActive = $this.hasClass( 'active' ),
          group = isActive ? 'all' : $this.data('group');

      // Hide current label, show current label in title
      if ( !isActive ) {
        $('.filter-options .active').removeClass('active');
      }

      $this.toggleClass('active');

      // Filter elements
      $grid.shuffle( 'shuffle', group );
    });

    $btns = null;
  },

  setupSorting = function() {
    // Sorting options
    $('.sort-options').on('change', function() {
      var sort = this.value,
          opts = {};

      // We're given the element wrapped in jQuery
      if ( sort === 'date-created' ) {
        opts = {
          reverse: true,
          by: function($el) {
            return $el.data('date-created');
          }
        };
      } else if ( sort === 'title' ) {
        opts = {
          by: function($el) {
            return $el.data('title').toLowerCase();
          }
        };
      }

      // Filter elements
      $grid.shuffle('sort', opts);
    });
  },

  setupSearching = function() {
    // Advanced filtering
    $('.js-shuffle-search').on('keyup change', function() {
      var val = this.value.toLowerCase();
      $grid.shuffle('shuffle', function($el, shuffle) {

        // Only search elements in the current group
        if (shuffle.group !== 'all' && $.inArray(shuffle.group, $el.data('groups')) === -1) {
          return false;
        }

        var text = $.trim( $el.find('.picture-item__title').text() ).toLowerCase();
        return text.indexOf(val) !== -1;
      });
    });
  },

  // Re layout shuffle when images load. This is only needed
  // below 768 pixels because the .picture-item height is auto and therefore
  // the height of the picture-item is dependent on the image
  // I recommend using imagesloaded to determine when an image is loaded
  // but that doesn't support IE7
  listen = function() {
    var debouncedLayout = $.throttle( 300, function() {
      $grid.shuffle('update');
    });

    // Get all images inside shuffle
    $grid.find('img').each(function() {
      var proxyImage;

      // Image already loaded
      if ( this.complete && this.naturalWidth !== undefined ) {
        return;
      }

      // If none of the checks above matched, simulate loading on detached element.
      proxyImage = new Image();
      $( proxyImage ).on('load', function() {
        $(this).off('load');
        debouncedLayout();
      });

      proxyImage.src = this.src;
    });

    // Because this method doesn't seem to be perfect.
    setTimeout(function() {
      debouncedLayout();
    }, 500);
  };

  return {
    init: init
  };
}( jQuery ));

$(document).ready(function() {
  DEMO.init();
});
<commit_msg>Make the javascript template generated a little more similar to the demo example<commit_after>var DEMO = (function( $ ) {
  'use strict';

  var $grid = $('#grid'),
      $filterOptions = $('.filter-options'),
      $sizer = $grid.find('.shuffle__sizer'),

  init = function() {

    // Display initial items
    displayItems();

    // None of these need to be executed synchronously
    setTimeout(function() {
      listen();
      setupFilters();
      setupSorting();
      setupSearching();
    }, 100);

    // You can subscribe to custom events.
    // shrink, shrunk, filter, filtered, sorted, load, done
    $grid.on('loading.shuffle done.shuffle layout.shuffle', function(evt, shuffle) {
      // Make sure the browser has a console
      if ( window.console && window.console.log && typeof window.console.log === 'function' ) {
        console.log( 'Shuffle:', evt.type );
      }
    });

    // instantiate the plugin
    $grid.shuffle({
      itemSelector: '.picture-item',
      sizer: $sizer
    });

    // Destroy it! o_O
    // $grid.shuffle('destroy');
  },

  getRandomInt = function(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  },

  displayItems = function() {
    // Creating random elements. You could use an
    // ajax request or clone elements instead
    var itemsToCreate = 5,
        frag = document.createDocumentFragment(),
        items = [],
        $items,
        classes = ['w2', 'h2', 'w3'],
        figure, item_inner, picture, item_details, picture_blur, figcaption, captionLink, tags,
        i, random, randomClass;

    for (i = 0; i < itemsToCreate; i++) {
      //Figure
      random = Math.random();
      figure = document.createElement('figure');
      figure.classList.add('span3', 'm-span3', 'picture-item', 'shuffle-item', 'filtered');
      figure.setAttribute('data-groups', "["photography"]");
      figure.setAttribute('data-created', "2010-09-14");
      figure.setAttribute('data-title', "Baseball");

      // Randomly add a class
      if ( random > 0.8 ) {
        // getRandomInt(1, 150)
        randomClass = Math.floor( Math.random() * 3 );
        figure.classList.add(classes[ randomClass ]);
      }

      item_inner = document.createElement('div');
      item_inner.className = 'picture-item__inner';
      figure.appendChild(item_inner);

      // Picture
      picture = document.createElement('img');
      picture.setAttribute('src','/Shuffle/img/baseball.png');
      picture.setAttribute('alt','');
      picture.setAttribute('height','145');
      picture.setAttribute('width','230');

      // Details
      item_details = document.createElement('div');
      item_details.className = 'picture-item__details clearfix';

        picture_blur = picture.cloneNode();
        picture_blur.className = 'picture-item__blur';

        // Caption
        figcaption = document.createElement('figcaption');
        figcaption.classList.add('picture-item__title', 'pull-left');

          captionLink = document.createElement('a');
          captionLink.setAttribute('target','_blank');
          captionLink.setAttribute('href', '/Shuffle/img/originals/baseball.jpg');
          captionLink.innerHTML = 'Baseball';

          figcaption.appendChild(captionLink);

        tags = document.createElement('p');
        tags.className = 'picture-item__tags pull-right';
        tags.innerHTML = 'photography';

        item_details.appendChild(picture_blur);
        item_details.appendChild(figcaption);
        item_details.appendChild(tags);

      // Appending children
      item_inner.appendChild(picture);
      item_inner.appendChild(item_details);

      items.push( figure );
      frag.appendChild( figure );
    }

    $items = $(items);

    // Insert items in the grid
    $grid.append(frag);

    // Tell shuffle items have been appended.
    // It expects a jQuery object as the parameter.
    $grid.shuffle('appended', $items );
  },

  // Set up button clicks
  setupFilters = function() {
    var $btns = $filterOptions.children();
    $btns.on('click', function() {
      var $this = $(this),
          isActive = $this.hasClass( 'active' ),
          group = isActive ? 'all' : $this.data('group');

      // Hide current label, show current label in title
      if ( !isActive ) {
        $('.filter-options .active').removeClass('active');
      }

      $this.toggleClass('active');

      // Filter elements
      $grid.shuffle( 'shuffle', group );
    });

    $btns = null;
  },

  setupSorting = function() {
    // Sorting options
    $('.sort-options').on('change', function() {
      var sort = this.value,
          opts = {};

      // We're given the element wrapped in jQuery
      if ( sort === 'date-created' ) {
        opts = {
          reverse: true,
          by: function($el) {
            return $el.data('date-created');
          }
        };
      } else if ( sort === 'title' ) {
        opts = {
          by: function($el) {
            return $el.data('title').toLowerCase();
          }
        };
      }

      // Filter elements
      $grid.shuffle('sort', opts);
    });
  },

  setupSearching = function() {
    // Advanced filtering
    $('.js-shuffle-search').on('keyup change', function() {
      var val = this.value.toLowerCase();
      $grid.shuffle('shuffle', function($el, shuffle) {

        // Only search elements in the current group
        if (shuffle.group !== 'all' && $.inArray(shuffle.group, $el.data('groups')) === -1) {
          return false;
        }

        var text = $.trim( $el.find('.picture-item__title').text() ).toLowerCase();
        return text.indexOf(val) !== -1;
      });
    });
  },

  // Re layout shuffle when images load. This is only needed
  // below 768 pixels because the .picture-item height is auto and therefore
  // the height of the picture-item is dependent on the image
  // I recommend using imagesloaded to determine when an image is loaded
  // but that doesn't support IE7
  listen = function() {
    var debouncedLayout = $.throttle( 300, function() {
      $grid.shuffle('update');
    });

    // Get all images inside shuffle
    $grid.find('img').each(function() {
      var proxyImage;

      // Image already loaded
      if ( this.complete && this.naturalWidth !== undefined ) {
        return;
      }

      // If none of the checks above matched, simulate loading on detached element.
      proxyImage = new Image();
      $( proxyImage ).on('load', function() {
        $(this).off('load');
        debouncedLayout();
      });

      proxyImage.src = this.src;
    });

    // Because this method doesn't seem to be perfect.
    setTimeout(function() {
      debouncedLayout();
    }, 500);
  };

  return {
    init: init
  };
}( jQuery ));

$(document).ready(function() {
  DEMO.init();
});
<|endoftext|>


<commit_before>var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        document.addEventListener("backbutton", function(e) {
            e.preventDefault();
        }, false);
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        AndroidFullScreen.immersiveMode(successFunction, errorFunction);
        StatusBar.hide();
        window.plugins.insomnia.keepAwake();
        loadApp();
    }
};

function successFunction() {
    console.info("It worked!");
}

function errorFunction(error) {
    console.error(error);
}

function trace(value) {
    console.log(value);
}

function loadApp() {
    if (navigator.onLine) {
        // var url = "http://rla.io/screen";
        var udl = "http://192.168.1.56:3000";
        var target = "_self";
        var options = "location=no,hidden=yes,zoom=no,hardwareback=no,toolbar=no,allowInlineMediaPlayback=yes";
        var ref = cordova.InAppBrowser.open(url, target, options);
        ref.addEventListener("loadstop", function() {
            ref.show();
        });
    } else {
        document.getElementById("loading").style.display = "none";
        document.getElementById('greet').innerHTML = "You need to be connected to the internet to use the RLA application.";
        return setTimeout(loadRemote, 1000);
    }
}<commit_msg>plugin<commit_after>var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        document.addEventListener("backbutton", function(e) {
            e.preventDefault();
        }, false);
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        var parentElement = document.getElementById(id);
        AndroidFullScreen.immersiveMode(successFunction, errorFunction);
        StatusBar.hide();
        window.plugins.insomnia.keepAwake();
        loadApp();
    }
};

function successFunction() {
    console.info("It worked!");
}

function errorFunction(error) {
    console.error(error);
}

function trace(value) {
    console.log(value);
}

function loadApp() {
    if (navigator.onLine) {
        // var url = "http://rla.io/screen";
        var url = "http://192.168.1.56:3000/screen";
        var target = "_self";
        var options = "location=no,hidden=yes,zoom=no,hardwareback=no,toolbar=no,allowInlineMediaPlayback=yes";
        var ref = cordova.InAppBrowser.open(url, target, options);
        ref.addEventListener("loadstop", function() {
            ref.show();
        });
    } else {
        document.getElementById("loading").style.display = "none";
        document.getElementById('greet').innerHTML = "You need to be connected to the internet to use the RLA application.";
        return setTimeout(loadRemote, 1000);
    }
}<|endoftext|>


<commit_before>var path = require('path'),
    express = require('express'),
    http = require('http'),
    mongoose = require('mongoose'),
    passport = require('passport'),
    LocalStrategy = require('passport-local').Strategy;

var app = express();

// Configuration
app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('view engine', 'jade');
    app.set('view options', { layout: false });

    app.use(express.logger());
    app.use(express.bodyParser());
    app.use(express.methodOverride());

    app.use(express.cookieParser('your secret here'));
    app.use(express.session());

    app.use(passport.initialize());
    app.use(passport.session());

    app.use(app.router);
    app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
    app.use(express.errorHandler());
});

// Configure passport
var Account = require('./models/account');

passport.use(new LocalStrategy(Account.authenticate()));

passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());

// Connect mongoose
mongoose.connect('mongodb://localhost/passport_local_mongoose_examples');

// Setup routes
require('./routes')(app);

http.createServer(app).listen(3000, '127.0.0.1', function() {
    console.log("Express server listening on %s:%d in %s mode", '127.0.0.1', 3000, app.settings.env);
});
<commit_msg>Beautify app configuration<commit_after>var path = require('path'),
    express = require('express'),
    http = require('http'),
    mongoose = require('mongoose'),
    passport = require('passport'),
    LocalStrategy = require('passport-local').Strategy;

var app = express();

// Configuration
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('view options', { layout: false });

app.use(express.logger());
app.use(express.bodyParser());
app.use(express.methodOverride());

app.use(express.cookieParser('your secret here'));
app.use(express.session());

app.use(passport.initialize());
app.use(passport.session());

app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

app.configure('development', function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
    app.use(express.errorHandler());
});

// Configure passport
var Account = require('./models/account');

passport.use(new LocalStrategy(Account.authenticate()));

passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());

// Connect mongoose
mongoose.connect('mongodb://localhost/passport_local_mongoose_examples');

// Setup routes
require('./routes')(app);

http.createServer(app).listen(3000, '127.0.0.1', function() {
    console.log("Express server listening on %s:%d in %s mode", '127.0.0.1', 3000, app.settings.env);
});
<|endoftext|>


<commit_before>/*
* Global vars
*/
var NAV_HEIGHT = 75;

var $w;
var $h;
var $slides;
var $components;
var $portraits;
var $play;
var $video;
var $navButton;
var $nav;
var $navItems;
var $navClose;
var $nextSectionButtton;
var $arrows;
var currentSection = '_'
var currentSectionIndex = 0;
var anchors;
var mobileSuffix;
var player;
var is_touch = Modernizr.touch;
var active_counter = null;
var begin = moment();

var resize = function() {
    /*
    * break slides into multiple slides if the screen is too small
    */
    $w = $(window).width();
    $h = $(window).height();
};

var setUpFullPage = function() {
    // clear all anchors
    anchors = [];

    // get the anchors

   _.each($slides, function(section) {
        var anchor = $(section).data('anchor');
        if (anchor === undefined) {
            return false;
        }
        anchors.push(anchor);
    });

    $.fn.fullpage({
        autoScrolling: false,
        anchors: anchors,
        menu: '.nav',
        verticalCentered: false,
        fixedElements: '.primary-navigation, .nav',
        resize: false,
        css3: true,
        loopHorizontal: false,
        afterSlideLoad: lazyLoad,
        afterRender: onPageLoad
    });
};

var onPageLoad = function() {
    // always get the home stuff
    lazyLoad('_', 0, 'home', 0);

    // fade in
    $('body').css('opacity', 1);
};

var lazyLoad = function(anchorLink, index, slideAnchor, slideIndex) {

    var thisSlide = $slides[slideIndex];

    if ($(thisSlide).data('anchor')) {
        currentSection = $(thisSlide).data('anchor');
        findSlideIndex();
    };

    slides = [
        $slides[slideIndex - 2],
        $slides[slideIndex - 1],
        thisSlide,
        $slides[slideIndex + 1],
        $slides[slideIndex + 2]
    ];

    setMobileSuffix(slides)

    // hide slide/section nav on titlecards
    if ($slides.first().hasClass('active') === true) {
        $arrows.css('display', 'none');
        $('.next-section').css('display', 'none');
    }
    else {
        $arrows.css('display', 'block');
        $('.next-section').css('display', 'block');
    }

    if (slideAnchor === 'dashboard') {
        onStartCounts();
    }
};

var findSlideIndex = function() {
    for (i=0; i < anchors.length; i++) {
        if (anchors[i] === currentSection) {
            currentSectionIndex = i;
        }
    }
}

var setMobileSuffix = function(slides) {
    /*
    * Set background images on slides.
    * Should get square images for mobile.
    */

    // Mobile suffix should be blank by default.
    mobileSuffix = '';

    //
    if ($w < 769 && is_touch) {
        mobileSuffix = '-sq';
    }

    _.each($(slides), function(slide) {

        getBackgroundImage(slide);
        var containedImage = $(slide).find('.contained-image');
       	getBackgroundImage(containedImage);
    });
};

var getBackgroundImage = function(container) {

	if ($(container).data('bgimage')) {

            var image_filename = $(container).data('bgimage').split('.')[0];
            var image_extension = '.' + $(container).data('bgimage').split('.')[1];
            var image_path = 'assets/img/' + image_filename + mobileSuffix + image_extension;

            if ($(container).css('background-image') === 'none') {
                $(container).css('background-image', 'url(' + image_path + ')');
            }

     }
}

var goToNextSection = function() {
    $.fn.fullpage.moveTo(0, anchors[currentSectionIndex + 1]);
}

var goToNextSlide = function() {
    $.fn.fullpage.moveSlideRight();
}

var showAndHideNav = function() {
    //$nav.height($h);
    $navButton.find('i').toggleClass('fa-bars').toggleClass('fa-times');
    $nav.toggleClass('active');
    if ($nav.hasClass('active')) {
        $nav.css('display', 'block');
        var fade = _.debounce(fadeInNav, 1);
        fade();
    }
    else {
        $nav.css('opacity', 0);
        var fade = _.debounce(fadeOutNav, 500);
        fade();
    }
}

var fadeInNav = function() {
    $nav.css('opacity', 1);
};

var fadeOutNav = function() {
    $nav.css('display', 'none');
};

var revealVideo = function() {
    /*
    * Show the video.
    */
    var text = $(this).parents('.text');
    $(text).hide();
    $(text).parent().css('background-image', '');
    $(text).next().css('display', 'block');

    var $player = text.siblings('.jp-jplayer');
    initPlayer($player);
};

var initPlayer = function($player) {
    /*
    * Setup jPlayer.
    */
    var computePlayerHeight = function() {
        return ($h - ($('.jp-interface').height() + NAV_HEIGHT))
    }

    $('.jp-jplayer').jPlayer({
        ready: function () {
            $(this).jPlayer('setMedia', {
                poster: '../assets/img/junior/junior.jpg',
                m4v: 'http://pd.npr.org/npr-mp4/npr/nprvid/2014/03/20140327_nprvid_junior-n.mp4',
                webmv: '../assets/img/junior/junior.webm'
            }).jPlayer('play');
        },
        size: {
            width: $w,
            height: computePlayerHeight() + 'px'
        },
        swfPath: 'js/lib',
        supplied: 'm4v, webmv',
        loop: false
    });

    $(window).resize(function() {
        $('.jp-jplayer').jPlayer('option', { 'size': {
            width: $w,
            height: computePlayerHeight() + 'px'
        }});
    });

};

var onUpdateCounts = function(e) {
    /*
    * Updates the count based on elapsed time and known rates.
    */
    var now = moment();
    var elapsed_seconds = (now - begin) / 1000;
    var RATES = [
        ['marijuana', 0.08844],
        ['cocaine', 0.01116],
        ['illegal-entry', 0.01065],
        ['vehicles', 2.15096],
        ['pedestrians', 1.30102]
    ]

    _.each(RATES, function(count, i){
        var count_category = count[0];
        var count_number = count[1];
        var count_unit = count[2];

        $('#' + count_category + ' span.number').html(Math.round(count_number * elapsed_seconds));
    });

};

var onStartCounts = function(e) {
    active_counter = setInterval(onUpdateCounts,500);
}

$(document).ready(function() {

    /*
    * Define vars
    */

    $slides = $('.slide');
    $play_video = $('.btn-video');
    $video = $('.video');
    $components = $('.component');
    $portraits = $('.section[data-anchor="people"] .slide')
    $navButton = $('.primary-navigation-btn');
    $nav = $('.nav');
    $navItems = $('.nav .section-tease');
    $navClose = $('.close-nav');
    $nextSectionButtton = $('.next-section');
    $titleCardButton = $('.btn-play');
    $arrows = $('.controlArrow');

    // init chapters

    resize();
    setUpFullPage();

    // handlers

    $play_video.on('click', revealVideo);
    $navButton.on('click', showAndHideNav);
    $navItems.on('click', showAndHideNav);
    $navClose.on('click', showAndHideNav);
    $titleCardButton.on('click', goToNextSlide);
    $nextSectionButtton.on('click', goToNextSection);

    // Redraw slides if the window resizes
    $(window).resize(resize);

});
<commit_msg>Show duration when video ends<commit_after>/*
* Global vars
*/
var NAV_HEIGHT = 75;

var $w;
var $h;
var $slides;
var $components;
var $portraits;
var $play;
var $video;
var $navButton;
var $nav;
var $navItems;
var $navClose;
var $nextSectionButtton;
var $arrows;
var currentSection = '_'
var currentSectionIndex = 0;
var anchors;
var mobileSuffix;
var player;
var is_touch = Modernizr.touch;
var active_counter = null;
var begin = moment();

var resize = function() {
    /*
    * break slides into multiple slides if the screen is too small
    */
    $w = $(window).width();
    $h = $(window).height();
};

var setUpFullPage = function() {
    // clear all anchors
    anchors = [];

    // get the anchors

   _.each($slides, function(section) {
        var anchor = $(section).data('anchor');
        if (anchor === undefined) {
            return false;
        }
        anchors.push(anchor);
    });

    $.fn.fullpage({
        autoScrolling: false,
        anchors: anchors,
        menu: '.nav',
        verticalCentered: false,
        fixedElements: '.primary-navigation, .nav',
        resize: false,
        css3: true,
        loopHorizontal: false,
        afterSlideLoad: lazyLoad,
        afterRender: onPageLoad
    });
};

var onPageLoad = function() {
    // always get the home stuff
    lazyLoad('_', 0, 'home', 0);

    // fade in
    $('body').css('opacity', 1);
};

var lazyLoad = function(anchorLink, index, slideAnchor, slideIndex) {

    var thisSlide = $slides[slideIndex];

    if ($(thisSlide).data('anchor')) {
        currentSection = $(thisSlide).data('anchor');
        findSlideIndex();
    };

    slides = [
        $slides[slideIndex - 2],
        $slides[slideIndex - 1],
        thisSlide,
        $slides[slideIndex + 1],
        $slides[slideIndex + 2]
    ];

    setMobileSuffix(slides)

    // hide slide/section nav on titlecards
    if ($slides.first().hasClass('active') === true) {
        $arrows.css('display', 'none');
        $('.next-section').css('display', 'none');
    }
    else {
        $arrows.css('display', 'block');
        $('.next-section').css('display', 'block');
    }

    if (slideAnchor === 'dashboard') {
        onStartCounts();
    }
};

var findSlideIndex = function() {
    for (i=0; i < anchors.length; i++) {
        if (anchors[i] === currentSection) {
            currentSectionIndex = i;
        }
    }
}

var setMobileSuffix = function(slides) {
    /*
    * Set background images on slides.
    * Should get square images for mobile.
    */

    // Mobile suffix should be blank by default.
    mobileSuffix = '';

    //
    if ($w < 769 && is_touch) {
        mobileSuffix = '-sq';
    }

    _.each($(slides), function(slide) {

        getBackgroundImage(slide);
        var containedImage = $(slide).find('.contained-image');
       	getBackgroundImage(containedImage);
    });
};

var getBackgroundImage = function(container) {

	if ($(container).data('bgimage')) {

            var image_filename = $(container).data('bgimage').split('.')[0];
            var image_extension = '.' + $(container).data('bgimage').split('.')[1];
            var image_path = 'assets/img/' + image_filename + mobileSuffix + image_extension;

            if ($(container).css('background-image') === 'none') {
                $(container).css('background-image', 'url(' + image_path + ')');
            }

     }
}

var goToNextSection = function() {
    $.fn.fullpage.moveTo(0, anchors[currentSectionIndex + 1]);
}

var goToNextSlide = function() {
    $.fn.fullpage.moveSlideRight();
}

var showAndHideNav = function() {
    //$nav.height($h);
    $navButton.find('i').toggleClass('fa-bars').toggleClass('fa-times');
    $nav.toggleClass('active');
    if ($nav.hasClass('active')) {
        $nav.css('display', 'block');
        var fade = _.debounce(fadeInNav, 1);
        fade();
    }
    else {
        $nav.css('opacity', 0);
        var fade = _.debounce(fadeOutNav, 500);
        fade();
    }
}

var fadeInNav = function() {
    $nav.css('opacity', 1);
};

var fadeOutNav = function() {
    $nav.css('display', 'none');
};

var revealVideo = function() {
    /*
    * Show the video.
    */
    var text = $(this).parents('.text');
    $(text).hide();
    $(text).parent().css('background-image', '');
    $(text).next().css('display', 'block');

    var $player = text.siblings('.jp-jplayer');
    initPlayer($player);
};

var initPlayer = function($player) {
    /*
    * Setup jPlayer.
    */
    var computePlayerHeight = function() {
        return ($h - ($('.jp-interface').height() + NAV_HEIGHT))
    }

    $('.jp-jplayer').jPlayer({
        ready: function () {
            $(this).jPlayer('setMedia', {
                poster: '../assets/img/junior/junior.jpg',
                m4v: 'http://pd.npr.org/npr-mp4/npr/nprvid/2014/03/20140327_nprvid_junior-n.mp4',
                webmv: '../assets/img/junior/junior.webm'
            }).jPlayer('play');
        },
        play: function (){
            $('.jp-current-time').removeClass('hide');
            $('.jp-duration').addClass('hide');
        },
        ended: function(){
            $('.jp-current-time').addClass('hide');
            $('.jp-duration').removeClass('hide');
        },
        size: {
            width: $w,
            height: computePlayerHeight() + 'px'
        },
        swfPath: 'js/lib',
        supplied: 'm4v, webmv',
        loop: false
    });

    $(window).resize(function() {
        $('.jp-jplayer').jPlayer('option', { 'size': {
            width: $w,
            height: computePlayerHeight() + 'px'
        }});
    });

};

var onUpdateCounts = function(e) {
    /*
    * Updates the count based on elapsed time and known rates.
    */
    var now = moment();
    var elapsed_seconds = (now - begin) / 1000;
    var RATES = [
        ['marijuana', 0.08844],
        ['cocaine', 0.01116],
        ['illegal-entry', 0.01065],
        ['vehicles', 2.15096],
        ['pedestrians', 1.30102]
    ]

    _.each(RATES, function(count, i){
        var count_category = count[0];
        var count_number = count[1];
        var count_unit = count[2];

        $('#' + count_category + ' span.number').html(Math.round(count_number * elapsed_seconds));
    });

};

var onStartCounts = function(e) {
    active_counter = setInterval(onUpdateCounts,500);
}

$(document).ready(function() {

    /*
    * Define vars
    */

    $slides = $('.slide');
    $play_video = $('.btn-video');
    $video = $('.video');
    $components = $('.component');
    $portraits = $('.section[data-anchor="people"] .slide')
    $navButton = $('.primary-navigation-btn');
    $nav = $('.nav');
    $navItems = $('.nav .section-tease');
    $navClose = $('.close-nav');
    $nextSectionButtton = $('.next-section');
    $titleCardButton = $('.btn-play');
    $arrows = $('.controlArrow');

    // init chapters

    resize();
    setUpFullPage();

    // handlers

    $play_video.on('click', revealVideo);
    $navButton.on('click', showAndHideNav);
    $navItems.on('click', showAndHideNav);
    $navClose.on('click', showAndHideNav);
    $titleCardButton.on('click', goToNextSlide);
    $nextSectionButtton.on('click', goToNextSection);

    // Redraw slides if the window resizes
    $(window).resize(resize);

});
<|endoftext|>


<commit_before>
/**
 * mod3rate graphs - a wrapper for d3 graphs
 *
 * Just a wrapper to create some basic graphs, see https://d3js.org/ for a full
 * powered, awesome data driven documents suite.
 *
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <christoph@lipautz.org> wrote this file. As long as you retain this notice
 * you can do whatever you want with this stuff. If we meet some day, and you
 * think this stuff is worth it, you can buy me a beer in return.
 * Christoph Lipautz
 * ----------------------------------------------------------------------------
 **/

var mod3rateGraphs = {
  BaseGraph: {
    data:        [],
    graph:       null,
    target:      "body",
    initialized: false,

    fetchWidth: function() {
      return d3.select(this.target).node().getBoundingClientRect().width;
    },
    fetchHeight: function() {
      return d3.select(this.target).node().getBoundingClientRect().height;
    },

    draw: function() {
      if(this.initialized == false) {
        this.init();
      } else {
        this.update();
      }
    },

    filter: function(d) { return d; }
  },

  graphs: {},

  addGraph: function(name, obj) {
    for(var prop in this.BaseGraph) {
      if(!obj.hasOwnProperty(prop)) {
        obj[prop] = this.BaseGraph[prop];
      }
    }
    this.graphs[name] = obj;
  },
};

mod3rateGraphs.addGraph("timeline", {

  valueline: d3.svg.area(),
  xAxis:     null,
  yAxis:     null,
  x:         null,
  y:         null,

  init: function() {
    var width  = this.fetchWidth(),
        height = this.fetchHeight();
    var margin = { h: width / 25, v: height / 5 };

    // Set the ranges
    this.x = d3.time.scale().range([0, width - margin.h]);
    this.y = d3.scale.linear().range([height - 2 * margin.v, 0]);

    // Define the axes
    this.xAxis = d3.svg.axis().scale(this.x).orient("bottom").ticks(5);
    this.yAxis = d3.svg.axis().scale(this.y).orient("left").ticks(5);

    // Adds the svg canvas
    this.graph = d3.select(this.target)
      .append("svg")
        .attr("width",  width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate("+margin.h+", "+margin.v+")");

    var data = this.data.map(this.filter);

    // Define the area
    this.valueline
      .x(function(d) { return this.x(d.time); })
      .y0(height)
      .y1(function(d) { return this.y(d.value); });

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Add the valueline path.
    this.graph.append("path")
      .attr("class", "line")
      .attr("d", this.valueline(data));

    // Add the X Axis
    this.graph.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0, "+(height - 2 * margin.v)+")")
      .call(this.xAxis);

    // Add the Y Axis
    this.graph.append("g")
      .attr("class", "y axis")
      .call(this.yAxis);

    this.initialized = true;
  },

  update: function() {
    var data = this.data.map(this.filter);

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Make the changes
    var graph = this.graph.transition().duration(750);
    graph.select(".line").attr("d", this.valueline(data));
    graph.select(".x.axis").call(this.xAxis);
    graph.select(".y.axis").call(this.yAxis);
  }

});

mod3rateGraphs.addGraph("timeline", {

  valueline: d3.svg.line(),
  xAxis:     null,
  yAxis:     null,
  x:         null,
  y:         null,

  init: function() {
    var width  = this.fetchWidth(),
        height = this.fetchHeight();
    var margin = { h: width / 25, v: height / 5 };

    // Set the ranges
    this.x = d3.time.scale().range([0, width - margin.h]);
    this.y = d3.scale.linear().range([height - 2 * margin.v, 0]);

    // Define the axes
    this.xAxis = d3.svg.axis().scale(this.x).orient("bottom").ticks(5);
    this.yAxis = d3.svg.axis().scale(this.y).orient("left").ticks(5);

    // Adds the svg canvas
    this.graph = d3.select(this.target)
      .append("svg")
        .attr("width",  width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate("+margin.h+", "+margin.v+")");

    var data = this.data.map(this.filter);

    // Define the line
    this.valueline = this.valueline
      .x(function(d) { return this.x(d.time); })
      .y(function(d) { return this.y(d.value); });

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Add the valueline path.
    this.graph.append("path")
      .attr("class", "line")
      .attr("d", this.valueline(data));

    // Add the X Axis
    this.graph.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0, "+(height - 2 * margin.v)+")")
      .call(this.xAxis);

    // Add the Y Axis
    this.graph.append("g")
      .attr("class", "y axis")
      .call(this.yAxis);

    this.initialized = true;
  },

  update: function() {
    var data = this.data.map(this.filter);

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    //this.graph = this.graph.transition();

    // Make the changes
    var graph = this.graph.transition().duration(750);
    graph.select(".line").attr("d", this.valueline(data));
    graph.select(".x.axis").call(this.xAxis);
    graph.select(".y.axis").call(this.yAxis);
  }

});

var mod3rate = (function() {
  if(typeof d3 === "undefined") {
    console.error("mod3erate requires d3 as it works as a wrapper");
  }

  var graph;

  var graphFactory = function(name) {
    var name = name.toLowerCase();
    graph    = mod3rateGraphs.graphs[name];

    if(typeof graph === "undefined") {
        console.error("no graph "+name+" registered");
    }

    return this;
  };

  var setTarget = function(target) {
    graph.target = target;

    return this;
  };

  var setFilter = function(filter) {
    graph.filter = filter;

    return this;
  };

  var setData = function(data) {
    graph.data = data;

    return this;
  };

  var draw = function(data=false) {
    if(data !== false) {
      setData(data);
    }
    graph.draw();

    return this;
  };

  return {
    use:    graphFactory,
    on:     setTarget,
    filter: setFilter,
    data:   setData,
    draw:   draw
  };
})();

<commit_msg>fix minimal js syntax error<commit_after>
/**
 * mod3rate graphs - a wrapper for d3 graphs
 *
 * Just a wrapper to create some basic graphs, see https://d3js.org/ for a full
 * powered, awesome data driven documents suite.
 *
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <christoph@lipautz.org> wrote this file. As long as you retain this notice
 * you can do whatever you want with this stuff. If we meet some day, and you
 * think this stuff is worth it, you can buy me a beer in return.
 * Christoph Lipautz
 * ----------------------------------------------------------------------------
 **/

var mod3rateGraphs = {
  BaseGraph: {
    data:        [],
    graph:       null,
    target:      "body",
    initialized: false,

    fetchWidth: function() {
      return d3.select(this.target).node().getBoundingClientRect().width;
    },
    fetchHeight: function() {
      return d3.select(this.target).node().getBoundingClientRect().height;
    },

    draw: function() {
      if(this.initialized == false) {
        this.init();
      } else {
        this.update();
      }
    },

    filter: function(d) { return d; }
  },

  graphs: {},

  addGraph: function(name, obj) {
    for(var prop in this.BaseGraph) {
      if(!obj.hasOwnProperty(prop)) {
        obj[prop] = this.BaseGraph[prop];
      }
    }
    this.graphs[name] = obj;
  }
};

mod3rateGraphs.addGraph("timeline", {

  valueline: d3.svg.area(),
  xAxis:     null,
  yAxis:     null,
  x:         null,
  y:         null,

  init: function() {
    var width  = this.fetchWidth(),
        height = this.fetchHeight();
    var margin = { h: width / 25, v: height / 5 };

    // Set the ranges
    this.x = d3.time.scale().range([0, width - margin.h]);
    this.y = d3.scale.linear().range([height - 2 * margin.v, 0]);

    // Define the axes
    this.xAxis = d3.svg.axis().scale(this.x).orient("bottom").ticks(5);
    this.yAxis = d3.svg.axis().scale(this.y).orient("left").ticks(5);

    // Adds the svg canvas
    this.graph = d3.select(this.target)
      .append("svg")
        .attr("width",  width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate("+margin.h+", "+margin.v+")");

    var data = this.data.map(this.filter);

    // Define the area
    this.valueline
      .x(function(d) { return this.x(d.time); })
      .y0(height)
      .y1(function(d) { return this.y(d.value); });

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Add the valueline path.
    this.graph.append("path")
      .attr("class", "line")
      .attr("d", this.valueline(data));

    // Add the X Axis
    this.graph.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0, "+(height - 2 * margin.v)+")")
      .call(this.xAxis);

    // Add the Y Axis
    this.graph.append("g")
      .attr("class", "y axis")
      .call(this.yAxis);

    this.initialized = true;
  },

  update: function() {
    var data = this.data.map(this.filter);

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Make the changes
    var graph = this.graph.transition().duration(750);
    graph.select(".line").attr("d", this.valueline(data));
    graph.select(".x.axis").call(this.xAxis);
    graph.select(".y.axis").call(this.yAxis);
  }

});

mod3rateGraphs.addGraph("timeline", {

  valueline: d3.svg.line(),
  xAxis:     null,
  yAxis:     null,
  x:         null,
  y:         null,

  init: function() {
    var width  = this.fetchWidth(),
        height = this.fetchHeight();
    var margin = { h: width / 25, v: height / 5 };

    // Set the ranges
    this.x = d3.time.scale().range([0, width - margin.h]);
    this.y = d3.scale.linear().range([height - 2 * margin.v, 0]);

    // Define the axes
    this.xAxis = d3.svg.axis().scale(this.x).orient("bottom").ticks(5);
    this.yAxis = d3.svg.axis().scale(this.y).orient("left").ticks(5);

    // Adds the svg canvas
    this.graph = d3.select(this.target)
      .append("svg")
        .attr("width",  width)
        .attr("height", height)
      .append("g")
        .attr("transform", "translate("+margin.h+", "+margin.v+")");

    var data = this.data.map(this.filter);

    // Define the line
    this.valueline = this.valueline
      .x(function(d) { return this.x(d.time); })
      .y(function(d) { return this.y(d.value); });

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    // Add the valueline path.
    this.graph.append("path")
      .attr("class", "line")
      .attr("d", this.valueline(data));

    // Add the X Axis
    this.graph.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0, "+(height - 2 * margin.v)+")")
      .call(this.xAxis);

    // Add the Y Axis
    this.graph.append("g")
      .attr("class", "y axis")
      .call(this.yAxis);

    this.initialized = true;
  },

  update: function() {
    var data = this.data.map(this.filter);

    // Scale the range of the data
    this.x.domain(d3.extent(data,  function(d) { return d.time;  }));
    this.y.domain([0, d3.max(data, function(d) { return d.value; })]);

    //this.graph = this.graph.transition();

    // Make the changes
    var graph = this.graph.transition().duration(750);
    graph.select(".line").attr("d", this.valueline(data));
    graph.select(".x.axis").call(this.xAxis);
    graph.select(".y.axis").call(this.yAxis);
  }

});

var mod3rate = (function() {
  if(typeof d3 === "undefined") {
    console.error("mod3erate requires d3 as it works as a wrapper");
  }

  var graph;

  var graphFactory = function(name) {
    var name = name.toLowerCase();
    graph    = mod3rateGraphs.graphs[name];

    if(typeof graph === "undefined") {
        console.error("no graph "+name+" registered");
    }

    return this;
  };

  var setTarget = function(target) {
    graph.target = target;

    return this;
  };

  var setFilter = function(filter) {
    graph.filter = filter;

    return this;
  };

  var setData = function(data) {
    graph.data = data;

    return this;
  };

  var draw = function(data=false) {
    if(data !== false) {
      setData(data);
    }
    graph.draw();

    return this;
  };

  return {
    use:    graphFactory,
    on:     setTarget,
    filter: setFilter,
    data:   setData,
    draw:   draw
  };
})();

<|endoftext|>