Index: t3lib/js/extjs/ux/Ext.app.SearchField.js =================================================================== --- t3lib/js/extjs/ux/Ext.app.SearchField.js (revision 0) +++ t3lib/js/extjs/ux/Ext.app.SearchField.js (revision 0) @@ -0,0 +1,53 @@ +/* + * Ext JS Library 2.2.1 + * Copyright(c) 2006-2009, Ext JS, LLC. + * licensing@extjs.com + * + * http://extjs.com/license + */ + +Ext.app.SearchField = Ext.extend(Ext.form.TwinTriggerField, { + initComponent : function() { + Ext.app.SearchField.superclass.initComponent.call(this); + this.on('specialkey', function(f, e) { + if (e.getKey() == e.ENTER) { + this.onTrigger2Click(); + } + }, this); + }, + + validationEvent: false, + validateOnBlur: false, + trigger1Class: 'x-form-clear-trigger', + trigger2Class: 'x-form-search-trigger', + hideTrigger1: true, + width: 180, + hasSearch : false, + paramName : 'filterTxt', + + onTrigger1Click : function() { + if (this.hasSearch) { + this.el.dom.value = ''; + var o = {start: 0}; + this.store.baseParams = this.store.baseParams || {}; + this.store.baseParams[this.paramName] = ''; + this.store.reload({params:o}); + this.triggers[0].hide(); + this.hasSearch = false; + } + }, + + onTrigger2Click : function() { + var v = this.getRawValue(); + if (v.length < 1) { + this.onTrigger1Click(); + return; + } + var o = {start: 0}; + this.store.baseParams = this.store.baseParams || {}; + this.store.baseParams[this.paramName] = v; + this.store.reload({params:o}); + this.hasSearch = true; + this.triggers[0].show(); + } +}); Index: t3lib/js/extjs/ux/Ext.grid.RowExpander.js =================================================================== --- t3lib/js/extjs/ux/Ext.grid.RowExpander.js (revision 0) +++ t3lib/js/extjs/ux/Ext.grid.RowExpander.js (revision 0) @@ -0,0 +1,159 @@ +/* + * Ext JS Library 2.0 + * Copyright(c) 2006-2007, Ext JS, LLC. + * licensing@extjs.com + * + * http://extjs.com/license + * + * MODIFIED: SGB [12.12.07] + * Added support for a new config option, remoteDataMethod, + * including getter and setter functions, and minor mods + * to the beforeExpand and expandRow functions + */ + +Ext.grid.RowExpander = function(config) { + Ext.apply(this, config); + Ext.grid.RowExpander.superclass.constructor.call(this); + + if (this.tpl) { + if (typeof this.tpl == 'string') { + this.tpl = new Ext.Template(this.tpl); + } + this.tpl.compile(); + } + + this.state = {}; + this.bodyContent = {}; + + this.addEvents({ + beforeexpand : true, + expand: true, + beforecollapse: true, + collapse: true + }); +}; + +Ext.extend(Ext.grid.RowExpander, Ext.util.Observable, { + header: "", + width: 20, + sortable: false, + fixed:true, + dataIndex: '', + id: 'expander', + lazyRender : true, + enableCaching: true, + + getRowClass : function(record, rowIndex, p, ds) { + p.cols = p.cols-1; + var content = this.bodyContent[record.id]; + if (!content && !this.lazyRender) { + content = this.getBodyContent(record, rowIndex); + } + if (content) { + p.body = content; + } + return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed'; + }, + + init : function(grid) { + this.grid = grid; + + var view = grid.getView(); + view.getRowClass = this.getRowClass.createDelegate(this); + + view.enableRowBody = true; + + grid.on('render', function() { + view.mainBody.on('mousedown', this.onMouseDown, this); + }, this); + }, + + getBodyContent : function(record, index) { + if (!this.enableCaching) { + return this.tpl.apply(record.data); + } + var content = this.bodyContent[record.id]; + if (!content) { + content = this.tpl.apply(record.data); + this.bodyContent[record.id] = content; + } + return content; + }, + // Setter and Getter methods for the remoteDataMethod property + setRemoteDataMethod : function (fn) { + this.remoteDataMethod = fn; + }, + + getRemoteDataMethod : function (record, index) { + if (!this.remoteDataMethod) { + return; + } + return this.remoteDataMethod.call(this,record,index); + }, + + onMouseDown : function(e, t) { + if (t.className == 'x-grid3-row-expander') { + e.stopEvent(); + var row = e.getTarget('.x-grid3-row'); + this.toggleRow(row); + } + }, + + renderer : function(v, p, record) { + p.cellAttr = 'rowspan="2"'; + return '
 
'; + }, + + beforeExpand : function(record, body, rowIndex) { + if (this.fireEvent('beforexpand', this, record, body, rowIndex) !== false) { + // If remoteDataMethod is defined then we'll need a div, with a unique ID, + // to place the content + if (this.remoteDataMethod) { + this.tpl = new Ext.Template("
<\div>"); + } + if (this.tpl && this.lazyRender) { + body.innerHTML = this.getBodyContent(record, rowIndex); + } + + return true; + }else{ + return false; + } + }, + + toggleRow : function(row) { + if (typeof row == 'number') { + row = this.grid.view.getRow(row); + } + this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row); + }, + + expandRow : function(row) { + if (typeof row == 'number') { + row = this.grid.view.getRow(row); + } + var record = this.grid.store.getAt(row.rowIndex); + var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row); + if (this.beforeExpand(record, body, row.rowIndex)) { + this.state[record.id] = true; + Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded'); + if (this.fireEvent('expand', this, record, body, row.rowIndex) !== false) { + // If the expand event is successful then get the remoteDataMethod + this.getRemoteDataMethod(record,row.rowIndex); + } + } + }, + + collapseRow : function(row) { + if (typeof row == 'number') { + row = this.grid.view.getRow(row); + } + var record = this.grid.store.getAt(row.rowIndex); + var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true); + if (this.fireEvent('beforcollapse', this, record, body, row.rowIndex) !== false) { + this.state[record.id] = false; + Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed'); + this.fireEvent('collapse', this, record, body, row.rowIndex); + } + } +}); Index: t3lib/js/extjs/ux/Ext.ux.FitToParent.js =================================================================== --- t3lib/js/extjs/ux/Ext.ux.FitToParent.js (revision 0) +++ t3lib/js/extjs/ux/Ext.ux.FitToParent.js (revision 0) @@ -0,0 +1,33 @@ +/* plugin for resize of grid in single container */ +Ext.namespace('Ext.ux.plugins'); + +Ext.ux.plugins.FitToParent = Ext.extend(Object, { + constructor : function(parent) { + this.parent = parent; + }, + init : function(c) { + c.on('render', function(c) { + c.fitToElement = Ext.get(this.parent + || c.getPositionEl().dom.parentNode); + if (!c.doLayout) { + this.fitSizeToParent(); + Ext.EventManager.onWindowResize(this.fitSizeToParent, this); + } + }, this, { + single : true + }); + if (c.doLayout) { + c.monitorResize = true; + c.doLayout = c.doLayout.createInterceptor(this.fitSizeToParent); + } + }, + fitSizeToParent : function() { + // Uses the dimension of the current viewport, but removes the document header + // and an addtional margin of 40 pixels (e.g. Safari needs this addition) + + this.fitToElement.setHeight(document.viewport.getHeight() - this.fitToElement.getTop() - 40); + var pos = this.getPosition(true), size = this.fitToElement.getViewSize(); + this.setSize(size.width - pos[0], size.height - pos[1]); + + } +}); Index: typo3/sysext/recycler/mod1/index.php =================================================================== --- typo3/sysext/recycler/mod1/index.php (revision 8566) +++ typo3/sysext/recycler/mod1/index.php (working copy) @@ -47,6 +47,11 @@ protected $recordsPageLimit = 50; /** + * @var t3lib_pageRenderer + */ + protected $pageRenderer; + + /** * Initializes the Module * * @return void @@ -57,6 +62,8 @@ $this->doc->setModuleTemplate(t3lib_extMgm::extPath('recycler') . 'mod1/mod_template.html'); $this->doc->backPath = $GLOBALS['BACK_PATH']; + $this->pageRenderer = $this->doc->getPageRenderer(); + $this->relativePath = t3lib_extMgm::extRelPath('recycler'); $this->pageRecord = t3lib_BEfunc::readPageAccess($this->id, $this->perms_clause); $this->isAccessibleForCurrentUser = ( @@ -135,44 +142,34 @@ */ protected function loadHeaderData() { // Load CSS Stylesheets: - $this->loadStylesheet($this->relativePath . 'res/css/customExtJs.css'); + $this->pageRenderer->addCssFile($this->relativePath . 'res/css/customExtJs.css'); + // Load Ext JS: - $this->doc->getPageRenderer()->loadExtJS(); + $this->pageRenderer->loadExtJS(); + $this->pageRenderer->enableExtJSQuickTips(); + // Integrate dynamic JavaScript such as configuration or lables: - $this->doc->JScode.= t3lib_div::wrapJS(' - Ext.namespace("Recycler"); - Recycler.statics = ' . json_encode($this->getJavaScriptConfiguration()) . '; - Recycler.lang = ' . json_encode($this->getJavaScriptLabels()) . ';' + $this->pageRenderer->addInlineSettingArray( + 'Recycler', + $this->getJavaScriptConfiguration() ); + $this->pageRenderer->addInlineLanguageLabelArray( + $this->getJavaScriptLabels() + ); + + // Load Recycler JavaScript: - $this->loadJavaScript($this->relativePath . 'res/js/ext_expander.js'); - $this->loadJavaScript($this->relativePath . 'res/js/search_field.js'); - $this->loadJavaScript($this->relativePath . 'res/js/t3_recycler.js'); - } - /** - * Loads a stylesheet by adding it to the HTML head section. - * - * @param string $fileName: Name of the file to be loaded - * @return void - */ - protected function loadStylesheet($fileName) { - $fileName = t3lib_div::resolveBackPath($this->doc->backPath . $fileName); - $this->doc->JScode .= TAB . '' . LF; + // Load Plugins + $uxPath = $this->doc->backpath . '../t3lib/js/extjs/ux/'; + $this->pageRenderer->addJsFile($uxPath . 'Ext.grid.RowExpander.js', NULL, TRUE); + $this->pageRenderer->addJsFile($uxPath . 'Ext.app.SearchField.js', NULL, TRUE); + $this->pageRenderer->addJsFile($uxPath . 'Ext.ux.FitToParent.js', NULL, TRUE); + // Load main script + $this->pageRenderer->addJsFile($this->relativePath . 'res/js/t3_recycler.js'); } /** - * Loads a JavaScript file. - * - * @param string $fileName: Name of the file to be loaded - * @return void - */ - protected function loadJavaScript($fileName) { - $fileName = t3lib_div::resolveBackPath($this->doc->backPath . $fileName); - $this->doc->JScode .= TAB . '' . LF; - } - - /** * Gets the JavaScript configuration for the Ext JS interface. * * @return array The JavaScript configuration Index: typo3/sysext/recycler/res/css/customExtJs.css =================================================================== --- typo3/sysext/recycler/res/css/customExtJs.css (revision 8566) +++ typo3/sysext/recycler/res/css/customExtJs.css (working copy) @@ -1,161 +1,32 @@ -body#ext-recycler-mod1-index-php { - margin-left: 0; +.delete { + background-image: url('../icons/delete.gif') !important; } - -#recyclerContent { - margin: 10px 0 0 0; +.undelete { + background-image: url('../icons/arrow_rotate_anticlockwise.png') !important; } - -.x-panel .x-grid-panel { - padding: 0; - margin: 0; - background-image: none; - background: none; - border: none; +.backup { + background-image: url('../icons/database_save.png') !important; } - -body .x-panel { - margin-bottom:20px; +.filter_refresh { + background-image: url('../icons/filter_refresh.png') !important; } - -.x-toolbar-left, .x-toolbar-right, .x-panel-mc, x-panel-tbar, .x-toolbar .x-small-editor .x-toolbar-layout-ct, x-toolbar-ct, -.x-panel-nofooter .x-panel-bc, .x-panel-nofooter .x-window-bc, -.x-toolbar, -.x-small-editor, -.x-toolbar-layout-ct, -.x-panel-mr, .x-panel-ml, .x-panel-tr, .x-panel-tl, .x-panel-br, .x-panel-bl, .x-panel-ml, .x-panel-mr, .x-panel-tm, .x-panel-tc { - background-image: none; - background: none; - padding: 0; - margin: 0; - border: none; +.filter_clear { + background-image: url('../icons/filter_clear.png') !important; } -.x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar { - padding: 2px; - margin: 0; - border: 0; +#recyclerContent { + margin-top: 10px; } -.x-panel-mr, .x-panel-ml { - padding: 0; - margin: 0; +.recycler-messagebox { + padding: 10px; + font-size: 12px; } -.x-toolbar { - padding: 0; - margin: 0; +ul.recycler-table-list { + list-style: disc; + margin: 5px 0 5px 15px; } - -.x-panel-bbar .x-toolbar, .x-panel-tbar .x-toolbar, -.x-panel-tbar-noheader .x-toolbar, .x-panel-mc .x-panel-tbar .x-toolbar { - background-color: #585858; -} - -.x-toolbar-ct .x-toolbar-left { - width: 400px; -} - -.x-toolbar-ct .x-toolbar-right, .x-toolbar-cell { -} - -.x-toolbar-ct .xtb-text { - color: #fff; -} - -.icon-grid { background-image:url('../icons/recycler2.gif') !important; } - -#button-grid .x-panel-body { - border:1px solid #99bbe8; - border-top:0 none; -} - -.loadingClass { top:200px !important; } - -.ext-el-mask-msg { width:200px; } - -.ext-el-mask-msg div { - height:30px; - background-image: url('../icons/loading.gif'); - background-position: 155px 3px; - background-repeat: no-repeat; -} - -.x-toolbar button { - color: #fff; -} - -.delete { background-image: url('../icons/delete.gif') !important; } -.undelete { background-image: url('../icons/arrow_rotate_anticlockwise.png') !important; } -.backup { background-image: url('../icons/database_save.png') !important; } -.filter_refresh { background-image: url('../icons/filter_refresh.png') !important; } -.filter_clear { background-image: url('../icons/filter_clear.png') !important; } - -.deletedPath { color: #ff0000; font-weight: bold; } - -.x-toolbar table { width: 100%; } - -#recordPaging table { width: auto; } -#recordPaging .x-tbar-page-number { text-align: center; } - -.x-window-body { padding: 5px; } -.x-window-body label { display: block; margin: 5px 0; } -.x-window-body .x-form-cb-label { margin-left: 5px; } - -/* Single rows and elements */ -.x-grid3-body .x-grid3-td-expander { - background-image: none; -} - -.x-grid3-row { - background-image:none; -} - -.x-grid3-row-selected { - background-color:#fff !important; - background-image:none; -} - -/* Flyout Menus */ -.x-menu-sep { - display: none; -} - -.x-menu { - background-image: none; -} - -.x-menu-item-active a.x-menu-item { - border: 1px solid #adb5c1; - background-color: #adb5c1; - color: #fff; -} - -.x-menu-list { - padding:0; -} - -/* Flyout Menu Shadows */ -.x-shadow .xstl, .x-shadow .xstc, .x-shadow .xstr, .x-shadow .xsbl, -.x-shadow .xsbc, .x-shadow .xsbr, .x-shadow .xstl, .x-shadow .xstr, .x-shadow .xsml, .x-shadow .xsmr { - background-image: none; -} - -.x-grid3-body .x-grid3-td-checker { - background-image: none; - background-color: none; -} - -.x-grid3-body .x-grid3-row-selected .x-grid3-td-numberer, -.x-grid3-body .x-grid3-row-selected .x-grid3-td-checker, -.x-grid3-body .x-grid3-row-selected .x-grid3-td-expander { - background-image: none; - background-color: none; -} - -.x-grid3-row-body, -.x-grid3-row-body-tr, -.x-grid3-row-body-td, -.x-grid3-body-cell { - background-color: none; +ul.recycler-table-list li { + margin-left: 10px; } \ No newline at end of file Index: typo3/sysext/recycler/res/js/t3_recycler.js =================================================================== --- typo3/sysext/recycler/res/js/t3_recycler.js (revision 8566) +++ typo3/sysext/recycler/res/js/t3_recycler.js (working copy) @@ -27,262 +27,328 @@ * * @author Julian Kleinhans * @author Erik Frister + * @author Steffen Kamper * @package TYPO3 * @subpackage tx_recycler * @version $Id$ */ -Event.observe(window, 'load', function() { - //Quicktips initialisieren - Ext.QuickTips.init(); - // @todo: description - // Ext.form.Field.prototype.msgTarget = 'side'; +Ext.ns('Recycler'); - // disable loadindicator - Ext.UpdateManager.defaults.showLoadIndicator = false; - - // fire recycler grid - new Recycler.grid.init(); +/**************************************************** + * row expander + ****************************************************/ +Recycler.Expander = new Ext.grid.RowExpander({ + tpl : new Ext.Template( + '
' + + '

' + TYPO3.lang.table + ': {table}

' + + '

' + TYPO3.lang.crdate + ': {crdate}

' + + '

' + TYPO3.lang.tstamp + ': {tstamp}

' + + '

' + TYPO3.lang.owner + ': {owner} (UID: {owner_uid})

' + + '

' + TYPO3.lang.path + ': {path}

' + + '
' + ) }); -Recycler.grid = { - /** - * Initializes the grid - * - * @return void - **/ - init: function() { - /**************************************************** - * row expander - ****************************************************/ - var expander = new Ext.grid.RowExpander({ - tpl : new Ext.Template( - '
' + - '

' + Recycler.lang.table + ': {table}

' + - '

' + Recycler.lang.crdate + ': {crdate}

' + - '

' + Recycler.lang.tstamp + ': {tstamp}

' + - '

' + Recycler.lang.owner + ': {owner} (UID: {owner_uid})

' + - '

' + Recycler.lang.path + ': {path}

' + - '
' - ) - }); +/**************************************************** + * Main store + ****************************************************/ +Recycler.MainStore = new Ext.data.Store({ + storeId: 'deletedRecordsStore', + reader: new Ext.data.JsonReader({ + totalProperty: 'total', + root: 'rows' + }, [ + {name: 'uid', type: 'int'}, + {name: 'pid', type: 'int'}, + {name: 'record', mapping: 'title'}, + {name: 'crdate'}, + {name: 'tstamp'}, + {name: 'owner'}, + {name: 'owner_uid'}, + {name: 'tableTitle'}, + {name: 'table'}, + {name: 'path'} + ]), + sortInfo: { + field: 'record', + direction: "ASC" + }, + groupField: 'table', + url: TYPO3.settings.Recycler.ajaxController + '&cmd=getDeletedRecords', + baseParams: { + depth: TYPO3.settings.Recycler.depthSelection, + startUid: TYPO3.settings.Recycler.startUid, + pagingSizeDefault: TYPO3.settings.Recycler.pagingSize, + table: TYPO3.settings.Recycler.tableSelection + } + +}); - /**************************************************** - * pluggable renderer - ****************************************************/ +/**************************************************** + * Simple table store + ****************************************************/ +Recycler.TableStore = new Ext.data.Store({ + url: TYPO3.settings.Recycler.ajaxController + '&startUid=' + TYPO3.settings.Recycler.startUid + '&cmd=getTables' + '&depth=' + TYPO3.settings.Recycler.depthSelection, + reader: new Ext.data.ArrayReader({}, [ + {name: 'table', type: 'string'}, + {name: 'records', type: 'int'}, + {name: 'valueField', type: 'string'}, + {name: 'tableTitle', type: 'string'} + ]), + listeners: { + 'load': { + fn: function(store, records) { + Ext.getCmp('tableSelector').setValue(TYPO3.settings.Recycler.tableSelection); + }, + single: true + } + } +}) - var renderTopic = function (value, p, record) { - return String.format('{0}', value, record.data.table, record.data.uid, record.data.pid); - }; - - /**************************************************** - * row checkbox - ****************************************************/ - - var sm = new Ext.grid.CheckboxSelectionModel({ - singleSelect: false +/**************************************************** + * Confirmation Window + ****************************************************/ +Recycler.ConfirmWindow = Ext.extend(Ext.Window, { + + width: 300, + height: 200, + + title: '', + confirmText: '', + confirmQuestion: '', + records: [], + hideRecursive: false, + showRecursiveCheckbox: false, + arePagesAffected: false, + command: '', + template: new Ext.XTemplate( + '
    ', + '', + '
  • {[values]}
  • ', + '
    ', + '
' + ), + initComponent:function() { + Ext.apply(this, { + xtype: 'form', + bodyCssClass: 'recycler-messagebox', + modal: true, + + items: [ + { + xtype: 'label', + text: this.confirmText + }, { + xtype: 'displayfield', + tpl: this.template, + data: this.tables + }, { + xtype: 'label', + text: this.confirmQuestion + }, { + xtype: 'checkbox', + boxLabel: TYPO3.lang.boxLabel_undelete_recursive, + name: 'recursiveCheckbox', + disabled: !this.showRecursiveCheckbox, + itemId: 'recursiveCheck', + hidden: this.hideRecursive // hide the checkbox when frm is used to permanently delete + } + ], + buttons: [ + { + text: TYPO3.lang.yes, + scope: this, + handler: function(button, event) { + var tcemainData = []; + + for (var i=0; i < this.records.length; i++) { + tcemainData[i] = [this.records[i].data.table, this.records[i].data.uid]; + } + Ext.Ajax.request({ + url: TYPO3.settings.Recycler.ajaxController + '&cmd=' + this.command, + params: { + 'data': Ext.encode(tcemainData), + 'recursive': this.getComponent('recursiveCheck').getValue() + }, + callback: function(options, success, response) { + if (response.responseText === "1") { + // reload the records and the table selector + Recycler.MainStore.reload(); + Recycler.TableStore.reload(); + if (this.arePagesAffected) { + Recycler.Utility.updatePageTree(); + } + } else { + Ext.MessageBox.show({ + title: 'ERROR', + msg: response.responseText, + buttons: Ext.MessageBox.OK, + icon: Ext.MessageBox.ERROR + }); + } + } + }); + + this.close(); + } + },{ + text: TYPO3.lang.no, + scope: this, + handler: function(button, event) { + this.close(); + } + } + ] }); + Recycler.ConfirmWindow.superclass.initComponent.apply(this, arguments); + } +}); - /**************************************************** - * filter grid - ****************************************************/ +/**************************************************** + * Utility functions + ****************************************************/ +Recycler.Utility = { + updatePageTree: function() { + if (top && top.content && top.content.nav_frame && top.content.nav_frame.Tree) { + top.content.nav_frame.Tree.refresh(); + } + }, + + // not used? + filterGrid: function(grid, component) { + var filterText = component.getValue(); - var filterGrid = function(grid, cmp) { - var filterText = cmp.getValue(); - - gridDs.setBaseParam('filterTxt', filterText); - // load the datastore - gridDs.load({ - params: { - start: 0 - } - }); - }; - - /**************************************************** - * grid datastore - ****************************************************/ - var gridDs = new Ext.data.Store({ - storeId: 'deletedRecordsStore', - reader: new Ext.data.JsonReader({ - totalProperty: 'total', - root: 'rows' - }, [ - {name: 'uid', type: 'int'}, - {name: 'pid', type: 'int'}, - {name: 'record', mapping: 'title'}, - {name: 'crdate'}, - {name: 'tstamp'}, - {name: 'owner'}, - {name: 'owner_uid'}, - {name: 'tableTitle'}, - {name: 'table'}, - {name: 'path'} - ]), - sortInfo: { - field: 'record', - direction: "ASC" - }, - groupField: 'table', - url: Recycler.statics.ajaxController + '&cmd=getDeletedRecords' + Recycler.MainStore.setBaseParam('filterTxt', filterText); + // load the datastore + Recycler.MainStore.load({ + params: { + start: 0 + } }); - - gridDs.baseParams = { - depth: Recycler.statics.depthSelection, - startUid: Recycler.statics.startUid, - pagingSizeDefault: Recycler.statics.pagingSize, - table: Recycler.statics.tableSelection - }; - - + }, + + /**************************************************** + * permanent deleting function + ****************************************************/ - /**************************************************** - * permanent deleting function - ****************************************************/ + function_delete: function(button, event) { + Recycler.Utility.rowAction( + 'doDelete', + TYPO3.lang.cmd_doDelete_confirmText, + TYPO3.lang.title_delete, + TYPO3.lang.text_delete + ); + }, - var function_delete = function(ob) { - rowAction(ob, Recycler.lang.cmd_doDelete_confirmText, 'doDelete', Recycler.lang.title_delete, Recycler.lang.text_delete); - }; + /**************************************************** + * Undeleting function + ****************************************************/ - /**************************************************** - * Undeleting function - ****************************************************/ + function_undelete: function(button, event) { + Recycler.Utility.rowAction( + 'doUndelete', + TYPO3.lang.sure, + TYPO3.lang.title_undelete, + TYPO3.lang.text_undelete + ); + }, - var function_undelete = function(ob) { - rowAction(ob, Recycler.lang.sure, 'doUndelete', Recycler.lang.title_undelete, Recycler.lang.text_undelete); - }; + /**************************************************** + * Row action function ( deleted or undeleted ) + ****************************************************/ - /**************************************************** - * Row action function ( deleted or undeleted ) - ****************************************************/ + rowAction: function(command, confirmQuestion, confirmTitle, confirmText) { + // get the 'undeleted records' grid object + var records = Recycler.Grid.getSelectionModel().getSelections(); - var rowAction = function(ob, confirmQuestion, cmd, confirmTitle, confirmText) { - // get the 'undeleted records' grid object - var recArray = gridContainer.getSelectionModel().getSelections(); + if (records.length > 0) { - if (recArray.length > 0) { - - // check if a page is checked - var recursiveCheckbox = false; - var arePagesAffected = false; - var tables = []; - var hideRecursive = ('doDelete' == cmd); - - for (iterator=0; iterator < recArray.length; iterator++) { - if (tables.indexOf(recArray[iterator].data.table) < 0) { - tables.push(recArray[iterator].data.table); - } - if (cmd == 'doUndelete' && recArray[iterator].data.table == 'pages' ) { - recursiveCheckbox = true; - arePagesAffected = true; - } + // check if a page is checked + var recursiveCheckbox = false; + var arePagesAffected = false; + var tables = []; + var hideRecursive = ('doDelete' == command); + + for (iterator=0; iterator < records.length; iterator++) { + if (tables.indexOf(records[iterator].data.table) < 0) { + tables.push(records[iterator].data.table); } + if (command == 'doUndelete' && records[iterator].data.table == 'pages' ) { + recursiveCheckbox = true; + arePagesAffected = true; + } + } - var frmConfirm = new Ext.Window({ - xtype: 'form', - width: 300, - height: 200, - modal: true, - title: confirmTitle, - items: [ - { - xtype: 'label', - text: confirmText + tables.join(', ') - },{ - xtype: 'label', - text: confirmQuestion - },{ - xtype: 'checkbox', - boxLabel: Recycler.lang.boxLabel_undelete_recursive, - name: 'recursiveCheckbox', - disabled: !recursiveCheckbox, - id: 'recursiveCheckbox', - hidden: hideRecursive // hide the checkbox when frm is used to permanently delete - } - ], - buttons: [ - { - text: Recycler.lang.yes, - handler: function(cmp, e) { - var tcemainData = []; + var frmConfirm = new Recycler.ConfirmWindow({ + title: confirmTitle, + records: records, + tables: tables, + confirmText: confirmText, + confirmQuestion: confirmQuestion, + hideRecursive: hideRecursive, + recursiveCheckbox: recursiveCheckbox, + arePagesAffected: arePagesAffected, + command: command + }).show(); - for (iterator=0; iterator < recArray.length; iterator++) { - tcemainData[iterator] = [recArray[iterator].data.table, recArray[iterator].data.uid]; - } + } else { + // no row selected + Ext.MessageBox.show({ + title: TYPO3.lang.error_NoSelectedRows_title, + msg: TYPO3.lang.error_NoSelectedRows_msg, + buttons: Ext.MessageBox.OK, + minWidth: 300, + minHeight: 200, + icon: Ext.MessageBox.ERROR + }); + } + }, + + /**************************************************** + * pluggable renderer + ****************************************************/ - Ext.Ajax.request({ - url: Recycler.statics.ajaxController + '&cmd=' + cmd, - callback: function(options, success, response) { - if (response.responseText === "1") { - // reload the records and the table selector - gridDs.reload(); - Ext.getCmp('tableSelector').store.reload(); - if (arePagesAffected) { - Recycler.utility.updatePageTree(); - } - }else{ - alert('ERROR: '+response.responseText); - } - }, - params: {'data': Ext.encode(tcemainData), 'recursive':frmConfirm.getComponent('recursiveCheckbox').getValue() } - }); + renderTopic: function (value, p, record) { + return String.format('{0}', value, record.data.table, record.data.uid, record.data.pid); + } +}; - frmConfirm.destroy(); - } - },{ - text: Recycler.lang.no, - handler: function(cmp, e) { - frmConfirm.destroy(); - } - } - ] - }); - frmConfirm.show(); - } else { - // no row selected - Ext.MessageBox.show({ - title: Recycler.lang.error_NoSelectedRows_title, - msg: Recycler.lang.error_NoSelectedRows_msg, - buttons: Ext.MessageBox.OK, - minWidth: 300, - minHeight: 200, - icon: Ext.MessageBox.INFO - }); - } - }; - - /**************************************************** - * grid container - ****************************************************/ - var gridContainer = new Ext.grid.GridPanel ({ - layout: 'fit', - renderTo: Recycler.statics.renderTo, - width: '98%', - frame: true, - border: true, - defaults: {autoScroll: false}, - plain: true, +/**************************************************** + * grid container + ****************************************************/ +Recycler.GridContainer = Ext.extend(Ext.grid.GridPanel, { + layout: 'fit', + renderTo: TYPO3.settings.Recycler.renderTo, + width: '98%', + frame: true, + border: false, + defaults: {autoScroll: false}, + plain: true, + + initComponent : function() { + Ext.apply(this, { id: 'delRecordId', loadMask: true, stripeRows: true, collapsible: false, animCollapse: false, - store: gridDs, + store: Recycler.MainStore, cm: new Ext.grid.ColumnModel([ - sm, - expander, + new Ext.grid.CheckboxSelectionModel({singleSelect: false}), + Recycler.Expander, {header: "UID", width: 10, sortable: true, dataIndex: 'uid'}, {header: "PID", width: 10, sortable: true, dataIndex: 'pid'}, - {id: 'record', header: Recycler.lang.records, width: 60, sortable: true, dataIndex: 'record', renderer: renderTopic}, - {id: 'table', header: Recycler.lang.table, width: 20, sortable: true, dataIndex: 'tableTitle'} + {id: 'record', header: TYPO3.lang.records, width: 60, sortable: true, dataIndex: 'record', renderer: Recycler.Utility.renderTopic}, + {id: 'table', header: TYPO3.lang.table, width: 20, sortable: true, dataIndex: 'tableTitle'} ]), viewConfig: { forceFit: true }, - sm: sm, - plugins: [expander, new Ext.ux.plugins.FitToParent()], + sm: Recycler.SelectionModel, + plugins: [Recycler.Expander, new Ext.ux.plugins.FitToParent()], bbar: [ { @@ -291,11 +357,11 @@ ****************************************************/ id: 'recordPaging', xtype: 'paging', - store: gridDs, - pageSize: Recycler.statics.pagingSize, + store: Recycler.MainStore, + pageSize: TYPO3.settings.Recycler.pagingSize, displayInfo: true, - displayMsg: Recycler.lang.pagingMessage, - emptyMsg: Recycler.lang.pagingEmpty + displayMsg: TYPO3.lang.pagingMessage, + emptyMsg: TYPO3.lang.pagingEmpty }, '-', { /**************************************************** * Delete button @@ -303,11 +369,11 @@ xtype: 'button', width: 80, id: 'deleteButton', - text: Recycler.lang.deleteButton_text, - tooltip: Recycler.lang.deleteButton_tooltip, + text: TYPO3.lang.deleteButton_text, + tooltip: TYPO3.lang.deleteButton_tooltip, iconCls: 'delete', - disabled: Recycler.statics.deleteDisable, - handler: function_delete + disabled: TYPO3.settings.Recycler.deleteDisable, + handler: Recycler.Utility.function_delete }, { /**************************************************** * Undelete button @@ -315,28 +381,28 @@ xtype: 'button', width: 80, id: 'undeleteButton', - text: Recycler.lang.undeleteButton_text, - tooltip: Recycler.lang.undeleteButton_tooltip, + text: TYPO3.lang.undeleteButton_text, + tooltip: TYPO3.lang.undeleteButton_tooltip, iconCls: 'undelete', - handler: function_undelete + handler: Recycler.Utility.function_undelete } ], tbar: [ - Recycler.lang.search, ' ', + TYPO3.lang.search, ' ', new Ext.app.SearchField({ - store: gridDs, + store: Recycler.MainStore, width: 200 }), '-', { xtype: 'tbtext', - text: Recycler.lang.depth + ':' + text: TYPO3.lang.depth + ':' },{ /**************************************************** * Depth menu ****************************************************/ - + xtype: 'combo', width: 150, lazyRender: true, @@ -344,36 +410,36 @@ displayField: 'label', id: 'depthSelector', mode: 'local', - emptyText: Recycler.lang.depth, + emptyText: TYPO3.lang.depth, selectOnFocus: true, triggerAction: 'all', editable: false, forceSelection: true, - hidden: Recycler.lang.showDepthMenu, + hidden: TYPO3.lang.showDepthMenu, store: new Ext.data.SimpleStore({ autoLoad: true, fields: ['depth','label'], data : [ - ['0', Recycler.lang.depth_0], - ['1', Recycler.lang.depth_1], - ['2', Recycler.lang.depth_2], - ['3', Recycler.lang.depth_3], - ['4', Recycler.lang.depth_4], - ['999', Recycler.lang.depth_infi] + ['0', TYPO3.lang.depth_0], + ['1', TYPO3.lang.depth_1], + ['2', TYPO3.lang.depth_2], + ['3', TYPO3.lang.depth_3], + ['4', TYPO3.lang.depth_4], + ['999', TYPO3.lang.depth_infi] ] }), - value: Recycler.statics.depthSelection, + value: TYPO3.settings.Recycler.depthSelection, listeners: { 'select': { fn: function(cmp, rec, index) { var depth = rec.get('depth'); - gridDs.setBaseParam('depth', depth); - gridDs.load({ + Recycler.MainStore.setBaseParam('depth', depth); + Recycler.MainStore.load({ params: { start: 0 } }); - + Ext.getCmp('tableSelector').store.load({ params: { depth: depth @@ -384,7 +450,7 @@ } },'-',{ xtype: 'tbtext', - text: Recycler.lang.tableMenu_label + text: TYPO3.lang.tableMenu_label },{ /**************************************************** @@ -396,45 +462,29 @@ valueField: 'valueField', displayField: 'tableTitle', id: 'tableSelector', + width: 220, mode: 'local', - emptyText: Recycler.lang.tableMenu_emptyText, + emptyText: TYPO3.lang.tableMenu_emptyText, selectOnFocus: true, triggerAction: 'all', editable: false, forceSelection: true, - store: new Ext.data.Store({ - autoLoad: true, - url: Recycler.statics.ajaxController + '&startUid=' + Recycler.statics.startUid + '&cmd=getTables' + '&depth=' + Recycler.statics.depthSelection, - reader: new Ext.data.ArrayReader({}, [ - {name: 'table', type: 'string'}, - {name: 'records', type: 'int'}, - {name: 'valueField', type: 'string'}, - {name: 'tableTitle', type: 'string'} - ]), - listeners: { - 'load': { - fn: function(store, records) { - Ext.getCmp('tableSelector').setValue(Recycler.statics.tableSelection); - }, - single: true - } - } - }), - valueNotFoundText: String.format(Recycler.lang.noValueFound, Recycler.statics.tableSelection), + store: Recycler.TableStore, + valueNotFoundText: String.format(TYPO3.lang.noValueFound, TYPO3.settings.Recycler.tableSelection), tpl: '
{tableTitle} ({records})
{tableTitle} ({records})
', listeners: { 'select': { - fn: function(cmp, rec, index) { - var table = rec.get('valueField'); + fn: function(component, record, index) { + var table = record.get('valueField'); // do not reload if the table selected has no deleted records - hide all records - if (rec.get('records') <= 0) { - gridDs.filter('uid', '-1'); // never true + if (record.get('records') <= 0) { + Recycler.MainStore.filter('uid', '-1'); // never true return false; } - gridDs.setBaseParam('table', table); - gridDs.load({ + Recycler.MainStore.setBaseParam('table', table); + Recycler.MainStore.load({ params: { start: 0 } @@ -444,50 +494,27 @@ } } ] - }); - gridDs.load(); + Recycler.GridContainer.superclass.initComponent.apply(this, arguments); + Recycler.TableStore.load(); } -}; +}); - -Recycler.utility = { - updatePageTree: function() { - if (top && top.content && top.content.nav_frame && top.content.nav_frame.Tree) { - top.content.nav_frame.Tree.refresh(); - } +Recycler.App = { + /** + * Initializes the recycler + * + * @return void + **/ + init: function() { + Recycler.Grid = new Recycler.GridContainer(); + Recycler.MainStore.load(); } }; -/* plugin for resize of grid in single container */ -Ext.namespace('Ext.ux.plugins'); -Ext.ux.plugins.FitToParent = Ext.extend(Object, { - constructor : function(parent) { - this.parent = parent; - }, - init : function(c) { - c.on('render', function(c) { - c.fitToElement = Ext.get(this.parent - || c.getPositionEl().dom.parentNode); - if (!c.doLayout) { - this.fitSizeToParent(); - Ext.EventManager.onWindowResize(this.fitSizeToParent, this); - } - }, this, { - single : true - }); - if (c.doLayout) { - c.monitorResize = true; - c.doLayout = c.doLayout.createInterceptor(this.fitSizeToParent); - } - }, - fitSizeToParent : function() { - // Uses the dimension of the current viewport, but removes the document header - // and an addtional margin of 40 pixels (e.g. Safari needs this addition) - - this.fitToElement.setHeight(document.viewport.getHeight() - this.fitToElement.getTop() - 40); - var pos = this.getPosition(true), size = this.fitToElement.getViewSize(); - this.setSize(size.width - pos[0], size.height - pos[1]); - - } +Ext.onReady(function(){ + // disable loadindicator + Ext.UpdateManager.defaults.showLoadIndicator = false; + // fire recycler grid + Recycler.App.init(); });