| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 /* 2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html or http://ckeditor.com/license 4 */ 5 6 /** 7 * @fileOverview The "wysiwygarea" plugin. It registers the "wysiwyg" editing 8 * mode, which handles the main editing area space. 9 */ 10 11 (function() 12 { 13 // List of elements in which has no way to move editing focus outside. 14 var nonExitableElementNames = { table:1,pre:1 }; 15 16 // Matching an empty paragraph at the end of document. 17 var emptyParagraphRegexp = /\s*<(p|div|address|h\d|center|li)[^>]*>\s*(?:<br[^>]*>| |\u00A0| )?\s*(:?<\/\1>)?\s*(?=$|<\/body>)/gi; 18 19 var notWhitespaceEval = CKEDITOR.dom.walker.whitespaces( true ); 20 21 function checkReadOnly( selection ) 22 { 23 if ( selection.getType() == CKEDITOR.SELECTION_ELEMENT ) 24 return selection.getSelectedElement().isReadOnly(); 25 else 26 return selection.getCommonAncestor().isReadOnly(); 27 } 28 29 function onInsertHtml( evt ) 30 { 31 if ( this.mode == 'wysiwyg' ) 32 { 33 this.focus(); 34 35 var selection = this.getSelection(); 36 if ( checkReadOnly( selection ) ) 37 return; 38 39 var data = evt.data; 40 this.fire( 'saveSnapshot' ); 41 42 if ( this.dataProcessor ) 43 data = this.dataProcessor.toHtml( data ); 44 45 if ( CKEDITOR.env.ie ) 46 { 47 var selIsLocked = selection.isLocked; 48 49 if ( selIsLocked ) 50 selection.unlock(); 51 52 var $sel = selection.getNative(); 53 54 // Delete control selections to avoid IE bugs on pasteHTML. 55 if ( $sel.type == 'Control' ) 56 $sel.clear(); 57 else if ( selection.getType() == CKEDITOR.SELECTION_TEXT ) 58 { 59 // Due to IE bugs on handling contenteditable=false blocks 60 // (#6005), we need to make some checks and eventually 61 // delete the selection first. 62 63 var range = selection.getRanges()[0], 64 endContainer = range && range.endContainer; 65 66 if ( endContainer && 67 endContainer.type == CKEDITOR.NODE_ELEMENT && 68 endContainer.getAttribute( 'contenteditable' ) == 'false' && 69 range.checkBoundaryOfElement( endContainer, CKEDITOR.END ) ) 70 { 71 range.setEndAfter( range.endContainer ); 72 range.deleteContents(); 73 } 74 } 75 76 $sel.createRange().pasteHTML( data ); 77 78 if ( selIsLocked ) 79 this.getSelection().lock(); 80 } 81 else 82 this.document.$.execCommand( 'inserthtml', false, data ); 83 84 // Webkit does not scroll to the cursor position after pasting (#5558) 85 if ( CKEDITOR.env.webkit ) 86 { 87 this.document.$.execCommand( 'inserthtml', false, '<span id="cke_paste_marker" cke_temp="1"></span>' ); 88 var marker = this.document.getById( 'cke_paste_marker' ); 89 marker.scrollIntoView(); 90 marker.remove(); 91 } 92 93 CKEDITOR.tools.setTimeout( function() 94 { 95 this.fire( 'saveSnapshot' ); 96 }, 0, this ); 97 } 98 } 99 100 function onInsertElement( evt ) 101 { 102 if ( this.mode == 'wysiwyg' ) 103 { 104 this.focus(); 105 106 var selection = this.getSelection(); 107 if ( checkReadOnly( selection ) ) 108 return; 109 110 this.fire( 'saveSnapshot' ); 111 112 var ranges = selection.getRanges(), 113 element = evt.data, 114 elementName = element.getName(), 115 isBlock = CKEDITOR.dtd.$block[ elementName ]; 116 117 var selIsLocked = selection.isLocked; 118 119 if ( selIsLocked ) 120 selection.unlock(); 121 122 var range, clone, lastElement, bookmark; 123 124 for ( var i = ranges.length - 1 ; i >= 0 ; i-- ) 125 { 126 range = ranges[ i ]; 127 128 // Remove the original contents. 129 range.deleteContents(); 130 131 clone = !i && element || element.clone( true ); 132 133 // If we're inserting a block at dtd-violated position, split 134 // the parent blocks until we reach blockLimit. 135 var current, dtd; 136 if ( isBlock ) 137 { 138 while ( ( current = range.getCommonAncestor( false, true ) ) 139 && ( dtd = CKEDITOR.dtd[ current.getName() ] ) 140 && !( dtd && dtd [ elementName ] ) ) 141 { 142 // Split up inline elements. 143 if ( current.getName() in CKEDITOR.dtd.span ) 144 range.splitElement( current ); 145 // If we're in an empty block which indicate a new paragraph, 146 // simply replace it with the inserting block.(#3664) 147 else if ( range.checkStartOfBlock() 148 && range.checkEndOfBlock() ) 149 { 150 range.setStartBefore( current ); 151 range.collapse( true ); 152 current.remove(); 153 } 154 else 155 range.splitBlock(); 156 } 157 } 158 159 // Insert the new node. 160 range.insertNode( clone ); 161 162 // Save the last element reference so we can make the 163 // selection later. 164 if ( !lastElement ) 165 lastElement = clone; 166 } 167 168 range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END ); 169 170 // If we're inserting a block element immediatelly followed by 171 // another block element, the selection must move there. (#3100,#5436) 172 if ( isBlock ) 173 { 174 var next = lastElement.getNext( notWhitespaceEval ), 175 nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName(); 176 177 // Check if it's a block element that accepts text. 178 if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] ) 179 range.moveToElementEditStart( next ); 180 } 181 182 selection.selectRanges( [ range ] ); 183 184 if ( selIsLocked ) 185 this.getSelection().lock(); 186 187 // Save snaps after the whole execution completed. 188 // This's a workaround for make DOM modification's happened after 189 // 'insertElement' to be included either, e.g. Form-based dialogs' 'commitContents' 190 // call. 191 CKEDITOR.tools.setTimeout( function(){ 192 this.fire( 'saveSnapshot' ); 193 }, 0, this ); 194 } 195 } 196 197 // DOM modification here should not bother dirty flag.(#4385) 198 function restoreDirty( editor ) 199 { 200 if ( !editor.checkDirty() ) 201 setTimeout( function(){ editor.resetDirty(); } ); 202 } 203 204 var isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ), 205 isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true ); 206 207 function isNotEmpty( node ) 208 { 209 return isNotWhitespace( node ) && isNotBookmark( node ); 210 } 211 212 function isNbsp( node ) 213 { 214 return node.type == CKEDITOR.NODE_TEXT 215 && CKEDITOR.tools.trim( node.getText() ).match( /^(?: |\xa0)$/ ); 216 } 217 218 function restoreSelection( selection ) 219 { 220 if ( selection.isLocked ) 221 { 222 selection.unlock(); 223 setTimeout( function() { selection.lock(); }, 0 ); 224 } 225 } 226 227 function isBlankParagraph( block ) 228 { 229 return block.getOuterHtml().match( emptyParagraphRegexp ); 230 } 231 232 isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ); 233 234 // Gecko need a key event to 'wake up' the editing 235 // ability when document is empty.(#3864, #5781) 236 function activateEditing( editor ) 237 { 238 var win = editor.window, 239 doc = editor.document, 240 body = editor.document.getBody(), 241 bodyChildsNum = body.getChildren().count(); 242 243 if ( !bodyChildsNum || ( bodyChildsNum == 1&& body.getFirst().hasAttribute( '_moz_editor_bogus_node' ) ) ) 244 { 245 restoreDirty( editor ); 246 247 // Simulating keyboard character input by dispatching a keydown of white-space text. 248 var keyEventSimulate = doc.$.createEvent( "KeyEvents" ); 249 keyEventSimulate.initKeyEvent( 'keypress', true, true, win.$, false, 250 false, false, false, 0, 32 ); 251 doc.$.dispatchEvent( keyEventSimulate ); 252 253 // Restore the original document status by placing the cursor before a bogus br created (#5021). 254 bodyChildsNum && body.getFirst().remove(); 255 doc.getBody().appendBogus(); 256 var nativeRange = new CKEDITOR.dom.range( doc ); 257 nativeRange.setStartAt( body , CKEDITOR.POSITION_AFTER_START ); 258 nativeRange.select(); 259 } 260 } 261 262 /** 263 * Auto-fixing block-less content by wrapping paragraph (#3190), prevent 264 * non-exitable-block by padding extra br.(#3189) 265 */ 266 function onSelectionChangeFixBody( evt ) 267 { 268 var editor = evt.editor, 269 path = evt.data.path, 270 blockLimit = path.blockLimit, 271 selection = evt.data.selection, 272 range = selection.getRanges()[0], 273 body = editor.document.getBody(), 274 enterMode = editor.config.enterMode; 275 276 CKEDITOR.env.gecko && activateEditing( editor ); 277 278 // When enterMode set to block, we'll establing new paragraph only if we're 279 // selecting inline contents right under body. (#3657) 280 if ( enterMode != CKEDITOR.ENTER_BR 281 && range.collapsed 282 && blockLimit.getName() == 'body' 283 && !path.block ) 284 { 285 editor.fire( 'updateSnapshot' ); 286 restoreDirty( editor ); 287 CKEDITOR.env.ie && restoreSelection( selection ); 288 289 var fixedBlock = range.fixBlock( true, 290 editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' ); 291 292 // For IE, we should remove any filler node which was introduced before. 293 if ( CKEDITOR.env.ie ) 294 { 295 var first = fixedBlock.getFirst( isNotEmpty ); 296 first && isNbsp( first ) && first.remove(); 297 } 298 299 // If the fixed block is actually blank and is already followed by an exitable blank 300 // block, we should revert the fix and move into the existed one. (#3684) 301 if ( isBlankParagraph( fixedBlock ) ) 302 { 303 var element = fixedBlock.getNext( isNotWhitespace ); 304 if ( element && 305 element.type == CKEDITOR.NODE_ELEMENT && 306 !nonExitableElementNames[ element.getName() ] ) 307 { 308 range.moveToElementEditStart( element ); 309 fixedBlock.remove(); 310 } 311 else 312 { 313 element = fixedBlock.getPrevious( isNotWhitespace ); 314 if ( element && 315 element.type == CKEDITOR.NODE_ELEMENT && 316 !nonExitableElementNames[ element.getName() ] ) 317 { 318 range.moveToElementEditEnd( element ); 319 fixedBlock.remove(); 320 } 321 } 322 } 323 324 range.select(); 325 // Notify non-IE that selection has changed. 326 if ( !CKEDITOR.env.ie ) 327 editor.selectionChange(); 328 } 329 330 // All browsers are incapable to moving cursor out of certain non-exitable 331 // blocks (e.g. table, list, pre) at the end of document, make this happen by 332 // place a bogus node there, which would be later removed by dataprocessor. 333 var walkerRange = new CKEDITOR.dom.range( editor.document ), 334 walker = new CKEDITOR.dom.walker( walkerRange ); 335 walkerRange.selectNodeContents( body ); 336 walker.evaluator = function( node ) 337 { 338 return node.type == CKEDITOR.NODE_ELEMENT && ( node.getName() in nonExitableElementNames ); 339 }; 340 walker.guard = function( node, isMoveout ) 341 { 342 return !( ( node.type == CKEDITOR.NODE_TEXT && isNotWhitespace( node ) ) || isMoveout ); 343 }; 344 345 if ( walker.previous() ) 346 { 347 editor.fire( 'updateSnapshot' ); 348 restoreDirty( editor ); 349 CKEDITOR.env.ie && restoreSelection( selection ); 350 351 var paddingBlock; 352 if ( enterMode != CKEDITOR.ENTER_BR ) 353 paddingBlock = body.append( new CKEDITOR.dom.element( enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ) ); 354 else 355 paddingBlock = body; 356 357 if ( !CKEDITOR.env.ie ) 358 paddingBlock.appendBogus(); 359 } 360 } 361 362 CKEDITOR.plugins.add( 'wysiwygarea', 363 { 364 requires : [ 'editingblock' ], 365 366 init : function( editor ) 367 { 368 var fixForBody = ( editor.config.enterMode != CKEDITOR.ENTER_BR ) 369 ? editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' : false; 370 371 var frameLabel = editor.lang.editorTitle.replace( '%1', editor.name ); 372 373 var contentDomReadyHandler; 374 editor.on( 'editingBlockReady', function() 375 { 376 var mainElement, 377 iframe, 378 isLoadingData, 379 isPendingFocus, 380 frameLoaded, 381 fireMode; 382 383 384 // Support for custom document.domain in IE. 385 var isCustomDomain = CKEDITOR.env.isCustomDomain(); 386 387 // Creates the iframe that holds the editable document. 388 var createIFrame = function( data ) 389 { 390 if ( iframe ) 391 iframe.remove(); 392 393 394 var srcScript = 395 'document.open();' + 396 397 // The document domain must be set any time we 398 // call document.open(). 399 ( isCustomDomain ? ( 'document.domain="' + document.domain + '";' ) : '' ) + 400 401 'document.close();'; 402 403 iframe = CKEDITOR.dom.element.createFromHtml( '<iframe' + 404 ' style="width:100%;height:100%"' + 405 ' frameBorder="0"' + 406 ' title="' + frameLabel + '"' + 407 // With IE, the custom domain has to be taken care at first, 408 // for other browers, the 'src' attribute should be left empty to 409 // trigger iframe's 'load' event. 410 ' src="' + ( CKEDITOR.env.ie ? 'javascript:void(function(){' + encodeURIComponent( srcScript ) + '}())' : '' ) + '"' + 411 ' tabIndex="' + ( CKEDITOR.env.webkit? -1 : editor.tabIndex ) + '"' + 412 ' allowTransparency="true"' + 413 '></iframe>' ); 414 415 // #5689 Running inside of Firefox chrome the load event doesn't bubble like in a normal page 416 if (document.location.protocol == 'chrome:') 417 CKEDITOR.event.useCapture = true; 418 419 // With FF, it's better to load the data on iframe.load. (#3894,#4058) 420 iframe.on( 'load', function( ev ) 421 { 422 frameLoaded = 1; 423 ev.removeListener(); 424 425 var doc = iframe.getFrameDocument().$; 426 427 // Don't leave any history log in IE. (#5657) 428 doc.open( "text/html","replace" ); 429 doc.write( data ); 430 doc.close(); 431 }); 432 433 // #5689 Reset adjustment back to default 434 if (document.location.protocol == 'chrome:') 435 CKEDITOR.event.useCapture = false; 436 437 mainElement.append( iframe ); 438 }; 439 440 // The script that launches the bootstrap logic on 'domReady', so the document 441 // is fully editable even before the editing iframe is fully loaded (#4455). 442 contentDomReadyHandler = CKEDITOR.tools.addFunction( contentDomReady ); 443 var activationScript = 444 '<script id="cke_actscrpt" type="text/javascript" cke_temp="1">' + 445 ( isCustomDomain ? ( 'document.domain="' + document.domain + '";' ) : '' ) + 446 'window.parent.CKEDITOR.tools.callFunction( ' + contentDomReadyHandler + ', window );' + 447 '</script>'; 448 449 // Editing area bootstrap code. 450 function contentDomReady( domWindow ) 451 { 452 if ( !frameLoaded ) 453 return; 454 frameLoaded = 0; 455 456 editor.fire( 'ariaWidget', iframe ); 457 458 var domDocument = domWindow.document, 459 body = domDocument.body; 460 461 // Remove this script from the DOM. 462 var script = domDocument.getElementById( "cke_actscrpt" ); 463 script.parentNode.removeChild( script ); 464 465 body.spellcheck = !editor.config.disableNativeSpellChecker; 466 467 if ( CKEDITOR.env.ie ) 468 { 469 // Don't display the focus border. 470 body.hideFocus = true; 471 472 // Disable and re-enable the body to avoid IE from 473 // taking the editing focus at startup. (#141 / #523) 474 body.disabled = true; 475 body.contentEditable = true; 476 body.removeAttribute( 'disabled' ); 477 } 478 else 479 { 480 // Avoid opening design mode in a frame window thread, 481 // which will cause host page scrolling.(#4397) 482 setTimeout( function() 483 { 484 // Prefer 'contentEditable' instead of 'designMode'. (#3593) 485 if ( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 486 || CKEDITOR.env.opera ) 487 domDocument.$.body.contentEditable = true; 488 else if ( CKEDITOR.env.webkit ) 489 domDocument.$.body.parentNode.contentEditable = true; 490 else 491 domDocument.$.designMode = 'on'; 492 }, 0 ); 493 } 494 495 CKEDITOR.env.gecko && CKEDITOR.tools.setTimeout( activateEditing, 0, null, editor ); 496 497 domWindow = editor.window = new CKEDITOR.dom.window( domWindow ); 498 domDocument = editor.document = new CKEDITOR.dom.document( domDocument ); 499 500 domDocument.on( 'dblclick', function( evt ) 501 { 502 var element = evt.data.getTarget(), 503 data = { element : element, dialog : '' }; 504 editor.fire( 'doubleclick', data ); 505 data.dialog && editor.openDialog( data.dialog ); 506 }); 507 508 // Gecko/Webkit need some help when selecting control type elements. (#3448) 509 if ( !( CKEDITOR.env.ie || CKEDITOR.env.opera) ) 510 { 511 domDocument.on( 'mousedown', function( ev ) 512 { 513 var control = ev.data.getTarget(); 514 if ( control.is( 'img', 'hr', 'input', 'textarea', 'select' ) ) 515 editor.getSelection().selectElement( control ); 516 } ); 517 } 518 519 if ( CKEDITOR.env.gecko ) 520 { 521 domDocument.on( 'mouseup', function( ev ) 522 { 523 if ( ev.data.$.button == 2 ) 524 { 525 var target = ev.data.getTarget(); 526 527 // Prevent right click from selecting an empty block even 528 // when selection is anchored inside it. (#5845) 529 if ( !target.getOuterHtml().replace( emptyParagraphRegexp, '' ) ) 530 { 531 var range = new CKEDITOR.dom.range( domDocument ); 532 range.moveToElementEditStart( target ); 533 range.select( true ); 534 } 535 } 536 } ); 537 } 538 539 // Prevent the browser opening links in read-only blocks. (#6032) 540 domDocument.on( 'click', function( ev ) 541 { 542 ev = ev.data; 543 if ( ev.getTarget().is( 'a' ) && ev.$.button != 2 ) 544 ev.preventDefault(); 545 }); 546 547 // Webkit: avoid from editing form control elements content. 548 if ( CKEDITOR.env.webkit ) 549 { 550 // Prevent from tick checkbox/radiobox/select 551 domDocument.on( 'click', function( ev ) 552 { 553 if ( ev.data.getTarget().is( 'input', 'select' ) ) 554 ev.data.preventDefault(); 555 } ); 556 557 // Prevent from editig textfield/textarea value. 558 domDocument.on( 'mouseup', function( ev ) 559 { 560 if ( ev.data.getTarget().is( 'input', 'textarea' ) ) 561 ev.data.preventDefault(); 562 } ); 563 } 564 565 // IE standard compliant in editing frame doesn't focus the editor when 566 // clicking outside actual content, manually apply the focus. (#1659) 567 if ( CKEDITOR.env.ie 568 && domDocument.$.compatMode == 'CSS1Compat' 569 || CKEDITOR.env.gecko 570 || CKEDITOR.env.opera ) 571 { 572 var htmlElement = domDocument.getDocumentElement(); 573 htmlElement.on( 'mousedown', function( evt ) 574 { 575 // Setting focus directly on editor doesn't work, we 576 // have to use here a temporary element to 'redirect' 577 // the focus. 578 if ( evt.data.getTarget().equals( htmlElement ) ) 579 { 580 if ( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 ) 581 blinkCursor(); 582 focusGrabber.focus(); 583 } 584 } ); 585 } 586 587 domWindow.on( 'blur', function() 588 { 589 editor.focusManager.blur(); 590 }); 591 592 domWindow.on( 'focus', function() 593 { 594 var doc = editor.document; 595 596 if ( CKEDITOR.env.gecko && CKEDITOR.env.version >= 10900 ) 597 blinkCursor(); 598 else if ( CKEDITOR.env.opera ) 599 doc.getBody().focus(); 600 601 editor.focusManager.focus(); 602 }); 603 604 var keystrokeHandler = editor.keystrokeHandler; 605 if ( keystrokeHandler ) 606 keystrokeHandler.attach( domDocument ); 607 608 if ( CKEDITOR.env.ie ) 609 { 610 domDocument.getDocumentElement().addClass( domDocument.$.compatMode ); 611 // Override keystrokes which should have deletion behavior 612 // on control types in IE . (#4047) 613 domDocument.on( 'keydown', function( evt ) 614 { 615 var keyCode = evt.data.getKeystroke(); 616 617 // Backspace OR Delete. 618 if ( keyCode in { 8 : 1, 46 : 1 } ) 619 { 620 var sel = editor.getSelection(), 621 control = sel.getSelectedElement(); 622 623 if ( control ) 624 { 625 // Make undo snapshot. 626 editor.fire( 'saveSnapshot' ); 627 628 // Delete any element that 'hasLayout' (e.g. hr,table) in IE8 will 629 // break up the selection, safely manage it here. (#4795) 630 var bookmark = sel.getRanges()[ 0 ].createBookmark(); 631 // Remove the control manually. 632 control.remove(); 633 sel.selectBookmarks( [ bookmark ] ); 634 635 editor.fire( 'saveSnapshot' ); 636 637 evt.data.preventDefault(); 638 } 639 } 640 } ); 641 642 // PageUp/PageDown scrolling is broken in document 643 // with standard doctype, manually fix it. (#4736) 644 if ( domDocument.$.compatMode == 'CSS1Compat' ) 645 { 646 var pageUpDownKeys = { 33 : 1, 34 : 1 }; 647 domDocument.on( 'keydown', function( evt ) 648 { 649 if ( evt.data.getKeystroke() in pageUpDownKeys ) 650 { 651 setTimeout( function () 652 { 653 editor.getSelection().scrollIntoView(); 654 }, 0 ); 655 } 656 } ); 657 } 658 } 659 660 // Adds the document body as a context menu target. 661 if ( editor.contextMenu ) 662 editor.contextMenu.addTarget( domDocument, editor.config.browserContextMenuOnCtrl !== false ); 663 664 setTimeout( function() 665 { 666 editor.fire( 'contentDom' ); 667 668 if ( fireMode ) 669 { 670 editor.mode = 'wysiwyg'; 671 editor.fire( 'mode' ); 672 fireMode = false; 673 } 674 675 isLoadingData = false; 676 677 if ( isPendingFocus ) 678 { 679 editor.focus(); 680 isPendingFocus = false; 681 } 682 setTimeout( function() 683 { 684 editor.fire( 'dataReady' ); 685 }, 0 ); 686 687 // IE, Opera and Safari may not support it and throw errors. 688 try { editor.document.$.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing ) ; } catch(e) {} 689 try { editor.document.$.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ) ; } catch(e) {} 690 691 /* 692 * IE BUG: IE might have rendered the iframe with invisible contents. 693 * (#3623). Push some inconsequential CSS style changes to force IE to 694 * refresh it. 695 * 696 * Also, for some unknown reasons, short timeouts (e.g. 100ms) do not 697 * fix the problem. :( 698 */ 699 if ( CKEDITOR.env.ie ) 700 { 701 setTimeout( function() 702 { 703 if ( editor.document ) 704 { 705 var $body = editor.document.$.body; 706 $body.runtimeStyle.marginBottom = '0px'; 707 $body.runtimeStyle.marginBottom = ''; 708 } 709 }, 1000 ); 710 } 711 }, 712 0 ); 713 } 714 715 editor.addMode( 'wysiwyg', 716 { 717 load : function( holderElement, data, isSnapshot ) 718 { 719 mainElement = holderElement; 720 721 if ( CKEDITOR.env.ie && CKEDITOR.env.quirks ) 722 holderElement.setStyle( 'position', 'relative' ); 723 724 // The editor data "may be dirty" after this 725 // point. 726 editor.mayBeDirty = true; 727 728 fireMode = true; 729 730 if ( isSnapshot ) 731 this.loadSnapshotData( data ); 732 else 733 this.loadData( data ); 734 }, 735 736 loadData : function( data ) 737 { 738 isLoadingData = true; 739 740 var config = editor.config, 741 fullPage = config.fullPage, 742 docType = config.docType; 743 744 // Build the additional stuff to be included into <head>. 745 var headExtra = 746 '<style type="text/css" cke_temp="1">' + 747 editor._.styles.join( '\n' ) + 748 '</style>'; 749 750 !fullPage && ( headExtra = 751 CKEDITOR.tools.buildStyleHtml( editor.config.contentsCss ) + 752 headExtra ); 753 754 var baseTag = config.baseHref ? '<base href="' + config.baseHref + '" cke_temp="1" />' : ''; 755 756 if ( fullPage ) 757 { 758 // Search and sweep out the doctype declaration. 759 data = data.replace( /<!DOCTYPE[^>]*>/i, function( match ) 760 { 761 editor.docType = docType = match; 762 return ''; 763 }); 764 } 765 766 // Get the HTML version of the data. 767 if ( editor.dataProcessor ) 768 data = editor.dataProcessor.toHtml( data, fixForBody ); 769 770 if ( fullPage ) 771 { 772 // Check if the <body> tag is available. 773 if ( !(/<body[\s|>]/).test( data ) ) 774 data = '<body>' + data; 775 776 // Check if the <html> tag is available. 777 if ( !(/<html[\s|>]/).test( data ) ) 778 data = '<html>' + data + '</html>'; 779 780 // Check if the <head> tag is available. 781 if ( !(/<head[\s|>]/).test( data ) ) 782 data = data.replace( /<html[^>]*>/, '$&<head><title></title></head>' ) ; 783 else if ( !(/<title[\s|>]/).test( data ) ) 784 data = data.replace( /<head[^>]*>/, '$&<title></title>' ) ; 785 786 // The base must be the first tag in the HEAD, e.g. to get relative 787 // links on styles. 788 baseTag && ( data = data.replace( /<head>/, '$&' + baseTag ) ); 789 790 // Inject the extra stuff into <head>. 791 // Attention: do not change it before testing it well. (V2) 792 // This is tricky... if the head ends with <meta ... content type>, 793 // Firefox will break. But, it works if we place our extra stuff as 794 // the last elements in the HEAD. 795 data = data.replace( /<\/head\s*>/, headExtra + '$&' ); 796 797 // Add the DOCTYPE back to it. 798 data = docType + data; 799 } 800 else 801 { 802 data = 803 config.docType + 804 '<html dir="' + config.contentsLangDirection + '"' + 805 ' lang="' + ( config.contentsLanguage || editor.langCode ) + '">' + 806 '<head>' + 807 '<title>' + frameLabel + '</title>' + 808 baseTag + 809 headExtra + 810 '</head>' + 811 '<body' + ( config.bodyId ? ' id="' + config.bodyId + '"' : '' ) + 812 ( config.bodyClass ? ' class="' + config.bodyClass + '"' : '' ) + 813 '>' + 814 data + 815 '</html>'; 816 } 817 818 data += activationScript; 819 820 821 // The iframe is recreated on each call of setData, so we need to clear DOM objects 822 this.onDispose(); 823 createIFrame( data ); 824 }, 825 826 getData : function() 827 { 828 var config = editor.config, 829 fullPage = config.fullPage, 830 docType = fullPage && editor.docType, 831 doc = iframe.getFrameDocument(); 832 833 var data = fullPage 834 ? doc.getDocumentElement().getOuterHtml() 835 : doc.getBody().getHtml(); 836 837 if ( editor.dataProcessor ) 838 data = editor.dataProcessor.toDataFormat( data, fixForBody ); 839 840 // Strip the last blank paragraph within document. 841 if ( config.ignoreEmptyParagraph ) 842 data = data.replace( emptyParagraphRegexp, '' ); 843 844 if ( docType ) 845 data = docType + '\n' + data; 846 847 return data; 848 }, 849 850 getSnapshotData : function() 851 { 852 return iframe.getFrameDocument().getBody().getHtml(); 853 }, 854 855 loadSnapshotData : function( data ) 856 { 857 iframe.getFrameDocument().getBody().setHtml( data ); 858 }, 859 860 onDispose : function() 861 { 862 if ( !editor.document ) 863 return; 864 865 editor.document.getDocumentElement().clearCustomData(); 866 editor.document.getBody().clearCustomData(); 867 868 editor.window.clearCustomData(); 869 editor.document.clearCustomData(); 870 871 iframe.clearCustomData(); 872 873 /* 874 * IE BUG: When destroying editor DOM with the selection remains inside 875 * editing area would break IE7/8's selection system, we have to put the editing 876 * iframe offline first. (#3812 and #5441) 877 */ 878 iframe.remove(); 879 }, 880 881 unload : function( holderElement ) 882 { 883 this.onDispose(); 884 885 editor.window = editor.document = iframe = mainElement = isPendingFocus = null; 886 887 editor.fire( 'contentDomUnload' ); 888 }, 889 890 focus : function() 891 { 892 if ( isLoadingData ) 893 isPendingFocus = true; 894 // Temporary solution caused by #6025, supposed be unified by #6154. 895 else if ( CKEDITOR.env.opera && editor.document ) 896 { 897 editor.document.getBody().focus(); 898 899 editor.selectionChange(); 900 } 901 else if ( !CKEDITOR.env.opera && editor.window ) 902 { 903 editor.window.focus(); 904 905 editor.selectionChange(); 906 } 907 } 908 }); 909 910 editor.on( 'insertHtml', onInsertHtml, null, null, 20 ); 911 editor.on( 'insertElement', onInsertElement, null, null, 20 ); 912 // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189) 913 editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 ); 914 }); 915 916 var titleBackup; 917 // Setting voice label as window title, backup the original one 918 // and restore it before running into use. 919 editor.on( 'contentDom', function () 920 { 921 var title = editor.document.getElementsByTag( 'title' ).getItem( 0 ); 922 title.setAttribute( '_cke_title', editor.document.$.title ); 923 editor.document.$.title = frameLabel; 924 }); 925 926 // IE8 stricts mode doesn't have 'contentEditable' in effect 927 // on element unless it has layout. (#5562) 928 if ( CKEDITOR.env.ie8Compat ) 929 { 930 editor.addCss( 'html.CSS1Compat [contenteditable=false]{ min-height:0 !important;}' ); 931 932 var selectors = []; 933 for ( var tag in CKEDITOR.dtd.$removeEmpty ) 934 selectors.push( 'html.CSS1Compat ' + tag + '[contenteditable=false]' ); 935 editor.addCss( selectors.join( ',' ) + '{ display:inline-block;}' ); 936 } 937 938 // Switch on design mode for a short while and close it after then. 939 function blinkCursor( retry ) 940 { 941 CKEDITOR.tools.tryThese( 942 function() 943 { 944 editor.document.$.designMode = 'on'; 945 setTimeout( function () 946 { 947 editor.document.$.designMode = 'off'; 948 editor.document.getBody().focus(); 949 }, 50 ); 950 }, 951 function() 952 { 953 // The above call is known to fail when parent DOM 954 // tree layout changes may break design mode. (#5782) 955 // Refresh the 'contentEditable' is a cue to this. 956 editor.document.$.designMode = 'off'; 957 var body = editor.document.getBody(); 958 body.setAttribute( 'contentEditable', false ); 959 body.setAttribute( 'contentEditable', true ); 960 // Try it again once.. 961 !retry && blinkCursor( 1 ); 962 }); 963 } 964 965 // Create an invisible element to grab focus. 966 if ( CKEDITOR.env.gecko || CKEDITOR.env.ie || CKEDITOR.env.opera ) 967 { 968 var focusGrabber; 969 editor.on( 'uiReady', function() 970 { 971 focusGrabber = editor.container.append( CKEDITOR.dom.element.createFromHtml( 972 // Use 'span' instead of anything else to fly under the screen-reader radar. (#5049) 973 '<span tabindex="-1" style="position:absolute; left:-10000" role="presentation"></span>' ) ); 974 975 focusGrabber.on( 'focus', function() 976 { 977 editor.focus(); 978 } ); 979 } ); 980 editor.on( 'destroy', function() 981 { 982 CKEDITOR.tools.removeFunction( contentDomReadyHandler ); 983 focusGrabber.clearCustomData(); 984 } ); 985 } 986 987 // Disable form elements editing mode provided by some browers. (#5746) 988 editor.on( 'insertElement', function ( evt ) 989 { 990 var element = evt.data; 991 if ( element.type == CKEDITOR.NODE_ELEMENT 992 && ( element.is( 'input' ) || element.is( 'textarea' ) ) ) 993 { 994 if ( !element.isReadOnly() ) 995 { 996 element.setAttribute( 'contentEditable', false ); 997 // We should flag that the element was locked by our code so 998 // it'll be editable by the editor functions (#6046). 999 element.setCustomData( '_cke_notReadOnly', 1 ); 1000 } 1001 } 1002 }); 1003 1004 } 1005 }); 1006 1007 // Fixing Firefox 'Back-Forward Cache' break design mode. (#4514) 1008 if ( CKEDITOR.env.gecko ) 1009 { 1010 ( function () 1011 { 1012 var body = document.body; 1013 1014 if ( !body ) 1015 window.addEventListener( 'load', arguments.callee, false ); 1016 else 1017 { 1018 var currentHandler = body.getAttribute( 'onpageshow' ); 1019 body.setAttribute( 'onpageshow', ( currentHandler ? currentHandler + ';' : '') + 1020 'event.persisted && (function(){' + 1021 'var allInstances = CKEDITOR.instances, editor, doc;' + 1022 'for ( var i in allInstances )' + 1023 '{' + 1024 ' editor = allInstances[ i ];' + 1025 ' doc = editor.document;' + 1026 ' if ( doc )' + 1027 ' {' + 1028 ' doc.$.designMode = "off";' + 1029 ' doc.$.designMode = "on";' + 1030 ' }' + 1031 '}' + 1032 '})();' ); 1033 } 1034 } )(); 1035 1036 } 1037 })(); 1038 1039 /** 1040 * Disables the ability of resize objects (image and tables) in the editing 1041 * area. 1042 * @type Boolean 1043 * @default false 1044 * @example 1045 * config.disableObjectResizing = true; 1046 */ 1047 CKEDITOR.config.disableObjectResizing = false; 1048 1049 /** 1050 * Disables the "table tools" offered natively by the browser (currently 1051 * Firefox only) to make quick table editing operations, like adding or 1052 * deleting rows and columns. 1053 * @type Boolean 1054 * @default true 1055 * @example 1056 * config.disableNativeTableHandles = false; 1057 */ 1058 CKEDITOR.config.disableNativeTableHandles = true; 1059 1060 /** 1061 * Disables the built-in spell checker while typing natively available in the 1062 * browser (currently Firefox and Safari only).<br /><br /> 1063 * 1064 * Even if word suggestions will not appear in the CKEditor context menu, this 1065 * feature is useful to help quickly identifying misspelled words.<br /><br /> 1066 * 1067 * This setting is currently compatible with Firefox only due to limitations in 1068 * other browsers. 1069 * @type Boolean 1070 * @default true 1071 * @example 1072 * config.disableNativeSpellChecker = false; 1073 */ 1074 CKEDITOR.config.disableNativeSpellChecker = true; 1075 1076 /** 1077 * Whether the editor must output an empty value ("") if it's contents is made 1078 * by an empty paragraph only. 1079 * @type Boolean 1080 * @default true 1081 * @example 1082 * config.ignoreEmptyParagraph = false; 1083 */ 1084 CKEDITOR.config.ignoreEmptyParagraph = true; 1085 1086 /** 1087 * Fired when data is loaded and ready for retrieval in an editor instance. 1088 * @name CKEDITOR.editor#dataReady 1089 * @event 1090 */
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |