diff --git a/static/plugin_dbui/src/form/field/List.js b/static/plugin_dbui/src/form/field/List.js index 439a3681ae4f6b8ed518c838df1874d3edd14729..0e2e3ce2369d9165fae26b3d8db0e814f93f648e 100644 --- a/static/plugin_dbui/src/form/field/List.js +++ b/static/plugin_dbui/src/form/field/List.js @@ -1,21 +1,18 @@ /** - * The field list is an Ext.grid.Panel which is associated - * to the database list field. It can be embedded in Ext.form.Panel. + * The form field to render the web2py database type list:string. * - * **Note** :The list can only contains string. + * The interface is less rich than the one of the Ext.form.field.Base. + * It contains the basic methods getValue, setValue, reset, ... * - * **Note** : The onRender handle can be removed using the approach - * describe - * [here](http://stackoverflow.com/questions/6153362/how-to-create-custom-extjs-form-field-component) - * (see rixo) - * - * @experimental * @since 0.4.15.0 * */ Ext.define('App.form.field.List', { - extend: 'Ext.form.field.Base', + extend: 'Ext.form.FieldContainer', + mixins: { + field: 'Ext.form.field.Field' + }, alias: 'widget.xlistfield', uses: ['Ext.data.ArrayStore', 'Ext.form.field.Text', @@ -50,7 +47,14 @@ Ext.define('App.form.field.List', { */ minimumRows: 3, + // Predefined configuration options + layout: 'anchor', + defaults: { + anchor: '100%' + }, + // private short cuts + cellEditing: null, grid: null, menu: null, record: null, @@ -67,88 +71,111 @@ Ext.define('App.form.field.List', { // private method requests by the component model of ExtJS initComponent: function () { - var cellEditing; - - // Hack to get the size of the grid render properly. - // The width is to small when it is not specified. - this.minWidth = this.minWidth || 258; + var me = this, + data = [], + grid, + i; // instantiate the local store - this.store = Ext.create('Ext.data.ArrayStore', { - fields: [{name: 'element'}] - }); + // it is filled with dummy data + for (i = 0; i < me.minimumRows; i += 1) { + data.push([]); + } - // instantiate the cellEditing plugin - cellEditing = Ext.create('Ext.grid.plugin.CellEditing', { - clicksToEdit: 1 + me.store = Ext.create('Ext.data.ArrayStore', { + fields: [{name: 'element'}], + data: data }); - // instantiate the grid - this.grid = Ext.create('Ext.grid.Panel', { + // configure the grid embedded in the container + // it will use the cellEditing plugin + // when a cell is edited it is not marked dirty + me.items = [{ columns: [{ dataIndex: 'element', editor: Ext.create('Ext.form.field.Text', {}), flex: 1, itemId: 'element', sortable: false, - text: this.header + text: me.header }], - hideHeaders: this.hideHeader, - plugins: [cellEditing], + hideHeaders: me.hideHeader, + plugins: { + ptype: 'cellediting', + triggerEvent: 'cellclick' + }, selType: 'cellmodel', - store: this.store - }); + store: me.store, + viewConfig: { + markDirty: false + }, + xtype: 'grid' + }]; + + me.callParent(arguments); // instantiate the context menu - this.menu = Ext.create('Ext.menu.Menu', { + me.menu = Ext.create('Ext.menu.Menu', { items: [{ - text: this.textAdd, + text: me.textAdd, iconCls: 'xaction-create', itemId: 'add', - handler: this.onAddRow, - scope: this + handler: me.onAddRow, + scope: me }, '-', { - text: this.textGoUp, + text: me.textGoUp, iconCls: 'xaction-go-up', itemId: 'goUp', - handler: this.onGoUp, - scope: this + handler: me.onGoUp, + scope: me }, { - text: this.textGoDown, + text: me.textGoDown, iconCls: 'xaction-go-down', itemId: 'goDown', - handler: this.onGoDown, - scope: this + handler: me.onGoDown, + scope: me }, '-', { - text: this.textDestroy, + text: me.textDestroy, iconCls: 'xaction-destroy', itemId: 'destroy', - handler: this.onDeleteRow, - scope: this + handler: me.onDeleteRow, + scope: me }] }); - this.grid.on('containercontextmenu', this.onContainerContextMenu, this); - this.grid.on('itemcontextmenu', this.onItemContextMenu, this); + // handler associate to the grid + me.grid = me.child('grid'); + + me.grid.on('containercontextmenu', me.onContainerContextMenu, me); + me.grid.on('itemcontextmenu', me.onItemContextMenu, me); - this.callParent(arguments); + // avoid editing when the menu is visible + me.cellEditing = me.grid.findPlugin('cellediting'); + me.cellEditing.on('beforeedit', me.onBeforeEdit, me); + + // initialize the mixin Field + me.initField(); }, // private method requests by the component model of ExtJS beforeDestroy: function () { - this.grid.un('containercontextmenu', this.onContainerContextMenu, this); - this.grid.un('itemcontextmenu', this.onItemContextMenu, this); + var me = this; + + me.cellEditing.un('beforeedit', me.onBeforeEdit, me); + + me.grid.un('containercontextmenu', me.onContainerContextMenu, me); + me.grid.un('itemcontextmenu', me.onItemContextMenu, me); - Ext.destroyMembers(this, 'grid'); - Ext.destroyMembers(this, 'menu'); - Ext.destroyMembers(this, 'store'); + Ext.destroyMembers(me, 'grid'); + Ext.destroyMembers(me, 'menu'); + Ext.destroyMembers(me, 'store'); - this.callParent(arguments); + me.callParent(arguments); }, /** - * Return the value of this field + * Return the value of me field * Empty string are not copied in the list when #ignoreEmptyRows is true. * * @return {Array} @@ -158,16 +185,17 @@ Ext.define('App.form.field.List', { "use strict"; - var i, + var me = this, + i, li = [], - records = this.store.getRange(), + records = me.store.getRange(), value; for (i = 0; i < records.length; i += 1) { value = records[i].get("element"); - if (!this.ignoreEmptyRows || value) { + if (!me.ignoreEmptyRows || value) { li.push(value); } } @@ -182,10 +210,27 @@ Ext.define('App.form.field.List', { "use strict"; - var record = this.store.getProxy().getModel().create(); + var me = this, + record = me.store.getProxy().getModel().create(); record.set("element", ""); - this.store.insert(this.rowIndex + 1, record); + me.store.insert(me.rowIndex + 1, record); + }, + + /** + * Inhibit the cell editing if the menu is visible. + * me is required since the cell editing is trigger by any + * cell click (left or right mouse button). + * + */ + onBeforeEdit: function () { + + "use strict"; + var me = this; + + if(me.menu.isVisible()) { + return false; + } }, /** @@ -199,14 +244,16 @@ Ext.define('App.form.field.List', { onContainerContextMenu: function (view, event, eOpts) { "use strict"; + var me = this; + event.stopEvent(); - this.menu.getComponent('destroy').setDisabled(true); - this.menu.getComponent('goDown').setDisabled(true); - this.menu.getComponent('goUp').setDisabled(true); + me.menu.getComponent('destroy').setDisabled(true); + me.menu.getComponent('goDown').setDisabled(true); + me.menu.getComponent('goUp').setDisabled(true); - this.rowIndex = -1; - this.menu.showAt(event.getXY()); + me.rowIndex = -1; + me.menu.showAt(event.getXY()); }, /** @@ -216,13 +263,14 @@ Ext.define('App.form.field.List', { "use strict"; - var value = this.record.get("element"); + var me = this, + value = me.record.get("element"); - Ext.Msg.confirm(this.textDestroyTitle, value, function (btn) { + Ext.Msg.confirm(me.textDestroyTitle, value, function (btn) { if (btn === 'yes') { - this.grid.getStore().remove(this.record); + me.store.remove(me.record); } - }, this); + }, me); }, /** @@ -232,13 +280,14 @@ Ext.define('App.form.field.List', { "use strict"; - var recordA, + var me = this, + recordA, recordB, valueA, valueB; - recordA = this.store.getAt(this.rowIndex); - recordB = this.store.getAt(this.rowIndex + 1); + recordA = me.store.getAt(me.rowIndex); + recordB = me.store.getAt(me.rowIndex + 1); valueA = recordA.get('element'); valueB = recordB.get('element'); @@ -254,13 +303,14 @@ Ext.define('App.form.field.List', { "use strict"; - var recordA, + var me = this, + recordA, recordB, valueA, valueB; - recordA = this.store.getAt(this.rowIndex); - recordB = this.store.getAt(this.rowIndex - 1); + recordA = me.store.getAt(me.rowIndex); + recordB = me.store.getAt(me.rowIndex - 1); valueA = recordA.get('element'); valueB = recordB.get('element'); @@ -283,69 +333,47 @@ Ext.define('App.form.field.List', { onItemContextMenu: function (view, record, item, index, event, eOpts) { "use strict"; + var me = this; event.stopEvent(); - this.record = record; - this.rowIndex = index; + // protection to hide the menu if it is already visible + if (me.menu.isVisible()) { + me.menu.hide(); + return; + } + + me.record = record; + me.rowIndex = index; - this.menu.showAt(event.getXY()); + me.menu.showAt(event.getXY()); - this.menu.getComponent('destroy').setDisabled(false); - this.menu.getComponent('goDown').setDisabled(false); - this.menu.getComponent('goUp').setDisabled(false); + me.menu.getComponent('destroy').setDisabled(false); + me.menu.getComponent('goDown').setDisabled(false); + me.menu.getComponent('goUp').setDisabled(false); if (index === 0) { - this.menu.getComponent('goUp').setDisabled(true); + me.menu.getComponent('goUp').setDisabled(true); } - if (index === this.grid.getStore().getCount() - 1) { - this.menu.getComponent('goDown').setDisabled(true); + if (index === me.store.getCount() - 1) { + me.menu.getComponent('goDown').setDisabled(true); } }, /** - * Render the field. - * - * @param {Ext.Element} ct The container to render to. - * @param {Object} position The position in the container to render to. - * - */ - onRender: function (ct, position) { - - this.callParent(arguments); - - // wrap an element around the input field - this.resizeEl = this.positionEl = this.wrap = this.bodyEl.wrap(); - this.grid.render(this.wrap); - - // hide the default input field - this.bodyEl.setVisibilityMode(Ext.dom.Element.DISPLAY).hide(); - }, - - /** - * Resize the component - * - * @param {Number} w - * @param {Number} h - * - */ - onResize: function (w, h) { - - this.grid.setSize(w - this.getLabelWidth(), h); - this.callParent(arguments); - }, - - /** - * Set the value for this field. + * Set the value for me field. * * @param {Array} value * The content of the list. */ setValue: function (value) { - var data = [], + "use strict"; + + var me = this, + data = [], i; // convert the list in a list of list @@ -355,22 +383,24 @@ Ext.define('App.form.field.List', { data.push([value[i]]); } - if (value.length < this.minimumRows) { - for (i = value.length; i < this.minimumRows; i += 1) { + if (value.length < me.minimumRows) { + for (i = value.length; i < me.minimumRows; i += 1) { data.push([]); } } } else { - for (i = 0; i < this.minimumRows; i += 1) { + for (i = 0; i < me.minimumRows; i += 1) { data.push([]); } } // replace the content of the store with the new data set - this.store.loadData(data, false); + me.store.loadData(data, false); - this.callParent(arguments); + // the standard way to set the value for a field + // extract from Ext.form.field.Base + return me.mixins.field.setValue.call(me, value); } }); \ No newline at end of file