Merge branch 'BF-2656' of /home/git/repositories/brainfood/rivets-error-binder
Showing
11 changed files
with
922 additions
and
98 deletions
.gitignore
0 → 100644
Gruntfile.js
0 → 100644
1 | // Generated on 2014-02-06 using generator-webapp 0.4.7 | ||
2 | /* global module */ | ||
3 | |||
4 | // # Globbing | ||
5 | // for performance reasons we're only matching one level down: | ||
6 | // 'test/spec/{,*/}*.js' | ||
7 | // use this if you want to recursively match all subfolders: | ||
8 | // 'test/spec/**/*.js' | ||
9 | |||
10 | module.exports = function (grunt) { | ||
11 | /* global require */ | ||
12 | 'use strict'; | ||
13 | |||
14 | var jasmineRequirejsTemplateOptions = function(withInstanbul) { | ||
15 | /* global requirejs */ | ||
16 | var callback; | ||
17 | if (withInstanbul) { | ||
18 | callback = function() { | ||
19 | var oldLoad = requirejs.load; | ||
20 | requirejs.load = function (context, moduleName, url) { | ||
21 | //console.log('context=' + JSON.stringify(arguments), 'moduleName=' + moduleName, 'url=' + url); | ||
22 | var parts = url.split('/'); | ||
23 | for (var i = 0; i < parts.length; ) { | ||
24 | var part = parts[i]; | ||
25 | if (part === '.') { | ||
26 | parts.splice(i, 1); | ||
27 | } else if (part === '') { | ||
28 | parts.splice(i, 1); | ||
29 | } else if (part === '..') { | ||
30 | if (i > 0) { | ||
31 | i--; | ||
32 | parts.splice(i, 2); | ||
33 | } else { | ||
34 | parts.splice(i, 1); | ||
35 | } | ||
36 | } else { | ||
37 | i++; | ||
38 | } | ||
39 | } | ||
40 | url = parts.join('/'); | ||
41 | if (url.indexOf('src/scripts/') === 0) { | ||
42 | url = './.grunt/grunt-contrib-jasmine/' + url; | ||
43 | } | ||
44 | if (url.indexOf('test/specs/') === 0) { | ||
45 | url = './.grunt/grunt-contrib-jasmine/' + url; | ||
46 | } | ||
47 | //console.log('url=' + url); | ||
48 | return oldLoad.apply(this, [context, moduleName, url]); | ||
49 | }; | ||
50 | }; | ||
51 | } | ||
52 | return { | ||
53 | requireConfigFile: '<%= yeoman.src %>/scripts/config.js', | ||
54 | requireConfig: { | ||
55 | baseUrl: '<%= yeoman.src %>/scripts', | ||
56 | callback: callback | ||
57 | } | ||
58 | }; | ||
59 | }; | ||
60 | |||
61 | var jasmineInstanbulTemplateOptions = function(nestedTemplate, nestedOptions) { | ||
62 | return { | ||
63 | coverage: 'bin/coverage/coverage.json', | ||
64 | report: 'bin/coverage', | ||
65 | replace: false, | ||
66 | template: require(nestedTemplate), | ||
67 | templateOptions: nestedOptions | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | // Load grunt tasks automatically | ||
72 | require('load-grunt-tasks')(grunt); | ||
73 | |||
74 | // Time how long tasks take. Can help when optimizing build times | ||
75 | require('time-grunt')(grunt); | ||
76 | |||
77 | // Define the configuration for all the tasks | ||
78 | grunt.initConfig({ | ||
79 | bower: { | ||
80 | target: { | ||
81 | options: { | ||
82 | exclude: [ | ||
83 | 'requirejs', | ||
84 | ], | ||
85 | transitive: true, | ||
86 | }, | ||
87 | rjsConfig: '<%= yeoman.src %>/scripts/config.js' | ||
88 | } | ||
89 | }, | ||
90 | |||
91 | // Project settings | ||
92 | yeoman: { | ||
93 | // Configurable paths | ||
94 | app: 'app', | ||
95 | dist: 'dist', | ||
96 | src: 'src', | ||
97 | }, | ||
98 | |||
99 | // Watches files for changes and runs tasks based on the changed files | ||
100 | watch: { | ||
101 | js: { | ||
102 | files: ['<%= yeoman.src %>/scripts/{,*/}*.js'], | ||
103 | tasks: ['jshint'], | ||
104 | }, | ||
105 | jstest: { | ||
106 | files: ['test/spec/{,*/}*.js'], | ||
107 | tasks: ['test:watch'] | ||
108 | }, | ||
109 | gruntfile: { | ||
110 | files: ['Gruntfile.js'] | ||
111 | }, | ||
112 | styles: { | ||
113 | files: ['<%= yeoman.src %>/styles/{,*/}*.css'], | ||
114 | tasks: ['newer:copy:styles', 'autoprefixer'] | ||
115 | } | ||
116 | }, | ||
117 | |||
118 | // The actual grunt server settings | ||
119 | connect: { | ||
120 | options: { | ||
121 | port: 9000, | ||
122 | // Change this to '0.0.0.0' to access the server from outside | ||
123 | hostname: 'localhost' | ||
124 | }, | ||
125 | app: { | ||
126 | options: { | ||
127 | open: false, | ||
128 | base: [ | ||
129 | '.tmp', | ||
130 | '<%= yeoman.src %>' | ||
131 | ] | ||
132 | } | ||
133 | }, | ||
134 | test: { | ||
135 | options: { | ||
136 | port: 9001, | ||
137 | base: [ | ||
138 | '.tmp', | ||
139 | 'test', | ||
140 | '<%= yeoman.src %>' | ||
141 | ] | ||
142 | } | ||
143 | }, | ||
144 | dist: { | ||
145 | options: { | ||
146 | open: false, | ||
147 | base: '<%= yeoman.dist %>', | ||
148 | } | ||
149 | } | ||
150 | }, | ||
151 | |||
152 | // Empties folders to start fresh | ||
153 | clean: { | ||
154 | dist: { | ||
155 | files: [{ | ||
156 | dot: true, | ||
157 | src: [ | ||
158 | '.tmp', | ||
159 | '<%= yeoman.dist %>/*', | ||
160 | '!<%= yeoman.dist %>/.git*' | ||
161 | ] | ||
162 | }] | ||
163 | }, | ||
164 | server: '.tmp' | ||
165 | }, | ||
166 | |||
167 | // Make sure code styles are up to par and there are no obvious mistakes | ||
168 | jshint: { | ||
169 | options: { | ||
170 | browser: true, | ||
171 | esnext: true, | ||
172 | bitwise: true, | ||
173 | camelcase: true, | ||
174 | curly: true, | ||
175 | eqeqeq: true, | ||
176 | immed: true, | ||
177 | indent: 4, | ||
178 | latedef: true, | ||
179 | newcap: true, | ||
180 | noarg: true, | ||
181 | quotmark: 'single', | ||
182 | undef: true, | ||
183 | unused: true, | ||
184 | strict: true, | ||
185 | trailing: true, | ||
186 | smarttabs: true, | ||
187 | jquery: true, | ||
188 | reporter: require('jshint-stylish') | ||
189 | }, | ||
190 | all: [ | ||
191 | 'Gruntfile.js', | ||
192 | ], | ||
193 | scripts: { | ||
194 | options: { | ||
195 | globals: { | ||
196 | define: false, | ||
197 | } | ||
198 | }, | ||
199 | files: { | ||
200 | src: [ | ||
201 | '<%= yeoman.src %>/scripts/**/*.js', | ||
202 | '!<%= yeoman.src %>/scripts/vendor/*', | ||
203 | ] | ||
204 | } | ||
205 | }, | ||
206 | specs: { | ||
207 | options: { | ||
208 | globals: { | ||
209 | afterEach: false, | ||
210 | beforeEach: false, | ||
211 | define: false, | ||
212 | describe: false, | ||
213 | expect: false, | ||
214 | it: false, | ||
215 | jasmine: false, | ||
216 | } | ||
217 | }, | ||
218 | files: { | ||
219 | src: [ | ||
220 | 'test/specs/**/*.spec.js' | ||
221 | ] | ||
222 | } | ||
223 | } | ||
224 | }, | ||
225 | |||
226 | jasmine: { | ||
227 | all: { | ||
228 | src: [ | ||
229 | '<%= yeoman.src %>/scripts/{,**/}*.js', | ||
230 | 'test/specs/**/*.spec.js', | ||
231 | ], | ||
232 | options: { | ||
233 | template: require('grunt-template-jasmine-istanbul'), | ||
234 | templateOptions: jasmineInstanbulTemplateOptions('grunt-template-jasmine-requirejs', jasmineRequirejsTemplateOptions(true)) | ||
235 | } | ||
236 | } | ||
237 | }, | ||
238 | |||
239 | // Mocha testing framework configuration options | ||
240 | mocha: { | ||
241 | all: { | ||
242 | options: { | ||
243 | run: true, | ||
244 | urls: ['http://<%= connect.test.options.hostname %>:<%= connect.test.options.port %>/index.html'] | ||
245 | } | ||
246 | } | ||
247 | }, | ||
248 | |||
249 | // Add vendor prefixed styles | ||
250 | autoprefixer: { | ||
251 | options: { | ||
252 | browsers: ['last 1 version'] | ||
253 | }, | ||
254 | dist: { | ||
255 | files: [{ | ||
256 | expand: true, | ||
257 | cwd: '.tmp/styles/', | ||
258 | src: '{,*/}*.css', | ||
259 | dest: '.tmp/styles/' | ||
260 | }] | ||
261 | } | ||
262 | }, | ||
263 | |||
264 | // Automatically inject Bower components into the HTML file | ||
265 | 'bower-install': { | ||
266 | app: { | ||
267 | html: '<%= yeoman.src %>/index.html', | ||
268 | ignorePath: '<%= yeoman.src %>/' | ||
269 | } | ||
270 | }, | ||
271 | |||
272 | // Renames files for browser caching purposes | ||
273 | rev: { | ||
274 | dist: { | ||
275 | files: { | ||
276 | src: [ | ||
277 | '<%= yeoman.dist %>/scripts/*/**/*.js', | ||
278 | '<%= yeoman.dist %>/scripts/!(config)*.js', | ||
279 | '<%= yeoman.dist %>/styles/{,*/}*.css', | ||
280 | '<%= yeoman.dist %>/images/{,*/}*.{gif,jpeg,jpg,png,webp}', | ||
281 | '<%= yeoman.dist %>/styles/fonts/{,*/}*.*' | ||
282 | ] | ||
283 | } | ||
284 | }, | ||
285 | requireconfig: { | ||
286 | files: { | ||
287 | src: [ | ||
288 | '<%= yeoman.dist %>/scripts/config.js' | ||
289 | ] | ||
290 | } | ||
291 | } | ||
292 | }, | ||
293 | |||
294 | requirejs: { | ||
295 | dist: { | ||
296 | options: { | ||
297 | done: function(done) { | ||
298 | var requireModules = grunt.config('requireModules') || {}; | ||
299 | var lines = [ | ||
300 | 'require.bundles = (function(bundles) {', | ||
301 | ]; | ||
302 | for (var key in requireModules) { | ||
303 | var keyS = JSON.stringify(key); | ||
304 | var value = requireModules[key]; | ||
305 | var included = []; | ||
306 | for (var i = 0; i < value.included.length; i++) { | ||
307 | var file = value.included[i]; | ||
308 | if (file.match(/\.js$/)) { | ||
309 | included.push(file.substring(0, file.length - 3)); | ||
310 | } | ||
311 | } | ||
312 | lines.push('bundles[' + keyS + '] = ' + JSON.stringify(included) + ';'); | ||
313 | } | ||
314 | lines.push('return bundles;'); | ||
315 | lines.push('})(require.bundles || {});'); | ||
316 | grunt.file.write('.tmp/scripts/bundles.js', lines.join('\n')); | ||
317 | done(); | ||
318 | }, | ||
319 | baseUrl: '<%= yeoman.src %>/scripts', | ||
320 | mainConfigFile: '<%= yeoman.src %>/scripts/config.js', | ||
321 | wrapShim: true, | ||
322 | dir: '<%= yeoman.dist %>/scripts', | ||
323 | optimize: 'none', | ||
324 | removeCombined: true, | ||
325 | onModuleBundleComplete: function(data) { | ||
326 | if (data.name.slice(0, 'bundles/'.length) === 'bundles/') { | ||
327 | var requireModules = grunt.config('requireModules') || {}; | ||
328 | requireModules[data.name] = data; | ||
329 | grunt.config('requireModules', requireModules); | ||
330 | } | ||
331 | }, | ||
332 | } | ||
333 | }, | ||
334 | }, | ||
335 | |||
336 | // Reads HTML for usemin blocks to enable smart builds that automatically | ||
337 | // concat, minify and revision files. Creates configurations in memory so | ||
338 | // additional tasks can operate on them | ||
339 | useminPrepare: { | ||
340 | options: { | ||
341 | dest: '<%= yeoman.dist %>' | ||
342 | }, | ||
343 | html: '<%= yeoman.src %>/index.html' | ||
344 | }, | ||
345 | |||
346 | // Performs rewrites based on rev and the useminPrepare configuration | ||
347 | usemin: { | ||
348 | options: { | ||
349 | assetsDirs: ['<%= yeoman.dist %>'] | ||
350 | }, | ||
351 | html: ['<%= yeoman.dist %>/{,*/}*.html'], | ||
352 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'] | ||
353 | }, | ||
354 | |||
355 | // The following *-min tasks produce minified files in the dist folder | ||
356 | imagemin: { | ||
357 | dist: { | ||
358 | files: [{ | ||
359 | expand: true, | ||
360 | cwd: '<%= yeoman.src %>/images', | ||
361 | src: '{,*/}*.{gif,jpeg,jpg,png}', | ||
362 | dest: '<%= yeoman.dist %>/images' | ||
363 | }] | ||
364 | } | ||
365 | }, | ||
366 | svgmin: { | ||
367 | dist: { | ||
368 | files: [{ | ||
369 | expand: true, | ||
370 | cwd: '<%= yeoman.src %>/images', | ||
371 | src: '{,*/}*.svg', | ||
372 | dest: '<%= yeoman.dist %>/images' | ||
373 | }] | ||
374 | } | ||
375 | }, | ||
376 | htmlmin: { | ||
377 | dist: { | ||
378 | options: { | ||
379 | collapseBooleanAttributes: true, | ||
380 | collapseWhitespace: true, | ||
381 | removeAttributeQuotes: true, | ||
382 | removeCommentsFromCDATA: true, | ||
383 | removeEmptyAttributes: true, | ||
384 | removeOptionalTags: true, | ||
385 | removeRedundantAttributes: true, | ||
386 | useShortDoctype: true | ||
387 | }, | ||
388 | files: [{ | ||
389 | expand: true, | ||
390 | cwd: '<%= yeoman.dist %>', | ||
391 | src: '{,*/}*.html', | ||
392 | dest: '<%= yeoman.dist %>' | ||
393 | }] | ||
394 | } | ||
395 | }, | ||
396 | |||
397 | // By default, your `index.html`'s <!-- Usemin block --> will take care of | ||
398 | // minification. These next options are pre-configured if you do not wish | ||
399 | // to use the Usemin blocks. | ||
400 | // cssmin: { | ||
401 | // dist: { | ||
402 | // files: { | ||
403 | // '<%= yeoman.dist %>/styles/main.css': [ | ||
404 | // '.tmp/styles/{,*/}*.css', | ||
405 | // '<%= yeoman.src %>/styles/{,*/}*.css' | ||
406 | // ] | ||
407 | // } | ||
408 | // } | ||
409 | // }, | ||
410 | // uglify: { | ||
411 | // dist: { | ||
412 | // files: { | ||
413 | // '<%= yeoman.dist %>/scripts/scripts.js': [ | ||
414 | // '<%= yeoman.dist %>/scripts/scripts.js' | ||
415 | // ] | ||
416 | // } | ||
417 | // } | ||
418 | // }, | ||
419 | // concat: { | ||
420 | // dist: {} | ||
421 | // }, | ||
422 | |||
423 | concat: { | ||
424 | requireconfig: { | ||
425 | } | ||
426 | }, | ||
427 | |||
428 | uglify: { | ||
429 | dist: { | ||
430 | }, | ||
431 | requireconfig: { | ||
432 | files: { | ||
433 | '<%= yeoman.dist %>/scripts/config.js': [ | ||
434 | '<%= yeoman.dist %>/scripts/config.js', | ||
435 | '.tmp/scripts/config.js', | ||
436 | ], | ||
437 | } | ||
438 | } | ||
439 | }, | ||
440 | |||
441 | // Copies remaining files to places other tasks can use | ||
442 | copy: { | ||
443 | dist: { | ||
444 | files: [{ | ||
445 | expand: true, | ||
446 | dot: true, | ||
447 | cwd: '<%= yeoman.src %>', | ||
448 | dest: '<%= yeoman.dist %>', | ||
449 | src: [ | ||
450 | '*.{ico,png,txt}', | ||
451 | '.htaccess', | ||
452 | 'images/{,*/}*.webp', | ||
453 | '{,*/}*.html', | ||
454 | 'styles/fonts/{,*/}*.*' | ||
455 | ] | ||
456 | }] | ||
457 | }, | ||
458 | styles: { | ||
459 | expand: true, | ||
460 | dot: true, | ||
461 | cwd: '<%= yeoman.src %>/styles', | ||
462 | dest: '.tmp/styles/', | ||
463 | src: '{,*/}*.css' | ||
464 | } | ||
465 | }, | ||
466 | |||
467 | |||
468 | // Run some tasks in parallel to speed up build process | ||
469 | concurrent: { | ||
470 | server: [ | ||
471 | 'copy:styles' | ||
472 | ], | ||
473 | test: [ | ||
474 | 'copy:styles' | ||
475 | ], | ||
476 | dist: [ | ||
477 | 'copy:styles', | ||
478 | 'imagemin', | ||
479 | 'svgmin' | ||
480 | ] | ||
481 | } | ||
482 | }); | ||
483 | |||
484 | grunt.loadNpmTasks('grunt-bower-requirejs'); | ||
485 | |||
486 | grunt.registerTask('revconfig', function () { | ||
487 | var prefix = grunt.template.process('<%= yeoman.dist %>/scripts/'); | ||
488 | var pattern = prefix + '**/*.{js,html}'; | ||
489 | var files = grunt.file.expand(pattern); | ||
490 | var lines = []; | ||
491 | grunt.util._.each(files, function(file) { | ||
492 | file = file.substring(prefix.length); | ||
493 | var res = file.match(/^(.*\/)?([0-9a-f]+)\.([^\/]+)\.([^\.]+)$/); | ||
494 | if (!res) { | ||
495 | return; | ||
496 | } | ||
497 | //grunt.log.oklns(JSON.stringify(res)); | ||
498 | var dir = res[1] || ''; | ||
499 | //var hash = res[2]; | ||
500 | var base = res[3]; | ||
501 | var ext = res[4]; | ||
502 | var id; | ||
503 | if (ext === 'js') { | ||
504 | id = dir + base; | ||
505 | file = file.substring(0, file.length - ext.length - 1); | ||
506 | } else if (ext === 'html') { | ||
507 | id = 'text!' + dir + base + '.' + ext; | ||
508 | } | ||
509 | grunt.log.oklns('map: ' + id + ' -> ' + file); | ||
510 | lines.push('require.paths[' + JSON.stringify(id) + ']=' + JSON.stringify(file) + ';\n'); | ||
511 | }); | ||
512 | grunt.file.write('.tmp/scripts/config.js', lines.join('')); | ||
513 | }); | ||
514 | |||
515 | grunt.registerTask('serve', function (target) { | ||
516 | if (target === 'dist') { | ||
517 | return grunt.task.run(['build', 'connect:dist:keepalive']); | ||
518 | } | ||
519 | |||
520 | grunt.task.run([ | ||
521 | 'clean:server', | ||
522 | 'concurrent:server', | ||
523 | 'autoprefixer', | ||
524 | 'connect:app', | ||
525 | 'watch' | ||
526 | ]); | ||
527 | }); | ||
528 | |||
529 | grunt.registerTask('server', function () { | ||
530 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); | ||
531 | grunt.task.run(['serve']); | ||
532 | }); | ||
533 | |||
534 | grunt.registerTask('test', function(target) { | ||
535 | if (target !== 'watch') { | ||
536 | grunt.task.run([ | ||
537 | 'clean:server', | ||
538 | 'concurrent:test', | ||
539 | 'autoprefixer', | ||
540 | ]); | ||
541 | } | ||
542 | |||
543 | grunt.task.run([ | ||
544 | 'connect:test', | ||
545 | 'mocha' | ||
546 | ]); | ||
547 | }); | ||
548 | |||
549 | grunt.registerTask('build', [ | ||
550 | 'clean:dist', | ||
551 | 'useminPrepare', | ||
552 | 'requirejs', | ||
553 | 'concurrent:dist', | ||
554 | 'autoprefixer', | ||
555 | 'concat', | ||
556 | // 'cssmin', | ||
557 | 'uglify:dist', | ||
558 | 'copy:dist', | ||
559 | // 'rev:dist', | ||
560 | 'revconfig', | ||
561 | 'uglify:requireconfig', | ||
562 | // 'rev:requireconfig', | ||
563 | 'usemin', | ||
564 | 'htmlmin' | ||
565 | ]); | ||
566 | |||
567 | grunt.registerTask('dist', [ | ||
568 | 'bower', | ||
569 | 'newer:jshint', | ||
570 | // 'test', | ||
571 | 'build' | ||
572 | ]); | ||
573 | grunt.registerTask('default', []); | ||
574 | }; |
bower.json
0 → 100644
1 | { | ||
2 | "name": "rivets-error-binder", | ||
3 | "version": "0.0.0", | ||
4 | "authors": [ | ||
5 | "Adam Heath <doogie@brainfood.com>" | ||
6 | ], | ||
7 | "main": [ | ||
8 | "src/scripts/rivets-error-binder.js" | ||
9 | ], | ||
10 | "private": true, | ||
11 | "ignore": [ | ||
12 | "**/.*", | ||
13 | "node_modules", | ||
14 | "src/lib", | ||
15 | "test" | ||
16 | ], | ||
17 | "dependencies": { | ||
18 | "backbone-seen": "git@gitlab.brainfood.com:brainfood/backbone-seen.git", | ||
19 | "backbone": "~1.1.0", | ||
20 | "backbone-validation": "0.9.1", | ||
21 | "jquery": "~1.10.2", | ||
22 | "requirejs": "~2.1.10", | ||
23 | "rivets": "~0.6.6", | ||
24 | "underscore": "~1.6.0" | ||
25 | }, | ||
26 | "devDependencies": { | ||
27 | "rivets-backbone-adapter": "~1.1.1" | ||
28 | } | ||
29 | } |
package.json
0 → 100644
1 | { | ||
2 | "name": "rivets-error-binder", | ||
3 | "version": "0.0.0", | ||
4 | "main": [ | ||
5 | "src/scripts/rivets-error-binder.js" | ||
6 | ], | ||
7 | "dependencies": { | ||
8 | "rivets": "~0.6.6", | ||
9 | "requirejs": "~2.1.10" | ||
10 | }, | ||
11 | "devDependencies": { | ||
12 | "bower-requirejs": "~0.9.2", | ||
13 | "grunt": "~0.4.1", | ||
14 | "grunt-contrib-copy": "~0.4.1", | ||
15 | "grunt-contrib-concat": "~0.3.0", | ||
16 | "grunt-contrib-uglify": "~0.2.0", | ||
17 | "grunt-contrib-jshint": "~0.7.0", | ||
18 | "grunt-contrib-cssmin": "~0.7.0", | ||
19 | "grunt-contrib-connect": "~0.5.0", | ||
20 | "grunt-contrib-clean": "~0.5.0", | ||
21 | "grunt-contrib-htmlmin": "~0.1.3", | ||
22 | "grunt-bower-install": "~0.7.0", | ||
23 | "grunt-contrib-imagemin": "~0.2.0", | ||
24 | "grunt-contrib-watch": "~0.5.2", | ||
25 | "grunt-rev": "~0.1.0", | ||
26 | "grunt-autoprefixer": "~0.5.0", | ||
27 | "grunt-usemin": "~0.1.10", | ||
28 | "grunt-mocha": "~0.4.0", | ||
29 | "grunt-newer": "~0.6.0", | ||
30 | "grunt-svgmin": "~0.2.0", | ||
31 | "grunt-concurrent": "~0.4.0", | ||
32 | "load-grunt-tasks": "~0.2.0", | ||
33 | "time-grunt": "~0.2.0", | ||
34 | "jshint-stylish": "~0.1.3", | ||
35 | "grunt-contrib-requirejs": "~0.4.0", | ||
36 | "grunt-bower-requirejs": "~0.8.4", | ||
37 | "grunt-template-jasmine-istanbul": "~0.2.6", | ||
38 | "grunt-template-jasmine-requirejs": "~0.1.10", | ||
39 | "grunt-contrib-jasmine": "~0.5.3" | ||
40 | }, | ||
41 | "engines": { | ||
42 | "node": ">=0.8.0" | ||
43 | } | ||
44 | } | ||
45 |
rivets-error-binder.js
deleted
100644 → 0
1 | define(['rivets', 'bootstrap'], function(rivets) { | ||
2 | var rivetsBinderCall = function(binding, binderName, methodName, args) { | ||
3 | var binder = rivets.binders[binderName]; | ||
4 | if (binder instanceof Function) { | ||
5 | if (methodName == 'routine') { | ||
6 | binder.apply(binding, args); | ||
7 | }; | ||
8 | } else if (binder) { | ||
9 | if (binder[methodName]) { | ||
10 | binder[methodName].apply(binding, args); | ||
11 | } | ||
12 | } | ||
13 | } | ||
14 | |||
15 | var diveIntoObject = function(obj, keypath, callback) { | ||
16 | if (!keypath) { | ||
17 | return callback(obj, null); | ||
18 | } | ||
19 | //return callback(obj, keypath); | ||
20 | var keyparts = keypath.replace(/^:/, '').split(/\:/); | ||
21 | //console.log('diveIntoObject(keyparts):', obj, keyparts); | ||
22 | while (keyparts.length > 1) { | ||
23 | var part = keyparts.shift(); | ||
24 | if (part.length == 0) { | ||
25 | continue; | ||
26 | } | ||
27 | //console.log('diveIntoObject:', obj, part); | ||
28 | obj = doObjectRead(obj, part); | ||
29 | } | ||
30 | //console.log('callback:', obj, keyparts[0]); | ||
31 | return callback(obj, keyparts.shift()); | ||
32 | }; | ||
33 | |||
34 | var doObjectRead = function(obj, id) { | ||
35 | if (obj === null) return obj; | ||
36 | if (!id) return obj; | ||
37 | //console.log('doObjectRead:', obj, id, obj instanceof Backbone.Model, obj instanceof Backbone.Collection); | ||
38 | if (obj instanceof Backbone.Model) { | ||
39 | return obj.get(id); | ||
40 | } else if (obj instanceof Backbone.Collection) { | ||
41 | return obj.at(id); | ||
42 | } else if (obj != null) { | ||
43 | return obj[id]; | ||
44 | } | ||
45 | }; | ||
46 | |||
47 | rivets.binders['error-*'] = { | ||
48 | bind: function(el) { | ||
49 | var self = this; | ||
50 | var holder = this.validationHolder = { | ||
51 | //marker: el.parentNode.insertBefore(document.createComment(" rivets: " + this.type + " "), el), | ||
52 | focus: function() { | ||
53 | $(holder.container).removeClass('focused'); | ||
54 | }, | ||
55 | blur: function() { | ||
56 | if (holder.lastObj) holder.lastObj.seen(holder.lastId, true); | ||
57 | $(holder.container).addClass('focused'); | ||
58 | if (holder.lastObj) holder.lastObj.validate(); | ||
59 | }, | ||
60 | validated: function(isValid, model, errors) { | ||
61 | var errorList = errors[holder.lastId]; | ||
62 | if (errorList && holder.lastObj.seen(holder.lastId)) { | ||
63 | $(el).tooltip({title: errorList, trigger: 'focus'}); | ||
64 | $(el).tooltip('show'); | ||
65 | $(el).parent().addClass('has-error'); | ||
66 | } else { | ||
67 | $(el).tooltip('destroy'); | ||
68 | $(el).parent().removeClass('has-error'); | ||
69 | } | ||
70 | } | ||
71 | }; | ||
72 | $(el).on('focus', holder.focus).on('blur', holder.blur); | ||
73 | rivetsBinderCall(this, this.args[0], 'bind', arguments); | ||
74 | }, | ||
75 | unbind: function(el) { | ||
76 | var holder = this.validationHolder; | ||
77 | $(this.validationHolder.marker).after(el).remove(); | ||
78 | $(el).off('focus', holder.focus).off('blur', holder.blur); | ||
79 | diveIntoObject(this.model, this.keypath, function(obj, id) { | ||
80 | obj.off('validated', holder.validated); | ||
81 | }); | ||
82 | delete this.validationHolder; | ||
83 | rivetsBinderCall(this, this.args[0], 'unbind', arguments); | ||
84 | }, | ||
85 | routine: function(el, value) { | ||
86 | var holder = this.validationHolder; | ||
87 | if (holder.lastObj) { | ||
88 | holder.lastObj.off('validated', holder.validated); | ||
89 | } | ||
90 | diveIntoObject(this.observer.target, this.observer.key.path, function(obj, id) { | ||
91 | holder.lastObj = obj; | ||
92 | holder.lastId = id; | ||
93 | obj.on('validated', holder.validated); | ||
94 | }); | ||
95 | rivetsBinderCall(this, this.args[0], 'routine', arguments); | ||
96 | } | ||
97 | }; | ||
98 | }); |
src/scripts/Backbone.js
0 → 100644
src/scripts/config.js
0 → 100644
1 | /* global require:true */ | ||
2 | var require; | ||
3 | require = (function() { | ||
4 | 'use strict'; | ||
5 | |||
6 | var require = { | ||
7 | baseUrl: 'scripts', | ||
8 | config: { | ||
9 | 'rivets-error-binder': {} | ||
10 | }, | ||
11 | shim: { | ||
12 | bootstrap: { | ||
13 | deps: [ | ||
14 | 'jquery' | ||
15 | ] | ||
16 | }, | ||
17 | rivets: { | ||
18 | deps: [ | ||
19 | 'jquery' | ||
20 | ] | ||
21 | } | ||
22 | }, | ||
23 | paths: { | ||
24 | 'backbone-validation': '../lib/backbone-validation/dist/backbone-validation-amd', | ||
25 | backbone: '../lib/backbone/backbone', | ||
26 | underscore: '../lib/underscore/underscore', | ||
27 | rivets: '../lib/rivets/dist/rivets', | ||
28 | bootstrap: '../lib/bootstrap/dist/js/bootstrap', | ||
29 | jquery: '../lib/jquery/dist/jquery', | ||
30 | 'rivets-backbone-adapter': '../lib/rivets-backbone-adapter/rivets-backbone', | ||
31 | 'backbone-seen': '../lib/backbone-seen/src/scripts/backbone-seen' | ||
32 | } | ||
33 | }; | ||
34 | |||
35 | return require; | ||
36 | })(); |
src/scripts/main.js
0 → 100644
src/scripts/rivets-error-binder.js
0 → 100644
1 | define([ | ||
2 | 'module', | ||
3 | 'rivets', | ||
4 | ], function( | ||
5 | module, | ||
6 | rivets | ||
7 | ) { | ||
8 | 'use strict'; | ||
9 | var rivetsBinderCall = function(binding, binderName, methodName, args) { | ||
10 | var binder = rivets.binders[binderName]; | ||
11 | binder[methodName].apply(binding, args); | ||
12 | }; | ||
13 | |||
14 | var render = function() { | ||
15 | var renderImpl = module.config().render; | ||
16 | if (renderImpl) { | ||
17 | return renderImpl.apply(this, arguments); | ||
18 | } | ||
19 | }; | ||
20 | |||
21 | rivets.binders['error-*'] = { | ||
22 | bind: function(el) { | ||
23 | var holder = this.validationHolder = { | ||
24 | //marker: el.parentNode.insertBefore(document.createComment(" rivets: " + this.type + " "), el), | ||
25 | focus: function() { | ||
26 | render(el, 'focus', false); | ||
27 | }, | ||
28 | blur: function() { | ||
29 | if (holder.observer && holder.observer.target) { | ||
30 | holder.observer.target.seen(holder.observer.key.path, true); | ||
31 | } | ||
32 | render(el, 'blur', false); | ||
33 | if (holder.observer && holder.observer.target) { | ||
34 | holder.observer.target.validate(); | ||
35 | } | ||
36 | }, | ||
37 | validated: function(isValid, model, errors) { | ||
38 | var errorList = errors[holder.observer.key.path]; | ||
39 | if (errorList && holder.observer.target && holder.observer.target.seen(holder.observer.key.path)) { | ||
40 | render(el, 'validated', errorList); | ||
41 | } else { | ||
42 | render(el, 'validated', false); | ||
43 | } | ||
44 | } | ||
45 | }; | ||
46 | $(el).on('focus', holder.focus).on('blur', holder.blur); | ||
47 | rivetsBinderCall(this, this.args[0], 'bind', arguments); | ||
48 | }, | ||
49 | unbind: function(el) { | ||
50 | var holder = this.validationHolder; | ||
51 | $(this.validationHolder.marker).after(el).remove(); | ||
52 | $(el).off('focus', holder.focus).off('blur', holder.blur); | ||
53 | if (holder.observer.target) { | ||
54 | holder.observer.target.off('validated', holder.validated); | ||
55 | } | ||
56 | delete this.validationHolder; | ||
57 | rivetsBinderCall(this, this.args[0], 'unbind', arguments); | ||
58 | }, | ||
59 | routine: function() { | ||
60 | var holder = this.validationHolder; | ||
61 | if (holder.observer) { | ||
62 | holder.observer.target.off('validated', holder.validated); | ||
63 | } | ||
64 | holder.observer = this.observer; | ||
65 | if (this.observer.target) { | ||
66 | this.observer.target.on('validated', holder.validated); | ||
67 | } | ||
68 | rivetsBinderCall(this, this.args[0], 'routine', arguments); | ||
69 | } | ||
70 | }; | ||
71 | }); |
test/specs/rivets-error-binder.spec.js
0 → 100644
1 | define(function(require) { | ||
2 | 'use strict'; | ||
3 | |||
4 | var $ = require('jquery'); | ||
5 | window.jQuery = $; | ||
6 | var RivetsErrorBinder = require('rivets-error-binder'); | ||
7 | var _ = require('underscore'); | ||
8 | var Backbone = require('backbone'); | ||
9 | var rivets = require('rivets'); | ||
10 | require('backbone-validation'); | ||
11 | var BackboneSeen = require('backbone-seen'); | ||
12 | require('rivets-backbone-adapter'); | ||
13 | _.extend(Backbone.Model.prototype, Backbone.Validation.mixin); | ||
14 | //rivets.config.rootInterface = ':'; | ||
15 | |||
16 | describe('RivetsErrorBinder', function() { | ||
17 | it('exists', function() { | ||
18 | expect(RivetsErrorBinder).toBeUndefined(); | ||
19 | }); | ||
20 | }); | ||
21 | describe('RivetsErrorBinder', function() { | ||
22 | var Model, Collection; | ||
23 | var scope; | ||
24 | var test; | ||
25 | var view; | ||
26 | var render; | ||
27 | beforeEach(function() { | ||
28 | render = function(el, cmd, errorList) { | ||
29 | render.lastCmd = cmd; | ||
30 | render.lastErrorList = errorList; | ||
31 | switch (cmd) { | ||
32 | case 'focus': | ||
33 | render.counts.focus++; | ||
34 | break; | ||
35 | case 'blur': | ||
36 | render.counts.blur++; | ||
37 | break; | ||
38 | case 'validated': | ||
39 | if (errorList) { | ||
40 | render.counts.validatedError++; | ||
41 | } else { | ||
42 | render.counts.validatedClean++; | ||
43 | } | ||
44 | break; | ||
45 | } | ||
46 | }; | ||
47 | render.counts = {focus: 0, blur: 0, validatedError: 0, validatedClean: 0}; | ||
48 | |||
49 | jasmine.Clock.useMock(); | ||
50 | Model = BackboneSeen.mixin(Backbone.Model.extend()); | ||
51 | Collection = Backbone.Collection.extend({model: Model}); | ||
52 | |||
53 | scope = new Model({ | ||
54 | test: test = new Model({ | ||
55 | constant: 'CONSTANT' | ||
56 | }) | ||
57 | }); | ||
58 | test.validation = { | ||
59 | constant: {required: true} | ||
60 | }; | ||
61 | }); | ||
62 | afterEach(function() { | ||
63 | view.unbind(); | ||
64 | }); | ||
65 | |||
66 | |||
67 | it('existing-no-render', function() { | ||
68 | var $node = $($.parseHTML('<div><form><input id="_1" rv-error-value="test:constant" /></form></div>')); | ||
69 | $(document).find('body').append($node[0]); | ||
70 | var $1 = $node.find('#_1'); | ||
71 | expect($1.length).toEqual(1); | ||
72 | expect($1.val()).toEqual(''); | ||
73 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
74 | view = rivets.bind($node, scope.attributes); | ||
75 | expect(view).toBeTruthy(); | ||
76 | expect($1.val()).toEqual('CONSTANT'); | ||
77 | //expect($node.html()).toBe(''); | ||
78 | test.set('constant', 'one'); | ||
79 | expect($1.val()).toEqual('one'); | ||
80 | test.set('constant', ''); | ||
81 | expect($1.val()).toEqual(''); | ||
82 | test.set('constant', 'CONSTANT'); | ||
83 | expect($1.val()).toEqual('CONSTANT'); | ||
84 | |||
85 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
86 | $1.focus().val('one').change().blur(); | ||
87 | jasmine.Clock.tick(1); | ||
88 | expect(test.get('constant')).toEqual('one'); | ||
89 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
90 | |||
91 | $1.focus().val('').change().blur(); | ||
92 | jasmine.Clock.tick(1); | ||
93 | expect(test.get('constant')).toEqual(''); | ||
94 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
95 | jasmine.Clock.tick(1); | ||
96 | expect(render.lastErrorList).toBeUndefined(); | ||
97 | }); | ||
98 | it('existing-with-render', function() { | ||
99 | /* global requirejs */ | ||
100 | requirejs.config({config: {'rivets-error-binder': { render: render } } }); | ||
101 | var $node = $($.parseHTML('<div><form><input id="_1" rv-error-value="test:constant" /></form></div>')); | ||
102 | $(document).find('body').append($node[0]); | ||
103 | var $1 = $node.find('#_1'); | ||
104 | expect($1.length).toEqual(1); | ||
105 | expect($1.val()).toEqual(''); | ||
106 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
107 | view = rivets.bind($node, scope.attributes); | ||
108 | expect(view).toBeTruthy(); | ||
109 | expect($1.val()).toEqual('CONSTANT'); | ||
110 | //expect($node.html()).toBe(''); | ||
111 | test.set('constant', 'one'); | ||
112 | expect($1.val()).toEqual('one'); | ||
113 | test.set('constant', ''); | ||
114 | expect($1.val()).toEqual(''); | ||
115 | test.set('constant', 'CONSTANT'); | ||
116 | expect($1.val()).toEqual('CONSTANT'); | ||
117 | |||
118 | expect(render.counts).toEqual({focus : 0, blur : 0, validatedError : 0, validatedClean : 0}); | ||
119 | $1.focus().val('one').change().blur(); | ||
120 | jasmine.Clock.tick(1); | ||
121 | expect(test.get('constant')).toEqual('one'); | ||
122 | expect(render.counts).toEqual({focus : 1, blur : 1, validatedError : 0, validatedClean : 1}); | ||
123 | |||
124 | $1.focus().val('').change().blur(); | ||
125 | jasmine.Clock.tick(1); | ||
126 | expect(test.get('constant')).toEqual(''); | ||
127 | expect(render.counts).toEqual({focus : 2, blur : 2, validatedError : 1, validatedClean : 1}); | ||
128 | jasmine.Clock.tick(1); | ||
129 | expect(render.lastErrorList).toEqual(jasmine.any(String)); | ||
130 | }); | ||
131 | it('missing', function() { | ||
132 | var $node = $($.parseHTML('<div><form><input id="_1" rv-error-value="test:missing:child" /></form></div>')); | ||
133 | $(document).find('body').append($node[0]); | ||
134 | var $1 = $node.find('#_1'); | ||
135 | expect($1.length).toEqual(1); | ||
136 | expect($1.val()).toEqual(''); | ||
137 | view = rivets.bind($node, scope.attributes); | ||
138 | expect(view).toBeTruthy(); | ||
139 | expect($1.val()).toEqual(''); | ||
140 | |||
141 | $1.focus().val('one').change().blur(); | ||
142 | jasmine.Clock.tick(1); | ||
143 | }); | ||
144 | }); | ||
145 | }); |
-
Please register or sign in to post a comment