info@54: /* jshint node: true */ info@54: info@54: module.exports = function(grunt) { info@54: "use strict"; info@54: info@54: // Force use of Unix newlines info@54: grunt.util.linefeed = '\n'; info@54: info@54: RegExp.quote = require('regexp-quote') info@54: var btoa = require('btoa') info@54: // Project configuration. info@54: grunt.initConfig({ info@54: info@54: // Metadata. info@54: pkg: grunt.file.readJSON('package.json'), info@54: banner: '/*!\n' + info@54: ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + info@54: ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + info@54: ' * Licensed under <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' + info@54: ' */\n\n', info@54: jqueryCheck: 'if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") }\n\n', info@54: info@54: // Task configuration. info@54: clean: { info@54: dist: ['dist'] info@54: }, info@54: info@54: jshint: { info@54: options: { info@54: jshintrc: 'js/.jshintrc' info@54: }, info@54: gruntfile: { info@54: src: 'Gruntfile.js' info@54: }, info@54: src: { info@54: src: ['js/*.js'] info@54: }, info@54: test: { info@54: src: ['js/tests/unit/*.js'] info@54: } info@54: }, info@54: info@54: concat: { info@54: options: { info@54: banner: '<%= banner %><%= jqueryCheck %>', info@54: stripBanners: false info@54: }, info@54: bootstrap: { info@54: src: [ info@54: 'js/transition.js', info@54: 'js/alert.js', info@54: 'js/button.js', info@54: 'js/carousel.js', info@54: 'js/collapse.js', info@54: 'js/dropdown.js', info@54: 'js/modal.js', info@54: 'js/tooltip.js', info@54: 'js/popover.js', info@54: 'js/scrollspy.js', info@54: 'js/tab.js', info@54: 'js/affix.js' info@54: ], info@54: dest: 'dist/js/<%= pkg.name %>.js' info@54: } info@54: }, info@54: info@54: uglify: { info@54: options: { info@54: banner: '<%= banner %>', info@54: report: 'min' info@54: }, info@54: bootstrap: { info@54: src: ['<%= concat.bootstrap.dest %>'], info@54: dest: 'dist/js/<%= pkg.name %>.min.js' info@54: } info@54: }, info@54: info@54: recess: { info@54: options: { info@54: compile: true, info@54: banner: '<%= banner %>' info@54: }, info@54: bootstrap: { info@54: src: ['less/bootstrap.less'], info@54: dest: 'dist/css/<%= pkg.name %>.css' info@54: }, info@54: min: { info@54: options: { info@54: compress: true info@54: }, info@54: src: ['less/bootstrap.less'], info@54: dest: 'dist/css/<%= pkg.name %>.min.css' info@54: }, info@54: theme: { info@54: src: ['less/theme.less'], info@54: dest: 'dist/css/<%= pkg.name %>-theme.css' info@54: }, info@54: theme_min: { info@54: options: { info@54: compress: true info@54: }, info@54: src: ['less/theme.less'], info@54: dest: 'dist/css/<%= pkg.name %>-theme.min.css' info@54: } info@54: }, info@54: info@54: copy: { info@54: fonts: { info@54: expand: true, info@54: src: ["fonts/*"], info@54: dest: 'dist/' info@54: } info@54: }, info@54: info@54: qunit: { info@54: options: { info@54: inject: 'js/tests/unit/phantom.js' info@54: }, info@54: files: ['js/tests/*.html'] info@54: }, info@54: info@54: connect: { info@54: server: { info@54: options: { info@54: port: 3000, info@54: base: '.' info@54: } info@54: } info@54: }, info@54: info@54: jekyll: { info@54: docs: {} info@54: }, info@54: info@54: validation: { info@54: options: { info@54: reset: true, info@54: relaxerror: [ info@54: "Bad value X-UA-Compatible for attribute http-equiv on element meta.", info@54: "Element img is missing required attribute src." info@54: ] info@54: }, info@54: files: { info@54: src: ["_gh_pages/**/*.html"] info@54: } info@54: }, info@54: info@54: watch: { info@54: src: { info@54: files: '<%= jshint.src.src %>', info@54: tasks: ['jshint:src', 'qunit'] info@54: }, info@54: test: { info@54: files: '<%= jshint.test.src %>', info@54: tasks: ['jshint:test', 'qunit'] info@54: }, info@54: recess: { info@54: files: 'less/*.less', info@54: tasks: ['recess'] info@54: } info@54: }, info@54: info@54: sed: { info@54: versionNumber: { info@54: pattern: (function () { info@54: var old = grunt.option('oldver') info@54: return old ? RegExp.quote(old) : old info@54: })(), info@54: replacement: grunt.option('newver'), info@54: recursive: true info@54: } info@54: }, info@54: info@54: 'saucelabs-qunit': { info@54: all: { info@54: options: { info@54: build: process.env.TRAVIS_JOB_ID, info@54: concurrency: 3, info@54: urls: ['http://127.0.0.1:3000/js/tests/index.html'], info@54: browsers: [ info@54: // See https://saucelabs.com/docs/platforms/webdriver info@54: { info@54: browserName: 'safari', info@54: version: '6', info@54: platform: 'OS X 10.8' info@54: }, info@54: { info@54: browserName: 'chrome', info@54: version: '28', info@54: platform: 'OS X 10.6' info@54: }, info@54: /* FIXME: currently fails 1 tooltip test info@54: { info@54: browserName: 'firefox', info@54: version: '25', info@54: platform: 'OS X 10.6' info@54: },*/ info@54: // Mac Opera not currently supported by Sauce Labs info@54: /* FIXME: currently fails 1 tooltip test info@54: { info@54: browserName: 'internet explorer', info@54: version: '11', info@54: platform: 'Windows 8.1' info@54: },*/ info@54: /* info@54: { info@54: browserName: 'internet explorer', info@54: version: '10', info@54: platform: 'Windows 8' info@54: }, info@54: { info@54: browserName: 'internet explorer', info@54: version: '9', info@54: platform: 'Windows 7' info@54: }, info@54: { info@54: browserName: 'internet explorer', info@54: version: '8', info@54: platform: 'Windows 7' info@54: }, info@54: {// unofficial info@54: browserName: 'internet explorer', info@54: version: '7', info@54: platform: 'Windows XP' info@54: }, info@54: */ info@54: { info@54: browserName: 'chrome', info@54: version: '31', info@54: platform: 'Windows 8.1' info@54: }, info@54: { info@54: browserName: 'firefox', info@54: version: '25', info@54: platform: 'Windows 8.1' info@54: }, info@54: // Win Opera 15+ not currently supported by Sauce Labs info@54: { info@54: browserName: 'iphone', info@54: version: '6.1', info@54: platform: 'OS X 10.8' info@54: }, info@54: // iOS Chrome not currently supported by Sauce Labs info@54: // Linux (unofficial) info@54: { info@54: browserName: 'chrome', info@54: version: '30', info@54: platform: 'Linux' info@54: }, info@54: { info@54: browserName: 'firefox', info@54: version: '25', info@54: platform: 'Linux' info@54: } info@54: // Android Chrome not currently supported by Sauce Labs info@54: /* Android Browser (super-unofficial) info@54: { info@54: browserName: 'android', info@54: version: '4.0', info@54: platform: 'Linux' info@54: } info@54: */ info@54: ], info@54: } info@54: } info@54: } info@54: }); info@54: info@54: info@54: // These plugins provide necessary tasks. info@54: grunt.loadNpmTasks('grunt-contrib-clean'); info@54: grunt.loadNpmTasks('grunt-contrib-concat'); info@54: grunt.loadNpmTasks('grunt-contrib-connect'); info@54: grunt.loadNpmTasks('grunt-contrib-copy'); info@54: grunt.loadNpmTasks('grunt-contrib-jshint'); info@54: grunt.loadNpmTasks('grunt-contrib-qunit'); info@54: grunt.loadNpmTasks('grunt-contrib-uglify'); info@54: grunt.loadNpmTasks('grunt-contrib-watch'); info@54: grunt.loadNpmTasks('grunt-html-validation'); info@54: grunt.loadNpmTasks('grunt-jekyll'); info@54: grunt.loadNpmTasks('grunt-recess'); info@54: grunt.loadNpmTasks('grunt-saucelabs'); info@54: grunt.loadNpmTasks('grunt-sed'); info@54: info@54: // Docs HTML validation task info@54: grunt.registerTask('validate-html', ['jekyll', 'validation']); info@54: info@54: // Test task. info@54: var testSubtasks = ['dist-css', 'jshint', 'qunit', 'validate-html']; info@54: // Only run Sauce Labs tests if there's a Sauce access key info@54: if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined') { info@54: testSubtasks.push('connect'); info@54: testSubtasks.push('saucelabs-qunit'); info@54: } info@54: grunt.registerTask('test', testSubtasks); info@54: info@54: // JS distribution task. info@54: grunt.registerTask('dist-js', ['concat', 'uglify']); info@54: info@54: // CSS distribution task. info@54: grunt.registerTask('dist-css', ['recess']); info@54: info@54: // Fonts distribution task. info@54: grunt.registerTask('dist-fonts', ['copy']); info@54: info@54: // Full distribution task. info@54: grunt.registerTask('dist', ['clean', 'dist-css', 'dist-fonts', 'dist-js']); info@54: info@54: // Default task. info@54: grunt.registerTask('default', ['test', 'dist', 'build-customizer']); info@54: info@54: // Version numbering task. info@54: // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z info@54: // This can be overzealous, so its changes should always be manually reviewed! info@54: grunt.registerTask('change-version-number', ['sed']); info@54: info@54: // task for building customizer info@54: grunt.registerTask('build-customizer', 'Add scripts/less files to customizer.', function () { info@54: var fs = require('fs') info@54: info@54: function getFiles(type) { info@54: var files = {} info@54: fs.readdirSync(type) info@54: .filter(function (path) { info@54: return type == 'fonts' ? true : new RegExp('\\.' + type + '$').test(path) info@54: }) info@54: .forEach(function (path) { info@54: var fullPath = type + '/' + path info@54: return files[path] = (type == 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8')) info@54: }) info@54: return 'var __' + type + ' = ' + JSON.stringify(files) + '\n' info@54: } info@54: info@54: var files = getFiles('js') + getFiles('less') + getFiles('fonts') info@54: fs.writeFileSync('docs-assets/js/raw-files.js', files) info@54: }); info@54: };