FloatingPane.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. require({cache:{
  2. 'url:dojox/layout/resources/FloatingPane.html':"<div class=\"dojoxFloatingPane\" id=\"${id}\">\n\t<div tabindex=\"0\" role=\"button\" class=\"dojoxFloatingPaneTitle\" dojoAttachPoint=\"focusNode\">\n\t\t<span dojoAttachPoint=\"closeNode\" dojoAttachEvent=\"onclick: close\" class=\"dojoxFloatingCloseIcon\"></span>\n\t\t<span dojoAttachPoint=\"maxNode\" dojoAttachEvent=\"onclick: maximize\" class=\"dojoxFloatingMaximizeIcon\">&thinsp;</span>\n\t\t<span dojoAttachPoint=\"restoreNode\" dojoAttachEvent=\"onclick: _restore\" class=\"dojoxFloatingRestoreIcon\">&thinsp;</span>\t\n\t\t<span dojoAttachPoint=\"dockNode\" dojoAttachEvent=\"onclick: minimize\" class=\"dojoxFloatingMinimizeIcon\">&thinsp;</span>\n\t\t<span dojoAttachPoint=\"titleNode\" class=\"dijitInline dijitTitleNode\"></span>\n\t</div>\n\t<div dojoAttachPoint=\"canvas\" class=\"dojoxFloatingPaneCanvas\">\n\t\t<div dojoAttachPoint=\"containerNode\" role=\"region\" tabindex=\"-1\" class=\"${contentClass}\">\n\t\t</div>\n\t\t<span dojoAttachPoint=\"resizeHandle\" class=\"dojoxFloatingResizeHandle\"></span>\n\t</div>\n</div>\n"}});
  3. define("dojox/layout/FloatingPane", ["dojo/_base/kernel","dojo/_base/lang","dojo/_base/window","dojo/_base/declare",
  4. "dojo/_base/fx","dojo/_base/connect","dojo/_base/array","dojo/_base/sniff",
  5. "dojo/window","dojo/dom","dojo/dom-class","dojo/dom-geometry","dojo/dom-construct",
  6. "dijit/_TemplatedMixin","dijit/_Widget","dijit/BackgroundIframe","dojo/dnd/Moveable",
  7. "./ContentPane","./ResizeHandle","dojo/text!./resources/FloatingPane.html"], function(
  8. kernel, lang, winUtil, declare, baseFx, connectUtil, arrayUtil,
  9. has, windowLib, dom, domClass, domGeom, domConstruct, TemplatedMixin, Widget, BackgroundIframe,
  10. Moveable, ContentPane, ResizeHandle, template){
  11. /*=====
  12. var Widget = dijit._Widget;
  13. var TemplatedMixin = dijit._TemplatedMixin;
  14. var ContentPane = dojox.layout.ContentPane;
  15. =====*/
  16. kernel.experimental("dojox.layout.FloatingPane");
  17. var FloatingPane = declare("dojox.layout.FloatingPane", [ ContentPane, TemplatedMixin ],{
  18. // summary:
  19. // A non-modal Floating window.
  20. //
  21. // description:
  22. // Makes a `dojox.layout.ContentPane` float and draggable by it's title [similar to TitlePane]
  23. // and over-rides onClick to onDblClick for wipeIn/Out of containerNode
  24. // provides minimize(dock) / show() and hide() methods, and resize [almost]
  25. //
  26. // closable: Boolean
  27. // Allow closure of this Node
  28. closable: true,
  29. // dockable: Boolean
  30. // Allow minimizing of pane if true
  31. dockable: true,
  32. // resizable: Boolean
  33. // Allow resizing of pane true if true
  34. resizable: false,
  35. // maxable: Boolean
  36. // Horrible param name for "Can you maximize this floating pane?"
  37. maxable: false,
  38. // resizeAxis: String
  39. // One of: x | xy | y to limit pane's sizing direction
  40. resizeAxis: "xy",
  41. // title: String
  42. // Title to use in the header
  43. title: "",
  44. // dockTo: DomNode?
  45. // if empty, will create private layout.Dock that scrolls with viewport
  46. // on bottom span of viewport.
  47. dockTo: "",
  48. // duration: Integer
  49. // Time is MS to spend toggling in/out node
  50. duration: 400,
  51. /*=====
  52. // iconSrc: String
  53. // [not implemented yet] will be either icon in titlepane to left
  54. // of Title, and/or icon show when docked in a fisheye-like dock
  55. // or maybe dockIcon would be better?
  56. iconSrc: null,
  57. =====*/
  58. // contentClass: String
  59. // The className to give to the inner node which has the content
  60. contentClass: "dojoxFloatingPaneContent",
  61. // animation holders for toggle
  62. _showAnim: null,
  63. _hideAnim: null,
  64. // node in the dock (if docked)
  65. _dockNode: null,
  66. // privates:
  67. _restoreState: {},
  68. _allFPs: [],
  69. _startZ: 100,
  70. templateString: template,
  71. attributeMap: lang.delegate(Widget.prototype.attributeMap, {
  72. title: { type:"innerHTML", node:"titleNode" }
  73. }),
  74. postCreate: function(){
  75. this.inherited(arguments);
  76. new Moveable(this.domNode,{ handle: this.focusNode });
  77. //this._listener = dojo.subscribe("/dnd/move/start",this,"bringToTop");
  78. if(!this.dockable){ this.dockNode.style.display = "none"; }
  79. if(!this.closable){ this.closeNode.style.display = "none"; }
  80. if(!this.maxable){
  81. this.maxNode.style.display = "none";
  82. this.restoreNode.style.display = "none";
  83. }
  84. if(!this.resizable){
  85. this.resizeHandle.style.display = "none";
  86. }else{
  87. this.domNode.style.width = domGeom.getMarginBox(this.domNode).w + "px";
  88. }
  89. this._allFPs.push(this);
  90. this.domNode.style.position = "absolute";
  91. this.bgIframe = new BackgroundIframe(this.domNode);
  92. this._naturalState = domGeom.position(this.domNode);
  93. },
  94. startup: function(){
  95. if(this._started){ return; }
  96. this.inherited(arguments);
  97. if(this.resizable){
  98. if(has("ie")){
  99. this.canvas.style.overflow = "auto";
  100. }else{
  101. this.containerNode.style.overflow = "auto";
  102. }
  103. this._resizeHandle = new ResizeHandle({
  104. targetId: this.id,
  105. resizeAxis: this.resizeAxis
  106. },this.resizeHandle);
  107. }
  108. if(this.dockable){
  109. // FIXME: argh.
  110. var tmpName = this.dockTo;
  111. if(this.dockTo){
  112. this.dockTo = dijit.byId(this.dockTo);
  113. }else{
  114. this.dockTo = dijit.byId('dojoxGlobalFloatingDock');
  115. }
  116. if(!this.dockTo){
  117. var tmpId, tmpNode;
  118. // we need to make our dock node, and position it against
  119. // .dojoxDockDefault .. this is a lot. either dockto="node"
  120. // and fail if node doesn't exist or make the global one
  121. // once, and use it on empty OR invalid dockTo="" node?
  122. if(tmpName){
  123. tmpId = tmpName;
  124. tmpNode = dom.byId(tmpName);
  125. }else{
  126. tmpNode = domConstruct.create('div', null, winUtil.body());
  127. domClass.add(tmpNode,"dojoxFloatingDockDefault");
  128. tmpId = 'dojoxGlobalFloatingDock';
  129. }
  130. this.dockTo = new Dock({ id: tmpId, autoPosition: "south" }, tmpNode);
  131. this.dockTo.startup();
  132. }
  133. if((this.domNode.style.display == "none")||(this.domNode.style.visibility == "hidden")){
  134. // If the FP is created dockable and non-visible, start up docked.
  135. this.minimize();
  136. }
  137. }
  138. this.connect(this.focusNode,"onmousedown","bringToTop");
  139. this.connect(this.domNode, "onmousedown","bringToTop");
  140. // Initial resize to give child the opportunity to lay itself out
  141. this.resize(domGeom.position(this.domNode));
  142. this._started = true;
  143. },
  144. setTitle: function(/* String */ title){
  145. // summary: Update the Title bar with a new string
  146. kernel.deprecated("pane.setTitle", "Use pane.set('title', someTitle)", "2.0");
  147. this.set("title", title);
  148. },
  149. close: function(){
  150. // summary: Close and destroy this widget
  151. if(!this.closable){ return; }
  152. connectUtil.unsubscribe(this._listener);
  153. this.hide(lang.hitch(this,function(){
  154. this.destroyRecursive();
  155. }));
  156. },
  157. hide: function(/* Function? */ callback){
  158. // summary: Close, but do not destroy this FloatingPane
  159. baseFx.fadeOut({
  160. node:this.domNode,
  161. duration:this.duration,
  162. onEnd: lang.hitch(this,function() {
  163. this.domNode.style.display = "none";
  164. this.domNode.style.visibility = "hidden";
  165. if(this.dockTo && this.dockable){
  166. this.dockTo._positionDock(null);
  167. }
  168. if(callback){
  169. callback();
  170. }
  171. })
  172. }).play();
  173. },
  174. show: function(/* Function? */callback){
  175. // summary: Show the FloatingPane
  176. var anim = baseFx.fadeIn({node:this.domNode, duration:this.duration,
  177. beforeBegin: lang.hitch(this,function(){
  178. this.domNode.style.display = "";
  179. this.domNode.style.visibility = "visible";
  180. if (this.dockTo && this.dockable) { this.dockTo._positionDock(null); }
  181. if (typeof callback == "function") { callback(); }
  182. this._isDocked = false;
  183. if (this._dockNode) {
  184. this._dockNode.destroy();
  185. this._dockNode = null;
  186. }
  187. })
  188. }).play();
  189. this.resize(domGeom.position(this.domNode));
  190. this._onShow(); // lazy load trigger
  191. },
  192. minimize: function(){
  193. // summary: Hide and dock the FloatingPane
  194. if(!this._isDocked){ this.hide(lang.hitch(this,"_dock")); }
  195. },
  196. maximize: function(){
  197. // summary: Make this FloatingPane full-screen (viewport)
  198. if(this._maximized){ return; }
  199. this._naturalState = domGeom.position(this.domNode);
  200. if(this._isDocked){
  201. this.show();
  202. setTimeout(lang.hitch(this,"maximize"),this.duration);
  203. }
  204. domClass.add(this.focusNode,"floatingPaneMaximized");
  205. this.resize(windowLib.getBox());
  206. this._maximized = true;
  207. },
  208. _restore: function(){
  209. if(this._maximized){
  210. this.resize(this._naturalState);
  211. domClass.remove(this.focusNode,"floatingPaneMaximized");
  212. this._maximized = false;
  213. }
  214. },
  215. _dock: function(){
  216. if(!this._isDocked && this.dockable){
  217. this._dockNode = this.dockTo.addNode(this);
  218. this._isDocked = true;
  219. }
  220. },
  221. resize: function(/* Object */dim){
  222. // summary: Size the FloatingPane and place accordingly
  223. dim = dim || this._naturalState;
  224. this._naturalState = dim;
  225. // From the ResizeHandle we only get width and height information
  226. var dns = this.domNode.style;
  227. if("t" in dim){ dns.top = dim.t + "px"; }
  228. else if("y" in dim){ dns.top = dim.y + "px"; }
  229. if("l" in dim){ dns.left = dim.l + "px"; }
  230. else if("x" in dim){ dns.left = dim.x + "px"; }
  231. dns.width = dim.w + "px";
  232. dns.height = dim.h + "px";
  233. // Now resize canvas
  234. var mbCanvas = { l: 0, t: 0, w: dim.w, h: (dim.h - this.focusNode.offsetHeight) };
  235. domGeom.setMarginBox(this.canvas, mbCanvas);
  236. // If the single child can resize, forward resize event to it so it can
  237. // fit itself properly into the content area
  238. this._checkIfSingleChild();
  239. if(this._singleChild && this._singleChild.resize){
  240. this._singleChild.resize(mbCanvas);
  241. }
  242. },
  243. bringToTop: function(){
  244. // summary: bring this FloatingPane above all other panes
  245. var windows = arrayUtil.filter(
  246. this._allFPs,
  247. function(i){
  248. return i !== this;
  249. },
  250. this);
  251. windows.sort(function(a, b){
  252. return a.domNode.style.zIndex - b.domNode.style.zIndex;
  253. });
  254. windows.push(this);
  255. arrayUtil.forEach(windows, function(w, x){
  256. w.domNode.style.zIndex = this._startZ + (x * 2);
  257. domClass.remove(w.domNode, "dojoxFloatingPaneFg");
  258. }, this);
  259. domClass.add(this.domNode, "dojoxFloatingPaneFg");
  260. },
  261. destroy: function(){
  262. // summary: Destroy this FloatingPane completely
  263. this._allFPs.splice(arrayUtil.indexOf(this._allFPs, this), 1);
  264. if(this._resizeHandle){
  265. this._resizeHandle.destroy();
  266. }
  267. this.inherited(arguments);
  268. }
  269. });
  270. var Dock = declare("dojox.layout.Dock",[Widget, TemplatedMixin],{
  271. // summary:
  272. // A widget that attaches to a node and keeps track of incoming / outgoing FloatingPanes
  273. // and handles layout
  274. templateString: '<div class="dojoxDock"><ul dojoAttachPoint="containerNode" class="dojoxDockList"></ul></div>',
  275. // private _docked: array of panes currently in our dock
  276. _docked: [],
  277. _inPositioning: false,
  278. autoPosition: false,
  279. addNode: function(refNode){
  280. // summary: Instert a dockNode refernce into the dock
  281. var div = domConstruct.create('li', null, this.containerNode),
  282. node = new DockNode({
  283. title: refNode.title,
  284. paneRef: refNode
  285. }, div)
  286. ;
  287. node.startup();
  288. return node;
  289. },
  290. startup: function(){
  291. if (this.id == "dojoxGlobalFloatingDock" || this.isFixedDock) {
  292. // attach window.onScroll, and a position like in presentation/dialog
  293. this.connect(window, 'onresize', "_positionDock");
  294. this.connect(window, 'onscroll', "_positionDock");
  295. if(has("ie")){
  296. this.connect(this.domNode, "onresize", "_positionDock");
  297. }
  298. }
  299. this._positionDock(null);
  300. this.inherited(arguments);
  301. },
  302. _positionDock: function(/* Event? */e){
  303. if(!this._inPositioning){
  304. if(this.autoPosition == "south"){
  305. // Give some time for scrollbars to appear/disappear
  306. setTimeout(lang.hitch(this, function() {
  307. this._inPositiononing = true;
  308. var viewport = windowLib.getBox();
  309. var s = this.domNode.style;
  310. s.left = viewport.l + "px";
  311. s.width = (viewport.w-2) + "px";
  312. s.top = (viewport.h + viewport.t) - this.domNode.offsetHeight + "px";
  313. this._inPositioning = false;
  314. }), 125);
  315. }
  316. }
  317. }
  318. });
  319. var DockNode = declare("dojox.layout._DockNode",[Widget, TemplatedMixin],{
  320. // summary:
  321. // dojox.layout._DockNode is a private widget used to keep track of
  322. // which pane is docked.
  323. //
  324. // title: String
  325. // Shown in dock icon. should read parent iconSrc?
  326. title: "",
  327. // paneRef: Widget
  328. // reference to the FloatingPane we reprasent in any given dock
  329. paneRef: null,
  330. templateString:
  331. '<li dojoAttachEvent="onclick: restore" class="dojoxDockNode">'+
  332. '<span dojoAttachPoint="restoreNode" class="dojoxDockRestoreButton" dojoAttachEvent="onclick: restore"></span>'+
  333. '<span class="dojoxDockTitleNode" dojoAttachPoint="titleNode">${title}</span>'+
  334. '</li>',
  335. restore: function(){
  336. // summary: remove this dock item from parent dock, and call show() on reffed floatingpane
  337. this.paneRef.show();
  338. this.paneRef.bringToTop();
  339. this.destroy();
  340. }
  341. });
  342. return FloatingPane;
  343. });