EntityQueryPanel.js (9352B)
1 Ext.define("PartKeepr.Widgets.EntityQueryPanel", { 2 extend: "Ext.panel.Panel", 3 layout: 'border', 4 items: [ 5 { 6 title: i18n("Results"), 7 xtype: 'grid', 8 region: 'center', 9 itemId: 'grid', 10 }, { 11 title: i18n("Available fields"), 12 xtype: 'treepanel', 13 region: 'east', 14 width: 265, 15 itemId: 'fieldTree', 16 plugins: { 17 ptype: 'cellediting', 18 clicksToEdit: 1, 19 pluginId: "cellediting", 20 }, 21 split: true, 22 viewConfig: { 23 markDirty: false 24 }, 25 store: { 26 folderSort: true, 27 sorters: [ 28 { 29 property: 'text', 30 direction: 'ASC' 31 } 32 ] 33 }, 34 columns: [ 35 { 36 xtype: 'treecolumn', //this is so we know which column will show the tree 37 text: i18n("Field"), 38 dataIndex: 'text', 39 flex: 3, 40 }, { 41 text: i18n("Index"), 42 flex: 1, 43 align: 'center', 44 dataIndex: 'entityIndex', 45 format: '0', 46 editor: { 47 xtype: 'numberfield', 48 minValue: 0, 49 maxValue: 99 50 }, 51 renderer: function (val, md, record) { 52 if (record.get("data") instanceof Object && 53 typeof(record.get("data").type) !== "undefined" && 54 record.get("data").type !== "onetomany") { 55 return ""; 56 } else { 57 return record.get("entityIndex"); 58 } 59 } 60 } 61 ], 62 useArrows: true 63 } 64 ], 65 /** 66 * @var {Array} Contains the models already in the field tree 67 */ 68 visitedModels: [], 69 70 /** 71 * @var {Array} All configured columns 72 */ 73 columns: [], 74 75 /** 76 * @var {Ext.data.Store} The store 77 */ 78 store: null, 79 80 initComponent: function () 81 { 82 this.callParent(arguments); 83 this.visitedModels = []; 84 85 var rootNode = this.down("#fieldTree").getRootNode(); 86 this.down("#fieldTree").on("itemdblclick", this.onTreeDblClick, this); 87 rootNode.set("text", this.model.getName()); 88 89 var treeMaker = Ext.create("PartKeepr.ModelTreeMaker.ModelTreeMaker"); 90 treeMaker.addIgnoreField("@id"); 91 treeMaker.make(rootNode, this.model, "", Ext.bind(this.appendFieldData, this), ["entityIndex"]); 92 rootNode.expand(); 93 94 rootNode.expand(); 95 96 this.store = Ext.create("Ext.data.Store", { 97 model: this.model.getName(), 98 autoLoad: true 99 }); 100 101 this.down("#fieldTree").addDocked({ 102 xtype: 'toolbar', 103 items: [ 104 { 105 xtype: 'button', 106 iconCls: 'web-icon add', 107 handler: "onAddColumn", 108 scope: this 109 }, 110 { 111 xtype: 'button', 112 iconCls: 'web-icon delete', 113 handler: "onRemoveColumn", 114 scope: this 115 } 116 ] 117 }); 118 119 this.down("#fieldTree").getPlugin("cellediting").on("beforeedit", this.onBeforeEdit, this); 120 this.down("#grid").addDocked(this.bottomToolbar); 121 122 this.down("#grid").reconfigure(this.store, this.columns); 123 }, 124 onBeforeEdit: function (editor, context) 125 { 126 if (context.record.get("data") !== null && 127 context.record.get("data").type !== "onetomany") { 128 129 return false; 130 } 131 }, 132 /** 133 * @param {Ext.data.field.Field} The model 134 */ 135 appendFieldData: function (field, node) 136 { 137 node.set("entityIndex", 0); 138 }, 139 /** 140 * Returns the parameters for the query string. 141 * @return {Object} An object containing all parameters 142 */ 143 getParams: function () 144 { 145 var i, originalColumns, columns = []; 146 originalColumns = this.down('#grid').getColumns(); 147 for (i = 0; i < originalColumns.length; i++) { 148 columns.push(originalColumns[i].dataIndex); 149 } 150 151 return { 152 itemsPerPage: 9999999, 153 columns: Ext.encode(columns) 154 }; 155 156 }, 157 /** 158 * Event handler for the add button 159 */ 160 onAddColumn: function () 161 { 162 var selModel = this.down("#fieldTree").getSelectionModel(); 163 if (!selModel.hasSelection()) { 164 return; 165 } 166 167 var record = this.down("#fieldTree").getSelectionModel().getSelection()[0]; 168 this.addColumn(record); 169 }, 170 /** 171 * Event handler for the remove button 172 */ 173 onRemoveColumn: function () 174 { 175 var selModel = this.down("#fieldTree").getSelectionModel(); 176 if (!selModel.hasSelection()) { 177 return; 178 } 179 180 var record = this.down("#fieldTree").getSelectionModel().getSelection()[0]; 181 this.removeColumn(record); 182 }, 183 /** 184 * Adds a specific column to the grid. Must be a record and has the "data" property defined. 185 * 186 * @param {Ext.data.Model} The record to process 187 */ 188 addColumn: function (record) 189 { 190 var columns, fieldPath; 191 192 fieldPath = this.getFieldPath(record).join("."); 193 194 if (this.hasColumn(fieldPath) || record.get("data").name === undefined) { 195 return; 196 } 197 198 if (record.get("data").type !== "field") { 199 return; 200 } 201 202 columns = this.down('#grid').getColumns(); 203 204 this.syncColumns(); 205 206 this.columns.push({ 207 dataIndex: fieldPath, 208 text: fieldPath, 209 renderer: this.columnRenderer, 210 scope: this.down('#grid') 211 }); 212 213 this.down("#grid").reconfigure(this.store, this.columns); 214 }, 215 getFieldPath: function (record) 216 { 217 var fieldPath = []; 218 219 if (record.parentNode !== null && !record.parentNode.isRoot()) { 220 fieldPath = this.getFieldPath(record.parentNode); 221 } 222 223 if (typeof(record.get("data")) === "object" && record.get("data").type === "onetomany") { 224 fieldPath.push(record.get("text") + "[" + record.get("entityIndex") + "]"); 225 } else { 226 fieldPath.push(record.get("text")); 227 } 228 229 return fieldPath; 230 }, 231 /** 232 * Removes a specific column to the grid. Must be a record and has the "data" property defined. 233 * 234 * @param {Ext.data.Model} The record to process 235 */ 236 removeColumn: function (record) 237 { 238 var i, fieldPath; 239 240 fieldPath = this.getFieldPath(record).join("."); 241 242 if (!this.hasColumn(fieldPath) || record.get("data").name === undefined) { 243 return; 244 } 245 246 this.syncColumns(); 247 248 for (i = 0; i < this.columns.length; i++) { 249 if (this.columns[i].dataIndex === fieldPath) { 250 Ext.Array.removeAt(this.columns, i); 251 } 252 } 253 this.down("#grid").reconfigure(this.store, this.columns); 254 255 }, 256 /** 257 * Syncronizes the internal columns storage with the grid. The reason it is done that way is because we can't 258 * operate on the return value of getColumns() directly, as these are instanciated objects which get removed 259 * during a reconfigure operation. 260 */ 261 syncColumns: function () 262 { 263 var columns, i; 264 this.columns = []; 265 266 columns = this.down('#grid').getColumns(); 267 268 for (i = 0; i < columns.length; i++) { 269 this.columns.push({ 270 dataIndex: columns[i].dataIndex, 271 text: columns[i].text, 272 renderer: this.columnRenderer, 273 scope: this.down('#grid') 274 }); 275 } 276 }, 277 columnRenderer: function (value, metadata, record, rowIndex, colIndex) 278 { 279 var index = this.getColumns()[colIndex].dataIndex; 280 return record.get(index); 281 }, 282 /** 283 * Returns if a specific column exists in the grid.Must be a record and has the "data" property defined. 284 * 285 * @param {Ext.data.Model} The record to process 286 * @return {Boolean} true if the column exist, false otherwise 287 */ 288 hasColumn: function (name) 289 { 290 var i, columns = this.down('#grid').getColumns(); 291 292 for (i = 0; i < columns.length; i++) { 293 if (columns[i].dataIndex === name) { 294 return true; 295 } 296 } 297 298 return false; 299 }, 300 /** 301 * Handles the double click on the tree. Adds the item if it doesn't exist, or remove it otherwise 302 * 303 * @param {Ext.tree.Tree} The tree panel 304 * @param {Ext.data.Model} The double clicked record 305 */ 306 onTreeDblClick: function (tree, record) 307 { 308 var fieldPath = this.getFieldPath(record).join("."); 309 310 if (this.hasColumn(fieldPath)) { 311 this.removeColumn(record); 312 } else { 313 this.addColumn(record); 314 } 315 } 316 }) 317 ;