<commit_before>(function($) {
  /*
    ======== A Handy Little QUnit Reference ========
    http://api.qunitjs.com/

    Test methods:
      module(name, {[setup][ ,teardown]})
      test(name, callback)
      expect(numberOfAssertions)
      stop(increment)
      start(decrement)
    Test assertions:
      ok(value, [message])
      equal(actual, expected, [message])
      notEqual(actual, expected, [message])
      deepEqual(actual, expected, [message])
      notDeepEqual(actual, expected, [message])
      strictEqual(actual, expected, [message])
      notStrictEqual(actual, expected, [message])
      throws(block, [expected], [message])
  */

 module('core', {
  // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.content_before = $('#qunit-fixture')[0].innerHTML;
      this.init = this.elems.scrollNav();
      this.instances = $('.scroll-nav').length;
      this.destroy = this.elems.scrollNav('destroy');
      this.destroyed = $('.scroll-nav').length;
      this.content_after = $('#qunit-fixture')[0].innerHTML;
    }, teardown: function() {
      // already torn down when destroyed
    }
 });

 test('is chainable', function() {
    expect(1);
    // Not a bad test to run on collection methods.
    strictEqual(this.init, this.elems, 'should be chainable');
  });

 test('correct instances', function() {
    expect(1);
    // Not a bad test to run on collection methods.
    strictEqual(this.instances, 1, 'should create one');
  });

 test('is destroyable', function() {
    expect(1);
    // Scroll Nav shouldn't exist after destroy method is called.
    strictEqual(this.destroyed, 0, 'should be zero');
 });

 test('removes dom changes when destroyed', function() {
  expect(1);
  // Section and sub-section wrappers should be removed without changing the content
  notStrictEqual(this.content_before, this.content_after, 'elem content should be reset to original');
 });

  module('sections', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.sections = this.elems.scrollNav().children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('correct total number of sections', function() {
    expect(3);

    strictEqual(this.sections.length, 2, 'should be two');
    notStrictEqual(this.sections.length, 1, 'should not be one');
    notStrictEqual(this.sections.length, 0, 'should not be zero');
  });

  test('correct number of children in first section', function() {
    expect(3);

    strictEqual(this.sections.eq(0).children().length, 6, 'should be six');
    notStrictEqual(this.sections.eq(0).children().length, 5, 'should not be five');
    notStrictEqual(this.sections.eq(0).children().length, 7, 'should not be seven');
  });

  test('correct number of children in second section', function() {
    expect(3);

    strictEqual(this.sections.eq(1).children().length, 6, 'should be six');
    notStrictEqual(this.sections.eq(1).children().length, 5, 'should not be five');
    notStrictEqual(this.sections.eq(1).children().length, 7, 'should not be seven');
  });

  test('first section is correct tag', function() {
    expect(4);
    var sectionTag = this.sections.eq(0).prop('tagName');

    strictEqual(sectionTag, 'SECTION', 'should be a section tag');
    notStrictEqual(sectionTag, 'DIV', 'should not be a div tag');
    notStrictEqual(sectionTag, 'H2', 'should not be an h2 tag');
    notStrictEqual(sectionTag, 'P', 'should not be a p tag');
  });

  test('second section is correct tag', function() {
    expect(4);
    var sectionTag = this.sections.eq(1).prop('tagName');

    strictEqual(sectionTag, 'SECTION', 'should be a section tag');
    notStrictEqual(sectionTag, 'DIV', 'should not be a div tag');
    notStrictEqual(sectionTag, 'H2', 'should not be an h2 tag');
    notStrictEqual(sectionTag, 'P', 'should not be a p tag');
  });

  test('first section has correct id', function() {
    expect(4);
    var sectionID = this.sections.eq(0).attr('id');

    strictEqual(sectionID, 'scrollNav-1', 'should be scrollNav-1');
    notStrictEqual(sectionID, 'scrollNav-0', 'should not be scrollNav-0');
    notStrictEqual(sectionID, 'scrollNav-2', 'should not be scrollNav-2');
    notStrictEqual(sectionID, 'scrollNav-1-1', 'should not be scrollNav-1-1');
  });

  test('second section has correct id', function() {
    expect(4);
    var sectionID = this.sections.eq(1).attr('id');

    strictEqual(sectionID, 'scrollNav-2', 'should be scrollNav-2');
    notStrictEqual(sectionID, 'scrollNav-1', 'should not be scrollNav-1');
    notStrictEqual(sectionID, 'scrollNav-3', 'should not be scrollNav-3');
    notStrictEqual(sectionID, 'scrollNav-2-1', 'should not be scrollNav-2-1');
  });

  test('firs section has correct class', function() {
    expect(2);

    var sectionClass = this.sections.eq(0).attr('class');

    strictEqual(sectionClass, 'scroll-nav__section', 'should be scroll-nav__section');
    notStrictEqual(sectionClass, '', 'should not be empty');
  });

  module('subSections', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        sections: 'h2',
        subSections: 'h3',
        showHeadline: true
      });
      this.sections = this.scrollNav.children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('correct total number of sub-sections in first section', function() {
    expect(3);
    var $subSections = this.sections.eq(0).find('.scroll-nav__sub-section');

    strictEqual($subSections.length, 2, 'should be two');
    notStrictEqual($subSections.length, 1, 'should not be one');
    notStrictEqual($subSections.length, 0, 'should not be zero');
  });

  module('nav', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav();
      this.sections = this.scrollNav.children();
      this.nav = this.scrollNav.siblings('nav');
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('nav is inserted', function() {
    expect(1);

    equal(this.nav.length, true, 'nav should exist');
  });

  test('nav has correct class', function() {
    expect(2);
    var navClass = this.nav.attr('class');

    strictEqual(navClass, 'scroll-nav', 'should be scroll-nav');
    notStrictEqual(navClass, '', 'should not be empty');
  });

  test('wrapper has correct class', function() {
    expect(2);
    var wrapperClass = this.nav.children('div').attr('class');

    strictEqual(wrapperClass, 'scroll-nav__wrapper', 'should be scroll-nav__wrapper');
    notStrictEqual(wrapperClass, '', 'should not be empty');
  });

  test('first nav link has correct text', function() {
    expect(3);
    var headingText = this.sections.eq(0).children().eq(0).text();
    var linkText = this.nav.find('li').eq(0).text();

    strictEqual(linkText, headingText, 'should be Test Heading');
    notStrictEqual(linkText, 'lame test markup', 'should not be lame test');
    notStrictEqual(linkText, 'Another Test Heading', 'should not be Another Test Heading');
  });

  test('second nav link has correct text', function() {
    expect(3);
    var headingText = this.sections.eq(1).children().eq(0).text();
    var linkText = this.nav.find('li').eq(1).text();

    strictEqual(linkText, headingText, 'should be Another Test Heading');
    notStrictEqual(linkText, 'lame test markup', 'should not be lame test');
    notStrictEqual(linkText, 'Test Heading', 'should not be Test Heading');
  });

  test('first nav link has correct url', function() {
    expect(3);
    var sectionID = this.sections.eq(0).attr('id');
    var linkURL = this.nav.find('li').eq(0).find('a').attr('href');

    strictEqual(linkURL, '#' + sectionID, 'should be #scrollNav-1');
    notStrictEqual(linkURL, 'lame test markup', 'should not be #scrollNav-0');
    notStrictEqual(linkURL, 'Another Test Heading', 'should not be #scrollNav-2');
  });

  test('second nav link has correct url', function() {
    expect(3);
    var sectionID = this.sections.eq(1).attr('id');
    var linkURL = this.nav.find('li').eq(1).find('a').attr('href');

    strictEqual(linkURL, '#' + sectionID, 'should be #scrollNav-2');
    notStrictEqual(linkURL, 'lame test markup', 'should not be #scrollNav-1');
    notStrictEqual(linkURL, 'Another Test Heading', 'should not be #scrollNav-3');
  });

  module('test-options', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        className: 'nav-test'
      });
      this.nav = this.scrollNav.siblings('nav');
      this.sections = this.scrollNav.children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('nav has correct class', function() {
    expect(3);
    var navClass = this.nav.attr('class');

    strictEqual(navClass, 'nav-test', 'should be nav-test');
    notStrictEqual(navClass, 'scroll-nav', 'should not be scroll-nav')
    notStrictEqual(navClass, '', 'should not be empty');
  });

  test('wrapper has correct class', function() {
    expect(3);
    var wrapperClass = this.nav.children('div').attr('class');

    strictEqual(wrapperClass, 'nav-test__wrapper', 'should be nav-test__wrapper');
    notStrictEqual(wrapperClass, 'scroll-nav__wrapper', 'schould not be scroll-nav__wrapper');
    notStrictEqual(wrapperClass, '', 'should not be empty');
  });

  test('firs section has correct class', function() {
    expect(3);

    var sectionClass = this.sections.eq(0).attr('class');

    strictEqual(sectionClass, 'nav-test__section', 'should be nav-test__section');
    notStrictEqual(sectionClass, 'scroll-nav__section', 'should not be scroll-nav__section');
    notStrictEqual(sectionClass, '', 'should not be empty');
  });

  module('callbacks', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        onInit: function() {
          $('body').addClass('init-callback');
        },
        onRender: function() {
          $('body').addClass('render-callback');
        },
        onDestroy: function() {
          $('body').removeClass('init-callback render-callback');
        }
      });
      this.hasInitClass = $('body').hasClass('init-callback');
      this.hasRenderClass = $('body').hasClass('render-callback');
      this.destroy = this.elems.scrollNav('destroy');
      this.destroyedInitClass = $('body').hasClass('init-callback');
      this.destroyedRenderClass = $('body').hasClass('render-callback');
    }, teardown: function() {
      // already torn down when destroyed
    }
  });

  test('onInit callback', function() {
    expect(1);

    strictEqual(true, this.hasInitClass, 'init-callback class should exist');
  });

  test('onRender callback', function() {
    expect(1);

    strictEqual(true, this.hasRenderClass, 'render-callback class should exist');
  });

  test('onDestroy callback', function() {
    expect(2);

    strictEqual(false, this.destroyedInitClass, 'init-callback class should be removed');
    strictEqual(false, this.destroyedRenderClass, 'render-callback class should be removed');
  });

}(jQuery));
<commit_msg>Added missing semi-colon<commit_after>(function($) {
  /*
    ======== A Handy Little QUnit Reference ========
    http://api.qunitjs.com/

    Test methods:
      module(name, {[setup][ ,teardown]})
      test(name, callback)
      expect(numberOfAssertions)
      stop(increment)
      start(decrement)
    Test assertions:
      ok(value, [message])
      equal(actual, expected, [message])
      notEqual(actual, expected, [message])
      deepEqual(actual, expected, [message])
      notDeepEqual(actual, expected, [message])
      strictEqual(actual, expected, [message])
      notStrictEqual(actual, expected, [message])
      throws(block, [expected], [message])
  */

 module('core', {
  // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.content_before = $('#qunit-fixture')[0].innerHTML;
      this.init = this.elems.scrollNav();
      this.instances = $('.scroll-nav').length;
      this.destroy = this.elems.scrollNav('destroy');
      this.destroyed = $('.scroll-nav').length;
      this.content_after = $('#qunit-fixture')[0].innerHTML;
    }, teardown: function() {
      // already torn down when destroyed
    }
 });

 test('is chainable', function() {
    expect(1);
    // Not a bad test to run on collection methods.
    strictEqual(this.init, this.elems, 'should be chainable');
  });

 test('correct instances', function() {
    expect(1);
    // Not a bad test to run on collection methods.
    strictEqual(this.instances, 1, 'should create one');
  });

 test('is destroyable', function() {
    expect(1);
    // Scroll Nav shouldn't exist after destroy method is called.
    strictEqual(this.destroyed, 0, 'should be zero');
 });

 test('removes dom changes when destroyed', function() {
  expect(1);
  // Section and sub-section wrappers should be removed without changing the content
  notStrictEqual(this.content_before, this.content_after, 'elem content should be reset to original');
 });

  module('sections', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.sections = this.elems.scrollNav().children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('correct total number of sections', function() {
    expect(3);

    strictEqual(this.sections.length, 2, 'should be two');
    notStrictEqual(this.sections.length, 1, 'should not be one');
    notStrictEqual(this.sections.length, 0, 'should not be zero');
  });

  test('correct number of children in first section', function() {
    expect(3);

    strictEqual(this.sections.eq(0).children().length, 6, 'should be six');
    notStrictEqual(this.sections.eq(0).children().length, 5, 'should not be five');
    notStrictEqual(this.sections.eq(0).children().length, 7, 'should not be seven');
  });

  test('correct number of children in second section', function() {
    expect(3);

    strictEqual(this.sections.eq(1).children().length, 6, 'should be six');
    notStrictEqual(this.sections.eq(1).children().length, 5, 'should not be five');
    notStrictEqual(this.sections.eq(1).children().length, 7, 'should not be seven');
  });

  test('first section is correct tag', function() {
    expect(4);
    var sectionTag = this.sections.eq(0).prop('tagName');

    strictEqual(sectionTag, 'SECTION', 'should be a section tag');
    notStrictEqual(sectionTag, 'DIV', 'should not be a div tag');
    notStrictEqual(sectionTag, 'H2', 'should not be an h2 tag');
    notStrictEqual(sectionTag, 'P', 'should not be a p tag');
  });

  test('second section is correct tag', function() {
    expect(4);
    var sectionTag = this.sections.eq(1).prop('tagName');

    strictEqual(sectionTag, 'SECTION', 'should be a section tag');
    notStrictEqual(sectionTag, 'DIV', 'should not be a div tag');
    notStrictEqual(sectionTag, 'H2', 'should not be an h2 tag');
    notStrictEqual(sectionTag, 'P', 'should not be a p tag');
  });

  test('first section has correct id', function() {
    expect(4);
    var sectionID = this.sections.eq(0).attr('id');

    strictEqual(sectionID, 'scrollNav-1', 'should be scrollNav-1');
    notStrictEqual(sectionID, 'scrollNav-0', 'should not be scrollNav-0');
    notStrictEqual(sectionID, 'scrollNav-2', 'should not be scrollNav-2');
    notStrictEqual(sectionID, 'scrollNav-1-1', 'should not be scrollNav-1-1');
  });

  test('second section has correct id', function() {
    expect(4);
    var sectionID = this.sections.eq(1).attr('id');

    strictEqual(sectionID, 'scrollNav-2', 'should be scrollNav-2');
    notStrictEqual(sectionID, 'scrollNav-1', 'should not be scrollNav-1');
    notStrictEqual(sectionID, 'scrollNav-3', 'should not be scrollNav-3');
    notStrictEqual(sectionID, 'scrollNav-2-1', 'should not be scrollNav-2-1');
  });

  test('firs section has correct class', function() {
    expect(2);

    var sectionClass = this.sections.eq(0).attr('class');

    strictEqual(sectionClass, 'scroll-nav__section', 'should be scroll-nav__section');
    notStrictEqual(sectionClass, '', 'should not be empty');
  });

  module('subSections', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        sections: 'h2',
        subSections: 'h3',
        showHeadline: true
      });
      this.sections = this.scrollNav.children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('correct total number of sub-sections in first section', function() {
    expect(3);
    var $subSections = this.sections.eq(0).find('.scroll-nav__sub-section');

    strictEqual($subSections.length, 2, 'should be two');
    notStrictEqual($subSections.length, 1, 'should not be one');
    notStrictEqual($subSections.length, 0, 'should not be zero');
  });

  module('nav', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav();
      this.sections = this.scrollNav.children();
      this.nav = this.scrollNav.siblings('nav');
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('nav is inserted', function() {
    expect(1);

    equal(this.nav.length, true, 'nav should exist');
  });

  test('nav has correct class', function() {
    expect(2);
    var navClass = this.nav.attr('class');

    strictEqual(navClass, 'scroll-nav', 'should be scroll-nav');
    notStrictEqual(navClass, '', 'should not be empty');
  });

  test('wrapper has correct class', function() {
    expect(2);
    var wrapperClass = this.nav.children('div').attr('class');

    strictEqual(wrapperClass, 'scroll-nav__wrapper', 'should be scroll-nav__wrapper');
    notStrictEqual(wrapperClass, '', 'should not be empty');
  });

  test('first nav link has correct text', function() {
    expect(3);
    var headingText = this.sections.eq(0).children().eq(0).text();
    var linkText = this.nav.find('li').eq(0).text();

    strictEqual(linkText, headingText, 'should be Test Heading');
    notStrictEqual(linkText, 'lame test markup', 'should not be lame test');
    notStrictEqual(linkText, 'Another Test Heading', 'should not be Another Test Heading');
  });

  test('second nav link has correct text', function() {
    expect(3);
    var headingText = this.sections.eq(1).children().eq(0).text();
    var linkText = this.nav.find('li').eq(1).text();

    strictEqual(linkText, headingText, 'should be Another Test Heading');
    notStrictEqual(linkText, 'lame test markup', 'should not be lame test');
    notStrictEqual(linkText, 'Test Heading', 'should not be Test Heading');
  });

  test('first nav link has correct url', function() {
    expect(3);
    var sectionID = this.sections.eq(0).attr('id');
    var linkURL = this.nav.find('li').eq(0).find('a').attr('href');

    strictEqual(linkURL, '#' + sectionID, 'should be #scrollNav-1');
    notStrictEqual(linkURL, 'lame test markup', 'should not be #scrollNav-0');
    notStrictEqual(linkURL, 'Another Test Heading', 'should not be #scrollNav-2');
  });

  test('second nav link has correct url', function() {
    expect(3);
    var sectionID = this.sections.eq(1).attr('id');
    var linkURL = this.nav.find('li').eq(1).find('a').attr('href');

    strictEqual(linkURL, '#' + sectionID, 'should be #scrollNav-2');
    notStrictEqual(linkURL, 'lame test markup', 'should not be #scrollNav-1');
    notStrictEqual(linkURL, 'Another Test Heading', 'should not be #scrollNav-3');
  });

  module('test-options', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        className: 'nav-test'
      });
      this.nav = this.scrollNav.siblings('nav');
      this.sections = this.scrollNav.children();
    }, teardown: function() {
      this.elems.scrollNav('destroy');
    }
  });

  test('nav has correct class', function() {
    expect(3);
    var navClass = this.nav.attr('class');

    strictEqual(navClass, 'nav-test', 'should be nav-test');
    notStrictEqual(navClass, 'scroll-nav', 'should not be scroll-nav');
    notStrictEqual(navClass, '', 'should not be empty');
  });

  test('wrapper has correct class', function() {
    expect(3);
    var wrapperClass = this.nav.children('div').attr('class');

    strictEqual(wrapperClass, 'nav-test__wrapper', 'should be nav-test__wrapper');
    notStrictEqual(wrapperClass, 'scroll-nav__wrapper', 'schould not be scroll-nav__wrapper');
    notStrictEqual(wrapperClass, '', 'should not be empty');
  });

  test('firs section has correct class', function() {
    expect(3);

    var sectionClass = this.sections.eq(0).attr('class');

    strictEqual(sectionClass, 'nav-test__section', 'should be nav-test__section');
    notStrictEqual(sectionClass, 'scroll-nav__section', 'should not be scroll-nav__section');
    notStrictEqual(sectionClass, '', 'should not be empty');
  });

  module('callbacks', {
    // This will run before each test in this module.
    setup: function() {
      this.elems = $('#qunit-fixture');
      this.scrollNav = this.elems.scrollNav({
        onInit: function() {
          $('body').addClass('init-callback');
        },
        onRender: function() {
          $('body').addClass('render-callback');
        },
        onDestroy: function() {
          $('body').removeClass('init-callback render-callback');
        }
      });
      this.hasInitClass = $('body').hasClass('init-callback');
      this.hasRenderClass = $('body').hasClass('render-callback');
      this.destroy = this.elems.scrollNav('destroy');
      this.destroyedInitClass = $('body').hasClass('init-callback');
      this.destroyedRenderClass = $('body').hasClass('render-callback');
    }, teardown: function() {
      // already torn down when destroyed
    }
  });

  test('onInit callback', function() {
    expect(1);

    strictEqual(true, this.hasInitClass, 'init-callback class should exist');
  });

  test('onRender callback', function() {
    expect(1);

    strictEqual(true, this.hasRenderClass, 'render-callback class should exist');
  });

  test('onDestroy callback', function() {
    expect(2);

    strictEqual(false, this.destroyedInitClass, 'init-callback class should be removed');
    strictEqual(false, this.destroyedRenderClass, 'render-callback class should be removed');
  });

}(jQuery));
<|endoftext|>


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

