diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index df1a59a51..000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,185 +0,0 @@ -module.exports = function (grunt) { - 'use strict'; - - var outputRoot = '_output/'; - var outputDir = outputRoot +'UI/'; - var srcRoot = 'src/UI/'; - var srcContent = srcRoot + 'Content/'; - var destContent = outputDir + 'Content/'; - - grunt.initConfig({ - - pkg: grunt.file.readJSON('package.json'), - - clean: { - output: outputDir, - scripts: [ outputDir + '/**.js','!_output/UI/**/templates.js'] - }, - - less : { - - options:{ - dumpLineNumbers : 'false', - compress : true, - yuicompress : false, - ieCompat : true, - strictImports : true - }, - - bootstrap: { - src : srcContent + 'bootstrap.less', - dest: destContent + 'bootstrap.css' - }, - general : { - cwd : srcRoot, - expand : true, - src :[ - 'Content/theme.less', - 'Content/overrides.less', - 'Series/series.less', - 'History/history.less', - 'AddSeries/addSeries.less', - 'Calendar/calendar.less', - 'Cells/cells.less', - 'Settings/settings.less', - 'System/Logs/logs.less', - 'System/Update/update.less' - ], - dest : outputDir, - ext: '.css' - } - }, - - handlebars: { - options: { - namespace : 'T', - partialRegex: /Partial.hbs/, - wrapped : true, - amd : true, - processName: function (fileName) { - return fileName - .replace(srcRoot, '') - .replace('.hbs', '') - .toLowerCase(); - } - }, - files : { - src : [ srcRoot + '**/*Template.hbs', srcRoot + '**/*Partial.hbs'], - dest: outputDir + 'templates.js' - } - }, - - copy: { - content: { - cwd : srcRoot, - expand: true, - src : [ - 'index.html', - '**/*.css', - '**/*.png', - '**/*.jpg', - '**/*.ico', - '**/*.swf', - '**/FontAwesome/*.*', - '**/fonts/*.*' - ], - dest : outputDir - }, - scripts: { - cwd : srcRoot, - expand: true, - src : [ - '**/*.js' - ], - dest : outputDir - } - }, - - jshint: { - options: { - '-W030': false, - '-W064': false, - '-W097': false, - '-W100': false, - 'undef': true, - 'globals': { - 'require': true, - 'define': true, - 'window': true, - 'document': true, - 'console': true - } - }, - all: [ - srcRoot + '**/*.js', - '!**/JsLibraries/*.js' - ] - }, - - requirejs: { - compile:{ - options: { - mainConfigFile: 'src/UI/app.js', - fileExclusionRegExp: /^.*\.(?!js$)[^.]+$/, - preserveLicenseComments: false, - dir: outputDir, - optimize: 'none', - removeCombined: true, - inlineText: false, - keepBuildDir : true, - modules: [{ - name: 'app', - exclude: ['templates.js'] - }] - } - } - }, - - watch: { - options: { - nospawn: false - }, - bootstrap : { - files: [ srcContent + 'Bootstrap/**', srcContent + 'FontAwesome/**', srcContent + 'bootstrap.less'], - tasks: ['less:bootstrap','less:general'] - }, - generalLess: { - files: [ srcRoot + '**/*.less', '!**/Bootstrap/**', '!**/FontAwesome/**', '!' + srcContent + '/bootstrap.less'], - tasks: ['less:general'] - }, - handlebars : { - files: '<%= handlebars.files.src %>', - tasks: ['handlebars'] - }, - content : { - files: [ - srcRoot + '**/index.html', - srcRoot + '**/*.css', - srcRoot + '**/*.png', - srcRoot + '**/*.jpg', - srcRoot + '**/*.ico', - srcRoot + '**/FontAwesome/*.*', - srcRoot + '**/fonts/*.*' - ], - tasks: ['copy:content'] - }, - scripts: { - files: '<%= copy.scripts.cwd %><%= copy.scripts.src %>', - tasks: ['copy:scripts'] - } - } - }); - - grunt.loadNpmTasks('grunt-contrib-handlebars'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-notify'); - grunt.loadNpmTasks('grunt-contrib-requirejs'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - - grunt.registerTask('package', ['clean:output', 'jshint', 'handlebars', 'copy', 'less']); - grunt.registerTask('packagerjs', ['clean:output','jshint', 'handlebars', 'requirejs', 'copy:content', 'less']); - grunt.registerTask('default', ['package', 'watch']); -}; diff --git a/build.ps1 b/build.ps1 index 316fc60e8..ffd2e343e 100644 --- a/build.ps1 +++ b/build.ps1 @@ -191,17 +191,17 @@ Function PackageTests() Function RunGrunt() { - Write-Host "##teamcity[progressStart 'Running Grunt']" - $gruntPath = [environment]::getfolderpath("applicationdata") + '\npm\node_modules\grunt-cli\bin\grunt' + Write-Host "##teamcity[progressStart 'Running Gulp']" + $gulpPath = '.\node_modules\gulp\bin\gulp' Invoke-Expression 'npm install' CheckExitCode - Invoke-Expression ('node ' + $gruntPath + ' packagerjs') -ErrorAction Continue -Verbose + Invoke-Expression ('node ' + $gulpPath + ' build') -ErrorAction Continue -Verbose CheckExitCode Remove-Item $outputFolder\UI\build.txt -ErrorAction Continue - Write-Host "##teamcity[progressFinish 'Running Grunt']" + Write-Host "##teamcity[progressFinish 'Running Gulp']" } Function CheckExitCode() diff --git a/gulp/build.js b/gulp/build.js new file mode 100644 index 000000000..aa519f453 --- /dev/null +++ b/gulp/build.js @@ -0,0 +1,13 @@ +var gulp = require('gulp'); +var runSequence = require('run-sequence'); + +require('./clean'); +require('./requirejs'); +require('./less'); +require('./handlebars'); +require('./copy'); + +gulp.task('build', function () { + return runSequence('clean', + ['requireJs', 'less', 'handlebars', 'copyIndex', 'copyContent']); +}); \ No newline at end of file diff --git a/gulp/clean.js b/gulp/clean.js new file mode 100644 index 000000000..7d68e0faa --- /dev/null +++ b/gulp/clean.js @@ -0,0 +1,9 @@ +var gulp = require('gulp'); +var clean = require('gulp-clean'); + +var paths = require('./paths'); + +gulp.task('clean', function () { + return gulp.src(paths.dest.root, {read: false}) + .pipe(clean()); +}); diff --git a/gulp/copy.js b/gulp/copy.js new file mode 100644 index 000000000..120bc5529 --- /dev/null +++ b/gulp/copy.js @@ -0,0 +1,22 @@ +var gulp = require('gulp'); +var print = require('gulp-print'); +var cache = require('gulp-cached'); + +var paths = require('./paths.js'); + +gulp.task('copyJs', function () { + return gulp.src([paths.src.scripts]) + .pipe(cache()) + .pipe(gulp.dest(paths.dest.root)); +}); + +gulp.task('copyIndex', function () { + return gulp.src(paths.src.index) + .pipe(cache()) + .pipe(gulp.dest(paths.dest.root)); +}); + +gulp.task('copyContent', function () { + return gulp.src([paths.src.content + '**/*.*', '!**/*.less']) + .pipe(gulp.dest(paths.dest.content)); +}); \ No newline at end of file diff --git a/gulp/gulpFile.js b/gulp/gulpFile.js new file mode 100644 index 000000000..05279f7ca --- /dev/null +++ b/gulp/gulpFile.js @@ -0,0 +1,11 @@ +require('./watch.js'); +require('./build.js'); +require('./clean.js'); +require('./requirejs.js'); +require('./jshint.js'); +require('./handlebars.js'); +require('./copy.js'); +require('./less.js'); +require('./stripBom.js'); + + diff --git a/gulp/handlebars.js b/gulp/handlebars.js new file mode 100644 index 000000000..4534d52cf --- /dev/null +++ b/gulp/handlebars.js @@ -0,0 +1,57 @@ +var gulp = require('gulp'); +var handlebars = require('gulp-handlebars'); +var declare = require('gulp-declare'); +var concat = require('gulp-concat'); +var wrapAmd = require('gulp-wrap-amd'); +var wrap = require("gulp-wrap"); +var path = require('path'); +var streamqueue = require('streamqueue'); + +var paths = require('./paths.js'); +var bom = require('./pipelines/gulp-bom.js'); + +gulp.task('handlebars', function () { + + var coreStream = gulp.src([paths.src.templates, '!*/**/*Partial.*']) + .pipe(bom()) + .pipe(handlebars()) + .pipe(declare({ + namespace: 'T', + noRedeclare: true, + processName: function (filePath) { + + filePath = path.relative(paths.src.root, filePath); + + return filePath.replace(/\\/g, '/') + .toLocaleLowerCase() + .replace('template', '') + .replace('.js', ''); + } + })); + + var partialStream = gulp.src([paths.src.partials]) + .pipe(bom()) + .pipe(handlebars()) + .pipe(wrap('Handlebars.template(<%= contents %>)')) + .pipe(wrap('Handlebars.registerPartial(<%= processPartialName(file.relative) %>, <%= contents %>)', {}, { + imports: { + processPartialName: function (fileName) { + return JSON.stringify( + path.basename(fileName, '.js') + ); + } + } + })); + + + return streamqueue({ objectMode: true }, + partialStream, + coreStream + ).pipe(concat('templates.js')) + .pipe(wrapAmd({ + deps: ['handlebars'], + params: ['Handlebars'], + exports: 'this["T"]' + })) + .pipe(gulp.dest(paths.dest.root)); +}); diff --git a/gulp/jshint.js b/gulp/jshint.js new file mode 100644 index 000000000..16e5c8ee7 --- /dev/null +++ b/gulp/jshint.js @@ -0,0 +1,26 @@ +var gulp = require('gulp'); +var jshint = require('gulp-jshint'); +var stylish = require('jshint-stylish'); +var cache = require('gulp-cached'); +var paths = require('./paths.js'); + + +gulp.task('jshint', function () { + return gulp.src([paths.src.scripts, paths.src.exclude.libs]) + .pipe(cache()) + .pipe(jshint({ + '-W030': false, + '-W064': false, + '-W097': false, + '-W100': false, + 'undef': true, + 'globals': { + 'require': true, + 'define': true, + 'window': true, + 'document': true, + 'console': true + } + })) + .pipe(jshint.reporter(stylish)); +}); \ No newline at end of file diff --git a/gulp/less.js b/gulp/less.js new file mode 100644 index 000000000..b6088008a --- /dev/null +++ b/gulp/less.js @@ -0,0 +1,30 @@ +var gulp = require('gulp'); +var less = require('gulp-less'); +var print = require('gulp-print'); + +var paths = require('./paths'); + +gulp.task('less', function () { + return gulp.src([ + paths.src.content + 'bootstrap.less', + paths.src.content + 'theme.less', + paths.src.content + 'overrides.less', + paths.src.root + 'Series/series.less', + paths.src.root + 'History/history.less', + paths.src.root + 'AddSeries/addSeries.less', + paths.src.root + 'Calendar/calendar.less', + paths.src.root + 'Cells/cells.less', + paths.src.root + 'Settings/settings.less', + paths.src.root + 'System/Logs/logs.less', + paths.src.root + 'System/Update/update.less', + ]) + .pipe(print()) + .pipe(less({ + dumpLineNumbers: 'false', + compress: true, + yuicompress: true, + ieCompat: true, + strictImports: true + })) + .pipe(gulp.dest(paths.dest.content)); +}); \ No newline at end of file diff --git a/gulp/paths.js b/gulp/paths.js new file mode 100644 index 000000000..52a8e6c8d --- /dev/null +++ b/gulp/paths.js @@ -0,0 +1,26 @@ +module.exports = { + js: [ + './app/**/*.js', + './src/**/*.js', + '!./**/libs/**', + '!./**/vendor/**', + '!./**/templates.js' + ], + + src: { + root: './src/UI/', + templates: './src/UI/**/*.hbs', + index: './src/UI/index.html', + partials: './src/UI/**/*Partial.hbs', + scripts: './src/UI/**/*.js', + less: ['./src/UI/**/*.less'], + content: './src/UI/Content/', + exclude :{ + libs:'!./src/UI/JsLibraries/**' + } + }, + dest: { + root: './_output/UI/', + content: './_output/UI/Content/' + } +}; \ No newline at end of file diff --git a/gulp/pipelines/gulp-bom.js b/gulp/pipelines/gulp-bom.js new file mode 100644 index 000000000..af6136443 --- /dev/null +++ b/gulp/pipelines/gulp-bom.js @@ -0,0 +1,4 @@ +var replace = require('gulp-replace'); +module.exports = function() { + return replace(/^\uFEFF/, ''); +}; \ No newline at end of file diff --git a/gulp/requirejs.js b/gulp/requirejs.js new file mode 100644 index 000000000..75ffd227e --- /dev/null +++ b/gulp/requirejs.js @@ -0,0 +1,32 @@ +var gulp = require('gulp'); +var requirejs = require('requirejs'); +var paths = require('./paths'); + +require('./handlebars.js'); +require('./jshint.js'); + + +gulp.task('requireJs', ['jshint'], function (cb) { + + var config = { + mainConfigFile: 'src/UI/app.js', + fileExclusionRegExp: /^.*\.(?!js$)[^.]+$/, + preserveLicenseComments: false, + dir: paths.dest.root, + optimize: 'none', + removeCombined: true, + inlineText: false, + keepBuildDir: true, + modules: [ + { + name: 'app', + exclude: ['templates.js'] + } + ]}; + + requirejs.optimize(config, function (buildResponse) { + console.log(buildResponse); + cb(); + }); + +}); diff --git a/gulp/stripBom.js b/gulp/stripBom.js new file mode 100644 index 000000000..b2ca39f2c --- /dev/null +++ b/gulp/stripBom.js @@ -0,0 +1,25 @@ +var gulp = require('gulp'); +var paths = require('./paths.js'); +var bom = require('./pipelines/gulp-bom.js'); +var gulpPrint = require('gulp-print'); + + +var stripBom = function (dest) { + gulp.src([paths.src.root, paths.src.exclude.libs]) + .pipe(bom()) + .pipe(gulpPrint(function (filepath) { + return "booming: " + filepath; + })) + .pipe(gulp.dest(dest)); + + gulp.src(paths.src.templates) + .pipe(bom()) + .pipe(gulpPrint(function (filepath) { + return "booming: " + filepath; + })) + .pipe(gulp.dest(dest)); +}; + +gulp.task('stripBom', function () { + stripBom(paths.src.root); +}); diff --git a/gulp/watch.js b/gulp/watch.js new file mode 100644 index 000000000..809c84936 --- /dev/null +++ b/gulp/watch.js @@ -0,0 +1,30 @@ +var gulp = require('gulp'); +//var livereload = require('gulp-livereload'); + + +var paths = require('./paths.js'); + +require('./jshint.js'); +require('./handlebars.js'); +require('./less.js'); +require('./copy.js'); + + +gulp.task('watch', ['jshint', 'handlebars', 'less', 'copyJs'], function () { + gulp.watch([paths.src.scripts, paths.src.exclude.libs], ['jshint', 'copyJs']); + gulp.watch(paths.src.templates, ['handlebars']); + gulp.watch([paths.src.less, paths.src.exclude.libs], ['less']); + gulp.watch([paths.src.index], ['copyIndex']); + gulp.watch([paths.src.content + '**/*.*', '!**/*.less'], ['copyContent']); +}); + +gulp.task('liveReload', ['jshint', 'handlebars', 'less', 'copyJs'], function () { + var server = livereload(); + gulp.watch([ + 'app/**/*.js', + 'app/**/*.css', + 'app/index.html' + ]).on('change', function (file) { + server.changed(file.path); + }); +}); \ No newline at end of file diff --git a/gulpFile.js b/gulpFile.js new file mode 100644 index 000000000..0a9c8c19f --- /dev/null +++ b/gulpFile.js @@ -0,0 +1 @@ +require('./gulp/gulpfile.js'); diff --git a/package.json b/package.json index 03f1da66d..150d04b90 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "NZBDrone", "main": "index.js", "scripts": { - "preinstall": "npm install grunt-cli -g" + "preinstall": "" }, "repository": { "type": "git", @@ -15,14 +15,22 @@ "gitHead": "9ff7aa1bf7fe38c4c5bdb92f56c8ad556916ed67", "readmeFilename": "readme.md", "dependencies": { - "grunt": "*", - "grunt-contrib-handlebars": "*", - "grunt-contrib-watch": "*", - "grunt-contrib-less": "0.8.3", - "grunt-contrib-copy": "*", - "grunt-notify": "*", - "grunt-contrib-clean": "*", - "grunt-contrib-requirejs": "*", - "grunt-contrib-jshint": "*" + "gulp": "^3.8.7", + "gulp-handlebars": "^2.2.0", + "gulp-declare": "^0.3.0", + "gulp-clean": "^0.3.1", + "gulp-concat": "^2.3.4", + "gulp-wrap-amd": "^0.3.1", + "gulp-wrap": "^0.3.0", + "streamqueue": "^0.1.1", + "gulp-replace": "^0.4.0", + "fs-extra": "^0.11.0", + "gulp-print": "^1.1.0", + "gulp-less": "^1.3.5", + "gulp-jshint": "^1.8.4", + "gulp-cached": "^1.0.1", + "jshint-stylish": "^0.4.0", + "requirejs": "^2.1.14", + "run-sequence": "^0.3.6" } } diff --git a/src/UI/Content/Overrides/bootstrap.toggle-switch.less b/src/UI/Content/Overrides/bootstrap.toggle-switch.less index 762656bb8..50c57065b 100644 --- a/src/UI/Content/Overrides/bootstrap.toggle-switch.less +++ b/src/UI/Content/Overrides/bootstrap.toggle-switch.less @@ -1,5 +1,5 @@ -@import "Bootstrap/variables"; -@import "Bootstrap/mixins"; +@import "../Bootstrap/variables"; +@import "../Bootstrap/mixins"; .toggle { height: 34px; diff --git a/src/UI/Handlebars/backbone.marionette.templates.js b/src/UI/Handlebars/backbone.marionette.templates.js index 69d72c4ed..825474da0 100644 --- a/src/UI/Handlebars/backbone.marionette.templates.js +++ b/src/UI/Handlebars/backbone.marionette.templates.js @@ -2,6 +2,7 @@ define( [ 'templates', + 'handlebars', 'handlebars.helpers', 'Handlebars/Helpers/DateTime', 'Handlebars/Helpers/Html', @@ -13,11 +14,10 @@ define( 'Handlebars/Helpers/EachReverse', 'Handlebars/Helpers/String', 'Handlebars/Handlebars.Debug' - ], function (Templates) { + ], function (Templates, Handlebars) { return function () { this.get = function (templateId) { - - var templateKey = templateId.toLowerCase(); + var templateKey = templateId.toLowerCase().replace('template', ''); var templateFunction = Templates[templateKey]; @@ -28,7 +28,8 @@ define( return function (data) { try { - return templateFunction(data); + var wrappedTemplate = Handlebars.template.call(Handlebars, templateFunction); + return wrappedTemplate(data); } catch (error) { console.error('template render failed for ' + templateKey + ' ' + error); diff --git a/src/UI/JsLibraries/handlebars.runtime.js b/src/UI/JsLibraries/handlebars.runtime.js index fac2cc5a4..708c42fe2 100644 --- a/src/UI/JsLibraries/handlebars.runtime.js +++ b/src/UI/JsLibraries/handlebars.runtime.js @@ -1,374 +1,530 @@ -/* +/*! -Copyright (C) 2011 by Yehuda Katz + handlebars v1.3.0 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + Copyright (C) 2011 by Yehuda Katz -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. -@license -*/ + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. -// lib/handlebars/browser-prefix.js -(function(undefined) { - var Handlebars = {}; -; -// lib/handlebars/base.js - -Handlebars.VERSION = "1.0.0"; -Handlebars.COMPILER_REVISION = 4; - -Handlebars.REVISION_CHANGES = { - 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it - 2: '== 1.0.0-rc.3', - 3: '== 1.0.0-rc.4', - 4: '>= 1.0.0' -}; - -Handlebars.helpers = {}; -Handlebars.partials = {}; - -var toString = Object.prototype.toString, - functionType = '[object Function]', - objectType = '[object Object]'; - -Handlebars.registerHelper = function(name, fn, inverse) { - if (toString.call(name) === objectType) { - if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); } - Handlebars.Utils.extend(this.helpers, name); - } else { - if (inverse) { fn.not = inverse; } - this.helpers[name] = fn; - } -}; - -Handlebars.registerPartial = function(name, str) { - if (toString.call(name) === objectType) { - Handlebars.Utils.extend(this.partials, name); - } else { - this.partials[name] = str; - } -}; - -Handlebars.registerHelper('helperMissing', function(arg) { - if(arguments.length === 2) { - return undefined; - } else { - throw new Error("Missing helper: '" + arg + "'"); - } -}); - -Handlebars.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse || function() {}, fn = options.fn; - - var type = toString.call(context); - - if(type === functionType) { context = context.call(this); } - - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if(type === "[object Array]") { - if(context.length > 0) { - return Handlebars.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - return fn(context); - } -}); - -Handlebars.K = function() {}; - -Handlebars.createFrame = Object.create || function(object) { - Handlebars.K.prototype = object; - var obj = new Handlebars.K(); - Handlebars.K.prototype = null; - return obj; -}; - -Handlebars.logger = { - DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3, - - methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'}, - - // can be overridden in the host environment - log: function(level, obj) { - if (Handlebars.logger.level <= level) { - var method = Handlebars.logger.methodMap[level]; - if (typeof console !== 'undefined' && console[method]) { - console[method].call(console, obj); - } - } - } -}; - -Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); }; - -Handlebars.registerHelper('each', function(context, options) { - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; - - var type = toString.call(context); - if(type === functionType) { context = context.call(this); } - - if (options.data) { - data = Handlebars.createFrame(options.data); - } - - if(context && typeof context === 'object') { - if(context instanceof Array){ - for(var j = context.length; i": ">", + '"': """, + "'": "'", + "`": "`" + }; -Handlebars.registerHelper('unless', function(conditional, options) { - return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn}); -}); + var badChars = /[&<>"'`]/g; + var possible = /[&<>"'`]/; -Handlebars.registerHelper('with', function(context, options) { - var type = toString.call(context); - if(type === functionType) { context = context.call(this); } - - if (!Handlebars.Utils.isEmpty(context)) return options.fn(context); -}); - -Handlebars.registerHelper('log', function(context, options) { - var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1; - Handlebars.log(level, context); -}); -; -// lib/handlebars/utils.js - -var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - -Handlebars.Exception = function(message) { - var tmp = Error.prototype.constructor.apply(this, arguments); - - // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. - for (var idx = 0; idx < errorProps.length; idx++) { - this[errorProps[idx]] = tmp[errorProps[idx]]; - } -}; -Handlebars.Exception.prototype = new Error(); - -// Build out our basic SafeString type -Handlebars.SafeString = function(string) { - this.string = string; -}; -Handlebars.SafeString.prototype.toString = function() { - return this.string.toString(); -}; - -var escape = { - "&": "&", - "<": "<", - ">": ">", - '"': """, - "'": "'", - "`": "`" -}; - -var badChars = /[&<>"'`]/g; -var possible = /[&<>"'`]/; - -var escapeChar = function(chr) { - return escape[chr] || "&"; -}; - -Handlebars.Utils = { - extend: function(obj, value) { - for(var key in value) { - if(value.hasOwnProperty(key)) { - obj[key] = value[key]; - } - } - }, - - escapeExpression: function(string) { - // don't escape SafeStrings, since they're already safe - if (string instanceof Handlebars.SafeString) { - return string.toString(); - } else if (string == null || string === false) { - return ""; - } - - // Force a string conversion as this will be done by the append regardless and - // the regex test will do this transparently behind the scenes, causing issues if - // an object's to string has escaped characters in it. - string = string.toString(); - - if(!possible.test(string)) { return string; } - return string.replace(badChars, escapeChar); - }, - - isEmpty: function(value) { - if (!value && value !== 0) { - return true; - } else if(toString.call(value) === "[object Array]" && value.length === 0) { - return true; - } else { - return false; - } - } -}; -; -// lib/handlebars/runtime.js - -Handlebars.VM = { - template: function(templateSpec) { - // Just add water - var container = { - escapeExpression: Handlebars.Utils.escapeExpression, - invokePartial: Handlebars.VM.invokePartial, - programs: [], - program: function(i, fn, data) { - var programWrapper = this.programs[i]; - if(data) { - programWrapper = Handlebars.VM.program(i, fn, data); - } else if (!programWrapper) { - programWrapper = this.programs[i] = Handlebars.VM.program(i, fn); + function escapeChar(chr) { + return escape[chr] || "&"; } - return programWrapper; - }, - merge: function(param, common) { - var ret = param || common; - if (param && common) { - ret = {}; - Handlebars.Utils.extend(ret, common); - Handlebars.Utils.extend(ret, param); + function extend(obj, value) { + for(var key in value) { + if(Object.prototype.hasOwnProperty.call(value, key)) { + obj[key] = value[key]; + } + } } - return ret; - }, - programWithDepth: Handlebars.VM.programWithDepth, - noop: Handlebars.VM.noop, - compilerInfo: null - }; - return function(context, options) { - options = options || {}; - var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data); - - var compilerInfo = container.compilerInfo || [], - compilerRevision = compilerInfo[0] || 1, - currentRevision = Handlebars.COMPILER_REVISION; - - if (compilerRevision !== currentRevision) { - if (compilerRevision < currentRevision) { - var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision], - compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision]; - throw "Template was precompiled with an older version of Handlebars than the current runtime. "+ - "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."; - } else { - // Use the embedded version info since the runtime doesn't know about this revision yet - throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+ - "Please update your runtime to a newer version ("+compilerInfo[1]+")."; + __exports__.extend = extend;var toString = Object.prototype.toString; + __exports__.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + var isFunction = function(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + if (isFunction(/x/)) { + isFunction = function(value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; } - } + var isFunction; + __exports__.isFunction = isFunction; + var isArray = Array.isArray || function(value) { + return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; + }; + __exports__.isArray = isArray; - return result; - }; - }, + function escapeExpression(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof SafeString) { + return string.toString(); + } else if (!string && string !== 0) { + return ""; + } - programWithDepth: function(i, fn, data /*, $depth */) { - var args = Array.prototype.slice.call(arguments, 3); + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = "" + string; - var program = function(context, options) { - options = options || {}; + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + } - return fn.apply(this, [context, options.data || data].concat(args)); - }; - program.program = i; - program.depth = args.length; - return program; - }, - program: function(i, fn, data) { - var program = function(context, options) { - options = options || {}; + __exports__.escapeExpression = escapeExpression;function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } - return fn(context, options.data || data); - }; - program.program = i; - program.depth = 0; - return program; - }, - noop: function() { return ""; }, - invokePartial: function(partial, name, context, helpers, partials, data) { - var options = { helpers: helpers, partials: partials, data: data }; + __exports__.isEmpty = isEmpty; + return __exports__; + })(__module3__); - if(partial === undefined) { - throw new Handlebars.Exception("The partial " + name + " could not be found"); - } else if(partial instanceof Function) { - return partial(context, options); - } else if (!Handlebars.compile) { - throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); - } else { - partials[name] = Handlebars.compile(partial, {data: data !== undefined}); - return partials[name](context, options); - } - } -}; +// handlebars/exception.js + var __module4__ = (function() { + "use strict"; + var __exports__; -Handlebars.template = Handlebars.VM.template; -; -// lib/handlebars/browser-suffix.js - if (typeof module === 'object' && module.exports) { - // CommonJS - module.exports = Handlebars; + var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - } else if (typeof define === "function" && define.amd) { - // AMD modules - define(function() { return Handlebars; }); + function Exception(message, node) { + var line; + if (node && node.firstLine) { + line = node.firstLine; - } else { - // other, i.e. browser - this.Handlebars = Handlebars; - } -}).call(this); -; + message += ' - ' + line + ':' + node.firstColumn; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + if (line) { + this.lineNumber = line; + this.column = node.firstColumn; + } + } + + Exception.prototype = new Error(); + + __exports__ = Exception; + return __exports__; + })(); + +// handlebars/base.js + var __module1__ = (function(__dependency1__, __dependency2__) { + "use strict"; + var __exports__ = {}; + var Utils = __dependency1__; + var Exception = __dependency2__; + + var VERSION = "1.3.0"; + __exports__.VERSION = VERSION;var COMPILER_REVISION = 4; + __exports__.COMPILER_REVISION = COMPILER_REVISION; + var REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '== 1.0.0-rc.3', + 3: '== 1.0.0-rc.4', + 4: '>= 1.0.0' + }; + __exports__.REVISION_CHANGES = REVISION_CHANGES; + var isArray = Utils.isArray, + isFunction = Utils.isFunction, + toString = Utils.toString, + objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials) { + this.helpers = helpers || {}; + this.partials = partials || {}; + + registerDefaultHelpers(this); + } + + __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: logger, + log: log, + + registerHelper: function(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } + }, + + registerPartial: function(name, str) { + if (toString.call(name) === objectType) { + Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } + } + }; + + function registerDefaultHelpers(instance) { + instance.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Exception("Missing helper: '" + arg + "'"); + } + }); + + instance.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + if (isFunction(context)) { context = context.call(this); } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if(context.length > 0) { + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + return fn(context); + } + }); + + instance.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; + + if (isFunction(context)) { context = context.call(this); } + + if (options.data) { + data = createFrame(options.data); + } + + if(context && typeof context === 'object') { + if (isArray(context)) { + for(var j = context.length; i":">",'"':""","'":"'","`":"`"},i=/[&<>"'`]/g,j=/[&<>"'`]/;f.extend=c;var k=Object.prototype.toString;f.toString=k;var l=function(a){return"function"==typeof a};l(/x/)&&(l=function(a){return"function"==typeof a&&"[object Function]"===k.call(a)});var l;f.isFunction=l;var m=Array.isArray||function(a){return a&&"object"==typeof a?"[object Array]"===k.call(a):!1};return f.isArray=m,f.escapeExpression=d,f.isEmpty=e,f}(a),c=function(){"use strict";function a(a,b){var d;b&&b.firstLine&&(d=b.firstLine,a+=" - "+d+":"+b.firstColumn);for(var e=Error.prototype.constructor.call(this,a),f=0;f0?a.helpers.each(b,c):d(this):e(b)}),a.registerHelper("each",function(a,b){var c,d=b.fn,e=b.inverse,f=0,g="";if(m(a)&&(a=a.call(this)),b.data&&(c=q(b.data)),a&&"object"==typeof a)if(l(a))for(var h=a.length;h>f;f++)c&&(c.index=f,c.first=0===f,c.last=f===a.length-1),g+=d(a[f],{data:c});else for(var i in a)a.hasOwnProperty(i)&&(c&&(c.key=i,c.index=f,c.first=0===f),g+=d(a[i],{data:c}),f++);return 0===f&&(g=e(this)),g}),a.registerHelper("if",function(a,b){return m(a)&&(a=a.call(this)),!b.hash.includeZero&&!a||g.isEmpty(a)?b.inverse(this):b.fn(this)}),a.registerHelper("unless",function(b,c){return a.helpers["if"].call(this,b,{fn:c.inverse,inverse:c.fn,hash:c.hash})}),a.registerHelper("with",function(a,b){return m(a)&&(a=a.call(this)),g.isEmpty(a)?void 0:b.fn(a)}),a.registerHelper("log",function(b,c){var d=c.data&&null!=c.data.level?parseInt(c.data.level,10):1;a.log(d,b)})}function e(a,b){p.log(a,b)}var f={},g=a,h=b,i="1.3.0";f.VERSION=i;var j=4;f.COMPILER_REVISION=j;var k={1:"<= 1.0.rc.2",2:"== 1.0.0-rc.3",3:"== 1.0.0-rc.4",4:">= 1.0.0"};f.REVISION_CHANGES=k;var l=g.isArray,m=g.isFunction,n=g.toString,o="[object Object]";f.HandlebarsEnvironment=c,c.prototype={constructor:c,logger:p,log:e,registerHelper:function(a,b,c){if(n.call(a)===o){if(c||b)throw new h("Arg not supported with multiple helpers");g.extend(this.helpers,a)}else c&&(b.not=c),this.helpers[a]=b},registerPartial:function(a,b){n.call(a)===o?g.extend(this.partials,a):this.partials[a]=b}};var p={methodMap:{0:"debug",1:"info",2:"warn",3:"error"},DEBUG:0,INFO:1,WARN:2,ERROR:3,level:3,log:function(a,b){if(p.level<=a){var c=p.methodMap[a];"undefined"!=typeof console&&console[c]&&console[c].call(console,b)}}};f.logger=p,f.log=e;var q=function(a){var b={};return g.extend(b,a),b};return f.createFrame=q,f}(b,c),e=function(a,b,c){"use strict";function d(a){var b=a&&a[0]||1,c=m;if(b!==c){if(c>b){var d=n[c],e=n[b];throw new l("Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version ("+d+") or downgrade your runtime to an older version ("+e+").")}throw new l("Template was precompiled with a newer version of Handlebars than the current runtime. Please update your runtime to a newer version ("+a[1]+").")}}function e(a,b){if(!b)throw new l("No environment passed to template");var c=function(a,c,d,e,f,g){var h=b.VM.invokePartial.apply(this,arguments);if(null!=h)return h;if(b.compile){var i={helpers:e,partials:f,data:g};return f[c]=b.compile(a,{data:void 0!==g},b),f[c](d,i)}throw new l("The partial "+c+" could not be compiled when running in runtime-only mode")},d={escapeExpression:k.escapeExpression,invokePartial:c,programs:[],program:function(a,b,c){var d=this.programs[a];return c?d=g(a,b,c):d||(d=this.programs[a]=g(a,b)),d},merge:function(a,b){var c=a||b;return a&&b&&a!==b&&(c={},k.extend(c,b),k.extend(c,a)),c},programWithDepth:b.VM.programWithDepth,noop:b.VM.noop,compilerInfo:null};return function(c,e){e=e||{};var f,g,h=e.partial?e:b;e.partial||(f=e.helpers,g=e.partials);var i=a.call(d,h,c,f,g,e.data);return e.partial||b.VM.checkRevision(d.compilerInfo),i}}function f(a,b,c){var d=Array.prototype.slice.call(arguments,3),e=function(a,e){return e=e||{},b.apply(this,[a,e.data||c].concat(d))};return e.program=a,e.depth=d.length,e}function g(a,b,c){var d=function(a,d){return d=d||{},b(a,d.data||c)};return d.program=a,d.depth=0,d}function h(a,b,c,d,e,f){var g={partial:!0,helpers:d,partials:e,data:f};if(void 0===a)throw new l("The partial "+b+" could not be found");return a instanceof Function?a(c,g):void 0}function i(){return""}var j={},k=a,l=b,m=c.COMPILER_REVISION,n=c.REVISION_CHANGES;return j.checkRevision=d,j.template=e,j.programWithDepth=f,j.program=g,j.invokePartial=h,j.noop=i,j}(b,c,d),f=function(a,b,c,d,e){"use strict";var f,g=a,h=b,i=c,j=d,k=e,l=function(){var a=new g.HandlebarsEnvironment;return j.extend(a,g),a.SafeString=h,a.Exception=i,a.Utils=j,a.VM=k,a.template=function(b){return k.template(b,a)},a},m=l();return m.create=l,f=m}(d,a,c,b,e);return f}(); \ No newline at end of file diff --git a/src/UI/Shared/Shims/handlebars.js b/src/UI/Shared/Shims/handlebars.js new file mode 100644 index 000000000..b36916fbf --- /dev/null +++ b/src/UI/Shared/Shims/handlebars.js @@ -0,0 +1,6 @@ +define([], function () { + + 'use strict'; + + return window.Handlebars; +}); \ No newline at end of file diff --git a/src/UI/app.js b/src/UI/app.js index cdec34b7c..4d8691952 100644 --- a/src/UI/app.js +++ b/src/UI/app.js @@ -5,7 +5,7 @@ require.config({ 'backbone' : 'JsLibraries/backbone', 'moment' : 'JsLibraries/moment', 'filesize' : 'JsLibraries/filesize', - 'handlebars' : 'JsLibraries/handlebars.runtime', + 'handlebars' : 'Shared/Shims/handlebars', 'handlebars.helpers' : 'JsLibraries/handlebars.helpers', 'bootstrap' : 'JsLibraries/bootstrap', 'backbone.deepmodel' : 'JsLibraries/backbone.deep.model', diff --git a/src/UI/index.html b/src/UI/index.html index 6ced33e35..f1542fcff 100644 --- a/src/UI/index.html +++ b/src/UI/index.html @@ -13,14 +13,14 @@ - - - - - - - - + + + + + + + + @@ -80,6 +80,7 @@ +