<commit_before>/*
 * Gruntfile
 * @lastmodifiedBy ChengFuLin(chengfulin0806@gmail.com)
 * @lastmodifiedDate 2015/5/20
 */
module.exports = function (grunt) {
    "use strict";
    grunt.initConfig({
        strip_code: {
            options: {
                start_comment: 'start-test-block',
                end_comment: 'end-test-block'
            },
            your_target: {
                src: ['lib/**/*.js']
            }
        },
        mocha_istanbul: {
            options: {
                timeout: 3000
            },
            coverage: {
                src: [
	                'tests/analyses/*.js',
	                'tests/dujs/var.js',
	                'tests/dujs/varfactory.js',
					'tests/dujs/def.js',
	                'tests/dujs/deffactory.js',
	                'tests/dujs/range.js',
	                'tests/dujs/rangefactory.js',
                    'tests/dujs/pair.js',
	                'tests/dujs/pairfactory.js',
	                'tests/dujs/dupair.js',
	                'tests/dujs/dupairfactory.js',
	                'tests/dujs/scope.js',
	                'tests/dujs/domainscope.js',
	                'tests/dujs/pagescope.js',
                    'tests/dujs/functionscope.js',
	                'tests/dujs/anonymousfunctionscope.js',
	                'tests/dujs/scopetree.js',
	                'tests/dujs/scopectrl.js',
                    'tests/dujs/model.js',
                    'tests/dujs/analysisexecution.js',
	                'tests/esgraph/flownodetest.js',
	                'tests/esgraph/test.js'
                ],
            },
            coveralls: {
                src: ['tests'], // multiple folders also works
                options: {
                    coverage: true, // this will make the grunt.event.on('coverage') event listener to be triggered
                    check: {
                        lines: 75,
                        statements: 75
                    },
                    root: './lib', // define where the cover task should consider the root of libraries that are covered by tests
                    reportFormats: ['cobertura', 'lcovonly']
                }
            }
        },
        istanbul_check_coverage: {
            default: {
                options: {
                    coverageFolder: 'coverage*', // will check both coverage folders and merge the coverage results
                    check: {
                        lines: 80,
                        statements: 80
                    }
                }
            }
        },
	    jsdoc: {
		    dist : {
			    src: [
				    'lib/namespace.js',
				    'lib/dujs/*.js',
				    'lib/esgraph/flownode.js',
				    'lib/esgraph/flownodefactory.js'
			    ],
			    jsdoc: './node_modules/.bin/jsdoc'
		    }
	    }
    });

    grunt.event.on('coverage', function(lcovFileContents, done){
        // Check below on the section "The coverage event"
        done();
    });

    grunt.loadNpmTasks('grunt-strip-code');
    grunt.loadNpmTasks('grunt-mocha-istanbul');
	grunt.loadNpmTasks('grunt-jsdoc');

    grunt.registerTask('default', ['mocha_istanbul:coverage']);
    //grunt.registerTask('deploy', ['strip_code']);
    grunt.registerTask('coverage', ['mocha_istanbul:coverage']);
	grunt.registerTask('doc', ['jsdoc']);
};<commit_msg>Show coverage on all tests<commit_after>/*
 * Gruntfile
 * @lastmodifiedBy ChengFuLin(chengfulin0806@gmail.com)
 * @lastmodifiedDate 2015/5/20
 */
module.exports = function (grunt) {
    "use strict";
    grunt.initConfig({
        strip_code: {
            options: {
                start_comment: 'start-test-block',
                end_comment: 'end-test-block'
            },
            your_target: {
                src: ['lib/**/*.js']
            }
        },
        mocha_istanbul: {
            options: {
                timeout: 3000
            },
            coverage: {
                src: [
	                'tests/analyses/*.js',
	                'tests/dujs/*.js',
	                'tests/esgraph/flownodetest.js',
	                'tests/esgraph/flownodefactory.js',
	                'tests/esgraph/test.js'
                ],
            },
            coveralls: {
                src: ['tests'], // multiple folders also works
                options: {
                    coverage: true, // this will make the grunt.event.on('coverage') event listener to be triggered
                    check: {
                        lines: 75,
                        statements: 75
                    },
                    root: './lib', // define where the cover task should consider the root of libraries that are covered by tests
                    reportFormats: ['cobertura', 'lcovonly']
                }
            }
        },
        istanbul_check_coverage: {
            default: {
                options: {
                    coverageFolder: 'coverage*', // will check both coverage folders and merge the coverage results
                    check: {
                        lines: 80,
                        statements: 80
                    }
                }
            }
        },
	    jsdoc: {
		    dist : {
			    src: [
				    'lib/namespace.js',
				    'lib/dujs/*.js',
				    'lib/esgraph/flownode.js',
				    'lib/esgraph/flownodefactory.js'
			    ],
			    jsdoc: './node_modules/.bin/jsdoc'
		    }
	    }
    });

    grunt.event.on('coverage', function(lcovFileContents, done){
        // Check below on the section "The coverage event"
        done();
    });

    grunt.loadNpmTasks('grunt-strip-code');
    grunt.loadNpmTasks('grunt-mocha-istanbul');
	grunt.loadNpmTasks('grunt-jsdoc');

    grunt.registerTask('default', ['mocha_istanbul:coverage']);
    //grunt.registerTask('deploy', ['strip_code']);
    grunt.registerTask('coverage', ['mocha_istanbul:coverage']);
	grunt.registerTask('doc', ['jsdoc']);
};<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-stylus');
  grunt.loadNpmTasks('grunt-jscs');
  grunt.loadNpmTasks('grunt-githooks');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadTasks('grunt');

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    jscs: {
      options: {
        config: '.jscsrc',
        reporter: 'checkstyle'
      },
      src: [
        'Gruntfile.js',
        'src/**/*.js',
        '!src/example.js'
      ]
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: 'checkstyle'
      },
      src: [
        'Gruntfile.js',
        'src/**/*.js',
        '!src/example.js'
      ]
    },
    githooks: {
      all: {
        options: {
          endMarker: ''
        },
        'pre-commit': 'analyze',
        'post-checkout': 'shell:gitLog',
        'post-commit': 'shell:gitLog'
      }
    },
    shell: {
      gitLog: {
        command: 'git log -1 > git-info.txt'
      }
    }
  });

  // Code tasks
  grunt.registerTask('default', ['analyze']);
  grunt.registerTask('analyze', 'Validates code style', ['jshint', 'jscs']);
};
<commit_msg>Fixing identation<commit_after>'use strict';

module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-stylus');
    grunt.loadNpmTasks('grunt-jscs');
    grunt.loadNpmTasks('grunt-githooks');
    grunt.loadNpmTasks('grunt-shell');
    grunt.loadTasks('grunt');

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jscs: {
            options: {
                config: '.jscsrc',
                reporter: 'checkstyle'
            },
            src: [
                'Gruntfile.js',
                'src/**/*.js',
                '!src/example.js'
            ]
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc',
                reporter: 'checkstyle'
            },
            src: [
                'Gruntfile.js',
                'src/**/*.js',
                '!src/example.js'
            ]
        },
        githooks: {
            all: {
                options: {
                    endMarker: ''
                },
                'pre-commit': 'analyze',
                'post-checkout': 'shell:gitLog',
                'post-commit': 'shell:gitLog'
            }
        },
        shell: {
            gitLog: {
                command: 'git log -1 > git-info.txt'
            }
        }
    });

    // Code tasks
    grunt.registerTask('default', ['analyze']);
    grunt.registerTask('analyze', 'Validates code style', ['jshint', 'jscs']);
};
<|endoftext|>


<commit_before>/* global module:false */

module.exports = function(grunt) {

  var header = '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
      allSources = [
        'src/Main.js',
        'src/Ajax.js',
        'src/Arrays.js',
        'src/Functions.js',
        'src/Misc.js',
        'src/Objects.js',
        'src/RegExp.js',
        'src/Strings.js',
      ];

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        banner: header,
      },
      dist: {
        src: allSources,
        dest: 'jUtils.js'
      },
    },
    uglify: {
      options: {
        banner: header,
        report: 'min'
      },
      build: {
        src: allSources,
        dest: 'jUtils.min.js'
      }
    },
    jsdoc : {
      dist : {
        src: ['src/*.js', 'test/*.js'],
        options: {
          destination: 'docs'
        }
      }
    },
    qunit: {
      all: {
        options: {
          urls: [
            'http://localhost:8000/test/test.html',
          ]
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8000,
          base: '.'
        }
      }
    }
  });

  // Modules
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-jsdoc');

  // Tasks
  grunt.registerTask('test', ['connect', 'qunit']);
  grunt.registerTask('doc', ['jsdoc']);
  grunt.registerTask('default', ['concat', 'uglify', 'test']);

};<commit_msg>Added Gzip report<commit_after>/* global module:false */

module.exports = function(grunt) {

  var header = '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
      allSources = [
        'src/Core.js',
        'src/Ajax.js',
        'src/Arrays.js',
        'src/Functions.js',
        'src/Misc.js',
        'src/Objects.js',
        'src/RegExp.js',
        'src/Strings.js',
      ];

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        banner: header,
      },
      dist: {
        src: allSources,
        dest: 'jUtils.js'
      },
    },
    uglify: {
      options: {
        banner: header,
        report: 'gzip'
      },
      build: {
        src: allSources,
        dest: 'jUtils.min.js'
      }
    },
    jsdoc : {
      dist : {
        src: ['src/*.js', 'test/*.js'],
        options: {
          destination: 'docs'
        }
      }
    },
    qunit: {
      all: {
        options: {
          urls: [
            'http://localhost:8000/test/test.html',
          ]
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8000,
          base: '.'
        }
      }
    }
  });

  // Modules
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-jsdoc');

  // Tasks
  grunt.registerTask('test', ['connect', 'qunit']);
  grunt.registerTask('doc', ['jsdoc']);
  grunt.registerTask('default', ['concat', 'uglify', 'test']);

};<|endoftext|>


<commit_before>/**
 * This file is used to build Handsontable from `src/*`
 *
 * Installation:
 * 1. Install Grunt CLI (`npm install -g grunt-cli`)
 * 1. Install Grunt 0.4.0 and other dependencies (`npm install`)
 *
 * Build:
 * Execute `grunt` from root directory of this directory (where Gruntfile.js is)
 * To execute automatically after each change, execute `grunt --force default watch`
 * To execute build followed by the test run, execute `grunt test`
 *
 * Result:
 * building Handsontable will create files:
 *  - dist/jquery.handsontable.js
 *  - dist/jquery.handsontable.css
 *  - dist/jquery.handsontable.full.js
 *  - dist/jquery.handsontable.full.css
 *
 * See http://gruntjs.com/getting-started for more information about Grunt
 */
var browsers = [
  /*{
   browserName: 'firefox',
   platform: 'Windows 7'
   },
   {
   browserName: 'chrome',
   platform: 'Windows 7'
   },*/
  {
    browserName: 'internet explorer',
    version: '8',
    platform: 'Windows 7'
  },
  {
    browserName: 'internet explorer',
    version: '9',
    platform: 'Windows 7'
  },
  {
    browserName: 'internet explorer',
    version: '10',
    platform: 'Windows 8'
  }
];

