fenix-ui-filter
Version:
770 lines (512 loc) • 19.3 kB
JavaScript
define([
'loglevel',
'jquery',
'underscore',
'../../config/errors',
'../../config/events',
'../../config/config',
'../../html/selector.hbs',
'../../html/group.hbs',
'../../nls/labels',
'./selector'
], function (log, $, _, ERR, EVT, C, templateSelector, templateGroup, i18nLabels, Selector) {
'use strict';
var s = {
SWITCH: "input[data-role='switch'][name='disable-selector']",
REMOVE_BTN: "[data-role='remove']",
ADD_BTN: "[data-role='add']",
GROUPS_CONTAINER: '[data-role="groups"]'
};
function Group(obj) {
$.extend(true, this, C, {initial: obj || {}, $filterEl: $(obj.el)});
this._initVariables();
this._attach();
this._render();
return this;
}
/**
* disposition
* @return {Object}
*/
Group.prototype.dispose = function () {
this._unbindEventListeners();
_.each(this.groups, _.bind(function (group) {
_.each(group, function(sel, id) {
if (sel && sel.instance && typeof sel.instance.dispose === "function") {
sel.instance.dispose();
}
});
}, this));
this._destroyDependencies();
this.$el.remove();
};
/**
* reset
* @return {Object}
*/
Group.prototype.printDefaultSelection = function () {
_.each(this.groups, _.bind(function (group) {
_.each(group, function(sel, id) {
if (sel && sel.instance && typeof sel.instance.printDefaultSelection === "function") {
sel.instance.printDefaultSelection();
}
});
}, this));
};
/**
* reset
* @return {Object}
*/
Group.prototype.reset = function () {
_.each(this.groups, _.bind(function (group) {
_.each(group, function(sel, id) {
if (sel && sel.instance && typeof sel.instance.reset === "function") {
sel.instance.reset();
}
});
}, this));
};
/**
* disposition
* @return {Object}
*/
Group.prototype.getValues = function (format) {
var result = {
values: {},
labels: {},
errors: {},
valid: true
}, v,
values,
errors = {},
valid = {},
labels = {};
if (!this.incremental) {
values = {};
var key = Object.keys(this.groups)[0];
_.each(this.groups[key], _.bind(function (selector, key) {
var instance = selector.instance;
if (instance) {
v = instance.getValues(format);
values[key] = v.values;
labels[key] = v.labels;
result.valid = result.valid && !!v.valid;
$.extend(true, result.errors, v.errors);
} else {
log.warn(key + " skip language");
}
}, this));
} else {
values = [];
_.each(this.groups, _.bind(function (group) {
var obj = {};
_.each(group, _.bind(function (selector) {
var instance = selector.instance;
if (instance) {
var values = instance.getValues();
obj[selector.id] = values.values.length === 1 ? values.values[0] : values.values;
labels[selector.id] = $.extend(true, labels[selector.id], values.labels);
}
}, this));
values.push(obj);
}, this));
}
result.values = values;
result.labels = labels;
return result;
};
/**
* set srouces
* @return {Object}
*/
Group.prototype.setSource = function (values) {
console.log("TODO setSource()");
};
/**
* set value
* @return {Object}
*/
Group.prototype.setValue = function (values) {
if (!this.incremental) {
_.each(this.groups, function (group) {
_.each(group, function (selector) {
var id = selector.id;
if (values.hasOwnProperty(id)) {
selector.instance.setValue(values[id])
}
});
});
} else {
if (Array.isArray(values)) {
_.each(values, _.bind(function (obj, index) {
var group = this.groups["group_" + (index + 1)];
if (group) {
_.each(obj, function (v, key) {
if (group[key] && group[key].instance) {
group[key].instance.setValue(v);
}
});
} else {
this._addGroup(obj);
}
}, this));
}
else {
log.warn("Group is incremental and values should be an array of object")
}
}
};
/**
* unset value
* @return {Object}
*/
Group.prototype.unsetValue = function (values) {
console.log("TODO unsetValue()");
};
/**
* enable
* @return {Object}
*/
Group.prototype.enable = function (silent) {
_.each(this.groups, _.bind(function (group) {
_.each(group, _.bind(function (selector) {
var instance = selector.instance;
if (instance) {
instance.enable(true)
}
}, this));
}, this));
this.status.disabled = false;
this.$el.find(s.SWITCH).prop("checked", true);
this.$el.find(s.ADD_BTN).prop('disabled', false);
if (!silent) {
this._trigger(EVT.SELECTOR_ENABLED);
}
};
/**
* disable
* @return {Object}
*/
Group.prototype.disable = function (silent) {
_.each(this.groups, _.bind(function (group) {
_.each(group, _.bind(function (selector) {
var instance = selector.instance;
if (instance) {
instance.disable(true)
}
}, this));
}, this));
this.status.disabled = true;
this.$el.find(s.SWITCH).prop("checked", false);
this.$el.find(s.ADD_BTN).prop('disabled', true);
if (!silent) {
this._trigger(EVT.SELECTOR_DISABLED);
}
};
/**
* tag selector container
* */
Group.prototype.tagAsInvalid = function () {
this.$el.find(".form-group").addClass("has-error");
};
/**
* tag selector container
* */
Group.prototype.tagAsValid = function () {
this.$el.find(".form-group").addClass("has-success");
};
/**
* untag selector container
* */
Group.prototype.untag = function () {
this.$el.find(".form-group").removeClass("has-error");
this.$el.find(".form-group").removeClass("has-success");
};
Group.prototype._initVariables = function () {
this.channels = {};
this.id = this.initial.id;
this.controller = this.initial.controller;
this.template = this.initial.template;
this.lang = this.initial.lang;
this.environment = this.initial.environment;
this.cache = this.initial.cache;
this.plugins = this.initial.plugins;
this.constraints = this.initial.constraints;
this.groups = {};
this._selectors = this.initial.selectors;
this.incremental = !!this.initial.incremental;
this.classNames = this.initial.classNames;
if (!this.incremental) {
this.initialAmount = 1;
} else {
this.initialAmount = !isNaN(this.initial.initialAmount) ? this.initial.initialAmount : 0;
}
this.amount = 0;
this.status = {
disable: false
};
this.dependeciesToDestory = [];
};
/**
* get Group status
* @return {Object}
*/
Group.prototype.getStatus = function () {
return this.status;
};
Group.prototype._attach = function () {
this.$el = this._getGroupContainer(this.id);
this._bindEventListeners();
};
Group.prototype._getGroupContainer = function (id) {
var $cont = this.$filterEl.find('[data-group="' + id + '"]'),
conf = this,
model;
if ($cont.length === 0) {
log.warn("Impossible to find selector container: " + id);
model = $.extend(true, {
classNames: conf.classNames,
id: id,
incremental: this.incremental
}, conf.template, i18nLabels[this.lang]);
$cont = $(templateGroup(model));
if (this.direction === "append") {
this.$filterEl.append($cont);
} else {
this.$filterEl.prepend($cont);
}
}
return $cont;
};
Group.prototype._createSelectorContainer = function (id) {
log.info("Create container for selector: " + id);
var conf = $.extend(true, {
id: id,
classNames: this.incremental ? "fx-group-item fx-boxed" : "fx-group-item",
incremental: this.incremental,
hideHeader: !this.incremental,
hideRemoveButton: !this.incremental,
hideSwitch: !this.incremental ? true : this.template.hideSwitch
}, i18nLabels[this.lang]),
$html;
$html = $(templateSelector(conf));
return $html;
};
Group.prototype._render = function () {
this.ready = false;
this.selectorsReady = 0; //used for "ready" event
for (var i = 0; i < this.initialAmount; i++) {
this._addGroup();
}
if (this.initialAmount === 0) {
window.setTimeout(_.bind(function () {
this._trigger(EVT.SELECTOR_READY, {id: this.id});
}, this), 100);
}
};
Group.prototype._addGroup = function (values) {
// increase the group amount
this.amount++;
var groupName = "group_" + this.amount;
//create new group
this.groups[groupName] = {};
//create group $el and cache it
var $el;
$el = this._createSelectorContainer(groupName);
this.groups[groupName].$el = $el;
this._bindSelectorEventListeners($el, groupName);
this.$el.find(s.GROUPS_CONTAINER).prepend($el);
_.each(this._selectors, _.bind(function (obj) {
var model = $.extend(true, {
id: obj.id,
controller: this.controller,
lang: this.lang,
languages: this.languages,
plugins: this.plugins,
el: $el,
values: values ? values[obj.id] : undefined,
cache: this.cache,
environment: this.environment,
template: {
hideRemoveButton: true,
hideSwitch: true
}
}, obj);
model.instance = new Selector(model);
model.instance.on(EVT.SELECTOR_READY, _.bind(this._onSelectorReady, this, groupName));
model.instance.on(EVT.SELECTOR_ENABLED, _.bind(this._onSelectorEnabled, this, groupName));
model.instance.on(EVT.SELECTOR_SELECTED, _.bind(this._onSelectorSelected, this, groupName));
this.groups[groupName][model.id] = model;
}, this));
this._initDependencies();
};
Group.prototype._initDependencies = function () {
_.each(this.groups, _.bind(function (group, groupName) {
_.each(group, _.bind(function (sel, id) {
if (!sel.hasOwnProperty("dependencies")) {
return;
}
this._processSelectDependencies(sel.dependencies, id, groupName);
}, this));
}, this));
};
Group.prototype._processSelectDependencies = function (d, id, groupName) {
var self = this;
_.each(d, _.bind(function (dependencies, selectorId) {
//Ensure dependencies is an array
if (!Array.isArray(dependencies)) {
dependencies = [dependencies];
}
var selectors = [selectorId];
_.each(selectors, _.bind(function (s) {
_.each(dependencies, _.bind(function (d) {
if (typeof d !== "object") {
log.warn(JSON.stringify(d) + " is not a valid dependency configuration");
return;
}
var toAdd = {
event: "dep_" + d.event + "_" + s + "_" + groupName,
callback: function (payload) {
var call = self["_dep_" + d.id];
if ($.isFunction(call)) {
call.call(self, payload, {src: s, target: id, group: groupName, args: d.args});
} else {
log.error("Impossible to find : " + "_dep_" + d.id);
}
}
};
this.dependeciesToDestory.push(toAdd);
this.on(toAdd.event, toAdd.callback, this);
}, this));
}, this));
}, this));
};
Group.prototype._onSelectorSelected = function (groupName, payload) {
if (payload) {
this._trigger("dep_select_" + payload.id + "_" + groupName, payload);
}
this._trigger(EVT.SELECTOR_SELECTED, payload)
};
Group.prototype._onSelectorEnabled = function () {
this.enable();
};
Group.prototype._onSelectorReady = function () {
this.selectorsReady++;
log.info("Ready event listened from group: " + this.id);
if (this.selectorsReady === Object.keys(this._selectors).length) {
this._onReady();
}
};
Group.prototype._onReady = function () {
log.info("Group is ready: " + this.id);
this._trigger(EVT.SELECTOR_READY, {id: this.id});
};
Group.prototype._unbindEventListeners = function () {
this.$el.find(s.SWITCH).off();
this.$el.find(s.REMOVE_BTN).off();
this.$el.find(s.ADD_BTN).off();
};
Group.prototype._bindEventListeners = function () {
this.$el.find(s.SWITCH).on("click", _.bind(this._onSwitchClick, this));
this.$el.find(s.REMOVE_BTN).on("click", _.bind(this._onRemoveClick, this));
this.$el.find(s.ADD_BTN).on("click", _.bind(this._onAddClick, this));
};
Group.prototype._bindSelectorEventListeners = function ($el, group) {
$el.find(s.SWITCH).on("click", _.bind(this._onSelectorSwitchClick, this, group));
$el.find(s.REMOVE_BTN).on("click", _.bind(this._onSelectorRemoveClick, this, group));
};
Group.prototype._unbindSelectorEventListeners = function ($el) {
$el.find(s.SWITCH).off();
$el.find(s.REMOVE_BTN).off();
};
Group.prototype._onSelectorSwitchClick = function (g, evt) {
var checked = $(evt.target).is(":checked"),
group = this.groups[g];
if (group) {
_.each(group, _.bind(function (s) {
var instance = s.instance;
if (!instance) {
return;
}
if (!!checked) {
s.instance.enable();
} else {
s.instance.disable();
}
}, this));
}
};
Group.prototype._onSelectorRemoveClick = function (g) {
var group = this.groups[g];
if (group) {
_.each(group, _.bind(function (s) {
var instance = s.instance;
if (!instance) {
return;
}
s.instance.dispose();
}, this))
}
this._unbindSelectorEventListeners(this.groups[g].$el);
this._destroyGroupDependencies(g);
this.groups[g].$el.remove();
delete this.groups[g];
};
Group.prototype._destroyDependencies = function () {
_.each(this.groups, _.bind(function (group, name) {
this._destroyGroupDependencies(name);
}, this))
};
Group.prototype._destroyGroupDependencies = function (group) {
_.each(this.dependeciesToDestory, _.bind(function (d) {
if (d.event.endsWith(group)) {
delete this.channels[d.event];
}
}, this));
};
Group.prototype._onSwitchClick = function (e) {
var checked = $(e.target).is(":checked");
if (!!checked) {
this.enable();
} else {
this.disable();
}
};
Group.prototype._onRemoveClick = function () {
this.dispose();
this._trigger(EVT.SELECTOR_REMOVED, {id: this.id});
};
Group.prototype._onAddClick = function () {
//force to be enabled
this.enable();
this._addGroup();
};
Group.prototype._getEventName = function (evt) {
return this.controller.id + evt;
};
//pub/sub
/**
* pub/sub
* @return {Object} component instance
*/
Group.prototype.on = function (channel, fn, context) {
var _context = context || this;
if (!this.channels[channel]) {
this.channels[channel] = [];
}
this.channels[channel].push({context: _context, callback: fn});
return this;
};
Group.prototype._trigger = function (channel) {
if (!this.channels[channel]) {
return false;
}
var args = Array.prototype.slice.call(arguments, 1);
for (var i = 0, l = this.channels[channel].length; i < l; i++) {
var subscription = this.channels[channel][i];
subscription.callback.apply(subscription.context, args);
}
return this;
};
return Group;
});