tabledragger.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. Trex.module("table resize dragger", function(editor, toolbar, sidebar, canvas) {
  2. canvas.observeJob(Trex.Ev.__IFRAME_LOAD_COMPLETE, function() {
  3. var wysiwygPanel = canvas.getPanel(Trex.Canvas.__WYSIWYG_MODE);
  4. var doc = wysiwygPanel.getDocument();
  5. var win = wysiwygPanel.getWindow();
  6. var body = doc.body;
  7. var MIN_WIDTH = 20;
  8. var w3cBoxModelWorks;
  9. var colDragger = $tom.collect(canvas.wysiwygEl, ".tx-table-col-resize-dragger");
  10. var rowDragger = $tom.collect(canvas.wysiwygEl, ".tx-table-row-resize-dragger");
  11. var isDragging = _FALSE;
  12. var currentTable, currentTD, currentLeftTD, currentRightTD;
  13. var currentLeftTDWidth, currentRightTDWidth, currentTDHeight;
  14. var currentTableWidth, currentPointX, currentPointY;
  15. var currentNode, currentDragger;
  16. var movingX, movingY;
  17. var leftTdArray, rightTdArray, topTdArray;
  18. var leftWidthArr, rightWidthArr, topHeightArr;
  19. var posiX, posiY, elem;
  20. var EDGE_TYPE = {
  21. TOP: "EDGE_TOP",
  22. BOTTOM: "EDGE_BOTTOM",
  23. LEFT: "EDGE_LEFT",
  24. RIGHT: "EDGE_RIGHT",
  25. NONE: "NONE"
  26. };
  27. var edgeType = EDGE_TYPE.NONE;
  28. var initDragger = function() {
  29. isDragging = _FALSE;
  30. currentNode = _NULL;
  31. currentDragger = _NULL;
  32. currentTable = currentTD = _NULL;
  33. currentLeftTD = currentRightTD = _NULL;
  34. rightTdArray = leftTdArray = topTdArray = _NULL;
  35. leftWidthArr = rightWidthArr = topHeightArr = _NULL;
  36. movingX = movingY = 0;
  37. currentTableWidth = currentPointX = currentPointY = 0;
  38. currentLeftTDWidth = currentRightTDWidth = currentTDHeight = 0;
  39. };
  40. var mouseDownHandler = function() {
  41. currentTable = $tom.find(currentNode, "table");
  42. if (currentTable == _NULL) {
  43. return _NULL;
  44. }
  45. isDragging = _TRUE;
  46. currentTableWidth = currentTable.offsetWidth;
  47. if (edgeType != EDGE_TYPE.NONE) {
  48. $tx.stop(elem);
  49. showDragger();
  50. }
  51. switch (edgeType) {
  52. case EDGE_TYPE.LEFT:
  53. makeTDArrForLeftEdge();
  54. startResizeCol();
  55. break;
  56. case EDGE_TYPE.RIGHT:
  57. makeTDArrForRightEdge();
  58. startResizeCol();
  59. break;
  60. case EDGE_TYPE.TOP:
  61. makeTDArrForTopEdge();
  62. startResizeRow();
  63. break;
  64. case EDGE_TYPE.BOTTOM:
  65. makeTDArrForBottomEdge();
  66. startResizeRow();
  67. break;
  68. }
  69. };
  70. var makeTDArrForLeftEdge = function() {
  71. var indexer = new Trex.TableUtil.Indexer(currentTable);
  72. var curBoundery = indexer.getBoundary(currentNode);
  73. if (curBoundery.left > 0) {
  74. leftTdArray = indexer.getTdArrHasRight(curBoundery.left - 1);
  75. rightTdArray = indexer.getTdArrHasLeft(curBoundery.left);
  76. }
  77. };
  78. var makeTDArrForRightEdge = function() {
  79. var indexer = new Trex.TableUtil.Indexer(currentTable);
  80. var curBoundery = indexer.getBoundary(currentNode);
  81. var colSize = indexer.getColSize();
  82. leftTdArray = indexer.getTdArrHasRight(curBoundery.right);
  83. if (curBoundery.right < colSize - 1) {
  84. rightTdArray = indexer.getTdArrHasLeft(curBoundery.right + 1);
  85. }
  86. };
  87. var makeTDArrForTopEdge = function() {
  88. var indexer = new Trex.TableUtil.Indexer(currentTable);
  89. var curBoundery = indexer.getBoundary(currentNode);
  90. topTdArray = indexer.getTdArrHasBottom(curBoundery.top - 1);
  91. };
  92. var makeTDArrForBottomEdge = function() {
  93. var indexer = new Trex.TableUtil.Indexer(currentTable);
  94. var curBoundery = indexer.getBoundary(currentNode);
  95. topTdArray = indexer.getTdArrHasTop(curBoundery.bottom);
  96. };
  97. var mouseupHandler = function() {
  98. switch (edgeType) {
  99. case EDGE_TYPE.LEFT:
  100. case EDGE_TYPE.RIGHT:
  101. stopResizeCol();
  102. break;
  103. case EDGE_TYPE.TOP:
  104. case EDGE_TYPE.BOTTOM:
  105. stopResizeRow();
  106. break;
  107. }
  108. };
  109. var mousemoveHandler = function() {
  110. if (isDragging) {
  111. currentDragger = getDragger();
  112. moveDraggingAction();
  113. }
  114. else {
  115. moveUnDraggingAction();
  116. }
  117. };
  118. var moveDraggingAction = function() {
  119. switch (edgeType) {
  120. case EDGE_TYPE.LEFT:
  121. case EDGE_TYPE.RIGHT:
  122. moveCalcResizeCol();
  123. break;
  124. case EDGE_TYPE.TOP:
  125. case EDGE_TYPE.BOTTOM:
  126. moveCalcResizeRow();
  127. break;
  128. }
  129. };
  130. var moveUnDraggingAction = function() {
  131. var td = $tom.find($tx.element(elem), "td");
  132. var isTxInfo = $tom.find(td, ".txc-info");
  133. if (td && !isTxInfo) {
  134. currentNode = td;
  135. edgeType = getEdgeType(currentNode);
  136. showDragger();
  137. }
  138. else {
  139. edgeType = EDGE_TYPE.NONE;
  140. showDragger();
  141. }
  142. };
  143. var getDragger = function() {
  144. var dragger = _NULL;
  145. switch (edgeType) {
  146. case EDGE_TYPE.LEFT:
  147. case EDGE_TYPE.RIGHT:
  148. dragger = colDragger;
  149. break;
  150. case EDGE_TYPE.TOP:
  151. case EDGE_TYPE.BOTTOM:
  152. dragger = rowDragger;
  153. break;
  154. }
  155. return dragger;
  156. };
  157. var startResizeCol = function() {
  158. isDragging = _TRUE;
  159. leftWidthArr = [];
  160. rightWidthArr = [];
  161. var i = 0;
  162. if (leftTdArray) {
  163. for (i = 0; i < leftTdArray.length; i++) {
  164. leftWidthArr.push(leftTdArray[i].offsetWidth);
  165. }
  166. currentLeftTDWidth = minimumOfArray(leftWidthArr);
  167. for (i = 0; i < leftTdArray.length; i++) {
  168. if (currentLeftTDWidth == leftWidthArr[i]) {
  169. currentLeftTD = leftTdArray[i];
  170. break;
  171. }
  172. }
  173. }
  174. if (rightTdArray) {
  175. for (i = 0; i < rightTdArray.length; i++) {
  176. rightWidthArr.push(rightTdArray[i].offsetWidth);
  177. }
  178. currentRightTDWidth = minimumOfArray(rightWidthArr);
  179. for (i = 0; i < rightTdArray.length; i++) {
  180. if (currentRightTDWidth == rightWidthArr[i]) {
  181. currentRightTD = rightTdArray[i];
  182. break;
  183. }
  184. }
  185. }
  186. currentPointX = $tx.getCoordsTarget(currentDragger).left;
  187. };
  188. var moveCalcResizeCol = function() {
  189. if (isDragging) {
  190. var distX = parseInt(posiX - $tom.getScrollLeft(doc) - currentPointX);
  191. var left;
  192. if (currentLeftTD && currentRightTD) {
  193. left = calcMiddleCol(currentLeftTD, distX);
  194. }
  195. if (currentLeftTD && currentRightTD == _NULL) {
  196. left = calcLeft(currentLeftTD, distX)
  197. }
  198. if (currentLeftTD == _NULL && currentRightTD) {
  199. left = calcRight(currentRightTD, distX);
  200. }
  201. if (left) {
  202. $tx.setStyle(currentDragger, {
  203. "left": left.toPx()
  204. });
  205. }
  206. }
  207. };
  208. var calcMiddleCol = function(currentLeftTD, distX) {
  209. var bothWidth, movingLeftWidth, movingRightWidth, tdRect, left;
  210. bothWidth = currentLeftTDWidth + currentRightTDWidth;
  211. movingLeftWidth = currentLeftTDWidth + distX;
  212. movingRightWidth = currentRightTDWidth - distX;
  213. tdRect = $tx.getCoordsTarget(currentLeftTD);
  214. if (movingLeftWidth >= MIN_WIDTH && movingRightWidth >= MIN_WIDTH) {
  215. left = posiX - $tom.getScrollLeft(doc);
  216. }
  217. else if (movingLeftWidth <= MIN_WIDTH) {
  218. movingLeftWidth = MIN_WIDTH;
  219. movingRightWidth = bothWidth - movingLeftWidth;
  220. left = tdRect.left - $tom.getScrollLeft(doc) + movingLeftWidth;
  221. }
  222. else if (movingRightWidth <= MIN_WIDTH) {
  223. movingRightWidth = MIN_WIDTH;
  224. movingLeftWidth = bothWidth - movingRightWidth;
  225. left = tdRect.left - $tom.getScrollLeft(doc) + movingLeftWidth;
  226. }
  227. movingX = movingLeftWidth - currentLeftTDWidth;
  228. return left;
  229. };
  230. var calcLeft = function(currentLeftTD, distX) {
  231. var movingLeftWidth, tdRect, left;
  232. movingLeftWidth = currentLeftTDWidth + distX;
  233. tdRect = $tx.getCoordsTarget(currentLeftTD);
  234. if (movingLeftWidth < MIN_WIDTH) {
  235. movingLeftWidth = MIN_WIDTH;
  236. }
  237. left = tdRect.left - $tom.getScrollLeft(doc) + movingLeftWidth;
  238. movingX = movingLeftWidth - currentLeftTDWidth;
  239. return left;
  240. };
  241. var calcRight = function(currentRightTD, distX) {
  242. var movingRightWidth, tdRect, left;
  243. movingRightWidth = currentRightTDWidth - distX;
  244. tdRect = $tx.getCoordsTarget(currentRightTD);
  245. if (movingRightWidth < MIN_WIDTH) {
  246. movingRightWidth = MIN_WIDTH;
  247. }
  248. left = tdRect.left + movingRightWidth;
  249. movingX = currentRightTDWidth - movingRightWidth;
  250. return left;
  251. };
  252. var stopResizeCol = function() {
  253. resizeWidth();
  254. initDragger();
  255. moveUnDraggingAction();
  256. saveHistory();
  257. };
  258. var resizeWidth = function() {
  259. var i;
  260. if (leftTdArray) {
  261. for (i = 0; i < leftTdArray.length; i++) {
  262. leftTdArray[i].style.width = (leftWidthArr[i] + movingX).toPx();
  263. }
  264. }
  265. if (rightTdArray) {
  266. for (i = 0; i < rightTdArray.length; i++) {
  267. rightTdArray[i].style.width = (rightWidthArr[i] - movingX ).toPx();
  268. }
  269. }
  270. if (leftTdArray && rightTdArray == _NULL) {
  271. resizeTableWidth();
  272. }
  273. };
  274. var startResizeRow = function() {
  275. isDragging = _TRUE;
  276. currentTDHeight = currentNode.offsetHeight;
  277. topHeightArr = [];
  278. if (topTdArray) {
  279. var i;
  280. for (i = 0; i < topTdArray.length; i++) {
  281. topHeightArr.push(parseInt(topTdArray[i].offsetHeight));
  282. }
  283. currentTDHeight = minimumOfArray(topHeightArr);
  284. for (i = 0; i < topTdArray.length; i++) {
  285. if (currentTDHeight == topHeightArr[i]) {
  286. currentTD = topTdArray[i];
  287. }
  288. }
  289. }
  290. currentPointY = $tx.getCoordsTarget(currentDragger).top;
  291. };
  292. var moveCalcResizeRow = function() {
  293. if (isDragging) {
  294. var distY = posiY - $tom.getScrollTop(doc) - currentPointY;
  295. var movingHeight = currentTDHeight + parseInt(distY);
  296. var tdRect = $tx.getCoordsTarget(currentTD);
  297. var top = _NULL;
  298. if (movingHeight < 0) {
  299. movingHeight = 0;
  300. top = tdRect.top + movingHeight - $tom.getScrollTop(doc);
  301. }
  302. else {
  303. top = posiY - $tom.getScrollTop(doc);
  304. }
  305. if (top) {
  306. $tx.setStyle(currentDragger, {
  307. "top": top.toPx()
  308. });
  309. }
  310. movingY = movingHeight - currentTDHeight;
  311. }
  312. };
  313. var stopResizeRow = function() {
  314. resizeHeight();
  315. initDragger();
  316. moveUnDraggingAction();
  317. saveHistory();
  318. };
  319. var resizeHeight = function() {
  320. if (topTdArray) {
  321. for (var i = 0; i < topTdArray.length; i++) {
  322. var height = topHeightArr[i] + movingY;
  323. if (height < 0) {
  324. height = 20;
  325. }
  326. topTdArray[i].style.height = height.toPx();
  327. }
  328. }
  329. };
  330. (function checkW3cBoxModel() {
  331. var div = doc.createElement( "div" );
  332. body.appendChild(div);
  333. div.style.width = div.style.paddingLeft = "1px";
  334. w3cBoxModelWorks = div.offsetWidth === 2;
  335. body.removeChild(div);
  336. })();
  337. var getEdgeType = function(node) {
  338. var rect, edgeType = EDGE_TYPE.NONE;
  339. //HISTORY. 아래 코드는 jQuery 1.6.4 에서 훔쳐옴..
  340. //버그 재현 코드
  341. /*
  342. <TABLE><TBODY><TR><TD style="BORDER-TOP: #ff8b16 50px solid">
  343. 여기에 테이블 삽입.
  344. </TD></TR></TBODY></TABLE>
  345. */
  346. if ("getBoundingClientRect" in document.documentElement) {
  347. try {
  348. var doc = node.ownerDocument,
  349. docElem = doc.documentElement,
  350. body = doc.body;
  351. var box = node.getBoundingClientRect(),
  352. win = doc.defaultView || doc.parentWindow,
  353. clientTop = docElem.clientTop || body.clientTop || 0,
  354. clientLeft = docElem.clientLeft || body.clientLeft || 0,
  355. scrollTop = win.pageYOffset || w3cBoxModelWorks && docElem.scrollTop || body.scrollTop,
  356. scrollLeft = win.pageXOffset || w3cBoxModelWorks && docElem.scrollLeft || body.scrollLeft,
  357. top = box.top + scrollTop - clientTop,
  358. left = box.left + scrollLeft - clientLeft;
  359. rect = {
  360. top: top,
  361. left: left,
  362. bottom: top + node.offsetHeight,
  363. right: left + node.offsetWidth
  364. };
  365. } catch (e) {
  366. rect = _NULL;
  367. }
  368. }
  369. //기존 코드는 fallback.
  370. if (!rect) {
  371. rect = $tx.getCoordsTarget(node);
  372. }
  373. if ((posiX - rect.left) < 5 && node.cellIndex != 0) {
  374. edgeType = EDGE_TYPE.LEFT;
  375. }
  376. else if ((rect.right - 5) < posiX) {
  377. edgeType = EDGE_TYPE.RIGHT;
  378. }
  379. else if ((posiY - rect.top) < 5 && node.parentNode.rowIndex != 0) {
  380. edgeType = EDGE_TYPE.TOP;
  381. }
  382. else if ((rect.bottom - 5) < posiY) {
  383. edgeType = EDGE_TYPE.BOTTOM;
  384. }
  385. return edgeType;
  386. };
  387. var showDragger = function() {
  388. canvas.query(function(processor) {
  389. if (processor.table) {
  390. if (processor.table.isDuringSelection() || canvas.config.readonly) {
  391. edgeType = EDGE_TYPE.NONE;
  392. }
  393. switch (edgeType) {
  394. case EDGE_TYPE.LEFT:
  395. case EDGE_TYPE.RIGHT:
  396. $tx.hide(rowDragger);
  397. $tx.show(colDragger);
  398. makeColDragger(colDragger);
  399. currentDragger = colDragger;
  400. break;
  401. case EDGE_TYPE.TOP:
  402. case EDGE_TYPE.BOTTOM:
  403. $tx.hide(colDragger);
  404. $tx.show(rowDragger);
  405. makeRowDragger(rowDragger);
  406. currentDragger = rowDragger;
  407. break;
  408. case EDGE_TYPE.NONE:
  409. $tx.hide(colDragger);
  410. $tx.hide(rowDragger);
  411. break;
  412. }
  413. }
  414. });
  415. };
  416. var makeColDragger = function(dragger) {
  417. if (dragger == _NULL) return;
  418. var left;
  419. if (isDragging) {
  420. left = $tx.getCoordsTarget(dragger).left;
  421. $tx.setStyle(dragger, {
  422. "width": "2px",
  423. "height": wysiwygPanel.el.clientHeight.toPx(),
  424. "border": "1px dotted #81aFFC",
  425. "background":"",
  426. "left": left.toPx()
  427. });
  428. $tx.setOpacity(colDragger, 1);
  429. }
  430. else {
  431. left = posiX - $tom.getScrollLeft(doc);
  432. $tx.setStyle(dragger, {
  433. "width": "2px",
  434. "height": wysiwygPanel.el.clientHeight.toPx(),
  435. "border": "",
  436. "background":"#fff",
  437. "left": left.toPx()
  438. });
  439. $tx.setOpacity(colDragger, 0);
  440. }
  441. };
  442. var makeRowDragger = function(dragger) {
  443. if (dragger == _NULL) return;
  444. var top = _NULL;
  445. if (isDragging) {
  446. top = $tx.getCoordsTarget(dragger).top;
  447. $tx.setStyle(dragger, {
  448. "height": "2px",
  449. "border": "1px dotted #81aFFC",
  450. "background":"",
  451. "top": top.toPx()
  452. });
  453. $tx.setOpacity(rowDragger, 1);
  454. }
  455. else {
  456. top = posiY - $tom.getScrollTop(doc);
  457. $tx.setStyle(dragger, {
  458. "height": "2px",
  459. "border": "",
  460. "background":"#fff",
  461. "top": top.toPx()
  462. });
  463. $tx.setOpacity(rowDragger, 0);
  464. }
  465. };
  466. /**
  467. * when I pasted MS office table, delete width or width style.
  468. */
  469. var resizeTableWidth = function() {
  470. var movingWidth = 0;
  471. if (currentTableWidth) {
  472. movingWidth = parseInt(currentTableWidth) + movingX;
  473. currentTable.width = movingWidth.toPx();
  474. currentTable.style.width = movingWidth.toPx();
  475. }
  476. };
  477. /**
  478. * dragger event binding
  479. */
  480. var eventBinding = function() {
  481. $tx.observe(_DOC.body, "mouseup", function(ev) {
  482. initElement(ev);
  483. mouseupHandler();
  484. });
  485. if ($tx.msie) {
  486. $tx.observe(body, "mousemove", function(ev) {
  487. initElement(ev);
  488. mousemoveHandler();
  489. });
  490. $tx.observe(body, "mouseup", function(ev) {
  491. initElement(ev);
  492. mouseupHandler();
  493. });
  494. }
  495. else {
  496. $tx.observe(win, "mousemove", function(ev) {
  497. initElement(ev);
  498. mousemoveHandler();
  499. });
  500. $tx.observe(win, "mouseup", function(ev) {
  501. initElement(ev);
  502. mouseupHandler();
  503. });
  504. }
  505. if ($tx.safari) {
  506. $tx.observe(_DOC.body, "mousemove", function(ev) {
  507. if (isDragging) {
  508. initElementForSafari(ev);
  509. mousemoveHandler();
  510. }
  511. });
  512. }
  513. $tx.observe(colDragger, "mousedown", function(ev) {
  514. initElement(ev);
  515. mouseDownHandler();
  516. });
  517. $tx.observe(rowDragger, "mousedown", function(ev) {
  518. initElement(ev);
  519. mouseDownHandler();
  520. });
  521. };
  522. var initElement = function(ev) {
  523. elem = ev;
  524. posiX = posX(elem);
  525. posiY = posY(elem);
  526. };
  527. var initElementForSafari = function(ev) {
  528. elem = ev;
  529. posiX = posX(elem) - $tx.getCoords(canvas.wysiwygEl).left + doc.body.scrollLeft;
  530. posiY = posY(elem) - $tx.getCoords(canvas.wysiwygEl).top + doc.body.scrollTop;
  531. };
  532. // tabledragger 에서 추가된 utility, check!!
  533. var posX = function(e) {
  534. var posx = 0;
  535. e = e || win.event;
  536. if (e.pageX) {
  537. posx = e.pageX;
  538. }
  539. else
  540. if (e.clientX) {
  541. posx = e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
  542. }
  543. return posx;
  544. };
  545. var posY = function(e) {
  546. var posy = 0;
  547. e = e || win.event;
  548. if (e.pageY) {
  549. posy = e.pageY;
  550. }
  551. else
  552. if (e.clientY) {
  553. posy = e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
  554. }
  555. return posy;
  556. };
  557. function minimumOfArray(array) {
  558. return Math.min.apply(Math, array);
  559. }
  560. function saveHistory() {
  561. console.log("saveHistory");
  562. canvas.history.saveHistory();
  563. }
  564. initDragger();
  565. eventBinding();
  566. });
  567. });