diff options
Diffstat (limited to 'sources/plugins/blockquote/plugin.js')
-rw-r--r-- | sources/plugins/blockquote/plugin.js | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/sources/plugins/blockquote/plugin.js b/sources/plugins/blockquote/plugin.js new file mode 100644 index 00000000..0b2bf332 --- /dev/null +++ b/sources/plugins/blockquote/plugin.js | |||
@@ -0,0 +1,251 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | ( function() { | ||
7 | function noBlockLeft( bqBlock ) { | ||
8 | for ( var i = 0, length = bqBlock.getChildCount(), child; i < length && ( child = bqBlock.getChild( i ) ); i++ ) { | ||
9 | if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() ) | ||
10 | return false; | ||
11 | } | ||
12 | return true; | ||
13 | } | ||
14 | |||
15 | var commandObject = { | ||
16 | exec: function( editor ) { | ||
17 | var state = editor.getCommand( 'blockquote' ).state, | ||
18 | selection = editor.getSelection(), | ||
19 | range = selection && selection.getRanges()[ 0 ]; | ||
20 | |||
21 | if ( !range ) | ||
22 | return; | ||
23 | |||
24 | var bookmarks = selection.createBookmarks(); | ||
25 | |||
26 | // Kludge for #1592: if the bookmark nodes are in the beginning of | ||
27 | // blockquote, then move them to the nearest block element in the | ||
28 | // blockquote. | ||
29 | if ( CKEDITOR.env.ie ) { | ||
30 | var bookmarkStart = bookmarks[ 0 ].startNode, | ||
31 | bookmarkEnd = bookmarks[ 0 ].endNode, | ||
32 | cursor; | ||
33 | |||
34 | if ( bookmarkStart && bookmarkStart.getParent().getName() == 'blockquote' ) { | ||
35 | cursor = bookmarkStart; | ||
36 | while ( ( cursor = cursor.getNext() ) ) { | ||
37 | if ( cursor.type == CKEDITOR.NODE_ELEMENT && cursor.isBlockBoundary() ) { | ||
38 | bookmarkStart.move( cursor, true ); | ||
39 | break; | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | |||
44 | if ( bookmarkEnd && bookmarkEnd.getParent().getName() == 'blockquote' ) { | ||
45 | cursor = bookmarkEnd; | ||
46 | while ( ( cursor = cursor.getPrevious() ) ) { | ||
47 | if ( cursor.type == CKEDITOR.NODE_ELEMENT && cursor.isBlockBoundary() ) { | ||
48 | bookmarkEnd.move( cursor ); | ||
49 | break; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | var iterator = range.createIterator(), | ||
56 | block; | ||
57 | iterator.enlargeBr = editor.config.enterMode != CKEDITOR.ENTER_BR; | ||
58 | |||
59 | if ( state == CKEDITOR.TRISTATE_OFF ) { | ||
60 | var paragraphs = []; | ||
61 | while ( ( block = iterator.getNextParagraph() ) ) | ||
62 | paragraphs.push( block ); | ||
63 | |||
64 | // If no paragraphs, create one from the current selection position. | ||
65 | if ( paragraphs.length < 1 ) { | ||
66 | var para = editor.document.createElement( editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ), | ||
67 | firstBookmark = bookmarks.shift(); | ||
68 | range.insertNode( para ); | ||
69 | para.append( new CKEDITOR.dom.text( '\ufeff', editor.document ) ); | ||
70 | range.moveToBookmark( firstBookmark ); | ||
71 | range.selectNodeContents( para ); | ||
72 | range.collapse( true ); | ||
73 | firstBookmark = range.createBookmark(); | ||
74 | paragraphs.push( para ); | ||
75 | bookmarks.unshift( firstBookmark ); | ||
76 | } | ||
77 | |||
78 | // Make sure all paragraphs have the same parent. | ||
79 | var commonParent = paragraphs[ 0 ].getParent(), | ||
80 | tmp = []; | ||
81 | for ( var i = 0; i < paragraphs.length; i++ ) { | ||
82 | block = paragraphs[ i ]; | ||
83 | commonParent = commonParent.getCommonAncestor( block.getParent() ); | ||
84 | } | ||
85 | |||
86 | // The common parent must not be the following tags: table, tbody, tr, ol, ul. | ||
87 | var denyTags = { table: 1, tbody: 1, tr: 1, ol: 1, ul: 1 }; | ||
88 | while ( denyTags[ commonParent.getName() ] ) | ||
89 | commonParent = commonParent.getParent(); | ||
90 | |||
91 | // Reconstruct the block list to be processed such that all resulting blocks | ||
92 | // satisfy parentNode.equals( commonParent ). | ||
93 | var lastBlock = null; | ||
94 | while ( paragraphs.length > 0 ) { | ||
95 | block = paragraphs.shift(); | ||
96 | while ( !block.getParent().equals( commonParent ) ) | ||
97 | block = block.getParent(); | ||
98 | if ( !block.equals( lastBlock ) ) | ||
99 | tmp.push( block ); | ||
100 | lastBlock = block; | ||
101 | } | ||
102 | |||
103 | // If any of the selected blocks is a blockquote, remove it to prevent | ||
104 | // nested blockquotes. | ||
105 | while ( tmp.length > 0 ) { | ||
106 | block = tmp.shift(); | ||
107 | if ( block.getName() == 'blockquote' ) { | ||
108 | var docFrag = new CKEDITOR.dom.documentFragment( editor.document ); | ||
109 | while ( block.getFirst() ) { | ||
110 | docFrag.append( block.getFirst().remove() ); | ||
111 | paragraphs.push( docFrag.getLast() ); | ||
112 | } | ||
113 | |||
114 | docFrag.replace( block ); | ||
115 | } else { | ||
116 | paragraphs.push( block ); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | // Now we have all the blocks to be included in a new blockquote node. | ||
121 | var bqBlock = editor.document.createElement( 'blockquote' ); | ||
122 | bqBlock.insertBefore( paragraphs[ 0 ] ); | ||
123 | while ( paragraphs.length > 0 ) { | ||
124 | block = paragraphs.shift(); | ||
125 | bqBlock.append( block ); | ||
126 | } | ||
127 | } else if ( state == CKEDITOR.TRISTATE_ON ) { | ||
128 | var moveOutNodes = [], | ||
129 | database = {}; | ||
130 | |||
131 | while ( ( block = iterator.getNextParagraph() ) ) { | ||
132 | var bqParent = null, | ||
133 | bqChild = null; | ||
134 | while ( block.getParent() ) { | ||
135 | if ( block.getParent().getName() == 'blockquote' ) { | ||
136 | bqParent = block.getParent(); | ||
137 | bqChild = block; | ||
138 | break; | ||
139 | } | ||
140 | block = block.getParent(); | ||
141 | } | ||
142 | |||
143 | // Remember the blocks that were recorded down in the moveOutNodes array | ||
144 | // to prevent duplicates. | ||
145 | if ( bqParent && bqChild && !bqChild.getCustomData( 'blockquote_moveout' ) ) { | ||
146 | moveOutNodes.push( bqChild ); | ||
147 | CKEDITOR.dom.element.setMarker( database, bqChild, 'blockquote_moveout', true ); | ||
148 | } | ||
149 | } | ||
150 | |||
151 | CKEDITOR.dom.element.clearAllMarkers( database ); | ||
152 | |||
153 | var movedNodes = [], | ||
154 | processedBlockquoteBlocks = []; | ||
155 | |||
156 | database = {}; | ||
157 | while ( moveOutNodes.length > 0 ) { | ||
158 | var node = moveOutNodes.shift(); | ||
159 | bqBlock = node.getParent(); | ||
160 | |||
161 | // If the node is located at the beginning or the end, just take it out | ||
162 | // without splitting. Otherwise, split the blockquote node and move the | ||
163 | // paragraph in between the two blockquote nodes. | ||
164 | if ( !node.getPrevious() ) | ||
165 | node.remove().insertBefore( bqBlock ); | ||
166 | else if ( !node.getNext() ) | ||
167 | node.remove().insertAfter( bqBlock ); | ||
168 | else { | ||
169 | node.breakParent( node.getParent() ); | ||
170 | processedBlockquoteBlocks.push( node.getNext() ); | ||
171 | } | ||
172 | |||
173 | // Remember the blockquote node so we can clear it later (if it becomes empty). | ||
174 | if ( !bqBlock.getCustomData( 'blockquote_processed' ) ) { | ||
175 | processedBlockquoteBlocks.push( bqBlock ); | ||
176 | CKEDITOR.dom.element.setMarker( database, bqBlock, 'blockquote_processed', true ); | ||
177 | } | ||
178 | |||
179 | movedNodes.push( node ); | ||
180 | } | ||
181 | |||
182 | CKEDITOR.dom.element.clearAllMarkers( database ); | ||
183 | |||
184 | // Clear blockquote nodes that have become empty. | ||
185 | for ( i = processedBlockquoteBlocks.length - 1; i >= 0; i-- ) { | ||
186 | bqBlock = processedBlockquoteBlocks[ i ]; | ||
187 | if ( noBlockLeft( bqBlock ) ) | ||
188 | bqBlock.remove(); | ||
189 | } | ||
190 | |||
191 | if ( editor.config.enterMode == CKEDITOR.ENTER_BR ) { | ||
192 | var firstTime = true; | ||
193 | while ( movedNodes.length ) { | ||
194 | node = movedNodes.shift(); | ||
195 | |||
196 | if ( node.getName() == 'div' ) { | ||
197 | docFrag = new CKEDITOR.dom.documentFragment( editor.document ); | ||
198 | var needBeginBr = firstTime && node.getPrevious() && !( node.getPrevious().type == CKEDITOR.NODE_ELEMENT && node.getPrevious().isBlockBoundary() ); | ||
199 | if ( needBeginBr ) | ||
200 | docFrag.append( editor.document.createElement( 'br' ) ); | ||
201 | |||
202 | var needEndBr = node.getNext() && !( node.getNext().type == CKEDITOR.NODE_ELEMENT && node.getNext().isBlockBoundary() ); | ||
203 | while ( node.getFirst() ) | ||
204 | node.getFirst().remove().appendTo( docFrag ); | ||
205 | |||
206 | if ( needEndBr ) | ||
207 | docFrag.append( editor.document.createElement( 'br' ) ); | ||
208 | |||
209 | docFrag.replace( node ); | ||
210 | firstTime = false; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | |||
216 | selection.selectBookmarks( bookmarks ); | ||
217 | editor.focus(); | ||
218 | }, | ||
219 | |||
220 | refresh: function( editor, path ) { | ||
221 | // Check if inside of blockquote. | ||
222 | var firstBlock = path.block || path.blockLimit; | ||
223 | this.setState( editor.elementPath( firstBlock ).contains( 'blockquote', 1 ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); | ||
224 | }, | ||
225 | |||
226 | context: 'blockquote', | ||
227 | |||
228 | allowedContent: 'blockquote', | ||
229 | requiredContent: 'blockquote' | ||
230 | }; | ||
231 | |||
232 | CKEDITOR.plugins.add( 'blockquote', { | ||
233 | // jscs:disable maximumLineLength | ||
234 | lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en,en-au,en-ca,en-gb,eo,es,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% | ||
235 | // jscs:enable maximumLineLength | ||
236 | icons: 'blockquote', // %REMOVE_LINE_CORE% | ||
237 | hidpi: true, // %REMOVE_LINE_CORE% | ||
238 | init: function( editor ) { | ||
239 | if ( editor.blockless ) | ||
240 | return; | ||
241 | |||
242 | editor.addCommand( 'blockquote', commandObject ); | ||
243 | |||
244 | editor.ui.addButton && editor.ui.addButton( 'Blockquote', { | ||
245 | label: editor.lang.blockquote.toolbar, | ||
246 | command: 'blockquote', | ||
247 | toolbar: 'blocks,10' | ||
248 | } ); | ||
249 | } | ||
250 | } ); | ||
251 | } )(); | ||