Ext.lingo.JsonTree.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /*
  2. * Ext JS Library 2.0.2
  3. * Copyright(c) 2006-2008, Ext JS, LLC.
  4. * licensing@extjs.com
  5. *
  6. * http://www.extjs.com/license
  7. *
  8. * @author Lingo
  9. * @since 2008-03-23
  10. * http://code.google.com/p/anewssystem/
  11. */
  12. Ext.namespace("Ext.lingo");
  13. /**
  14. * 拥有CRUD功能的树形.
  15. *
  16. * @param config 需要的配置{}
  17. */
  18. Ext.lingo.JsonTree = Ext.extend(Ext.tree.TreePanel, {
  19. autoScroll: true,
  20. initComponent: function() {
  21. Ext.applyIf(this, {
  22. rootName: '分类',
  23. urlGetAllTree: "getAllTree.do",
  24. urlInsertTree: "insertTree.do",
  25. urlRemoveTree: "removeTree.do",
  26. urlSortTree: "sortTree.do",
  27. urlLoadData: "loadData.do",
  28. urlUpdateTree: "updateTree.do"
  29. });
  30. var loader = new Ext.tree.TreeLoader({
  31. dataUrl: this.urlGetAllTree
  32. })
  33. var root = new Ext.tree.AsyncTreeNode({
  34. text : this.rootName,
  35. draggable : this.draggable,
  36. id : '-1'
  37. });
  38. Ext.applyIf(this, {
  39. root: root,
  40. loader: loader,
  41. tbar: this.buildToolbar()
  42. });
  43. Ext.lingo.JsonTree.superclass.initComponent.call(this);
  44. // DEL快捷键,删除节点
  45. this.setupDeleteKey();
  46. // 自动排序
  47. if (this.folderSort) {
  48. new Ext.tree.TreeSorter(this, {folderSort:true});
  49. }
  50. this.buildEditor();
  51. this.buildContextMenu();
  52. this.buildDragDrop();
  53. //
  54. this.on('render', function() {
  55. this.loadMask = new Ext.LoadMask(this.bwrap, {
  56. store: loader
  57. });
  58. }, this);
  59. },
  60. setupDeleteKey: function() {
  61. // DEL快捷键,删除节点
  62. //this.on(Ext.EventObject.DELETE, this.removeNode);
  63. this.on('render', function() {
  64. this.body.on('keyup', function(e) {
  65. if(e.getKey() == e.DELETE) {
  66. this.removeNode();
  67. }
  68. }, this);
  69. }, this);
  70. },
  71. buildToolbar: function() {
  72. var toolbar = [{
  73. text : '新增下级分类',
  74. iconCls : 'add',
  75. tooltip : '添加选中节点的下级分类',
  76. handler : this.createChild.createDelegate(this)
  77. }, {
  78. text : '新增同级分类',
  79. iconCls : 'go',
  80. tooltip : '添加选中节点的同级分类',
  81. handler : this.createBrother.createDelegate(this)
  82. }, {
  83. text : '修改分类',
  84. iconCls : 'edit',
  85. tooltip : '修改选中分类',
  86. handler : this.updateNode.createDelegate(this)
  87. }, {
  88. text : '删除分类',
  89. iconCls : 'delete',
  90. tooltip : '删除一个分类',
  91. handler : this.removeNode.createDelegate(this)
  92. }, '-', {
  93. text : '保存排序',
  94. iconCls : 'save',
  95. tooltip : '保存排序结果',
  96. handler : this.save.createDelegate(this)
  97. }, '-', {
  98. text : '展开',
  99. iconCls : 'expand',
  100. tooltip : '展开所有分类',
  101. handler : this.expandAll.createDelegate(this)
  102. }, {
  103. text : '合拢',
  104. iconCls : 'collapse',
  105. tooltip : '合拢所有分类',
  106. handler : this.collapseAll.createDelegate(this)
  107. }, {
  108. text : '刷新',
  109. iconCls : 'refresh',
  110. tooltip : '刷新所有节点',
  111. handler : this.refresh.createDelegate(this)
  112. }];
  113. return toolbar;
  114. },
  115. buildEditor: function() {
  116. var treeEditor = new Ext.tree.TreeEditor(this, {
  117. allowBlank : false,
  118. blankText : '请添写名称',
  119. selectOnFocus : true
  120. });
  121. this.treeEditor = treeEditor;
  122. treeEditor.on('beforestartedit', function() {
  123. var node = this.treeEditor.editNode;
  124. if(!node.attributes.allowEdit) {
  125. return false;
  126. } else {
  127. node.attributes.oldText = node.text;
  128. }
  129. }.createDelegate(this));
  130. treeEditor.on('complete', function(editor, value, startValue) {
  131. var node = this.treeEditor.editNode;
  132. // 如果节点没有改变,就向服务器发送修改信息
  133. if (startValue == value) {
  134. return true;
  135. }
  136. var item = {
  137. id : node.id,
  138. text : value,
  139. parentId : node.parentNode.id
  140. };
  141. var params = 'id=' + node.id + '&name=' + value + '&parentId=' + node.parentNode.id;
  142. this.el.mask('提交数据,请稍候...', 'x-mask-loading');
  143. var hide = this.el.unmask.createDelegate(this.el);
  144. var doSuccess = function(responseObject) {
  145. eval("var o = " + responseObject.responseText + ";");
  146. this.treeEditor.editNode.id = o.info.id;
  147. hide();
  148. }.createDelegate(this);
  149. Ext.lib.Ajax.request(
  150. 'POST',
  151. this.urlInsertTree,
  152. {success:doSuccess,failure:hide},
  153. params
  154. );
  155. }.createDelegate(this));
  156. },
  157. buildContextMenu: function() {
  158. // 右键菜单
  159. this.on('contextmenu', this.prepareContext);
  160. this.contextMenu = new Ext.menu.Menu({
  161. id : 'copyCtx',
  162. items : [{
  163. id : 'createChild',
  164. handler : this.createChild.createDelegate(this),
  165. iconCls : 'add',
  166. text : '新增下级节点'
  167. },{
  168. id : 'createBrother',
  169. handler : this.createBrother.createDelegate(this),
  170. iconCls : 'go',
  171. text : '新增同级节点'
  172. },{
  173. id : 'updateNode',
  174. handler : this.updateNode.createDelegate(this),
  175. iconCls : 'edit',
  176. text : '修改节点'
  177. },{
  178. id : 'remove',
  179. handler : this.removeNode.createDelegate(this),
  180. iconCls : 'delete',
  181. text : '删除节点'
  182. },'-',{
  183. id : 'expand',
  184. handler : this.expandAll.createDelegate(this),
  185. iconCls : 'expand',
  186. text : '展开'
  187. },{
  188. id : 'collapse',
  189. handler : this.collapseAll.createDelegate(this),
  190. iconCls : 'collapse',
  191. text : '合拢'
  192. },{
  193. id : 'refresh',
  194. handler : this.refresh.createDelegate(this),
  195. iconCls : 'refresh',
  196. text : '刷新'
  197. },{
  198. id : 'config',
  199. iconCls : 'config',
  200. handler : this.configInfo.createDelegate(this),
  201. text : '详细配置'
  202. }]
  203. });
  204. },
  205. buildDragDrop: function() {
  206. // 拖拽判断
  207. this.on("nodedragover", function(e){
  208. var n = e.target;
  209. if (n.leaf) {
  210. n.leaf = false;
  211. }
  212. return true;
  213. });
  214. // 拖拽后,就向服务器发送消息,更新数据
  215. // 本人不喜欢这种方式
  216. if (this.dropUpdate) {
  217. this.on('nodedrop', function(e) {
  218. var n = e.dropNode;
  219. var item = {
  220. id : n.id,
  221. text : n.text,
  222. parentId : e.target.id
  223. };
  224. this.el.mask('提交数据,请稍候...', 'x-mask-loading');
  225. var hide = this.el.unmask.createDelegate(this.el);
  226. Ext.lib.Ajax.request(
  227. 'POST',
  228. this.urlInsertTree,
  229. {success:hide,failure:hide},
  230. 'data=' + encodeURIComponent(Ext.encode(item))
  231. );
  232. });
  233. } else {
  234. this.on('nodedrop', function(e) {
  235. var n = e.dropNode;
  236. n.ui.textNode.style.fontWeight = "bold";
  237. n.ui.textNode.style.color = "red";
  238. n.ui.textNode.style.border = "1px red dotted";
  239. });
  240. }
  241. },
  242. createChild : function() {
  243. var sm = this.getSelectionModel();
  244. var n = sm.getSelectedNode();
  245. if (!n) {
  246. n = this.getRootNode();
  247. } else {
  248. n.expand(false, false);
  249. }
  250. this.createNode(n);
  251. },
  252. createBrother : function() {
  253. var n = this.getSelectionModel().getSelectedNode();
  254. if (!n) {
  255. Ext.Msg.alert('提示', "请选择一个节点");
  256. } else if (n == this.getRootNode()) {
  257. Ext.Msg.alert('提示', "不能为根节点增加同级节点");
  258. } else {
  259. this.createNode(n.parentNode);
  260. }
  261. },
  262. createNode : function(n) {
  263. var node = n.appendChild(new Ext.tree.TreeNode({
  264. id : Ext.id(),
  265. text : '请输入分类名',
  266. cls : 'album-node',
  267. allowDrag : true,
  268. allowDelete : true,
  269. allowEdit : true,
  270. allowChildren : true
  271. }));
  272. this.getSelectionModel().select(node);
  273. setTimeout(function(){
  274. this.treeEditor.editNode = node;
  275. this.treeEditor.startEdit(node.ui.textNode);
  276. }.createDelegate(this), 10);
  277. },
  278. updateNode: function() {
  279. var n = this.getSelectionModel().getSelectedNode();
  280. if (!n) {
  281. Ext.Msg.alert('提示', "请选择一个节点");
  282. } else if (n == this.getRootNode()) {
  283. Ext.Msg.alert('提示', "不能修改根节点");
  284. } else {
  285. setTimeout(function(){
  286. this.treeEditor.editNode = n;
  287. this.treeEditor.startEdit(n.ui.textNode);
  288. }.createDelegate(this), 10);
  289. }
  290. },
  291. removeNode: function() {
  292. var sm = this.getSelectionModel();
  293. var n = sm.getSelectedNode();
  294. if (n == null) {
  295. Ext.Msg.alert('提示', "请选择一个节点");
  296. } else if(n.attributes.allowDelete) {
  297. Ext.Msg.confirm("提示", "是否确定删除?", function(btn, text) {
  298. if (btn == 'yes') {
  299. this.getSelectionModel().selectPrevious();
  300. this.el.mask('提交数据,请稍候...', 'x-mask-loading');
  301. // var hide = this.treePanel.el.unmask.createDelegate(this.treePanel.el);
  302. var hide = function() {
  303. this.el.unmask(this.el);
  304. n.parentNode.removeChild(n);
  305. }.createDelegate(this);
  306. Ext.lib.Ajax.request(
  307. 'POST',
  308. this.urlRemoveTree,
  309. {success:hide,failure:hide},
  310. 'id=' + n.id
  311. );
  312. }
  313. }.createDelegate(this));
  314. } else {
  315. Ext.Msg.alert("提示", "这个节点不能删除");
  316. }
  317. },
  318. appendNode: function(node, array) {
  319. if (!node || node.childNodes.length < 1) {
  320. return;
  321. }
  322. for (var i = 0; i < node.childNodes.length; i++) {
  323. var child = node.childNodes[i];
  324. array.push({id:child.id,parentId:child.parentNode.id});
  325. this.appendNode(child, array);
  326. }
  327. },
  328. save: function() {
  329. // 向数据库发送一个json数组,保存排序信息
  330. this.el.mask('提交数据,请稍候...', 'x-mask-loading');
  331. // var hide = this.treePanel.el.unmask.createDelegate(this.treePanel.el);
  332. var hide = function() {
  333. this.el.unmask(this.el);
  334. this.refresh();
  335. }.createDelegate(this);
  336. var ch = [];
  337. this.appendNode(this.root, ch);
  338. Ext.lib.Ajax.request(
  339. 'POST',
  340. this.urlSortTree,
  341. {success:hide,failure:hide},
  342. 'data=' + encodeURIComponent(Ext.encode(ch))
  343. );
  344. },
  345. collapseAll: function() {
  346. this.contextMenu.hide();
  347. setTimeout(function() {
  348. var node = this.getSelectedNode();
  349. if (node == null) {
  350. this.getRootNode().eachChild(function(n) {
  351. n.collapse(true, false);
  352. });
  353. } else {
  354. node.collapse(true, false);
  355. }
  356. }.createDelegate(this), 10);
  357. },
  358. expandAll: function() {
  359. this.contextMenu.hide();
  360. setTimeout(function() {
  361. var node = this.getSelectedNode();
  362. if (node == null) {
  363. this.getRootNode().eachChild(function(n) {
  364. n.expand(false, false);
  365. });
  366. } else {
  367. node.expand(false, false);
  368. }
  369. }.createDelegate(this), 10);
  370. },
  371. prepareContext: function(node, e) {
  372. node.select();
  373. if (this.contextMenu.items.get('remove')) {
  374. this.contextMenu.items.get('remove')[node.attributes.allowDelete ? 'enable' : 'disable']();
  375. }
  376. if (this.contextMenu.items.get('updateNode')) {
  377. this.contextMenu.items.get('updateNode')[node.attributes.allowEdit ? 'enable' : 'disable']();
  378. }
  379. if (this.contextMenu.items.get('expand')) {
  380. this.contextMenu.items.get('expand')[node.attributes.leaf ? 'disable' : 'enable']();
  381. }
  382. if (this.contextMenu.items.get('collapse')) {
  383. this.contextMenu.items.get('collapse')[node.attributes.leaf ? 'disable' : 'enable']();
  384. }
  385. this.contextMenu.showAt(e.getXY());
  386. },
  387. refresh: function() {
  388. this.root.reload();
  389. this.root.expand(false, false);
  390. },
  391. configInfo: function() {
  392. if (!this.dialog) {
  393. this.createDialog();
  394. }
  395. var n = this.getSelectedNode();
  396. this.dialog.show(this.getSelectionModel().getSelectedNode().ui.textNode);
  397. this.formPanel.load({
  398. url: this.urlLoadData + "?id=" + n.id
  399. });
  400. },
  401. // 生成对话框
  402. createDialog : function() {
  403. var reader = new Ext.data.JsonReader({}, this.formConfig);
  404. this.formPanel = new Ext.form.FormPanel({
  405. defaultType: 'textfield',
  406. labelAlign: 'right',
  407. labelWidth: 70,
  408. frame: true,
  409. autoScroll: true,
  410. title: '详细信息',
  411. reader: reader,
  412. url: this.urlUpdateTree,
  413. items: this.formConfig,
  414. buttons: [{
  415. text: '确定',
  416. handler: function() {
  417. this.formPanel.getForm().submit({
  418. waitTitle: "请稍候",
  419. waitMsg : '正在提交......',
  420. success: function() {
  421. this.dialog.hide();
  422. this.refresh();
  423. }.createDelegate(this),
  424. failure: function() {
  425. }
  426. });
  427. }.createDelegate(this)
  428. },{
  429. text: '取消',
  430. handler: function() {
  431. this.dialog.hide();
  432. }.createDelegate(this)
  433. }]
  434. });
  435. this.dialog = new Ext.Window({
  436. layout: 'fit',
  437. width: this.dlgWidth ? this.dlgWidth : 400,
  438. height: this.dlgHeight ? this.dlgHeight : 300,
  439. closeAction: 'hide',
  440. items: [this.formPanel]
  441. });
  442. },
  443. // 返回当前选中的节点,可能为null
  444. getSelectedNode: function() {
  445. return this.getSelectionModel().getSelectedNode();
  446. },
  447. onDestroy : function(){
  448. if(this.rendered){
  449. if (this.contextMenu) {
  450. this.contextMenu.destroy();
  451. }
  452. if (this.dialog) {
  453. this.dialog.destroy();
  454. }
  455. }
  456. Ext.lingo.JsonTree.superclass.onDestroy.call(this);
  457. }
  458. });