var fs = require( 'fs' );
var esprima = require( 'esprima' );
var beautify_html = require( 'js-beautify' ).html;
var extractDocumentation = require( '../chipper/js/common/extractDocumentation' );
var documentationToHTML = require( '../chipper/js/common/documentationToHTML' );

/*global module:false*/
module.exports = function( grunt ) {
  'use strict';

  // print this immediately, so it is clear what project grunt is building
  grunt.log.writeln( 'Dot' );

  // --disable-es-cache disables the cache, useful for developing rules
  var cache = !grunt.option( 'disable-eslint-cache' );

  // Project configuration.
  grunt.initConfig( {
    pkg: '<json:package.json>',

    requirejs: {
      // unminified
      development: {
        options: {
          almond: true,
          mainConfigFile: 'js/config.js',
          out: 'build/development/dot.js',
          name: 'config',
          optimize: 'none',
          wrap: {
            startFile: [ 'js/wrap-start.frag', '../assert/js/assert.js' ],
            endFile: [ 'js/wrap-end.frag' ]
          }
        }
      },

      production: {
        options: {
          almond: true,
          mainConfigFile: 'js/config.js',
          out: 'build/production/dot.min.js',
          name: 'config',
          optimize: 'uglify2',
          generateSourceMaps: true,
          preserveLicenseComments: false,
          wrap: {
            startFile: [ 'js/wrap-start.frag', '../assert/js/assert.js' ],
            endFile: [ 'js/wrap-end.frag' ]
          },
          uglify2: {
            compress: {
              global_defs: {
                assert: false,
                assertSlow: false,
                phetAllocation: false
              },
              dead_code: true
            }
          }
        }
      }
    },

    eslint: {
      options: {

        // Rules are specified in the .eslintrc file
        configFile: '../chipper/eslint/.eslintrc',

        // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
        // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
        // grunt was run from.
        cache: cache,

        // Our custom rules live here
        rulePaths: [ '../chipper/eslint/rules' ]
      },

      files: [
        'Gruntfile.js',
        '../phet-core/js/**/*.js',
        '../axon/js/**/*.js',
        '../assert/js/**/*.js',
        'js/**/*.js'
      ]
    }
  } );

  // default task ('grunt')
  grunt.registerTask( 'default', [ 'lint', 'development', 'production' ] );

  // linter on dot subset only ('grunt lint')
  grunt.registerTask( 'lint', [ 'eslint:files' ] );

  // compilation targets. invoke only one like ('grunt development')
  grunt.registerTask( 'production', [ 'requirejs:production' ] );
  grunt.registerTask( 'development', [ 'requirejs:development' ] );

  grunt.registerTask( 'doc', 'Generates Documentation', function() {
    var indexHTML = '';
    var contentHTML = '';

    var localTypeIds = {
      BinPacker: 'binPacker',
      Bin: 'binPacker-bin',
      Bounds2: 'bounds2',
      Bounds3: 'bounds3',
      Complex: 'complex',
      ConvexHull2: 'convexHull2',
      Dimension2: 'dimension2',
      EigenvalueDecomposition: 'eigenvalueDecomposition',
      LinearFunction: 'linearFunction',
      LUDecomposition: 'luDecomposition',
      Matrix: 'matrix',
      Matrix3: 'matrix3',
      Matrix4: 'matrix4',
      MatrixOps3: 'matrixOps3',
      Permutation: 'permutation',
      Plane3: 'plane3',
      QRDecomposition: 'qrDecomposition',
      Quaternion: 'quaternion',
      Random: 'random',
      Range: 'range',
      Ray2: 'ray2',
      Ray3: 'ray3',
      Rectangle: 'rectangle', // TODO: How to not have a namespace conflict?
      SingularValueDecomposition: 'singularValueDecomposition',
      Sphere3: 'sphere3',
      Transform3: 'transform3',
      Transform4: 'transform4',
      Util: 'util',
      Vector2: 'vector2',
      Vector3: 'vector3',
      Vector4: 'vector4'
    };

    var externalTypeURLs = {
      Events: '../../axon/doc#events',
      Shape: '../../kite/doc#shape'
    };

    function docFile( file, baseName, typeNames ) {
      var codeFile = fs.readFileSync( file, 'utf8' );
      var program = esprima.parse( codeFile, {
        attachComment: true
      } );
      var doc = extractDocumentation( program );
      if ( baseName === 'ConvexHull2' ) { // for testing
        // console.log( JSON.stringify( doc, null, 2 ) );
      }
      var htmlDoc = documentationToHTML( doc, baseName, typeNames, localTypeIds, externalTypeURLs );

      indexHTML += htmlDoc.indexHTML;
      contentHTML += htmlDoc.contentHTML;
    }

    docFile( 'js/BinPacker.js', 'BinPacker', [ 'BinPacker', 'Bin' ] );
    docFile( 'js/Bounds2.js', 'Bounds2', [ 'Bounds2' ] );
    docFile( 'js/Bounds3.js', 'Bounds3', [ 'Bounds3' ] );
    docFile( 'js/Complex.js', 'Complex', [ 'Complex' ] );
    docFile( 'js/ConvexHull2.js', 'ConvexHull2', [ 'ConvexHull2' ] );
    docFile( 'js/Dimension2.js', 'Dimension2', [ 'Dimension2' ] );
    docFile( 'js/Transform3.js', 'Transform3', [ 'Transform3' ] );
    docFile( 'js/Transform4.js', 'Transform4', [ 'Transform4' ] );
    docFile( 'js/Util.js', 'Util', [ 'Util' ] );
    docFile( 'js/Vector2.js', 'Vector2', [ 'Vector2' ] );
    docFile( 'js/Vector3.js', 'Vector3', [ 'Vector3' ] );
    docFile( 'js/Vector4.js', 'Vector4', [ 'Vector4' ] );

    var template = fs.readFileSync( 'doc/template.html', 'utf8' );

    var html = template.replace( '$API_INDEX$', indexHTML ).replace( '$API_CONTENT$', contentHTML );

    html = beautify_html( html, { indent_size: 2 } );

    fs.writeFileSync( 'doc/index.html', html );
  } );

  // dependencies
  grunt.loadNpmTasks( 'grunt-requirejs' );
  grunt.loadNpmTasks( 'grunt-eslint' );
};
<commit_msg>Fixed property access in require statement, see https://github.com/phetsims/chipper/issues/461<commit_after>// Copyright 2002-2015, University of Colorado Boulder