module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    gitinfo: {
    },
    meta: {
      src: [
        'tmp/core.js',
        'src/focusCatcher.js',
        'src/tableView.js',
        'src/editors.js',
        'src/editorManager.js',
        'src/helpers.js',
        'src/fillHandle.js',
        'src/selectionPoint.js',

        'src/renderers/textRenderer.js',
        'src/renderers/autocompleteRenderer.js',
        'src/renderers/checkboxRenderer.js',
        'src/renderers/numericRenderer.js',
        'src/renderers/passwordRenderer.js',

        'src/editors/baseEditor.js',
        'src/editors/textEditor.js',
        'src/editors/checkboxEditor.js',
        'src/editors/dateEditor.js',
        'src/editors/handsontableEditor.js',
        'src/editors/autocompleteEditor.js',
        'src/editors/passwordEditor.js',
        'src/editors/selectEditor.js',

        'src/validators/numericValidator.js',
        'src/validators/autocompleteValidator.js',

        'src/cellTypes.js',

        'src/pluginHooks.js',
        'src/plugins/autoColumnSize.js',
        'src/plugins/columnSorting.js',
        'src/plugins/contextMenu.js',
        'src/plugins/legacy.js',
        'src/plugins/manualColumnMove.js',
        'src/plugins/manualColumnResize.js',
        'src/plugins/observeChanges.js',
        'src/plugins/persistentState.js',
        'src/plugins/undoRedo.js',

        'src/3rdparty/jquery.autoresize.js',
        'src/3rdparty/sheetclip.js',
        'src/3rdparty/copypaste.js',
        'src/3rdparty/json-patch-duplex.js'
      ],
      walkontable: [
        'src/3rdparty/walkontable/src/*.js',
        'src/3rdparty/walkontable/src/3rdparty/*.js'
      ],
      vendor: [
        'lib/numeral.js',
        'lib/jQuery-contextMenu/jquery.contextMenu.js'
        // seems to have no effect when turned off on contextmenu.html
        //'lib/jQuery-contextMenu/jquery.ui.position.js'
      ],
      shims: [
        'lib/shims/array.filter.js'
      ]
    },

    concat: {
      dist: {
        files: {
          'dist/jquery.handsontable.js': [
            'tmp/intro.js',
            '<%= meta.src %>',
            '<%= meta.walkontable %>',
            '<%= meta.shims %>',
            'src/outro.js'
          ]
        }
      },
      full_js: {
        files: {
          'dist/jquery.handsontable.full.js': [
            'dist/jquery.handsontable.js',
            '<%= meta.vendor %>'
          ]
        }
      },
      full_css: {
        files: {
          'dist/jquery.handsontable.full.css': [
            'dist/jquery.handsontable.css',
            'lib/jQuery-contextMenu/jquery.contextMenu.css'
          ]
        }
      },
      wc: {
        files: {
          'dist_wc/x-handsontable/jquery-2.min.js': [
            'lib/jquery-2.min.js'
          ],
          'dist_wc/x-handsontable/numeral.de-de.js': [
            'lib/numeral.de-de.js'
          ],
          'dist_wc/x-handsontable/jquery.handsontable.full.js': [
            'dist/jquery.handsontable.full.js'
          ],
          'dist_wc/x-handsontable/jquery.handsontable.full.css': [
            'dist/jquery.handsontable.full.css'
          ]
        }
      }
    },

    watch: {
      options: {
        livereload: true //works with Chrome LiveReload extension. See: https://github.com/gruntjs/grunt-contrib-watch
      },
      files: [
        'src/**/*.js',
        'src/**/*.css',
        'src/**/*.html',
        'lib/**/*.js',
        'lib/**/*.css'
      ],
      tasks: ['default']
    },

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

    replace: {
      dist: {
        options: {
          variables: {
            version: '<%= pkg.version %>',
            timestamp: '<%= (new Date()).toString() %>'
          }
        },
        files: {
          'tmp/intro.js': 'src/intro.js',
          'tmp/core.js': 'src/core.js',
          'dist/jquery.handsontable.css': 'src/css/jquery.handsontable.css'
        }
      },
      wc: {
        options: {
          variables: {
            controller: '<%= grunt.file.read("src/wc/x-handsontable-controller.js") %>'
          }
        },
        files: {
          'dist_wc/x-handsontable.html': 'src/wc/x-handsontable.html'
        }
      }
    },
    jasmine: {
      handsontable: {
        src: [
          'dist/jquery.handsontable.js',
          'demo/js/backbone/lodash.underscore.js',
          'demo/js/backbone/backbone.js',
          'demo/js/backbone/backbone-relational/backbone-relational.js',
          'lib/jquery-ui/js/jquery-ui.custom.js',
          'extensions/jquery.handsontable.removeRow.js'
        ],
        options: {
          specs: [
            'test/jasmine/spec/*Spec.js',
            'test/jasmine/spec/*/*Spec.js'
          ],
          styles: [
            'test/jasmine/css/SpecRunner.css',
            'dist/jquery.handsontable.css',
            'lib/jQuery-contextMenu/jquery.contextMenu.css',
            'lib/jquery-ui/css/ui-bootstrap/jquery-ui.custom.css',
            'extensions/jquery.handsontable.removeRow.css'
          ],
          vendor: [
            'lib/jquery.min.js',
            'lib/numeral.js',
            'lib/jQuery-contextMenu/jquery.contextMenu.js',
            'test/jasmine/lib/jasmine-extensions.js'
          ],
          helpers: [
            'test/jasmine/spec/SpecHelper.js',
            'test/jasmine/lib/nodeShim.js',
            'test/jasmine/spec/test-init.js'
          ],
          outfile: 'test/jasmine/SpecRunner.html',
          template: 'test/jasmine/templates/SpecRunner.tmpl',
          keepRunner: true
        }
      },
      walkontable: {
        src: [
          'src/3rdparty/walkontable/src/*.js',
          'src/3rdparty/walkontable/src/3rdparty/*.js'
        ],
        options: {
          specs: [
            'src/3rdparty/walkontable/test/jasmine/spec/*.spec.js'
          ],
          styles: [
            'src/3rdparty/walkontable/css/walkontable.css'
          ],
          vendor: [
            'lib/jquery.min.js'
          ],
          helpers: [
            'src/3rdparty/walkontable/test/jasmine/SpecHelper.js',
            'test/jasmine/lib/nodeShim.js',
            'src/3rdparty/walkontable/test/jasmine/test-init.js'

          ],
          outfile: 'src/3rdparty/walkontable/test/jasmine/SpecRunner.html',
          template: 'test/jasmine/templates/SpecRunner.tmpl',
          keepRunner: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8080,
          base: '.',
          keepalive: true
        }
      },
      sauce: {
        options: {
          port: 9999,
          base: '.',
          keepalive: false
        }
      }
    },
    'saucelabs-jasmine': {
      handsontable: {
        options: {
          urls: ['http://localhost:9999/test/jasmine/SpecRunner.html'],
//          build: process.env.TRAVIS_JOB_ID,
          build: '<%= pkg.version %>-<%= gitinfo.local.branch.current.name %>',
          concurrency: 3,
          browsers: browsers,
          testname: "Development test (Handsontable)"
        }
      },
      walkontable: {
        options: {
          urls: ['http://localhost:9999/src/3rdparty/walkontable/test/jasmine/SpecRunner.html'],
//          build: process.env.TRAVIS_JOB_ID,
          build: '<%= pkg.version %>-<%= gitinfo.local.branch.current.name %>',
          concurrency: 3,
          browsers: browsers,
          testname: "Development test (Walkontable)"
        }
      }
    }
  });

  // Default task.
  grunt.registerTask('default', ['gitinfo', 'replace:dist', 'concat', 'replace:wc', 'clean']);
  grunt.registerTask('test', ['default', 'jasmine']);
  grunt.registerTask('test:handsontable', ['default', 'jasmine:handsontable']);
  grunt.registerTask('test:walkontable', ['default', 'jasmine:walkontable']);
  grunt.registerTask('sauce', ['default', 'connect:sauce', 'saucelabs-jasmine:walkontable', 'saucelabs-jasmine:handsontable']);
  grunt.registerTask('sauce:handsontable', ['default', 'connect:sauce', 'saucelabs-jasmine:handsontable']);
  grunt.registerTask('sauce:walkontable', ['default', 'connect:sauce', 'saucelabs-jasmine:walkontable']);

  grunt.loadNpmTasks('grunt-replace');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-saucelabs');
  grunt.loadNpmTasks('grunt-gitinfo');
};<commit_msg>Bugfix #1010. Grunt configuration for source maps<commit_after>/**
 * This file is used to build Handsontable from `src/*`
 *
 * Installation:
 * 1. Install Grunt CLI (`npm install -g grunt-cli`)
 * 1. Install Grunt 0.4.0 and other dependencies (`npm install`)
 *
 * Build:
 * Execute `grunt` from root directory of this directory (where Gruntfile.js is)
 * To execute automatically after each change, execute `grunt --force default watch`
 * To execute build followed by the test run, execute `grunt test`
 *
 * Result:
 * building Handsontable will create files:
 *  - dist/jquery.handsontable.js
 *  - dist/jquery.handsontable.css
 *  - dist/jquery.handsontable.full.js
 *  - dist/jquery.handsontable.full.css
 *
 * See http://gruntjs.com/getting-started for more information about Grunt
 */
var browsers = [
  /*{
   browserName: 'firefox',
   platform: 'Windows 7'
   },
   {
   browserName: 'chrome',
   platform: 'Windows 7'
   },*/
  {
    browserName: 'internet explorer',
    version: '8',
    platform: 'Windows 7'
  },
  {
    browserName: 'internet explorer',
    version: '9',
    platform: 'Windows 7'
  },
  {
    browserName: 'internet explorer',
    version: '10',
    platform: 'Windows 8'
  }
];

