GridContainer.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. define("dojox/layout/GridContainer", [
  2. "dojo/_base/kernel",
  3. "dojo/_base/array",
  4. "dojo/_base/connect",
  5. "dojo/_base/declare",
  6. "dojo/_base/html",
  7. "dojo/_base/lang",
  8. "dojo/_base/window",
  9. "dojo/ready", // dojo.ready
  10. "dojox/layout/GridContainerLite"
  11. ],function(dojo){
  12. return dojo.declare(
  13. "dojox.layout.GridContainer",
  14. dojox.layout.GridContainerLite,
  15. {
  16. // summary:
  17. // A grid containing any kind of objects and acting like web portals.
  18. //
  19. // description:
  20. // This component inherits of all features of gridContainerLite plus :
  21. // - Resize colums
  22. // - Add / remove columns
  23. // - Fix columns at left or at right.
  24. // example:
  25. // | <div dojoType="dojox.layout.GridContainer" nbZones="3" isAutoOrganized="true">
  26. // | <div dojoType="dijit.layout.ContentPane">Content Pane 1 : Drag Me !</div>
  27. // | <div dojoType="dijit.layout.ContentPane">Content Pane 2 : Drag Me !</div>
  28. // | <div dojoType="dijit.layout.ContentPane">Content Pane 3 : Drag Me !</div>
  29. // | </div>
  30. //
  31. // example:
  32. // | dojo.ready(function(){
  33. // | var cpane1 = new dijit.layout.ContentPane({ title:"cpane1", content: "Content Pane 1 : Drag Me !" }),
  34. // | cpane2 = new dijit.layout.ContentPane({ title:"cpane2", content: "Content Pane 2 : Drag Me !" }),
  35. // | cpane3 = new dijit.layout.ContentPane({ title:"cpane3", content: "Content Pane 3 : Drag Me !" });
  36. // |
  37. // | var widget = new dojox.layout.GridContainer({
  38. // | nbZones: 3,
  39. // | isAutoOrganized: true
  40. // | }, dojo.byId("idNode"));
  41. // | widget.addChild(cpane1, 0, 0);
  42. // | widget.addChild(cpane2, 1, 0);
  43. // | widget.addChild(cpane3, 2, 1);
  44. // | widget.startup();
  45. // | });
  46. // hasResizableColumns: Boolean
  47. // Allow or not resizing of columns by a grip handle.
  48. hasResizableColumns: true,
  49. // liveResizeColumns: Boolean
  50. // Specifies whether columns resize as you drag (true) or only upon mouseup (false)
  51. liveResizeColumns : false,
  52. // minColWidth: Integer
  53. // Minimum column width in percentage.
  54. minColWidth: 20,
  55. // minChildWidth: Integer
  56. // Minimum children width in pixel (only used for IE6 which doesn't handle min-width css property)
  57. minChildWidth: 150,
  58. // mode: String
  59. // Location to add/remove columns, must be set to 'left' or 'right' (default).
  60. mode: "right",
  61. // isRightFixed: Boolean
  62. // Define if the last right column is fixed.
  63. // Used when you add or remove columns by calling setColumns method.
  64. isRightFixed: false,
  65. // isLeftFixed: Boolean
  66. // Define if the last left column is fixed.
  67. // Used when you add or remove columns by calling setColumns method.
  68. isLeftFixed: false,
  69. startup: function(){
  70. // summary:
  71. // Call the startup of GridContainerLite and place grips
  72. // if user has chosen the hasResizableColumns attribute to true.
  73. //console.log("dojox.layout.GridContainer ::: startup");
  74. this.inherited(arguments);
  75. if(this.hasResizableColumns){
  76. for(var i = 0; i < this._grid.length - 1; i++){
  77. this._createGrip(i);
  78. }
  79. // If widget has a container parent, grips will be placed
  80. // by method onShow.
  81. if(!this.getParent()){
  82. // Fix IE7 :
  83. // The CSS property height:100% for the grip
  84. // doesn't work anytime. It's necessary to wait
  85. // the end of loading before to place grips.
  86. dojo.ready(dojo.hitch(this, "_placeGrips"));
  87. }
  88. }
  89. },
  90. resizeChildAfterDrop : function(/*Node*/node, /*Object*/targetArea, /*Integer*/indexChild){
  91. // summary:
  92. // Call when a child is dropped.
  93. // description:
  94. // Allow to resize and put grips
  95. // node:
  96. // domNode of dropped widget.
  97. // targetArea:
  98. // AreaManager Object containing information of targetArea
  99. // indexChild:
  100. // Index where the dropped widget has been placed
  101. if(this.inherited(arguments)){
  102. this._placeGrips();
  103. }
  104. },
  105. onShow: function(){
  106. // summary:
  107. // Place grips in the right place when the GridContainer becomes visible.
  108. //console.log("dojox.layout.GridContainer ::: onShow");
  109. this.inherited(arguments);
  110. this._placeGrips();
  111. },
  112. resize: function(){
  113. // summary:
  114. // Resize the GridContainer widget and columns.
  115. // Replace grips if it's necessary.
  116. // tags:
  117. // callback
  118. //console.log("dojox.layout.GridContainer ::: resize");
  119. this.inherited(arguments);
  120. // Fix IE6 :
  121. // IE6 calls method resize itself.
  122. // If the GridContainer is not visible at this time,
  123. // the method _placeGrips can return a negative value with
  124. // contentBox method. (see method _placeGrip() with Fix Ie6 for the height)
  125. if(this._isShown() && this.hasResizableColumns){
  126. this._placeGrips();
  127. }
  128. },
  129. _createGrip: function(/*Integer*/ index){
  130. // summary:
  131. // Create a grip for a specific zone.
  132. // index:
  133. // index where the grip has to be created.
  134. // tags:
  135. // protected
  136. //console.log("dojox.layout.GridContainer ::: _createGrip");
  137. var dropZone = this._grid[index],
  138. grip = dojo.create("div", { 'class': "gridContainerGrip" }, this.domNode);
  139. dropZone.grip = grip;
  140. dropZone.gripHandler = [
  141. this.connect(grip, "onmouseover", function(e){
  142. var gridContainerGripShow = false;
  143. for(var i = 0; i < this._grid.length - 1; i++){
  144. if(dojo.hasClass(this._grid[i].grip, "gridContainerGripShow")){
  145. gridContainerGripShow = true;
  146. break;
  147. }
  148. }
  149. if(!gridContainerGripShow){
  150. dojo.removeClass(e.target, "gridContainerGrip");
  151. dojo.addClass(e.target, "gridContainerGripShow");
  152. }
  153. })[0],
  154. this.connect(grip, "onmouseout", function(e){
  155. if(!this._isResized){
  156. dojo.removeClass(e.target, "gridContainerGripShow");
  157. dojo.addClass(e.target, "gridContainerGrip");
  158. }
  159. })[0],
  160. this.connect(grip, "onmousedown", "_resizeColumnOn")[0],
  161. this.connect(grip, "ondblclick", "_onGripDbClick")[0]
  162. ];
  163. },
  164. _placeGrips: function(){
  165. // summary:
  166. // Define the position of a grip and place it on page.
  167. // tags:
  168. // protected
  169. //console.log("dojox.layout.GridContainer ::: _placeGrips");
  170. var gripWidth, height, left = 0, grip;
  171. var scroll = this.domNode.style.overflowY;
  172. dojo.forEach(this._grid, function(dropZone){
  173. if(dropZone.grip){
  174. grip = dropZone.grip;
  175. if(!gripWidth){
  176. gripWidth = grip.offsetWidth / 2;
  177. }
  178. left += dojo.marginBox(dropZone.node).w;
  179. dojo.style(grip, "left", (left - gripWidth) + "px");
  180. //if(dojo.isIE == 6){ do it fot all navigators
  181. if(!height){
  182. height = dojo.contentBox(this.gridNode).h;
  183. }
  184. if(height > 0){
  185. dojo.style(grip, "height", height + "px");
  186. }
  187. //}
  188. }
  189. }, this);
  190. },
  191. _onGripDbClick: function(){
  192. // summary:
  193. // Called when a double click is catch. Resize all columns with the same width.
  194. // The method resize of children have to be called.
  195. // tags:
  196. // callback protected
  197. //console.log("dojox.layout.GridContainer ::: _onGripDbClick");
  198. this._updateColumnsWidth(this._dragManager);
  199. this.resize();
  200. },
  201. _resizeColumnOn: function(/*Event*/e){
  202. // summary:
  203. // Connect events to listen the resize action.
  204. // Change the type of width columns (% to px).
  205. // Calculate the minwidth according to the children.
  206. // tags:
  207. // callback
  208. //console.log("dojox.layout.GridContainer ::: _resizeColumnOn", e);
  209. this._activeGrip = e.target;
  210. this._initX = e.pageX;
  211. e.preventDefault();
  212. dojo.body().style.cursor = "ew-resize";
  213. this._isResized = true;
  214. var tabSize = [];
  215. var grid;
  216. var i;
  217. for(i = 0; i < this._grid.length; i++){
  218. tabSize[i] = dojo.contentBox(this._grid[i].node).w;
  219. }
  220. this._oldTabSize = tabSize;
  221. for(i = 0; i < this._grid.length; i++){
  222. grid = this._grid[i];
  223. if(this._activeGrip == grid.grip){
  224. this._currentColumn = grid.node;
  225. this._currentColumnWidth = tabSize[i];
  226. this._nextColumn = this._grid[i + 1].node;
  227. this._nextColumnWidth = tabSize[i + 1];
  228. }
  229. grid.node.style.width = tabSize[i] + "px";
  230. }
  231. // calculate the minWidh of all children for current and next column
  232. var calculateChildMinWidth = function(childNodes, minChild){
  233. var width = 0;
  234. var childMinWidth = 0;
  235. dojo.forEach(childNodes, function(child){
  236. if(child.nodeType == 1){
  237. var objectStyle = dojo.getComputedStyle(child);
  238. var minWidth = (dojo.isIE) ? minChild : parseInt(objectStyle.minWidth);
  239. childMinWidth = minWidth +
  240. parseInt(objectStyle.marginLeft) +
  241. parseInt(objectStyle.marginRight);
  242. if(width < childMinWidth){
  243. width = childMinWidth;
  244. }
  245. }
  246. });
  247. return width;
  248. }
  249. var currentColumnMinWidth = calculateChildMinWidth(this._currentColumn.childNodes, this.minChildWidth);
  250. var nextColumnMinWidth = calculateChildMinWidth(this._nextColumn.childNodes, this.minChildWidth);
  251. var minPix = Math.round((dojo.marginBox(this.gridContainerTable).w * this.minColWidth) / 100);
  252. this._currentMinCol = currentColumnMinWidth;
  253. this._nextMinCol = nextColumnMinWidth;
  254. if(minPix > this._currentMinCol){
  255. this._currentMinCol = minPix;
  256. }
  257. if(minPix > this._nextMinCol){
  258. this._nextMinCol = minPix;
  259. }
  260. this._connectResizeColumnMove = dojo.connect(dojo.doc, "onmousemove", this, "_resizeColumnMove");
  261. this._connectOnGripMouseUp = dojo.connect(dojo.doc, "onmouseup", this, "_onGripMouseUp");
  262. },
  263. _onGripMouseUp: function(){
  264. // summary:
  265. // Call on the onMouseUp only if the reiszeColumnMove was not called.
  266. // tags:
  267. // callback
  268. //console.log(dojox.layout.GridContainer ::: _onGripMouseUp");
  269. dojo.body().style.cursor = "default";
  270. dojo.disconnect(this._connectResizeColumnMove);
  271. dojo.disconnect(this._connectOnGripMouseUp);
  272. this._connectOnGripMouseUp = this._connectResizeColumnMove = null;
  273. if(this._activeGrip){
  274. dojo.removeClass(this._activeGrip, "gridContainerGripShow");
  275. dojo.addClass(this._activeGrip, "gridContainerGrip");
  276. }
  277. this._isResized = false;
  278. },
  279. _resizeColumnMove: function(/*Event*/e){
  280. // summary:
  281. // Change columns size.
  282. // tags:
  283. // callback
  284. //console.log("dojox.layout.GridContainer ::: _resizeColumnMove");
  285. e.preventDefault();
  286. if(!this._connectResizeColumnOff){
  287. dojo.disconnect(this._connectOnGripMouseUp);
  288. this._connectOnGripMouseUp = null;
  289. this._connectResizeColumnOff = dojo.connect(dojo.doc, "onmouseup", this, "_resizeColumnOff");
  290. }
  291. var d = e.pageX - this._initX;
  292. if(d == 0){ return; }
  293. if(!(this._currentColumnWidth + d < this._currentMinCol ||
  294. this._nextColumnWidth - d < this._nextMinCol)){
  295. this._currentColumnWidth += d;
  296. this._nextColumnWidth -= d;
  297. this._initX = e.pageX;
  298. this._activeGrip.style.left = parseInt(this._activeGrip.style.left) + d + "px";
  299. if(this.liveResizeColumns){
  300. this._currentColumn.style["width"] = this._currentColumnWidth + "px";
  301. this._nextColumn.style["width"] = this._nextColumnWidth + "px";
  302. this.resize();
  303. }
  304. }
  305. },
  306. _resizeColumnOff: function(/*Event*/e){
  307. // summary:
  308. // Disconnect resize events.
  309. // Change the type of width columns (px to %).
  310. // tags:
  311. // callback
  312. //console.log("dojox.layout.GridContainer ::: _resizeColumnOff");
  313. dojo.body().style.cursor = "default";
  314. dojo.disconnect(this._connectResizeColumnMove);
  315. dojo.disconnect(this._connectResizeColumnOff);
  316. this._connectResizeColumnOff = this._connectResizeColumnMove = null;
  317. if(!this.liveResizeColumns){
  318. this._currentColumn.style["width"] = this._currentColumnWidth + "px";
  319. this._nextColumn.style["width"] = this._nextColumnWidth + "px";
  320. //this.resize();
  321. }
  322. var tabSize = [],
  323. testSize = [],
  324. tabWidth = this.gridContainerTable.clientWidth,
  325. node,
  326. update = false,
  327. i;
  328. for(i = 0; i < this._grid.length; i++){
  329. node = this._grid[i].node;
  330. if(dojo.isIE){
  331. tabSize[i] = dojo.marginBox(node).w;
  332. testSize[i] = dojo.contentBox(node).w;
  333. }
  334. else{
  335. tabSize[i] = dojo.contentBox(node).w;
  336. testSize = tabSize;
  337. }
  338. }
  339. for(i = 0; i < testSize.length; i++){
  340. if(testSize[i] != this._oldTabSize[i]){
  341. update = true;
  342. break;
  343. }
  344. }
  345. if(update){
  346. var mul = dojo.isIE ? 100 : 10000;
  347. for(i = 0; i < this._grid.length; i++){
  348. this._grid[i].node.style.width = Math.round((100 * mul * tabSize[i]) / tabWidth) / mul + "%";
  349. }
  350. this.resize();
  351. }
  352. if(this._activeGrip){
  353. dojo.removeClass(this._activeGrip, "gridContainerGripShow");
  354. dojo.addClass(this._activeGrip, "gridContainerGrip");
  355. }
  356. this._isResized = false;
  357. },
  358. setColumns: function(/*Integer*/nbColumns){
  359. // summary:
  360. // Set the number of columns.
  361. // nbColumns:
  362. // Number of columns
  363. //console.log("dojox.layout.GridContainer ::: setColumns");
  364. var z, j;
  365. if(nbColumns > 0){
  366. var length = this._grid.length,
  367. delta = length - nbColumns;
  368. if(delta > 0){
  369. var count = [], zone, start, end, nbChildren;
  370. // Check if right or left columns are fixed
  371. // Columns are not taken in account and can't be deleted
  372. if(this.mode == "right"){
  373. end = (this.isLeftFixed && length > 0) ? 1 : 0;
  374. start = (this.isRightFixed) ? length - 2 : length - 1
  375. for(z = start; z >= end; z--){
  376. nbChildren = 0;
  377. zone = this._grid[z].node;
  378. for(j = 0; j < zone.childNodes.length; j++){
  379. if(zone.childNodes[j].nodeType == 1 && !(zone.childNodes[j].id == "")){
  380. nbChildren++;
  381. break;
  382. }
  383. }
  384. if(nbChildren == 0){ count[count.length] = z; }
  385. if(count.length >= delta){
  386. this._deleteColumn(count);
  387. break;
  388. }
  389. }
  390. if(count.length < delta){
  391. dojo.publish("/dojox/layout/gridContainer/noEmptyColumn", [this]);
  392. }
  393. }
  394. else{ // mode = "left"
  395. start = (this.isLeftFixed && length > 0) ? 1 : 0;
  396. end = (this.isRightFixed) ? length - 1 : length;
  397. for(z = start; z < end; z++){
  398. nbChildren = 0;
  399. zone = this._grid[z].node;
  400. for(j = 0; j < zone.childNodes.length; j++){
  401. if(zone.childNodes[j].nodeType == 1 && !(zone.childNodes[j].id == "")){
  402. nbChildren++;
  403. break;
  404. }
  405. }
  406. if(nbChildren == 0){ count[count.length] = z; }
  407. if(count.length >= delta){
  408. this._deleteColumn(count);
  409. break;
  410. }
  411. }
  412. if(count.length < delta){
  413. //Not enough empty columns
  414. dojo.publish("/dojox/layout/gridContainer/noEmptyColumn", [this]);
  415. }
  416. }
  417. }
  418. else{
  419. if(delta < 0){ this._addColumn(Math.abs(delta)); }
  420. }
  421. if(this.hasResizableColumns){ this._placeGrips(); }
  422. }
  423. },
  424. _addColumn: function(/*Integer*/nbColumns){
  425. // summary:
  426. // Add some columns.
  427. // nbColumns:
  428. // Number of column to added
  429. // tags:
  430. // private
  431. //console.log("dojox.layout.GridContainer ::: _addColumn");
  432. var grid = this._grid,
  433. dropZone,
  434. node,
  435. index,
  436. length,
  437. isRightMode = (this.mode == "right"),
  438. accept = this.acceptTypes.join(","),
  439. m = this._dragManager;
  440. //Add a grip to the last column
  441. if(this.hasResizableColumns && ((!this.isRightFixed && isRightMode)
  442. || (this.isLeftFixed && !isRightMode && this.nbZones == 1) )){
  443. this._createGrip(grid.length - 1);
  444. }
  445. for(var i = 0; i < nbColumns; i++){
  446. // Fix CODEX defect #53025 :
  447. // Apply acceptType attribute on each new column.
  448. node = dojo.create("td", {
  449. 'class': "gridContainerZone dojoxDndArea" ,
  450. 'accept': accept,
  451. 'id': this.id + "_dz" + this.nbZones
  452. });
  453. length = grid.length;
  454. if(isRightMode){
  455. if(this.isRightFixed){
  456. index = length - 1;
  457. grid.splice(index, 0, {
  458. 'node': grid[index].node.parentNode.insertBefore(node, grid[index].node)
  459. });
  460. }
  461. else{
  462. index = length;
  463. grid.push({ 'node': this.gridNode.appendChild(node) });
  464. }
  465. }
  466. else{
  467. if(this.isLeftFixed){
  468. index = (length == 1) ? 0 : 1;
  469. this._grid.splice(1, 0, {
  470. 'node': this._grid[index].node.parentNode.appendChild(node, this._grid[index].node)
  471. });
  472. index = 1;
  473. }
  474. else{
  475. index = length - this.nbZones;
  476. this._grid.splice(index, 0, {
  477. 'node': grid[index].node.parentNode.insertBefore(node, grid[index].node)
  478. });
  479. }
  480. }
  481. if(this.hasResizableColumns){
  482. //Add a grip to resize columns
  483. if((!isRightMode && this.nbZones != 1) ||
  484. (!isRightMode && this.nbZones == 1 && !this.isLeftFixed) ||
  485. (isRightMode && i < nbColumns-1) ||
  486. (isRightMode && i == nbColumns-1 && this.isRightFixed)){
  487. this._createGrip(index);
  488. }
  489. }
  490. // register tnbZoneshe new area into the areaManager
  491. m.registerByNode(grid[index].node);
  492. this.nbZones++;
  493. }
  494. this._updateColumnsWidth(m);
  495. },
  496. _deleteColumn: function(/*Array*/indices){
  497. // summary:
  498. // Remove some columns with indices passed as an array.
  499. // indices:
  500. // Column index array
  501. // tags:
  502. // private
  503. //console.log("dojox.layout.GridContainer ::: _deleteColumn");
  504. var child, grid, index,
  505. nbDelZones = 0,
  506. length = indices.length,
  507. m = this._dragManager;
  508. for(var i = 0; i < length; i++){
  509. index = (this.mode == "right") ? indices[i] : indices[i] - nbDelZones;
  510. grid = this._grid[index];
  511. if(this.hasResizableColumns && grid.grip){
  512. dojo.forEach(grid.gripHandler, function(handler){
  513. dojo.disconnect(handler);
  514. });
  515. dojo.destroy(this.domNode.removeChild(grid.grip));
  516. grid.grip = null;
  517. }
  518. m.unregister(grid.node);
  519. dojo.destroy(this.gridNode.removeChild(grid.node));
  520. this._grid.splice(index, 1);
  521. this.nbZones--;
  522. nbDelZones++;
  523. }
  524. // last grip
  525. var lastGrid = this._grid[this.nbZones-1];
  526. if(lastGrid.grip){
  527. dojo.forEach(lastGrid.gripHandler, dojo.disconnect);
  528. dojo.destroy(this.domNode.removeChild(lastGrid.grip));
  529. lastGrid.grip = null;
  530. }
  531. this._updateColumnsWidth(m);
  532. },
  533. _updateColumnsWidth: function(/*Object*/ manager){
  534. // summary:
  535. // Update the columns width.
  536. // manager:
  537. // dojox.mdnd.AreaManager singleton
  538. // tags:
  539. // private
  540. //console.log("dojox.layout.GridContainer ::: _updateColumnsWidth");
  541. this.inherited(arguments);
  542. manager._dropMode.updateAreas(manager._areaList);
  543. },
  544. destroy: function(){
  545. dojo.unsubscribe(this._dropHandler);
  546. this.inherited(arguments);
  547. }
  548. });
  549. });