var fs = require( 'fs' );
var esprima = require( 'esprima' );
var jsBeautify = require( 'js-beautify' ); // eslint-disable-line require-statement-match
var extractDocumentation = require( '../chipper/js/common/extractDocumentation' );
var documentationToHTML = require( '../chipper/js/common/documentationToHTML' );

// constants
var beautify_html = jsBeautify.html;

/*global module:false*/
module.exports = function( grunt ) {
  'use strict';

  // print this immediately, so it is clear what project grunt is building
  grunt.log.writeln( 'Dot' );

  // --disable-es-cache disables the cache, useful for developing rules
  var cache = !grunt.option( 'disable-eslint-cache' );

  // Project configuration.
  grunt.initConfig( {
    pkg: '<json:package.json>',

    requirejs: {
      // unminified
      development: {
        options: {
          almond: true,
          mainConfigFile: 'js/config.js',
          out: 'build/development/dot.js',
          name: 'config',
          optimize: 'none',
          wrap: {
            startFile: [ 'js/wrap-start.frag', '../assert/js/assert.js' ],
            endFile: [ 'js/wrap-end.frag' ]
          }
        }
      },

      production: {
        options: {
          almond: true,
          mainConfigFile: 'js/config.js',
          out: 'build/production/dot.min.js',
          name: 'config',
          optimize: 'uglify2',
          generateSourceMaps: true,
          preserveLicenseComments: false,
          wrap: {
            startFile: [ 'js/wrap-start.frag', '../assert/js/assert.js' ],
            endFile: [ 'js/wrap-end.frag' ]
          },
          uglify2: {
            compress: {
              global_defs: {
                assert: false,
                assertSlow: false,
                phetAllocation: false
              },
              dead_code: true
            }
          }
        }
      }
    },

    eslint: {
      options: {

        // Rules are specified in the .eslintrc file
        configFile: '../chipper/eslint/.eslintrc',

        // Caching only checks changed files or when the list of rules is changed.  Changing the implementation of a
        // custom rule does not invalidate the cache.  Caches are declared in .eslintcache files in the directory where
        // grunt was run from.
        cache: cache,

        // Our custom rules live here
        rulePaths: [ '../chipper/eslint/rules' ]
      },

      files: [
        'Gruntfile.js',
        '../phet-core/js/**/*.js',
        '../axon/js/**/*.js',
        '../assert/js/**/*.js',
        'js/**/*.js'
      ]
    }
  } );

  // default task ('grunt')
  grunt.registerTask( 'default', [ 'lint', 'development', 'production' ] );

  // linter on dot subset only ('grunt lint')
  grunt.registerTask( 'lint', [ 'eslint:files' ] );

  // compilation targets. invoke only one like ('grunt development')
  grunt.registerTask( 'production', [ 'requirejs:production' ] );
  grunt.registerTask( 'development', [ 'requirejs:development' ] );

  grunt.registerTask( 'doc', 'Generates Documentation', function() {
    var indexHTML = '';
    var contentHTML = '';

    var localTypeIds = {
      BinPacker: 'binPacker',
      Bin: 'binPacker-bin',
      Bounds2: 'bounds2',
      Bounds3: 'bounds3',
      Complex: 'complex',
      ConvexHull2: 'convexHull2',
      Dimension2: 'dimension2',
      EigenvalueDecomposition: 'eigenvalueDecomposition',
      LinearFunction: 'linearFunction',
      LUDecomposition: 'luDecomposition',
      Matrix: 'matrix',
      Matrix3: 'matrix3',
      Matrix4: 'matrix4',
      MatrixOps3: 'matrixOps3',
      Permutation: 'permutation',
      Plane3: 'plane3',
      QRDecomposition: 'qrDecomposition',
      Quaternion: 'quaternion',
      Random: 'random',
      Range: 'range',
      Ray2: 'ray2',
      Ray3: 'ray3',
      Rectangle: 'rectangle', // TODO: How to not have a namespace conflict?
      SingularValueDecomposition: 'singularValueDecomposition',
      Sphere3: 'sphere3',
      Transform3: 'transform3',
      Transform4: 'transform4',
      Util: 'util',
      Vector2: 'vector2',
      Vector3: 'vector3',
      Vector4: 'vector4'
    };

    var externalTypeURLs = {
      Events: '../../axon/doc#events',
      Shape: '../../kite/doc#shape'
    };

    function docFile( file, baseName, typeNames ) {
      var codeFile = fs.readFileSync( file, 'utf8' );
      var program = esprima.parse( codeFile, {
        attachComment: true
      } );
      var doc = extractDocumentation( program );
      if ( baseName === 'ConvexHull2' ) { // for testing
        // console.log( JSON.stringify( doc, null, 2 ) );
      }
      var htmlDoc = documentationToHTML( doc, baseName, typeNames, localTypeIds, externalTypeURLs );

      indexHTML += htmlDoc.indexHTML;
      contentHTML += htmlDoc.contentHTML;
    }

    docFile( 'js/BinPacker.js', 'BinPacker', [ 'BinPacker', 'Bin' ] );
    docFile( 'js/Bounds2.js', 'Bounds2', [ 'Bounds2' ] );
    docFile( 'js/Bounds3.js', 'Bounds3', [ 'Bounds3' ] );
    docFile( 'js/Complex.js', 'Complex', [ 'Complex' ] );
    docFile( 'js/ConvexHull2.js', 'ConvexHull2', [ 'ConvexHull2' ] );
    docFile( 'js/Dimension2.js', 'Dimension2', [ 'Dimension2' ] );
    docFile( 'js/Transform3.js', 'Transform3', [ 'Transform3' ] );
    docFile( 'js/Transform4.js', 'Transform4', [ 'Transform4' ] );
    docFile( 'js/Util.js', 'Util', [ 'Util' ] );
    docFile( 'js/Vector2.js', 'Vector2', [ 'Vector2' ] );
    docFile( 'js/Vector3.js', 'Vector3', [ 'Vector3' ] );
    docFile( 'js/Vector4.js', 'Vector4', [ 'Vector4' ] );

    var template = fs.readFileSync( 'doc/template.html', 'utf8' );

    var html = template.replace( '$API_INDEX$', indexHTML ).replace( '$API_CONTENT$', contentHTML );

    html = beautify_html( html, { indent_size: 2 } );

    fs.writeFileSync( 'doc/index.html', html );
  } );

  // dependencies
  grunt.loadNpmTasks( 'grunt-requirejs' );
  grunt.loadNpmTasks( 'grunt-eslint' );
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        less: {
            dist: {
                files: {
                    '_css/style-guide.css': 'less/style-guide.less'
                }
            },
            jekyll: {
                files: {
                    '_site/style-guide.css': 'less/style-guide.less'
                }
            }
        },

        cssmin: {
            css: {
                src: ['_css/style-guide.css'],
                dest: 'docs/style-guide.min.css'
            }
        },

        jekyll: {
            options: {
                src: 'docs',
                config: '_config.yml'
            },
            dev: {
                options: {
                    dest: '_site/style-guide'
                }
            },
            publish: {
                options: {
                    dest: '_site'
                }
            }
        },

        connect: {
            server: {
                options: {
                    livereload: true,
                    port: 8888,
                    base: './_site'
                }
            }
        },

        watch: {
            options: {
                livereload: true
            },
            less: {
                files: ['less/**/*.less', 'docs/docs.less'],
                tasks: ['less']
            },
            jekyll: {
                files: ['docs/**/*.md', 'docs/**/*.html'],
                tasks: ['jekyll'],
                options: {
                    spawn: false
                }
            }
        },

        buildcontrol: {
            options: {
                dir: '_site',
                commit: true,
                push: true,
                message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
            },
            pages: {
                options: {
                    remote: 'git@github.com:daptiv/style-guide.git',
                    branch: 'gh-pages'
                }
            }
        }
    });

    // Load dependencies
    grunt.loadNpmTasks('grunt-build-control');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-jekyll');

    // Generate and format the CSS
    grunt.registerTask('default', ['less', 'cssmin:css', 'jekyll:dev']);

    //running pattern library locally
    grunt.registerTask('serve',['default', 'connect', 'watch']);

    // Publish to GitHub
    grunt.registerTask('publish', ['less', 'cssmin:css', 'jekyll:publish', 'buildcontrol:pages']);
};
<commit_msg>fix issue running grunt serve<commit_after>module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        less: {
            dist: {
                files: {
                    '_css/style-guide.css': 'less/style-guide.less'
                }
            },
            jekyll: {
                files: {
                    '_site/style-guide.css': 'less/style-guide.less'
                }
            }
        },

        cssmin: {
            css: {
                src: ['_css/style-guide.css'],
                dest: 'docs/style-guide.min.css'
            }
        },

        jekyll: {
            options: {
                src: 'docs',
                config: '_config.yml'
            },
            dev: {
                options: {
                    dest: '_site/style-guide'
                }
            },
            publish: {
                options: {
                    dest: '_site'
                }
            }
        },

        connect: {
            server: {
                options: {
                    livereload: true,
                    port: 8888,
                    base: './_site'
                }
            }
        },

        watch: {
            options: {
                livereload: true
            },
            less: {
                files: ['less/**/*.less', 'docs/docs.less'],
                tasks: ['less']
            },
            jekyll: {
                files: ['docs/**/*.md', 'docs/**/*.html'],
                tasks: ['jekyll:dev'],
                options: {
                    spawn: false
                }
            }
        },

        buildcontrol: {
            options: {
                dir: '_site',
                commit: true,
                push: true,
                message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
            },
            pages: {
                options: {
                    remote: 'git@github.com:daptiv/style-guide.git',
                    branch: 'gh-pages'
                }
            }
        }
    });

    // Load dependencies
    grunt.loadNpmTasks('grunt-build-control');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-jekyll');

    // Generate and format the CSS
    grunt.registerTask('default', ['less', 'cssmin:css', 'jekyll:dev']);

    //running pattern library locally
    grunt.registerTask('serve',['default', 'connect', 'watch']);

    // Publish to GitHub
    grunt.registerTask('publish', ['less', 'cssmin:css', 'jekyll:publish', 'buildcontrol:pages']);
};
<|endoftext|>


