|
164 | 164 | var needsBlock = currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && ( paragraphMode != CKEDITOR.ENTER_BR || dirLoose || style || className );
|
165 | 165 |
|
166 | 166 | var child,
|
167 |
| - count = item.contents.length; |
| 167 | + count = item.contents.length, |
| 168 | + cachedBookmark; |
| 169 | + |
168 | 170 | for ( i = 0; i < count; i++ ) {
|
169 | 171 | child = item.contents[ i ];
|
170 | 172 |
|
171 |
| - if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() ) { |
| 173 | + // Append bookmark if we can, or cache it and append it when we'll know |
| 174 | + // what to do with it. Generally - we want to keep it next to its original neighbour. |
| 175 | + // Exception: if bookmark is the only child it hasn't got any neighbour, so handle it normally |
| 176 | + // (wrap with block if needed). |
| 177 | + if ( bookmarks( child ) && count > 1 ) { |
| 178 | + // If we don't need block, it's simple - append bookmark directly to the current list item. |
| 179 | + if ( !needsBlock ) |
| 180 | + currentListItem.append( child.clone( 1, 1 ) ); |
| 181 | + else |
| 182 | + cachedBookmark = child.clone( 1, 1 ); |
| 183 | + } |
| 184 | + // Block content goes directly to the current list item, without wrapping. |
| 185 | + else if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() ) { |
172 | 186 | // Apply direction on content blocks.
|
173 | 187 | if ( dirLoose && !child.getDirection() )
|
174 | 188 | child.setAttribute( 'dir', orgDir );
|
175 | 189 |
|
176 | 190 | inheirtInlineStyles( li, child );
|
177 | 191 |
|
178 | 192 | className && child.addClass( className );
|
179 |
| - } else if ( needsBlock ) { |
| 193 | + |
| 194 | + // Close the block which we started for inline content. |
| 195 | + block = null; |
| 196 | + // Append bookmark directly before current child. |
| 197 | + if ( cachedBookmark ) { |
| 198 | + currentListItem.append( cachedBookmark ); |
| 199 | + cachedBookmark = null; |
| 200 | + } |
| 201 | + // Append this block element to the list item. |
| 202 | + currentListItem.append( child.clone( 1, 1 ) ); |
| 203 | + } |
| 204 | + // Some inline content was found - wrap it with block and append that |
| 205 | + // block to the current list item or append it to the block previously created. |
| 206 | + else if ( needsBlock ) { |
180 | 207 | // Establish new block to hold text direction and styles.
|
181 | 208 | if ( !block ) {
|
182 | 209 | block = doc.createElement( paragraphName );
|
| 210 | + currentListItem.append( block ); |
183 | 211 | dirLoose && block.setAttribute( 'dir', orgDir );
|
184 | 212 | }
|
185 | 213 |
|
186 | 214 | // Copy over styles to new block;
|
187 | 215 | style && block.setAttribute( 'style', style );
|
188 | 216 | className && block.setAttribute( 'class', className );
|
189 | 217 |
|
| 218 | + // Append bookmark directly before current child. |
| 219 | + if ( cachedBookmark ) { |
| 220 | + block.append( cachedBookmark ); |
| 221 | + cachedBookmark = null; |
| 222 | + } |
190 | 223 | block.append( child.clone( 1, 1 ) );
|
191 | 224 | }
|
| 225 | + // E.g. BR mode - inline content appended directly to the list item. |
| 226 | + else |
| 227 | + currentListItem.append( child.clone( 1, 1 ) ); |
| 228 | + } |
192 | 229 |
|
193 |
| - currentListItem.append( block || child.clone( 1, 1 ) ); |
| 230 | + // No content after bookmark - append it to the block if we had one |
| 231 | + // or directly to the current list item if we finished directly in the current list item. |
| 232 | + if ( cachedBookmark ) { |
| 233 | + ( block || currentListItem ).append( cachedBookmark ); |
| 234 | + cachedBookmark = null; |
194 | 235 | }
|
195 | 236 |
|
196 | 237 | if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT && currentIndex != listArray.length - 1 ) {
|
|
295 | 336 | editor.fire( 'contentDomInvalidated' );
|
296 | 337 | }
|
297 | 338 |
|
298 |
| - var headerTagRegex = /^h[1-6]$/; |
299 |
| - |
300 | 339 | function createList( editor, groupObj, listsCreated ) {
|
301 | 340 | var contents = groupObj.contents,
|
302 | 341 | doc = groupObj.root.getDocument(),
|
|
366 | 405 | contentBlock = listContents.shift();
|
367 | 406 | listItem = doc.createElement( 'li' );
|
368 | 407 |
|
369 |
| - // Preserve preformat block and heading structure when converting to list item. (#5335) (#5271) |
370 |
| - if ( contentBlock.is( 'pre' ) || headerTagRegex.test( contentBlock.getName() ) ) |
| 408 | + // If current block should be preserved, append it to list item instead of |
| 409 | + // transforming it to <li> element. |
| 410 | + if ( shouldPreserveBlock( contentBlock ) ) |
371 | 411 | contentBlock.appendTo( listItem );
|
372 | 412 | else {
|
373 | 413 | contentBlock.copyAttributes( listItem );
|
|
449 | 489 | editor.fire( 'contentDomInvalidated' );
|
450 | 490 | }
|
451 | 491 |
|
| 492 | + var headerTagRegex = /^h[1-6]$/; |
| 493 | + |
| 494 | + // Checks wheather this block should be element preserved (not transformed to <li>) when creating list. |
| 495 | + function shouldPreserveBlock( block ) { |
| 496 | + return ( |
| 497 | + // #5335 |
| 498 | + block.is( 'pre' ) || |
| 499 | + // #5271 - this is a header. |
| 500 | + headerTagRegex.test( block.getName() ) || |
| 501 | + // 11083 - this is a non-editable element. |
| 502 | + block.getAttribute( 'contenteditable' ) == 'false' |
| 503 | + ); |
| 504 | + } |
| 505 | + |
452 | 506 | function listCommand( name, type ) {
|
453 | 507 | this.name = name;
|
454 | 508 | this.type = type;
|
|
0 commit comments