module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    gitinfo: {
    },
    meta: {
      src: [
        'tmp/core.js',
        'src/focusCatcher.js',
        'src/tableView.js',
        'src/editors.js',
        'src/editorManager.js',
        'src/helpers.js',
        'src/fillHandle.js',
        'src/selectionPoint.js',

        'src/renderers/textRenderer.js',
        'src/renderers/autocompleteRenderer.js',
        'src/renderers/checkboxRenderer.js',
        'src/renderers/numericRenderer.js',
        'src/renderers/passwordRenderer.js',

        'src/editors/baseEditor.js',
        'src/editors/textEditor.js',
        'src/editors/checkboxEditor.js',
        'src/editors/dateEditor.js',
        'src/editors/handsontableEditor.js',
        'src/editors/autocompleteEditor.js',
        'src/editors/passwordEditor.js',
        'src/editors/selectEditor.js',

        'src/validators/numericValidator.js',
        'src/validators/autocompleteValidator.js',

        'src/cellTypes.js',

        'src/pluginHooks.js',
        'src/plugins/autoColumnSize.js',
        'src/plugins/columnSorting.js',
        'src/plugins/contextMenu.js',
        'src/plugins/legacy.js',
        'src/plugins/manualColumnMove.js',
        'src/plugins/manualColumnResize.js',
        'src/plugins/observeChanges.js',
        'src/plugins/persistentState.js',
        'src/plugins/undoRedo.js',

        'src/3rdparty/jquery.autoresize.js',
        'src/3rdparty/sheetclip.js',
        'src/3rdparty/copypaste.js',
        'src/3rdparty/json-patch-duplex.js'
      ],
      walkontable: [
        'src/3rdparty/walkontable/src/*.js',
        'src/3rdparty/walkontable/src/3rdparty/*.js'
      ],
      vendor: [
        'lib/numeral.js',
        'lib/jQuery-contextMenu/jquery.contextMenu.js'
        // seems to have no effect when turned off on contextmenu.html
        //'lib/jQuery-contextMenu/jquery.ui.position.js'
      ],
      shims: [
        'lib/shims/array.filter.js'
      ]
    },

    concat: {
      dist: {
        files: {
          'dist/jquery.handsontable.js': [
            'tmp/intro.js',
            '<%= meta.src %>',
            '<%= meta.walkontable %>',
            '<%= meta.shims %>',
            'src/outro.js'
          ]
        }
      },
      full_js: {
        files: {
          'dist/jquery.handsontable.full.js': [
            'dist/jquery.handsontable.js',
            '<%= meta.vendor %>'
          ]
        }
      },
      full_css: {
        files: {
          'dist/jquery.handsontable.full.css': [
            'dist/jquery.handsontable.css',
            'lib/jQuery-contextMenu/jquery.contextMenu.css'
          ]
        }
      },
      wc: {
        files: {
          'dist_wc/x-handsontable/jquery-2.min.js': [
            'lib/jquery-2.min.js'
          ],
          'dist_wc/x-handsontable/numeral.de-de.js': [
            'lib/numeral.de-de.js'
          ],
          'dist_wc/x-handsontable/jquery.handsontable.full.js': [
            'dist/jquery.handsontable.full.js'
          ],
          'dist_wc/x-handsontable/jquery.handsontable.full.css': [
            'dist/jquery.handsontable.full.css'
          ]
        }
      }
    },

    watch: {
      options: {
        livereload: true //works with Chrome LiveReload extension. See: https://github.com/gruntjs/grunt-contrib-watch
      },
      files: [
        'src/**/*.js',
        'src/**/*.css',
        'src/**/*.html',
        'lib/**/*.js',
        'lib/**/*.css'
      ],
      tasks: ['default']
    },

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

    copy: {
      nonMinifiedLibs: {
        files: [
          {
            src: 'src/3rdparty/json-patch-duplex.ts',
            dest: 'dist/json-patch-duplex.ts'
          }
        ]
      },
      sourceMaps: {
        files: [
          {
            src: 'src/3rdparty/json-patch-duplex.js.map',
            dest: 'dist/json-patch-duplex.js.map'
          }
        ]
      }
    },

    replace: {
      dist: {
        options: {
          variables: {
            version: '<%= pkg.version %>',
            timestamp: '<%= (new Date()).toString() %>'
          }
        },
        files: {
          'tmp/intro.js': 'src/intro.js',
          'tmp/core.js': 'src/core.js',
          'dist/jquery.handsontable.css': 'src/css/jquery.handsontable.css'
        }
      },
      wc: {
        options: {
          variables: {
            controller: '<%= grunt.file.read("src/wc/x-handsontable-controller.js") %>'
          }
        },
        files: {
          'dist_wc/x-handsontable.html': 'src/wc/x-handsontable.html'
        }
      }
    },
    jasmine: {
      handsontable: {
        src: [
          'dist/jquery.handsontable.js',
          'demo/js/backbone/lodash.underscore.js',
          'demo/js/backbone/backbone.js',
          'demo/js/backbone/backbone-relational/backbone-relational.js',
          'lib/jquery-ui/js/jquery-ui.custom.js',
          'extensions/jquery.handsontable.removeRow.js'
        ],
        options: {
          specs: [
            'test/jasmine/spec/*Spec.js',
            'test/jasmine/spec/*/*Spec.js'
          ],
          styles: [
            'test/jasmine/css/SpecRunner.css',
            'dist/jquery.handsontable.css',
            'lib/jQuery-contextMenu/jquery.contextMenu.css',
            'lib/jquery-ui/css/ui-bootstrap/jquery-ui.custom.css',
            'extensions/jquery.handsontable.removeRow.css'
          ],
          vendor: [
            'lib/jquery.min.js',
            'lib/numeral.js',
            'lib/jQuery-contextMenu/jquery.contextMenu.js',
            'test/jasmine/lib/jasmine-extensions.js'
          ],
          helpers: [
            'test/jasmine/spec/SpecHelper.js',
            'test/jasmine/lib/nodeShim.js',
            'test/jasmine/spec/test-init.js'
          ],
          outfile: 'test/jasmine/SpecRunner.html',
          template: 'test/jasmine/templates/SpecRunner.tmpl',
          keepRunner: true
        }
      },
      walkontable: {
        src: [
          'src/3rdparty/walkontable/src/*.js',
          'src/3rdparty/walkontable/src/3rdparty/*.js'
        ],
        options: {
          specs: [
            'src/3rdparty/walkontable/test/jasmine/spec/*.spec.js'
          ],
          styles: [
            'src/3rdparty/walkontable/css/walkontable.css'
          ],
          vendor: [
            'lib/jquery.min.js'
          ],
          helpers: [
            'src/3rdparty/walkontable/test/jasmine/SpecHelper.js',
            'test/jasmine/lib/nodeShim.js',
            'src/3rdparty/walkontable/test/jasmine/test-init.js'

          ],
          outfile: 'src/3rdparty/walkontable/test/jasmine/SpecRunner.html',
          template: 'test/jasmine/templates/SpecRunner.tmpl',
          keepRunner: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 8080,
          base: '.',
          keepalive: true
        }
      },
      sauce: {
        options: {
          port: 9999,
          base: '.',
          keepalive: false
        }
      }
    },
    'saucelabs-jasmine': {
      handsontable: {
        options: {
          urls: ['http://localhost:9999/test/jasmine/SpecRunner.html'],
//          build: process.env.TRAVIS_JOB_ID,
          build: '<%= pkg.version %>-<%= gitinfo.local.branch.current.name %>',
          concurrency: 3,
          browsers: browsers,
          testname: "Development test (Handsontable)"
        }
      },
      walkontable: {
        options: {
          urls: ['http://localhost:9999/src/3rdparty/walkontable/test/jasmine/SpecRunner.html'],
//          build: process.env.TRAVIS_JOB_ID,
          build: '<%= pkg.version %>-<%= gitinfo.local.branch.current.name %>',
          concurrency: 3,
          browsers: browsers,
          testname: "Development test (Walkontable)"
        }
      }
    }
  });

  // Default task.
  grunt.registerTask('default', ['gitinfo', 'replace:dist', 'concat', 'copy:sourceMaps', 'copy:nonMinifiedLibs', 'replace:wc', 'clean']);
  grunt.registerTask('test', ['default', 'jasmine']);
  grunt.registerTask('test:handsontable', ['default', 'jasmine:handsontable']);
  grunt.registerTask('test:walkontable', ['default', 'jasmine:walkontable']);
  grunt.registerTask('sauce', ['default', 'connect:sauce', 'saucelabs-jasmine:walkontable', 'saucelabs-jasmine:handsontable']);
  grunt.registerTask('sauce:handsontable', ['default', 'connect:sauce', 'saucelabs-jasmine:handsontable']);
  grunt.registerTask('sauce:walkontable', ['default', 'connect:sauce', 'saucelabs-jasmine:walkontable']);

  grunt.loadNpmTasks('grunt-replace');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-saucelabs');
  grunt.loadNpmTasks('grunt-gitinfo');
};<|endoftext|>


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

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    meta: {
      banner: '/*wilddog realtime*/\n'
    },

    // merge files from src/ into angularfire.js
    concat: {
      app: {
        options: { banner: '<%= meta.banner %>' },
        src: [
          'src/module.js',
          'src/**/*.js'
        ],
        dest: 'dist/wild-angular.js'
      }
    },

    // Run shell commands
    shell: {
      options: {
        stdout: true
      },
      protractor_install: {
        command: 'node ./node_modules/protractor/bin/webdriver-manager update'
      },
      npm_install: {
        command: 'npm install'
      },
      bower_install: {
        command: 'bower install'
      }
    },

    // Create local server
    connect: {
      testserver: {
        options: {
          hostname: 'localhost',
          port: 3030
        }
      }
    },

    // Minify JavaScript
    uglify : {
      options: {
        preserveComments: 'some'
      },
      app : {
        files : {
          'dist/wild-angular.min.js' : ['dist/wild-angular.js']
        }
      }
    },

    // Lint JavaScript
    jshint : {
      options : {
        jshintrc: '.jshintrc',
        ignores: ['src/lib/polyfills.js']
      },
      all : ['src/**/*.js']
    },

    // Auto-run tasks on file changes
    watch : {
      scripts : {
        files : ['src/**/*.js', 'tests/unit/**/*.spec.js', 'tests/lib/**/*.js', 'tests/mocks/**/*.js'],
        tasks : ['test:unit', 'notify:watch'],
        options : {
          interrupt : true,
          atBegin: true
        }
      }
    },

    // Unit tests
    karma: {
      options: {
        configFile: 'tests/automatic_karma.conf.js'
      },
      manual: {
        configFile: 'tests/manual_karma.conf.js'
      },
      singlerun: {},
      watch: {
         autowatch: true,
         singleRun: false
      },
      saucelabs: {
        configFile: 'tests/sauce_karma.conf.js'
      }
    },

    // End to end (e2e) tests
    protractor: {
      options: {
        configFile: "tests/local_protractor.conf.js"
      },
      singlerun: {},
      saucelabs: {
        options: {
          configFile: "tests/sauce_protractor.conf.js",
          args: {
            sauceUser: process.env.SAUCE_USERNAME,
            sauceKey: process.env.SAUCE_ACCESS_KEY
          }
        }
      }
    },

    // Desktop notificaitons
    notify: {
      watch: {
        options: {
          title: 'Grunt Watch',
          message: 'Build Finished'
        }
      }
    }
  });

  require('load-grunt-tasks')(grunt);

  // Installation
  grunt.registerTask('install', ['shell:protractor_install']);
  grunt.registerTask('update', ['shell:npm_install']);

  // Single run tests
  grunt.registerTask('test', ['test:unit', 'test:e2e']);
  grunt.registerTask('test:unit', ['karma:singlerun']);
  grunt.registerTask('test:e2e', ['concat', 'connect:testserver', 'protractor:singlerun']);
  grunt.registerTask('test:manual', ['karma:manual']);

  // Travis CI testing
  //grunt.registerTask('test:travis', ['build', 'test:unit', 'connect:testserver', 'protractor:saucelabs']);
  grunt.registerTask('test:travis', ['build', 'test:unit']);

  // Sauce tasks
  grunt.registerTask('sauce:unit', ['karma:saucelabs']);
  grunt.registerTask('sauce:e2e', ['concat', 'connect:testserver', 'protractor:saucelabs']);

  // Watch tests
  grunt.registerTask('test:watch', ['karma:watch']);
  grunt.registerTask('test:watch:unit', ['karma:watch']);

  // Build tasks
  grunt.registerTask('build', ['concat', 'jshint', 'uglify']);

  // Default task
  grunt.registerTask('default', ['build', 'test']);
};
<commit_msg>temp remove e2e test<commit_after>/* global module */
module.exports = function(grunt) {
  'use strict';

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    meta: {
      banner: '/*wilddog realtime*/\n'
    },

    // merge files from src/ into angularfire.js
    concat: {
      app: {
        options: { banner: '<%= meta.banner %>' },
        src: [
          'src/module.js',
          'src/**/*.js'
        ],
        dest: 'dist/wild-angular.js'
      }
    },

    // Run shell commands
    shell: {
      options: {
        stdout: true
      },
      protractor_install: {
        command: 'node ./node_modules/protractor/bin/webdriver-manager update'
      },
      npm_install: {
        command: 'npm install'
      },
      bower_install: {
        command: 'bower install'
      }
    },

    // Create local server
    connect: {
      testserver: {
        options: {
          hostname: 'localhost',
          port: 3030
        }
      }
    },

    // Minify JavaScript
    uglify : {
      options: {
        preserveComments: 'some'
      },
      app : {
        files : {
          'dist/wild-angular.min.js' : ['dist/wild-angular.js']
        }
      }
    },

    // Lint JavaScript
    jshint : {
      options : {
        jshintrc: '.jshintrc',
        ignores: ['src/lib/polyfills.js']
      },
      all : ['src/**/*.js']
    },

    // Auto-run tasks on file changes
    watch : {
      scripts : {
        files : ['src/**/*.js', 'tests/unit/**/*.spec.js', 'tests/lib/**/*.js', 'tests/mocks/**/*.js'],
        tasks : ['test:unit', 'notify:watch'],
        options : {
          interrupt : true,
          atBegin: true
        }
      }
    },

    // Unit tests
    karma: {
      options: {
        configFile: 'tests/automatic_karma.conf.js'
      },
      manual: {
        configFile: 'tests/manual_karma.conf.js'
      },
      singlerun: {},
      watch: {
         autowatch: true,
         singleRun: false
      },
      saucelabs: {
        configFile: 'tests/sauce_karma.conf.js'
      }
    },

    // End to end (e2e) tests
    protractor: {
      options: {
        configFile: "tests/local_protractor.conf.js"
      },
      singlerun: {},
      saucelabs: {
        options: {
          configFile: "tests/sauce_protractor.conf.js",
          args: {
            sauceUser: process.env.SAUCE_USERNAME,
            sauceKey: process.env.SAUCE_ACCESS_KEY
          }
        }
      }
    },

    // Desktop notificaitons
    notify: {
      watch: {
        options: {
          title: 'Grunt Watch',
          message: 'Build Finished'
        }
      }
    }
  });

  require('load-grunt-tasks')(grunt);

  // Installation
  grunt.registerTask('install', ['shell:protractor_install']);
  grunt.registerTask('update', ['shell:npm_install']);

  // Single run tests
 // grunt.registerTask('test', ['test:unit', 'test:e2e']);

  grunt.registerTask('test', ['test:unit']);
  grunt.registerTask('test:unit', ['karma:singlerun']);
  grunt.registerTask('test:e2e', ['concat', 'connect:testserver', 'protractor:singlerun']);
  grunt.registerTask('test:manual', ['karma:manual']);

  // Travis CI testing
  //grunt.registerTask('test:travis', ['build', 'test:unit', 'connect:testserver', 'protractor:saucelabs']);
  grunt.registerTask('test:travis', ['build', 'test:unit']);

  // Sauce tasks
  grunt.registerTask('sauce:unit', ['karma:saucelabs']);
  grunt.registerTask('sauce:e2e', ['concat', 'connect:testserver', 'protractor:saucelabs']);

  // Watch tests
  grunt.registerTask('test:watch', ['karma:watch']);
  grunt.registerTask('test:watch:unit', ['karma:watch']);

  // Build tasks
  grunt.registerTask('build', ['concat', 'jshint', 'uglify']);

  // Default task
  grunt.registerTask('default', ['build', 'test']);
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    watch: {
      files: '<%= jshint.all %>',
      tasks: 'default'
    },
    jshint: {
      all: ['Gruntfile.js', 'lib/**/*.js', 'tasks/**/*.js', 'test/**/*.js']
    },
    simplemocha: {
      all: {
        src: 'test/**/*.test.js',
        options: {
          ui: 'tdd',
          reporter: 'list',
          growl: true,
          timeout: 20000
        }
      }
    }
  });

  // Load local tasks.
  grunt.loadTasks('tasks');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-simple-mocha');

  // Default task.
  grunt.registerTask('default', ['jshint', 'simplemocha']);
  grunt.registerTask('test', ['jshint', 'simplemocha']);

};
<commit_msg>added dev task and added data.json to watch<commit_after>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    watch: {
      files: [
        '<%= jshint.all %>',
        'data.json'
      ],
      tasks: 'default'
    },
    jshint: {
      all: ['Gruntfile.js', 'lib/**/*.js', 'tasks/**/*.js', 'test/**/*.js']
    },
    simplemocha: {
      all: {
        src: 'test/**/*.test.js',
        options: {
          ui: 'tdd',
          reporter: 'list',
          //grep: 'generate',
          timeout: 20000,
          growl: true
        }
      }
    }
  });

  // Load local tasks.
  grunt.loadTasks('tasks');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-simple-mocha');

  // Default task.
  grunt.registerTask('default', ['jshint', 'simplemocha']);
  grunt.registerTask('test', ['jshint', 'simplemocha']);
  grunt.registerTask('dev', ['default', 'watch']);

};
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    // Load tasks
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-browserify');

    grunt.initConfig({

        less: {
            development: {
                options: {
                    paths: ["assets/css"]
                },
                files: {
                    "client/css/app.css": "client/css/app.less"
                }
            }
        },

        browserify: {
            development: {
                files: {
                    'client/js/game.bundle.js': ['game/game.js']
                }
            }
        },

        watch: {
            styles: {
                // Which files to watch (all .less files recursively in the less directory)
                files: ['client/css/**/*.less'],
                tasks: ['less'],
                options: {
                    nospawn: true
                }
            },

            scripts: {
                files: ['game/**/*.js'],
                tasks: ['browserify']
            }
        },

        concurrent: {
            dev: ['nodemon:dev', 'watch'],
            options: {
                logConcurrentOutput: true
            }

        },

        nodemon: {
            dev: {
                script: './server/main.js'
            },
            options: {
                nodeArgs: ['--debug']
            }
        },

        clean: ["node_modules", "client/components"]

    });

    grunt.registerTask('dev', ['less', 'browserify', 'concurrent:dev']);

};<commit_msg>Change an option for a grunt task<commit_after>module.exports = function(grunt) {

    // Load tasks
    grunt.loadNpmTasks('grunt-nodemon');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-concurrent');
    grunt.loadNpmTasks('grunt-browserify');

    grunt.initConfig({

        less: {
            development: {
                options: {
                    paths: ["assets/css"]
                },
                files: {
                    "client/css/app.css": "client/css/app.less"
                }
            }
        },

        browserify: {
            development: {
                files: {
                    'client/js/game.bundle.js': ['game/game.js']
                }
            }
        },

        watch: {
            styles: {
                // Which files to watch (all .less files recursively in the less directory)
                files: ['client/css/**/*.less'],
                tasks: ['less'],
                options: {
                    spawn: false
                }
            },

            scripts: {
                files: ['game/**/*.js'],
                tasks: ['browserify'],
                options: {
                    spawn: false
                }
            }
        },

        concurrent: {
            dev: ['nodemon:dev', 'watch'],
            options: {
                logConcurrentOutput: true
            }

        },

        nodemon: {
            dev: {
                script: './server/main.js'
            },
            options: {
                nodeArgs: ['--debug']
            }
        },

        clean: ["node_modules", "client/components"]

    });

    grunt.registerTask('dev', ['less', 'browserify', 'concurrent:dev']);

};<|endoftext|>