<commit_before>/* ========================================================
 * bootstrap-hashtab.js v1.0.0
 * ========================================================
 * Based on bootstrap-tab.js.
 * Written by Tom Rees.
 *  * http://zephod.com
 *  * http://github.com/zephod
 * Custom plugin for handling data-toggle="hashtab".
 * Works exactly like data-toggle="tab" but I respond to
 * hashchange events.  Page state is memo-ized in the URL.
 * ======================================================== */

!function ($) {

  "use strict"; // jshint ;_;

 /* HASHTAB CLASS DEFINITION
  * ==================== */

  var HashTab = function (element) {
    this.element = $(element)
  }

  HashTab.prototype = {

    constructor: HashTab

  , show: function () {
      var $this = this.element
        , $ul = $this.closest('ul:not(.dropdown-menu)')
        , selector = $this.attr('data-target')
        , previous
        , $target
        , e

      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
      }

      if (selector.substr(0,1)=='#') {
        window.location.hash = 'tab-'+selector.substr(1);
      }

      if ( $this.parent('li').hasClass('active') ) return

      previous = $ul.find('.active:last a')[0]

      e = $.Event('show', {
        relatedTarget: previous
      })

      $this.trigger(e)

      if (e.isDefaultPrevented()) return

      $target = $(selector)

      this.activate($this.parent('li'), $ul)
      this.activate($target, $target.parent(), function () {
        $this.trigger({
          type: 'shown'
        , relatedTarget: previous
        })
      })
    }

  , activate: function ( element, container, callback) {
      var $active = container.find('> .active')
        , transition = callback
            && $.support.transition
            && $active.hasClass('fade')

      function next() {
        $active
          .removeClass('active')
          .find('> .dropdown-menu > .active')
          .removeClass('active')

        element.addClass('active')

        if (transition) {
          element[0].offsetWidth // reflow for transition
          element.addClass('in')
        } else {
          element.removeClass('fade')
        }

        if ( element.parent('.dropdown-menu') ) {
          element.closest('li.dropdown').addClass('active')
        }

        callback && callback()
      }

      transition ?
        $active.one($.support.transition.end, next) :
        next()

      $active.removeClass('in')
    }
  }

 /* HASHTAB PLUGIN DEFINITION
  * ===================== */

  var old = $.fn.hashtab

  $.fn.hashtab = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('hashtab')
      if (!data) $this.data('hashtab', (data = new HashTab(this)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.hashtab.Constructor = HashTab

 /* HASHTAB NO CONFLICT
  * =============== */

  $.fn.hashtab.noConflict = function () {
    $.fn.hashtab = old
    return this
  }

 /* TAB DATA-API
  * ============ */

  $(document).on('click.tab.data-api', '[data-toggle="hashtab"], [data-toggle="hashpill"]', function (e) {
    e.preventDefault();
    var disabled = $(this).attr('disabled') == 'disabled';
    if (!disabled) { $(this).hashtab('show') }
  })

  /* HANDLE HASH CHANGES
   * =================== */
  $(function() {
    // Triggered when links are clicked, or browser 'back' fires...
    $(window).hashchange(function() {
      var hash = window.location.hash;
      if (hash.substr(0,5)=='#tab-') {
        var href = '#'+hash.substr(5);
        var link = $('a[data-toggle="hashtab"][href="'+href+'"]');
        var disabled = link.attr('disabled') == 'disabled';
        if (!disabled) { link.hashtab('show'); }
      }
    });
    // Handle initial state
    $(window).trigger('hashchange');
  });

}(window.jQuery);

/*
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}$.browser.msie&&!d&&(function(){var q,r;j.start=function(){if(!q){r=$.fn[c].src;r=r&&r+a();q=$('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){r||l(a());n()}).attr("src",r||"javascript:0").insertAfter("body")[0].contentWindow;h.onpropertychange=function(){try{if(event.propertyName==="title"){q.document.title=h.title}}catch(s){}}}};j.stop=k;o=function(){return a(q.location.href)};l=function(v,s){var u=q.document,t=$.fn[c].domain;if(v!==s){u.title=h.title;u.open();t&&u.write('<script>document.domain="'+t+'"<\/script>');u.close();q.location.hash=v}}})();return j})()})(jQuery,this);
<commit_msg>Switch minified for raw hashchange code in src/js/<commit_after>/* ========================================================
 * bootstrap-hashtab.js v1.0.0
 * ========================================================
 * Based on bootstrap-tab.js.
 * Written by Tom Rees.
 *  * http://zephod.com
 *  * http://github.com/zephod
 * Custom plugin for handling data-toggle="hashtab".
 * Works exactly like data-toggle="tab" but I respond to
 * hashchange events.  Page state is memo-ized in the URL.
 * ======================================================== */

!function ($) {

  "use strict"; // jshint ;_;

 /* HASHTAB CLASS DEFINITION
  * ==================== */

  var HashTab = function (element) {
    this.element = $(element)
  }

  HashTab.prototype = {

    constructor: HashTab

  , show: function () {
      var $this = this.element
        , $ul = $this.closest('ul:not(.dropdown-menu)')
        , selector = $this.attr('data-target')
        , previous
        , $target
        , e

      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
      }

      if (selector.substr(0,1)=='#') {
        window.location.hash = 'tab-'+selector.substr(1);
      }

      if ( $this.parent('li').hasClass('active') ) return

      previous = $ul.find('.active:last a')[0]

      e = $.Event('show', {
        relatedTarget: previous
      })

      $this.trigger(e)

      if (e.isDefaultPrevented()) return

      $target = $(selector)

      this.activate($this.parent('li'), $ul)
      this.activate($target, $target.parent(), function () {
        $this.trigger({
          type: 'shown'
        , relatedTarget: previous
        })
      })
    }

  , activate: function ( element, container, callback) {
      var $active = container.find('> .active')
        , transition = callback
            && $.support.transition
            && $active.hasClass('fade')

      function next() {
        $active
          .removeClass('active')
          .find('> .dropdown-menu > .active')
          .removeClass('active')

        element.addClass('active')

        if (transition) {
          element[0].offsetWidth // reflow for transition
          element.addClass('in')
        } else {
          element.removeClass('fade')
        }

        if ( element.parent('.dropdown-menu') ) {
          element.closest('li.dropdown').addClass('active')
        }

        callback && callback()
      }

      transition ?
        $active.one($.support.transition.end, next) :
        next()

      $active.removeClass('in')
    }
  }

 /* HASHTAB PLUGIN DEFINITION
  * ===================== */

  var old = $.fn.hashtab

  $.fn.hashtab = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('hashtab')
      if (!data) $this.data('hashtab', (data = new HashTab(this)))
      if (typeof option == 'string') data[option]()
    })
  }

  $.fn.hashtab.Constructor = HashTab

 /* HASHTAB NO CONFLICT
  * =============== */

  $.fn.hashtab.noConflict = function () {
    $.fn.hashtab = old
    return this
  }

 /* TAB DATA-API
  * ============ */

  $(document).on('click.tab.data-api', '[data-toggle="hashtab"], [data-toggle="hashpill"]', function (e) {
    e.preventDefault();
    var disabled = $(this).attr('disabled') == 'disabled';
    if (!disabled) { $(this).hashtab('show') }
  })

  /* HANDLE HASH CHANGES
   * =================== */
  $(function() {
    // Triggered when links are clicked, or browser 'back' fires...
    $(window).hashchange(function() {
      var hash = window.location.hash;
      if (hash.substr(0,5)=='#tab-') {
        var href = '#'+hash.substr(5);
        var link = $('a[data-toggle="hashtab"][href="'+href+'"]');
        var disabled = link.attr('disabled') == 'disabled';
        if (!disabled) { link.hashtab('show'); }
      }
    });
    // Handle initial state
    $(window).trigger('hashchange');
  });

}(window.jQuery);

