FloatingPane.js 12 KB

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