235 lines
5.9 KiB
JavaScript
235 lines
5.9 KiB
JavaScript
|
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();
|
||
|
}
|
||
|
});
|