Initial commit
This commit is contained in:
+3
@@ -0,0 +1,3 @@
|
||||
<div class="CDB-ListDecoration-itemLink u-flex u-justifySpace u-alignCenter u-actionTextColor <% if (isSelected) { %> is-selected <% } %>">
|
||||
<%- _t('form-components.editors.fill.quantification.methods.' + name) %>
|
||||
</div>
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var CustomListView = require('builder/components/custom-list/custom-view');
|
||||
var CustomListCollection = require('builder/components/custom-list/custom-list-collection');
|
||||
var ColumnListViewTemplate = require('builder/components/custom-list/column-list/column-list-view.tpl');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
defaults: {
|
||||
headerTitle: ''
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .js-back': '_onClickBack'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.stackLayoutModel) throw new Error('stackLayoutModel is required');
|
||||
if (!opts.columns) throw new Error('columns param is required');
|
||||
|
||||
this._stackLayoutModel = opts.stackLayoutModel;
|
||||
this._columns = opts.columns;
|
||||
this._showSearch = opts.showSearch || false;
|
||||
this._typeLabel = opts.typeLabel;
|
||||
this._itemTemplate = opts.itemTemplate;
|
||||
|
||||
this.collection = new CustomListCollection(this._columns);
|
||||
this.listenTo(this.collection, 'change:selected', this._onSelectItem);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
this.$el.append(
|
||||
ColumnListViewTemplate({
|
||||
headerTitle: this.options.headerTitle
|
||||
})
|
||||
);
|
||||
|
||||
this._initViews();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClickBack: function (e) {
|
||||
this.killEvent(e);
|
||||
this.trigger('back', this);
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._listView = new CustomListView({
|
||||
collection: this.collection,
|
||||
showSearch: this._showSearch,
|
||||
typeLabel: this._typeLabel,
|
||||
itemTemplate: this._itemTemplate
|
||||
});
|
||||
this.$('.js-content').append(this._listView.render().$el);
|
||||
this.addView(this._listView);
|
||||
},
|
||||
|
||||
_onSelectItem: function (item) {
|
||||
this.trigger('selectItem', item, this);
|
||||
}
|
||||
});
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
<% if (headerTitle) { %>
|
||||
<div class="CDB-Box-modalHeader">
|
||||
<ul class="CDB-Box-modalHeaderItem CDB-Box-modalHeaderItem--block CDB-Box-modalHeaderItem--paddingHorizontal">
|
||||
<li class="CDB-ListDecoration-item CDB-ListDecoration-itemPadding--vertical CDB-Text CDB-Size-medium u-secondaryTextColor">
|
||||
<button class="u-actionTextColor js-back u-rSpace">
|
||||
<i class="CDB-IconFont CDB-IconFont-arrowPrev Size-large"></i>
|
||||
</button>
|
||||
<%- headerTitle%>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
<div class="js-content"></div>
|
||||
@@ -0,0 +1,32 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var template = require('./custom-list-action.tpl');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
className: 'CDB-Text CDB-Size-small is-semibold u-upperCase u-actionTextColor u-lSpace--xl',
|
||||
|
||||
tagName: 'button',
|
||||
|
||||
events: {
|
||||
'click': '_onClick'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
this.options = opts;
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.clearSubViews();
|
||||
|
||||
this.$el.append(template({
|
||||
label: this.options.label
|
||||
}));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClick: function () {
|
||||
this.options.action && this.options.action();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<%- label %>
|
||||
@@ -0,0 +1,6 @@
|
||||
<div class="CDB-ListDecoration-item CustomList-item js-listItem">
|
||||
<button type="button" class="CDB-ListDecoration-itemLink CustomList--full js-add-custom-value u-ellipsis" data-val="<%- query %>" title="<%- query %>">
|
||||
<p class="CDB-Text CDB-FontSize-small u-altTextColor"><%- _t('components.custom-list.add-custom-result') %></p>
|
||||
“<%- query %>”
|
||||
</button>
|
||||
</div>
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
var Backbone = require('backbone');
|
||||
var CustomListItemModel = require('./custom-list-item-model');
|
||||
var _ = require('underscore');
|
||||
|
||||
/*
|
||||
* Custom list collection, it parses pairs like:
|
||||
*
|
||||
* [{ val, label }]
|
||||
* ["string"]
|
||||
*/
|
||||
|
||||
module.exports = Backbone.Collection.extend({
|
||||
sort_key: 'id', // default sort key
|
||||
|
||||
initialize: function (models, options) {
|
||||
this.options = _.extend({ silent: true }, options);
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
comparator: function (item) {
|
||||
var name = item.get(this.sort_key);
|
||||
|
||||
return this._nameToLowerCase(name);
|
||||
},
|
||||
|
||||
model: function (attrs, opts) {
|
||||
var d = {};
|
||||
if (typeof attrs === 'string') {
|
||||
d.val = attrs;
|
||||
} else {
|
||||
d = attrs;
|
||||
}
|
||||
return new CustomListItemModel(d, opts);
|
||||
},
|
||||
|
||||
sortByKey: function (key) {
|
||||
this.sort_key = key;
|
||||
this.sort();
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.bind('change:selected', this._onSelectedChange, this);
|
||||
},
|
||||
|
||||
_nameToLowerCase: function (name) {
|
||||
/*
|
||||
* It could still be evaluated like true if it is a boolean/number
|
||||
* in that case, we convert it to a string
|
||||
*/
|
||||
|
||||
if (_.isUndefined(name) || _.isNull(name)) return name;
|
||||
|
||||
return _.isString(name) ? name.toLowerCase() : name.toString().toLowerCase();
|
||||
},
|
||||
|
||||
search: function (query) {
|
||||
if (!query) return this;
|
||||
query = query.toLowerCase();
|
||||
|
||||
return _(this.filter(function (model) {
|
||||
var name = model.getName();
|
||||
var val = this._nameToLowerCase(name);
|
||||
|
||||
return val ? ~val.indexOf(query) : -1;
|
||||
}, this));
|
||||
},
|
||||
|
||||
_onSelectedChange: function (changedModel, isSelected) {
|
||||
if (isSelected) {
|
||||
this.each(function (m) {
|
||||
if (m.cid !== changedModel.cid) {
|
||||
m.set({
|
||||
selected: false
|
||||
}, {
|
||||
silent: this.options.silent
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
getSelectedItem: function () {
|
||||
return this.findWhere({ selected: true });
|
||||
},
|
||||
|
||||
containsValue: function (value) {
|
||||
return this.find(function (mdl) {
|
||||
return mdl.getValue() === value;
|
||||
});
|
||||
},
|
||||
|
||||
setSelected: function (value) {
|
||||
var selectedModel;
|
||||
var silent = { silent: this.options.silent };
|
||||
|
||||
this.each(function (mdl) {
|
||||
if (mdl.getValue() === value) {
|
||||
mdl.set({
|
||||
selected: true
|
||||
}, silent);
|
||||
selectedModel = mdl;
|
||||
} else {
|
||||
mdl.set({
|
||||
selected: false
|
||||
}, silent);
|
||||
}
|
||||
});
|
||||
return selectedModel;
|
||||
},
|
||||
|
||||
removeSelected: function () {
|
||||
this.each(function (mdl) {
|
||||
mdl.set({
|
||||
selected: false
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
isAsync: function () {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<div class="CustomList-message">
|
||||
<p class="CustomList-messageText CDB-Text CDB-Size-medium u-secondaryTextColor">
|
||||
<% if (query && query.length) { %>
|
||||
<%- _t('components.custom-list.no-results', { typeLabel: typeLabel, query: query }) %>
|
||||
<% } else { %>
|
||||
<%- _t('components.custom-list.no-items', { typeLabel: typeLabel }) %>
|
||||
<% } %>
|
||||
</p>
|
||||
</div>
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<div class="CDB-Box-modalHeader">
|
||||
<div class="CDB-Box-modalHeaderItem js-header u-alignCenter u-justifySpace">
|
||||
<div class="u-flex js-actions"></div>
|
||||
</div>
|
||||
</div>
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
var Backbone = require('backbone');
|
||||
|
||||
/*
|
||||
* List item model
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
|
||||
defaults: {
|
||||
selected: false
|
||||
},
|
||||
|
||||
getName: function () {
|
||||
return (this.get('label') == null) ? this.getValue() : this.get('label'); // eslint-disable-line
|
||||
},
|
||||
|
||||
getValue: function () {
|
||||
return this.get('val');
|
||||
}
|
||||
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
var _ = require('underscore');
|
||||
var CoreView = require('backbone/core-view');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
options: {
|
||||
template: require('./custom-list-item.tpl')
|
||||
},
|
||||
|
||||
className: 'CDB-ListDecoration-item CustomList-item js-listItem',
|
||||
tagName: 'li',
|
||||
|
||||
events: {
|
||||
'mouseenter': '_onMouseEnter',
|
||||
'mouseleave': '_onMouseLeave',
|
||||
'click': '_onClick'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
this.options = _.extend({}, this.options, opts);
|
||||
this.model.on('change', this.render, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.clearSubViews();
|
||||
|
||||
var name = this.model.getName() == null ? 'null' : this.model.getName();
|
||||
|
||||
this.$el.append(
|
||||
this.options.template(
|
||||
_.extend({
|
||||
typeLabel: this.options.typeLabel,
|
||||
isSelected: this.model.get('selected'),
|
||||
isDisabled: this.model.get('disabled'),
|
||||
isDestructive: this.model.get('destructive'),
|
||||
name: name,
|
||||
val: this.model.getValue(),
|
||||
options: this.model.get('renderOptions')
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
this.$el
|
||||
.attr('data-val', this.model.getValue())
|
||||
.toggleClass('is-disabled', !!this.model.get('disabled'));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onMouseLeave: function () {
|
||||
this.$el.removeClass('is-highlighted');
|
||||
},
|
||||
|
||||
_onMouseEnter: function () {
|
||||
this.$el.addClass('is-highlighted');
|
||||
},
|
||||
|
||||
_onClick: function (ev) {
|
||||
this.killEvent(ev);
|
||||
this.model.set({
|
||||
selectedClass: ev.target.classList,
|
||||
selected: true
|
||||
});
|
||||
}
|
||||
});
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<button type="button" class="CDB-ListDecoration-itemLink u-ellipsis
|
||||
<% if (isSelected) { %> is-selected <% } %>
|
||||
<% if (isDestructive) { %>
|
||||
u-errorTextColor
|
||||
<% } else if (isDisabled) { %>
|
||||
u-hintTextColor
|
||||
<% } else { %>
|
||||
u-actionTextColor
|
||||
<% } %>
|
||||
" title="<%- name %>">
|
||||
|
||||
<div class="u-iBlock u-rSpace">
|
||||
<input class="CDB-Checkbox js-input" type="checkbox" name="" value="" <% if (isSelected) { %>checked<% } %> <% if (isDisabled) { %>disabled<% } %> />
|
||||
<span class="u-iBlock CDB-Checkbox-face"></span>
|
||||
</div>
|
||||
<%- name %>
|
||||
</button>
|
||||
@@ -0,0 +1,12 @@
|
||||
<button type="button" class="CDB-ListDecoration-itemLink u-ellipsis
|
||||
<% if (isSelected) { %> is-selected <% } %>
|
||||
<% if (isDestructive) { %>
|
||||
u-errorTextColor
|
||||
<% } else if (isDisabled) { %>
|
||||
u-hintTextColor
|
||||
<% } else { %>
|
||||
u-actionTextColor
|
||||
<% } %>
|
||||
" title="<%- name %>">
|
||||
<%- name %>
|
||||
</button>
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
var _ = require('underscore');
|
||||
var CustomListCollection = require('./custom-list-collection');
|
||||
|
||||
module.exports = CustomListCollection.extend({
|
||||
_initBinds: function () { },
|
||||
|
||||
setSelected: function (value) {
|
||||
var selectedModel;
|
||||
var silentTrue = { silent: true };
|
||||
|
||||
if (_.isArray(value)) {
|
||||
this.each(function (mdl) {
|
||||
if (_.contains(value, mdl.getValue())) {
|
||||
mdl.set({
|
||||
selected: true
|
||||
}, silentTrue);
|
||||
selectedModel = mdl;
|
||||
} else {
|
||||
mdl.set({
|
||||
selected: false
|
||||
}, silentTrue);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.each(function (mdl) {
|
||||
if (mdl.getValue() === value) {
|
||||
mdl.set({
|
||||
selected: true
|
||||
}, silentTrue);
|
||||
selectedModel = mdl;
|
||||
} else {
|
||||
mdl.set({
|
||||
selected: false
|
||||
}, silentTrue);
|
||||
}
|
||||
});
|
||||
}
|
||||
return selectedModel;
|
||||
}
|
||||
});
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
var CustomListItemView = require('./custom-list-item-view');
|
||||
|
||||
module.exports = CustomListItemView.extend({
|
||||
_onClick: function (ev) {
|
||||
this.killEvent(ev);
|
||||
this.model.set('selected', !this.model.get('selected'));
|
||||
}
|
||||
});
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var template = require('./custom-list-search.tpl');
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
className: 'CustomList--full',
|
||||
tagName: 'form',
|
||||
|
||||
events: {
|
||||
'keyup .js-search': '_onSearchType',
|
||||
'click .js-clear': '_onClickClear',
|
||||
'submit': '_submit'
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
this.template = this.options.template || template;
|
||||
this.searchPlaceholder = this.options.searchPlaceholder || _t('components.custom-list.placeholder', { typeLabel: this.options.typeLabel });
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el
|
||||
.empty()
|
||||
.append(
|
||||
this.template({
|
||||
query: this.model.get('query'),
|
||||
searchPlaceholder: this.searchPlaceholder
|
||||
})
|
||||
);
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.model.on('change:query', this._checkButtons, this);
|
||||
},
|
||||
|
||||
_checkButtons: function () {
|
||||
var query = this.model.get('query');
|
||||
this.$('.js-clear').toggleClass('u-transparent', query.length === 0);
|
||||
},
|
||||
|
||||
_onSearchType: function (e) {
|
||||
this._submit();
|
||||
},
|
||||
|
||||
_onClickClear: function (e) {
|
||||
e.stopPropagation();
|
||||
this.model.set('query', '');
|
||||
this.render();
|
||||
this.focus();
|
||||
},
|
||||
|
||||
focus: function () {
|
||||
this.$('.js-search').focus();
|
||||
},
|
||||
|
||||
_submit: function (ev) {
|
||||
this.killEvent(ev);
|
||||
var query = this.$('.js-search').val();
|
||||
this.model.set('query', query);
|
||||
}
|
||||
});
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<div class="u-flex">
|
||||
<input type="text" name="text" autocomplete="off" value="<%- query %>" placeholder="<%- searchPlaceholder %>" class="CDB-InputTextPlain CDB-Text js-search">
|
||||
<button type="button" class="u-lSpace--xl u-transparent js-clear">
|
||||
<div class="CDB-Shape">
|
||||
<div class="CDB-Shape-close is-blue is-large"></div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,234 @@
|
||||
var CoreView = require('backbone/core-view');
|
||||
var _ = require('underscore');
|
||||
var Ps = require('perfect-scrollbar');
|
||||
var emptyTemplate = require('./custom-list-empty.tpl');
|
||||
var addTemplate = require('./custom-list-add.tpl');
|
||||
var template = require('./custom-list.tpl');
|
||||
var Utils = require('builder/helpers/utils');
|
||||
|
||||
var ARROW_DOWN_KEY_CODE = 40;
|
||||
var ARROW_UP_KEY_CODE = 38;
|
||||
var ENTER_KEY_CODE = 13;
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'components:custom-list:custom-list-view',
|
||||
|
||||
options: {
|
||||
size: 3
|
||||
},
|
||||
|
||||
className: 'CDB-Text CDB-Size-medium CustomList-listWrapper',
|
||||
|
||||
tagName: 'div',
|
||||
|
||||
events: {
|
||||
'click .js-add-custom-value': '_onClickAddCustomValue',
|
||||
'mouseover': '_onMouseOver',
|
||||
'mouseout': '_onMouseOut'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
this.options = _.extend({}, this.options, opts);
|
||||
|
||||
this._onKeyDownBinded = this._onKeyDown.bind(this);
|
||||
this._needsMaxSize = true;
|
||||
|
||||
if (this.options.mouseOverAction) {
|
||||
this._mouseOverAction = this.options.mouseOverAction;
|
||||
}
|
||||
|
||||
if (this.options.mouseOutAction) {
|
||||
this._mouseOutAction = this.options.mouseOutAction;
|
||||
}
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._removeArrowBinds();
|
||||
this._destroyCustomScroll();
|
||||
this.$el.empty();
|
||||
|
||||
var query = this.model.get('query');
|
||||
var items = this.collection.search(query);
|
||||
|
||||
this.$el.append(template());
|
||||
|
||||
var allowFreeTextInput = this.options.allowFreeTextInput;
|
||||
|
||||
if (allowFreeTextInput && query && !Utils.isBlank(query)) {
|
||||
if (!this.collection.containsValue(query)) {
|
||||
this.$el.prepend(
|
||||
addTemplate({
|
||||
query: query,
|
||||
typeLabel: this.options.typeLabel
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (items.size() > 0) {
|
||||
items.each(this._renderItem, this);
|
||||
this._applyArrowBinds();
|
||||
// Perfect-scroll needs to have the element in the DOM in order to
|
||||
// style/positionate the scroll properly, small trick
|
||||
setTimeout(this._applyCustomScroll.bind(this), 0);
|
||||
} else if (!allowFreeTextInput || Utils.isBlank(query)) {
|
||||
this.$el.append(
|
||||
emptyTemplate({
|
||||
query: query,
|
||||
typeLabel: this.options.typeLabel
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_renderItem: function (model) {
|
||||
if (model.get('hidden')) return;
|
||||
var ItemViewClass = this.options.itemView;
|
||||
|
||||
var itemView = new ItemViewClass({
|
||||
model: model,
|
||||
typeLabel: this.options.typeLabel,
|
||||
template: this.options.itemTemplate
|
||||
});
|
||||
this.$('.js-list').append(itemView.render().el);
|
||||
this.addView(itemView);
|
||||
|
||||
itemView.bind('customEvent', function (eventName, item) {
|
||||
this.trigger('customEvent', eventName, item, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.model.bind('change:query', this._onQueryChanged, this);
|
||||
},
|
||||
|
||||
_applyArrowBinds: function () {
|
||||
document.addEventListener('keydown', this._onKeyDownBinded);
|
||||
},
|
||||
|
||||
_removeArrowBinds: function () {
|
||||
document.removeEventListener('keydown', this._onKeyDownBinded);
|
||||
},
|
||||
|
||||
_getSelected: function () {
|
||||
var selectedModel = this.collection.getSelectedItem();
|
||||
var selectedValue;
|
||||
|
||||
if (selectedModel) {
|
||||
selectedValue = selectedModel.getValue();
|
||||
return this.$("[data-val='" + selectedValue + "']");
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_highlightSelected: function (item) {
|
||||
var itemHeight = item.outerHeight();
|
||||
item.addClass('is-highlighted');
|
||||
this.$('.js-list').scrollTop(item.index() * itemHeight);
|
||||
},
|
||||
|
||||
_onClickAddCustomValue: function (event) {
|
||||
this.killEvent(event);
|
||||
|
||||
var query = this.model.get('query');
|
||||
|
||||
var model = this.collection.add({
|
||||
val: query,
|
||||
label: '“' + query + '”',
|
||||
dirty: true
|
||||
});
|
||||
|
||||
this.collection.sortByKey('val');
|
||||
model.set('selected', true);
|
||||
},
|
||||
|
||||
_onKeyDown: function (event) {
|
||||
if (this.model.get('visible') === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var key = event.which;
|
||||
var $listItems = this.$('.js-listItem');
|
||||
var $highlighted = $listItems.filter('.is-highlighted');
|
||||
var $current;
|
||||
var model;
|
||||
|
||||
$highlighted.removeClass('is-highlighted');
|
||||
|
||||
if (key === ARROW_DOWN_KEY_CODE) {
|
||||
if (!$highlighted.length || $highlighted[0] === $listItems.last()[0]) {
|
||||
$current = $listItems.eq(0);
|
||||
} else {
|
||||
$current = $highlighted.next();
|
||||
}
|
||||
} else if (key === ARROW_UP_KEY_CODE) {
|
||||
if (!$highlighted.length || $highlighted[0] === $listItems.first()[0]) {
|
||||
$current = $listItems.last();
|
||||
} else {
|
||||
$current = $highlighted.prev();
|
||||
}
|
||||
} else if (key === ENTER_KEY_CODE) {
|
||||
event.preventDefault();
|
||||
if ($highlighted && $highlighted.length) {
|
||||
model = _.first(this.collection.where({ val: $highlighted.data('val') }));
|
||||
if (model) {
|
||||
model.set('selected', true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$current && this._highlightSelected($current);
|
||||
},
|
||||
|
||||
_onQueryChanged: function () {
|
||||
var prevQuery = this.collection.findWhere({ val: this.model.previous('query'), dirty: true });
|
||||
this.collection.remove(prevQuery);
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
_applyCustomScroll: function () {
|
||||
Ps.initialize(this._wrapperContainer().get(0), {
|
||||
wheelSpeed: 2,
|
||||
wheelPropagation: true,
|
||||
stopPropagationOnClick: false,
|
||||
minScrollbarLength: 20
|
||||
});
|
||||
},
|
||||
|
||||
_destroyCustomScroll: function () {
|
||||
if (this._wrapperContainer().length > 0) {
|
||||
Ps.destroy(this._wrapperContainer().get(0));
|
||||
}
|
||||
},
|
||||
|
||||
_wrapperContainer: function () {
|
||||
return this.$('.js-list');
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._removeArrowBinds();
|
||||
this._destroyCustomScroll();
|
||||
CoreView.prototype.clean.apply(this);
|
||||
},
|
||||
|
||||
highlight: function () {
|
||||
var selected = this._getSelected();
|
||||
selected && this._highlightSelected(selected);
|
||||
},
|
||||
|
||||
_onMouseOver: function () {
|
||||
this._mouseOverAction && this._mouseOverAction();
|
||||
},
|
||||
|
||||
_onMouseOut: function () {
|
||||
this._mouseOutAction && this._mouseOutAction();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
<ul class="CustomList-list js-list"></ul>
|
||||
@@ -0,0 +1,221 @@
|
||||
var _ = require('underscore');
|
||||
var Backbone = require('backbone');
|
||||
var CoreView = require('backbone/core-view');
|
||||
var CustomListCollection = require('./custom-list-collection');
|
||||
var SearchView = require('./custom-list-search-view');
|
||||
var CustomListView = require('./custom-list-view');
|
||||
var headerTemplate = require('./custom-list-header.tpl');
|
||||
var CustomListAction = require('./custom-list-action-view');
|
||||
var itemTemplate = require('./custom-list-item.tpl');
|
||||
var CustomListItemView = require('./custom-list-item-view');
|
||||
|
||||
/*
|
||||
* A custom list with possibility to search within values.
|
||||
*
|
||||
* It accepts a collection of (val, label) model attributes or a values array
|
||||
* with the same content or only strings.
|
||||
*
|
||||
* new CustomList({
|
||||
* showSearch: false,
|
||||
* itemTemplate: itemTemplate,
|
||||
* values: [
|
||||
* {
|
||||
* val: 'hello',
|
||||
* label: 'hi'
|
||||
* }
|
||||
* ]
|
||||
* });
|
||||
*/
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
module: 'components:custom-list:custom-view',
|
||||
|
||||
options: {
|
||||
showSearch: true,
|
||||
allowFreeTextInput: false,
|
||||
typeLabel: 'column',
|
||||
itemTemplate: itemTemplate,
|
||||
itemView: CustomListItemView
|
||||
},
|
||||
|
||||
className: 'CDB-Box-modal CustomList',
|
||||
tagName: 'div',
|
||||
|
||||
events: {
|
||||
'mouseover': '_onMouseOver',
|
||||
'mouseout': '_onMouseOut'
|
||||
},
|
||||
|
||||
initialize: function (opts) {
|
||||
if (!opts.collection) {
|
||||
if (!opts.options) { throw new Error('options array {value, label} is required'); }
|
||||
this.collection = new CustomListCollection(opts.options);
|
||||
}
|
||||
|
||||
if (opts.position) {
|
||||
this.$el.css(opts.position);
|
||||
}
|
||||
|
||||
this.options = _.extend({}, this.options, opts);
|
||||
this._selectModel = this.options.selectModel;
|
||||
|
||||
if (this.options.mouseOverAction) {
|
||||
this._mouseOverAction = this.options.mouseOverAction;
|
||||
}
|
||||
|
||||
if (this.options.mouseOutAction) {
|
||||
this._mouseOutAction = this.options.mouseOutAction;
|
||||
}
|
||||
|
||||
this.model = new Backbone.Model({
|
||||
query: '',
|
||||
visible: false
|
||||
});
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
this.clearSubViews();
|
||||
|
||||
if (this.options.showSearch || this.options.actions) {
|
||||
this._renderHeader();
|
||||
}
|
||||
|
||||
if (this.options.showSearch) {
|
||||
this._renderSearch();
|
||||
}
|
||||
|
||||
if (this.options.actions) {
|
||||
this._renderActions();
|
||||
}
|
||||
|
||||
this._renderList();
|
||||
|
||||
if (this.options.showSearch) {
|
||||
this._focusSearch();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.model.bind('change:visible', this._onVisibleChanged, this);
|
||||
this.model.bind('change:query', this._setActionsVisibility, this);
|
||||
},
|
||||
|
||||
_renderHeader: function () {
|
||||
this.$el.prepend(headerTemplate());
|
||||
},
|
||||
|
||||
_renderSearch: function () {
|
||||
this._searchView = new SearchView({
|
||||
template: this.options.searchTemplate,
|
||||
typeLabel: this.options.typeLabel,
|
||||
searchPlaceholder: this.options.searchPlaceholder,
|
||||
model: this.model
|
||||
});
|
||||
this.$('.js-header').prepend(this._searchView.render().el);
|
||||
this.addView(this._searchView);
|
||||
},
|
||||
|
||||
_renderActions: function () {
|
||||
_.each(this.options.actions, function (action) {
|
||||
var view = new CustomListAction(action);
|
||||
this.$('.js-actions').append(view.render().el);
|
||||
this.addView(view);
|
||||
}, this);
|
||||
},
|
||||
|
||||
_setActionsVisibility: function () {
|
||||
this.$('.js-actions').toggleClass('u-hide', this.model.get('query') !== '');
|
||||
},
|
||||
|
||||
_focusSearch: function () {
|
||||
setTimeout(function () {
|
||||
if (this._searchView) {
|
||||
this._searchView.focus();
|
||||
var input = this._searchView.$('input');
|
||||
var $initialVal = input.val();
|
||||
input.val($initialVal + ' ');
|
||||
input.val($initialVal);
|
||||
}
|
||||
}.bind(this), 0);
|
||||
},
|
||||
|
||||
_renderList: function () {
|
||||
this._listView = new CustomListView({
|
||||
model: this.model,
|
||||
allowFreeTextInput: this.options.allowFreeTextInput,
|
||||
collection: this.collection,
|
||||
typeLabel: this.options.typeLabel,
|
||||
itemView: this.options.itemView,
|
||||
itemTemplate: this.options.itemTemplate,
|
||||
size: this.options.size,
|
||||
mouseOverAction: this._mouseOverAction,
|
||||
mouseOutAction: this._mouseOutAction
|
||||
});
|
||||
this.$el.append(this._listView.render().el);
|
||||
|
||||
this._listView.highlight();
|
||||
this.addView(this._listView);
|
||||
|
||||
this._listView.bind('customEvent', function (eventName, item) {
|
||||
this.trigger(eventName, item, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
highlight: function () {
|
||||
this._listView.highlight();
|
||||
},
|
||||
|
||||
_onVisibleChanged: function (_model, isVisible) {
|
||||
this._resetQuery();
|
||||
this._toggleVisibility();
|
||||
|
||||
isVisible ? this.render() : this.clearSubViews();
|
||||
},
|
||||
|
||||
_resetQuery: function () {
|
||||
var query = this._selectModel && this._selectModel.get(this.options.typeLabel) || '';
|
||||
this.model.set('query', query);
|
||||
|
||||
var isInCollection = this.collection.findWhere({ val: query });
|
||||
if (query && !isInCollection) {
|
||||
this.collection.add({ label: query, val: query });
|
||||
}
|
||||
},
|
||||
|
||||
show: function () {
|
||||
this.model.set('visible', true);
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.trigger('hidden', this);
|
||||
this.model.set('visible', false);
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
this.model.set('visible', !this.model.get('visible'));
|
||||
},
|
||||
|
||||
_toggleVisibility: function () {
|
||||
this.$el.toggleClass('is-visible', !!this.model.get('visible'));
|
||||
},
|
||||
|
||||
isVisible: function () {
|
||||
return this.model.get('visible');
|
||||
},
|
||||
|
||||
_onMouseOver: function () {
|
||||
this._mouseOverAction && this._mouseOverAction();
|
||||
},
|
||||
|
||||
_onMouseOut: function () {
|
||||
this._mouseOutAction && this._mouseOutAction();
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
this._listView && this._listView.clean();
|
||||
CoreView.prototype.remove.call(this);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user