commit 72e5314e0facd30825ae68027ddc51af9172f97e
parent 39f42ea620781a97d5e85eb933253053bcdd32dc
Author: Felicitus <felicitus@felicitus.org>
Date: Sat, 14 Nov 2015 19:31:11 +0100
Validate storage location, fixes #463
Diffstat:
3 files changed, 154 insertions(+), 26 deletions(-)
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Editor/EditorGrid.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Editor/EditorGrid.js
@@ -182,6 +182,7 @@ Ext.define('PartKeepr.EditorGrid', {
this.getSelectionModel().on("select", this._onItemSelect, this);
this.getSelectionModel().on("deselect", this._onItemDeselect, this);
+ this.getView().on("itemkeydown", this._onItemKeyPress, this);
if (this.automaticPageSize) {
this.on("resize", this.reassignPageSize, this);
@@ -245,7 +246,11 @@ Ext.define('PartKeepr.EditorGrid', {
this.deleteButton.disable();
}
},
-
+ _onItemKeyPress: function (view, record, item, index, e) {
+ if (e.getKey() == e.ENTER || e.getKey() == e.TAB) {
+ this._onItemEdit(view, record);
+ }
+ },
/**
* Called when an item should be edited
*/
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/StorageLocation/StorageLocationNavigation.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/StorageLocation/StorageLocationNavigation.js
@@ -55,7 +55,7 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
this.callParent(arguments);
- this.down("partkeepr\\.StorageLocationTree").on("itemclick", this.onCategoryClick, this);
+ this.getTree().on("itemclick", this.onCategoryClick, this);
this.getGrid().setStore(this.store);
this.getGrid().on("storageLocationMultiAdd", this.onMultiAddStorageLocation,
@@ -75,6 +75,9 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
getGrid: function () {
return this.down("partkeepr\\.StorageLocationGrid");
},
+ getTree: function () {
+ return this.down("partkeepr\\.StorageLocationTree");
+ },
setSearchValue: function (val) {
var searchField = this.getGrid().searchField;
searchField.setValue(val);
@@ -88,6 +91,9 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
*/
onCategoryClick: function (tree, record)
{
+ this.setCategoryFilter(record);
+ },
+ setCategoryFilter: function (record) {
var filter = Ext.create("Ext.util.Filter", {
property: 'category',
operator: 'IN',
@@ -95,6 +101,7 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
});
this.store.addFilter(filter);
+
},
/**
* Returns the ID for this node and all child nodes
@@ -119,11 +126,11 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
*/
onAddStorageLocation: function ()
{
- var selection = this.down("partkeepr\\.StorageLocationTree").getSelection();
+ var selection = this.getTree().getSelection();
var category;
if (selection.length === 0) {
- category = this.down("partkeepr\\.StorageLocationTree").getRootNode().firstChild.getId();
+ category = this.getTree().getRootNode().firstChild.getId();
} else {
var item = selection.shift();
category = item.getId();
@@ -137,11 +144,11 @@ Ext.define("PartKeepr.StorageLocationNavigation", {
*/
onMultiAddStorageLocation: function ()
{
- var selection = this.down("partkeepr\\.StorageLocationTree").getSelection();
+ var selection = this.getTree().getSelection();
var category;
if (selection.length === 0) {
- category = this.down("partkeepr\\.StorageLocationTree").getRootNode().firstChild.getId();
+ category = this.getTree().getRootNode().firstChild.getId();
} else {
var item = selection.shift();
category = item.getId();
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/StorageLocationPicker.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/StorageLocationPicker.js
@@ -20,6 +20,17 @@ Ext.define("PartKeepr.StorageLocationPicker", {
*/
selectedStorageLocation: null,
+ textValue: "",
+
+ enableKeyEvents: true,
+
+ listeners: {
+ 'specialkey': {
+ fn: 'keyHandler',
+ scope: 'this'
+ }
+ },
+
initComponent: function ()
{
this.store = Ext.create("Ext.data.Store", {
@@ -31,54 +42,158 @@ Ext.define("PartKeepr.StorageLocationPicker", {
{
property: 'category.categoryPath',
direction: 'ASC'
- },{
+ }, {
property: 'name',
- direction:'ASC'
+ direction: 'ASC'
}
- ],
+ ],
groupField: 'categoryPath'
});
- this.on("change", Ext.bind(this.onFieldChange, this));
+ this.on("keyup", Ext.bind(this.onFieldChange, this));
this.on("blur", Ext.bind(this.onBlur, this));
this.callParent();
},
- onFieldChange: function (f, newValue) {
- if (this.selectedStorageLocation instanceof PartKeepr.StorageLocationBundle.Entity.StorageLocation) {
- if (this.selectedStorageLocation.get("name") === newValue) {
- return;
- }
- }
+ onFieldChange: function (field, e)
+ {
+ var newValue = this.inputEl.getValue();
+
if (!this.typeAheadTask) {
this.typeAheadTask = new Ext.util.DelayedTask(this.onTypeAhead, this, [newValue]);
}
this.typeAheadTask.delay(this.typeAheadDelay, false, false, [newValue]);
},
- getValue: function () {
+ /**
+ * Handles special keys used in this field.
+ *
+ * Enter: Starts the search
+ * Escape: Removes the search and clears the field contents
+ */
+ keyHandler: function (field, e)
+ {
+ var picker = this.getPicker();
+ var grid = picker.getGrid();
+
+ switch (e.getKey()) {
+ case e.DOWN:
+ var currentSelection = grid.getSelectionModel().getSelection();
+
+ if (currentSelection.length === 0) {
+ grid.getSelectionModel().select(0);
+ } else {
+ var index = grid.getStore().indexOf(currentSelection[0]) + 1;
+
+ if (index < grid.getStore().count()) {
+ grid.getSelectionModel().select(index);
+ grid.getView().focusRow(grid.getStore().getAt(index));
+ }
+ }
+ break;
+ case e.UP:
+ var currentSelection = grid.getSelectionModel().getSelection();
+
+ if (currentSelection.length === 0) {
+ grid.getSelectionModel().select(grid.getStore().count());
+ } else {
+ var index = grid.getStore().indexOf(currentSelection[0]) - 1;
+
+ if (index >= 0) {
+ grid.getSelectionModel().select(index);
+ grid.getView().focusRow(grid.getStore().getAt(index));
+ }
+ }
+ break;
+ case e.ENTER:
+ if (!this.isExpanded) {
+ this.expand();
+ return;
+ } else {
+ this.applyGridSelection(grid);
+ }
+ break;
+ case e.TAB:
+ this.applyGridSelection(grid);
+ break;
+ }
+ },
+ applyGridSelection: function (grid)
+ {
+ var currentSelection = grid.getSelectionModel().getSelection();
+
+ if (currentSelection.length === 1) {
+ this.setValue(currentSelection[0]);
+ }
+
+ this.collapse();
+
+ },
+ getValue: function ()
+ {
return this.selectedStorageLocation;
},
- onTypeAhead: function (newValue) {
- var picker = this.getPicker(newValue);
- picker.setSearchValue(newValue);
- this.expand();
+ onTypeAhead: function (newValue)
+ {
+ if (newValue !== this.textValue) {
+ var picker = this.getPicker();
+ picker.setCategoryFilter(picker.getTree().getRootNode().firstChild);
+ picker.getTree().getSelectionModel().select(picker.getTree().getRootNode().firstChild);
+ picker.setSearchValue(newValue);
+ picker.getGrid().getSelectionModel().deselectAll();
+ this.expand();
+ this.textValue = newValue;
+ }
},
- onBlur: function () {
+ onBlur: function ()
+ {
var picker = this.getPicker();
if (picker.getGrid().getStore().count() === 1) {
this.setValue(picker.getGrid().getStore().getAt(0));
}
+
+ this.validate();
},
- setValue: function (value) {
+ setValue: function (value)
+ {
this.selectedStorageLocation = value;
+ this.textValue = value.get("name");
PartKeepr.StorageLocationPicker.superclass.setValue.call(this, value.get("name"));
+ this.validate();
+ },
+ getErrors: function (value) {
+ var errors = this.callParent(arguments);
+
+ if (!this.inputEl) {
+ return errors;
+ }
+
+ if (!(this.selectedStorageLocation instanceof PartKeepr.StorageLocationBundle.Entity.StorageLocation) ||
+ this.inputEl.getValue() !== this.selectedStorageLocation.get("name")) {
+ errors.push(i18n("An existing storage location must be selected"));
+ }
+
+ return errors;
+
},
- /**
+ asdisValid: function () {
+ if (!this.inputEl) {
+ return false;
+ }
+
+ if (this.selectedStorageLocation instanceof PartKeepr.StorageLocationBundle.Entity.StorageLocation &&
+ this.inputEl.getValue() === this.selectedStorageLocation.get("name")) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+ /**
* Creates and returns the tree panel to be used as this field's picker.
*/
- createPicker: function() {
+ createPicker: function ()
+ {
var me = this,
picker = new PartKeepr.StorageLocationNavigation({
store: me.store,
@@ -94,7 +209,8 @@ Ext.define("PartKeepr.StorageLocationPicker", {
itemEditActions: false,
editItemAsObject: true,
listeners: {
- itemEdit: function (v) {
+ itemEdit: function (v)
+ {
this.setValue(v);
this.collapse();
},