/*!
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 *
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub       - http://github.com/cowboy/jquery-hashchange/
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
//         "removable" for mobile-only development. Added IE6/7 document.title
//         support. Attempted to make Iframe as hidden as possible by using
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added
//         support for the "shortcut" format $(window).hashchange( fn ) and
//         $(window).hashchange() like jQuery provides for built-in events.
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
//         file to address access denied issues when setting document.domain in
//         IE6/7.
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
//         from a page on another domain would cause an error in Safari 4. Also,
//         IE6/7 Iframe is now inserted after the body (this actually works),
//         which prevents the page from scrolling when the event is first bound.
//         Event can also now be bound before DOM ready, but it won't be usable
//         before then in IE6/7.
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
//         where browser version is incorrectly reported as 8.0, despite
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
//         window.onhashchange functionality into a separate plugin for users
//         who want just the basic event & back button support, without all the
//         extra awesomeness that BBQ provides. This plugin will be included as
//         part of jQuery BBQ, but also be available separately.

(function($,window,undefined){
  '$:nomunge'; // Used by YUI compressor.

  // Reused string.
  var str_hashchange = 'hashchange',

    // Method / object references.
    doc = document,
    fake_onhashchange,
    special = $.event.special,

    // Does the browser support window.onhashchange? Note that IE8 running in
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
    // though the event isn't supported, so also test document.documentMode.
    doc_mode = doc.documentMode,
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );

  // Get location.hash (or what you'd expect location.hash to be) sans any
  // leading #. Thanks for making this necessary, Firefox!
  function get_fragment( url ) {
    url = url || location.href;
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
  };

  // Method: jQuery.fn.hashchange
  //
  // Bind a handler to the window.onhashchange event or trigger all bound
  // window.onhashchange event handlers. This behavior is consistent with
  // jQuery's built-in event handlers.
  //
  // Usage:
  //
  // > jQuery(window).hashchange( [ handler ] );
  //
  // Arguments:
  //
  //  handler - (Function) Optional handler to be bound to the hashchange
  //    event. This is a "shortcut" for the more verbose form:
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
  //    all bound window.onhashchange event handlers will be triggered. This
  //    is a shortcut for the more verbose
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
  //    the <hashchange event> section.
  //
  // Returns:
  //
  //  (jQuery) The initial jQuery collection of elements.

  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
  $.fn[ str_hashchange ] = function( fn ) {
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
  };

  // Property: jQuery.fn.hashchange.delay
  //
  // The numeric interval (in milliseconds) at which the <hashchange event>
  // polling loop executes. Defaults to 50.

  // Property: jQuery.fn.hashchange.domain
  //
  // If you're setting document.domain in your JavaScript, and you want hash
  // history to work in IE6/7, not only must this property be set, but you must
  // also set document.domain BEFORE jQuery is loaded into the page. This
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
  // in "IE7 compatibility" mode).
  //
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
  // path of the included "document-domain.html" file, which can be renamed or
  // modified if necessary (note that the document.domain specified must be the
  // same in both your main JavaScript as well as in this file).
  //
  // Usage:
  //
  // jQuery.fn.hashchange.domain = document.domain;

  // Property: jQuery.fn.hashchange.src
  //
  // If, for some reason, you need to specify an Iframe src file (for example,
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
  // do so using this property. Note that when using this property, history
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
  // compatibility" mode).
  //
  // Usage:
  //
  // jQuery.fn.hashchange.src = 'path/to/file.html';

  $.fn[ str_hashchange ].delay = 50;
  /*
  $.fn[ str_hashchange ].domain = null;
  $.fn[ str_hashchange ].src = null;
  */

  // Event: hashchange event
  //
  // Fired when location.hash changes. In browsers that support it, the native
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
  // compatibility" mode), a hidden Iframe is created to allow the back button
  // and hash-based history to work.
  //
  // Usage as described in <jQuery.fn.hashchange>:
  //
  // > // Bind an event handler.
  // > jQuery(window).hashchange( function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // >
  // > // Manually trigger the event handler.
  // > jQuery(window).hashchange();
  //
  // A more verbose usage that allows for event namespacing:
  //
  // > // Bind an event handler.
  // > jQuery(window).bind( 'hashchange', function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // >
  // > // Manually trigger the event handler.
  // > jQuery(window).trigger( 'hashchange' );
  //
  // Additional Notes:
  //
  // * The polling loop and Iframe are not created until at least one handler
  //   is actually bound to the 'hashchange' event.
  // * If you need the bound handler(s) to execute immediately, in cases where
  //   a location.hash exists on page load, via bookmark or page refresh for
  //   example, use jQuery(window).hashchange() or the more verbose
  //   jQuery(window).trigger( 'hashchange' ).
  // * The event can be bound before DOM ready, but since it won't be usable
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
  //   to bind it inside a DOM ready handler.

  // Override existing $.event.special.hashchange methods (allowing this plugin
  // to be defined after jQuery BBQ in BBQ's source code).
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {

    // Called only when the first 'hashchange' event is bound to window.
    setup: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }

      // Otherwise, we need to create our own. And we don't want to call this
      // until the user binds to the event, just in case they never do, since it
      // will create a polling loop and possibly even a hidden Iframe.
      $( fake_onhashchange.start );
    },

    // Called only when the last 'hashchange' event is unbound from window.
    teardown: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }

      // Otherwise, we need to stop ours (if possible).
      $( fake_onhashchange.stop );
    }

  });

  // fake_onhashchange does all the work of triggering the window.onhashchange
  // event for browsers that don't natively support it, including creating a
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
  // Iframe to enable back and forward.
  fake_onhashchange = (function(){
    var self = {},
      timeout_id,

      // Remember the initial hash so it doesn't get triggered immediately.
      last_hash = get_fragment(),

      fn_retval = function(val){ return val; },
      history_set = fn_retval,
      history_get = fn_retval;

    // Start the polling loop.
    self.start = function() {
      timeout_id || poll();
    };

    // Stop the polling loop.
    self.stop = function() {
      timeout_id && clearTimeout( timeout_id );
      timeout_id = undefined;
    };

    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
    // if location.hash has changed, and triggers the 'hashchange' event on
    // window when necessary.
    function poll() {
      var hash = get_fragment(),
        history_hash = history_get( last_hash );

      if ( hash !== last_hash ) {
        history_set( last_hash = hash, history_hash );

        $(window).trigger( str_hashchange );

      } else if ( history_hash !== last_hash ) {
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
      }

      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
    };

    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    $.browser.msie && !supports_onhashchange && (function(){
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
      // when running in "IE7 compatibility" mode.

      var iframe,
        iframe_src;

      // When the event is bound and polling starts in IE 6/7, create a hidden
      // Iframe for history handling.
      self.start = function(){
        if ( !iframe ) {
          iframe_src = $.fn[ str_hashchange ].src;
          iframe_src = iframe_src && iframe_src + get_fragment();

          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()

            // When Iframe has completely loaded, initialize the history and
            // start polling.
            .one( 'load', function(){
              iframe_src || history_set( get_fragment() );
              poll();
            })

            // Load Iframe src if specified, otherwise nothing.
            .attr( 'src', iframe_src || 'javascript:0' )

            // Append Iframe after the end of the body to prevent unnecessary
            // initial page scrolling (yes, this works).
            .insertAfter( 'body' )[0].contentWindow;

          // Whenever `document.title` changes, update the Iframe's title to
          // prettify the back/next history menu entries. Since IE sometimes
          // errors with "Unspecified error" the very first time this is set
          // (yes, very useful) wrap this with a try/catch block.
          doc.onpropertychange = function(){
            try {
              if ( event.propertyName === 'title' ) {
                iframe.document.title = doc.title;
              }
            } catch(e) {}
          };

        }
      };

      // Override the "stop" method since an IE6/7 Iframe was created. Even
      // if there are no longer any bound event handlers, the polling loop
      // is still necessary for back/next to work at all!
      self.stop = fn_retval;

      // Get history by looking at the hidden Iframe's location.hash.
      history_get = function() {
        return get_fragment( iframe.location.href );
      };

      // Set a new history item by opening and then closing the Iframe
      // document, *then* setting its location.hash. If document.domain has
      // been set, update that as well.
      history_set = function( hash, history_hash ) {
        var iframe_doc = iframe.document,
          domain = $.fn[ str_hashchange ].domain;

        if ( hash !== history_hash ) {
          // Update Iframe with any initial `document.title` that might be set.
          iframe_doc.title = doc.title;

          // Opening the Iframe's document after it has been closed is what
          // actually adds a history entry.
          iframe_doc.open();

          // Set document.domain for the Iframe document as well, if necessary.
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );

          iframe_doc.close();

          // Update the Iframe's hash, for great justice.
          iframe.location.hash = hash;
        }
      };

    })();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    return self;
  })();

})(jQuery,this);
<|endoftext|>


