]>
Commit | Line | Data |
---|---|---|
1 | /**\r | |
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.\r | |
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license\r | |
4 | */\r | |
5 | \r | |
6 | /**\r | |
7 | * @fileOverview The WYSIWYG Area plugin. It registers the "wysiwyg" editing\r | |
8 | * mode, which handles the main editing area space.\r | |
9 | */\r | |
10 | \r | |
11 | ( function() {\r | |
12 | var framedWysiwyg;\r | |
13 | \r | |
14 | CKEDITOR.plugins.add( 'wysiwygarea', {\r | |
15 | init: function( editor ) {\r | |
16 | if ( editor.config.fullPage ) {\r | |
17 | editor.addFeature( {\r | |
18 | allowedContent: 'html head title; style [media,type]; body (*)[id]; meta link [*]',\r | |
19 | requiredContent: 'body'\r | |
20 | } );\r | |
21 | }\r | |
22 | \r | |
23 | editor.addMode( 'wysiwyg', function( callback ) {\r | |
24 | var src = 'document.open();' +\r | |
25 | // In IE, the document domain must be set any time we call document.open().\r | |
26 | ( CKEDITOR.env.ie ? '(' + CKEDITOR.tools.fixDomain + ')();' : '' ) +\r | |
27 | 'document.close();';\r | |
28 | \r | |
29 | // With IE, the custom domain has to be taken care at first,\r | |
30 | // for other browers, the 'src' attribute should be left empty to\r | |
31 | // trigger iframe's 'load' event.\r | |
32 | // Microsoft Edge throws "Permission Denied" if treated like an IE (#13441).\r | |
33 | if ( CKEDITOR.env.air ) {\r | |
34 | src = 'javascript:void(0)'; // jshint ignore:line\r | |
35 | } else if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {\r | |
36 | src = 'javascript:void(function(){' + encodeURIComponent( src ) + '}())'; // jshint ignore:line\r | |
37 | } else {\r | |
38 | src = '';\r | |
39 | }\r | |
40 | \r | |
41 | var iframe = CKEDITOR.dom.element.createFromHtml( '<iframe src="' + src + '" frameBorder="0"></iframe>' );\r | |
42 | iframe.setStyles( { width: '100%', height: '100%' } );\r | |
43 | iframe.addClass( 'cke_wysiwyg_frame' ).addClass( 'cke_reset' );\r | |
44 | \r | |
45 | var contentSpace = editor.ui.space( 'contents' );\r | |
46 | contentSpace.append( iframe );\r | |
47 | \r | |
48 | \r | |
49 | // Asynchronous iframe loading is only required in IE>8 and Gecko (other reasons probably).\r | |
50 | // Do not use it on WebKit as it'll break the browser-back navigation.\r | |
51 | var useOnloadEvent = ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) || CKEDITOR.env.gecko;\r | |
52 | if ( useOnloadEvent )\r | |
53 | iframe.on( 'load', onLoad );\r | |
54 | \r | |
55 | var frameLabel = editor.title,\r | |
56 | helpLabel = editor.fire( 'ariaEditorHelpLabel', {} ).label;\r | |
57 | \r | |
58 | if ( frameLabel ) {\r | |
59 | if ( CKEDITOR.env.ie && helpLabel )\r | |
60 | frameLabel += ', ' + helpLabel;\r | |
61 | \r | |
62 | iframe.setAttribute( 'title', frameLabel );\r | |
63 | }\r | |
64 | \r | |
65 | if ( helpLabel ) {\r | |
66 | var labelId = CKEDITOR.tools.getNextId(),\r | |
67 | desc = CKEDITOR.dom.element.createFromHtml( '<span id="' + labelId + '" class="cke_voice_label">' + helpLabel + '</span>' );\r | |
68 | \r | |
69 | contentSpace.append( desc, 1 );\r | |
70 | iframe.setAttribute( 'aria-describedby', labelId );\r | |
71 | }\r | |
72 | \r | |
73 | // Remove the ARIA description.\r | |
74 | editor.on( 'beforeModeUnload', function( evt ) {\r | |
75 | evt.removeListener();\r | |
76 | if ( desc )\r | |
77 | desc.remove();\r | |
78 | } );\r | |
79 | \r | |
80 | iframe.setAttributes( {\r | |
81 | tabIndex: editor.tabIndex,\r | |
82 | allowTransparency: 'true'\r | |
83 | } );\r | |
84 | \r | |
85 | // Execute onLoad manually for all non IE||Gecko browsers.\r | |
86 | !useOnloadEvent && onLoad();\r | |
87 | \r | |
88 | editor.fire( 'ariaWidget', iframe );\r | |
89 | \r | |
90 | function onLoad( evt ) {\r | |
91 | evt && evt.removeListener();\r | |
92 | editor.editable( new framedWysiwyg( editor, iframe.$.contentWindow.document.body ) );\r | |
93 | editor.setData( editor.getData( 1 ), callback );\r | |
94 | }\r | |
95 | } );\r | |
96 | }\r | |
97 | } );\r | |
98 | \r | |
99 | /**\r | |
100 | * Adds the path to a stylesheet file to the exisiting {@link CKEDITOR.config#contentsCss} value.\r | |
101 | *\r | |
102 | * **Note:** This method is available only with the `wysiwygarea` plugin and only affects\r | |
103 | * classic editors based on it (so it does not affect inline editors).\r | |
104 | *\r | |
105 | * editor.addContentsCss( 'assets/contents.css' );\r | |
106 | *\r | |
107 | * @since 4.4\r | |
108 | * @param {String} cssPath The path to the stylesheet file which should be added.\r | |
109 | * @member CKEDITOR.editor\r | |
110 | */\r | |
111 | CKEDITOR.editor.prototype.addContentsCss = function( cssPath ) {\r | |
112 | var cfg = this.config,\r | |
113 | curContentsCss = cfg.contentsCss;\r | |
114 | \r | |
115 | // Convert current value into array.\r | |
116 | if ( !CKEDITOR.tools.isArray( curContentsCss ) )\r | |
117 | cfg.contentsCss = curContentsCss ? [ curContentsCss ] : [];\r | |
118 | \r | |
119 | cfg.contentsCss.push( cssPath );\r | |
120 | };\r | |
121 | \r | |
122 | function onDomReady( win ) {\r | |
123 | var editor = this.editor,\r | |
124 | doc = win.document,\r | |
125 | body = doc.body;\r | |
126 | \r | |
127 | // Remove helper scripts from the DOM.\r | |
128 | var script = doc.getElementById( 'cke_actscrpt' );\r | |
129 | script && script.parentNode.removeChild( script );\r | |
130 | script = doc.getElementById( 'cke_shimscrpt' );\r | |
131 | script && script.parentNode.removeChild( script );\r | |
132 | script = doc.getElementById( 'cke_basetagscrpt' );\r | |
133 | script && script.parentNode.removeChild( script );\r | |
134 | \r | |
135 | body.contentEditable = true;\r | |
136 | \r | |
137 | if ( CKEDITOR.env.ie ) {\r | |
138 | // Don't display the focus border.\r | |
139 | body.hideFocus = true;\r | |
140 | \r | |
141 | // Disable and re-enable the body to avoid IE from\r | |
142 | // taking the editing focus at startup. (#141 / #523)\r | |
143 | body.disabled = true;\r | |
144 | body.removeAttribute( 'disabled' );\r | |
145 | }\r | |
146 | \r | |
147 | delete this._.isLoadingData;\r | |
148 | \r | |
149 | // Play the magic to alter element reference to the reloaded one.\r | |
150 | this.$ = body;\r | |
151 | \r | |
152 | doc = new CKEDITOR.dom.document( doc );\r | |
153 | \r | |
154 | this.setup();\r | |
155 | this.fixInitialSelection();\r | |
156 | \r | |
157 | var editable = this;\r | |
158 | \r | |
159 | // Without it IE8 has problem with removing selection in nested editable. (#13785)\r | |
160 | if ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) {\r | |
161 | doc.getDocumentElement().addClass( doc.$.compatMode );\r | |
162 | }\r | |
163 | \r | |
164 | // Prevent IE/Edge from leaving a new paragraph/div after deleting all contents in body. (#6966, #13142)\r | |
165 | if ( CKEDITOR.env.ie && !CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_P ) {\r | |
166 | removeSuperfluousElement( 'p' );\r | |
167 | } else if ( CKEDITOR.env.edge && editor.enterMode != CKEDITOR.ENTER_DIV ) {\r | |
168 | removeSuperfluousElement( 'div' );\r | |
169 | }\r | |
170 | \r | |
171 | // Fix problem with cursor not appearing in Webkit and IE11+ when clicking below the body (#10945, #10906).\r | |
172 | // Fix for older IEs (8-10 and QM) is placed inside selection.js.\r | |
173 | if ( CKEDITOR.env.webkit || ( CKEDITOR.env.ie && CKEDITOR.env.version > 10 ) ) {\r | |
174 | doc.getDocumentElement().on( 'mousedown', function( evt ) {\r | |
175 | if ( evt.data.getTarget().is( 'html' ) ) {\r | |
176 | // IE needs this timeout. Webkit does not, but it does not cause problems too.\r | |
177 | setTimeout( function() {\r | |
178 | editor.editable().focus();\r | |
179 | } );\r | |
180 | }\r | |
181 | } );\r | |
182 | }\r | |
183 | \r | |
184 | // Config props: disableObjectResizing and disableNativeTableHandles handler.\r | |
185 | objectResizeDisabler( editor );\r | |
186 | \r | |
187 | // Enable dragging of position:absolute elements in IE.\r | |
188 | try {\r | |
189 | editor.document.$.execCommand( '2D-position', false, true );\r | |
190 | } catch ( e ) {}\r | |
191 | \r | |
192 | if ( CKEDITOR.env.gecko || CKEDITOR.env.ie && editor.document.$.compatMode == 'CSS1Compat' ) {\r | |
193 | this.attachListener( this, 'keydown', function( evt ) {\r | |
194 | var keyCode = evt.data.getKeystroke();\r | |
195 | \r | |
196 | // PageUp OR PageDown\r | |
197 | if ( keyCode == 33 || keyCode == 34 ) {\r | |
198 | // PageUp/PageDown scrolling is broken in document\r | |
199 | // with standard doctype, manually fix it. (#4736)\r | |
200 | if ( CKEDITOR.env.ie ) {\r | |
201 | setTimeout( function() {\r | |
202 | editor.getSelection().scrollIntoView();\r | |
203 | }, 0 );\r | |
204 | }\r | |
205 | // Page up/down cause editor selection to leak\r | |
206 | // outside of editable thus we try to intercept\r | |
207 | // the behavior, while it affects only happen\r | |
208 | // when editor contents are not overflowed. (#7955)\r | |
209 | else if ( editor.window.$.innerHeight > this.$.offsetHeight ) {\r | |
210 | var range = editor.createRange();\r | |
211 | range[ keyCode == 33 ? 'moveToElementEditStart' : 'moveToElementEditEnd' ]( this );\r | |
212 | range.select();\r | |
213 | evt.data.preventDefault();\r | |
214 | }\r | |
215 | }\r | |
216 | } );\r | |
217 | }\r | |
218 | \r | |
219 | if ( CKEDITOR.env.ie ) {\r | |
220 | // [IE] Iframe will still keep the selection when blurred, if\r | |
221 | // focus is moved onto a non-editing host, e.g. link or button, but\r | |
222 | // it becomes a problem for the object type selection, since the resizer\r | |
223 | // handler attached on it will mark other part of the UI, especially\r | |
224 | // for the dialog. (#8157)\r | |
225 | // [IE<8 & Opera] Even worse For old IEs, the cursor will not vanish even if\r | |
226 | // the selection has been moved to another text input in some cases. (#4716)\r | |
227 | //\r | |
228 | // Now the range restore is disabled, so we simply force IE to clean\r | |
229 | // up the selection before blur.\r | |
230 | this.attachListener( doc, 'blur', function() {\r | |
231 | // Error proof when the editor is not visible. (#6375)\r | |
232 | try {\r | |
233 | doc.$.selection.empty();\r | |
234 | } catch ( er ) {}\r | |
235 | } );\r | |
236 | }\r | |
237 | \r | |
238 | if ( CKEDITOR.env.iOS ) {\r | |
239 | // [iOS] If touch is bound to any parent of the iframe blur happens on any touch\r | |
240 | // event and body becomes the focused element (#10714).\r | |
241 | this.attachListener( doc, 'touchend', function() {\r | |
242 | win.focus();\r | |
243 | } );\r | |
244 | }\r | |
245 | \r | |
246 | var title = editor.document.getElementsByTag( 'title' ).getItem( 0 );\r | |
247 | // document.title is malfunctioning on Chrome, so get value from the element (#12402).\r | |
248 | title.data( 'cke-title', title.getText() );\r | |
249 | \r | |
250 | // [IE] JAWS will not recognize the aria label we used on the iframe\r | |
251 | // unless the frame window title string is used as the voice label,\r | |
252 | // backup the original one and restore it on output.\r | |
253 | if ( CKEDITOR.env.ie )\r | |
254 | editor.document.$.title = this._.docTitle;\r | |
255 | \r | |
256 | CKEDITOR.tools.setTimeout( function() {\r | |
257 | // Editable is ready after first setData.\r | |
258 | if ( this.status == 'unloaded' )\r | |
259 | this.status = 'ready';\r | |
260 | \r | |
261 | editor.fire( 'contentDom' );\r | |
262 | \r | |
263 | if ( this._.isPendingFocus ) {\r | |
264 | editor.focus();\r | |
265 | this._.isPendingFocus = false;\r | |
266 | }\r | |
267 | \r | |
268 | setTimeout( function() {\r | |
269 | editor.fire( 'dataReady' );\r | |
270 | }, 0 );\r | |
271 | }, 0, this );\r | |
272 | \r | |
273 | function removeSuperfluousElement( tagName ) {\r | |
274 | var lockRetain = false;\r | |
275 | \r | |
276 | // Superfluous elements appear after keydown\r | |
277 | // and before keyup, so the procedure is as follows:\r | |
278 | // 1. On first keydown mark all elements with\r | |
279 | // a specified tag name as non-superfluous.\r | |
280 | editable.attachListener( editable, 'keydown', function() {\r | |
281 | var body = doc.getBody(),\r | |
282 | retained = body.getElementsByTag( tagName );\r | |
283 | \r | |
284 | if ( !lockRetain ) {\r | |
285 | for ( var i = 0; i < retained.count(); i++ ) {\r | |
286 | retained.getItem( i ).setCustomData( 'retain', true );\r | |
287 | }\r | |
288 | lockRetain = true;\r | |
289 | }\r | |
290 | }, null, null, 1 );\r | |
291 | \r | |
292 | // 2. On keyup remove all elements that were not marked\r | |
293 | // as non-superfluous (which means they must have had appeared in the meantime).\r | |
294 | // Also we should preserve all temporary elements inserted by editor – otherwise we'd likely\r | |
295 | // leak fake selection's content into editable due to removing hidden selection container (#14831).\r | |
296 | editable.attachListener( editable, 'keyup', function() {\r | |
297 | var elements = doc.getElementsByTag( tagName );\r | |
298 | if ( lockRetain ) {\r | |
299 | if ( elements.count() == 1 && !elements.getItem( 0 ).getCustomData( 'retain' ) &&\r | |
300 | !elements.getItem( 0 ).hasAttribute( 'data-cke-temp' ) ) {\r | |
301 | elements.getItem( 0 ).remove( 1 );\r | |
302 | }\r | |
303 | lockRetain = false;\r | |
304 | }\r | |
305 | } );\r | |
306 | }\r | |
307 | }\r | |
308 | \r | |
309 | framedWysiwyg = CKEDITOR.tools.createClass( {\r | |
310 | $: function() {\r | |
311 | this.base.apply( this, arguments );\r | |
312 | \r | |
313 | this._.frameLoadedHandler = CKEDITOR.tools.addFunction( function( win ) {\r | |
314 | // Avoid opening design mode in a frame window thread,\r | |
315 | // which will cause host page scrolling.(#4397)\r | |
316 | CKEDITOR.tools.setTimeout( onDomReady, 0, this, win );\r | |
317 | }, this );\r | |
318 | \r | |
319 | this._.docTitle = this.getWindow().getFrame().getAttribute( 'title' );\r | |
320 | },\r | |
321 | \r | |
322 | base: CKEDITOR.editable,\r | |
323 | \r | |
324 | proto: {\r | |
325 | setData: function( data, isSnapshot ) {\r | |
326 | var editor = this.editor;\r | |
327 | \r | |
328 | if ( isSnapshot ) {\r | |
329 | this.setHtml( data );\r | |
330 | this.fixInitialSelection();\r | |
331 | \r | |
332 | // Fire dataReady for the consistency with inline editors\r | |
333 | // and because it makes sense. (#10370)\r | |
334 | editor.fire( 'dataReady' );\r | |
335 | }\r | |
336 | else {\r | |
337 | this._.isLoadingData = true;\r | |
338 | editor._.dataStore = { id: 1 };\r | |
339 | \r | |
340 | var config = editor.config,\r | |
341 | fullPage = config.fullPage,\r | |
342 | docType = config.docType;\r | |
343 | \r | |
344 | // Build the additional stuff to be included into <head>.\r | |
345 | var headExtra = CKEDITOR.tools.buildStyleHtml( iframeCssFixes() ).replace( /<style>/, '<style data-cke-temp="1">' );\r | |
346 | \r | |
347 | if ( !fullPage )\r | |
348 | headExtra += CKEDITOR.tools.buildStyleHtml( editor.config.contentsCss );\r | |
349 | \r | |
350 | var baseTag = config.baseHref ? '<base href="' + config.baseHref + '" data-cke-temp="1" />' : '';\r | |
351 | \r | |
352 | if ( fullPage ) {\r | |
353 | // Search and sweep out the doctype declaration.\r | |
354 | data = data.replace( /<!DOCTYPE[^>]*>/i, function( match ) {\r | |
355 | editor.docType = docType = match;\r | |
356 | return '';\r | |
357 | } ).replace( /<\?xml\s[^\?]*\?>/i, function( match ) {\r | |
358 | editor.xmlDeclaration = match;\r | |
359 | return '';\r | |
360 | } );\r | |
361 | }\r | |
362 | \r | |
363 | // Get the HTML version of the data.\r | |
364 | data = editor.dataProcessor.toHtml( data );\r | |
365 | \r | |
366 | if ( fullPage ) {\r | |
367 | // Check if the <body> tag is available.\r | |
368 | if ( !( /<body[\s|>]/ ).test( data ) )\r | |
369 | data = '<body>' + data;\r | |
370 | \r | |
371 | // Check if the <html> tag is available.\r | |
372 | if ( !( /<html[\s|>]/ ).test( data ) )\r | |
373 | data = '<html>' + data + '</html>';\r | |
374 | \r | |
375 | // Check if the <head> tag is available.\r | |
376 | if ( !( /<head[\s|>]/ ).test( data ) )\r | |
377 | data = data.replace( /<html[^>]*>/, '$&<head><title></title></head>' );\r | |
378 | else if ( !( /<title[\s|>]/ ).test( data ) )\r | |
379 | data = data.replace( /<head[^>]*>/, '$&<title></title>' );\r | |
380 | \r | |
381 | // The base must be the first tag in the HEAD, e.g. to get relative\r | |
382 | // links on styles.\r | |
383 | baseTag && ( data = data.replace( /<head[^>]*?>/, '$&' + baseTag ) );\r | |
384 | \r | |
385 | // Inject the extra stuff into <head>.\r | |
386 | // Attention: do not change it before testing it well. (V2)\r | |
387 | // This is tricky... if the head ends with <meta ... content type>,\r | |
388 | // Firefox will break. But, it works if we place our extra stuff as\r | |
389 | // the last elements in the HEAD.\r | |
390 | data = data.replace( /<\/head\s*>/, headExtra + '$&' );\r | |
391 | \r | |
392 | // Add the DOCTYPE back to it.\r | |
393 | data = docType + data;\r | |
394 | } else {\r | |
395 | data = config.docType +\r | |
396 | '<html dir="' + config.contentsLangDirection + '"' +\r | |
397 | ' lang="' + ( config.contentsLanguage || editor.langCode ) + '">' +\r | |
398 | '<head>' +\r | |
399 | '<title>' + this._.docTitle + '</title>' +\r | |
400 | baseTag +\r | |
401 | headExtra +\r | |
402 | '</head>' +\r | |
403 | '<body' + ( config.bodyId ? ' id="' + config.bodyId + '"' : '' ) +\r | |
404 | ( config.bodyClass ? ' class="' + config.bodyClass + '"' : '' ) +\r | |
405 | '>' +\r | |
406 | data +\r | |
407 | '</body>' +\r | |
408 | '</html>';\r | |
409 | }\r | |
410 | \r | |
411 | if ( CKEDITOR.env.gecko ) {\r | |
412 | // Hack to make Fx put cursor at the start of doc on fresh focus.\r | |
413 | data = data.replace( /<body/, '<body contenteditable="true" ' );\r | |
414 | \r | |
415 | // Another hack which is used by onDomReady to remove a leading\r | |
416 | // <br> which is inserted by Firefox 3.6 when document.write is called.\r | |
417 | // This additional <br> is present because of contenteditable="true"\r | |
418 | if ( CKEDITOR.env.version < 20000 )\r | |
419 | data = data.replace( /<body[^>]*>/, '$&<!-- cke-content-start -->' );\r | |
420 | }\r | |
421 | \r | |
422 | // The script that launches the bootstrap logic on 'domReady', so the document\r | |
423 | // is fully editable even before the editing iframe is fully loaded (#4455).\r | |
424 | var bootstrapCode =\r | |
425 | '<script id="cke_actscrpt" type="text/javascript"' + ( CKEDITOR.env.ie ? ' defer="defer" ' : '' ) + '>' +\r | |
426 | 'var wasLoaded=0;' + // It must be always set to 0 as it remains as a window property.\r | |
427 | 'function onload(){' +\r | |
428 | 'if(!wasLoaded)' + // FF3.6 calls onload twice when editor.setData. Stop that.\r | |
429 | 'window.parent.CKEDITOR.tools.callFunction(' + this._.frameLoadedHandler + ',window);' +\r | |
430 | 'wasLoaded=1;' +\r | |
431 | '}' +\r | |
432 | ( CKEDITOR.env.ie ? 'onload();' : 'document.addEventListener("DOMContentLoaded", onload, false );' ) +\r | |
433 | '</script>';\r | |
434 | \r | |
435 | // For IE<9 add support for HTML5's elements.\r | |
436 | // Note: this code must not be deferred.\r | |
437 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) {\r | |
438 | bootstrapCode +=\r | |
439 | '<script id="cke_shimscrpt">' +\r | |
440 | 'window.parent.CKEDITOR.tools.enableHtml5Elements(document)' +\r | |
441 | '</script>';\r | |
442 | }\r | |
443 | \r | |
444 | // IE<10 needs this hack to properly enable <base href="...">.\r | |
445 | // See: http://stackoverflow.com/a/13373180/1485219 (#11910).\r | |
446 | if ( baseTag && CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {\r | |
447 | bootstrapCode +=\r | |
448 | '<script id="cke_basetagscrpt">' +\r | |
449 | 'var baseTag = document.querySelector( "base" );' +\r | |
450 | 'baseTag.href = baseTag.href;' +\r | |
451 | '</script>';\r | |
452 | }\r | |
453 | \r | |
454 | data = data.replace( /(?=\s*<\/(:?head)>)/, bootstrapCode );\r | |
455 | \r | |
456 | // Current DOM will be deconstructed by document.write, cleanup required.\r | |
457 | this.clearCustomData();\r | |
458 | this.clearListeners();\r | |
459 | \r | |
460 | editor.fire( 'contentDomUnload' );\r | |
461 | \r | |
462 | var doc = this.getDocument();\r | |
463 | \r | |
464 | // Work around Firefox bug - error prune when called from XUL (#320),\r | |
465 | // defer it thanks to the async nature of this method.\r | |
466 | try {\r | |
467 | doc.write( data );\r | |
468 | } catch ( e ) {\r | |
469 | setTimeout( function() {\r | |
470 | doc.write( data );\r | |
471 | }, 0 );\r | |
472 | }\r | |
473 | }\r | |
474 | },\r | |
475 | \r | |
476 | getData: function( isSnapshot ) {\r | |
477 | if ( isSnapshot )\r | |
478 | return this.getHtml();\r | |
479 | else {\r | |
480 | var editor = this.editor,\r | |
481 | config = editor.config,\r | |
482 | fullPage = config.fullPage,\r | |
483 | docType = fullPage && editor.docType,\r | |
484 | xmlDeclaration = fullPage && editor.xmlDeclaration,\r | |
485 | doc = this.getDocument();\r | |
486 | \r | |
487 | var data = fullPage ? doc.getDocumentElement().getOuterHtml() : doc.getBody().getHtml();\r | |
488 | \r | |
489 | // BR at the end of document is bogus node for Mozilla. (#5293).\r | |
490 | // Prevent BRs from disappearing from the end of the content\r | |
491 | // while enterMode is ENTER_BR (#10146).\r | |
492 | if ( CKEDITOR.env.gecko && config.enterMode != CKEDITOR.ENTER_BR )\r | |
493 | data = data.replace( /<br>(?=\s*(:?$|<\/body>))/, '' );\r | |
494 | \r | |
495 | data = editor.dataProcessor.toDataFormat( data );\r | |
496 | \r | |
497 | if ( xmlDeclaration )\r | |
498 | data = xmlDeclaration + '\n' + data;\r | |
499 | if ( docType )\r | |
500 | data = docType + '\n' + data;\r | |
501 | \r | |
502 | return data;\r | |
503 | }\r | |
504 | },\r | |
505 | \r | |
506 | focus: function() {\r | |
507 | if ( this._.isLoadingData )\r | |
508 | this._.isPendingFocus = true;\r | |
509 | else\r | |
510 | framedWysiwyg.baseProto.focus.call( this );\r | |
511 | },\r | |
512 | \r | |
513 | detach: function() {\r | |
514 | var editor = this.editor,\r | |
515 | doc = editor.document,\r | |
516 | iframe,\r | |
517 | onResize;\r | |
518 | \r | |
519 | // Trying to access window's frameElement property on Edge throws an exception\r | |
520 | // when frame was already removed from DOM. (#13850, #13790)\r | |
521 | try {\r | |
522 | iframe = editor.window.getFrame();\r | |
523 | } catch ( e ) {}\r | |
524 | \r | |
525 | framedWysiwyg.baseProto.detach.call( this );\r | |
526 | \r | |
527 | // Memory leak proof.\r | |
528 | this.clearCustomData();\r | |
529 | doc.getDocumentElement().clearCustomData();\r | |
530 | CKEDITOR.tools.removeFunction( this._.frameLoadedHandler );\r | |
531 | \r | |
532 | // On IE, iframe is returned even after remove() method is called on it.\r | |
533 | // Checking if parent is present fixes this issue. (#13850)\r | |
534 | if ( iframe && iframe.getParent() ) {\r | |
535 | iframe.clearCustomData();\r | |
536 | onResize = iframe.removeCustomData( 'onResize' );\r | |
537 | onResize && onResize.removeListener();\r | |
538 | \r | |
539 | // IE BUG: When destroying editor DOM with the selection remains inside\r | |
540 | // editing area would break IE7/8's selection system, we have to put the editing\r | |
541 | // iframe offline first. (#3812 and #5441)\r | |
542 | iframe.remove();\r | |
543 | } else {\r | |
544 | CKEDITOR.warn( 'editor-destroy-iframe' );\r | |
545 | }\r | |
546 | }\r | |
547 | }\r | |
548 | } );\r | |
549 | \r | |
550 | function objectResizeDisabler( editor ) {\r | |
551 | if ( CKEDITOR.env.gecko ) {\r | |
552 | // FF allows to change resizing preferences by calling execCommand.\r | |
553 | try {\r | |
554 | var doc = editor.document.$;\r | |
555 | doc.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing );\r | |
556 | doc.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles );\r | |
557 | } catch ( e ) {}\r | |
558 | } else if ( CKEDITOR.env.ie && CKEDITOR.env.version < 11 && editor.config.disableObjectResizing ) {\r | |
559 | // It's possible to prevent resizing up to IE10.\r | |
560 | blockResizeStart( editor );\r | |
561 | }\r | |
562 | \r | |
563 | // Disables resizing by preventing default action on resizestart event.\r | |
564 | function blockResizeStart() {\r | |
565 | var lastListeningElement;\r | |
566 | \r | |
567 | // We'll attach only one listener at a time, instead of adding it to every img, input, hr etc.\r | |
568 | // Listener will be attached upon selectionChange, we'll also check if there was any element that\r | |
569 | // got listener before (lastListeningElement) - if so we need to remove previous listener.\r | |
570 | editor.editable().attachListener( editor, 'selectionChange', function() {\r | |
571 | var selectedElement = editor.getSelection().getSelectedElement();\r | |
572 | \r | |
573 | if ( selectedElement ) {\r | |
574 | if ( lastListeningElement ) {\r | |
575 | lastListeningElement.detachEvent( 'onresizestart', resizeStartListener );\r | |
576 | lastListeningElement = null;\r | |
577 | }\r | |
578 | \r | |
579 | // IE requires using attachEvent, because it does not work using W3C compilant addEventListener,\r | |
580 | // tested with IE10.\r | |
581 | selectedElement.$.attachEvent( 'onresizestart', resizeStartListener );\r | |
582 | lastListeningElement = selectedElement.$;\r | |
583 | }\r | |
584 | } );\r | |
585 | }\r | |
586 | \r | |
587 | function resizeStartListener( evt ) {\r | |
588 | evt.returnValue = false;\r | |
589 | }\r | |
590 | }\r | |
591 | \r | |
592 | function iframeCssFixes() {\r | |
593 | var css = [];\r | |
594 | \r | |
595 | // IE>=8 stricts mode doesn't have 'contentEditable' in effect\r | |
596 | // on element unless it has layout. (#5562)\r | |
597 | if ( CKEDITOR.document.$.documentMode >= 8 ) {\r | |
598 | css.push( 'html.CSS1Compat [contenteditable=false]{min-height:0 !important}' );\r | |
599 | \r | |
600 | var selectors = [];\r | |
601 | \r | |
602 | for ( var tag in CKEDITOR.dtd.$removeEmpty )\r | |
603 | selectors.push( 'html.CSS1Compat ' + tag + '[contenteditable=false]' );\r | |
604 | \r | |
605 | css.push( selectors.join( ',' ) + '{display:inline-block}' );\r | |
606 | }\r | |
607 | // Set the HTML style to 100% to have the text cursor in affect (#6341)\r | |
608 | else if ( CKEDITOR.env.gecko ) {\r | |
609 | css.push( 'html{height:100% !important}' );\r | |
610 | css.push( 'img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}' );\r | |
611 | }\r | |
612 | \r | |
613 | // #6341: The text cursor must be set on the editor area.\r | |
614 | // #6632: Avoid having "text" shape of cursor in IE7 scrollbars.\r | |
615 | css.push( 'html{cursor:text;*cursor:auto}' );\r | |
616 | \r | |
617 | // Use correct cursor for these elements\r | |
618 | css.push( 'img,input,textarea{cursor:default}' );\r | |
619 | \r | |
620 | return css.join( '\n' );\r | |
621 | }\r | |
622 | } )();\r | |
623 | \r | |
624 | /**\r | |
625 | * Disables the ability to resize objects (images and tables) in the editing area.\r | |
626 | *\r | |
627 | * config.disableObjectResizing = true;\r | |
628 | *\r | |
629 | * **Note:** Because of incomplete implementation of editing features in browsers\r | |
630 | * this option does not work for inline editors (see ticket [#10197](http://dev.ckeditor.com/ticket/10197)),\r | |
631 | * does not work in Internet Explorer 11+ (see [#9317](http://dev.ckeditor.com/ticket/9317#comment:16) and\r | |
632 | * [IE11+ issue](https://connect.microsoft.com/IE/feedback/details/742593/please-respect-execcommand-enableobjectresizing-in-contenteditable-elements)).\r | |
633 | * In Internet Explorer 8-10 this option only blocks resizing, but it is unable to hide the resize handles.\r | |
634 | *\r | |
635 | * @cfg\r | |
636 | * @member CKEDITOR.config\r | |
637 | */\r | |
638 | CKEDITOR.config.disableObjectResizing = false;\r | |
639 | \r | |
640 | /**\r | |
641 | * Disables the "table tools" offered natively by the browser (currently\r | |
642 | * Firefox only) to perform quick table editing operations, like adding or\r | |
643 | * deleting rows and columns.\r | |
644 | *\r | |
645 | * config.disableNativeTableHandles = false;\r | |
646 | *\r | |
647 | * @cfg\r | |
648 | * @member CKEDITOR.config\r | |
649 | */\r | |
650 | CKEDITOR.config.disableNativeTableHandles = true;\r | |
651 | \r | |
652 | /**\r | |
653 | * Disables the built-in spell checker if the browser provides one.\r | |
654 | *\r | |
655 | * **Note:** Although word suggestions provided natively by the browsers will\r | |
656 | * not appear in CKEditor's default context menu,\r | |
657 | * users can always reach the native context menu by holding the\r | |
658 | * *Ctrl* key when right-clicking if {@link #browserContextMenuOnCtrl}\r | |
659 | * is enabled or you are simply not using the\r | |
660 | * [context menu](http://ckeditor.com/addon/contextmenu) plugin.\r | |
661 | *\r | |
662 | * config.disableNativeSpellChecker = false;\r | |
663 | *\r | |
664 | * @cfg\r | |
665 | * @member CKEDITOR.config\r | |
666 | */\r | |
667 | CKEDITOR.config.disableNativeSpellChecker = true;\r | |
668 | \r | |
669 | /**\r | |
670 | * Language code of the writing language which is used to author the editor\r | |
671 | * content. This option accepts one single entry value in the format defined in the\r | |
672 | * [Tags for Identifying Languages (BCP47)](http://www.ietf.org/rfc/bcp/bcp47.txt)\r | |
673 | * IETF document and is used in the `lang` attribute.\r | |
674 | *\r | |
675 | * config.contentsLanguage = 'fr';\r | |
676 | *\r | |
677 | * @cfg {String} [contentsLanguage=same value with editor's UI language]\r | |
678 | * @member CKEDITOR.config\r | |
679 | */\r | |
680 | \r | |
681 | /**\r | |
682 | * The base href URL used to resolve relative and absolute URLs in the\r | |
683 | * editor content.\r | |
684 | *\r | |
685 | * config.baseHref = 'http://www.example.com/path/';\r | |
686 | *\r | |
687 | * @cfg {String} [baseHref='']\r | |
688 | * @member CKEDITOR.config\r | |
689 | */\r | |
690 | \r | |
691 | /**\r | |
692 | * Whether to automatically create wrapping blocks around inline content inside the document body.\r | |
693 | * This helps to ensure the integrity of the block *Enter* mode.\r | |
694 | *\r | |
695 | * **Note:** This option is deprecated. Changing the default value might introduce unpredictable usability issues and is\r | |
696 | * highly unrecommended.\r | |
697 | *\r | |
698 | * config.autoParagraph = false;\r | |
699 | *\r | |
700 | * @deprecated\r | |
701 | * @since 3.6\r | |
702 | * @cfg {Boolean} [autoParagraph=true]\r | |
703 | * @member CKEDITOR.config\r | |
704 | */\r | |
705 | \r | |
706 | /**\r | |
707 | * Fired when some elements are added to the document.\r | |
708 | *\r | |
709 | * @event ariaWidget\r | |
710 | * @member CKEDITOR.editor\r | |
711 | * @param {CKEDITOR.editor} editor This editor instance.\r | |
712 | * @param {CKEDITOR.dom.element} data The element being added.\r | |
713 | */\r |