modx.grid.trash.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. MODx.grid.Trash = function (config) {
  2. config = config || {};
  3. this.sm = new Ext.grid.CheckboxSelectionModel();
  4. Ext.applyIf(config, {
  5. url: MODx.config.connector_url,
  6. baseParams: {
  7. action: 'resource/trash/getlist'
  8. },
  9. fields: [
  10. 'id',
  11. 'pagetitle',
  12. 'longtitle',
  13. 'published',
  14. 'context_key',
  15. 'context_name',
  16. 'parentPath',
  17. 'deletedon',
  18. 'deletedby',
  19. 'deletedby_name',
  20. 'cls'
  21. ],
  22. paging: true,
  23. autosave: true,
  24. save_action: 'resource/updatefromgrid',
  25. save_callback: this.refreshEverything,
  26. remoteSort: true,
  27. sm: this.sm,
  28. columns: [this.sm, {
  29. header: _('id'),
  30. dataIndex: 'id',
  31. width: 20,
  32. sortable: true
  33. }, {
  34. header: _('pagetitle'),
  35. dataIndex: 'pagetitle',
  36. width: 80,
  37. sortable: true,
  38. renderer: this.renderTooltip
  39. }, {
  40. header: _('trash.context_title'),
  41. dataIndex: 'context_name',
  42. width: 60,
  43. sortable: false
  44. }, {
  45. header: _('published'),
  46. dataIndex: 'published',
  47. width: 40,
  48. sortable: true,
  49. editor: {xtype: 'combo-boolean', renderer: 'boolean'}
  50. }, {
  51. header: _('trash.deletedon_title'),
  52. dataIndex: 'deletedon',
  53. width: 75,
  54. sortable: true
  55. }, {
  56. header: _('trash.deletedbyUser_title'),
  57. dataIndex: 'deletedby',
  58. width: 75,
  59. sortable: true,
  60. renderer: function (value, metaData, record) {
  61. return record.data.deletedby_name;
  62. }
  63. }],
  64. tbar: [{
  65. text: _('bulk_actions'),
  66. menu: [{
  67. text: _('trash.selected_purge'),
  68. handler: this.purgeSelected,
  69. scope: this
  70. }, {
  71. text: _('trash.selected_restore'),
  72. handler: this.restoreSelected,
  73. scope: this
  74. }]
  75. }, {
  76. xtype: 'button',
  77. text: _('trash.purge_all'),
  78. id: 'modx-purge-all',
  79. cls: 'x-btn-purge-all',
  80. listeners: {
  81. 'click': {fn: this.purgeAll, scope: this}
  82. }
  83. }, {
  84. xtype: 'button',
  85. text: _('trash.restore_all'),
  86. id: 'modx-restore-all',
  87. cls: 'x-btn-restore-all',
  88. listeners: {
  89. 'click': {fn: this.restoreAll, scope: this}
  90. }
  91. }, '->', {
  92. xtype: 'modx-combo-context',
  93. id: 'modx-trash-context',
  94. emptyText: _('context'),
  95. exclude: 'mgr',
  96. listeners: {
  97. 'select': {fn: this.searchContext, scope: this}
  98. }
  99. },{
  100. xtype: 'textfield',
  101. id: 'modx-trash-search',
  102. cls: 'x-form-filter',
  103. emptyText: _('search_ellipsis'),
  104. listeners: {
  105. 'change': {fn: this.search, scope: this},
  106. 'render': {
  107. fn: function (cmp) {
  108. new Ext.KeyMap(cmp.getEl(), {
  109. key: Ext.EventObject.ENTER,
  110. fn: this.blur,
  111. scope: cmp
  112. });
  113. }, scope: this
  114. }
  115. }
  116. }, {
  117. xtype: 'button',
  118. text: _('filter_clear'),
  119. id: 'modx-filter-clear',
  120. cls: 'x-form-filter-clear',
  121. listeners: {
  122. 'click': {fn: this.clearFilter, scope: this}
  123. }
  124. }]
  125. });
  126. MODx.grid.Trash.superclass.constructor.call(this, config);
  127. };
  128. Ext.extend(MODx.grid.Trash, MODx.grid.Grid, {
  129. getMenu: function () {
  130. var r = this.getSelectionModel().getSelected();
  131. var p = r.data.cls;
  132. var m = [];
  133. if (this.getSelectionModel().getCount() > 1) {
  134. m.push({
  135. text: _('trash.selected_purge'),
  136. handler: this.purgeSelected,
  137. scope: this
  138. });
  139. m.push({
  140. text: _('trash.selected_restore'),
  141. handler: this.restoreSelected,
  142. scope: this
  143. });
  144. } else {
  145. if (p.indexOf('trashpurge') !== -1) {
  146. m.push({
  147. text: _('trash.purge'),
  148. handler: this.purgeResource
  149. });
  150. }
  151. if (p.indexOf('trashundelete') !== -1) {
  152. m.push({
  153. text: _('trash.restore'),
  154. handler: this.restoreResource
  155. });
  156. }
  157. }
  158. if (m.length > 0) {
  159. this.addContextMenuItem(m);
  160. }
  161. },
  162. search: function (tf, newValue) {
  163. var nv = newValue || tf;
  164. this.getStore().baseParams.query = Ext.isEmpty(nv) || Ext.isObject(nv) ? '' : nv;
  165. this.getBottomToolbar().changePage(1);
  166. this.refresh();
  167. return true;
  168. },
  169. searchContext: function (tf) {
  170. this.getStore().baseParams.context = !Ext.isEmpty(tf) ? tf.value : '';
  171. this.getBottomToolbar().changePage(1);
  172. this.refresh();
  173. return true;
  174. },
  175. clearFilter: function () {
  176. this.getStore().baseParams.query = '';
  177. this.getStore().baseParams.context = '';
  178. Ext.getCmp('modx-trash-search').reset();
  179. Ext.getCmp('modx-trash-context').reset();
  180. this.getBottomToolbar().changePage(1);
  181. this.refresh();
  182. },
  183. purgeResource: function () {
  184. MODx.msg.confirm({
  185. title: _('trash.purge_confirm_title'),
  186. text: _('trash.purge_confirm_message', {
  187. 'list': this.listResources('')
  188. }),
  189. url: this.config.url,
  190. params: {
  191. action: 'resource/trash/purge',
  192. ids: this.menu.record.id
  193. },
  194. listeners: {
  195. 'success': {
  196. fn: function (data) {
  197. this.refreshEverything(data.total);
  198. }, scope: this
  199. },
  200. 'error': {
  201. fn: function (data) {
  202. MODx.msg.status({
  203. title: _('error'),
  204. message: data.message
  205. });
  206. }, scope: this
  207. }
  208. }
  209. });
  210. },
  211. restoreResource: function () {
  212. var withPublish = '';
  213. if (this.menu.record.published) {
  214. withPublish = '_with_publish';
  215. }
  216. MODx.msg.confirm({
  217. title: _('trash.restore_confirm_title'),
  218. text: _('trash.restore_confirm_message' + withPublish, {
  219. 'list': this.listResources('')
  220. }),
  221. url: this.config.url,
  222. params: {
  223. action: 'resource/undelete',
  224. id: this.menu.record.id
  225. },
  226. listeners: {
  227. 'success': {
  228. fn: function (data) {
  229. this.refreshEverything(data.total);
  230. }, scope: this
  231. },
  232. 'error': {
  233. fn: function (data) {
  234. MODx.msg.status({
  235. title: _('error'),
  236. message: data.message
  237. });
  238. }, scope: this
  239. }
  240. }
  241. });
  242. },
  243. purgeSelected: function () {
  244. var cs = this.getSelectedAsList();
  245. if (cs === false) return false;
  246. MODx.msg.confirm({
  247. title: _('trash.purge_confirm_title'),
  248. text: _('trash.purge_confirm_message', {
  249. 'list': this.listResources('')
  250. }),
  251. url: this.config.url,
  252. params: {
  253. action: 'resource/trash/purge',
  254. ids: cs
  255. },
  256. listeners: {
  257. 'success': {
  258. fn: function (data) {
  259. this.getSelectionModel().clearSelections(true);
  260. this.refreshEverything(data.total);
  261. }, scope: this
  262. },
  263. 'error': {
  264. fn: function (data) {
  265. MODx.msg.status({
  266. title: _('error'),
  267. message: data.message
  268. });
  269. }, scope: this
  270. }
  271. }
  272. });
  273. return true;
  274. },
  275. restoreSelected: function () {
  276. var cs = this.getSelectedAsList();
  277. if (cs === false) return false;
  278. MODx.msg.confirm({
  279. title: _('trash.restore_confirm_title'),
  280. text: _('trash.restore_confirm_message', {
  281. 'list': this.listResources('')
  282. }),
  283. url: this.config.url,
  284. params: {
  285. action: 'resource/trash/restore',
  286. ids: cs
  287. },
  288. listeners: {
  289. 'success': {
  290. fn: function (data) {
  291. this.refreshEverything(data.total);
  292. }, scope: this
  293. },
  294. 'error': {
  295. fn: function (data) {
  296. MODx.msg.status({
  297. title: _('error'),
  298. message: data.message
  299. });
  300. }, scope: this
  301. }
  302. }
  303. });
  304. return true;
  305. },
  306. purgeAll: function () {
  307. var sm = this.getSelectionModel();
  308. sm.selectAll();
  309. var cs = this.getSelectedAsList();
  310. if (cs === false) return false;
  311. MODx.msg.confirm({
  312. title: _('trash.purge_confirm_title'),
  313. text: _('trash.purge_all_confirm_message', {
  314. 'count': sm.selections.length,
  315. 'list': this.listResources('')
  316. }),
  317. url: this.config.url,
  318. params: {
  319. action: 'resource/trash/purge',
  320. // we can't just purge everything, because it might happen that in
  321. // the meantime something was deleted by another user which is not yet
  322. // shown in the trash manager list because of missing reload.
  323. // in that case we would purge something unreviewed/blindly.
  324. // therefore we have to pass all ids which are shown in our list here
  325. ids: cs
  326. },
  327. listeners: {
  328. 'success': {
  329. fn: function (data) {
  330. MODx.msg.status({
  331. title: _('success'),
  332. message: data.message
  333. });
  334. if (data.object.count_success > 0) {
  335. this.refreshEverything(data.total); // no need to refresh if nothing was purged
  336. this.fireEvent('emptyTrash');
  337. }
  338. }, scope: this
  339. },
  340. 'error': {
  341. fn: function (data) {
  342. MODx.msg.status({
  343. title: _('error'),
  344. message: data.message
  345. });
  346. }, scope: this
  347. }
  348. }
  349. })
  350. },
  351. restoreAll: function () {
  352. var sm = this.getSelectionModel();
  353. sm.selectAll();
  354. var cs = this.getSelectedAsList();
  355. if (cs === false) return false;
  356. MODx.msg.confirm({
  357. title: _('trash.restore_confirm_title'),
  358. text: _('trash.restore_all_confirm_message', {
  359. 'count': sm.selections.length,
  360. 'list': this.listResources('')
  361. }),
  362. url: this.config.url,
  363. params: {
  364. action: 'resource/trash/restore',
  365. // we can't just restore everything, because it might happen that in
  366. // the meantime something was deleted by another user which is not yet
  367. // shown in the trash manager list because of missing reload.
  368. // in that case we would restore something unreviewed/blindly.
  369. // therefore we have to pass all ids which are shown in our list here
  370. ids: cs
  371. },
  372. listeners: {
  373. 'success': {
  374. fn: function (data) {
  375. MODx.msg.status({
  376. title: _('success'),
  377. message: data.message
  378. });
  379. if (data.object.count_success > 0) {
  380. this.refreshEverything(data.total); // no need to refresh if nothing was purged
  381. this.fireEvent('emptyTrash');
  382. }
  383. }, scope: this
  384. },
  385. 'error': {
  386. fn: function (data) {
  387. MODx.msg.status({
  388. title: _('error'),
  389. message: data.message
  390. });
  391. }, scope: this
  392. }
  393. }
  394. })
  395. },
  396. refreshTree: function () {
  397. var t = Ext.getCmp('modx-resource-tree');
  398. t.refresh();
  399. this.refreshRecycleBinButton();
  400. },
  401. refreshEverything: function (total) {
  402. this.refresh();
  403. this.refreshTree();
  404. this.refreshRecycleBinButton(total);
  405. },
  406. refreshRecycleBinButton: function (total) {
  407. var t = Ext.getCmp('modx-resource-tree');
  408. var trashButton = t.getTopToolbar().findById('emptifier');
  409. if (total !== undefined) {
  410. // if no resource is deleted, we disable the icon.
  411. // otherwise we have to update the tooltip
  412. if (total = 0) {
  413. trashButton.disable();
  414. trashButton.setTooltip(_('trash.manage_recycle_bin_tooltip'));
  415. } else {
  416. trashButton.enable();
  417. trashButton.setTooltip(_('trash.manage_recycle_bin_tooltip', total));
  418. }
  419. }
  420. },
  421. listResources: function (separator) {
  422. separator = separator || '';
  423. // creates a textual representation of the selected resources
  424. // we create a textlist of the resources here to show them again in the confirmation box
  425. var selections = this.getSelectionModel().getSelections();
  426. var text = [], t;
  427. selections.forEach(function (selection) {
  428. //t = selection.data.pagetitle + " (" + selection.data.id + ")";
  429. t = selection.data.parentPath + "<strong>" + selection.data.pagetitle + " (" + selection.data.id + ")" + "</strong>";
  430. if (selection.data.published) {
  431. t = '<em>' + t + '</em>';
  432. }
  433. t = "<div style='white-space:nowrap'>" + t + "</div>";
  434. text.push(t);
  435. });
  436. return text.join(separator);
  437. },
  438. renderTooltip: function (value, metadata, record) {
  439. if (value) {
  440. var preview = ((record.json.pagetitle) ? '<p><strong>' + _('pagetitle') + ':</strong> ' + record.json.pagetitle + '</p>' : '')
  441. + ((record.json.longtitle) ? '<p><strong>' + _('long_title') + ':</strong> ' + record.json.longtitle + '</p>' : '')
  442. + ((record.data.parentPath) ? '<p><strong>' + _('trash.parent_path') + ':</strong> ' + record.data.parentPath + '</p>' : '')
  443. + ((record.json.content) ? '<p><strong>' + _('content') + ':</strong> ' + Ext.util.Format.ellipsis(record.json.content.replace(/<\/?[^>]+>/gi, ''), 100) + '</p>' : '');
  444. preview = Ext.util.Format.htmlEncode(preview);
  445. return '<div ext:qtip="' + preview + '">' + value + '</div>';
  446. } else {
  447. return '';
  448. }
  449. }
  450. });
  451. Ext.reg('modx-grid-trash', MODx.grid.Trash);