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.
260 lines (225 loc) • 9.35 kB
JavaScript
/**
* Developer: Stepan Burguchev
* Date: 10/13/2014
* Copyright: 2009-2016 Comindware®
* All Rights Reserved
* Published under the MIT license
*/
import { Handlebars, keypress } from 'lib';
import VirtualCollection from '../../collections/VirtualCollection';
import dropdown from 'dropdown';
import template from './templates/referenceEditor.hbs';
import BaseLayoutEditorView from './base/BaseLayoutEditorView';
import ReferenceButtonView from './impl/reference/views/ReferenceButtonView';
import ReferencePanelView from './impl/reference/views/ReferencePanelView';
import DefaultReferenceModel from './impl/reference/models/DefaultReferenceModel';
import ReferenceListItemView from './impl/reference/views/ReferenceListItemView';
import formRepository from '../formRepository';
const ReferenceCollection = Backbone.Collection.extend({
model: DefaultReferenceModel
});
const classes = {
};
const defaultOptions = {
displayAttribute: 'text',
controller: null,
showAddNewButton: false,
showEditButton: false,
buttonView: ReferenceButtonView,
listItemView: ReferenceListItemView,
textFilterDelay: 300,
showTitle: true
};
/**
* @name ReferenceEditorView
* @memberof module:core.form.editors
* @class Editor to select object in the format <code>{ id, text }</code>, using async fetch for 'options collection'.
* @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 {BaseReferenceEditorController} [options.controller=null] Data provider, instance
* {@link module:core.form.editors.reference.controllers.BaseReferenceEditorController BaseReferenceEditorController}.
* @param {Boolean} [options.showAddNewButton=false] responsible for displaying button, which providing to user adding new elements.
* @param {Marionette.ItemView} [options.buttonView=ReferenceButtonView] view to display button (what we click on to show dropdown).
* @param {Marionette.ItemView} [options.listItemView=ReferenceListItemView] view to display item in the dropdown list.
* @param {String} [options.displayAttribute='text'] The name of the attribute that contains display text.
* @param {Boolean} {options.showTitle=true} Whether to show title attribute.
* */
formRepository.editors.Reference = BaseLayoutEditorView.extend(/** @lends module:core.form.editors.ReferenceEditorView.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, '__getDisplayText');
this.reqres = new Backbone.Wreqr.RequestResponse();
this.controller = this.options.controller;
this.showAddNewButton = this.options.showAddNewButton;
this.reqres.setHandler('panel:open', this.__onPanelOpenRequest, this);
this.reqres.setHandler('value:clear', this.__onValueClear, this);
this.reqres.setHandler('value:set', this.__onValueSet, this);
this.reqres.setHandler('value:edit', this.__onValueEdit, this);
this.reqres.setHandler('filter:text', this.__onFilterText, this);
this.reqres.setHandler('add:new:item', this.__onAddNewItem, this);
this.value = this.__adjustValue(this.value);
this.viewModel = new Backbone.Model({
button: new Backbone.Model({
value: this.getValue(),
state: 'view',
enabled: this.getEnabled(),
readonly: this.getReadonly()
}),
panel: new Backbone.Model({
value: this.getValue(),
collection: new VirtualCollection(new ReferenceCollection([])),
totalCount: this.controller.totalCount || 0
})
});
},
regions: {
dropdownRegion: '.js-dropdown-region'
},
className: 'editor editor_reference',
template: Handlebars.compile(template),
setValue(value) {
this.__value(value, false);
},
onRender() {
// dropdown
const schema = this.getOption('schema');
this.dropdownView = dropdown.factory.createDropdown({
buttonView: this.options.buttonView,
buttonViewOptions: {
model: this.viewModel.get('button'),
reqres: this.reqres,
getDisplayText: this.__getDisplayText,
showEditButton: this.options.showEditButton,
createValueUrl: this.controller.createValueUrl.bind(this.controller)
},
panelView: ReferencePanelView,
panelViewOptions: {
model: this.viewModel.get('panel'),
reqres: this.reqres,
showAddNewButton: this.showAddNewButton,
listItemView: this.options.listItemView,
getDisplayText: this.__getDisplayText,
textFilterDelay: this.options.textFilterDelay,
hideSearchBar: schema ? schema.hideSearchBar : false
},
panelPosition: 'down-over',
autoOpen: false
});
this.listenTo(this.dropdownView, 'open', this.onFocus);
this.listenTo(this.dropdownView, 'close', this.onBlur);
this.listenTo(this.dropdownView, 'panel:cancel', this.__onCancel);
this.dropdownRegion.show(this.dropdownView);
// hotkeys
if (this.keyListener) {
this.keyListener.reset();
}
this.keyListener = new keypress.Listener(this.el);
_.each('down,enter,num_enter'.split(','), function(key) {
this.keyListener.simple_combo(key, () => {
if (this.getEnabled() && !this.getReadonly()) {
this.dropdownView.open();
}
});
}, this);
if (this.options.showTitle) {
const value = this.getValue();
this.$el.prop('title', value && value.text ? value.text : '');
}
},
__adjustValue(value) {
if (!value || !value.id) {
return null;
}
return value;
},
__value(value, triggerChange) {
if (this.value === value) {
return;
}
this.value = this.__adjustValue(value);
this.viewModel.get('button').set('value', this.value);
this.viewModel.get('panel').set('value', this.value);
if (this.options.showTitle) {
this.$el.prop('title', value && value.text ? value.text : '');
}
if (triggerChange) {
this.__triggerChange();
}
},
isEmptyValue() {
const value = this.getValue();
return !value || _.isEmpty(value);
},
__onValueClear() {
this.__value(null, true);
this.focus();
return false;
},
__onValueSet(model) {
const value = model ? model.toJSON() : null;
this.__value(value, true);
this.dropdownView.close();
this.$el.focus();
},
__onValueEdit() {
return this.controller.edit(this.getValue());
},
__onFilterText(options) {
const text = (options && options.text) || null;
this.text = text;
return this.controller.fetch(options).then(data => {
if (this.text === text) {
this.viewModel.get('panel').get('collection').reset(data.collection);
this.viewModel.get('panel').set('totalCount', data.totalCount);
}
});
},
__onPanelOpenRequest() {
if (this.getEnabled() && !this.getReadonly()) {
this.dropdownView.open();
}
},
__onAddNewItem() {
this.dropdownView.close();
this.controller.addNewItem(createdValue => {
if (createdValue) {
this.__value(createdValue, true);
}
});
},
__getDisplayText(value) {
if (!value) {
return '';
}
return value[this.options.displayAttribute] || `#${value.id}`;
},
setReadonly(readonly) {
//noinspection Eslint
BaseLayoutEditorView.prototype.__setReadonly.call(this, readonly);
this.viewModel.get('button').set('readonly', this.getReadonly());
},
setEnabled(enabled) {
//noinspection Eslint
BaseLayoutEditorView.prototype.__setEnabled.call(this, enabled);
this.viewModel.get('button').set('enabled', this.getEnabled());
},
__setReadonly(readonly) {
BaseLayoutEditorView.prototype.__setReadonly.call(this, readonly);
this.$el.prop('tabindex', readonly ? -1 : 0);
},
focus() {
this.dropdownView.open();
},
blur() {
this.dropdownView.close();
},
__onCancel() {
this.dropdownView.close();
this.$el.focus();
}
});
export default formRepository.editors.Reference;