/*global module:false*/ module.exports = function( grunt ) { 'use strict'; var pkg = grunt.file.readJSON( 'package.json' ), tasks, widgetFilePrefix, widgetFileSuffix, defaults = { dependencies : { widgets: { 'saveSort resizable pager filter columnSelector' : 'storage', 'filter-formatter-html5 filter-formatter-jui filter-formatter-select2' : 'filter' // 'stickyHeaders' : 'addResizeEvent' // included with stickyHeaders widget (for now) } }, standardWidgets: [ 'storage', // req by saveSort; optional in others 'uitheme', 'columns', 'filter', 'stickyHeaders', 'resizable', 'saveSort' // 'addResizeEvent', // included with stickyHeaders widget // 'zeba' // included in core ] }, // example widgets = [ 'pager','column', 'filter', 'stickyHeaders' ]; addWidgetDependencies = function(widgets) { var indx, dep, maxDeps = 40, // just in case (there are currently 27 widgets) len = widgets.length, deps = defaults.dependencies.widgets; for ( dep in deps ) { if ( typeof dep === 'string' ) { for ( indx = 0; indx < len; indx++ ) { // make sure indexOf is not matching "column" instead of "columnSelector" with surrounding spaces if ( (' ' + dep + ' ').indexOf(' ' + widgets[indx] + ' ') >= 0 && widgets.indexOf( deps[dep] ) < 0 ) { widgets.push( deps[dep] ); // keep checking newly added widgets, in case "filter" is added and "storage" hasn't been if (len < maxDeps) { len++; } continue; } } } } return widgets; }, formFileNames = function(){ // add widget path & file extension pkg.processedWidgets = ( widgetFilePrefix + pkg.selectedWidgets.join( widgetFileSuffix + ',' + widgetFilePrefix ) + widgetFileSuffix ).split( ',' ); console.info( 'Creating a widgets file with: ' + pkg.selectedWidgets.join(', ') ); }; // minified banner template - updated ##/##/20## (v2.##.##) pkg.banner = '/*! <%= pkg.name %> (FORK) widgets - updated ' + '<%= grunt.template.today("mm-dd-yyyy") %> (v<%= pkg.version %>)*/\n'; widgetFilePrefix = 'js/widgets/widget-'; widgetFileSuffix = '.js'; pkg.buildWidget = 'jquery.tablesorter.widgets.js'; // Project configuration. grunt.initConfig({ pkg: pkg, clean: { build: { src: [ 'dist/**/**/**/*', 'dist/**/**/*', 'dist/**/*', 'dist' ] }, css: { src: [ 'dist/css/*.css', '!dist/css/*.min.css' ] } }, copy: { main: { expand: true, src: [ 'js/jquery.*.js', '!js/_test-*.js', '!js/*.min.js', ], dest: 'dist/', filter: 'isFile' }, css: { files : [{ expand: true, dot: true, flatten: true, src: ['css/*.css', 'addons/pager/*.css'], dest: 'dist/css/', rename: function(dest, src) { if (/black-ice/.test(src)) { src = src.replace(/-/, ''); } return dest + src; } }] }, less: { expand: true, flatten: true, src: 'css/*.less', dest: 'dist/css/less/' }, images: { expand: true, flatten: true, src: [ 'addons/pager/icons/*', 'css/images/*' ], dest: 'dist/css/images/' } }, concat: { widgets: { options: { banner: '<%= pkg.banner %>/* Includes: <%= pkg.selectedWidgets %> */\n' + "(function(factory) {\n" + " if (typeof define === 'function' && define.amd) {\n" + " define(['jquery'], factory);\n" + " } else if (typeof module === 'object' && typeof module.exports === 'object') {\n" + " module.exports = factory(require('jquery'));\n" + " } else {\n" + " factory(jQuery);\n" + " }\n" + "}(function($) {\n\n", footer: "\n\n return $.tablesorter;\n}));\n" }, src: [ '<%= pkg.processedWidgets %>', '!js/widgets/_test-*.js', '!js/widgets/*.min.js' ], dest: 'dist/js/<%= pkg.buildWidget %>' }, // keep all the existing jsFiddle demos from breaking copyback: { options: { banner: '/*** This file is dynamically generated ***\n' + '█████▄ ▄████▄ █████▄ ▄████▄ ██████ ███████▄ ▄████▄ █████▄ ██ ██████ ██ ██\n' + '██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██\n' + '██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀▀▀▀██\n' + '█████▀ ▀████▀ ██ ██ ▀████▀ ██ ██ ██ ██ ▀████▀ █████▀ ██ ██ █████▀\n*/\n' }, src : ['dist/js/<%= pkg.buildWidget %>'], dest: 'js/<%= pkg.buildWidget %>' } }, jshint: { files: { src: [ 'addons/pager/*.js', '!addons/pager/*.min.js', 'js/jquery.*.js', 'js/**/*.js', '!js/_test-*.js', '!js/**/_test-*.js', '!js/*.min.js', '!js/**/semver*.js' ] }, options: { globals: { "localStorage": false, "navigator": false, "console": false, "alert": false }, "loopfunc": true, "jquery": true, "browser": true } }, uglify: { options: { preserveComments: 'some', report: 'gzip' }, allFiles: { files: [{ expand: true, cwd: './js/', // Src matches are relative to this path. src: [ '*.js', '**/*.js', '!_test-*.js', '!**/_test-*.js', '!*.min.js', '!**/semver.js' ], dest: 'dist/js/', ext: '.min.js', // Dist files will have this extension. extDot: 'last' // Extensions in filenames begin after the first dot }] }, pageraddon: { files: { 'dist/js/extras/jquery.tablesorter.pager.min.js': [ 'addons/pager/*.js' ] } } }, cssmin: { target: { files: [{ expand: true, flatten: true, cwd: 'dist/css', src: ['*.css'], dest: 'dist/css', ext: '.min.css', extDot: 'last' }] } }, qunit: { files: [ 'test.html' ] }, watch: { scripts: { files: [ 'js/*.js', 'js/**/*.js', '!js/_test-*.js', '!js/*.min.js' ], tasks: [ 'build' ] } } }); grunt.loadNpmTasks( 'grunt-contrib-clean' ); grunt.loadNpmTasks( 'grunt-contrib-jshint' ); grunt.loadNpmTasks( 'grunt-contrib-qunit' ); grunt.loadNpmTasks( 'grunt-contrib-concat' ); grunt.loadNpmTasks( 'grunt-contrib-uglify' ); grunt.loadNpmTasks( 'grunt-contrib-copy' ); grunt.loadNpmTasks( 'grunt-contrib-watch' ); grunt.loadNpmTasks( 'grunt-contrib-cssmin' ); grunt.registerTask( 'test', [ 'jshint', 'qunit' ] ); tasks = [ 'clean:build', 'copy', 'concat', 'uglify', 'cssmin', 'clean:css', 'updateManifest' ]; // basic = same as before: core, widgets, filterformatter all separate grunt.registerTask( 'default', 'Default build', function(){ pkg.selectedWidgets = addWidgetDependencies( defaults.standardWidgets ); formFileNames(); grunt.task.run(tasks); }); // enter "grunt custom:{filename}" (not including the ".json") // to load in a custom json file // the expected JSON format is (with custom widgets in a string): // { "widgets" : "columnHighlight filter resizable saveSort stickyHeaders uitheme" } grunt.registerTask( 'custom', 'Custom build', function(file){ var temp, widgets, deps = true; /* Allow developer to set up a custom widget build (json file will have settings)*/ try { temp = grunt.file.readJSON( file ); if (temp) { // include dependencies? deps = ('includeDependencies' in temp) ? temp.includeDependencies : true; // custom file name? pkg.buildWidget = ('destFileName' in temp) ? temp.destFileName : "jquery.tablesorter.custom-widgets.js"; // widgets to include widgets = (temp.widgets || ''); if (widgets.replace(/\s+/g,'') === '') { grunt.fail.warn('Aborting... No widgets found in custom build file.'); } else { temp = widgets.split(/\s+/); } } } catch (err) { grunt.log.error('Custom build json not found - Use "grunt custom:{filename}"'); console.info('Continuing build with default settings'); temp = defaults.standardWidgets; } // add dependencies pkg.selectedWidgets = deps ? addWidgetDependencies( temp ) : temp; formFileNames(); grunt.task.run(tasks); }); // update bower.json & tablesorter.jquery.json file version numbers to match the package.json version grunt.registerTask( 'updateManifest', function() { var i, project, projectFile = [ 'tablesorter.jquery.json', 'bower.json' ], len = projectFile.length; for ( i = 0; i < len; i++ ) { if ( !grunt.file.exists( projectFile[ i ] ) ) { grunt.log.error( "file " + projectFile[ i ] + " not found" ); return true; // return false to abort the execution } project = grunt.file.readJSON( projectFile[ i ] ); // get file as json object project.version = pkg.version; grunt.file.write( projectFile[i], JSON.stringify( project, null, 2 ) ); // serialize it back to file } }); };