diff --git a/.sass-lint.yml b/.sass-lint.yml new file mode 100644 index 00000000..2d387551 --- /dev/null +++ b/.sass-lint.yml @@ -0,0 +1,9 @@ +rules: + property-sort-order: [0] + force-pseudo-nesting: [0] + force-element-nesting: [0] + force-attribute-nesting: [0] + no-important: [0] + no-qualifying-elements: [0] + shorthand-values: [1, {allowed-shorthands: [1, 2, 4]}] + hex-notation: [1, {style: uppercase}] diff --git a/.scss-lint.yml b/.scss-lint.yml deleted file mode 100644 index db8d4f79..00000000 --- a/.scss-lint.yml +++ /dev/null @@ -1,31 +0,0 @@ -linters: - PropertySortOrder: - enabled: false - - SingleLinePerSelector: - enabled: false - - SelectorDepth: - max_depth: 4 - - NestingDepth: - max_depth: 4 - - HexLength: - enabled: false - - HexNotation: - style: uppercase - - Shorthand: - allowed_shorthands: [1, 2, 4] - - QualifyingElement: - enabled: false - - ImportantRule: - enabled: false - - VendorPrefix: - exclude: - - src/scss/_mixins.scss diff --git a/.travis.yml b/.travis.yml index 59e0af84..689c955f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: node_js node_js: - "5" before_install: - - gem install sass - - gem install scss_lint -v 0.49.0 - npm install -g grunt-cli - npm install -g bower before_script: diff --git a/Gruntfile.js b/Gruntfile.js index cfb31c00..40cdd50a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,7 +6,7 @@ var cleanLn = require('./build/cleanLn'); module.exports = function(grunt) { require('time-grunt')(grunt); require('jit-grunt')(grunt, { - scsslint: 'grunt-scss-lint', + sasslint: 'grunt-sass-lint', sass_injection: 'grunt-sass-injection', usebanner: 'grunt-banner' }); @@ -177,7 +177,7 @@ module.exports = function(grunt) { wrap: { js: { src: ['dist/js/query-builder.js'], - dest: '', + dest: 'dist/js/query-builder.js', options: { separator: '', wrapper: function() { @@ -217,8 +217,8 @@ module.exports = function(grunt) { // parse scss sass: { options: { - sourcemap: 'none', - style: 'expanded' + sourceMap: false, + outputStyle: 'expanded' }, dist: { files: [{ @@ -293,11 +293,10 @@ module.exports = function(grunt) { }, // scss tests - scsslint: { + sasslint: { lib: { options: { - colorizeOutput: true, - config: '.scss-lint.yml' + configFile: '.sass-lint.yml' }, src: ['src/**/*.scss'] } @@ -410,7 +409,7 @@ module.exports = function(grunt) { grunt.registerTask('test', [ 'jshint', 'jscs', - 'scsslint', + 'sasslint', 'build_lang', 'build_css', 'injector:testSrc', diff --git a/README.md b/README.md index 1fe97bb1..6798d48e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Bower version](https://img.shields.io/bower/v/jQuery-QueryBuilder.svg?style=flat-square)](http://querybuilder.js.org) [![npm version](https://img.shields.io/npm/v/jQuery-QueryBuilder.svg?style=flat-square)](https://www.npmjs.com/package/jQuery-QueryBuilder) -[![CDN](https://img.shields.io/badge/cdn-jsdelivr-%23EB4C36.svg?style=flat-square)](http://www.jsdelivr.com/projects/jquery.query-builder) +[![jsDelivr CDN](https://data.jsdelivr.com/v1/package/npm/jQuery-QueryBuilder/badge)](https://www.jsdelivr.com/package/npm/jQuery-QueryBuilder) [![Build Status](https://img.shields.io/travis/mistic100/jQuery-QueryBuilder.svg?style=flat-square)](https://travis-ci.org/mistic100/jQuery-QueryBuilder) [![Coverage Status](https://img.shields.io/coveralls/mistic100/jQuery-QueryBuilder/master.svg?style=flat-square)](https://coveralls.io/r/mistic100/jQuery-QueryBuilder) @@ -37,8 +37,7 @@ $ npm install jQuery-QueryBuilder #### Via CDN -jQuery-QueryBuilder is available on [jsDelivr](https://cdn.jsdelivr.net/npm/jQuery-QueryBuilder/dist/) and [unpkg](https://unpkg.com/jQuery-QueryBuilder/dist/)) - +jQuery-QueryBuilder is available on [jsDelivr](https://www.jsdelivr.com/package/npm/jQuery-QueryBuilder). ### Dependencies * jQuery >= 1.10 * Bootstrap >= 3.1 (CSS only) @@ -60,10 +59,8 @@ jQuery-QueryBuilder is available on [jsDelivr](https://cdn.jsdelivr.net/npm/jQue #### Prerequisites * NodeJS + NPM: `apt-get install nodejs-legacy npm` - * Ruby Dev: `apt-get install ruby-dev` * Grunt CLI: `npm install -g grunt-cli` * Bower: `npm install -g bower` - * SASS: `gem install sass` #### Run diff --git a/bower.json b/bower.json index 9f597a38..8c6ce3a3 100644 --- a/bower.json +++ b/bower.json @@ -14,7 +14,7 @@ ], "dependencies": { "jquery": ">=1.9.0", - "bootstrap": ">=3.1.0", + "bootstrap": ">=3.1.0 <4", "moment": ">=2.6.0", "jquery-extendext": ">=0.1.2", "doT": ">=1.0.3" diff --git a/composer.json b/composer.json index 8bb72252..7fd8ad11 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "mistic100/jquery-querybuilder", - "version": "2.4.2", + "version": "2.4.5", "authors": [{ "name": "Damien \"Mistic\" Sorel", "email": "contact@git.strangeplanet.fr", @@ -11,7 +11,7 @@ "robloach/component-installer": "*", "components/jquery": ">=1.9.0", "moment/moment": ">=2.6.0", - "components/bootstrap": ">=3.1.0" + "components/bootstrap": ">=3.1.0 <4" }, "keywords": [ "jquery", diff --git a/dist/css/query-builder.dark.css b/dist/css/query-builder.dark.css index 06d28fc8..01d3c6ac 100644 --- a/dist/css/query-builder.dark.css +++ b/dist/css/query-builder.dark.css @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -26,11 +26,13 @@ border: 1px solid #00164A; background: rgba(50, 70, 80, 0.5); } + .query-builder .rules-group-header { margin-bottom: 10px; } + .query-builder .rules-group-header .group-conditions .btn.readonly:not(.active), -.query-builder .rules-group-header .group-conditions input[name$=_cond] { +.query-builder .rules-group-header .group-conditions input[name$='_cond'] { border: 0; clip: rect(0 0 0 0); height: 1px; @@ -41,40 +43,52 @@ width: 1px; white-space: nowrap; } + .query-builder .rules-group-header .group-conditions .btn.readonly { border-radius: 3px; } + .query-builder .rules-list { list-style: none; padding: 0 0 0 15px; margin: 0; } + .query-builder .rule-value-container { border-left: 1px solid #DDD; padding-left: 5px; } + .query-builder .rule-value-container label { margin-bottom: 0; font-weight: normal; } + .query-builder .rule-value-container label.block { display: block; } -.query-builder .rule-value-container select, .query-builder .rule-value-container input[type=text], .query-builder .rule-value-container input[type=number] { + +.query-builder .rule-value-container select, +.query-builder .rule-value-container input[type='text'], +.query-builder .rule-value-container input[type='number'] { padding: 1px; } + .query-builder .error-container { display: none; cursor: help; color: #F00; } + .query-builder .has-error { background-color: #322; border-color: #800; } + .query-builder .has-error .error-container { display: inline-block !important; } + .query-builder .rules-list > *::before, .query-builder .rules-list > *::after { content: ''; position: absolute; @@ -84,29 +98,35 @@ border-color: #222; border-style: solid; } + .query-builder .rules-list > *::before { top: -4px; border-width: 0 0 2px 2px; } + .query-builder .rules-list > *::after { top: 50%; border-width: 0 0 0 2px; } + .query-builder .rules-list > *:first-child::before { top: -12px; height: calc(50% + 14px); } + .query-builder .rules-list > *:last-child::before { border-radius: 0 0 0 4px; } + .query-builder .rules-list > *:last-child::after { display: none; } -.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked + label::after { +.query-builder.bt-checkbox-glyphicons .checkbox input[type='checkbox']:checked + label::after { font-family: 'Glyphicons Halflings'; content: '\e013'; } + .query-builder.bt-checkbox-glyphicons .checkbox label::after { padding-left: 4px; padding-top: 2px; @@ -136,14 +156,17 @@ vertical-align: middle; margin-left: 5px; } + .query-builder .dragging { position: fixed; opacity: .5; z-index: 100; } + .query-builder .dragging::before, .query-builder .dragging::after { display: none; } + .query-builder .rule-placeholder { border: 1px dashed #BBB; opacity: .7; diff --git a/dist/css/query-builder.dark.min.css b/dist/css/query-builder.dark.min.css index 6b2ff809..56c37cbd 100644 --- a/dist/css/query-builder.dark.min.css +++ b/dist/css/query-builder.dark.min.css @@ -1,6 +1,6 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -.query-builder .rule-container,.query-builder .rule-placeholder,.query-builder .rules-group-container{position:relative;margin:4px 0;border-radius:5px;padding:5px;border:1px solid #111;background:rgba(40,40,40,.9)}.query-builder .drag-handle,.query-builder .error-container,.query-builder .rule-container .rule-filter-container,.query-builder .rule-container .rule-operator-container,.query-builder .rule-container .rule-value-container{display:inline-block;margin:0 5px 0 0;vertical-align:middle}.query-builder .rules-group-container{padding:10px 10px 6px;border:1px solid #00164A;background:rgba(50,70,80,.5)}.query-builder .rules-group-header{margin-bottom:10px}.query-builder .rules-group-header .group-conditions .btn.readonly:not(.active),.query-builder .rules-group-header .group-conditions input[name$=_cond]{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.query-builder .rules-group-header .group-conditions .btn.readonly{border-radius:3px}.query-builder .rules-list{list-style:none;padding:0 0 0 15px;margin:0}.query-builder .rule-value-container{border-left:1px solid #DDD;padding-left:5px}.query-builder .rule-value-container label{margin-bottom:0;font-weight:400}.query-builder .rule-value-container label.block{display:block}.query-builder .rule-value-container input[type=number],.query-builder .rule-value-container input[type=text],.query-builder .rule-value-container select{padding:1px}.query-builder .error-container{display:none;cursor:help;color:red}.query-builder .has-error{background-color:#322;border-color:#800}.query-builder .has-error .error-container{display:inline-block!important}.query-builder .dragging::after,.query-builder .dragging::before,.query-builder .rules-list>:last-child::after{display:none}.query-builder .rules-list>::after,.query-builder .rules-list>::before{content:'';position:absolute;left:-10px;width:10px;height:calc(50% + 4px);border-color:#222;border-style:solid}.query-builder .rules-list>::before{top:-4px;border-width:0 0 2px 2px}.query-builder .rules-list>::after{top:50%;border-width:0 0 0 2px}.query-builder .rules-list>:first-child::before{top:-12px;height:calc(50% + 14px)}.query-builder .rules-list>:last-child::before{border-radius:0 0 0 4px}.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked+label::after{font-family:'Glyphicons Halflings';content:'\e013'}.query-builder.bt-checkbox-glyphicons .checkbox label::after{padding-left:4px;padding-top:2px;font-size:9px}.query-builder .error-container+.tooltip .tooltip-inner{color:#F22!important}.query-builder p.filter-description{margin:5px 0 0;background:rgba(0,170,255,.2);border:1px solid #346F7B;color:#AAD1E4;border-radius:5px;padding:2.5px 5px;font-size:.8em}.query-builder .rules-group-header [data-invert]{margin-left:5px}.query-builder .drag-handle{cursor:move;vertical-align:middle;margin-left:5px}.query-builder .dragging{position:fixed;opacity:.5;z-index:100}.query-builder .rule-placeholder{border:1px dashed #BBB;opacity:.7} \ No newline at end of file +.query-builder .rule-container,.query-builder .rule-placeholder,.query-builder .rules-group-container{position:relative;margin:4px 0;border-radius:5px;padding:5px;border:1px solid #111;background:rgba(40,40,40,.9)}.query-builder .drag-handle,.query-builder .error-container,.query-builder .rule-container .rule-filter-container,.query-builder .rule-container .rule-operator-container,.query-builder .rule-container .rule-value-container{display:inline-block;margin:0 5px 0 0;vertical-align:middle}.query-builder .rules-group-container{padding:10px 10px 6px;border:1px solid #00164A;background:rgba(50,70,80,.5)}.query-builder .rules-group-header{margin-bottom:10px}.query-builder .rules-group-header .group-conditions .btn.readonly:not(.active),.query-builder .rules-group-header .group-conditions input[name$='_cond']{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.query-builder .rules-group-header .group-conditions .btn.readonly{border-radius:3px}.query-builder .rules-list{list-style:none;padding:0 0 0 15px;margin:0}.query-builder .rule-value-container{border-left:1px solid #DDD;padding-left:5px}.query-builder .rule-value-container label{margin-bottom:0;font-weight:400}.query-builder .rule-value-container label.block{display:block}.query-builder .rule-value-container input[type=text],.query-builder .rule-value-container input[type=number],.query-builder .rule-value-container select{padding:1px}.query-builder .error-container{display:none;cursor:help;color:red}.query-builder .has-error{background-color:#322;border-color:#800}.query-builder .has-error .error-container{display:inline-block!important}.query-builder .dragging::after,.query-builder .dragging::before,.query-builder .rules-list>:last-child::after{display:none}.query-builder .rules-list>::after,.query-builder .rules-list>::before{content:'';position:absolute;left:-10px;width:10px;height:calc(50% + 4px);border-color:#222;border-style:solid}.query-builder .rules-list>::before{top:-4px;border-width:0 0 2px 2px}.query-builder .rules-list>::after{top:50%;border-width:0 0 0 2px}.query-builder .rules-list>:first-child::before{top:-12px;height:calc(50% + 14px)}.query-builder .rules-list>:last-child::before{border-radius:0 0 0 4px}.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked+label::after{font-family:'Glyphicons Halflings';content:'\e013'}.query-builder.bt-checkbox-glyphicons .checkbox label::after{padding-left:4px;padding-top:2px;font-size:9px}.query-builder .error-container+.tooltip .tooltip-inner{color:#F22!important}.query-builder p.filter-description{margin:5px 0 0;background:rgba(0,170,255,.2);border:1px solid #346F7B;color:#AAD1E4;border-radius:5px;padding:2.5px 5px;font-size:.8em}.query-builder .rules-group-header [data-invert]{margin-left:5px}.query-builder .drag-handle{cursor:move;vertical-align:middle;margin-left:5px}.query-builder .dragging{position:fixed;opacity:.5;z-index:100}.query-builder .rule-placeholder{border:1px dashed #BBB;opacity:.7} \ No newline at end of file diff --git a/dist/css/query-builder.default.css b/dist/css/query-builder.default.css index 80fcbf42..f3e3a15a 100644 --- a/dist/css/query-builder.default.css +++ b/dist/css/query-builder.default.css @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -26,11 +26,13 @@ border: 1px solid #DCC896; background: rgba(250, 240, 210, 0.5); } + .query-builder .rules-group-header { margin-bottom: 10px; } + .query-builder .rules-group-header .group-conditions .btn.readonly:not(.active), -.query-builder .rules-group-header .group-conditions input[name$=_cond] { +.query-builder .rules-group-header .group-conditions input[name$='_cond'] { border: 0; clip: rect(0 0 0 0); height: 1px; @@ -41,40 +43,52 @@ width: 1px; white-space: nowrap; } + .query-builder .rules-group-header .group-conditions .btn.readonly { border-radius: 3px; } + .query-builder .rules-list { list-style: none; padding: 0 0 0 15px; margin: 0; } + .query-builder .rule-value-container { border-left: 1px solid #DDD; padding-left: 5px; } + .query-builder .rule-value-container label { margin-bottom: 0; font-weight: normal; } + .query-builder .rule-value-container label.block { display: block; } -.query-builder .rule-value-container select, .query-builder .rule-value-container input[type=text], .query-builder .rule-value-container input[type=number] { + +.query-builder .rule-value-container select, +.query-builder .rule-value-container input[type='text'], +.query-builder .rule-value-container input[type='number'] { padding: 1px; } + .query-builder .error-container { display: none; cursor: help; color: #F00; } + .query-builder .has-error { background-color: #FDD; border-color: #F99; } + .query-builder .has-error .error-container { display: inline-block !important; } + .query-builder .rules-list > *::before, .query-builder .rules-list > *::after { content: ''; position: absolute; @@ -84,29 +98,35 @@ border-color: #CCC; border-style: solid; } + .query-builder .rules-list > *::before { top: -4px; border-width: 0 0 2px 2px; } + .query-builder .rules-list > *::after { top: 50%; border-width: 0 0 0 2px; } + .query-builder .rules-list > *:first-child::before { top: -12px; height: calc(50% + 14px); } + .query-builder .rules-list > *:last-child::before { border-radius: 0 0 0 4px; } + .query-builder .rules-list > *:last-child::after { display: none; } -.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked + label::after { +.query-builder.bt-checkbox-glyphicons .checkbox input[type='checkbox']:checked + label::after { font-family: 'Glyphicons Halflings'; content: '\e013'; } + .query-builder.bt-checkbox-glyphicons .checkbox label::after { padding-left: 4px; padding-top: 2px; @@ -136,14 +156,17 @@ vertical-align: middle; margin-left: 5px; } + .query-builder .dragging { position: fixed; opacity: .5; z-index: 100; } + .query-builder .dragging::before, .query-builder .dragging::after { display: none; } + .query-builder .rule-placeholder { border: 1px dashed #BBB; opacity: .7; diff --git a/dist/css/query-builder.default.min.css b/dist/css/query-builder.default.min.css index 049380f5..985eb9ba 100644 --- a/dist/css/query-builder.default.min.css +++ b/dist/css/query-builder.default.min.css @@ -1,6 +1,6 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -.query-builder .rule-container,.query-builder .rule-placeholder,.query-builder .rules-group-container{position:relative;margin:4px 0;border-radius:5px;padding:5px;border:1px solid #EEE;background:rgba(255,255,255,.9)}.query-builder .drag-handle,.query-builder .error-container,.query-builder .rule-container .rule-filter-container,.query-builder .rule-container .rule-operator-container,.query-builder .rule-container .rule-value-container{display:inline-block;margin:0 5px 0 0;vertical-align:middle}.query-builder .rules-group-container{padding:10px 10px 6px;border:1px solid #DCC896;background:rgba(250,240,210,.5)}.query-builder .rules-group-header{margin-bottom:10px}.query-builder .rules-group-header .group-conditions .btn.readonly:not(.active),.query-builder .rules-group-header .group-conditions input[name$=_cond]{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.query-builder .rules-group-header .group-conditions .btn.readonly{border-radius:3px}.query-builder .rules-list{list-style:none;padding:0 0 0 15px;margin:0}.query-builder .rule-value-container{border-left:1px solid #DDD;padding-left:5px}.query-builder .rule-value-container label{margin-bottom:0;font-weight:400}.query-builder .rule-value-container label.block{display:block}.query-builder .rule-value-container input[type=number],.query-builder .rule-value-container input[type=text],.query-builder .rule-value-container select{padding:1px}.query-builder .error-container{display:none;cursor:help;color:red}.query-builder .has-error{background-color:#FDD;border-color:#F99}.query-builder .has-error .error-container{display:inline-block!important}.query-builder .dragging::after,.query-builder .dragging::before,.query-builder .rules-list>:last-child::after{display:none}.query-builder .rules-list>::after,.query-builder .rules-list>::before{content:'';position:absolute;left:-10px;width:10px;height:calc(50% + 4px);border-color:#CCC;border-style:solid}.query-builder .rules-list>::before{top:-4px;border-width:0 0 2px 2px}.query-builder .rules-list>::after{top:50%;border-width:0 0 0 2px}.query-builder .rules-list>:first-child::before{top:-12px;height:calc(50% + 14px)}.query-builder .rules-list>:last-child::before{border-radius:0 0 0 4px}.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked+label::after{font-family:'Glyphicons Halflings';content:'\e013'}.query-builder.bt-checkbox-glyphicons .checkbox label::after{padding-left:4px;padding-top:2px;font-size:9px}.query-builder .error-container+.tooltip .tooltip-inner{color:#F99!important}.query-builder p.filter-description{margin:5px 0 0;background:#D9EDF7;border:1px solid #BCE8F1;color:#31708F;border-radius:5px;padding:2.5px 5px;font-size:.8em}.query-builder .rules-group-header [data-invert]{margin-left:5px}.query-builder .drag-handle{cursor:move;vertical-align:middle;margin-left:5px}.query-builder .dragging{position:fixed;opacity:.5;z-index:100}.query-builder .rule-placeholder{border:1px dashed #BBB;opacity:.7} \ No newline at end of file +.query-builder .rule-container,.query-builder .rule-placeholder,.query-builder .rules-group-container{position:relative;margin:4px 0;border-radius:5px;padding:5px;border:1px solid #EEE;background:rgba(255,255,255,.9)}.query-builder .drag-handle,.query-builder .error-container,.query-builder .rule-container .rule-filter-container,.query-builder .rule-container .rule-operator-container,.query-builder .rule-container .rule-value-container{display:inline-block;margin:0 5px 0 0;vertical-align:middle}.query-builder .rules-group-container{padding:10px 10px 6px;border:1px solid #DCC896;background:rgba(250,240,210,.5)}.query-builder .rules-group-header{margin-bottom:10px}.query-builder .rules-group-header .group-conditions .btn.readonly:not(.active),.query-builder .rules-group-header .group-conditions input[name$='_cond']{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;white-space:nowrap}.query-builder .rules-group-header .group-conditions .btn.readonly{border-radius:3px}.query-builder .rules-list{list-style:none;padding:0 0 0 15px;margin:0}.query-builder .rule-value-container{border-left:1px solid #DDD;padding-left:5px}.query-builder .rule-value-container label{margin-bottom:0;font-weight:400}.query-builder .rule-value-container label.block{display:block}.query-builder .rule-value-container input[type=text],.query-builder .rule-value-container input[type=number],.query-builder .rule-value-container select{padding:1px}.query-builder .error-container{display:none;cursor:help;color:red}.query-builder .has-error{background-color:#FDD;border-color:#F99}.query-builder .has-error .error-container{display:inline-block!important}.query-builder .dragging::after,.query-builder .dragging::before,.query-builder .rules-list>:last-child::after{display:none}.query-builder .rules-list>::after,.query-builder .rules-list>::before{content:'';position:absolute;left:-10px;width:10px;height:calc(50% + 4px);border-color:#CCC;border-style:solid}.query-builder .rules-list>::before{top:-4px;border-width:0 0 2px 2px}.query-builder .rules-list>::after{top:50%;border-width:0 0 0 2px}.query-builder .rules-list>:first-child::before{top:-12px;height:calc(50% + 14px)}.query-builder .rules-list>:last-child::before{border-radius:0 0 0 4px}.query-builder.bt-checkbox-glyphicons .checkbox input[type=checkbox]:checked+label::after{font-family:'Glyphicons Halflings';content:'\e013'}.query-builder.bt-checkbox-glyphicons .checkbox label::after{padding-left:4px;padding-top:2px;font-size:9px}.query-builder .error-container+.tooltip .tooltip-inner{color:#F99!important}.query-builder p.filter-description{margin:5px 0 0;background:#D9EDF7;border:1px solid #BCE8F1;color:#31708F;border-radius:5px;padding:2.5px 5px;font-size:.8em}.query-builder .rules-group-header [data-invert]{margin-left:5px}.query-builder .drag-handle{cursor:move;vertical-align:middle;margin-left:5px}.query-builder .dragging{position:fixed;opacity:.5;z-index:100}.query-builder .rule-placeholder{border:1px dashed #BBB;opacity:.7} \ No newline at end of file diff --git a/dist/i18n/query-builder.ar.js b/dist/i18n/query-builder.ar.js index 892c1dcf..345c6215 100644 --- a/dist/i18n/query-builder.ar.js +++ b/dist/i18n/query-builder.ar.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Arabic (ar) * Author: Mohamed YOUNES, https://github.com/MedYOUNES * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.az.js b/dist/i18n/query-builder.az.js index 75d7cbc3..83eec512 100644 --- a/dist/i18n/query-builder.az.js +++ b/dist/i18n/query-builder.az.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Azerbaijan (az) * Author: Megaplan, mborisv * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.bg.js b/dist/i18n/query-builder.bg.js index fa673f1b..5e7106a5 100644 --- a/dist/i18n/query-builder.bg.js +++ b/dist/i18n/query-builder.bg.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Bulgarian (bg) * Author: Valentin Hristov * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.cs.js b/dist/i18n/query-builder.cs.js index 0c9dc581..49192f00 100644 --- a/dist/i18n/query-builder.cs.js +++ b/dist/i18n/query-builder.cs.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Čeština (cs) * Author: Megaplan, mborisv * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.da.js b/dist/i18n/query-builder.da.js index ca2a023b..83017c89 100644 --- a/dist/i18n/query-builder.da.js +++ b/dist/i18n/query-builder.da.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Danish (da) * Author: Jna Borup Coyle, github@coyle.dk * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.de.js b/dist/i18n/query-builder.de.js index 6e05a5d2..605b98d5 100644 --- a/dist/i18n/query-builder.de.js +++ b/dist/i18n/query-builder.de.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: German (de) * Author: "raimu" * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.el.js b/dist/i18n/query-builder.el.js index 958dd9b4..fa9dddd1 100644 --- a/dist/i18n/query-builder.el.js +++ b/dist/i18n/query-builder.el.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Greek (el) * Author: Stelios Patsatzis, https://www.linkedin.com/in/stelios-patsatzis-89841561 * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.en.js b/dist/i18n/query-builder.en.js index b985bc8f..d4f55468 100644 --- a/dist/i18n/query-builder.en.js +++ b/dist/i18n/query-builder.en.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -66,10 +66,12 @@ QueryBuilder.regional['en'] = { "number_exceed_min": "Must be greater than {0}", "number_exceed_max": "Must be lower than {0}", "number_wrong_step": "Must be a multiple of {0}", + "number_between_invalid": "Invalid values, {0} is greater than {1}", "datetime_empty": "Empty value", "datetime_invalid": "Invalid date format ({0})", "datetime_exceed_min": "Must be after {0}", "datetime_exceed_max": "Must be before {0}", + "datetime_between_invalid": "Invalid values, {0} isgreater than {1}", "boolean_not_valid": "Not a boolean", "operator_not_multiple": "Operator \"{1}\" cannot accept multiple values" }, diff --git a/dist/i18n/query-builder.es.js b/dist/i18n/query-builder.es.js index a6094daf..80ded2b3 100644 --- a/dist/i18n/query-builder.es.js +++ b/dist/i18n/query-builder.es.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Spanish (es) * Author: "pyarza", "kddlb" * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.fa-IR.js b/dist/i18n/query-builder.fa-IR.js index 9e84e415..4c2d3196 100644 --- a/dist/i18n/query-builder.fa-IR.js +++ b/dist/i18n/query-builder.fa-IR.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Farsi (fa-ir) * Author: Behzad Sedighzade, behzad.sedighzade@gmail.com * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -38,6 +38,7 @@ QueryBuilder.regional['fa-IR'] = { "greater": "بزرگتر از", "greater_or_equal": "بزرگتر یا مساوی با", "between": "مابین", + "not_between": "مابین نباشد", "begins_with": "شروع شود با", "not_begins_with": "شروع نشود با", "contains": "شامل شود", diff --git a/dist/i18n/query-builder.fr.js b/dist/i18n/query-builder.fr.js index 7f478e67..a2f7acb2 100644 --- a/dist/i18n/query-builder.fr.js +++ b/dist/i18n/query-builder.fr.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: French (fr) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -66,10 +66,12 @@ QueryBuilder.regional['fr'] = { "number_exceed_min": "Doit être plus grand que {0}", "number_exceed_max": "Doit être plus petit que {0}", "number_wrong_step": "Doit être un multiple de {0}", + "number_between_invalid": "Valeurs invalides, {0} est plus grand que {1}", "datetime_empty": "Valeur vide", "datetime_invalid": "Fomat de date invalide ({0})", "datetime_exceed_min": "Doit être après {0}", "datetime_exceed_max": "Doit être avant {0}", + "datetime_between_invalid": "Valeurs invalides, {0} est plus grand que {1}", "boolean_not_valid": "N'est pas un booléen", "operator_not_multiple": "L'opérateur \"{1}\" ne peut utiliser plusieurs valeurs" }, diff --git a/dist/i18n/query-builder.he.js b/dist/i18n/query-builder.he.js index cbd91635..10f413cd 100644 --- a/dist/i18n/query-builder.he.js +++ b/dist/i18n/query-builder.he.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Hebrew (he) * Author: Kfir Stri https://github.com/kfirstri * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.it.js b/dist/i18n/query-builder.it.js index 7bbf9658..d5dd2437 100644 --- a/dist/i18n/query-builder.it.js +++ b/dist/i18n/query-builder.it.js @@ -1,6 +1,7 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Italian (it) + * Author: davegraziosi * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -18,6 +19,7 @@ var QueryBuilder = $.fn.queryBuilder; QueryBuilder.regional['it'] = { "__locale": "Italian (it)", + "__author": "davegraziosi", "add_rule": "Aggiungi regola", "add_group": "Aggiungi gruppo", "delete_rule": "Elimina", @@ -35,6 +37,8 @@ QueryBuilder.regional['it'] = { "less_or_equal": "minore o uguale", "greater": "maggiore", "greater_or_equal": "maggiore o uguale", + "between": "compreso tra", + "not_between": "non compreso tra", "begins_with": "inizia con", "not_begins_with": "non inizia con", "contains": "contiene", @@ -45,6 +49,29 @@ QueryBuilder.regional['it'] = { "is_not_empty": "non è vuoto", "is_null": "è nullo", "is_not_null": "non è nullo" + }, + "errors": { + "no_filter": "Nessun filtro selezionato", + "empty_group": "Il gruppo è vuoto", + "radio_empty": "No value selected", + "checkbox_empty": "Nessun valore selezionato", + "select_empty": "Nessun valore selezionato", + "string_empty": "Valore vuoto", + "string_exceed_min_length": "Deve contenere almeno {0} caratteri", + "string_exceed_max_length": "Non deve contenere più di {0} caratteri", + "string_invalid_format": "Formato non valido ({0})", + "number_nan": "Non è un numero", + "number_not_integer": "Non è un intero", + "number_not_double": "Non è un numero con la virgola", + "number_exceed_min": "Deve essere maggiore di {0}", + "number_exceed_max": "Deve essere minore di {0}", + "number_wrong_step": "Deve essere multiplo di {0}", + "datetime_empty": "Valore vuoto", + "datetime_invalid": "Formato data non valido ({0})", + "datetime_exceed_min": "Deve essere successivo a {0}", + "datetime_exceed_max": "Deve essere precedente a {0}", + "boolean_not_valid": "Non è un booleano", + "operator_not_multiple": "L'Operatore {0} non può accettare valori multipli" } }; diff --git a/dist/i18n/query-builder.nl.js b/dist/i18n/query-builder.nl.js index 96692687..46a9e411 100644 --- a/dist/i18n/query-builder.nl.js +++ b/dist/i18n/query-builder.nl.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Dutch (nl) * Author: "Roywcm" * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.no.js b/dist/i18n/query-builder.no.js index 5a7d5285..99a62f44 100644 --- a/dist/i18n/query-builder.no.js +++ b/dist/i18n/query-builder.no.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Norwegian (no) * Author: Jna Borup Coyle, github@coyle.dk * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.pl.js b/dist/i18n/query-builder.pl.js index df3c25f4..574e26e5 100644 --- a/dist/i18n/query-builder.pl.js +++ b/dist/i18n/query-builder.pl.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Polish (pl) * Author: Artur Smolarek * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -25,8 +25,8 @@ QueryBuilder.regional['pl'] = { "delete_rule": "Usuń", "delete_group": "Usuń", "conditions": { - "AND": "AND", - "OR": "OR" + "AND": "ORAZ", + "OR": "LUB" }, "operators": { "equal": "równa się", diff --git a/dist/i18n/query-builder.pt-BR.js b/dist/i18n/query-builder.pt-BR.js index 2c286409..68781c7d 100644 --- a/dist/i18n/query-builder.pt-BR.js +++ b/dist/i18n/query-builder.pt-BR.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Brazilian Portuguese (pr-BR) * Author: Leandro Gehlen, leandrogehlen@gmail.com; Marcos Ferretti, marcosvferretti@gmail.com * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.pt-PT.js b/dist/i18n/query-builder.pt-PT.js index 616478a5..8779f84f 100644 --- a/dist/i18n/query-builder.pt-PT.js +++ b/dist/i18n/query-builder.pt-PT.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Portuguese (pt-PT) * Author: Miguel Guerreiro, migas.csi@gmail.com * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.ro.js b/dist/i18n/query-builder.ro.js index 2e6aadb0..bac123d6 100644 --- a/dist/i18n/query-builder.ro.js +++ b/dist/i18n/query-builder.ro.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Romanian (ro) * Author: ArianServ * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.ru.js b/dist/i18n/query-builder.ru.js index 7cc02101..009c3276 100644 --- a/dist/i18n/query-builder.ru.js +++ b/dist/i18n/query-builder.ru.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Russian (ru) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/dist/i18n/query-builder.sq.js b/dist/i18n/query-builder.sq.js index 533b873b..fa49a0ea 100644 --- a/dist/i18n/query-builder.sq.js +++ b/dist/i18n/query-builder.sq.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Albanian (sq) * Author: Tomor Pupovci * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.tr.js b/dist/i18n/query-builder.tr.js index fc069087..ad72d35b 100644 --- a/dist/i18n/query-builder.tr.js +++ b/dist/i18n/query-builder.tr.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Turkish (tr) * Author: Aykut Alpgiray Ateş * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.ua.js b/dist/i18n/query-builder.ua.js index 731dda80..cfbf57ac 100644 --- a/dist/i18n/query-builder.ua.js +++ b/dist/i18n/query-builder.ua.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Ukrainian (ua) * Author: Megaplan, mborisv * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.zh-CN.js b/dist/i18n/query-builder.zh-CN.js index c85a82e4..4ef85f24 100644 --- a/dist/i18n/query-builder.zh-CN.js +++ b/dist/i18n/query-builder.zh-CN.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: Simplified Chinese (zh_CN) * Author: shadowwind, shatteredwindgo@gmail.com * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/js/query-builder.js b/dist/js/query-builder.js index 2257bd53..97850ced 100644 --- a/dist/js/query-builder.js +++ b/dist/js/query-builder.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -32,7 +32,6 @@ * @param {jQuery} $el * @param {object} options - see {@link http://querybuilder.js.org/#options} * @constructor - * @fires QueryBuilder.afterInit */ var QueryBuilder = function($el, options) { $el[0].queryBuilder = this; @@ -159,21 +158,6 @@ var QueryBuilder = function($el, options) { this.operators = this.checkOperators(this.operators); this.bindEvents(); this.initPlugins(); - - /** - * When the initilization is done, just before creating the root group - * @event afterInit - * @memberof QueryBuilder - */ - this.trigger('afterInit'); - - if (options.rules) { - this.setRules(options.rules); - delete this.settings.rules; - } - else { - this.setRoot(true); - } }; $.extend(QueryBuilder.prototype, /** @lends QueryBuilder.prototype */ { @@ -570,6 +554,29 @@ QueryBuilder.prototype.getPluginOptions = function(name, property) { }; +/** + * Final initialisation of the builder + * @param {object} [rules] + * @fires QueryBuilder.afterInit + * @private + */ +QueryBuilder.prototype.init = function(rules) { + /** + * When the initilization is done, just before creating the root group + * @event afterInit + * @memberof QueryBuilder + */ + this.trigger('afterInit'); + + if (rules) { + this.setRules(rules); + delete this.settings.rules; + } + else { + this.setRoot(true); + } +}; + /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters @@ -831,7 +838,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'value': - self.updateRuleValue(node); + self.updateRuleValue(node, oldValue); break; } } @@ -846,7 +853,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'condition': - self.updateGroupCondition(node); + self.updateGroupCondition(node, oldValue); break; } } @@ -929,6 +936,13 @@ QueryBuilder.prototype.addGroup = function(parent, addRule, data, flags) { */ this.trigger('afterAddGroup', model); + /** + * After any change in the rules + * @event rulesChanged + * @memberof QueryBuilder + */ + this.trigger('rulesChanged'); + model.condition = this.settings.default_condition; if (addRule) { @@ -978,6 +992,8 @@ QueryBuilder.prototype.deleteGroup = function(group) { * @memberof QueryBuilder */ this.trigger('afterDeleteGroup'); + + this.trigger('rulesChanged'); } return del; @@ -986,10 +1002,11 @@ QueryBuilder.prototype.deleteGroup = function(group) { /** * Performs actions when a group's condition changes * @param {Group} group + * @param {object} previousCondition * @fires QueryBuilder.afterUpdateGroupCondition * @private */ -QueryBuilder.prototype.updateGroupCondition = function(group) { +QueryBuilder.prototype.updateGroupCondition = function(group, previousCondition) { group.$el.find('>' + QueryBuilder.selectors.group_condition).each(function() { var $this = $(this); $this.prop('checked', $this.val() === group.condition); @@ -1001,8 +1018,11 @@ QueryBuilder.prototype.updateGroupCondition = function(group) { * @event afterUpdateGroupCondition * @memberof QueryBuilder * @param {Group} group + * @param {object} previousCondition */ - this.trigger('afterUpdateGroupCondition', group); + this.trigger('afterUpdateGroupCondition', group, previousCondition); + + this.trigger('rulesChanged'); }; /** @@ -1062,6 +1082,8 @@ QueryBuilder.prototype.addRule = function(parent, data, flags) { */ this.trigger('afterAddRule', model); + this.trigger('rulesChanged'); + this.createRuleFilters(model); if (this.settings.default_filter || !this.settings.display_empty_filter) { @@ -1114,6 +1136,8 @@ QueryBuilder.prototype.deleteRule = function(rule) { */ this.trigger('afterDeleteRule'); + this.trigger('rulesChanged'); + return true; }; @@ -1166,7 +1190,14 @@ QueryBuilder.prototype.createRuleOperators = function(rule) { $operatorContainer.html($operatorSelect); // set the operator without triggering update event - rule.__.operator = operators[0]; + if (rule.filter.default_operator) { + rule.__.operator = this.getOperatorByType(rule.filter.default_operator); + } + else { + rule.__.operator = operators[0]; + } + + rule.$el.find(QueryBuilder.selectors.rule_operator).val(rule.operator.type); /** * After creating the dropdown for operators @@ -1259,8 +1290,11 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { * @event afterUpdateRuleFilter * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousFilter */ - this.trigger('afterUpdateRuleFilter', rule); + this.trigger('afterUpdateRuleFilter', rule, previousFilter); + + this.trigger('rulesChanged'); }; /** @@ -1272,6 +1306,7 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { */ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { var $valueContainer = rule.$el.find(QueryBuilder.selectors.value_container); + var ruleValue = rule.value; if (!rule.operator || rule.operator.nb_inputs === 0) { $valueContainer.hide(); @@ -1298,19 +1333,24 @@ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { * @event afterUpdateRuleOperator * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousOperator */ - this.trigger('afterUpdateRuleOperator', rule); + this.trigger('afterUpdateRuleOperator', rule, previousOperator); + + this.trigger('rulesChanged'); - this.updateRuleValue(rule); + // FIXME is it necessary ? + this.updateRuleValue(rule, ruleValue); }; /** * Performs actions when rule's value changes * @param {Rule} rule + * @param {object} previousValue * @fires QueryBuilder.afterUpdateRuleValue * @private */ -QueryBuilder.prototype.updateRuleValue = function(rule) { +QueryBuilder.prototype.updateRuleValue = function(rule, previousValue) { if (!rule._updating_value) { this.setRuleInputValue(rule, rule.value); } @@ -1320,8 +1360,11 @@ QueryBuilder.prototype.updateRuleValue = function(rule) { * @event afterUpdateRuleValue * @memberof QueryBuilder * @param {Rule} rule + * @param {*} previousValue */ - this.trigger('afterUpdateRuleValue', rule); + this.trigger('afterUpdateRuleValue', rule, previousValue); + + this.trigger('rulesChanged'); }; /** @@ -1528,6 +1571,8 @@ QueryBuilder.prototype.reset = function() { * @memberof QueryBuilder */ this.trigger('afterReset'); + + this.trigger('rulesChanged'); }; /** @@ -1560,6 +1605,8 @@ QueryBuilder.prototype.clear = function() { * @memberof QueryBuilder */ this.trigger('afterClear'); + + this.trigger('rulesChanged'); }; /** @@ -1884,17 +1931,22 @@ QueryBuilder.prototype.setRules = function(data, options) { if (!item.empty) { model.filter = self.getFilterById(item.id, !options.allow_invalid); + } - if (model.filter) { - model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); + if (model.filter) { + model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); - if (!model.operator) { - model.operator = self.getOperators(model.filter)[0]; - } + if (!model.operator) { + model.operator = self.getOperators(model.filter)[0]; + } + } - if (model.operator && model.operator.nb_inputs !== 0 && item.value !== undefined) { - model.value = item.value; - } + if (model.operator && model.operator.nb_inputs !== 0) { + if (item.value !== undefined) { + model.value = item.value; + } + else if (model.filter.default_value !== undefined) { + model.value = model.filter.default_value; } } @@ -2160,6 +2212,29 @@ QueryBuilder.prototype._validateValue = function(rule, value) { } } + if ((rule.operator.type === 'between' || rule.operator.type === 'not_between') && value.length === 2) { + switch (QueryBuilder.types[filter.type]) { + case 'number': + if (value[0] > value[1]) { + result = ['number_between_invalid', value[0], value[1]]; + } + break; + + case 'datetime': + // we need MomentJS + if (validation.format) { + if (!('moment' in window)) { + Utils.error('MissingLibrary', 'MomentJS is required for Date/Time validation. Get it here http://momentjs.com'); + } + + if (moment(value[0], validation.format).isAfter(moment(value[1], validation.format))) { + result = ['datetime_between_invalid', value[0], value[1]]; + } + } + break; + } + } + return result; }; @@ -2741,7 +2816,7 @@ QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) { /** * Modifies the raw HTML of the rule's filter dropdown - * @event changer:getRuleFilterTemplate + * @event changer:getRuleFilterSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule @@ -2771,7 +2846,7 @@ QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) { /** * Modifies the raw HTML of the rule's operator dropdown - * @event changer:getRuleOperatorTemplate + * @event changer:getRuleOperatorSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule @@ -3689,7 +3764,9 @@ $.fn.queryBuilder = function(option) { return this; } if (!data) { - this.data('queryBuilder', new QueryBuilder(this, options)); + var builder = new QueryBuilder(this, options); + this.data('queryBuilder', builder); + builder.init(options.rules); } if (typeof option == 'string') { return data[option].apply(data, Array.prototype.slice.call(arguments, 1)); @@ -3926,6 +4003,8 @@ QueryBuilder.extend(/** @lends module:plugins.ChangeFilters.prototype */ { function(rule) { if (rule.filter && filtersIds.indexOf(rule.filter.id) === -1) { rule.drop(); + + self.trigger('rulesChanged'); } else { self.createRuleFilters(rule); @@ -4134,6 +4213,9 @@ QueryBuilder.define('filter-description', function(options) { bootbox.alert($b.data('description')); }); } + else { + $b.show(); + } $b.data('description', description); } @@ -4315,6 +4397,8 @@ QueryBuilder.extend(/** @lends module:plugins.Invert.prototype */ { * @param {object} options */ this.trigger('afterInvert', node, options); + + this.trigger('rulesChanged'); } } }); @@ -4427,6 +4511,10 @@ QueryBuilder.extend(/** @lends module:plugins.MongoDbSupport.prototype */ { getMongo: function(data) { data = (data === undefined) ? this.getRules() : data; + if (!data) { + return null; + } + var self = this; return (function parse(group) { @@ -4854,6 +4942,8 @@ QueryBuilder.extend(/** @lends module:plugins.NotGroup.prototype */ { * @param {Group} group */ this.trigger('afterUpdateGroupNot', group); + + this.trigger('rulesChanged'); } }); @@ -4952,6 +5042,8 @@ QueryBuilder.define('sortable', function(options) { * @param {Node} node */ self.trigger('afterMove', src); + + self.trigger('rulesChanged'); } }); } @@ -5333,6 +5425,11 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; + + if (!data) { + return null; + } + nl = !!nl ? '\n' : ' '; var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); @@ -5681,7 +5778,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQLFieldID: function(field, value) { var matchingFilters = this.filters.filter(function(filter) { - return filter.field === field; + return filter.field.toLowerCase() === field.toLowerCase(); }); var id; @@ -5835,7 +5932,7 @@ QueryBuilder.extend(/** @lends module:plugins.UniqueFilter.prototype */ { /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -5890,10 +5987,12 @@ QueryBuilder.regional['en'] = { "number_exceed_min": "Must be greater than {0}", "number_exceed_max": "Must be lower than {0}", "number_wrong_step": "Must be a multiple of {0}", + "number_between_invalid": "Invalid values, {0} is greater than {1}", "datetime_empty": "Empty value", "datetime_invalid": "Invalid date format ({0})", "datetime_exceed_min": "Must be after {0}", "datetime_exceed_max": "Must be before {0}", + "datetime_between_invalid": "Invalid values, {0} isgreater than {1}", "boolean_not_valid": "Not a boolean", "operator_not_multiple": "Operator \"{1}\" cannot accept multiple values" }, diff --git a/dist/js/query-builder.min.js b/dist/js/query-builder.min.js index e512bd0f..9c515efb 100644 --- a/dist/js/query-builder.min.js +++ b/dist/js/query-builder.min.js @@ -1,8 +1,8 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -!function(a,b){"function"==typeof define&&define.amd?define(["jquery","dot/doT","jquery-extendext"],b):"object"==typeof module&&module.exports?module.exports=b(require("jquery"),require("dot/doT"),require("jquery-extendext")):b(a.jQuery,a.doT)}(this,function($,a){"use strict";function b(){this.root=null,this.$=$(this)}function c(a){if(null!==a&&"object"==typeof a){var b=Object.keys(a);return 1===b.length?b[0]:void 0!==a.$gte&&void 0!==a.$lte?"between":void 0!==a.$lt&&void 0!==a.$gt?"not_between":void 0!==a.$regex?"$regex":void 0}return"eq"}function d(a){for(var b=Object.keys(a),c=0,d=b.length;d>c;c++)if("$or"==b[c].toLowerCase()||"$and"==b[c].toLowerCase())return b[c]}function e(a,b,c){var d,e,f=g.selectors;d=b.closest(f.rule_container),d.length&&(e="moveAfter"),e||(d=b.closest(f.group_header),d.length&&(d=b.closest(f.group_container),e="moveAtBegin")),e||(d=b.closest(f.group_container),d.length&&(e="moveAtEnd")),e&&(a[e](c.getModel(d)),c&&a instanceof k&&c.setRuleInputValue(a,a.value))}function f(a){var b=a.match(/(question_mark|numbered|named)(?:\((.)\))?/);return b||(b=[null,"question_mark",void 0]),b}var g=function(c,d){c[0].queryBuilder=this,this.$el=c,this.settings=$.extendext(!0,"replace",{},g.DEFAULTS,d),this.model=new b,this.status={id:null,generated_id:!1,group_id:0,rule_id:0,has_optgroup:!1,has_operator_optgroup:!1},this.filters=this.settings.filters,this.icons=this.settings.icons,this.operators=this.settings.operators,this.templates=this.settings.templates,this.plugins=this.settings.plugins,this.lang=null,void 0===g.regional.en&&h.error("Config",'"i18n/en.js" not loaded.'),this.lang=$.extendext(!0,"replace",{},g.regional.en,g.regional[this.settings.lang_code],this.settings.lang),this.settings.allow_groups===!1?this.settings.allow_groups=0:this.settings.allow_groups===!0&&(this.settings.allow_groups=-1),Object.keys(this.templates).forEach(function(b){this.templates[b]||(this.templates[b]=g.templates[b]),"string"==typeof this.templates[b]&&(this.templates[b]=a.template(this.templates[b]))},this),this.$el.attr("id")||(this.$el.attr("id","qb_"+Math.floor(99999*Math.random())),this.status.generated_id=!0),this.status.id=this.$el.attr("id"),this.$el.addClass("query-builder form-inline"),this.filters=this.checkFilters(this.filters),this.operators=this.checkOperators(this.operators),this.bindEvents(),this.initPlugins(),this.trigger("afterInit"),d.rules?(this.setRules(d.rules),delete this.settings.rules):this.setRoot(!0)};$.extend(g.prototype,{trigger:function(a){var b=new $.Event(this._tojQueryEvent(a),{builder:this});return this.$el.triggerHandler(b,Array.prototype.slice.call(arguments,1)),b},change:function(a,b){var c=new $.Event(this._tojQueryEvent(a,!0),{builder:this,value:b});return this.$el.triggerHandler(c,Array.prototype.slice.call(arguments,2)),c.value},on:function(a,b){return this.$el.on(this._tojQueryEvent(a),b),this},off:function(a,b){return this.$el.off(this._tojQueryEvent(a),b),this},once:function(a,b){return this.$el.one(this._tojQueryEvent(a),b),this},_tojQueryEvent:function(a,b){return a.split(" ").map(function(a){return a+".queryBuilder"+(b?".filter":"")}).join(" ")}}),g.types={string:"string",integer:"number","double":"number",date:"datetime",time:"datetime",datetime:"datetime","boolean":"boolean"},g.inputs=["text","number","textarea","radio","checkbox","select"],g.modifiable_options=["display_errors","allow_groups","allow_empty","default_condition","default_filter"],g.selectors={group_container:".rules-group-container",rule_container:".rule-container",filter_container:".rule-filter-container",operator_container:".rule-operator-container",value_container:".rule-value-container",error_container:".error-container",condition_container:".rules-group-header .group-conditions",rule_header:".rule-header",group_header:".rules-group-header",group_actions:".group-actions",rule_actions:".rule-actions",rules_list:".rules-group-body>.rules-list",group_condition:".rules-group-header [name$=_cond]",rule_filter:".rule-filter-container [name$=_filter]",rule_operator:".rule-operator-container [name$=_operator]",rule_value:".rule-value-container [name*=_value_]",add_rule:"[data-add=rule]",delete_rule:"[data-delete=rule]",add_group:"[data-add=group]",delete_group:"[data-delete=group]"},g.templates={},g.regional={},g.OPERATORS={equal:{type:"equal",nb_inputs:1,multiple:!1,apply_to:["string","number","datetime","boolean"]},not_equal:{type:"not_equal",nb_inputs:1,multiple:!1,apply_to:["string","number","datetime","boolean"]},"in":{type:"in",nb_inputs:1,multiple:!0,apply_to:["string","number","datetime"]},not_in:{type:"not_in",nb_inputs:1,multiple:!0,apply_to:["string","number","datetime"]},less:{type:"less",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},less_or_equal:{type:"less_or_equal",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},greater:{type:"greater",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},greater_or_equal:{type:"greater_or_equal",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},between:{type:"between",nb_inputs:2,multiple:!1,apply_to:["number","datetime"]},not_between:{type:"not_between",nb_inputs:2,multiple:!1,apply_to:["number","datetime"]},begins_with:{type:"begins_with",nb_inputs:1,multiple:!1,apply_to:["string"]},not_begins_with:{type:"not_begins_with",nb_inputs:1,multiple:!1,apply_to:["string"]},contains:{type:"contains",nb_inputs:1,multiple:!1,apply_to:["string"]},not_contains:{type:"not_contains",nb_inputs:1,multiple:!1,apply_to:["string"]},ends_with:{type:"ends_with",nb_inputs:1,multiple:!1,apply_to:["string"]},not_ends_with:{type:"not_ends_with",nb_inputs:1,multiple:!1,apply_to:["string"]},is_empty:{type:"is_empty",nb_inputs:0,multiple:!1,apply_to:["string"]},is_not_empty:{type:"is_not_empty",nb_inputs:0,multiple:!1,apply_to:["string"]},is_null:{type:"is_null",nb_inputs:0,multiple:!1,apply_to:["string","number","datetime","boolean"]},is_not_null:{type:"is_not_null",nb_inputs:0,multiple:!1,apply_to:["string","number","datetime","boolean"]}},g.DEFAULTS={filters:[],plugins:[],sort_filters:!1,display_errors:!0,allow_groups:-1,allow_empty:!1,conditions:["AND","OR"],default_condition:"AND",inputs_separator:" , ",select_placeholder:"------",display_empty_filter:!0,default_filter:null,optgroups:{},default_rule_flags:{filter_readonly:!1,operator_readonly:!1,value_readonly:!1,no_delete:!1},default_group_flags:{condition_readonly:!1,no_add_rule:!1,no_add_group:!1,no_delete:!1},templates:{group:null,rule:null,filterSelect:null,operatorSelect:null},lang_code:"en",lang:{},operators:["equal","not_equal","in","not_in","less","less_or_equal","greater","greater_or_equal","between","not_between","begins_with","not_begins_with","contains","not_contains","ends_with","not_ends_with","is_empty","is_not_empty","is_null","is_not_null"],icons:{add_group:"glyphicon glyphicon-plus-sign",add_rule:"glyphicon glyphicon-plus",remove_group:"glyphicon glyphicon-remove",remove_rule:"glyphicon glyphicon-remove",error:"glyphicon glyphicon-warning-sign"}},g.plugins={},g.defaults=function(a){return"object"!=typeof a?"string"==typeof a?"object"==typeof g.DEFAULTS[a]?$.extend(!0,{},g.DEFAULTS[a]):g.DEFAULTS[a]:$.extend(!0,{},g.DEFAULTS):void $.extendext(!0,"replace",g.DEFAULTS,a)},g.define=function(a,b,c){g.plugins[a]={fct:b,def:c||{}}},g.extend=function(a){$.extend(g.prototype,a)},g.prototype.initPlugins=function(){if(this.plugins){if($.isArray(this.plugins)){var a={};this.plugins.forEach(function(b){a[b]=null}),this.plugins=a}Object.keys(this.plugins).forEach(function(a){a in g.plugins?(this.plugins[a]=$.extend(!0,{},g.plugins[a].def,this.plugins[a]||{}),g.plugins[a].fct.call(this,this.plugins[a])):h.error("Config",'Unable to find plugin "{0}"',a)},this)}},g.prototype.getPluginOptions=function(a,b){var c;return this.plugins&&this.plugins[a]?c=this.plugins[a]:g.plugins[a]&&(c=g.plugins[a].def),c?b?c[b]:c:void h.error("Config",'Unable to find plugin "{0}"',a)},g.prototype.checkFilters=function(a){var b=[];if(a&&0!==a.length||h.error("Config","Missing filters list"),a.forEach(function(a,c){switch(a.id||h.error("Config","Missing filter {0} id",c),-1!=b.indexOf(a.id)&&h.error("Config",'Filter "{0}" already defined',a.id),b.push(a.id),a.type?g.types[a.type]||h.error("Config",'Invalid type "{0}"',a.type):a.type="string",a.input?"function"!=typeof a.input&&-1==g.inputs.indexOf(a.input)&&h.error("Config",'Invalid input "{0}"',a.input):a.input="number"===g.types[a.type]?"number":"text",a.operators&&a.operators.forEach(function(a){"string"!=typeof a&&h.error("Config","Filter operators must be global operators types (string)")}),a.field||(a.field=a.id),a.label||(a.label=a.field),a.optgroup?(this.status.has_optgroup=!0,this.settings.optgroups[a.optgroup]||(this.settings.optgroups[a.optgroup]=a.optgroup)):a.optgroup=null,a.input){case"radio":case"checkbox":(!a.values||a.values.length<1)&&h.error("Config",'Missing filter "{0}" values',a.id);break;case"select":a.placeholder&&(void 0===a.placeholder_value&&(a.placeholder_value=-1),h.iterateOptions(a.values,function(b){b==a.placeholder_value&&h.error("Config",'Placeholder of filter "{0}" overlaps with one of its values',a.id)}))}},this),this.settings.sort_filters)if("function"==typeof this.settings.sort_filters)a.sort(this.settings.sort_filters);else{var c=this;a.sort(function(a,b){return c.translate(a.label).localeCompare(c.translate(b.label))})}return this.status.has_optgroup&&(a=h.groupSort(a,"optgroup")),a},g.prototype.checkOperators=function(a){var b=[];return a.forEach(function(c,d){"string"==typeof c?(g.OPERATORS[c]||h.error("Config",'Unknown operator "{0}"',c),a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c])):(c.type||h.error("Config",'Missing "type" for operator {0}',d),g.OPERATORS[c.type]&&(a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c.type],c)),void 0!==c.nb_inputs&&void 0!==c.apply_to||h.error("Config",'Missing "nb_inputs" and/or "apply_to" for operator "{0}"',c.type)),-1!=b.indexOf(c.type)&&h.error("Config",'Operator "{0}" already defined',c.type),b.push(c.type),c.optgroup?(this.status.has_operator_optgroup=!0,this.settings.optgroups[c.optgroup]||(this.settings.optgroups[c.optgroup]=c.optgroup)):c.optgroup=null},this),this.status.has_operator_optgroup&&(a=h.groupSort(a,"optgroup")),a},g.prototype.bindEvents=function(){var a=this,b=g.selectors;this.$el.on("change.queryBuilder",b.group_condition,function(){if($(this).is(":checked")){var c=$(this).closest(b.group_container);a.getModel(c).condition=$(this).val()}}),this.$el.on("change.queryBuilder",b.rule_filter,function(){var c=$(this).closest(b.rule_container);a.getModel(c).filter=a.getFilterById($(this).val())}),this.$el.on("change.queryBuilder",b.rule_operator,function(){var c=$(this).closest(b.rule_container);a.getModel(c).operator=a.getOperatorByType($(this).val())}),this.$el.on("click.queryBuilder",b.add_rule,function(){var c=$(this).closest(b.group_container);a.addRule(a.getModel(c))}),this.$el.on("click.queryBuilder",b.delete_rule,function(){var c=$(this).closest(b.rule_container);a.deleteRule(a.getModel(c))}),0!==this.settings.allow_groups&&(this.$el.on("click.queryBuilder",b.add_group,function(){var c=$(this).closest(b.group_container);a.addGroup(a.getModel(c))}),this.$el.on("click.queryBuilder",b.delete_group,function(){var c=$(this).closest(b.group_container);a.deleteGroup(a.getModel(c))})),this.model.on({drop:function(b,c){c.$el.remove(),a.refreshGroupsConditions()},add:function(b,c,d,e){0===e?d.$el.prependTo(c.$el.find(">"+g.selectors.rules_list)):d.$el.insertAfter(c.rules[e-1].$el),a.refreshGroupsConditions()},move:function(b,c,d,e){c.$el.detach(),0===e?c.$el.prependTo(d.$el.find(">"+g.selectors.rules_list)):c.$el.insertAfter(d.rules[e-1].$el),a.refreshGroupsConditions()},update:function(b,c,d,e,f){if(c instanceof k)switch(d){case"error":a.updateError(c);break;case"flags":a.applyRuleFlags(c);break;case"filter":a.updateRuleFilter(c,f);break;case"operator":a.updateRuleOperator(c,f);break;case"value":a.updateRuleValue(c)}else switch(d){case"error":a.updateError(c);break;case"flags":a.applyGroupFlags(c);break;case"condition":a.updateGroupCondition(c)}}})},g.prototype.setRoot=function(a,b,c){a=void 0===a||a===!0;var d=this.nextGroupId(),e=$(this.getGroupTemplate(d,1));return this.$el.append(e),this.model.root=new j(null,e),this.model.root.model=this.model,this.model.root.data=b,this.model.root.__.flags=$.extend({},this.settings.default_group_flags,c),this.trigger("afterAddGroup",this.model.root),this.model.root.condition=this.settings.default_condition,a&&this.addRule(this.model.root),this.model.root},g.prototype.addGroup=function(a,b,c,d){b=void 0===b||b===!0;var e=a.level+1,f=this.trigger("beforeAddGroup",a,b,e);if(f.isDefaultPrevented())return null;var g=this.nextGroupId(),h=$(this.getGroupTemplate(g,e)),i=a.addGroup(h);return i.data=c,i.__.flags=$.extend({},this.settings.default_group_flags,d),this.trigger("afterAddGroup",i),i.condition=this.settings.default_condition,b&&this.addRule(i),i},g.prototype.deleteGroup=function(a){if(a.isRoot())return!1;var b=this.trigger("beforeDeleteGroup",a);if(b.isDefaultPrevented())return!1;var c=!0;return a.each("reverse",function(a){c&=this.deleteRule(a)},function(a){c&=this.deleteGroup(a)},this),c&&(a.drop(),this.trigger("afterDeleteGroup")),c},g.prototype.updateGroupCondition=function(a){a.$el.find(">"+g.selectors.group_condition).each(function(){var b=$(this);b.prop("checked",b.val()===a.condition),b.parent().toggleClass("active",b.val()===a.condition)}),this.trigger("afterUpdateGroupCondition",a)},g.prototype.refreshGroupsConditions=function(){!function a(b){(!b.flags||b.flags&&!b.flags.condition_readonly)&&b.$el.find(">"+g.selectors.group_condition).prop("disabled",b.rules.length<=1).parent().toggleClass("disabled",b.rules.length<=1),b.each(null,function(b){a(b)},this)}(this.model.root)},g.prototype.addRule=function(a,b,c){var d=this.trigger("beforeAddRule",a);if(d.isDefaultPrevented())return null;var e=this.nextRuleId(),f=$(this.getRuleTemplate(e)),g=a.addRule(f);return void 0!==b&&(g.data=b),g.__.flags=$.extend({},this.settings.default_rule_flags,c),this.trigger("afterAddRule",g),this.createRuleFilters(g),!this.settings.default_filter&&this.settings.display_empty_filter||(g.filter=this.change("getDefaultFilter",this.getFilterById(this.settings.default_filter||this.filters[0].id),g)),g},g.prototype.deleteRule=function(a){if(a.flags.no_delete)return!1;var b=this.trigger("beforeDeleteRule",a);return b.isDefaultPrevented()?!1:(a.drop(),this.trigger("afterDeleteRule"),!0)},g.prototype.createRuleFilters=function(a){var b=this.change("getRuleFilters",this.filters,a),c=$(this.getRuleFilterSelect(a,b));a.$el.find(g.selectors.filter_container).html(c),this.trigger("afterCreateRuleFilters",a)},g.prototype.createRuleOperators=function(a){var b=a.$el.find(g.selectors.operator_container).empty();if(a.filter){var c=this.getOperators(a.filter),d=$(this.getRuleOperatorSelect(a,c));b.html(d),a.__.operator=c[0],this.trigger("afterCreateRuleOperators",a,c)}},g.prototype.createRuleInput=function(a){var b=a.$el.find(g.selectors.value_container).empty();if(a.__.value=void 0,a.filter&&a.operator&&0!==a.operator.nb_inputs){for(var c=this,d=$(),e=a.filter,f=0;f0&&b.append(this.settings.inputs_separator),b.append(h),d=d.add(h)}b.show(),d.on("change "+(e.input_event||""),function(){this._updating_input||(a._updating_value=!0,a.value=c.getRuleInputValue(a),a._updating_value=!1)}),e.plugin&&d[e.plugin](e.plugin_config||{}),this.trigger("afterCreateRuleInput",a),void 0!==e.default_value?a.value=e.default_value:(a._updating_value=!0,a.value=c.getRuleInputValue(a),a._updating_value=!1)}},g.prototype.updateRuleFilter=function(a,b){this.createRuleOperators(a),this.createRuleInput(a),a.$el.find(g.selectors.rule_filter).val(a.filter?a.filter.id:"-1"),b&&a.filter&&b.id!==a.filter.id&&(a.data=void 0),this.trigger("afterUpdateRuleFilter",a)},g.prototype.updateRuleOperator=function(a,b){var c=a.$el.find(g.selectors.value_container);a.operator&&0!==a.operator.nb_inputs?(c.show(),!c.is(":empty")&&b&&a.operator.nb_inputs===b.nb_inputs&&a.operator.optgroup===b.optgroup||this.createRuleInput(a)):(c.hide(),a.__.value=void 0),a.operator&&a.$el.find(g.selectors.rule_operator).val(a.operator.type),this.trigger("afterUpdateRuleOperator",a),this.updateRuleValue(a)},g.prototype.updateRuleValue=function(a){a._updating_value||this.setRuleInputValue(a,a.value),this.trigger("afterUpdateRuleValue",a)},g.prototype.applyRuleFlags=function(a){var b=a.flags,c=g.selectors;b.filter_readonly&&a.$el.find(c.rule_filter).prop("disabled",!0),b.operator_readonly&&a.$el.find(c.rule_operator).prop("disabled",!0),b.value_readonly&&a.$el.find(c.rule_value).prop("disabled",!0),b.no_delete&&a.$el.find(c.delete_rule).remove(),this.trigger("afterApplyRuleFlags",a)},g.prototype.applyGroupFlags=function(a){var b=a.flags,c=g.selectors;b.condition_readonly&&a.$el.find(">"+c.group_condition).prop("disabled",!0).parent().addClass("readonly"),b.no_add_rule&&a.$el.find(c.add_rule).remove(),b.no_add_group&&a.$el.find(c.add_group).remove(),b.no_delete&&a.$el.find(c.delete_group).remove(),this.trigger("afterApplyGroupFlags",a)},g.prototype.clearErrors=function(a){a=a||this.model.root,a&&(a.error=null,a instanceof j&&a.each(function(a){a.error=null},function(a){this.clearErrors(a)},this))},g.prototype.updateError=function(a){if(this.settings.display_errors)if(null===a.error)a.$el.removeClass("has-error");else{var b=this.translate("errors",a.error[0]);b=h.fmt(b,a.error.slice(1)),b=this.change("displayError",b,a.error,a),a.$el.addClass("has-error").find(g.selectors.error_container).eq(0).attr("title",b)}},g.prototype.triggerValidationError=function(a,b,c){$.isArray(b)||(b=[b]);var d=this.trigger("validationError",a,b,c);d.isDefaultPrevented()||(a.error=b)},g.prototype.destroy=function(){this.trigger("beforeDestroy"),this.status.generated_id&&this.$el.removeAttr("id"),this.clear(),this.model=null,this.$el.off(".queryBuilder").removeClass("query-builder").removeData("queryBuilder"),delete this.$el[0].queryBuilder},g.prototype.reset=function(){var a=this.trigger("beforeReset");a.isDefaultPrevented()||(this.status.group_id=1,this.status.rule_id=0,this.model.root.empty(),this.addRule(this.model.root),this.trigger("afterReset"))},g.prototype.clear=function(){var a=this.trigger("beforeClear");a.isDefaultPrevented()||(this.status.group_id=0,this.status.rule_id=0,this.model.root&&(this.model.root.drop(),this.model.root=null),this.trigger("afterClear"))},g.prototype.setOptions=function(a){$.each(a,function(a,b){-1!==g.modifiable_options.indexOf(a)&&(this.settings[a]=b)}.bind(this))},g.prototype.getModel=function(a){return a?a instanceof i?a:$(a).data("queryBuilderModel"):this.model.root},g.prototype.validate=function(a){a=$.extend({skip_empty:!1},a),this.clearErrors();var b=this,c=function d(c){var e=0,f=0;return c.each(function(c){if(c.filter||!a.skip_empty){if(!c.filter)return b.triggerValidationError(c,"no_filter",null),void f++;if(!c.operator)return b.triggerValidationError(c,"no_operator",null),void f++;if(0!==c.operator.nb_inputs){var d=b.validateValue(c,c.value);if(d!==!0)return b.triggerValidationError(c,d,c.value),void f++}e++}},function(a){var b=d(a);b===!0?e++:b===!1&&f++}),f>0?!1:0===e&&!c.isRoot()&&a.skip_empty?null:0!==e||b.settings.allow_empty&&c.isRoot()?!0:(b.triggerValidationError(c,"empty_group",null),!1)}(this.model.root);return this.change("validate",c)},g.prototype.getRules=function(a){a=$.extend({get_flags:!1,allow_invalid:!1,skip_empty:!1},a);var b=this.validate(a);if(!b&&!a.allow_invalid)return null;var c=this,d=function e(b){var d={condition:b.condition,rules:[]};if(b.data&&(d.data=$.extendext(!0,"replace",{},b.data)),a.get_flags){var f=c.getGroupFlags(b.flags,"all"===a.get_flags);$.isEmptyObject(f)||(d.flags=f)}return b.each(function(b){if(b.filter||!a.skip_empty){var e=null;b.operator&&0===b.operator.nb_inputs||(e=b.value);var f={id:b.filter?b.filter.id:null,field:b.filter?b.filter.field:null,type:b.filter?b.filter.type:null,input:b.filter?b.filter.input:null,operator:b.operator?b.operator.type:null,value:e};if((b.filter&&b.filter.data||b.data)&&(f.data=$.extendext(!0,"replace",{},b.filter.data,b.data)),a.get_flags){var g=c.getRuleFlags(b.flags,"all"===a.get_flags);$.isEmptyObject(g)||(f.flags=g)}d.rules.push(c.change("ruleToJson",f,b))}},function(b){var c=e(b);0===c.rules.length&&a.skip_empty||d.rules.push(c)},this),c.change("groupToJson",d,b)}(this.model.root);return d.valid=b,this.change("getRules",d)},g.prototype.setRules=function(a,b){b=$.extend({allow_invalid:!1},b),$.isArray(a)&&(a={condition:this.settings.default_condition,rules:a}),a&&a.rules&&(0!==a.rules.length||this.settings.allow_empty)||h.error("RulesParse","Incorrect data object passed"),this.clear(),this.setRoot(!1,a.data,this.parseGroupFlags(a)),this.applyGroupFlags(this.model.root),a=this.change("setRules",a,b);var c=this;!function d(a,e){null!==e&&(void 0===a.condition?a.condition=c.settings.default_condition:-1==c.settings.conditions.indexOf(a.condition)&&(h.error(!b.allow_invalid,"UndefinedCondition",'Invalid condition "{0}"',a.condition),a.condition=c.settings.default_condition),e.condition=a.condition,a.rules.forEach(function(a){var f;if(void 0!==a.rules)if(-1!==c.settings.allow_groups&&c.settings.allow_groups1){j=["operator_not_multiple",f.type,this.translate("operators",f.type)];break}switch(e.input){case"radio":if(void 0===b[k]||0===b[k].length){i.allow_empty_value||(j=["radio_empty"]);break}break;case"checkbox":if(void 0===b[k]||0===b[k].length){i.allow_empty_value||(j=["checkbox_empty"]);break}break;case"select":if(void 0===b[k]||0===b[k].length||e.placeholder&&b[k]==e.placeholder_value){i.allow_empty_value||(j=["select_empty"]);break}break;default:d=$.isArray(b[k])?b[k]:[b[k]];for(var l=0;lparseInt(i.max)){j=[this.getValidationMessage(i,"max","string_exceed_max_length"),i.max];break}if(i.format&&("string"==typeof i.format&&(i.format=new RegExp(i.format)),!i.format.test(d[l]))){j=[this.getValidationMessage(i,"format","string_invalid_format"),i.format];break}break;case"number":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["number_nan"]);break}if(isNaN(d[l])){j=["number_nan"];break}if("integer"==e.type){if(parseInt(d[l])!=d[l]){j=["number_not_integer"];break}}else if(parseFloat(d[l])!=d[l]){j=["number_not_double"];break}if(void 0!==i.min&&d[l]parseFloat(i.max)){j=[this.getValidationMessage(i,"max","number_exceed_max"),i.max];break}if(void 0!==i.step&&"any"!==i.step){var m=(d[l]/i.step).toPrecision(14);if(parseInt(m)!=m){j=[this.getValidationMessage(i,"step","number_wrong_step"),i.step];break}}break;case"datetime":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["datetime_empty"]);break}if(i.format){"moment"in window||h.error("MissingLibrary","MomentJS is required for Date/Time validation. Get it here http://momentjs.com");var n=moment(d[l],i.format);if(!n.isValid()){j=[this.getValidationMessage(i,"format","datetime_invalid"),i.format];break}if(i.min&&nmoment(i.max,i.format)){j=[this.getValidationMessage(i,"max","datetime_exceed_max"),i.max];break}}break;case"boolean":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["boolean_not_valid"]);break}if(c=(""+d[l]).trim().toLowerCase(),"true"!==c&&"false"!==c&&"1"!==c&&"0"!==c&&1!==d[l]&&0!==d[l]){j=["boolean_not_valid"];break}}if(j!==!0)break}}if(j!==!0)break}return j},g.prototype.nextGroupId=function(){return this.status.id+"_group_"+this.status.group_id++},g.prototype.nextRuleId=function(){return this.status.id+"_rule_"+this.status.rule_id++},g.prototype.getOperators=function(a){"string"==typeof a&&(a=this.getFilterById(a));for(var b=[],c=0,d=this.operators.length;d>c;c++){if(a.operators){if(-1==a.operators.indexOf(this.operators[c].type))continue}else if(-1==this.operators[c].apply_to.indexOf(g.types[a.type]))continue;b.push(this.operators[c])}return a.operators&&b.sort(function(b,c){return a.operators.indexOf(b.type)-a.operators.indexOf(c.type)}),this.change("getOperators",b,a)},g.prototype.getFilterById=function(a,b){if("-1"==a)return null;for(var c=0,d=this.filters.length;d>c;c++)if(this.filters[c].id==a)return this.filters[c];return h.error(b!==!1,"UndefinedFilter",'Undefined filter "{0}"',a),null},g.prototype.getOperatorByType=function(a,b){if("-1"==a)return null;for(var c=0,d=this.operators.length;d>c;c++)if(this.operators[c].type==a)return this.operators[c];return h.error(b!==!1,"UndefinedOperator",'Undefined operator "{0}"',a),null},g.prototype.getRuleInputValue=function(a){var b=a.filter,c=a.operator,d=[];if(b.valueGetter)d=b.valueGetter.call(this,a);else{for(var e=a.$el.find(g.selectors.value_container),f=0;f '+b+" "});break;case"select":g+='";break;case"textarea":g+='";break;case"number":g+='=f:e<=f},i=!1;h()&&(this.rules[e]instanceof j?c&&(i=c.call(d,this.rules[e])===!1):b&&(i=b.call(d,this.rules[e])===!1),!i);e+=g);return!i},j.prototype.contains=function(a,b){return this.getNodePos(a)!==-1||!!b&&!this.each(function(){return!0},function(b){return!b.contains(a,!0)})};var k=function(a,b){return this instanceof k?(i.call(this,a,b),this._updating_value=!1,this._updating_input=!1,this.__.filter=null,this.__.operator=null,void(this.__.value=void 0)):new k(a,b)};return k.prototype=Object.create(i.prototype),k.prototype.constructor=k,h.defineModelProperties(k,["filter","operator","value"]),k.prototype.isRoot=function(){return!1},g.Group=j,g.Rule=k,$.fn.queryBuilder=function(a){0===this.length&&h.error("Config","No target defined"),this.length>1&&h.error("Config","Unable to initialize on multiple target");var b=this.data("queryBuilder"),c="object"==typeof a&&a||{};if(!b&&"destroy"==a)return this;if(!b){var d=new g(this,c);this.data("queryBuilder",d),d.init(c.rules)}return"string"==typeof a?b[a].apply(b,Array.prototype.slice.call(arguments,1)):this},$.fn.queryBuilder.constructor=g,$.fn.queryBuilder.defaults=g.defaults,$.fn.queryBuilder.extend=g.extend,$.fn.queryBuilder.define=g.define,$.fn.queryBuilder.regional=g.regional,g.define("bt-checkbox",function(a){"glyphicons"==a.font&&this.$el.addClass("bt-checkbox-glyphicons"),this.on("getRuleInput.filter",function(b,c,d){var e=c.filter;if(("radio"===e.input||"checkbox"===e.input)&&!e.plugin){b.value="",e.colors||(e.colors={}),e.color&&(e.colors._def_=e.color);var f=e.vertical?' style="display:block"':"",g=0;h.iterateOptions(e.values,function(c,h){var i=e.colors[c]||e.colors._def_||a.color,j=d+"_"+g++;b.value+=" "})}})},{font:"glyphicons",color:"default"}),g.define("bt-selectpicker",function(a){$.fn.selectpicker&&$.fn.selectpicker.Constructor||h.error("MissingLibrary",'Bootstrap Select is required to use "bt-selectpicker" plugin. Get it here: http://silviomoreto.github.io/bootstrap-select');var b=g.selectors;this.on("afterCreateRuleFilters",function(c,d){d.$el.find(b.rule_filter).removeClass("form-control").selectpicker(a)}),this.on("afterCreateRuleOperators",function(c,d){d.$el.find(b.rule_operator).removeClass("form-control").selectpicker(a)}),this.on("afterUpdateRuleFilter",function(a,c){c.$el.find(b.rule_filter).selectpicker("render")}),this.on("afterUpdateRuleOperator",function(a,c){c.$el.find(b.rule_operator).selectpicker("render")}),this.on("beforeDeleteRule",function(a,c){c.$el.find(b.rule_filter).selectpicker("destroy"),c.$el.find(b.rule_operator).selectpicker("destroy")})},{container:"body",style:"btn-inverse btn-xs",width:"auto",showIcon:!1}),g.define("bt-tooltip-errors",function(a){$.fn.tooltip&&$.fn.tooltip.Constructor&&$.fn.tooltip.Constructor.prototype.fixTitle||h.error("MissingLibrary",'Bootstrap Tooltip is required to use "bt-tooltip-errors" plugin. Get it here: http://getbootstrap.com');var b=this;this.on("getRuleTemplate.filter getGroupTemplate.filter",function(a){var b=$(a.value);b.find(g.selectors.error_container).attr("data-toggle","tooltip"),a.value=b.prop("outerHTML")}),this.model.on("update",function(c,d,e){"error"==e&&b.settings.display_errors&&d.$el.find(g.selectors.error_container).eq(0).tooltip(a).tooltip("hide").tooltip("fixTitle")})},{placement:"right"}),g.extend({setFilters:function(a,b){var c=this;void 0===b&&(b=a,a=!1),b=this.checkFilters(b),b=this.change("setFilters",b);var d=b.map(function(a){return a.id});if(a||!function f(a){a.each(function(a){a.filter&&d.indexOf(a.filter.id)===-1&&h.error("ChangeFilter",'A rule is using filter "{0}"',a.filter.id)},f)}(this.model.root),this.filters=b,function i(a){a.each(!0,function(a){a.filter&&d.indexOf(a.filter.id)===-1?(a.drop(),c.trigger("rulesChanged")):(c.createRuleFilters(a),a.$el.find(g.selectors.rule_filter).val(a.filter?a.filter.id:"-1"),c.trigger("afterUpdateRuleFilter",a))},i)}(this.model.root),this.settings.plugins&&(this.settings.plugins["unique-filter"]&&this.updateDisabledFilters(),this.settings.plugins["bt-selectpicker"]&&this.$el.find(g.selectors.rule_filter).selectpicker("render")),this.settings.default_filter)try{this.getFilterById(this.settings.default_filter)}catch(e){this.settings.default_filter=null}this.trigger("afterSetFilters",b)},addFilter:function(a,b){void 0===b||"#end"==b?b=this.filters.length:"#start"==b&&(b=0),$.isArray(a)||(a=[a]);var c=$.extend(!0,[],this.filters);parseInt(b)==b?Array.prototype.splice.apply(c,[b,0].concat(a)):this.filters.some(function(a,c){if(a.id==b)return b=c+1,!0})?Array.prototype.splice.apply(c,[b,0].concat(a)):Array.prototype.push.apply(c,a),this.setFilters(c)},removeFilter:function(a,b){var c=$.extend(!0,[],this.filters);"string"==typeof a&&(a=[a]),c=c.filter(function(b){return a.indexOf(b.id)===-1}),this.setFilters(b,c)}}),g.define("filter-description",function(a){"inline"===a.mode?this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("p.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$('

'),d.appendTo(c.$el)):d.show(),d.html(' '+e)):d.hide()}):"popover"===a.mode?($.fn.popover&&$.fn.popover.Constructor&&$.fn.popover.Constructor.prototype.fixTitle||h.error("MissingLibrary",'Bootstrap Popover is required to use "filter-description" plugin. Get it here: http://getbootstrap.com'),this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("button.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$(''),d.prependTo(c.$el.find(g.selectors.rule_actions)),d.popover({placement:"left",container:"body",html:!0}),d.on("mouseout",function(){d.popover("hide")})):d.show(),d.data("bs.popover").options.content=e,d.attr("aria-describedby")&&d.popover("show")):(d.hide(),d.data("bs.popover")&&d.popover("hide"))})):"bootbox"===a.mode&&("bootbox"in window||h.error("MissingLibrary",'Bootbox is required to use "filter-description" plugin. Get it here: http://bootboxjs.com'),this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("button.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$(''),d.prependTo(c.$el.find(g.selectors.rule_actions)),d.on("click",function(){bootbox.alert(d.data("description"))})):d.show(),d.data("description",e)):d.hide()}))},{icon:"glyphicon glyphicon-info-sign",mode:"popover"}),g.extend({getFilterDescription:function(a,b){return a?"function"==typeof a.description?a.description.call(this,b):a.description:void 0}}),g.define("invert",function(a){var b=this,c=g.selectors;this.on("afterInit",function(){b.$el.on("click.queryBuilder","[data-invert=group]",function(){var d=$(this).closest(c.group_container);b.invert(b.getModel(d),a)}),a.display_rules_button&&a.invert_rules&&b.$el.on("click.queryBuilder","[data-invert=rule]",function(){var d=$(this).closest(c.rule_container);b.invert(b.getModel(d),a)})}),this.on("getGroupTemplate.filter",function(d,e){var f=$(d.value);f.find(c.condition_container).after('"),d.value=f.prop("outerHTML")}),a.display_rules_button&&a.invert_rules&&this.on("getRuleTemplate.filter",function(d){var e=$(d.value);e.find(c.rule_actions).prepend('"),d.value=e.prop("outerHTML")})},{icon:"glyphicon glyphicon-random",recursive:!0,invert_rules:!0,display_rules_button:!1,silent_fail:!1}),g.defaults({operatorOpposites:{equal:"not_equal",not_equal:"equal","in":"not_in",not_in:"in",less:"greater_or_equal",less_or_equal:"greater",greater:"less_or_equal",greater_or_equal:"less",between:"not_between",not_between:"between",begins_with:"not_begins_with",not_begins_with:"begins_with",contains:"not_contains",not_contains:"contains",ends_with:"not_ends_with",not_ends_with:"ends_with",is_empty:"is_not_empty",is_not_empty:"is_empty",is_null:"is_not_null",is_not_null:"is_null"},conditionOpposites:{AND:"OR",OR:"AND"}}),g.extend({invert:function(a,b){if(!(a instanceof i)){if(!this.model.root)return;b=a,a=this.model.root}if("object"!=typeof b&&(b={}),void 0===b.recursive&&(b.recursive=!0),void 0===b.invert_rules&&(b.invert_rules=!0),void 0===b.silent_fail&&(b.silent_fail=!1),void 0===b.trigger&&(b.trigger=!0),a instanceof j){if(this.settings.conditionOpposites[a.condition]?a.condition=this.settings.conditionOpposites[a.condition]:b.silent_fail||h.error("InvertCondition",'Unknown inverse of condition "{0}"',a.condition),b.recursive){var c=$.extend({},b,{trigger:!1});a.each(function(a){b.invert_rules&&this.invert(a,c)},function(a){this.invert(a,c)},this)}}else if(a instanceof k&&a.operator&&!a.filter.no_invert)if(this.settings.operatorOpposites[a.operator.type]){var d=this.settings.operatorOpposites[a.operator.type];a.filter.operators&&a.filter.operators.indexOf(d)==-1||(a.operator=this.getOperatorByType(d))}else b.silent_fail||h.error("InvertOperator",'Unknown inverse of operator "{0}"',a.operator.type);b.trigger&&(this.trigger("afterInvert",a,b),this.trigger("rulesChanged"))}}),g.defaults({mongoOperators:{equal:function(a){return a[0]},not_equal:function(a){return{$ne:a[0]}},"in":function(a){return{$in:a}},not_in:function(a){return{$nin:a}},less:function(a){return{$lt:a[0]}},less_or_equal:function(a){return{$lte:a[0]}},greater:function(a){return{$gt:a[0]}},greater_or_equal:function(a){return{$gte:a[0]}},between:function(a){return{$gte:a[0],$lte:a[1]}},not_between:function(a){return{$lt:a[0],$gt:a[1]}},begins_with:function(a){return{$regex:"^"+h.escapeRegExp(a[0])}},not_begins_with:function(a){return{$regex:"^(?!"+h.escapeRegExp(a[0])+")"}},contains:function(a){return{$regex:h.escapeRegExp(a[0])}},not_contains:function(a){return{$regex:"^((?!"+h.escapeRegExp(a[0])+").)*$",$options:"s"}},ends_with:function(a){return{$regex:h.escapeRegExp(a[0])+"$"}},not_ends_with:function(a){return{$regex:"(?0)d.push(c(a));else{var e=b.settings.mongoOperators[a.operator],f=b.getOperatorByType(a.operator),g=[];void 0===e&&h.error("UndefinedMongoOperator",'Unknown MongoDB operation for operator "{0}"',a.operator),0!==f.nb_inputs&&(a.value instanceof Array||(a.value=[a.value]),a.value.forEach(function(b){g.push(h.changeType(b,a.type,!1))}));var i=b.change("getMongoDBField",a.field,a),j={};j[i]=e.call(b,g),d.push(b.change("ruleToMongo",j,a,g,e))}});var e={};return e["$"+a.condition.toLowerCase()]=d,b.change("groupToMongo",e,a)}(a)},getRulesFromMongo:function(a){if(void 0===a||null===a)return null;var b=this;if(a=b.change("parseMongoNode",a),"rules"in a&&"condition"in a)return a;if("id"in a&&"operator"in a&&"value"in a)return{condition:this.settings.default_condition,rules:[a]};var e=d(a);return e||h.error("MongoParse","Invalid MongoDB query format"),function f(a,e){var g=a[e],i=[];return g.forEach(function(a){if(a=b.change("parseMongoNode",a),"rules"in a&&"condition"in a)return void i.push(a);if("id"in a&&"operator"in a&&"value"in a)return void i.push(a);var e=d(a);if(e)i.push(f(a,e));else{var g=Object.keys(a)[0],j=a[g],k=c(j,g);void 0===k&&h.error("MongoParse","Invalid MongoDB query format");var l=b.settings.mongoRuleOperators[k];void 0===l&&h.error("UndefinedMongoOperator",'JSON Rule operation unknown for operator "{0}"',k);var m=l.call(b,j),n=b.getMongoDBFieldID(g,j),o=b.change("mongoToRule",{id:n,field:g,operator:m.op,value:m.val},a);i.push(o)}}),b.change("mongoToGroup",{condition:e.replace("$","").toUpperCase(),rules:i},a)}(a,e)},setRulesFromMongo:function(a){this.setRules(this.getRulesFromMongo(a))},getMongoDBFieldID:function(a,b){var c,d=this.filters.filter(function(b){return b.field===a});return c=1===d.length?d[0].id:this.change("getMongoDBFieldID",a,b)}}),g.define("not-group",function(a){var b=this;this.on("afterInit",function(){b.$el.on("click.queryBuilder","[data-not=group]",function(){var a=$(this).closest(g.selectors.group_container),c=b.getModel(a);c.not=!c.not}),b.model.on("update",function(a,c,d){c instanceof j&&"not"===d&&b.updateGroupNot(c)})}),this.on("afterAddGroup",function(a,b){b.__.not=!1}),this.on("getGroupTemplate.filter",function(c,d){var e=$(c.value);e.find(g.selectors.condition_container).prepend('"),c.value=e.prop("outerHTML")}),this.on("groupToJson.filter",function(a,b){a.value.not=b.not}),this.on("jsonToGroup.filter",function(a,b){a.value.not=!!b.not}),this.on("groupToSQL.filter",function(a,b){b.not&&(a.value="NOT ( "+a.value+" )")}),this.on("parseSQLNode.filter",function(a){a.value.name&&"NOT"==a.value.name.toUpperCase()&&(a.value=a.value.arguments.value[0],a.value.not=!0)}),this.on("sqlToGroup.filter",function(a,b){a.value.not=!!b.not}),this.on("groupToMongo.filter",function(a,b){var c="$"+b.condition.toLowerCase();b.not&&a.value[c]&&(a.value={$nor:[a.value]})}),this.on("parseMongoNode.filter",function(a){var b=Object.keys(a.value);"$nor"==b[0]&&(a.value=a.value[b[0]][0],a.value.not=!0)}),this.on("mongoToGroup.filter",function(a,b){a.value.not=!!b.not})},{icon_unchecked:"glyphicon glyphicon-unchecked",icon_checked:"glyphicon glyphicon-check"}),h.defineModelProperties(j,["not"]),g.selectors.group_not=g.selectors.group_header+" [data-not=group]",g.extend({updateGroupNot:function(a){var b=this.plugins["not-group"];a.$el.find(">"+g.selectors.group_not).toggleClass("active",a.not).find("i").attr("class",a.not?b.icon_checked:b.icon_unchecked),this.trigger("afterUpdateGroupNot",a),this.trigger("rulesChanged")}}),g.define("sortable",function(a){"interact"in window||h.error("MissingLibrary",'interact.js is required to use "sortable" plugin. Get it here: http://interactjs.io'),void 0!==a.default_no_sortable&&(h.error(!1,"Config",'Sortable plugin : "default_no_sortable" options is deprecated, use standard "default_rule_flags" and "default_group_flags" instead'),this.settings.default_rule_flags.no_sortable=this.settings.default_group_flags.no_sortable=a.default_no_sortable),interact.dynamicDrop(!0),interact.pointerMoveTolerance(10);var b,c,d;this.on("afterAddRule afterAddGroup",function(f,h){if(h!=b){var i=f.builder;a.inherit_no_sortable&&h.parent&&h.parent.flags.no_sortable&&(h.flags.no_sortable=!0),a.inherit_no_drop&&h.parent&&h.parent.flags.no_drop&&(h.flags.no_drop=!0),h.flags.no_sortable||interact(h.$el[0]).allowFrom(g.selectors.drag_handle).draggable({onstart:function(a){d=i.getModel(a.target),c=d.$el.clone().appendTo(d.$el.parent()).width(d.$el.outerWidth()).addClass("dragging");var e=$('
 
').height(d.$el.outerHeight());b=d.parent.addRule(e,d.getPos()),d.$el.hide()},onmove:function(a){c[0].style.top=a.clientY-15+"px",c[0].style.left=a.clientX-15+"px"},onend:function(){c.remove(),c=void 0,b.drop(),b=void 0,d.$el.show(),i.trigger("afterMove",d),i.trigger("rulesChanged")}}),h.flags.no_drop||(interact(h.$el[0]).dropzone({accept:g.selectors.rule_and_group_containers,ondragenter:function(a){e(b,$(a.target),i)},ondrop:function(a){e(d,$(a.target),i)}}),h instanceof j&&interact(h.$el.find(g.selectors.group_header)[0]).dropzone({accept:g.selectors.rule_and_group_containers,ondragenter:function(a){e(b,$(a.target),i)},ondrop:function(a){e(d,$(a.target),i)}}))}}),this.on("beforeDeleteRule beforeDeleteGroup",function(a,b){a.isDefaultPrevented()||(interact(b.$el[0]).unset(),b instanceof j&&interact(b.$el.find(g.selectors.group_header)[0]).unset())}),this.on("afterApplyRuleFlags afterApplyGroupFlags",function(a,b){b.flags.no_sortable&&b.$el.find(".drag-handle").remove()}),this.on("getGroupTemplate.filter",function(b,c){if(c>1){var d=$(b.value);d.find(g.selectors.condition_container).after('
'),b.value=d.prop("outerHTML")}}),this.on("getRuleTemplate.filter",function(b){var c=$(b.value);c.find(g.selectors.rule_header).after('
'),b.value=c.prop("outerHTML")})},{inherit_no_sortable:!0,inherit_no_drop:!0,icon:"glyphicon glyphicon-sort"}),g.selectors.rule_and_group_containers=g.selectors.rule_container+", "+g.selectors.group_container,g.selectors.drag_handle=".drag-handle",g.defaults({default_rule_flags:{no_sortable:!1,no_drop:!1},default_group_flags:{no_sortable:!1,no_drop:!1}}),g.define("sql-support",function(a){},{boolean_as_integer:!0}),g.defaults({sqlOperators:{equal:{op:"= ?"},not_equal:{op:"!= ?"},"in":{op:"IN(?)",sep:", "},not_in:{op:"NOT IN(?)",sep:", "},less:{op:"< ?"},less_or_equal:{op:"<= ?"},greater:{op:"> ?"},greater_or_equal:{op:">= ?"},between:{op:"BETWEEN ?",sep:" AND "},not_between:{op:"NOT BETWEEN ?",sep:" AND "},begins_with:{op:"LIKE(?)",mod:"{0}%"},not_begins_with:{op:"NOT LIKE(?)",mod:"{0}%"},contains:{op:"LIKE(?)",mod:"%{0}%"},not_contains:{op:"NOT LIKE(?)",mod:"%{0}%"},ends_with:{op:"LIKE(?)",mod:"%{0}"},not_ends_with:{op:"NOT LIKE(?)",mod:"%{0}"},is_empty:{op:"= ''"},is_not_empty:{op:"!= ''"},is_null:{op:"IS NULL"},is_not_null:{op:"IS NOT NULL"}},sqlRuleOperator:{"=":function(a){return{val:a,op:""===a?"is_empty":"equal"}},"!=":function(a){return{val:a,op:""===a?"is_not_empty":"not_equal"}},LIKE:function(a){return"%"==a.slice(0,1)&&"%"==a.slice(-1)?{val:a.slice(1,-1),op:"contains"}:"%"==a.slice(0,1)?{val:a.slice(1),op:"ends_with"}:"%"==a.slice(-1)?{val:a.slice(0,-1),op:"begins_with"}:void h.error("SQLParse",'Invalid value for LIKE operator "{0}"',a)},"NOT LIKE":function(a){return"%"==a.slice(0,1)&&"%"==a.slice(-1)?{val:a.slice(1,-1),op:"not_contains"}:"%"==a.slice(0,1)?{val:a.slice(1),op:"not_ends_with"}:"%"==a.slice(-1)?{val:a.slice(0,-1),op:"not_begins_with"}:void h.error("SQLParse",'Invalid value for NOT LIKE operator "{0}"',a)},IN:function(a){return{val:a,op:"in"}},"NOT IN":function(a){return{val:a,op:"not_in"}},"<":function(a){return{val:a,op:"less"}},"<=":function(a){return{val:a,op:"less_or_equal"}},">":function(a){return{val:a,op:"greater"}},">=":function(a){return{val:a,op:"greater_or_equal"}},BETWEEN:function(a){return{val:a,op:"between"}},"NOT BETWEEN":function(a){return{val:a,op:"not_between"}},IS:function(a){return null!==a&&h.error("SQLParse","Invalid value for IS operator"),{val:null,op:"is_null"}},"IS NOT":function(a){return null!==a&&h.error("SQLParse","Invalid value for IS operator"),{val:null,op:"is_not_null"}}},sqlStatements:{question_mark:function(){var a=[];return{add:function(b,c){return a.push(c),"?"},run:function(){return a}}},numbered:function(a){(!a||a.length>1)&&(a="$");var b=0,c=[];return{add:function(d,e){return c.push(e),b++,a+b},run:function(){return c}}},named:function(a){(!a||a.length>1)&&(a=":");var b={},c={};return{add:function(d,e){b[d.field]||(b[d.field]=1);var f=d.field+"_"+b[d.field]++;return c[f]=e,a+f},run:function(){return c}}}},sqlRuleStatement:{question_mark:function(a){var b=0;return{parse:function(c){return"?"==c?a[b++]:c},esc:function(a){return a.replace(/\?/g,"'?'")}}},numbered:function(a,b){(!b||b.length>1)&&(b="$");var c=new RegExp("^\\"+b+"[0-9]+$"),d=new RegExp("\\"+b+"([0-9]+)","g");return{parse:function(b){return c.test(b)?a[b.slice(1)-1]:b},esc:function(a){return a.replace(d,"'"+("$"==b?"$$":b)+"$1'")}}},named:function(a,b){(!b||b.length>1)&&(b=":");var c=new RegExp("^\\"+b),d=new RegExp("\\"+b+"("+Object.keys(a).join("|")+")","g");return{parse:function(b){return c.test(b)?a[b.slice(1)]:b},esc:function(a){return a.replace(d,"'"+("$"==b?"$$":b)+"$1'")}}}}}),g.extend({getSQL:function(a,b,c){if(c=void 0===c?this.getRules():c,!c)return null;b=b?"\n":" ";var d=this.getPluginOptions("sql-support","boolean_as_integer");if(a===!0&&(a="question_mark"),"string"==typeof a){var e=f(a);a=this.settings.sqlStatements[e[1]](e[2])}var g=this,i=function j(c){if(c.condition||(c.condition=g.settings.default_condition),["AND","OR"].indexOf(c.condition.toUpperCase())===-1&&h.error("UndefinedSQLCondition",'Unable to build SQL query with condition "{0}"',c.condition),!c.rules)return"";var e=[];c.rules.forEach(function(c){if(c.rules&&c.rules.length>0)e.push("("+b+j(c)+b+")"+b);else{var f=g.settings.sqlOperators[c.operator],i=g.getOperatorByType(c.operator),k="";void 0===f&&h.error("UndefinedSQLOperator",'Unknown SQL operation for operator "{0}"',c.operator),0!==i.nb_inputs&&(c.value instanceof Array||(c.value=[c.value]),c.value.forEach(function(b,e){e>0&&(k+=f.sep),"integer"==c.type||"double"==c.type||"boolean"==c.type?b=h.changeType(b,c.type,d):a||(b=h.escapeString(b)),f.mod&&(b=h.fmt(f.mod,b)),a?k+=a.add(c,b):("string"==typeof b&&(b="'"+b+"'"),k+=b)}));var l=function(a){return f.op.replace(/\?/,a)},m=g.change("getSQLField",c.field,c),n=m+" "+l(k);e.push(g.change("ruleToSQL",n,c,k,l))}});var f=e.join(" "+c.condition+b);return g.change("groupToSQL",f,c)}(c);return a?{sql:i,params:a.run()}:{sql:i}},getRulesFromSQL:function(a,b){"SQLParser"in window||h.error("MissingLibrary","SQLParser is required to parse SQL queries. Get it here https://github.com/mistic100/sql-parser");var c=this;if("string"==typeof a&&(a={sql:a}),b===!0&&(b="question_mark"),"string"==typeof b){var d=f(b);b=this.settings.sqlRuleStatement[d[1]](a.params,d[2])}b&&(a.sql=b.esc(a.sql)),0!==a.sql.toUpperCase().indexOf("SELECT")&&(a.sql="SELECT * FROM table WHERE "+a.sql); +var e=SQLParser.parse(a.sql);e.where||h.error("SQLParse","No WHERE clause found");var g=c.change("parseSQLNode",e.where.conditions);if("rules"in g&&"condition"in g)return g;if("id"in g&&"operator"in g&&"value"in g)return{condition:this.settings.default_condition,rules:[g]};var i=c.change("sqlToGroup",{condition:this.settings.default_condition,rules:[]},g),j=i;return function k(a,d){if(a=c.change("parseSQLNode",a),"rules"in a&&"condition"in a)return void j.rules.push(a);if("id"in a&&"operator"in a&&"value"in a)return void j.rules.push(a);if("left"in a&&"right"in a&&"operation"in a||h.error("SQLParse","Unable to parse WHERE clause"),["AND","OR"].indexOf(a.operation.toUpperCase())!==-1){if(d>0&&j.condition!=a.operation.toUpperCase()){var e=c.change("sqlToGroup",{condition:c.settings.default_condition,rules:[]},a);j.rules.push(e),j=e}j.condition=a.operation.toUpperCase(),d++;var f=j;k(a.left,d),j=f,k(a.right,d)}else{$.isPlainObject(a.right.value)&&h.error("SQLParse","Value format not supported for {0}.",a.left.value);var g;g=$.isArray(a.right.value)?a.right.value.map(function(a){return a.value}):a.right.value,b&&(g=$.isArray(g)?g.map(b.parse):b.parse(g));var i=a.operation.toUpperCase();"<>"==i&&(i="!=");var l=c.settings.sqlRuleOperator[i];void 0===l&&h.error("UndefinedSQLOperator",'Invalid SQL operation "{0}".',a.operation);var m,n=l.call(this,g,a.operation);"values"in a.left?m=a.left.values.join("."):"value"in a.left?m=a.left.value:h.error("SQLParse","Cannot find field name in {0}",JSON.stringify(a.left));var o=c.getSQLFieldID(m,g),p=c.change("sqlToRule",{id:o,field:m,operator:n.op,value:n.val},a);j.rules.push(p)}}(g,0),i},setRulesFromSQL:function(a,b){this.setRules(this.getRulesFromSQL(a,b))},getSQLFieldID:function(a,b){var c,d=this.filters.filter(function(b){return b.field.toLowerCase()===a.toLowerCase()});return c=1===d.length?d[0].id:this.change("getSQLFieldID",a,b)}}),g.define("unique-filter",function(){this.status.used_filters={},this.on("afterUpdateRuleFilter",this.updateDisabledFilters),this.on("afterDeleteRule",this.updateDisabledFilters),this.on("afterCreateRuleFilters",this.applyDisabledFilters),this.on("afterReset",this.clearDisabledFilters),this.on("afterClear",this.clearDisabledFilters),this.on("getDefaultFilter.filter",function(a,b){var c=a.builder;if(c.updateDisabledFilters(),a.value.id in c.status.used_filters){var d=c.filters.some(function(d){if(!(d.id in c.status.used_filters)||c.status.used_filters[d.id].length>0&&c.status.used_filters[d.id].indexOf(b.parent)===-1)return a.value=d,!0});d||(h.error(!1,"UniqueFilter","No more non-unique filters available"),a.value=void 0)}})}),g.extend({updateDisabledFilters:function(a){var b=a?a.builder:this;b.status.used_filters={},b.model&&(!function c(a){a.each(function(a){a.filter&&a.filter.unique&&(b.status.used_filters[a.filter.id]||(b.status.used_filters[a.filter.id]=[]),"group"==a.filter.unique&&b.status.used_filters[a.filter.id].push(a.parent))},function(a){c(a)})}(b.model.root),b.applyDisabledFilters(a))},clearDisabledFilters:function(a){var b=a?a.builder:this;b.status.used_filters={},b.applyDisabledFilters(a)},applyDisabledFilters:function(a){var b=a?a.builder:this;b.$el.find(g.selectors.filter_container+" option").prop("disabled",!1),$.each(b.status.used_filters,function(a,c){0===c.length?b.$el.find(g.selectors.filter_container+' option[value="'+a+'"]:not(:selected)').prop("disabled",!0):c.forEach(function(b){b.each(function(b){b.$el.find(g.selectors.filter_container+' option[value="'+a+'"]:not(:selected)').prop("disabled",!0)})})}),b.settings.plugins&&b.settings.plugins["bt-selectpicker"]&&b.$el.find(g.selectors.rule_filter).selectpicker("render")}}),g.regional.en={__locale:"English (en)",__author:'Damien "Mistic" Sorel, http://www.strangeplanet.fr',add_rule:"Add rule",add_group:"Add group",delete_rule:"Delete",delete_group:"Delete",conditions:{AND:"AND",OR:"OR"},operators:{equal:"equal",not_equal:"not equal","in":"in",not_in:"not in",less:"less",less_or_equal:"less or equal",greater:"greater",greater_or_equal:"greater or equal",between:"between",not_between:"not between",begins_with:"begins with",not_begins_with:"doesn't begin with",contains:"contains",not_contains:"doesn't contain",ends_with:"ends with",not_ends_with:"doesn't end with",is_empty:"is empty",is_not_empty:"is not empty",is_null:"is null",is_not_null:"is not null"},errors:{no_filter:"No filter selected",empty_group:"The group is empty",radio_empty:"No value selected",checkbox_empty:"No value selected",select_empty:"No value selected",string_empty:"Empty value",string_exceed_min_length:"Must contain at least {0} characters",string_exceed_max_length:"Must not contain more than {0} characters",string_invalid_format:"Invalid format ({0})",number_nan:"Not a number",number_not_integer:"Not an integer",number_not_double:"Not a real number",number_exceed_min:"Must be greater than {0}",number_exceed_max:"Must be lower than {0}",number_wrong_step:"Must be a multiple of {0}",number_between_invalid:"Invalid values, {0} is greater than {1}",datetime_empty:"Empty value",datetime_invalid:"Invalid date format ({0})",datetime_exceed_min:"Must be after {0}",datetime_exceed_max:"Must be before {0}",datetime_between_invalid:"Invalid values, {0} isgreater than {1}",boolean_not_valid:"Not a boolean",operator_not_multiple:'Operator "{1}" cannot accept multiple values'},invert:"Invert",NOT:"NOT"},g.defaults({lang_code:"en"}),g}); \ No newline at end of file diff --git a/dist/js/query-builder.standalone.js b/dist/js/query-builder.standalone.js index a411d8aa..cae1f10a 100644 --- a/dist/js/query-builder.standalone.js +++ b/dist/js/query-builder.standalone.js @@ -273,7 +273,7 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -306,7 +306,6 @@ * @param {jQuery} $el * @param {object} options - see {@link http://querybuilder.js.org/#options} * @constructor - * @fires QueryBuilder.afterInit */ var QueryBuilder = function($el, options) { $el[0].queryBuilder = this; @@ -433,21 +432,6 @@ var QueryBuilder = function($el, options) { this.operators = this.checkOperators(this.operators); this.bindEvents(); this.initPlugins(); - - /** - * When the initilization is done, just before creating the root group - * @event afterInit - * @memberof QueryBuilder - */ - this.trigger('afterInit'); - - if (options.rules) { - this.setRules(options.rules); - delete this.settings.rules; - } - else { - this.setRoot(true); - } }; $.extend(QueryBuilder.prototype, /** @lends QueryBuilder.prototype */ { @@ -844,6 +828,29 @@ QueryBuilder.prototype.getPluginOptions = function(name, property) { }; +/** + * Final initialisation of the builder + * @param {object} [rules] + * @fires QueryBuilder.afterInit + * @private + */ +QueryBuilder.prototype.init = function(rules) { + /** + * When the initilization is done, just before creating the root group + * @event afterInit + * @memberof QueryBuilder + */ + this.trigger('afterInit'); + + if (rules) { + this.setRules(rules); + delete this.settings.rules; + } + else { + this.setRoot(true); + } +}; + /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters @@ -1105,7 +1112,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'value': - self.updateRuleValue(node); + self.updateRuleValue(node, oldValue); break; } } @@ -1120,7 +1127,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'condition': - self.updateGroupCondition(node); + self.updateGroupCondition(node, oldValue); break; } } @@ -1203,6 +1210,13 @@ QueryBuilder.prototype.addGroup = function(parent, addRule, data, flags) { */ this.trigger('afterAddGroup', model); + /** + * After any change in the rules + * @event rulesChanged + * @memberof QueryBuilder + */ + this.trigger('rulesChanged'); + model.condition = this.settings.default_condition; if (addRule) { @@ -1252,6 +1266,8 @@ QueryBuilder.prototype.deleteGroup = function(group) { * @memberof QueryBuilder */ this.trigger('afterDeleteGroup'); + + this.trigger('rulesChanged'); } return del; @@ -1260,10 +1276,11 @@ QueryBuilder.prototype.deleteGroup = function(group) { /** * Performs actions when a group's condition changes * @param {Group} group + * @param {object} previousCondition * @fires QueryBuilder.afterUpdateGroupCondition * @private */ -QueryBuilder.prototype.updateGroupCondition = function(group) { +QueryBuilder.prototype.updateGroupCondition = function(group, previousCondition) { group.$el.find('>' + QueryBuilder.selectors.group_condition).each(function() { var $this = $(this); $this.prop('checked', $this.val() === group.condition); @@ -1275,8 +1292,11 @@ QueryBuilder.prototype.updateGroupCondition = function(group) { * @event afterUpdateGroupCondition * @memberof QueryBuilder * @param {Group} group + * @param {object} previousCondition */ - this.trigger('afterUpdateGroupCondition', group); + this.trigger('afterUpdateGroupCondition', group, previousCondition); + + this.trigger('rulesChanged'); }; /** @@ -1336,6 +1356,8 @@ QueryBuilder.prototype.addRule = function(parent, data, flags) { */ this.trigger('afterAddRule', model); + this.trigger('rulesChanged'); + this.createRuleFilters(model); if (this.settings.default_filter || !this.settings.display_empty_filter) { @@ -1388,6 +1410,8 @@ QueryBuilder.prototype.deleteRule = function(rule) { */ this.trigger('afterDeleteRule'); + this.trigger('rulesChanged'); + return true; }; @@ -1440,7 +1464,14 @@ QueryBuilder.prototype.createRuleOperators = function(rule) { $operatorContainer.html($operatorSelect); // set the operator without triggering update event - rule.__.operator = operators[0]; + if (rule.filter.default_operator) { + rule.__.operator = this.getOperatorByType(rule.filter.default_operator); + } + else { + rule.__.operator = operators[0]; + } + + rule.$el.find(QueryBuilder.selectors.rule_operator).val(rule.operator.type); /** * After creating the dropdown for operators @@ -1533,8 +1564,11 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { * @event afterUpdateRuleFilter * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousFilter */ - this.trigger('afterUpdateRuleFilter', rule); + this.trigger('afterUpdateRuleFilter', rule, previousFilter); + + this.trigger('rulesChanged'); }; /** @@ -1546,6 +1580,7 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { */ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { var $valueContainer = rule.$el.find(QueryBuilder.selectors.value_container); + var ruleValue = rule.value; if (!rule.operator || rule.operator.nb_inputs === 0) { $valueContainer.hide(); @@ -1572,19 +1607,24 @@ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { * @event afterUpdateRuleOperator * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousOperator */ - this.trigger('afterUpdateRuleOperator', rule); + this.trigger('afterUpdateRuleOperator', rule, previousOperator); + + this.trigger('rulesChanged'); - this.updateRuleValue(rule); + // FIXME is it necessary ? + this.updateRuleValue(rule, ruleValue); }; /** * Performs actions when rule's value changes * @param {Rule} rule + * @param {object} previousValue * @fires QueryBuilder.afterUpdateRuleValue * @private */ -QueryBuilder.prototype.updateRuleValue = function(rule) { +QueryBuilder.prototype.updateRuleValue = function(rule, previousValue) { if (!rule._updating_value) { this.setRuleInputValue(rule, rule.value); } @@ -1594,8 +1634,11 @@ QueryBuilder.prototype.updateRuleValue = function(rule) { * @event afterUpdateRuleValue * @memberof QueryBuilder * @param {Rule} rule + * @param {*} previousValue */ - this.trigger('afterUpdateRuleValue', rule); + this.trigger('afterUpdateRuleValue', rule, previousValue); + + this.trigger('rulesChanged'); }; /** @@ -1802,6 +1845,8 @@ QueryBuilder.prototype.reset = function() { * @memberof QueryBuilder */ this.trigger('afterReset'); + + this.trigger('rulesChanged'); }; /** @@ -1834,6 +1879,8 @@ QueryBuilder.prototype.clear = function() { * @memberof QueryBuilder */ this.trigger('afterClear'); + + this.trigger('rulesChanged'); }; /** @@ -2158,17 +2205,22 @@ QueryBuilder.prototype.setRules = function(data, options) { if (!item.empty) { model.filter = self.getFilterById(item.id, !options.allow_invalid); + } - if (model.filter) { - model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); + if (model.filter) { + model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); - if (!model.operator) { - model.operator = self.getOperators(model.filter)[0]; - } + if (!model.operator) { + model.operator = self.getOperators(model.filter)[0]; + } + } - if (model.operator && model.operator.nb_inputs !== 0 && item.value !== undefined) { - model.value = item.value; - } + if (model.operator && model.operator.nb_inputs !== 0) { + if (item.value !== undefined) { + model.value = item.value; + } + else if (model.filter.default_value !== undefined) { + model.value = model.filter.default_value; } } @@ -2434,6 +2486,29 @@ QueryBuilder.prototype._validateValue = function(rule, value) { } } + if ((rule.operator.type === 'between' || rule.operator.type === 'not_between') && value.length === 2) { + switch (QueryBuilder.types[filter.type]) { + case 'number': + if (value[0] > value[1]) { + result = ['number_between_invalid', value[0], value[1]]; + } + break; + + case 'datetime': + // we need MomentJS + if (validation.format) { + if (!('moment' in window)) { + Utils.error('MissingLibrary', 'MomentJS is required for Date/Time validation. Get it here http://momentjs.com'); + } + + if (moment(value[0], validation.format).isAfter(moment(value[1], validation.format))) { + result = ['datetime_between_invalid', value[0], value[1]]; + } + } + break; + } + } + return result; }; @@ -3015,7 +3090,7 @@ QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) { /** * Modifies the raw HTML of the rule's filter dropdown - * @event changer:getRuleFilterTemplate + * @event changer:getRuleFilterSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule @@ -3045,7 +3120,7 @@ QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) { /** * Modifies the raw HTML of the rule's operator dropdown - * @event changer:getRuleOperatorTemplate + * @event changer:getRuleOperatorSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule @@ -3963,7 +4038,9 @@ $.fn.queryBuilder = function(option) { return this; } if (!data) { - this.data('queryBuilder', new QueryBuilder(this, options)); + var builder = new QueryBuilder(this, options); + this.data('queryBuilder', builder); + builder.init(options.rules); } if (typeof option == 'string') { return data[option].apply(data, Array.prototype.slice.call(arguments, 1)); @@ -4200,6 +4277,8 @@ QueryBuilder.extend(/** @lends module:plugins.ChangeFilters.prototype */ { function(rule) { if (rule.filter && filtersIds.indexOf(rule.filter.id) === -1) { rule.drop(); + + self.trigger('rulesChanged'); } else { self.createRuleFilters(rule); @@ -4408,6 +4487,9 @@ QueryBuilder.define('filter-description', function(options) { bootbox.alert($b.data('description')); }); } + else { + $b.show(); + } $b.data('description', description); } @@ -4589,6 +4671,8 @@ QueryBuilder.extend(/** @lends module:plugins.Invert.prototype */ { * @param {object} options */ this.trigger('afterInvert', node, options); + + this.trigger('rulesChanged'); } } }); @@ -4701,6 +4785,10 @@ QueryBuilder.extend(/** @lends module:plugins.MongoDbSupport.prototype */ { getMongo: function(data) { data = (data === undefined) ? this.getRules() : data; + if (!data) { + return null; + } + var self = this; return (function parse(group) { @@ -5128,6 +5216,8 @@ QueryBuilder.extend(/** @lends module:plugins.NotGroup.prototype */ { * @param {Group} group */ this.trigger('afterUpdateGroupNot', group); + + this.trigger('rulesChanged'); } }); @@ -5226,6 +5316,8 @@ QueryBuilder.define('sortable', function(options) { * @param {Node} node */ self.trigger('afterMove', src); + + self.trigger('rulesChanged'); } }); } @@ -5607,6 +5699,11 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; + + if (!data) { + return null; + } + nl = !!nl ? '\n' : ' '; var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); @@ -5955,7 +6052,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQLFieldID: function(field, value) { var matchingFilters = this.filters.filter(function(filter) { - return filter.field === field; + return filter.field.toLowerCase() === field.toLowerCase(); }); var id; @@ -6109,7 +6206,7 @@ QueryBuilder.extend(/** @lends module:plugins.UniqueFilter.prototype */ { /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -6164,10 +6261,12 @@ QueryBuilder.regional['en'] = { "number_exceed_min": "Must be greater than {0}", "number_exceed_max": "Must be lower than {0}", "number_wrong_step": "Must be a multiple of {0}", + "number_between_invalid": "Invalid values, {0} is greater than {1}", "datetime_empty": "Empty value", "datetime_invalid": "Invalid date format ({0})", "datetime_exceed_min": "Must be after {0}", "datetime_exceed_max": "Must be before {0}", + "datetime_between_invalid": "Invalid values, {0} isgreater than {1}", "boolean_not_valid": "Not a boolean", "operator_not_multiple": "Operator \"{1}\" cannot accept multiple values" }, diff --git a/dist/js/query-builder.standalone.min.js b/dist/js/query-builder.standalone.min.js index 1ba11267..b78c4632 100644 --- a/dist/js/query-builder.standalone.min.js +++ b/dist/js/query-builder.standalone.min.js @@ -1,8 +1,8 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -!function(a,b){"function"==typeof define&&define.amd?define("jQuery.extendext",["jquery"],b):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function($){"use strict";$.extendext=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1,k="default";for("boolean"==typeof g&&(j=g,g=arguments[h++]||{}),"string"==typeof g&&(k=g.toLowerCase(),"concat"!==k&&"replace"!==k&&"extend"!==k&&(k="default"),g=arguments[h++]||{}),"object"==typeof g||$.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!==(a=arguments[h]))if($.isArray(a)&&"default"!==k)switch(f=g&&$.isArray(g)?g:[],k){case"concat":g=f.concat($.extend(j,[],a));break;case"replace":g=$.extend(j,[],a);break;case"extend":a.forEach(function(a,b){if("object"==typeof a){var c=$.isArray(a)?[]:{};f[b]=$.extendext(j,k,f[b]||c,a)}else-1===f.indexOf(a)&&f.push(a)}),g=f}else for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&($.isPlainObject(d)||(e=$.isArray(d)))?(e?(e=!1,f=c&&$.isArray(c)?c:[]):f=c&&$.isPlainObject(c)?c:{},g[b]=$.extendext(j,k,f,d)):void 0!==d&&(g[b]=d));return g}}),function(){"use strict";function a(b,c,d){return("string"==typeof c?c:c.toString()).replace(b.define||f,function(a,c,e,f){return 0===c.indexOf("def.")&&(c=c.substring(4)),c in d||(":"===e?(b.defineParams&&f.replace(b.defineParams,function(a,b,e){d[c]={arg:b,text:e}}),c in d||(d[c]=f)):new Function("def","def['"+c+"']="+f)(d)),""}).replace(b.use||f,function(c,e){b.useParams&&(e=e.replace(b.useParams,function(a,b,c,e){if(d[c]&&d[c].arg&&e){var f=(c+":"+e).replace(/'|\\/g,"_");return d.__exp=d.__exp||{},d.__exp[f]=d[c].text.replace(new RegExp("(^|[^\\w$])"+d[c].arg+"([^\\w$])","g"),"$1"+e+"$2"),b+"def.__exp['"+f+"']"}}));var f=new Function("def","return "+e)(d);return f?a(b,f,d):f})}function b(a){return a.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var c,d={version:"1.0.3",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0,log:!0};d.encodeHTMLSource=function(a){var b={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},c=a?/[&<>"'\/]/g:/&(?!#?\w+;)|<|>|"|'|\//g;return function(a){return a?a.toString().replace(c,function(a){return b[a]||a}):""}},c=function(){return this||(0,eval)("this")}(),"undefined"!=typeof module&&module.exports?module.exports=d:"function"==typeof define&&define.amd?define("doT",function(){return d}):c.doT=d;var e={append:{start:"'+(",end:")+'",startencode:"'+encodeHTML("},split:{start:"';out+=(",end:");out+='",startencode:"';out+=encodeHTML("}},f=/$^/;d.template=function(g,h,i){h=h||d.templateSettings;var j,k,l=h.append?e.append:e.split,m=0,n=h.use||h.define?a(h,g,i||{}):g;n=("var out='"+(h.strip?n.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):n).replace(/'|\\/g,"\\$&").replace(h.interpolate||f,function(a,c){return l.start+b(c)+l.end}).replace(h.encode||f,function(a,c){return j=!0,l.startencode+b(c)+l.end}).replace(h.conditional||f,function(a,c,d){return c?d?"';}else if("+b(d)+"){out+='":"';}else{out+='":d?"';if("+b(d)+"){out+='":"';}out+='"}).replace(h.iterate||f,function(a,c,d,e){return c?(m+=1,k=e||"i"+m,c=b(c),"';var arr"+m+"="+c+";if(arr"+m+"){var "+d+","+k+"=-1,l"+m+"=arr"+m+".length-1;while("+k+"c;c++)if("$or"==b[c].toLowerCase()||"$and"==b[c].toLowerCase())return b[c]}function e(a,b,c){var d,e,f=g.selectors;d=b.closest(f.rule_container),d.length&&(e="moveAfter"),e||(d=b.closest(f.group_header),d.length&&(d=b.closest(f.group_container),e="moveAtBegin")),e||(d=b.closest(f.group_container),d.length&&(e="moveAtEnd")),e&&(a[e](c.getModel(d)),c&&a instanceof k&&c.setRuleInputValue(a,a.value))}function f(a){var b=a.match(/(question_mark|numbered|named)(?:\((.)\))?/);return b||(b=[null,"question_mark",void 0]),b}var g=function(c,d){c[0].queryBuilder=this,this.$el=c,this.settings=$.extendext(!0,"replace",{},g.DEFAULTS,d),this.model=new b,this.status={id:null,generated_id:!1,group_id:0,rule_id:0,has_optgroup:!1,has_operator_optgroup:!1},this.filters=this.settings.filters,this.icons=this.settings.icons,this.operators=this.settings.operators,this.templates=this.settings.templates,this.plugins=this.settings.plugins,this.lang=null,void 0===g.regional.en&&h.error("Config",'"i18n/en.js" not loaded.'),this.lang=$.extendext(!0,"replace",{},g.regional.en,g.regional[this.settings.lang_code],this.settings.lang),this.settings.allow_groups===!1?this.settings.allow_groups=0:this.settings.allow_groups===!0&&(this.settings.allow_groups=-1),Object.keys(this.templates).forEach(function(b){this.templates[b]||(this.templates[b]=g.templates[b]),"string"==typeof this.templates[b]&&(this.templates[b]=a.template(this.templates[b]))},this),this.$el.attr("id")||(this.$el.attr("id","qb_"+Math.floor(99999*Math.random())),this.status.generated_id=!0),this.status.id=this.$el.attr("id"),this.$el.addClass("query-builder form-inline"),this.filters=this.checkFilters(this.filters),this.operators=this.checkOperators(this.operators),this.bindEvents(),this.initPlugins(),this.trigger("afterInit"),d.rules?(this.setRules(d.rules),delete this.settings.rules):this.setRoot(!0)};$.extend(g.prototype,{trigger:function(a){var b=new $.Event(this._tojQueryEvent(a),{builder:this});return this.$el.triggerHandler(b,Array.prototype.slice.call(arguments,1)),b},change:function(a,b){var c=new $.Event(this._tojQueryEvent(a,!0),{builder:this,value:b});return this.$el.triggerHandler(c,Array.prototype.slice.call(arguments,2)),c.value},on:function(a,b){return this.$el.on(this._tojQueryEvent(a),b),this},off:function(a,b){return this.$el.off(this._tojQueryEvent(a),b),this},once:function(a,b){return this.$el.one(this._tojQueryEvent(a),b),this},_tojQueryEvent:function(a,b){return a.split(" ").map(function(a){return a+".queryBuilder"+(b?".filter":"")}).join(" ")}}),g.types={string:"string",integer:"number","double":"number",date:"datetime",time:"datetime",datetime:"datetime","boolean":"boolean"},g.inputs=["text","number","textarea","radio","checkbox","select"],g.modifiable_options=["display_errors","allow_groups","allow_empty","default_condition","default_filter"],g.selectors={group_container:".rules-group-container",rule_container:".rule-container",filter_container:".rule-filter-container",operator_container:".rule-operator-container",value_container:".rule-value-container",error_container:".error-container",condition_container:".rules-group-header .group-conditions",rule_header:".rule-header",group_header:".rules-group-header",group_actions:".group-actions",rule_actions:".rule-actions",rules_list:".rules-group-body>.rules-list",group_condition:".rules-group-header [name$=_cond]",rule_filter:".rule-filter-container [name$=_filter]",rule_operator:".rule-operator-container [name$=_operator]",rule_value:".rule-value-container [name*=_value_]",add_rule:"[data-add=rule]",delete_rule:"[data-delete=rule]",add_group:"[data-add=group]",delete_group:"[data-delete=group]"},g.templates={},g.regional={},g.OPERATORS={equal:{type:"equal",nb_inputs:1,multiple:!1,apply_to:["string","number","datetime","boolean"]},not_equal:{type:"not_equal",nb_inputs:1,multiple:!1,apply_to:["string","number","datetime","boolean"]},"in":{type:"in",nb_inputs:1,multiple:!0,apply_to:["string","number","datetime"]},not_in:{type:"not_in",nb_inputs:1,multiple:!0,apply_to:["string","number","datetime"]},less:{type:"less",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},less_or_equal:{type:"less_or_equal",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},greater:{type:"greater",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},greater_or_equal:{type:"greater_or_equal",nb_inputs:1,multiple:!1,apply_to:["number","datetime"]},between:{type:"between",nb_inputs:2,multiple:!1,apply_to:["number","datetime"]},not_between:{type:"not_between",nb_inputs:2,multiple:!1,apply_to:["number","datetime"]},begins_with:{type:"begins_with",nb_inputs:1,multiple:!1,apply_to:["string"]},not_begins_with:{type:"not_begins_with",nb_inputs:1,multiple:!1,apply_to:["string"]},contains:{type:"contains",nb_inputs:1,multiple:!1,apply_to:["string"]},not_contains:{type:"not_contains",nb_inputs:1,multiple:!1,apply_to:["string"]},ends_with:{type:"ends_with",nb_inputs:1,multiple:!1,apply_to:["string"]},not_ends_with:{type:"not_ends_with",nb_inputs:1,multiple:!1,apply_to:["string"]},is_empty:{type:"is_empty",nb_inputs:0,multiple:!1,apply_to:["string"]},is_not_empty:{type:"is_not_empty",nb_inputs:0,multiple:!1,apply_to:["string"]},is_null:{type:"is_null",nb_inputs:0,multiple:!1,apply_to:["string","number","datetime","boolean"]},is_not_null:{type:"is_not_null",nb_inputs:0,multiple:!1,apply_to:["string","number","datetime","boolean"]}},g.DEFAULTS={filters:[],plugins:[],sort_filters:!1,display_errors:!0,allow_groups:-1,allow_empty:!1,conditions:["AND","OR"],default_condition:"AND",inputs_separator:" , ",select_placeholder:"------",display_empty_filter:!0,default_filter:null,optgroups:{},default_rule_flags:{filter_readonly:!1,operator_readonly:!1,value_readonly:!1,no_delete:!1},default_group_flags:{condition_readonly:!1,no_add_rule:!1,no_add_group:!1,no_delete:!1},templates:{group:null,rule:null,filterSelect:null,operatorSelect:null},lang_code:"en",lang:{},operators:["equal","not_equal","in","not_in","less","less_or_equal","greater","greater_or_equal","between","not_between","begins_with","not_begins_with","contains","not_contains","ends_with","not_ends_with","is_empty","is_not_empty","is_null","is_not_null"],icons:{add_group:"glyphicon glyphicon-plus-sign",add_rule:"glyphicon glyphicon-plus",remove_group:"glyphicon glyphicon-remove",remove_rule:"glyphicon glyphicon-remove",error:"glyphicon glyphicon-warning-sign"}},g.plugins={},g.defaults=function(a){return"object"!=typeof a?"string"==typeof a?"object"==typeof g.DEFAULTS[a]?$.extend(!0,{},g.DEFAULTS[a]):g.DEFAULTS[a]:$.extend(!0,{},g.DEFAULTS):void $.extendext(!0,"replace",g.DEFAULTS,a)},g.define=function(a,b,c){g.plugins[a]={fct:b,def:c||{}}},g.extend=function(a){$.extend(g.prototype,a)},g.prototype.initPlugins=function(){if(this.plugins){if($.isArray(this.plugins)){var a={};this.plugins.forEach(function(b){a[b]=null}),this.plugins=a}Object.keys(this.plugins).forEach(function(a){a in g.plugins?(this.plugins[a]=$.extend(!0,{},g.plugins[a].def,this.plugins[a]||{}),g.plugins[a].fct.call(this,this.plugins[a])):h.error("Config",'Unable to find plugin "{0}"',a)},this)}},g.prototype.getPluginOptions=function(a,b){var c;return this.plugins&&this.plugins[a]?c=this.plugins[a]:g.plugins[a]&&(c=g.plugins[a].def),c?b?c[b]:c:void h.error("Config",'Unable to find plugin "{0}"',a)},g.prototype.checkFilters=function(a){var b=[];if(a&&0!==a.length||h.error("Config","Missing filters list"),a.forEach(function(a,c){switch(a.id||h.error("Config","Missing filter {0} id",c),-1!=b.indexOf(a.id)&&h.error("Config",'Filter "{0}" already defined',a.id),b.push(a.id),a.type?g.types[a.type]||h.error("Config",'Invalid type "{0}"',a.type):a.type="string",a.input?"function"!=typeof a.input&&-1==g.inputs.indexOf(a.input)&&h.error("Config",'Invalid input "{0}"',a.input):a.input="number"===g.types[a.type]?"number":"text",a.operators&&a.operators.forEach(function(a){"string"!=typeof a&&h.error("Config","Filter operators must be global operators types (string)")}),a.field||(a.field=a.id),a.label||(a.label=a.field),a.optgroup?(this.status.has_optgroup=!0,this.settings.optgroups[a.optgroup]||(this.settings.optgroups[a.optgroup]=a.optgroup)):a.optgroup=null,a.input){case"radio":case"checkbox":(!a.values||a.values.length<1)&&h.error("Config",'Missing filter "{0}" values',a.id);break;case"select":a.placeholder&&(void 0===a.placeholder_value&&(a.placeholder_value=-1),h.iterateOptions(a.values,function(b){b==a.placeholder_value&&h.error("Config",'Placeholder of filter "{0}" overlaps with one of its values',a.id)}))}},this),this.settings.sort_filters)if("function"==typeof this.settings.sort_filters)a.sort(this.settings.sort_filters);else{var c=this;a.sort(function(a,b){return c.translate(a.label).localeCompare(c.translate(b.label))})}return this.status.has_optgroup&&(a=h.groupSort(a,"optgroup")),a},g.prototype.checkOperators=function(a){var b=[];return a.forEach(function(c,d){"string"==typeof c?(g.OPERATORS[c]||h.error("Config",'Unknown operator "{0}"',c),a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c])):(c.type||h.error("Config",'Missing "type" for operator {0}',d),g.OPERATORS[c.type]&&(a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c.type],c)),void 0!==c.nb_inputs&&void 0!==c.apply_to||h.error("Config",'Missing "nb_inputs" and/or "apply_to" for operator "{0}"',c.type)),-1!=b.indexOf(c.type)&&h.error("Config",'Operator "{0}" already defined',c.type),b.push(c.type),c.optgroup?(this.status.has_operator_optgroup=!0,this.settings.optgroups[c.optgroup]||(this.settings.optgroups[c.optgroup]=c.optgroup)):c.optgroup=null},this),this.status.has_operator_optgroup&&(a=h.groupSort(a,"optgroup")),a},g.prototype.bindEvents=function(){var a=this,b=g.selectors;this.$el.on("change.queryBuilder",b.group_condition,function(){if($(this).is(":checked")){var c=$(this).closest(b.group_container);a.getModel(c).condition=$(this).val()}}),this.$el.on("change.queryBuilder",b.rule_filter,function(){var c=$(this).closest(b.rule_container);a.getModel(c).filter=a.getFilterById($(this).val())}),this.$el.on("change.queryBuilder",b.rule_operator,function(){var c=$(this).closest(b.rule_container);a.getModel(c).operator=a.getOperatorByType($(this).val())}),this.$el.on("click.queryBuilder",b.add_rule,function(){var c=$(this).closest(b.group_container);a.addRule(a.getModel(c))}),this.$el.on("click.queryBuilder",b.delete_rule,function(){var c=$(this).closest(b.rule_container);a.deleteRule(a.getModel(c))}),0!==this.settings.allow_groups&&(this.$el.on("click.queryBuilder",b.add_group,function(){var c=$(this).closest(b.group_container);a.addGroup(a.getModel(c))}),this.$el.on("click.queryBuilder",b.delete_group,function(){var c=$(this).closest(b.group_container);a.deleteGroup(a.getModel(c))})),this.model.on({drop:function(b,c){c.$el.remove(),a.refreshGroupsConditions()},add:function(b,c,d,e){0===e?d.$el.prependTo(c.$el.find(">"+g.selectors.rules_list)):d.$el.insertAfter(c.rules[e-1].$el),a.refreshGroupsConditions()},move:function(b,c,d,e){c.$el.detach(),0===e?c.$el.prependTo(d.$el.find(">"+g.selectors.rules_list)):c.$el.insertAfter(d.rules[e-1].$el),a.refreshGroupsConditions()},update:function(b,c,d,e,f){if(c instanceof k)switch(d){case"error":a.updateError(c);break;case"flags":a.applyRuleFlags(c);break;case"filter":a.updateRuleFilter(c,f);break;case"operator":a.updateRuleOperator(c,f);break;case"value":a.updateRuleValue(c)}else switch(d){case"error":a.updateError(c);break;case"flags":a.applyGroupFlags(c);break;case"condition":a.updateGroupCondition(c)}}})},g.prototype.setRoot=function(a,b,c){a=void 0===a||a===!0;var d=this.nextGroupId(),e=$(this.getGroupTemplate(d,1));return this.$el.append(e),this.model.root=new j(null,e),this.model.root.model=this.model,this.model.root.data=b,this.model.root.__.flags=$.extend({},this.settings.default_group_flags,c),this.trigger("afterAddGroup",this.model.root),this.model.root.condition=this.settings.default_condition,a&&this.addRule(this.model.root),this.model.root},g.prototype.addGroup=function(a,b,c,d){b=void 0===b||b===!0;var e=a.level+1,f=this.trigger("beforeAddGroup",a,b,e);if(f.isDefaultPrevented())return null;var g=this.nextGroupId(),h=$(this.getGroupTemplate(g,e)),i=a.addGroup(h);return i.data=c,i.__.flags=$.extend({},this.settings.default_group_flags,d),this.trigger("afterAddGroup",i),i.condition=this.settings.default_condition,b&&this.addRule(i),i},g.prototype.deleteGroup=function(a){if(a.isRoot())return!1;var b=this.trigger("beforeDeleteGroup",a);if(b.isDefaultPrevented())return!1;var c=!0;return a.each("reverse",function(a){c&=this.deleteRule(a)},function(a){c&=this.deleteGroup(a)},this),c&&(a.drop(),this.trigger("afterDeleteGroup")),c},g.prototype.updateGroupCondition=function(a){a.$el.find(">"+g.selectors.group_condition).each(function(){var b=$(this);b.prop("checked",b.val()===a.condition),b.parent().toggleClass("active",b.val()===a.condition)}),this.trigger("afterUpdateGroupCondition",a)},g.prototype.refreshGroupsConditions=function(){!function a(b){(!b.flags||b.flags&&!b.flags.condition_readonly)&&b.$el.find(">"+g.selectors.group_condition).prop("disabled",b.rules.length<=1).parent().toggleClass("disabled",b.rules.length<=1),b.each(null,function(b){a(b)},this)}(this.model.root)},g.prototype.addRule=function(a,b,c){var d=this.trigger("beforeAddRule",a);if(d.isDefaultPrevented())return null;var e=this.nextRuleId(),f=$(this.getRuleTemplate(e)),g=a.addRule(f);return void 0!==b&&(g.data=b),g.__.flags=$.extend({},this.settings.default_rule_flags,c),this.trigger("afterAddRule",g),this.createRuleFilters(g),!this.settings.default_filter&&this.settings.display_empty_filter||(g.filter=this.change("getDefaultFilter",this.getFilterById(this.settings.default_filter||this.filters[0].id),g)),g},g.prototype.deleteRule=function(a){if(a.flags.no_delete)return!1;var b=this.trigger("beforeDeleteRule",a);return b.isDefaultPrevented()?!1:(a.drop(),this.trigger("afterDeleteRule"),!0)},g.prototype.createRuleFilters=function(a){var b=this.change("getRuleFilters",this.filters,a),c=$(this.getRuleFilterSelect(a,b));a.$el.find(g.selectors.filter_container).html(c),this.trigger("afterCreateRuleFilters",a)},g.prototype.createRuleOperators=function(a){var b=a.$el.find(g.selectors.operator_container).empty();if(a.filter){var c=this.getOperators(a.filter),d=$(this.getRuleOperatorSelect(a,c));b.html(d),a.__.operator=c[0],this.trigger("afterCreateRuleOperators",a,c)}},g.prototype.createRuleInput=function(a){var b=a.$el.find(g.selectors.value_container).empty();if(a.__.value=void 0,a.filter&&a.operator&&0!==a.operator.nb_inputs){for(var c=this,d=$(),e=a.filter,f=0;f0&&b.append(this.settings.inputs_separator),b.append(h),d=d.add(h)}b.show(),d.on("change "+(e.input_event||""),function(){this._updating_input||(a._updating_value=!0,a.value=c.getRuleInputValue(a),a._updating_value=!1)}),e.plugin&&d[e.plugin](e.plugin_config||{}),this.trigger("afterCreateRuleInput",a),void 0!==e.default_value?a.value=e.default_value:(a._updating_value=!0,a.value=c.getRuleInputValue(a),a._updating_value=!1)}},g.prototype.updateRuleFilter=function(a,b){this.createRuleOperators(a),this.createRuleInput(a),a.$el.find(g.selectors.rule_filter).val(a.filter?a.filter.id:"-1"),b&&a.filter&&b.id!==a.filter.id&&(a.data=void 0),this.trigger("afterUpdateRuleFilter",a)},g.prototype.updateRuleOperator=function(a,b){var c=a.$el.find(g.selectors.value_container);a.operator&&0!==a.operator.nb_inputs?(c.show(),!c.is(":empty")&&b&&a.operator.nb_inputs===b.nb_inputs&&a.operator.optgroup===b.optgroup||this.createRuleInput(a)):(c.hide(),a.__.value=void 0),a.operator&&a.$el.find(g.selectors.rule_operator).val(a.operator.type),this.trigger("afterUpdateRuleOperator",a),this.updateRuleValue(a)},g.prototype.updateRuleValue=function(a){a._updating_value||this.setRuleInputValue(a,a.value),this.trigger("afterUpdateRuleValue",a)},g.prototype.applyRuleFlags=function(a){var b=a.flags,c=g.selectors;b.filter_readonly&&a.$el.find(c.rule_filter).prop("disabled",!0),b.operator_readonly&&a.$el.find(c.rule_operator).prop("disabled",!0),b.value_readonly&&a.$el.find(c.rule_value).prop("disabled",!0),b.no_delete&&a.$el.find(c.delete_rule).remove(),this.trigger("afterApplyRuleFlags",a)},g.prototype.applyGroupFlags=function(a){var b=a.flags,c=g.selectors;b.condition_readonly&&a.$el.find(">"+c.group_condition).prop("disabled",!0).parent().addClass("readonly"),b.no_add_rule&&a.$el.find(c.add_rule).remove(),b.no_add_group&&a.$el.find(c.add_group).remove(),b.no_delete&&a.$el.find(c.delete_group).remove(),this.trigger("afterApplyGroupFlags",a)},g.prototype.clearErrors=function(a){a=a||this.model.root,a&&(a.error=null,a instanceof j&&a.each(function(a){a.error=null},function(a){this.clearErrors(a)},this))},g.prototype.updateError=function(a){if(this.settings.display_errors)if(null===a.error)a.$el.removeClass("has-error");else{var b=this.translate("errors",a.error[0]);b=h.fmt(b,a.error.slice(1)),b=this.change("displayError",b,a.error,a),a.$el.addClass("has-error").find(g.selectors.error_container).eq(0).attr("title",b)}},g.prototype.triggerValidationError=function(a,b,c){$.isArray(b)||(b=[b]);var d=this.trigger("validationError",a,b,c);d.isDefaultPrevented()||(a.error=b)},g.prototype.destroy=function(){this.trigger("beforeDestroy"),this.status.generated_id&&this.$el.removeAttr("id"),this.clear(),this.model=null,this.$el.off(".queryBuilder").removeClass("query-builder").removeData("queryBuilder"),delete this.$el[0].queryBuilder},g.prototype.reset=function(){var a=this.trigger("beforeReset");a.isDefaultPrevented()||(this.status.group_id=1,this.status.rule_id=0,this.model.root.empty(),this.addRule(this.model.root),this.trigger("afterReset"))},g.prototype.clear=function(){var a=this.trigger("beforeClear");a.isDefaultPrevented()||(this.status.group_id=0,this.status.rule_id=0,this.model.root&&(this.model.root.drop(),this.model.root=null),this.trigger("afterClear"))},g.prototype.setOptions=function(a){$.each(a,function(a,b){-1!==g.modifiable_options.indexOf(a)&&(this.settings[a]=b)}.bind(this))},g.prototype.getModel=function(a){return a?a instanceof i?a:$(a).data("queryBuilderModel"):this.model.root},g.prototype.validate=function(a){a=$.extend({skip_empty:!1},a),this.clearErrors();var b=this,c=function d(c){var e=0,f=0;return c.each(function(c){if(c.filter||!a.skip_empty){if(!c.filter)return b.triggerValidationError(c,"no_filter",null),void f++;if(!c.operator)return b.triggerValidationError(c,"no_operator",null),void f++;if(0!==c.operator.nb_inputs){var d=b.validateValue(c,c.value);if(d!==!0)return b.triggerValidationError(c,d,c.value),void f++}e++}},function(a){var b=d(a);b===!0?e++:b===!1&&f++}),f>0?!1:0===e&&!c.isRoot()&&a.skip_empty?null:0!==e||b.settings.allow_empty&&c.isRoot()?!0:(b.triggerValidationError(c,"empty_group",null),!1)}(this.model.root);return this.change("validate",c)},g.prototype.getRules=function(a){a=$.extend({get_flags:!1,allow_invalid:!1,skip_empty:!1},a);var b=this.validate(a);if(!b&&!a.allow_invalid)return null;var c=this,d=function e(b){var d={condition:b.condition,rules:[]};if(b.data&&(d.data=$.extendext(!0,"replace",{},b.data)),a.get_flags){var f=c.getGroupFlags(b.flags,"all"===a.get_flags);$.isEmptyObject(f)||(d.flags=f)}return b.each(function(b){if(b.filter||!a.skip_empty){var e=null;b.operator&&0===b.operator.nb_inputs||(e=b.value);var f={id:b.filter?b.filter.id:null,field:b.filter?b.filter.field:null,type:b.filter?b.filter.type:null,input:b.filter?b.filter.input:null,operator:b.operator?b.operator.type:null,value:e};if((b.filter&&b.filter.data||b.data)&&(f.data=$.extendext(!0,"replace",{},b.filter.data,b.data)),a.get_flags){var g=c.getRuleFlags(b.flags,"all"===a.get_flags);$.isEmptyObject(g)||(f.flags=g)}d.rules.push(c.change("ruleToJson",f,b))}},function(b){var c=e(b);0===c.rules.length&&a.skip_empty||d.rules.push(c)},this),c.change("groupToJson",d,b)}(this.model.root);return d.valid=b,this.change("getRules",d)},g.prototype.setRules=function(a,b){b=$.extend({allow_invalid:!1},b),$.isArray(a)&&(a={condition:this.settings.default_condition,rules:a}),a&&a.rules&&(0!==a.rules.length||this.settings.allow_empty)||h.error("RulesParse","Incorrect data object passed"),this.clear(),this.setRoot(!1,a.data,this.parseGroupFlags(a)),this.applyGroupFlags(this.model.root),a=this.change("setRules",a,b);var c=this;!function d(a,e){null!==e&&(void 0===a.condition?a.condition=c.settings.default_condition:-1==c.settings.conditions.indexOf(a.condition)&&(h.error(!b.allow_invalid,"UndefinedCondition",'Invalid condition "{0}"',a.condition),a.condition=c.settings.default_condition),e.condition=a.condition,a.rules.forEach(function(a){var f;if(void 0!==a.rules)if(-1!==c.settings.allow_groups&&c.settings.allow_groups1){j=["operator_not_multiple",f.type,this.translate("operators",f.type)];break}switch(e.input){case"radio":if(void 0===b[k]||0===b[k].length){i.allow_empty_value||(j=["radio_empty"]);break}break;case"checkbox":if(void 0===b[k]||0===b[k].length){i.allow_empty_value||(j=["checkbox_empty"]);break}break;case"select":if(void 0===b[k]||0===b[k].length||e.placeholder&&b[k]==e.placeholder_value){i.allow_empty_value||(j=["select_empty"]);break}break;default:d=$.isArray(b[k])?b[k]:[b[k]];for(var l=0;lparseInt(i.max)){j=[this.getValidationMessage(i,"max","string_exceed_max_length"),i.max];break}if(i.format&&("string"==typeof i.format&&(i.format=new RegExp(i.format)),!i.format.test(d[l]))){j=[this.getValidationMessage(i,"format","string_invalid_format"),i.format];break}break;case"number":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["number_nan"]);break}if(isNaN(d[l])){j=["number_nan"];break}if("integer"==e.type){if(parseInt(d[l])!=d[l]){j=["number_not_integer"];break}}else if(parseFloat(d[l])!=d[l]){j=["number_not_double"];break}if(void 0!==i.min&&d[l]parseFloat(i.max)){j=[this.getValidationMessage(i,"max","number_exceed_max"),i.max];break}if(void 0!==i.step&&"any"!==i.step){var m=(d[l]/i.step).toPrecision(14);if(parseInt(m)!=m){j=[this.getValidationMessage(i,"step","number_wrong_step"),i.step];break}}break;case"datetime":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["datetime_empty"]);break}if(i.format){"moment"in window||h.error("MissingLibrary","MomentJS is required for Date/Time validation. Get it here http://momentjs.com");var n=moment(d[l],i.format);if(!n.isValid()){j=[this.getValidationMessage(i,"format","datetime_invalid"),i.format];break}if(i.min&&nmoment(i.max,i.format)){j=[this.getValidationMessage(i,"max","datetime_exceed_max"),i.max];break}}break;case"boolean":if(void 0===d[l]||0===d[l].length){i.allow_empty_value||(j=["boolean_not_valid"]);break}if(c=(""+d[l]).trim().toLowerCase(),"true"!==c&&"false"!==c&&"1"!==c&&"0"!==c&&1!==d[l]&&0!==d[l]){j=["boolean_not_valid"];break}}if(j!==!0)break}}if(j!==!0)break}return j},g.prototype.nextGroupId=function(){return this.status.id+"_group_"+this.status.group_id++},g.prototype.nextRuleId=function(){return this.status.id+"_rule_"+this.status.rule_id++},g.prototype.getOperators=function(a){"string"==typeof a&&(a=this.getFilterById(a));for(var b=[],c=0,d=this.operators.length;d>c;c++){if(a.operators){if(-1==a.operators.indexOf(this.operators[c].type))continue}else if(-1==this.operators[c].apply_to.indexOf(g.types[a.type]))continue;b.push(this.operators[c])}return a.operators&&b.sort(function(b,c){return a.operators.indexOf(b.type)-a.operators.indexOf(c.type)}),this.change("getOperators",b,a)},g.prototype.getFilterById=function(a,b){if("-1"==a)return null;for(var c=0,d=this.filters.length;d>c;c++)if(this.filters[c].id==a)return this.filters[c];return h.error(b!==!1,"UndefinedFilter",'Undefined filter "{0}"',a),null},g.prototype.getOperatorByType=function(a,b){if("-1"==a)return null;for(var c=0,d=this.operators.length;d>c;c++)if(this.operators[c].type==a)return this.operators[c];return h.error(b!==!1,"UndefinedOperator",'Undefined operator "{0}"',a),null},g.prototype.getRuleInputValue=function(a){var b=a.filter,c=a.operator,d=[];if(b.valueGetter)d=b.valueGetter.call(this,a);else{for(var e=a.$el.find(g.selectors.value_container),f=0;f '+b+" "});break;case"select":g+='";break;case"textarea":g+='";break;case"number":g+='=f:e<=f},i=!1;h()&&(this.rules[e]instanceof j?c&&(i=c.call(d,this.rules[e])===!1):b&&(i=b.call(d,this.rules[e])===!1),!i);e+=g);return!i},j.prototype.contains=function(a,b){return this.getNodePos(a)!==-1||!!b&&!this.each(function(){return!0},function(b){return!b.contains(a,!0)})};var k=function(a,b){return this instanceof k?(i.call(this,a,b),this._updating_value=!1,this._updating_input=!1,this.__.filter=null,this.__.operator=null,void(this.__.value=void 0)):new k(a,b)};return k.prototype=Object.create(i.prototype),k.prototype.constructor=k,h.defineModelProperties(k,["filter","operator","value"]),k.prototype.isRoot=function(){return!1},g.Group=j,g.Rule=k,$.fn.queryBuilder=function(a){0===this.length&&h.error("Config","No target defined"),this.length>1&&h.error("Config","Unable to initialize on multiple target");var b=this.data("queryBuilder"),c="object"==typeof a&&a||{};if(!b&&"destroy"==a)return this;if(!b){var d=new g(this,c);this.data("queryBuilder",d),d.init(c.rules)}return"string"==typeof a?b[a].apply(b,Array.prototype.slice.call(arguments,1)):this},$.fn.queryBuilder.constructor=g,$.fn.queryBuilder.defaults=g.defaults,$.fn.queryBuilder.extend=g.extend,$.fn.queryBuilder.define=g.define,$.fn.queryBuilder.regional=g.regional,g.define("bt-checkbox",function(a){"glyphicons"==a.font&&this.$el.addClass("bt-checkbox-glyphicons"),this.on("getRuleInput.filter",function(b,c,d){var e=c.filter;if(("radio"===e.input||"checkbox"===e.input)&&!e.plugin){b.value="",e.colors||(e.colors={}),e.color&&(e.colors._def_=e.color);var f=e.vertical?' style="display:block"':"",g=0;h.iterateOptions(e.values,function(c,h){var i=e.colors[c]||e.colors._def_||a.color,j=d+"_"+g++;b.value+=" "})}})},{font:"glyphicons",color:"default"}),g.define("bt-selectpicker",function(a){$.fn.selectpicker&&$.fn.selectpicker.Constructor||h.error("MissingLibrary",'Bootstrap Select is required to use "bt-selectpicker" plugin. Get it here: http://silviomoreto.github.io/bootstrap-select');var b=g.selectors;this.on("afterCreateRuleFilters",function(c,d){d.$el.find(b.rule_filter).removeClass("form-control").selectpicker(a)}),this.on("afterCreateRuleOperators",function(c,d){d.$el.find(b.rule_operator).removeClass("form-control").selectpicker(a)}),this.on("afterUpdateRuleFilter",function(a,c){c.$el.find(b.rule_filter).selectpicker("render")}),this.on("afterUpdateRuleOperator",function(a,c){c.$el.find(b.rule_operator).selectpicker("render")}),this.on("beforeDeleteRule",function(a,c){c.$el.find(b.rule_filter).selectpicker("destroy"),c.$el.find(b.rule_operator).selectpicker("destroy")})},{container:"body",style:"btn-inverse btn-xs",width:"auto",showIcon:!1}),g.define("bt-tooltip-errors",function(a){$.fn.tooltip&&$.fn.tooltip.Constructor&&$.fn.tooltip.Constructor.prototype.fixTitle||h.error("MissingLibrary",'Bootstrap Tooltip is required to use "bt-tooltip-errors" plugin. Get it here: http://getbootstrap.com');var b=this;this.on("getRuleTemplate.filter getGroupTemplate.filter",function(a){var b=$(a.value);b.find(g.selectors.error_container).attr("data-toggle","tooltip"),a.value=b.prop("outerHTML")}),this.model.on("update",function(c,d,e){"error"==e&&b.settings.display_errors&&d.$el.find(g.selectors.error_container).eq(0).tooltip(a).tooltip("hide").tooltip("fixTitle")})},{placement:"right"}),g.extend({setFilters:function(a,b){var c=this;void 0===b&&(b=a,a=!1),b=this.checkFilters(b),b=this.change("setFilters",b);var d=b.map(function(a){return a.id});if(a||!function f(a){a.each(function(a){a.filter&&d.indexOf(a.filter.id)===-1&&h.error("ChangeFilter",'A rule is using filter "{0}"',a.filter.id)},f)}(this.model.root),this.filters=b,function i(a){a.each(!0,function(a){a.filter&&d.indexOf(a.filter.id)===-1?(a.drop(),c.trigger("rulesChanged")):(c.createRuleFilters(a),a.$el.find(g.selectors.rule_filter).val(a.filter?a.filter.id:"-1"),c.trigger("afterUpdateRuleFilter",a))},i)}(this.model.root),this.settings.plugins&&(this.settings.plugins["unique-filter"]&&this.updateDisabledFilters(),this.settings.plugins["bt-selectpicker"]&&this.$el.find(g.selectors.rule_filter).selectpicker("render")),this.settings.default_filter)try{this.getFilterById(this.settings.default_filter)}catch(e){this.settings.default_filter=null}this.trigger("afterSetFilters",b)},addFilter:function(a,b){void 0===b||"#end"==b?b=this.filters.length:"#start"==b&&(b=0),$.isArray(a)||(a=[a]);var c=$.extend(!0,[],this.filters);parseInt(b)==b?Array.prototype.splice.apply(c,[b,0].concat(a)):this.filters.some(function(a,c){if(a.id==b)return b=c+1,!0})?Array.prototype.splice.apply(c,[b,0].concat(a)):Array.prototype.push.apply(c,a),this.setFilters(c)},removeFilter:function(a,b){var c=$.extend(!0,[],this.filters);"string"==typeof a&&(a=[a]),c=c.filter(function(b){return a.indexOf(b.id)===-1}),this.setFilters(b,c)}}),g.define("filter-description",function(a){"inline"===a.mode?this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("p.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$('

'),d.appendTo(c.$el)):d.show(),d.html(' '+e)):d.hide()}):"popover"===a.mode?($.fn.popover&&$.fn.popover.Constructor&&$.fn.popover.Constructor.prototype.fixTitle||h.error("MissingLibrary",'Bootstrap Popover is required to use "filter-description" plugin. Get it here: http://getbootstrap.com'),this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("button.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$(''),d.prependTo(c.$el.find(g.selectors.rule_actions)),d.popover({placement:"left",container:"body",html:!0}),d.on("mouseout",function(){d.popover("hide")})):d.show(),d.data("bs.popover").options.content=e,d.attr("aria-describedby")&&d.popover("show")):(d.hide(),d.data("bs.popover")&&d.popover("hide"))})):"bootbox"===a.mode&&("bootbox"in window||h.error("MissingLibrary",'Bootbox is required to use "filter-description" plugin. Get it here: http://bootboxjs.com'),this.on("afterUpdateRuleFilter afterUpdateRuleOperator",function(b,c){var d=c.$el.find("button.filter-description"),e=b.builder.getFilterDescription(c.filter,c);e?(0===d.length?(d=$(''),d.prependTo(c.$el.find(g.selectors.rule_actions)),d.on("click",function(){bootbox.alert(d.data("description"))})):d.show(),d.data("description",e)):d.hide()}))},{icon:"glyphicon glyphicon-info-sign",mode:"popover"}),g.extend({getFilterDescription:function(a,b){return a?"function"==typeof a.description?a.description.call(this,b):a.description:void 0}}),g.define("invert",function(a){var b=this,c=g.selectors;this.on("afterInit",function(){b.$el.on("click.queryBuilder","[data-invert=group]",function(){var d=$(this).closest(c.group_container);b.invert(b.getModel(d),a)}),a.display_rules_button&&a.invert_rules&&b.$el.on("click.queryBuilder","[data-invert=rule]",function(){var d=$(this).closest(c.rule_container);b.invert(b.getModel(d),a)})}),this.on("getGroupTemplate.filter",function(d,e){var f=$(d.value);f.find(c.condition_container).after('"),d.value=f.prop("outerHTML")}),a.display_rules_button&&a.invert_rules&&this.on("getRuleTemplate.filter",function(d){var e=$(d.value);e.find(c.rule_actions).prepend('"),d.value=e.prop("outerHTML")})},{icon:"glyphicon glyphicon-random",recursive:!0,invert_rules:!0,display_rules_button:!1,silent_fail:!1}),g.defaults({operatorOpposites:{equal:"not_equal",not_equal:"equal","in":"not_in",not_in:"in",less:"greater_or_equal",less_or_equal:"greater",greater:"less_or_equal",greater_or_equal:"less",between:"not_between",not_between:"between",begins_with:"not_begins_with",not_begins_with:"begins_with",contains:"not_contains",not_contains:"contains",ends_with:"not_ends_with",not_ends_with:"ends_with",is_empty:"is_not_empty",is_not_empty:"is_empty",is_null:"is_not_null",is_not_null:"is_null"},conditionOpposites:{AND:"OR",OR:"AND"}}),g.extend({invert:function(a,b){if(!(a instanceof i)){if(!this.model.root)return;b=a,a=this.model.root}if("object"!=typeof b&&(b={}),void 0===b.recursive&&(b.recursive=!0),void 0===b.invert_rules&&(b.invert_rules=!0),void 0===b.silent_fail&&(b.silent_fail=!1),void 0===b.trigger&&(b.trigger=!0),a instanceof j){if(this.settings.conditionOpposites[a.condition]?a.condition=this.settings.conditionOpposites[a.condition]:b.silent_fail||h.error("InvertCondition",'Unknown inverse of condition "{0}"',a.condition),b.recursive){var c=$.extend({},b,{trigger:!1});a.each(function(a){b.invert_rules&&this.invert(a,c)},function(a){this.invert(a,c)},this)}}else if(a instanceof k&&a.operator&&!a.filter.no_invert)if(this.settings.operatorOpposites[a.operator.type]){var d=this.settings.operatorOpposites[a.operator.type];a.filter.operators&&a.filter.operators.indexOf(d)==-1||(a.operator=this.getOperatorByType(d))}else b.silent_fail||h.error("InvertOperator",'Unknown inverse of operator "{0}"',a.operator.type);b.trigger&&(this.trigger("afterInvert",a,b),this.trigger("rulesChanged"))}}),g.defaults({mongoOperators:{equal:function(a){return a[0]},not_equal:function(a){return{$ne:a[0]}},"in":function(a){return{$in:a}},not_in:function(a){return{$nin:a}},less:function(a){return{$lt:a[0]}},less_or_equal:function(a){return{$lte:a[0]}},greater:function(a){return{$gt:a[0]}},greater_or_equal:function(a){return{$gte:a[0]}},between:function(a){return{$gte:a[0],$lte:a[1]}},not_between:function(a){return{$lt:a[0],$gt:a[1]}},begins_with:function(a){return{$regex:"^"+h.escapeRegExp(a[0])}},not_begins_with:function(a){return{$regex:"^(?!"+h.escapeRegExp(a[0])+")"}},contains:function(a){return{$regex:h.escapeRegExp(a[0])}},not_contains:function(a){return{$regex:"^((?!"+h.escapeRegExp(a[0])+").)*$",$options:"s"}},ends_with:function(a){return{$regex:h.escapeRegExp(a[0])+"$"}},not_ends_with:function(a){return{$regex:"(?0)d.push(c(a));else{var e=b.settings.mongoOperators[a.operator],f=b.getOperatorByType(a.operator),g=[];void 0===e&&h.error("UndefinedMongoOperator",'Unknown MongoDB operation for operator "{0}"',a.operator),0!==f.nb_inputs&&(a.value instanceof Array||(a.value=[a.value]),a.value.forEach(function(b){g.push(h.changeType(b,a.type,!1))}));var i=b.change("getMongoDBField",a.field,a),j={};j[i]=e.call(b,g),d.push(b.change("ruleToMongo",j,a,g,e))}});var e={};return e["$"+a.condition.toLowerCase()]=d,b.change("groupToMongo",e,a)}(a)},getRulesFromMongo:function(a){if(void 0===a||null===a)return null;var b=this;if(a=b.change("parseMongoNode",a),"rules"in a&&"condition"in a)return a;if("id"in a&&"operator"in a&&"value"in a)return{condition:this.settings.default_condition,rules:[a]};var e=d(a);return e||h.error("MongoParse","Invalid MongoDB query format"),function f(a,e){var g=a[e],i=[];return g.forEach(function(a){if(a=b.change("parseMongoNode",a),"rules"in a&&"condition"in a)return void i.push(a);if("id"in a&&"operator"in a&&"value"in a)return void i.push(a);var e=d(a);if(e)i.push(f(a,e));else{var g=Object.keys(a)[0],j=a[g],k=c(j,g);void 0===k&&h.error("MongoParse","Invalid MongoDB query format");var l=b.settings.mongoRuleOperators[k];void 0===l&&h.error("UndefinedMongoOperator",'JSON Rule operation unknown for operator "{0}"',k);var m=l.call(b,j),n=b.getMongoDBFieldID(g,j),o=b.change("mongoToRule",{id:n,field:g,operator:m.op,value:m.val},a);i.push(o)}}),b.change("mongoToGroup",{condition:e.replace("$","").toUpperCase(),rules:i},a)}(a,e)},setRulesFromMongo:function(a){this.setRules(this.getRulesFromMongo(a))},getMongoDBFieldID:function(a,b){var c,d=this.filters.filter(function(b){return b.field===a});return c=1===d.length?d[0].id:this.change("getMongoDBFieldID",a,b)}}),g.define("not-group",function(a){var b=this;this.on("afterInit",function(){b.$el.on("click.queryBuilder","[data-not=group]",function(){var a=$(this).closest(g.selectors.group_container),c=b.getModel(a);c.not=!c.not}),b.model.on("update",function(a,c,d){c instanceof j&&"not"===d&&b.updateGroupNot(c)})}),this.on("afterAddGroup",function(a,b){b.__.not=!1}),this.on("getGroupTemplate.filter",function(c,d){var e=$(c.value);e.find(g.selectors.condition_container).prepend('"),c.value=e.prop("outerHTML")}),this.on("groupToJson.filter",function(a,b){a.value.not=b.not}),this.on("jsonToGroup.filter",function(a,b){a.value.not=!!b.not}),this.on("groupToSQL.filter",function(a,b){b.not&&(a.value="NOT ( "+a.value+" )")}),this.on("parseSQLNode.filter",function(a){a.value.name&&"NOT"==a.value.name.toUpperCase()&&(a.value=a.value.arguments.value[0],a.value.not=!0)}),this.on("sqlToGroup.filter",function(a,b){a.value.not=!!b.not}),this.on("groupToMongo.filter",function(a,b){var c="$"+b.condition.toLowerCase();b.not&&a.value[c]&&(a.value={$nor:[a.value]})}),this.on("parseMongoNode.filter",function(a){var b=Object.keys(a.value);"$nor"==b[0]&&(a.value=a.value[b[0]][0],a.value.not=!0)}),this.on("mongoToGroup.filter",function(a,b){a.value.not=!!b.not})},{icon_unchecked:"glyphicon glyphicon-unchecked",icon_checked:"glyphicon glyphicon-check"}),h.defineModelProperties(j,["not"]),g.selectors.group_not=g.selectors.group_header+" [data-not=group]",g.extend({updateGroupNot:function(a){var b=this.plugins["not-group"];a.$el.find(">"+g.selectors.group_not).toggleClass("active",a.not).find("i").attr("class",a.not?b.icon_checked:b.icon_unchecked),this.trigger("afterUpdateGroupNot",a),this.trigger("rulesChanged")}}),g.define("sortable",function(a){"interact"in window||h.error("MissingLibrary",'interact.js is required to use "sortable" plugin. Get it here: http://interactjs.io'),void 0!==a.default_no_sortable&&(h.error(!1,"Config",'Sortable plugin : "default_no_sortable" options is deprecated, use standard "default_rule_flags" and "default_group_flags" instead'),this.settings.default_rule_flags.no_sortable=this.settings.default_group_flags.no_sortable=a.default_no_sortable),interact.dynamicDrop(!0),interact.pointerMoveTolerance(10);var b,c,d;this.on("afterAddRule afterAddGroup",function(f,h){if(h!=b){var i=f.builder;a.inherit_no_sortable&&h.parent&&h.parent.flags.no_sortable&&(h.flags.no_sortable=!0),a.inherit_no_drop&&h.parent&&h.parent.flags.no_drop&&(h.flags.no_drop=!0),h.flags.no_sortable||interact(h.$el[0]).allowFrom(g.selectors.drag_handle).draggable({onstart:function(a){d=i.getModel(a.target),c=d.$el.clone().appendTo(d.$el.parent()).width(d.$el.outerWidth()).addClass("dragging");var e=$('
 
').height(d.$el.outerHeight());b=d.parent.addRule(e,d.getPos()),d.$el.hide()},onmove:function(a){c[0].style.top=a.clientY-15+"px",c[0].style.left=a.clientX-15+"px"},onend:function(){c.remove(),c=void 0,b.drop(),b=void 0,d.$el.show(),i.trigger("afterMove",d),i.trigger("rulesChanged")}}),h.flags.no_drop||(interact(h.$el[0]).dropzone({accept:g.selectors.rule_and_group_containers,ondragenter:function(a){e(b,$(a.target),i)},ondrop:function(a){e(d,$(a.target),i)}}),h instanceof j&&interact(h.$el.find(g.selectors.group_header)[0]).dropzone({accept:g.selectors.rule_and_group_containers,ondragenter:function(a){e(b,$(a.target),i)},ondrop:function(a){e(d,$(a.target),i)}}))}}),this.on("beforeDeleteRule beforeDeleteGroup",function(a,b){a.isDefaultPrevented()||(interact(b.$el[0]).unset(),b instanceof j&&interact(b.$el.find(g.selectors.group_header)[0]).unset())}),this.on("afterApplyRuleFlags afterApplyGroupFlags",function(a,b){b.flags.no_sortable&&b.$el.find(".drag-handle").remove()}),this.on("getGroupTemplate.filter",function(b,c){if(c>1){var d=$(b.value);d.find(g.selectors.condition_container).after('
'),b.value=d.prop("outerHTML")}}),this.on("getRuleTemplate.filter",function(b){var c=$(b.value);c.find(g.selectors.rule_header).after('
'),b.value=c.prop("outerHTML")})},{inherit_no_sortable:!0,inherit_no_drop:!0,icon:"glyphicon glyphicon-sort"}),g.selectors.rule_and_group_containers=g.selectors.rule_container+", "+g.selectors.group_container,g.selectors.drag_handle=".drag-handle",g.defaults({default_rule_flags:{no_sortable:!1,no_drop:!1},default_group_flags:{no_sortable:!1,no_drop:!1}}),g.define("sql-support",function(a){},{boolean_as_integer:!0}),g.defaults({sqlOperators:{equal:{op:"= ?"},not_equal:{op:"!= ?"},"in":{op:"IN(?)",sep:", "},not_in:{op:"NOT IN(?)",sep:", "},less:{op:"< ?"},less_or_equal:{op:"<= ?"},greater:{op:"> ?"},greater_or_equal:{op:">= ?"},between:{op:"BETWEEN ?",sep:" AND "},not_between:{op:"NOT BETWEEN ?",sep:" AND "},begins_with:{op:"LIKE(?)",mod:"{0}%"}, +not_begins_with:{op:"NOT LIKE(?)",mod:"{0}%"},contains:{op:"LIKE(?)",mod:"%{0}%"},not_contains:{op:"NOT LIKE(?)",mod:"%{0}%"},ends_with:{op:"LIKE(?)",mod:"%{0}"},not_ends_with:{op:"NOT LIKE(?)",mod:"%{0}"},is_empty:{op:"= ''"},is_not_empty:{op:"!= ''"},is_null:{op:"IS NULL"},is_not_null:{op:"IS NOT NULL"}},sqlRuleOperator:{"=":function(a){return{val:a,op:""===a?"is_empty":"equal"}},"!=":function(a){return{val:a,op:""===a?"is_not_empty":"not_equal"}},LIKE:function(a){return"%"==a.slice(0,1)&&"%"==a.slice(-1)?{val:a.slice(1,-1),op:"contains"}:"%"==a.slice(0,1)?{val:a.slice(1),op:"ends_with"}:"%"==a.slice(-1)?{val:a.slice(0,-1),op:"begins_with"}:void h.error("SQLParse",'Invalid value for LIKE operator "{0}"',a)},"NOT LIKE":function(a){return"%"==a.slice(0,1)&&"%"==a.slice(-1)?{val:a.slice(1,-1),op:"not_contains"}:"%"==a.slice(0,1)?{val:a.slice(1),op:"not_ends_with"}:"%"==a.slice(-1)?{val:a.slice(0,-1),op:"not_begins_with"}:void h.error("SQLParse",'Invalid value for NOT LIKE operator "{0}"',a)},IN:function(a){return{val:a,op:"in"}},"NOT IN":function(a){return{val:a,op:"not_in"}},"<":function(a){return{val:a,op:"less"}},"<=":function(a){return{val:a,op:"less_or_equal"}},">":function(a){return{val:a,op:"greater"}},">=":function(a){return{val:a,op:"greater_or_equal"}},BETWEEN:function(a){return{val:a,op:"between"}},"NOT BETWEEN":function(a){return{val:a,op:"not_between"}},IS:function(a){return null!==a&&h.error("SQLParse","Invalid value for IS operator"),{val:null,op:"is_null"}},"IS NOT":function(a){return null!==a&&h.error("SQLParse","Invalid value for IS operator"),{val:null,op:"is_not_null"}}},sqlStatements:{question_mark:function(){var a=[];return{add:function(b,c){return a.push(c),"?"},run:function(){return a}}},numbered:function(a){(!a||a.length>1)&&(a="$");var b=0,c=[];return{add:function(d,e){return c.push(e),b++,a+b},run:function(){return c}}},named:function(a){(!a||a.length>1)&&(a=":");var b={},c={};return{add:function(d,e){b[d.field]||(b[d.field]=1);var f=d.field+"_"+b[d.field]++;return c[f]=e,a+f},run:function(){return c}}}},sqlRuleStatement:{question_mark:function(a){var b=0;return{parse:function(c){return"?"==c?a[b++]:c},esc:function(a){return a.replace(/\?/g,"'?'")}}},numbered:function(a,b){(!b||b.length>1)&&(b="$");var c=new RegExp("^\\"+b+"[0-9]+$"),d=new RegExp("\\"+b+"([0-9]+)","g");return{parse:function(b){return c.test(b)?a[b.slice(1)-1]:b},esc:function(a){return a.replace(d,"'"+("$"==b?"$$":b)+"$1'")}}},named:function(a,b){(!b||b.length>1)&&(b=":");var c=new RegExp("^\\"+b),d=new RegExp("\\"+b+"("+Object.keys(a).join("|")+")","g");return{parse:function(b){return c.test(b)?a[b.slice(1)]:b},esc:function(a){return a.replace(d,"'"+("$"==b?"$$":b)+"$1'")}}}}}),g.extend({getSQL:function(a,b,c){if(c=void 0===c?this.getRules():c,!c)return null;b=b?"\n":" ";var d=this.getPluginOptions("sql-support","boolean_as_integer");if(a===!0&&(a="question_mark"),"string"==typeof a){var e=f(a);a=this.settings.sqlStatements[e[1]](e[2])}var g=this,i=function j(c){if(c.condition||(c.condition=g.settings.default_condition),["AND","OR"].indexOf(c.condition.toUpperCase())===-1&&h.error("UndefinedSQLCondition",'Unable to build SQL query with condition "{0}"',c.condition),!c.rules)return"";var e=[];c.rules.forEach(function(c){if(c.rules&&c.rules.length>0)e.push("("+b+j(c)+b+")"+b);else{var f=g.settings.sqlOperators[c.operator],i=g.getOperatorByType(c.operator),k="";void 0===f&&h.error("UndefinedSQLOperator",'Unknown SQL operation for operator "{0}"',c.operator),0!==i.nb_inputs&&(c.value instanceof Array||(c.value=[c.value]),c.value.forEach(function(b,e){e>0&&(k+=f.sep),"integer"==c.type||"double"==c.type||"boolean"==c.type?b=h.changeType(b,c.type,d):a||(b=h.escapeString(b)),f.mod&&(b=h.fmt(f.mod,b)),a?k+=a.add(c,b):("string"==typeof b&&(b="'"+b+"'"),k+=b)}));var l=function(a){return f.op.replace(/\?/,a)},m=g.change("getSQLField",c.field,c),n=m+" "+l(k);e.push(g.change("ruleToSQL",n,c,k,l))}});var f=e.join(" "+c.condition+b);return g.change("groupToSQL",f,c)}(c);return a?{sql:i,params:a.run()}:{sql:i}},getRulesFromSQL:function(a,b){"SQLParser"in window||h.error("MissingLibrary","SQLParser is required to parse SQL queries. Get it here https://github.com/mistic100/sql-parser");var c=this;if("string"==typeof a&&(a={sql:a}),b===!0&&(b="question_mark"),"string"==typeof b){var d=f(b);b=this.settings.sqlRuleStatement[d[1]](a.params,d[2])}b&&(a.sql=b.esc(a.sql)),0!==a.sql.toUpperCase().indexOf("SELECT")&&(a.sql="SELECT * FROM table WHERE "+a.sql);var e=SQLParser.parse(a.sql);e.where||h.error("SQLParse","No WHERE clause found");var g=c.change("parseSQLNode",e.where.conditions);if("rules"in g&&"condition"in g)return g;if("id"in g&&"operator"in g&&"value"in g)return{condition:this.settings.default_condition,rules:[g]};var i=c.change("sqlToGroup",{condition:this.settings.default_condition,rules:[]},g),j=i;return function k(a,d){if(a=c.change("parseSQLNode",a),"rules"in a&&"condition"in a)return void j.rules.push(a);if("id"in a&&"operator"in a&&"value"in a)return void j.rules.push(a);if("left"in a&&"right"in a&&"operation"in a||h.error("SQLParse","Unable to parse WHERE clause"),["AND","OR"].indexOf(a.operation.toUpperCase())!==-1){if(d>0&&j.condition!=a.operation.toUpperCase()){var e=c.change("sqlToGroup",{condition:c.settings.default_condition,rules:[]},a);j.rules.push(e),j=e}j.condition=a.operation.toUpperCase(),d++;var f=j;k(a.left,d),j=f,k(a.right,d)}else{$.isPlainObject(a.right.value)&&h.error("SQLParse","Value format not supported for {0}.",a.left.value);var g;g=$.isArray(a.right.value)?a.right.value.map(function(a){return a.value}):a.right.value,b&&(g=$.isArray(g)?g.map(b.parse):b.parse(g));var i=a.operation.toUpperCase();"<>"==i&&(i="!=");var l=c.settings.sqlRuleOperator[i];void 0===l&&h.error("UndefinedSQLOperator",'Invalid SQL operation "{0}".',a.operation);var m,n=l.call(this,g,a.operation);"values"in a.left?m=a.left.values.join("."):"value"in a.left?m=a.left.value:h.error("SQLParse","Cannot find field name in {0}",JSON.stringify(a.left));var o=c.getSQLFieldID(m,g),p=c.change("sqlToRule",{id:o,field:m,operator:n.op,value:n.val},a);j.rules.push(p)}}(g,0),i},setRulesFromSQL:function(a,b){this.setRules(this.getRulesFromSQL(a,b))},getSQLFieldID:function(a,b){var c,d=this.filters.filter(function(b){return b.field.toLowerCase()===a.toLowerCase()});return c=1===d.length?d[0].id:this.change("getSQLFieldID",a,b)}}),g.define("unique-filter",function(){this.status.used_filters={},this.on("afterUpdateRuleFilter",this.updateDisabledFilters),this.on("afterDeleteRule",this.updateDisabledFilters),this.on("afterCreateRuleFilters",this.applyDisabledFilters),this.on("afterReset",this.clearDisabledFilters),this.on("afterClear",this.clearDisabledFilters),this.on("getDefaultFilter.filter",function(a,b){var c=a.builder;if(c.updateDisabledFilters(),a.value.id in c.status.used_filters){var d=c.filters.some(function(d){if(!(d.id in c.status.used_filters)||c.status.used_filters[d.id].length>0&&c.status.used_filters[d.id].indexOf(b.parent)===-1)return a.value=d,!0});d||(h.error(!1,"UniqueFilter","No more non-unique filters available"),a.value=void 0)}})}),g.extend({updateDisabledFilters:function(a){var b=a?a.builder:this;b.status.used_filters={},b.model&&(!function c(a){a.each(function(a){a.filter&&a.filter.unique&&(b.status.used_filters[a.filter.id]||(b.status.used_filters[a.filter.id]=[]),"group"==a.filter.unique&&b.status.used_filters[a.filter.id].push(a.parent))},function(a){c(a)})}(b.model.root),b.applyDisabledFilters(a))},clearDisabledFilters:function(a){var b=a?a.builder:this;b.status.used_filters={},b.applyDisabledFilters(a)},applyDisabledFilters:function(a){var b=a?a.builder:this;b.$el.find(g.selectors.filter_container+" option").prop("disabled",!1),$.each(b.status.used_filters,function(a,c){0===c.length?b.$el.find(g.selectors.filter_container+' option[value="'+a+'"]:not(:selected)').prop("disabled",!0):c.forEach(function(b){b.each(function(b){b.$el.find(g.selectors.filter_container+' option[value="'+a+'"]:not(:selected)').prop("disabled",!0)})})}),b.settings.plugins&&b.settings.plugins["bt-selectpicker"]&&b.$el.find(g.selectors.rule_filter).selectpicker("render")}}),g.regional.en={__locale:"English (en)",__author:'Damien "Mistic" Sorel, http://www.strangeplanet.fr',add_rule:"Add rule",add_group:"Add group",delete_rule:"Delete",delete_group:"Delete",conditions:{AND:"AND",OR:"OR"},operators:{equal:"equal",not_equal:"not equal","in":"in",not_in:"not in",less:"less",less_or_equal:"less or equal",greater:"greater",greater_or_equal:"greater or equal",between:"between",not_between:"not between",begins_with:"begins with",not_begins_with:"doesn't begin with",contains:"contains",not_contains:"doesn't contain",ends_with:"ends with",not_ends_with:"doesn't end with",is_empty:"is empty",is_not_empty:"is not empty",is_null:"is null",is_not_null:"is not null"},errors:{no_filter:"No filter selected",empty_group:"The group is empty",radio_empty:"No value selected",checkbox_empty:"No value selected",select_empty:"No value selected",string_empty:"Empty value",string_exceed_min_length:"Must contain at least {0} characters",string_exceed_max_length:"Must not contain more than {0} characters",string_invalid_format:"Invalid format ({0})",number_nan:"Not a number",number_not_integer:"Not an integer",number_not_double:"Not a real number",number_exceed_min:"Must be greater than {0}",number_exceed_max:"Must be lower than {0}",number_wrong_step:"Must be a multiple of {0}",number_between_invalid:"Invalid values, {0} is greater than {1}",datetime_empty:"Empty value",datetime_invalid:"Invalid date format ({0})",datetime_exceed_min:"Must be after {0}",datetime_exceed_max:"Must be before {0}",datetime_between_invalid:"Invalid values, {0} isgreater than {1}",boolean_not_valid:"Not a boolean",operator_not_multiple:'Operator "{1}" cannot accept multiple values'},invert:"Invert",NOT:"NOT"},g.defaults({lang_code:"en"}),g}); \ No newline at end of file diff --git a/dist/scss/dark.scss b/dist/scss/dark.scss index 3e7afda5..22bdf7ba 100644 --- a/dist/scss/dark.scss +++ b/dist/scss/dark.scss @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/dist/scss/default.scss b/dist/scss/default.scss index 37cc4124..4bb7dcd6 100644 --- a/dist/scss/default.scss +++ b/dist/scss/default.scss @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.4 + * jQuery QueryBuilder 2.4.5 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ @@ -67,7 +67,7 @@ $ticks-position: 5px, 10px !default; .group-conditions { .btn.readonly:not(.active), - input[name$=_cond] { + input[name$='_cond'] { border: 0; clip: rect(0 0 0 0); height: 1px; @@ -115,7 +115,9 @@ $ticks-position: 5px, 10px !default; } } - select, input[type=text], input[type=number] { + select, + input[type='text'], + input[type='number'] { padding: 1px; } } diff --git a/dist/scss/plugins/_bt-checkbox.scss b/dist/scss/plugins/_bt-checkbox.scss index 9b259265..324f610f 100644 --- a/dist/scss/plugins/_bt-checkbox.scss +++ b/dist/scss/plugins/_bt-checkbox.scss @@ -1,5 +1,5 @@ .query-builder.bt-checkbox-glyphicons { - .checkbox input[type=checkbox]:checked + label::after { + .checkbox input[type='checkbox']:checked + label::after { font-family: 'Glyphicons Halflings'; content: '\e013'; } diff --git a/dist/scss/plugins/_sortable.scss b/dist/scss/plugins/_sortable.scss index cf57c795..ac902fe1 100644 --- a/dist/scss/plugins/_sortable.scss +++ b/dist/scss/plugins/_sortable.scss @@ -14,7 +14,8 @@ $placeholder-border: 1px dashed $placeholder-border-color; opacity: .5; z-index: 100; - &::before, &::after { + &::before, + &::after { display: none; } } diff --git a/examples/index.html b/examples/index.html index 369c9eda..350b9896 100644 --- a/examples/index.html +++ b/examples/index.html @@ -274,7 +274,8 @@

Output

2: 'warning', 5: 'success' }, - operators: ['in', 'not_in', 'equal', 'not_equal', 'is_null', 'is_not_null'] + operators: ['equal', 'not_equal', 'in', 'not_in', 'is_null', 'is_not_null'], + default_operator: 'in' }, /* * select @@ -545,7 +546,7 @@

Output

}, { id: 'coord', operator: 'equal', - value: 'B.3' + value: undefined // will use filter's default value }] }, { id: 'name', diff --git a/package.json b/package.json index 51350701..5bbdf592 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jQuery-QueryBuilder", - "version": "2.4.4", + "version": "2.4.5", "author": { "name": "Damien \"Mistic\" Sorel", "email": "contact@git.strangeplanet.fr", @@ -10,14 +10,14 @@ "main": "dist/js/query-builder.js", "dependencies": { "jquery": ">=1.9.0", - "bootstrap": ">=3.1.0", + "bootstrap": ">=3.1.0 <4", "moment": ">=2.6.0", "jquery-extendext": ">=0.1.2", "dot": ">=1.0.3" }, "devDependencies": { "deepmerge": "^0.2.0", - "foodoc": "git://github.com/mistic100/foodoc.git#custom", + "foodoc": "^0.0.8", "grunt": "^1.0.0", "grunt-banner": "^0.6.0", "grunt-contrib-clean": "^1.0.0", @@ -27,7 +27,6 @@ "grunt-contrib-cssmin": "^1.0.0", "grunt-contrib-jshint": "^1.0.0", "grunt-contrib-qunit": "^0.7.0", - "grunt-contrib-sass": "^1.0.0", "grunt-contrib-uglify": "^1.0.0", "grunt-contrib-watch": "^1.0.0", "grunt-coveralls": "^1.0.0", @@ -36,8 +35,9 @@ "grunt-jsdoc": "^2.1.0", "grunt-open": "^0.2.3", "grunt-qunit-blanket-lcov": "^0.3.0", + "grunt-sass": "^2.0.0", "grunt-sass-injection": "^1.0.3", - "grunt-scss-lint": "^0.3.8", + "grunt-sass-lint": "^0.2.2", "grunt-wrap": "^0.3.0", "jit-grunt": "^0.10.0", "time-grunt": "^1.3.0" diff --git a/src/core.js b/src/core.js index b3e2d2ec..dddabca4 100644 --- a/src/core.js +++ b/src/core.js @@ -1,3 +1,26 @@ +/** + * Final initialisation of the builder + * @param {object} [rules] + * @fires QueryBuilder.afterInit + * @private + */ +QueryBuilder.prototype.init = function(rules) { + /** + * When the initilization is done, just before creating the root group + * @event afterInit + * @memberof QueryBuilder + */ + this.trigger('afterInit'); + + if (rules) { + this.setRules(rules); + delete this.settings.rules; + } + else { + this.setRoot(true); + } +}; + /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters @@ -259,7 +282,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'value': - self.updateRuleValue(node); + self.updateRuleValue(node, oldValue); break; } } @@ -274,7 +297,7 @@ QueryBuilder.prototype.bindEvents = function() { break; case 'condition': - self.updateGroupCondition(node); + self.updateGroupCondition(node, oldValue); break; } } @@ -357,6 +380,13 @@ QueryBuilder.prototype.addGroup = function(parent, addRule, data, flags) { */ this.trigger('afterAddGroup', model); + /** + * After any change in the rules + * @event rulesChanged + * @memberof QueryBuilder + */ + this.trigger('rulesChanged'); + model.condition = this.settings.default_condition; if (addRule) { @@ -406,6 +436,8 @@ QueryBuilder.prototype.deleteGroup = function(group) { * @memberof QueryBuilder */ this.trigger('afterDeleteGroup'); + + this.trigger('rulesChanged'); } return del; @@ -414,10 +446,11 @@ QueryBuilder.prototype.deleteGroup = function(group) { /** * Performs actions when a group's condition changes * @param {Group} group + * @param {object} previousCondition * @fires QueryBuilder.afterUpdateGroupCondition * @private */ -QueryBuilder.prototype.updateGroupCondition = function(group) { +QueryBuilder.prototype.updateGroupCondition = function(group, previousCondition) { group.$el.find('>' + QueryBuilder.selectors.group_condition).each(function() { var $this = $(this); $this.prop('checked', $this.val() === group.condition); @@ -429,8 +462,11 @@ QueryBuilder.prototype.updateGroupCondition = function(group) { * @event afterUpdateGroupCondition * @memberof QueryBuilder * @param {Group} group + * @param {object} previousCondition */ - this.trigger('afterUpdateGroupCondition', group); + this.trigger('afterUpdateGroupCondition', group, previousCondition); + + this.trigger('rulesChanged'); }; /** @@ -490,6 +526,8 @@ QueryBuilder.prototype.addRule = function(parent, data, flags) { */ this.trigger('afterAddRule', model); + this.trigger('rulesChanged'); + this.createRuleFilters(model); if (this.settings.default_filter || !this.settings.display_empty_filter) { @@ -542,6 +580,8 @@ QueryBuilder.prototype.deleteRule = function(rule) { */ this.trigger('afterDeleteRule'); + this.trigger('rulesChanged'); + return true; }; @@ -594,7 +634,14 @@ QueryBuilder.prototype.createRuleOperators = function(rule) { $operatorContainer.html($operatorSelect); // set the operator without triggering update event - rule.__.operator = operators[0]; + if (rule.filter.default_operator) { + rule.__.operator = this.getOperatorByType(rule.filter.default_operator); + } + else { + rule.__.operator = operators[0]; + } + + rule.$el.find(QueryBuilder.selectors.rule_operator).val(rule.operator.type); /** * After creating the dropdown for operators @@ -687,8 +734,11 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { * @event afterUpdateRuleFilter * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousFilter */ - this.trigger('afterUpdateRuleFilter', rule); + this.trigger('afterUpdateRuleFilter', rule, previousFilter); + + this.trigger('rulesChanged'); }; /** @@ -700,6 +750,7 @@ QueryBuilder.prototype.updateRuleFilter = function(rule, previousFilter) { */ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { var $valueContainer = rule.$el.find(QueryBuilder.selectors.value_container); + var ruleValue = rule.value; if (!rule.operator || rule.operator.nb_inputs === 0) { $valueContainer.hide(); @@ -726,19 +777,24 @@ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) { * @event afterUpdateRuleOperator * @memberof QueryBuilder * @param {Rule} rule + * @param {object} previousOperator */ - this.trigger('afterUpdateRuleOperator', rule); + this.trigger('afterUpdateRuleOperator', rule, previousOperator); + + this.trigger('rulesChanged'); - this.updateRuleValue(rule); + // FIXME is it necessary ? + this.updateRuleValue(rule, ruleValue); }; /** * Performs actions when rule's value changes * @param {Rule} rule + * @param {object} previousValue * @fires QueryBuilder.afterUpdateRuleValue * @private */ -QueryBuilder.prototype.updateRuleValue = function(rule) { +QueryBuilder.prototype.updateRuleValue = function(rule, previousValue) { if (!rule._updating_value) { this.setRuleInputValue(rule, rule.value); } @@ -748,8 +804,11 @@ QueryBuilder.prototype.updateRuleValue = function(rule) { * @event afterUpdateRuleValue * @memberof QueryBuilder * @param {Rule} rule + * @param {*} previousValue */ - this.trigger('afterUpdateRuleValue', rule); + this.trigger('afterUpdateRuleValue', rule, previousValue); + + this.trigger('rulesChanged'); }; /** diff --git a/src/data.js b/src/data.js index 1594f334..8d87848a 100644 --- a/src/data.js +++ b/src/data.js @@ -221,6 +221,29 @@ QueryBuilder.prototype._validateValue = function(rule, value) { } } + if ((rule.operator.type === 'between' || rule.operator.type === 'not_between') && value.length === 2) { + switch (QueryBuilder.types[filter.type]) { + case 'number': + if (value[0] > value[1]) { + result = ['number_between_invalid', value[0], value[1]]; + } + break; + + case 'datetime': + // we need MomentJS + if (validation.format) { + if (!('moment' in window)) { + Utils.error('MissingLibrary', 'MomentJS is required for Date/Time validation. Get it here http://momentjs.com'); + } + + if (moment(value[0], validation.format).isAfter(moment(value[1], validation.format))) { + result = ['datetime_between_invalid', value[0], value[1]]; + } + } + break; + } + } + return result; }; diff --git a/src/i18n/en.json b/src/i18n/en.json index a0e9fd12..41e48539 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -51,10 +51,12 @@ "number_exceed_min": "Must be greater than {0}", "number_exceed_max": "Must be lower than {0}", "number_wrong_step": "Must be a multiple of {0}", + "number_between_invalid": "Invalid values, {0} is greater than {1}", "datetime_empty": "Empty value", "datetime_invalid": "Invalid date format ({0})", "datetime_exceed_min": "Must be after {0}", "datetime_exceed_max": "Must be before {0}", + "datetime_between_invalid": "Invalid values, {0} isgreater than {1}", "boolean_not_valid": "Not a boolean", "operator_not_multiple": "Operator \"{1}\" cannot accept multiple values" } diff --git a/src/i18n/fa-IR.json b/src/i18n/fa-IR.json index 2900248c..55a6e456 100644 --- a/src/i18n/fa-IR.json +++ b/src/i18n/fa-IR.json @@ -22,6 +22,7 @@ "greater": "بزرگتر از", "greater_or_equal": "بزرگتر یا مساوی با", "between": "مابین", + "not_between": "مابین نباشد", "begins_with": "شروع شود با", "not_begins_with": "شروع نشود با", "contains": "شامل شود", @@ -57,4 +58,4 @@ "boolean_not_valid": "مقدار دودویی وارد کنید", "operator_not_multiple": "اپراتور \"{1}\" نمی تواند چند مقدار قبول کند" } -} \ No newline at end of file +} diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 56cbad52..dabacbfe 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -51,10 +51,12 @@ "number_exceed_min": "Doit être plus grand que {0}", "number_exceed_max": "Doit être plus petit que {0}", "number_wrong_step": "Doit être un multiple de {0}", + "number_between_invalid": "Valeurs invalides, {0} est plus grand que {1}", "datetime_empty": "Valeur vide", "datetime_invalid": "Fomat de date invalide ({0})", "datetime_exceed_min": "Doit être après {0}", "datetime_exceed_max": "Doit être avant {0}", + "datetime_between_invalid": "Valeurs invalides, {0} est plus grand que {1}", "boolean_not_valid": "N'est pas un booléen", "operator_not_multiple": "L'opérateur \"{1}\" ne peut utiliser plusieurs valeurs" } diff --git a/src/i18n/it.json b/src/i18n/it.json index 015cf3aa..d16fb50c 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -1,5 +1,6 @@ { "__locale": "Italian (it)", + "__author": "davegraziosi", "add_rule": "Aggiungi regola", "add_group": "Aggiungi gruppo", @@ -20,6 +21,8 @@ "less_or_equal": "minore o uguale", "greater": "maggiore", "greater_or_equal": "maggiore o uguale", + "between" : "compreso tra", + "not_between" : "non compreso tra", "begins_with": "inizia con", "not_begins_with": "non inizia con", "contains": "contiene", @@ -30,5 +33,29 @@ "is_not_empty": "non è vuoto", "is_null": "è nullo", "is_not_null": "non è nullo" + }, + + "errors": { + "no_filter": "Nessun filtro selezionato", + "empty_group": "Il gruppo è vuoto", + "radio_empty": "No value selected", + "checkbox_empty": "Nessun valore selezionato", + "select_empty": "Nessun valore selezionato", + "string_empty": "Valore vuoto", + "string_exceed_min_length": "Deve contenere almeno {0} caratteri", + "string_exceed_max_length": "Non deve contenere più di {0} caratteri", + "string_invalid_format": "Formato non valido ({0})", + "number_nan": "Non è un numero", + "number_not_integer": "Non è un intero", + "number_not_double": "Non è un numero con la virgola", + "number_exceed_min": "Deve essere maggiore di {0}", + "number_exceed_max": "Deve essere minore di {0}", + "number_wrong_step": "Deve essere multiplo di {0}", + "datetime_empty": "Valore vuoto", + "datetime_invalid": "Formato data non valido ({0})", + "datetime_exceed_min": "Deve essere successivo a {0}", + "datetime_exceed_max": "Deve essere precedente a {0}", + "boolean_not_valid": "Non è un booleano", + "operator_not_multiple": "L'Operatore {0} non può accettare valori multipli" } } \ No newline at end of file diff --git a/src/i18n/pl.json b/src/i18n/pl.json index c27069f4..9cddba15 100644 --- a/src/i18n/pl.json +++ b/src/i18n/pl.json @@ -8,8 +8,8 @@ "delete_group": "Usuń", "conditions": { - "AND": "AND", - "OR": "OR" + "AND": "ORAZ", + "OR": "LUB" }, "operators": { diff --git a/src/jquery.js b/src/jquery.js index 62742019..941ea675 100644 --- a/src/jquery.js +++ b/src/jquery.js @@ -30,7 +30,9 @@ $.fn.queryBuilder = function(option) { return this; } if (!data) { - this.data('queryBuilder', new QueryBuilder(this, options)); + var builder = new QueryBuilder(this, options); + this.data('queryBuilder', builder); + builder.init(options.rules); } if (typeof option == 'string') { return data[option].apply(data, Array.prototype.slice.call(arguments, 1)); diff --git a/src/main.js b/src/main.js index 0ebfc940..f799af6f 100644 --- a/src/main.js +++ b/src/main.js @@ -14,7 +14,6 @@ * @param {jQuery} $el * @param {object} options - see {@link http://querybuilder.js.org/#options} * @constructor - * @fires QueryBuilder.afterInit */ var QueryBuilder = function($el, options) { $el[0].queryBuilder = this; @@ -141,21 +140,6 @@ var QueryBuilder = function($el, options) { this.operators = this.checkOperators(this.operators); this.bindEvents(); this.initPlugins(); - - /** - * When the initilization is done, just before creating the root group - * @event afterInit - * @memberof QueryBuilder - */ - this.trigger('afterInit'); - - if (options.rules) { - this.setRules(options.rules); - delete this.settings.rules; - } - else { - this.setRoot(true); - } }; $.extend(QueryBuilder.prototype, /** @lends QueryBuilder.prototype */ { diff --git a/src/plugins/bt-checkbox/plugin.scss b/src/plugins/bt-checkbox/plugin.scss index 9b259265..324f610f 100644 --- a/src/plugins/bt-checkbox/plugin.scss +++ b/src/plugins/bt-checkbox/plugin.scss @@ -1,5 +1,5 @@ .query-builder.bt-checkbox-glyphicons { - .checkbox input[type=checkbox]:checked + label::after { + .checkbox input[type='checkbox']:checked + label::after { font-family: 'Glyphicons Halflings'; content: '\e013'; } diff --git a/src/plugins/change-filters/plugin.js b/src/plugins/change-filters/plugin.js index 823edac1..f44934ab 100644 --- a/src/plugins/change-filters/plugin.js +++ b/src/plugins/change-filters/plugin.js @@ -59,6 +59,8 @@ QueryBuilder.extend(/** @lends module:plugins.ChangeFilters.prototype */ { function(rule) { if (rule.filter && filtersIds.indexOf(rule.filter.id) === -1) { rule.drop(); + + self.trigger('rulesChanged'); } else { self.createRuleFilters(rule); diff --git a/src/plugins/filter-description/plugin.js b/src/plugins/filter-description/plugin.js index 91762b6b..4525cbe0 100644 --- a/src/plugins/filter-description/plugin.js +++ b/src/plugins/filter-description/plugin.js @@ -96,6 +96,9 @@ QueryBuilder.define('filter-description', function(options) { bootbox.alert($b.data('description')); }); } + else { + $b.show(); + } $b.data('description', description); } diff --git a/src/plugins/invert/plugin.js b/src/plugins/invert/plugin.js index 8928d4be..1b1cd686 100644 --- a/src/plugins/invert/plugin.js +++ b/src/plugins/invert/plugin.js @@ -147,6 +147,8 @@ QueryBuilder.extend(/** @lends module:plugins.Invert.prototype */ { * @param {object} options */ this.trigger('afterInvert', node, options); + + this.trigger('rulesChanged'); } } }); diff --git a/src/plugins/mongodb-support/plugin.js b/src/plugins/mongodb-support/plugin.js index 93a17348..a6aebdc3 100644 --- a/src/plugins/mongodb-support/plugin.js +++ b/src/plugins/mongodb-support/plugin.js @@ -105,6 +105,10 @@ QueryBuilder.extend(/** @lends module:plugins.MongoDbSupport.prototype */ { getMongo: function(data) { data = (data === undefined) ? this.getRules() : data; + if (!data) { + return null; + } + var self = this; return (function parse(group) { diff --git a/src/plugins/not-group/plugin.js b/src/plugins/not-group/plugin.js index da6f98b0..8d94b5fc 100644 --- a/src/plugins/not-group/plugin.js +++ b/src/plugins/not-group/plugin.js @@ -128,5 +128,7 @@ QueryBuilder.extend(/** @lends module:plugins.NotGroup.prototype */ { * @param {Group} group */ this.trigger('afterUpdateGroupNot', group); + + this.trigger('rulesChanged'); } }); diff --git a/src/plugins/sortable/plugin.js b/src/plugins/sortable/plugin.js index 83f0b4df..4cf3cf1a 100644 --- a/src/plugins/sortable/plugin.js +++ b/src/plugins/sortable/plugin.js @@ -92,6 +92,8 @@ QueryBuilder.define('sortable', function(options) { * @param {Node} node */ self.trigger('afterMove', src); + + self.trigger('rulesChanged'); } }); } diff --git a/src/plugins/sortable/plugin.scss b/src/plugins/sortable/plugin.scss index cf57c795..ac902fe1 100644 --- a/src/plugins/sortable/plugin.scss +++ b/src/plugins/sortable/plugin.scss @@ -14,7 +14,8 @@ $placeholder-border: 1px dashed $placeholder-border-color; opacity: .5; z-index: 100; - &::before, &::after { + &::before, + &::after { display: none; } } diff --git a/src/plugins/sql-support/plugin.js b/src/plugins/sql-support/plugin.js index 6abc101a..b6751818 100644 --- a/src/plugins/sql-support/plugin.js +++ b/src/plugins/sql-support/plugin.js @@ -248,6 +248,11 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; + + if (!data) { + return null; + } + nl = !!nl ? '\n' : ' '; var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); @@ -596,7 +601,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { */ getSQLFieldID: function(field, value) { var matchingFilters = this.filters.filter(function(filter) { - return filter.field === field; + return filter.field.toLowerCase() === field.toLowerCase(); }); var id; diff --git a/src/public.js b/src/public.js index 610a4adf..d0bbf35a 100644 --- a/src/public.js +++ b/src/public.js @@ -54,6 +54,8 @@ QueryBuilder.prototype.reset = function() { * @memberof QueryBuilder */ this.trigger('afterReset'); + + this.trigger('rulesChanged'); }; /** @@ -86,6 +88,8 @@ QueryBuilder.prototype.clear = function() { * @memberof QueryBuilder */ this.trigger('afterClear'); + + this.trigger('rulesChanged'); }; /** @@ -410,17 +414,22 @@ QueryBuilder.prototype.setRules = function(data, options) { if (!item.empty) { model.filter = self.getFilterById(item.id, !options.allow_invalid); + } - if (model.filter) { - model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); + if (model.filter) { + model.operator = self.getOperatorByType(item.operator, !options.allow_invalid); - if (!model.operator) { - model.operator = self.getOperators(model.filter)[0]; - } + if (!model.operator) { + model.operator = self.getOperators(model.filter)[0]; + } + } - if (model.operator && model.operator.nb_inputs !== 0 && item.value !== undefined) { - model.value = item.value; - } + if (model.operator && model.operator.nb_inputs !== 0) { + if (item.value !== undefined) { + model.value = item.value; + } + else if (model.filter.default_value !== undefined) { + model.value = model.filter.default_value; } } diff --git a/src/scss/default.scss b/src/scss/default.scss index ace2f2fb..b8445fb7 100644 --- a/src/scss/default.scss +++ b/src/scss/default.scss @@ -62,7 +62,7 @@ $ticks-position: 5px, 10px !default; .group-conditions { .btn.readonly:not(.active), - input[name$=_cond] { + input[name$='_cond'] { border: 0; clip: rect(0 0 0 0); height: 1px; @@ -110,7 +110,9 @@ $ticks-position: 5px, 10px !default; } } - select, input[type=text], input[type=number] { + select, + input[type='text'], + input[type='number'] { padding: 1px; } } diff --git a/src/template.js b/src/template.js index b1379f47..40b52ce1 100644 --- a/src/template.js +++ b/src/template.js @@ -163,7 +163,7 @@ QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) { /** * Modifies the raw HTML of the rule's filter dropdown - * @event changer:getRuleFilterTemplate + * @event changer:getRuleFilterSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule @@ -193,7 +193,7 @@ QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) { /** * Modifies the raw HTML of the rule's operator dropdown - * @event changer:getRuleOperatorTemplate + * @event changer:getRuleOperatorSelect * @memberof QueryBuilder * @param {string} html * @param {Rule} rule diff --git a/tests/common.js b/tests/common.js index 91a3ffb5..89550f42 100644 --- a/tests/common.js +++ b/tests/common.js @@ -301,7 +301,8 @@ var basic_filters = [{ label: 'Age', type: 'integer', input: 'text', - value_separator: '|' + value_separator: '|', + default_operator: 'in' }]; var basic_rules = { diff --git a/tests/data.module.js b/tests/data.module.js index 358df511..d7f11838 100644 --- a/tests/data.module.js +++ b/tests/data.module.js @@ -170,6 +170,11 @@ $(function() { /number_wrong_step/ ); + assert.validationError($b, + { id: 'integer', operator: 'between', value: [5, 1] }, + /number_between_invalid/ + ); + assert.validationError($b, { id: 'date' }, /datetime_empty/ @@ -190,6 +195,11 @@ $(function() { /datetime_exceed_max/ ); + assert.validationError($b, + { id: 'date', operator: 'between', value: ['2015/01/01', '2014/01/01'] }, + /datetime_between_invalid/ + ); + assert.validationError($b, { id: 'boolean', value: 'oui' }, /boolean_not_valid/ @@ -411,6 +421,23 @@ $(function() { ); }); + /** + * Test default operator + */ + QUnit.test('default operator', function(assert) { + $b.queryBuilder({ + filters: basic_filters + }); + + $('[name=builder_rule_0_filter]').val('age').trigger('change'); + + assert.equal( + $('[name=builder_rule_0_operator]').val(), + 'in', + 'Should set "age" operator to "in" by default' + ); + }); + /** * Test allow_invalid option */ @@ -490,6 +517,35 @@ $(function() { ); }); + QUnit.test('apply default value', function(assert) { + $b.queryBuilder({ + filters: [ + { + id: 'name', + default_value: 'Mistic' + } + ], + rules: [ + { + id: 'name' + } + ] + }); + + assert.rulesMatch( + $b.queryBuilder('getRules'), + { + condition: 'AND', + rules: [{ + id: 'name', + operator: 'equal', + value: 'Mistic' + }] + }, + 'Should have used the filter default value' + ); + }); + /** * Test allow_empty_value option */