<commit_before>define(["firebug/lib/lib", "firecompass/firecompass", "firecompass/cssPanelExtension"],
function(FBL, FireCompass, CssPanelExtension) {
	var SourceLink, origFetSourceLinkTitleFn;

	// TODO Didn't find a way to import SourceLink through AMD.
	//
	// Importing "firebug/js/sourceLink" returned an object but changing
	// getTooltip() on that object didn't work:
	//	- SourceLink.[...]
	//	- SourceLink.prototype.[...]
	//	- Firebug.getRep(SourceLink).[...]
	//	- Firebug.getRep(new SourceLink()).[...]

	// Get SourceLink reference to override getTooltip()
	// SourceLink represents the link to a source in the CSS panel
	SourceLink = Firebug.getRep(new FBL.SourceLink());

	// link: SourceLink reference
	// short: whether the label is rendered short or not
	function formatCompassInfoString(link, short){
		var line = link.line,
			href = link.href,
			compassInfo,
			cache = FireCompass.CACHE,
			str, filename;

		if (!cache[href] || !cache[href].compassInfoMap[line]) {
			return "";
		}

		// Get previously cached compass info by href and line
		compassInfo = cache[href].compassInfoMap[line];

		if (short) {
			// get filename part and shorten string (if too long)
			filename = compassInfo.path;
			filename = filename.substring(filename.lastIndexOf("/") + 1);
			filename = decodeURIComponent(filename);
			filename = FBL.cropString(filename, 17);

			// If it's a Compass internal file return with brackets around the name
			//	Compass: [reset.scss]
			//	Normal: _wizard.scss
			filename = compassInfo.isCompassInternal ? "["+ filename +"] " : filename;

			// TODO Maybe make the link italic if Compass internal?

			str = FBL.$STRF("Line", [filename, compassInfo.line]);
		} else {
			// If it's a Compass internal file, prefix with [Compass]
			str = (compassInfo.isCompassInternal ? "[Compass] " : "");
			str += FBL.$STRF("Line", [compassInfo.path, compassInfo.line]);
		}

		return str;
	}

	// Remember original getSourceLinkTitle() for reuse
	origGetSourceLinkTitleFn = SourceLink.getSourceLinkTitle;

	// Override to change the source link in the CSS panel (right to the rules)
	SourceLink.getSourceLinkTitle = function(link) {
		var str;

		if (link == null) {
			return "";
		}

		// Link to CSS file (default), reuse original method
		if (CssPanelExtension.isShowCss()) {
			return origGetSourceLinkTitleFn(link);
		}

		// Show SCSS path in source link as !isShowCss(), therefor chache data
		FireCompass.cacheCompassInfo(link);

		str = formatCompassInfoString(link, true);

		return str !== "" ? str : origGetSourceLinkTitleFn(link);
	};

	// Override to manipulate the tooltip string with our content/format
	SourceLink.getTooltip = function(link) {
		var line = link.line,
			href = link.href,
			str;

		// If showing the CSS path (default), do caching upon tooltip-show
		if (CssPanelExtension.isShowCss()) {
			// cache compass info when building the title
			FireCompass.cacheCompassInfo(link);
		}

		str = formatCompassInfoString(link, false);

		return decodeURI(FBL.$STRF("Line", [link.href, link.line]) + (str !== "" ? "\n" + str : ""));
	};

	return {
		initialize: function(){
			Firebug.registerModule(FireCompass);
			Firebug.registerModule(CssPanelExtension);
			Firebug.registerStringBundle("chrome://firecompass/locale/firecompass.properties");
		},

		shutdown: function(){
			Firebug.unregisterModule(FireCompass);
			Firebug.unregisterModule(CssPanelExtension);
			Firebug.unregisterStringBundle("chrome://firecompass/locale/firecompass.properties");
		}
	};

});
<commit_msg>Fixed typo in variable declaration<commit_after>define(["firebug/lib/lib", "firecompass/firecompass", "firecompass/cssPanelExtension"],
function(FBL, FireCompass, CssPanelExtension) {
	var SourceLink, origGetSourceLinkTitleFn;

	// TODO Didn't find a way to import SourceLink through AMD.
	//
	// Importing "firebug/js/sourceLink" returned an object but changing
	// getTooltip() on that object didn't work:
	//	- SourceLink.[...]
	//	- SourceLink.prototype.[...]
	//	- Firebug.getRep(SourceLink).[...]
	//	- Firebug.getRep(new SourceLink()).[...]

	// Get SourceLink reference to override getTooltip()
	// SourceLink represents the link to a source in the CSS panel
	SourceLink = Firebug.getRep(new FBL.SourceLink());

	// link: SourceLink reference
	// short: whether the label is rendered short or not
	function formatCompassInfoString(link, short){
		var line = link.line,
			href = link.href,
			compassInfo,
			cache = FireCompass.CACHE,
			str, filename;

		if (!cache[href] || !cache[href].compassInfoMap[line]) {
			return "";
		}

		// Get previously cached compass info by href and line
		compassInfo = cache[href].compassInfoMap[line];

		if (short) {
			// get filename part and shorten string (if too long)
			filename = compassInfo.path;
			filename = filename.substring(filename.lastIndexOf("/") + 1);
			filename = decodeURIComponent(filename);
			filename = FBL.cropString(filename, 17);

			// If it's a Compass internal file return with brackets around the name
			//	Compass: [reset.scss]
			//	Normal: _wizard.scss
			filename = compassInfo.isCompassInternal ? "["+ filename +"] " : filename;

			// TODO Maybe make the link italic if Compass internal?

			str = FBL.$STRF("Line", [filename, compassInfo.line]);
		} else {
			// If it's a Compass internal file, prefix with [Compass]
			str = (compassInfo.isCompassInternal ? "[Compass] " : "");
			str += FBL.$STRF("Line", [compassInfo.path, compassInfo.line]);
		}

		return str;
	}

	// Remember original getSourceLinkTitle() for reuse
	origGetSourceLinkTitleFn = SourceLink.getSourceLinkTitle;

	// Override to change the source link in the CSS panel (right to the rules)
	SourceLink.getSourceLinkTitle = function(link) {
		var str;

		if (link == null) {
			return "";
		}

		// Link to CSS file (default), reuse original method
		if (CssPanelExtension.isShowCss()) {
			return origGetSourceLinkTitleFn(link);
		}

		// Show SCSS path in source link as !isShowCss(), therefor chache data
		FireCompass.cacheCompassInfo(link);

		str = formatCompassInfoString(link, true);

		return str !== "" ? str : origGetSourceLinkTitleFn(link);
	};

	// Override to manipulate the tooltip string with our content/format
	SourceLink.getTooltip = function(link) {
		var line = link.line,
			href = link.href,
			str;

		// If showing the CSS path (default), do caching upon tooltip-show
		if (CssPanelExtension.isShowCss()) {
			// cache compass info when building the title
			FireCompass.cacheCompassInfo(link);
		}

		str = formatCompassInfoString(link, false);

		return decodeURI(FBL.$STRF("Line", [link.href, link.line]) + (str !== "" ? "\n" + str : ""));
	};

	return {
		initialize: function(){
			Firebug.registerModule(FireCompass);
			Firebug.registerModule(CssPanelExtension);
			Firebug.registerStringBundle("chrome://firecompass/locale/firecompass.properties");
		},

		shutdown: function(){
			Firebug.unregisterModule(FireCompass);
			Firebug.unregisterModule(CssPanelExtension);
			Firebug.unregisterStringBundle("chrome://firecompass/locale/firecompass.properties");
		}
	};

});
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {
	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		qunit: {
			all: ['tests/*.html']
		},
		jshint: {
			all: ['Gruntfile.js',
				'src/**/cl.accordion.js',
				'src/**/cl.autocomplete.js',
				'src/**/cl.carousel.js',
				//'src/**/cl.debug.js',
				'src/**/cl.gallery.js',
				'src/**/cl.lightbox.js',
				'src/**/cl.mobilemenu.js',
				'src/**/cl.parallax.js',
				'src/**/cl.scroll.js',
				'src/**/cl.touch.js',
				'src/**/cl.uniform.js',
				'tests/cl.*.js'],
			options: {
				// http://www.jshint.com/docs/options/
				// Enforcing options
				bitwise: true,
				camelcase: true,
				curly: false,
				eqeqeq: true,
				freeze: true,
				immed: true,
				indent: true,
				latedef: true,
				newcap: true,
				noarg: true,
				noempty: true,
				quotmark: 'single',
				undef: false,
				unused: true,
				// Relaxing options
				boss: true,
				expr: true,
				jquery: true,
				// Global variables
				globals: {
					jQuery: true,
					Cl: true
				}
			}
		},
		uglify: {
			all: {
				files: {
					'src/cl.accordion/cl.accordion.min.js': ['src/cl.accordion/cl.accordion.js'],
					'src/cl.autocomplete/cl.autocomplete.min.js': ['src/cl.autocomplete/cl.autocomplete.js'],
					'src/cl.carousel/cl.carousel.min.js': ['src/cl.carousel/cl.carousel.js'],
					'src/cl.debug/cl.debug.min.js': ['src/cl.debug/cl.debug.js'],
					'src/cl.gallery/cl.gallery.min.js': ['src/cl.gallery/cl.gallery.js'],
					'src/cl.lightbox/cl.lightbox.min.js': ['src/cl.lightbox/cl.lightbox.js'],
					'src/cl.mobilemenu/cl.mobilemenu.min.js': ['src/cl.mobilemenu/cl.mobilemenu.js'],
					'src/cl.parallax/cl.parallax.min.js': ['src/cl.parallax/cl.parallax.js'],
					'src/cl.scroll/cl.scroll.min.js': ['src/cl.scroll/cl.scroll.js'],
					'src/cl.touch/cl.touch.min.js': ['src/cl.touch/cl.touch.js'],
					'src/cl.uniform/cl.uniform.min.js': ['src/cl.uniform/cl.uniform.js']
				},
				options: {
					report: 'min'
				}
			}
		}
	});

	// Travis CI task.
	grunt.loadNpmTasks('grunt-contrib-qunit');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-uglify');

	// Default task.
	grunt.registerTask('default', ['uglify', 'qunit', 'jshint']);
};<commit_msg>add comments<commit_after>/*global module:false*/
module.exports = function(grunt) {
	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		qunit: {
			all: ['tests/*.html']
		},
		jshint: {
			all: ['Gruntfile.js',
				'src/**/cl.accordion.js',
				'src/**/cl.autocomplete.js',
				'src/**/cl.carousel.js',
				//'src/**/cl.debug.js',
				'src/**/cl.gallery.js',
				'src/**/cl.lightbox.js',
				'src/**/cl.mobilemenu.js',
				'src/**/cl.parallax.js',
				'src/**/cl.scroll.js',
				'src/**/cl.touch.js',
				'src/**/cl.uniform.js',
				'tests/cl.*.js'],
			options: {
				// http://www.jshint.com/docs/options/
				// Enforcing options
				bitwise: true,
				camelcase: true,
				curly: false,
				eqeqeq: true,
				freeze: true,
				immed: true,
				indent: true,
				latedef: true,
				newcap: true,
				noarg: true,
				noempty: true,
				quotmark: 'single',
				undef: false,
				unused: true,
				// Relaxing options
				boss: true,
				expr: true,
				jquery: true,
				// Global variables
				globals: {
					jQuery: true,
					Cl: true
				}
			}
		},
		uglify: {
			all: {
				files: {
					'src/cl.accordion/cl.accordion.min.js': ['src/cl.accordion/cl.accordion.js'],
					'src/cl.autocomplete/cl.autocomplete.min.js': ['src/cl.autocomplete/cl.autocomplete.js'],
					'src/cl.carousel/cl.carousel.min.js': ['src/cl.carousel/cl.carousel.js'],
					'src/cl.debug/cl.debug.min.js': ['src/cl.debug/cl.debug.js'],
					'src/cl.gallery/cl.gallery.min.js': ['src/cl.gallery/cl.gallery.js'],
					'src/cl.lightbox/cl.lightbox.min.js': ['src/cl.lightbox/cl.lightbox.js'],
					'src/cl.mobilemenu/cl.mobilemenu.min.js': ['src/cl.mobilemenu/cl.mobilemenu.js'],
					'src/cl.parallax/cl.parallax.min.js': ['src/cl.parallax/cl.parallax.js'],
					'src/cl.scroll/cl.scroll.min.js': ['src/cl.scroll/cl.scroll.js'],
					'src/cl.touch/cl.touch.min.js': ['src/cl.touch/cl.touch.js'],
					'src/cl.uniform/cl.uniform.min.js': ['src/cl.uniform/cl.uniform.js']
				},
				options: {
					report: 'min'
				}
			}
		}
	});

	// Travis CI task.
	grunt.loadNpmTasks('grunt-contrib-qunit');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-uglify');

	// Default task.
	grunt.registerTask('default', ['uglify', 'qunit', 'jshint']);
	// use grunt test for testing and grunt build for building and add grunt watch
};<|endoftext|>


