1 /**
  2  * Add maximizeWindow/restoreWindow to Editor.
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("editor/plugin/maximize/cmd", function (S, Editor) {
  6     var UA = S.UA,
  7         ie = UA['ie'],
  8         doc = document,
  9         Node = S.Node,
 10         Event = S.Event,
 11         DOM = S.DOM,
 12         iframe,
 13         MAXIMIZE_TOOLBAR_CLASS = "ks-editor-toolbar-padding",
 14         init = function () {
 15             if (!iframe) {
 16                 iframe = new Node("<" + "iframe " +
 17                     " class='ks-editor-maximize-shim'" +
 18                     " style='" +
 19                     "position:absolute;" +
 20                     "top:-9999px;" +
 21                     "left:-9999px;" +
 22                     "'" +
 23                     " frameborder='0'>").prependTo(doc.body, undefined);
 24             }
 25         };
 26 
 27     function MaximizeCmd(editor) {
 28         this.editor = editor;
 29     }
 30 
 31     S.augment(MaximizeCmd, {
 32 
 33         restoreWindow:function () {
 34             var self = this,
 35                 editor = self.editor;
 36 
 37             if (editor.fire("beforeRestoreWindow") === false) {
 38                 return;
 39             }
 40 
 41             if (self._resize) {
 42                 Event.remove(window, "resize", self._resize);
 43                 self._resize = 0;
 44             } else {
 45                 return;
 46             }
 47 
 48             //body overflow 变化也会引起 resize 变化!!!!先去除
 49             self._saveEditorStatus();
 50             self._restoreState();
 51 
 52             //firefox 必须timeout
 53             setTimeout(function () {
 54                 self._restoreEditorStatus();
 55                 editor.notifySelectionChange();
 56                 editor.fire("afterRestoreWindow");
 57             }, 30);
 58         },
 59 
 60         /**
 61          * 从内存恢复最大化前的外围状态信息到编辑器实际动作,
 62          * 包括编辑器位置以及周围元素,浏览器窗口
 63          */
 64         _restoreState:function () {
 65             var self = this,
 66                 editor = self.editor,
 67                 textareaEl=editor.get("textarea"),
 68                 //恢复父节点的position原状态 bugfix:最大化被父元素限制
 69                 _savedParents = self._savedParents;
 70             if (_savedParents) {
 71                 for (var i = 0; i < _savedParents.length; i++) {
 72                     var po = _savedParents[i];
 73                     po.el.css("position", po.position);
 74                 }
 75                 self._savedParents = null;
 76             }
 77             //如果没有失去焦点,重新获得当前选取元素
 78             //self._saveEditorStatus();
 79             textareaEl.parent().css({
 80                 height:self.iframeHeight
 81             });
 82             textareaEl.css({
 83                 height:self.iframeHeight
 84             });
 85             DOM.css(doc.body, {
 86                 width:"",
 87                 height:"",
 88                 overflow:""
 89             });
 90             //documentElement 设置宽高,ie崩溃
 91             doc.documentElement.style.overflow = "";
 92 
 93             var editorElStyle = editor.get("el")[0].style;
 94             editorElStyle.position = "static";
 95             editorElStyle.width = self.editorElWidth;
 96 
 97             /*
 98              iframe 中时假死!
 99              editor.editorEl.css({
100              position:"static",
101              width:self.editorElWidth
102              });*/
103 
104             iframe.css({
105                 left:"-99999px",
106                 top:"-99999px"
107             });
108 
109             window.scrollTo(self.scrollLeft, self.scrollTop);
110 
111             if (ie < 8) {
112                 self.editor.get("toolBarEl").removeClass(MAXIMIZE_TOOLBAR_CLASS, undefined);
113             }
114         },
115         /**
116          * 保存最大化前的外围状态信息到内存,
117          * 包括编辑器位置以及周围元素,浏览器窗口
118          */
119         _saveSate:function () {
120             var self = this,
121                 editor = self.editor,
122                 _savedParents = [],
123                 editorEl = editor.get("el");
124             self.iframeHeight = editor.get("textarea").parent().style("height");
125             self.editorElWidth = editorEl.style("width");
126             //主窗口滚动条也要保存哦
127             self.scrollLeft = DOM.scrollLeft();
128             self.scrollTop = DOM.scrollTop();
129             window.scrollTo(0, 0);
130 
131             //将父节点的position都改成static并保存原状态 bugfix:最大化被父元素限制
132             var p = editorEl.parent();
133 
134             while (p) {
135                 var pre = p.css("position");
136                 if (pre != "static") {
137                     _savedParents.push({
138                         el:p,
139                         position:pre
140                     });
141                     p.css("position", "static");
142                 }
143                 p = p.parent();
144             }
145             self._savedParents = _savedParents;
146 
147             //ie6,7 图标到了窗口边界,不可点击,给个padding
148             if (ie < 8) {
149                 self.editor.get("toolBarEl").addClass(MAXIMIZE_TOOLBAR_CLASS, undefined);
150             }
151         },
152 
153         /**
154          *  编辑器自身核心状态保存,每次最大化最小化都要save,restore,
155          *  firefox修正,iframe layout变化时,range丢了
156          */
157         _saveEditorStatus:function () {
158             var self = this,
159                 editor = self.editor;
160             self.savedRanges = null;
161             if (!UA['gecko'] || !editor.__iframeFocus) {
162                 return;
163             }
164             var sel = editor.getSelection();
165             //firefox 光标丢失bug,位置丢失,所以这里保存下
166             self.savedRanges = sel && sel.getRanges();
167         },
168 
169         /**
170          * 编辑器自身核心状态恢复,每次最大化最小化都要save,restore,
171          * 维持编辑器核心状态不变
172          */
173         _restoreEditorStatus:function () {
174             var self = this,
175                 editor = self.editor,
176                 sel = editor.getSelection(),
177                 savedRanges = self.savedRanges;
178 
179             //firefox焦点bug
180 
181             //原来是聚焦,现在刷新designmode
182             //firefox 先失去焦点才行
183             if (UA['gecko']) {
184                 editor.activateGecko();
185             }
186 
187             if (savedRanges && sel) {
188                 sel.selectRanges(savedRanges);
189             }
190 
191             //firefox 有焦点时才重新聚焦
192             if (editor.__iframeFocus && sel) {
193                 var element = sel.getStartElement();
194                 //使用原生不行的,会使主窗口滚动
195                 //element[0] && element[0].scrollIntoView(true);
196                 element && element.scrollIntoView(undefined, false);
197             }
198         },
199 
200         /**
201          * 将编辑器最大化-实际动作
202          * 必须做两次,何解??
203          */
204         _maximize:function (stop) {
205             var self = this,
206                 editor = self.editor,
207                 editorEl = editor.get("el"),
208                 viewportHeight = DOM.viewportHeight(),
209                 viewportWidth = DOM.viewportWidth(),
210                 textareaEl=editor.get("textarea"),
211                 statusHeight = editor.get("statusBarEl") ?
212                     editor.get("statusBarEl")[0].offsetHeight : 0,
213                 toolHeight = editor.get("toolBarEl")[0].offsetHeight;
214 
215             if (!ie) {
216                 DOM.css(doc.body, {
217                     width:0,
218                     height:0,
219                     overflow:"hidden"
220                 });
221             } else {
222                 doc.body.style.overflow = "hidden";
223             }
224             doc.documentElement.style.overflow = "hidden";
225 
226             editorEl.css({
227                 position:"absolute",
228                 zIndex:Editor.baseZIndex(Editor.zIndexManager.MAXIMIZE),
229                 width:viewportWidth + "px"
230             });
231             iframe.css({
232                 zIndex:Editor.baseZIndex(Editor.zIndexManager.MAXIMIZE - 5),
233                 height:viewportHeight + "px",
234                 width:viewportWidth + "px"
235             });
236             editorEl.offset({
237                 left:0,
238                 top:0
239             });
240             iframe.css({
241                 left:0,
242                 top:0
243             });
244 
245             textareaEl.parent().css({
246                 height:(viewportHeight - statusHeight - toolHeight ) + "px"
247             });
248 
249 
250             textareaEl.css({
251                 height:(viewportHeight - statusHeight - toolHeight ) + "px"
252             });
253 
254             if (stop !== true) {
255                 arguments.callee.call(self, true);
256             }
257         },
258         _real:function () {
259             var self = this,
260                 editor = self.editor;
261             if (self._resize) {
262                 return;
263             }
264 
265             self._saveEditorStatus();
266             self._saveSate();
267             self._maximize();
268             if (!self._resize) {
269                 self._resize = S.buffer(function () {
270                     self._maximize();
271                     editor.fire("afterMaximizeWindow");
272                 }, 100);
273             }
274 
275             Event.on(window, "resize", self._resize);
276 
277             setTimeout(function () {
278                 self._restoreEditorStatus();
279                 editor.notifySelectionChange();
280                 editor.fire("afterMaximizeWindow");
281             }, 30);
282         },
283         maximizeWindow:function () {
284             var self = this,
285                 editor = self.editor;
286             if (editor.fire("beforeMaximizeWindow") === false) {
287                 return;
288             }
289             init();
290             self._real();
291         },
292         destroy:function () {
293             var self = this;
294             if (self._resize) {
295                 Event.remove(window, "resize", self._resize);
296                 self._resize = 0;
297             }
298         }
299     });
300 
301     return {
302         init:function (editor) {
303 
304             if (!editor.hasCommand("maximizeWindow")) {
305 
306                 var maximizeCmd = new MaximizeCmd(editor);
307 
308                 editor.addCommand("maximizeWindow", {
309                     exec:function () {
310                         maximizeCmd.maximizeWindow();
311                     }
312                 });
313 
314                 editor.addCommand("restoreWindow", {
315                     exec:function () {
316                         maximizeCmd.restoreWindow();
317                     }
318                 });
319 
320             }
321 
322         }
323     };
324 }, {
325     requires:['editor']
326 });