source: Dev/trunk/src/client/dijit/_editor/plugins/FullScreen.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

  • Property svn:executable set to *
File size: 13.7 KB
Line 
1define([
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/i18n", // i18n.getLocalization
8        "dojo/keys", // keys.F11 keys.TAB
9        "dojo/_base/lang", // lang.hitch
10        "dojo/on", // on()
11        "dojo/sniff", // has("ie"), has("quirks")
12        "dojo/_base/window", // win.body
13        "dojo/window", // winUtils.getBox winUtils.scrollIntoView
14        "../../focus", // focus.focus(), focus.curNode
15        "../_Plugin",
16        "../../form/ToggleButton",
17        "../../registry", // registry.getEnclosingWidget()
18        "dojo/i18n!../nls/commands"
19], function(aspect, declare, domClass, domGeometry, domStyle, i18n, keys, lang, on, has, win, winUtils,
20                        focus, _Plugin, ToggleButton, registry){
21
22        // module:
23        //              dijit/_editor/plugins/FullScreen
24
25        var FullScreen = declare("dijit._editor.plugins.FullScreen", _Plugin, {
26                // summary:
27                //              This plugin provides FullScreen capability to the editor.  When
28                //              toggled on, it will render the editor into the full window and
29                //              overlay everything.  It also binds to the hotkey: CTRL-SHIFT-F11
30                //              for toggling fullscreen mode.
31
32                // zIndex: [public] Number
33                //              zIndex value used for overlaying the full page.
34                //              default is 500.
35                zIndex: 500,
36
37                // _origState: [private] Object
38                //              The original view state of the editor.
39                _origState: null,
40
41                // _origiFrameState: [private] Object
42                //              The original view state of the iframe of the editor.
43                _origiFrameState: null,
44
45                // _resizeHandle: [private] Object
46                //              Connection point used for handling resize when window resizes.
47                _resizeHandle: null,
48
49                // isFullscreen: [const] boolean
50                //              Read-Only variable used to denote of the editor is in fullscreen mode or not.
51                isFullscreen: false,
52
53                toggle: function(){
54                        // summary:
55                        //              Function to allow programmatic toggling of the view.
56                        this.button.set("checked", !this.button.get("checked"));
57                },
58
59                _initButton: function(){
60                        // summary:
61                        //              Over-ride for creation of the resize button.
62                        var strings = i18n.getLocalization("dijit._editor", "commands"),
63                                editor = this.editor;
64                        this.button = new ToggleButton({
65                                label: strings["fullScreen"],
66                                ownerDocument: editor.ownerDocument,
67                                dir: editor.dir,
68                                lang: editor.lang,
69                                showLabel: false,
70                                iconClass: this.iconClassPrefix + " " + this.iconClassPrefix + "FullScreen",
71                                tabIndex: "-1",
72                                onChange: lang.hitch(this, "_setFullScreen")
73                        });
74                },
75
76                setEditor: function(editor){
77                        // summary:
78                        //              Over-ride for the setting of the editor.
79                        // editor: Object
80                        //              The editor to configure for this plugin to use.
81                        this.editor = editor;
82                        this._initButton();
83
84                        this.editor.addKeyHandler(keys.F11, true, true, lang.hitch(this, function(e){
85                                // Enable the CTRL-SHIFT-F11 hotkey for fullscreen mode.
86                                this.toggle();
87                                e.stopPropagation();
88                                e.preventDefault();
89                                this.editor.defer("focus", 250);
90                                return true;
91                        }));
92                        this.own(on(this.editor.domNode, "keydown", lang.hitch(this, "_containFocus")));
93                },
94
95                _containFocus: function(e){
96                        // summary:
97                        //              When in Full Screen mode, it's good to try and retain focus in the editor
98                        //              so this function is intended to try and constrain the TAB key.
99                        // e: Event
100                        //              The key event.
101                        // tags:
102                        //              private
103                        if(this.isFullscreen){
104                                var ed = this.editor;
105                                if(!ed.isTabIndent &&
106                                        ed._fullscreen_oldOnKeyDown &&
107                                        e.keyCode === keys.TAB){
108                                        // If we're in fullscreen mode, we want to take over how tab moves focus a bit.
109                                        // to keep it within the editor since it's hiding the rest of the page.
110                                        // IE hates changing focus IN the event handler, so need to put calls
111                                        // in a timeout.  Gotta love IE.
112                                        // Also need to check for alternate view nodes if present and active.
113                                        var f = focus.curNode;
114                                        var avn = this._getAltViewNode();
115                                        if(f == ed.iframe ||
116                                                (avn && f === avn)){
117                                                setTimeout(lang.hitch(this, function(){
118                                                        ed.toolbar.focus();
119                                                }), 10);
120                                        }else{
121                                                if(avn && domStyle.get(ed.iframe, "display") === "none"){
122                                                        setTimeout(lang.hitch(this, function(){
123                                                                focus.focus(avn);
124                                                        }), 10);
125                                                }else{
126                                                        setTimeout(lang.hitch(this, function(){
127                                                                ed.focus();
128                                                        }), 10);
129                                                }
130                                        }
131                                        event.stopPropagation();
132                                        event.preventDefault();
133                                }else if(ed._fullscreen_oldOnKeyDown){
134                                        // Only call up when it's a different function.  Traps corner case event issue
135                                        // on IE which caused stack overflow on handler cleanup.
136                                        ed._fullscreen_oldOnKeyDown(e);
137                                }
138                        }
139                },
140
141                _resizeEditor: function(){
142                        // summary:
143                        //              Function to handle resizing the editor as the viewport
144                        //              resizes (window scaled)
145                        // tags:
146                        //              private
147                        var vp = winUtils.getBox(this.editor.ownerDocument);
148                        domGeometry.setMarginBox(this.editor.domNode, {
149                                w: vp.w,
150                                h: vp.h
151                        });
152
153                        //Adjust the internal heights too, as they can be a bit off.
154                        var hHeight = this.editor.getHeaderHeight();
155                        var fHeight = this.editor.getFooterHeight();
156                        var extents = domGeometry.getPadBorderExtents(this.editor.domNode);
157                        var fcpExtents = domGeometry.getPadBorderExtents(this.editor.iframe.parentNode);
158                        var fcmExtents = domGeometry.getMarginExtents(this.editor.iframe.parentNode);
159
160                        var cHeight = vp.h - (hHeight + extents.h + fHeight);
161                        domGeometry.setMarginBox(this.editor.iframe.parentNode, {
162                                h: cHeight,
163                                w: vp.w
164                        });
165                        domGeometry.setMarginBox(this.editor.iframe, {
166                                h: cHeight - (fcpExtents.h + fcmExtents.h)
167                        });
168                },
169
170                _getAltViewNode: function(){
171                        // summary:
172                        //              This function is intended as a hook point for setting an
173                        //              alternate view node for when in full screen mode and the
174                        //              editable iframe is hidden.
175                        // tags:
176                        //              protected.
177                },
178
179                _setFullScreen: function(full){
180                        // summary:
181                        //              Function to handle toggling between full screen and
182                        //              regular view.
183                        // tags:
184                        //              private
185
186                        //Alias this for shorter code.
187                        var ed = this.editor;
188                        var body = ed.ownerDocumentBody;
189                        var editorParent = ed.domNode.parentNode;
190
191                        var vp = winUtils.getBox(ed.ownerDocument);
192
193                        this.isFullscreen = full;
194
195                        if(full){
196                                //Parent classes can royally screw up this plugin, so we
197                                //have to set everything to position static.
198                                while(editorParent && editorParent !== body){
199                                        domClass.add(editorParent, "dijitForceStatic");
200                                        editorParent = editorParent.parentNode;
201                                }
202
203                                // Save off the resize function.  We want to kill its behavior.
204                                this._editorResizeHolder = this.editor.resize;
205                                ed.resize = function(){
206                                };
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(){
338                                        winUtils.scrollIntoView(dn);
339                                }, 250);
340                        }else{
341                                if(this._resizeHandle){
342                                        // Cleanup resizing listeners
343                                        this._resizeHandle.remove();
344                                        this._resizeHandle = null;
345                                }
346                                if(this._resizeHandle2){
347                                        // Cleanup resizing listeners
348                                        this._resizeHandle2.remove();
349                                        this._resizeHandle2 = null;
350                                }
351                                if(this._rst){
352                                        clearTimeout(this._rst);
353                                        this._rst = null;
354                                }
355
356                                //Remove all position static class assigns.
357                                while(editorParent && editorParent !== body){
358                                        domClass.remove(editorParent, "dijitForceStatic");
359                                        editorParent = editorParent.parentNode;
360                                }
361
362                                // Restore resize function
363                                if(this._editorResizeHolder){
364                                        this.editor.resize = this._editorResizeHolder;
365                                }
366
367                                if(!this._origState && !this._origiFrameState){
368                                        // If we actually didn't toggle, then don't do anything.
369                                        return;
370                                }
371                                if(ed._fullscreen_oldOnKeyDown){
372                                        ed.onKeyDown = ed._fullscreen_oldOnKeyDown;
373                                        delete ed._fullscreen_oldOnKeyDown;
374                                }
375
376                                // Add a timeout to make sure we don't have a resize firing in the
377                                // background at the time of minimize.
378                                var self = this;
379                                setTimeout(function(){
380                                        // Restore all the editor state.
381                                        var mb = self._origState.marginBox;
382                                        var oh = self._origState.height;
383                                        if(has("ie") && !has("quirks")){
384                                                body.parentNode.style.overflow = self._oldBodyParentOverflow;
385                                                delete self._oldBodyParentOverflow;
386                                        }
387                                        domStyle.set(body, "overflow", self._oldOverflow);
388                                        delete self._oldOverflow;
389
390                                        domStyle.set(ed.domNode, self._origState);
391                                        domStyle.set(ed.iframe.parentNode, {
392                                                height: "",
393                                                width: ""
394                                        });
395                                        domStyle.set(ed.iframe, self._origiFrameState);
396                                        delete self._origState;
397                                        delete self._origiFrameState;
398                                        // In case it is contained in a layout and the layout changed size,
399                                        // go ahead and call resize.
400                                        var pWidget = registry.getEnclosingWidget(ed.domNode.parentNode);
401                                        if(pWidget && pWidget.resize){
402                                                pWidget.resize();
403                                        }else{
404                                                if(!oh || oh.indexOf("%") < 0){
405                                                        // Resize if the original size wasn't set
406                                                        // or wasn't in percent.  Timeout is to avoid
407                                                        // an IE crash in unit testing.
408                                                        setTimeout(lang.hitch(this, function(){
409                                                                ed.resize({h: mb.h});
410                                                        }), 0);
411                                                }
412                                        }
413                                        winUtils.scrollIntoView(self.editor.toolbar.domNode);
414                                }, 100);
415                        }
416                },
417
418                updateState: function(){
419                        // summary:
420                        //              Over-ride for button state control for disabled to work.
421                        this.button.set("disabled", this.get("disabled"));
422                },
423
424                destroy: function(){
425                        // summary:
426                        //              Over-ride to ensure the resize handle gets cleaned up.
427                        if(this._resizeHandle){
428                                // Cleanup resizing listeners
429                                this._resizeHandle.remove();
430                                this._resizeHandle = null;
431                        }
432                        if(this._resizeHandle2){
433                                // Cleanup resizing listeners
434                                this._resizeHandle2.remove();
435                                this._resizeHandle2 = null;
436                        }
437                        if(this._resizer){
438                                clearTimeout(this._resizer);
439                                this._resizer = null;
440                        }
441                        this.inherited(arguments);
442                }
443        });
444
445        // Register this plugin.
446        // For back-compat accept "fullscreen" (all lowercase) too, remove in 2.0
447        _Plugin.registry["fullScreen"] = _Plugin.registry["fullscreen"] = function(args){
448                return new FullScreen({
449                        zIndex: ("zIndex" in args) ? args.zIndex : 500
450                });
451        };
452
453        return FullScreen;
454});
Note: See TracBrowser for help on using the repository browser.