<commit_before>module.exports = function(grunt) {
  'use strict';

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-shell');

  var mochaShelljsOpt = {stdout: true, stderr: true};

  grunt.initConfig({
    jshint: {
      src: {
        files: {
          src: ['index.js']
        }
      },
      grunt: {
        files: {
          src: ['Gruntfile.js']
        }
      },
      tests: {
        options: {
          expr: true
        },
        files: {
          src: ['test.js']
        }
      },
      json: {
        files: {
          src: ['*.json']
        }
      }
    },
    uglify: {
      dist: {
        options: {
          compress: false,
          mangle: false,
          beautify: true
        },
        files: {
          'dist/bdd-flow.js': 'dist/bdd-flow.js'
        }
      }
    },
    shell: {
      options: {
        failOnError: true,
        stdout: true,
        stderr: true
      },
      build: {
        command: 'component install --dev && component build --standalone bddflow --name bdd-flow --out dist --dev'
      },
      dist: {
        command: 'component build --standalone bddflow --name bdd-flow --out dist'
      },
      shrinkwrap: {
        command: 'npm shrinkwrap'
      },
      test_lib: {
        options: mochaShelljsOpt,
        command: 'mocha --colors --async-only --reporter spec test.js'
      }
    }
  });

  grunt.registerTask('default', ['jshint', 'shell:shrinkwrap']);
  grunt.registerTask('build', ['shell:build']);
  grunt.registerTask('dist', ['default', 'shell:dist', 'uglify:dist', 'shell:shrinkwrap']);
  grunt.registerTask('test', ['build', 'shell:test_lib']);
};
<commit_msg>chore(grunt): Stop shrinkwrapping after lint<commit_after>module.exports = function(grunt) {
  'use strict';

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-shell');

  var mochaShelljsOpt = {stdout: true, stderr: true};

  grunt.initConfig({
    jshint: {
      src: {
        files: {
          src: ['index.js']
        }
      },
      grunt: {
        files: {
          src: ['Gruntfile.js']
        }
      },
      tests: {
        options: {
          expr: true
        },
        files: {
          src: ['test.js']
        }
      },
      json: {
        files: {
          src: ['*.json']
        }
      }
    },
    uglify: {
      dist: {
        options: {
          compress: false,
          mangle: false,
          beautify: true
        },
        files: {
          'dist/bdd-flow.js': 'dist/bdd-flow.js'
        }
      }
    },
    shell: {
      options: {
        failOnError: true,
        stdout: true,
        stderr: true
      },
      build: {
        command: 'component install --dev && component build --standalone bddflow --name bdd-flow --out dist --dev'
      },
      dist: {
        command: 'component build --standalone bddflow --name bdd-flow --out dist'
      },
      shrinkwrap: {
        command: 'npm shrinkwrap'
      },
      test_lib: {
        options: mochaShelljsOpt,
        command: 'mocha --colors --async-only --reporter spec test.js'
      }
    }
  });

  grunt.registerTask('default', ['jshint']);
  grunt.registerTask('build', ['shell:build']);
  grunt.registerTask('dist', ['default', 'shell:dist', 'uglify:dist', 'shell:shrinkwrap']);
  grunt.registerTask('test', ['build', 'shell:test_lib']);
};
<|endoftext|>


<commit_before>import React from 'react';

/**
 * Status bar component creates a segmented bar based on the data input
 * @example
 * <StatusBar
 *   data={[
 *    {
 *      value: 20,
 *      className: 'status'
 *    }, {
 *      value: 30,
 *      className: 'failed'
 *    }
 *  ]} />
 */
class StatusBar extends React.Component {
  constructor() {
    super(...arguments);
  }

  static get defaultProps() {
    return {
      className: 'status-bar',
      height: 10
    };
  }

  getBarsFunction(total) {
    let offset = 0;
    return function (status, index) {
      let {value, className} = status;
      if (!className) {
        className = `element-${index}`;
      }
      let width = value / total * 100;
      let bar = (
        <rect
          x={`${offset}%`}
          y="0"
          key={index}
          height="100%"
          width={`${width}%`}
          className={className} />
      );
      offset += width;
      return bar;
    };
  }

  render() {
    let {data, className} = this.props;
    if (!data) {
      return null;
    }
    let total = data.reduce(function (sum, item) {
      return sum + item.value;
    }, 0);

    return (
      <svg
        className={className}
        preserveAspectRatio="none">
        {data.map(this.getBarsFunction(total))}
      </svg>
    );
  }
}

StatusBar.propTypes = {
  className: React.PropTypes.string,
  data: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      className: React.PropTypes.string,
      value: React.PropTypes.number.isRequired
    })
  ).isRequired
};

module.exports = StatusBar;
<commit_msg>Refactor getBars to return bars and not a function<commit_after>import React from 'react';

/**
 * Status bar component creates a segmented bar based on the data input
 * @example
 * <StatusBar
 *   data={[
 *    {
 *      value: 20,
 *      className: 'status'
 *    }, {
 *      value: 30,
 *      className: 'failed'
 *    }
 *  ]} />
 */
class StatusBar extends React.Component {
  constructor() {
    super(...arguments);
  }

  static get defaultProps() {
    return {
      className: 'status-bar',
      height: 10
    };
  }

  getBars(data) {
    let total = data.reduce(function (sum, item) {
      return sum + item.value;
    }, 0);
    let offset = 0;

    return data.map(function (status, index) {
      let {value, className} = status;
      if (!className) {
        className = `element-${index}`;
      }
      let width = value / total * 100;
      let bar = (
        <rect
          x={`${offset}%`}
          y="0"
          key={index}
          height="100%"
          width={`${width}%`}
          className={className} />
      );
      offset += width;
      return bar;
    });
  }

  render() {
    let {data, className} = this.props;
    if (!data) {
      return null;
    }

    return (
      <svg
        className={className}
        preserveAspectRatio="none">
        {this.getBars(data)}
      </svg>
    );
  }
}

StatusBar.propTypes = {
  className: React.PropTypes.string,
  data: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      className: React.PropTypes.string,
      value: React.PropTypes.number.isRequired
    })
  ).isRequired
};

