|
1730 | 1730 | } );
|
1731 | 1731 | }
|
1732 | 1732 |
|
| 1733 | + // And now we've got two problems - original problem and RegExp. |
| 1734 | + // Some softeners: |
| 1735 | + // * FF tends to copy all blocks up to the copybin container. |
| 1736 | + // * IE tends to copy only the copybin, without its container. |
| 1737 | + // * We use spans on IE and blockless editors, but divs in other cases. |
| 1738 | + var pasteReplaceRegex = new RegExp( |
| 1739 | + '^' + |
| 1740 | + '(?:<(?:div|span)(?: id="cke_copybin")?>)?' + |
| 1741 | + '(?:<(?:div|span)(?: style="[^"]+")?>)?' + |
| 1742 | + '<span [^>]*data-cke-copybin-start="1"[^>]*>.?</span>([\\s\\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?</span>' + |
| 1743 | + '(?:</(?:div|span)>)?' + |
| 1744 | + '(?:</(?:div|span)>)?' + |
| 1745 | + '$' |
| 1746 | + ); |
| 1747 | + |
1733 | 1748 | // Set up data processing like:
|
1734 | 1749 | // * toHtml/toDataFormat,
|
1735 | 1750 | // * pasting handling,
|
|
1747 | 1762 | // Handle pasted single widget.
|
1748 | 1763 | editor.on( 'paste', function( evt ) {
|
1749 | 1764 | evt.data.dataValue = evt.data.dataValue.replace(
|
1750 |
| - /^(?:<div id="cke_copybin">)?<span [^>]*data-cke-copybin-start="1"[^>]*>.?<\/span>([\s\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?<\/span>(?:<\/div>)?$/, |
| 1765 | + pasteReplaceRegex, |
1751 | 1766 | '$1'
|
1752 | 1767 | );
|
1753 | 1768 | } );
|
|
2231 | 2246 |
|
2232 | 2247 | function copySingleWidget( widget, isCut ) {
|
2233 | 2248 | var editor = widget.editor,
|
2234 |
| - copybin = new CKEDITOR.dom.element( 'div', editor.document ); |
| 2249 | + doc = editor.document; |
| 2250 | + |
| 2251 | + // We're still handling previous copy/cut. |
| 2252 | + if ( doc.getById( 'cke_copybin' ) ) |
| 2253 | + return; |
2235 | 2254 |
|
2236 |
| - copybin.setAttributes( { |
2237 |
| - id: 'cke_copybin' |
| 2255 | + // [IE] Use span for copybin and its container to avoid bug with expanding editable height by |
| 2256 | + // absolutely positioned element. |
| 2257 | + var copybinName = ( editor.blockless || CKEDITOR.env.ie ) ? 'span' : 'div', |
| 2258 | + copybin = doc.createElement( copybinName ), |
| 2259 | + copybinContainer = doc.createElement( copybinName ), |
| 2260 | + // IE8 always jumps to the end of document. |
| 2261 | + needsScrollHack = CKEDITOR.env.ie && CKEDITOR.env.version < 9; |
| 2262 | + |
| 2263 | + copybinContainer.setAttribute( 'id', 'cke_copybin' ); |
| 2264 | + |
| 2265 | + // Position copybin element outside current viewport. |
| 2266 | + copybin.setStyles( { |
| 2267 | + position: 'absolute', |
| 2268 | + width: '1px', |
| 2269 | + height: '1px', |
| 2270 | + overflow: 'hidden' |
2238 | 2271 | } );
|
2239 | 2272 |
|
| 2273 | + copybin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-5000px' ); |
| 2274 | + |
2240 | 2275 | copybin.setHtml( '<span data-cke-copybin-start="1">\u200b</span>' + widget.wrapper.getOuterHtml() + '<span data-cke-copybin-end="1">\u200b</span>' );
|
2241 | 2276 |
|
2242 | 2277 | // Save snapshot with the current state.
|
|
2245 | 2280 | // Ignore copybin.
|
2246 | 2281 | editor.fire( 'lockSnapshot' );
|
2247 | 2282 |
|
2248 |
| - editor.editable().append( copybin ); |
| 2283 | + copybinContainer.append( copybin ); |
| 2284 | + editor.editable().append( copybinContainer ); |
2249 | 2285 |
|
2250 | 2286 | var listener1 = editor.on( 'selectionChange', cancel, null, null, 0 ),
|
2251 | 2287 | listener2 = widget.repository.on( 'checkSelection', cancel, null, null, 0 );
|
2252 | 2288 |
|
| 2289 | + if ( needsScrollHack ) { |
| 2290 | + var docElement = doc.getDocumentElement().$, |
| 2291 | + scrollTop = docElement.scrollTop; |
| 2292 | + } |
| 2293 | + |
2253 | 2294 | // Once the clone of the widget is inside of copybin, select
|
2254 | 2295 | // the entire contents. This selection will be copied by the
|
2255 | 2296 | // native browser's clipboard system.
|
2256 | 2297 | var range = editor.createRange();
|
2257 | 2298 | range.selectNodeContents( copybin );
|
2258 | 2299 | range.select();
|
2259 | 2300 |
|
2260 |
| - setTimeout( function() { |
2261 |
| - copybin.remove(); |
| 2301 | + if ( needsScrollHack ) |
| 2302 | + docElement.scrollTop = scrollTop; |
2262 | 2303 |
|
| 2304 | + setTimeout( function() { |
| 2305 | + // [IE] Focus widget before removing copybin to avoid scroll jump. |
2263 | 2306 | if ( !isCut )
|
2264 | 2307 | widget.focus();
|
2265 | 2308 |
|
| 2309 | + copybinContainer.remove(); |
| 2310 | + |
2266 | 2311 | listener1.removeListener();
|
2267 | 2312 | listener2.removeListener();
|
2268 | 2313 |
|
|
2272 | 2317 | widget.repository.del( widget );
|
2273 | 2318 | editor.fire( 'saveSnapshot' );
|
2274 | 2319 | }
|
2275 |
| - }, 10 ); // Use 10ms, so Chrome (@Mac) will be able to grab the content. |
| 2320 | + }, 100 ); // Use 100ms, so Chrome (@Mac) will be able to grab the content. |
2276 | 2321 | }
|
2277 | 2322 |
|
2278 | 2323 | // [IE] Force keeping focus because IE sometimes forgets to fire focus on main editable
|
|
0 commit comments