| | 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 | */ |