partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 854420ebd9ff5f450765ab93923a6e2cf8a11b86
parent ffa1cfe3cb01844f2a1f1a3a3f054ddfeba885b8
Author: Felicitus <felicitus@felicitus.org>
Date:   Tue, 10 Jul 2012 03:59:01 +0200

Reworked the RemotePartComboBox, Fixes #189 and #226
Diffstat:
Msrc/frontend/js/Components/Project/ProjectPartGrid.js | 23++++++++++++++++++++---
Msrc/frontend/js/Components/Widgets/RemotePartComboBox.js | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 179 insertions(+), 49 deletions(-)

diff --git a/src/frontend/js/Components/Project/ProjectPartGrid.js b/src/frontend/js/Components/Project/ProjectPartGrid.js @@ -20,13 +20,18 @@ Ext.define('PartKeepr.ProjectPartGrid', { xtype: 'RemotePartComboBox' }, renderer: function (val,p,rec) { - return rec.get("part_name"); + return Ext.util.Format.htmlEncode(rec.get("part_name")); } },{ header: i18n("Remarks"), dataIndex: 'remarks', flex: 1, editor: { - xtype: 'textfield' + xtype: 'textfield', + listeners: { + focus: function () { + console.log("TEXTFIELDFOCUS"); + } + } } }], @@ -36,7 +41,19 @@ Ext.define('PartKeepr.ProjectPartGrid', { initComponent: function () { this.editing = Ext.create('Ext.grid.plugin.CellEditing', { - clicksToEdit: 1 + clicksToEdit: 1, + listeners: { + beforeedit: function (editor, e, eOpts) { + if (e.field == "part_id") { + e.value = e.record.get("part_name"); + var header = this.headerCt.getHeaderAtIndex(e.colIdx); + var edit = this.editing.getEditor(editor.record, header); + + edit.field.setDisplayValue(e.record.get("part_name")); + } + }, + scope: this + } }); this.plugins = [ this.editing ]; diff --git a/src/frontend/js/Components/Widgets/RemotePartComboBox.js b/src/frontend/js/Components/Widgets/RemotePartComboBox.js @@ -1,52 +1,164 @@ /** - * Represents a part chooser which supports type-ahead and remote querying. + * A part picker with an attached grid. */ -Ext.define("PartKeepr.RemotePartComboBox", { - extend : "Ext.form.field.ComboBox", - alias : 'widget.RemotePartComboBox', - - // Fixed configurations for the data - displayField : 'name', - valueField : 'id', - queryMode : 'remote', - triggerAction : 'all', - - // Typing configuration - typeAhead : true, - typeAheadDelay : 100, - minChars : 2, - - // Misc settings - pageSize : 30, - forceSelection : true, - - /** - * Initializes the component. Applies a custom list configuration and an own store, then calls the ComboBox - * superclass. - */ - initComponent : function() { +Ext.define("PartKeepr.RemotePartComboBox",{ + extend:"Ext.form.field.Picker", + alias: 'widget.RemotePartComboBox', + requires:["Ext.grid.Panel"], + selectedValue: null, + + /** + * Initializes the component. + */ + initComponent: function(){ + Ext.apply(this,{ + pickerAlign:"tl-bl?", + editable: false + }); - // Custom list configuration to display additional information about the part - this.listConfig = { - loadingText : i18n('Searching...'), - emptyText : i18n('No matching parts found.'), + /** + * Create the store with the default sorter "name ASC" + */ + this.createStore({ + model: 'PartKeepr.Part', + proxy: PartKeepr.getRESTProxy("Part"), + groupField: 'categoryPath', + sorters: [{ + property: 'name', + direction:'ASC' + }] + }); + + this.callParent(); + this.createPicker(); + + // @todo This is currently buggy due to EXTJSIV-5364. + this.on("focus", function () { this.onTriggerClick();}, this); + }, + // Creates a store. To be called from child's initComponent + createStore: function (config) { + Ext.Object.merge(config, { + autoLoad: true, + autoSync: false, // Do not change. If true, new (empty) records would be immediately commited to the database. + remoteFilter: true, + remoteSort: true, + pageSize: 15}); + + this.store = Ext.create('Ext.data.Store', config); + + // Workaround for bug http://www.sencha.com/forum/showthread.php?133767-Store.sync()-does-not-update-dirty-flag&p=607093#post607093 + this.store.on('write', function(store, operation) { + var success=operation.wasSuccessful(); + if (success) { + Ext.each(operation.records, function(record){ + if (record.dirty) { + record.commit(); + } + }); + } + }); + }, + onTrigger1Click: function () { + this.onTriggerClick(); + }, + createPicker: function(){ + this.partsGrid = Ext.create("PartKeepr.PartsGrid", { + enableTopToolbar: true, + editingEnabled: false, + store: this.store, + region: 'center' + }); + + this.filter = Ext.create("PartKeepr.PartFilterPanel", { + region: 'south', + floatable: false, + titleCollapse: true, + height: 225, + autoScroll: true, + store: this.store, + title: i18n("Part Filter"), + split: true, + collapsed: true, + collapsible: true + }); + + this.picker = Ext.create("Ext.panel.Panel", { + layout: 'border', + floating: true, + focusOnToFront: false, + height:300, + minWidth: 350, + shadow: false, + ownerCt: this.ownerCt, + items: [ this.partsGrid, this.filter ] + }); - itemTpl : Ext.create( 'Ext.XTemplate', - '<div style="margin-bottom: 5px;">', - '<h2>{name}</h2>', - '<p>{categoryPath}</p>', - '<p>{description}</p>', - '<p>{footprintName}</p>', - '</div>') - }; + this.picker.on({ + show: function () { + this.partsGrid.searchField.setValue(this.getDisplayValue()); + this.partsGrid.searchField.startSearch(); + }, + scope: this + }); + + this.partsGrid.on("select", + function (selModel, record) { + this.setSelectedValue(record.get("id")); + this.setDisplayValue(record.get("name")); + this.collapse(); + }, this); + + return self.picker; + }, + getDisplayValue: function () { + return this.displayValue; + }, + setSelectedValue: function (id) { + this.selectedValue = id; + }, + getValue: function () { + return this.selectedValue; + }, + setDisplayValue: function (value) { + this.setRawValue(value); + this.displayValue = value; + }, + setValue: function () { + + }, + _selectRecords: function (r) { + this.picker.getView().select(r); + this.picker.getView().ensureVisible(r); + this.picker.getView().scrollIntoView(r); + }, + alignPicker: function() { + // override the original method because otherwise the height of the treepanel would be always 0 + var me = this, + picker, isAbove, + aboveSfx = '-above'; - // Create a separate store used for querying parts - this.store = Ext.create("Ext.data.Store", { - model : 'PartKeepr.Part', - proxy : PartKeepr.getRESTProxy("Part"), - autoLoad : true - }); + if (this.isExpanded) { + picker = me.getPicker(); + if (me.matchFieldWidth) { + // Auto the height (it will be constrained by min and max width) unless there are no records to display. + picker.setWidth( me.bodyEl.getWidth()); + } + if (picker.isFloating()) { + picker.alignTo(me.inputEl, me.pickerAlign, me.pickerOffset); - this.callParent(); - } -}); + // add the {openCls}-above class if the picker was aligned above + // the field due to hitting the bottom of the viewport + isAbove = picker.el.getY() < me.inputEl.getY(); + me.bodyEl[isAbove ? 'addCls' : 'removeCls'](me.openCls + aboveSfx); + picker.el[isAbove ? 'addCls' : 'removeCls'](picker.baseCls + aboveSfx); + } + } + }, + getErrors: function(value) { + if (this.getValue() === null) { + return [ i18n("You need to select a category")]; + } + + return []; + } +});+ \ No newline at end of file