ResizeTableColumn.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.editor.plugins.ResizeTableColumn"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.editor.plugins.ResizeTableColumn"] = true;
  8. dojo.provide("dojox.editor.plugins.ResizeTableColumn");
  9. dojo.require("dojox.editor.plugins.TablePlugins");
  10. dojo.declare("dojox.editor.plugins.ResizeTableColumn", dojox.editor.plugins.TablePlugins, {
  11. constructor: function(){
  12. // summary:
  13. // Because IE will ignore the cursor style when the editMode of the document is on,
  14. // we need to create a div within the outer document to mimic the behavior of drag&drop
  15. this.isLtr = this.dir ? (this.dir == "ltr") : dojo._isBodyLtr();
  16. this.ruleDiv = dojo.create("div",
  17. {style: "top: -10000px; z-index: 10001"},
  18. dojo.body(), "last");
  19. },
  20. setEditor: function(editor){
  21. // summary:
  22. // Handle the drag&drop events
  23. // editor:
  24. // The editor which this plugin belongs to
  25. // tags:
  26. // protected
  27. var ruleDiv = this.ruleDiv;
  28. this.editor = editor;
  29. this.editor.customUndo = true;
  30. this.onEditorLoaded();
  31. // The content of the editor is loaded asynchronously, so the function
  32. // should be called when it is loaded.
  33. editor.onLoadDeferred.addCallback(dojo.hitch(this, function(){
  34. this.connect(this.editor.editNode, "onmousemove", function(evt){
  35. var editorCoords = dojo.coords(editor.iframe, true),
  36. ex = editorCoords.x, cx = evt.clientX;
  37. if(!this.isDragging){
  38. // If it is just a movement, put the div at the edge of the
  39. // target cell so that when the cursor hover on it, it will
  40. // change to the col-resize style.
  41. var obj = evt.target;
  42. if(obj.tagName && obj.tagName.toLowerCase() == "td"){
  43. var objCoords = dojo.coords(obj), ox = objCoords.x, ow = objCoords.w,
  44. pos = ex + objCoords.x - 2;
  45. if(this.isLtr){
  46. ruleDiv.headerColumn = true;
  47. if(!isBoundary(obj, "first") || cx > ox + ow / 2){
  48. pos += ow;
  49. ruleDiv.headerColumn = false;
  50. }
  51. }else{
  52. ruleDiv.headerColumn = false;
  53. if(isBoundary(obj, "first") && cx > ox + ow / 2){
  54. pos += ow;
  55. ruleDiv.headerColumn = true;
  56. }
  57. }
  58. dojo.style(ruleDiv, {
  59. position: "absolute",
  60. cursor: "col-resize",
  61. display: "block",
  62. width: "4px",
  63. backgroundColor: "transparent",
  64. top: editorCoords.y + objCoords.y + "px",
  65. left: pos + "px",
  66. height: objCoords.h + "px"
  67. });
  68. this.activeCell = obj;
  69. }else{
  70. dojo.style(ruleDiv, {display: "none", top: "-10000px"});
  71. }
  72. }else{
  73. // Begin to drag&drop
  74. var activeCell = this.activeCell,
  75. activeCoords = dojo.coords(activeCell), ax = activeCoords.x, aw = activeCoords.w,
  76. sibling = nextSibling(activeCell), siblingCoords, sx, sw,
  77. containerCoords = dojo.coords(getTable(activeCell).parentNode),
  78. ctx = containerCoords.x, ctw = containerCoords.w;
  79. if(sibling){
  80. siblingCoords = dojo.coords(sibling);
  81. sx = siblingCoords.x;
  82. sw = siblingCoords.w;
  83. }
  84. // The leading and trailing columns can only be sized to the extent of the containing div.
  85. if(this.isLtr &&
  86. ((ruleDiv.headerColumn && sibling && ctx < cx && cx < ax + aw) ||
  87. ((!sibling && ax < cx && cx < ctx + ctw) || (sibling && ax < cx && cx < sx + sw))) ||
  88. !this.isLtr &&
  89. ((ruleDiv.headerColumn && sibling && ctx > cx && cx > ax) ||
  90. ((!sibling && ax + aw > cx && cx > ctx) || (sibling && ax + aw > cx && cx > sx)))){
  91. dojo.style(ruleDiv, {left: ex + cx + "px"});
  92. }
  93. }
  94. });
  95. this.connect(ruleDiv, "onmousedown", function(evt){
  96. var editorCoords = dojo.coords(editor.iframe, true),
  97. tableCoords = dojo.coords(getTable(this.activeCell));
  98. this.isDragging = true;
  99. dojo.style(editor.editNode, {cursor: "col-resize"});
  100. dojo.style(ruleDiv, {
  101. width: "1px",
  102. left: evt.clientX + "px",
  103. top: editorCoords.y + tableCoords.y + "px",
  104. height: tableCoords.h + "px",
  105. backgroundColor: "#777"
  106. });
  107. });
  108. this.connect(ruleDiv, "onmouseup", function(evt){
  109. var activeCell = this.activeCell,
  110. activeCoords = dojo.coords(activeCell), aw = activeCoords.w, ax = activeCoords.x,
  111. sibling = nextSibling(activeCell), siblingCoords, sx, sw,
  112. editorCoords = dojo.coords(editor.iframe), ex = editorCoords.x,
  113. table = getTable(activeCell), tableCoords = dojo.coords(table),
  114. cs = table.getAttribute("cellspacing"),
  115. cx = evt.clientX,
  116. headerCell = getHeaderCell(activeCell), headerSibling,
  117. newWidth, newSiblingWidth;
  118. if(!cs || (cs = parseInt(cs, 10)) < 0){ cs = 2; }
  119. if(sibling){
  120. siblingCoords = dojo.coords(sibling);
  121. sx = siblingCoords.x;
  122. sw = siblingCoords.w;
  123. headerSibling = getHeaderCell(sibling);
  124. }
  125. // The delta width is either taken from or added to the adjacent column on the trailing edge.
  126. // Sizing the rightmost or leftmost columns affects only those columns.
  127. if(this.isLtr){
  128. if(ruleDiv.headerColumn){
  129. newWidth = ex + ax + aw - cx;
  130. }else{
  131. newWidth = cx - ex - ax;
  132. if(sibling) { newSiblingWidth = ex + sx + sw - cx - cs; }
  133. }
  134. }else{
  135. if(ruleDiv.headerColumn){
  136. newWidth = cx - ex - ax;
  137. }else{
  138. newWidth = ex + ax + aw - cx;
  139. if(sibling) { newSiblingWidth = cx - ex - sx - cs; }
  140. }
  141. }
  142. this.isDragging = false;
  143. marginBox(headerCell, newWidth);
  144. if(sibling){
  145. if(!ruleDiv.headerColumn){
  146. marginBox(headerSibling, newSiblingWidth);
  147. }
  148. }
  149. if(ruleDiv.headerColumn && isBoundary(activeCell, "first") || isBoundary(activeCell, "last")){
  150. dojo.marginBox(table, {w: tableCoords.w + newWidth - aw});
  151. }
  152. // Do it again to consolidate the result,
  153. // because maybe the cell cannot be so narrow as you specified.
  154. marginBox(headerCell, dojo.coords(activeCell).w);
  155. if(sibling){
  156. marginBox(headerSibling, dojo.coords(sibling).w);
  157. }
  158. dojo.style(editor.editNode, {cursor: "auto"});
  159. dojo.style(ruleDiv, {display: "none", top: "-10000px"});
  160. this.activeCell = null;
  161. });
  162. }));
  163. function isBoundary(/*DomNode*/ n, /*String*/ b){
  164. // summary:
  165. // Check if the current cell is in the first column or
  166. // in the last column.
  167. // n:
  168. // The node of a table cell
  169. // b:
  170. // Indicate if the cell node is compared with the first coluln
  171. // or the last column
  172. var nodes = dojo.withGlobal(editor.window, "query", dojo, ["> td", n.parentNode]);
  173. switch(b){
  174. case "first":
  175. return nodes[0] == n;
  176. case "last":
  177. return nodes[nodes.length - 1] == n;
  178. default:
  179. return false;
  180. }
  181. }
  182. function nextSibling(/*DomNode*/ node){
  183. // summary:
  184. // Get the next cell in row
  185. // node:
  186. // The table cell
  187. node = node.nextSibling
  188. while(node){
  189. if(node.tagName && node.tagName.toLowerCase() == "td"){
  190. break;
  191. }
  192. node = node.nextSibling
  193. }
  194. return node;
  195. }
  196. function getTable(/*DomNode*/ t){
  197. // summary:
  198. // Get the table that this cell belongs to.
  199. // t:
  200. // The table cell
  201. while((t = t.parentNode) && t.tagName.toLowerCase() != "table"){}
  202. return t;
  203. }
  204. function getHeaderCell(/*DomNode*/ t){
  205. // summary:
  206. // Get the table cell in the first row that shares the same
  207. // column with the node t.
  208. // t:
  209. // The node of the table cell
  210. var tds = dojo.withGlobal(editor.window, "query", dojo, ["td", getTable(t)]),
  211. len = tds.length;
  212. for(var i = 0; i < len; i++){
  213. if(dojo.coords(tds[i]).x == dojo.coords(t).x){
  214. return tds[i];
  215. }
  216. }
  217. return null;
  218. }
  219. function marginBox(/*DomNode*/ node, /*Number*/ width){
  220. // summary:
  221. // In IE, if the border width of the td is not specified in table, the default value is 1px,
  222. // though it is marked "medium".
  223. // node:
  224. // The node to be set width
  225. // width:
  226. // The new width of the node
  227. if(dojo.isIE){
  228. var s = node.currentStyle,
  229. bl = px(node, s.borderLeftWidth), br = px(node, s.borderRightWidth),
  230. pl = px(node, s.paddingLeft), pr = px(node, s.paddingRight);
  231. node.style.width = width - bl - br - pl - pr;
  232. }else{
  233. dojo.marginBox(node, {w: width});
  234. }
  235. function px(element, avalue){
  236. if(!avalue){ return 0; }
  237. if(avalue == "medium"){ return 1; }
  238. // style values can be floats, client code may
  239. // want to round this value for integer pixels.
  240. if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
  241. with(element){
  242. var sLeft = style.left;
  243. var rsLeft = runtimeStyle.left;
  244. runtimeStyle.left = currentStyle.left;
  245. try{
  246. // 'avalue' may be incompatible with style.left, which can cause IE to throw
  247. // this has been observed for border widths using "thin", "medium", "thick" constants
  248. // those particular constants could be trapped by a lookup
  249. // but perhaps there are more
  250. style.left = avalue;
  251. avalue = style.pixelLeft;
  252. }catch(e){
  253. avalue = 0;
  254. }
  255. style.left = sLeft;
  256. runtimeStyle.left = rsLeft;
  257. }
  258. return avalue;
  259. }
  260. }
  261. }
  262. });
  263. dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
  264. if(o.plugin){ return; }
  265. // make first character lower case
  266. if(o.args && o.args.command){
  267. var cmd = o.args.command.charAt(0).toLowerCase() + o.args.command.substring(1, o.args.command.length);
  268. if(cmd == "resizeTableColumn"){
  269. o.plugin = new dojox.editor.plugins.ResizeTableColumn({commandName: cmd});
  270. }
  271. }
  272. });
  273. }