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