commit 8b764b7a5d96d7f411e89e9b72cffe5bde442080
parent 483212434c8bda26f1f2b1ccfaa09346c1312878
Author: Felicitus <felicitus@felicitus.org>
Date: Sun, 30 Aug 2015 15:47:19 +0200
Externalized part category store, re-added category combobox, reverted to classic theme for easier migration
Diffstat:
5 files changed, 531 insertions(+), 628 deletions(-)
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Part/Editor/PartEditor.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Part/Editor/PartEditor.js
@@ -4,452 +4,470 @@
* <p>The PartEditor provides an editing form for a part. It contains multiple tabs, one for each nested record.</p>
*/
Ext.define('PartKeepr.PartEditor', {
- extend: 'PartKeepr.Editor',
-
- // Assigned model
- model: 'PartKeepr.PartBundle.Entity.Part',
-
- // Layout stuff
- border: false,
- layout: 'fit',
- bodyStyle: 'background:#DBDBDB;',
-
- /**
- * Initializes the editor fields
- */
- initComponent: function () {
- // Defines the overall height of all fields, used to calculate the anchoring for the description field
- var overallHeight = (this.partMode == "create") ? '-280' : '-235';
-
- this.nameField = Ext.create("Ext.form.field.Text", {
- name: 'name',
- fieldLabel: i18n("Name"),
- allowBlank: false,
- labelWidth: 150
- });
-
- this.storageLocationComboBox = Ext.create("PartKeepr.StorageLocationComboBox",
- {
- fieldLabel: i18n("Storage Location"),
- name: 'storageLocation',
- allowBlank: false,
- labelWidth: 150
- });
-
- this.storageLocationComboBox.store.on("load", function () {
- // Re-trigger validation because of asynchronous loading of the storage location field,
- // which would be marked invalid because validation happens immediately, but after loading
- // the storage locations, the field is valid, but not re-validated.
-
- // This workaround is done twice; once after the store is loaded and once when we start editing,
- // because we don't know which event will come first
- this.getForm().isValid();
- }, this);
-
- this.footprintNone = Ext.create("Ext.form.field.Radio", {
- boxLabel: i18n("None"),
- name: 'footprint_mode',
- margin: {
- right: 5
- },
- value: "unset",
- listeners: {
- scope: this,
- change: function (field, newValue) {
- if (newValue === true) {
- this.footprintComboBox.clearValue();
- }
- }
- }
- });
-
- this.footprintSet = Ext.create("Ext.form.field.Radio", {
- name: 'footprint_mode',
- margin: {
- right: 5
- },
- value: "set"
- });
-
- /*
- * Creates the footprint combo box. We listen for the "change" event, because we need to set the footprint
- * comboboxes to the right state, depending on the selection. Another way would be to patch the combobox
- * to support "null" values, however, this is a major change within ExtJS and probably not supported for
- * updates of ExtJS.
- */
- this.footprintComboBox = Ext.create("PartKeepr.FootprintComboBox", {
- name: 'footprint',
- flex: 1,
- listeners: {
- scope: this,
- change: function (field, newValue) {
- if (newValue !== 0) {
- this.footprintSet.setValue(true);
- }
- }
- }
- });
-
- // Defines the basic editor fields
- var basicEditorFields = [
- this.nameField,
- {
- xtype: 'textfield',
- fieldLabel: i18n("Description"),
- name: 'description'
- },{
- layout: 'column',
- bodyStyle: 'background:#DBDBDB',
- border: false,
- items: [{
- xtype: 'numberfield',
- fieldLabel: i18n('Minimum Stock'),
- allowDecimals: false,
- allowBlank: false,
- labelWidth: 150,
- name: 'minStockLevel',
- value: 0,
- columnWidth: 0.5,
- minValue: 0
- },{
- xtype: 'PartUnitComboBox',
- fieldLabel: i18n("Part Unit"),
- columnWidth: 0.5,
- margin: "0 0 0 5",
- name: 'partUnit',
- value: PartKeepr.getApplication().getDefaultPartUnit().get("id")
- }]
- },{
- xtype: 'CategoryComboBox',
- fieldLabel: i18n("Category"),
- name: 'category'
- },
- this.storageLocationComboBox,
- {
- xtype: 'fieldcontainer',
- layout: 'hbox',
- fieldLabel: i18n("Footprint"),
- defaults: {
- hideLabel: true
- },
- items: [
- this.footprintNone,
- this.footprintSet,
- this.footprintComboBox
- ]
- },{
- xtype: 'textarea',
- fieldLabel: i18n("Comment"),
- name: 'comment',
- anchor: '100% ' + overallHeight
- },
- {
- xtype: 'fieldcontainer',
- layout: 'hbox',
- fieldLabel: i18n("Status"),
- defaults: {
- hideLabel: true
- },
- items: [{
- xtype: 'textfield',
- fieldLabel: i18n("Status"),
- flex: 1,
- name: 'status'
- },{
- xtype: 'checkbox',
- hideEmptyLabel: false,
- fieldLabel: '',
- margins: {
- left: 5
- },
- boxLabel: i18n("Needs Review"),
- name: 'needsReview'
- }]
- },{
- xtype: 'textfield',
- fieldLabel: i18n("Condition"),
- name: 'partCondition'
- },{
+ extend: 'PartKeepr.Editor',
+
+ // Assigned model
+ model: 'PartKeepr.PartBundle.Entity.Part',
+
+ // Layout stuff
+ border: false,
+ layout: 'fit',
+ bodyStyle: 'background:#DBDBDB;',
+
+ /**
+ * Initializes the editor fields
+ */
+ initComponent: function ()
+ {
+ // Defines the overall height of all fields, used to calculate the anchoring for the description field
+ var overallHeight = (this.partMode == "create") ? '-280' : '-235';
+
+ this.nameField = Ext.create("Ext.form.field.Text", {
+ name: 'name',
+ fieldLabel: i18n("Name"),
+ allowBlank: false,
+ labelWidth: 150
+ });
+
+ this.storageLocationComboBox = Ext.create("PartKeepr.StorageLocationComboBox",
+ {
+ fieldLabel: i18n("Storage Location"),
+ name: 'storageLocation',
+ allowBlank: false,
+ labelWidth: 150
+ });
+
+ this.storageLocationComboBox.store.on("load", function ()
+ {
+ // Re-trigger validation because of asynchronous loading of the storage location field,
+ // which would be marked invalid because validation happens immediately, but after loading
+ // the storage locations, the field is valid, but not re-validated.
+
+ // This workaround is done twice; once after the store is loaded and once when we start editing,
+ // because we don't know which event will come first
+ this.getForm().isValid();
+ }, this);
+
+ this.footprintNone = Ext.create("Ext.form.field.Radio", {
+ boxLabel: i18n("None"),
+ name: 'footprint_mode',
+ margin: {
+ right: 5
+ },
+ value: "unset",
+ listeners: {
+ scope: this,
+ change: function (field, newValue)
+ {
+ if (newValue === true) {
+ this.footprintComboBox.clearValue();
+ }
+ }
+ }
+ });
+
+ this.footprintSet = Ext.create("Ext.form.field.Radio", {
+ name: 'footprint_mode',
+ margin: {
+ right: 5
+ },
+ value: "set"
+ });
+
+ /*
+ * Creates the footprint combo box. We listen for the "change" event, because we need to set the footprint
+ * comboboxes to the right state, depending on the selection. Another way would be to patch the combobox
+ * to support "null" values, however, this is a major change within ExtJS and probably not supported for
+ * updates of ExtJS.
+ */
+ this.footprintComboBox = Ext.create("PartKeepr.FootprintComboBox", {
+ name: 'footprint',
+ flex: 1,
+ listeners: {
+ scope: this,
+ change: function (field, newValue)
+ {
+ if (newValue !== 0) {
+ this.footprintSet.setValue(true);
+ }
+ }
+ }
+ });
+
+ // Defines the basic editor fields
+ var basicEditorFields = [
+ this.nameField,
+ {
+ xtype: 'textfield',
+ fieldLabel: i18n("Description"),
+ name: 'description'
+ }, {
+ layout: 'column',
+ bodyStyle: 'background:#DBDBDB',
+ border: false,
+ items: [
+ {
+ xtype: 'numberfield',
+ fieldLabel: i18n('Minimum Stock'),
+ allowDecimals: false,
+ allowBlank: false,
+ labelWidth: 150,
+ name: 'minStockLevel',
+ value: 0,
+ columnWidth: 0.5,
+ minValue: 0
+ }, {
+ xtype: 'PartUnitComboBox',
+ fieldLabel: i18n("Part Unit"),
+ columnWidth: 0.5,
+ margin: "0 0 0 5",
+ name: 'partUnit',
+ value: PartKeepr.getApplication().getDefaultPartUnit().get("id")
+ }
+ ]
+ }, {
+ xtype: 'CategoryComboBox',
+ fieldLabel: i18n("Category"),
+ name: 'category',
+ displayField: "name",
+ store: Ext.create("PartKeepr.data.store.PartCategoryStore"),
+ rootVisible: false
+ },
+ this.storageLocationComboBox,
+ {
+ xtype: 'fieldcontainer',
+ layout: 'hbox',
+ fieldLabel: i18n("Footprint"),
+ defaults: {
+ hideLabel: true
+ },
+ items: [
+ this.footprintNone,
+ this.footprintSet,
+ this.footprintComboBox
+ ]
+ }, {
+ xtype: 'textarea',
+ fieldLabel: i18n("Comment"),
+ name: 'comment',
+ anchor: '100% ' + overallHeight
+ },
+ {
+ xtype: 'fieldcontainer',
+ layout: 'hbox',
+ fieldLabel: i18n("Status"),
+ defaults: {
+ hideLabel: true
+ },
+ items: [
+ {
+ xtype: 'textfield',
+ fieldLabel: i18n("Status"),
+ flex: 1,
+ name: 'status'
+ }, {
+ xtype: 'checkbox',
+ hideEmptyLabel: false,
+ fieldLabel: '',
+ margins: {
+ left: 5
+ },
+ boxLabel: i18n("Needs Review"),
+ name: 'needsReview'
+ }
+ ]
+ }, {
+ xtype: 'textfield',
+ fieldLabel: i18n("Condition"),
+ name: 'partCondition'
+ }, {
xtype: 'fieldcontainer',
layout: 'hbox',
- items : [{
- xtype: 'textfield',
- labelWidth: 150,
- fieldLabel: i18n("Internal Part Number"),
- name: 'internalPartNumber',
- flex: 1
- },{
- xtype: 'displayfield',
- margins: {
- left: 5
+ items: [
+ {
+ xtype: 'textfield',
+ labelWidth: 150,
+ fieldLabel: i18n("Internal Part Number"),
+ name: 'internalPartNumber',
+ flex: 1
+ }, {
+ xtype: 'displayfield',
+ margins: {
+ left: 5
+ },
+ fieldLabel: i18n("Internal ID"),
+ name: 'id'
+ }
+ ]
+
+ }
+ ];
+
+ // Creates the distributor grid
+ this.partDistributorGrid = Ext.create("PartKeepr.PartDistributorGrid", {
+ title: i18n("Distributors"),
+ iconCls: 'icon-lorry',
+ layout: 'fit'
+ });
+
+ // Creates the manufacturer grid
+ this.partManufacturerGrid = Ext.create("PartKeepr.PartManufacturerGrid", {
+ title: i18n("Manufacturers"),
+ iconCls: 'icon-building',
+ layout: 'fit'
+ });
+
+ // Creates the parameter grid
+ this.partParameterGrid = Ext.create("PartKeepr.PartParameterGrid", {
+ title: i18n("Parameters"),
+ iconCls: 'icon-table',
+ layout: 'fit'
+ });
+
+ // Creates the attachment grid
+ this.partAttachmentGrid = Ext.create("PartKeepr.PartAttachmentGrid", {
+ title: i18n("Attachments"),
+ iconCls: 'icon-attach',
+ layout: 'fit'
+ });
+
+ // Adds stock level fields for new items
+ if (this.partMode && this.partMode == "create") {
+ this.initialStockLevel = Ext.create("Ext.form.field.Number", {
+ fieldLabel: i18n("Initial Stock Level"),
+ name: "initialStockLevel",
+ labelWidth: 150,
+ columnWidth: 0.5
+ });
+
+ this.initialStockLevelUser = Ext.create("PartKeepr.UserComboBox", {
+ fieldLabel: i18n("Stock User"),
+ name: 'initialStockLevelUser',
+ columnWidth: 0.5,
+ margin: "0 0 0 5"
+ });
+
+ basicEditorFields.push({
+ layout: 'column',
+ bodyStyle: 'background:#DBDBDB',
+ border: false,
+ items: [
+ this.initialStockLevel,
+ this.initialStockLevelUser
+ ]
+ });
+
+ this.initialStockLevelPrice = Ext.create("PartKeepr.CurrencyField", {
+ fieldLabel: i18n('Price'),
+ labelWidth: 150,
+ columnWidth: 0.5,
+ name: 'initialStockLevelPrice'
+ });
+
+ this.initialStockLevelPricePerItem = Ext.create("Ext.form.field.Checkbox", {
+ boxLabel: i18n("Per Item"),
+ columnWidth: 0.5,
+ margin: "0 0 0 5",
+ name: 'initialStockLevelPricePerItem'
+ });
+
+ basicEditorFields.push({
+ layout: 'column',
+ bodyStyle: 'background:#DBDBDB',
+ border: false,
+ items: [
+ this.initialStockLevelPrice,
+ this.initialStockLevelPricePerItem
+ ]
+ });
+
+
+ }
+
+ // Create a tab panel of all fields
+ this.items = {
+ xtype: 'tabpanel',
+ border: false,
+ plain: true,
+ items: [
+ {
+ iconCls: 'icon-brick',
+ xtype: 'panel',
+ border: false,
+ autoScroll: false,
+ layout: 'anchor',
+ defaults: {
+ anchor: '100%',
+ labelWidth: 150
},
- fieldLabel: i18n("Internal ID"),
- name: 'id'
- }]
-
- }];
-
- // Creates the distributor grid
- this.partDistributorGrid = Ext.create("PartKeepr.PartDistributorGrid", {
- title: i18n("Distributors"),
- iconCls: 'icon-lorry',
- layout: 'fit'
- });
-
- // Creates the manufacturer grid
- this.partManufacturerGrid = Ext.create("PartKeepr.PartManufacturerGrid", {
- title: i18n("Manufacturers"),
- iconCls: 'icon-building',
- layout: 'fit'
- });
-
- // Creates the parameter grid
- this.partParameterGrid = Ext.create("PartKeepr.PartParameterGrid", {
- title: i18n("Parameters"),
- iconCls: 'icon-table',
- layout: 'fit'
- });
-
- // Creates the attachment grid
- this.partAttachmentGrid = Ext.create("PartKeepr.PartAttachmentGrid", {
- title: i18n("Attachments"),
- iconCls: 'icon-attach',
- layout: 'fit'
- });
-
- // Adds stock level fields for new items
- if (this.partMode && this.partMode == "create") {
- this.initialStockLevel = Ext.create("Ext.form.field.Number", {
- fieldLabel: i18n("Initial Stock Level"),
- name: "initialStockLevel",
- labelWidth: 150,
- columnWidth: 0.5
- });
-
- this.initialStockLevelUser = Ext.create("PartKeepr.UserComboBox", {
- fieldLabel: i18n("Stock User"),
- name: 'initialStockLevelUser',
- columnWidth: 0.5,
- margin: "0 0 0 5"
- });
-
- basicEditorFields.push({
- layout: 'column',
- bodyStyle: 'background:#DBDBDB',
- border: false,
- items: [
- this.initialStockLevel,
- this.initialStockLevelUser
- ]
- });
-
- this.initialStockLevelPrice = Ext.create("PartKeepr.CurrencyField", {
- fieldLabel: i18n('Price'),
- labelWidth: 150,
- columnWidth: 0.5,
- name: 'initialStockLevelPrice'
- });
-
- this.initialStockLevelPricePerItem = Ext.create("Ext.form.field.Checkbox", {
- boxLabel: i18n("Per Item"),
- columnWidth: 0.5,
- margin: "0 0 0 5",
- name: 'initialStockLevelPricePerItem'
- });
-
- basicEditorFields.push({
- layout: 'column',
- bodyStyle: 'background:#DBDBDB',
- border: false,
- items: [
- this.initialStockLevelPrice,
- this.initialStockLevelPricePerItem
- ]
- });
-
-
- }
-
- // Create a tab panel of all fields
- this.items = {
- xtype: 'tabpanel',
- border: false,
- plain: true,
- items: [{
- iconCls: 'icon-brick',
- xtype: 'panel',
- border: false,
- autoScroll: false,
- layout: 'anchor',
- defaults: {
- anchor: '100%',
- labelWidth: 150
- },
- bodyStyle: 'background:#DBDBDB;padding: 10px;',
- title: i18n("Basic Data"),
- items: basicEditorFields
- },
- this.partDistributorGrid,
- this.partManufacturerGrid,
- this.partParameterGrid,
- this.partAttachmentGrid
- ]
- };
-
- this.on("startEdit", this.onEditStart, this, { delay: 200 });
- this.on("itemSaved", this._onItemSaved, this);
-
- this.callParent();
-
- this.on("itemSave", this.onItemSave, this);
-
- },
- /**
- * Cleans up the record prior saving.
- */
- onItemSave: function () {
- var removeRecords = [], j;
-
- /**
- * Iterate through all records and check if a valid distributor
- * ID is assigned. If not, the record is removed as it is assumed
- * that the record is invalid and being removed.
- */
- for (j=0;j<this.record.distributors().getCount();j++) {
- if (this.record.distributors().getAt(j).get("distributor_id") === 0) {
- removeRecords.push(this.record.distributors().getAt(j));
- }
- }
-
- if (removeRecords.length > 0) {
- this.record.distributors().remove(removeRecords);
- }
-
- removeRecords = [];
-
- /**
- * Iterate through all records and check if a valid parameter
- * ID is assigned. If not, the record is removed as it is assumed
- * that the record is invalid and being removed.
- */
-
- for (j=0;j<this.record.parameters().getCount();j++) {
- if (this.record.parameters().getAt(j).get("unit_id") === 0) {
- removeRecords.push(this.record.parameters().getAt(j));
- }
- }
-
- if (removeRecords.length > 0) {
- this.record.parameters().remove(removeRecords);
- }
-
- removeRecords = [];
-
- /**
- * Iterate through all records and check if a valid manufacturer
- * ID is assigned. If not, the record is removed as it is assumed
- * that the record is invalid and being removed.
- */
-
- for (j=0;j<this.record.manufacturers().getCount();j++) {
- if (this.record.manufacturers().getAt(j).get("manufacturer_id") === 0) {
- removeRecords.push(this.record.manufacturers().getAt(j));
- }
- }
-
- if (removeRecords.length > 0) {
- this.record.manufacturers().remove(removeRecords);
- }
-
- /**
- * Check if the storage location is valid. If not, try an exact, case-insensitive match for the
- * storage location name and inject that into the record.
- */
- if (isNaN(this.record.get("storageLocation"))) {
- var storageLocationRecord = this.storageLocationComboBox.getStore().findRecord(
- "name",
- this.storageLocationComboBox.getValue(),
- 0, false, false, true) ;
-
- this.record.set("storageLocation", storageLocationRecord.get("id"));
- }
-
- // Force footprint to be "null" when the checkbox is checked.
- if (this.footprintNone.getValue() === true) {
- this.record.set("footprint", 0);
- }
-
- },
- onEditStart: function () {
- this.bindChildStores();
- this.nameField.focus();
-
- // Re-trigger validation because of asynchronous loading of the storage location field,
- // which would be marked invalid because validation happens immediately, but after loading
- // the storage locations, the field is valid, but not re-validated.
-
- // This workaround is done twice; once after the store is loaded and once when we start editing,
- // because we don't know which event will come first
- this.getForm().isValid();
-
- if (this.record.get("footprint") === 0) {
- this.footprintNone.setValue(true);
- } else {
- this.footprintSet.setValue(true);
- }
- },
- _onItemSaved: function () {
- this.fireEvent("partSaved", this.record);
-
- if (this.keepOpenCheckbox.getValue() !== true && this.createCopyCheckbox.getValue() !== true) {
- this.fireEvent("editorClose", this);
- } else {
- var newItem;
- if (this.partMode == "create") {
- if (this.copyPartDataCheckbox.getValue() === true) {
- data = this.record.getData(true);
- data.id = null;
- newItem = Ext.create("PartKeepr.PartBundle.Entity.Part");
- newItem.setDataWithAssociations(data);
-
- this.editItem(newItem);
- } else {
- newItem = Ext.create("PartKeepr.PartBundle.Entity.Part", this.partDefaults);
- this.editItem(newItem);
- }
- } else {
- var data = this.record.getData(true);
- data.id = null;
- newItem = Ext.create("PartKeepr.PartBundle.Entity.Part");
- newItem.setDataWithAssociations(data);
-
- this.editItem(newItem);
- }
-
-
-
-
- }
- },
- bindChildStores: function () {
- this.partDistributorGrid.bindStore(this.record.distributors());
- this.partManufacturerGrid.bindStore(this.record.manufacturers());
- this.partParameterGrid.bindStore(this.record.parameters());
- this.partAttachmentGrid.bindStore(this.record.attachments());
- },
- setTitle: function (title) {
- var tmpTitle;
-
- if (this.record.phantom) {
- tmpTitle = i18n("Add Part");
- } else {
- tmpTitle = i18n("Edit Part");
- }
-
- if (title !== "") {
- tmpTitle = tmpTitle + ": " + title;
- }
-
- this.fireEvent("_titleChange", tmpTitle);
- }
+ bodyStyle: 'background:#DBDBDB;padding: 10px;',
+ title: i18n("Basic Data"),
+ items: basicEditorFields
+ },
+ this.partDistributorGrid,
+ this.partManufacturerGrid,
+ this.partParameterGrid,
+ this.partAttachmentGrid
+ ]
+ };
+
+ this.on("startEdit", this.onEditStart, this, {delay: 200});
+ this.on("itemSaved", this._onItemSaved, this);
+
+ this.callParent();
+
+ this.on("itemSave", this.onItemSave, this);
+
+ },
+ /**
+ * Cleans up the record prior saving.
+ */
+ onItemSave: function ()
+ {
+ var removeRecords = [], j;
+
+ /**
+ * Iterate through all records and check if a valid distributor
+ * ID is assigned. If not, the record is removed as it is assumed
+ * that the record is invalid and being removed.
+ */
+ for (j = 0; j < this.record.distributors().getCount(); j++) {
+ if (this.record.distributors().getAt(j).get("distributor_id") === 0) {
+ removeRecords.push(this.record.distributors().getAt(j));
+ }
+ }
+
+ if (removeRecords.length > 0) {
+ this.record.distributors().remove(removeRecords);
+ }
+
+ removeRecords = [];
+
+ /**
+ * Iterate through all records and check if a valid parameter
+ * ID is assigned. If not, the record is removed as it is assumed
+ * that the record is invalid and being removed.
+ */
+
+ for (j = 0; j < this.record.parameters().getCount(); j++) {
+ if (this.record.parameters().getAt(j).get("unit_id") === 0) {
+ removeRecords.push(this.record.parameters().getAt(j));
+ }
+ }
+
+ if (removeRecords.length > 0) {
+ this.record.parameters().remove(removeRecords);
+ }
+
+ removeRecords = [];
+
+ /**
+ * Iterate through all records and check if a valid manufacturer
+ * ID is assigned. If not, the record is removed as it is assumed
+ * that the record is invalid and being removed.
+ */
+
+ for (j = 0; j < this.record.manufacturers().getCount(); j++) {
+ if (this.record.manufacturers().getAt(j).get("manufacturer_id") === 0) {
+ removeRecords.push(this.record.manufacturers().getAt(j));
+ }
+ }
+
+ if (removeRecords.length > 0) {
+ this.record.manufacturers().remove(removeRecords);
+ }
+
+ /**
+ * Check if the storage location is valid. If not, try an exact, case-insensitive match for the
+ * storage location name and inject that into the record.
+ */
+ if (isNaN(this.record.get("storageLocation"))) {
+ var storageLocationRecord = this.storageLocationComboBox.getStore().findRecord(
+ "name",
+ this.storageLocationComboBox.getValue(),
+ 0, false, false, true);
+
+ this.record.set("storageLocation", storageLocationRecord.get("id"));
+ }
+
+ // Force footprint to be "null" when the checkbox is checked.
+ if (this.footprintNone.getValue() === true) {
+ this.record.set("footprint", 0);
+ }
+
+ },
+ onEditStart: function ()
+ {
+ this.bindChildStores();
+ this.nameField.focus();
+
+ // Re-trigger validation because of asynchronous loading of the storage location field,
+ // which would be marked invalid because validation happens immediately, but after loading
+ // the storage locations, the field is valid, but not re-validated.
+
+ // This workaround is done twice; once after the store is loaded and once when we start editing,
+ // because we don't know which event will come first
+ this.getForm().isValid();
+
+ if (this.record.get("footprint") === 0) {
+ this.footprintNone.setValue(true);
+ } else {
+ this.footprintSet.setValue(true);
+ }
+ },
+ _onItemSaved: function ()
+ {
+ this.fireEvent("partSaved", this.record);
+
+ if (this.keepOpenCheckbox.getValue() !== true && this.createCopyCheckbox.getValue() !== true) {
+ this.fireEvent("editorClose", this);
+ } else {
+ var newItem;
+ if (this.partMode == "create") {
+ if (this.copyPartDataCheckbox.getValue() === true) {
+ data = this.record.getData(true);
+ data.id = null;
+ newItem = Ext.create("PartKeepr.PartBundle.Entity.Part");
+ newItem.setDataWithAssociations(data);
+
+ this.editItem(newItem);
+ } else {
+ newItem = Ext.create("PartKeepr.PartBundle.Entity.Part", this.partDefaults);
+ this.editItem(newItem);
+ }
+ } else {
+ var data = this.record.getData(true);
+ data.id = null;
+ newItem = Ext.create("PartKeepr.PartBundle.Entity.Part");
+ newItem.setDataWithAssociations(data);
+
+ this.editItem(newItem);
+ }
+
+
+ }
+ },
+ bindChildStores: function ()
+ {
+ this.partDistributorGrid.bindStore(this.record.distributors());
+ this.partManufacturerGrid.bindStore(this.record.manufacturers());
+ this.partParameterGrid.bindStore(this.record.parameters());
+ this.partAttachmentGrid.bindStore(this.record.attachments());
+ },
+ setTitle: function (title)
+ {
+ var tmpTitle;
+
+ if (this.record.phantom) {
+ tmpTitle = i18n("Add Part");
+ } else {
+ tmpTitle = i18n("Edit Part");
+ }
+
+ if (title !== "") {
+ tmpTitle = tmpTitle + ": " + title;
+ }
+
+ this.fireEvent("_titleChange", tmpTitle);
+ }
});
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Part/PartCategoryTree.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Part/PartCategoryTree.js
@@ -8,33 +8,7 @@ Ext.define("PartKeepr.PartCategoryTree", {
initComponent: function ()
{
- this.store = Ext.create("Ext.data.TreeStore",
- {
- remoteSort: false,
- folderSort: true,
- rootVisible: true,
- autoLoad: true,
- sorters: [
- {
- property: 'name',
- direction: 'ASC'
- }
- ],
- root: {
- "@id": "@local-tree-root"
- },
- model: "PartKeepr.PartBundle.Entity.PartCategory",
- proxy: {
- ignoreLoadId: '@local-tree-root',
- url: "/api/part_categories/getExtJSRootNode",
- type: "Hydra",
- appendId: false,
- reader: {
- type: 'json'
- }
-
- }
- });
+ this.store = Ext.create("PartKeepr.data.store.PartCategoryStore");
this.callParent();
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/CategoryComboBox.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/CategoryComboBox.js
@@ -1,154 +1,4 @@
Ext.define("PartKeepr.CategoryComboBox",{
- extend:"Ext.form.field.Picker",
- alias: 'widget.CategoryComboBox',
- requires:["Ext.tree.Panel"],
- selectedValue: null,
-
- trigger2Cls: Ext.baseCSSPrefix + 'form-reload-trigger',
-
- initComponent: function(){
- var self = this;
-
- Ext.apply(self,{
- pickerAlign:"tl-bl?",
- editable: false
-
- });
-
- self.callParent();
-
- this.createPicker();
-
- },
- onTrigger1Click: function () {
- this.onTriggerClick();
- },
- onTrigger2Click: function () {
- this.collapse();
- this.picker.loadCategories();
- this.expand();
- },
- /**
- * Override the expand method so that it doesn't expand immediately when data is being loaded. Defers the expand
- * function for 100 milliseconds until the picker data has been loaded.
- */
- expand: function () {
- if (!this.picker.loaded) {
- Ext.defer(this.expand, 100, this);
- return;
- } else {
- this.callParent();
- }
- },
- createPicker: function(){
- var self = this;
-
- self.picker = new PartKeepr.CategoryTree({
- height:290,
- categoryService: 'PartCategory',
- categoryModel: 'PartKeepr.PartCategory',
- floating: true,
- focusOnToFront: false,
- shadow: false,
- ownerCt: this.ownerCt
- });
-
- self.picker.on({
- itemclick: Ext.bind(function(sm, record){
- this.setValue(record.get("name"), true);
- this.setSelectedValue(record.get("id"));
- this.collapse();
- },this),
- show: {
- fn: Ext.bind(function(cmp) {
- var record = this.picker.getSelectionModel().getLastSelected();
-
- this.picker.getView().focusRow(record);
- }, this),
- delay: 50
- }
- });
-
- self.picker.getView().on("render", Ext.bind(function () {
- var record = this.picker.getSelectionModel().getLastSelected();
- this.picker.getView().ensureVisible(record);
-
- this.picker.getView().focusRow(record);
- },this));
-
- return self.picker;
- },
- setSelectedValue: function (id) {
- this.selectedValue = id;
- },
- getValue: function () {
- return this.selectedValue;
- },
- setValue: function (val, parent) {
- if (parent) {
- this.callParent([val]);
- }
-
- if (!this.picker) { return; }
-
- if (!this.picker.loaded) {
- this.picker.on("categoriesLoaded", function () { this._setValue(val); }, this);
- } else {
- this._setValue(val);
- }
- },
- _setValue: function (val) {
- var r = this.findById(val);
-
- /* We have found a record. Apply it */
- if (r !== null) {
- this.setSelectedValue(r.get("id"));
- this.setValue(r.get("name"), true);
-
- if (this.picker.getView().rendered) {
- this._selectRecords(r);
- } else {
- this.picker.getView().on("render", function () { this._selectRecords(r); }, this);
- }
-
- }
- },
- _selectRecords: function (r) {
- this.picker.getView().select(r);
- this.picker.getView().ensureVisible(r);
- this.picker.getView().scrollIntoView(r);
- },
- findById: function (id) {
- return this.picker.getRootNode().findChild("id", id, true);
- },
- alignPicker: function() {
- // override the original method because otherwise the height of the treepanel would be always 0
- var me = this,
- picker, isAbove,
- aboveSfx = '-above';
-
- 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);
-
- // 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 [];
- }
+ extend:"Ext.ux.TreePicker",
+ alias: 'widget.CategoryComboBox'
});
\ No newline at end of file
diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/store/PartCategoryStore.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/store/PartCategoryStore.js
@@ -0,0 +1,60 @@
+Ext.define('PartKeepr.data.store.PartCategoryStore', {
+ extend: 'Ext.data.TreeStore',
+
+ /**
+ * The store ID to use
+ */
+ storeId: 'PartCategoryStore',
+
+ /**
+ * Don't sort remotely as this is a tree store
+ */
+ remoteSort: false,
+
+ /**
+ * Sort folders alphabetically
+ */
+ folderSort: true,
+
+ /**
+ * Hide the root node by default
+ */
+ rootVisible: false,
+
+ /**
+ * Automatically load the store
+ */
+ autoLoad: true,
+
+ /**
+ * Sort by name ascending by default
+ */
+ sorters: [
+ {
+ property: 'name',
+ direction: 'ASC'
+ }
+ ],
+
+ /**
+ * Virtual Root Node
+ */
+ root: {
+ "@id": "@local-tree-root"
+ },
+
+ /**
+ * The model to use
+ */
+ model: "PartKeepr.PartBundle.Entity.PartCategory",
+
+ proxy: {
+ ignoreLoadId: '@local-tree-root',
+ url: "/api/part_categories/getExtJSRootNode",
+ type: "Hydra",
+ appendId: false,
+ reader: {
+ type: 'json'
+ }
+ }
+});+
\ No newline at end of file
diff --git a/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig b/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig
@@ -14,9 +14,8 @@
<!-- Include the ExtJS CSS Theme -->
{% stylesheets
filter='cssrewrite'
- 'js/packages/extjs6/build/classic/theme-crisp/resources/theme-crisp-all_1.css'
- 'js/packages/extjs6/build/classic/theme-crisp/resources/theme-crisp-all_2.css'
- 'js/packages/extjs6/build/packages/ux/classic/crisp/resources/ux-all.css'
+ 'js/packages/extjs6/build/classic/theme-classic/resources/theme-classic-all.css'
+ 'js/packages/extjs6/build/packages/ux/classic/classic/resources/ux-all.css'
'js/packages/extjs6/build/packages/charts/classic/neptune/resources/charts-all.css'
'bundles/partkeeprfrontend/css/PartKeepr.css'
%}
@@ -39,7 +38,7 @@
output='js/compiled/main.js'
'js/packages/extjs6/build/ext-all-debug.js'
'js/packages/extjs6/build/packages/charts/classic/charts.js'
- 'js/packages/extjs6/build/packages/ux/classic/ux.js'
+ 'js/packages/extjs6/build/packages/ux/classic/ux-debug.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/field/Array.js'
'@PartKeeprFrontendBundle/Resources/public/js/Util/Crypto/isaac.js'
'@PartKeeprFrontendBundle/Resources/public/js/Util/Crypto/bcrypt.js'
@@ -68,6 +67,7 @@
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraModel.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraTreeModel.js'
'@PartKeeprFrontendBundle/Resources/public/js/Data/HydraReader.js'
+ '@PartKeeprFrontendBundle/Resources/public/js/Data/store/PartCategoryStore.js'
'@PartKeeprFrontendBundle/Resources/public/js/ExtJS/Enhancements/Ext.tree.View-missingMethods.js'
'@PartKeeprFrontendBundle/Resources/public/js/ExtJS/Enhancements/Ext.form.Basic-AssociationSupport.js'
'@PartKeeprFrontendBundle/Resources/public/js/Components/Statusbar.js'