Code:
1 Ext.define('Writer.Form', {
2 extend: 'Ext.form.Panel',
3
4 requires: ['Ext.form.field.Text'],
5
6 initComponent: function(){
7 this.addEvents('create');
8 Ext.apply(this, {
9 activeRecord: null,
10 iconCls: 'icon-user',
11 frame: true,
12 defaultType: 'textfield',
13 bodyPadding: 5,
14 fieldDefaults: {
15 anchor: '100%',
16 width: 500,
17 labelWidth: 200,
18 labelAlign: 'right'
19 },
20 items: [{
21 xtype:'tabpanel',
22 activeTab: 0,
23 defaults:{
24 bodyStyle:'padding:10px'
25 },
26 items:[{
27 title:'Page \'partenaires\'',
28 defaultType: 'textfield',
29 items: [{
30 emptyText: 'Sélectionnez une image',
31 xtype: 'filefield',
32 fieldLabel: 'Photo ',
33 name: 'partenaires_photo',
34 buttonText: '',
35 buttonConfig: {
36 iconCls: 'upload-icon'
37 }
38 },{
39 xtype: 'textarea',
40 emptyText: 'Description du partenaire',
41 fieldLabel: 'Description ',
42 name: 'partenaires_description',
43 style: 'margin:0', /* Remove default margin */
44 flex: 1 /* Take up all *remaining* vertical space */
45 }]
46 },{
47 title:'Produits',
48 defaultType: 'textfield',
49 items: []
50 },{
51 title:'Évenements',
52 defaultType: 'textfield',
53 items: []
54 },{
55 title:'Références',
56 defaultType: 'textfield',
57 items: []
58 },{
59 title:'Promotions',
60 defaultType: 'textfield',
61 items: []
62 }]
63 }],
64 dockedItems: [{
65 xtype: 'toolbar',
66 dock: 'bottom',
67 ui: 'footer',
68 items: [{
69 iconCls: 'icon-save',
70 itemId: 'save',
71 text: 'Sauver',
72 disabled: true,
73 scope: this,
74 handler: this.onSave
75 }, {
76 iconCls: 'icon-user-add',
77 text: 'Créer',
78 scope: this,
79 handler: this.onCreate
80 }, {
81 iconCls: 'icon-reset',
82 text: 'Reset',
83 scope: this,
84 handler: this.onReset
85 }]
86 }]
87 });
88 this.callParent();
89 },
90
91 setActiveRecord: function(record){
92 this.activeRecord = record;
93 if (record) {
94 this.down('#save').enable();
95 this.getForm().loadRecord(record);
96 } else {
97 this.down('#save').disable();
98 this.getForm().reset();
99 }
100 },
101
102 onSave: function(){
103 var active = this.activeRecord,
104 form = this.getForm();
105
106 if (!active) {
107 return;
108 }
109 if (form.isValid()) {
110 form.updateRecord(active);
111 this.onReset();
112 }
113 },
114
115 onCreate: function(){
116 var form = this.getForm();
117
118 if (form.isValid()) {
119 this.fireEvent('create', this, form.getValues());
120 form.reset();
121 }
122
123 },
124
125 onReset: function(){
126 this.setActiveRecord(null);
127 this.getForm().reset();
128 }
129 });
130
131 Ext.define('Writer.Grid', {
132 extend: 'Ext.grid.Panel',
133
134 requires: [
135 'Ext.form.field.Text',
136 'Ext.toolbar.TextItem'
137 ],
138
139 initComponent: function(){
140
141 Ext.apply(this, {
142 iconCls: 'icon-grid',
143 frame: true,
144 plugins: [],
145 dockedItems: [{
146 xtype: 'toolbar',
147 dock: 'bottom',
148 items: [{
149 iconCls: 'icon-add',
150 text: 'Nouveau',
151 scope: this,
152 handler: this.onAddClick
153 }, {
154 iconCls: 'icon-delete',
155 text: 'Supprimer',
156 disabled: true,
157 itemId: 'delete',
158 scope: this,
159 handler: this.onDeleteClick
160 }, {
161 iconCls: 'icon-save',
162 text: 'Synchroniser',
163 scope: this,
164 handler: this.onSync
165 },
166 /* '->' = Décaler à droite le reste : */
167 '->', {
168 xtype: 'tbtext',
169 text: '<b>@cfg</b>'
170 }, '|', {
171 text: 'autoSync',
172 enableToggle: true,
173 pressed: true,
174 tooltip: 'When enabled, Store will execute '+
175 'Ajax requests as soon as a Record '+
176 'becomes dirty.',
177 scope: this,
178 toggleHandler: function(btn, pressed){
179 this.store.autoSync = pressed;
180 }
181 }, {
182 text: 'batch',
183 enableToggle: true,
184 pressed: true,
185 tooltip: 'When enabled, Store will batch all '+
186 'records for each type of CRUD verb '+
187 'into a single Ajax request.',
188 scope: this,
189 toggleHandler: function(btn, pressed){
190 this.store.getProxy().batchActions = pressed;
191 }
192 }, {
193 text: 'writeAllFields',
194 enableToggle: true,
195 pressed: false,
196 tooltip: 'When enabled, Writer will write '+
197 '*all* fields to the server -- '+
198 'not just those that changed.',
199 scope: this,
200 toggleHandler: function(btn, pressed){
201 this.store.getProxy().getWriter().writeAllFields = pressed;
202 }
203 }]
204 }],
205 columns: [{
206 header: 'id',
207 width: 50,
208 sortable: true,
209 dataIndex: 'id',
210 field: {
211 type: 'textfield'
212 }
213 }, {
214 header: 'Description',
215 width: 450,
216 sortable: true,
217 dataIndex: 'description',
218 field: {
219 type: 'textfield'
220 }
221 }]
222 });
223 this.callParent();
224 this.getSelectionModel().on('selectionchange', this.onSelectChange, this);
225 },
226
227 onSelectChange: function(selModel, selections){
228 this.down('#delete').setDisabled(selections.length === 0);
229 },
230
231 onSync: function(){
232 this.store.sync();
233 },
234
235 onDeleteClick: function(){
236 var selection = this.getView().getSelectionModel().getSelection()[0];
237 if (selection) {
238 this.store.remove(selection);
239 }
240 },
241
242 onAddClick: function(){
243 var rec = new Writer.Person({
244 first: '',
245 last: '',
246 email: ''
247 });
248
249 this.store.insert(0, rec);
250 }
251 });
252
253 Ext.define('Writer.Panel', {
254 extend: 'Ext.panel.Panel',
255 /* Je n'aime pas me servir des alias, mais je laisse
256 * le code au cas où :
257 *
258 alias: 'widget.writerpanel',
259 */
260
261 /* C'est ici qu'on met tous les 'requires' :
262 * mais c'est inutile dans notre cas, car
263 * on ne construit que des composants et on
264 * n'a besoin de rien de spécial. Je laisse
265 * le code au cas où :
266 requires: [
267 'Ext.form.field.Text',
268 'Ext.toolbar.TextItem'
269 ],
270 */
271
272 initComponent: function(){
273 this.writerForm = new Writer.Form({
274 listeners: {
275 create: function(form, data){
276 this.store.insert(0, data);
277 }
278 }
279 });
280 this.writerGrid = new Writer.Grid({
281 store: this.store,
282 listeners: {
283 /* scope: this => super important pour les
284 * fonctions anonymes qui veulent accéder
285 * aux variables "this" de la classe,
286 * p.ex ici c'est this.writerForm :
287 */
288 scope: this,
289 selectionchange: function(selModel, selected) {
290 this.writerForm.setActiveRecord(selected[0] || null);
291 }
292 }
293 });
294 Ext.apply(this, {
295 title: this.title,
296 layout: {
297 type: 'vbox',
298 align: 'stretch'
299 },
300 flex: 1,
301 bodyPadding: 5,
302 items: [{
303 xtype: 'panel',
304 layout: 'fit',
305 flex: 1,
306 items: [this.writerGrid]
307 },{
308 xtype: 'splitter',
309 height: 10
310 },{
311 xtype: 'panel',
312 layout: 'fit',
313 flex: 2,
314 items: [this.writerForm]
315 }]
316 });
317 this.callParent();
318 }
319 });
320
321 Ext.define('Writer.Person', {
322 extend: 'Ext.data.Model',
323 fields: [{
324 name: 'id',
325 type: 'int',
326 useNull: true
327 },
328 'description'
329 ]
330 /*,
331 validations: [{
332 type: 'length',
333 field: 'email',
334 min: 1
335 }, {
336 type: 'length',
337 field: 'first',
338 min: 1
339 }, {
340 type: 'length',
341 field: 'last',
342 min: 1
343 }]
344 */
345 });
346
347 Ext.require([
348 'Ext.data.*',
349 'Ext.tip.QuickTipManager',
350 'Ext.window.MessageBox'
351 ]);
352
353 Ext.onReady(function(){
354 Ext.tip.QuickTipManager.init();
355 var store = Ext.create('Ext.data.Store', {
356 model: 'Writer.Person',
357 autoLoad: true,
358 autoSync: true,
359 proxy: {
360 type: 'ajax',
361 api: {
362 read: 'json/liste_view.php',
363 create: 'json/item.php?mode=create',
364 update: 'json/item.php?mode=update',
365 destroy: 'json/item.php?mode=destroy'
366 },
367 reader: {
368 type: 'json',
369 successProperty: 'success',
370 root: 'data',
371 messageProperty: 'message'
372 },
373 writer: {
374 type: 'json',
375 writeAllFields: false,
376 root: 'data'
377 },
378 listeners: {
379 exception: function(proxy, response, operation){
380 Ext.MessageBox.show({
381 title: 'Erreur du serveur',
382 msg: operation.getError(),
383 icon: Ext.MessageBox.ERROR,
384 buttons: Ext.Msg.OK
385 });
386 }
387 }
388 },
389 listeners: {
390 write: function(proxy, operation){
391 if (operation.action == 'destroy') {
392 main.child('#form').setActiveRecord(null);
393 }
394 Ext.example.msg(
395 Ext.String.capitalize(operation.action),
396 operation.resultSet.message);
397 }
398 }
399 });
400
401 /* Pour qu'il soit resizable automatiquement,
402 * créer un Viewport au lieu d'un Container :
403 * A la place de 'Ext.Viewport'
404 * il y avait 'Ext.container.Container' :
405 */
406 var viewport = Ext.create('Ext.Viewport', {
407 layout: 'fit',
408 items: [
409 new Ext.Panel({
410 layout: {
411 type: 'hbox',
412 align: 'stretch'
413 },
414 bodyPadding: 5,
415 items: [new Writer.Panel({
416 title: 'Test 1',
417 store: store
418 }),{
419 xtype: 'splitter',
420 width: 10
421 },new Writer.Panel({
422 title: 'Test 1',
423 store: store
424 }),{
425 xtype: 'splitter',
426 width: 10
427 }, new Writer.Panel({
428 title: 'Test 2',
429 store: store
430 })]
431 })
432 ]
433 });
434 });
435