From 49cc55a5195741c60b0e0294363ba9f9a5a4c948 Mon Sep 17 00:00:00 2001
From: mistic100
Date: Sat, 21 Jan 2017 14:57:41 +0100
Subject: [PATCH 001/107] Revamp grunt config
---
Gruntfile.js | 401 ++++----------
build/cleanLn.js | 3 +
build/initConfig.js | 68 +++
build/processLang.js | 30 +
build/removeJshint.js | 5 +
build/tasks/describeErrors.js | 39 ++
build/tasks/describeTriggers.js | 36 ++
build/tasks/listModules.js | 23 +
examples/index.html | 936 +++++++++++++++++---------------
package.json | 4 +-
src/scss/default.scss | 3 +
tests/index.html | 65 ++-
12 files changed, 828 insertions(+), 785 deletions(-)
create mode 100644 build/cleanLn.js
create mode 100644 build/initConfig.js
create mode 100644 build/processLang.js
create mode 100644 build/removeJshint.js
create mode 100644 build/tasks/describeErrors.js
create mode 100644 build/tasks/describeTriggers.js
create mode 100644 build/tasks/listModules.js
diff --git a/Gruntfile.js b/Gruntfile.js
index 36ab0d62..3725a9be 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,52 +1,23 @@
-var deepmerge = require('deepmerge');
+var initConfig = require('./build/initConfig');
+var processLang = require('./build/processLang');
+var removeJshint = require('./build/removeJshint');
+var cleanLn = require('./build/cleanLn');
+var taskDescribeTriggers = require('./build/tasks/describeTriggers');
+var taskDescribeErrors = require('./build/tasks/describeErrors');
+var taskListModules = require('./build/tasks/listModules');
module.exports = function(grunt) {
require('time-grunt')(grunt);
require('jit-grunt')(grunt, {
- scsslint: 'grunt-scss-lint'
+ scsslint: 'grunt-scss-lint',
+ sass_injection: 'grunt-sass-injection',
+ usebanner: 'grunt-banner'
});
grunt.util.linefeed = '\n';
- function removeJshint(src) {
- return src
- .replace(/\/\*jshint [a-z:]+ \*\/\r?\n\r?\n?/g, '')
- .replace(/\/\*jshint -[EWI]{1}[0-9]{3} \*\/\r?\n\r?\n?/g, '');
- }
-
- function process_lang(file, src, wrapper) {
- var lang = file.split(/[\/\.]/)[2];
- var content = JSON.parse(src);
- wrapper = wrapper || ['', ''];
-
- grunt.config.set('lang_locale', content.__locale || lang);
- grunt.config.set('lang_author', content.__author);
- var header = grunt.template.process('<%= langBanner %>');
-
- loaded_plugins.forEach(function(p) {
- var plugin_file = 'src/plugins/' + p + '/i18n/' + lang + '.json';
-
- if (grunt.file.exists(plugin_file)) {
- content = deepmerge(content, grunt.file.readJSON(plugin_file));
- }
- });
-
- return header
- + '\n\n'
- + wrapper[0]
- + 'QueryBuilder.regional[\'' + lang + '\'] = '
- + JSON.stringify(content, null, 2)
- + ';\n\n'
- + 'QueryBuilder.defaults({ lang_code: \'' + lang + '\' });'
- + wrapper[1];
- }
-
-
- var all_plugins = {},
- all_langs = {},
- loaded_plugins = [],
- loaded_langs = [],
- js_core_files = [
+ var config = initConfig(grunt, {
+ js_core_files: [
'src/main.js',
'src/defaults.js',
'src/core.js',
@@ -57,88 +28,23 @@ module.exports = function(grunt) {
'src/utils.js',
'src/jquery.js'
],
- js_files_to_load = js_core_files.slice(),
- all_js_files = js_core_files.slice(),
- js_files_for_standalone = [
+ js_files_for_standalone: [
'bower_components/jquery-extendext/jQuery.extendext.js',
'bower_components/doT/doT.js',
'dist/js/query-builder.js'
- ];
-
-
- (function() {
- // list available plugins and languages
- grunt.file.expand('src/plugins/**/plugin.js')
- .forEach(function(f) {
- var n = f.split('/')[2];
- all_plugins[n] = f;
- });
-
- grunt.file.expand('src/i18n/*.json')
- .forEach(function(f) {
- var n = f.split(/[\/\.]/)[2];
- all_langs[n] = f;
- });
-
- // fill all js files
- for (var p in all_plugins) {
- all_js_files.push(all_plugins[p]);
- }
-
- // parse 'plugins' parameter
- var arg_plugins = grunt.option('plugins');
- if (typeof arg_plugins === 'string') {
- arg_plugins.replace(/ /g, '').split(',').forEach(function(p) {
- if (all_plugins[p]) {
- js_files_to_load.push(all_plugins[p]);
- loaded_plugins.push(p);
- }
- else {
- grunt.fail.warn('Plugin ' + p + ' unknown');
- }
- });
- }
- else if (arg_plugins === undefined) {
- for (var p in all_plugins) {
- js_files_to_load.push(all_plugins[p]);
- loaded_plugins.push(p);
- }
- }
-
- // default language
- js_files_to_load.push('.temp/i18n/en.js');
- loaded_langs.push('en');
-
- // parse 'lang' parameter
- var arg_langs = grunt.option('languages');
- if (typeof arg_langs === 'string') {
- arg_langs.replace(/ /g, '').split(',').forEach(function(l) {
- if (all_langs[l]) {
- if (l !== 'en') {
- js_files_to_load.push(all_langs[l].replace(/^src/, '.temp').replace(/json$/, 'js'));
- loaded_langs.push(l);
- }
- }
- else {
- grunt.fail.warn('Language ' + l + ' unknown');
- }
- });
- }
- }());
-
+ ]
+ });
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
- banner:
- '/*!\n' +
+ banner: '/*!\n' +
' * jQuery QueryBuilder <%= pkg.version %>\n' +
' * Copyright 2014-<%= grunt.template.today("yyyy") %> Damien "Mistic" Sorel (http://www.strangeplanet.fr)\n' +
' * Licensed under MIT (http://opensource.org/licenses/MIT)\n' +
' */',
- langBanner:
- '/*!\n' +
+ langBanner: '/*!\n' +
' * jQuery QueryBuilder <%= pkg.version %>\n' +
' * Locale: <%= lang_locale %>\n' +
'<% if (lang_author) { %> * Author: <%= lang_author %>\n<% } %>' +
@@ -163,7 +69,7 @@ module.exports = function(grunt) {
},
js: {
files: ['src/*.js', 'src/plugins/**/plugin.js'],
- tasks: ['build_js']
+ tasks: ['injector:example']
},
css: {
files: ['src/scss/*.scss', 'src/plugins/**/plugin.scss'],
@@ -197,10 +103,10 @@ module.exports = function(grunt) {
}]
},
sass_plugins: {
- files: loaded_plugins.map(function(name) {
+ files: config.loaded_plugins.map(function(name) {
return {
src: 'src/plugins/' + name + '/plugin.scss',
- dest: 'dist/scss/plugins/' + name + '.scss'
+ dest: 'dist/scss/plugins/_' + name + '.scss'
};
})
}
@@ -209,19 +115,19 @@ module.exports = function(grunt) {
concat: {
// concat all JS
js: {
- src: js_files_to_load,
+ src: config.js_files_to_load,
dest: 'dist/js/query-builder.js',
options: {
stripBanners: false,
separator: '\n\n',
process: function(src) {
- return removeJshint(src).replace(/\r\n/g, '\n');
+ return cleanLn(removeJshint(src));
}
}
},
// create standalone version
js_standalone: {
- src: js_files_for_standalone,
+ src: config.js_files_for_standalone,
dest: 'dist/js/query-builder.standalone.js',
options: {
stripBanners: false,
@@ -229,15 +135,14 @@ module.exports = function(grunt) {
process: function(src, file) {
var name = file.match(/([^\/]+?).js$/)[1];
- return removeJshint(src)
- .replace(/\r\n/g, '\n')
+ return cleanLn(removeJshint(src))
.replace(/define\((.*?)\);/, 'define(\'' + name + '\', $1);');
}
}
},
// compile language files with AMD wrapper
lang: {
- files: Object.keys(all_langs).map(function(name) {
+ files: Object.keys(config.all_langs).map(function(name) {
return {
src: 'src/i18n/' + name + '.json',
dest: 'dist/i18n/query-builder.' + name + '.js'
@@ -245,14 +150,14 @@ module.exports = function(grunt) {
}),
options: {
process: function(src, file) {
- var wrapper = grunt.file.read('src/i18n/.wrapper.js').replace(/\r\n/g, '\n').split(/@@js\n/);
- return process_lang(file, src, wrapper);
+ var wrapper = cleanLn(grunt.file.read('src/i18n/.wrapper.js')).split(/@@js\n/);
+ return processLang(grunt, config.loaded_plugins)(file, src, wrapper);
}
}
},
- // compile language files without wrapper
+ // compile language files without AMD wrapper
lang_temp: {
- files: Object.keys(all_langs).map(function(name) {
+ files: Object.keys(config.all_langs).map(function(name) {
return {
src: 'src/i18n/' + name + '.json',
dest: '.temp/i18n/' + name + '.js'
@@ -260,60 +165,50 @@ module.exports = function(grunt) {
}),
options: {
process: function(src, file) {
- return process_lang(file, src);
+ return processLang(grunt, config.loaded_plugins)(file, src);
}
}
- },
- // add banner to CSS files
- css: {
- options: {
- banner: '<%= banner %>\n\n',
- },
- files: [{
- expand: true,
- src: ['dist/css/*.css', 'dist/scss/*.scss'],
- dest: ''
- }]
}
},
+ // add AMD wrapper
wrap: {
- // add AMD wrapper and banner
js: {
src: ['dist/js/query-builder.js'],
dest: '',
options: {
separator: '',
wrapper: function() {
- var wrapper = grunt.file.read('src/.wrapper.js').replace(/\r\n/g, '\n').split(/@@js\n/);
-
- if (loaded_plugins.length) {
- wrapper[0] = '// Plugins: ' + loaded_plugins.join(', ') + '\n' + wrapper[0];
- }
- if (loaded_langs.length) {
- wrapper[0] = '// Languages: ' + loaded_langs.join(', ') + '\n' + wrapper[0];
- }
- wrapper[0] = grunt.template.process('<%= banner %>\n\n') + wrapper[0];
-
- return wrapper;
+ return cleanLn(grunt.file.read('src/.wrapper.js')).split(/@@js\n/);
}
}
+ }
+ },
+
+ // add banners
+ usebanner: {
+ options: {
+ banner: '<%= banner %>'
},
- // add plugins SASS imports
- sass: {
- src: ['dist/scss/default.scss'],
- dest: '',
+ js: {
+ src: ['dist/js/*.js']
+ },
+ css: {
+ src: ['dist/css/*.css', 'dist/css/*.scss']
+ }
+ },
+
+ // add plugins SASS imports
+ sass_injection: {
+ dist: {
options: {
- separator: '',
- wrapper: function() {
- return ['', loaded_plugins.reduce(function(wrapper, name) {
- if (grunt.file.exists('dist/scss/plugins/' + name + '.scss')) {
- wrapper += '\n@import \'plugins/' + name + '\';';
- }
- return wrapper;
- }, '\n')];
+ replacePath: {
+ pattern: 'dist/scss/',
+ replace: ''
}
- }
+ },
+ src: ['dist/scss/plugins/*.scss'],
+ target: 'dist/scss/default.scss'
}
},
@@ -340,7 +235,7 @@ module.exports = function(grunt) {
// compress js
uglify: {
options: {
- banner: '<%= banner %>\n\n',
+ banner: '<%= banner %>\n',
mangle: { except: ['$'] }
},
dist: {
@@ -380,7 +275,7 @@ module.exports = function(grunt) {
options: {
jshintrc: '.jshintrc'
},
- src: js_files_to_load
+ src: ['src/**/*.js', '!src/**/.wrapper.js']
}
},
@@ -390,7 +285,7 @@ module.exports = function(grunt) {
options: {
config: '.jscsrc'
},
- src: js_files_to_load
+ src: ['src/**/*.js', '!src/**/.wrapper.js']
}
},
@@ -405,42 +300,32 @@ module.exports = function(grunt) {
}
},
- // inject all source files and test modules in the test file
- 'string-replace': {
- test: {
- src: 'tests/index.html',
- dest: 'tests/index.html',
+ // inject sources files and tests modules in demo and test
+ injector: {
+ options: {
+ relative: true,
+ addRootSlash: false
+ },
+ example: {
+ src: config.all_js_files.concat(['dist/i18n/query-builder.en.js']),
+ dest: 'examples/index.html'
+ },
+ testSrc: {
options: {
- replacements: [{
- pattern: /()(?:[\s\S]*)()/m,
- replacement: function(match, m1, m2) {
- var scripts = '\n';
-
- js_core_files.forEach(function(file) {
- scripts += '\n';
- });
-
- scripts += '\n';
-
- for (var p in all_plugins) {
- scripts += '\n';
- }
-
- return m1 + scripts + m2;
- }
- }, {
- pattern: /()(?:[\s\S]*)()/m,
- replacement: function(match, m1, m2) {
- var scripts = '\n';
-
- grunt.file.expand('tests/*.module.js').forEach(function(file) {
- scripts += '\n';
- });
-
- return m1 + scripts + m2;
- }
- }]
- }
+ starttag: '',
+ transform: function(filepath) {
+ return '';
+ }
+ },
+ src: config.all_js_files,
+ dest: 'tests/index.html'
+ },
+ testModules: {
+ options: {
+ starttag: ''
+ },
+ src: ['tests/*.module.js'],
+ dest: 'tests/index.html'
}
},
@@ -473,115 +358,23 @@ module.exports = function(grunt) {
force: true
},
all: {
- src: '.coverage-results/all.lcov',
+ src: '.coverage-results/all.lcov'
}
}
});
- // list the triggers and changes
- grunt.registerTask('describe_triggers', 'List QueryBuilder triggers.', function() {
- var triggers = {};
- var total = 0;
-
- for (var f in all_js_files) {
- grunt.file.read(all_js_files[f]).split(/\r?\n/).forEach(function(line, i) {
- var matches = /(e = )?(?:this|that)\.(trigger|change)\('(\w+)'([^)]*)\);/.exec(line);
- if (matches !== null) {
- triggers[matches[3]] = {
- name: matches[3],
- type: matches[2],
- file: all_js_files[f],
- line: i,
- args: matches[4].slice(2),
- prevent: !!matches[1]
- };
-
- total++;
- }
- });
- }
-
- grunt.log.write('\n');
-
- for (var t in triggers) {
- grunt.log.write(t['cyan'] + ' ' + triggers[t].type['magenta']);
- if (triggers[t].prevent) grunt.log.write(' (*)'['yellow']);
- grunt.log.write('\n');
- grunt.log.writeln(' ' + (triggers[t].file + ':' + triggers[t].line)['red'] + ' ' + triggers[t].args);
- grunt.log.write('\n');
- }
-
- grunt.log.writeln((total + ' Triggers in QueryBuilder.')['cyan']['bold']);
- });
-
- // list all possible thrown errors
- grunt.registerTask('describe_errors', 'List QueryBuilder errors.', function() {
- var errors = {};
- var total = 0;
-
- for (var f in all_js_files) {
- grunt.file.read(all_js_files[f]).split(/\r?\n/).forEach(function(line, i) {
- var matches = /Utils\.error\('(\w+)', '([^)]+)'([^)]*)\);/.exec(line);
- if (matches !== null) {
- (errors[matches[1]] = errors[matches[1]] || []).push({
- type: matches[1],
- message: matches[2],
- file: all_js_files[f],
- line: i,
- args: matches[3].slice(2).split(', ')
- });
-
- total++;
- }
- });
- }
-
- grunt.log.write('\n');
-
- for (var e in errors) {
- grunt.log.writeln((e + 'Error')['cyan']);
- errors[e].forEach(function(error) {
- var message = error.message.replace(/{([0-9]+)}/g, function(m, i) {
- return error.args[parseInt(i)]['yellow'];
- });
- grunt.log.writeln(' ' + (error.file + ':' + error.line)['red']);
- grunt.log.writeln(' ' + message);
- });
- grunt.log.write('\n');
- }
-
- grunt.log.writeln((total + ' Errors in QueryBuilder.')['cyan']['bold']);
- });
-
- // display available modules
- grunt.registerTask('list_modules', 'List QueryBuilder plugins and languages.', function() {
- grunt.log.writeln('\nAvailable QueryBuilder plugins:\n');
-
- for (var p in all_plugins) {
- grunt.log.write(p['cyan']);
-
- if (grunt.file.exists(all_plugins[p].replace(/js$/, 'scss'))) {
- grunt.log.write(' + CSS');
- }
-
- grunt.log.write('\n');
- }
-
- grunt.log.writeln('\nAvailable QueryBuilder languages:\n');
-
- for (var l in all_langs) {
- if (l !== 'en') {
- grunt.log.writeln(l['cyan']);
- }
- }
- });
+ // custom tasks
+ taskDescribeTriggers(grunt, config);
+ taskDescribeErrors(grunt, config);
+ taskListModules(grunt, config);
grunt.registerTask('build_js', [
'concat:lang_temp',
'concat:js',
'wrap:js',
+ 'usebanner:js',
'concat:js_standalone',
'uglify',
'clean:temp'
@@ -590,10 +383,10 @@ module.exports = function(grunt) {
grunt.registerTask('build_css', [
'copy:sass_core',
'copy:sass_plugins',
- 'wrap:sass',
+ 'sass_injection',
'sass',
'cssmin',
- 'concat:css'
+ 'usebanner:css'
]);
grunt.registerTask('build_lang', [
@@ -610,14 +403,18 @@ module.exports = function(grunt) {
'jshint',
'jscs',
'scsslint',
- 'default',
- 'string-replace:test',
+ 'build_lang',
+ 'build_css',
+ 'injector:testSrc',
+ 'injector:testModules',
'qunit_blanket_lcov',
'qunit'
]);
grunt.registerTask('serve', [
- 'default',
+ 'build_lang',
+ 'build_css',
+ 'injector:example',
'open',
'connect',
'watch'
diff --git a/build/cleanLn.js b/build/cleanLn.js
new file mode 100644
index 00000000..f93432e8
--- /dev/null
+++ b/build/cleanLn.js
@@ -0,0 +1,3 @@
+module.exports = function(src) {
+ return src.replace(/\r\n/g, '\n');
+};
diff --git a/build/initConfig.js b/build/initConfig.js
new file mode 100644
index 00000000..5bb333ee
--- /dev/null
+++ b/build/initConfig.js
@@ -0,0 +1,68 @@
+module.exports = function(grunt, config) {
+ config.all_plugins = {};
+ config.all_langs = {};
+ config.loaded_plugins = [];
+ config.loaded_langs = [];
+ config.js_files_to_load = config.js_core_files.slice();
+ config.all_js_files = config.js_core_files.slice();
+
+ // list available plugins and languages
+ grunt.file.expand('src/plugins/**/plugin.js')
+ .forEach(function(f) {
+ var n = f.split('/')[2];
+ config.all_plugins[n] = f;
+ });
+
+ grunt.file.expand('src/i18n/*.json')
+ .forEach(function(f) {
+ var n = f.split(/[\/\.]/)[2];
+ config.all_langs[n] = f;
+ });
+
+ // fill all js files
+ for (var p in config.all_plugins) {
+ config.all_js_files.push(config.all_plugins[p]);
+ }
+
+ // parse 'plugins' parameter
+ var arg_plugins = grunt.option('plugins');
+ if (typeof arg_plugins === 'string') {
+ arg_plugins.replace(/ /g, '').split(',').forEach(function(p) {
+ if (config.all_plugins[p]) {
+ config.js_files_to_load.push(config.all_plugins[p]);
+ config.loaded_plugins.push(p);
+ }
+ else {
+ grunt.fail.warn('Plugin ' + p + ' unknown');
+ }
+ });
+ }
+ else if (arg_plugins === undefined) {
+ for (var p in config.all_plugins) {
+ config.js_files_to_load.push(config.all_plugins[p]);
+ config.loaded_plugins.push(p);
+ }
+ }
+
+ // default language
+ config.js_files_to_load.push('.temp/i18n/en.js');
+ config.loaded_langs.push('en');
+
+ // parse 'lang' parameter
+ var arg_langs = grunt.option('languages');
+ if (typeof arg_langs === 'string') {
+ arg_langs.replace(/ /g, '').split(',').forEach(function(l) {
+ if (config.all_langs[l]) {
+ if (l !== 'en') {
+ config.js_files_to_load.push(config.all_langs[l].replace(/^src/, '.temp').replace(/json$/, 'js'));
+ config.loaded_langs.push(l);
+ }
+ }
+ else {
+ grunt.fail.warn('Language ' + l + ' unknown');
+ }
+ });
+ }
+
+ return config;
+};
diff --git a/build/processLang.js b/build/processLang.js
new file mode 100644
index 00000000..33c6b2c7
--- /dev/null
+++ b/build/processLang.js
@@ -0,0 +1,30 @@
+var deepmerge = require('deepmerge');
+
+module.exports = function(grunt, loaded_plugins) {
+ return function(file, src, wrapper) {
+ var lang = file.split(/[\/\.]/)[2];
+ var content = JSON.parse(src);
+ wrapper = wrapper || ['', ''];
+
+ grunt.config.set('lang_locale', content.__locale || lang);
+ grunt.config.set('lang_author', content.__author);
+ var header = grunt.template.process('<%= langBanner %>');
+
+ loaded_plugins.forEach(function(p) {
+ var plugin_file = 'src/plugins/' + p + '/i18n/' + lang + '.json';
+
+ if (grunt.file.exists(plugin_file)) {
+ content = deepmerge(content, grunt.file.readJSON(plugin_file));
+ }
+ });
+
+ return header
+ + '\n\n'
+ + wrapper[0]
+ + 'QueryBuilder.regional[\'' + lang + '\'] = '
+ + JSON.stringify(content, null, 2)
+ + ';\n\n'
+ + 'QueryBuilder.defaults({ lang_code: \'' + lang + '\' });'
+ + wrapper[1];
+ };
+};
diff --git a/build/removeJshint.js b/build/removeJshint.js
new file mode 100644
index 00000000..4ff583ac
--- /dev/null
+++ b/build/removeJshint.js
@@ -0,0 +1,5 @@
+module.exports = function(src) {
+ return src
+ .replace(/\/\*jshint [a-z:]+ \*\/\r?\n\r?\n?/g, '')
+ .replace(/\/\*jshint -[EWI]{1}[0-9]{3} \*\/\r?\n\r?\n?/g, '');
+};
diff --git a/build/tasks/describeErrors.js b/build/tasks/describeErrors.js
new file mode 100644
index 00000000..c058e6e5
--- /dev/null
+++ b/build/tasks/describeErrors.js
@@ -0,0 +1,39 @@
+module.exports = function(grunt, config) {
+ grunt.registerTask('describe_errors', 'List QueryBuilder errors.', function() {
+ var errors = {};
+ var total = 0;
+
+ for (var f in config.all_js_files) {
+ grunt.file.read(config.all_js_files[f]).split(/\r?\n/).forEach(function(line, i) {
+ var matches = /Utils\.error\((?:[^)]+, )?'(\w+)', '([^)]+)'([^)]*)\);/.exec(line);
+ if (matches !== null) {
+ (errors[matches[1]] = errors[matches[1]] || []).push({
+ type: matches[1],
+ message: matches[2],
+ file: config.all_js_files[f],
+ line: i,
+ args: matches[3].slice(2).split(', ')
+ });
+
+ total++;
+ }
+ });
+ }
+
+ grunt.log.write('\n');
+
+ for (var e in errors) {
+ grunt.log.writeln((e + 'Error')['cyan']);
+ errors[e].forEach(function(error) {
+ var message = error.message.replace(/{([0-9]+)}/g, function(m, i) {
+ return error.args[parseInt(i)]['yellow'];
+ });
+ grunt.log.writeln(' ' + (error.file + ':' + error.line)['red']);
+ grunt.log.writeln(' ' + message);
+ });
+ grunt.log.write('\n');
+ }
+
+ grunt.log.writeln((total + ' Errors in QueryBuilder.')['cyan']['bold']);
+ });
+};
diff --git a/build/tasks/describeTriggers.js b/build/tasks/describeTriggers.js
new file mode 100644
index 00000000..68b36ec9
--- /dev/null
+++ b/build/tasks/describeTriggers.js
@@ -0,0 +1,36 @@
+module.exports = function(grunt, config) {
+ grunt.registerTask('describe_triggers', 'List QueryBuilder triggers.', function() {
+ var triggers = {};
+ var total = 0;
+
+ for (var f in config.all_js_files) {
+ grunt.file.read(config.all_js_files[f]).split(/\r?\n/).forEach(function(line, i) {
+ var matches = /(e = )?(?:this|that)\.(trigger|change)\('(\w+)'([^)]*)\);/.exec(line);
+ if (matches !== null) {
+ triggers[matches[3]] = {
+ name: matches[3],
+ type: matches[2],
+ file: config.all_js_files[f],
+ line: i,
+ args: matches[4].slice(2),
+ prevent: !!matches[1]
+ };
+
+ total++;
+ }
+ });
+ }
+
+ grunt.log.write('\n');
+
+ for (var t in triggers) {
+ grunt.log.write(t['cyan'] + ' ' + triggers[t].type['magenta']);
+ if (triggers[t].prevent) grunt.log.write(' (*)'['yellow']);
+ grunt.log.write('\n');
+ grunt.log.writeln(' ' + (triggers[t].file + ':' + triggers[t].line)['red'] + ' ' + triggers[t].args);
+ grunt.log.write('\n');
+ }
+
+ grunt.log.writeln((total + ' Triggers in QueryBuilder.')['cyan']['bold']);
+ });
+};
diff --git a/build/tasks/listModules.js b/build/tasks/listModules.js
new file mode 100644
index 00000000..95d02fbf
--- /dev/null
+++ b/build/tasks/listModules.js
@@ -0,0 +1,23 @@
+module.exports = function(grunt, config) {
+ grunt.registerTask('list_modules', 'List QueryBuilder plugins and languages.', function() {
+ grunt.log.writeln('\nAvailable QueryBuilder plugins:\n');
+
+ for (var p in config.all_plugins) {
+ grunt.log.write(p['cyan']);
+
+ if (grunt.file.exists(config.all_plugins[p].replace(/js$/, 'scss'))) {
+ grunt.log.write(' + CSS');
+ }
+
+ grunt.log.write('\n');
+ }
+
+ grunt.log.writeln('\nAvailable QueryBuilder languages:\n');
+
+ for (var l in config.all_langs) {
+ if (l !== 'en') {
+ grunt.log.writeln(l['cyan']);
+ }
+ }
+ });
+};
diff --git a/examples/index.html b/examples/index.html
index 2f232ee6..054b83ec 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -16,7 +16,9 @@
@@ -28,47 +30,55 @@
- jQuery QueryBuilder Example
+ jQuery QueryBuilder
+ Example
+
-
+
You must execute bower install in the example directory to run this demo.
-
-
+
+
@@ -76,7 +86,9 @@ jQuery QueryBuilder Example
-
+
@@ -112,479 +124,505 @@
Output
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+