comindware.ui
Version:
Comindware Core UI provides the basic components like editors, lists, dropdowns, popups that we so desperately need while creating Marionette-based single-page applications.
230 lines (196 loc) • 8.59 kB
JavaScript
/**
* Developer: Stepan Burguchev
* Date: 1/16/2015
* Copyright: 2009-2016 Comindware®
* All Rights Reserved
* Published under the MIT license
*/
'use strict';
import { Handlebars, keypress } from 'lib';
import list from 'list';
import dropdown from 'dropdown';
import template from './templates/dropdownEditor.hbs';
import BaseLayoutEditorView from './base/BaseLayoutEditorView';
import DropdownPanelView from './impl/dropdown/views/DropdownPanelView';
import DropdownButtonView from './impl/dropdown/views/DropdownButtonView';
import formRepository from '../formRepository';
const classes = {
};
const defaultOptions = {
collection: null,
displayAttribute: 'text',
allowEmptyValue: true,
enableSearch: false,
showTitle: true
};
/**
* @name DropdownEditorView
* @memberof module:core.form.editors
* @class Dropdown editor that allows to select a value from a list. Тип данных редактируемого значения должен
* совпадать с типом данных поля <code>id</code> элементов коллекции <code>collection</code>.
* @extends module:core.form.editors.base.BaseEditorView
* @param {Object} options Options object. All the properties of {@link module:core.form.editors.base.BaseEditorView BaseEditorView} class are also supported.
* @param {Boolean} [options.allowEmptyValue=true] Whether to allow <code>null</code> value to be set.
* @param {Backbone.Collection|Array} options.collection Массив объектов <code>{ id, text }</code> или
* Backbone коллекция моделей с такими атрибутами. Используйте свойство <code>displayAttribute</code> для отображения
* текста из поля, отличного от <code>text</code>. В случае передачи Backbone.Collection, дальнейшее ее изменение
* отражается в выпадающем списке.
* @param {String} [options.displayAttribute='text'] The name of the attribute that contains display text.
* @param {Boolean} [options.enableSearch=false] Whether to display search bar in the dropdown panel.
* @param {Boolean} {options.showTitle=true} Whether to show title attribute.
* */
formRepository.editors.Dropdown = BaseLayoutEditorView.extend(/** @lends module:core.form.editors.DropdownEditorView.prototype */{
initialize(options) {
if (options.schema) {
_.extend(this.options, defaultOptions, _.pick(options.schema, _.keys(defaultOptions)));
} else {
_.extend(this.options, defaultOptions, _.pick(options || {}, _.keys(defaultOptions)));
}
_.bindAll(this, '__onCollectionChange');
this.reqres = new Backbone.Wreqr.RequestResponse();
this.reqres.setHandler('value:set', this.onValueSet, this);
this.reqres.setHandler('panel:open', this.onPanelOpen, this);
if (_.isArray(this.options.collection)) {
this.options.collection = new Backbone.Collection(this.options.collection);
}
this.collection = this.options.collection;
// adding ListItem behavior to collection model
const fixModel = function(model) {
_.extend(model, new list.models.behaviors.ListItemBehavior(model));
};
this.collection.each(fixModel);
const oldModel = this.collection.model;
this.collection.model = oldModel.extend({
initialize() {
oldModel.prototype.initialize.apply(this, arguments);
fixModel(this);
}
});
this.listenTo(this.collection, 'add', this.__onCollectionChange);
this.listenTo(this.collection, 'remove', this.__onCollectionChange);
this.listenTo(this.collection, 'reset', this.__onCollectionChange);
this.viewModel = new Backbone.Model({
button: new Backbone.Model({
value: this.__findModel(this.getValue()),
displayAttribute: this.options.displayAttribute
}),
panel: new Backbone.Model({
collection: this.collection,
value: this.__findModel(this.getValue()),
displayAttribute: this.options.displayAttribute
})
});
},
focusElement: '.js-dropdown-region',
regions: {
dropdownRegion: '.js-dropdown-region'
},
className: 'dropdown-view editor',
template: Handlebars.compile(template),
setValue(value) {
this.__value(value, false);
},
onRender() {
this.__assignKeyboardShortcuts();
this.dropdownView = dropdown.factory.createDropdown({
buttonView: DropdownButtonView,
buttonViewOptions: {
model: this.viewModel.get('button'),
reqres: this.reqres,
allowEmptyValue: this.options.allowEmptyValue
},
panelView: DropdownPanelView,
panelViewOptions: {
model: this.viewModel.get('panel'),
reqres: this.reqres,
enableSearch: this.options.enableSearch
},
autoOpen: false
});
this.listenTo(this.dropdownView, 'close', this.onBlur);
this.listenTo(this.dropdownView, 'panel:cancel', this.__onCancel);
this.dropdownRegion.show(this.dropdownView);
if (this.options.showTitle) {
const valueModel = this.__findModel(this.getValue());
this.$el.prop('title', valueModel && valueModel.has('text') ? valueModel.get('text') : '');
}
},
__onCollectionChange() {
const value = this.getValue();
const valueModel = this.collection.findWhere({ id: value });
if (valueModel !== null) {
if (valueModel !== this.viewModel.get('button').get('value')) {
this.viewModel.get('button').set('value', valueModel);
}
if (valueModel !== this.viewModel.get('panel').get('value')) {
this.viewModel.get('panel').set('value', valueModel);
}
return;
}
if (this.options.allowEmptyValue || this.collection.length === null) {
this.setValue(null);
} else {
this.setValue(this.collection.at(0).id);
}
},
__findModel(value) {
return this.collection ? this.collection.findWhere({ id: value }) : null;
},
__assignKeyboardShortcuts() {
if (this.keyListener) {
this.keyListener.reset();
}
this.keyListener = new keypress.Listener(this.el);
_.each('enter,num_enter,down'.split(','), function(key) {
this.keyListener.simple_combo(key, () => {
if (this.getEnabled() && !this.getReadonly()) {
this.dropdownView.open();
}
});
}, this);
this.keyListener.simple_combo('esc', () => {
if (this.getEnabled() && !this.getReadonly()) {
this.dropdownView.close();
}
});
},
__setReadonly(readonly) {
BaseLayoutEditorView.prototype.__setReadonly.call(this, readonly);
if (this.getEnabled()) {
this.__getFocusElement().prop('tabindex', readonly ? -1 : 0);
}
},
__value(value, triggerChange) {
if (this.value === value) {
return;
}
this.value = value;
const valueModel = this.__findModel(value) || null;
this.viewModel.get('button').set('value', valueModel);
this.viewModel.get('panel').set('value', valueModel);
if (this.options.showTitle) {
this.$el.prop('title', valueModel && valueModel.has('text') ? valueModel.get('text') : '');
}
if (triggerChange) {
this.__triggerChange();
}
},
onValueSet(o) {
this.__value(o ? o.id : null, true);
this.dropdownView.close();
this.focus();
},
onPanelOpen() {
if (this.getEnabled() && !this.getReadonly()) {
this.dropdownView.open();
}
},
blur() {
this.dropdownView.close();
},
__onCancel() {
this.dropdownView.close();
this.focus();
}
});
export default formRepository.editors.Dropdown;