diff --git a/models/ui_new_fields.py b/models/ui_new_fields.py index 7bf125935e4d48a8f4f0192c5bd46c673e80f31d..17f68e54b84615a22b544782671693fed5ad8d25 100644 --- a/models/ui_new_fields.py +++ b/models/ui_new_fields.py @@ -10,12 +10,11 @@ fieldsModifier = dbui.FieldsModifier('new_fields') fieldsModifier.configure_field('dictionary', headers=['foo', 'faa'], modifyKeys=True, - height=150, - dictCfg={"string": "test", - "boolean": False, - "integer": 0, - "float": 0.01, - "date": "not implemented"}) + value={"string": "test", + "boolean": False, + "integer": 0, + "float": 0.01, + "date": "not implemented"}) fieldsModifier.configure_field('python_code', xtype='xaceeditorfield') diff --git a/static/plugin_dbui/src/form/field/Dict.js b/static/plugin_dbui/src/form/field/Dict.js index 999cfb435704dbe8feae3c918ce1e2a594cdc291..f0ffc9fc74b8ec859b438683841dcf184913e6b8 100644 --- a/static/plugin_dbui/src/form/field/Dict.js +++ b/static/plugin_dbui/src/form/field/Dict.js @@ -1,39 +1,41 @@ /** - * The Dict widget is an Ext.grid.PropertyGrid which is associated - * to a JSON database field. It can be embedded in Ext.form.Panel. - * + * The form field to render the web2py database type JSON. * The JSON object is a dictionary. It can only contains boolean, * date, float and string objects. * * The default structure of the dictionary can be defined via - * the configuration option #dictCfg. - * It is possible to add / delete key value pairs. + * the configuration option #value: + * { + * "(name)": "My Object", + * "Created": new Date(Date.parse('10/15/2006')), + * "Available": false, + * "Version": .01, + * "Description": "A test object" + * } + * + * The basic syntax is also working: + * { + * foo: 1.23 + * } + * + * Keys can be added / modified / deleted key when the configuration + * option #modifyKeys is true. + * + * The interface is less rich than the one of the Ext.form.field.Base. + * It contains the basic methods getValue, setValue, reset, ... * - * @experimental * @since 0.4.15.0 * */ Ext.define('App.form.field.Dict', { - extend: 'Ext.form.field.Base', + extend: 'Ext.form.FieldContainer', + mixins: { + field: 'Ext.form.field.Field' + }, alias: 'widget.xdictfield', uses: ['Ext.grid.property.Grid', 'Ext.menu.Menu'], - /** - * @cfg {Object} - * The default configuration for the dictionary, e.g. - * - * { - * "(name)": "My Object", - * "Created": new Date(Date.parse('10/15/2006')), - * "Available": false, - * "Version": .01, - * "Description": "A test object" - * } - * - */ - dictCfg: {}, - /** * @cfg {String[]} * The labels of the columns to be shown in the grid widget. @@ -52,10 +54,25 @@ Ext.define('App.form.field.Dict', { */ modifyKeys: false, + /** + * @event keychange + * Fire when a key is added, modified or destroyed. + * + * @param {object} this + * @param {String} action + * @param {String} oldKey + * @param {String} newKey + */ + + // Predefined configuration options + layout: 'anchor', + defaults: { + anchor: '100%' + }, + // private short cuts grid: null, menu: null, - record: null, // private properties for internationalization textAddMenu: 'Add', @@ -70,89 +87,87 @@ Ext.define('App.form.field.Dict', { // private method requests by the component model of ExtJS initComponent: function () { - var columns, + var me = this, + columns, i, - headerContainer; - - this.addEvents( - /** - * @event keychange - * Fire when a key is added, modified or destroyed. - * - * @param {object} this - * @param {String} action - * @param {String} oldKey - * @param {String} newKey - */ - 'keychange' - ); - - // property grid - this.grid = Ext.create('Ext.grid.property.Grid', { - hideHeaders: this.hideHeaders, - source: Ext.apply({}, this.dictCfg) - }); + headerContainer, + source = me.value || {}; + + // configure the property grid embedded in the container + me.items = [{ + xtype: 'propertygrid', + hideHeaders: me.hideHeaders, + source: source + }]; + + // instantiate the base class + me.callParent(arguments); + + // short cut to the grid + me.grid = me.child('propertygrid'); // dedicated column headers - if (this.headers) { + if (me.headers) { - headerContainer = this.grid.getDockedItems('headercontainer')[0]; + headerContainer = me.grid.getDockedItems('headercontainer')[0]; columns = headerContainer.getGridColumns(); for (i = 0; i < columns.length; i += 1) { - columns[i].setText(this.headers[i]); + columns[i].setText(me.headers[i]); } } // context menu - this.grid.on('cellcontextmenu', this.onCellContextMenu, this); - this.grid.on('containercontextmenu', this.onContainerContextMenu, this); - this.grid.on('headercontextmenu', this.onHeaderContextMenu, this); + me.grid.on('cellcontextmenu', me.onCellContextMenu, me); + me.grid.on('containercontextmenu', me.onContainerContextMenu, me); + me.grid.on('headercontextmenu', me.onHeaderContextMenu, me); - if (this.modifyKeys) { + if (me.modifyKeys) { - this.menu = Ext.create('Ext.menu.Menu', { + me.menu = Ext.create('Ext.menu.Menu', { items: [{ - text: this.textAddMenu, + text: me.textAddMenu, iconCls: 'xaction-create', itemId: 'add', - handler: this.onAddKey, - scope: this + handler: me.onAddKey, + scope: me }, '-', { - text: this.textUpdateMenu, + text: me.textUpdateMenu, iconCls: 'xaction-update', itemId: 'update', - handler: this.onUpdateKey, - scope: this + handler: me.onUpdateKey, + scope: me }, '-', { - text: this.textDestroyMenu, + text: me.textDestroyMenu, iconCls: 'xaction-destroy', itemId: 'destroy', - handler: this.onDeleteKey, - scope: this + handler: me.onDeleteKey, + scope: me }] }); } - // instantiate the base class - this.callParent(arguments); + // initialize the mixin Field + me.initField(); }, // private method requests by the component model of ExtJS beforeDestroy: function () { - this.grid.un('cellcontextmenu', this.onCellContextMenu, this); - this.grid.un('containercontextmenu', this.onContainerContextMenu, this); - this.grid.un('headercontextmenu', this.onHeaderContextMenu, this); + var me = this; - Ext.destroyMembers(this, 'grid'); - Ext.destroyMembers(this, 'menu'); + me.grid.un('cellcontextmenu', me.onCellContextMenu, me); + me.grid.un('containercontextmenu', me.onContainerContextMenu, me); + me.grid.un('headercontextmenu', me.onHeaderContextMenu, me); - this.callParent(arguments); + Ext.destroyMembers(me, 'grid'); + Ext.destroyMembers(me, 'menu'); + + me.callParent(arguments); }, /** - * Return the value of this field. + * Return the value of me field. * * @return {Object} the content of the dictionary. * @@ -160,7 +175,9 @@ Ext.define('App.form.field.Dict', { getValue: function () { "use strict"; - return Ext.apply({}, this.grid.getSource()); + var me = this; + + return Ext.apply({}, me.grid.getSource()); }, /** @@ -170,21 +187,26 @@ Ext.define('App.form.field.Dict', { "use strict"; + var me = this, + source = me.grid.getSource(); + // prompt the user to get the key name - Ext.Msg.prompt(this.textAddTitle, "", function (btn, text) { + Ext.Msg.prompt(me.textAddTitle, "", function (btn, text) { if (btn === 'ok') { // check that the key is unique - if (this.grid.getSource().hasOwnProperty(text)) { - Ext.Msg.alert(this.textErrorTitle, this.textErrorMsg); + if (source.hasOwnProperty(text)) { + Ext.Msg.alert(me.textErrorTitle, me.textErrorMsg); return; } // add the new key - this.grid.setProperty(text, null, true); - this.fireEvent('keychange', this, 'add', undefined, text); + source[text] = null; + me.grid.setSource(source); + + me.fireEvent('keychange', me, 'add', undefined, text); } - }, this); + }, me); }, /** @@ -203,15 +225,16 @@ Ext.define('App.form.field.Dict', { onCellContextMenu: function (table, td, cellIndex, record, tr, rowIndex, event, eOpts) { "use strict"; + var me = this; + event.stopEvent(); - if (this.modifyKeys && cellIndex === 0) { - this.record = record; + if (me.modifyKeys && cellIndex === 0) { - this.menu.getComponent('destroy').setDisabled(false); - this.menu.getComponent('update').setDisabled(false); + me.menu.getComponent('destroy').setDisabled(false); + me.menu.getComponent('update').setDisabled(false); - this.menu.showAt(event.getXY()); + me.menu.showAt(event.getXY()); } }, @@ -227,13 +250,15 @@ Ext.define('App.form.field.Dict', { onContainerContextMenu: function (view, event, eOpts) { "use strict"; + var me = this; + event.stopEvent(); - if (this.modifyKeys) { - this.menu.getComponent('destroy').setDisabled(true); - this.menu.getComponent('update').setDisabled(true); + if (me.modifyKeys) { + me.menu.getComponent('destroy').setDisabled(true); + me.menu.getComponent('update').setDisabled(true); - this.menu.showAt(event.getXY()); + me.menu.showAt(event.getXY()); } }, @@ -244,14 +269,16 @@ Ext.define('App.form.field.Dict', { "use strict"; - var prop = this.record.get("name"); + var me = this, + record = me.grid.getSelectionModel().getSelection()[0], + prop = record.get("name"); - Ext.Msg.confirm(this.textDestroyTitle, prop, function (btn) { + Ext.Msg.confirm(me.textDestroyTitle, prop, function (btn) { if (btn === "yes") { - this.grid.removeProperty(prop); - this.fireEvent('keychange', this, 'destroy', prop, undefined); + me.grid.removeProperty(prop); + me.fireEvent('keychange', me, 'destroy', prop, undefined); } - }, this); + }, me); }, /** @@ -266,39 +293,17 @@ Ext.define('App.form.field.Dict', { onHeaderContextMenu: function (headerContainer, column, event, html, eOpts) { "use strict"; - event.stopEvent(); - }, - - /** - * Render the widget. - * - * @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); + var me = this, + source = me.grid.getSource(), + isSourceEmpty = Object.keys(source).length === 0; - // 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) { + event.stopEvent(); - this.grid.setSize(w - this.getLabelWidth(), h); - this.callParent(arguments); + // allow to add key if source is not defined + if (me.modifyKeys && isSourceEmpty && column.getItemId() === 'name') { + me.onAddKey(); + } }, /** @@ -308,25 +313,30 @@ Ext.define('App.form.field.Dict', { "use strict"; - var key = this.record.get("name"), - value = this.record.get("value"); + var me = this, + record = me.grid.getSelectionModel().getSelection()[0], + key = record.get("name"), + value = record.get("value"), + source = me.grid.getSource(); // prompt the user to modify the key - Ext.Msg.prompt(this.textUpdateTitle, "", function (btn, text) { + Ext.Msg.prompt(me.textUpdateTitle, "", function (btn, text) { if (btn === 'ok') { // check that the key is unique - if (this.grid.getSource().hasOwnProperty(text)) { - Ext.Msg.alert(this.textErrorTitle, this.textErrorMsg); + if (source.hasOwnProperty(text)) { + Ext.Msg.alert(me.textErrorTitle, me.textErrorMsg); return; } // update the key - this.grid.removeProperty(key); - this.grid.setProperty(text, value, true); - this.fireEvent('keychange', this, 'update', key, text); + delete source[key]; + source[text] = value; + me.grid.setSource(source); + + me.fireEvent('keychange', me, 'update', key, text); } - }, this, false, key); + }, me, false, key); }, @@ -340,9 +350,15 @@ Ext.define('App.form.field.Dict', { */ setValue: function (value) { - var source = value || this.dictCfg; - this.grid.setSource(source); + "use strict"; + + var me = this, + source = value || me.originalValue; + + me.grid.setSource(source); - return this.callParent([source]); + // the standard way to set the value for a field + // extract from Ext.form.field.Base + return me.mixins.field.setValue.call(me, source); } -}); \ No newline at end of file +}); diff --git a/static/scripts/dict.js b/static/scripts/dict.js index 54c8f7c132b947e7d4bc16bb926b787086c6d10c..530aa22b5369ec94c2aa98b3795e102a8d8ebf77 100644 --- a/static/scripts/dict.js +++ b/static/scripts/dict.js @@ -47,7 +47,7 @@ Ext.onReady(function(){ listeners: { keychange: { fn: function (cmp, action, oldKey, newKey) { - Ext.Msg.alert('Event', action + ' ' + oldKey + ' ' + newKey); + Ext.Msg.alert('Catch event with arguments:', action + ', ' + oldKey + ', ' + newKey); } } }