diff --git a/controllers/reports.py b/controllers/reports.py index 0f8ded05072aa6374c53e611cda2cca800102bf5..00f38ca41821bf483018ffe045d5df9b9c07a039 100644 --- a/controllers/reports.py +++ b/controllers/reports.py @@ -22,17 +22,15 @@ def report_2(): """Return the URL arguments """ - print "hello word" -# selector = Selector(virtdb.foo1, extfield='my_format') + selector = Selector(virtdb.foo1, extfield='my_format') # user request a file with a specific format (latex,...) -# iframe = selector.download() -# if iframe: -# return iframe + iframe = selector.download() + if iframe: + return iframe - # standart response with the selected values -# return dict(test=selector.as_dict()) - return "report_2" + # standard response with the selected values + return dict(test=selector.as_dict()) def report_3(): diff --git a/models/widgets_fields.py b/models/widgets_fields.py index 84529f11b3e7f283623de512e57b05078982361e..826baa6518625cfea50f401ee38b544ab4440580 100644 --- a/models/widgets_fields.py +++ b/models/widgets_fields.py @@ -2,30 +2,36 @@ """ widgets fields """ +#------------------------------------------------------------------------------- # # harvest selector (merge) # fieldsModifier = dbui.FieldsModifier('harvester_selector') fieldsModifier.configure_field('year_start', flex=1) fieldsModifier.configure_field('year_end', flex=1) -fieldsModifier.merge_fields('year_start', 'year_end', fieldLabel=T('Year')) +fieldsModifier.merge_fields('year_start', + 'year_end', + combineLabels=True, + defaults={'flex': 1}, + fieldLabel=T('Year'), + layout='hbox') +#------------------------------------------------------------------------------- # # new_fields # fieldsModifier = dbui.FieldsModifier('new_fields') -fieldsModifier.configure_field('dictionary', height=120, +fieldsModifier.configure_field('dictionary', headers=['foo', 'faa'], + modifyKeys=True, dictCfg={"string": "test", "boolean": False, "integer": 0, "float": 0.01, "date": "not implemented"}) + +fieldsModifier.configure_field('python_code', xtype='xaceeditorfield') -fieldsModifier.configure_field('list_string', height=120) - -fieldsModifier.configure_field('python_code', height=120, - xtype='xaceeditorfield',) - +#------------------------------------------------------------------------------- # # publications # diff --git a/models/widgets_forms.py b/models/widgets_forms.py index 9ef413461132ec98f6964935501608cd24772390..6e11d693f631c3ad4651f43bf7849cfb0d9542cf 100644 --- a/models/widgets_forms.py +++ b/models/widgets_forms.py @@ -2,46 +2,36 @@ """ widgets forms """ +#------------------------------------------------------------------------------- # # add plugin to all forms # dbui.configure_forms(db, plugins=['pFormToolTip']) +#------------------------------------------------------------------------------- # -# link comboboxes in foo1 selector -# -#formModifier = dbui.FormModifier('foo1') -#formModifier.link_comboboxes(masterName='my_axis', -# slaveNames='my_granularity', -# storeName='axesStore', -# displayFieldMaster='axis_local', -# valueFieldMaster='axis', -# displayFieldSlaves='granularity_local', -# valueFieldSlaves='granularity') - -# -# link several comboboxes in harvester selector +# harvester selector # formModifier = dbui.FormModifier('harvester_selector') formModifier.link_comboboxes(master=virtdb.harvester_selector.id_projects, slave=virtdb.harvester_selector.controller, masterHasSlaveData='harvesters') - + formModifier = dbui.FormModifier('harvester_selector') formModifier.link_comboboxes(master=virtdb.harvester_selector.id_projects, slave=virtdb.harvester_selector.id_teams, masterHasSlaveData='harvesters') -# -# new fields +#------------------------------------------------------------------------------- +# +# new_fields # formModifier = dbui.FormModifier('new_fields') -formModifier.configure(width=400, - defaults={'width': 270}) - +formModifier.configure(width=400) +#------------------------------------------------------------------------------- # -# Create fieldSet for the publication form +# publication # formModifier = dbui.FormModifier('publications') formModifier.merge_fields('title', diff --git a/models/widgets_grids.py b/models/widgets_grids.py index dcbd1cba4be3113c5859922213aad4bb3ddf909c..9f65e4bbd8054f7247aedd8c47bef7b9da61ae16 100644 --- a/models/widgets_grids.py +++ b/models/widgets_grids.py @@ -2,6 +2,7 @@ """ widgets grids """ +#------------------------------------------------------------------------------- # # add plugin to all grids # @@ -9,8 +10,10 @@ dbui.configure_grids(db, plugins=['pGridRowEditorConfirmDelete', 'pGridRowEditorContextMenu', 'pGridRowEditorDblClick', 'pGridExpertMenu']) + +#------------------------------------------------------------------------------- # -# Polish categories grid +# categories # gridModifier = dbui.GridModifier('categories') gridModifier.configure_column('code', width=10) @@ -20,8 +23,9 @@ gridModifier.append_filter(('code', 'contains', T('bla bla...'))) gridModifier.set_filters(plugins=['pFormToolTip'], width=300) +#------------------------------------------------------------------------------- # -# Define a column template for the publications grid +# publications # tpl = ['<b>{PublicationsTitle}</b><br>', '{PublicationsAuthors}', diff --git a/models/widgets_stores.py b/models/widgets_stores.py index 061d32780230485f7df5d5430eafb2e6c6bced60..45b9989ae8a0ac008307cf9f2fdaebb38e1b0ec7 100644 --- a/models/widgets_stores.py +++ b/models/widgets_stores.py @@ -2,19 +2,10 @@ """ widgets stores """ -# -# Create a static store with the axes definition -# -cfg = dbui.ArrayStore(fields=['axis', 'axis_local', 'granularity', 'granularity_local'], - data=[['projects', T('projects'), 'project', T('project')], - ['projects', T('projects'), 'agency', T('agency')], - ['teams', T('teams'), 'team', T('team')], - ['teams', T('teams'), 'domain', T('domain')], - ['time', T('time'), 'year', T('year')]]) -dbui.AddStore('axes', **cfg) +#------------------------------------------------------------------------------- # -# order store contents for technical tables +# teams # storeModifier = dbui.StoreModifier('teams') storeModifier.orderby(~db.teams.team) diff --git a/models/widgets_viewport.py b/models/widgets_viewport.py index 30d34d6af090049b4f1d1ec85d732cdad0106b8f..4fbcdd49fa2af386a5a4b3359b16e2b8a32e7ca5 100644 --- a/models/widgets_viewport.py +++ b/models/widgets_viewport.py @@ -10,34 +10,16 @@ casNode = None # # The form node # -categoriesLeaf = dbui.Window(closable=True, - items=[dbui.to_formPanel(db['categories'])], - title="Add category ...", - layout='fit', - modal=True, - autoHeight=True, - widht=500) - -harvestersLeaf = dbui.Window(closable=True, - items=[dbui.to_formPanel(db['harvesters'])], - layout='fit', - title="Add harvester ...", - modal=True, - autoHeight=True, - widht=500) +formNode = dbui.Node(T('Forms')) +for tablename in ('categories', 'harvesters', 'publications', 'new_fields'): -publicationsLeaf = dbui.Window(closable=True, - items=[dbui.to_formPanel(db['publications'])], - layout='fit', - title="Add publication ...", - modal=True, - autoHeight=True, - widht=500) + leaf = dbui.Window(closable=True, + items=[dbui.to_formPanel(db[tablename])], + layout='fit', + title="Add %s ..." % tablename, + modal=True) -formNode = dbui.Node(T('Forms')) -formNode.add_child(T("categories"), categoriesLeaf) -formNode.add_child(T("harvesters"), harvestersLeaf) -formNode.add_child(T("publications"), publicationsLeaf) + formNode.add_child(T(tablename), leaf) # # the grid node @@ -64,7 +46,7 @@ leaf_2 = dbui.to_panelWithUrlSelector(virtdb.foo1, leaf_3 = dbui.to_panelWithUrlSelector(virtdb.harvester_selector, baseUrl=URL('reports', 'report_3'), - selectorRegion='north', + selectorRegion='east', selectorTitle='Select a project') reportNode = dbui.Node(T('Reports')) @@ -76,8 +58,8 @@ reportNode.add_child(T('report_3'), leaf_3) # The viewport with its navigation tree # viewportModifier = dbui.ViewportModifier() -# viewportModifier.append_plugins('pViewportLogin') -# viewportModifier.configure(logged=True) +viewportModifier.append_plugins('pViewportLogin') +viewportModifier.configure(logged=True); viewportModifier.add_node(helpNode, casNode, formNode, gridNode, reportNode) # viewportModifier.default_node(T('Tables'), T('publications')) diff --git a/modules/plugin_dbui/converter.py b/modules/plugin_dbui/converter.py index fdab65bbd4b78f4f4026bfa74418189994a4fb05..9048e83b886012dfecac43e8e1c652aa0774bc13 100644 --- a/modules/plugin_dbui/converter.py +++ b/modules/plugin_dbui/converter.py @@ -597,8 +597,8 @@ def to_gridPanel(table, **kwargs): # grid with filter filter = to_gridFilter(table) if filter: - cfg = GridWithFilter(panelCfg=dict(cfg), - selectorCfg=filter) + cfg = GridWithFilter(panelItems=dict(cfg), + selectorItems=filter) return cfg @@ -773,9 +773,7 @@ def to_panelWithUrlSelector(table, selectorTitle='Select', **kwargs): # build the configuration for the PanelWithUrlSelector default = dict(isMathJax=False, - panelCfg=Panel(), - selectorCfg=selector, - selectorCollapsible=False) + selectorItems=selector) default.update(kwargs) cfg = PanelWithUrlSelector(**default) diff --git a/modules/plugin_dbui/formmodifier.py b/modules/plugin_dbui/formmodifier.py index 6cd0764c7e2628b22861496a0b94345cf1aeb059..5d6bcd240c083c943a63697f9403ab8b58f2e14b 100644 --- a/modules/plugin_dbui/formmodifier.py +++ b/modules/plugin_dbui/formmodifier.py @@ -137,33 +137,35 @@ class FormModifier(Modifier): fieldsModifier = FieldsModifier(myTable) # Configure the master field - # Skip this step if the master is already defined -- multi slaves master = kwargs['master'] data = fieldsModifier.data.extjs_fields + + extjs = {} + if 'masterExtJS' in kwargs: + extjs = kwargs['masterExtJS'] + + if is_foreign_field(master): + kTable, kField, kId = get_foreign_field(master) + + else: + kTable = exTable + kField = master.name + + masterValueField = encode_field(exTable, master.name) + + # Skip this step if the master is already defined -- multi slaves is_master = master in data and \ 'xtype' in data[master] and \ - data[master]['xtype'] == 'xlinkedcombobox' + data[master]['xtype'] == 'xcomboboxmaster' if not is_master: - - extjs = {} - if 'masterExtJS' in kwargs: - extjs = kwargs['masterExtJS'] - - if is_foreign_field(master): - kTable, kField, kId = get_foreign_field(master) - - else: - kTable = exTable - kField = master.name - fieldsModifier.configure_field(master.name, + itemId=master.name, displayField=encode_field(kTable, kField), valueField=encode_field(exTable, master.name), - role='master', - store=get_store_id(exTable), - xtype='xlinkedcombobox', + refStore=get_store_id(exTable), + xtype='xcomboboxmaster', **extjs) # Configure the slave field @@ -181,11 +183,11 @@ class FormModifier(Modifier): fieldsModifier.configure_field(slave.name, displayField=encode_field(kTable, kField), + masterValueField=masterValueField, + masterItemId=master.name, valueField=encode_field(exTable, slave.name), - mode='local', - role='slave', - store=get_store_id(exTable), - xtype='xlinkedcombobox', + refStore=get_store_id(exTable), + xtype='xcomboboxslave', **extjs) diff --git a/static/plugin_dbui/locale/dbui-lang-fr.js b/static/plugin_dbui/locale/dbui-lang-fr.js index e01446c782d791701c3bb3dcf91486b47e998e85..6f823c53f95492105bede70b51c9a037438e9879 100644 --- a/static/plugin_dbui/locale/dbui-lang-fr.js +++ b/static/plugin_dbui/locale/dbui-lang-fr.js @@ -5,6 +5,7 @@ if (App.BasePanelWithSelector) { Ext.apply(App.BasePanelWithSelector.prototype, { + textError: 'Erreur ... ', textGo: 'Go', textReset: 'Annuler' }); @@ -12,27 +13,23 @@ if (App.BasePanelWithSelector) { if (App.form.field.ComboBox) { Ext.apply(App.form.field.ComboBox.prototype, { - textSelect: 'Sélectioner un(e) ', - + textSelect: 'Sélectioner un(e) ' }); } if (App.form.DictField) { Ext.apply(App.form.DictField.prototype, { - textAdd: 'Ajouter', - textAddTitle: 'Ajouter ...', - textAddMsg: 'Entrez le nom de la clé :', + textAddMenu: 'Ajouter', + textAddTitle: 'Entrez le nom de la clé', - textDestroy: 'Détruire', - textDestroytitle: 'Détruire ...', - textDestroyMsg: 'Voulez-vous vraiment détruire la clé :', + textDestroyMenu: 'Détruire', + textDestroyTitle: 'Voulez-vous vraiment détruire la clé', textErrorTitle: 'Erreur ...', - textErrorMsg: 'Cette clé existe !', + textErrorMsg: 'Cette clé existe déjà !', - textUpdate: 'Modifier', - textUpdatetitle: 'Modifier ...', - textUpdateMsg: 'Modifier la clé :', + textUpdateMenu: 'Modifier', + textUpdateTitle: 'Modifier la clé' }); } @@ -54,16 +51,16 @@ if (App.form.FormPanel) { textServerError: 'Erreur coté serveur.', textStoreError: "la zone de skoctage interne n'est pas défini !!!", textUpdateErrorAction: "Les modifications ont été annulées.", - textUpdateFailed: 'La mise à jour a échoué...', + textUpdateFailed: 'La mise à jour a échoué...' }); } if (App.form.ListField) { Ext.apply(App.form.ListField.prototype, { - textAdd: 'Ajouter une ligne', - textDestroy: 'Détruire cette ligne', + textAdd: 'Ajouter un élément', + textDestroy: 'Détruire cet élément', textDestroytitle: 'Détruire ...', - textDestroyMsg: 'Voulez-vous vraiment détruire la ligne :', + textDestroyMsg: 'Voulez-vous vraiment détruire cet élément', textGoDown: 'Déplacer vers le bas', textGoUp: 'Déplacer vers le haut' }); @@ -128,6 +125,6 @@ if (App.ViewportLogin) { Ext.apply(App.ViewportLogin.prototype, { textChangePwd: 'Changer votre mot de passe', textLogin: "S'identifier", - textLogout: "Quitter l'application", + textLogout: "Quitter l'application" }); } diff --git a/static/plugin_dbui/main.js b/static/plugin_dbui/main.js index 6788a96af5af0cdac2aeaf9a0e0028f1574bfa6b..0d5c144fcc3ad47d160652260bc5c4279e9dc654 100644 --- a/static/plugin_dbui/main.js +++ b/static/plugin_dbui/main.js @@ -5,6 +5,8 @@ Ext.onReady(function(){ + var app; + Ext.QuickTips.init(); // Expose the remote methods @@ -20,6 +22,5 @@ Ext.onReady(function(){ Ext.EventManager.on(window, 'beforeunload', App.closeUserSession); // Instantiate the application - var app = new App.Viewport(App.config.viewport); - + app = Ext.create('App.Viewport', App.config.viewport); }); \ No newline at end of file diff --git a/static/plugin_dbui/src/basepanelwithselector.js b/static/plugin_dbui/src/basepanelwithselector.js index 3a229d7034f66e749d650434d9fa3b31a9e9df77..614c348d06a3c86723ab0dc13b65b2d99b1c3406 100644 --- a/static/plugin_dbui/src/basepanelwithselector.js +++ b/static/plugin_dbui/src/basepanelwithselector.js @@ -6,7 +6,7 @@ * The selector contains a set of Fields usually organized in field sets. * and two buttons Go and Reset. * - * The configuration parameter selectorRegion defined the position + * The configuration parameter **selectorRegion** defined the position * of the selector with respect to the central panel. Value are those * of the border layout: east, west, south and north. * By default the selector is on the east side (right). @@ -21,14 +21,14 @@ */ Ext.define('App.BasePanelWithSelector', { - extend: 'Ext.Panel', + extend: 'Ext.panel.Panel', alias: 'widget.xpanelwithselector', /** * @cfg {Object} - * The main panel configuration + * The main panel items. */ - panelCfg: null, + panelItems: null, /** * @cfg {Boolean} @@ -37,9 +37,9 @@ Ext.define('App.BasePanelWithSelector', { /** * @cfg {Object} - * The configuration of the items encapsulated in the selector. + * The selector items. */ - selectorCfg: null, + selectorItems: null, /** * @cfg {Boolean} @@ -102,6 +102,7 @@ Ext.define('App.BasePanelWithSelector', { selectorPanel: null, // Private attribute for internationalization + textError: 'Error ...', textGo: 'Go', textReset: 'Reset', @@ -122,7 +123,7 @@ Ext.define('App.BasePanelWithSelector', { loader: {}, layout: 'fit', itemId: 'mainPanel', - items: this.panelCfg, + items: this.panelItems, region: 'center' }, { bodyPadding: "0 5 0 0", @@ -138,7 +139,7 @@ Ext.define('App.BasePanelWithSelector', { height: this.selectorHeight, layout: 'form', itemId: 'selectorPanel', - items: this.selectorCfg, + items: this.selectorItems, region: this.selectorRegion, split: this.selectorSplit, title: this.selectorTitle, @@ -156,8 +157,40 @@ Ext.define('App.BasePanelWithSelector', { this.mainPanel = this.getComponent('mainPanel'); this.selectorPanel = this.getComponent('selectorPanel'); + // selector buttons toolbar = this.selectorPanel.getDockedItems()[0]; this.goButton = toolbar.getComponent('goButton'); this.resetButton = toolbar.getComponent('resetButton'); + + // loader failure + this.mainPanel.getLoader().on('exception', this.onLoaderFailure, this); + }, + + // Private method requires by the Ext JS component model + beforeDestroy: function () { + + this.mainPanel.getLoader().un('exception', this.onLoaderFailure, this); + this.callParent(arguments); + }, + + /** + * Handler call when the procedure loading the mainPanel failed. + * + * @param {Ext.ComponentLaoder} loader + * @param {Object} response + * @param {Object} options + */ + onLoaderFailure: function (loader, response, options) { + + "use strict"; + + if (response.statusText) { + Ext.Msg.show({ + title: this.textError, + msg: response.statusText, + buttons: Ext.Msg.OK, + icon: Ext.Msg.WARNING + }); + } } }); \ No newline at end of file diff --git a/static/plugin_dbui/src/buttondownload.js b/static/plugin_dbui/src/buttondownload.js index da43a7e50ba8c4ba7231a759575d612984d74ccc..7fdab5974bf10557879b4a6981ab0beed6c6c4a5 100644 --- a/static/plugin_dbui/src/buttondownload.js +++ b/static/plugin_dbui/src/buttondownload.js @@ -4,7 +4,7 @@ */ Ext.define('App.ButtonDownload', { - extend: 'Ext.Button', + extend: 'Ext.button.Button', alias: 'widget.xbuttondownload', /** @@ -16,10 +16,8 @@ Ext.define('App.ButtonDownload', { // private method requests by the component model of ExtJS initComponent: function () { - "use strict"; - - // initialize the underlying class - App.ButtonDownload.superclass.initComponent.call(this); + // initialize the base class + this.callParent(arguments); // download when the button is pressed this.on('click', this.onDownload, this); diff --git a/static/plugin_dbui/src/comboboxmaster.js b/static/plugin_dbui/src/comboboxmaster.js new file mode 100644 index 0000000000000000000000000000000000000000..8306a07744f59754ecdb5dcf7661f572394d8007 --- /dev/null +++ b/static/plugin_dbui/src/comboboxmaster.js @@ -0,0 +1,124 @@ +/** + * The #ComboBoxMaster and the #ComboBoxSlave are two standard ComboBoxes + * linked together in such a way that the values available in the slave + * depends on the selected value in the master. + * + * Both are bind to the unique store, the #refStore. It defines the + * relation between master and slave values. It has to contain the + * displayField and the valueField for the master and for the slave. + * + * The slave ComboBox has two additional configuration parameters: + * + * - ComboBoxSlave#masterItemId. + * It is the itemId of the master widget. + * It is required to link the slave and the master widget in order to + * implement the logic between them. + * + * - ComboBoxSlave@masterValueField. + * The field name containing the valueField used by the master. + * + * Several slaves can be bind to the same master. + * + */ +Ext.define('App.form.field.ComboBoxMaster', { + + extend: 'Ext.form.field.ComboBox', + alias: 'widget.xcomboboxmaster', + + /** + * @cfg {Ext.data.Store/String} [required] + * The reference store shared by the master and by the slave. + * It contains the relation between the master and slave values. + * It has to contain the displayField and the valueField for the master + * and for the slave. + */ + refStore: null, + + // Predefined setting + // Works in auto completion mode when the user type value. + // In any case the value should belongs to the list. + editable: true, + forceSelection: true, + queryMode: 'local', + triggerAction: 'all', + + // private properties for internationalization + textSelect: 'Select a ', + + // private method require by the ExtJs component model + initComponent: function () { + + // defined the empty text from the field label + if (this.fieldLabel && !this.emptyText) { + this.emptyText = this.textSelect + this.fieldLabel + " ..."; + } + + // instantiate the reference store which contains + // the relation between the master and the slave value + this.refStore = App.getStore(this.refStore); + + // build the local store containing master values + // Value are static and never change. + this.store = Ext.create('Ext.data.ArrayStore', { + fields: [this.displayField, this.valueField] + }); + + // initialise the base class + this.callParent(arguments); + + // fill the local store from the reference store + this.loadStore(); + }, + + /** + * Load the local store with the value from the reference one + * + */ + loadStore: function () { + + "use strict"; + + if (this.refStore.isFiltered() || !this.refStore.getTotalCount()) { + + this.refStore.restoreWhere(); + + this.refStore.load({ + callback: this.loadData, + scope: this + }); + + } else { + this.loadData(this.refStore.getRange()); + } + }, + + /** + * Load the data form the reference store to the local store + * + * @param {Ext.data.Model[]} records + * + */ + loadData: function (records) { + + "use strict"; + + var data=[], + i, + keys=[], + master, + value; + + for (i = 0; i < records.length; i += 1) { + + master = records[i].get(this.displayField); + + if (keys.indexOf(master) === -1) { + keys.push(master); + value = records[i].get(this.valueField); + data.push([master, value]); + } + } + + this.store.loadData(data); + } +}); \ No newline at end of file diff --git a/static/plugin_dbui/src/comboboxslave.js b/static/plugin_dbui/src/comboboxslave.js new file mode 100644 index 0000000000000000000000000000000000000000..4fef13b43bf9d5291f6b9c6a1415edaacc99b3d5 --- /dev/null +++ b/static/plugin_dbui/src/comboboxslave.js @@ -0,0 +1,188 @@ +/** + * The counter part of the EXt.form.field.ComboBoxMaster. + * + */ +Ext.define('App.form.field.ComboBoxSlave', { + + extend: 'Ext.form.field.ComboBox', + alias: 'widget.xcomboboxslave', + + /** + * @cfg {String} [required] + * The name of field containing master values. + */ + masterValueField: undefined, + + /** + * @cfg {String} [required] + * The itemId of the master ComboBox. + */ + masterItemId: undefined, + + /** + * @cfg {Ext.data.Store/String} [required] + * The reference store shared by the master and by the slave. + * It contains the relation between the master and slave values. + * It has to contain the displayField and the valueField for the master + * and for the slave. + */ + refStore: null, + + // Predefined setting + // Works in auto completion mode when the user type value. + // In any case the value should belongs to the list. + editable: true, + forceSelection: true, + queryMode: 'local', + triggerAction: 'all', + + // private properties for internationalization + textSelect: 'Select a ', + + // private method require by the ExtJs component model + initComponent: function () { + + // defined the empty text from the field label + if (this.fieldLabel && !this.emptyText) { + this.emptyText = this.textSelect + this.fieldLabel + " ..."; + } + + // instantiate the reference store which contains + // the relation between the master and the slave value + this.refStore = App.getStore(this.refStore); + + // build the local store containing slave and master values + this.store = Ext.create('Ext.data.ArrayStore', { + fields: [ + this.masterValueField, + this.displayField, + this.valueField + ] + }); + + // initialise the base class + this.callParent(arguments); + + // fill the local store from the reference store + this.loadStore(); + + // the slave is disable at start up + this.setDisabled(true); + + // Bind the slave to the master widget. + // Can only be done when widgets exists. + this.on('afterrender', this.bindToMaster, this, {single: true}); + }, + + /** + * Handler binding the master and the slave comboBoxes. + * It is triggered by the afterrender event. + * + */ + bindToMaster: function () { + + "use strict"; + + // Find the master widget + // Assume that it is above in the widget stack. + // Not the optimal way but failed to use this.up(path) ??? + var path = 'xcomboboxmaster[itemId=' + this.masterItemId + ']', + master = this.getRefOwner().query(path)[0]; + + master.on('select', this.onMasterSelect, this); + }, + + /** + * Load the local store with the value from the reference one + * + */ + loadStore: function () { + + "use strict"; + + if (this.refStore.isFiltered() || !this.refStore.getTotalCount()) { + + this.refStore.restoreWhere(); + + this.refStore.load({ + callback: this.loadData, + scope: this + }); + + } else { + this.loadData(this.refStore.getRange()); + } + }, + + /** + * Load the slave data from the reference store to the local store + * Slave value are unique. + * + * @param {Ext.data.Model[]} records + * + */ + loadData: function (records) { + + "use strict"; + + var data=[], + i, + keys=[], + master, + slave, + value; + + for (i = 0; i < records.length; i += 1) { + + slave = records[i].get(this.displayField); + + if (keys.indexOf(slave) === -1) { + keys.push(slave); + master = records[i].get(this.masterValueField); + value = records[i].get(this.valueField); + data.push([master, slave, value]); + } + } + + this.store.loadData(data); + }, + + /** + * Select the authorized slave values. + * When the number of authorized value is equal to 1, the + * value is loaded in the slave. + * + * @param {Ext.form.field.ComboBox} combo + * @param {Ext.data.Model[]} records + * @param {Object} eOpts + */ + onMasterSelect: function (combo, records, eOpts) { + + "use strict"; + + var value = records[0].get(this.masterValueField); + + // clear previous filter + this.store.clearFilter(true); + this.reset(); + + // filter the local store + this.store.filter(this.masterValueField, value); + + // enable the widget + this.setDisabled(false); + + // load the value when there is only one + if (this.store.getCount() === 1) { + this.setValue(this.store.getAt(0).get(this.valueField)); + } + }, + + /** + * Reset and disabled the slave ComboBox + */ + reset: function () { + this.setDisabled(true); + this.callParent(arguments); + } +}); \ No newline at end of file diff --git a/static/plugin_dbui/src/directstore.js b/static/plugin_dbui/src/directstore.js index a3f8705515944841729b73654193e89a20d4c2d7..9aa3c8ff59b1d4de27e03366432f00e791dea451 100644 --- a/static/plugin_dbui/src/directstore.js +++ b/static/plugin_dbui/src/directstore.js @@ -56,10 +56,10 @@ Ext.define('App.data.DirectStore', { } // copy of the initial where condition - if (this.extraParams && this.extraParams.where) { + if (config.extraParams && config.extraParams.where) { this.initialWhere = []; - for (i = 0; i < this.extraParams.where.length; i += 1) { - this.initialWhere.push(this.extraParams.where[i]); + for (i = 0; i < config.extraParams.where.length; i += 1) { + this.initialWhere.push(config.extraParams.where[i]); } } @@ -73,11 +73,8 @@ Ext.define('App.data.DirectStore', { // private method request by the Ext JS component model destroy: function () { - "use strict"; - this.un('write', this.onWrite); - - App.data.DirectStore.superclass.destroy.call(this); + this.callParent(arguments); }, /** @@ -112,18 +109,20 @@ Ext.define('App.data.DirectStore', { "use strict"; - var i; + var conditions = [], + i; if (this.extraParams.where) { if (this.initialWhere) { - this.extraParams.where = []; + for (i = 0; i < this.initialWhere.length; i += 1) { - this.extraParams.where.push(this.initialWhere[i]); + conditions.push(this.initialWhere[i]); } + this.getProxy().setExtraParam('where', conditions); } else { - delete this.extraParams.where; + delete this.getProxy().extraParams.where; } } } diff --git a/static/plugin_dbui/src/fielddict.js b/static/plugin_dbui/src/fielddict.js index b572663bef9fa1fce17b02b7db4efb547e140654..60c4efd6bfcd45f5a5534a95733c9124a69c180b 100644 --- a/static/plugin_dbui/src/fielddict.js +++ b/static/plugin_dbui/src/fielddict.js @@ -11,10 +11,8 @@ Ext.define('Ext.grid.JsonColumn', { constructor: function (cfg) { - "use strict"; - - Ext.grid.JsonColumn.superclass.constructor.call(this, cfg); this.renderer = JSON.stringify; + this.callParent(arguments); } }); @@ -34,18 +32,12 @@ Ext.define('Ext.grid.JsonColumn', { */ Ext.define('App.form.DictField', { - extend: 'Ext.form.Field', + extend: 'Ext.form.field.Base', alias: 'widget.xdictfield', - /** - * @cfg {Boolean} - * - */ - autoHeight: false, - /** * @cfg {Object} - * The default configuration for the dictionary. + * The default configuration for the dictionary, e.g. * * { * "(name)": "My Object", @@ -59,16 +51,14 @@ Ext.define('App.form.DictField', { dictCfg: {}, /** - * @cfg {Array} + * @cfg {String[]} * The labels of the columns to be shown in the grid widget. */ headers: null, - /** - * @cfg {Number} height - */ /** * @cfg {Boolean} + * The columns header is hidden when true. */ hideHeader: false, @@ -81,98 +71,87 @@ Ext.define('App.form.DictField', { // private short cuts grid: null, menu: null, - rowIndex: undefined, + record: null, // private properties for internationalization - textAdd: 'Add', - textAddTitle: 'Add ...', - textAddMsg: 'Please enter the new key:', - textDestroy: 'Delete', - textDestroytitle: 'Delete ...', - textDestroyMsg: 'Are you sure to destroy the key:', + textAddMenu: 'Add', + textAddTitle: 'Please enter the new key', + textDestroyMenu: 'Delete', + textDestroyTitle: 'Are you sure to destroy the key', textErrorTitle: 'Error ...', textErrorMsg: 'The key already exists!', - textUpdate: 'Update', - textUpdateTitle: 'Update ...', - textUpdateMsg: 'Modify the key:', + textUpdateMenu: 'Update', + textUpdateTitle: 'Modify the key', // private method requests by the component model of ExtJS initComponent: function () { - "use strict"; - - var cm, - i; + var columns, + i, + headerContainer; // property grid - this.grid = new Ext.grid.PropertyGrid({ - autoHeight: this.autoHeight, + this.grid = Ext.create('Ext.grid.property.Grid', { hideHeaders: this.hideHeaders, source: Ext.apply({}, this.dictCfg), - viewConfig : { - forceFit: true - } }); - // set the grid height keeping a bottom margin of 5 - if (this.height) { - this.grid.setHeight(this.height); - } - // dedicated column headers if (this.headers) { - cm = this.grid.getColumnModel(); - for (i = 0; i < this.headers.length; i += 1) { - cm.setColumnHeader(i, this.headers[i]); + headerContainer = this.grid.getDockedItems('headercontainer')[0]; + columns = headerContainer.getGridColumns(); + + for (i = 0; i < columns.length; i += 1) { + columns[i].setText(this.headers[i]); } } // context menu - this.grid.on('contextmenu', this.onContextMenu, this); + this.grid.on('cellcontextmenu', this.onCellContextMenu, this); + this.grid.on('containercontextmenu', this.onContainerContextMenu, this); + this.grid.on('headercontextmenu', this.onHeaderContextMenu, this); if (this.modifyKeys) { - this.menu = new Ext.menu.Menu(); - - this.menu.add({ - text: this.textAdd, - iconCls: 'xaction-create', - handler: this.onAddKey, - scope: this - }, '-', { - text: this.textUpdate, - iconCls: 'xaction-update', - handler: this.onUpdateKey, - scope: this - }, '-', { - text: this.textDestroy, - iconCls: 'xaction-destroy', - handler: this.onDeleteKey, - scope: this - }); - this.grid.on('rowcontextmenu', this.onRowContextMenu, this); + this.menu = Ext.create('Ext.menu.Menu', { + items: [{ + text: this.textAddMenu, + iconCls: 'xaction-create', + itemId: 'add', + handler: this.onAddKey, + scope: this + }, '-', { + text: this.textUpdateMenu, + iconCls: 'xaction-update', + itemId: 'update', + handler: this.onUpdateKey, + scope: this + }, '-', { + text: this.textDestroyMenu, + iconCls: 'xaction-destroy', + itemId: 'destroy', + handler: this.onDeleteKey, + scope: this + }] + }); } - // instantiate the underlying class - App.form.DictField.superclass.initComponent.call(this); + // instantiate the base class + this.callParent(arguments); }, // private method requests by the component model of ExtJS beforeDestroy: function () { - "use strict"; - - this.grid.un('contextmenu', this.onContextMenu, this); - - if (this.modifyKeys) { - this.grid.un('rowcontextmenu', this.onRowContextMenu, this); - } + this.grid.un('cellcontextmenu', this.onCellContextMenu, this); + this.grid.un('containercontextmenu', this.onContainerContextMenu, this); + this.grid.un('headercontextmenu', this.onHeaderContextMenu, this); Ext.destroyMembers(this, 'grid'); Ext.destroyMembers(this, 'menu'); - App.form.DictField.superclass.beforeDestroy.call(this); + this.callParent(arguments); }, /** @@ -194,39 +173,68 @@ Ext.define('App.form.DictField', { "use strict"; - var errorTitle = this.textErrorTitle, - errorMsg = this.textErrorMsg, - grid = this.grid; - // prompt the user to get the key name - Ext.Msg.prompt(this.textAddTitle, this.textAddMsg, function (btn, text) { + Ext.Msg.prompt(this.textAddTitle, "", function (btn, text) { if (btn === 'ok') { // check that the key is unique - if (grid.getSource().hasOwnProperty(text)) { - Ext.Msg.alert(errorTitle, errorMsg); + if (this.grid.getSource().hasOwnProperty(text)) { + Ext.Msg.alert(this.textErrorTitle, this.textErrorMsg); return; } // add the new key - grid.setProperty(text, null, true); + this.grid.setProperty(text, null, true); } - }); + }, this); + }, + + /** + * Show the context menu to modify key when right clicking on the first row. + * + * @param {Ext.view.Table} table + * @param {HTMLElement} td + * @param {Number} cellIndec + * @param {Ext.data.Model} record + * @param {HTMLElement} tr + * @param {Number} rowIndex + * @param {Ext.EventObject} event + * @param {Object} eOpts + * + */ + onCellContextMenu: function (table, td, cellIndex, record, tr, rowIndex, event, eOpts) { + + "use strict"; + event.stopEvent(); + + if (this.modifyKeys && cellIndex === 0) { + this.record = record; + + this.menu.getComponent('destroy').setDisabled(false); + this.menu.getComponent('update').setDisabled(false); + + this.menu.showAt(event.getXY()); + } }, /** - * Show the context menu to modify key. + * Show the context menu when the grid is empty. + * In that case only the add option is allowed. * + * @param {Ext.view.View} view * @param {Ext.EventObject} event + * @param {Object} eOpts * */ - onContextMenu: function (event) { + onContainerContextMenu: function (view, event, eOpts) { "use strict"; event.stopEvent(); if (this.modifyKeys) { - this.rowIndex = 0; + this.menu.getComponent('destroy').setDisabled(true); + this.menu.getComponent('update').setDisabled(true); + this.menu.showAt(event.getXY()); } }, @@ -238,19 +246,28 @@ Ext.define('App.form.DictField', { "use strict"; - var grid = this.grid, - msg, - prop, - record = this.grid.getStore().getAt(this.rowIndex); + var prop = this.record.get("name"); - prop = record.get("name"); - msg = this.textDestroyMsg + ' ' + prop; - - Ext.Msg.confirm(this.textDestroyTitle, msg, function (btn) { - if (btn === 'yes') { - grid.removeProperty(prop); + Ext.Msg.confirm(this.textDestroyTitle, prop, function (btn) { + if (btn === "yes") { + this.grid.removeProperty(prop); } - }); + }, this); + }, + + /** + * Inhibit the context menu when the user right click on the header + * + * @param {Ext.grid.header.Container} headerContainer + * @param {Ext.grid.column.Column} column + * @param {Ext.EventObject} event + * @param {HTMLElement} html + * @param {Object} eOpts + */ + onHeaderContextMenu: function (headerContainer, column, event, html, eOpts) { + + "use strict"; + event.stopEvent(); }, /** @@ -262,43 +279,27 @@ Ext.define('App.form.DictField', { */ onRender: function (ct, position) { - "use strict"; - - // hide the default input field - this.autoCreate = { - id: this.id, - name: this.name, - type: 'hidden', - tag: 'input' - }; - - App.form.DictField.superclass.onRender.call(this, ct, position); - - this.wrap = this.el.wrap({cls: 'x-form-field'}); + this.callParent(arguments); - if (this.height) { - this.wrap.setHeight(this.height); - } - - this.resizeEl = this.positionEl = this.wrap; + // 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(); }, /** - * Show the row context menu to modify keys. + * Resize the component * - * @param {Ext.grid.PropertyGrid} grid - * @param {Number} rowIndex - * @param {Ext.EventObject} event + * @param {Number} w + * @param {Number} h * */ - onRowContextMenu: function (grid, rowIndex, event) { - - "use strict"; + onResize: function (w, h) { - event.stopEvent(); - this.rowIndex = rowIndex; - this.menu.showAt(event.getXY()); + this.grid.setSize(w - this.getLabelWidth(), h); + this.callParent(arguments); }, /** @@ -308,22 +309,17 @@ Ext.define('App.form.DictField', { "use strict"; - var key, - record, - value; - - record = this.grid.getStore().getAt(this.rowIndex); - key = record.get("name"); - value = record.get("value"); + var key = this.record.get("name"), + value = this.record.get("value"); // prompt the user to modify the key - Ext.Msg.prompt(this.textUpdateTitle, this.textUpdateMsg, function (btn, text) { + Ext.Msg.prompt(this.textUpdateTitle, "", function (btn, text) { if (btn === 'ok') { // check that the key is unique if (this.grid.getSource().hasOwnProperty(text)) { - Ext.Msg.alert(errorTitle, errorMsg); + Ext.Msg.alert(this.textErrorTitle, this.textErrorMsg); return; } // update the key @@ -343,11 +339,9 @@ Ext.define('App.form.DictField', { */ setValue: function (value) { - "use strict"; - var source = Ext.apply({}, value, this.dictCfg); this.grid.setSource(source); - return App.form.DictField.superclass.setValue.call(this, source); + return this.callParent([source]); } }); \ No newline at end of file diff --git a/static/plugin_dbui/src/fieldeditor.js b/static/plugin_dbui/src/fieldeditor.js index 19fe3553b19990e1c0f9991704fe74a0ab349300..deddad36ee6a4af67f684a271861c87ce75644ce 100644 --- a/static/plugin_dbui/src/fieldeditor.js +++ b/static/plugin_dbui/src/fieldeditor.js @@ -9,7 +9,7 @@ */ Ext.define('App.form.AceEditorField', { - extend: 'Ext.form.Field', + extend: 'Ext.form.field.Base', alias: 'widget.xaceeditorfield', /** @@ -24,6 +24,12 @@ Ext.define('App.form.AceEditorField', { */ language: 'python', + /** + * @cfg {Number} [required] + * The height of the editor widget + */ + editorHeight: 150, + /** * @cfg {String} */ @@ -33,12 +39,21 @@ Ext.define('App.form.AceEditorField', { editor: null, // private method requests by the component model of ExtJS - beforeDestroy: function () { + initComponent: function (config) { - "use strict"; + // Hack to get the size of the editor render properly + // The width is to small when it is not specified. + this.minWidth = this.minWidth || 258; + + this.callParent(arguments); + }, + + // private method requests by the component model of ExtJS + beforeDestroy: function () { Ext.destroyMembers(this, 'editor'); - App.form.AceEditorField.superclass.beforeDestroy.call(this); + + this.callParent(arguments); }, /** @@ -67,13 +82,16 @@ Ext.define('App.form.AceEditorField', { */ onRender: function (ct, position) { - "use strict"; + this.callParent(arguments); - App.form.AceEditorField.superclass.onRender.call(this, ct, position); + // wrap an element around the input field + this.resizeEl = this.positionEl = this.wrap = this.bodyEl.wrap(); - this.wrap = this.el.wrap({cls: 'x-form-text'}); - this.resizeEl = this.positionEl = this.wrap; + // the editor require that the width an height are defined + this.wrap.setWidth(this.wrap.getWidth()); + this.wrap.setHeight(this.editorHeight); + // instantiate the editor this.editor = ace.edit(this.wrap.id); this.editor.getSession().setMode('ace/mode/' + this.language); this.editor.setFontSize(this.fontSize); @@ -81,6 +99,26 @@ Ext.define('App.form.AceEditorField', { if (this.theme) { this.editor.setTheme('ace/theme/' + this.theme); } + + // 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.wrap.setSize(w - this.getLabelWidth(), h); + if (this.editor) { + this.editor.resize(); + } + + this.callParent(arguments); }, /** @@ -91,9 +129,7 @@ Ext.define('App.form.AceEditorField', { */ setValue: function (value) { - "use strict"; - - App.form.AceEditorField.superclass.setValue.call(this, value); + this.callParent(arguments); if (this.editor) { this.editor.setValue(value); diff --git a/static/plugin_dbui/src/fieldlist.js b/static/plugin_dbui/src/fieldlist.js index cbddd064681104cfa3cb01749bd346812e1c458f..095f3b04d2cfaffdc9c408165d630fb6496fcae3 100644 --- a/static/plugin_dbui/src/fieldlist.js +++ b/static/plugin_dbui/src/fieldlist.js @@ -4,31 +4,28 @@ * * **Note** :The list can only contains string. * + * **Note** : The onRender handle can be removed using the approach + * describe in the url (see rixo): + * http://stackoverflow.com/questions/6153362/how-to-create-custom-extjs-form-field-component + * * @experimental * @since 0.4.15.0 * */ Ext.define('App.form.ListField', { - extend: 'Ext.form.Field', + extend: 'Ext.form.field.Base', alias: 'widget.xlistfield', - /** - * @cfg {boolean} - */ - autoHeight: false, - /** * @cfg {string} * The label of the column to be shown in the grid widget. */ header: 'Element', - /** - * @cfg {number} height - */ /** * @cfg {boolean} + * Hide the column header when true. */ hideHeader: false, @@ -51,107 +48,98 @@ Ext.define('App.form.ListField', { // private short cuts grid: null, menu: null, + record: null, rowIndex: undefined, + store: null, // private properties for internationalization - textAdd: 'Insert row', - textDestroy: 'Delete row', - textDestroytitle: 'Delete ...', - textDestroyMsg: 'Are you sure to destroy the row:', + textAdd: 'Insert element', + textDestroy: 'Delete element', + textDestroyTitle: 'Are you sure to destroy the element', textGoDown: 'Move down', textGoUp: 'Move up', // private method requests by the component model of ExtJS initComponent: function () { - "use strict"; + var cellEditing; - var cm, - store; + // 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; // instantiate the local store - store = new Ext.data.ArrayStore({ - fields: [{name: 'element'}], + this.store = Ext.create('Ext.data.ArrayStore', { + fields: [{name: 'element'}] }); - // instantiate the column model - cm = new Ext.grid.ColumnModel([ - { - header: this.header, - dataIndex: 'element', - id: 'element', - editable: true, - editor: new Ext.form.TextField(), - sortable: false - } - ]); + // instantiate the cellEditing plugin + cellEditing = Ext.create('Ext.grid.plugin.CellEditing', { + clicksToEdit: 1 + }); // instantiate the grid - this.grid = new Ext.grid.EditorGridPanel({ - autoExpandColumn: 'element', - autoHeight: this.autoHeight, + this.grid = Ext.create('Ext.grid.Panel', { + columns: [{ + dataIndex: 'element', + editor: new Ext.form.TextField(), + flex: 1, + itemId: 'element', + sortable: false, + text: this.header + }], hideHeaders: this.hideHeader, - clicksToEdit: 1, - colModel: cm, - store: store, - stripeRows: true, - viewConfig: { - forcefit: true - } + plugins: [cellEditing], + selType: 'cellmodel', + store: this.store, }); - // Set the height of the grid with a bottom margin of 10 - if (this.height) { - this.grid.setHeight(this.height - 10); - } - // instantiate the context menu - this.menu = new Ext.menu.Menu(); - - this.menu.add({ - text: this.textAdd, - iconCls: 'xaction-create', - itemId: 'itemInsert', - handler: this.onAddRow, - scope: this - }, '-', { - text: this.textGoUp, - iconCls: 'xaction-go-up', - itemId: 'itemGoUp', - handler: this.onGoUp, - scope: this - }, { - text: this.textGoDown, - iconCls: 'xaction-go-down', - itemId: 'itemGoDown', - handler: this.onGoDown, - scope: this - }, '-', { - text: this.textDestroy, - iconCls: 'xaction-destroy', - itemId: 'itemDestroy', - handler: this.onDeleteRow, - scope: this + this.menu = Ext.create('Ext.menu.Menu', { + items: [{ + text: this.textAdd, + iconCls: 'xaction-create', + itemId: 'add', + handler: this.onAddRow, + scope: this + }, '-', { + text: this.textGoUp, + iconCls: 'xaction-go-up', + itemId: 'goUp', + handler: this.onGoUp, + scope: this + }, { + text: this.textGoDown, + iconCls: 'xaction-go-down', + itemId: 'goDown', + handler: this.onGoDown, + scope: this + }, '-', { + text: this.textDestroy, + iconCls: 'xaction-destroy', + itemId: 'destroy', + handler: this.onDeleteRow, + scope: this + }] }); - this.grid.on('contextmenu', this.onContextMenu, this); - this.grid.on('rowcontextmenu', this.onRowContextMenu, this); + this.grid.on('containercontextmenu', this.onContainerContextMenu, this); + this.grid.on('itemcontextmenu', this.onItemContextMenu, this); - App.form.ListField.superclass.initComponent.call(this); + this.callParent(arguments); }, // private method requests by the component model of ExtJS beforeDestroy: function () { - "use strict"; - - this.grid.un('contextmenu', this.onContextMenu, this); - this.grid.un('rowcontextmenu', this.onRowContextMenu, this); + this.grid.un('containercontextmenu', this.onContainerContextMenu, this); + this.grid.un('itemcontextmenu', this.onItemContextMenu, this); Ext.destroyMembers(this, 'grid'); Ext.destroyMembers(this, 'menu'); + Ext.destroyMembers(this, 'store'); - App.form.ListField.superclass.beforeDestroy.call(this); + this.callParent(arguments); }, /** @@ -167,15 +155,18 @@ Ext.define('App.form.ListField', { var i, li = [], - records = this.grid.getStore().getRange(); + records = this.store.getRange(), + value; for (i = 0; i < records.length; i += 1) { - if (this.ignoreEmptyRows && records[i].data.element === "") { + value = records[i].get("element"); + + if (this.ignoreEmptyRows && value === "") { continue; } - li.push(records[i].data.element); + li.push(value); } return li; @@ -188,25 +179,28 @@ Ext.define('App.form.ListField', { "use strict"; - var record, - store = this.grid.getStore(); + var record = this.store.getProxy().getModel().create(); - record = new store.recordType({element: ""}); - store.insert(this.rowIndex + 1, record); + record.set("element", ""); + this.store.insert(this.rowIndex + 1, record); }, /** * Show the context menu. * + * @param {Ext.view.View} view * @param {Ext.EventObject} event + * @param {Object} eOpts * */ - onContextMenu: function (event) { + onContainerContextMenu: function (view, event, eOpts) { "use strict"; event.stopEvent(); - this.menu.getComponent('itemDestroy').disable(); + this.menu.getComponent('destroy').setDisabled(true); + this.menu.getComponent('goDown').setDisabled(true); + this.menu.getComponent('goUp').setDisabled(true); this.rowIndex = -1; this.menu.showAt(event.getXY()); @@ -219,37 +213,29 @@ Ext.define('App.form.ListField', { "use strict"; - var msg, - record, - store; - - store = this.grid.getStore(); - record = store.getAt(this.rowIndex); + var value = this.record.get("element"); - msg = this.textDestroyMsg + ' ' + record.get("element"); - - Ext.Msg.confirm(this.textDestroyTitle, msg, function (btn) { + Ext.Msg.confirm(this.textDestroyTitle, value, function (btn) { if (btn === 'yes') { - store.remove(record); + this.grid.getStore().remove(this.record); } - }); + }, this); }, /** - * Move the selected row down. + * Move the selected element down. */ onGoDown: function () { "use strict"; - var store = this.grid.getStore(), - recordA, + var recordA, recordB, valueA, valueB; - recordA = store.getAt(this.rowIndex); - recordB = store.getAt(this.rowIndex + 1); + recordA = this.store.getAt(this.rowIndex); + recordB = this.store.getAt(this.rowIndex + 1); valueA = recordA.get('element'); valueB = recordB.get('element'); @@ -259,20 +245,19 @@ Ext.define('App.form.ListField', { }, /** - * Move the selected row up. + * Move the selected element up. */ onGoUp: function () { "use strict"; - var store = this.grid.getStore(), - recordA, + var recordA, recordB, valueA, valueB; - recordA = store.getAt(this.rowIndex); - recordB = store.getAt(this.rowIndex - 1); + recordA = this.store.getAt(this.rowIndex); + recordB = this.store.getAt(this.rowIndex - 1); valueA = recordA.get('element'); valueB = recordB.get('element'); @@ -282,69 +267,71 @@ Ext.define('App.form.ListField', { }, /** - * Render the field. + * Show the row context menu. * - * @param {Ext.Element} ct The container to render to. - * @param {Object} position The position in the container to render to. + * @param {Ext.view.View} view + * @param {Ext.data.Model} record + * @param {HTMLElement} item + * @param {Number} index + * @param {Ext.EventObject} event + * @param {Object} eOpts * */ - onRender: function (ct, position) { + onItemContextMenu: function (view, record, item, index, event, eOpts) { "use strict"; - // hide the default input field - this.autoCreate = { - id: this.id, - name: this.name, - type: 'hidden', - tag: 'input' - }; + event.stopEvent(); + + this.record = record; + this.rowIndex = index; - App.form.ListField.superclass.onRender.call(this, ct, position); + this.menu.showAt(event.getXY()); - this.wrap = this.el.wrap({cls: 'x-form-field'}); - this.wrap.setStyle('border', '1px solid'); - this.wrap.setStyle('border-color', '#B5B8C8'); + this.menu.getComponent('destroy').setDisabled(false); + this.menu.getComponent('goDown').setDisabled(false); + this.menu.getComponent('goUp').setDisabled(false); - if (this.height) { - this.wrap.setHeight(this.height); + if (index === 0) { + this.menu.getComponent('goUp').setDisabled(true); + } + + if (index === this.grid.getStore().getCount() - 1) { + this.menu.getComponent('goDown').setDisabled(true); } - this.resizeEl = this.positionEl = this.wrap; - this.grid.render(this.wrap); }, /** - * Show the row context menu. + * Render the field. * - * @param {Ext.grid.PropertyGrid} grid - * @param {Number} rowIndex - * @param {Ext.EventObject} event + * @param {Ext.Element} ct The container to render to. + * @param {Object} position The position in the container to render to. * */ - onRowContextMenu: function (grid, rowIndex, event) { - - "use strict"; - - event.stopEvent(); - - grid.getSelectionModel().select(rowIndex, 0); + onRender: function (ct, position) { - this.rowIndex = rowIndex; - this.menu.showAt(event.getXY()); + this.callParent(arguments); - this.menu.getComponent('itemDestroy').enable(); - this.menu.getComponent('itemGoDown').enable(); - this.menu.getComponent('itemGoUp').enable(); + // wrap an element around the input field + this.resizeEl = this.positionEl = this.wrap = this.bodyEl.wrap(); + this.grid.render(this.wrap); - if (rowIndex === 0) { - this.menu.getComponent('itemGoUp').disable(); - } + // hide the default input field + this.bodyEl.setVisibilityMode(Ext.dom.Element.DISPLAY).hide(); + }, - if (rowIndex === grid.getStore().getCount() - 1) { - this.menu.getComponent('itemGoDown').disable(); - } + /** + * Resize the component + * + * @param {Number} w + * @param {Number} h + * + */ + onResize: function (w, h) { + this.grid.setSize(w - this.getLabelWidth(), h); + this.callParent(arguments); }, /** @@ -355,8 +342,6 @@ Ext.define('App.form.ListField', { */ setValue: function (value) { - "use strict"; - var data = [], i; @@ -381,8 +366,8 @@ Ext.define('App.form.ListField', { } // replace the content of the store with the new data set - this.grid.getStore().loadData(data, false); + this.store.loadData(data, false); - return App.form.ListField.superclass.setValue.call(this, value); + this.callParent(arguments); } }); \ No newline at end of file diff --git a/static/plugin_dbui/src/grid.js b/static/plugin_dbui/src/grid.js index be6eb07fdf80e24e3e52b814260c9c46cbdee4eb..7d87f94157c0384c763327074fe4319b47dff466 100644 --- a/static/plugin_dbui/src/grid.js +++ b/static/plugin_dbui/src/grid.js @@ -11,7 +11,7 @@ */ Ext.define('App.grid.Grid', { - extend: 'Ext.grid.GridPanel', + extend: 'Ext.grid.Panel', alias: 'widget.xgrid', /** diff --git a/static/plugin_dbui/src/linkedcombobox.js b/static/plugin_dbui/src/linkedcombobox.js deleted file mode 100644 index 53122da0a44e6b77577e02b3e967131deddf77b5..0000000000000000000000000000000000000000 --- a/static/plugin_dbui/src/linkedcombobox.js +++ /dev/null @@ -1,207 +0,0 @@ -/** - * The linked combobox widget has been designed to solve the case - * when the values of a combobox depends on the select value of another one. - * - * The design is based on a master and a slave combobox which are - * linked to a common store. - * - * The master is a standard combobox showing the values used to filter - * the common store. Values are unique and never change. - * The properties role, store, displayField and valueField have to be defined. - * - * A slave is a standard combobox. - * The properties store, displayField and valueField have to be defined. - * The store identifier should be the same for the master and the slave. - * - * Several masters and slaves can be attached to a single store. - * - */ -Ext.define('App.form.LinkedComboBox', { - - extend: 'Ext.form.ComboBox', - alias: 'widget.xlinkedcombobox', - - /** - * @cfg {String} - * The role of the combobox either master of slave. - */ - role: 'slave', - - // private properties - // the masterStore (Ext.data.Store) is the common store - // shared by the master and slaves - masterStore: null, - - // private method require by the ExtJS component model - initComponent: function () { - - "use strict"; - - // common configuration - this.triggerAction = 'all'; - - // prepare the stores for the master role - if (this.role === 'master') { - - this.masterStore = App.getStore(this.store); - - this.mode = 'local'; - this.store = new Ext.data.ArrayStore({ - fields: [this.displayField, this.valueField] - }); - - // reset and/or load the master store - // fill the local store - if (this.masterStore.isFiltered() || !this.masterStore.getTotalCount()) { - - this.masterStore.restoreWhere(); - - this.masterStore.load({ - callback: this.loadMasterData, - scope: this - }); - - } else { - this.loadMasterData(); - } - } - - // prepare the store for the slave role - if (this.role === 'slave') { - this.store = App.getStore(this.store); - - if (!this.store.getTotalCount()) { - this.store.on('load', this.initSlave, this, {single: true}); - - } else { - this.initSlave(); - } - } - - // construct the underlying class. DON'T MOVE - App.form.LinkedComboBox.superclass.initComponent.call(this); - - // logic to filter the content of the master store - // when a value is selected in the master combobox - if (this.role === 'master') { - this.on('select', this.filterMasterStore, this); - - // logic to update the content of a slave - // when a value is selected in the master combobox - } else if (this.role === 'slave') { - this.store.on('datachanged', this.onDataChanged, this); - } - }, - - // private method requires by the Ext JS component model - beforeDestroy: function () { - - "use strict"; - - if (this.role === 'master') { - if (this.masterStore.isFiltered()) { - this.masterStore.restoreWhere(); - this.masterStore.load(); - } - this.store.destroy(); - - } else if (this.role === 'slave') { - this.store.un('load', this.initSlave, this); - this.store.un('datachanged', this.onDataChanged, this); - } - - App.form.LinkedComboBox.superclass.beforeDestroy.call(this); - }, - - /** - * filter the master store with the current value of the combobox - * - * @param {Ext.form.combobox} combo - * @param {Ext.data.Record} record - * @param {Number} index - */ - filterMasterStore: function (combo, record, index) { - "use strict"; - this.masterStore.filter(this.valueField, combo.getValue()); - }, - - // private method to initialise the slave combobox - // A slave is disable at startup. - initSlave: function () { - - "use strict"; - - // Reset and disable the combobox. - // - // NOTE - // when the user select a value in the master combobox - // for the first time, the value of the slave are not filtered - // It contains all possible values. - // To fix this issue, the code mimic the click by a user - // on the slave combobox and then it works !!! - // - // In some case a window on the top left appears with - // the content of the combobox. - // The line combo.hasFocus is a protection against this case. - // - - function initialise(combo) { - combo.onTriggerClick(); - combo.hasFocus = false; - combo.collapse(); - combo.reset(); - combo.disable(); - } - - if (this.role !== 'slave') { - return; - } - - if (this.rendered) { - initialise(this); - - } else { - this.on('render', function (combo) { - initialise(combo); - }); - } - }, - - // Private method to load data in the combo store from the master one - loadMasterData: function () { - - "use strict"; - - var data = [], - key, - keys = [], - i, - record; - - for (i = 0; i < this.masterStore.getCount(); i += 1) { - record = this.masterStore.getAt(i); - key = record.get(this.displayField); - if (keys.indexOf(key) === -1) { - keys.push(key); - data.push([key, record.get(this.valueField)]); - } - } - - this.store.loadData(data); - this.fireEvent('masterready'); - }, - - /** - * Update the content of the slave combobox content - * when a master value is selected. - */ - onDataChanged: function () { - - "use strict"; - - var value = this.store.getAt(0).get(this.valueField); - - this.setValue(value); - this.enable(); - } -}); \ No newline at end of file diff --git a/static/plugin_dbui/src/panelwithurlselector.js b/static/plugin_dbui/src/panelwithurlselector.js index 1a78c2677543053daaefc223e1a28f01c444e28b..15e578dd7358c41c035a9af5f307b7c2aef88a7b 100644 --- a/static/plugin_dbui/src/panelwithurlselector.js +++ b/static/plugin_dbui/src/panelwithurlselector.js @@ -1,20 +1,20 @@ /** * The Panel with URL selector is split in two parts a main panel and a selector. - * The selector display a list of fields organized in fieldset. + * The selector display a list of fields organized in Ext.form.Fieldset. * There values define the URL parameters. The main panel displays * the URL content. * * Configuration for the main panel and the selector are set via - * the option panelCfg and selectorCgf. + * the option panelCfg and selectorCfg. * * The URL display in the main panel is defined by the baseUrl option. * It can be modified dynamically by extracting the name of the * controller, function and/or extension from the selector fields. - * The options ctrlField, extField and funcField associated field - * used to determine the value. + * The options ctrlField, extField and funcField are used to determine + * the associated fields. * - * Mathematical symbols will be interpreted, if the javascript library - * mathjax is load. Use the isMathJax property. + * Mathematical symbols will be interpreted when the javascript library + * mathjax is load and when the isMathJax property is true. * */ Ext.define('App.PanelWithUrlSelector', { @@ -47,7 +47,7 @@ Ext.define('App.PanelWithUrlSelector', { * The name of the field defining the function. * The URL become baseUrl/funcFieldValue */ - funcField: null, + funcField: undefined, /** * @cfg {Boolean} @@ -57,9 +57,9 @@ Ext.define('App.PanelWithUrlSelector', { /** * @cfg {Number} - * The timeout for the Ajax request in second. + * The time out for the Ajax request in millisecond. */ - timeout: 30, + timeout: 30000, // Private properties for internationalization textLoad: 'Loading...', @@ -72,6 +72,11 @@ Ext.define('App.PanelWithUrlSelector', { // connect the buttons this.goButton.on('click', this.onGo, this); this.resetButton.on('click', this.onReset, this); + + // MathJax processing + if (this.isMathJax) { + this.mainPanel.getLoader().on('load', this.onMathJax, this); + } }, // Private method requires by the Ext JS component model @@ -80,6 +85,10 @@ Ext.define('App.PanelWithUrlSelector', { this.goButton.un('click', this.onGo, this); this.resetButton.un('click', this.onReset, this); + if (this.isMathJax) { + this.mainPanel.getLoader().un('load', this.onMathJax, this); + } + this.callParent(arguments); }, @@ -94,9 +103,9 @@ Ext.define('App.PanelWithUrlSelector', { i, params = {}, url = this.baseUrl, - urlCtrl = null, - urlFunc = null, - urlExt = null; + urlCtrl = undefined, + urlFunc = undefined, + urlExt = undefined; function extract(key, subfield) { params[subfield.getName()] = subfield.getValue(); @@ -130,26 +139,21 @@ Ext.define('App.PanelWithUrlSelector', { } // build the URL - if (urlCtrl !== null) { + if (urlCtrl !== undefined) { url = url + '/' + urlCtrl; } - if (urlFunc !== null) { + if (urlFunc !== undefined) { url = url + '/' + urlFunc; } - if (urlExt !== null) { + if (urlExt !== undefined) { url = url + '.' + urlExt; } - // load url in the main panel - console.log(this.mainPanel.getLoader()); - console.log(url); - console.log(params); + // load the URL content in the main panel this.mainPanel.getLoader().load({ - callback: this.onLoad, params: params, - scope: this, text: this.textLoad, url: url, timeout: this.timeout @@ -157,34 +161,18 @@ Ext.define('App.PanelWithUrlSelector', { }, /** - * Handler call when the web page is load in the panel. - * It is useful to detect HTTP error and to perform post - * processing (MathJax). + * Handler to process Mathematical symbols * - * Arguments are those of the Ext.Update.update. - * @param {Ext.Element} el the element being update - * @param {Boolean} success true for success false for failure - * @param {XMLHttpRequest} response + * @param {Ext.ComponentLoader} loader + * @param {Object} response * @param {Object} options + * */ - onLoad: function(el, success, response, options) { + onMathJax: function (loader, response, options) { "use strict"; - var panelWithSelector = this; - - console.log(el); - console.log(success); - console.log(response); - - // errors detection - if (success === false) { - el.updateManager.abort(); - el.update(response.responseText); - } - - // post processing - if (panelWithSelector.isMathJax) { + if (MathJax) { MathJax.Hub.PreProcess(); MathJax.Hub.Process(); } @@ -200,7 +188,6 @@ Ext.define('App.PanelWithUrlSelector', { var fields, i; - fields = this.selectorPanel.query('field'); for (i = 0; i < fields.length; i += 1) { fields[i].reset(); diff --git a/static/plugin_dbui/src/pgridroweditorbase.js b/static/plugin_dbui/src/pgridroweditorbase.js index 4dd5b7893c41c0ca288159f869b503b99e74e064..7abb7228c3acd509a65fff7226c388cb8bce21be 100644 --- a/static/plugin_dbui/src/pgridroweditorbase.js +++ b/static/plugin_dbui/src/pgridroweditorbase.js @@ -9,7 +9,7 @@ */ Ext.define('App.grid.RowEditor', { - extend: 'Ext.Window', + extend: 'Ext.window.Window', alias: 'plugin.pGridRowEditor', // Private short cuts diff --git a/static/plugin_dbui/src/pviewportlogin.js b/static/plugin_dbui/src/pviewportlogin.js index b82f2e2dacac5cab1b6c8239f3ea99781819fda7..93ce861739cc06555ad6e77948b118c70f304ba8 100644 --- a/static/plugin_dbui/src/pviewportlogin.js +++ b/static/plugin_dbui/src/pviewportlogin.js @@ -40,7 +40,7 @@ Ext.define('App.ViewportLogin', { tbar.add('->', '-'); - tbar.addButton({ + tbar.add({ hidden: inhibit_login, href: "admin", handler: this.openURL, @@ -48,7 +48,7 @@ Ext.define('App.ViewportLogin', { tooltip: this.textLogin }); - tbar.addButton({ + tbar.add({ hidden: inhibit_logout, href: "default/user/change_password", handler: this.openURL, @@ -57,10 +57,10 @@ Ext.define('App.ViewportLogin', { }); if (inhibit_login) { - tbar.addSeparator(); + tbar.add('-'); } - tbar.addButton({ + tbar.add({ hidden: inhibit_logout, href: "default/user/logout", handler: this.openURL, diff --git a/static/plugin_dbui/src/viewport.js b/static/plugin_dbui/src/viewport.js index e642ac98ba89f7cc6e30da8812db74c6b052dfc0..10e56abf4eea3d2712606958961cfa895dcd731f 100644 --- a/static/plugin_dbui/src/viewport.js +++ b/static/plugin_dbui/src/viewport.js @@ -20,7 +20,7 @@ Ext.define('App.Viewport', { alias: 'widget.xviewport', /** - * @property {Ext.tree.TreeNode.tex[]} + * @property {Ext.tree.TreeNode.text[]} * The list of node.text attribute defining the path of the node * to be opened at start up. */ @@ -111,7 +111,7 @@ Ext.define('App.Viewport', { this.treePanel.on('itemcontextmenu', this.onItemContextMenu, this); // open the default Tab - //loader.on('load', this.onTreeLoaderLoaded, this); + this.openDefaultTab(); }, // Private method requires by the Ext JS component model @@ -229,50 +229,25 @@ Ext.define('App.Viewport', { }, /** - * Activate the default tab when the tree is loaded - * Expand all the nodes, create the Tab for the leaf, collapse node. + * Open the default tab defined in #defaultTabPath * - * @param {Ext.tree.TreeLoader} treeLoader - * @param {Ext.tree.TreeNode} rootNode - * @param {Object} response */ - onTreeLoaderLoaded: function (treeLoader, rootNode, response) { + openDefaultTab: function () { "use strict"; var i, - leaf, node, - nodes = [], - path = this.defaultTabPath; + path = this.defaultTabPath, + treePanel = this.getComponent('treePanel'); - if (!path) { - return; - } - - // expand all intermediate nodes - node = rootNode; + // get the node of the path + node = treePanel.getStore().getRootNode(); for (i = 0; i < path.length; i += 1) { - node = node.findChild('text', path[i]); - - if (node.isLeaf()) { - leaf = node; - break; - } - - node.expand(); - nodes.push(node); } - // create the tab for the leaf - if (leaf) { - this.onCreate(leaf); - } - - // collapse all intermediate nodes - for (i = 0; i < nodes.length; i += 1) { - nodes[i].collapse(); - } + // create the tab for the last one + this.onItemClick(treePanel.getView(), node); } }); \ No newline at end of file