<commit_before>// STcommon.js : Show Timer common JavaScript
// This file should be included first, before module-specific JS.
//
// Example:
// <script type="text/javascript" src="STcommon.js"></script>
// <script type="text/javascript" src="edit_a_break.js"></script>
//
// This contains functions and variables used in all modules of
// the Show Timer.

var dbug = 3;

function get_show_start_hour_offset() {

    // This returns the number of hours difference between the
    // computer's configured local timezone and US/Eastern.  This
    // would depend on the browswer's implementatin of the Date
    // object's getTimezoneOffset() method.  US/Eastern is 5 hours
    // (300 minutes) behind UTC in January, and during daylight saving
    // time (DST), 240 minutes.  So for example, if the computer is
    // configured for US/Pacific time during DST, getTimezoneOffset()
    // will return 420, therefore 240-420 = -180, or 3 hours west of
    // EDT.  For the example of "The Tech Guy," this would be added to
    // 14 to produce 11, or 11 AM, which is the hour of the beginning
    // of the show in Petaluma.

    var now = new Date();
    var nowOff = now.getTimezoneOffset();
    now.setMonth(0);
    var JanOff = now.getTimezoneOffset();
    var EToff = 300;
    var localDiff;

    if ( nowOff !== JanOff ) {
	// We're under daylight saving time
	EToff = 240;
    }

    localDiff = EToff - nowOff;

    return localDiff / 60;
}

// symbolic states of the show
// This acts sort of like an enum in C

const BEFORE_SHOW = 0,
      BUMP_IN = 1, // technically ON_AIR, but while bumper music is playing
      ON_AIR = 2, // talent should be talking
      TIME_SHORT = 3, // break/end coming soon
      TIME_VERY_SHORT = 4, // break/end coming REALLY soon
      IN_BREAK = 5, // ad should be playing
      BUMP_SOON = 6, // ad still playing, but BUMP_IN approaching
      BUMP_VERY_SOON = 7, // ad still playing, but very near to BUMP_IN
      SHOW_DONE = 8;

// You could think of "after show" as "before show", as in, before
// the next show.  But SHOW_DONE marks the end of the precomputed
// events table.

function dbg(lvl, msg) {

    // This function is called for debugging.  "lvl" describes the
    // intended level of the message, from lower numbers being very
    // low level details, like every single member being added to a
    // complex structure, to higher numbers like general program
    // state.  If "lvl" is greater than or equal to the global
    // variable "dbug," the message (including its level and a colon)
    // goes to the debugging console, otherwise it's just ignored.
    // There are no constraints on "lvl" or "dbug", for example they
    // could be negative.

    if ( lvl >= dbug ) {
	console.log(lvl+": "+msg);
    }
    return true;
}

function zeropad(num, places) {

    // This takes "num" and pads with zeroes so that the result ends
    // up being "places" digits.  For example, positive seconds less
    // than 10 are typically preceeded by ":0".

    var s = num.toString();
    var i;

    while ( s.length < places ) {
	s = "0" + s;
    }

    return s;
}

var brk = [];  // the list of breaks

var remind = []; // list of reminders

function load_reminders(profname) {

    // Load the reminders list from the localStorage key named
    // "profname" and return it.  If the "profname" profile is not in
    // localStorage, see if "defaultremind" exists and prompt the user
    // to return that instead.

    // This is functionally equivalent to loading breaks (scrounge
    // around localStorage, JSON.parse() what's found), just with a
    // "reminders" instead of "breaks" suffix, and with a different
    // array destination, basically.  So reuse try_load_breaks()
    //
    // ******** D A N G E R **********
    //
    // If that routine changes, we'll have to do something else.

    var remindtab = try_load_breaks(profname);

    if ( remindtab !== false ) {
	return remindtab;
    }

    if ( typeof defaultremind !== "undefined" &&
	 Array.isArray(defaultremind) ) {
	console.warn('Tried to load reminders "'+profname+'" but that does not exist.');
	if ( confirm('Profile "'+profname.replace(/_reminders/, "")+'" not found in localStorage, load the default list instead?') ) {
	    return defaultremind;
	}
    }

    return false;
}

function load_breaks(profname) {

    // Load the breaks list from the localStorage key named
    // "profname" and return it.  Historical note: this used
    // to append "_breaks" to the key name, but then that did
    // not allow for the idea of a profile backup name.  If the
    // "profname" profile is not in localStorage, see if "defaultbrk"
    // exists and prompt the user to return that instead.

    var breaktab = try_load_breaks(profname);

    if ( breaktab !== false ) {
	return breaktab;
    }

    if ( typeof defaultbrk !== "undefined" &&
	 Array.isArray(defaultbrk) ) {
	console.warn('Tried to load breaks "'+profname+'" but that does not exist.');
	if ( confirm('Profile "'+profname.replace(/_breaks/, "")+'" not found in localStorage, load the default list instead?') ) {
	    return defaultbrk;
	}
    }

    return false;
}

