/public/javascripts/dojo/dojox/layout/ResizeHandle.js

http://enginey.googlecode.com/ · JavaScript · 267 lines · 170 code · 42 blank · 55 comment · 22 complexity · 3008b5fdf73cca4f2dc634e1159d7981 MD5 · raw file

  1. dojo.provide("dojox.layout.ResizeHandle");
  2. dojo.experimental("dojox.layout.ResizeHandle");
  3. dojo.require("dijit._Widget");
  4. dojo.require("dijit._Templated");
  5. dojo.require("dojo.fx");
  6. dojo.declare("dojox.layout.ResizeHandle",
  7. [dijit._Widget, dijit._Templated],
  8. {
  9. // summary: A dragable handle used to resize an attached node.
  10. // description:
  11. // The handle on the bottom-right corner of FloatingPane or other widgets that allows
  12. // the widget to be resized.
  13. // Typically not used directly.
  14. //
  15. // targetId: String
  16. // id of the Widget OR DomNode that I will size
  17. targetId: '',
  18. // targetContainer: DomNode
  19. // over-ride targetId and attch this handle directly to a reference of a DomNode
  20. targetContainer: null,
  21. // resizeAxis: String
  22. // one of: x|y|xy limit resizing to a single axis, default to xy ...
  23. resizeAxis: "xy",
  24. // activeResize: Boolean
  25. // if true, node will size realtime with mouse movement,
  26. // if false, node will create virtual node, and only resize target on mouseUp
  27. activeResize: false,
  28. // activeResizeClass: String
  29. // css class applied to virtual resize node.
  30. activeResizeClass: 'dojoxResizeHandleClone',
  31. // animateSizing: Boolean
  32. // only applicable if activeResize = false. onMouseup, animate the node to the
  33. // new size
  34. animateSizing: true,
  35. // animateMethod: String
  36. // one of "chain" or "combine" ... visual effect only. combine will "scale"
  37. // node to size, "chain" will alter width, then height
  38. animateMethod: 'chain',
  39. // animateDuration: Integer
  40. // time in MS to run sizing animation. if animateMethod="chain", total animation
  41. // playtime is 2*animateDuration
  42. animateDuration: 225,
  43. // minHeight: Integer
  44. // smallest height in px resized node can be
  45. minHeight: 100,
  46. // minWidth: Integer
  47. // smallest width in px resize node can be
  48. minWidth: 100,
  49. templateString: '<div dojoAttachPoint="resizeHandle" class="dojoxResizeHandle"><div></div></div>',
  50. postCreate: function(){
  51. // summary: setup our one major listener upon creation
  52. this.connect(this.resizeHandle, "onmousedown", "_beginSizing");
  53. if(!this.activeResize){
  54. // there shall be only a single resize rubberbox that at the top
  55. // level so that we can overlay it on anything whenever the user
  56. // resizes something. Since there is only one mouse pointer he
  57. // can't at once resize multiple things interactively.
  58. this._resizeHelper = dijit.byId('dojoxGlobalResizeHelper');
  59. if (!this._resizeHelper){
  60. var tmpNode = document.createElement('div');
  61. tmpNode.style.display = "none";
  62. dojo.body().appendChild(tmpNode);
  63. dojo.addClass(tmpNode,this.activeResizeClass);
  64. this._resizeHelper = new dojox.layout._ResizeHelper({
  65. id: 'dojoxGlobalResizeHelper'},tmpNode);
  66. this._resizeHelper.startup();
  67. }
  68. }else{ this.animateSizing = false; }
  69. if (!this.minSize) {
  70. this.minSize = { w: this.minWidth, h: this.minHeight };
  71. }
  72. // should we modify the css for the cursor hover to n-resize nw-resize and w-resize?
  73. this._resizeX = this._resizeY = false;
  74. switch (this.resizeAxis.toLowerCase()) {
  75. case "xy" :
  76. this._resizeX = this._resizeY = true;
  77. // FIXME: need logic to determine NW or NE class to see
  78. // based on which [todo] corner is clicked
  79. dojo.addClass(this.resizeHandle,"dojoxResizeNW");
  80. break;
  81. case "x" :
  82. this._resizeX = true;
  83. dojo.addClass(this.resizeHandle,"dojoxResizeW");
  84. break;
  85. case "y" :
  86. this._resizeY = true;
  87. dojo.addClass(this.resizeHandle,"dojoxResizeN");
  88. break;
  89. }
  90. },
  91. _beginSizing: function(/*Event*/ e){
  92. // summary: setup movement listeners and calculate initial size
  93. if (this._isSizing){ return false; }
  94. this.targetWidget = dijit.byId(this.targetId);
  95. this.targetDomNode = this.targetWidget ? this.targetWidget.domNode : dojo.byId(this.targetId);
  96. if (this.targetContainer) { this.targetDomNode = this.targetContainer; }
  97. if (!this.targetDomNode){ return false; }
  98. if (!this.activeResize) {
  99. var c = dojo.coords(this.targetDomNode, true);
  100. this._resizeHelper.resize({l: c.x, t: c.y, w: c.w, h: c.h});
  101. this._resizeHelper.show();
  102. }
  103. this._isSizing = true;
  104. this.startPoint = {'x':e.clientX, 'y':e.clientY};
  105. // FIXME: this is funky: marginBox adds height, contentBox ignores padding (expected, but foo!)
  106. var mb = (this.targetWidget) ? dojo.marginBox(this.targetDomNode) : dojo.contentBox(this.targetDomNode);
  107. this.startSize = { 'w':mb.w, 'h':mb.h };
  108. this._pconnects = [];
  109. this._pconnects.push(dojo.connect(document,"onmousemove",this,"_updateSizing"));
  110. this._pconnects.push(dojo.connect(document,"onmouseup", this, "_endSizing"));
  111. e.preventDefault();
  112. },
  113. _updateSizing: function(/*Event*/ e){
  114. // summary: called when moving the ResizeHandle ... determines
  115. // new size based on settings/position and sets styles.
  116. if(this.activeResize){
  117. this._changeSizing(e);
  118. }else{
  119. var tmp = this._getNewCoords(e);
  120. if(tmp === false){ return; }
  121. this._resizeHelper.resize(tmp);
  122. }
  123. e.preventDefault();
  124. },
  125. _getNewCoords: function(/* Event */ e){
  126. // On IE, if you move the mouse above/to the left of the object being resized,
  127. // sometimes clientX/Y aren't set, apparently. Just ignore the event.
  128. try{
  129. if(!e.clientX || !e.clientY){ return false; }
  130. }catch(e){
  131. // sometimes you get an exception accessing above fields...
  132. return false;
  133. }
  134. this._activeResizeLastEvent = e;
  135. var dx = this.startPoint.x - e.clientX;
  136. var dy = this.startPoint.y - e.clientY;
  137. var newW = (this._resizeX) ? this.startSize.w - dx : this.startSize.w;
  138. var newH = (this._resizeY) ? this.startSize.h - dy : this.startSize.h;
  139. // minimum size check
  140. if(this.minSize){
  141. //var mb = dojo.marginBox(this.targetDomNode);
  142. if(newW < this.minSize.w){
  143. newW = this.minSize.w;
  144. }
  145. if(newH < this.minSize.h){
  146. newH = this.minSize.h;
  147. }
  148. }
  149. return {w:newW, h:newH}; // Object
  150. },
  151. _changeSizing: function(/*Event*/ e){
  152. // summary: apply sizing information based on information in (e) to attached node
  153. var tmp = this._getNewCoords(e);
  154. if(tmp===false){ return; }
  155. if(this.targetWidget && typeof this.targetWidget.resize == "function"){
  156. this.targetWidget.resize(tmp);
  157. }else{
  158. if(this.animateSizing){
  159. var anim = dojo.fx[this.animateMethod]([
  160. dojo.animateProperty({
  161. node: this.targetDomNode,
  162. properties: {
  163. width: { start: this.startSize.w, end: tmp.w, unit:'px' }
  164. },
  165. duration: this.animateDuration
  166. }),
  167. dojo.animateProperty({
  168. node: this.targetDomNode,
  169. properties: {
  170. height: { start: this.startSize.h, end: tmp.h, unit:'px' }
  171. },
  172. duration: this.animateDuration
  173. })
  174. ]);
  175. anim.play();
  176. }else{
  177. dojo.style(this.targetDomNode,"width",tmp.w+"px");
  178. dojo.style(this.targetDomNode,"height",tmp.h+"px");
  179. }
  180. }
  181. },
  182. _endSizing: function(/*Event*/ e){
  183. // summary: disconnect listenrs and cleanup sizing
  184. dojo.forEach(this._pconnects,dojo.disconnect);
  185. if(!this.activeResize){
  186. this._resizeHelper.hide();
  187. this._changeSizing(e);
  188. }
  189. this._isSizing = false;
  190. this.onResize(e);
  191. },
  192. onResize: function(e){
  193. // summary: Stub fired when sizing is done, for things like Grid
  194. }
  195. });
  196. dojo.declare("dojox.layout._ResizeHelper",
  197. dijit._Widget,
  198. {
  199. // summary: A global private resize helper shared between any resizeHandle with activeSizing='false;
  200. startup: function(){
  201. if(this._started){ return; }
  202. this.inherited(arguments);
  203. },
  204. show: function(){
  205. // summary: show helper to start resizing
  206. dojo.fadeIn({ node: this.domNode, duration:120,
  207. beforeBegin: dojo.hitch(this,function(){
  208. this.domNode.style.display='';
  209. })
  210. }).play();
  211. },
  212. hide: function(){
  213. // summary: hide helper after resizing is complete
  214. dojo.fadeOut({ node:this.domNode, duration:250,
  215. onEnd: dojo.hitch(this,function(){
  216. this.domNode.style.display="none";
  217. })
  218. }).play();
  219. },
  220. resize: function(/* Object */dim){
  221. // summary: size the widget and place accordingly
  222. // FIXME: this is off when padding present
  223. dojo.marginBox(this.domNode, dim);
  224. }
  225. });