module.exports = StatusBar;
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  grunt.initConfig({
    info: grunt.file.readJSON('bower.json'),
    meta: {
      banner: '/*!\n'+
              ' * <%= info.name %> - <%= info.description %>\n'+
              ' * v<%= info.version %>\n'+
              ' * <%= info.homepage %>\n'+
              ' * copyright <%= info.copyright %> <%= grunt.template.today("yyyy") %>\n'+
              ' * <%= info.license %> License\n'+
              '*/\n'
    },

    jshint: {
      main: [
        'Gruntfile.js',
        'bower.json',
        'lib/**/*.js',
        'test/*.js'
      ]
    },
    bower: {
      main: {
        dest: 'dist/_bower.js',
        exclude: [
          'assert',
          'jquery',
          'moment',
          'timezones',
          'jquery-simulate'
        ]
      }
    },
    concat: {
      options: {
        banner: '<%= meta.banner %>'
      },

      dist: {
        src: [
          'lib/dates.js',
          'lib/time.js',
          'lib/weekly.js'
        ],
        dest: 'dist/weekly.js'
      },

      full: {
        src: [
          'dist/_bower.js',
          'lib/time.js',
          'lib/dates.js',
          'lib/weekly.js'
        ],
        dest: 'dist/weekly.full.js'
      }
    },

    template2js: {
      dist: {
        src: 'lib/template.html',
        dest: 'dist/weekly.js'
      },

      full: {
        src: 'lib/template.html',
        dest: 'dist/weekly.full.js'
      }
    },

    uglify: {
      options: {
        banner: '<%= meta.banner %>'
      },

      dist: {
        src: 'dist/weekly.js',
        dest: 'dist/weekly.min.js'
      },

      full: {
        src: 'dist/weekly.full.js',
        dest: 'dist/weekly.full.min.js'
      }
    },

    clean: {
      bower: [
        'dist/_bower.js'
      ],
      dist: [
        'dist'
      ]
    },

    less: {
      'default': {
        src: 'less/theme1.less',
        dest: 'dist/weekly.css'
      }
    },

    watch: {
      scripts: {
        files: [
          '<%= jshint.main %>',
          'lib/template.html'
        ],
        tasks: 'scripts',
        options: {
          livereload: true
        }
      },

      styles: {
        files: [
          'less/*.less'
        ],
        tasks: 'styles',
        options: {
          livereload: true
        }
      },

      example: {
        files: [
          'example/*'
        ],
        options: {
          livereload: true
        }
      },

      ci: {
        files: [
          'Gruntfile.js',
          'test/index.html',
          'test/time.html',
          'test/dates.html'
        ],
        tasks: 'default'
      }
    },

    mocha: {
      options: {
        run: true,
        growl: true,
        reporter: 'Spec'
      },
      weekly: {
        src: 'test/index.html',
      },
      time: {
        src: 'test/time.html',
      },
      dates: {
        src: 'test/dates.html',
      }
    },

    plato: {
      main: {
        files: {
          'reports': ['lib/*.js']
        }
      }
    },

    connect: {
      server:{
        options: {
          hostname: '*'
        }
      },

      plato: {
        port: 8000,
        base: 'reports',
        options: {
          keepalive: true
        }
      }
    },
    bytesize: {
      scripts: {
        src: [
          'dist/*'
        ]
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-concat-bower');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-bytesize');
  grunt.loadNpmTasks('grunt-mocha');
  grunt.loadNpmTasks('grunt-plato');
  grunt.loadTasks('tasks');
  grunt.registerTask('scripts', ['jshint', 'bower', 'concat', 'template2js', 'uglify', 'clean:bower', 'mocha', 'bytesize']);
  grunt.registerTask('styles', ['less']);
  grunt.registerTask('default', ['scripts', 'styles']);
  grunt.registerTask('dev', ['connect:server', 'watch']);
  grunt.registerTask('reports', ['plato', 'connect:plato']);
};
<commit_msg>moved livereload option to the top<commit_after>module.exports = function(grunt) {
  grunt.initConfig({
    info: grunt.file.readJSON('bower.json'),
    meta: {
      banner: '/*!\n'+
              ' * <%= info.name %> - <%= info.description %>\n'+
              ' * v<%= info.version %>\n'+
              ' * <%= info.homepage %>\n'+
              ' * copyright <%= info.copyright %> <%= grunt.template.today("yyyy") %>\n'+
              ' * <%= info.license %> License\n'+
              '*/\n'
    },

    jshint: {
      main: [
        'Gruntfile.js',
        'bower.json',
        'lib/**/*.js',
        'test/*.js'
      ]
    },
    bower: {
      main: {
        dest: 'dist/_bower.js',
        exclude: [
          'assert',
          'jquery',
          'moment',
          'timezones',
          'jquery-simulate'
        ]
      }
    },
    concat: {
      options: {
        banner: '<%= meta.banner %>'
      },

      dist: {
        src: [
          'lib/dates.js',
          'lib/time.js',
          'lib/weekly.js'
        ],
        dest: 'dist/weekly.js'
      },

      full: {
        src: [
          'dist/_bower.js',
          'lib/time.js',
          'lib/dates.js',
          'lib/weekly.js'
        ],
        dest: 'dist/weekly.full.js'
      }
    },

    template2js: {
      dist: {
        src: 'lib/template.html',
        dest: 'dist/weekly.js'
      },

      full: {
        src: 'lib/template.html',
        dest: 'dist/weekly.full.js'
      }
    },

    uglify: {
      options: {
        banner: '<%= meta.banner %>'
      },

      dist: {
        src: 'dist/weekly.js',
        dest: 'dist/weekly.min.js'
      },

      full: {
        src: 'dist/weekly.full.js',
        dest: 'dist/weekly.full.min.js'
      }
    },

    clean: {
      bower: [
        'dist/_bower.js'
      ],
      dist: [
        'dist'
      ]
    },

    less: {
      'default': {
        src: 'less/theme1.less',
        dest: 'dist/weekly.css'
      }
    },

    watch: {
      options: {
        livereload: true
      },
      scripts: {
        files: [
          '<%= jshint.main %>',
          'lib/template.html'
        ],
        tasks: 'scripts'
      },

      styles: {
        files: [
          'less/*.less'
        ],
        tasks: 'styles',
      },

      example: {
        files: [
          'example/*'
        ]
      },

      ci: {
        files: [
          'Gruntfile.js',
          'test/index.html',
          'test/time.html',
          'test/dates.html'
        ],
        tasks: 'default'
      }
    },

    mocha: {
      options: {
        run: true,
        growl: true,
        reporter: 'Spec'
      },
      weekly: {
        src: 'test/index.html',
      },
      time: {
        src: 'test/time.html',
      },
      dates: {
        src: 'test/dates.html',
      }
    },

    plato: {
      main: {
        files: {
          'reports': ['lib/*.js']
        }
      }
    },

    connect: {
      server:{
        options: {
          hostname: '*'
        }
      },

      plato: {
        port: 8000,
        base: 'reports',
        options: {
          keepalive: true
        }
      }
    },
    bytesize: {
      scripts: {
        src: [
          'dist/*'
        ]
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-concat-bower');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-bytesize');
  grunt.loadNpmTasks('grunt-mocha');
  grunt.loadNpmTasks('grunt-plato');
  grunt.loadTasks('tasks');
  grunt.registerTask('scripts', ['jshint', 'bower', 'concat', 'template2js', 'uglify', 'clean:bower', 'mocha', 'bytesize']);
  grunt.registerTask('styles', ['less']);
  grunt.registerTask('default', ['scripts', 'styles']);
  grunt.registerTask('dev', ['connect:server', 'watch']);
  grunt.registerTask('reports', ['plato', 'connect:plato']);
};
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var childProcess = require('child_process');

function cp(cmd, args) {
	return new Promise(function(resolve, reject) {
		childProcess.execFile(cmd, args, function(err, stdout, stderr) {
			if (err || stderr) {
				return reject(err || stderr);
			}
			resolve();
		});
	});
}

function shellEscape(str) {
	return str.replace(/ /g, '\\ ');
}

var InnoSetup = function(appDir, outDir, version, gameUID, certFile, certPw) {
	this.appDir = appDir;
	this.outDir = outDir;
	this.version = version;
	this.gameUID = gameUID;
	this.certFile = certFile;
	this.certPw = certPw;
};

InnoSetup.prototype.build = function() {
	var script = fs.readFileSync(path.resolve(__dirname, 'vendor/gamejolt.iss'), {
		encoding: 'utf8',
	});
	script = script
		.replace(/\{\{ICON_DIR\}\}/g, shellEscape(path.resolve(__dirname, 'icons')))
		.replace(/\{\{APP_DIR\}\}/g, shellEscape(this.appDir))
		.replace(/\{\{OUT_DIR\}\}/g, shellEscape(this.outDir))
		.replace(/\{\{GAME_UID\}\}/g, this.gameUID)
		.replace(/\{\{APP_VERSION\}\}/g, this.version);

	var scriptFile = path.resolve(__dirname, 'vendor/tmp-gamejolt.iss');
	fs.writeFileSync(scriptFile, script, { encoding: 'utf8' });

	return cp('iscc.exe', [
		'/Ssigntool=' +
			shellEscape(path.resolve(__dirname, 'vendor/signtool.exe')) +
			' sign /f ' +
			shellEscape(this.certFile) +
			' /p ' +
			this.certPw +
			' /t http://timestamp.verisign.com/scripts/timstamp.dll $f',
		'/Q',
		scriptFile,
	]);
};

module.exports = InnoSetup;
<commit_msg>Use digicert timestamp server<commit_after>var fs = require('fs');
var path = require('path');
var childProcess = require('child_process');

function cp(cmd, args) {
	return new Promise(function(resolve, reject) {
		childProcess.execFile(cmd, args, function(err, stdout, stderr) {
			if (err || stderr) {
				return reject(err || stderr);
			}
			resolve();
		});
	});
}

function shellEscape(str) {
	return str.replace(/ /g, '\\ ');
}

var InnoSetup = function(appDir, outDir, version, gameUID, certFile, certPw) {
	this.appDir = appDir;
	this.outDir = outDir;
	this.version = version;
	this.gameUID = gameUID;
	this.certFile = certFile;
	this.certPw = certPw;
};

InnoSetup.prototype.build = function() {
	var script = fs.readFileSync(path.resolve(__dirname, 'vendor/gamejolt.iss'), {
		encoding: 'utf8',
	});
	script = script
		.replace(/\{\{ICON_DIR\}\}/g, shellEscape(path.resolve(__dirname, 'icons')))
		.replace(/\{\{APP_DIR\}\}/g, shellEscape(this.appDir))
		.replace(/\{\{OUT_DIR\}\}/g, shellEscape(this.outDir))
		.replace(/\{\{GAME_UID\}\}/g, this.gameUID)
		.replace(/\{\{APP_VERSION\}\}/g, this.version);

	var scriptFile = path.resolve(__dirname, 'vendor/tmp-gamejolt.iss');
	fs.writeFileSync(scriptFile, script, { encoding: 'utf8' });

	return cp('iscc.exe', [
		'/Ssigntool=' +
			shellEscape(path.resolve(__dirname, 'vendor/signtool.exe')) +
			' sign /f ' +
			shellEscape(this.certFile) +
			' /p ' +
			this.certPw +
			' /t http://timestamp.digicert.com $f',
		'/Q',
		scriptFile,
	]);
};

module.exports = InnoSetup;
<|endoftext|>