function try_load_breaks(profname) {

    // This does the actual work of attempting to load the profile.
    // This was refactored because there are now two ways this can
    // fail to load the profile (return false), and I wanted an idea
    // of a built-in default breaks list.  So the "API" as it were is
    // to call "load_breaks()" and if we return false from
    // try_load_breaks(), load_breaks() sees if there exists a
    // "defaultbrk" array and returns that instead.  It's just a lot
    // handier this way, instead of longer if(){} blocks or a label.

    var breaklist = new Array();
    var breakListStr;

    try {
	breakListStr = localStorage.getItem(profname);
    } catch (err) {
	console.warn("could not access "+profname+" in localStorage: "+err);
	return false;
    }

    breaklist = JSON.parse(breakListStr);
    if ( ! breaklist ) {
	console.warn("try_load_breaks("+profname+"): came up empty.");
	return false;
    }

    // Just a historical note: The .begin and .end used to be Date()
    // objects, and of course, JSON records the date as a string
    // instead of an object.  Therefore, there USED TO BE a loop here
    // recreating objects from strings.  However, it did not seem
    // useful to keep them as objects, and instead they're offsets in
    // seconds from the start of the show.

    return breaklist;
}

function break_cmp(obja, objb) {

    // When sorting the brk array (the break descriptions), this
    // provides the comparison function to the .sort() method.

    return obja.begin - objb.begin;
}

function reminder_cmp(obja, objb) {

    // When sorting the remind array (the reminder descriptions), this
    // provides the comparison function to the .sort() method.

    return obja.begin - objb.begin;
}

function secs2minsec(insecs) {

    // Form a minutes:seconds string from "insecs" number of seconds,
    // if possible. This is visually nicer for break lengths than full
    // hh:mm:ss.  If the hours: portion is nonzero, return it.

    var str = "";
    var hrs;

    // Centralize this conversion by calling the hms converter (JUST
    // in case the format changes or a bug is discovered).  It is
    // admittedly a little inefficient in terms of computation.

    str = secs2hmsStr(insecs);
    hrs = str.substring(0,2);
    if ( hrs === "00" ) {
	// drop the "00:"
	str = str.substring(3);
	if ( str.charAt(0) === "0" ) {
	    // drop the leading zero
	    str = str.substring(1);
	}
    }

    return str;
}

function secs2hmsStr(insecs) {

    // form an hours, minutes, seconds string (hh:mm:ss) from "insecs"
    // number of seconds.  Each portion of the results is zero padded
    // to 2 digits.

    var str = "";
    var t = insecs;
    var secs,mins,hrs;

    secs = t % 60;
    t = Math.floor(t/60);
    mins = t % 60;
    t = Math.floor(t/60);
    str += zeropad(t, 2)
    str += ":";
    str += zeropad(mins, 2)
    str += ":";
    str += zeropad(secs, 2)

    return str;
}

function hms2secs(str) {

    // Take string "str" which is in the format hours:minutes:seconds and
    // convert that to a number of seconds.  Zero, one, or two colons are
    // allowed.  Any characters other than the digits and a colon make this
    // function return false.  Also if minutes or seconds are greater than
    // 59 will cause a return of false.  A colon followed by nothing
    // assumes zero, so for example "4:" means four minutes.

    var secs = 0;
    var c, l, i;
    var coloncnt = 0;
    var val; // intermediate value while walking along the string
    var hms = new Array(); // hours, minutes, seconds as accumulated

    dbg(0, "  hms2secs(): converting "+str);

    val = 0;
    l = str.length;
    for ( i = 0; i < l; i++ ) {
	c = str.charAt(i);
	dbg(0, "    considering "+c+" at "+i+" ("+val+")");
	if ( c === ":" ) {
	    if ( ++coloncnt > 2 ) {
		dbg(1, "    too many colons, "+coloncnt);
		return false;
	    }
	    dbg(0, "      processing colon, before "+val);
	    hms.push(val);
	    val = 0;
	} else if ( c < "0" || c > "9" ) {
	    dbg(1, "    char "+c+" not in range");
	    return false;
	} else {
	    // add the next digit by shifting the <result so
	    // far> by one decimal place and add current one
	    val *= 10;
	    val += parseInt(c);
	}
    }
    hms.push(val);

    while ( ++coloncnt < 3 ) {
	hms.unshift(0);
    }

    dbg(1, "  ready with hms len "+hms.length+" and hms "+hms);
    if ( hms[0] > 23 || hms[1] > 59 || hms[2] > 59 ) {
	dbg(1, "    something was too big");
	return false;
    }

    secs = hms[0] * 3600 + hms[1] * 60 + hms[2];

    return secs;
}

function state2str(st) {
    // Given state "st", what does the const look
    // like in the source?
    // Returns "unknown" if the number is out of range.
    const state = [ "BEFORE_SHOW",
		    "BUMP_IN",
		    "ON_AIR",
		    "TIME_SHORT",
		    "TIME_VERY_SHORT",
		    "IN_BREAK",
		    "BUMP_SOON",
		    "BUMP_VERY_SOON",
		    "SHOW_DONE" ];

    if ( st < BEFORE_SHOW ||
	 st > SHOW_DONE ) {
	return "unknown";
    } else {
	return state[st];
    }
}

function st2col(st) {

    // For state "st", which member of st.color should be
    // used for coloration of the HTML node?  If the state
    // is out of range, let CSS take over by returning "".

    const statetab =
	  [ "revertCSS", //"BEFORE_SHOW"
	    "onAir",     //"BUMP_IN"
	    "onAir",     //"ON_AIR"
	    "soon",      //"TIME_SHORT"
	    "verysoon",  //"TIME_VERY_SHORT"
	    "revertCSS", //"IN_BREAK"
	    "soon",      //"BUMP_SOON"
	    "verysoon",  //"BUMP_VERY_SOON"
	    "revertCSS"  //"SHOW_DONE"
	  ];

    if ( st < BEFORE_SHOW ||
	 st > SHOW_DONE ) {
	return "revertCSS";
    } else {
	return statetab[st];
    }
}

function find_all_profiles() {

    // finds all the profiles in localStorage and inserts <option>
    // elements into the node with an ID of "profiles" (expected to be
    // a <datalist> element)

    var i, l, k;
    var seen = new Array();
    var prof;
    var optproto = document.createElement("option");
    var opt;
    var profblk;

    var brksidx, klen;

    if ( typeof profiles !== "undefined" ) {
	profblk = profiles;
    } else {
	if ( (profblk = document.getElementById("profiles")) === null ) {
	    // If one isn't in the document already, provide one.
	    // Other JavaScript could likewise use appendChild to add
	    // an input field which utilizes this list.
	    profblk = document.createElement("datalist");
	    document.body.appendChild(profblk);
	}
    }

    // empty out any existing options
    while ( (opt = profiles.firstChild) !== null ) {
	profiles.removeChild(opt);
    }

    l = localStorage.length;
    for ( i = 0; i < l; i++ ) {
	k = localStorage.key(i);
	klen = k.length;
	dbg(1, "got key "+k+" length "+klen);
	prof = k.replace(/_(break|param|reminder)s(_bak[0-9]*)?$/, "");
	if ( ! seen.includes(prof) ) {
	    dbg(1,"*** so added from key "+k+" the profile "+prof);
	    seen.push(prof);
	    opt = optproto.cloneNode(false);
	    opt.textContent = prof;
	    profblk.appendChild(opt);
	}
    }
}

<commit_msg>Reference "profblk" instead of global "profiles" consistently<commit_after>// STcommon.js : Show Timer common JavaScript
// This file should be included first, before module-specific JS.
//
// Example:
// <script type="text/javascript" src="STcommon.js"></script>
// <script type="text/javascript" src="edit_a_break.js"></script>
//
// This contains functions and variables used in all modules of
// the Show Timer.

var dbug = 3;

function get_show_start_hour_offset() {

    // This returns the number of hours difference between the
    // computer's configured local timezone and US/Eastern.  This
    // would depend on the browswer's implementatin of the Date
    // object's getTimezoneOffset() method.  US/Eastern is 5 hours
    // (300 minutes) behind UTC in January, and during daylight saving
    // time (DST), 240 minutes.  So for example, if the computer is
    // configured for US/Pacific time during DST, getTimezoneOffset()
    // will return 420, therefore 240-420 = -180, or 3 hours west of
    // EDT.  For the example of "The Tech Guy," this would be added to
    // 14 to produce 11, or 11 AM, which is the hour of the beginning
    // of the show in Petaluma.

    var now = new Date();
    var nowOff = now.getTimezoneOffset();
    now.setMonth(0);
    var JanOff = now.getTimezoneOffset();
    var EToff = 300;
    var localDiff;

    if ( nowOff !== JanOff ) {
	// We're under daylight saving time
	EToff = 240;
    }

    localDiff = EToff - nowOff;

    return localDiff / 60;
}

// symbolic states of the show
// This acts sort of like an enum in C

const BEFORE_SHOW = 0,
      BUMP_IN = 1, // technically ON_AIR, but while bumper music is playing
      ON_AIR = 2, // talent should be talking
      TIME_SHORT = 3, // break/end coming soon
      TIME_VERY_SHORT = 4, // break/end coming REALLY soon
      IN_BREAK = 5, // ad should be playing
      BUMP_SOON = 6, // ad still playing, but BUMP_IN approaching
      BUMP_VERY_SOON = 7, // ad still playing, but very near to BUMP_IN
      SHOW_DONE = 8;

// You could think of "after show" as "before show", as in, before
// the next show.  But SHOW_DONE marks the end of the precomputed
// events table.

function dbg(lvl, msg) {

    // This function is called for debugging.  "lvl" describes the
    // intended level of the message, from lower numbers being very
    // low level details, like every single member being added to a
    // complex structure, to higher numbers like general program
    // state.  If "lvl" is greater than or equal to the global
    // variable "dbug," the message (including its level and a colon)
    // goes to the debugging console, otherwise it's just ignored.
    // There are no constraints on "lvl" or "dbug", for example they
    // could be negative.

    if ( lvl >= dbug ) {
	console.log(lvl+": "+msg);
    }
    return true;
}

function zeropad(num, places) {

    // This takes "num" and pads with zeroes so that the result ends
    // up being "places" digits.  For example, positive seconds less
    // than 10 are typically preceeded by ":0".

    var s = num.toString();
    var i;

    while ( s.length < places ) {
	s = "0" + s;
    }

    return s;
}

var brk = [];  // the list of breaks

var remind = []; // list of reminders

function load_reminders(profname) {

    // Load the reminders list from the localStorage key named
    // "profname" and return it.  If the "profname" profile is not in
    // localStorage, see if "defaultremind" exists and prompt the user
    // to return that instead.

    // This is functionally equivalent to loading breaks (scrounge
    // around localStorage, JSON.parse() what's found), just with a
    // "reminders" instead of "breaks" suffix, and with a different
    // array destination, basically.  So reuse try_load_breaks()
    //
    // ******** D A N G E R **********
    //
    // If that routine changes, we'll have to do something else.

    var remindtab = try_load_breaks(profname);

    if ( remindtab !== false ) {
	return remindtab;
    }

    if ( typeof defaultremind !== "undefined" &&
	 Array.isArray(defaultremind) ) {
	console.warn('Tried to load reminders "'+profname+'" but that does not exist.');
	if ( confirm('Profile "'+profname.replace(/_reminders/, "")+'" not found in localStorage, load the default list instead?') ) {
	    return defaultremind;
	}
    }

    return false;
}

