12cfd2d6ea39c7939f8a5f2d2bbce65fd787cbd2
[Packages/TYPO3.CMS.git] / typo3 / sysext / recycler / res / js / t3_recycler.js
1 /***************************************************************
2 * Copyright notice
3 *
4 * (c) 2009 Julian Kleinhans <typo3@kj187.de>
5 * All rights reserved
6 *
7 * This script is part of the TYPO3 project. The TYPO3 project is
8 * free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * The GNU General Public License can be found at
14 * http://www.gnu.org/copyleft/gpl.html.
15 *
16 * This script is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * This copyright notice MUST APPEAR in all copies of the script!
22 ***************************************************************/
23
24 /**
25 * ExtJS for the 'recycler' extension.
26 * Contains the Recycler functions
27 *
28 * @author Julian Kleinhans <typo3@kj187.de>
29 * @author Erik Frister <erik_frister@otq-solutions.com>
30 * @package TYPO3
31 * @subpackage tx_recycler
32 * @version $Id$
33 */
34 Event.observe(window, 'load', function() {
35 //Quicktips initialisieren
36 Ext.QuickTips.init();
37
38 // @todo: description
39 // Ext.form.Field.prototype.msgTarget = 'side';
40
41 // disable loadindicator
42 Ext.UpdateManager.defaults.showLoadIndicator = false;
43
44 // fire recycler grid
45 new Recycler.grid.init();
46 });
47
48 Recycler.grid = {
49 /**
50 * Initializes the grid
51 *
52 * @return void
53 **/
54 init: function() {
55 /****************************************************
56 * row expander
57 ****************************************************/
58
59 var expander = new Ext.grid.RowExpander({
60 tpl : new Ext.Template(
61 '<br/>' +
62 '<p style="margin-left:45px;"><b>' + Recycler.lang.table + ':</b> {table}</p>' +
63 '<p style="margin-left:45px;"><b>' + Recycler.lang.crdate + ':</b> {crdate}</p>' +
64 '<p style="margin-left:45px;"><b>' + Recycler.lang.tstamp + ':</b> {tstamp}</p>' +
65 '<p style="margin-left:45px;"><b>' + Recycler.lang.owner + ':</b> {owner} (UID: {owner_uid})</p>' +
66 '<p style="margin-left:45px;"><b>' + Recycler.lang.path + ':</b> {path}</p>' +
67 '<br/>'
68 )
69 });
70
71 /****************************************************
72 * pluggable renderer
73 ****************************************************/
74
75 var renderTopic = function (value, p, record) {
76 return String.format('{0}', value, record.data.table, record.data.uid, record.data.pid);
77 };
78
79 /****************************************************
80 * row checkbox
81 ****************************************************/
82
83 var sm = new Ext.grid.CheckboxSelectionModel({
84 singleSelect: false
85 });
86
87 /****************************************************
88 * filter grid
89 ****************************************************/
90
91 var filterGrid = function(grid, cmp) {
92 var filterText = cmp.getValue();
93
94 gridDs.setBaseParam('filterTxt', filterText);
95 // load the datastore
96 gridDs.load({
97 params: {
98 start: 0
99 }
100 });
101 };
102
103 /****************************************************
104 * grid datastore
105 ****************************************************/
106 var gridDs = new Ext.data.Store({
107 storeId: 'deletedRecordsStore',
108 reader: new Ext.data.JsonReader({
109 totalProperty: 'total',
110 root: 'rows'
111 }, [
112 {name: 'uid', type: 'int'},
113 {name: 'pid', type: 'int'},
114 {name: 'record', mapping: 'title'},
115 {name: 'crdate'},
116 {name: 'tstamp'},
117 {name: 'owner'},
118 {name: 'owner_uid'},
119 {name: 'tableTitle'},
120 {name: 'table'},
121 {name: 'path'}
122 ]),
123 sortInfo: {
124 field: 'record',
125 direction: "ASC"
126 },
127 groupField: 'table',
128 url: Recycler.statics.ajaxController + '&cmd=getDeletedRecords'
129 });
130
131 gridDs.baseParams = {
132 depth: Recycler.statics.depthSelection,
133 startUid: Recycler.statics.startUid,
134 pagingSizeDefault: Recycler.statics.pagingSize,
135 table: Recycler.statics.tableSelection
136 }
137
138
139
140 /****************************************************
141 * permanent deleting function
142 ****************************************************/
143
144 var function_delete = function(ob) {
145 rowAction(ob, Recycler.lang.cmd_doDelete_confirmText, 'doDelete', Recycler.lang.title_delete, Recycler.lang.text_delete);
146 };
147
148 /****************************************************
149 * Undeleting function
150 ****************************************************/
151
152 var function_undelete = function(ob) {
153 rowAction(ob, Recycler.lang.sure, 'doUndelete', Recycler.lang.title_undelete, Recycler.lang.text_undelete);
154 };
155
156 /****************************************************
157 * Row action function ( deleted or undeleted )
158 ****************************************************/
159
160 var rowAction = function(ob, confirmQuestion, cmd, confirmTitle, confirmText) {
161 // get the 'undeleted records' grid object
162 var grid = tabs.getComponent(0).getComponent(0);
163 recArray = grid.getSelectionModel().getSelections();
164
165 if (recArray.length > 0) {
166
167 // check if a page is checked
168 var recursiveCheckbox = false;
169 var arePagesAffected = false;
170 var tables = [];
171 var hideRecursive = ('doDelete' == cmd);
172
173 for (iterator=0; iterator < recArray.length; iterator++) {
174 if (tables.indexOf(recArray[iterator].data.table) < 0) {
175 tables.push(recArray[iterator].data.table);
176 }
177 if (cmd == 'doUndelete' && recArray[iterator].data.table == 'pages' ) {
178 recursiveCheckbox = true;
179 arePagesAffected = true;
180 }
181 }
182
183 var frmConfirm = new Ext.Window({
184 xtype: 'form',
185 width: 300,
186 height: 200,
187 modal: true,
188 title: confirmTitle,
189 items: [
190 {
191 xtype: 'label',
192 text: confirmText + tables.join(', ')
193 },{
194 xtype: 'label',
195 text: confirmQuestion
196 },{
197 xtype: 'checkbox',
198 boxLabel: Recycler.lang.boxLabel_undelete_recursive,
199 name: 'recursiveCheckbox',
200 disabled: !recursiveCheckbox,
201 id: 'recursiveCheckbox',
202 hidden: hideRecursive // hide the checkbox when frm is used to permanently delete
203 }
204 ],
205 buttons: [
206 {
207 text: Recycler.lang.yes,
208 handler: function(cmp, e) {
209 tcemainData = new Array();
210
211 for (iterator=0; iterator < recArray.length; iterator++) {
212 tcemainData[iterator] = [recArray[iterator].data.table, recArray[iterator].data.uid];
213 }
214
215 Ext.Ajax.request({
216 url: Recycler.statics.ajaxController + '&cmd=' + cmd,
217 callback: function(options, success, response) {
218 if (response.responseText === "1") {
219 // reload the records and the table selector
220 grid.getStore().reload();
221 Ext.getCmp('tableSelector').store.reload();
222 if (arePagesAffected) {
223 Recycler.utility.updatePageTree();
224 }
225 }else{
226 alert('ERROR: '+response.responseText);
227 }
228 },
229 params: {'data': Ext.encode(tcemainData), 'recursive':frmConfirm.getComponent('recursiveCheckbox').getValue() }
230 });
231
232 frmConfirm.destroy();
233 }
234 },{
235 text: Recycler.lang.no,
236 handler: function(cmp, e) {
237 frmConfirm.destroy();
238 }
239 }
240 ]
241 });
242 frmConfirm.show();
243
244 } else {
245 // no row selected
246 Ext.MessageBox.show({
247 title: Recycler.lang.error_NoSelectedRows_title,
248 msg: Recycler.lang.error_NoSelectedRows_msg,
249 buttons: Ext.MessageBox.OK,
250 minWidth: 300,
251 minHeight: 200,
252 icon: Ext.MessageBox.INFO
253 });
254 }
255 };
256
257 /****************************************************
258 * tab container
259 ****************************************************/
260
261 var tabs = new Ext.TabPanel({
262 renderTo: Recycler.statics.renderTo,
263 layoutOnTabChange: true,
264 activeTab: 0,
265 width: '99%',
266 height: 600,
267 frame: true,
268 border: false,
269 defaults: {autoScroll: true},
270 plain: true,
271 buttons: [{
272
273 /****************************************************
274 * Delete button
275 ****************************************************/
276
277 id: 'deleteButton',
278 text: Recycler.lang.deleteButton_text,
279 tooltip: Recycler.lang.deleteButton_tooltip,
280 iconCls: 'delete',
281 disabled: Recycler.statics.deleteDisable,
282 handler: function_delete
283 },{
284
285 /****************************************************
286 * Undelete button
287 ****************************************************/
288
289 id: 'undeleteButton',
290 text: Recycler.lang.undeleteButton_text,
291 tooltip: Recycler.lang.undeleteButton_tooltip,
292 iconCls: 'undelete',
293 handler: function_undelete
294 }
295 ],
296 buttonAlign:'left',
297 items:[
298 {
299
300 /****************************************************
301 * Deleted records Tab
302 ****************************************************/
303
304 id: 'delRecordId',
305 title: Recycler.lang.deletedTab,
306 items: [
307 {
308
309 /****************************************************
310 * Grid
311 ****************************************************/
312
313 xtype: 'grid',
314 loadMask: true,
315 store: gridDs,
316 cm: new Ext.grid.ColumnModel([
317 sm,
318 expander,
319 {header: "UID", width: 10, sortable: true, dataIndex: 'uid'},
320 {header: "PID", width: 10, sortable: true, dataIndex: 'pid'},
321 {id:'record',header: "Records", width: 60, sortable: true, dataIndex: 'record', renderer: renderTopic},
322 {header: "Table", width: 20, sortable: true, dataIndex: 'tableTitle'}
323 ]),
324
325 view: new Ext.grid.GridView({
326 forceFit:true
327 }),
328
329 bbar: [
330 {
331
332 /****************************************************
333 * Paging toolbar
334 ****************************************************/
335 id: 'recordPaging',
336 xtype: 'paging',
337 store: gridDs,
338 pageSize: Recycler.statics.pagingSize,
339 displayInfo: true,
340 displayMsg: Recycler.lang.pagingMessage,
341 emptyMsg: Recycler.lang.pagingEmpty
342 }
343 ],
344
345 tbar: [
346 Recycler.lang.search, ' ',
347 new Ext.app.SearchField({
348 store: gridDs,
349 width: 200
350 }),
351 '->', {
352
353 /****************************************************
354 * Depth menu
355 ****************************************************/
356
357 xtype: 'combo',
358 lazyRender: true,
359 valueField: 'depth',
360 displayField: 'label',
361 id: 'depthSelector',
362 mode: 'local',
363 emptyText: Recycler.lang.depth,
364 selectOnFocus: true,
365 readOnly: true,
366 triggerAction: 'all',
367 editable: false,
368 forceSelection: true,
369 hidden: Recycler.lang.showDepthMenu,
370 store: new Ext.data.SimpleStore({
371 autoLoad: true,
372 fields: ['depth','label'],
373 data : [
374 ['0', Recycler.lang.depth_0],
375 ['1', Recycler.lang.depth_1],
376 ['2', Recycler.lang.depth_2],
377 ['3', Recycler.lang.depth_3],
378 ['4', Recycler.lang.depth_4],
379 ['999', Recycler.lang.depth_infi]
380 ]
381 }),
382 value: Recycler.statics.depthSelection,
383 listeners: {
384 'select': {
385 fn: function(cmp, rec, index) {
386 var store = tabs.getComponent(0).getComponent(0).getStore();
387 var depth = rec.get('depth');
388 gridDs.setBaseParam('depth', depth);
389 store.load({
390 params: {
391 start: 0
392 }
393 });
394
395 Ext.getCmp('tableSelector').store.load({
396 params: {
397 depth: depth
398 }
399 });
400 }
401 }
402 }
403 },'->',{
404
405 /****************************************************
406 * Table menu
407 ****************************************************/
408
409 xtype: 'combo',
410 lazyRender: true,
411 valueField: 'valueField',
412 displayField: 'tableTitle',
413 id: 'tableSelector',
414 mode: 'local',
415 emptyText: Recycler.lang.tableMenu_emptyText,
416 selectOnFocus: true,
417 readOnly: true,
418 triggerAction: 'all',
419 editable: false,
420 forceSelection: true,
421
422 store: new Ext.data.Store({
423 autoLoad: true,
424 url: Recycler.statics.ajaxController + '&startUid=' + Recycler.statics.startUid + '&cmd=getTables' + '&depth=' + Recycler.statics.depthSelection,
425 reader: new Ext.data.ArrayReader({}, [
426 {name: 'table', type: 'string'},
427 {name: 'records', type: 'int'},
428 {name: 'valueField', type: 'string'},
429 {name: 'tableTitle', type: 'string'}
430 ]),
431 listeners: {
432 'load': {
433 fn: function(store, records) {
434 Ext.getCmp('tableSelector').setValue(Recycler.statics.tableSelection);
435 },
436 single: true
437 }
438 }
439 }),
440 valueNotFoundText: String.format(Recycler.lang.noValueFound, Recycler.statics.tableSelection),
441 tpl: '<tpl for="."><tpl if="records &gt; 0"><div ext:qtip="{table} ({records})" class="x-combo-list-item">{tableTitle} ({records}) </div></tpl><tpl if="records &lt; 1"><div ext:qtip="{table} ({records})" class="x-combo-list-item x-item-disabled">{tableTitle} ({records}) </div></tpl></tpl>',
442 listeners: {
443 'select': {
444 fn: function(cmp, rec, index) {
445 var store = gridDs;
446 var table = rec.get('valueField');
447
448 // do not reload if the table selected has no deleted records - hide all records
449 if (rec.get('records') <= 0) {
450 store.filter('uid', '-1'); // never true
451 return false;
452 }
453 gridDs.setBaseParam('table', table);
454 store.load({
455 params: {
456 start: 0
457 }
458 });
459 }
460 }
461 }
462 }
463 ],
464
465 sm: sm,
466 plugins: expander,
467 loadMask: true,
468 stripeRows: true,
469 width: '100%',
470 height: 530,
471 collapsible: false,
472 animCollapse: false,
473 frame: false,
474 border: false,
475 listeners: {
476 'render': {
477 fn: function(cmp) {
478 cmp.getStore().load();
479 },
480 single: true
481 }
482 }
483 }
484 ]
485 }//,{
486
487 /****************************************************
488 * Lost and found Tab
489 ****************************************************/
490 /*
491 id: 'lostAndFoundId',
492 title: Recycler.staticsRecycler.statics.lostFoundTab,
493 html:'Later'
494 } */
495 ]
496 });
497 }
498 };
499
500
501 Recycler.utility = {
502 updatePageTree: function() {
503 if (top && top.content && top.content.nav_frame && top.content.nav_frame.Tree) {
504 top.content.nav_frame.Tree.refresh();
505 }
506 }
507 };