| 1 | /* |
| 2 | Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved. |
| 3 | For licensing, see LICENSE.html or http://ckeditor.com/license |
| 4 | */ |
| 5 | |
| 6 | /** |
| 7 | * @file Plugin for creating Drupal teasers(fake object). |
| 8 | */ |
| 9 | CKEDITOR.plugins.add( 'drupalpagebreak', |
| 10 | { |
| 11 | requires : [ 'htmldataprocessor','fakeobjects', 'styles' ], |
| 12 | init : function( editor ) |
| 13 | { |
| 14 | // Add the style that renders our placeholder. |
| 15 | editor.addCss( |
| 16 | 'img.cke_drupal_break' + |
| 17 | '{' + |
| 18 | 'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/placeholder.gif' ) + ');' + |
| 19 | '-webkit-background-size: 20px 20px;' + |
| 20 | '-o-background-size: 20px 20px;' + |
| 21 | 'background-position: center center;' + |
| 22 | 'background-repeat: no-repeat;' + |
| 23 | 'display: inline;' + |
| 24 | 'width: 20px;' + |
| 25 | 'vertical-align: middle;' + |
| 26 | 'border: #999999 1px dotted;' + |
| 27 | '}' ); |
| 28 | |
| 29 | editor.ui.addButton( 'DrupalPageBreak', |
| 30 | { |
| 31 | label : editor.lang.drupalPageBreak, |
| 32 | command : 'drupalpagebreak' |
| 33 | }); |
| 34 | }, |
| 35 | |
| 36 | // There's currently no gurantee on registration order, this make sure |
| 37 | // the registration will come after the default ones in 'htmldataprocessor'. |
| 38 | afterInit : function( editor ) |
| 39 | { |
| 40 | var dataProcessor = editor.dataProcessor, |
| 41 | dataFilter = dataProcessor.dataFilter, |
| 42 | htmlFilter = dataProcessor.htmlFilter, |
| 43 | // Borrow the comment output filters to restore them. |
| 44 | commentFilters = htmlFilter._.comment, |
| 45 | filter = commentFilters && ( commentFilters.filter || commentFilters[ 0 ] ), |
| 46 | config = editor.config, |
| 47 | pageBreak = config.drupalPageBreak, |
| 48 | displayName, |
| 49 | allFakeWrapperTagNames = {}; |
| 50 | |
| 51 | pageBreak.displayName = displayName = pageBreak.displayName || 'drupal-page-break'; |
| 52 | |
| 53 | // Register into DTDs. |
| 54 | var dtd = CKEDITOR.dtd, |
| 55 | dtdParents = pageBreak.dtdParents; |
| 56 | for( var tag in dtdParents ) |
| 57 | { |
| 58 | if( dtdParents.hasOwnProperty( tag ) ) |
| 59 | { |
| 60 | |
| 61 | var parentDtd = tag == 'body' ? dtd.$body : dtd[ tag ]; |
| 62 | parentDtd && ( parentDtd[ displayName ] = 1 ); |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | // DataFilter for creating fake objects from HTML comment. |
| 67 | dataFilter.addRules( |
| 68 | { |
| 69 | comment : function( value ) |
| 70 | { |
| 71 | var cdata = filter( value ); |
| 72 | |
| 73 | // CData instance is received. |
| 74 | if ( cdata.value ) |
| 75 | { |
| 76 | var fakeElement; |
| 77 | // Is it actually a comment and match the desired pattern? |
| 78 | cdata.value.replace( /<!--([\s\S]*?)-->/, function( match, content ) |
| 79 | { |
| 80 | if( content == pageBreak.content ) |
| 81 | { |
| 82 | var fakeWrapper = new CKEDITOR.htmlParser.element( displayName, {} ); |
| 83 | fakeWrapper.add( cdata ); |
| 84 | fakeElement = editor.createFakeParserElement( |
| 85 | fakeWrapper, |
| 86 | 'cke_drupal_break cke_' + CKEDITOR.tools.escapeCssSelector( displayName ), |
| 87 | displayName, |
| 88 | false ); |
| 89 | |
| 90 | // Comment content specific style. |
| 91 | fakeElement.attributes.style = CKEDITOR.style.getStyleText( pageBreak ); |
| 92 | allFakeWrapperTagNames[ displayName ] = 1; |
| 93 | } |
| 94 | } ); |
| 95 | |
| 96 | if ( fakeElement ) |
| 97 | { |
| 98 | return fakeElement; |
| 99 | } |
| 100 | } |
| 101 | return value; |
| 102 | } |
| 103 | } ); |
| 104 | |
| 105 | // HtmlFilter rules for outputting as a HTML comment. |
| 106 | var restorePageBreakRule = { elements : {} }; |
| 107 | restorePageBreakRule.elements[ displayName ] = function( wrapper ) |
| 108 | { |
| 109 | delete wrapper.name; |
| 110 | } |
| 111 | htmlFilter.addRules( restorePageBreakRule ); |
| 112 | |
| 113 | editor.addCommand( 'drupalpagebreak', |
| 114 | { |
| 115 | exec : function( editor ) |
| 116 | { |
| 117 | var ranges = editor.getSelection().getRanges(); |
| 118 | for ( var range, i = 0 ; i < ranges.length ; i++ ) |
| 119 | { |
| 120 | range = ranges[ i ]; |
| 121 | range.deleteContents(); |
| 122 | var current, dtd; |
| 123 | while ( ( current = range.getCommonAncestor( false, true ) ) |
| 124 | && ( dtd = CKEDITOR.dtd[ current.getName( ) ] ) |
| 125 | && !dtd[ displayName ] ) |
| 126 | range.splitBlock(); |
| 127 | |
| 128 | // We intend to place the cursor right at the last split |
| 129 | // point for later use of editor::insertHtml, while in some |
| 130 | // situation this kind of selection doesn't work (e.g. between |
| 131 | // two tables in IE), so here we employ a text node as place-holder. |
| 132 | var placeholder = editor.document.createText( '\xa0' ), |
| 133 | next; |
| 134 | range.insertNode( placeholder ); |
| 135 | range.select(); |
| 136 | next = placeholder.getNextSourceNode( true ); |
| 137 | |
| 138 | editor.insertHtml( '<!--' + pageBreak.content + '-->'); |
| 139 | |
| 140 | // Place cursor at the next editable position. |
| 141 | if ( next && next.type == CKEDITOR.NODE_ELEMENT ) |
| 142 | range.moveToElementEditStart( next ); |
| 143 | else |
| 144 | range.collapse(); |
| 145 | |
| 146 | range.select( true ); |
| 147 | } |
| 148 | } |
| 149 | } ); |
| 150 | } |
| 151 | } ); |
| 152 | |
| 153 | /** |
| 154 | * A list of comment definition which will be converted to fake element in wysiwyg mode. |
| 155 | * @name CKEDITOR.config.fakeComments |
| 156 | * @type Array |
| 157 | * @default [] |
| 158 | * @example |
| 159 | * CKEDITOR.config.drupalPageBreak = |
| 160 | * { |
| 161 | * content : 'pagebreak', |
| 162 | * styles : |
| 163 | * { |
| 164 | * display : 'block' |
| 165 | * }, |
| 166 | * dtdParents : CKEDITOR.dtd.$block, // List of of valid parent element tag names, |
| 167 | * // could impact on the position how fake object |
| 168 | * // is positioned in document. |
| 169 | * displayName : 'page-break' |
| 170 | * }; |
| 171 | */ |