From 601ff0d074ab99a9b96a635ac425114c578e80a5 Mon Sep 17 00:00:00 2001
From: mistic100 setOptions method
+ * Runtime modifiable options with `setOptions` method
* @type {string[]}
* @readonly
*/
diff --git a/src/main.js b/src/main.js
index c7ca252d..5baff3ce 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,10 +1,12 @@
/**
- * @typedef {object} QueryBuilder#Filter
+ * @typedef {object} Filter
+ * @memberof QueryBuilder
* @description See {@link http://querybuilder.js.org/index.html#filters}
*/
/**
- * @typedef {object} QueryBuilder#Operator
+ * @typedef {object} Operator
+ * @memberof QueryBuilder
* @description See {@link http://querybuilder.js.org/index.html#operators}
*/
@@ -61,7 +63,7 @@ var QueryBuilder = function($el, options) {
/**
* List of filters
- * @member {QueryBuilder#Filter[]}
+ * @member {QueryBuilder.Filter[]}
* @readonly
*/
this.filters = this.settings.filters;
@@ -75,7 +77,7 @@ var QueryBuilder = function($el, options) {
/**
* List of operators
- * @member {QueryBuilder#Operator[]}
+ * @member {QueryBuilder.Operator[]}
* @readonly
*/
this.operators = this.settings.operators;
@@ -142,7 +144,8 @@ var QueryBuilder = function($el, options) {
/**
* When the initilization is done, just before creating the root group
- * @event QueryBuilder#afterInit
+ * @event afterInit
+ * @memberof QueryBuilder
*/
this.trigger('afterInit');
@@ -235,15 +238,9 @@ $.extend(QueryBuilder.prototype, /** @lends QueryBuilder.prototype */ {
}
});
-/**
- * @typedef {object} QueryBuilder#Plugin
- * @property {object} def - default options
- * @property {function} fct - init function
- */
-
/**
* Definition of available plugins
- * @type {object.null but not omitted)
+ * @param {Model#GroupIteratee} cbRule - callback for Rules (can be `null` but not omitted)
* @param {Model#GroupIteratee} [cbGroup] - callback for Groups
* @param {object} [context] - context for callbacks
* @returns {boolean} if the iteration has been stopped by a callback
@@ -528,7 +535,7 @@ var Rule = function(parent, $el) {
/**
* @name filter
- * @member {QueryBuilder#Filter}
+ * @member {QueryBuilder.Filter}
* @memberof Rule
* @instance
*/
@@ -536,7 +543,7 @@ var Rule = function(parent, $el) {
/**
* @name operator
- * @member {QueryBuilder#Operator}
+ * @member {QueryBuilder.Operator}
* @memberof Rule
* @instance
*/
diff --git a/src/plugins/bt-checkbox/plugin.js b/src/plugins/bt-checkbox/plugin.js
index fd5257af..2f7af0be 100644
--- a/src/plugins/bt-checkbox/plugin.js
+++ b/src/plugins/bt-checkbox/plugin.js
@@ -1,13 +1,18 @@
/**
- * Applies Awesome Bootstrap Checkbox for checkbox and radio inputs
- * @class BtCheckboxPlugin
+ * @module BtCheckboxPlugin
+ * @description Applies Awesome Bootstrap Checkbox for checkbox and radio inputs.
+ */
+
+/**
+ * @function init
+ * @memberof module:BtCheckboxPlugin
* @param {object} [options]
- * @param {string} [options.font=glypicons]
- * @param {string} [options.color=default]
+ * @param {string} [options.font='glyphicons']
+ * @param {string} [options.color='default']
*/
QueryBuilder.define('bt-checkbox', function(options) {
if (options.font == 'glyphicons') {
- this.$el.addClass('bt-checkbox-glypicons');
+ this.$el.addClass('bt-checkbox-glyphicons');
}
this.on('getRuleInput.filter', function(h, rule, name) {
diff --git a/src/plugins/bt-checkbox/plugins.scss b/src/plugins/bt-checkbox/plugins.scss
index f2ba2375..9b259265 100644
--- a/src/plugins/bt-checkbox/plugins.scss
+++ b/src/plugins/bt-checkbox/plugins.scss
@@ -1,4 +1,4 @@
-.query-builder.bt-checkbox-glypicons {
+.query-builder.bt-checkbox-glyphicons {
.checkbox input[type=checkbox]:checked + label::after {
font-family: 'Glyphicons Halflings';
content: '\e013';
diff --git a/src/plugins/bt-selectpicker/plugin.js b/src/plugins/bt-selectpicker/plugin.js
index 8909b425..9ca505ec 100644
--- a/src/plugins/bt-selectpicker/plugin.js
+++ b/src/plugins/bt-selectpicker/plugin.js
@@ -1,10 +1,15 @@
/**
- * Applies Bootstrap Select on filters and operators combo-boxes.
- * @class BtSelectpickerPlugin
+ * @module BtSelectpickerPlugin
+ * @descriptioon Applies Bootstrap Select on filters and operators combo-boxes.
+ */
+
+/**
+ * @function init
+ * @memberof module:BtSelectpickerPlugin
* @param {object} [options]
- * @param {string} [options.container=body]
- * @param {string} [options.style=btn-inverse btn-xs]
- * @param {int|string} [options.width=auto]
+ * @param {string} [options.container='body']
+ * @param {string} [options.style='btn-inverse btn-xs']
+ * @param {int|string} [options.width='auto']
* @param {boolean} [options.showIcon=false]
* @throws MissingLibraryError
*/
diff --git a/src/plugins/bt-tooltip-errors/plugin.js b/src/plugins/bt-tooltip-errors/plugin.js
index 0da378de..2907d98c 100644
--- a/src/plugins/bt-tooltip-errors/plugin.js
+++ b/src/plugins/bt-tooltip-errors/plugin.js
@@ -1,8 +1,13 @@
/**
- * Applies Bootstrap Tooltips on validation error messages.
- * @class BtTooltipErrorsPlugin
+ * @module BtTooltipErrorsPlugin
+ * @description Applies Bootstrap Tooltips on validation error messages.
+ */
+
+/**
+ * @function init
+ * @memberof module:BtTooltipErrorsPlugin
* @param {object} [options]
- * @param {string} [options.placement=right]
+ * @param {string} [options.placement='right']
* @throws MissingLibraryError
*/
QueryBuilder.define('bt-tooltip-errors', function(options) {
@@ -23,9 +28,9 @@ QueryBuilder.define('bt-tooltip-errors', function(options) {
this.model.on('update', function(e, node, field) {
if (field == 'error' && self.settings.display_errors) {
node.$el.find(QueryBuilder.selectors.error_container).eq(0)
- .tooltip(options)
- .tooltip('hide')
- .tooltip('fixTitle');
+ .tooltip(options)
+ .tooltip('hide')
+ .tooltip('fixTitle');
}
});
}, {
diff --git a/src/plugins/change-filters/plugin.js b/src/plugins/change-filters/plugin.js
index 368ac448..064b82dd 100644
--- a/src/plugins/change-filters/plugin.js
+++ b/src/plugins/change-filters/plugin.js
@@ -1,13 +1,15 @@
/**
- * Allows to change available filters after plugin initialization.
- * @class ChangeFiltersPlugin
+ * @module ChangeFiltersPlugin
+ * @description Allows to change available filters after plugin initialization.
*/
-QueryBuilder.extend(/** @lends ChangeFiltersPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Change the filters of the builder
+ * @memberof module:ChangeFiltersPlugin
* @param {boolean} [deleteOrphans=false] - delete rules using old filters
- * @param {QueryBuilder#Filter[]} filters
- * @fires ChangeFiltersPlugin#afterSetFilters
+ * @param {QueryBuilder[]} filters
+ * @fires module:ChangeFiltersPlugin.changer:setFilters
+ * @fires module:ChangeFiltersPlugin.afterSetFilters
* @throws ChangeFilterError
*/
setFilters: function(deleteOrphans, filters) {
@@ -21,10 +23,11 @@ QueryBuilder.extend(/** @lends ChangeFiltersPlugin.prototype */ {
filters = this.checkFilters(filters);
/**
- * Modifies the filters before {@link ChangeFiltersPlugin#setFilters} method
- * @event ChangeFiltersPlugin#filter:setFilters
- * @param {QueryBuilder#Filter[]} filters
- * @returns {QueryBuilder#Filter[]}
+ * Modifies the filters before {@link module:ChangeFiltersPlugin.setFilters} method
+ * @event changer:setFilters
+ * @memberof module:ChangeFiltersPlugin
+ * @param {QueryBuilder.Filter[]} filters
+ * @returns {QueryBuilder.Filter[]}
*/
filters = this.change('setFilters', filters);
@@ -88,18 +91,21 @@ QueryBuilder.extend(/** @lends ChangeFiltersPlugin.prototype */ {
}
/**
- * After {@link ChangeFiltersPlugin#setFilters} method
- * @event ChangeFiltersPlugin#afterSetFilters
- * @param {QueryBuilder#Filter[]} filters
+ * After {@link module:ChangeFiltersPlugin.setFilters} method
+ * @event afterSetFilters
+ * @memberof module:ChangeFiltersPlugin
+ * @param {QueryBuilder.Filter[]} filters
*/
this.trigger('afterSetFilters', filters);
},
/**
* Adds a new filter to the builder
- * @param {QueryBuilder#Filter|QueryBuilder#Filter[]} newFilters
+ * @memberof module:ChangeFiltersPlugin
+ * @param {QueryBuilder.Filter|Filter[]} newFilters
* @param {int|string} [position=#end] - index or '#start' or '#end'
- * @fires ChangeFiltersPlugin#afterSetFilters
+ * @fires module:ChangeFiltersPlugin.changer:setFilters
+ * @fires module:ChangeFiltersPlugin.afterSetFilters
* @throws ChangeFilterError
*/
addFilter: function(newFilters, position) {
@@ -142,9 +148,11 @@ QueryBuilder.extend(/** @lends ChangeFiltersPlugin.prototype */ {
/**
* Removes a filter from the builder
+ * @memberof module:ChangeFiltersPlugin
* @param {string|string[]} filterIds
* @param {boolean} [deleteOrphans=false] delete rules using old filters
- * @fires ChangeFiltersPlugin#afterSetFilters
+ * @fires module:ChangeFiltersPlugin.changer:setFilters
+ * @fires module:ChangeFiltersPlugin.afterSetFilters
* @throws ChangeFilterError
*/
removeFilter: function(filterIds, deleteOrphans) {
diff --git a/src/plugins/filter-description/plugin.js b/src/plugins/filter-description/plugin.js
index 5cbde11f..7f2de44f 100644
--- a/src/plugins/filter-description/plugin.js
+++ b/src/plugins/filter-description/plugin.js
@@ -1,15 +1,18 @@
/**
- * Provides three ways to display a description about a filter: inline, Bootsrap Popover or Bootbox.
- * @class FilterDescriptionPlugin
+ * @module FilterDescriptionPlugin
+ * @description Provides three ways to display a description about a filter: inline, Bootsrap Popover or Bootbox.
+ */
+
+/**
+ * @function init
+ * @memberof module:FilterDescriptionPlugin
* @param {object} [options]
- * @param {string} [options.icon=glyphicon glyphicon-info-sign]
- * @param {string} [options.mode=popover] - inline, popover or bootbox
+ * @param {string} [options.icon='glyphicon glyphicon-info-sign']
+ * @param {string} [options.mode='popover'] - inline, popover or bootbox
* @throws ConfigError
*/
QueryBuilder.define('filter-description', function(options) {
- /**
- * INLINE
- */
+ // INLINE
if (options.mode === 'inline') {
this.on('afterUpdateRuleFilter afterUpdateRuleOperator', function(e, rule) {
var $p = rule.$el.find('p.filter-description');
@@ -31,9 +34,7 @@ QueryBuilder.define('filter-description', function(options) {
}
});
}
- /**
- * POPOVER
- */
+ // POPOVER
else if (options.mode === 'popover') {
if (!$.fn.popover || !$.fn.popover.Constructor || !$.fn.popover.Constructor.prototype.fixTitle) {
Utils.error('MissingLibrary', 'Bootstrap Popover is required to use "filter-description" plugin. Get it here: http://getbootstrap.com');
@@ -77,9 +78,7 @@ QueryBuilder.define('filter-description', function(options) {
}
});
}
- /**
- * BOOTBOX
- */
+ // BOOTBOX
else if (options.mode === 'bootbox') {
if (!('bootbox' in window)) {
Utils.error('MissingLibrary', 'Bootbox is required to use "filter-description" plugin. Get it here: http://bootboxjs.com');
@@ -111,12 +110,14 @@ QueryBuilder.define('filter-description', function(options) {
mode: 'popover'
});
-QueryBuilder.extend(/** @lends FilterDescriptionPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Returns the description of a filter for a particular rule (if present)
+ * @memberof module:FilterDescriptionPlugin
* @param {object} filter
* @param {Rule} [rule]
* @returns {string}
+ * @private
*/
getFilterDescription: function(filter, rule) {
if (!filter) {
diff --git a/src/plugins/invert/plugin.js b/src/plugins/invert/plugin.js
index 188f037f..8fb97bec 100644
--- a/src/plugins/invert/plugin.js
+++ b/src/plugins/invert/plugin.js
@@ -1,12 +1,6 @@
/**
- * Allows to invert a rule operator, a group condition or the entire builder.
- * @class InvertPlugin
- * @param {object} [options]
- * @param {string} [options.icon='glyphicon glyphicon-random]
- * @param {boolean} [options.recursive=true]
- * @param {boolean} [options.invert_rules=true]
- * @param {boolean} [options.display_rules_button=false]
- * @param {boolean} [options.silent_fail=false]
+ * @module InvertPlugin
+ * @description Allows to invert a rule operator, a group condition or the entire builder.
*/
QueryBuilder.defaults({
@@ -39,13 +33,21 @@ QueryBuilder.defaults({
}
});
+/**
+ * @function init
+ * @memberof module:InvertPlugin
+ * @param {object} [options]
+ * @param {string} [options.icon='glyphicon glyphicon-random']
+ * @param {boolean} [options.recursive=true]
+ * @param {boolean} [options.invert_rules=true]
+ * @param {boolean} [options.display_rules_button=false]
+ * @param {boolean} [options.silent_fail=false]
+ */
QueryBuilder.define('invert', function(options) {
var self = this;
var Selectors = QueryBuilder.selectors;
- /**
- * Bind events
- */
+ // Bind events
this.on('afterInit', function() {
self.$el.on('click.queryBuilder', '[data-invert=group]', function() {
var $group = $(this).closest(Selectors.group_container);
@@ -60,9 +62,7 @@ QueryBuilder.define('invert', function(options) {
}
});
- /**
- * Modify templates
- */
+ // Modify templates
this.on('getGroupTemplate.filter', function(h, level) {
var $h = $(h.value);
$h.find(Selectors.condition_container).after('');
@@ -84,12 +84,13 @@ QueryBuilder.define('invert', function(options) {
silent_fail: false
});
-QueryBuilder.extend(/** @lends InvertPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Invert a Group, a Rule or the whole builder
+ * @memberof module:InvertPlugin
* @param {Node} [node]
- * @param {object} [options] {@link InvertPlugin}
- * @fires InvertPlugin#afterInvert
+ * @param {object} [options] {@link module:InvertPlugin.init}
+ * @fires module:InvertPlugin.afterInvert
* @throws InvertConditionError, InvertOperatorError
*/
invert: function(node, options) {
@@ -144,8 +145,9 @@ QueryBuilder.extend(/** @lends InvertPlugin.prototype */ {
if (options.trigger) {
/**
- * After {@link InvertPlugin#invert} method
- * @event InvertPlugin#afterInvert
+ * After {@link module:InvertPlugin.invert} method
+ * @event afterInvert
+ * @memberof module:InvertPlugin
* @param {Node} node - the main group or rule that has been modified
* @param {object} options
*/
diff --git a/src/plugins/mongodb-support/plugin.js b/src/plugins/mongodb-support/plugin.js
index 619e5b0f..961c3b79 100644
--- a/src/plugins/mongodb-support/plugin.js
+++ b/src/plugins/mongodb-support/plugin.js
@@ -1,6 +1,6 @@
/**
- * Allows to export rules as a MongoDB find object as well as populating the builder from a MongoDB object.
- * @class MongoDbSupportPlugin
+ * @module MongoDbSupportPlugin
+ * @description Allows to export rules as a MongoDB find object as well as populating the builder from a MongoDB object.
*/
QueryBuilder.defaults({
@@ -91,14 +91,15 @@ QueryBuilder.defaults({
}
});
-QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Returns rules as a MongoDB query
+ * @memberof module:MongoDbSupportPlugin
* @param {object} [data] - current rules by default
* @returns {object}
- * @fires MongoDbSupportPlugin#filter:getMongoDBField
- * @fires MongoDbSupportPlugin#filter:ruleToMongo
- * @fires MongoDbSupportPlugin#filter:groupToMongo
+ * @fires module:MongoDbSupportPlugin.changer:getMongoDBField
+ * @fires module:MongoDbSupportPlugin.changer:ruleToMongo
+ * @fires module:MongoDbSupportPlugin.changer:groupToMongo
* @throws UndefinedMongoConditionError, UndefinedMongoOperatorError
*/
getMongo: function(data) {
@@ -145,7 +146,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Modifies the MongoDB field used by a rule
- * @event MongoDbSupportPlugin#filter:getMongoDBField
+ * @event changer:getMongoDBField
+ * @memberof module:MongoDbSupportPlugin
* @param {string} field
* @param {Rule} rule
* @returns {string}
@@ -157,7 +159,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Modifies the MongoDB expression generated for a rul
- * @event MongoDbSupportPlugin#filter:ruleToMongo
+ * @event changer:ruleToMongo
+ * @memberof module:MongoDbSupportPlugin
* @param {object} expression
* @param {Rule} rule
* @param {*} value
@@ -173,7 +176,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Modifies the MongoDB expression generated for a group
- * @event MongoDbSupportPlugin#filter:groupToMongo
+ * @event changer:groupToMongo
+ * @memberof module:MongoDbSupportPlugin
* @param {object} expression
* @param {Group} group
* @returns {object}
@@ -184,12 +188,13 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Converts a MongoDB query to rules
+ * @memberof module:MongoDbSupportPlugin
* @param {object} query
* @returns {object}
- * @fires MongoDbSupportPlugin#filter:parseMongoNode
- * @fires MongoDbSupportPlugin#filter:getMongoDBFieldID
- * @fires MongoDbSupportPlugin#filter:mongoToRule
- * @fires MongoDbSupportPlugin#filter:mongoToGroup
+ * @fires module:MongoDbSupportPlugin.changer:parseMongoNode
+ * @fires module:MongoDbSupportPlugin.changer:getMongoDBFieldID
+ * @fires module:MongoDbSupportPlugin.changer:mongoToRule
+ * @fires module:MongoDbSupportPlugin.changer:mongoToGroup
* @throws MongoParseError, UndefinedMongoConditionError, UndefinedMongoOperatorError
*/
getRulesFromMongo: function(query) {
@@ -201,7 +206,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Custom parsing of a MongoDB expression, you can return a sub-part of the expression, or a well formed group or rule JSON
- * @event MongoDbSupportPlugin#filter:parseMongoNode
+ * @event changer:parseMongoNode
+ * @memberof module:MongoDbSupportPlugin
* @param {object} expression
* @returns {object} expression, rule or group
*/
@@ -267,7 +273,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Returns a filter identifier from the MongoDB field
- * @event MongoDbSupportPlugin#filter:getMongoDBFieldID
+ * @event changer:getMongoDBFieldID
+ * @memberof module:MongoDbSupportPlugin
* @param {string} field
* @param {*} value
* @returns {string}
@@ -276,7 +283,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Modifies the rule generated from the MongoDB expression
- * @event MongoDbSupportPlugin#filter:mongoToRule
+ * @event changer:mongoToRule
+ * @memberof module:MongoDbSupportPlugin
* @param {object} rule
* @param {object} expression
* @returns {object}
@@ -294,7 +302,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Modifies the group generated from the MongoDB expression
- * @event MongoDbSupportPlugin#filter:mongoToGroup
+ * @event changer:mongoToGroup
+ * @memberof module:MongoDbSupportPlugin
* @param {object} group
* @param {object} expression
* @returns {object}
@@ -308,7 +317,8 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Sets rules a from MongoDB query
- * @see MongoDbSupportPlugin#getRulesFromMongo
+ * @memberof module:MongoDbSupportPlugin
+ * @see module:MongoDbSupportPlugin.getRulesFromMongo
*/
setRulesFromMongo: function(query) {
this.setRules(this.getRulesFromMongo(query));
@@ -317,9 +327,9 @@ QueryBuilder.extend(/** @lends MongoDbSupportPlugin.prototype */ {
/**
* Finds which operator is used in a MongoDB sub-object
+ * @memberof module:MongoDbSupportPlugin
* @param {*} value
* @returns {string|undefined}
- * @memberof MongoDbSupportPlugin
* @private
*/
function determineMongoOperator(value) {
@@ -351,9 +361,9 @@ function determineMongoOperator(value) {
/**
* Returns the key corresponding to "$or" or "$and"
+ * @memberof module:MongoDbSupportPlugin
* @param {object} data
* @returns {string}
- * @memberof MongoDbSupportPlugin
* @private
*/
function andOr(data) {
diff --git a/src/plugins/not-group/plugin.js b/src/plugins/not-group/plugin.js
index 6f2be7e1..891869fa 100644
--- a/src/plugins/not-group/plugin.js
+++ b/src/plugins/not-group/plugin.js
@@ -1,13 +1,10 @@
/**
- * Adds a "Not" checkbox in front of group conditions.
- * @class NotGroupPlugin
- * @param {object} [options]
- * @param {string} [options.icon_checked=glyphicon glyphicon-checked]
- * @param {string} [options.icon_unchecked=glyphicon glyphicon-unchecked]
+ * @module NotGroupPlugin
+ * @description Adds a "Not" checkbox in front of group conditions.
*/
/**
- * From {@link NotGroupPlugin}
+ * From {@link module:NotGroupPlugin}
* @name not
* @member {boolean}
* @memberof Group
@@ -17,12 +14,17 @@ Model.defineModelProperties(Group, ['not']);
QueryBuilder.selectors.group_not = QueryBuilder.selectors.group_header + ' [data-not=group]';
+/**
+ * @function init
+ * @memberof module:NotGroupPlugin
+ * @param {object} [options]
+ * @param {string} [options.icon_checked='glyphicon glyphicon-checked']
+ * @param {string} [options.icon_unchecked='glyphicon glyphicon-unchecked']
+ */
QueryBuilder.define('not-group', function(options) {
var self = this;
- /**
- * Bind events
- */
+ // Bind events
this.on('afterInit', function() {
self.$el.on('click.queryBuilder', '[data-not=group]', function() {
var $group = $(this).closest(QueryBuilder.selectors.group_container);
@@ -37,16 +39,12 @@ QueryBuilder.define('not-group', function(options) {
});
});
- /**
- * Init "not" property
- */
+ // Init "not" property
this.on('afterAddGroup', function(e, group) {
group.__.not = false;
});
- /**
- * Modify templates
- */
+ // Modify templates
this.on('getGroupTemplate.filter', function(h, level) {
var $h = $(h.value);
$h.find(QueryBuilder.selectors.condition_container).prepend(
@@ -57,32 +55,24 @@ QueryBuilder.define('not-group', function(options) {
h.value = $h.prop('outerHTML');
});
- /**
- * Export "not" to JSON
- */
+ // Export "not" to JSON
this.on('groupToJson.filter', function(e, group) {
e.value.not = group.not;
});
- /**
- * Read "not" from JSON
- */
+ // Read "not" from JSON
this.on('jsonToGroup.filter', function(e, json) {
e.value.not = !!json.not;
});
- /**
- * Export "not" to SQL
- */
+ // Export "not" to SQL
this.on('groupToSQL.filter', function(e, group) {
if (group.not) {
e.value = 'NOT ( ' + e.value + ' )';
}
});
- /**
- * Parse "NOT" function from sqlparser
- */
+ // Parse "NOT" function from sqlparser
this.on('parseSQLNode.filter', function(e) {
if (e.value.name && e.value.name.toUpperCase() == 'NOT') {
e.value = e.value.arguments.value[0];
@@ -90,16 +80,12 @@ QueryBuilder.define('not-group', function(options) {
}
});
- /**
- * Read "not" from parsed SQL
- */
+ // Read "not" from parsed SQL
this.on('sqlToGroup.filter', function(e, data) {
e.value.not = !!data.not;
});
- /**
- * Export "not" to Mongo
- */
+ // Export "not" to Mongo
this.on('groupToMongo.filter', function(e, group) {
var key = '$' + group.condition.toLowerCase();
if (group.not && e.value[key]) {
@@ -107,9 +93,7 @@ QueryBuilder.define('not-group', function(options) {
}
});
- /**
- * Parse "$nor" operator from Mongo
- */
+ // Parse "$nor" operator from Mongo
this.on('parseMongoNode.filter', function(e) {
var keys = Object.keys(e.value);
@@ -119,9 +103,7 @@ QueryBuilder.define('not-group', function(options) {
}
});
- /**
- * Read "not" from parsed Mongo
- */
+ // Read "not" from parsed Mongo
this.on('mongoToGroup.filter', function(e, data) {
e.value.not = !!data.not;
});
@@ -130,11 +112,12 @@ QueryBuilder.define('not-group', function(options) {
icon_checked: 'glyphicon glyphicon-check'
});
-QueryBuilder.extend(/** @lends NotGroupPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Performs actions when a group's not changes
+ * @memberof module:NotGroupPlugin
* @param {Group} group
- * @fires NotGroupPlugin#afterUpdateGroupNot
+ * @fires module:NotGroupPlugin.afterUpdateGroupNot
* @private
*/
updateGroupNot: function(group) {
@@ -145,7 +128,8 @@ QueryBuilder.extend(/** @lends NotGroupPlugin.prototype */ {
/**
* After the group's not flag has been modified
- * @event NotGroupPlugin#afterUpdateGroupNot
+ * @event afterUpdateGroupNot
+ * @memberof module:NotGroupPlugin
* @param {Group} group
*/
this.trigger('afterUpdateGroupNot', group);
diff --git a/src/plugins/sortable/plugin.js b/src/plugins/sortable/plugin.js
index 8514ffd0..77973df3 100644
--- a/src/plugins/sortable/plugin.js
+++ b/src/plugins/sortable/plugin.js
@@ -1,11 +1,6 @@
/**
- * Enables drag & drop sort of rules.
- * @class SortablePlugin
- * @param {object} [options]
- * @param {boolean} [options.inherit_no_drop=true]
- * @param {boolean} [options.inherit_no_sortable=true]
- * @param {string} [options.icon=glyphicon glyphicon-sort]
- * @throws MissingLibraryError, ConfigError
+ * @module SortablePlugin
+ * @description Enables drag & drop sort of rules.
*/
QueryBuilder.selectors.rule_and_group_containers = QueryBuilder.selectors.rule_container + ', ' + QueryBuilder.selectors.group_container;
@@ -22,6 +17,15 @@ QueryBuilder.defaults({
}
});
+/**
+ * @function init
+ * @memberof module:SortablePlugin
+ * @param {object} [options]
+ * @param {boolean} [options.inherit_no_drop=true]
+ * @param {boolean} [options.inherit_no_sortable=true]
+ * @param {string} [options.icon='glyphicon glyphicon-sort']
+ * @throws MissingLibraryError, ConfigError
+ */
QueryBuilder.define('sortable', function(options) {
if (!('interact' in window)) {
Utils.error('MissingLibrary', 'interact.js is required to use "sortable" plugin. Get it here: http://interactjs.io');
@@ -42,9 +46,7 @@ QueryBuilder.define('sortable', function(options) {
var ghost;
var src;
- /**
- * Init drag and drop
- */
+ // Init drag and drop
this.on('afterAddRule afterAddGroup', function(e, node) {
if (node == placeholder) {
return;
@@ -52,9 +54,7 @@ QueryBuilder.define('sortable', function(options) {
var self = e.builder;
- /**
- * Inherit flags
- */
+ // Inherit flags
if (options.inherit_no_sortable && node.parent && node.parent.flags.no_sortable) {
node.flags.no_sortable = true;
}
@@ -62,9 +62,7 @@ QueryBuilder.define('sortable', function(options) {
node.flags.no_drop = true;
}
- /**
- * Configure drag
- */
+ // Configure drag
if (!node.flags.no_sortable) {
interact(node.$el[0])
.allowFrom(QueryBuilder.selectors.drag_handle)
@@ -106,8 +104,9 @@ QueryBuilder.define('sortable', function(options) {
src.$el.show();
/**
- * After a node has been moved with {@link SortablePlugin}
- * @event SortablePlugin#afterMove
+ * After a node has been moved with {@link module:SortablePlugin}
+ * @event afterMove
+ * @memberof module:SortablePlugin
* @param {Node} node
*/
self.trigger('afterMove', src);
@@ -116,9 +115,7 @@ QueryBuilder.define('sortable', function(options) {
}
if (!node.flags.no_drop) {
- /**
- * Configure drop on groups and rules
- */
+ // Configure drop on groups and rules
interact(node.$el[0])
.dropzone({
accept: QueryBuilder.selectors.rule_and_group_containers,
@@ -130,9 +127,7 @@ QueryBuilder.define('sortable', function(options) {
}
});
- /**
- * Configure drop on group headers
- */
+ // Configure drop on group headers
if (node instanceof Group) {
interact(node.$el.find(QueryBuilder.selectors.group_header)[0])
.dropzone({
@@ -148,9 +143,7 @@ QueryBuilder.define('sortable', function(options) {
}
});
- /**
- * Detach interactables
- */
+ // Detach interactables
this.on('beforeDeleteRule beforeDeleteGroup', function(e, node) {
if (!e.isDefaultPrevented()) {
interact(node.$el[0]).unset();
@@ -161,18 +154,14 @@ QueryBuilder.define('sortable', function(options) {
}
});
- /**
- * Remove drag handle from non-sortable items
- */
+ // Remove drag handle from non-sortable items
this.on('afterApplyRuleFlags afterApplyGroupFlags', function(e, node) {
if (node.flags.no_sortable) {
node.$el.find('.drag-handle').remove();
}
});
- /**
- * Modify templates
- */
+ // Modify templates
this.on('getGroupTemplate.filter', function(h, level) {
if (level > 1) {
var $h = $(h.value);
@@ -194,10 +183,10 @@ QueryBuilder.define('sortable', function(options) {
/**
* Moves an element (placeholder or actual object) depending on active target
+ * @memberof module:SortablePlugin
* @param {Node} node
* @param {jQuery} target
* @param {QueryBuilder} [builder]
- * @memberof SortablePlugin
* @private
*/
function moveSortableToTarget(node, target, builder) {
diff --git a/src/plugins/sql-support/plugin.js b/src/plugins/sql-support/plugin.js
index c2956494..8dc92ca9 100644
--- a/src/plugins/sql-support/plugin.js
+++ b/src/plugins/sql-support/plugin.js
@@ -1,10 +1,10 @@
/**
- * Allows to export rules as a SQL WHERE statement as well as populating the builder from an SQL query.
- * @class SqlSupportPlugin
+ * @module SqlSupportPlugin
+ * @description Allows to export rules as a SQL WHERE statement as well as populating the builder from an SQL query.
*/
QueryBuilder.defaults({
- /* operators for internal -> SQL conversion */
+ // operators for internal -> SQL conversion
sqlOperators: {
equal: { op: '= ?' },
not_equal: { op: '!= ?' },
@@ -28,7 +28,7 @@ QueryBuilder.defaults({
is_not_null: { op: 'IS NOT NULL' }
},
- /* operators for SQL -> internal conversion */
+ // operators for SQL -> internal conversion
sqlRuleOperator: {
'=': function(v) {
return {
@@ -126,7 +126,7 @@ QueryBuilder.defaults({
}
},
- /* statements for internal -> SQL conversion */
+ // statements for internal -> SQL conversion
sqlStatements: {
'question_mark': function() {
var params = [];
@@ -175,7 +175,7 @@ QueryBuilder.defaults({
}
},
- /* statements for SQL -> internal conversion */
+ // statements for SQL -> internal conversion
sqlRuleStatement: {
'question_mark': function(values) {
var index = 0;
@@ -220,21 +220,23 @@ QueryBuilder.defaults({
});
/**
- * @typedef {object} SqlSupportPlugin#SqlQuery
+ * @typedef {object} SqlQuery
+ * @memberof module:SqlSupportPlugin
* @property {string} sql
* @property {object} params
*/
-QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
+QueryBuilder.extend({
/**
* Returns rules as a SQL query
+ * @memberof module:SqlSupportPlugin
* @param {boolean|string} [stmt] - use prepared statements: false, 'question_mark', 'numbered', 'numbered(@)', 'named', 'named(@)'
* @param {boolean} [nl=false] output with new lines
* @param {object} [data] - current rules by default
- * @returns {SqlSupportPlugin#SqlQuery}
- * @fires SqlSupportPlugin#filter:getSQLField
- * @fires SqlSupportPlugin#filter:ruleToSQL
- * @fires SqlSupportPlugin#filter:groupToSQL
+ * @returns {module:SqlSupportPlugin.SqlQuery}
+ * @fires module:SqlSupportPlugin.changer:getSQLField
+ * @fires module:SqlSupportPlugin.changer:ruleToSQL
+ * @fires module:SqlSupportPlugin.changer:groupToSQL
* @throws UndefinedSQLConditionError, UndefinedSQLOperatorError
*/
getSQL: function(stmt, nl, data) {
@@ -316,7 +318,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Modifies the SQL field used by a rule
- * @event SqlSupportPlugin#filter:getSQLField
+ * @event changer:getSQLField
+ * @memberof module:SqlSupportPlugin
* @param {string} field
* @param {Rule} rule
* @returns {string}
@@ -327,7 +330,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Modifies the SQL generated for a rule
- * @event SqlSupportPlugin#filter:ruleToSQL
+ * @event changer:ruleToSQL
+ * @memberof module:SqlSupportPlugin
* @param {string} expression
* @param {Rule} rule
* @param {*} value
@@ -342,7 +346,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Modifies the SQL generated for a group
- * @event SqlSupportPlugin#filter:groupToSQL
+ * @event changer:groupToSQL
+ * @memberof module:SqlSupportPlugin
* @param {string} expression
* @param {Group} group
* @returns {string}
@@ -365,13 +370,14 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Convert a SQL query to rules
- * @param {string|SqlSupportPlugin#SqlQuery} query
+ * @memberof module:SqlSupportPlugin
+ * @param {string|module:SqlSupportPlugin.SqlQuery} query
* @param {boolean|string} stmt
* @returns {object}
- * @fires SqlSupportPlugin#filter:parseSQLNode
- * @fires SqlSupportPlugin#filter:getSQLFieldID
- * @fires SqlSupportPlugin#filter:sqlToRule
- * @fires SqlSupportPlugin#filter:sqlToGroup
+ * @fires module:SqlSupportPlugin.changer:parseSQLNode
+ * @fires module:SqlSupportPlugin.changer:getSQLFieldID
+ * @fires module:SqlSupportPlugin.changer:sqlToRule
+ * @fires module:SqlSupportPlugin.changer:sqlToGroup
* @throws MissingLibraryError, SQLParseError, UndefinedSQLOperatorError
*/
getRulesFromSQL: function(query, stmt) {
@@ -407,7 +413,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Custom parsing of an AST node generated by SQLParser, you can return a sub-part of the tree, or a well formed group or rule JSON
- * @event SqlSupportPlugin#filter:parseSQLNode
+ * @event changer:parseSQLNode
+ * @memberof module:SqlSupportPlugin
* @param {object} AST node
* @returns {object} tree, rule or group
*/
@@ -462,7 +469,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
if (i > 0 && curr.condition != data.operation.toUpperCase()) {
/**
* Modifies the group generated from the SQL expression (this is called before the group is filled with rules)
- * @event SqlSupportPlugin#filter:sqlToGroup
+ * @event changer:sqlToGroup
+ * @memberof module:SqlSupportPlugin
* @param {object} group
* @param {object} AST
* @returns {object}
@@ -529,7 +537,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Returns a filter identifier from the SQL field
- * @event SqlSupportPlugin#filter:getSQLFieldID
+ * @event changer:getSQLFieldID
+ * @memberof module:SqlSupportPlugin
* @param {string} field
* @param {*} value
* @returns {string}
@@ -538,7 +547,8 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Modifies the rule generated from the SQL expression
- * @event SqlSupportPlugin#filter:sqlToRule
+ * @event changer:sqlToRule
+ * @memberof module:SqlSupportPlugin
* @param {object} rule
* @param {object} AST
* @returns {object}
@@ -558,8 +568,9 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
},
/**
- * Sets the rules from a SQL query
- * @see SqlSupportPlugin#getRulesFromSQL
+ * Sets the builder's rules from a SQL query
+ * @memberof module:SqlSupportPlugin
+ * @see module:SqlSupportPlugin.getRulesFromSQL
*/
setRulesFromSQL: function(query, stmt) {
this.setRules(this.getRulesFromSQL(query, stmt));
@@ -568,9 +579,9 @@ QueryBuilder.extend(/** @lends SqlSupportPlugin.prototype */ {
/**
* Parses the statement configuration
+ * @memberof module:SqlSupportPlugin
* @param {string} stmt
* @returns {Array} null, mode, option
- * @memberof SqlSupportPlugin
* @private
*/
function getStmtConfig(stmt) {
diff --git a/src/plugins/unique-filter/plugin.js b/src/plugins/unique-filter/plugin.js
index 7a2d6c10..9a318a59 100644
--- a/src/plugins/unique-filter/plugin.js
+++ b/src/plugins/unique-filter/plugin.js
@@ -1,6 +1,11 @@
/**
- * Allows to define some filters as "unique": ie which can be used for only one rule, globally or in the same group.
- * @class UniqueFilterPlugin
+ * @module UniqueFilterPlugin
+ * @description Allows to define some filters as "unique": ie which can be used for only one rule, globally or in the same group.
+ */
+
+/**
+ * @function init
+ * @memberof module:UniqueFilterPlugin
*/
QueryBuilder.define('unique-filter', function() {
this.status.used_filters = {};
@@ -11,10 +16,7 @@ QueryBuilder.define('unique-filter', function() {
this.on('afterReset', this.clearDisabledFilters);
this.on('afterClear', this.clearDisabledFilters);
- /**
- * Ensure that the default filter is not already used if unique
- * @throws UniqueFilterError
- */
+ // Ensure that the default filter is not already used if unique
this.on('getDefaultFilter.filter', function(e, model) {
var self = e.builder;
@@ -36,9 +38,10 @@ QueryBuilder.define('unique-filter', function() {
});
});
-QueryBuilder.extend(/** @lends UniqueFilterPlugin.prototype*/ {
+QueryBuilder.extend({
/**
* Updates the list of used filters
+ * @memberof module:UniqueFilterPlugin
* @param {$.Event} [e]
* @private
*/
@@ -72,6 +75,7 @@ QueryBuilder.extend(/** @lends UniqueFilterPlugin.prototype*/ {
/**
* Clear the list of used filters
+ * @memberof module:UniqueFilterPlugin
* @param {$.Event} [e]
* @private
*/
@@ -85,6 +89,7 @@ QueryBuilder.extend(/** @lends UniqueFilterPlugin.prototype*/ {
/**
* Disabled filters depending on the list of used ones
+ * @memberof module:UniqueFilterPlugin
* @param {$.Event} [e]
* @private
*/
diff --git a/src/public.js b/src/public.js
index dcaf7fd1..2b5b3654 100644
--- a/src/public.js
+++ b/src/public.js
@@ -5,7 +5,8 @@
QueryBuilder.prototype.destroy = function() {
/**
* Before the {@link QueryBuilder#destroy} method
- * @event QueryBuilder#beforeDestroy
+ * @event beforeDestroy
+ * @memberof QueryBuilder
*/
this.trigger('beforeDestroy');
@@ -32,7 +33,8 @@ QueryBuilder.prototype.destroy = function() {
QueryBuilder.prototype.reset = function() {
/**
* Before the {@link QueryBuilder#reset} method, can be prevented
- * @event QueryBuilder#beforeReset
+ * @event beforeReset
+ * @memberof QueryBuilder
*/
var e = this.trigger('beforeReset');
if (e.isDefaultPrevented()) {
@@ -48,7 +50,8 @@ QueryBuilder.prototype.reset = function() {
/**
* After the {@link QueryBuilder#reset} method
- * @event QueryBuilder#afterReset
+ * @event afterReset
+ * @memberof QueryBuilder
*/
this.trigger('afterReset');
};
@@ -61,7 +64,8 @@ QueryBuilder.prototype.reset = function() {
QueryBuilder.prototype.clear = function() {
/**
* Before the {@link QueryBuilder#clear} method, can be prevented
- * @event QueryBuilder#beforeClear
+ * @event beforeClear
+ * @memberof QueryBuilder
*/
var e = this.trigger('beforeClear');
if (e.isDefaultPrevented()) {
@@ -78,7 +82,8 @@ QueryBuilder.prototype.clear = function() {
/**
* After the {@link QueryBuilder#clear} method
- * @event QueryBuilder#afterClear
+ * @event afterClear
+ * @memberof QueryBuilder
*/
this.trigger('afterClear');
};
@@ -118,7 +123,7 @@ QueryBuilder.prototype.getModel = function(target) {
* @param {object} [options]
* @param {boolean} [options.skip_empty=false] - skips validating rules that have no filter selected
* @returns {boolean}
- * @fires QueryBuilder#filter:validate
+ * @fires QueryBuilder#changer:validate
*/
QueryBuilder.prototype.validate = function(options) {
options = $.extend({
@@ -189,7 +194,8 @@ QueryBuilder.prototype.validate = function(options) {
/**
* Modifies the result of the {@link QueryBuilder#validate} method
- * @event QueryBuilder#filter:validate
+ * @event changer:validate
+ * @memberof QueryBuilder
* @param {boolean} valid
* @returns {boolean}
*/
@@ -203,9 +209,9 @@ QueryBuilder.prototype.validate = function(options) {
* @param {boolean} [options.allow_invalid=false] - returns rules even if they are invalid
* @param {boolean} [options.skip_empty=false] - remove rules that have no filter selected
* @returns {object}
- * @fires QueryBuilder#filter:ruleToJson
- * @fires QueryBuilder#filter:groupToJson
- * @fires QueryBuilder#filter:getRules
+ * @fires QueryBuilder#changer:ruleToJson
+ * @fires QueryBuilder#changer:groupToJson
+ * @fires QueryBuilder#changer:getRules
*/
QueryBuilder.prototype.getRules = function(options) {
options = $.extend({
@@ -270,7 +276,8 @@ QueryBuilder.prototype.getRules = function(options) {
/**
* Modifies the JSON generated from a Rule object
- * @event QueryBuilder#filter:ruleToJson
+ * @event changer:ruleToJson
+ * @memberof QueryBuilder
* @param {object} json
* @param {Rule} rule
* @returns {object}
@@ -286,7 +293,8 @@ QueryBuilder.prototype.getRules = function(options) {
/**
* Modifies the JSON generated from a Group object
- * @event QueryBuilder#filter:groupToJson
+ * @event changer:groupToJson
+ * @memberof QueryBuilder
* @param {object} json
* @param {Group} group
* @returns {object}
@@ -298,7 +306,8 @@ QueryBuilder.prototype.getRules = function(options) {
out.valid = valid;
/**
- * @avant QueryBuilder#filter:getRules
+ * Modifies the result of the {@link QueryBuilder#getRules} method
+ * @event changer:getRules
* @param {object} json
* @returns {object}
*/
@@ -311,9 +320,9 @@ QueryBuilder.prototype.getRules = function(options) {
* @param {object} [options]
* @param {boolean} [options.allow_invalid=false] - silent-fail if the data are invalid
* @throws RulesError, UndefinedConditionError
- * @fires QueryBuilder#filter:setRules
- * @fires QueryBuilder#filter:jsonToRule
- * @fires QueryBuilder#filter:jsonToGroup
+ * @fires QueryBuilder#changer:setRules
+ * @fires QueryBuilder#changer:jsonToRule
+ * @fires QueryBuilder#changer:jsonToGroup
* @fires QueryBuilder#afterSetRules
*/
QueryBuilder.prototype.setRules = function(data, options) {
@@ -338,7 +347,8 @@ QueryBuilder.prototype.setRules = function(data, options) {
/**
* Modifies data before the {@link QueryBuilder#setRules} method
- * @event QueryBuilder#filter:setRules
+ * @event changer:setRules
+ * @memberof QueryBuilder
* @param {object} json
* @param {object} options
* @returns {object}
@@ -417,7 +427,8 @@ QueryBuilder.prototype.setRules = function(data, options) {
/**
* Modifies the Rule object generated from the JSON
- * @event QueryBuilder#filter:jsonToRule
+ * @event changer:jsonToRule
+ * @memberof QueryBuilder
* @param {Rule} rule
* @param {object} json
* @returns {Rule} the same rule
@@ -430,7 +441,8 @@ QueryBuilder.prototype.setRules = function(data, options) {
/**
* Modifies the Group object generated from the JSON
- * @event QueryBuilder#filter:jsonToGroup
+ * @event changer:jsonToGroup
+ * @memberof QueryBuilder
* @param {Group} group
* @param {object} json
* @returns {Group} the same group
@@ -443,7 +455,8 @@ QueryBuilder.prototype.setRules = function(data, options) {
/**
* After the {@link QueryBuilder#setRules} method
- * @event QueryBuilder#afterSetRules
+ * @event afterSetRules
+ * @memberof QueryBuilder
*/
this.trigger('afterSetRules');
};
diff --git a/src/template.js b/src/template.js
index a7bfbdc0..1bca5f1f 100644
--- a/src/template.js
+++ b/src/template.js
@@ -92,7 +92,7 @@ QueryBuilder.templates.operatorSelect = '\
* @param {string} group_id
* @param {int} level
* @returns {string}
- * @fires QueryBuilder#filter:getGroupTemplate
+ * @fires QueryBuilder#changer:getGroupTemplate
* @private
*/
QueryBuilder.prototype.getGroupTemplate = function(group_id, level) {
@@ -108,7 +108,8 @@ QueryBuilder.prototype.getGroupTemplate = function(group_id, level) {
/**
* Modifies the raw HTML of a group
- * @event QueryBuilder#filter:getGroupTemplate
+ * @event changer:getGroupTemplate
+ * @memberof QueryBuilder
* @param {string} html
* @param {int} level
* @returns {string}
@@ -120,7 +121,7 @@ QueryBuilder.prototype.getGroupTemplate = function(group_id, level) {
* Returns rule's HTML
* @param {string} rule_id
* @returns {string}
- * @fires QueryBuilder#filter:getRuleTemplate
+ * @fires QueryBuilder#changer:getRuleTemplate
* @private
*/
QueryBuilder.prototype.getRuleTemplate = function(rule_id) {
@@ -134,7 +135,8 @@ QueryBuilder.prototype.getRuleTemplate = function(rule_id) {
/**
* Modifies the raw HTML of a rule
- * @event QueryBuilder#filter:getRuleTemplate
+ * @event changer:getRuleTemplate
+ * @memberof QueryBuilder
* @param {string} html
* @returns {string}
*/
@@ -146,7 +148,7 @@ QueryBuilder.prototype.getRuleTemplate = function(rule_id) {
* @param {Rule} rule
* @param {object[]} filters
* @returns {string}
- * @fires QueryBuilder#filter:getRuleFilterTemplate
+ * @fires QueryBuilder#changer:getRuleFilterTemplate
* @private
*/
QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) {
@@ -162,10 +164,11 @@ QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) {
/**
* Modifies the raw HTML of the rule's filter dropdown
- * @event QueryBuilder#filter:getRuleFilterTemplate
+ * @event changer:getRuleFilterTemplate
+ * @memberof QueryBuilder
* @param {string} html
* @param {Rule} rule
- * @param {QueryBuilder#Filter[]} filters
+ * @param {QueryBuilder.Filter[]} filters
* @returns {string}
*/
return this.change('getRuleFilterSelect', h, rule, filters);
@@ -176,7 +179,7 @@ QueryBuilder.prototype.getRuleFilterSelect = function(rule, filters) {
* @param {Rule} rule
* @param {object[]} operators
* @returns {string}
- * @fires QueryBuilder#filter:getRuleOperatorTemplate
+ * @fires QueryBuilder#changer:getRuleOperatorTemplate
* @private
*/
QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) {
@@ -192,10 +195,11 @@ QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) {
/**
* Modifies the raw HTML of the rule's operator dropdown
- * @event QueryBuilder#filter:getRuleOperatorTemplate
+ * @event changer:getRuleOperatorTemplate
+ * @memberof QueryBuilder
* @param {string} html
* @param {Rule} rule
- * @param {QueryBuilder#Operator[]} operators
+ * @param {QueryBuilder.Operator[]} operators
* @returns {string}
*/
return this.change('getRuleOperatorSelect', h, rule, operators);
@@ -206,7 +210,7 @@ QueryBuilder.prototype.getRuleOperatorSelect = function(rule, operators) {
* @param {Rule} rule
* @param {int} value_id
* @returns {string}
- * @fires QueryBuilder#filter:getRuleInput
+ * @fires QueryBuilder#changer:getRuleInput
* @private
*/
QueryBuilder.prototype.getRuleInput = function(rule, value_id) {
@@ -271,7 +275,8 @@ QueryBuilder.prototype.getRuleInput = function(rule, value_id) {
/**
* Modifies the raw HTML of the rule's input
- * @event QueryBuilder#filter:getRuleInput
+ * @event changer:getRuleInput
+ * @memberof QueryBuilder
* @param {string} html
* @param {Rule} rule
* @param {string} name - the name that the input must have
diff --git a/src/utils.js b/src/utils.js
index 65853f18..8f6150f2 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,7 +1,14 @@
/**
* @namespace
*/
-var Utils = QueryBuilder.utils = {};
+var Utils = {};
+
+/**
+ * @member {object}
+ * @memberof QueryBuilder
+ * @see Utils
+ */
+QueryBuilder.utils = Utils;
/**
* @callback Utils#OptionsIteratee
@@ -163,7 +170,7 @@ Utils.escapeElementId = function(str) {
};
/**
- * Sorts objects by grouping them by key, preserving initial order when possible
+ * Sorts objects by grouping them by `key`, preserving initial order when possible
* @param {object[]} items
* @param {string} key
* @returns {object[]}
From 7e3c6b683a26e4bb705d657ea7d6e90fc7a603b3 Mon Sep 17 00:00:00 2001
From: Hendri Smit Output
+
@@ -208,6 +209,7 @@ Output
*/
{
id: 'name',
+ field: 'username',
label: {
en: 'Name',
fr: 'Nom'
@@ -582,7 +584,7 @@ Output
// set rules from SQL
$('.set-sql').on('click', function() {
- $('#builder').queryBuilder('setRulesFromSQL', 'name NOT LIKE "Mistic%" OR price BETWEEN 100 OR 200 OR NOT (category IN(1, 2) AND rate <= 2)');
+ $('#builder').queryBuilder('setRulesFromSQL', 'username NOT LIKE "Mistic%" OR price BETWEEN 100 OR 200 OR NOT (category IN(1, 2) AND rate <= 2)');
});
// reset builder
diff --git a/package.json b/package.json
index 3d6d917e..af0dbb90 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "jQuery-QueryBuilder",
- "version": "2.4.0",
+ "version": "2.5.0",
"author": {
"name": "Damien \"Mistic\" Sorel",
"email": "contact@git.strangeplanet.fr",
diff --git a/src/plugins/sql-support/plugin.js b/src/plugins/sql-support/plugin.js
index bb190c49..e3676825 100644
--- a/src/plugins/sql-support/plugin.js
+++ b/src/plugins/sql-support/plugin.js
@@ -545,15 +545,7 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ {
Utils.error('SQLParse', 'Cannot find field name in {0}', JSON.stringify(data.left));
}
- /**
- * Returns a filter identifier from the SQL field
- * @event changer:getSQLFieldID
- * @memberof module:plugins.SqlSupport
- * @param {string} field
- * @param {*} value
- * @returns {string}
- */
- var id = self.change('getSQLFieldID', field, value);
+ var id = self.getSQLFieldID(field, value);
/**
* Modifies the rule generated from the SQL expression
@@ -583,6 +575,39 @@ QueryBuilder.extend(/** @lends module:plugins.SqlSupport.prototype */ {
*/
setRulesFromSQL: function(query, stmt) {
this.setRules(this.getRulesFromSQL(query, stmt));
+ },
+
+ /**
+ * Returns a filter identifier from the SQL field.
+ * Automatically use the only one filter with a matching field, fires a changer otherwise.
+ * @param {string} field
+ * @param {*} value
+ * @fires module:plugins.SqlSupport:changer:getSQLFieldID
+ * @returns {string}
+ * @private
+ */
+ getSQLFieldID: function(field, value) {
+ var matchingFilters = this.filters.filter(function(filter) {
+ return filter.field === field;
+ });
+
+ var id;
+ if (matchingFilters.length === 1) {
+ id = matchingFilters[0].id;
+ }
+ else {
+ /**
+ * Returns a filter identifier from the SQL field
+ * @event changer:getSQLFieldID
+ * @memberof module:plugins.SqlSupport
+ * @param {string} field
+ * @param {*} value
+ * @returns {string}
+ */
+ id = this.change('getSQLFieldID', field, value);
+ }
+
+ return id;
}
});
diff --git a/tests/index.html b/tests/index.html
index 875f9320..343c9210 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -33,6 +33,7 @@
+
diff --git a/tests/plugins.sql-support.module.js b/tests/plugins.sql-support.module.js
index 6dc82cfe..a64ecf4a 100644
--- a/tests/plugins.sql-support.module.js
+++ b/tests/plugins.sql-support.module.js
@@ -1,13 +1,13 @@
-$(function () {
+$(function() {
var $b = $('#builder');
QUnit.module('plugins.sql-support', {
- afterEach: function () {
+ afterEach: function() {
$b.queryBuilder('destroy');
}
});
- QUnit.test('Raw SQL', function (assert) {
+ QUnit.test('Raw SQL', function(assert) {
$b.queryBuilder({
filters: basic_filters,
rules: basic_rules
@@ -30,7 +30,7 @@ $(function () {
);
});
- QUnit.test('Placeholder SQL', function (assert) {
+ QUnit.test('Placeholder SQL', function(assert) {
$b.queryBuilder({
filters: basic_filters,
rules: basic_rules
@@ -53,7 +53,7 @@ $(function () {
);
});
- QUnit.test('Numbered SQL', function (assert) {
+ QUnit.test('Numbered SQL', function(assert) {
$b.queryBuilder({
filters: basic_filters,
rules: basic_rules
@@ -92,7 +92,7 @@ $(function () {
);
});
- QUnit.test('Named SQL', function (assert) {
+ QUnit.test('Named SQL', function(assert) {
$b.queryBuilder({
filters: basic_filters,
rules: basic_rules
@@ -131,7 +131,7 @@ $(function () {
);
});
- QUnit.test('All operators', function (assert) {
+ QUnit.test('All operators', function(assert) {
$b.queryBuilder({
filters: basic_filters,
rules: all_operators_rules
@@ -154,14 +154,14 @@ $(function () {
);
});
- QUnit.test('Nested rules', function (assert) {
+ QUnit.test('Nested rules', function(assert) {
$b.queryBuilder({
filters: [
- {id: 'a', type: 'integer'},
- {id: 'b', type: 'integer'},
- {id: 'c', type: 'integer'},
- {id: 'd', type: 'integer'}
+ { id: 'a', type: 'integer' },
+ { id: 'b', type: 'integer' },
+ { id: 'c', type: 'integer' },
+ { id: 'd', type: 'integer' }
]
});
@@ -191,7 +191,7 @@ $(function () {
);
});
- QUnit.test('Custom export/parsing', function (assert) {
+ QUnit.test('Custom export/parsing', function(assert) {
var rules = {
condition: 'AND',
rules: [
@@ -225,13 +225,13 @@ $(function () {
]
});
- $b.on('ruleToSQL.queryBuilder.filter', function (e, rule, sqlValue, sqlOperator) {
+ $b.on('ruleToSQL.queryBuilder.filter', function(e, rule, sqlValue, sqlOperator) {
if (rule.id === 'last_days') {
e.value = rule.field + ' ' + sqlOperator('DATE_SUB(NOW(), INTERVAL ' + sqlValue + ' DAY)');
}
});
- $b.on('parseSQLNode.queryBuilder.filter', function (e) {
+ $b.on('parseSQLNode.queryBuilder.filter', function(e) {
var data = e.value;
// left must be the field name and right must be the date_sub function
if (data.left && data.left.value == 'display_date' && data.operation == '>' && data.right && data.right.name == 'DATE_SUB') {
@@ -269,6 +269,44 @@ $(function () {
);
});
+ QUnit.test('Automatically use filter from field', function(assert) {
+ var rules = {
+ condition: 'AND',
+ rules: [
+ {
+ id: 'name',
+ operator: 'equal',
+ value: 'Mistic'
+ }
+ ]
+ };
+
+ var sql = 'username = \'Mistic\'';
+
+ $b.queryBuilder({
+ filters: [
+ {
+ id: 'name',
+ field: 'username',
+ type: 'string'
+ },
+ {
+ id: 'last_days',
+ field: 'display_date',
+ type: 'integer'
+ }
+ ]
+ });
+
+ $b.queryBuilder('setRulesFromSQL', sql);
+
+ assert.rulesMatch(
+ $b.queryBuilder('getRules'),
+ rules,
+ 'Should use "name" filter from "username" field'
+ );
+ });
+
var basic_rules_sql_raw = {
sql: 'price < 10.25 AND name IS NULL AND ( category IN(\'mo\', \'mu\') OR id != \'1234-azer-5678\' ) '
From 7b2b6863826cad430cbe8e5ef3dd485faff36710 Mon Sep 17 00:00:00 2001
From: David Beer-Gabel Output
$('.set-mongo').on('click', function() {
$('#builder').queryBuilder('setRulesFromMongo', {
"$or": [{
- "name": {
+ "username": {
"$regex": "^(?!Mistic)"
}
}, {
diff --git a/src/plugins/mongodb-support/plugin.js b/src/plugins/mongodb-support/plugin.js
index eca501bc..93a17348 100644
--- a/src/plugins/mongodb-support/plugin.js
+++ b/src/plugins/mongodb-support/plugin.js
@@ -270,15 +270,7 @@ QueryBuilder.extend(/** @lends module:plugins.MongoDbSupport.prototype */ {
var opVal = mdbrl.call(self, value);
- /**
- * Returns a filter identifier from the MongoDB field
- * @event changer:getMongoDBFieldID
- * @memberof module:plugins.MongoDbSupport
- * @param {string} field
- * @param {*} value
- * @returns {string}
- */
- var id = self.change('getMongoDBFieldID', field, value);
+ var id = self.getMongoDBFieldID(field, value);
/**
* Modifies the rule generated from the MongoDB expression
@@ -320,6 +312,39 @@ QueryBuilder.extend(/** @lends module:plugins.MongoDbSupport.prototype */ {
*/
setRulesFromMongo: function(query) {
this.setRules(this.getRulesFromMongo(query));
+ },
+
+ /**
+ * Returns a filter identifier from the MongoDB field.
+ * Automatically use the only one filter with a matching field, fires a changer otherwise.
+ * @param {string} field
+ * @param {*} value
+ * @fires module:plugins.MongoDbSupport:changer:getMongoDBFieldID
+ * @returns {string}
+ * @private
+ */
+ getMongoDBFieldID: function(field, value) {
+ var matchingFilters = this.filters.filter(function(filter) {
+ return filter.field === field;
+ });
+
+ var id;
+ if (matchingFilters.length === 1) {
+ id = matchingFilters[0].id;
+ }
+ else {
+ /**
+ * Returns a filter identifier from the MongoDB field
+ * @event changer:getMongoDBFieldID
+ * @memberof module:plugins.MongoDbSupport
+ * @param {string} field
+ * @param {*} value
+ * @returns {string}
+ */
+ id = this.change('getMongoDBFieldID', field, value);
+ }
+
+ return id;
}
});
diff --git a/tests/plugins.mongo-support.module.js b/tests/plugins.mongo-support.module.js
index 68e4a329..73ff20f9 100644
--- a/tests/plugins.mongo-support.module.js
+++ b/tests/plugins.mongo-support.module.js
@@ -62,6 +62,48 @@ $(function(){
);
});
+ QUnit.test('Automatically use filter from field', function(assert) {
+ var rules = {
+ condition: 'AND',
+ rules: [
+ {
+ id: 'name',
+ operator: 'equal',
+ value: 'Mistic'
+ }
+ ]
+ };
+
+ var mongo = {
+ $and: [{
+ username: 'Mistic'
+ }]
+ };
+
+ $b.queryBuilder({
+ filters: [
+ {
+ id: 'name',
+ field: 'username',
+ type: 'string'
+ },
+ {
+ id: 'last_days',
+ field: 'display_date',
+ type: 'integer'
+ }
+ ]
+ });
+
+ $b.queryBuilder('setRulesFromMongo', mongo);
+
+ assert.rulesMatch(
+ $b.queryBuilder('getRules'),
+ rules,
+ 'Should use "name" filter from "username" field'
+ );
+ });
+
var all_operators_rules = {
condition: 'AND',
From 845017c85bf73125a1dea5f657099fdb139cb63e Mon Sep 17 00:00:00 2001
From: mistic100 Output
-
+
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/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/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 @@
-
+
From d552fde68147ec6a8f654be409a51155af2e4171 Mon Sep 17 00:00:00 2001
From: Damien SOREL Output
2: 'warning',
5: 'success'
},
- operators: ['in', 'not_in', 'equal', 'not_equal', 'is_null', 'is_not_null']
+ operators: ['equal', 'not_equal', 'in', 'not_in', 'is_null', 'is_not_null'],
+ default_operator: 'in'
},
/*
* select
diff --git a/src/core.js b/src/core.js
index 764c8c6b..31964cc6 100644
--- a/src/core.js
+++ b/src/core.js
@@ -617,7 +617,20 @@ QueryBuilder.prototype.createRuleOperators = function(rule) {
$operatorContainer.html($operatorSelect);
// set the operator without triggering update event
- rule.__.operator = operators[0];
+ if (rule.filter.default_operator) {
+ rule.__.operator = operators.filter(function(operator) {
+ return operator.type === rule.filter.default_operator;
+ })[0];
+
+ if (!rule.__.operator) {
+ Utils.error('Config', 'Invalid operator {0}', rule.filter.default_operator);
+ }
+ }
+ else {
+ rule.__.operator = operators[0];
+ }
+
+ rule.$el.find(QueryBuilder.selectors.rule_operator).val(rule.operator.type);
/**
* After creating the dropdown for operators
@@ -752,6 +765,7 @@ QueryBuilder.prototype.updateRuleOperator = function(rule, previousOperator) {
*/
this.trigger('afterUpdateRuleOperator', rule);
+ // FIXME is it necessary ?
this.updateRuleValue(rule);
};
diff --git a/tests/common.js b/tests/common.js
index 91a3ffb5..89550f42 100644
--- a/tests/common.js
+++ b/tests/common.js
@@ -301,7 +301,8 @@ var basic_filters = [{
label: 'Age',
type: 'integer',
input: 'text',
- value_separator: '|'
+ value_separator: '|',
+ default_operator: 'in'
}];
var basic_rules = {
diff --git a/tests/data.module.js b/tests/data.module.js
index 358df511..ea381717 100644
--- a/tests/data.module.js
+++ b/tests/data.module.js
@@ -411,6 +411,23 @@ $(function() {
);
});
+ /**
+ * Test default operator
+ */
+ QUnit.test('default operator', function(assert) {
+ $b.queryBuilder({
+ filters: basic_filters
+ });
+
+ $('[name=builder_rule_0_filter]').val('age').trigger('change');
+
+ assert.equal(
+ $('[name=builder_rule_0_operator]').val(),
+ 'in',
+ 'Should set "age" operator to "in" by default'
+ );
+ });
+
/**
* Test allow_invalid option
*/
From 6331d3ea61c5eb7c740be8f26f633cd12813c85b Mon Sep 17 00:00:00 2001
From: mistic100 Output
}, {
id: 'coord',
operator: 'equal',
- value: 'B.3'
+ value: undefined // will use filter's default value
}]
}, {
id: 'name',
diff --git a/src/core.js b/src/core.js
index 31964cc6..5036062f 100644
--- a/src/core.js
+++ b/src/core.js
@@ -618,13 +618,7 @@ QueryBuilder.prototype.createRuleOperators = function(rule) {
// set the operator without triggering update event
if (rule.filter.default_operator) {
- rule.__.operator = operators.filter(function(operator) {
- return operator.type === rule.filter.default_operator;
- })[0];
-
- if (!rule.__.operator) {
- Utils.error('Config', 'Invalid operator {0}', rule.filter.default_operator);
- }
+ rule.__.operator = this.getOperatorByType(rule.filter.default_operator);
}
else {
rule.__.operator = operators[0];
diff --git a/src/public.js b/src/public.js
index 610a4adf..14a16c60 100644
--- a/src/public.js
+++ b/src/public.js
@@ -410,17 +410,22 @@ QueryBuilder.prototype.setRules = function(data, options) {
if (!item.empty) {
model.filter = self.getFilterById(item.id, !options.allow_invalid);
+ }
- if (model.filter) {
- model.operator = self.getOperatorByType(item.operator, !options.allow_invalid);
+ if (model.filter) {
+ model.operator = self.getOperatorByType(item.operator, !options.allow_invalid);
- if (!model.operator) {
- model.operator = self.getOperators(model.filter)[0];
- }
+ if (!model.operator) {
+ model.operator = self.getOperators(model.filter)[0];
+ }
+ }
- if (model.operator && model.operator.nb_inputs !== 0 && item.value !== undefined) {
- model.value = item.value;
- }
+ if (model.operator && model.operator.nb_inputs !== 0) {
+ if (item.value !== undefined) {
+ model.value = item.value;
+ }
+ else if (model.filter.default_value !== undefined) {
+ model.value = model.filter.default_value;
}
}
diff --git a/tests/data.module.js b/tests/data.module.js
index 72de4539..d7f11838 100644
--- a/tests/data.module.js
+++ b/tests/data.module.js
@@ -517,6 +517,35 @@ $(function() {
);
});
+ QUnit.test('apply default value', function(assert) {
+ $b.queryBuilder({
+ filters: [
+ {
+ id: 'name',
+ default_value: 'Mistic'
+ }
+ ],
+ rules: [
+ {
+ id: 'name'
+ }
+ ]
+ });
+
+ assert.rulesMatch(
+ $b.queryBuilder('getRules'),
+ {
+ condition: 'AND',
+ rules: [{
+ id: 'name',
+ operator: 'equal',
+ value: 'Mistic'
+ }]
+ },
+ 'Should have used the filter default value'
+ );
+ });
+
/**
* Test allow_empty_value option
*/
From e1887ad2650531ff3c3a0263442a8d7259251582 Mon Sep 17 00:00:00 2001
From: mistic100 \
-
Output
-
+
From f66174a0980cf13734849a4efb95978b54438289 Mon Sep 17 00:00:00 2001
From: mistic100 jQuery QueryBuilder
Output