FullScreen.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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["dijit._editor.plugins.FullScreen"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dijit._editor.plugins.FullScreen"] = true;
  8. dojo.provide("dijit._editor.plugins.FullScreen");
  9. dojo.require("dojo.window");
  10. dojo.require("dojo.i18n");
  11. dojo.require("dijit._editor._Plugin");
  12. dojo.require("dijit.form.Button");
  13. dojo.requireLocalization("dijit._editor", "commands", null, "ROOT,ar,az,bg,ca,cs,da,de,el,es,fi,fr,he,hr,hu,it,ja,kk,ko,nb,nl,pl,pt,pt-pt,ro,ru,sk,sl,sv,th,tr,zh,zh-tw");
  14. dojo.declare("dijit._editor.plugins.FullScreen",dijit._editor._Plugin,{
  15. // summary:
  16. // This plugin provides FullScreen cabability to the editor. When
  17. // toggled on, it will render the editor into the full window and
  18. // overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11
  19. // for toggling fullscreen mode.
  20. // zIndex: [public] Number
  21. // zIndex value used for overlaying the full page.
  22. // default is 500.
  23. zIndex: 500,
  24. // _origState: [private] Object
  25. // The original view state of the editor.
  26. _origState: null,
  27. // _origiFrameState: [private] Object
  28. // The original view state of the iframe of the editor.
  29. _origiFrameState: null,
  30. // _resizeHandle: [private] Object
  31. // Connection point used for handling resize when window resizes.
  32. _resizeHandle: null,
  33. // isFullscreen: [const] boolean
  34. // Read-Only variable used to denote of the editor is in fullscreen mode or not.
  35. isFullscreen: false,
  36. toggle: function(){
  37. // summary:
  38. // Function to allow programmatic toggling of the view.
  39. this.button.set("checked", !this.button.get("checked"));
  40. },
  41. _initButton: function(){
  42. // summary:
  43. // Over-ride for creation of the resize button.
  44. var strings = dojo.i18n.getLocalization("dijit._editor", "commands"),
  45. editor = this.editor;
  46. this.button = new dijit.form.ToggleButton({
  47. label: strings["fullScreen"],
  48. dir: editor.dir,
  49. lang: editor.lang,
  50. showLabel: false,
  51. iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen",
  52. tabIndex: "-1",
  53. onChange: dojo.hitch(this, "_setFullScreen")
  54. });
  55. },
  56. setEditor: function(editor){
  57. // summary:
  58. // Over-ride for the setting of the editor.
  59. // editor: Object
  60. // The editor to configure for this plugin to use.
  61. this.editor = editor;
  62. this._initButton();
  63. this.editor.addKeyHandler(dojo.keys.F11, true, true, dojo.hitch(this, function(e){
  64. // Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode.
  65. this.toggle();
  66. dojo.stopEvent(e);
  67. setTimeout(dojo.hitch(this, function(){this.editor.focus();}), 250);
  68. return true;
  69. }));
  70. this.connect(this.editor.domNode, "onkeydown", "_containFocus");
  71. },
  72. _containFocus: function(e){
  73. // summary:
  74. // When in Full Screen mode, it's good to try and retain focus in the editor
  75. // so this function is intended to try and constrain the TAB key.
  76. // e: Event
  77. // The key event.
  78. // tags:
  79. // private
  80. if(this.isFullscreen){
  81. var ed = this.editor;
  82. if(!ed.isTabIndent &&
  83. ed._fullscreen_oldOnKeyDown &&
  84. e.keyCode === dojo.keys.TAB){
  85. // If we're in fullscreen mode, we want to take over how tab moves focus a bit.
  86. // to keep it within the editor since it's hiding the rest of the page.
  87. // IE hates changing focus IN the event handler, so need to put calls
  88. // in a timeout. Gotta love IE.
  89. // Also need to check for alternate view nodes if present and active.
  90. var f = dijit.getFocus();
  91. var avn = this._getAltViewNode();
  92. if(f.node == ed.iframe ||
  93. (avn && f.node === avn)){
  94. setTimeout(dojo.hitch(this, function(){
  95. ed.toolbar.focus();
  96. }), 10);
  97. }else{
  98. if(avn && dojo.style(ed.iframe, "display") === "none"){
  99. setTimeout(dojo.hitch(this, function(){
  100. dijit.focus(avn);
  101. }), 10);
  102. }else{
  103. setTimeout(dojo.hitch(this, function(){
  104. ed.focus();
  105. }), 10);
  106. }
  107. }
  108. dojo.stopEvent(e);
  109. }else if(ed._fullscreen_oldOnKeyDown){
  110. // Only call up when it's a different function. Traps corner case event issue
  111. // on IE which caused stack overflow on handler cleanup.
  112. ed._fullscreen_oldOnKeyDown(e);
  113. }
  114. }
  115. },
  116. _resizeEditor: function(){
  117. // summary:
  118. // Function to handle resizing the editor as the viewport
  119. // resizes (window scaled)
  120. // tags:
  121. // private
  122. var vp = dojo.window.getBox();
  123. dojo.marginBox(this.editor.domNode, {
  124. w: vp.w,
  125. h: vp.h
  126. });
  127. //Adjust the inernal heights too, as they can be a bit off.
  128. var hHeight = this.editor.getHeaderHeight();
  129. var fHeight = this.editor.getFooterHeight();
  130. var extents = dojo._getPadBorderExtents(this.editor.domNode);
  131. var fcpExtents = dojo._getPadBorderExtents(this.editor.iframe.parentNode);
  132. var fcmExtents = dojo._getMarginExtents(this.editor.iframe.parentNode);
  133. var cHeight = vp.h - (hHeight + extents.h + fHeight);
  134. dojo.marginBox(this.editor.iframe.parentNode, {
  135. h: cHeight,
  136. w: vp.w
  137. });
  138. dojo.marginBox(this.editor.iframe, {
  139. h: cHeight - (fcpExtents.h + fcmExtents.h)
  140. });
  141. },
  142. _getAltViewNode: function(){
  143. // summary:
  144. // This function is intended as a hook point for setting an
  145. // alternate view node for when in full screen mode and the
  146. // editable iframe is hidden.
  147. // tags:
  148. // protected.
  149. },
  150. _setFullScreen: function(full){
  151. // summary:
  152. // Function to handle toggling between full screen and
  153. // regular view.
  154. // tags:
  155. // private
  156. var vp = dojo.window.getBox();
  157. //Alias this for shorter code.
  158. var ed = this.editor;
  159. var body = dojo.body();
  160. var editorParent = ed.domNode.parentNode;
  161. this.isFullscreen = full;
  162. if(full){
  163. //Parent classes can royally screw up this plugin, so we
  164. //have to set eveything to position static.
  165. while(editorParent && editorParent !== dojo.body()){
  166. dojo.addClass(editorParent, "dijitForceStatic");
  167. editorParent = editorParent.parentNode;
  168. }
  169. // Save off the resize function. We want to kill its behavior.
  170. this._editorResizeHolder = this.editor.resize;
  171. ed.resize = function() {} ;
  172. // Try to constrain focus control.
  173. ed._fullscreen_oldOnKeyDown = ed.onKeyDown;
  174. ed.onKeyDown = dojo.hitch(this, this._containFocus);
  175. this._origState = {};
  176. this._origiFrameState = {};
  177. // Store the basic editor state we have to restore later.
  178. // Not using dojo.style here, had problems, didn't
  179. // give me stuff like 100%, gave me pixel calculated values.
  180. // Need the exact original values.
  181. var domNode = ed.domNode,
  182. domStyle = domNode && domNode.style || {};
  183. this._origState = {
  184. width: domStyle.width || "",
  185. height: domStyle.height || "",
  186. top: dojo.style(domNode, "top") || "",
  187. left: dojo.style(domNode, "left") || "",
  188. position: dojo.style(domNode, "position") || "static",
  189. marginBox: dojo.marginBox(ed.domNode)
  190. };
  191. // Store the iframe state we have to restore later.
  192. // Not using dojo.style here, had problems, didn't
  193. // give me stuff like 100%, gave me pixel calculated values.
  194. // Need the exact original values.
  195. var iframe = ed.iframe,
  196. iframeStyle = iframe && iframe.style || {};
  197. var bc = dojo.style(ed.iframe, "backgroundColor");
  198. this._origiFrameState = {
  199. backgroundColor: bc || "transparent",
  200. width: iframeStyle.width || "auto",
  201. height: iframeStyle.height || "auto",
  202. zIndex: iframeStyle.zIndex || ""
  203. };
  204. // Okay, size everything.
  205. dojo.style(ed.domNode, {
  206. position: "absolute",
  207. top: "0px",
  208. left: "0px",
  209. zIndex: this.zIndex,
  210. width: vp.w + "px",
  211. height: vp.h + "px"
  212. });
  213. dojo.style(ed.iframe, {
  214. height: "100%",
  215. width: "100%",
  216. zIndex: this.zIndex,
  217. backgroundColor: bc !== "transparent" &&
  218. bc !== "rgba(0, 0, 0, 0)"?bc:"white"
  219. });
  220. dojo.style(ed.iframe.parentNode, {
  221. height: "95%",
  222. width: "100%"
  223. });
  224. // Store the overflow state we have to restore later.
  225. // IE had issues, so have to check that it's defined. Ugh.
  226. if(body.style && body.style.overflow){
  227. this._oldOverflow = dojo.style(body, "overflow");
  228. }else{
  229. this._oldOverflow = "";
  230. }
  231. if(dojo.isIE && !dojo.isQuirks){
  232. // IE will put scrollbars in anyway, html (parent of body)
  233. // also controls them in standards mode, so we have to
  234. // remove them, argh.
  235. if(body.parentNode &&
  236. body.parentNode.style &&
  237. body.parentNode.style.overflow){
  238. this._oldBodyParentOverflow = body.parentNode.style.overflow;
  239. }else{
  240. try{
  241. this._oldBodyParentOverflow = dojo.style(body.parentNode, "overflow");
  242. }catch(e){
  243. this._oldBodyParentOverflow = "scroll";
  244. }
  245. }
  246. dojo.style(body.parentNode, "overflow", "hidden");
  247. }
  248. dojo.style(body, "overflow", "hidden");
  249. var resizer = function(){
  250. // function to handle resize events.
  251. // Will check current VP and only resize if
  252. // different.
  253. var vp = dojo.window.getBox();
  254. if("_prevW" in this && "_prevH" in this){
  255. // No actual size change, ignore.
  256. if(vp.w === this._prevW && vp.h === this._prevH){
  257. return;
  258. }
  259. }else{
  260. this._prevW = vp.w;
  261. this._prevH = vp.h;
  262. }
  263. if(this._resizer){
  264. clearTimeout(this._resizer);
  265. delete this._resizer;
  266. }
  267. // Timeout it to help avoid spamming resize on IE.
  268. // Works for all browsers.
  269. this._resizer = setTimeout(dojo.hitch(this, function(){
  270. delete this._resizer;
  271. this._resizeEditor();
  272. }), 10);
  273. };
  274. this._resizeHandle = dojo.connect(window, "onresize", this, resizer);
  275. // Also monitor for direct calls to resize and adapt editor.
  276. this._resizeHandle2 = dojo.connect(ed, "resize", dojo.hitch(this, function(){
  277. if(this._resizer){
  278. clearTimeout(this._resizer);
  279. delete this._resizer;
  280. }
  281. this._resizer = setTimeout(dojo.hitch(this, function(){
  282. delete this._resizer;
  283. this._resizeEditor();
  284. }), 10);
  285. }));
  286. // Call it once to work around IE glitchiness. Safe for other browsers too.
  287. this._resizeEditor();
  288. var dn = this.editor.toolbar.domNode;
  289. setTimeout(function(){dojo.window.scrollIntoView(dn);}, 250);
  290. }else{
  291. if(this._resizeHandle){
  292. // Cleanup resizing listeners
  293. dojo.disconnect(this._resizeHandle);
  294. this._resizeHandle = null;
  295. }
  296. if(this._resizeHandle2){
  297. // Cleanup resizing listeners
  298. dojo.disconnect(this._resizeHandle2);
  299. this._resizeHandle2 = null;
  300. }
  301. if(this._rst){
  302. clearTimeout(this._rst);
  303. this._rst = null;
  304. }
  305. //Remove all position static class assigns.
  306. while(editorParent && editorParent !== dojo.body()){
  307. dojo.removeClass(editorParent, "dijitForceStatic");
  308. editorParent = editorParent.parentNode;
  309. }
  310. // Restore resize function
  311. if(this._editorResizeHolder){
  312. this.editor.resize = this._editorResizeHolder;
  313. }
  314. if(!this._origState && !this._origiFrameState){
  315. // If we actually didn't toggle, then don't do anything.
  316. return;
  317. }
  318. if(ed._fullscreen_oldOnKeyDown){
  319. ed.onKeyDown = ed._fullscreen_oldOnKeyDown;
  320. delete ed._fullscreen_oldOnKeyDown;
  321. }
  322. // Add a timeout to make sure we don't have a resize firing in the
  323. // background at the time of minimize.
  324. var self = this;
  325. setTimeout(function(){
  326. // Restore all the editor state.
  327. var mb = self._origState.marginBox;
  328. var oh = self._origState.height;
  329. if(dojo.isIE && !dojo.isQuirks){
  330. body.parentNode.style.overflow = self._oldBodyParentOverflow;
  331. delete self._oldBodyParentOverflow;
  332. }
  333. dojo.style(body, "overflow", self._oldOverflow);
  334. delete self._oldOverflow;
  335. dojo.style(ed.domNode, self._origState);
  336. dojo.style(ed.iframe.parentNode, {
  337. height: "",
  338. width: ""
  339. });
  340. dojo.style(ed.iframe, self._origiFrameState);
  341. delete self._origState;
  342. delete self._origiFrameState;
  343. // In case it is contained in a layout and the layout changed size,
  344. // go ahead and call resize.
  345. var pWidget = dijit.getEnclosingWidget(ed.domNode.parentNode);
  346. if(pWidget && pWidget.resize){
  347. pWidget.resize();
  348. }else{
  349. if(!oh || oh.indexOf("%") < 0){
  350. // Resize if the original size wasn't set
  351. // or wasn't in percent. Timeout is to avoid
  352. // an IE crash in unit testing.
  353. setTimeout(dojo.hitch(this, function(){ed.resize({h: mb.h});}), 0);
  354. }
  355. }
  356. dojo.window.scrollIntoView(self.editor.toolbar.domNode);
  357. }, 100);
  358. }
  359. },
  360. updateState: function(){
  361. // summary:
  362. // Over-ride for button state control for disabled to work.
  363. this.button.set("disabled", this.get("disabled"));
  364. },
  365. destroy: function(){
  366. // summary:
  367. // Over-ride to ensure the resize handle gets cleaned up.
  368. if(this._resizeHandle){
  369. // Cleanup resizing listeners
  370. dojo.disconnect(this._resizeHandle);
  371. this._resizeHandle = null;
  372. }
  373. if(this._resizeHandle2){
  374. // Cleanup resizing listeners
  375. dojo.disconnect(this._resizeHandle2);
  376. this._resizeHandle2 = null;
  377. }
  378. if(this._resizer){
  379. clearTimeout(this._resizer);
  380. this._resizer = null;
  381. }
  382. this.inherited(arguments);
  383. }
  384. });
  385. // Register this plugin.
  386. dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
  387. if(o.plugin){ return; }
  388. var name = o.args.name.toLowerCase();
  389. if(name === "fullscreen"){
  390. o.plugin = new dijit._editor.plugins.FullScreen({
  391. zIndex: ("zIndex" in o.args)?o.args.zIndex:500
  392. });
  393. }
  394. });
  395. }