tree_table.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * Created by MaiXinRong on 2017/2/9.
  3. * 项目管理 专用树结构
  4. */
  5. (function($) {
  6. var _setting = {
  7. tree: {
  8. id: 'ID',
  9. pid: 'ParentID',
  10. nid: 'NextSiblingID',
  11. btnColumn: 1,
  12. nullId: -1
  13. },
  14. columns: [
  15. {
  16. head: '工程列表',
  17. data: 'name',
  18. static: false,
  19. width: '100%',
  20. event: {
  21. getText: null,
  22. getIcon: null
  23. }
  24. }
  25. ],
  26. dataTemp: {
  27. id: -1,
  28. parentId: -1,
  29. nextId: -1,
  30. isTemp: true
  31. },
  32. viewEvent: {
  33. beforeSelect: null,
  34. onSelectNode: null
  35. }
  36. };
  37. var Node = (function () {
  38. function Node(tree, data) {
  39. this.parent = null;
  40. this.nextSibling = null;
  41. this.children = [];
  42. this.tree = tree;
  43. this.data = data;
  44. this.setting = tree.setting;
  45. this.expanded = true;
  46. this.row = null;
  47. this.expandBtn = null;
  48. }
  49. Node.prototype.firstChild = function() {
  50. return (this.children.length === 0) ? null : this.children[0];
  51. };
  52. Node.prototype.lastChild = function () {
  53. return (this.children.length === 0) ? null : this.children[this.children.length - 1];
  54. }
  55. Node.prototype.deepestRow = function () {
  56. return (this.children.length === 0) ? this.row : this.lastChild().deepestRow();
  57. }
  58. Node.prototype.addChild = function (child, childNext) {
  59. if (childNext){
  60. this.children.push(child);
  61. } else {
  62. if (this.childIndex(childNext) > -1){
  63. this.children.splice(this.childIndex(childNext) - 1, 0, child);
  64. } else {
  65. this.children.push(child);
  66. }
  67. }
  68. return child;
  69. };
  70. Node.prototype.childIndex = function (child) {
  71. return this.children.indexOf(child);
  72. };
  73. Node.prototype.depth = function () {
  74. return this.parent ? this.parent.depth() + 1 : 0;
  75. };
  76. Node.prototype.domId = function () {
  77. return this.data ? this.tree.domId + '_' + this.data[this.setting.tree.id] : '';
  78. };
  79. Node.prototype.expand = function (bool) {
  80. this.expanded = bool;
  81. _view._refreshTreeBtn(this);
  82. if (this.expanded) {
  83. _view._showNodes(this.children);
  84. } else {
  85. _view._hideNodes(this.children);
  86. }
  87. };
  88. Node.prototype.preSibling = function () {
  89. var iIndex = this.parent.childIndex(this);
  90. if (iIndex === -1){
  91. return null;
  92. } else {
  93. return iIndex > 0 ? this.parent.children[iIndex-1] : null;
  94. }
  95. };
  96. Node.prototype.setParent = function (parent) {
  97. if (parent && this.parent !== parent) {
  98. this.parent = parent;
  99. this.data[this.setting.tree.pid] = this.pid();
  100. }
  101. };
  102. Node.prototype.setNextSibling = function (nextSibling) {
  103. if (this.nextSibling !== nextSibling) {
  104. this.nextSibling = nextSibling;
  105. this.data[this.setting.tree.nid] = this.nid();
  106. }
  107. }
  108. Node.prototype.id = function () {
  109. return this.data ? this.data[this.setting.tree.id] : -1;
  110. };
  111. Node.prototype.pid = function () {
  112. return this.parent ? this.parent.id() : -1;
  113. };
  114. Node.prototype.nid = function () {
  115. return this.nextSibling ? this.nextSibling.id() : -1;
  116. };
  117. Node.prototype.propertyJoin = function (dataName) {
  118. return this.parent ? this.parent.propertyJoin(dataName) + ';' + this.data[dataName] : this.data[dataName];
  119. }
  120. return Node;
  121. })();
  122. var Tree = (function () {
  123. function Tree(obj, setting) {
  124. this._root = new Node(this);
  125. this.treeObj = obj;
  126. this.domId = obj.attr('id');
  127. this.treeHeadObj = _view._makeTableHead(this.treeObj, setting);
  128. this.treeBodyObj = _view._makeTableBody(this.treeObj);
  129. this.setting = setting;
  130. var _maxNodeId = 0;
  131. this.newNodeId = function (id) {
  132. if (arguments.length > 0){
  133. _maxNodeId = (id > _maxNodeId) ? id : _maxNodeId;
  134. } else {
  135. _maxNodeId += 1;
  136. return _maxNodeId;
  137. }
  138. };
  139. this.maxNodeId = function (id){
  140. if (arguments.length > 0) {
  141. _maxNodeId = Math.max(id, _maxNodeId);
  142. } else {
  143. return _maxNodeId;
  144. }
  145. }
  146. };
  147. Tree.prototype.firstNode = function (){
  148. return this._root.firstChild();
  149. };
  150. Tree.prototype.traverseDF = function(callback){
  151. var recurse = function (node) {
  152. var i;
  153. if (node !== this._root) {
  154. callback(node);
  155. }
  156. for (i = 0; i < node.children.length; i++){
  157. recurse(node.children[i]);
  158. }
  159. }
  160. recurse(this._root);
  161. };
  162. Tree.prototype.findNode = function (id){
  163. var treenode = null,
  164. callback = function (node) {
  165. if (node.data && node.data[node.setting.tree.id] === id){
  166. treenode = node;
  167. }
  168. };
  169. this.traverseDF.call(this, callback);
  170. return treenode;
  171. };
  172. Tree.prototype.findNodeByNid = function (nid) {
  173. let treenode = null,
  174. callback = function (node) {
  175. if(node.data && node.data[node.setting.tree.nid] === nid){
  176. treenode = node;
  177. }
  178. };
  179. this.traverseDF.call(this, callback);
  180. return treenode;
  181. }
  182. Tree.prototype.findNodeByDomId = function (domId) {
  183. var treenode = null,
  184. callback = function (node) {
  185. if (node.domId === domId) {
  186. treenode = node;
  187. }
  188. };
  189. this.traverseDF.call(this, callback);
  190. return treenode;
  191. };
  192. Tree.prototype.removeNode = function (node) {
  193. var iIndex;
  194. if (node) {
  195. iIndex = node.parent.childIndex(node);
  196. if (iIndex > 0) {
  197. node.parent.children[iIndex - 1].setNextSibling(node.nextSibling);
  198. }
  199. node.parent.children.splice(iIndex, 1);
  200. }
  201. _view._removeNodesRowDom([node]);
  202. };
  203. /*Tree.prototype.loadData = function (arrData) {
  204. var i, that = this;
  205. var createTempNode = function (id, setting) {
  206. var tempData = {};
  207. tempData[setting.tree.id] = id;
  208. return new Node(that, tempData);
  209. };
  210. var loadNode = function (data, setting) {//mark
  211. var node = that.findNode(data[setting.tree.id]) || null,
  212. parent = that.findNode(data[setting.tree.pid]) || null,
  213. next = that.findNode(data[setting.tree.nid]) || null,
  214. tempData;
  215. if (!node) {
  216. node = new Node(that, data);
  217. }
  218. node.data = data;
  219. that.maxNodeId(node.id());
  220. if (!parent){
  221. if (data[setting.tree.pid] === setting.tree.nullId) {
  222. parent = that._root;
  223. } else {
  224. parent = createTempNode(data[setting.tree.pid], setting);
  225. parent.parent = that._root;
  226. that._root.children.push(parent);
  227. }
  228. }
  229. if (node.parent && node.parent !== parent) {
  230. node.parent.children.splice(node.parent.childIndex(node), 1);
  231. }
  232. node.parent = parent;
  233. if (!next && data[setting.tree.nid] !== setting.tree.nullId) {
  234. next = createTempNode(data[setting.tree.nid], setting);
  235. next.parent = parent;
  236. parent.children.push(next);
  237. }
  238. node.nextSibling = next;
  239. if (parent.childIndex(node) === -1){
  240. if (!next){
  241. parent.children.push(node);
  242. } else if (parent.childIndex(next) === -1){
  243. parent.children.push(node);
  244. parent.children.push(next);
  245. } else {
  246. parent.children.splice(parent.childIndex(next), 0, node);
  247. }
  248. } else if (node.nextSibling && parent.childIndex(node) !== parent.childIndex(node.nextSibling) - 1) {
  249. parent.children.splice(parent.childIndex(next), 1);
  250. parent.children.splice(parent.childIndex(node) + 1, 0, next);
  251. };
  252. let pre = that.findNodeByNid(node.data.ID) || null;
  253. if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){
  254. parent.children.splice(parent.childIndex(pre), 1);
  255. parent.children.splice(parent.childIndex(node), 0, pre);
  256. }
  257. };
  258. for (i = 0; i < arrData.length; i++){
  259. loadNode(arrData[i], this.setting);
  260. }
  261. };*/
  262. Tree.prototype.loadData = function (arrData) {
  263. let i, that = this;
  264. let nodesIndex = {};
  265. function getPreNode(id){
  266. for(let index in nodesIndex){
  267. let node = nodesIndex[index];
  268. if(node['data'][node.setting.tree.nid] === id){
  269. return node;
  270. }
  271. }
  272. return null;
  273. }
  274. function loadNode (data, setting) {//mark
  275. var node = nodesIndex[data[setting.tree.id]] || null,
  276. parent = nodesIndex[data[setting.tree.pid]] || that._root,
  277. next = nodesIndex[data[setting.tree.nid]] || null,
  278. pre = getPreNode(data[setting.tree.id]) || null,
  279. tempData;
  280. if (!node) {
  281. node = new Node(that, data);
  282. }
  283. that.maxNodeId(node.id());
  284. if(parent.childIndex(node) === -1){
  285. if(pre && parent.childIndex(pre) !== -1){
  286. parent.children.splice(parent.childIndex(pre) + 1, 0, node);
  287. }
  288. else if(next && parent.childIndex(next) !== -1){
  289. parent.children.splice(parent.childIndex(next), 0, node);
  290. }
  291. else {
  292. parent.children.push(node);
  293. }
  294. }
  295. if(pre && parent.childIndex(pre) === -1){
  296. parent.children.splice(parent.childIndex(node), 0, pre);
  297. }
  298. if(next && parent.childIndex(next) === -1){
  299. parent.children.splice(parent.childIndex(node) + 1, 0, next);
  300. }
  301. if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){
  302. parent.children.splice(parent.childIndex(pre), 1);
  303. parent.children.splice(parent.childIndex(node), 0, pre);
  304. }
  305. if(next && parent.childIndex(next) !== parent.childIndex(node) + 1){
  306. parent.children.splice(parent.childIndex(next), 1);
  307. parent.children.splice(parent.childIndex(node) + 1, 0, next);
  308. }
  309. node.parent = parent;
  310. node.nextSibling = next;
  311. }
  312. //建立索引
  313. for(let data of arrData){
  314. nodesIndex[data.ID] = new Node(that, data);
  315. }
  316. for (i = 0; i < arrData.length; i++){
  317. loadNode(arrData[i], this.setting);
  318. }
  319. };
  320. Tree.prototype.refreshNodesDom = function (nodes, recurse){
  321. var that = this;
  322. nodes.forEach(function (node) {
  323. if (node.row) {
  324. $('td', node.row).remove();
  325. _view._makeTableRowCells(node.row, node);
  326. } else if (node !== that._root) {
  327. _view._makeRowDom(that.treeBodyObj, node);
  328. }
  329. if (recurse) {
  330. that.refreshNodesDom(node.children, recurse);
  331. }
  332. })
  333. };
  334. Tree.prototype.refreshTreeDom = function () {
  335. this.refreshNodesDom(this._root.children, true);
  336. };
  337. Tree.prototype.addNodeData = function (data, parent, nextSibling) {
  338. var node = null;
  339. var pNode = parent ? parent : this._root;
  340. if (!nextSibling || (nextSibling.parent === pNode && pNode.childIndex(nextSibling) > -1)) {
  341. node = new Node(this, data);
  342. this.maxNodeId(data[this.setting.tree.id]);
  343. node.row = _view._makeRowDom(this.treeBodyObj, node);
  344. this.move(node, pNode, nextSibling);
  345. }
  346. return node;
  347. }
  348. Tree.prototype.move = function(node, parent, nextSibling) {
  349. var iIndex = -1, pre;
  350. if (parent && (!nextSibling || (nextSibling.parent === parent && parent.childIndex(nextSibling) > -1))) {
  351. if (node) {
  352. if (node.parent) {
  353. iIndex = node.parent.childIndex(node);
  354. if (iIndex > 0) {
  355. node.parent.children[iIndex - 1].setNextSibling(node.nextSibling);
  356. }
  357. node.parent.children.splice(iIndex, 1);
  358. this.refreshNodesDom([node.parent], false);
  359. }
  360. if (nextSibling) {
  361. iIndex = parent.childIndex(nextSibling);
  362. if (iIndex > 0){
  363. pre = parent.children[iIndex - 1];
  364. pre.setNextSibling(node);
  365. //parent.children.splice(iIndex - 1, 0, node);
  366. parent.children.splice(iIndex, 0, node);
  367. } else {
  368. parent.children.splice(0, 0, node);
  369. }
  370. } else {
  371. if (parent.children.length > 0){
  372. pre = parent.lastChild();
  373. pre.setNextSibling(node);
  374. }
  375. parent.children.push(node);
  376. }
  377. node.setParent(parent);
  378. node.setNextSibling(nextSibling);
  379. if (node.row) {
  380. if (pre) {
  381. _view._moveRowDom(node, pre.deepestRow());
  382. } else if (parent.id() !== this.setting.tree.nullId) {
  383. _view._moveRowDom(node, parent.row);
  384. } else if (nextSibling) {
  385. _view._moveRowDomBefore(node, nextSibling.row);
  386. }
  387. }
  388. if (node.parent.row) {
  389. this.refreshNodesDom([node.parent], false);
  390. }
  391. }
  392. } else {
  393. this.e.throw('Error: information of moving node has mistake.');
  394. }
  395. };
  396. Tree.prototype.selected = (function () {
  397. var selectNode = null;
  398. var select = function (node) {
  399. if (arguments.length === 0) {
  400. return selectNode;
  401. } else {
  402. if (node) {
  403. if (selectNode && selectNode.row) {
  404. selectNode.row.removeClass('table-active');
  405. }
  406. selectNode = node;
  407. node.row.addClass('table-active');
  408. }
  409. }
  410. }
  411. return select;
  412. })();
  413. return Tree;
  414. })();
  415. _data = {
  416. clone: function (obj) {
  417. if (obj === null) return null;
  418. var o = _data.isArray(obj) ? [] : {};
  419. for (var i in obj) {
  420. o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? _data.clone(obj[i]) : obj[i]);
  421. }
  422. return o;
  423. },
  424. isArray: function (arr) {
  425. return Object.prototype.toString.apply(arr) === "[object Array]";
  426. }
  427. },
  428. _event = {
  429. _selectProj: function (node) {
  430. if (node.setting.viewEvent.beforeSelect) {
  431. node.setting.viewEvent.beforeSelect(node.tree.selected());
  432. }
  433. node.tree.selected(node);
  434. if (node.setting.viewEvent.onSelectNode) {
  435. node.setting.viewEvent.onSelectNode(node);
  436. }
  437. }
  438. }
  439. _view = {
  440. _makeTableHeadCell: function (obj, col){
  441. var th;
  442. th = $('<th>');
  443. th.attr('width', col.width);
  444. th.text(col.head);
  445. obj.append(th);
  446. },
  447. _makeTableHead: function (obj, setting){
  448. var thead, tr, i;
  449. thead = $('<thead>');
  450. tr = $('<tr>');
  451. for (i = 0; i < setting.columns.length; i++){
  452. _view._makeTableHeadCell(tr, setting.columns[i]);
  453. }
  454. thead.append(tr);
  455. obj.append(thead);
  456. return thead;
  457. },
  458. _makeTableBody: function (obj){
  459. var tbody;
  460. tbody = $('<tbody>');
  461. obj.append(tbody);
  462. return tbody;
  463. },
  464. _makeTableRowCell: function (obj, node, columns, index) {
  465. var html = [], td, i, url;
  466. html.push('<td ');
  467. if (index === node.setting.tree.btnColumn){
  468. html.push('class=', 'in-', node.depth().toString(), '>');
  469. if (node.children.length !== 0) {
  470. html.push('<a href="#" class="tree-open" title="收起"><i class="fa fa-minus-square-o mr-1"></i></a>');
  471. } else {
  472. html.push('<a href="#" class="tree-open" title="收起"><i></i></a>');
  473. }
  474. } else {
  475. html.push('>');
  476. }
  477. if (columns.event.getIcon) {
  478. columns.event.getIcon(html, node);
  479. }
  480. if (columns.name !== '') {
  481. if (columns.event.getText) {
  482. columns.event.getText(html, node, node.data[columns.data]);
  483. } else {
  484. html.push(node.data[columns.name]);
  485. }
  486. }
  487. html.push('</td>');
  488. td = $(html.join(''));
  489. if (index === node.setting.tree.btnColumn) {
  490. node.expandBtn = $('.tree-open>.fa', td);
  491. node.expandBtn.bind('click', {node: node}, function(e){
  492. e.data.node.expand(!e.data.node.expanded);
  493. });
  494. node.icon = $('.tree-icon', td);
  495. }
  496. if (columns.event.tdBindEvent) {
  497. columns.event.tdBindEvent(td, node);
  498. }
  499. obj.append(td);
  500. return td;
  501. },
  502. _makeTableRowCells: function (obj, node) {
  503. for (i = 0; i < node.setting.columns.length; i++){
  504. _view._makeTableRowCell(obj, node, node.setting.columns[i], i);
  505. }
  506. },
  507. _makeRowDom: function (obj, node) {
  508. var tr, i;
  509. tr = $('<tr>');
  510. obj.append(tr);
  511. tr.attr('id', node.domId());
  512. node.row = tr;
  513. _view._makeTableRowCells(tr, node);
  514. tr.click(function(){
  515. _event._selectProj(node);
  516. });
  517. /*$(tr).draggable({
  518. helper: "clone",
  519. opacity: .75,
  520. refreshPositions: true, // Performance?
  521. revert: "invalid",
  522. revertDuration: 300,
  523. scroll: true
  524. });
  525. tr.droppable({
  526. drop: function (e, ui) {
  527. var target = node.tree.findNodeByDomId($(this).attr('id')),
  528. drag = node.tree.findNodeByDomId($(ui).attr('id'));
  529. tree.move(drag, target);
  530. }
  531. }); */
  532. return tr;
  533. },
  534. _moveRowDomBefore: function (node, destination) {
  535. var moveNodesRowDomBefore = function (nodes) {
  536. nodes.forEach(function (node) {
  537. node.row.insertBefore(destination);
  538. moveNodesRowDomBefore(node.children);
  539. });
  540. }
  541. moveNodesRowDomBefore([node]);
  542. _view._refreshNodesLevelCss([node]);
  543. },
  544. _moveRowDom: function (node, destination) {
  545. var pre = destination,
  546. moveNodeRowDom = function (node) {
  547. node.row.insertAfter(pre);
  548. pre = node.row;
  549. moveChildrenRowDom(node);
  550. },
  551. moveChildrenRowDom = function(node){
  552. var i;
  553. for (i = 0; i < node.children.length; i++){
  554. moveNodeRowDom(node.children[i]);
  555. }
  556. };
  557. moveNodeRowDom(node);
  558. _view._refreshNodesLevelCss([node]);
  559. },
  560. _refreshTreeBtn: function (node) {
  561. var i;
  562. if (node.children.length === 0) {
  563. node.expandBtn.hide();
  564. } else {
  565. node.expandBtn.show();
  566. if (node.expanded) {
  567. node.expandBtn.removeClass('fa-plus-square-o');
  568. node.expandBtn.addClass('fa-minus-square-o');
  569. } else {
  570. node.expandBtn.removeClass('fa-minus-square-o');
  571. node.expandBtn.addClass('fa-plus-square-o');
  572. }
  573. }
  574. },
  575. _refreshNodesLevelCss: function (nodes) {
  576. nodes.forEach(function(node){
  577. var td = $('td:eq(' + node.setting.tree.btnColumn.toString() + ')', node.row);
  578. td.attr('class', 'in-'+ node.depth().toString());
  579. _view._refreshNodesLevelCss(node.children);
  580. })
  581. },
  582. _hideNodes: function (nodes) {
  583. var i, node;
  584. for (i = 0; i < nodes.length; i++){
  585. node = nodes[i];
  586. node.row.hide();
  587. _view._hideNodes(node.children);
  588. }
  589. },
  590. _showNodes: function (nodes) {
  591. var i, node;
  592. for (i = 0; i < nodes.length; i++){
  593. node = nodes[i];
  594. node.row.show();
  595. if (node.expanded) {
  596. _view._showNodes(node.children);
  597. }
  598. }
  599. },
  600. _removeNodesRowDom: function (nodes) {
  601. var i, node;
  602. for (i = 0; i < nodes.length; i++){
  603. node = nodes[i];
  604. _view._removeNodesRowDom(node.children);
  605. if (node.row) {
  606. node.row.remove();
  607. }
  608. }
  609. }
  610. };
  611. $.fn.treeTable = {
  612. init: function(obj, setting, arrData){
  613. var _treeSetting, _tree;
  614. _treeSetting = _data.clone(_setting);
  615. $.extend(true, _treeSetting, setting);
  616. var _tree = new Tree(obj, _treeSetting);
  617. _tree.loadData(arrData);
  618. _tree.refreshTreeDom();
  619. return _tree;
  620. }
  621. }
  622. })(jQuery);