1 /* jshint node: true */ |
|
2 |
|
3 module.exports = function(grunt) { |
|
4 "use strict"; |
|
5 |
|
6 // Force use of Unix newlines |
|
7 grunt.util.linefeed = '\n'; |
|
8 |
|
9 RegExp.quote = require('regexp-quote') |
|
10 var btoa = require('btoa') |
|
11 // Project configuration. |
|
12 grunt.initConfig({ |
|
13 |
|
14 // Metadata. |
|
15 pkg: grunt.file.readJSON('package.json'), |
|
16 banner: '/*!\n' + |
|
17 ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + |
|
18 ' * Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + |
|
19 ' * Licensed under <%= _.pluck(pkg.licenses, "url").join(", ") %>\n' + |
|
20 ' */\n\n', |
|
21 jqueryCheck: 'if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") }\n\n', |
|
22 |
|
23 // Task configuration. |
|
24 clean: { |
|
25 dist: ['dist'] |
|
26 }, |
|
27 |
|
28 jshint: { |
|
29 options: { |
|
30 jshintrc: 'js/.jshintrc' |
|
31 }, |
|
32 gruntfile: { |
|
33 src: 'Gruntfile.js' |
|
34 }, |
|
35 src: { |
|
36 src: ['js/*.js'] |
|
37 }, |
|
38 test: { |
|
39 src: ['js/tests/unit/*.js'] |
|
40 } |
|
41 }, |
|
42 |
|
43 concat: { |
|
44 options: { |
|
45 banner: '<%= banner %><%= jqueryCheck %>', |
|
46 stripBanners: false |
|
47 }, |
|
48 bootstrap: { |
|
49 src: [ |
|
50 'js/transition.js', |
|
51 'js/alert.js', |
|
52 'js/button.js', |
|
53 'js/carousel.js', |
|
54 'js/collapse.js', |
|
55 'js/dropdown.js', |
|
56 'js/modal.js', |
|
57 'js/tooltip.js', |
|
58 'js/popover.js', |
|
59 'js/scrollspy.js', |
|
60 'js/tab.js', |
|
61 'js/affix.js' |
|
62 ], |
|
63 dest: 'dist/js/<%= pkg.name %>.js' |
|
64 } |
|
65 }, |
|
66 |
|
67 uglify: { |
|
68 options: { |
|
69 banner: '<%= banner %>', |
|
70 report: 'min' |
|
71 }, |
|
72 bootstrap: { |
|
73 src: ['<%= concat.bootstrap.dest %>'], |
|
74 dest: 'dist/js/<%= pkg.name %>.min.js' |
|
75 } |
|
76 }, |
|
77 |
|
78 recess: { |
|
79 options: { |
|
80 compile: true, |
|
81 banner: '<%= banner %>' |
|
82 }, |
|
83 bootstrap: { |
|
84 src: ['less/bootstrap.less'], |
|
85 dest: 'dist/css/<%= pkg.name %>.css' |
|
86 }, |
|
87 min: { |
|
88 options: { |
|
89 compress: true |
|
90 }, |
|
91 src: ['less/bootstrap.less'], |
|
92 dest: 'dist/css/<%= pkg.name %>.min.css' |
|
93 }, |
|
94 theme: { |
|
95 src: ['less/theme.less'], |
|
96 dest: 'dist/css/<%= pkg.name %>-theme.css' |
|
97 }, |
|
98 theme_min: { |
|
99 options: { |
|
100 compress: true |
|
101 }, |
|
102 src: ['less/theme.less'], |
|
103 dest: 'dist/css/<%= pkg.name %>-theme.min.css' |
|
104 } |
|
105 }, |
|
106 |
|
107 copy: { |
|
108 fonts: { |
|
109 expand: true, |
|
110 src: ["fonts/*"], |
|
111 dest: 'dist/' |
|
112 } |
|
113 }, |
|
114 |
|
115 qunit: { |
|
116 options: { |
|
117 inject: 'js/tests/unit/phantom.js' |
|
118 }, |
|
119 files: ['js/tests/*.html'] |
|
120 }, |
|
121 |
|
122 connect: { |
|
123 server: { |
|
124 options: { |
|
125 port: 3000, |
|
126 base: '.' |
|
127 } |
|
128 } |
|
129 }, |
|
130 |
|
131 jekyll: { |
|
132 docs: {} |
|
133 }, |
|
134 |
|
135 validation: { |
|
136 options: { |
|
137 reset: true, |
|
138 relaxerror: [ |
|
139 "Bad value X-UA-Compatible for attribute http-equiv on element meta.", |
|
140 "Element img is missing required attribute src." |
|
141 ] |
|
142 }, |
|
143 files: { |
|
144 src: ["_gh_pages/**/*.html"] |
|
145 } |
|
146 }, |
|
147 |
|
148 watch: { |
|
149 src: { |
|
150 files: '<%= jshint.src.src %>', |
|
151 tasks: ['jshint:src', 'qunit'] |
|
152 }, |
|
153 test: { |
|
154 files: '<%= jshint.test.src %>', |
|
155 tasks: ['jshint:test', 'qunit'] |
|
156 }, |
|
157 recess: { |
|
158 files: 'less/*.less', |
|
159 tasks: ['recess'] |
|
160 } |
|
161 }, |
|
162 |
|
163 sed: { |
|
164 versionNumber: { |
|
165 pattern: (function () { |
|
166 var old = grunt.option('oldver') |
|
167 return old ? RegExp.quote(old) : old |
|
168 })(), |
|
169 replacement: grunt.option('newver'), |
|
170 recursive: true |
|
171 } |
|
172 }, |
|
173 |
|
174 'saucelabs-qunit': { |
|
175 all: { |
|
176 options: { |
|
177 build: process.env.TRAVIS_JOB_ID, |
|
178 concurrency: 3, |
|
179 urls: ['http://127.0.0.1:3000/js/tests/index.html'], |
|
180 browsers: [ |
|
181 // See https://saucelabs.com/docs/platforms/webdriver |
|
182 { |
|
183 browserName: 'safari', |
|
184 version: '6', |
|
185 platform: 'OS X 10.8' |
|
186 }, |
|
187 { |
|
188 browserName: 'chrome', |
|
189 version: '28', |
|
190 platform: 'OS X 10.6' |
|
191 }, |
|
192 /* FIXME: currently fails 1 tooltip test |
|
193 { |
|
194 browserName: 'firefox', |
|
195 version: '25', |
|
196 platform: 'OS X 10.6' |
|
197 },*/ |
|
198 // Mac Opera not currently supported by Sauce Labs |
|
199 /* FIXME: currently fails 1 tooltip test |
|
200 { |
|
201 browserName: 'internet explorer', |
|
202 version: '11', |
|
203 platform: 'Windows 8.1' |
|
204 },*/ |
|
205 /* |
|
206 { |
|
207 browserName: 'internet explorer', |
|
208 version: '10', |
|
209 platform: 'Windows 8' |
|
210 }, |
|
211 { |
|
212 browserName: 'internet explorer', |
|
213 version: '9', |
|
214 platform: 'Windows 7' |
|
215 }, |
|
216 { |
|
217 browserName: 'internet explorer', |
|
218 version: '8', |
|
219 platform: 'Windows 7' |
|
220 }, |
|
221 {// unofficial |
|
222 browserName: 'internet explorer', |
|
223 version: '7', |
|
224 platform: 'Windows XP' |
|
225 }, |
|
226 */ |
|
227 { |
|
228 browserName: 'chrome', |
|
229 version: '31', |
|
230 platform: 'Windows 8.1' |
|
231 }, |
|
232 { |
|
233 browserName: 'firefox', |
|
234 version: '25', |
|
235 platform: 'Windows 8.1' |
|
236 }, |
|
237 // Win Opera 15+ not currently supported by Sauce Labs |
|
238 { |
|
239 browserName: 'iphone', |
|
240 version: '6.1', |
|
241 platform: 'OS X 10.8' |
|
242 }, |
|
243 // iOS Chrome not currently supported by Sauce Labs |
|
244 // Linux (unofficial) |
|
245 { |
|
246 browserName: 'chrome', |
|
247 version: '30', |
|
248 platform: 'Linux' |
|
249 }, |
|
250 { |
|
251 browserName: 'firefox', |
|
252 version: '25', |
|
253 platform: 'Linux' |
|
254 } |
|
255 // Android Chrome not currently supported by Sauce Labs |
|
256 /* Android Browser (super-unofficial) |
|
257 { |
|
258 browserName: 'android', |
|
259 version: '4.0', |
|
260 platform: 'Linux' |
|
261 } |
|
262 */ |
|
263 ], |
|
264 } |
|
265 } |
|
266 } |
|
267 }); |
|
268 |
|
269 |
|
270 // These plugins provide necessary tasks. |
|
271 grunt.loadNpmTasks('grunt-contrib-clean'); |
|
272 grunt.loadNpmTasks('grunt-contrib-concat'); |
|
273 grunt.loadNpmTasks('grunt-contrib-connect'); |
|
274 grunt.loadNpmTasks('grunt-contrib-copy'); |
|
275 grunt.loadNpmTasks('grunt-contrib-jshint'); |
|
276 grunt.loadNpmTasks('grunt-contrib-qunit'); |
|
277 grunt.loadNpmTasks('grunt-contrib-uglify'); |
|
278 grunt.loadNpmTasks('grunt-contrib-watch'); |
|
279 grunt.loadNpmTasks('grunt-html-validation'); |
|
280 grunt.loadNpmTasks('grunt-jekyll'); |
|
281 grunt.loadNpmTasks('grunt-recess'); |
|
282 grunt.loadNpmTasks('grunt-saucelabs'); |
|
283 grunt.loadNpmTasks('grunt-sed'); |
|
284 |
|
285 // Docs HTML validation task |
|
286 grunt.registerTask('validate-html', ['jekyll', 'validation']); |
|
287 |
|
288 // Test task. |
|
289 var testSubtasks = ['dist-css', 'jshint', 'qunit', 'validate-html']; |
|
290 // Only run Sauce Labs tests if there's a Sauce access key |
|
291 if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined') { |
|
292 testSubtasks.push('connect'); |
|
293 testSubtasks.push('saucelabs-qunit'); |
|
294 } |
|
295 grunt.registerTask('test', testSubtasks); |
|
296 |
|
297 // JS distribution task. |
|
298 grunt.registerTask('dist-js', ['concat', 'uglify']); |
|
299 |
|
300 // CSS distribution task. |
|
301 grunt.registerTask('dist-css', ['recess']); |
|
302 |
|
303 // Fonts distribution task. |
|
304 grunt.registerTask('dist-fonts', ['copy']); |
|
305 |
|
306 // Full distribution task. |
|
307 grunt.registerTask('dist', ['clean', 'dist-css', 'dist-fonts', 'dist-js']); |
|
308 |
|
309 // Default task. |
|
310 grunt.registerTask('default', ['test', 'dist', 'build-customizer']); |
|
311 |
|
312 // Version numbering task. |
|
313 // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z |
|
314 // This can be overzealous, so its changes should always be manually reviewed! |
|
315 grunt.registerTask('change-version-number', ['sed']); |
|
316 |
|
317 // task for building customizer |
|
318 grunt.registerTask('build-customizer', 'Add scripts/less files to customizer.', function () { |
|
319 var fs = require('fs') |
|
320 |
|
321 function getFiles(type) { |
|
322 var files = {} |
|
323 fs.readdirSync(type) |
|
324 .filter(function (path) { |
|
325 return type == 'fonts' ? true : new RegExp('\\.' + type + '$').test(path) |
|
326 }) |
|
327 .forEach(function (path) { |
|
328 var fullPath = type + '/' + path |
|
329 return files[path] = (type == 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8')) |
|
330 }) |
|
331 return 'var __' + type + ' = ' + JSON.stringify(files) + '\n' |
|
332 } |
|
333 |
|
334 var files = getFiles('js') + getFiles('less') + getFiles('fonts') |
|
335 fs.writeFileSync('docs-assets/js/raw-files.js', files) |
|
336 }); |
|
337 }; |
|