You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
454 lines
14 KiB
454 lines
14 KiB
define([ |
|
"dojo/aspect", |
|
"dojo/_base/declare", // declare |
|
"dojo/dom-class", // domClass.add domClass.remove |
|
"dojo/dom-geometry", |
|
"dojo/dom-style", |
|
"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, 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(); |
|
e.stopPropagation(); |
|
e.preventDefault(); |
|
this.editor.defer("focus", 250); |
|
return true; |
|
})); |
|
this.own(on(this.editor.domNode, "keydown", lang.hitch(this, "_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.stopPropagation(); |
|
event.preventDefault(); |
|
}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; |
|
});
|
|
|