/**
* @fileOverview jui_filter_rules is a jQuery plugin, useful to create dataset filter rules as JSON object and the relevant WHERE SQL.
*
License MIT
*
Copyright 2013 Christos Pontikis http://pontikis.net
*
Project page http://pontikis.net/labs/jui_filter_rules
* @version 1.0.2 (16 Oct 2013)
* @author Christos Pontikis http://www.pontikis.net
* @requires jquery, bowser.js (optional but highly recommended moment.js, jquery-ui)
*/
/**
* See http://jquery.com.
* @name $
* @class
* See the jQuery Library (http://jquery.com) for full details. This just
* documents the function and classes that are added to jQuery by this plug-in.
*/
/**
* See http://jquery.com
* @name fn
* @class
* See the jQuery Library (http://jquery.com) for full details. This just
* documents the function and classes that are added to jQuery by this plug-in.
* @memberOf $
*/
/**
* Pseudo-Namespace containing private methods (for documentation purposes)
* @name _private_methods
* @namespace
*/
"use strict";
(function($) {
var pluginName = 'jui_filter_rules',
pluginStatus = 'jui_filter_rules_status',
filter_types = [
"text",
"number",
"date"
], operators = [
{type: "equal", accept_values: "yes", apply_to: ["text", "number", "date"], group: "equality"},
{type: "not_equal", accept_values: "yes", apply_to: ["text", "number", "date"], group: "equality"},
{type: "in", accept_values: "yes", apply_to: ["text", "number", "date"], group: "multiple_choice"},
{type: "not_in", accept_values: "yes", apply_to: ["text", "number", "date"], group: "multiple_choice"},
{type: "less", accept_values: "yes", apply_to: ["number", "date"], group: "inequality"},
{type: "less_or_equal", accept_values: "yes", apply_to: ["number", "date"], group: "inequality"},
{type: "greater", accept_values: "yes", apply_to: ["number", "date"], group: "inequality"},
{type: "greater_or_equal", accept_values: "yes", apply_to: ["number", "date"], group: "inequality"},
{type: "begins_with", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "not_begins_with", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "contains", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "not_contains", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "ends_with", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "not_ends_with", accept_values: "yes", apply_to: ["text"], group: "substring"},
{type: "is_empty", accept_values: "no", apply_to: ["text"], group: "empty_string"},
{type: "is_not_empty", accept_values: "no", apply_to: ["text"], group: "empty_string"},
{type: "is_null", accept_values: "no", apply_to: ["text", "number", "date"], group: "null"},
{type: "is_not_null", accept_values: "no", apply_to: ["text", "number", "date"], group: "null"}
];
/* public methods ------------------------------------------------------- */
var methods = {
/**
* @lends $.fn.jui_filter_rules
*/
init: function(options) {
var elem = this;
return this.each(function() {
/**
* settings and defaults
* using $.extend, settings modification will affect elem.data() and vive versa
*/
var settings = elem.data(pluginName);
if(typeof(settings) == 'undefined') {
var defaults = elem.jui_filter_rules('getDefaults');
settings = $.extend({}, defaults, options);
} else {
settings = $.extend({}, settings, options);
}
elem.data(pluginName, settings);
// initialize plugin status
if(typeof elem.data(pluginStatus) === 'undefined') {
elem.data(pluginStatus, {});
elem.data(pluginStatus)["group_id"] = 0;
elem.data(pluginStatus)["rule_id"] = 0;
}
var container_id = elem.attr("id");
// simple validation
validate_input(container_id);
// bind events
elem.unbind("onValidationError").bind("onValidationError", settings.onValidationError);
var filters = settings.filters,
filters_list_id_prefix = create_id(settings.filters_list_id_prefix, container_id) + '_',
operators_container_id_prefix = create_id(settings.operators_container_id_prefix, container_id) + '_',
operators_list_id_prefix = create_id(settings.operators_list_id_prefix, container_id) + '_',
operator,
filter_value_container_id_prefix = create_id(settings.filter_value_container_id_prefix, container_id) + '_',
group_condition_id_prefix = create_id(settings.group_condition_id_prefix, container_id) + '_',
group_tools_id_prefix = create_id(settings.group_tools_id_prefix, container_id) + '_',
rule_tools_id_prefix = create_id(settings.rule_tools_id_prefix, container_id) + '_',
filters_list_id, operators_list_id, operators_container_id, filter_value_container_id,
elem_filters_list, elem_operators_list, elem_operators_container, elem_filter_value_container,
selector, len, rule_id, filter_index, group_selected, tool_selected,
rulesListLiAppliedClass = settings.rulesListLiAppliedClass,
rulesListLiErrorClass = settings.rulesListLiErrorClass;
if(elem.data(pluginStatus)["rule_id"] == 0) {
if(filters.length > 0) {
elem.html(createRulesGroup(container_id));
} else {
elem.html('
' + rsc_jui_fr.no_filters_found + '
');
}
}
elem.addClass(settings.containerClass);
/* EVENTS --------------------------------------------------- */
// rule group actions
selector = '[id^="' + group_tools_id_prefix + '"]';
elem.off('change', selector).on('change', selector, function() {
len = group_tools_id_prefix.length;
rule_id = $(this).attr("id").substr(len);
group_selected = $(this).val();
switch(group_selected) {
case "rule_insert_before":
$(this).closest("dt").parent("dl").before(createRule(container_id));
break;
case "rule_insert_after":
$(this).closest("dt").parent("dl").after(createRule(container_id));
break;
case "rule_insert_inside":
$(this).closest("dt").next("dd:first").find("ul:first").prepend(createRule(container_id));
break;
case "group_insert_before":
$(this).closest("dl").before(createRulesGroup(container_id));
break;
case "group_insert_after":
$(this).closest("dl").after(createRulesGroup(container_id));
break;
case "group_insert_inside":
$(this).closest("dt").next("dd:first").find("ul:first").prepend(createRulesGroup(container_id));
break;
case "group_delete":
$(this).closest("dl").remove();
break;
}
$(this).prop("selectedIndex", 0);
});
// rule actions
selector = '[id^="' + rule_tools_id_prefix + '"]';
elem.off('change', selector).on('change', selector, function() {
len = rule_tools_id_prefix.length;
rule_id = $(this).attr("id").substr(len);
tool_selected = $(this).val();
switch(tool_selected) {
case "rule_insert_before":
$(this).closest("li").before(createRule(container_id));
break;
case "rule_insert_after":
$(this).closest("li").after(createRule(container_id));
break;
case "rule_clear":
filters_list_id = filters_list_id_prefix + rule_id;
operators_container_id = operators_container_id_prefix + rule_id;
filter_value_container_id = filter_value_container_id_prefix + rule_id;
elem_filters_list = $("#" + filters_list_id);
elem_operators_container = $("#" + operators_container_id);
elem_filter_value_container = $("#" + filter_value_container_id);
elem_filters_list.prop("selectedIndex", 0);
elem_operators_container.html('');
elem_filter_value_container.html('');
elem.jui_filter_rules("markRuleAsPending", $(this).closest("li").attr("id"));
break;
case "rule_delete":
$(this).closest("li").remove();
break;
case "group_insert_before":
$(this).closest("li").before(createRulesGroup(container_id));
break;
case "group_insert_after":
$(this).closest("li").after(createRulesGroup(container_id));
break;
}
$(this).prop("selectedIndex", 0);
});
// change group condition
selector = '[id^="' + group_condition_id_prefix + '"]';
elem.off('change', selector).on('change', selector, function() {
// unmark applied rules
$(this).closest("dl").find("li").each(function() {
elem.jui_filter_rules("markRuleAsApplied", $(this).attr("id"), false);
});
});
// change filter
selector = '[id^="' + filters_list_id_prefix + '"]';
elem.off('change', selector).on('change', selector, function() {
len = filters_list_id_prefix.length;
rule_id = $(this).attr("id").substr(len);
filter_index = $(this).prop('selectedIndex') - 1;
operators_container_id = operators_container_id_prefix + rule_id;
operators_list_id = operators_list_id_prefix + rule_id;
filter_value_container_id = filter_value_container_id_prefix + rule_id;
elem_operators_container = $("#" + operators_container_id);
elem_filter_value_container = $("#" + filter_value_container_id);
elem_filter_value_container.show();
if(filter_index >= 0) {
elem_operators_container.html(create_operators_list(container_id, rule_id, $(this).val()));
elem_operators_list = $("#" + operators_list_id);
create_filter_value(container_id, rule_id, $(this).val(), elem_operators_list.val());
} else {
elem_operators_container.html('');
elem_filter_value_container.html('');
}
elem.jui_filter_rules("markRuleAsPending", $(this).closest("li").attr("id"));
});
// change operator
selector = '[id^="' + operators_list_id_prefix + '"]';
elem.off('change', selector).on('change', selector, function() {
len = operators_list_id_prefix.length;
rule_id = $(this).attr("id").substr(len);
filters_list_id = filters_list_id_prefix + rule_id;
operators_list_id = operators_list_id_prefix + rule_id;
filter_value_container_id = filter_value_container_id_prefix + rule_id;
elem_filters_list = $("#" + filters_list_id);
elem_operators_list = $("#" + operators_list_id);
elem_filter_value_container = $("#" + filter_value_container_id);
operator = getOperator($(this).val());
if(operator.accept_values !== "yes") {
elem_filter_value_container.hide();
} else {
elem_filter_value_container.show();
if(elem_filter_value_container.html() == '') {
create_filter_value(container_id, rule_id, elem_filters_list.val(), elem_operators_list.val());
}
}
elem.jui_filter_rules("markRuleAsPending", $(this).closest("li").attr("id"));
});
});
},
/**
* Get default values
* @example $(element).jui_filter_rules('getDefaults');
* @return {Object}
*/
getDefaults: function() {
return {
filters: [],
decimal_separator: ".",
htmlentities: false,
// styles
containerClass: "filter_rules_container",
rulesGroupContainerClass: "rules_group_container",
rulesGroupHeaderClass: "rules_group_header",
rulesGroupBodyClass: "rules_group_body",
rulesGroupConditionContainerClass: "rules_group_condition_container",
rulesGroupConditionListClass: "rules_group_condition_list",
rulesGroupToolsContainerClass: "rules_group_tools_container",
rulesGroupToolsListClass: "rules_group_tools_list",
rulesListClass: "rules_list",
rulesListLiClass: "rules_list_li",
rulesListLiErrorClass: "rules_list_error_li",
rulesListLiAppliedClass: "rules_list_applied_li",
filterContainerClass: "filter_container",
filterListClass: "filter_list",
operatorsListContainerClass: "operators_list_container",
operatorsListClass: "operators_list",
filterValueContainerClass: "filter_value_container",
filterInputTextClass: "filter_input_text",
filterInputNumberClass: "filter_input_number",
filterInputDateClass: "filter_input_date",
filterInputCheckboxClass: "filter_input_checkbox",
filterInputRadioClass: "filter_input_radio",
filterSelectClass: "filter_select",
filterGroupListClass: "filter_group_list",
filterGroupListItemHorizontalClass: "filter_group_list_item_horizontal",
filterGroupListItemVerticalClass: "filter_group_list_item_vertical",
ruleToolsContainerClass: "rule_tools_container",
ruleToolsClass: "rule_tools_list",
noFiltersFoundClass: "no_filters_found",
// elements id prefix
group_dl_id_prefix: "group_",
group_condition_id_prefix: "group_cond_",
group_tools_id_prefix: "group_tools_",
rule_li_id_prefix: "rule_",
filters_list_id_prefix: "filters_list_",
operators_container_id_prefix: "oper_wrap_",
operators_list_id_prefix: "oper_list_",
filter_value_container_id_prefix: "flt_wrap_",
filter_element_id_prefix: "flt_",
filter_element_name_prefix: "flt_name_",
rule_tools_id_prefix: "rule_tools_",
onValidationError: function() {
}
};
},
/**
* Get any option set to plugin using its name (as string)
* @example $(element).jui_filter_rules('getOption', some_option);
* @param {String} opt
* @return {*}
*/
getOption: function(opt) {
var elem = this;
return elem.data(pluginName)[opt];
},
/**
* Get all options
* @example $(element).jui_filter_rules('getAllOptions');
* @return {*}
*/
getAllOptions: function() {
var elem = this;
return elem.data(pluginName);
},
/**
* Set option
* @example $(element).jui_filter_rules('setOption', 'option_name', 'option_value', reinit);
* @param {String} opt option name
* @param val
* @param {Boolean} reinit
*/
setOption: function(opt, val, reinit) {
var elem = this;
elem.data(pluginName)[opt] = val;
if(reinit) {
elem.jui_filter_rules('init');
}
},
/**
* Refresh plugin
* @example $(element).jui_filter_rules('refresh');
* @return {*|jQuery}
*/
refresh: function() {
var elem = this;
elem.jui_filter_rules();
},
/**
* Destroy plugin
* @example $(element).jui_filter_rules('destroy');
* @return {*|jQuery}
*/
destroy: function() {
return $(this).each(function() {
var $this = $(this);
$this.removeData(pluginName);
});
},
/**
* Get rules
* @example $(element).jui_filter_rules("getRules", 0, []);
* @param {Number} rules_group_index The index of rules group
* @param {Array} a_rules Rules array
* @return {*} rules array or false (on validation error)
*/
getRules: function(rules_group_index, a_rules) {
var elem = this,
container_id = elem.attr("id"),
rules_group, group_logical_operator,
a_group_rules, a_group_rules_len, r, group_rule,
current_rule, filter_name, filter_operator, current_filter, current_filter_value,
rule_li_id_prefix = create_id(elem.jui_filter_rules("getOption", "rule_li_id_prefix"), container_id) + '_',
rule_li_id_prefix_len = rule_li_id_prefix.length, rule_id,
pos;
rules_group = elem.find("dl").eq(rules_group_index);
group_logical_operator = rules_group.find("dt:first").find("select:first").val();
a_group_rules = rules_group.find("dd:first").find("ul:first").children().get();
a_group_rules_len = a_group_rules.length;
for(r = 0; r < a_group_rules_len; r++) {
group_rule = a_group_rules[r];
current_rule = {};
if(group_rule.tagName == 'LI') {
// no filter set
if($(group_rule).find("select:first").prop("selectedIndex") == 0) {
continue;
}
rule_id = $(group_rule).attr("id").substr(rule_li_id_prefix_len);
current_rule.element_rule_id = $(group_rule).attr("id");
current_rule.condition = {};
filter_name = $(group_rule).find("select:first").val();
current_filter = remove_obj_empty_props(getFilterByName(container_id, filter_name));
filter_operator = $(group_rule).find("select").eq(1).val();
current_rule.condition.filterType = current_filter.filterType;
if(current_filter.hasOwnProperty("numberType")) {
current_rule.condition.numberType = current_filter.numberType;
}
current_rule.condition.field = current_filter.field;
current_rule.condition.operator = filter_operator;
current_filter_value = get_filter_value(container_id, rule_id, current_filter, filter_operator);
if(current_filter_value === false) {
return false;
} else {
if(current_filter_value.length > 0) {
current_rule.condition.filterValue = current_filter_value;
}
}
if(getOperator(filter_operator).accept_values == "yes") {
if(current_filter.hasOwnProperty("filter_value_conversion_server_side")) {
current_rule.filter_value_conversion_server_side = current_filter.filter_value_conversion_server_side;
}
}
current_rule.logical_operator = group_logical_operator;
a_rules.push(current_rule);
} else if(group_rule.tagName == 'DL') {
current_rule.condition = [];
current_rule.logical_operator = group_logical_operator;
a_rules.push(current_rule);
pos = a_rules.length - 1;
rules_group_index = parseInt(rules_group_index) + 1;
elem.jui_filter_rules("getRules", rules_group_index, a_rules[pos].condition);
// cleanup empty groups
cleanup_empty_groups(a_rules);
}
}
return a_rules;
},
/**
* Mark rule as applied
* @example $(element).jui_filter_rules("markRuleAsApplied", "element_rule_id", true);
*
* @param {String} element_rule_id
* @param {Boolean} status
*/
markRuleAsApplied: function(element_rule_id, status) {
var elem = this,
elem_rule = $("#" + element_rule_id),
rulesListLiAppliedClass = elem.jui_filter_rules("getOption", "rulesListLiAppliedClass");
if(status) {
elem_rule.addClass(rulesListLiAppliedClass);
} else {
elem_rule.removeClass(rulesListLiAppliedClass);
}
},
/**
* Mark rule as error
* @example $(element).jui_filter_rules("markRuleAsError", "element_rule_id", true);
*
* @param {String} element_rule_id
* @param {Boolean} status
*/
markRuleAsError: function(element_rule_id, status) {
var elem = this,
elem_rule = $("#" + element_rule_id),
rulesListLiErrorClass = elem.jui_filter_rules("getOption", "rulesListLiErrorClass");
if(status) {
elem_rule.addClass(rulesListLiErrorClass);
} else {
elem_rule.removeClass(rulesListLiErrorClass);
}
},
/**
* Mark rule as pending
* @example $(element).jui_filter_rules("markRuleAsPending", "element_rule_id");
*
* @param {String} element_rule_id
*/
markRuleAsPending: function(element_rule_id) {
var elem = this,
elem_rule = $("#" + element_rule_id),
rulesListLiErrorClass = elem.jui_filter_rules("getOption", "rulesListLiErrorClass"),
rulesListLiAppliedClass = elem.jui_filter_rules("getOption", "rulesListLiAppliedClass");
elem_rule.removeClass(rulesListLiErrorClass);
elem_rule.removeClass(rulesListLiAppliedClass);
},
/**
* Mark all rules as applied
* @example $(element).jui_filter_rules("markAllRulesAsApplied");
*/
markAllRulesAsApplied: function() {
var elem = this,
rulesListLiErrorClass = elem.jui_filter_rules("getOption", "rulesListLiErrorClass"),
rulesListLiAppliedClass = elem.jui_filter_rules("getOption", "rulesListLiAppliedClass"),
a_rules = elem.jui_filter_rules("getRules", 0, []);
if(a_rules !== false) {
if(a_rules.length > 0) {
elem.find("li").each(function() {
if($(this).find("select:first").prop("selectedIndex") > 0) {
elem.jui_filter_rules("markRuleAsError", $(this).attr("id"), false);
elem.jui_filter_rules("markRuleAsApplied", $(this).attr("id"), true);
}
})
}
}
},
/**
* Clear rules
* @example $(element).jui_filter_rules("clearAllRules");
*/
clearAllRules: function() {
var elem = this,
container_id = elem.attr("id");
elem.find("dl:first").html('');
elem.data(pluginStatus)["group_id"] = 0;
elem.data(pluginStatus)["rule_id"] = 0;
elem.jui_filter_rules("refresh");
}
};
/* private methods ------------------------------------------------------ */
/**
* @lends _private_methods
*/
/**
* Validate input values
* @param container_id
*/
var validate_input = function(container_id) {
var elem = $("#" + container_id),
err_msg, i,
filters = elem.jui_filter_rules("getOption", "filters"),
filters_len = filters.length,
filternames = [];
// unique filter name
for(i = 0; i < filters_len; i++) {
filternames.push(filters[i].filterName);
}
if(array_has_duplicates(filternames)) {
err_msg = 'Filternames are not unique...';
elem.html('' + 'ERROR: ' + err_msg + '');
$.error(err_msg);
}
};
/**
* Create element id
* @param prefix
* @param plugin_container_id
* @return {*}
*/
var create_id = function(prefix, plugin_container_id) {
return prefix + plugin_container_id;
};
/**
* Check array for duplicated values
* @param arr
* @return {Boolean}
*/
var array_has_duplicates = function(arr) {
var x = {}, len = arr.length, i;
for(i = 0; i < len; i++) {
if(x[arr[i]] === true) {
return true;
}
x[arr[i]] = true;
}
return false;
};
/**
*
* @param value
* @return {*}
*/
var htmlEncode = function(value) {
if(value) {
return jQuery('').text(value).html();
} else {
return '';
}
};
/**
*
* @param value
* @return {*}
*/
var htmlDecode = function(value) {
if(value) {
return $('').html(value).text();
} else {
return '';
}
};
/**
* Remove empty object properties
* @param obj
* @return {Object}
*/
var remove_obj_empty_props = function(obj) {
var obj_clone = {}, prop;
for(prop in obj) {
if(obj.hasOwnProperty(prop)) {
if(obj[prop] !== "") {
obj_clone[prop] = obj[prop];
}
}
}
return obj_clone;
};
/**
* Remove empty rule groups
* @param {Array} a_rules
*/
var cleanup_empty_groups = function(a_rules) {
var i, condition, len = a_rules.length;
for(i = 0; i < len; i++) {
condition = a_rules[i].condition;
if($.isArray(condition)) {
if(condition.length == 0) {
a_rules.splice(i, 1);
} else {
cleanup_empty_groups(condition);
}
}
}
};
/**
*
* Escape regex special characters !@#$^&%*()+=-[]\/{}|:<>?,.
*
* @param expr
* @return {String|XML|void}
*
* @see http://simonwillison.net/2006/Jan/20/escape/#p-6
* @see http://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript
*/
var RegExp_escape = function(expr) {
return expr.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
/**
* Get filter attributes by filter name
* @param {String} container_id
* @param {String} filter_name
* @return {*} filter object or undefined
*/
var getFilterByName = function(container_id, filter_name) {
var elem = $("#" + container_id),
i, filters = elem.jui_filter_rules("getOption", "filters"),
filters_len = filters.length,
flt = undefined;
for(i = 0; i < filters_len; i++) {
if(filters[i].filterName == filter_name) {
flt = filters[i];
break;
}
}
return flt;
};
/**
* Get operators for filter type
* @param filterName {string}
* @return {Array}
*/
var getOperators = function(container_id, filterName) {
var elem = $("#" + container_id),
filters = elem.jui_filter_rules("getOption", "filters"),
filter, filter_type, excluded_operators,
operators_len = operators.length,
i, oper = [], item;
filter = getFilterByName(container_id, filterName);
filter_type = filter.filterType;
excluded_operators = (filter.excluded_operators === undefined ? [] : filter.excluded_operators);
for(i = 0; i < operators_len; i++) {
if($.inArray(operators[i].type, excluded_operators) > -1) {
continue;
}
if($.inArray(filter_type, operators[i].apply_to) > -1) {
item = {};
item.operator_type = operators[i].type;
item.operator_label = rsc_jui_fr['operator_' + operators[i].type];
item.group = operators[i].group;
oper.push(item);
}
}
return oper;
};
/**
* Get operator attributes
* @param operator_type
* @return {*} operator object or undefined
*/
var getOperator = function(operator_type) {
var i,
operators_len = operators.length,
oper = undefined;
for(i = 0; i < operators_len; i++) {
if(operators[i].type == operator_type) {
oper = operators[i];
break;
}
}
return oper;
};
/**
* Create rules group condition select (AND - OR)
* @return {String}
*/
var create_group_condition = function(container_id) {
var elem = $("#" + container_id),
group_condition_id,
rulesGroupConditionContainerClass = elem.jui_filter_rules('getOption', 'rulesGroupConditionContainerClass'),
rulesGroupConditionListClass = elem.jui_filter_rules('getOption', 'rulesGroupConditionListClass'),
gc_html = '';
group_condition_id = create_id(elem.jui_filter_rules('getOption', 'group_condition_id_prefix'), container_id) +
'_' + elem.data(pluginStatus)["group_id"];
gc_html += '';
gc_html += '';
gc_html += '
';
return gc_html;
};
/**
* Cgeate rules group tools dropdown list
* @param container_id {String}
* @return {String}
*/
var create_rules_group_tools = function(container_id) {
var elem = $("#" + container_id),
rule_id = parseInt(elem.data(pluginStatus)["rule_id"]),
rulesGroupToolsContainerClass = elem.jui_filter_rules("getOption", "rulesGroupToolsContainerClass"),
rulesGroupToolsListClass = elem.jui_filter_rules("getOption", "rulesGroupToolsListClass"),
group_tools_id = create_id(elem.jui_filter_rules("getOption", "group_tools_id_prefix"), container_id) + '_' + rule_id,
disabled_html = (rule_id == 0 ? ' disabled="disabled"' : ''),
shrink_class_html = (bowser.msie && parseInt(bowser.version) < 9 ? '' : ' tools_list_shrink'),
tools_html = '';
tools_html += '';
tools_html += '';
tools_html += '
';
return tools_html;
};
/**
* Create filters list
* @param container_id {string}
* @return {String} filter list html
*/
var create_filters_list = function(container_id) {
var elem = $("#" + container_id),
rule_id = parseInt(elem.data(pluginStatus)["rule_id"]),
filters = elem.jui_filter_rules('getOption', 'filters'),
filters_len = filters.length,
filterContainerClass = elem.jui_filter_rules("getOption", "filterContainerClass"),
filterListClass = elem.jui_filter_rules("getOption", "filterListClass"),
filters_list_id = create_id(elem.jui_filter_rules("getOption", "filters_list_id_prefix"), container_id) + '_' + rule_id,
i, f_html = '';
f_html += '';
f_html += '';
f_html += '
';
return f_html;
};
/**
* Create operator list
* @param container_id
* @param rule_id
* @param filterName
*/
var create_operators_list = function(container_id, rule_id, filterName) {
var elem = $("#" + container_id),
operators_container_id = create_id(elem.jui_filter_rules("getOption", "operators_container_id_prefix"), container_id) + '_' + rule_id,
elem_operators_container = $("#" + operators_container_id),
operatorsListClass = elem.jui_filter_rules("getOption", "operatorsListClass"),
operators_list_id_prefix = create_id(elem.jui_filter_rules("getOption", "operators_list_id_prefix"), container_id) + '_',
operators_list_id = operators_list_id_prefix + rule_id,
oper, i, len, oper_html = '', operators_group = '';
oper = getOperators(container_id, filterName);
len = oper.length;
oper_html += '';
elem_operators_container.html(oper_html);
};
/**
* Create inputs or widgets for the user to set filter values
* @param container_id {String}
* @param rule_id {String}
* @param filterName {String}
* @param operator_type {String}
* @return {Boolean}
*/
var create_filter_value = function(container_id, rule_id, filterName, operator_type) {
var elem = $("#" + container_id),
operator = getOperator(operator_type),
filter_value_container_id = create_id(elem.jui_filter_rules("getOption", "filter_value_container_id_prefix"), container_id) + '_' + rule_id,
elem_filter_value_container = $("#" + filter_value_container_id),
filters = elem.jui_filter_rules('getOption', 'filters'),
filter = remove_obj_empty_props(getFilterByName(container_id, filterName)),
filter_type = filter.filterType,
filter_interface = filter.filter_interface,
filter_interface_len = filter_interface.length, i,
filter_element, filter_element_id, filter_element_name, filter_input_type = "", filter_element_attributes, fe_attr,
a_ignore_attributes = ["id", "name"],
class_name_default = "",
filter_lookup_data, filter_lookup_data_len, lk, selected_html, lookup_values_ajax_url = "",
vertical_orientation = "no", group_list_item_class,
group_list_class = elem.jui_filter_rules("getOption", "filterGroupListClass"),
filterGroupListItemHorizontalClass = elem.jui_filter_rules("getOption", "filterGroupListItemHorizontalClass"),
filterGroupListItemVerticalClass = elem.jui_filter_rules("getOption", "filterGroupListItemVerticalClass"),
f_html = '';
if(operator.accept_values !== "yes") {
elem_filter_value_container.html('');
return true;
}
if(filter.hasOwnProperty("lookup_values_ajax_url")) {
lookup_values_ajax_url = filter["lookup_values_ajax_url"];
$.ajax({
url: lookup_values_ajax_url,
success: (function(data) {
filter_lookup_data = $.parseJSON(data);
elem_filter_value_container.html(create_filter_value_html());
apply_widgets();
})
});
} else {
if(filter.hasOwnProperty("lookup_values")) {
filter_lookup_data = filter["lookup_values"];
}
elem_filter_value_container.html(create_filter_value_html());
apply_widgets();
}
// ---------------------------------------------------------------------
function create_filter_value_html() {
for(i = 0; i < filter_interface_len; i++) {
filter_element = filter_interface[i].filter_element;
filter_element_attributes = remove_obj_empty_props(filter_interface[i].filter_element_attributes);
if(filter_element == "input") {
filter_input_type = filter_element_attributes["type"];
}
setFilterElementIgnoreProperties();
if(filter_input_type == "checkbox" || filter_input_type == "radio") {
setFilterGroupClass();
filter_lookup_data_len = filter_lookup_data.length;
f_html += '';
for(lk = 0; lk < filter_lookup_data_len; lk++) {
f_html += '- ';
f_html += '<' + filter_element;
setFilterElementID(lk);
f_html += ' id="' + filter_element_id + '"';
if(filter_input_type == "radio") {
setFilterElementName();
f_html += ' name="' + filter_element_name + '"';
}
setFilterElementAttributes();
f_html += ' value="' + filter_lookup_data[lk]["lk_value"] + '"';
selected_html = (filter_lookup_data[lk]["lk_selected"] == 'yes' ? ' checked="checked"' : '');
f_html += selected_html;
f_html += '>';
f_html += '';
f_html += '
';
}
f_html += '
';
} else {
f_html += '<' + filter_element;
setFilterElementID(i);
f_html += ' id="' + filter_element_id + '"';
setFilterElementAttributes();
f_html += '>';
if(filter_element == "select") {
createFilterElementSelectOptions();
}
if(filter_element == "div") {
f_html += '';
}
}
}
return f_html;
}
// ---------------------------------------------------------------------
function setFilterElementID(group_index) {
filter_element_id = create_id(elem.jui_filter_rules("getOption", "filter_element_id_prefix"), container_id)
+ '_' + rule_id
+ '_' + group_index;
}
// ---------------------------------------------------------------------
function setFilterElementName() {
filter_element_name = create_id(elem.jui_filter_rules("getOption", "filter_element_name_prefix"), container_id) + '_' + rule_id;
}
// ---------------------------------------------------------------------
function setFilterElementIgnoreProperties() {
if(filter_element == "input") {
if(filter_input_type == "text") {
a_ignore_attributes = ["id", "name"]
} else if(filter_input_type == "radio") {
a_ignore_attributes = ["id", "name", "value", "checked"]
} else if(filter_input_type == "checkbox") {
a_ignore_attributes = ["id", "name", "value", "checked"]
}
} else if(filter_element == "select") {
a_ignore_attributes = ["id", "name", "value"]
}
}
// ---------------------------------------------------------------------
function setFilterElementDefaultClass() {
var class_option = "";
class_name_default = "";
if(filter_element == "input") {
if(filter_input_type == "text") {
if(filter_type == "text") {
class_option = "filterInputTextClass";
} else if(filter_type == "number") {
class_option = "filterInputNumberClass";
} else if(filter_type == "date") {
class_option = "filterInputDateClass";
}
} else if(filter_input_type == "radio") {
class_option = "filterInputRadioClass";
} else if(filter_input_type == "checkbox") {
class_option = "filterInputCheckboxClass";
}
} else if(filter_element == "select") {
class_option = "filterSelectClass";
}
if(class_option !== "") {
class_name_default = elem.jui_filter_rules('getOption', class_option);
}
}
// ---------------------------------------------------------------------
function setFilterElementAttributes() {
for(fe_attr in filter_element_attributes) {
if(filter_element_attributes.hasOwnProperty(fe_attr)) {
if($.inArray(fe_attr, a_ignore_attributes) > -1) {
continue;
}
f_html += ' ' + fe_attr + '="' + filter_element_attributes[fe_attr] + '"';
}
}
if(!filter_element_attributes.hasOwnProperty("class")) {
setFilterElementDefaultClass();
if(class_name_default !== "") {
f_html += ' class="' + class_name_default + '"';
}
}
}
// ---------------------------------------------------------------------
function createFilterElementSelectOptions() {
filter_lookup_data_len = filter_lookup_data.length;
for(lk = 0; lk < filter_lookup_data_len; lk++) {
selected_html = (filter_lookup_data[lk]["lk_selected"] == 'yes' ? ' selected="selected"' : '');
f_html += '';
}
f_html += '';
}
// ---------------------------------------------------------------------
function setFilterGroupClass() {
vertical_orientation = "no";
if(filter_interface[i].hasOwnProperty("vertical_orientation")) {
vertical_orientation = filter_interface[i].vertical_orientation;
}
group_list_item_class = (vertical_orientation == "yes" ? filterGroupListItemVerticalClass : filterGroupListItemHorizontalClass);
}
// ---------------------------------------------------------------------
function apply_widgets() {
if(filter_input_type == "checkbox" || filter_input_type == "radio") {
return true;
}
for(i = 0; i < filter_interface_len; i++) {
if(!filter_interface[i].hasOwnProperty("filter_widget")) {
continue;
}
filter_element_id = create_id(elem.jui_filter_rules("getOption", "filter_element_id_prefix"), container_id) + '_' + rule_id
+ '_' + i;
var elem_filter = $("#" + filter_element_id);
var filter_widget = filter_interface[i]["filter_widget"];
var filter_widget_properties = filter_interface[i]["filter_widget_properties"];
if(filter_widget == "datepicker") {
elem_filter.datepicker(
filter_widget_properties
);
}
if(filter_widget == "datetimepicker") {
elem_filter.datetimepicker(
filter_widget_properties
);
}
if(filter_widget == "autocomplete") {
elem_filter.autocomplete(filter_widget_properties);
}
if(filter_widget == "spinner") {
elem_filter.spinner(filter_widget_properties);
}
if(filter_widget == "slider") {
elem_filter.slider(filter_widget_properties);
}
}
return true;
}
// ---------------------------------------------------------------------
return true;
};
/**
* Create rule tools dropdown list
* @param container_id {string}
* @return {String}
*/
var create_rule_tools = function(container_id) {
var elem = $("#" + container_id),
rule_id = parseInt(elem.data(pluginStatus)["rule_id"]),
ruleToolsContainerClass = elem.jui_filter_rules("getOption", "ruleToolsContainerClass"),
ruleToolsClass = elem.jui_filter_rules("getOption", "ruleToolsClass"),
rule_tools_id = create_id(elem.jui_filter_rules("getOption", "rule_tools_id_prefix"), container_id) + '_' + rule_id,
shrink_class_html = (bowser.msie && parseInt(bowser.version) < 9 ? '' : ' tools_list_shrink'),
tools_html = '';
tools_html += '';
tools_html += '';
tools_html += '
';
return tools_html;
};
/**
* Create a group of rules (with the first rule)
* @param container_id
* @return {String}
*/
var createRulesGroup = function(container_id) {
var elem = $("#" + container_id),
group_dl_id_prefix = elem.jui_filter_rules("getOption", "group_dl_id_prefix"),
group_dl_id, group_id,
rulesGroupContainerClass = elem.jui_filter_rules("getOption", "rulesGroupContainerClass"),
rulesGroupHeaderClass = elem.jui_filter_rules("getOption", "rulesGroupHeaderClass"),
rulesGroupBodyClass = elem.jui_filter_rules("getOption", "rulesGroupBodyClass"),
rulesListClass = elem.jui_filter_rules("getOption", "rulesListClass"),
rg_html = '';
group_id = parseInt(elem.data(pluginStatus)["group_id"]) + 1;
elem.data(pluginStatus)["group_id"] = group_id;
group_dl_id = create_id(group_dl_id_prefix, container_id) + '_' + group_id;
rg_html += '';
rg_html += '';
rg_html += '- ';
rg_html += '
';
rg_html += createRule(container_id);
rg_html += '
';
rg_html += ' ';
rg_html += '
';
return rg_html;
};
/**
* Create rule
* @param container_id {String}
* @return {String}
*/
var createRule = function(container_id) {
var elem = $("#" + container_id),
rulesListLiClass = elem.jui_filter_rules("getOption", "rulesListLiClass"),
operatorsListContainerClass = elem.jui_filter_rules("getOption", "operatorsListContainerClass"),
filterValueContainerClass = elem.jui_filter_rules("getOption", "filterValueContainerClass"),
rule_li_id_prefix = create_id(elem.jui_filter_rules("getOption", "rule_li_id_prefix"), container_id) + '_',
operators_container_id_prefix = create_id(elem.jui_filter_rules("getOption", "operators_container_id_prefix"), container_id) + '_',
filter_value_container_id_prefix = create_id(elem.jui_filter_rules("getOption", "filter_value_container_id_prefix"), container_id) + '_',
rule_li_id, operators_container_id, filter_value_container_id, rule_id,
r_html = '';
rule_id = parseInt(elem.data(pluginStatus)["rule_id"]) + 1;
elem.data(pluginStatus)["rule_id"] = rule_id;
operators_container_id = operators_container_id_prefix + rule_id;
filter_value_container_id = filter_value_container_id_prefix + rule_id;
rule_li_id = rule_li_id_prefix + rule_id;
r_html += '';
r_html += create_filters_list(container_id);
r_html += '';
r_html += '
';
r_html += '';
r_html += '
';
r_html += create_rule_tools(container_id);
r_html += '';
return r_html;
};
/**
* Get filter value
* @param container_id
* @param rule_id
* @param filter
* @param operator_type
* @return {Array} or false if input validation failed
*/
var get_filter_value = function(container_id, rule_id, filter, operator_type) {
var elem = $("#" + container_id),
filter_type = filter.filterType,
filter_interface = filter.filter_interface,
filter_interface_len = filter_interface.length, i,
filter_element,
filter_value_container_id = create_id(elem.jui_filter_rules("getOption", "filter_value_container_id_prefix"), container_id) + '_' + rule_id,
elem_filter_value_container = $("#" + filter_value_container_id),
filter_element_id_prefix = elem.jui_filter_rules("getOption", "filter_element_id_prefix"),
filter_element_id, filter_input_type = "", filter_element_attributes,
group_elems,
operator = getOperator(operator_type),
elem_rule_id = create_id(elem.jui_filter_rules("getOption", "rule_li_id_prefix"), container_id) + '_' + rule_id,
elem_rule = $("#" + elem_rule_id),
rulesListLiErrorClass = elem.jui_filter_rules("getOption", "rulesListLiErrorClass"),
decimal_separator = elem.jui_filter_rules("getOption", "decimal_separator"),
dc_regex_pattern = new RegExp(RegExp_escape(decimal_separator), "g"),
htmlentities = elem.jui_filter_rules("getOption", "htmlentities"),
elem_filter, filter_value = [], filter_value_len, v, elem_filter_group = [],
filter_value_conversion, conversion_function = "", args, conversion_args = [], arg_len, a;
elem_rule.removeClass(rulesListLiErrorClass);
if(operator.accept_values !== "yes") {
return filter_value;
}
for(i = 0; i < filter_interface_len; i++) {
if(filter_interface[i].hasOwnProperty("returns_no_value")) {
if(filter_interface[i]["returns_no_value"] == "yes") {
continue;
}
}
filter_element = filter_interface[i].filter_element;
filter_element_attributes = filter_interface[i].filter_element_attributes;
if(filter_element == "input") {
filter_input_type = filter_element_attributes["type"];
if(filter_input_type == "text") {
filter_element_id = getFilterElementID(i);
elem_filter = $("#" + filter_element_id);
filter_value.push(elem_filter.val());
}
if(filter_input_type == "checkbox" || filter_input_type == "radio") {
group_elems = $('[id^="' + create_id(filter_element_id_prefix, container_id) + '_' + rule_id + '_' + '"]');
group_elems.each(function() {
if($(this).is(":checked"))
filter_value.push($(this).val());
elem_filter_group.push($(this));
})
}
}
if(filter_element == "select") {
filter_element_id = getFilterElementID(i);
elem_filter = $("#" + filter_element_id);
if(filter_element_attributes.hasOwnProperty("multiple")) {
filter_value = elem_filter.val();
} else {
filter_value.push(elem_filter.val());
}
}
}
// No value validation
if(filter_input_type == "checkbox" || filter_input_type == "radio") {
if($("input:checked", elem_filter_value_container).length == 0) {
noValueGiven();
return false;
}
}
filter_value_len = filter_value.length;
for(v = 0; v < filter_value_len; v++) {
if($.trim(filter_value[v]).length == 0) {
noValueGiven();
return false;
}
}
// Numeric validation
if(filter_type == "number") {
filter_value_len = filter_value.length;
for(v = 0; v < filter_value_len; v++) {
// set decimal separator
filter_value[v] = filter_value[v].replace(dc_regex_pattern, ".");
if(!$.isNumeric(filter_value[v])) {
elem_rule.addClass(rulesListLiErrorClass);
elem.triggerHandler("onValidationError", {err_code: "filter_error_2", err_description: rsc_jui_fr.error_invalid_number, elem_filter: getCurrentFilterElement()});
return false;
}
}
}
// Date validation (using moment.js)
if(filter_type == "date") {
filter_value_len = filter_value.length;
if(filter.hasOwnProperty("validate_dateformat")) {
for(v = 0; v < filter_value_len; v++) {
if(moment(filter_value[v], filter.validate_dateformat).isValid() == false) {
elem_rule.addClass(rulesListLiErrorClass);
elem.triggerHandler("onValidationError", {err_code: "filter_error_3", err_description: rsc_jui_fr.error_invalid_datetime, elem_filter: getCurrentFilterElement()});
return false;
}
}
}
}
// apply value conversion (if any)
if(filter.hasOwnProperty("filter_value_conversion")) {
filter_value_conversion = filter.filter_value_conversion;
conversion_function = filter_value_conversion["function_name"];
args = filter_value_conversion["args"];
arg_len = args.length;
filter_value_len = filter_value.length;
for(v = 0; v < filter_value_len; v++) {
// create arguments values for this filter value
conversion_args = [];
for(a = 0; a < arg_len; a++) {
if(args[a].hasOwnProperty("filter_value")) {
conversion_args.push(filter_value[v]);
}
if(args[a].hasOwnProperty("value")) {
conversion_args.push(args[a]["value"]);
}
}
// execute user function and assign return value to filter value
try {
filter_value[v] = window[conversion_function].apply(null, conversion_args);
}
catch(err) {
elem.jui_filter_rules("markRuleAsError", elem_rule.attr("id"), true);
elem.triggerHandler("onValidationError", {err_code: "filter_error_0", err_description: rsc_jui_fr.error_converting_value + ':\n\n' + err.message, elem_filter: getCurrentFilterElement()});
return false;
}
}
}
// encode html (against XSS attack)
if(filter_type !== "number") {
if(htmlentities) {
filter_value_len = filter_value.length;
for(v = 0; v < filter_value_len; v++) {
filter_value[v] = htmlEncode(filter_value[v]);
}
}
}
// ---------------------------------------------------------------------
function getFilterElementID(group_index) {
return create_id(filter_element_id_prefix, container_id) + '_' + rule_id + '_' + group_index;
}
// ---------------------------------------------------------------------
function noValueGiven() {
elem_rule.addClass(rulesListLiErrorClass);
elem.triggerHandler("onValidationError", {err_code: "filter_error_1", err_description: rsc_jui_fr.error_no_value_given, elem_filter: getCurrentFilterElement()});
}
// ---------------------------------------------------------------------
function getCurrentFilterElement() {
if(filter_input_type == "checkbox" || filter_input_type == "radio") {
if(v == undefined) {
v = 0;
}
return elem_filter_group[v];
} else {
return elem_filter;
}
}
return filter_value;
};
/**
* jui_filter_rules - Create rules to filter dataset using jquery.
*
* @class jui_filter_rules
* @memberOf $.fn
*/
$.fn.jui_filter_rules = function(method) {
// OPTIONAL
if(this.size() != 1) {
var err_msg = 'You must use this plugin (' + pluginName + ') with a unique element (at once)';
this.html('' + 'ERROR: ' + err_msg + '');
$.error(err_msg);
}
// Method calling logic
if(methods[method]) {
return methods[ method ].apply(this, Array.prototype.slice.call(arguments, 1));
} else if(typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.' + pluginName);
}
};
})(jQuery);