define("dijit/_editor/plugins/FullScreen", [ "dojo/aspect", "dojo/_base/declare", // declare "dojo/dom-class", // domClass.add domClass.remove "dojo/dom-geometry", "dojo/dom-style", "dojo/_base/event", // event.stop "dojo/i18n", // i18n.getLocalization "dojo/keys", // keys.F11 keys.TAB "dojo/_base/lang", // lang.hitch "dojo/on", // on() "dojo/sniff", // has("ie"), has("quirks") "dojo/_base/window", // win.body "dojo/window", // winUtils.getBox winUtils.scrollIntoView "../../focus", // focus.focus(), focus.curNode "../_Plugin", "../../form/ToggleButton", "../../registry", // registry.getEnclosingWidget() "dojo/i18n!../nls/commands" ], function(aspect, declare, domClass, domGeometry, domStyle, event, i18n, keys, lang, on, has, win, winUtils, focus, _Plugin, ToggleButton, registry){ // module: // dijit/_editor/plugins/FullScreen var FullScreen = declare("dijit._editor.plugins.FullScreen",_Plugin,{ // summary: // This plugin provides FullScreen capability to the editor. When // toggled on, it will render the editor into the full window and // overlay everything. It also binds to the hotkey: CTRL-SHIFT-F11 // for toggling fullscreen mode. // zIndex: [public] Number // zIndex value used for overlaying the full page. // default is 500. zIndex: 500, // _origState: [private] Object // The original view state of the editor. _origState: null, // _origiFrameState: [private] Object // The original view state of the iframe of the editor. _origiFrameState: null, // _resizeHandle: [private] Object // Connection point used for handling resize when window resizes. _resizeHandle: null, // isFullscreen: [const] boolean // Read-Only variable used to denote of the editor is in fullscreen mode or not. isFullscreen: false, toggle: function(){ // summary: // Function to allow programmatic toggling of the view. this.button.set("checked", !this.button.get("checked")); }, _initButton: function(){ // summary: // Over-ride for creation of the resize button. var strings = i18n.getLocalization("dijit._editor", "commands"), editor = this.editor; this.button = new ToggleButton({ label: strings["fullScreen"], ownerDocument: editor.ownerDocument, dir: editor.dir, lang: editor.lang, showLabel: false, iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen", tabIndex: "-1", onChange: lang.hitch(this, "_setFullScreen") }); }, setEditor: function(editor){ // summary: // Over-ride for the setting of the editor. // editor: Object // The editor to configure for this plugin to use. this.editor = editor; this._initButton(); this.editor.addKeyHandler(keys.F11, true, true, lang.hitch(this, function(e){ // Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode. this.toggle(); event.stop(e); setTimeout(lang.hitch(this, function(){this.editor.focus();}), 250); return true; })); this.connect(this.editor.domNode, "onkeydown", "_containFocus"); }, _containFocus: function(e){ // summary: // When in Full Screen mode, it's good to try and retain focus in the editor // so this function is intended to try and constrain the TAB key. // e: Event // The key event. // tags: // private if(this.isFullscreen){ var ed = this.editor; if(!ed.isTabIndent && ed._fullscreen_oldOnKeyDown && e.keyCode === keys.TAB){ // If we're in fullscreen mode, we want to take over how tab moves focus a bit. // to keep it within the editor since it's hiding the rest of the page. // IE hates changing focus IN the event handler, so need to put calls // in a timeout. Gotta love IE. // Also need to check for alternate view nodes if present and active. var f = focus.curNode; var avn = this._getAltViewNode(); if(f == ed.iframe || (avn && f === avn)){ setTimeout(lang.hitch(this, function(){ ed.toolbar.focus(); }), 10); }else{ if(avn && domStyle.get(ed.iframe, "display") === "none"){ setTimeout(lang.hitch(this, function(){ focus.focus(avn); }), 10); }else{ setTimeout(lang.hitch(this, function(){ ed.focus(); }), 10); } } event.stop(e); }else if(ed._fullscreen_oldOnKeyDown){ // Only call up when it's a different function. Traps corner case event issue // on IE which caused stack overflow on handler cleanup. ed._fullscreen_oldOnKeyDown(e); } } }, _resizeEditor: function(){ // summary: // Function to handle resizing the editor as the viewport // resizes (window scaled) // tags: // private var vp = winUtils.getBox(this.editor.ownerDocument); domGeometry.setMarginBox(this.editor.domNode, { w: vp.w, h: vp.h }); //Adjust the internal heights too, as they can be a bit off. var hHeight = this.editor.getHeaderHeight(); var fHeight = this.editor.getFooterHeight(); var extents = domGeometry.getPadBorderExtents(this.editor.domNode); var fcpExtents = domGeometry.getPadBorderExtents(this.editor.iframe.parentNode); var fcmExtents = domGeometry.getMarginExtents(this.editor.iframe.parentNode); var cHeight = vp.h - (hHeight + extents.h + fHeight); domGeometry.setMarginBox(this.editor.iframe.parentNode, { h: cHeight, w: vp.w }); domGeometry.setMarginBox(this.editor.iframe, { h: cHeight - (fcpExtents.h + fcmExtents.h) }); }, _getAltViewNode: function(){ // summary: // This function is intended as a hook point for setting an // alternate view node for when in full screen mode and the // editable iframe is hidden. // tags: // protected. }, _setFullScreen: function(full){ // summary: // Function to handle toggling between full screen and // regular view. // tags: // private //Alias this for shorter code. var ed = this.editor; var body = ed.ownerDocumentBody; var editorParent = ed.domNode.parentNode; var vp = winUtils.getBox(ed.ownerDocument); this.isFullscreen = full; if(full){ //Parent classes can royally screw up this plugin, so we //have to set everything to position static. while(editorParent && editorParent !== body){ domClass.add(editorParent, "dijitForceStatic"); editorParent = editorParent.parentNode; } // Save off the resize function. We want to kill its behavior. this._editorResizeHolder = this.editor.resize; ed.resize = function(){} ; // Try to constrain focus control. ed._fullscreen_oldOnKeyDown = ed.onKeyDown; ed.onKeyDown = lang.hitch(this, this._containFocus); this._origState = {}; this._origiFrameState = {}; // Store the basic editor state we have to restore later. // Not using domStyle.get here, had problems, didn't // give me stuff like 100%, gave me pixel calculated values. // Need the exact original values. var domNode = ed.domNode, rawStyle = domNode && domNode.style || {}; this._origState = { width: rawStyle.width || "", height: rawStyle.height || "", top: domStyle.get(domNode, "top") || "", left: domStyle.get(domNode, "left") || "", position: domStyle.get(domNode, "position") || "static", marginBox: domGeometry.getMarginBox(ed.domNode) }; // Store the iframe state we have to restore later. // Not using domStyle.get here, had problems, didn't // give me stuff like 100%, gave me pixel calculated values. // Need the exact original values. var iframe = ed.iframe, iframeStyle = iframe && iframe.style || {}; var bc = domStyle.get(ed.iframe, "backgroundColor"); this._origiFrameState = { backgroundColor: bc || "transparent", width: iframeStyle.width || "auto", height: iframeStyle.height || "auto", zIndex: iframeStyle.zIndex || "" }; // Okay, size everything. domStyle.set(ed.domNode, { position: "absolute", top: "0px", left: "0px", zIndex: this.zIndex, width: vp.w + "px", height: vp.h + "px" }); domStyle.set(ed.iframe, { height: "100%", width: "100%", zIndex: this.zIndex, backgroundColor: bc !== "transparent" && bc !== "rgba(0, 0, 0, 0)"?bc:"white" }); domStyle.set(ed.iframe.parentNode, { height: "95%", width: "100%" }); // Store the overflow state we have to restore later. // IE had issues, so have to check that it's defined. Ugh. if(body.style && body.style.overflow){ this._oldOverflow = domStyle.get(body, "overflow"); }else{ this._oldOverflow = ""; } if(has("ie") && !has("quirks")){ // IE will put scrollbars in anyway, html (parent of body) // also controls them in standards mode, so we have to // remove them, argh. if(body.parentNode && body.parentNode.style && body.parentNode.style.overflow){ this._oldBodyParentOverflow = body.parentNode.style.overflow; }else{ try{ this._oldBodyParentOverflow = domStyle.get(body.parentNode, "overflow"); }catch(e){ this._oldBodyParentOverflow = "scroll"; } } domStyle.set(body.parentNode, "overflow", "hidden"); } domStyle.set(body, "overflow", "hidden"); var resizer = function(){ // function to handle resize events. // Will check current VP and only resize if // different. var vp = winUtils.getBox(ed.ownerDocument); if("_prevW" in this && "_prevH" in this){ // No actual size change, ignore. if(vp.w === this._prevW && vp.h === this._prevH){ return; } }else{ this._prevW = vp.w; this._prevH = vp.h; } if(this._resizer){ clearTimeout(this._resizer); delete this._resizer; } // Timeout it to help avoid spamming resize on IE. // Works for all browsers. this._resizer = setTimeout(lang.hitch(this, function(){ delete this._resizer; this._resizeEditor(); }), 10); }; this._resizeHandle = on(window, "resize", lang.hitch(this, resizer)); // Also monitor for direct calls to resize and adapt editor. this._resizeHandle2 = aspect.after(ed, "onResize", lang.hitch(this, function(){ if(this._resizer){ clearTimeout(this._resizer); delete this._resizer; } this._resizer = setTimeout(lang.hitch(this, function(){ delete this._resizer; this._resizeEditor(); }), 10); })); // Call it once to work around IE glitchiness. Safe for other browsers too. this._resizeEditor(); var dn = this.editor.toolbar.domNode; setTimeout(function(){winUtils.scrollIntoView(dn);}, 250); }else{ if(this._resizeHandle){ // Cleanup resizing listeners this._resizeHandle.remove(); this._resizeHandle = null; } if(this._resizeHandle2){ // Cleanup resizing listeners this._resizeHandle2.remove(); this._resizeHandle2 = null; } if(this._rst){ clearTimeout(this._rst); this._rst = null; } //Remove all position static class assigns. while(editorParent && editorParent !== body){ domClass.remove(editorParent, "dijitForceStatic"); editorParent = editorParent.parentNode; } // Restore resize function if(this._editorResizeHolder){ this.editor.resize = this._editorResizeHolder; } if(!this._origState && !this._origiFrameState){ // If we actually didn't toggle, then don't do anything. return; } if(ed._fullscreen_oldOnKeyDown){ ed.onKeyDown = ed._fullscreen_oldOnKeyDown; delete ed._fullscreen_oldOnKeyDown; } // Add a timeout to make sure we don't have a resize firing in the // background at the time of minimize. var self = this; setTimeout(function(){ // Restore all the editor state. var mb = self._origState.marginBox; var oh = self._origState.height; if(has("ie") && !has("quirks")){ body.parentNode.style.overflow = self._oldBodyParentOverflow; delete self._oldBodyParentOverflow; } domStyle.set(body, "overflow", self._oldOverflow); delete self._oldOverflow; domStyle.set(ed.domNode, self._origState); domStyle.set(ed.iframe.parentNode, { height: "", width: "" }); domStyle.set(ed.iframe, self._origiFrameState); delete self._origState; delete self._origiFrameState; // In case it is contained in a layout and the layout changed size, // go ahead and call resize. var pWidget = registry.getEnclosingWidget(ed.domNode.parentNode); if(pWidget && pWidget.resize){ pWidget.resize(); }else{ if(!oh || oh.indexOf("%") < 0){ // Resize if the original size wasn't set // or wasn't in percent. Timeout is to avoid // an IE crash in unit testing. setTimeout(lang.hitch(this, function(){ed.resize({h: mb.h});}), 0); } } winUtils.scrollIntoView(self.editor.toolbar.domNode); }, 100); } }, updateState: function(){ // summary: // Over-ride for button state control for disabled to work. this.button.set("disabled", this.get("disabled")); }, destroy: function(){ // summary: // Over-ride to ensure the resize handle gets cleaned up. if(this._resizeHandle){ // Cleanup resizing listeners this._resizeHandle.remove(); this._resizeHandle = null; } if(this._resizeHandle2){ // Cleanup resizing listeners this._resizeHandle2.remove(); this._resizeHandle2 = null; } if(this._resizer){ clearTimeout(this._resizer); this._resizer = null; } this.inherited(arguments); } }); // Register this plugin. // For back-compat accept "fullscreen" (all lowercase) too, remove in 2.0 _Plugin.registry["fullScreen"] = _Plugin.registry["fullscreen"] = function(args){ return new FullScreen({ zIndex: ("zIndex" in args)?args.zIndex:500 }); }; return FullScreen; });