EditorComponent.js (6372B)
1 /** 2 * @class PartKeepr.EditorComponent 3 4 * <p>The EditorComponent encapsulates an editing workflow. In general, we have four actions 5 * for each object: create, update, delete, view. These actions stay exactly the same for each 6 * distinct object.</p> 7 * <p>The EditorComponent is a border layout, which has a navigation and an editor area.</p> 8 * @todo Document the editor system a bit better 9 */ 10 Ext.define('PartKeepr.EditorComponent', { 11 extend: 'Ext.panel.Panel', 12 alias: 'widget.EditorComponent', 13 14 /** 15 * Misc layout settings 16 */ 17 layout: 'border', 18 padding: 5, 19 border: false, 20 21 /** 22 * Specifies the class name of the navigation. The navigation is placed in the "west" region 23 * and needs to fire the event "itemSelect". The component listens on that event and 24 * creates an editor based on the selected record. 25 */ 26 navigationClass: null, 27 28 /** 29 * Specifies the class name of the editor. 30 */ 31 editorClass: null, 32 33 /** 34 * Contains the store for the item overview. 35 */ 36 store: null, 37 38 /** 39 * Contains the associated model to load a record for. 40 */ 41 model: null, 42 43 /** 44 * Defines the store to use. Defaults to {Ext.data.Store} 45 */ 46 storeType: "Ext.data.Store", 47 48 /** 49 * Some default text messages. Can be overridden by sub classes. 50 */ 51 deleteMessage: i18n("Do you really wish to delete the item %s?"), 52 deleteTitle: i18n("Delete Item"), 53 newItemText: i18n("New Item"), 54 55 /** 56 * @var {string} The record field to read the title property from 57 */ 58 titleProperty: 'name', 59 60 initComponent: function () 61 { 62 63 /** 64 * Create the navigation panel 65 */ 66 this.navigation = Ext.create(this.navigationClass, { 67 region: 'west', 68 width: 300, 69 split: true, 70 store: this.store, 71 titleProperty: this.titleProperty 72 }); 73 74 this.navigation.on("itemAdd", this.newRecord, this); 75 this.navigation.on("itemDelete", this.confirmDelete, this); 76 this.navigation.on("itemEdit", this.startEdit, this); 77 78 /** 79 * Create the editor panel 80 */ 81 this.editorTabPanel = Ext.create("Ext.tab.Panel", { 82 region: "center", 83 layout: 'fit', 84 plugins: Ext.create('Ext.ux.TabCloseMenu') 85 }); 86 87 this.items = [this.navigation, this.editorTabPanel]; 88 89 this.callParent(); 90 }, 91 /** 92 * Creates a new record. Creates a new instance of the editor. 93 */ 94 newRecord: function (defaults) 95 { 96 Ext.apply(defaults, {}); 97 98 var editor = this.createEditor(this.newItemText); 99 editor.newItem(defaults); 100 this.editorTabPanel.add(editor).show(); 101 }, 102 /** 103 * Instructs the component to edit a new record. 104 * @param {Record} record The record to edit 105 */ 106 startEdit: function (id) 107 { 108 /* Search for an open editor for the current record. If we 109 * already have an editor, show the editor instead of loading 110 * a new record. 111 */ 112 var editor = this.findEditor(id); 113 114 if (editor !== null) { 115 editor.show(); 116 return; 117 } 118 119 // Still here? OK, we don't have an editor open. Create a new one 120 var model = Ext.ClassManager.get(this.model); 121 122 model.load(id, { 123 scope: this, 124 success: function (record, operation) 125 { 126 editor = this.createEditor(record.get(this.titleProperty)); 127 editor.editItem(record); 128 this.editorTabPanel.add(editor).show(); 129 } 130 }); 131 }, 132 findEditor: function (id) 133 { 134 for (var i = 0; i < this.editorTabPanel.items.getCount(); i++) { 135 if (this.editorTabPanel.items.getAt(i).getRecordId() == id) { 136 return this.editorTabPanel.items.getAt(i); 137 } 138 } 139 140 return null; 141 }, 142 createEditor: function (title) 143 { 144 var editor = Ext.create(this.editorClass, { 145 store: this.store, 146 title: title, 147 model: this.model, 148 closable: true, 149 titleProperty: this.titleProperty, 150 listeners: { 151 editorClose: Ext.bind(function (m) 152 { 153 this.editorTabPanel.remove(m); 154 }, this) 155 } 156 }); 157 158 editor.on("itemSaved", this.onItemSaved, this); 159 return editor; 160 }, 161 confirmDelete: function () 162 { 163 var r = this.navigation.getSelectionModel().getLastSelected(); 164 var recordName; 165 166 recordName = r.get(this.titleProperty); 167 168 Ext.Msg.confirm( 169 this.deleteTitle, 170 sprintf(this.deleteMessage, recordName), 171 function (but) 172 { 173 if (but == "yes") { 174 this.deleteRecord(r); 175 } 176 }, this); 177 }, 178 deleteRecord: function (r) 179 { 180 var editor = this.findEditor(r.getId()); 181 182 if (editor !== null) { 183 this.editorTabPanel.remove(editor); 184 } 185 186 r.erase(); 187 this.store.load(); 188 }, 189 // Creates a store. To be called from child's initComponent 190 createStore: function (config) 191 { 192 Ext.applyIf(config, { 193 autoLoad: true, 194 model: this.model, 195 autoSync: false, // Do not change. If true, new (empty) records would be immediately committed to the database. 196 remoteFilter: true, 197 remoteSort: true, 198 pageSize: 15 199 }); 200 201 this.store = Ext.create(this.storeType, config); 202 203 // Workaround for bug http://www.sencha.com/forum/showthread.php?133767-Store.sync()-does-not-update-dirty-flag&p=607093#post607093 204 this.store.on('write', function (store, operation) 205 { 206 var success = operation.wasSuccessful(); 207 if (success) { 208 Ext.each(operation.records, function (record) 209 { 210 if (record.dirty) { 211 record.commit(); 212 } 213 }); 214 } 215 }); 216 }, 217 getStore: function () 218 { 219 return this.store; 220 }, 221 onItemSaved: function (record) 222 { 223 this.navigation.syncChanges(record); 224 } 225 });