function load_breaks(profname) {

    // Load the breaks list from the localStorage key named
    // "profname" and return it.  Historical note: this used
    // to append "_breaks" to the key name, but then that did
    // not allow for the idea of a profile backup name.  If the
    // "profname" profile is not in localStorage, see if "defaultbrk"
    // exists and prompt the user to return that instead.

    var breaktab = try_load_breaks(profname);

    if ( breaktab !== false ) {
	return breaktab;
    }

    if ( typeof defaultbrk !== "undefined" &&
	 Array.isArray(defaultbrk) ) {
	console.warn('Tried to load breaks "'+profname+'" but that does not exist.');
	if ( confirm('Profile "'+profname.replace(/_breaks/, "")+'" not found in localStorage, load the default list instead?') ) {
	    return defaultbrk;
	}
    }

    return false;
}

function try_load_breaks(profname) {

    // This does the actual work of attempting to load the profile.
    // This was refactored because there are now two ways this can
    // fail to load the profile (return false), and I wanted an idea
    // of a built-in default breaks list.  So the "API" as it were is
    // to call "load_breaks()" and if we return false from
    // try_load_breaks(), load_breaks() sees if there exists a
    // "defaultbrk" array and returns that instead.  It's just a lot
    // handier this way, instead of longer if(){} blocks or a label.

    var breaklist = new Array();
    var breakListStr;

    try {
	breakListStr = localStorage.getItem(profname);
    } catch (err) {
	console.warn("could not access "+profname+" in localStorage: "+err);
	return false;
    }

    breaklist = JSON.parse(breakListStr);
    if ( ! breaklist ) {
	console.warn("try_load_breaks("+profname+"): came up empty.");
	return false;
    }

    // Just a historical note: The .begin and .end used to be Date()
    // objects, and of course, JSON records the date as a string
    // instead of an object.  Therefore, there USED TO BE a loop here
    // recreating objects from strings.  However, it did not seem
    // useful to keep them as objects, and instead they're offsets in
    // seconds from the start of the show.

    return breaklist;
}

function break_cmp(obja, objb) {

    // When sorting the brk array (the break descriptions), this
    // provides the comparison function to the .sort() method.

    return obja.begin - objb.begin;
}

function reminder_cmp(obja, objb) {

    // When sorting the remind array (the reminder descriptions), this
    // provides the comparison function to the .sort() method.

    return obja.begin - objb.begin;
}

function secs2minsec(insecs) {

    // Form a minutes:seconds string from "insecs" number of seconds,
    // if possible. This is visually nicer for break lengths than full
    // hh:mm:ss.  If the hours: portion is nonzero, return it.

    var str = "";
    var hrs;

    // Centralize this conversion by calling the hms converter (JUST
    // in case the format changes or a bug is discovered).  It is
    // admittedly a little inefficient in terms of computation.

    str = secs2hmsStr(insecs);
    hrs = str.substring(0,2);
    if ( hrs === "00" ) {
	// drop the "00:"
	str = str.substring(3);
	if ( str.charAt(0) === "0" ) {
	    // drop the leading zero
	    str = str.substring(1);
	}
    }

    return str;
}

function secs2hmsStr(insecs) {

    // form an hours, minutes, seconds string (hh:mm:ss) from "insecs"
    // number of seconds.  Each portion of the results is zero padded
    // to 2 digits.

    var str = "";
    var t = insecs;
    var secs,mins,hrs;

    secs = t % 60;
    t = Math.floor(t/60);
    mins = t % 60;
    t = Math.floor(t/60);
    str += zeropad(t, 2)
    str += ":";
    str += zeropad(mins, 2)
    str += ":";
    str += zeropad(secs, 2)

    return str;
}

function hms2secs(str) {

    // Take string "str" which is in the format hours:minutes:seconds and
    // convert that to a number of seconds.  Zero, one, or two colons are
    // allowed.  Any characters other than the digits and a colon make this
    // function return false.  Also if minutes or seconds are greater than
    // 59 will cause a return of false.  A colon followed by nothing
    // assumes zero, so for example "4:" means four minutes.

    var secs = 0;
    var c, l, i;
    var coloncnt = 0;
    var val; // intermediate value while walking along the string
    var hms = new Array(); // hours, minutes, seconds as accumulated

    dbg(0, "  hms2secs(): converting "+str);

    val = 0;
    l = str.length;
    for ( i = 0; i < l; i++ ) {
	c = str.charAt(i);
	dbg(0, "    considering "+c+" at "+i+" ("+val+")");
	if ( c === ":" ) {
	    if ( ++coloncnt > 2 ) {
		dbg(1, "    too many colons, "+coloncnt);
		return false;
	    }
	    dbg(0, "      processing colon, before "+val);
	    hms.push(val);
	    val = 0;
	} else if ( c < "0" || c > "9" ) {
	    dbg(1, "    char "+c+" not in range");
	    return false;
	} else {
	    // add the next digit by shifting the <result so
	    // far> by one decimal place and add current one
	    val *= 10;
	    val += parseInt(c);
	}
    }
    hms.push(val);

    while ( ++coloncnt < 3 ) {
	hms.unshift(0);
    }

    dbg(1, "  ready with hms len "+hms.length+" and hms "+hms);
    if ( hms[0] > 23 || hms[1] > 59 || hms[2] > 59 ) {
	dbg(1, "    something was too big");
	return false;
    }

    secs = hms[0] * 3600 + hms[1] * 60 + hms[2];

    return secs;
}

function state2str(st) {
    // Given state "st", what does the const look
    // like in the source?
    // Returns "unknown" if the number is out of range.
    const state = [ "BEFORE_SHOW",
		    "BUMP_IN",
		    "ON_AIR",
		    "TIME_SHORT",
		    "TIME_VERY_SHORT",
		    "IN_BREAK",
		    "BUMP_SOON",
		    "BUMP_VERY_SOON",
		    "SHOW_DONE" ];

    if ( st < BEFORE_SHOW ||
	 st > SHOW_DONE ) {
	return "unknown";
    } else {
	return state[st];
    }
}

function st2col(st) {

    // For state "st", which member of st.color should be
    // used for coloration of the HTML node?  If the state
    // is out of range, let CSS take over by returning "".

    const statetab =
	  [ "revertCSS", //"BEFORE_SHOW"
	    "onAir",     //"BUMP_IN"
	    "onAir",     //"ON_AIR"
	    "soon",      //"TIME_SHORT"
	    "verysoon",  //"TIME_VERY_SHORT"
	    "revertCSS", //"IN_BREAK"
	    "soon",      //"BUMP_SOON"
	    "verysoon",  //"BUMP_VERY_SOON"
	    "revertCSS"  //"SHOW_DONE"
	  ];

    if ( st < BEFORE_SHOW ||
	 st > SHOW_DONE ) {
	return "revertCSS";
    } else {
	return statetab[st];
    }
}

function find_all_profiles() {

    // finds all the profiles in localStorage and inserts <option>
    // elements into the node with an ID of "profiles" (expected to be
    // a <datalist> element)

    var i, l, k;
    var seen = new Array();
    var prof;
    var optproto = document.createElement("option");
    var opt;
    var profblk;

    var brksidx, klen;

    if ( typeof profiles !== "undefined" ) {
	profblk = profiles;
    } else {
	if ( (profblk = document.getElementById("profiles")) === null ) {
	    // If one isn't in the document already, provide one.
	    // Other JavaScript could likewise use appendChild to add
	    // an input field which utilizes this list.
	    profblk = document.createElement("datalist");
	    document.body.appendChild(profblk);
	}
    }

    // empty out any existing options
    while ( (opt = profblk.firstChild) !== null ) {
	profblk.removeChild(opt);
    }

    l = localStorage.length;
    for ( i = 0; i < l; i++ ) {
	k = localStorage.key(i);
	klen = k.length;
	dbg(1, "got key "+k+" length "+klen);
	prof = k.replace(/_(break|param|reminder)s(_bak[0-9]*)?$/, "");
	if ( ! seen.includes(prof) ) {
	    dbg(1,"*** so added from key "+k+" the profile "+prof);
	    seen.push(prof);
	    opt = optproto.cloneNode(false);
	    opt.textContent = prof;
	    profblk.appendChild(opt);
	}
    }
}

<|endoftext|>


<commit_before>/*globals desc, task, taskSync, file, directory, fileSync, FileList, CLOBBER, CLEAN, write, read, log */
var Path    = require("path"),
    futil   = require("sake/file-utils"),
    files   = new FileList("**/*", "some/non-existing/file.js"),
    authorInfo
;

desc("Keep the LICENSE file up-to-date.");
taskSync("LICENSE", ["read-authors"], function (t) {
    var year = new Date().getFullYear(),
        license = read(t.name, "utf8").split("\n")
    ;

    license[0] = "Copyright (c) " + year + " " + authorInfo;

    write(t.name, license.join("\n"), "utf8");
    log(t.name + " updated");
});

taskSync("read-authors", ["AUTHORS"], function (t) {
    authorInfo = read(t.prerequisites[0], "utf8").split("\n")[0];
    log("Read author info");
});

taskSync("pre-build", function (t) {
    log("Starting build...");
});

taskSync("build", ["pre-build", "LICENSE"], function (t) {
    log("Build complete");
});

taskSync("default", ["build"]);<commit_msg>Clock the build.<commit_after>/*globals desc, task, taskSync, file, directory, fileSync, FileList, CLOBBER, CLEAN, write, read, log */
var Path    = require("path"),
    futil   = require("sake/file-utils"),
    files   = new FileList("**/*", "some/non-existing/file.js"),
    authorInfo,
    buildStart,
    buildComplete
;

desc("Keep the LICENSE file up-to-date.");
taskSync("LICENSE", ["read-authors"], function (t) {
    var year = new Date().getFullYear(),
        license = read(t.name, "utf8").split("\n")
    ;

    license[0] = "Copyright (c) " + year + " " + authorInfo;

    write(t.name, license.join("\n"), "utf8");
    log(t.name + " updated");
});

taskSync("read-authors", ["AUTHORS"], function (t) {
    authorInfo = read(t.prerequisites[0], "utf8").split("\n")[0];
    log("Read author info");
});

taskSync("pre-build", function (t) {
    buildStart = Date.now();
    log("Starting build...");
});

taskSync("build", ["pre-build", "LICENSE"], function (t) {
    var delta;

    buildComplete = Date.now();
    delta = buildComplete - buildStart;

    log("Build complete");
    log(delta + " ms");
});

taskSync("default", ["build"]);<|endoftext|>


