diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index a9007708..7a8c011b 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,4 +3,4 @@ - Please search in the [documentation](http://querybuilder.js.org) before asking. - Any issue without enough details won't get any answer and will be closed. - Help requests must be exhaustive, precise and come with some code explaining the need (use Markdown code highlight). -- Bug reports must come with a simple test case, preferably on jsFiddle, Plunker, etc. (QueryBuilder is available on [jsDelivr](https://www.jsdelivr.com/projects/jquery.query-builder) to be used on such platforms). +- Bug reports must come with a simple test case, preferably on jsFiddle, Plunker, etc. (QueryBuilder is available on [jsDelivr](https://cdn.jsdelivr.net/npm/jQuery-QueryBuilder/dist/) and [unpkg](https://unpkg.com/jQuery-QueryBuilder/dist/) to be used on such platforms). diff --git a/Gruntfile.js b/Gruntfile.js index bdb40cc2..cfb31c00 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -22,8 +22,8 @@ module.exports = function(grunt) { 'src/public.js', 'src/data.js', 'src/template.js', - 'src/model.js', 'src/utils.js', + 'src/model.js', 'src/jquery.js' ], js_files_for_standalone: [ diff --git a/LICENSE b/LICENSE index 99070e3d..50b5d4bd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014-2015 Damien Sorel +Copyright (c) 2014-2017 Damien Sorel Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.md b/README.md index e48cf2e2..1fe97bb1 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ $ bower install jQuery-QueryBuilder $ 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/)) + ### Dependencies * jQuery >= 1.10 * Bootstrap >= 3.1 (CSS only) diff --git a/dist/css/query-builder.dark.css b/dist/css/query-builder.dark.css index 95788a54..06d28fc8 100644 --- a/dist/css/query-builder.dark.css +++ b/dist/css/query-builder.dark.css @@ -1,150 +1,150 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -.query-builder .rules-group-container, .query-builder .rule-container, .query-builder .rule-placeholder { - position: relative; - margin: 4px 0; - border-radius: 5px; - padding: 5px; - border: 1px solid #111; - background: rgba(40, 40, 40, 0.9); -} - -.query-builder .rule-container .rule-filter-container, -.query-builder .rule-container .rule-operator-container, -.query-builder .rule-container .rule-value-container, .query-builder .error-container, .query-builder .drag-handle { - display: inline-block; - margin: 0 5px 0 0; - vertical-align: middle; -} - -.query-builder .rules-group-container { - padding: 10px; - padding-bottom: 6px; - 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] { - 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: 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] { - 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; - 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 .rules-list > *:last-child::after { - display: none; -} - -.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 0; - background: rgba(0, 170, 255, 0.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 .dragging::before, .query-builder .dragging::after { - display: none; -} -.query-builder .rule-placeholder { - border: 1px dashed #BBB; - opacity: .7; -} +.query-builder .rules-group-container, .query-builder .rule-container, .query-builder .rule-placeholder { + position: relative; + margin: 4px 0; + border-radius: 5px; + padding: 5px; + border: 1px solid #111; + background: rgba(40, 40, 40, 0.9); +} + +.query-builder .rule-container .rule-filter-container, +.query-builder .rule-container .rule-operator-container, +.query-builder .rule-container .rule-value-container, .query-builder .error-container, .query-builder .drag-handle { + display: inline-block; + margin: 0 5px 0 0; + vertical-align: middle; +} + +.query-builder .rules-group-container { + padding: 10px; + padding-bottom: 6px; + 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] { + 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: 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] { + 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; + 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 .rules-list > *:last-child::after { + display: none; +} + +.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 0; + background: rgba(0, 170, 255, 0.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 .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 a2231859..6b2ff809 100644 --- a/dist/css/query-builder.dark.min.css +++ b/dist/css/query-builder.dark.min.css @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/dist/css/query-builder.default.css b/dist/css/query-builder.default.css index c1f4eca0..80fcbf42 100644 --- a/dist/css/query-builder.default.css +++ b/dist/css/query-builder.default.css @@ -1,150 +1,150 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ -.query-builder .rules-group-container, .query-builder .rule-container, .query-builder .rule-placeholder { - position: relative; - margin: 4px 0; - border-radius: 5px; - padding: 5px; - border: 1px solid #EEE; - background: rgba(255, 255, 255, 0.9); -} - -.query-builder .rule-container .rule-filter-container, -.query-builder .rule-container .rule-operator-container, -.query-builder .rule-container .rule-value-container, .query-builder .error-container, .query-builder .drag-handle { - display: inline-block; - margin: 0 5px 0 0; - vertical-align: middle; -} - -.query-builder .rules-group-container { - padding: 10px; - padding-bottom: 6px; - 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] { - 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: 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] { - 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; - 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 .rules-list > *:last-child::after { - display: none; -} - -.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 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 .dragging::before, .query-builder .dragging::after { - display: none; -} -.query-builder .rule-placeholder { - border: 1px dashed #BBB; - opacity: .7; -} +.query-builder .rules-group-container, .query-builder .rule-container, .query-builder .rule-placeholder { + position: relative; + margin: 4px 0; + border-radius: 5px; + padding: 5px; + border: 1px solid #EEE; + background: rgba(255, 255, 255, 0.9); +} + +.query-builder .rule-container .rule-filter-container, +.query-builder .rule-container .rule-operator-container, +.query-builder .rule-container .rule-value-container, .query-builder .error-container, .query-builder .drag-handle { + display: inline-block; + margin: 0 5px 0 0; + vertical-align: middle; +} + +.query-builder .rules-group-container { + padding: 10px; + padding-bottom: 6px; + 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] { + 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: 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] { + 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; + 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 .rules-list > *:last-child::after { + display: none; +} + +.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 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 .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 32c53dfd..049380f5 100644 --- a/dist/css/query-builder.default.min.css +++ b/dist/css/query-builder.default.min.css @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/dist/i18n/query-builder.ar.js b/dist/i18n/query-builder.ar.js index 35a17348..892c1dcf 100644 --- a/dist/i18n/query-builder.ar.js +++ b/dist/i18n/query-builder.ar.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 072d2c5a..75d7cbc3 100644 --- a/dist/i18n/query-builder.az.js +++ b/dist/i18n/query-builder.az.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 6d0c8a3f..fa673f1b 100644 --- a/dist/i18n/query-builder.bg.js +++ b/dist/i18n/query-builder.bg.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 4640fe2c..0c9dc581 100644 --- a/dist/i18n/query-builder.cs.js +++ b/dist/i18n/query-builder.cs.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 d11318cb..ca2a023b 100644 --- a/dist/i18n/query-builder.da.js +++ b/dist/i18n/query-builder.da.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 d20e9fc2..6e05a5d2 100644 --- a/dist/i18n/query-builder.de.js +++ b/dist/i18n/query-builder.de.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 930dd5cf..958dd9b4 100644 --- a/dist/i18n/query-builder.el.js +++ b/dist/i18n/query-builder.el.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 663c78e2..b985bc8f 100644 --- a/dist/i18n/query-builder.en.js +++ b/dist/i18n/query-builder.en.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.es.js b/dist/i18n/query-builder.es.js index 63ca44bb..a6094daf 100644 --- a/dist/i18n/query-builder.es.js +++ b/dist/i18n/query-builder.es.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 5b5b888b..9e84e415 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.3 + * jQuery QueryBuilder 2.4.4 * Locale: Farsi (fa-ir) * Author: Behzad Sedighzade, behzad.sedighzade@gmail.com * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.fr.js b/dist/i18n/query-builder.fr.js index 4601dc7d..7f478e67 100644 --- a/dist/i18n/query-builder.fr.js +++ b/dist/i18n/query-builder.fr.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: French (fr) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.he.js b/dist/i18n/query-builder.he.js index 0ad045d8..cbd91635 100644 --- a/dist/i18n/query-builder.he.js +++ b/dist/i18n/query-builder.he.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 83e31cc6..7bbf9658 100644 --- a/dist/i18n/query-builder.it.js +++ b/dist/i18n/query-builder.it.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: Italian (it) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/dist/i18n/query-builder.nl.js b/dist/i18n/query-builder.nl.js index 78015018..96692687 100644 --- a/dist/i18n/query-builder.nl.js +++ b/dist/i18n/query-builder.nl.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 db06ab29..5a7d5285 100644 --- a/dist/i18n/query-builder.no.js +++ b/dist/i18n/query-builder.no.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 39e028c8..df3c25f4 100644 --- a/dist/i18n/query-builder.pl.js +++ b/dist/i18n/query-builder.pl.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: Polish (pl) * Author: Artur Smolarek * Licensed under MIT (http://opensource.org/licenses/MIT) diff --git a/dist/i18n/query-builder.pt-BR.js b/dist/i18n/query-builder.pt-BR.js index 27d78403..2c286409 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.3 + * jQuery QueryBuilder 2.4.4 * 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 6534da8f..616478a5 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.3 + * jQuery QueryBuilder 2.4.4 * 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 e789f5f5..2e6aadb0 100644 --- a/dist/i18n/query-builder.ro.js +++ b/dist/i18n/query-builder.ro.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 cbf892fd..7cc02101 100644 --- a/dist/i18n/query-builder.ru.js +++ b/dist/i18n/query-builder.ru.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 9a9e71ad..533b873b 100644 --- a/dist/i18n/query-builder.sq.js +++ b/dist/i18n/query-builder.sq.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 7c9ba730..fc069087 100644 --- a/dist/i18n/query-builder.tr.js +++ b/dist/i18n/query-builder.tr.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 63c85531..731dda80 100644 --- a/dist/i18n/query-builder.ua.js +++ b/dist/i18n/query-builder.ua.js @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 374c7d92..c85a82e4 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.3 + * jQuery QueryBuilder 2.4.4 * 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 6c7e77ea..2257bd53 100644 --- a/dist/js/query-builder.js +++ b/dist/js/query-builder.js @@ -1,11 +1,14 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ (function(root, factory) { if (typeof define == 'function' && define.amd) { - define(['jquery', 'doT', 'jQuery.extendext'], factory); + define(['jquery', 'dot/doT', 'jquery-extendext'], factory); + } + else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('jquery'), require('dot/doT'), require('jquery-extendext')); } else { factory(root.jQuery, root.doT); @@ -504,7 +507,6 @@ QueryBuilder.extend = function(methods) { $.extend(QueryBuilder.prototype, methods); }; - /** * Initializes plugins for an instance * @throws ConfigError @@ -538,6 +540,36 @@ QueryBuilder.prototype.initPlugins = function() { }, this); }; +/** + * Returns the config of a plugin, if the plugin is not loaded, returns the default config. + * @param {string} name + * @param {string} [property] + * @throws ConfigError + * @returns {*} + */ +QueryBuilder.prototype.getPluginOptions = function(name, property) { + var plugin; + if (this.plugins && this.plugins[name]) { + plugin = this.plugins[name]; + } + else if (QueryBuilder.plugins[name]) { + plugin = QueryBuilder.plugins[name].def; + } + + if (plugin) { + if (property) { + return plugin[property]; + } + else { + return plugin; + } + } + else { + Utils.error('Config', 'Unable to find plugin "{0}"', name); + } +}; + + /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters @@ -2830,6 +2862,250 @@ QueryBuilder.prototype.getRuleInput = function(rule, value_id) { }; +/** + * @namespace + */ +var Utils = {}; + +/** + * @member {object} + * @memberof QueryBuilder + * @see Utils + */ +QueryBuilder.utils = Utils; + +/** + * @callback Utils#OptionsIteratee + * @param {string} key + * @param {string} value + */ + +/** + * Iterates over radio/checkbox/selection options, it accept three formats + * + * @example + * // array of values + * options = ['one', 'two', 'three'] + * @example + * // simple key-value map + * options = {1: 'one', 2: 'two', 3: 'three'} + * @example + * // array of 1-element maps + * options = [{1: 'one'}, {2: 'two'}, {3: 'three'}] + * + * @param {object|array} options + * @param {Utils#OptionsIteratee} tpl + */ +Utils.iterateOptions = function(options, tpl) { + if (options) { + if ($.isArray(options)) { + options.forEach(function(entry) { + // array of one-element maps + if ($.isPlainObject(entry)) { + $.each(entry, function(key, val) { + tpl(key, val); + return false; // break after first entry + }); + } + // array of values + else { + tpl(entry, entry); + } + }); + } + // unordered map + else { + $.each(options, function(key, val) { + tpl(key, val); + }); + } + } +}; + +/** + * Replaces {0}, {1}, ... in a string + * @param {string} str + * @param {...*} args + * @returns {string} + */ +Utils.fmt = function(str, args) { + if (!Array.isArray(args)) { + args = Array.prototype.slice.call(arguments, 1); + } + + return str.replace(/{([0-9]+)}/g, function(m, i) { + return args[parseInt(i)]; + }); +}; + +/** + * Throws an Error object with custom name or logs an error + * @param {boolean} [doThrow=true] + * @param {string} type + * @param {string} message + * @param {...*} args + */ +Utils.error = function() { + var i = 0; + var doThrow = typeof arguments[i] === 'boolean' ? arguments[i++] : true; + var type = arguments[i++]; + var message = arguments[i++]; + var args = Array.isArray(arguments[i]) ? arguments[i] : Array.prototype.slice.call(arguments, i); + + if (doThrow) { + var err = new Error(Utils.fmt(message, args)); + err.name = type + 'Error'; + err.args = args; + throw err; + } + else { + console.error(type + 'Error: ' + Utils.fmt(message, args)); + } +}; + +/** + * Changes the type of a value to int, float or bool + * @param {*} value + * @param {string} type - 'integer', 'double', 'boolean' or anything else (passthrough) + * @param {boolean} [boolAsInt=false] - return 0 or 1 for booleans + * @returns {*} + */ +Utils.changeType = function(value, type, boolAsInt) { + switch (type) { + // @formatter:off + case 'integer': return parseInt(value); + case 'double': return parseFloat(value); + case 'boolean': + var bool = value.trim().toLowerCase() === 'true' || value.trim() === '1' || value === 1; + return boolAsInt ? (bool ? 1 : 0) : bool; + default: return value; + // @formatter:on + } +}; + +/** + * Escapes a string like PHP's mysql_real_escape_string does + * @param {string} value + * @returns {string} + */ +Utils.escapeString = function(value) { + if (typeof value != 'string') { + return value; + } + + return value + .replace(/[\0\n\r\b\\\'\"]/g, function(s) { + switch (s) { + // @formatter:off + case '\0': return '\\0'; + case '\n': return '\\n'; + case '\r': return '\\r'; + case '\b': return '\\b'; + default: return '\\' + s; + // @formatter:off + } + }) + // uglify compliant + .replace(/\t/g, '\\t') + .replace(/\x1a/g, '\\Z'); +}; + +/** + * Escapes a string for use in regex + * @param {string} str + * @returns {string} + */ +Utils.escapeRegExp = function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); +}; + +/** + * Escapes a string for use in HTML element id + * @param {string} str + * @returns {string} + */ +Utils.escapeElementId = function(str) { + // Regex based on that suggested by: + // https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/ + // - escapes : . [ ] , + // - avoids escaping already escaped values + return (str) ? str.replace(/(\\)?([:.\[\],])/g, + function( $0, $1, $2 ) { return $1 ? $0 : '\\' + $2; }) : str; +}; + +/** + * Sorts objects by grouping them by `key`, preserving initial order when possible + * @param {object[]} items + * @param {string} key + * @returns {object[]} + */ +Utils.groupSort = function(items, key) { + var optgroups = []; + var newItems = []; + + items.forEach(function(item) { + var idx; + + if (item[key]) { + idx = optgroups.lastIndexOf(item[key]); + + if (idx == -1) { + idx = optgroups.length; + } + else { + idx++; + } + } + else { + idx = optgroups.length; + } + + optgroups.splice(idx, 0, item[key]); + newItems.splice(idx, 0, item); + }); + + return newItems; +}; + +/** + * Defines properties on an Node prototype with getter and setter.
+ * Update events are emitted in the setter through root Model (if any).
+ * The object must have a `__` object, non enumerable property to store values. + * @param {function} obj + * @param {string[]} fields + */ +Utils.defineModelProperties = function(obj, fields) { + fields.forEach(function(field) { + Object.defineProperty(obj.prototype, field, { + enumerable: true, + get: function() { + return this.__[field]; + }, + set: function(value) { + var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? + $.extend({}, this.__[field]) : + this.__[field]; + + this.__[field] = value; + + if (this.model !== null) { + /** + * After a value of the model changed + * @event model:update + * @memberof Model + * @param {Node} node + * @param {string} field + * @param {*} value + * @param {*} previousValue + */ + this.model.trigger('update', this, field, value, previousValue); + } + } + }); + }); +}; + + /** * Main object storing data model and emitting model events * @constructor @@ -2896,44 +3172,6 @@ $.extend(Model.prototype, /** @lends Model.prototype */ { } }); -/** - * Defines properties on an Node prototype with getter and setter.
- * Update events are emitted in the setter through root Model (if any).
- * The object must have a `__` object, non enumerable property to store values. - * @param {function} obj - * @param {string[]} fields - */ -Model.defineModelProperties = function(obj, fields) { - fields.forEach(function(field) { - Object.defineProperty(obj.prototype, field, { - enumerable: true, - get: function() { - return this.__[field]; - }, - set: function(value) { - var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? - $.extend({}, this.__[field]) : - this.__[field]; - - this.__[field] = value; - - if (this.model !== null) { - /** - * After a value of the model changed - * @event model:update - * @memberof Model - * @param {Node} node - * @param {string} field - * @param {*} value - * @param {*} previousValue - */ - this.model.trigger('update', this, field, value, previousValue); - } - } - }); - }); -}; - /** * Root abstract object @@ -3009,7 +3247,7 @@ var Node = function(parent, $el) { this.parent = parent; }; -Model.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); +Utils.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); Object.defineProperty(Node.prototype, 'parent', { enumerable: true, @@ -3172,7 +3410,7 @@ var Group = function(parent, $el) { Group.prototype = Object.create(Node.prototype); Group.prototype.constructor = Group; -Model.defineModelProperties(Group, ['condition']); +Utils.defineModelProperties(Group, ['condition']); /** * Removes group's content @@ -3393,7 +3631,7 @@ var Rule = function(parent, $el) { Rule.prototype = Object.create(Node.prototype); Rule.prototype.constructor = Rule; -Model.defineModelProperties(Rule, ['filter', 'operator', 'value']); +Utils.defineModelProperties(Rule, ['filter', 'operator', 'value']); /** * Checks if this Node is the root @@ -3419,212 +3657,6 @@ QueryBuilder.Group = Group; QueryBuilder.Rule = Rule; -/** - * @namespace - */ -var Utils = {}; - -/** - * @member {object} - * @memberof QueryBuilder - * @see Utils - */ -QueryBuilder.utils = Utils; - -/** - * @callback Utils#OptionsIteratee - * @param {string} key - * @param {string} value - */ - -/** - * Iterates over radio/checkbox/selection options, it accept three formats - * - * @example - * // array of values - * options = ['one', 'two', 'three'] - * @example - * // simple key-value map - * options = {1: 'one', 2: 'two', 3: 'three'} - * @example - * // array of 1-element maps - * options = [{1: 'one'}, {2: 'two'}, {3: 'three'}] - * - * @param {object|array} options - * @param {Utils#OptionsIteratee} tpl - */ -Utils.iterateOptions = function(options, tpl) { - if (options) { - if ($.isArray(options)) { - options.forEach(function(entry) { - // array of one-element maps - if ($.isPlainObject(entry)) { - $.each(entry, function(key, val) { - tpl(key, val); - return false; // break after first entry - }); - } - // array of values - else { - tpl(entry, entry); - } - }); - } - // unordered map - else { - $.each(options, function(key, val) { - tpl(key, val); - }); - } - } -}; - -/** - * Replaces {0}, {1}, ... in a string - * @param {string} str - * @param {...*} args - * @returns {string} - */ -Utils.fmt = function(str, args) { - if (!Array.isArray(args)) { - args = Array.prototype.slice.call(arguments, 1); - } - - return str.replace(/{([0-9]+)}/g, function(m, i) { - return args[parseInt(i)]; - }); -}; - -/** - * Throws an Error object with custom name or logs an error - * @param {boolean} [doThrow=true] - * @param {string} type - * @param {string} message - * @param {...*} args - */ -Utils.error = function() { - var i = 0; - var doThrow = typeof arguments[i] === 'boolean' ? arguments[i++] : true; - var type = arguments[i++]; - var message = arguments[i++]; - var args = Array.isArray(arguments[i]) ? arguments[i] : Array.prototype.slice.call(arguments, i); - - if (doThrow) { - var err = new Error(Utils.fmt(message, args)); - err.name = type + 'Error'; - err.args = args; - throw err; - } - else { - console.error(type + 'Error: ' + Utils.fmt(message, args)); - } -}; - -/** - * Changes the type of a value to int, float or bool - * @param {*} value - * @param {string} type - 'integer', 'double', 'boolean' or anything else (passthrough) - * @param {boolean} [boolAsInt=false] - return 0 or 1 for booleans - * @returns {*} - */ -Utils.changeType = function(value, type, boolAsInt) { - switch (type) { - // @formatter:off - case 'integer': return parseInt(value); - case 'double': return parseFloat(value); - case 'boolean': - var bool = value.trim().toLowerCase() === 'true' || value.trim() === '1' || value === 1; - return boolAsInt ? (bool ? 1 : 0) : bool; - default: return value; - // @formatter:on - } -}; - -/** - * Escapes a string like PHP's mysql_real_escape_string does - * @param {string} value - * @returns {string} - */ -Utils.escapeString = function(value) { - if (typeof value != 'string') { - return value; - } - - return value - .replace(/[\0\n\r\b\\\'\"]/g, function(s) { - switch (s) { - // @formatter:off - case '\0': return '\\0'; - case '\n': return '\\n'; - case '\r': return '\\r'; - case '\b': return '\\b'; - default: return '\\' + s; - // @formatter:off - } - }) - // uglify compliant - .replace(/\t/g, '\\t') - .replace(/\x1a/g, '\\Z'); -}; - -/** - * Escapes a string for use in regex - * @param {string} str - * @returns {string} - */ -Utils.escapeRegExp = function(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); -}; - -/** - * Escapes a string for use in HTML element id - * @param {string} str - * @returns {string} - */ -Utils.escapeElementId = function(str) { - // Regex based on that suggested by: - // https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/ - // - escapes : . [ ] , - // - avoids escaping already escaped values - return (str) ? str.replace(/(\\)?([:.\[\],])/g, - function( $0, $1, $2 ) { return $1 ? $0 : '\\' + $2; }) : str; -}; - -/** - * Sorts objects by grouping them by `key`, preserving initial order when possible - * @param {object[]} items - * @param {string} key - * @returns {object[]} - */ -Utils.groupSort = function(items, key) { - var optgroups = []; - var newItems = []; - - items.forEach(function(item) { - var idx; - - if (item[key]) { - idx = optgroups.lastIndexOf(item[key]); - - if (idx == -1) { - idx = optgroups.length; - } - else { - idx++; - } - } - else { - idx = optgroups.length; - } - - optgroups.splice(idx, 0, item[key]); - newItems.splice(idx, 0, item); - }); - - return newItems; -}; - - /** * The {@link http://learn.jquery.com/plugins/|jQuery Plugins} namespace * @external "jQuery.fn" @@ -4798,7 +4830,7 @@ QueryBuilder.define('not-group', function(options) { * @memberof Group * @instance */ -Model.defineModelProperties(Group, ['not']); +Utils.defineModelProperties(Group, ['not']); QueryBuilder.selectors.group_not = QueryBuilder.selectors.group_header + ' [data-not=group]'; @@ -5055,7 +5087,14 @@ function moveSortableToTarget(node, target, builder) { * @class SqlSupport * @memberof module:plugins * @description Allows to export rules as a SQL WHERE statement as well as populating the builder from an SQL query. + * @param {object} [options] + * @param {boolean} [options.boolean_as_integer=true] - `true` to convert boolean values to integer in the SQL output */ +QueryBuilder.define('sql-support', function(options) { + +}, { + boolean_as_integer: true +}); QueryBuilder.defaults({ // operators for internal -> SQL conversion @@ -5295,6 +5334,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; nl = !!nl ? '\n' : ' '; + var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); if (stmt === true) stmt = 'question_mark'; if (typeof stmt == 'string') { @@ -5342,7 +5382,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { } if (rule.type == 'integer' || rule.type == 'double' || rule.type == 'boolean') { - v = Utils.changeType(v, rule.type, true); + v = Utils.changeType(v, rule.type, boolean_as_integer); } else if (!stmt) { v = Utils.escapeString(v); @@ -5795,7 +5835,7 @@ QueryBuilder.extend(/** @lends module:plugins.UniqueFilter.prototype */ { /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -5862,4 +5902,6 @@ QueryBuilder.regional['en'] = { }; QueryBuilder.defaults({ lang_code: 'en' }); -})); \ No newline at end of file +return QueryBuilder; + +})); diff --git a/dist/js/query-builder.min.js b/dist/js/query-builder.min.js index f8131eb0..e512bd0f 100644 --- a/dist/js/query-builder.min.js +++ b/dist/js/query-builder.min.js @@ -1,8 +1,8 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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","jQuery.extendext"],b):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;c.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])):k.error("Config",'Unable to find plugin "{0}"',a)},this)}},g.prototype.checkFilters=function(a){var b=[];if(a&&0!==a.length||k.error("Config","Missing filters list"),a.forEach(function(a,c){switch(a.id||k.error("Config","Missing filter {0} id",c),b.indexOf(a.id)!=-1&&k.error("Config",'Filter "{0}" already defined',a.id),b.push(a.id),a.type?g.types[a.type]||k.error("Config",'Invalid type "{0}"',a.type):a.type="string",a.input?"function"!=typeof a.input&&g.inputs.indexOf(a.input)==-1&&k.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&&k.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)&&k.error("Config",'Missing filter "{0}" values',a.id);break;case"select":a.placeholder&&(void 0===a.placeholder_value&&(a.placeholder_value=-1),k.iterateOptions(a.values,function(b){b==a.placeholder_value&&k.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=k.groupSort(a,"optgroup")),a},g.prototype.checkOperators=function(a){var b=[];return a.forEach(function(c,d){"string"==typeof c?(g.OPERATORS[c]||k.error("Config",'Unknown operator "{0}"',c),a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c])):(c.type||k.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||k.error("Config",'Missing "nb_inputs" and/or "apply_to" for operator "{0}"',c.type)),b.indexOf(c.type)!=-1&&k.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=k.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 j)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 i(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()&&(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 i&&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=k.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){g.modifiable_options.indexOf(a)!==-1&&(this.settings[a]=b)}.bind(this))},g.prototype.getModel=function(a){return a?a instanceof h?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)&&(0===e&&!c.isRoot()&&a.skip_empty?null:!!(0!==e||b.settings.allow_empty&&c.isRoot())||(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)||k.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:c.settings.conditions.indexOf(a.condition)==-1&&(k.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(c.settings.allow_groups!==-1&&c.settings.allow_groups1){i=["operator_not_multiple",f.type,this.translate("operators",f.type)];break}switch(e.input){case"radio":if(void 0===b[j]||0===b[j].length){h.allow_empty_value||(i=["radio_empty"]);break}break;case"checkbox":if(void 0===b[j]||0===b[j].length){h.allow_empty_value||(i=["checkbox_empty"]);break}break;case"select":if(void 0===b[j]||0===b[j].length||e.placeholder&&b[j]==e.placeholder_value){h.allow_empty_value||(i=["select_empty"]);break}break;default:d=$.isArray(b[j])?b[j]:[b[j]];for(var l=0;lparseInt(h.max)){i=[this.getValidationMessage(h,"max","string_exceed_max_length"),h.max];break}if(h.format&&("string"==typeof h.format&&(h.format=new RegExp(h.format)),!h.format.test(d[l]))){i=[this.getValidationMessage(h,"format","string_invalid_format"),h.format];break}break;case"number":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["number_nan"]);break}if(isNaN(d[l])){i=["number_nan"];break}if("integer"==e.type){if(parseInt(d[l])!=d[l]){i=["number_not_integer"];break}}else if(parseFloat(d[l])!=d[l]){i=["number_not_double"];break}if(void 0!==h.min&&d[l]parseFloat(h.max)){i=[this.getValidationMessage(h,"max","number_exceed_max"),h.max];break}if(void 0!==h.step&&"any"!==h.step){var m=(d[l]/h.step).toPrecision(14);if(parseInt(m)!=m){i=[this.getValidationMessage(h,"step","number_wrong_step"),h.step];break}}break;case"datetime":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["datetime_empty"]);break}if(h.format){"moment"in window||k.error("MissingLibrary","MomentJS is required for Date/Time validation. Get it here http://momentjs.com");var n=moment(d[l],h.format);if(!n.isValid()){i=[this.getValidationMessage(h,"format","datetime_invalid"),h.format];break}if(h.min&&nmoment(h.max,h.format)){i=[this.getValidationMessage(h,"max","datetime_exceed_max"),h.max];break}}break;case"boolean":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["boolean_not_valid"]);break}if(c=(""+d[l]).trim().toLowerCase(),"true"!==c&&"false"!==c&&"1"!==c&&"0"!==c&&1!==d[l]&&0!==d[l]){i=["boolean_not_valid"];break}}if(i!==!0)break}}if(i!==!0)break}return i},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;c '+b+" "});break;case"select":g+='";break;case"textarea":g+='";break;case"number":g+='=f:f>=e},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-1!==this.getNodePos(a)?!0:b?!this.each(function(){return!0},function(b){return!b.contains(a,!0)}):!1};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||{};return b||"destroy"!=a?(b||this.data("queryBuilder",new g(this,c)),"string"==typeof a?b[a].apply(b,Array.prototype.slice.call(arguments,1)):this):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&&-1===d.indexOf(a.filter.id)&&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&&-1===d.indexOf(a.filter.id)?a.drop():(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){return a.id==b?(b=c+1,!0):void 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-1===a.indexOf(b.id)}),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.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&&-1==a.filter.operators.indexOf(d)||(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)}}),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)}}),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)}}),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){c=void 0===c?this.getRules():c,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),-1===["AND","OR"].indexOf(c.condition.toUpperCase())&&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"),-1!==["AND","OR"].indexOf(a.operation.toUpperCase())){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===a});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){return!(d.id in c.status.used_filters)||c.status.used_filters[d.id].length>0&&-1===c.status.used_filters[d.id].indexOf(b.parent)?(a.value=d,!0):void 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}",datetime_empty:"Empty value",datetime_invalid:"Invalid date format ({0})",datetime_exceed_min:"Must be after {0}",datetime_exceed_max:"Must be before {0}",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 b762ba62..a411d8aa 100644 --- a/dist/js/query-builder.standalone.js +++ b/dist/js/query-builder.standalone.js @@ -273,13 +273,16 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ (function(root, factory) { if (typeof define == 'function' && define.amd) { - define('query-builder', ['jquery', 'doT', 'jQuery.extendext'], factory); + define('query-builder', ['jquery', 'dot/doT', 'jquery-extendext'], factory); + } + else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('jquery'), require('dot/doT'), require('jquery-extendext')); } else { factory(root.jQuery, root.doT); @@ -778,7 +781,6 @@ QueryBuilder.extend = function(methods) { $.extend(QueryBuilder.prototype, methods); }; - /** * Initializes plugins for an instance * @throws ConfigError @@ -812,6 +814,36 @@ QueryBuilder.prototype.initPlugins = function() { }, this); }; +/** + * Returns the config of a plugin, if the plugin is not loaded, returns the default config. + * @param {string} name + * @param {string} [property] + * @throws ConfigError + * @returns {*} + */ +QueryBuilder.prototype.getPluginOptions = function(name, property) { + var plugin; + if (this.plugins && this.plugins[name]) { + plugin = this.plugins[name]; + } + else if (QueryBuilder.plugins[name]) { + plugin = QueryBuilder.plugins[name].def; + } + + if (plugin) { + if (property) { + return plugin[property]; + } + else { + return plugin; + } + } + else { + Utils.error('Config', 'Unable to find plugin "{0}"', name); + } +}; + + /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters @@ -3104,6 +3136,250 @@ QueryBuilder.prototype.getRuleInput = function(rule, value_id) { }; +/** + * @namespace + */ +var Utils = {}; + +/** + * @member {object} + * @memberof QueryBuilder + * @see Utils + */ +QueryBuilder.utils = Utils; + +/** + * @callback Utils#OptionsIteratee + * @param {string} key + * @param {string} value + */ + +/** + * Iterates over radio/checkbox/selection options, it accept three formats + * + * @example + * // array of values + * options = ['one', 'two', 'three'] + * @example + * // simple key-value map + * options = {1: 'one', 2: 'two', 3: 'three'} + * @example + * // array of 1-element maps + * options = [{1: 'one'}, {2: 'two'}, {3: 'three'}] + * + * @param {object|array} options + * @param {Utils#OptionsIteratee} tpl + */ +Utils.iterateOptions = function(options, tpl) { + if (options) { + if ($.isArray(options)) { + options.forEach(function(entry) { + // array of one-element maps + if ($.isPlainObject(entry)) { + $.each(entry, function(key, val) { + tpl(key, val); + return false; // break after first entry + }); + } + // array of values + else { + tpl(entry, entry); + } + }); + } + // unordered map + else { + $.each(options, function(key, val) { + tpl(key, val); + }); + } + } +}; + +/** + * Replaces {0}, {1}, ... in a string + * @param {string} str + * @param {...*} args + * @returns {string} + */ +Utils.fmt = function(str, args) { + if (!Array.isArray(args)) { + args = Array.prototype.slice.call(arguments, 1); + } + + return str.replace(/{([0-9]+)}/g, function(m, i) { + return args[parseInt(i)]; + }); +}; + +/** + * Throws an Error object with custom name or logs an error + * @param {boolean} [doThrow=true] + * @param {string} type + * @param {string} message + * @param {...*} args + */ +Utils.error = function() { + var i = 0; + var doThrow = typeof arguments[i] === 'boolean' ? arguments[i++] : true; + var type = arguments[i++]; + var message = arguments[i++]; + var args = Array.isArray(arguments[i]) ? arguments[i] : Array.prototype.slice.call(arguments, i); + + if (doThrow) { + var err = new Error(Utils.fmt(message, args)); + err.name = type + 'Error'; + err.args = args; + throw err; + } + else { + console.error(type + 'Error: ' + Utils.fmt(message, args)); + } +}; + +/** + * Changes the type of a value to int, float or bool + * @param {*} value + * @param {string} type - 'integer', 'double', 'boolean' or anything else (passthrough) + * @param {boolean} [boolAsInt=false] - return 0 or 1 for booleans + * @returns {*} + */ +Utils.changeType = function(value, type, boolAsInt) { + switch (type) { + // @formatter:off + case 'integer': return parseInt(value); + case 'double': return parseFloat(value); + case 'boolean': + var bool = value.trim().toLowerCase() === 'true' || value.trim() === '1' || value === 1; + return boolAsInt ? (bool ? 1 : 0) : bool; + default: return value; + // @formatter:on + } +}; + +/** + * Escapes a string like PHP's mysql_real_escape_string does + * @param {string} value + * @returns {string} + */ +Utils.escapeString = function(value) { + if (typeof value != 'string') { + return value; + } + + return value + .replace(/[\0\n\r\b\\\'\"]/g, function(s) { + switch (s) { + // @formatter:off + case '\0': return '\\0'; + case '\n': return '\\n'; + case '\r': return '\\r'; + case '\b': return '\\b'; + default: return '\\' + s; + // @formatter:off + } + }) + // uglify compliant + .replace(/\t/g, '\\t') + .replace(/\x1a/g, '\\Z'); +}; + +/** + * Escapes a string for use in regex + * @param {string} str + * @returns {string} + */ +Utils.escapeRegExp = function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); +}; + +/** + * Escapes a string for use in HTML element id + * @param {string} str + * @returns {string} + */ +Utils.escapeElementId = function(str) { + // Regex based on that suggested by: + // https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/ + // - escapes : . [ ] , + // - avoids escaping already escaped values + return (str) ? str.replace(/(\\)?([:.\[\],])/g, + function( $0, $1, $2 ) { return $1 ? $0 : '\\' + $2; }) : str; +}; + +/** + * Sorts objects by grouping them by `key`, preserving initial order when possible + * @param {object[]} items + * @param {string} key + * @returns {object[]} + */ +Utils.groupSort = function(items, key) { + var optgroups = []; + var newItems = []; + + items.forEach(function(item) { + var idx; + + if (item[key]) { + idx = optgroups.lastIndexOf(item[key]); + + if (idx == -1) { + idx = optgroups.length; + } + else { + idx++; + } + } + else { + idx = optgroups.length; + } + + optgroups.splice(idx, 0, item[key]); + newItems.splice(idx, 0, item); + }); + + return newItems; +}; + +/** + * Defines properties on an Node prototype with getter and setter.
+ * Update events are emitted in the setter through root Model (if any).
+ * The object must have a `__` object, non enumerable property to store values. + * @param {function} obj + * @param {string[]} fields + */ +Utils.defineModelProperties = function(obj, fields) { + fields.forEach(function(field) { + Object.defineProperty(obj.prototype, field, { + enumerable: true, + get: function() { + return this.__[field]; + }, + set: function(value) { + var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? + $.extend({}, this.__[field]) : + this.__[field]; + + this.__[field] = value; + + if (this.model !== null) { + /** + * After a value of the model changed + * @event model:update + * @memberof Model + * @param {Node} node + * @param {string} field + * @param {*} value + * @param {*} previousValue + */ + this.model.trigger('update', this, field, value, previousValue); + } + } + }); + }); +}; + + /** * Main object storing data model and emitting model events * @constructor @@ -3170,44 +3446,6 @@ $.extend(Model.prototype, /** @lends Model.prototype */ { } }); -/** - * Defines properties on an Node prototype with getter and setter.
- * Update events are emitted in the setter through root Model (if any).
- * The object must have a `__` object, non enumerable property to store values. - * @param {function} obj - * @param {string[]} fields - */ -Model.defineModelProperties = function(obj, fields) { - fields.forEach(function(field) { - Object.defineProperty(obj.prototype, field, { - enumerable: true, - get: function() { - return this.__[field]; - }, - set: function(value) { - var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? - $.extend({}, this.__[field]) : - this.__[field]; - - this.__[field] = value; - - if (this.model !== null) { - /** - * After a value of the model changed - * @event model:update - * @memberof Model - * @param {Node} node - * @param {string} field - * @param {*} value - * @param {*} previousValue - */ - this.model.trigger('update', this, field, value, previousValue); - } - } - }); - }); -}; - /** * Root abstract object @@ -3283,7 +3521,7 @@ var Node = function(parent, $el) { this.parent = parent; }; -Model.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); +Utils.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); Object.defineProperty(Node.prototype, 'parent', { enumerable: true, @@ -3446,7 +3684,7 @@ var Group = function(parent, $el) { Group.prototype = Object.create(Node.prototype); Group.prototype.constructor = Group; -Model.defineModelProperties(Group, ['condition']); +Utils.defineModelProperties(Group, ['condition']); /** * Removes group's content @@ -3667,7 +3905,7 @@ var Rule = function(parent, $el) { Rule.prototype = Object.create(Node.prototype); Rule.prototype.constructor = Rule; -Model.defineModelProperties(Rule, ['filter', 'operator', 'value']); +Utils.defineModelProperties(Rule, ['filter', 'operator', 'value']); /** * Checks if this Node is the root @@ -3693,212 +3931,6 @@ QueryBuilder.Group = Group; QueryBuilder.Rule = Rule; -/** - * @namespace - */ -var Utils = {}; - -/** - * @member {object} - * @memberof QueryBuilder - * @see Utils - */ -QueryBuilder.utils = Utils; - -/** - * @callback Utils#OptionsIteratee - * @param {string} key - * @param {string} value - */ - -/** - * Iterates over radio/checkbox/selection options, it accept three formats - * - * @example - * // array of values - * options = ['one', 'two', 'three'] - * @example - * // simple key-value map - * options = {1: 'one', 2: 'two', 3: 'three'} - * @example - * // array of 1-element maps - * options = [{1: 'one'}, {2: 'two'}, {3: 'three'}] - * - * @param {object|array} options - * @param {Utils#OptionsIteratee} tpl - */ -Utils.iterateOptions = function(options, tpl) { - if (options) { - if ($.isArray(options)) { - options.forEach(function(entry) { - // array of one-element maps - if ($.isPlainObject(entry)) { - $.each(entry, function(key, val) { - tpl(key, val); - return false; // break after first entry - }); - } - // array of values - else { - tpl(entry, entry); - } - }); - } - // unordered map - else { - $.each(options, function(key, val) { - tpl(key, val); - }); - } - } -}; - -/** - * Replaces {0}, {1}, ... in a string - * @param {string} str - * @param {...*} args - * @returns {string} - */ -Utils.fmt = function(str, args) { - if (!Array.isArray(args)) { - args = Array.prototype.slice.call(arguments, 1); - } - - return str.replace(/{([0-9]+)}/g, function(m, i) { - return args[parseInt(i)]; - }); -}; - -/** - * Throws an Error object with custom name or logs an error - * @param {boolean} [doThrow=true] - * @param {string} type - * @param {string} message - * @param {...*} args - */ -Utils.error = function() { - var i = 0; - var doThrow = typeof arguments[i] === 'boolean' ? arguments[i++] : true; - var type = arguments[i++]; - var message = arguments[i++]; - var args = Array.isArray(arguments[i]) ? arguments[i] : Array.prototype.slice.call(arguments, i); - - if (doThrow) { - var err = new Error(Utils.fmt(message, args)); - err.name = type + 'Error'; - err.args = args; - throw err; - } - else { - console.error(type + 'Error: ' + Utils.fmt(message, args)); - } -}; - -/** - * Changes the type of a value to int, float or bool - * @param {*} value - * @param {string} type - 'integer', 'double', 'boolean' or anything else (passthrough) - * @param {boolean} [boolAsInt=false] - return 0 or 1 for booleans - * @returns {*} - */ -Utils.changeType = function(value, type, boolAsInt) { - switch (type) { - // @formatter:off - case 'integer': return parseInt(value); - case 'double': return parseFloat(value); - case 'boolean': - var bool = value.trim().toLowerCase() === 'true' || value.trim() === '1' || value === 1; - return boolAsInt ? (bool ? 1 : 0) : bool; - default: return value; - // @formatter:on - } -}; - -/** - * Escapes a string like PHP's mysql_real_escape_string does - * @param {string} value - * @returns {string} - */ -Utils.escapeString = function(value) { - if (typeof value != 'string') { - return value; - } - - return value - .replace(/[\0\n\r\b\\\'\"]/g, function(s) { - switch (s) { - // @formatter:off - case '\0': return '\\0'; - case '\n': return '\\n'; - case '\r': return '\\r'; - case '\b': return '\\b'; - default: return '\\' + s; - // @formatter:off - } - }) - // uglify compliant - .replace(/\t/g, '\\t') - .replace(/\x1a/g, '\\Z'); -}; - -/** - * Escapes a string for use in regex - * @param {string} str - * @returns {string} - */ -Utils.escapeRegExp = function(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); -}; - -/** - * Escapes a string for use in HTML element id - * @param {string} str - * @returns {string} - */ -Utils.escapeElementId = function(str) { - // Regex based on that suggested by: - // https://learn.jquery.com/using-jquery-core/faq/how-do-i-select-an-element-by-an-id-that-has-characters-used-in-css-notation/ - // - escapes : . [ ] , - // - avoids escaping already escaped values - return (str) ? str.replace(/(\\)?([:.\[\],])/g, - function( $0, $1, $2 ) { return $1 ? $0 : '\\' + $2; }) : str; -}; - -/** - * Sorts objects by grouping them by `key`, preserving initial order when possible - * @param {object[]} items - * @param {string} key - * @returns {object[]} - */ -Utils.groupSort = function(items, key) { - var optgroups = []; - var newItems = []; - - items.forEach(function(item) { - var idx; - - if (item[key]) { - idx = optgroups.lastIndexOf(item[key]); - - if (idx == -1) { - idx = optgroups.length; - } - else { - idx++; - } - } - else { - idx = optgroups.length; - } - - optgroups.splice(idx, 0, item[key]); - newItems.splice(idx, 0, item); - }); - - return newItems; -}; - - /** * The {@link http://learn.jquery.com/plugins/|jQuery Plugins} namespace * @external "jQuery.fn" @@ -5072,7 +5104,7 @@ QueryBuilder.define('not-group', function(options) { * @memberof Group * @instance */ -Model.defineModelProperties(Group, ['not']); +Utils.defineModelProperties(Group, ['not']); QueryBuilder.selectors.group_not = QueryBuilder.selectors.group_header + ' [data-not=group]'; @@ -5329,7 +5361,14 @@ function moveSortableToTarget(node, target, builder) { * @class SqlSupport * @memberof module:plugins * @description Allows to export rules as a SQL WHERE statement as well as populating the builder from an SQL query. + * @param {object} [options] + * @param {boolean} [options.boolean_as_integer=true] - `true` to convert boolean values to integer in the SQL output */ +QueryBuilder.define('sql-support', function(options) { + +}, { + boolean_as_integer: true +}); QueryBuilder.defaults({ // operators for internal -> SQL conversion @@ -5569,6 +5608,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; nl = !!nl ? '\n' : ' '; + var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); if (stmt === true) stmt = 'question_mark'; if (typeof stmt == 'string') { @@ -5616,7 +5656,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { } if (rule.type == 'integer' || rule.type == 'double' || rule.type == 'boolean') { - v = Utils.changeType(v, rule.type, true); + v = Utils.changeType(v, rule.type, boolean_as_integer); } else if (!stmt) { v = Utils.escapeString(v); @@ -6069,7 +6109,7 @@ QueryBuilder.extend(/** @lends module:plugins.UniqueFilter.prototype */ { /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Locale: English (en) * Author: Damien "Mistic" Sorel, http://www.strangeplanet.fr * Licensed under MIT (http://opensource.org/licenses/MIT) @@ -6136,4 +6176,6 @@ QueryBuilder.regional['en'] = { }; QueryBuilder.defaults({ lang_code: 'en' }); -})); \ No newline at end of file +return QueryBuilder; + +})); diff --git a/dist/js/query-builder.standalone.min.js b/dist/js/query-builder.standalone.min.js index 87c37031..1ba11267 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.3 + * jQuery QueryBuilder 2.4.4 * 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--);h":">",'"':""","'":"'","/":"/"},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+".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])):k.error("Config",'Unable to find plugin "{0}"',a)},this)}},g.prototype.checkFilters=function(a){var b=[];if(a&&0!==a.length||k.error("Config","Missing filters list"),a.forEach(function(a,c){switch(a.id||k.error("Config","Missing filter {0} id",c),b.indexOf(a.id)!=-1&&k.error("Config",'Filter "{0}" already defined',a.id),b.push(a.id),a.type?g.types[a.type]||k.error("Config",'Invalid type "{0}"',a.type):a.type="string",a.input?"function"!=typeof a.input&&g.inputs.indexOf(a.input)==-1&&k.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&&k.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)&&k.error("Config",'Missing filter "{0}" values',a.id);break;case"select":a.placeholder&&(void 0===a.placeholder_value&&(a.placeholder_value=-1),k.iterateOptions(a.values,function(b){b==a.placeholder_value&&k.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=k.groupSort(a,"optgroup")),a},g.prototype.checkOperators=function(a){var b=[];return a.forEach(function(c,d){"string"==typeof c?(g.OPERATORS[c]||k.error("Config",'Unknown operator "{0}"',c),a[d]=c=$.extendext(!0,"replace",{},g.OPERATORS[c])):(c.type||k.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||k.error("Config",'Missing "nb_inputs" and/or "apply_to" for operator "{0}"',c.type)),b.indexOf(c.type)!=-1&&k.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=k.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 j)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 i(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()&&(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 i&&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=k.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){g.modifiable_options.indexOf(a)!==-1&&(this.settings[a]=b)}.bind(this))},g.prototype.getModel=function(a){return a?a instanceof h?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)&&(0===e&&!c.isRoot()&&a.skip_empty?null:!!(0!==e||b.settings.allow_empty&&c.isRoot())||(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)||k.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:c.settings.conditions.indexOf(a.condition)==-1&&(k.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(c.settings.allow_groups!==-1&&c.settings.allow_groups1){i=["operator_not_multiple",f.type,this.translate("operators",f.type)];break}switch(e.input){case"radio":if(void 0===b[j]||0===b[j].length){h.allow_empty_value||(i=["radio_empty"]);break}break;case"checkbox":if(void 0===b[j]||0===b[j].length){h.allow_empty_value||(i=["checkbox_empty"]);break}break;case"select":if(void 0===b[j]||0===b[j].length||e.placeholder&&b[j]==e.placeholder_value){h.allow_empty_value||(i=["select_empty"]);break}break;default:d=$.isArray(b[j])?b[j]:[b[j]];for(var l=0;lparseInt(h.max)){i=[this.getValidationMessage(h,"max","string_exceed_max_length"),h.max];break}if(h.format&&("string"==typeof h.format&&(h.format=new RegExp(h.format)),!h.format.test(d[l]))){i=[this.getValidationMessage(h,"format","string_invalid_format"),h.format];break}break;case"number":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["number_nan"]);break}if(isNaN(d[l])){i=["number_nan"];break}if("integer"==e.type){if(parseInt(d[l])!=d[l]){i=["number_not_integer"];break}}else if(parseFloat(d[l])!=d[l]){i=["number_not_double"];break}if(void 0!==h.min&&d[l]parseFloat(h.max)){i=[this.getValidationMessage(h,"max","number_exceed_max"),h.max];break}if(void 0!==h.step&&"any"!==h.step){var m=(d[l]/h.step).toPrecision(14);if(parseInt(m)!=m){i=[this.getValidationMessage(h,"step","number_wrong_step"),h.step];break}}break;case"datetime":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["datetime_empty"]);break}if(h.format){"moment"in window||k.error("MissingLibrary","MomentJS is required for Date/Time validation. Get it here http://momentjs.com");var n=moment(d[l],h.format);if(!n.isValid()){i=[this.getValidationMessage(h,"format","datetime_invalid"),h.format];break}if(h.min&&nmoment(h.max,h.format)){i=[this.getValidationMessage(h,"max","datetime_exceed_max"),h.max];break}}break;case"boolean":if(void 0===d[l]||0===d[l].length){h.allow_empty_value||(i=["boolean_not_valid"]);break}if(c=(""+d[l]).trim().toLowerCase(),"true"!==c&&"false"!==c&&"1"!==c&&"0"!==c&&1!==d[l]&&0!==d[l]){i=["boolean_not_valid"];break}}if(i!==!0)break}}if(i!==!0)break}return i},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;c '+b+" "});break;case"select":g+='";break;case"textarea":g+='";break;case"number":g+='=f:f>=e},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-1!==this.getNodePos(a)?!0:b?!this.each(function(){return!0},function(b){return!b.contains(a,!0)}):!1};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||{};return b||"destroy"!=a?(b||this.data("queryBuilder",new g(this,c)),"string"==typeof a?b[a].apply(b,Array.prototype.slice.call(arguments,1)):this):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&&-1===d.indexOf(a.filter.id)&&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&&-1===d.indexOf(a.filter.id)?a.drop():(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){return a.id==b?(b=c+1,!0):void 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-1===a.indexOf(b.id)}),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.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&&-1==a.filter.operators.indexOf(d)||(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)}}),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)}}),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)}}),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){c=void 0===c?this.getRules():c,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),-1===["AND","OR"].indexOf(c.condition.toUpperCase())&&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"),-1!==["AND","OR"].indexOf(a.operation.toUpperCase())){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===a});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){return!(d.id in c.status.used_filters)||c.status.used_filters[d.id].length>0&&-1===c.status.used_filters[d.id].indexOf(b.parent)?(a.value=d,!0):void 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}",datetime_empty:"Empty value",datetime_invalid:"Invalid date format ({0})",datetime_exceed_min:"Must be after {0}",datetime_exceed_max:"Must be before {0}",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 97fa1f38..3e7afda5 100644 --- a/dist/scss/dark.scss +++ b/dist/scss/dark.scss @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * 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 f62dae69..37cc4124 100644 --- a/dist/scss/default.scss +++ b/dist/scss/default.scss @@ -1,5 +1,5 @@ /*! - * jQuery QueryBuilder 2.4.3 + * jQuery QueryBuilder 2.4.4 * Copyright 2014-2017 Damien "Mistic" Sorel (http://www.strangeplanet.fr) * Licensed under MIT (http://opensource.org/licenses/MIT) */ diff --git a/examples/index.html b/examples/index.html index ff6592b0..369c9eda 100644 --- a/examples/index.html +++ b/examples/index.html @@ -133,8 +133,8 @@

Output

- + diff --git a/package.json b/package.json index 4af56cc3..51350701 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "jQuery-QueryBuilder", - "version": "2.4.3", + "version": "2.4.4", "author": { "name": "Damien \"Mistic\" Sorel", "email": "contact@git.strangeplanet.fr", "url": "http://www.strangeplanet.fr" }, "description": "jQuery plugin for user friendly query/filter creator", + "main": "dist/js/query-builder.js", "dependencies": { "jquery": ">=1.9.0", "bootstrap": ">=3.1.0", diff --git a/src/.wrapper.js b/src/.wrapper.js index b4b9da8d..732ae480 100644 --- a/src/.wrapper.js +++ b/src/.wrapper.js @@ -1,6 +1,9 @@ (function(root, factory) { if (typeof define == 'function' && define.amd) { - define(['jquery', 'doT', 'jQuery.extendext'], factory); + define(['jquery', 'dot/doT', 'jquery-extendext'], factory); + } + else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('jquery'), require('dot/doT'), require('jquery-extendext')); } else { factory(root.jQuery, root.doT); @@ -10,4 +13,6 @@ @@js -})); \ No newline at end of file +return QueryBuilder; + +})); diff --git a/src/core.js b/src/core.js index d9f1a85a..b3e2d2ec 100644 --- a/src/core.js +++ b/src/core.js @@ -1,36 +1,3 @@ -/** - * Initializes plugins for an instance - * @throws ConfigError - * @private - */ -QueryBuilder.prototype.initPlugins = function() { - if (!this.plugins) { - return; - } - - if ($.isArray(this.plugins)) { - var tmp = {}; - this.plugins.forEach(function(plugin) { - tmp[plugin] = null; - }); - this.plugins = tmp; - } - - Object.keys(this.plugins).forEach(function(plugin) { - if (plugin in QueryBuilder.plugins) { - this.plugins[plugin] = $.extend(true, {}, - QueryBuilder.plugins[plugin].def, - this.plugins[plugin] || {} - ); - - QueryBuilder.plugins[plugin].fct.call(this, this.plugins[plugin]); - } - else { - Utils.error('Config', 'Unable to find plugin "{0}"', plugin); - } - }, this); -}; - /** * Checks the configuration of each filter * @param {QueryBuilder.Filter[]} filters diff --git a/src/model.js b/src/model.js index af13aac7..a397c98f 100644 --- a/src/model.js +++ b/src/model.js @@ -64,44 +64,6 @@ $.extend(Model.prototype, /** @lends Model.prototype */ { } }); -/** - * Defines properties on an Node prototype with getter and setter.
- * Update events are emitted in the setter through root Model (if any).
- * The object must have a `__` object, non enumerable property to store values. - * @param {function} obj - * @param {string[]} fields - */ -Model.defineModelProperties = function(obj, fields) { - fields.forEach(function(field) { - Object.defineProperty(obj.prototype, field, { - enumerable: true, - get: function() { - return this.__[field]; - }, - set: function(value) { - var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? - $.extend({}, this.__[field]) : - this.__[field]; - - this.__[field] = value; - - if (this.model !== null) { - /** - * After a value of the model changed - * @event model:update - * @memberof Model - * @param {Node} node - * @param {string} field - * @param {*} value - * @param {*} previousValue - */ - this.model.trigger('update', this, field, value, previousValue); - } - } - }); - }); -}; - /** * Root abstract object @@ -177,7 +139,7 @@ var Node = function(parent, $el) { this.parent = parent; }; -Model.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); +Utils.defineModelProperties(Node, ['level', 'error', 'data', 'flags']); Object.defineProperty(Node.prototype, 'parent', { enumerable: true, @@ -340,7 +302,7 @@ var Group = function(parent, $el) { Group.prototype = Object.create(Node.prototype); Group.prototype.constructor = Group; -Model.defineModelProperties(Group, ['condition']); +Utils.defineModelProperties(Group, ['condition']); /** * Removes group's content @@ -561,7 +523,7 @@ var Rule = function(parent, $el) { Rule.prototype = Object.create(Node.prototype); Rule.prototype.constructor = Rule; -Model.defineModelProperties(Rule, ['filter', 'operator', 'value']); +Utils.defineModelProperties(Rule, ['filter', 'operator', 'value']); /** * Checks if this Node is the root diff --git a/src/plugins.js b/src/plugins.js index 35108e3e..036f9cc4 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -50,3 +50,65 @@ QueryBuilder.define = function(name, fct, def) { QueryBuilder.extend = function(methods) { $.extend(QueryBuilder.prototype, methods); }; + +/** + * Initializes plugins for an instance + * @throws ConfigError + * @private + */ +QueryBuilder.prototype.initPlugins = function() { + if (!this.plugins) { + return; + } + + if ($.isArray(this.plugins)) { + var tmp = {}; + this.plugins.forEach(function(plugin) { + tmp[plugin] = null; + }); + this.plugins = tmp; + } + + Object.keys(this.plugins).forEach(function(plugin) { + if (plugin in QueryBuilder.plugins) { + this.plugins[plugin] = $.extend(true, {}, + QueryBuilder.plugins[plugin].def, + this.plugins[plugin] || {} + ); + + QueryBuilder.plugins[plugin].fct.call(this, this.plugins[plugin]); + } + else { + Utils.error('Config', 'Unable to find plugin "{0}"', plugin); + } + }, this); +}; + +/** + * Returns the config of a plugin, if the plugin is not loaded, returns the default config. + * @param {string} name + * @param {string} [property] + * @throws ConfigError + * @returns {*} + */ +QueryBuilder.prototype.getPluginOptions = function(name, property) { + var plugin; + if (this.plugins && this.plugins[name]) { + plugin = this.plugins[name]; + } + else if (QueryBuilder.plugins[name]) { + plugin = QueryBuilder.plugins[name].def; + } + + if (plugin) { + if (property) { + return plugin[property]; + } + else { + return plugin; + } + } + else { + Utils.error('Config', 'Unable to find plugin "{0}"', name); + } +}; diff --git a/src/plugins/not-group/plugin.js b/src/plugins/not-group/plugin.js index 6596a817..da6f98b0 100644 --- a/src/plugins/not-group/plugin.js +++ b/src/plugins/not-group/plugin.js @@ -104,7 +104,7 @@ QueryBuilder.define('not-group', function(options) { * @memberof Group * @instance */ -Model.defineModelProperties(Group, ['not']); +Utils.defineModelProperties(Group, ['not']); QueryBuilder.selectors.group_not = QueryBuilder.selectors.group_header + ' [data-not=group]'; diff --git a/src/plugins/sql-support/plugin.js b/src/plugins/sql-support/plugin.js index e3676825..6abc101a 100644 --- a/src/plugins/sql-support/plugin.js +++ b/src/plugins/sql-support/plugin.js @@ -2,7 +2,14 @@ * @class SqlSupport * @memberof module:plugins * @description Allows to export rules as a SQL WHERE statement as well as populating the builder from an SQL query. + * @param {object} [options] + * @param {boolean} [options.boolean_as_integer=true] - `true` to convert boolean values to integer in the SQL output */ +QueryBuilder.define('sql-support', function(options) { + +}, { + boolean_as_integer: true +}); QueryBuilder.defaults({ // operators for internal -> SQL conversion @@ -242,6 +249,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { getSQL: function(stmt, nl, data) { data = (data === undefined) ? this.getRules() : data; nl = !!nl ? '\n' : ' '; + var boolean_as_integer = this.getPluginOptions('sql-support', 'boolean_as_integer'); if (stmt === true) stmt = 'question_mark'; if (typeof stmt == 'string') { @@ -289,7 +297,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ { } if (rule.type == 'integer' || rule.type == 'double' || rule.type == 'boolean') { - v = Utils.changeType(v, rule.type, true); + v = Utils.changeType(v, rule.type, boolean_as_integer); } else if (!stmt) { v = Utils.escapeString(v); diff --git a/src/utils.js b/src/utils.js index 8f6150f2..94af0956 100644 --- a/src/utils.js +++ b/src/utils.js @@ -202,3 +202,41 @@ Utils.groupSort = function(items, key) { return newItems; }; + +/** + * Defines properties on an Node prototype with getter and setter.
+ * Update events are emitted in the setter through root Model (if any).
+ * The object must have a `__` object, non enumerable property to store values. + * @param {function} obj + * @param {string[]} fields + */ +Utils.defineModelProperties = function(obj, fields) { + fields.forEach(function(field) { + Object.defineProperty(obj.prototype, field, { + enumerable: true, + get: function() { + return this.__[field]; + }, + set: function(value) { + var previousValue = (this.__[field] !== null && typeof this.__[field] == 'object') ? + $.extend({}, this.__[field]) : + this.__[field]; + + this.__[field] = value; + + if (this.model !== null) { + /** + * After a value of the model changed + * @event model:update + * @memberof Model + * @param {Node} node + * @param {string} field + * @param {*} value + * @param {*} previousValue + */ + this.model.trigger('update', this, field, value, previousValue); + } + } + }); + }); +}; diff --git a/tests/index.html b/tests/index.html index 343c9210..3af96d4d 100644 --- a/tests/index.html +++ b/tests/index.html @@ -38,8 +38,8 @@ - + diff --git a/tests/plugins.sql-support.module.js b/tests/plugins.sql-support.module.js index a64ecf4a..7d2da34e 100644 --- a/tests/plugins.sql-support.module.js +++ b/tests/plugins.sql-support.module.js @@ -307,6 +307,44 @@ $(function() { ); }); + QUnit.test('Cast booleans', function(assert) { + $b.queryBuilder({ + plugins: { + 'sql-support': { + boolean_as_integer: true + } + }, + filters: [ + { + id: 'done', + type: 'boolean' + } + ], + rules: [ + { + id: 'done', + operator: 'equal', + value: true + } + ] + }); + + assert.rulesMatch( + $b.queryBuilder('getSQL'), + 'done = 1', + 'Should convert boolean value to integer' + ); + + // don't do that in real life ! + $b[0].queryBuilder.plugins['sql-support'].boolean_as_integer = false; + + assert.rulesMatch( + $b.queryBuilder('getSQL'), + 'done = true', + 'Should not convert boolean value to integer' + ); + }); + var basic_rules_sql_raw = { sql: 'price < 10.25 AND name IS NULL AND ( category IN(\'mo\', \'mu\') OR id != \'1234-azer-5678\' ) '