idTree.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. /**
  2. * Created by Mai on 2017/3/17.
  3. */
  4. var idTree = {
  5. createNew: function (setting) {
  6. var _setting = {
  7. id: 'id',
  8. pid: 'pid',
  9. nid: 'nid',
  10. rootId: -1
  11. };
  12. var tools = {
  13. findNode: function (nodes, check) {
  14. for (var i = 0; i < nodes.length; i++) {
  15. if (check(nodes[i])) {
  16. return nodes[i];
  17. }
  18. }
  19. return null;
  20. },
  21. reSortNodes: function (nodes, recursive) {
  22. var temp = [], first;
  23. var findFirstNode = function (nodes) {
  24. return tools.findNode(nodes, function (node) {
  25. return node.preSibling === null;
  26. });
  27. };
  28. var moveNode = function (node, orgArray, newArray, newIndex) {
  29. var next;
  30. orgArray.splice(orgArray.indexOf(node), 1);
  31. newArray.splice(newIndex, 0, node);
  32. if (node.getNextSiblingID() !== -1) {
  33. next = node.nextSibling;
  34. if (next && (orgArray.indexOf(next) >= 0)) {
  35. moveNode(next, orgArray, newArray, newIndex + 1);
  36. }
  37. }
  38. };
  39. if (nodes.length === 0) {
  40. return nodes;
  41. }
  42. if (recursive) {
  43. nodes.forEach(function (node) {
  44. node.children = tools.reSortNodes(node.children, recursive);
  45. });
  46. }
  47. while (nodes.length > 0) {
  48. first = findFirstNode(nodes);
  49. first = first ? first : nodes[0];
  50. moveNode(first, nodes, temp, temp.length);
  51. }
  52. nodes = null;
  53. tools.reSiblingNodes(temp);
  54. return temp;
  55. },
  56. reSiblingNodes: function (nodes) {
  57. var i;
  58. for (i = 0; i < nodes.length; i++) {
  59. nodes[i].preSibling = (i === 0) ? null : nodes[i - 1];
  60. nodes[i].nextSibling = (i === nodes.length - 1) ? null : nodes[i + 1];
  61. }
  62. },
  63. // 在nodes中,从iIndex(包括)开始全部移除
  64. removeNodes: function (tree, parent, iIndex, count) {
  65. var children = parent ? parent.children : tree.roots;
  66. var pre = (iIndex < 0 || iIndex >= children.length) ? null : children[iIndex].preSibling;
  67. var next = (pre && iIndex + count - 1 < children.length) ? children[iIndex + count] : null;
  68. if (pre) {
  69. pre.nextSibling = next;
  70. }
  71. if (next) {
  72. next.preSibling = pre;
  73. }
  74. if (arguments.length === 4) {
  75. children.splice(iIndex, count);
  76. } else {
  77. children.splice(iIndex, children.length - iIndex);
  78. }
  79. },
  80. // 在nodes中增加addNodes, 位置从index开始
  81. addNodes: function (tree, parent, nodes, iIndex) {
  82. var children = parent ? parent.children : tree.roots;
  83. var pre, next, i;
  84. if (nodes.length === 0) { return; }
  85. if (arguments.length === 4) {
  86. pre = (iIndex <= 0 || iIndex > children.length) ? null : children[iIndex - 1];
  87. next = pre ? pre.nextSibling : null;
  88. } else if (arguments.length === 3) {
  89. pre = children.length === 0 ? null : children[children.length - 1];
  90. next = null;
  91. }
  92. if (pre) {
  93. pre.nextSibling = nodes[0];
  94. }
  95. nodes[0].preSibling = pre;
  96. if (next) {
  97. next.preSibling = nodes[nodes.length - 1];
  98. }
  99. nodes[nodes.length - 1].nextSibling = next;
  100. for (i = 0; i < nodes.length; i++) {
  101. if (arguments.length === 4) {
  102. children.splice(iIndex + i, 0, nodes[i]);
  103. } else if (arguments.length === 3) {
  104. children.push(nodes[i]);
  105. }
  106. nodes[i].parent = parent;
  107. }
  108. },
  109. sortTreeItems: function (tree) {
  110. var addItems = function (items) {
  111. var i;
  112. for (i = 0; i < items.length; i++) {
  113. tree.items.push(items[i]);
  114. addItems(items[i].children);
  115. }
  116. };
  117. tree.items.splice(0, tree.items.length);
  118. addItems(tree.roots);
  119. }
  120. };
  121. var Node = function (tree, data) {
  122. // 以下的属性,本单元外均不可直接修改
  123. this.tree = tree;
  124. this.data = data;
  125. this.children = [];
  126. this.parent = null;
  127. this.nextSibling = null;
  128. this.preSibling = null;
  129. this.expanded = true;
  130. this.visible = true;
  131. this.visible = true;
  132. this.isUpdate = false;
  133. this.isNew = false;
  134. };
  135. Node.prototype.getID = function () {
  136. return this.data[this.tree.setting.id];
  137. };
  138. Node.prototype.getParentID = function () {
  139. return this.parent ? this.parent.getID() : -1;
  140. };
  141. Node.prototype.getNextSiblingID = function () {
  142. return this.nextSibling ? this.nextSibling.getID() : -1;
  143. };
  144. Node.prototype.firstChild = function () {
  145. return this.children.length === 0 ? null : this.children[0];
  146. };
  147. Node.prototype.depth = function () {
  148. return this.parent ? this.parent.depth() + 1 : 0;
  149. };
  150. Node.prototype.isFirst = function () {
  151. if (this.parent) {
  152. return this.parent.children.indexOf(this) === 0 ? true : false;
  153. } else {
  154. return this.tree.roots.indexOf(this) === 0 ? true : false;
  155. }
  156. };
  157. Node.prototype.isLast = function () {
  158. if (this.parent) {
  159. return this.parent.children.indexOf(this) === this.parent.children.length - 1 ? true : false;
  160. } else {
  161. return this.tree.roots.indexOf(this) === this.tree.roots.length - 1 ? true : false;
  162. }
  163. };
  164. Node.prototype.siblingIndex = function () {
  165. return this.parent ? this.parent.children.indexOf(this) : this.tree.roots.indexOf(this);
  166. }
  167. Node.prototype.posterityCount = function () {
  168. var iCount = 0;
  169. if (this.children.length !== 0) {
  170. iCount += this.children.length;
  171. this.children.forEach(function (child) {
  172. iCount += child.posterityCount();
  173. });
  174. }
  175. return iCount;
  176. /*return (node.children.length === 0) ? 0 : node.children.reduce(function (x, y) {
  177. return x.posterityCount() + y.posterityCount();
  178. }) + node.children.count;*/
  179. };
  180. Node.prototype.setExpanded = function (expanded) {
  181. var setNodesVisible = function (nodes, visible) {
  182. nodes.forEach(function (node) {
  183. node.visible = visible;
  184. setNodesVisible(node.children, visible && node.expanded);
  185. })
  186. };
  187. this.expanded = expanded;
  188. setNodesVisible(this.children, expanded);
  189. };
  190. /*Node.prototype.vis = function () {
  191. return this.parent ? this.parent.vis() && this.parent.expanded() : true;
  192. };*/
  193. Node.prototype.serialNo = function () {
  194. return this.tree.items.indexOf(this);
  195. }
  196. /*Node.prototype.serialNo = function () {
  197. if (this.preSibling) {
  198. return this.preSibling.serialNo() + this.preSibling.posterityCount() + 1;
  199. } else if (this.parent) {
  200. return this.parent.serialNo() + 1;
  201. } else {
  202. return 0;
  203. }
  204. };*/
  205. Node.prototype.addChild = function (node) {
  206. var preSibling = this.children.length === 0 ? null : this.children[this.children.length - 1];
  207. node.parent = this;
  208. if (preSibling) {
  209. preSibling.nextSibling = node;
  210. }
  211. node.preSibling = preSibling;
  212. this.children.push(node);
  213. };
  214. Node.prototype.removeChild = function (node) {
  215. var preSibling = node.preSibling, nextSibling = node.nextSibling;
  216. if (preSibling) {
  217. preSibling.nextSibling = nextSibling;
  218. }
  219. if (nextSibling) {
  220. nextSibling.preSibling = preSibling;
  221. }
  222. this.children.splice(this.children.re)
  223. };
  224. Node.prototype.canUpLevel = function () {
  225. return this.parent ? true : false;
  226. };
  227. Node.prototype.canDownLevel = function () {
  228. return !this.isFirst();
  229. };
  230. Node.prototype.canUpMove = function () {
  231. return !this.isFirst();
  232. };
  233. Node.prototype.canDownMove = function () {
  234. return !this.isLast();
  235. }
  236. Node.prototype.upLevel = function () {
  237. var success = false,
  238. iIndex = this.parent.children.indexOf(this), orgParent = this.parent, newNextSibling = this.parent.nextSibling;
  239. if (this.canUpLevel) {
  240. // NextSiblings become child
  241. tools.addNodes(this.tree, this, this.parent.children.slice(iIndex + 1));
  242. // Orginal Parent remove node and nextSiblings
  243. tools.removeNodes(this.tree, this.parent, iIndex);
  244. // New Parent add node
  245. tools.addNodes(this.tree, this.parent.parent, [this], this.parent.siblingIndex() + 1);
  246. if (!this.expanded) {
  247. this.setExpanded(true);
  248. }
  249. success = true;
  250. }
  251. return success;
  252. };
  253. Node.prototype.downLevel = function () {
  254. var success = false, iIndex = this.parent ? this.parent.children.indexOf(this) : this.tree.roots.indexOf(this);
  255. var newParent = this.preSibling;
  256. if (this.canDownLevel()) {
  257. tools.removeNodes(this.tree, this.parent, this.siblingIndex(), 1);
  258. tools.addNodes(this.tree, this.preSibling, [this]);
  259. if (!newParent.expanded) {
  260. newParent.setExpanded(true);
  261. }
  262. success = true;
  263. }
  264. return success;
  265. };
  266. Node.prototype.upMove = function () {
  267. var success = false;
  268. var iIndex = this.siblingIndex(), belongArray = this.parent ? this.parent.children : this.tree.roots, orgPre = this.preSibling;
  269. if (this.canUpMove()) {
  270. orgPre.nextSibling = this.nextSibling;
  271. this.preSibling = orgPre.preSibling;
  272. orgPre.preSibling = this;
  273. this.nextSibling = orgPre;
  274. belongArray.splice(iIndex, 1);
  275. belongArray.splice(iIndex - 1, 0, this);
  276. tools.sortTreeItems(this.tree);
  277. success = true;
  278. }
  279. return success;
  280. };
  281. Node.prototype.downMove = function () {
  282. var success = false;
  283. var iIndex = this.siblingIndex(), belongArray = this.parent ? this.parent.children : this.tree.roots, orgNext = this.nextSibling;
  284. if (this.canDownMove()) {
  285. orgNext.preSibling = this.preSibling;
  286. this.nextSibling = orgNext.nextSibling;
  287. orgNext.nextSibling = this;
  288. this.preSibling = orgNext;
  289. belongArray.splice(iIndex, 1);
  290. belongArray.splice(iIndex + 1, 0, this);
  291. tools.sortTreeItems(this.tree);
  292. success = true;
  293. }
  294. return success;
  295. }
  296. var Tree = function (setting) {
  297. this.nodes = {};
  298. this.roots = [];
  299. this.items = [];
  300. this.setting = setting;
  301. this.prefix = 'id_';
  302. this.selected = null;
  303. };
  304. Tree.prototype.maxNodeID = (function () {
  305. var maxID = 0;
  306. return function (ID) {
  307. if (arguments.length === 0) {
  308. return maxID;
  309. } else {
  310. maxID = Math.max(maxID, ID);
  311. }
  312. };
  313. })();
  314. Tree.prototype.rangeNodeID = (function () {
  315. var rangeID = -1;
  316. return function (ID) {
  317. if (arguments.length === 0) {
  318. return rangeID;
  319. } else {
  320. rangeID = Math.max(rangeID, ID);
  321. }
  322. }
  323. })();
  324. Tree.prototype.newNodeID = function () {
  325. if (this.rangeNodeID() === -1) {
  326. return this.maxNodeID() + 1;
  327. } else {
  328. if (this.maxNodeID() >= this.rangeNodeID()) {
  329. return this.maxNodeID() + 1;
  330. } else {
  331. return -1;
  332. }
  333. }
  334. /*if (this.maxID >= this.rangeNodeID() || this.rangeNodeID === -1) {
  335. return -1;
  336. } else {
  337. return this.maxNodeID() + 1;
  338. }*/
  339. };
  340. Tree.prototype.loadDatas = function (datas) {
  341. var prefix = this.prefix, i, node, parent, next, that = this;
  342. // prepare index
  343. datas.forEach(function (data) {
  344. var node = new Node(that, data);
  345. that.nodes[prefix + data[that.setting.id]] = node;
  346. that.maxNodeID(data[that.setting.id]);
  347. });
  348. // set parent by pid, set nextSibling by nid
  349. datas.forEach(function (data) {
  350. node = that.nodes[prefix + data[that.setting.id]];
  351. if (data[that.setting.pid] === that.setting.rootId) {
  352. that.roots.push(node);
  353. } else {
  354. parent = that.nodes[prefix + data[that.setting.pid]];
  355. if (parent) {
  356. node.parent = parent;
  357. parent.children.push(node);
  358. }
  359. }
  360. if (data[that.setting.nid] !== that.setting.rootId) {
  361. next = that.nodes[prefix + data[that.setting.nid]];
  362. if (next) {
  363. node.nextSibling = next;
  364. next.preSibling = node;
  365. }
  366. }
  367. })
  368. // sort by nid
  369. this.roots = tools.reSortNodes(this.roots, true);
  370. tools.sortTreeItems(this);
  371. };
  372. Tree.prototype.firstNode = function () {
  373. return this.roots.length === 0 ? null : this.roots[0];
  374. };
  375. Tree.prototype.findNode = function (id) {
  376. return this.nodes[this.prefix + id];
  377. };
  378. Tree.prototype.count = function () {
  379. var iCount = 0;
  380. if (this.roots.length !== 0) {
  381. iCount += this.roots.length;
  382. this.roots.forEach(function (node) {
  383. iCount += node.posterityCount();
  384. });
  385. }
  386. return iCount;
  387. };
  388. Tree.prototype.insert = function (parentID, nextSiblingID) {
  389. var newID = this.newNodeID(), node = null, data = {};
  390. var parent = parentID === -1 ? null : this.nodes[this.prefix + parentID];
  391. var nextSibling = nextSiblingID === -1 ? null: this.nodes[this.prefix + nextSiblingID];
  392. if (newID !== -1) {
  393. data = {};
  394. data[this.setting.id] = newID;
  395. data[this.setting.pid] = parentID;
  396. data[this.setting.nid] = nextSiblingID;
  397. node = new Node(this, data);
  398. if (nextSibling) {
  399. tools.addNodes(this, parent, [node], nextSibling.siblingIndex());
  400. } else {
  401. tools.addNodes(this, parent, [node]);
  402. }
  403. this.nodes[this.prefix + newID] = node;
  404. tools.sortTreeItems(this);
  405. this.maxNodeID(newID);
  406. }
  407. return node;
  408. };
  409. Tree.prototype.delete = function (node) {
  410. var success = false;
  411. if (node) {
  412. delete this.nodes[this.prefix + node.getID()];
  413. if (node.preSibling) {
  414. node.preSibling.nextSibling = node.nextSibling;
  415. }
  416. if (node.nextSibling) {
  417. node.nextSibling.preSibling = node.preSibling;
  418. }
  419. if (node.parent) {
  420. node.parent.children.splice(node.siblingIndex(), 1);
  421. } else {
  422. this.roots.splice(node.siblingIndex(), 1);
  423. }
  424. tools.sortTreeItems(this);
  425. success = true;
  426. }
  427. return success;
  428. }
  429. return new Tree(setting);
  430. }
  431. };