<commit_before>/** @module deliteful/SidePane */
define([
	"dcl/dcl",
	"dpointer/events",
	"requirejs-dplugins/jquery!attributes/classes",
	"decor/sniff",
	"delite/register",
	"delite/DisplayContainer",
	"requirejs-dplugins/Promise!",
	"delite/theme!./SidePane/themes/{{theme}}/SidePane.css"
],
	function (dcl, pointer, $, has, register, DisplayContainer, Promise) {
		function prefix(v) {
			return "-d-side-pane-" + v;
		}
		function setVisibility(node, val) {
			if (val) {
				node.style.visibility = "visible";
				node.style.display = "block";
			} else {
				node.style.visibility = "hidden";
				node.style.display = "none";
			}
		}
		function getNextSibling(node) {
			do {
				node = node.nextElementSibling;
			} while (node && node.nodeType !== 1);
			return node;
		}

		/**
		 * Dispatched after SidePane is shown.
		 * @example
		 * mySidePane.on("sidepane-after-show", function (evt) {
		 *      firstField.focus();
		 * });
		 * @event module:deliteful/SidePane#sidepane-after-show
		 */

		/**
		 * A widget displayed on the side of the screen.
		 *
		 * It can be displayed on top of the page
		 * (mode=overlay) or can push the content of the page (mode=push or mode=reveal).
		 * SidePane is a widget hidden by default.
		 * This widget must be a sibling of html's body element.
		 * If mode is set to "push" or "reveal", the width of the SidePane can't be changed in the markup
		 * (15em by default).
		 * However it can be changed in SidePane.less (@PANE_WIDTH variable).
		 * In "push" and "reveal" mode, the pushed element is the first sibling of the SidePane which has
		 * of type element (nodeType == 1) and not a SidePane.
		 * @example
		 *
		 *   <d-side-pane>
		 *       SidePane content
		 *   </d-side-pane>
		 *

		 *       Main application
		 *

		 *
		 * @class module:deliteful/SidePane
		 * @augments module:delite/DisplayContainer
		 */
		return register("d-side-pane", [HTMLElement, DisplayContainer],
			/** @lends module:deliteful/SidePane#*/ {
			/**
			 * The name of the CSS class of this widget.
			 * @member {string}
			 * @default "d-side-pane"
			 */
			baseClass: "d-side-pane",

			/**
			 * Can be "overlay", "reveal" or "push".
			 * In overlay mode, the pane is shown on top of the page.
			 * In reveal and push modes, The page is moved to make the pane visible. The difference between
			 * these two modes is the animated transition: in reveal mode, the pane does not move, it is
			 * already under the page. In push mode, the pane slide with the page.
			 * @member {string}
			 * @default "push"
			 */
			mode: "push",

			/**
			 * Can be "start" or "end". If set to "start", the panel is displayed on the
			 * left side in LTR mode.
			 * @member {string}
			 * @default "push"
			 */
			position: "start",

			/**
			 * Enable/Disable animations.
			 * @member {boolean}
			 * @default true
			 */
			animate: true,

			/**
			 * Enables the swipe closing of the pane.
			 * @member {boolean}
			 * @default true
			 */
			swipeClosing: true,

			_transitionTiming: {default: 0, chrome: 50, ios: 20, android: 100, ff: 100},
			_timing: 0,
			_visible: false,
			_opening: false,
			_originX: NaN,
			_originY: NaN,

			attachedCallback: function () {
				this.parentNode.style.overflow = "hidden";
			},

			show: dcl.superCall(function (sup) {
				return function () {
					if (arguments.length > 0) {
						return sup.apply(this, arguments).then(function (value) {
							return this._open().then(function () {
								return value;
							});
						}.bind(this));
					} else {
						return this._open();
					}
				};
			}),

			hide: dcl.superCall(function (sup) {
				return function () {
					if (arguments.length > 0) {
						return sup.apply(this, arguments).then(function (value) {
							return this._close().then(function () {
								return value;
							});
						}.bind(this));
					} else {
						return this._close();
					}
				};
			}),
			/**
			 * This method is called to toggle the visibility of the SidePane.
			 * @returns {Promise} A promise that will be resolved when the display & transition effect will have been
			 * performed.
			 */
			toggle: function () {
				return this._visible ? this.hide() : this.show();
			},

			/**
			 * Open the pane.
			 * @private
			 */
			_open: function () {
				var promise;
				var nextElement = getNextSibling(this);
				var animate = this.animate && has("ie") !== 9;
				if (!this._visible) {
					if (animate) {
						$(this).addClass(prefix("animate"));
						if (nextElement) {
							$(nextElement).addClass(prefix("animate"));
						}
					}

					if (this.mode === "reveal") {
						if (nextElement) {
							promise = this._setAfterTransitionHandlers(nextElement);
						}
					} else {
						promise = this._setAfterTransitionHandlers(this);
					}

					setVisibility(this, true);

					if (animate) {
						this.defer(this._openImpl, this._timing);
					} else {
						this._openImpl();
						promise = new Promise(function (resolve) {
							this.defer(resolve, this._timing);
						}.bind(this));
					}
				}
				return (promise || Promise.resolve(true)).then(function () {
					this.emit("sidepane-after-show");
				}.bind(this));
			},

			/**
			 * Close the pane.
			 * @private
			 */
			_close: function () {
				var promise;
				if (this._visible) {
					if (this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							promise = this._setAfterTransitionHandlers(nextElement);
						}
					} else {
						promise = this._setAfterTransitionHandlers(this);
					}

					if (this.animate && has("ie") !== 9) {
						// This defer should be useless but is needed for Firefox, see #25
						this.defer(function () {this._hideImpl(); }, this._timing);
					} else {
						this._hideImpl();
						setVisibility(this, false);
					}
				}
				return promise || Promise.resolve(true);
			},

			_setAfterTransitionHandlers: function (node) {
				var self = this, holder = { node: node};
				var promise = new Promise(function (resolve) {
					holder.handle =  function () { self._afterTransitionHandle(holder, resolve); };
				});
				node.addEventListener("webkitTransitionEnd", holder.handle);
				node.addEventListener("transitionend", holder.handle); // IE10 + FF
				return promise;
			},

			_afterTransitionHandle: function (holder, resolve) {
				$(this).removeClass(prefix("under"));
				if (!this._visible) {
					setVisibility(this, false);
				}
				holder.node.removeEventListener("webkitTransitionEnd", holder.handle);
				holder.node.removeEventListener("transitionend", holder.handle);
				resolve();
			},

			postRender: function () {
				setVisibility(this, false);
			},

			preRender: function () {
				this._transitionTiming = {default: 0, chrome: 20, ios: 20, android: 100, ff: 100};
				for (var o in this._transitionTiming) {
					if (has(o) && this._timing < this._transitionTiming[o]) {
						this._timing = this._transitionTiming[o];
					}
				}
			},

			render: function () {
				pointer.setTouchAction(this, "pan-y");
				this._resetInteractions();
			},

			_refreshMode: function (nextElement) {
				$(this).removeClass([prefix("push"), prefix("overlay"), prefix("reveal")].join(" "))
					.addClass(prefix(this.mode));

				if (nextElement && this._visible) {
					$(nextElement).toggleClass(prefix("translated"), this.mode !== "overlay");
				}

				if (this.mode === "reveal" && !this._visible) {
					// Needed by FF only for the first opening.
					$(this).removeClass(prefix("ontop"))
						.addClass(prefix("under"));
				}
				else if (this.mode === "overlay") {
					$(this).removeClass(prefix("under"))
						.addClass(prefix("ontop"));
				} else {
					$(this).removeClass([prefix("under"), prefix("ontop")].join(" "));
				}
			},

			_refreshPosition: function (nextElement) {
				$(this).removeClass([prefix("start"), prefix("end")].join(" "))
					.addClass(prefix(this.position));
				if (nextElement && this._visible) {
					$(nextElement).removeClass([prefix("start"), prefix("end")].join(" "))
						.addClass(prefix(this.position));
				}
			},

			refreshRendering: function (props) {
				if (!("mode" in props || "position" in props || "animate" in props)) {
					return;
				}
				var nextElement = getNextSibling(this);

				// Always remove animation during a refresh. Avoid to see the pane moving on mode changes.
				// Not very reliable on IE11.
				$(this).removeClass(prefix("animate"));

				if (nextElement) {
					$(nextElement).removeClass(prefix("animate"));
					$(nextElement).toggleClass("d-rtl", this.effectiveDir === "rtl");
				}

				if ("mode" in props) {
					this._refreshMode(nextElement);
				}

				if ("position" in props) {
					this._refreshPosition(nextElement);
				}

				$(this).toggleClass(prefix("hidden"), !this._visible)
					.toggleClass(prefix("visible"), this._visible);

				// Re-enable animation
				if (this.animate) {
					this.defer(function () {
						$(this).addClass(prefix("animate"));
						if (nextElement) {
							$(nextElement).addClass(prefix("animate"));
						}
					}, this._timing);
				}
			},

			_openImpl: function () {
				if (!this._visible) {
					this._visible = true;
					$(this).removeClass(prefix("hidden"))
						.addClass(prefix("visible"));

					if (this.mode === "push" || this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							$(nextElement)
								.removeClass([prefix("nottranslated"), prefix("start"), prefix("end")].join(" "))
								.addClass([prefix(this.position), prefix("translated")].join(" "));
						}
					}
				}
			},

			_hideImpl: function () {
				if (this._visible) {
					this._visible = false;
					this._opening = false;
					$(this.ownerDocument.body).removeClass(prefix("no-select"));
					$(this).removeClass(prefix("visible"))
						.addClass(prefix("hidden"));
					if (this.mode === "push" || this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							$(nextElement)
								.removeClass([prefix("translated"), prefix("start"), prefix("end")].join(" "))
								.addClass([prefix(this.position), prefix("nottranslated")].join(" "));
						}
					}
				}
			},

			_isLeft: function () {
				return (this.position === "start" && this.effectiveDir === "ltr") ||
					(this.position === "end" && this.effectiveDir === "rtl");
			},

			_pointerDownHandler: function (event) {
				this._originX = event.pageX;
				this._originY = event.pageY;

				if (this._visible || (this._isLeft() && !this._visible && this._originX <= 10) ||
					(!this._isLeft() && !this._visible && this._originX >= this.ownerDocument.width - 10)) {
					this._opening = !this._visible;
					this._pressHandle.remove();
					this._moveHandle = this.on("pointermove", this._pointerMoveHandler.bind(this));
					this._releaseHandle = this.on("pointerup", this._pointerUpHandler.bind(this));

					$(this.ownerDocument.body).addClass(prefix("no-select"));
				}
			},

			_pointerMoveHandler: function (event) {
				if (!this._opening && Math.abs(event.pageY - this._originY) > 10) {
					this._resetInteractions();
				} else {
					var pos = event.pageX;

					if (this._isLeft()) {
						if (this._visible) {
							if (this._originX < pos) {
								this._originX = pos;
							}

							if ((this.swipeClosing && this._originX - pos) > 10) {
								this._close();
								this._originX = pos;
							}
						}
					} else {
						if (this._visible) {
							if (this._originX > pos) {
								this._originX = pos;
							}
							if ((this.swipeClosing && pos - this._originX) > 10) {
								this._close();
								this._originX = pos;
							}
						}
					}
				}
			},

			_pointerUpHandler: function () {
				this._opening = false;
				$(this.ownerDocument.body).removeClass(prefix("no-select"));
				this._resetInteractions();
			},

			_resetInteractions: function () {
				if (this._releaseHandle) {
					this._releaseHandle.remove();
				}
				if (this._moveHandle) {
					this._moveHandle.remove();
				}
				if (this._pressHandle) {
					this._pressHandle.remove();
				}

				if (this.swipeClosing) {
					this._pressHandle = this.on("pointerdown", this._pointerDownHandler.bind(this));
				}

				this._originX = NaN;
				this._originY = NaN;
			}
		});
	});
