modx.tree.element.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /**
  2. * Generates the Element Tree
  3. *
  4. * @class MODx.tree.Element
  5. * @extends MODx.tree.Tree
  6. * @param {Object} config An object of options.
  7. * @xtype modx-tree-element
  8. */
  9. MODx.tree.Element = function(config) {
  10. config = config || {};
  11. Ext.applyIf(config,{
  12. rootVisible: false
  13. ,enableDD: !Ext.isEmpty(MODx.config.enable_dragdrop) ? true : false
  14. ,ddGroup: 'modx-treedrop-elements-dd'
  15. ,title: ''
  16. ,url: MODx.config.connector_url
  17. ,action: 'element/getnodes'
  18. ,sortAction: 'element/sort'
  19. ,useDefaultToolbar: false
  20. ,baseParams: {
  21. currentElement: MODx.request.id || 0
  22. ,currentAction: MODx.request.a || 0
  23. }
  24. ,tbar: [{
  25. cls: 'tree-new-template'
  26. ,tooltip: {text: _('new')+' '+_('template')}
  27. ,handler: function() {
  28. this.redirect('?a=element/template/create');
  29. }
  30. ,scope: this
  31. ,hidden: MODx.perm.new_template ? false : true
  32. },{
  33. cls: 'tree-new-tv'
  34. ,tooltip: {text: _('new')+' '+_('tv')}
  35. ,handler: function() {
  36. this.redirect('?a=element/tv/create');
  37. }
  38. ,scope: this
  39. ,hidden: MODx.perm.new_tv ? false : true
  40. },{
  41. cls: 'tree-new-chunk'
  42. ,tooltip: {text: _('new')+' '+_('chunk')}
  43. ,handler: function() {
  44. this.redirect('?a=element/chunk/create');
  45. }
  46. ,scope: this
  47. ,hidden: MODx.perm.new_chunk ? false : true
  48. },{
  49. cls: 'tree-new-snippet'
  50. ,tooltip: {text: _('new')+' '+_('snippet')}
  51. ,handler: function() {
  52. this.redirect('?a=element/snippet/create');
  53. }
  54. ,scope: this
  55. ,hidden: MODx.perm.new_snippet ? false : true
  56. },{
  57. cls: 'tree-new-plugin'
  58. ,tooltip: {text: _('new')+' '+_('plugin')}
  59. ,handler: function() {
  60. this.redirect('?a=element/plugin/create');
  61. }
  62. ,scope: this
  63. ,hidden: MODx.perm.new_plugin ? false : true
  64. },{
  65. cls: 'tree-new-category'
  66. ,tooltip: {text: _('new_category')}
  67. ,handler: function() {
  68. this.createCategory(null,{target: this.getEl()});
  69. }
  70. ,scope: this
  71. ,hidden: MODx.perm.new_category ? false : true
  72. }]
  73. });
  74. MODx.tree.Element.superclass.constructor.call(this,config);
  75. this.on('afterSort',this.afterSort);
  76. };
  77. Ext.extend(MODx.tree.Element,MODx.tree.Tree,{
  78. forms: {}
  79. ,windows: {}
  80. ,stores: {}
  81. ,createCategory: function(n,e) {
  82. var r = {};
  83. if (this.cm.activeNode && this.cm.activeNode.attributes.data) {
  84. r['parent'] = this.cm.activeNode.attributes.data.id;
  85. }
  86. var w = MODx.load({
  87. xtype: 'modx-window-category-create'
  88. ,record: r
  89. ,listeners: {
  90. success: {
  91. fn: function() {
  92. var node = (this.cm.activeNode) ? this.cm.activeNode.id : 'n_category'
  93. ,self = node.indexOf('_category_') !== -1;
  94. this.refreshNode(node, self);
  95. }
  96. ,scope: this
  97. }
  98. ,hide: {
  99. fn: function() {
  100. this.destroy();
  101. }
  102. }
  103. }
  104. });
  105. w.show(e.target);
  106. }
  107. ,renameCategory: function(itm,e) {
  108. var r = this.cm.activeNode.attributes.data;
  109. var w = MODx.load({
  110. xtype: 'modx-window-category-rename'
  111. ,record: r
  112. ,listeners: {
  113. 'success':{fn:function(r) {
  114. var c = r.a.result.object;
  115. var n = this.cm.activeNode;
  116. n.setText(c.category+' ('+c.id+')');
  117. Ext.get(n.getUI().getEl()).frame();
  118. n.attributes.data.id = c.id;
  119. n.attributes.data.category = c.category;
  120. },scope:this}
  121. ,'hide':{fn:function() {this.destroy();}}
  122. }
  123. });
  124. w.show(e.target);
  125. }
  126. ,removeCategory: function(itm,e) {
  127. var id = this.cm.activeNode.attributes.data.id;
  128. MODx.msg.confirm({
  129. title: _('warning')
  130. ,text: _('category_confirm_delete')
  131. ,url: MODx.config.connector_url
  132. ,params: {
  133. action: 'element/category/remove'
  134. ,id: id
  135. }
  136. ,listeners: {
  137. 'success': {fn:function() {
  138. this.cm.activeNode.remove();
  139. },scope:this}
  140. }
  141. });
  142. }
  143. ,duplicateElement: function(itm,e,id,type) {
  144. MODx.Ajax.request({
  145. url: MODx.config.connector_url
  146. ,params: {
  147. action: 'element/' + type + '/get'
  148. ,id: id
  149. }
  150. ,listeners: {
  151. 'success': {fn:function(results) {
  152. var r = {
  153. id: id
  154. ,type: type
  155. ,name: _('duplicate_of',{name: this.cm.activeNode.attributes.name})
  156. ,caption: _('duplicate_of',{name: this.cm.activeNode.attributes.caption})
  157. ,category: results.object.category
  158. ,source: results.object.source
  159. ,static: results.object.static
  160. ,static_file: results.object.static_file
  161. };
  162. var w = MODx.load({
  163. xtype: 'modx-window-element-duplicate'
  164. ,record: r
  165. ,listeners: {
  166. 'success': {fn:function() {this.refreshNode(this.cm.activeNode.id);},scope:this}
  167. ,'hide':{fn:function() {this.destroy();}}
  168. }
  169. });
  170. w.show(e.target);
  171. },scope:this}
  172. }
  173. });
  174. }
  175. ,removeElement: function(itm,e) {
  176. var id = this.cm.activeNode.id.substr(2);
  177. var oar = id.split('_');
  178. MODx.msg.confirm({
  179. title: _('warning')
  180. ,text: _('remove_this_confirm',{
  181. type: _(oar[0])
  182. ,name: this.cm.activeNode.attributes.name
  183. })
  184. ,url: MODx.config.connector_url
  185. ,params: {
  186. action: 'element/'+oar[0]+'/remove'
  187. ,id: oar[2]
  188. }
  189. ,listeners: {
  190. 'success': {fn:function() {
  191. this.cm.activeNode.remove();
  192. /* if editing the element being removed */
  193. if (MODx.request.a == 'element/'+oar[0]+'/update' && MODx.request.id == oar[2]) {
  194. MODx.loadPage('welcome');
  195. }
  196. },scope:this}
  197. }
  198. });
  199. }
  200. ,activatePlugin: function(itm,e) {
  201. var id = this.cm.activeNode.id.substr(2);
  202. var oar = id.split('_');
  203. MODx.Ajax.request({
  204. url: MODx.config.connector_url
  205. ,params: {
  206. action: 'element/plugin/activate'
  207. ,id: oar[2]
  208. }
  209. ,listeners: {
  210. 'success': {fn:function() {
  211. this.refreshParentNode();
  212. },scope:this}
  213. }
  214. });
  215. }
  216. ,deactivatePlugin: function(itm,e) {
  217. var id = this.cm.activeNode.id.substr(2);
  218. var oar = id.split('_');
  219. MODx.Ajax.request({
  220. url: MODx.config.connector_url
  221. ,params: {
  222. action: 'element/plugin/deactivate'
  223. ,id: oar[2]
  224. }
  225. ,listeners: {
  226. 'success': {fn:function() {
  227. this.refreshParentNode();
  228. },scope:this}
  229. }
  230. });
  231. }
  232. ,quickCreate: function(itm,e,type) {
  233. var r = {
  234. category: this.cm.activeNode.attributes.pk || ''
  235. };
  236. var w = MODx.load({
  237. xtype: 'modx-window-quick-create-'+type
  238. ,record: r
  239. ,listeners: {
  240. success: {
  241. fn: function() {
  242. this.refreshNode(this.cm.activeNode.id, true);
  243. }
  244. ,scope: this
  245. }
  246. ,hide: {
  247. fn: function() {
  248. this.destroy();
  249. }
  250. }
  251. }
  252. });
  253. w.setValues(r);
  254. w.show(e.target);
  255. }
  256. ,quickUpdate: function(itm,e,type) {
  257. MODx.Ajax.request({
  258. url: MODx.config.connector_url
  259. ,params: {
  260. action: 'element/'+type+'/get'
  261. ,id: this.cm.activeNode.attributes.pk
  262. }
  263. ,listeners: {
  264. 'success': {fn:function(r) {
  265. var nameField = (type == 'template') ? 'templatename' : 'name';
  266. var w = MODx.load({
  267. xtype: 'modx-window-quick-update-'+type
  268. ,record: r.object
  269. ,listeners: {
  270. 'success':{fn:function(r) {
  271. this.refreshNode(this.cm.activeNode.id);
  272. var newTitle = '<span dir="ltr">' + r.f.findField(nameField).getValue() + ' (' + w.record.id + ')</span>';
  273. w.setTitle(w.title.replace(/<span.*\/span>/, newTitle));
  274. },scope:this}
  275. ,'hide':{fn:function() {this.destroy();}}
  276. }
  277. });
  278. w.title += ': <span dir="ltr">' + w.record[nameField] + ' ('+ w.record.id + ')</span>';
  279. w.setValues(r.object);
  280. w.show(e.target);
  281. },scope:this}
  282. }
  283. });
  284. }
  285. ,_createElement: function(itm,e,t) {
  286. var id = this.cm.activeNode.id.substr(2);
  287. var oar = id.split('_');
  288. var type = oar[0] == 'type' ? oar[1] : oar[0];
  289. var cat_id = oar[0] == 'type' ? 0 : (oar[1] == 'category' ? oar[2] : oar[3]);
  290. var a = 'element/'+type+'/create';
  291. this.redirect('?a='+a+'&category='+cat_id);
  292. this.cm.hide();
  293. return false;
  294. }
  295. ,afterSort: function(o) {
  296. var tn = o.event.target.attributes;
  297. if (tn.type == 'category') {
  298. var dn = o.event.dropNode.attributes;
  299. if (tn.id != 'n_category' && dn.type == 'category') {
  300. o.event.target.expand();
  301. } else {
  302. this.refreshNode(o.event.target.attributes.id,true);
  303. this.refreshNode('n_type_'+o.event.dropNode.attributes.type,true);
  304. }
  305. }
  306. }
  307. ,_handleDrop: function(e) {
  308. var target = e.target;
  309. if (e.point == 'above' || e.point == 'below') {return false;}
  310. if (target.attributes.classKey != 'modCategory' && target.attributes.classKey != 'root') { return false; }
  311. if (!this.isCorrectType(e.dropNode,target)) {return false;}
  312. if (target.attributes.type == 'category' && e.point == 'append') {return true;}
  313. return target.getDepth() > 0;
  314. }
  315. ,isCorrectType: function(dropNode,targetNode) {
  316. var r = false;
  317. /* types must be the same */
  318. if(targetNode.attributes.type == dropNode.attributes.type) {
  319. /* do not allow anything to be dropped on an element */
  320. if(!(targetNode.parentNode &&
  321. ((dropNode.attributes.cls == 'folder'
  322. && targetNode.attributes.cls == 'folder'
  323. && dropNode.parentNode.id == targetNode.parentNode.id
  324. ) || targetNode.attributes.cls == 'file'))) {
  325. r = true;
  326. }
  327. }
  328. return r;
  329. }
  330. /**
  331. * Shows the current context menu.
  332. * @param {Ext.tree.TreeNode} n The current node
  333. * @param {Ext.EventObject} e The event object run.
  334. */
  335. ,_showContextMenu: function(n,e) {
  336. this.cm.activeNode = n;
  337. this.cm.removeAll();
  338. if (n.attributes.menu && n.attributes.menu.items) {
  339. this.addContextMenuItem(n.attributes.menu.items);
  340. this.cm.show(n.getUI().getEl(),'t?');
  341. } else {
  342. var m = [];
  343. switch (n.attributes.classKey) {
  344. case 'root':
  345. m = this._getRootMenu(n);
  346. break;
  347. case 'modCategory':
  348. m = this._getCategoryMenu(n);
  349. break;
  350. default:
  351. m = this._getElementMenu(n);
  352. break;
  353. }
  354. this.addContextMenuItem(m);
  355. this.cm.showAt(e.xy);
  356. }
  357. e.stopEvent();
  358. }
  359. ,_getQuickCreateMenu: function(n,m) {
  360. var ui = n.getUI();
  361. var mn = [];
  362. var types = ['template','tv','chunk','snippet','plugin'];
  363. var t;
  364. for (var i=0;i<types.length;i++) {
  365. t = types[i];
  366. if (ui.hasClass('pnew_'+t)) {
  367. mn.push({
  368. text: _(t)
  369. ,scope: this
  370. ,type: t
  371. ,handler: function(itm,e) {
  372. this.quickCreate(itm,e,itm.type);
  373. }
  374. });
  375. }
  376. }
  377. m.push({
  378. text: _('quick_create')
  379. ,handler: function() {return false;}
  380. ,menu: {
  381. items: mn
  382. }
  383. });
  384. return m;
  385. }
  386. ,_getElementMenu: function(n) {
  387. var a = n.attributes;
  388. var ui = n.getUI();
  389. var m = [];
  390. m.push({
  391. text: '<b>'+a.text+'</b>'
  392. ,handler: function() { return false; }
  393. ,header: true
  394. });
  395. m.push('-');
  396. if (ui.hasClass('pedit')) {
  397. m.push({
  398. text: _('edit_'+a.type)
  399. ,type: a.type
  400. ,pk: a.pk
  401. ,handler: function(itm,e) {
  402. MODx.loadPage('element/'+itm.type+'/update',
  403. 'id='+itm.pk);
  404. }
  405. });
  406. m.push({
  407. text: _('quick_update_'+a.type)
  408. ,type: a.type
  409. ,handler: function(itm,e) {
  410. this.quickUpdate(itm,e,itm.type);
  411. }
  412. });
  413. if (a.classKey == 'modPlugin') {
  414. if (a.active) {
  415. m.push({
  416. text: _('plugin_deactivate')
  417. ,type: a.type
  418. ,handler: this.deactivatePlugin
  419. });
  420. } else {
  421. m.push({
  422. text: _('plugin_activate')
  423. ,type: a.type
  424. ,handler: this.activatePlugin
  425. });
  426. }
  427. }
  428. }
  429. if (ui.hasClass('pnew')) {
  430. m.push({
  431. text: _('duplicate_'+a.type)
  432. ,pk: a.pk
  433. ,type: a.type
  434. ,handler: function(itm,e) {
  435. this.duplicateElement(itm,e,itm.pk,itm.type);
  436. }
  437. });
  438. }
  439. if (ui.hasClass('pdelete')) {
  440. m.push({
  441. text: _('remove_'+a.type)
  442. ,handler: this.removeElement
  443. });
  444. }
  445. m.push('-');
  446. if (ui.hasClass('pnew')) {
  447. m.push({
  448. text: _('add_to_category_'+a.type)
  449. ,handler: this._createElement
  450. });
  451. }
  452. if (ui.hasClass('pnewcat')) {
  453. m.push({
  454. text: _('new_category')
  455. ,handler: this.createCategory
  456. });
  457. }
  458. return m;
  459. }
  460. ,_getCategoryMenu: function(n) {
  461. var a = n.attributes;
  462. var ui = n.getUI();
  463. var m = [];
  464. m.push({
  465. text: '<b>'+a.text+'</b>'
  466. ,handler: function() { return false; }
  467. ,header: true
  468. });
  469. m.push('-');
  470. if (ui.hasClass('pnewcat')) {
  471. m.push({
  472. text: _('category_create')
  473. ,handler: this.createCategory
  474. });
  475. }
  476. if (ui.hasClass('peditcat')) {
  477. m.push({
  478. text: _('category_rename')
  479. ,handler: this.renameCategory
  480. });
  481. }
  482. if (m.length > 2) {m.push('-');}
  483. if (a.elementType) {
  484. m.push({
  485. text: _('add_to_category_'+a.type)
  486. ,handler: this._createElement
  487. });
  488. }
  489. this._getQuickCreateMenu(n,m);
  490. if (ui.hasClass('pdelcat')) {
  491. m.push('-');
  492. m.push({
  493. text: _('category_remove')
  494. ,handler: this.removeCategory
  495. });
  496. }
  497. return m;
  498. }
  499. ,_getRootMenu: function(n) {
  500. var a = n.attributes;
  501. var ui = n.getUI();
  502. var m = [];
  503. if (ui.hasClass('pnew')) {
  504. m.push({
  505. text: _('new_'+a.type)
  506. ,handler: this._createElement
  507. });
  508. m.push({
  509. text: _('quick_create_'+a.type)
  510. ,type: a.type
  511. ,handler: function(itm,e) {
  512. this.quickCreate(itm,e,itm.type);
  513. }
  514. });
  515. }
  516. if (ui.hasClass('pnewcat')) {
  517. if (ui.hasClass('pnew')) {m.push('-');}
  518. m.push({
  519. text: _('new_category')
  520. ,handler: this.createCategory
  521. });
  522. }
  523. return m;
  524. }
  525. ,handleCreateClick: function(node){
  526. this.cm.activeNode = node;
  527. var type = this.cm.activeNode.id.substr(2).split('_');
  528. if (type[0] != 'category') {
  529. this._createElement(null, null, null);
  530. } else {
  531. this.createCategory(null, {target: this});
  532. }
  533. }
  534. });
  535. Ext.reg('modx-tree-element',MODx.tree.Element);