<commit_msg>Small refactor so that SidePane subclass can have template. Fixes #661.<commit_after>/** @module deliteful/SidePane */
define([
	"dcl/dcl",
	"dpointer/events",
	"requirejs-dplugins/jquery!attributes/classes",
	"decor/sniff",
	"delite/register",
	"delite/DisplayContainer",
	"requirejs-dplugins/Promise!",
	"delite/theme!./SidePane/themes/{{theme}}/SidePane.css"
],
	function (dcl, pointer, $, has, register, DisplayContainer, Promise) {
		function prefix(v) {
			return "-d-side-pane-" + v;
		}
		function setVisibility(node, val) {
			if (val) {
				node.style.visibility = "visible";
				node.style.display = "block";
			} else {
				node.style.visibility = "hidden";
				node.style.display = "none";
			}
		}
		function getNextSibling(node) {
			do {
				node = node.nextElementSibling;
			} while (node && node.nodeType !== 1);
			return node;
		}

		/**
		 * Dispatched after SidePane is shown.
		 * @example
		 * mySidePane.on("sidepane-after-show", function (evt) {
		 *      firstField.focus();
		 * });
		 * @event module:deliteful/SidePane#sidepane-after-show
		 */

		/**
		 * A widget displayed on the side of the screen.
		 *
		 * It can be displayed on top of the page
		 * (mode=overlay) or can push the content of the page (mode=push or mode=reveal).
		 * SidePane is a widget hidden by default.
		 * This widget must be a sibling of html's body element.
		 * If mode is set to "push" or "reveal", the width of the SidePane can't be changed in the markup
		 * (15em by default).
		 * However it can be changed in SidePane.less (@PANE_WIDTH variable).
		 * In "push" and "reveal" mode, the pushed element is the first sibling of the SidePane which has
		 * of type element (nodeType == 1) and not a SidePane.
		 * @example
		 *
		 *   <d-side-pane>
		 *       SidePane content
		 *   </d-side-pane>
		 *

		 *       Main application
		 *

		 *
		 * @class module:deliteful/SidePane
		 * @augments module:delite/DisplayContainer
		 */
		return register("d-side-pane", [HTMLElement, DisplayContainer],
			/** @lends module:deliteful/SidePane#*/ {
			/**
			 * The name of the CSS class of this widget.
			 * @member {string}
			 * @default "d-side-pane"
			 */
			baseClass: "d-side-pane",

			/**
			 * Can be "overlay", "reveal" or "push".
			 * In overlay mode, the pane is shown on top of the page.
			 * In reveal and push modes, The page is moved to make the pane visible. The difference between
			 * these two modes is the animated transition: in reveal mode, the pane does not move, it is
			 * already under the page. In push mode, the pane slide with the page.
			 * @member {string}
			 * @default "push"
			 */
			mode: "push",

			/**
			 * Can be "start" or "end". If set to "start", the panel is displayed on the
			 * left side in LTR mode.
			 * @member {string}
			 * @default "push"
			 */
			position: "start",

			/**
			 * Enable/Disable animations.
			 * @member {boolean}
			 * @default true
			 */
			animate: true,

			/**
			 * Enables the swipe closing of the pane.
			 * @member {boolean}
			 * @default true
			 */
			swipeClosing: true,

			_transitionTiming: {default: 0, chrome: 50, ios: 20, android: 100, ff: 100},
			_timing: 0,
			_visible: false,
			_opening: false,
			_originX: NaN,
			_originY: NaN,

			attachedCallback: function () {
				this.parentNode.style.overflow = "hidden";
			},

			show: dcl.superCall(function (sup) {
				return function () {
					if (arguments.length > 0) {
						return sup.apply(this, arguments).then(function (value) {
							return this._open().then(function () {
								return value;
							});
						}.bind(this));
					} else {
						return this._open();
					}
				};
			}),

			hide: dcl.superCall(function (sup) {
				return function () {
					if (arguments.length > 0) {
						return sup.apply(this, arguments).then(function (value) {
							return this._close().then(function () {
								return value;
							});
						}.bind(this));
					} else {
						return this._close();
					}
				};
			}),
			/**
			 * This method is called to toggle the visibility of the SidePane.
			 * @returns {Promise} A promise that will be resolved when the display & transition effect will have been
			 * performed.
			 */
			toggle: function () {
				return this._visible ? this.hide() : this.show();
			},

			/**
			 * Open the pane.
			 * @private
			 */
			_open: function () {
				var promise;
				var nextElement = getNextSibling(this);
				var animate = this.animate && has("ie") !== 9;
				if (!this._visible) {
					if (animate) {
						$(this).addClass(prefix("animate"));
						if (nextElement) {
							$(nextElement).addClass(prefix("animate"));
						}
					}

					if (this.mode === "reveal") {
						if (nextElement) {
							promise = this._setAfterTransitionHandlers(nextElement);
						}
					} else {
						promise = this._setAfterTransitionHandlers(this);
					}

					setVisibility(this, true);

					if (animate) {
						this.defer(this._openImpl, this._timing);
					} else {
						this._openImpl();
						promise = new Promise(function (resolve) {
							this.defer(resolve, this._timing);
						}.bind(this));
					}
				}
				return (promise || Promise.resolve(true)).then(function () {
					this.emit("sidepane-after-show");
				}.bind(this));
			},

			/**
			 * Close the pane.
			 * @private
			 */
			_close: function () {
				var promise;
				if (this._visible) {
					if (this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							promise = this._setAfterTransitionHandlers(nextElement);
						}
					} else {
						promise = this._setAfterTransitionHandlers(this);
					}

					if (this.animate && has("ie") !== 9) {
						// This defer should be useless but is needed for Firefox, see #25
						this.defer(function () {this._hideImpl(); }, this._timing);
					} else {
						this._hideImpl();
						setVisibility(this, false);
					}
				}
				return promise || Promise.resolve(true);
			},

			_setAfterTransitionHandlers: function (node) {
				var self = this, holder = { node: node};
				var promise = new Promise(function (resolve) {
					holder.handle =  function () { self._afterTransitionHandle(holder, resolve); };
				});
				node.addEventListener("webkitTransitionEnd", holder.handle);
				node.addEventListener("transitionend", holder.handle); // IE10 + FF
				return promise;
			},

			_afterTransitionHandle: function (holder, resolve) {
				$(this).removeClass(prefix("under"));
				if (!this._visible) {
					setVisibility(this, false);
				}
				holder.node.removeEventListener("webkitTransitionEnd", holder.handle);
				holder.node.removeEventListener("transitionend", holder.handle);
				resolve();
			},

			preRender: function () {
				this._transitionTiming = {default: 0, chrome: 20, ios: 20, android: 100, ff: 100};
				for (var o in this._transitionTiming) {
					if (has(o) && this._timing < this._transitionTiming[o]) {
						this._timing = this._transitionTiming[o];
					}
				}
			},

			postRender: function () {
				pointer.setTouchAction(this, "pan-y");
				this._resetInteractions();
				setVisibility(this, false);
			},

			_refreshMode: function (nextElement) {
				$(this).removeClass([prefix("push"), prefix("overlay"), prefix("reveal")].join(" "))
					.addClass(prefix(this.mode));

				if (nextElement && this._visible) {
					$(nextElement).toggleClass(prefix("translated"), this.mode !== "overlay");
				}

				if (this.mode === "reveal" && !this._visible) {
					// Needed by FF only for the first opening.
					$(this).removeClass(prefix("ontop"))
						.addClass(prefix("under"));
				}
				else if (this.mode === "overlay") {
					$(this).removeClass(prefix("under"))
						.addClass(prefix("ontop"));
				} else {
					$(this).removeClass([prefix("under"), prefix("ontop")].join(" "));
				}
			},

			_refreshPosition: function (nextElement) {
				$(this).removeClass([prefix("start"), prefix("end")].join(" "))
					.addClass(prefix(this.position));
				if (nextElement && this._visible) {
					$(nextElement).removeClass([prefix("start"), prefix("end")].join(" "))
						.addClass(prefix(this.position));
				}
			},

			refreshRendering: function (props) {
				if (!("mode" in props || "position" in props || "animate" in props)) {
					return;
				}
				var nextElement = getNextSibling(this);

				// Always remove animation during a refresh. Avoid to see the pane moving on mode changes.
				// Not very reliable on IE11.
				$(this).removeClass(prefix("animate"));

				if (nextElement) {
					$(nextElement).removeClass(prefix("animate"));
					$(nextElement).toggleClass("d-rtl", this.effectiveDir === "rtl");
				}

				if ("mode" in props) {
					this._refreshMode(nextElement);
				}

				if ("position" in props) {
					this._refreshPosition(nextElement);
				}

				$(this).toggleClass(prefix("hidden"), !this._visible)
					.toggleClass(prefix("visible"), this._visible);

				// Re-enable animation
				if (this.animate) {
					this.defer(function () {
						$(this).addClass(prefix("animate"));
						if (nextElement) {
							$(nextElement).addClass(prefix("animate"));
						}
					}, this._timing);
				}
			},

			_openImpl: function () {
				if (!this._visible) {
					this._visible = true;
					$(this).removeClass(prefix("hidden"))
						.addClass(prefix("visible"));

					if (this.mode === "push" || this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							$(nextElement)
								.removeClass([prefix("nottranslated"), prefix("start"), prefix("end")].join(" "))
								.addClass([prefix(this.position), prefix("translated")].join(" "));
						}
					}
				}
			},

			_hideImpl: function () {
				if (this._visible) {
					this._visible = false;
					this._opening = false;
					$(this.ownerDocument.body).removeClass(prefix("no-select"));
					$(this).removeClass(prefix("visible"))
						.addClass(prefix("hidden"));
					if (this.mode === "push" || this.mode === "reveal") {
						var nextElement = getNextSibling(this);
						if (nextElement) {
							$(nextElement)
								.removeClass([prefix("translated"), prefix("start"), prefix("end")].join(" "))
								.addClass([prefix(this.position), prefix("nottranslated")].join(" "));
						}
					}
				}
			},

			_isLeft: function () {
				return (this.position === "start" && this.effectiveDir === "ltr") ||
					(this.position === "end" && this.effectiveDir === "rtl");
			},

			_pointerDownHandler: function (event) {
				this._originX = event.pageX;
				this._originY = event.pageY;

				if (this._visible || (this._isLeft() && !this._visible && this._originX <= 10) ||
					(!this._isLeft() && !this._visible && this._originX >= this.ownerDocument.width - 10)) {
					this._opening = !this._visible;
					this._pressHandle.remove();
					this._moveHandle = this.on("pointermove", this._pointerMoveHandler.bind(this));
					this._releaseHandle = this.on("pointerup", this._pointerUpHandler.bind(this));

					$(this.ownerDocument.body).addClass(prefix("no-select"));
				}
			},

			_pointerMoveHandler: function (event) {
				if (!this._opening && Math.abs(event.pageY - this._originY) > 10) {
					this._resetInteractions();
				} else {
					var pos = event.pageX;

					if (this._isLeft()) {
						if (this._visible) {
							if (this._originX < pos) {
								this._originX = pos;
							}

							if ((this.swipeClosing && this._originX - pos) > 10) {
								this._close();
								this._originX = pos;
							}
						}
					} else {
						if (this._visible) {
							if (this._originX > pos) {
								this._originX = pos;
							}
							if ((this.swipeClosing && pos - this._originX) > 10) {
								this._close();
								this._originX = pos;
							}
						}
					}
				}
			},

			_pointerUpHandler: function () {
				this._opening = false;
				$(this.ownerDocument.body).removeClass(prefix("no-select"));
				this._resetInteractions();
			},

			_resetInteractions: function () {
				if (this._releaseHandle) {
					this._releaseHandle.remove();
				}
				if (this._moveHandle) {
					this._moveHandle.remove();
				}
				if (this._pressHandle) {
					this._pressHandle.remove();
				}

				if (this.swipeClosing) {
					this._pressHandle = this.on("pointerdown", this._pointerDownHandler.bind(this));
				}

				this._originX = NaN;
				this._originY = NaN;
			}
		});
	});
<|endoftext|>