aboutsummaryrefslogtreecommitdiff
path: root/sources/plugins/clipboard
diff options
context:
space:
mode:
Diffstat (limited to 'sources/plugins/clipboard')
-rw-r--r--sources/plugins/clipboard/dev/clipboard.html190
-rw-r--r--sources/plugins/clipboard/dev/console.js49
-rw-r--r--sources/plugins/clipboard/dev/dnd.html185
-rw-r--r--sources/plugins/clipboard/icons/copy-rtl.pngbin0 -> 506 bytes
-rw-r--r--sources/plugins/clipboard/icons/copy.pngbin0 -> 506 bytes
-rw-r--r--sources/plugins/clipboard/icons/cut-rtl.pngbin0 -> 776 bytes
-rw-r--r--sources/plugins/clipboard/icons/cut.pngbin0 -> 776 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/copy-rtl.pngbin0 -> 759 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/copy.pngbin0 -> 759 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/cut-rtl.pngbin0 -> 1576 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/cut.pngbin0 -> 1576 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/paste-rtl.pngbin0 -> 854 bytes
-rw-r--r--sources/plugins/clipboard/icons/hidpi/paste.pngbin0 -> 854 bytes
-rw-r--r--sources/plugins/clipboard/icons/paste-rtl.pngbin0 -> 464 bytes
-rw-r--r--sources/plugins/clipboard/icons/paste.pngbin0 -> 464 bytes
-rw-r--r--sources/plugins/clipboard/lang/af.js12
-rw-r--r--sources/plugins/clipboard/lang/ar.js12
-rw-r--r--sources/plugins/clipboard/lang/az.js12
-rw-r--r--sources/plugins/clipboard/lang/bg.js12
-rw-r--r--sources/plugins/clipboard/lang/bn.js12
-rw-r--r--sources/plugins/clipboard/lang/bs.js12
-rw-r--r--sources/plugins/clipboard/lang/ca.js12
-rw-r--r--sources/plugins/clipboard/lang/cs.js12
-rw-r--r--sources/plugins/clipboard/lang/cy.js12
-rw-r--r--sources/plugins/clipboard/lang/da.js12
-rw-r--r--sources/plugins/clipboard/lang/de-ch.js12
-rw-r--r--sources/plugins/clipboard/lang/de.js12
-rw-r--r--sources/plugins/clipboard/lang/el.js12
-rw-r--r--sources/plugins/clipboard/lang/en-au.js12
-rw-r--r--sources/plugins/clipboard/lang/en-ca.js12
-rw-r--r--sources/plugins/clipboard/lang/en-gb.js12
-rw-r--r--sources/plugins/clipboard/lang/en.js12
-rw-r--r--sources/plugins/clipboard/lang/eo.js12
-rw-r--r--sources/plugins/clipboard/lang/es-mx.js12
-rw-r--r--sources/plugins/clipboard/lang/es.js12
-rw-r--r--sources/plugins/clipboard/lang/et.js12
-rw-r--r--sources/plugins/clipboard/lang/eu.js12
-rw-r--r--sources/plugins/clipboard/lang/fa.js12
-rw-r--r--sources/plugins/clipboard/lang/fi.js12
-rw-r--r--sources/plugins/clipboard/lang/fo.js12
-rw-r--r--sources/plugins/clipboard/lang/fr-ca.js12
-rw-r--r--sources/plugins/clipboard/lang/fr.js12
-rw-r--r--sources/plugins/clipboard/lang/gl.js12
-rw-r--r--sources/plugins/clipboard/lang/gu.js12
-rw-r--r--sources/plugins/clipboard/lang/he.js12
-rw-r--r--sources/plugins/clipboard/lang/hi.js12
-rw-r--r--sources/plugins/clipboard/lang/hr.js12
-rw-r--r--sources/plugins/clipboard/lang/hu.js12
-rw-r--r--sources/plugins/clipboard/lang/id.js12
-rw-r--r--sources/plugins/clipboard/lang/is.js12
-rw-r--r--sources/plugins/clipboard/lang/it.js12
-rw-r--r--sources/plugins/clipboard/lang/ja.js12
-rw-r--r--sources/plugins/clipboard/lang/ka.js12
-rw-r--r--sources/plugins/clipboard/lang/km.js12
-rw-r--r--sources/plugins/clipboard/lang/ko.js12
-rw-r--r--sources/plugins/clipboard/lang/ku.js12
-rw-r--r--sources/plugins/clipboard/lang/lt.js12
-rw-r--r--sources/plugins/clipboard/lang/lv.js12
-rw-r--r--sources/plugins/clipboard/lang/mk.js12
-rw-r--r--sources/plugins/clipboard/lang/mn.js12
-rw-r--r--sources/plugins/clipboard/lang/ms.js12
-rw-r--r--sources/plugins/clipboard/lang/nb.js12
-rw-r--r--sources/plugins/clipboard/lang/nl.js12
-rw-r--r--sources/plugins/clipboard/lang/no.js12
-rw-r--r--sources/plugins/clipboard/lang/oc.js12
-rw-r--r--sources/plugins/clipboard/lang/pl.js12
-rw-r--r--sources/plugins/clipboard/lang/pt-br.js12
-rw-r--r--sources/plugins/clipboard/lang/pt.js12
-rw-r--r--sources/plugins/clipboard/lang/ro.js12
-rw-r--r--sources/plugins/clipboard/lang/ru.js12
-rw-r--r--sources/plugins/clipboard/lang/si.js12
-rw-r--r--sources/plugins/clipboard/lang/sk.js12
-rw-r--r--sources/plugins/clipboard/lang/sl.js12
-rw-r--r--sources/plugins/clipboard/lang/sq.js12
-rw-r--r--sources/plugins/clipboard/lang/sr-latn.js12
-rw-r--r--sources/plugins/clipboard/lang/sr.js12
-rw-r--r--sources/plugins/clipboard/lang/sv.js12
-rw-r--r--sources/plugins/clipboard/lang/th.js12
-rw-r--r--sources/plugins/clipboard/lang/tr.js12
-rw-r--r--sources/plugins/clipboard/lang/tt.js12
-rw-r--r--sources/plugins/clipboard/lang/ug.js12
-rw-r--r--sources/plugins/clipboard/lang/uk.js12
-rw-r--r--sources/plugins/clipboard/lang/vi.js12
-rw-r--r--sources/plugins/clipboard/lang/zh-cn.js12
-rw-r--r--sources/plugins/clipboard/lang/zh.js12
-rw-r--r--sources/plugins/clipboard/plugin.js2780
86 files changed, 4044 insertions, 0 deletions
diff --git a/sources/plugins/clipboard/dev/clipboard.html b/sources/plugins/clipboard/dev/clipboard.html
new file mode 100644
index 0000000..735d00e
--- /dev/null
+++ b/sources/plugins/clipboard/dev/clipboard.html
@@ -0,0 +1,190 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Clipboard playground &ndash; CKEditor Sample</title>
10 <script src="../../../ckeditor.js"></script>
11 <link href="../../../samples/old/sample.css" rel="stylesheet">
12 <style>
13body {
14 margin: 0;
15}
16
17#editables, #console
18{
19 width: 48%;
20}
21#editable {
22 padding: 5px 10px;
23}
24
25#console {
26 position: fixed;
27 top: 10px;
28 right: 30px;
29 height: 500px;
30 border: solid 3px #555;
31 overflow: auto;
32}
33#console > p {
34 border-bottom: solid 1px #555;
35 margin: 0;
36 padding: 0 5px;
37 background: rgba(0, 0, 0, 0.25);
38 transition: background-color 1s;
39}
40#console > p.old {
41 background: rgba(0, 0, 0, 0);
42}
43#console time, #console .prompt {
44 padding: 0 5px;
45 display: inline-block;
46}
47#console time {
48 background: #999;
49 background: rgba(0, 0, 0, 0.5 );
50 color: #FFF;
51 margin-left: -5px;
52}
53#console .prompt {
54 background: #DDD;
55 background: rgba(0, 0, 0, 0.1 );
56 min-width: 200px;
57}
58.someClass {
59 color: blue;
60}
61.specChar {
62 color: #777;
63 background-color: #EEE;
64 background-color: rgba(0, 0, 0, 0.1);
65 font-size: 0.8em;
66 border-radius: 2px;
67 padding: 1px;
68}
69 </style>
70</head>
71<body>
72 <h1 class="samples">
73 CKEditor Sample &mdash; clipboard plugin playground
74 </h1>
75 <div id="editables">
76 <p>
77 <label for="editor1">
78 Editor 1:</label>
79 <textarea cols="80" id="editor1" name="editor1" rows="10">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://ckeditor.com/"&gt;CKEditor&lt;/a&gt;.&lt;/p&gt;</textarea>
80 </p>
81 <p>
82 <label for="editor2">
83 Editor 2:</label>
84 <textarea cols="80" id="editor2" name="editor2" rows="10">&lt;p&gt;This is more &lt;strong class="MsoNormal"&gt;sample text&lt;/strong&gt;.&lt;/p&gt;</textarea>
85 </p>
86 <p>
87 <label for="editor3">
88 Editor 3:</label>
89 <textarea cols="80" id="editor3" name="editor3" rows="10">&lt;p&gt;This editor &lt;strong&gt;forces pasting in text mode&lt;/strong&gt; by listening for "beforePaste" event.&lt;/p&gt;</textarea>
90 </p>
91 <p>
92 <label for="editor4">
93 Editor 4:</label>
94 <textarea cols="80" id="editor4" name="editor4" rows="10">&lt;p&gt;This editor &lt;strong&gt;forces pasting in text mode&lt;/strong&gt; by "forcePasteAsPlainText" config option.&lt;/p&gt;</textarea>
95 </p>
96 <p>
97 <label for="editor5">
98 Editor 5:</label>
99 <textarea cols="80" id="editor5" name="editor5" rows="10">Editor with autoParagraphing set to off.</textarea>
100 </p>
101 <div id="editor6" contenteditable="true" style="font-family: Georgia; font-size: 14px">
102 <h1>Editor 6</h1>
103 <p>Content content content.</p>
104 <p class="someClass">Styled by <code>.someClass</code>.</p>
105 </div>
106 </div>
107 <div id="console">
108 </div>
109 <script>
110( function()
111{
112 'use strict';
113
114 var log = window.__log = function( title, msg ) {
115 var msgEl = new CKEDITOR.dom.element( 'p' ),
116 consoleEl = CKEDITOR.document.getById( 'console' ),
117 time = new Date().toString().match( /\d\d:\d\d:\d\d/ )[ 0 ],
118 format = function( tpl ) {
119 return tpl.replace( /{time}/g, time ).replace( '{title}', title ).replace( '{msg}', msg || '' );
120 };
121
122 window.console && console.log && console.log( format( '[{time}] {title}: {msg}' ) );
123
124 msg = ( msg || '' ).replace( /\r/g, '{\\r}' ).replace( /\n/g, '{\\n}' ).replace( /\t/g, '{\\t}' );
125 msg = CKEDITOR.tools.htmlEncode( msg );
126 msg = msg.replace( /\{(\\\w)\}/g, '<code class="specChar">$1</code>' );
127
128 msgEl.setHtml( format( '<time datetime="{time}">{time}</time><span class="prompt">{title}</span> {msg}' ) );
129 consoleEl.append( msgEl );
130 consoleEl.$.scrollTop = consoleEl.$.scrollHeight;
131 setTimeout( function() { msgEl.addClass( 'old' ); }, 250 );
132 };
133
134 var observe = function( editor, num ) {
135 var p = 'EDITOR ' + num + ' > ';
136
137 editor.on( 'paste', function( event ) {
138 log( p + 'paste(prior:-1)', event.data.type + ' - "' + event.data.dataValue + '"' );
139 }, null, null, -1 );
140 editor.on( 'paste', function( event ) {
141 log( p + 'paste(prior:10)', event.data.type + ' - "' + event.data.dataValue + '"' );
142 } );
143 editor.on( 'paste', function( event ) {
144 log( p + 'paste(prior:999)', event.data.type + ' - "' + event.data.dataValue + '"' );
145 }, null, null, 999 );
146 editor.on( 'beforePaste', function( event ) {
147 log( p + 'beforePaste', event.data.type );
148 } );
149 editor.on( 'beforePaste', function( event ) {
150 log( p + 'beforePaste(prior:999)', event.data.type );
151 }, null, null, 999 );
152 editor.on( 'afterPaste', function( event ) {
153 log( p + 'afterPaste' );
154 } );
155 editor.on( 'copy', function( event ) {
156 log( p + 'copy' );
157 } );
158 editor.on( 'cut', function( event ) {
159 log( p + 'cut' );
160 } );
161 };
162
163 CKEDITOR.disableAutoInline = true;
164 var config = {
165 height: 120,
166 toolbar: [ [ 'Source' ] ],
167 allowedContent: true
168 },
169 editor1 = CKEDITOR.replace( 'editor1', config ),
170 editor2 = CKEDITOR.replace( 'editor2', config ),
171 editor3 = CKEDITOR.replace( 'editor3', config ),
172 editor4 = CKEDITOR.replace( 'editor4', CKEDITOR.tools.extend( { forcePasteAsPlainText: true }, config ) ),
173 editor5 = CKEDITOR.replace( 'editor5', CKEDITOR.tools.extend( { autoParagraph: false }, config ) ),
174 editor6 = CKEDITOR.inline( document.getElementById( 'editor6' ), config );
175
176 editor3.on( 'beforePaste', function( evt ) {
177 evt.data.type = 'text';
178 } );
179
180 observe( editor1, 1 );
181 observe( editor2, 2 );
182 observe( editor3, 3 );
183 observe( editor4, 4 );
184 observe( editor5, 5 );
185 observe( editor6, 6 );
186
187})();
188 </script>
189</body>
190</html>
diff --git a/sources/plugins/clipboard/dev/console.js b/sources/plugins/clipboard/dev/console.js
new file mode 100644
index 0000000..96ccd81
--- /dev/null
+++ b/sources/plugins/clipboard/dev/console.js
@@ -0,0 +1,49 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/* global CKCONSOLE */
7
8'use strict';
9
10( function() {
11 var pasteType, pasteValue;
12
13 CKCONSOLE.add( 'paste', {
14 panels: [
15 {
16 type: 'box',
17 content:
18 '<ul class="ckconsole_list">' +
19 '<li>type: <span class="ckconsole_value" data-value="type"></span></li>' +
20 '<li>value: <span class="ckconsole_value" data-value="value"></span></li>' +
21 '</ul>',
22
23 refresh: function() {
24 return {
25 header: 'Paste',
26 type: pasteType,
27 value: pasteValue
28 };
29 },
30
31 refreshOn: function( editor, refresh ) {
32 editor.on( 'paste', function( evt ) {
33 pasteType = evt.data.type;
34 pasteValue = CKEDITOR.tools.htmlEncode( evt.data.dataValue );
35 refresh();
36 } );
37 }
38 },
39 {
40 type: 'log',
41 on: function( editor, log, logFn ) {
42 editor.on( 'paste', function( evt ) {
43 logFn( 'paste; type:' + evt.data.type )();
44 } );
45 }
46 }
47 ]
48 } );
49} )();
diff --git a/sources/plugins/clipboard/dev/dnd.html b/sources/plugins/clipboard/dev/dnd.html
new file mode 100644
index 0000000..c45475b
--- /dev/null
+++ b/sources/plugins/clipboard/dev/dnd.html
@@ -0,0 +1,185 @@
1<!DOCTYPE html>
2<!--
3Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
4For licensing, see LICENSE.md or http://ckeditor.com/license
5-->
6<html>
7<head>
8 <meta charset="utf-8">
9 <title>Manual test for http://dev.ckeditor.com/ticket/11460</title>
10 <script src="../../../ckeditor.js"></script>
11 <script src="../../../dev/console/console.js"></script>
12 <script src="../../../plugins/clipboard/dev/console.js"></script>
13 <link rel="stylesheet" href="../../../samples/old/sample.css">
14 <style type="text/css">
15 h2 {
16 margin: 10px 0px 4px 0px;
17 padding: 0;
18 font-size: 14px;
19 }
20 h3 {
21 margin: 5px 0px 2px 0px;
22 padding: 0;
23 font-size: 12px;
24 }
25 </style>
26</head>
27<body>
28 <h1 class="samples">
29 Manual test for #11460
30 </h1>
31 <h2>Description (<a href="javascript:hideshow('description');">hide/show</a>)</h2>
32 <div id="description" class="description">
33 <p>Test internal D&amp;D in the editor, dropping content from an external source (helpers, MS Word) and D&amp;D between editors. Keep in mind that internal D&amp;D is the most complex operation because editor have to handle two ranges at the same time.</p>
34 <h3>Expected behavior:</h3>
35 <ul>
36 <li>proper drop position,</li>
37 <li>in the internal and cross editor D&amp;D: dragged content should be removed,</li>
38 <li>dropped content should be (more less) the same as dragged content,</li>
39 <li>paste event should be fired,</li>
40 <li>undo should work properly (one undo operation for one D&amp;D),</li>
41 <li>no crashes, nor errors,</li>
42 </ul>
43 <h3>Drag scenarios:</h3>
44 <ul>
45 <li>drag simple text,</li>
46 <li>drag table cell/cells,</li>
47 <li>drag link,</li>
48 <li>drag helpers textarea content,</li>
49 <li>drag helpers html content,</li>
50 <li>drag content from MS Word.</li>
51 </ul>
52 <h3>Drop scenarios:</h3>
53 <ul>
54 <li>drop in the different paragraph (before and after),</li>
55 <li>drop in the same paragraph (before and after),</li>
56 <li>drop in the same text node (before and after),</li>
57 <li>drop between text lines,</li>
58 <li>drop on the whitespace next to the header,</li>
59 <li>drop on the whitespace on the left side from the quote,</li>
60 <li>drop into a cell.</li>
61 </ul>
62 <h3>Known issues (not part of this ticket):</h3>
63 <ul>
64 <li>because of <a href="http://dev.ckeditor.com/ticket/11636">#11636</a> dragged content is not correct in some cases (e.g. when you drag part of the link),</li>
65 <li>drag position needs clean up after D&amp;D (e.g. remove empty paragraphs, fix table),</li>
66 <li>drop position needs clean up after D&amp;D (e.g. add spaces before/after dropped content, apply parents styles, break paragraph when one paragraph is dropped at the end to the other paragraph),</li>
67 <li>in the external D&amp;D: Chrome add plenty of addition tags.</li>
68 </ul>
69 </div>
70 <div>
71 <h2>Helpers (<a href="javascript:hideshow('helpers');">hide/show</a>)</h2>
72 <div id="helpers">
73 <textarea style="width:49%; height:50px; float: left;">Lorem ipsum dolor sit amet, consectetur adipiscing elit. In commodo vulputate tempor. Sed <b>at</b> elit.</textarea>
74 <div style="width:49%; height:50px; float: right;">
75 Lorem ipsum <b>dolor</b> sit <i>amet</i>, consectetur adipiscing elit. In commodo vulputate tempor. Sed &lt;b&gt;at elit&lt;/b&gt; vel ligula mollis aliquet a ac odio.
76 <pre>
77Aenean cursus egestas ipsum.
78 </pre>
79 </div>
80 <div style="clear:both;"></div>
81 </div>
82 </div>
83 <div>
84 <h2>Classic editor (<a href="javascript:hideshow('classic-editor');">hide/show</a>)</h2>
85 <div id="classic-editor">
86 <textarea cols="80" id="classic" name="classic" rows="10">
87 &lt;h1&gt;&lt;img alt=&quot;Saturn V carrying Apollo 11&quot; class=&quot;right&quot; src=&quot;../../../samples/assets/sample.jpg&quot;/&gt; Apollo 11&lt;/h1&gt; &lt;p&gt;&lt;b&gt;Apollo 11&lt;/b&gt; was the spaceflight that landed the first humans, Americans &lt;a href=&quot;http://en.wikipedia.org/wiki/Neil_Armstrong&quot; title=&quot;Neil Armstrong&quot;&gt;Neil Armstrong&lt;/a&gt; and &lt;a href=&quot;http://en.wikipedia.org/wiki/Buzz_Aldrin&quot; title=&quot;Buzz Aldrin&quot;&gt;Buzz Aldrin&lt;/a&gt;, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.&lt;/p&gt; &lt;p&gt;Armstrong spent about &lt;s&gt;three and a half&lt;/s&gt; two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&amp;nbsp;kg) of lunar material for return to Earth. A third member of the mission, &lt;a href=&quot;http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)&quot; title=&quot;Michael Collins (astronaut)&quot;&gt;Michael Collins&lt;/a&gt;, piloted the &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_Command/Service_Module&quot; title=&quot;Apollo Command/Service Module&quot;&gt;command&lt;/a&gt; spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.&lt;/p&gt; &lt;h2&gt;Broadcasting and &lt;em&gt;quotes&lt;/em&gt; &lt;a id=&quot;quotes&quot; name=&quot;quotes&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;p&gt;Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;One small step for [a] man, one giant leap for mankind.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Apollo 11 effectively ended the &lt;a href=&quot;http://en.wikipedia.org/wiki/Space_Race&quot; title=&quot;Space Race&quot;&gt;Space Race&lt;/a&gt; and fulfilled a national goal proposed in 1961 by the late U.S. President &lt;a href=&quot;http://en.wikipedia.org/wiki/John_F._Kennedy&quot; title=&quot;John F. Kennedy&quot;&gt;John F. Kennedy&lt;/a&gt; in a speech before the United States Congress:&lt;/p&gt; &lt;blockquote&gt;&lt;p&gt;[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Technical details &lt;a id=&quot;tech-details&quot; name=&quot;tech-details&quot;&gt;&lt;/a&gt;&lt;/h2&gt; &lt;table align=&quot;right&quot; border=&quot;1&quot; bordercolor=&quot;#ccc&quot; cellpadding=&quot;5&quot; cellspacing=&quot;0&quot; style=&quot;border-collapse:collapse;margin:10px 0 10px 15px;&quot;&gt; &lt;caption&gt;&lt;strong&gt;Mission crew&lt;/strong&gt;&lt;/caption&gt; &lt;thead&gt; &lt;tr&gt; &lt;th scope=&quot;col&quot;&gt;Position&lt;/th&gt; &lt;th scope=&quot;col&quot;&gt;Astronaut&lt;/th&gt; &lt;/tr&gt; &lt;/thead&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td&gt;Commander&lt;/td&gt; &lt;td&gt;Neil A. Armstrong&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Command Module Pilot&lt;/td&gt; &lt;td&gt;Michael Collins&lt;/td&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;Lunar Module Pilot&lt;/td&gt; &lt;td&gt;Edwin &amp;quot;Buzz&amp;quot; E. Aldrin, Jr.&lt;/td&gt; &lt;/tr&gt; &lt;/tbody&gt; &lt;/table&gt; &lt;p&gt;Launched by a &lt;strong&gt;Saturn V&lt;/strong&gt; rocket from &lt;a href=&quot;http://en.wikipedia.org/wiki/Kennedy_Space_Center&quot; title=&quot;Kennedy Space Center&quot;&gt;Kennedy Space Center&lt;/a&gt; in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of &lt;a href=&quot;http://en.wikipedia.org/wiki/NASA&quot; title=&quot;NASA&quot;&gt;NASA&lt;/a&gt;&amp;#39;s Apollo program. The Apollo spacecraft had three parts:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Command Module&lt;/strong&gt; with a cabin for the three astronauts which was the only part which landed back on Earth&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Service Module&lt;/strong&gt; which supported the Command Module with propulsion, electrical power, oxygen and water&lt;/li&gt; &lt;li&gt;&lt;strong&gt;Lunar Module&lt;/strong&gt; for landing on the Moon.&lt;/li&gt; &lt;/ol&gt; &lt;p&gt;After being sent to the Moon by the Saturn V&amp;#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Mare_Tranquillitatis&quot; title=&quot;Mare Tranquillitatis&quot;&gt;Sea of Tranquility&lt;/a&gt;. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pacific_Ocean&quot; title=&quot;Pacific Ocean&quot;&gt;Pacific Ocean&lt;/a&gt; on July 24.&lt;/p&gt; &lt;hr/&gt; &lt;p style=&quot;text-align: right;&quot;&gt;&lt;small&gt;Source: &lt;a href=&quot;http://en.wikipedia.org/wiki/Apollo_11&quot;&gt;Wikipedia.org&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;
88 </textarea>
89 </div>
90 </div>
91 <div>
92 <h2>Inline editor (<a href="javascript:hideshow('inline');">hide/show</a>)</h2>
93 <div id="inline" contenteditable="true">
94 <h1><img alt="Saturn V carrying Apollo 11" class="right" src="../../../samples/assets/sample.jpg" /> Apollo 11</h1>
95
96 <p><b>Apollo 11</b> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p>
97
98 <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p>
99
100 <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2>
101
102 <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p>
103
104 <blockquote>
105 <p>One small step for [a] man, one giant leap for mankind.</p>
106 </blockquote>
107
108 <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p>
109
110 <blockquote>
111 <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p>
112 </blockquote>
113
114 <h2>Technical details <a id="tech-details" name="tech-details"></a></h2>
115
116 <table align="right" border="1" bordercolor="#ccc" cellpadding="5" cellspacing="0" style="border-collapse:collapse;margin:10px 0 10px 15px;">
117 <caption><strong>Mission crew</strong></caption>
118 <thead>
119 <tr>
120 <th scope="col">Position</th>
121 <th scope="col">Astronaut</th>
122 </tr>
123 </thead>
124 <tbody>
125 <tr>
126 <td>Commander</td>
127 <td>Neil A. Armstrong</td>
128 </tr>
129 <tr>
130 <td>Command Module Pilot</td>
131 <td>Michael Collins</td>
132 </tr>
133 <tr>
134 <td>Lunar Module Pilot</td>
135 <td>Edwin &quot;Buzz&quot; E. Aldrin, Jr.</td>
136 </tr>
137 </tbody>
138 </table>
139
140 <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p>
141
142 <ol>
143 <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li>
144 <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li>
145 <li><strong>Lunar Module</strong> for landing on the Moon.</li>
146 </ol>
147
148 <p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p>
149
150 <hr />
151 <p style="text-align: right;"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p>
152 </div>
153 </div>
154 <script type="text/javascript">
155 CKEDITOR.disableAutoInline = true;
156
157 function hideshow( id ) {
158 var element = CKEDITOR.document.getById( id );
159
160 if( element.getStyle( 'display' ) == 'none' )
161 element.show();
162 else
163 element.hide();
164 }
165
166 CKEDITOR.replace( 'classic' );
167 CKEDITOR.inline( 'inline' );
168
169 CKCONSOLE.addEventPanel( 'dragstart', [ '$', 'target', 'dataTransfer' ] );
170 CKCONSOLE.addEventPanel( 'dragend', [ '$', 'target', 'dataTransfer' ] );
171 CKCONSOLE.addEventPanel( 'drop',
172 [ '$', 'target', 'dataTransfer', 'dragRange', 'dropRange' ] );
173
174 CKCONSOLE.create( 'dragstart', { editor: 'classic' } );
175 CKCONSOLE.create( 'drop', { editor: 'classic' } );
176 CKCONSOLE.create( 'paste', { editor: 'classic' } );
177 CKCONSOLE.create( 'dragend', { editor: 'classic' } );
178
179 CKCONSOLE.create( 'dragstart', { editor: 'inline' } );
180 CKCONSOLE.create( 'drop', { editor: 'inline' } );
181 CKCONSOLE.create( 'paste', { editor: 'inline' } );
182 CKCONSOLE.create( 'dragend', { editor: 'inline' } );
183 </script>
184</body>
185</html>
diff --git a/sources/plugins/clipboard/icons/copy-rtl.png b/sources/plugins/clipboard/icons/copy-rtl.png
new file mode 100644
index 0000000..ce94fc0
--- /dev/null
+++ b/sources/plugins/clipboard/icons/copy-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/copy.png b/sources/plugins/clipboard/icons/copy.png
new file mode 100644
index 0000000..ce94fc0
--- /dev/null
+++ b/sources/plugins/clipboard/icons/copy.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/cut-rtl.png b/sources/plugins/clipboard/icons/cut-rtl.png
new file mode 100644
index 0000000..8ae48d9
--- /dev/null
+++ b/sources/plugins/clipboard/icons/cut-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/cut.png b/sources/plugins/clipboard/icons/cut.png
new file mode 100644
index 0000000..8ae48d9
--- /dev/null
+++ b/sources/plugins/clipboard/icons/cut.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/copy-rtl.png b/sources/plugins/clipboard/icons/hidpi/copy-rtl.png
new file mode 100644
index 0000000..74c6765
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/copy-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/copy.png b/sources/plugins/clipboard/icons/hidpi/copy.png
new file mode 100644
index 0000000..74c6765
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/copy.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/cut-rtl.png b/sources/plugins/clipboard/icons/hidpi/cut-rtl.png
new file mode 100644
index 0000000..f5a9b0d
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/cut-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/cut.png b/sources/plugins/clipboard/icons/hidpi/cut.png
new file mode 100644
index 0000000..f5a9b0d
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/cut.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/paste-rtl.png b/sources/plugins/clipboard/icons/hidpi/paste-rtl.png
new file mode 100644
index 0000000..12cac92
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/paste-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/hidpi/paste.png b/sources/plugins/clipboard/icons/hidpi/paste.png
new file mode 100644
index 0000000..12cac92
--- /dev/null
+++ b/sources/plugins/clipboard/icons/hidpi/paste.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/paste-rtl.png b/sources/plugins/clipboard/icons/paste-rtl.png
new file mode 100644
index 0000000..7039251
--- /dev/null
+++ b/sources/plugins/clipboard/icons/paste-rtl.png
Binary files differ
diff --git a/sources/plugins/clipboard/icons/paste.png b/sources/plugins/clipboard/icons/paste.png
new file mode 100644
index 0000000..7039251
--- /dev/null
+++ b/sources/plugins/clipboard/icons/paste.png
Binary files differ
diff --git a/sources/plugins/clipboard/lang/af.js b/sources/plugins/clipboard/lang/af.js
new file mode 100644
index 0000000..5860867
--- /dev/null
+++ b/sources/plugins/clipboard/lang/af.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'af', {
6 copy: 'Kopiëer',
7 copyError: 'U blaaier se sekuriteitsinstelling belet die kopiëringsaksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+C).',
8 cut: 'Knip',
9 cutError: 'U blaaier se sekuriteitsinstelling belet die outomatiese knip-aksie. Gebruik die sleutelbordkombinasie (Ctrl/Cmd+X).',
10 paste: 'Plak',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ar.js b/sources/plugins/clipboard/lang/ar.js
new file mode 100644
index 0000000..6d1a0b0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ar.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ar', {
6 copy: 'نسخ',
7 copyError: 'الإعدادات الأمنية للمتصفح الذي تستخدمه تمنع عمليات النسخ التلقائي. فضلاً إستخدم لوحة المفاتيح لفعل ذلك (Ctrl/Cmd+C).',
8 cut: 'قص',
9 cutError: 'الإعدادات الأمنية للمتصفح الذي تستخدمه تمنع القص التلقائي. فضلاً إستخدم لوحة المفاتيح لفعل ذلك (Ctrl/Cmd+X).',
10 paste: 'لصق',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/az.js b/sources/plugins/clipboard/lang/az.js
new file mode 100644
index 0000000..8f60f35
--- /dev/null
+++ b/sources/plugins/clipboard/lang/az.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'az', {
6 copy: 'Köçür',
7 copyError: 'Avtomatik köçürülməsi mümkün deyil. Ctrl+C basın.',
8 cut: 'Kəs',
9 cutError: 'Avtomatik kəsmə mümkün deyil. Ctrl+X basın.',
10 paste: 'Əlavə et',
11 pasteNotification: 'Sizin İnternet bələdçisi bu cür mətnin köçürməsi dəstəklənmir. Əlavə etmək üçün %1 basın.'
12} );
diff --git a/sources/plugins/clipboard/lang/bg.js b/sources/plugins/clipboard/lang/bg.js
new file mode 100644
index 0000000..2d8eede
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bg.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bg', {
6 copy: 'Копирай',
7 copyError: 'Настройките за сигурност на вашия бразуър не разрешават на редактора да изпълни запаметяването. За целта използвайте клавиатурата (Ctrl/Cmd+C).',
8 cut: 'Отрежи',
9 cutError: 'Настройките за сигурност на Вашия браузър не позволяват на редактора автоматично да изъплни действията за отрязване. Моля ползвайте клавиатурните команди за целта (ctrl+x).',
10 paste: 'Вмъкни',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/bn.js b/sources/plugins/clipboard/lang/bn.js
new file mode 100644
index 0000000..1d0922a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bn', {
6 copy: 'কপি',
7 copyError: 'আপনার ব্রাউজারের নিরাপত্তা সেটিংসমূহ এডিটরকে স্বয়ংক্রিয়ভাবে কপি করার প্রক্রিয়া চালনা করার অনুমতি দেয় না। অনুগ্রহপূর্বক এই কাজের জন্য কিবোর্ড ব্যবহার করুন (Ctrl/Cmd+C)।',
8 cut: 'কাট',
9 cutError: 'আপনার ব্রাউজারের সুরক্ষা সেটিংস এডিটরকে অটোমেটিক কাট করার অনুমতি দেয়নি। দয়া করে এই কাজের জন্য কিবোর্ড ব্যবহার করুন (Ctrl/Cmd+X)।',
10 paste: 'পেস্ট',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/bs.js b/sources/plugins/clipboard/lang/bs.js
new file mode 100644
index 0000000..62f3f1b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/bs.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'bs', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosne postavke Vašeg pretraživaèa ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Sigurnosne postavke vašeg pretraživaèa ne dozvoljavaju operacije automatskog rezanja. Molimo koristite kraticu na tastaturi (Ctrl/Cmd+X).',
10 paste: 'Zalijepi',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ca.js b/sources/plugins/clipboard/lang/ca.js
new file mode 100644
index 0000000..6cd3b58
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ca', {
6 copy: 'Copiar',
7 copyError: 'La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de copiar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+C).',
8 cut: 'Retallar',
9 cutError: 'La configuració de seguretat del vostre navegador no permet executar automàticament les operacions de retallar. Si us plau, utilitzeu el teclat (Ctrl/Cmd+X).',
10 paste: 'Enganxar',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/cs.js b/sources/plugins/clipboard/lang/cs.js
new file mode 100644
index 0000000..4cbf3b4
--- /dev/null
+++ b/sources/plugins/clipboard/lang/cs.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'cs', {
6 copy: 'Kopírovat',
7 copyError: 'Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro kopírování zvoleného textu do schránky. Prosím zkopírujte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+C).',
8 cut: 'Vyjmout',
9 cutError: 'Bezpečnostní nastavení vašeho prohlížeče nedovolují editoru spustit funkci pro vyjmutí zvoleného textu do schránky. Prosím vyjměte zvolený text do schránky pomocí klávesnice (Ctrl/Cmd+X).',
10 paste: 'Vložit',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/cy.js b/sources/plugins/clipboard/lang/cy.js
new file mode 100644
index 0000000..e854e13
--- /dev/null
+++ b/sources/plugins/clipboard/lang/cy.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'cy', {
6 copy: 'Copïo',
7 copyError: '\'Dyw gosodiadau diogelwch eich porwr ddim yn caniatàu\'r golygydd i gynnal \'gweithredoedd copïo\' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+C).',
8 cut: 'Torri',
9 cutError: 'Nid yw gosodiadau diogelwch eich porwr yn caniatàu\'r golygydd i gynnal \'gweithredoedd torri\' yn awtomatig. Defnyddiwch y bysellfwrdd (Ctrl/Cmd+X).',
10 paste: 'Gludo',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/da.js b/sources/plugins/clipboard/lang/da.js
new file mode 100644
index 0000000..257c9d4
--- /dev/null
+++ b/sources/plugins/clipboard/lang/da.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'da', {
6 copy: 'Kopiér',
7 copyError: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at kopiere teksten (Ctrl/Cmd+C).',
8 cut: 'Klip',
9 cutError: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.<br><br>Brug i stedet tastaturet til at klippe teksten (Ctrl/Cmd+X).',
10 paste: 'Indsæt',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/de-ch.js b/sources/plugins/clipboard/lang/de-ch.js
new file mode 100644
index 0000000..e3b9ead
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de-ch.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'de-ch', {
6 copy: 'Kopieren',
7 copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
8 cut: 'Ausschneiden',
9 cutError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).',
10 paste: 'Einfügen',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/de.js b/sources/plugins/clipboard/lang/de.js
new file mode 100644
index 0000000..5244081
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'de', {
6 copy: 'Kopieren',
7 copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
8 cut: 'Ausschneiden',
9 cutError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch auszuschneiden. Bitte benutzen Sie die System-Zwischenablage über STRG-X (ausschneiden) und STRG-V (einfügen).',
10 paste: 'Einfügen',
11 pasteNotification: 'Ihr Browser verhindert das Einfügen über diesen Weg. Zum einfügen drücken Sie %1.'
12} );
diff --git a/sources/plugins/clipboard/lang/el.js b/sources/plugins/clipboard/lang/el.js
new file mode 100644
index 0000000..4ee396b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/el.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'el', {
6 copy: 'Αντιγραφή',
7 copyError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αντιγραφής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+C).',
8 cut: 'Αποκοπή',
9 cutError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αποκοπής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+X).',
10 paste: 'Επικόλληση',
11 pasteNotification: 'Ο περιηγητής σας δεν σας επιτρέπει να επικολλήσετε με αυτόν τον τρόπο. Πατήστε %1 για επικόλληση.'
12} );
diff --git a/sources/plugins/clipboard/lang/en-au.js b/sources/plugins/clipboard/lang/en-au.js
new file mode 100644
index 0000000..018a754
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-au.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-au', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/en-ca.js b/sources/plugins/clipboard/lang/en-ca.js
new file mode 100644
index 0000000..fd76ba7
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-ca', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/en-gb.js b/sources/plugins/clipboard/lang/en-gb.js
new file mode 100644
index 0000000..fb6aa2e
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-gb.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en-gb', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/en.js b/sources/plugins/clipboard/lang/en.js
new file mode 100644
index 0000000..5d81cc0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'en', {
6 copy: 'Copy',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
8 cut: 'Cut',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
10 paste: 'Paste',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.'
12} );
diff --git a/sources/plugins/clipboard/lang/eo.js b/sources/plugins/clipboard/lang/eo.js
new file mode 100644
index 0000000..3a01213
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eo.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'eo', {
6 copy: 'Kopii',
7 copyError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras kopiajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-C).',
8 cut: 'Eltondi',
9 cutError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras eltondajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-X).',
10 paste: 'Interglui',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/es-mx.js b/sources/plugins/clipboard/lang/es-mx.js
new file mode 100644
index 0000000..f4a1be2
--- /dev/null
+++ b/sources/plugins/clipboard/lang/es-mx.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'es-mx', {
6 copy: 'Copiar',
7 copyError: 'La configuración de seguridad de su navegador no permite al editor ejecutar automáticamente operaciones de copiado. Por favor, utilice el teclado para (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'La configuración de seguridad de su navegador no permite al editor ejecutar automáticamente operaciones de corte. Por favor, utilice el teclado para (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteNotification: 'Tu navegador no permite pegar de esta manera. Presiona %1 para pegar.'
12} );
diff --git a/sources/plugins/clipboard/lang/es.js b/sources/plugins/clipboard/lang/es.js
new file mode 100644
index 0000000..741d912
--- /dev/null
+++ b/sources/plugins/clipboard/lang/es.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'es', {
6 copy: 'Copiar',
7 copyError: 'La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de copiado.\r\nPor favor use el teclado (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'La configuración de seguridad de este navegador no permite la ejecución automática de operaciones de cortado.\r\nPor favor use el teclado (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/et.js b/sources/plugins/clipboard/lang/et.js
new file mode 100644
index 0000000..106ca61
--- /dev/null
+++ b/sources/plugins/clipboard/lang/et.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'et', {
6 copy: 'Kopeeri',
7 copyError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt kopeerida. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+C).',
8 cut: 'Lõika',
9 cutError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt lõigata. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+X).',
10 paste: 'Aseta',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/eu.js b/sources/plugins/clipboard/lang/eu.js
new file mode 100644
index 0000000..140fcb8
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'eu', {
6 copy: 'Kopiatu',
7 copyError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki kopiatzea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+C).',
8 cut: 'Ebaki',
9 cutError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki moztea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+X).',
10 paste: 'Itsatsi',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/fa.js b/sources/plugins/clipboard/lang/fa.js
new file mode 100644
index 0000000..8dca4b3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fa.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fa', {
6 copy: 'رونوشت',
7 copyError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای کپی کردن را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+C).',
8 cut: 'برش',
9 cutError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای برش را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+X).',
10 paste: 'چسباندن',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/fi.js b/sources/plugins/clipboard/lang/fi.js
new file mode 100644
index 0000000..b2db77a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fi', {
6 copy: 'Kopioi',
7 copyError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa kopioimista. Käytä näppäimistöä kopioimiseen (Ctrl+C).',
8 cut: 'Leikkaa',
9 cutError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa leikkaamista. Käytä näppäimistöä leikkaamiseen (Ctrl+X).',
10 paste: 'Liitä',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/fo.js b/sources/plugins/clipboard/lang/fo.js
new file mode 100644
index 0000000..8485ef3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fo.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fo', {
6 copy: 'Avrita',
7 copyError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at avrita tekstin. Vinarliga nýt knappaborðið til at avrita tekstin (Ctrl/Cmd+C).',
8 cut: 'Kvett',
9 cutError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at kvetta tekstin. Vinarliga nýt knappaborðið til at kvetta tekstin (Ctrl/Cmd+X).',
10 paste: 'Innrita',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/fr-ca.js b/sources/plugins/clipboard/lang/fr-ca.js
new file mode 100644
index 0000000..1a2dd3d
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr-ca.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fr-ca', {
6 copy: 'Copier',
7 copyError: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur de copier automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+C).',
8 cut: 'Couper',
9 cutError: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur de couper automatiquement vos données. Veuillez utiliser les équivalents claviers (Ctrl/Cmd+X).',
10 paste: 'Coller',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/fr.js b/sources/plugins/clipboard/lang/fr.js
new file mode 100644
index 0000000..054d055
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'fr', {
6 copy: 'Copier',
7 copyError: 'Les paramètres de sécurité de votre navigateur n\'autorisent pas l\'éditeur à exécuter automatiquement l\'opération « Copier ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+C).',
8 cut: 'Couper',
9 cutError: 'Les paramètres de sécurité de votre navigateur n\'autorisent pas l\'éditeur à exécuter automatiquement l\'opération « Couper ». Veuillez utiliser le raccourci clavier à cet effet (Ctrl/Cmd+X).',
10 paste: 'Coller',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/gl.js b/sources/plugins/clipboard/lang/gl.js
new file mode 100644
index 0000000..5b4fd1a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'gl', {
6 copy: 'Copiar',
7 copyError: 'Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de copia. Use o teclado para iso (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'Os axustes de seguranza do seu navegador non permiten que o editor realice automaticamente as tarefas de corte. Use o teclado para iso (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteNotification: 'O seu navegador non permite pegar deste xeito. Prema %1 para pegar.'
12} );
diff --git a/sources/plugins/clipboard/lang/gu.js b/sources/plugins/clipboard/lang/gu.js
new file mode 100644
index 0000000..aeac560
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'gu', {
6 copy: 'નકલ',
7 copyError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કોપી કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+C) का प्रयोग करें।',
8 cut: 'કાપવું',
9 cutError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કટ કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+X) નો ઉપયોગ કરો.',
10 paste: 'પેસ્ટ',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/he.js b/sources/plugins/clipboard/lang/he.js
new file mode 100644
index 0000000..460b9c6
--- /dev/null
+++ b/sources/plugins/clipboard/lang/he.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'he', {
6 copy: 'העתקה',
7 copyError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות העתקה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+C).',
8 cut: 'גזירה',
9 cutError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות גזירה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+X).',
10 paste: 'הדבקה',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/hi.js b/sources/plugins/clipboard/lang/hi.js
new file mode 100644
index 0000000..112853c
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hi', {
6 copy: 'कॉपी',
7 copyError: 'आपके ब्राआउज़र की सुरक्षा सॅटिन्ग्स ने कॉपी करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+C) का प्रयोग करें।',
8 cut: 'कट',
9 cutError: 'आपके ब्राउज़र की सुरक्षा सॅटिन्ग्स ने कट करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+X) का प्रयोग करें।',
10 paste: 'पेस्ट',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/hr.js b/sources/plugins/clipboard/lang/hr.js
new file mode 100644
index 0000000..4eff9ce
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hr', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog izrezivanja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+X).',
10 paste: 'Zalijepi',
11 pasteNotification: 'Vaš preglednik Vam ne dozvoljava lijepljenje na ovaj način. Za lijepljenje, pritisnite %1.'
12} );
diff --git a/sources/plugins/clipboard/lang/hu.js b/sources/plugins/clipboard/lang/hu.js
new file mode 100644
index 0000000..646fb15
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hu.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'hu', {
6 copy: 'Másolás',
7 copyError: 'A böngésző biztonsági beállításai nem engedélyezik a szerkesztőnek, hogy végrehajtsa a másolás műveletet. Használja az alábbi billentyűkombinációt (Ctrl/Cmd+X).',
8 cut: 'Kivágás',
9 cutError: 'A böngésző biztonsági beállításai nem engedélyezik a szerkesztőnek, hogy végrehajtsa a kivágás műveletet. Használja az alábbi billentyűkombinációt (Ctrl/Cmd+X).',
10 paste: 'Beillesztés',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/id.js b/sources/plugins/clipboard/lang/id.js
new file mode 100644
index 0000000..b68425f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/id.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'id', {
6 copy: 'Salin',
7 copyError: 'Pengaturan keamanan peramban anda tidak mengizinkan editor untuk mengeksekusi operasi menyalin secara otomatis. Mohon gunakan papan tuts (Ctrl/Cmd+C)',
8 cut: 'Potong',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).', // MISSING
10 paste: 'Tempel',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/is.js b/sources/plugins/clipboard/lang/is.js
new file mode 100644
index 0000000..32a0fce
--- /dev/null
+++ b/sources/plugins/clipboard/lang/is.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'is', {
6 copy: 'Afrita',
7 copyError: 'Öryggisstillingar vafrans þíns leyfa ekki afritun texta með músaraðgerð. Notaðu lyklaborðið í afrita (Ctrl/Cmd+C).',
8 cut: 'Klippa',
9 cutError: 'Öryggisstillingar vafrans þíns leyfa ekki klippingu texta með músaraðgerð. Notaðu lyklaborðið í klippa (Ctrl/Cmd+X).',
10 paste: 'Líma',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/it.js b/sources/plugins/clipboard/lang/it.js
new file mode 100644
index 0000000..46e015c
--- /dev/null
+++ b/sources/plugins/clipboard/lang/it.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'it', {
6 copy: 'Copia',
7 copyError: 'Le impostazioni di sicurezza del browser non permettono di copiare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+C).',
8 cut: 'Taglia',
9 cutError: 'Le impostazioni di sicurezza del browser non permettono di tagliare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+X).',
10 paste: 'Incolla',
11 pasteNotification: 'Il browser non permette di incollare in questo modo. Premere %1 per incollare.'
12} );
diff --git a/sources/plugins/clipboard/lang/ja.js b/sources/plugins/clipboard/lang/ja.js
new file mode 100644
index 0000000..f527e7c
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ja.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ja', {
6 copy: 'コピー',
7 copyError: 'ブラウザーのセキュリティ設定によりエディタのコピー操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+C)を使用してください。',
8 cut: '切り取り',
9 cutError: 'ブラウザーのセキュリティ設定によりエディタの切り取り操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+X)を使用してください。',
10 paste: '貼り付け',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ka.js b/sources/plugins/clipboard/lang/ka.js
new file mode 100644
index 0000000..2fa9e23
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ka.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ka', {
6 copy: 'ასლი',
7 copyError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ასლის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+C).',
8 cut: 'ამოჭრა',
9 cutError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ამოჭრის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+X).',
10 paste: 'ჩასმა',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/km.js b/sources/plugins/clipboard/lang/km.js
new file mode 100644
index 0000000..dc66ee8
--- /dev/null
+++ b/sources/plugins/clipboard/lang/km.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'km', {
6 copy: 'ចម្លង',
7 copyError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះ​មិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ ចំលងអត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+C)។',
8 cut: 'កាត់យក',
9 cutError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះ​មិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ កាត់អត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+X) ។',
10 paste: 'បិទ​ភ្ជាប់',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ko.js b/sources/plugins/clipboard/lang/ko.js
new file mode 100644
index 0000000..8472358
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ko.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ko', {
6 copy: '복사',
7 copyError: '브라우저의 보안설정 때문에 복사할 수 없습니다. 키보드(Ctrl/Cmd+C)를 이용해서 복사하십시오.',
8 cut: '잘라내기',
9 cutError: '브라우저의 보안설정 때문에 잘라내기 기능을 실행할 수 없습니다. 키보드(Ctrl/Cmd+X)를 이용해서 잘라내기 하십시오',
10 paste: '붙여넣기',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ku.js b/sources/plugins/clipboard/lang/ku.js
new file mode 100644
index 0000000..b87aa8b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ku.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ku', {
6 copy: 'لەبەرگرتنەوە',
7 copyError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بەسەرنووسەکە لە لکاندنی دەقی خۆکارارنە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+C).',
8 cut: 'بڕین',
9 cutError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بە سەرنووسەکە لەبڕینی خۆکارانە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+X).',
10 paste: 'لکاندن',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/lt.js b/sources/plugins/clipboard/lang/lt.js
new file mode 100644
index 0000000..c8d3611
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'lt', {
6 copy: 'Kopijuoti',
7 copyError: 'Jūsų naršyklės saugumo nustatymai neleidžia redaktoriui automatiškai įvykdyti kopijavimo operacijų. Tam prašome naudoti klaviatūrą (Ctrl/Cmd+C).',
8 cut: 'Iškirpti',
9 cutError: 'Jūsų naršyklės saugumo nustatymai neleidžia redaktoriui automatiškai įvykdyti iškirpimo operacijų. Tam prašome naudoti klaviatūrą (Ctrl/Cmd+X).',
10 paste: 'Įdėti',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/lv.js b/sources/plugins/clipboard/lang/lv.js
new file mode 100644
index 0000000..49775de
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lv.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'lv', {
6 copy: 'Kopēt',
7 copyError: 'Jūsu pārlūkprogrammas drošības iestatījumi nepieļauj redaktoram automātiski veikt kopēšanas darbību. Lūdzu, izmantojiet (Ctrl/Cmd+C), lai veiktu šo darbību.',
8 cut: 'Izgriezt',
9 cutError: 'Jūsu pārlūkprogrammas drošības iestatījumi nepieļauj redaktoram automātiski veikt izgriezšanas darbību. Lūdzu, izmantojiet (Ctrl/Cmd+X), lai veiktu šo darbību.',
10 paste: 'Ielīmēt',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/mk.js b/sources/plugins/clipboard/lang/mk.js
new file mode 100644
index 0000000..07a3d56
--- /dev/null
+++ b/sources/plugins/clipboard/lang/mk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'mk', {
6 copy: 'Копирај (Copy)',
7 copyError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши копирање. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
8 cut: 'Исечи (Cut)',
9 cutError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши сечење. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
10 paste: 'Залепи (Paste)',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/mn.js b/sources/plugins/clipboard/lang/mn.js
new file mode 100644
index 0000000..3ba66f5
--- /dev/null
+++ b/sources/plugins/clipboard/lang/mn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'mn', {
6 copy: 'Хуулах',
7 copyError: 'Таны browser-ын хамгаалалтын тохиргоо editor-д автоматаар хуулах үйлдэлийг зөвшөөрөхгүй байна. (Ctrl/Cmd+C) товчны хослолыг ашиглана уу.',
8 cut: 'Хайчлах',
9 cutError: 'Таны browser-ын хамгаалалтын тохиргоо editor-д автоматаар хайчлах үйлдэлийг зөвшөөрөхгүй байна. (Ctrl/Cmd+X) товчны хослолыг ашиглана уу.',
10 paste: 'Буулгах',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ms.js b/sources/plugins/clipboard/lang/ms.js
new file mode 100644
index 0000000..b9e479a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ms.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ms', {
6 copy: 'Salin',
7 copyError: 'Keselamatan perisian browser anda tidak membenarkan operasi salinan text/imej. Sila gunakan papan kekunci (Ctrl/Cmd+C).',
8 cut: 'Potong',
9 cutError: 'Keselamatan perisian browser anda tidak membenarkan operasi suntingan text/imej. Sila gunakan papan kekunci (Ctrl/Cmd+X).',
10 paste: 'Tampal',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/nb.js b/sources/plugins/clipboard/lang/nb.js
new file mode 100644
index 0000000..bdf1563
--- /dev/null
+++ b/sources/plugins/clipboard/lang/nb.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'nb', {
6 copy: 'Kopier',
7 copyError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk kopiering av tekst. Vennligst bruk tastatursnarveien (Ctrl/Cmd+C).',
8 cut: 'Klipp ut',
9 cutError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk utklipping av tekst. Vennligst bruk tastatursnarveien (Ctrl/Cmd+X).',
10 paste: 'Lim inn',
11 pasteNotification: 'Nettleseren din lar deg ikke lime inn på denne måten. Trykk %1 for å lime inn.'
12} );
diff --git a/sources/plugins/clipboard/lang/nl.js b/sources/plugins/clipboard/lang/nl.js
new file mode 100644
index 0000000..16bafd8
--- /dev/null
+++ b/sources/plugins/clipboard/lang/nl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'nl', {
6 copy: 'Kopiëren',
7 copyError: 'De beveiligingsinstelling van de browser verhinderen het automatisch kopiëren. Gebruik de sneltoets Ctrl/Cmd+C van het toetsenbord.',
8 cut: 'Knippen',
9 cutError: 'De beveiligingsinstelling van de browser verhinderen het automatisch knippen. Gebruik de sneltoets Ctrl/Cmd+X van het toetsenbord.',
10 paste: 'Plakken',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/no.js b/sources/plugins/clipboard/lang/no.js
new file mode 100644
index 0000000..77ff08a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/no.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'no', {
6 copy: 'Kopier',
7 copyError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk kopiering av tekst. Vennligst bruk snarveien (Ctrl/Cmd+C).',
8 cut: 'Klipp ut',
9 cutError: 'Din nettlesers sikkerhetsinstillinger tillater ikke automatisk utklipping av tekst. Vennligst bruk snarveien (Ctrl/Cmd+X).',
10 paste: 'Lim inn',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/oc.js b/sources/plugins/clipboard/lang/oc.js
new file mode 100644
index 0000000..40d99fa
--- /dev/null
+++ b/sources/plugins/clipboard/lang/oc.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'oc', {
6 copy: 'Copiar',
7 copyError: 'Los paramètres de seguretat de vòstre navigador autorizan pas l\'editor a executar automaticament l\'operacion « Copiar ». Utilizatz l\'acorchi de clavièr a aqueste efièit (Ctrl/Cmd+C).',
8 cut: 'Talhar',
9 cutError: 'Los paramètres de seguretat de vòstre navigador autorizan pas l\'editor a executar automaticament l\'operacion « Talhar ». Utilizatz l\'acorchi de clavièr a aqueste efièit (Ctrl/Cmd+X).',
10 paste: 'Pegar',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/pl.js b/sources/plugins/clipboard/lang/pl.js
new file mode 100644
index 0000000..494c9c1
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pl', {
6 copy: 'Kopiuj',
7 copyError: 'Ustawienia bezpieczeństwa Twojej przeglądarki nie pozwalają na automatyczne kopiowanie tekstu. Użyj skrótu klawiszowego Ctrl/Cmd+C.',
8 cut: 'Wytnij',
9 cutError: 'Ustawienia bezpieczeństwa Twojej przeglądarki nie pozwalają na automatyczne wycinanie tekstu. Użyj skrótu klawiszowego Ctrl/Cmd+X.',
10 paste: 'Wklej',
11 pasteNotification: 'Twoja przeglądarka nie pozwala na wklejanie treści w ten sposób. Naciśnij %1 by wkleić tekst.'
12} );
diff --git a/sources/plugins/clipboard/lang/pt-br.js b/sources/plugins/clipboard/lang/pt-br.js
new file mode 100644
index 0000000..e0359d9
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pt-br.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pt-br', {
6 copy: 'Copiar',
7 copyError: 'As configurações de segurança do seu navegador não permitem que o editor execute operações de copiar automaticamente. Por favor, utilize o teclado para copiar (Ctrl/Cmd+C).',
8 cut: 'Recortar',
9 cutError: 'As configurações de segurança do seu navegador não permitem que o editor execute operações de recortar automaticamente. Por favor, utilize o teclado para recortar (Ctrl/Cmd+X).',
10 paste: 'Colar',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/pt.js b/sources/plugins/clipboard/lang/pt.js
new file mode 100644
index 0000000..6a6df67
--- /dev/null
+++ b/sources/plugins/clipboard/lang/pt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'pt', {
6 copy: 'Copiar',
7 copyError: 'A configuração de segurança do navegador não permite a execução automática de operações de copiar. Por favor use o teclado (Ctrl/Cmd+C).',
8 cut: 'Cortar',
9 cutError: 'A configuração de segurança do navegador não permite a execução automática de operações de cortar. Por favor use o teclado (Ctrl/Cmd+X).',
10 paste: 'Colar',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ro.js b/sources/plugins/clipboard/lang/ro.js
new file mode 100644
index 0000000..4eb472a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ro.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ro', {
6 copy: 'Copiază',
7 copyError: 'Setările de securitate ale navigatorului (browser) pe care îl folosiţi nu permit editorului să execute automat operaţiunea de copiere. Vă rugăm folosiţi tastatura (Ctrl/Cmd+C).',
8 cut: 'Taie',
9 cutError: 'Setările de securitate ale navigatorului (browser) pe care îl folosiţi nu permit editorului să execute automat operaţiunea de tăiere. Vă rugăm folosiţi tastatura (Ctrl/Cmd+X).',
10 paste: 'Adaugă',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ru.js b/sources/plugins/clipboard/lang/ru.js
new file mode 100644
index 0000000..9ef951f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ru.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ru', {
6 copy: 'Копировать',
7 copyError: 'Настройки безопасности вашего браузера не разрешают редактору выполнять операции по копированию текста. Пожалуйста, используйте для этого клавиатуру (Ctrl/Cmd+C).',
8 cut: 'Вырезать',
9 cutError: 'Настройки безопасности вашего браузера не разрешают редактору выполнять операции по вырезке текста. Пожалуйста, используйте для этого клавиатуру (Ctrl/Cmd+X).',
10 paste: 'Вставить',
11 pasteNotification: 'Ваш браузер не поддерживает данный метод вставки. Для вставки нажмите %1'
12} );
diff --git a/sources/plugins/clipboard/lang/si.js b/sources/plugins/clipboard/lang/si.js
new file mode 100644
index 0000000..7356cf4
--- /dev/null
+++ b/sources/plugins/clipboard/lang/si.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'si', {
6 copy: 'පිටපත් කරන්න',
7 copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).', // MISSING
8 cut: 'කපාගන්න',
9 cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).', // MISSING
10 paste: 'අලවන්න',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/sk.js b/sources/plugins/clipboard/lang/sk.js
new file mode 100644
index 0000000..b844e58
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sk', {
6 copy: 'Kopírovať',
7 copyError: 'Bezpečnostné nastavenia vášho prehliadača nedovoľujú editoru automaticky spustiť operáciu kopírovania. Použite na to klávesnicu (Ctrl/Cmd+C).',
8 cut: 'Vystrihnúť',
9 cutError: 'Bezpečnostné nastavenia vášho prehliadača nedovoľujú editoru automaticky spustiť operáciu vystrihnutia. Použite na to klávesnicu (Ctrl/Cmd+X).',
10 paste: 'Vložiť',
11 pasteNotification: 'Váš prehliadač nepovoľuje prilepiť text takýmto spôsobom. Pre prilepenie stlačte %1.'
12} );
diff --git a/sources/plugins/clipboard/lang/sl.js b/sources/plugins/clipboard/lang/sl.js
new file mode 100644
index 0000000..787e6fc
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sl.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sl', {
6 copy: 'Kopiraj',
7 copyError: 'Varnostne nastavitve brskalnika ne dopuščajo samodejnega kopiranja. Uporabite kombinacijo tipk na tipkovnici (Ctrl/Cmd+C).',
8 cut: 'Izreži',
9 cutError: 'Varnostne nastavitve brskalnika ne dopuščajo samodejnega izrezovanja. Uporabite kombinacijo tipk na tipkovnici (Ctrl/Cmd+X).',
10 paste: 'Prilepi',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/sq.js b/sources/plugins/clipboard/lang/sq.js
new file mode 100644
index 0000000..d78b2e7
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sq.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sq', {
6 copy: 'Kopjo',
7 copyError: 'Të dhënat e sigurisë së shfletuesit tuaj nuk lejojnë që redaktuesi automatikisht të kryej veprimin e kopjimit. Ju lutemi shfrytëzoni tastierën për këtë veprim (Ctrl/Cmd+C).',
8 cut: 'Preje',
9 cutError: 'Të dhënat e sigurisë së shfletuesit tuaj nuk lejojnë që redaktuesi automatikisht të kryej veprimin e prerjes. Ju lutemi shfrytëzoni tastierën për këtë veprim (Ctrl/Cmd+X).',
10 paste: 'Hidhe',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/sr-latn.js b/sources/plugins/clipboard/lang/sr-latn.js
new file mode 100644
index 0000000..797429f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sr-latn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sr-latn', {
6 copy: 'Kopiraj',
7 copyError: 'Sigurnosna podešavanja Vašeg pretraživača ne dozvoljavaju operacije automatskog kopiranja teksta. Molimo Vas da koristite prečicu sa tastature (Ctrl/Cmd+C).',
8 cut: 'Iseci',
9 cutError: 'Sigurnosna podešavanja Vašeg pretraživača ne dozvoljavaju operacije automatskog isecanja teksta. Molimo Vas da koristite prečicu sa tastature (Ctrl/Cmd+X).',
10 paste: 'Zalepi',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/sr.js b/sources/plugins/clipboard/lang/sr.js
new file mode 100644
index 0000000..bd4e655
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sr', {
6 copy: 'Копирај',
7 copyError: 'Сигурносна подешавања Вашег претраживача не дозвољавају операције аутоматског копирања текста. Молимо Вас да користите пречицу са тастатуре (Ctrl/Cmd+C).',
8 cut: 'Исеци',
9 cutError: 'Сигурносна подешавања Вашег претраживача не дозвољавају операције аутоматског исецања текста. Молимо Вас да користите пречицу са тастатуре (Ctrl/Cmd+X).',
10 paste: 'Залепи',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/sv.js b/sources/plugins/clipboard/lang/sv.js
new file mode 100644
index 0000000..d1ab00b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/sv.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'sv', {
6 copy: 'Kopiera',
7 copyError: 'Säkerhetsinställningar i din webbläsare tillåter inte åtgärden kopiera. Använd (Ctrl/Cmd+C) istället.',
8 cut: 'Klipp ut',
9 cutError: 'Säkerhetsinställningar i din webbläsare tillåter inte åtgärden klipp ut. Använd (Ctrl/Cmd+X) istället.',
10 paste: 'Klistra in',
11 pasteNotification: 'Din webbläsare tillåter dig inte att klistra in på detta vis. Tryck på %1 för att klistra in.'
12} );
diff --git a/sources/plugins/clipboard/lang/th.js b/sources/plugins/clipboard/lang/th.js
new file mode 100644
index 0000000..b645b90
--- /dev/null
+++ b/sources/plugins/clipboard/lang/th.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'th', {
6 copy: 'สำเนา',
7 copyError: 'ไม่สามารถสำเนาข้อความที่เลือกไว้ได้เนื่องจากการกำหนดค่าระดับความปลอดภัย. กรุณาใช้ปุ่มลัดเพื่อวางข้อความแทน (กดปุ่ม Ctrl/Cmd และตัว C พร้อมกัน).',
8 cut: 'ตัด',
9 cutError: 'ไม่สามารถตัดข้อความที่เลือกไว้ได้เนื่องจากการกำหนดค่าระดับความปลอดภัย. กรุณาใช้ปุ่มลัดเพื่อวางข้อความแทน (กดปุ่ม Ctrl/Cmd และตัว X พร้อมกัน).',
10 paste: 'วาง',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/tr.js b/sources/plugins/clipboard/lang/tr.js
new file mode 100644
index 0000000..4645335
--- /dev/null
+++ b/sources/plugins/clipboard/lang/tr.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'tr', {
6 copy: 'Kopyala',
7 copyError: 'Gezgin yazılımınızın güvenlik ayarları düzenleyicinin otomatik kopyalama işlemine izin vermiyor. İşlem için (Ctrl/Cmd+C) tuşlarını kullanın.',
8 cut: 'Kes',
9 cutError: 'Gezgin yazılımınızın güvenlik ayarları düzenleyicinin otomatik kesme işlemine izin vermiyor. İşlem için (Ctrl/Cmd+X) tuşlarını kullanın.',
10 paste: 'Yapıştır',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/tt.js b/sources/plugins/clipboard/lang/tt.js
new file mode 100644
index 0000000..5e641e3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/tt.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'tt', {
6 copy: 'Күчермәләү',
7 copyError: 'Браузерыгызның иминлек үзлекләре автоматик рәвештә күчермәләү үтәүне тыя. Тиз төймәләрне (Ctrl/Cmd+C) кулланыгыз.',
8 cut: 'Кисеп алу',
9 cutError: 'Браузерыгызның иминлек үзлекләре автоматик рәвештә күчермәләү үтәүне тыя. Тиз төймәләрне (Ctrl/Cmd+C) кулланыгыз.',
10 paste: 'Өстәү',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/ug.js b/sources/plugins/clipboard/lang/ug.js
new file mode 100644
index 0000000..deb1d2b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ug.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'ug', {
6 copy: 'كۆچۈر',
7 copyError: 'تور كۆرگۈڭىزنىڭ بىخەتەرلىك تەڭشىكى تەھرىرلىگۈچنىڭ كۆچۈر مەشغۇلاتىنى ئۆزلۈكىدىن ئىجرا قىلىشىغا يول قويمايدۇ، ھەرپتاختا تېز كۇنۇپكا (Ctrl/Cmd+C) ئارقىلىق تاماملاڭ',
8 cut: 'كەس',
9 cutError: 'تور كۆرگۈڭىزنىڭ بىخەتەرلىك تەڭشىكى تەھرىرلىگۈچنىڭ كەس مەشغۇلاتىنى ئۆزلۈكىدىن ئىجرا قىلىشىغا يول قويمايدۇ، ھەرپتاختا تېز كۇنۇپكا (Ctrl/Cmd+X) ئارقىلىق تاماملاڭ',
10 paste: 'چاپلا',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/uk.js b/sources/plugins/clipboard/lang/uk.js
new file mode 100644
index 0000000..f3e06a5
--- /dev/null
+++ b/sources/plugins/clipboard/lang/uk.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'uk', {
6 copy: 'Копіювати',
7 copyError: 'Налаштування безпеки Вашого браузера не дозволяють редактору автоматично виконувати операції копіювання. Будь ласка, використовуйте клавіатуру для цього (Ctrl/Cmd+C).',
8 cut: 'Вирізати',
9 cutError: 'Налаштування безпеки Вашого браузера не дозволяють редактору автоматично виконувати операції вирізування. Будь ласка, використовуйте клавіатуру для цього (Ctrl/Cmd+X)',
10 paste: 'Вставити',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/vi.js b/sources/plugins/clipboard/lang/vi.js
new file mode 100644
index 0000000..2928a95
--- /dev/null
+++ b/sources/plugins/clipboard/lang/vi.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'vi', {
6 copy: 'Sao chép',
7 copyError: 'Các thiết lập bảo mật của trình duyệt không cho phép trình biên tập tự động thực thi lệnh sao chép. Hãy sử dụng bàn phím cho lệnh này (Ctrl/Cmd+C).',
8 cut: 'Cắt',
9 cutError: 'Các thiết lập bảo mật của trình duyệt không cho phép trình biên tập tự động thực thi lệnh cắt. Hãy sử dụng bàn phím cho lệnh này (Ctrl/Cmd+X).',
10 paste: 'Dán',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/lang/zh-cn.js b/sources/plugins/clipboard/lang/zh-cn.js
new file mode 100644
index 0000000..4b738cb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/zh-cn.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'zh-cn', {
6 copy: '复制',
7 copyError: '您的浏览器安全设置不允许编辑器自动执行复制操作,请使用键盘快捷键(Ctrl/Cmd+C)来完成。',
8 cut: '剪切',
9 cutError: '您的浏览器安全设置不允许编辑器自动执行剪切操作,请使用键盘快捷键(Ctrl/Cmd+X)来完成。',
10 paste: '粘贴',
11 pasteNotification: '您的浏览器不允许用此方式粘贴,要粘贴请按 %1。'
12} );
diff --git a/sources/plugins/clipboard/lang/zh.js b/sources/plugins/clipboard/lang/zh.js
new file mode 100644
index 0000000..f91de7e
--- /dev/null
+++ b/sources/plugins/clipboard/lang/zh.js
@@ -0,0 +1,12 @@
1/*
2Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3For licensing, see LICENSE.md or http://ckeditor.com/license
4*/
5CKEDITOR.plugins.setLang( 'clipboard', 'zh', {
6 copy: '複製',
7 copyError: '瀏覽器的安全性設定不允許編輯器自動執行複製動作。請使用鍵盤快捷鍵 (Ctrl/Cmd+C) 複製。',
8 cut: '剪下',
9 cutError: '瀏覽器的安全性設定不允許編輯器自動執行剪下動作。請使用鏐盤快捷鍵 (Ctrl/Cmd+X) 剪下。',
10 paste: '貼上',
11 pasteNotification: 'Your browser doesn\'t allow you to paste this way. Press %1 to paste.' // MISSING
12} );
diff --git a/sources/plugins/clipboard/plugin.js b/sources/plugins/clipboard/plugin.js
new file mode 100644
index 0000000..433f547
--- /dev/null
+++ b/sources/plugins/clipboard/plugin.js
@@ -0,0 +1,2780 @@
1/**
2 * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
3 * For licensing, see LICENSE.md or http://ckeditor.com/license
4 */
5
6/**
7 * @ignore
8 * File overview: Clipboard support.
9 */
10
11//
12// COPY & PASTE EXECUTION FLOWS:
13// -- CTRL+C
14// * if ( isCustomCopyCutSupported )
15// * dataTransfer.setData( 'text/html', getSelectedHtml )
16// * else
17// * browser's default behavior
18// -- CTRL+X
19// * listen onKey (onkeydown)
20// * fire 'saveSnapshot' on editor
21// * if ( isCustomCopyCutSupported )
22// * dataTransfer.setData( 'text/html', getSelectedHtml )
23// * extractSelectedHtml // remove selected contents
24// * else
25// * browser's default behavior
26// * deferred second 'saveSnapshot' event
27// -- CTRL+V
28// * listen onKey (onkeydown)
29// * simulate 'beforepaste' for non-IEs on editable
30// * listen 'onpaste' on editable ('onbeforepaste' for IE)
31// * fire 'beforePaste' on editor
32// * if ( !canceled && ( htmlInDataTransfer || !external paste) && dataTransfer is not empty ) getClipboardDataByPastebin
33// * fire 'paste' on editor
34// * !canceled && fire 'afterPaste' on editor
35// -- Copy command
36// * tryToCutCopy
37// * execCommand
38// * !success && notification
39// -- Cut command
40// * fixCut
41// * tryToCutCopy
42// * execCommand
43// * !success && notification
44// -- Paste command
45// * fire 'paste' on editable ('beforepaste' for IE)
46// * !canceled && execCommand 'paste'
47// -- Paste from native context menu & menubar
48// (Fx & Webkits are handled in 'paste' default listener.
49// Opera cannot be handled at all because it doesn't fire any events
50// Special treatment is needed for IE, for which is this part of doc)
51// * listen 'onpaste'
52// * cancel native event
53// * fire 'beforePaste' on editor
54// * if ( !canceled && ( htmlInDataTransfer || !external paste) && dataTransfer is not empty ) getClipboardDataByPastebin
55// * execIECommand( 'paste' ) -> this fires another 'paste' event, so cancel it
56// * fire 'paste' on editor
57// * !canceled && fire 'afterPaste' on editor
58//
59//
60// PASTE EVENT - PREPROCESSING:
61// -- Possible dataValue types: auto, text, html.
62// -- Possible dataValue contents:
63// * text (possible \n\r)
64// * htmlified text (text + br,div,p - no presentational markup & attrs - depends on browser)
65// * html
66// -- Possible flags:
67// * htmlified - if true then content is a HTML even if no markup inside. This flag is set
68// for content from editable pastebins, because they 'htmlify' pasted content.
69//
70// -- Type: auto:
71// * content: htmlified text -> filter, unify text markup (brs, ps, divs), set type: text
72// * content: html -> filter, set type: html
73// -- Type: text:
74// * content: htmlified text -> filter, unify text markup
75// * content: html -> filter, strip presentational markup, unify text markup
76// -- Type: html:
77// * content: htmlified text -> filter, unify text markup
78// * content: html -> filter
79//
80// -- Phases:
81// * if dataValue is empty copy data from dataTransfer to dataValue (priority 1)
82// * filtering (priorities 3-5) - e.g. pastefromword filters
83// * content type sniffing (priority 6)
84// * markup transformations for text (priority 6)
85//
86// DRAG & DROP EXECUTION FLOWS:
87// -- Drag
88// * save to the global object:
89// * drag timestamp (with 'cke-' prefix),
90// * selected html,
91// * drag range,
92// * editor instance.
93// * put drag timestamp into event.dataTransfer.text
94// -- Drop
95// * if events text == saved timestamp && editor == saved editor
96// internal drag & drop occurred
97// * getRangeAtDropPosition
98// * create bookmarks for drag and drop ranges starting from the end of the document
99// * dragRange.deleteContents()
100// * fire 'paste' with saved html and drop range
101// * if events text == saved timestamp && editor != saved editor
102// cross editor drag & drop occurred
103// * getRangeAtDropPosition
104// * fire 'paste' with saved html
105// * dragRange.deleteContents()
106// * FF: refreshCursor on afterPaste
107// * if events text != saved timestamp
108// drop form external source occurred
109// * getRangeAtDropPosition
110// * if event contains html data then fire 'paste' with html
111// * else if event contains text data then fire 'paste' with encoded text
112// * FF: refreshCursor on afterPaste
113
114'use strict';
115
116( function() {
117 // Register the plugin.
118 CKEDITOR.plugins.add( 'clipboard', {
119 requires: 'notification,toolbar',
120 // jscs:disable maximumLineLength
121 lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,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,oc,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%
122 // jscs:enable maximumLineLength
123 icons: 'copy,copy-rtl,cut,cut-rtl,paste,paste-rtl', // %REMOVE_LINE_CORE%
124 hidpi: true, // %REMOVE_LINE_CORE%
125 init: function( editor ) {
126 var filterType,
127 filtersFactory = filtersFactoryFactory();
128
129 if ( editor.config.forcePasteAsPlainText ) {
130 filterType = 'plain-text';
131 } else if ( editor.config.pasteFilter ) {
132 filterType = editor.config.pasteFilter;
133 }
134 // On Webkit the pasteFilter defaults 'semantic-content' because pasted data is so terrible
135 // that it must be always filtered.
136 else if ( CKEDITOR.env.webkit && !( 'pasteFilter' in editor.config ) ) {
137 filterType = 'semantic-content';
138 }
139
140 editor.pasteFilter = filtersFactory.get( filterType );
141
142 initPasteClipboard( editor );
143 initDragDrop( editor );
144
145 // Convert image file (if present) to base64 string for Firefox. Do it as the first
146 // step as the conversion is asynchronous and should hold all further paste processing.
147 if ( CKEDITOR.env.gecko ) {
148 var supportedImageTypes = [ 'image/png', 'image/jpeg', 'image/gif' ],
149 latestId;
150
151 editor.on( 'paste', function( evt ) {
152 var dataObj = evt.data,
153 data = dataObj.dataValue,
154 dataTransfer = dataObj.dataTransfer;
155
156 // If data empty check for image content inside data transfer. http://dev.ckeditor.com/ticket/16705
157 if ( !data && dataObj.method == 'paste' && dataTransfer && dataTransfer.getFilesCount() == 1 && latestId != dataTransfer.id ) {
158 var file = dataTransfer.getFile( 0 );
159
160 if ( CKEDITOR.tools.indexOf( supportedImageTypes, file.type ) != -1 ) {
161 var fileReader = new FileReader();
162
163 // Convert image file to img tag with base64 image.
164 fileReader.addEventListener( 'load', function() {
165 evt.data.dataValue = '<img src="' + fileReader.result + '" />';
166 editor.fire( 'paste', evt.data );
167 }, false );
168
169 // Proceed with normal flow if reading file was aborted.
170 fileReader.addEventListener( 'abort', function() {
171 editor.fire( 'paste', evt.data );
172 }, false );
173
174 // Proceed with normal flow if reading file failed.
175 fileReader.addEventListener( 'error', function() {
176 editor.fire( 'paste', evt.data );
177 }, false );
178
179 fileReader.readAsDataURL( file );
180
181 latestId = dataObj.dataTransfer.id;
182
183 evt.stop();
184 }
185 }
186 }, null, null, 1 );
187 }
188
189 editor.on( 'paste', function( evt ) {
190 // Init `dataTransfer` if `paste` event was fired without it, so it will be always available.
191 if ( !evt.data.dataTransfer ) {
192 evt.data.dataTransfer = new CKEDITOR.plugins.clipboard.dataTransfer();
193 }
194
195 // If dataValue is already set (manually or by paste bin), so do not override it.
196 if ( evt.data.dataValue ) {
197 return;
198 }
199
200 var dataTransfer = evt.data.dataTransfer,
201 // IE support only text data and throws exception if we try to get html data.
202 // This html data object may also be empty if we drag content of the textarea.
203 value = dataTransfer.getData( 'text/html' );
204
205 if ( value ) {
206 evt.data.dataValue = value;
207 evt.data.type = 'html';
208 } else {
209 // Try to get text data otherwise.
210 value = dataTransfer.getData( 'text/plain' );
211
212 if ( value ) {
213 evt.data.dataValue = editor.editable().transformPlainTextToHtml( value );
214 evt.data.type = 'text';
215 }
216 }
217 }, null, null, 1 );
218
219 editor.on( 'paste', function( evt ) {
220 var data = evt.data.dataValue,
221 blockElements = CKEDITOR.dtd.$block;
222
223 // Filter webkit garbage.
224 if ( data.indexOf( 'Apple-' ) > -1 ) {
225 // Replace special webkit's &nbsp; with simple space, because webkit
226 // produces them even for normal spaces.
227 data = data.replace( /<span class="Apple-converted-space">&nbsp;<\/span>/gi, ' ' );
228
229 // Strip <span> around white-spaces when not in forced 'html' content type.
230 // This spans are created only when pasting plain text into Webkit,
231 // but for safety reasons remove them always.
232 if ( evt.data.type != 'html' ) {
233 data = data.replace( /<span class="Apple-tab-span"[^>]*>([^<]*)<\/span>/gi, function( all, spaces ) {
234 // Replace tabs with 4 spaces like Fx does.
235 return spaces.replace( /\t/g, '&nbsp;&nbsp; &nbsp;' );
236 } );
237 }
238
239 // This br is produced only when copying & pasting HTML content.
240 if ( data.indexOf( '<br class="Apple-interchange-newline">' ) > -1 ) {
241 evt.data.startsWithEOL = 1;
242 evt.data.preSniffing = 'html'; // Mark as not text.
243 data = data.replace( /<br class="Apple-interchange-newline">/, '' );
244 }
245
246 // Remove all other classes.
247 data = data.replace( /(<[^>]+) class="Apple-[^"]*"/gi, '$1' );
248 }
249
250 // Strip editable that was copied from inside. (http://dev.ckeditor.com/ticket/9534)
251 if ( data.match( /^<[^<]+cke_(editable|contents)/i ) ) {
252 var tmp,
253 editable_wrapper,
254 wrapper = new CKEDITOR.dom.element( 'div' );
255
256 wrapper.setHtml( data );
257 // Verify for sure and check for nested editor UI parts. (http://dev.ckeditor.com/ticket/9675)
258 while ( wrapper.getChildCount() == 1 &&
259 ( tmp = wrapper.getFirst() ) &&
260 tmp.type == CKEDITOR.NODE_ELEMENT && // Make sure first-child is element.
261 ( tmp.hasClass( 'cke_editable' ) || tmp.hasClass( 'cke_contents' ) ) ) {
262 wrapper = editable_wrapper = tmp;
263 }
264
265 // If editable wrapper was found strip it and bogus <br> (added on FF).
266 if ( editable_wrapper )
267 data = editable_wrapper.getHtml().replace( /<br>$/i, '' );
268 }
269
270 if ( CKEDITOR.env.ie ) {
271 // &nbsp; <p> -> <p> (br.cke-pasted-remove will be removed later)
272 data = data.replace( /^&nbsp;(?: |\r\n)?<(\w+)/g, function( match, elementName ) {
273 if ( elementName.toLowerCase() in blockElements ) {
274 evt.data.preSniffing = 'html'; // Mark as not a text.
275 return '<' + elementName;
276 }
277 return match;
278 } );
279 } else if ( CKEDITOR.env.webkit ) {
280 // </p><div><br></div> -> </p><br>
281 // We don't mark br, because this situation can happen for htmlified text too.
282 data = data.replace( /<\/(\w+)><div><br><\/div>$/, function( match, elementName ) {
283 if ( elementName in blockElements ) {
284 evt.data.endsWithEOL = 1;
285 return '</' + elementName + '>';
286 }
287 return match;
288 } );
289 } else if ( CKEDITOR.env.gecko ) {
290 // Firefox adds bogus <br> when user pasted text followed by space(s).
291 data = data.replace( /(\s)<br>$/, '$1' );
292 }
293
294 evt.data.dataValue = data;
295 }, null, null, 3 );
296
297 editor.on( 'paste', function( evt ) {
298 var dataObj = evt.data,
299 type = editor._.nextPasteType || dataObj.type,
300 data = dataObj.dataValue,
301 trueType,
302 // Default is 'html'.
303 defaultType = editor.config.clipboard_defaultContentType || 'html',
304 transferType = dataObj.dataTransfer.getTransferType( editor );
305
306 // If forced type is 'html' we don't need to know true data type.
307 if ( type == 'html' || dataObj.preSniffing == 'html' ) {
308 trueType = 'html';
309 } else {
310 trueType = recogniseContentType( data );
311 }
312
313 delete editor._.nextPasteType;
314
315 // Unify text markup.
316 if ( trueType == 'htmlifiedtext' ) {
317 data = htmlifiedTextHtmlification( editor.config, data );
318 }
319
320 // Strip presentational markup & unify text markup.
321 // Forced plain text.
322 // Note: we do not check dontFilter option in this case, because forcePAPT was implemented
323 // before pasteFilter and pasteFilter is automatically used on Webkit&Blink since 4.5, so
324 // forcePAPT should have priority as it had before 4.5.
325 if ( type == 'text' && trueType == 'html' ) {
326 data = filterContent( editor, data, filtersFactory.get( 'plain-text' ) );
327 }
328 // External paste and pasteFilter exists and filtering isn't disabled.
329 else if ( transferType == CKEDITOR.DATA_TRANSFER_EXTERNAL && editor.pasteFilter && !dataObj.dontFilter ) {
330 data = filterContent( editor, data, editor.pasteFilter );
331 }
332
333 if ( dataObj.startsWithEOL ) {
334 data = '<br data-cke-eol="1">' + data;
335 }
336 if ( dataObj.endsWithEOL ) {
337 data += '<br data-cke-eol="1">';
338 }
339
340 if ( type == 'auto' ) {
341 type = ( trueType == 'html' || defaultType == 'html' ) ? 'html' : 'text';
342 }
343
344 dataObj.type = type;
345 dataObj.dataValue = data;
346 delete dataObj.preSniffing;
347 delete dataObj.startsWithEOL;
348 delete dataObj.endsWithEOL;
349 }, null, null, 6 );
350
351 // Inserts processed data into the editor at the end of the
352 // events chain.
353 editor.on( 'paste', function( evt ) {
354 var data = evt.data;
355
356 if ( data.dataValue ) {
357 editor.insertHtml( data.dataValue, data.type, data.range );
358
359 // Defer 'afterPaste' so all other listeners for 'paste' will be fired first.
360 // Fire afterPaste only if paste inserted some HTML.
361 setTimeout( function() {
362 editor.fire( 'afterPaste' );
363 }, 0 );
364 }
365 }, null, null, 1000 );
366 }
367 } );
368
369 function firePasteEvents( editor, data, withBeforePaste ) {
370 if ( !data.type ) {
371 data.type = 'auto';
372 }
373
374 if ( withBeforePaste ) {
375 // Fire 'beforePaste' event so clipboard flavor get customized
376 // by other plugins.
377 if ( editor.fire( 'beforePaste', data ) === false )
378 return false; // Event canceled
379 }
380
381 // Do not fire paste if there is no data (dataValue and dataTranfser are empty).
382 // This check should be done after firing 'beforePaste' because for native paste
383 // 'beforePaste' is by default fired even for empty clipboard.
384 if ( !data.dataValue && data.dataTransfer.isEmpty() ) {
385 return false;
386 }
387
388 if ( !data.dataValue ) {
389 data.dataValue = '';
390 }
391
392 // Because of FF bug we need to use this hack, otherwise cursor is hidden
393 // or it is not possible to move it (http://dev.ckeditor.com/ticket/12420).
394 // Also, check that editor.toolbox exists, because the toolbar plugin might not be loaded (http://dev.ckeditor.com/ticket/13305).
395 if ( CKEDITOR.env.gecko && data.method == 'drop' && editor.toolbox ) {
396 editor.once( 'afterPaste', function() {
397 editor.toolbox.focus();
398 } );
399 }
400
401 return editor.fire( 'paste', data );
402 }
403
404 function initPasteClipboard( editor ) {
405 var clipboard = CKEDITOR.plugins.clipboard,
406 preventBeforePasteEvent = 0,
407 preventPasteEvent = 0,
408 inReadOnly = 0;
409
410 addListeners();
411 addButtonsCommands();
412
413 /**
414 * Gets clipboard data by directly accessing the clipboard (IE only).
415 *
416 * editor.getClipboardData( function( data ) {
417 * if ( data )
418 * alert( data.type + ' ' + data.dataValue );
419 * } );
420 *
421 * @member CKEDITOR.editor
422 * @param {Function/Object} callbackOrOptions For function, see the `callback` parameter documentation. The object was used before 4.7.0 with the `title` property, to set the paste dialog's title.
423 * @param {Function} callback A function that will be executed with the `data` property of the
424 * {@link CKEDITOR.editor#event-paste paste event} or `null` if none of the capturing methods succeeded.
425 * Since 4.7.0 the `callback` should be provided as a first argument, just like in the example above. This parameter will be removed in
426 * an upcoming major release.
427 */
428 editor.getClipboardData = function( callbackOrOptions, callback ) {
429 // Options are optional - args shift.
430 if ( !callback ) {
431 callback = callbackOrOptions;
432 callbackOrOptions = null;
433 }
434
435 // Listen with maximum priority to handle content before everyone else.
436 // This callback will handle paste event that will be fired if direct
437 // access to the clipboard succeed in IE.
438 editor.on( 'paste', onPaste, null, null, 0 );
439
440 // If command didn't succeed (only IE allows to access clipboard and only if
441 // user agrees) invoke callback with null, meaning that paste is not blocked.
442 if ( getClipboardDataDirectly() === false ) {
443 // Direct access to the clipboard wasn't successful so remove listener.
444 editor.removeListener( 'paste', onPaste );
445
446 callback( null );
447 }
448
449 function onPaste( evt ) {
450 evt.removeListener();
451 evt.cancel();
452 callback( evt.data );
453 }
454 };
455
456 function addButtonsCommands() {
457 addButtonCommand( 'Cut', 'cut', createCutCopyCmd( 'cut' ), 10, 1 );
458 addButtonCommand( 'Copy', 'copy', createCutCopyCmd( 'copy' ), 20, 4 );
459 addButtonCommand( 'Paste', 'paste', createPasteCmd(), 30, 8 );
460
461 function addButtonCommand( buttonName, commandName, command, toolbarOrder, ctxMenuOrder ) {
462 var lang = editor.lang.clipboard[ commandName ];
463
464 editor.addCommand( commandName, command );
465 editor.ui.addButton && editor.ui.addButton( buttonName, {
466 label: lang,
467 command: commandName,
468 toolbar: 'clipboard,' + toolbarOrder
469 } );
470
471 // If the "menu" plugin is loaded, register the menu item.
472 if ( editor.addMenuItems ) {
473 editor.addMenuItem( commandName, {
474 label: lang,
475 command: commandName,
476 group: 'clipboard',
477 order: ctxMenuOrder
478 } );
479 }
480 }
481 }
482
483 function addListeners() {
484 editor.on( 'key', onKey );
485 editor.on( 'contentDom', addPasteListenersToEditable );
486
487 // For improved performance, we're checking the readOnly state on selectionChange instead of hooking a key event for that.
488 editor.on( 'selectionChange', function( evt ) {
489 inReadOnly = evt.data.selection.getRanges()[ 0 ].checkReadOnly();
490 setToolbarStates();
491 } );
492
493 // If the "contextmenu" plugin is loaded, register the listeners.
494 if ( editor.contextMenu ) {
495 editor.contextMenu.addListener( function( element, selection ) {
496 inReadOnly = selection.getRanges()[ 0 ].checkReadOnly();
497 return {
498 cut: stateFromNamedCommand( 'cut' ),
499 copy: stateFromNamedCommand( 'copy' ),
500 paste: stateFromNamedCommand( 'paste' )
501 };
502 } );
503 }
504 }
505
506 // Add events listeners to editable.
507 function addPasteListenersToEditable() {
508 var editable = editor.editable();
509
510 if ( CKEDITOR.plugins.clipboard.isCustomCopyCutSupported ) {
511 var initOnCopyCut = function( evt ) {
512 // If user tries to cut in read-only editor, we must prevent default action. (http://dev.ckeditor.com/ticket/13872)
513 if ( !editor.readOnly || evt.name != 'cut' ) {
514 clipboard.initPasteDataTransfer( evt, editor );
515 }
516 evt.data.preventDefault();
517 };
518
519 editable.on( 'copy', initOnCopyCut );
520 editable.on( 'cut', initOnCopyCut );
521
522 // Delete content with the low priority so one can overwrite cut data.
523 editable.on( 'cut', function() {
524 // If user tries to cut in read-only editor, we must prevent default action. (http://dev.ckeditor.com/ticket/13872)
525 if ( !editor.readOnly ) {
526 editor.extractSelectedHtml();
527 }
528 }, null, null, 999 );
529 }
530
531 // We'll be catching all pasted content in one line, regardless of whether
532 // it's introduced by a document command execution (e.g. toolbar buttons) or
533 // user paste behaviors (e.g. CTRL+V).
534 editable.on( clipboard.mainPasteEvent, function( evt ) {
535 if ( clipboard.mainPasteEvent == 'beforepaste' && preventBeforePasteEvent ) {
536 return;
537 }
538
539 // If you've just asked yourself why preventPasteEventNow() is not here, but
540 // in listener for CTRL+V and exec method of 'paste' command
541 // you've asked the same question we did.
542 //
543 // THE ANSWER:
544 //
545 // First thing to notice - this answer makes sense only for IE,
546 // because other browsers don't listen for 'paste' event.
547 //
548 // What would happen if we move preventPasteEventNow() here?
549 // For:
550 // * CTRL+V - IE fires 'beforepaste', so we prevent 'paste' and pasteDataFromClipboard(). OK.
551 // * editor.execCommand( 'paste' ) - we fire 'beforepaste', so we prevent
552 // 'paste' and pasteDataFromClipboard() and doc.execCommand( 'Paste' ). OK.
553 // * native context menu - IE fires 'beforepaste', so we prevent 'paste', but unfortunately
554 // on IE we fail with pasteDataFromClipboard() here, because of... we don't know why, but
555 // we just fail, so... we paste nothing. FAIL.
556 // * native menu bar - the same as for native context menu.
557 //
558 // But don't you know any way to distinguish first two cases from last two?
559 // Only one - special flag set in CTRL+V handler and exec method of 'paste'
560 // command. And that's what we did using preventPasteEventNow().
561
562 pasteDataFromClipboard( evt );
563 } );
564
565 // It's not possible to clearly handle all four paste methods (ctrl+v, native menu bar
566 // native context menu, editor's command) in one 'paste/beforepaste' event in IE.
567 //
568 // For ctrl+v & editor's command it's easy to handle pasting in 'beforepaste' listener,
569 // so we do this. For another two methods it's better to use 'paste' event.
570 //
571 // 'paste' is always being fired after 'beforepaste' (except of weird one on opening native
572 // context menu), so for two methods handled in 'beforepaste' we're canceling 'paste'
573 // using preventPasteEvent state.
574 //
575 // 'paste' event in IE is being fired before getClipboardDataByPastebin executes its callback.
576 //
577 // QUESTION: Why didn't you handle all 4 paste methods in handler for 'paste'?
578 // Wouldn't this just be simpler?
579 // ANSWER: Then we would have to evt.data.preventDefault() only for native
580 // context menu and menu bar pastes. The same with execIECommand().
581 // That would force us to mark CTRL+V and editor's paste command with
582 // special flag, other than preventPasteEvent. But we still would have to
583 // have preventPasteEvent for the second event fired by execIECommand.
584 // Code would be longer and not cleaner.
585 if ( clipboard.mainPasteEvent == 'beforepaste' ) {
586 editable.on( 'paste', function( evt ) {
587 if ( preventPasteEvent ) {
588 return;
589 }
590
591 // Cancel next 'paste' event fired by execIECommand( 'paste' )
592 // at the end of this callback.
593 preventPasteEventNow();
594
595 // Prevent native paste.
596 evt.data.preventDefault();
597
598 pasteDataFromClipboard( evt );
599
600 // Force IE to paste content into pastebin so pasteDataFromClipboard will work.
601 execIECommand( 'paste' );
602 } );
603
604 // If mainPasteEvent is 'beforePaste' (IE before Edge),
605 // dismiss the (wrong) 'beforepaste' event fired on context/toolbar menu open. (http://dev.ckeditor.com/ticket/7953)
606 editable.on( 'contextmenu', preventBeforePasteEventNow, null, null, 0 );
607
608 editable.on( 'beforepaste', function( evt ) {
609 // Do not prevent event on CTRL+V and SHIFT+INS because it blocks paste (http://dev.ckeditor.com/ticket/11970).
610 if ( evt.data && !evt.data.$.ctrlKey && !evt.data.$.shiftKey )
611 preventBeforePasteEventNow();
612 }, null, null, 0 );
613 }
614
615 editable.on( 'beforecut', function() {
616 !preventBeforePasteEvent && fixCut( editor );
617 } );
618
619 var mouseupTimeout;
620
621 // Use editor.document instead of editable in non-IEs for observing mouseup
622 // since editable won't fire the event if selection process started within
623 // iframe and ended out of the editor (http://dev.ckeditor.com/ticket/9851).
624 editable.attachListener( CKEDITOR.env.ie ? editable : editor.document.getDocumentElement(), 'mouseup', function() {
625 mouseupTimeout = setTimeout( function() {
626 setToolbarStates();
627 }, 0 );
628 } );
629
630 // Make sure that deferred mouseup callback isn't executed after editor instance
631 // had been destroyed. This may happen when editor.destroy() is called in parallel
632 // with mouseup event (i.e. a button with onclick callback) (http://dev.ckeditor.com/ticket/10219).
633 editor.on( 'destroy', function() {
634 clearTimeout( mouseupTimeout );
635 } );
636
637 editable.on( 'keyup', setToolbarStates );
638 }
639
640 // Create object representing Cut or Copy commands.
641 function createCutCopyCmd( type ) {
642 return {
643 type: type,
644 canUndo: type == 'cut', // We can't undo copy to clipboard.
645 startDisabled: true,
646 fakeKeystroke: type == 'cut' ? CKEDITOR.CTRL + 88 /*X*/ : CKEDITOR.CTRL + 67 /*C*/,
647 exec: function() {
648 // Attempts to execute the Cut and Copy operations.
649 function tryToCutCopy( type ) {
650 if ( CKEDITOR.env.ie )
651 return execIECommand( type );
652
653 // non-IEs part
654 try {
655 // Other browsers throw an error if the command is disabled.
656 return editor.document.$.execCommand( type, false, null );
657 } catch ( e ) {
658 return false;
659 }
660 }
661
662 this.type == 'cut' && fixCut();
663
664 var success = tryToCutCopy( this.type );
665
666 if ( !success ) {
667 // Show cutError or copyError.
668 editor.showNotification( editor.lang.clipboard[ this.type + 'Error' ] ); // jshint ignore:line
669 }
670
671 return success;
672 }
673 };
674 }
675
676 function createPasteCmd() {
677 return {
678 // Snapshots are done manually by editable.insertXXX methods.
679 canUndo: false,
680 async: true,
681 fakeKeystroke: CKEDITOR.CTRL + 86 /*V*/,
682
683 /**
684 * The default implementation of the paste command.
685 *
686 * @private
687 * @param {CKEDITOR.editor} editor An instance of the editor where the command is being executed.
688 * @param {Object/String} data If `data` is a string, then it is considered content that is being pasted.
689 * Otherwise it is treated as an object with options.
690 * @param {Boolean/String} [data.notification=true] Content for a notification shown after an unsuccessful
691 * paste attempt. If `false`, the notification will not be displayed. This parameter was added in 4.7.0.
692 * @param {String} [data.type='html'] The type of pasted content. There are two allowed values:
693 * * 'html'
694 * * 'text'
695 * @param {String/Object} data.dataValue Content being pasted. If this parameter is an object, it
696 * is supposed to be a `data` property of the {@link CKEDITOR.editor#paste} event.
697 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer Data transfer instance connected
698 * with the current paste action.
699 * @member CKEDITOR.editor.commands.paste
700 */
701 exec: function( editor, data ) {
702 data = typeof data !== 'undefined' && data !== null ? data : {};
703
704 var cmd = this,
705 notification = typeof data.notification !== 'undefined' ? data.notification : true,
706 forcedType = data.type,
707 keystroke = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard,
708 editor.getCommandKeystroke( this ) ),
709 msg = typeof notification === 'string' ? notification : editor.lang.clipboard.pasteNotification
710 .replace( /%1/, '<kbd aria-label="' + keystroke.aria + '">' + keystroke.display + '</kbd>' ),
711 pastedContent = typeof data === 'string' ? data : data.dataValue;
712
713 function callback( data, withBeforePaste ) {
714 withBeforePaste = typeof withBeforePaste !== 'undefined' ? withBeforePaste : true;
715
716 if ( data ) {
717 data.method = 'paste';
718
719 if ( !data.dataTransfer ) {
720 data.dataTransfer = clipboard.initPasteDataTransfer();
721 }
722
723 firePasteEvents( editor, data, withBeforePaste );
724 } else if ( notification ) {
725 editor.showNotification( msg, 'info', editor.config.clipboard_notificationDuration );
726 }
727
728 editor.fire( 'afterCommandExec', {
729 name: 'paste',
730 command: cmd,
731 returnValue: !!data
732 } );
733 }
734
735 // Force type for the next paste.
736 if ( forcedType ) {
737 editor._.nextPasteType = forcedType;
738 } else {
739 delete editor._.nextPasteType;
740 }
741
742 if ( typeof pastedContent === 'string' ) {
743 callback( {
744 dataValue: pastedContent
745 } );
746 } else {
747 editor.getClipboardData( callback );
748 }
749 }
750 };
751 }
752
753 function preventPasteEventNow() {
754 preventPasteEvent = 1;
755 // For safety reason we should wait longer than 0/1ms.
756 // We don't know how long execution of quite complex getClipboardData will take
757 // and in for example 'paste' listener execCommand() (which fires 'paste') is called
758 // after getClipboardData finishes.
759 // Luckily, it's impossible to immediately fire another 'paste' event we want to handle,
760 // because we only handle there native context menu and menu bar.
761 setTimeout( function() {
762 preventPasteEvent = 0;
763 }, 100 );
764 }
765
766 function preventBeforePasteEventNow() {
767 preventBeforePasteEvent = 1;
768 setTimeout( function() {
769 preventBeforePasteEvent = 0;
770 }, 10 );
771 }
772
773 // Tries to execute any of the paste, cut or copy commands in IE. Returns a
774 // boolean indicating that the operation succeeded.
775 // @param {String} command *LOWER CASED* name of command ('paste', 'cut', 'copy').
776 function execIECommand( command ) {
777 var doc = editor.document,
778 body = doc.getBody(),
779 enabled = false,
780 onExec = function() {
781 enabled = true;
782 };
783
784 // The following seems to be the only reliable way to detect that
785 // clipboard commands are enabled in IE. It will fire the
786 // onpaste/oncut/oncopy events only if the security settings allowed
787 // the command to execute.
788 body.on( command, onExec );
789
790 // IE7: document.execCommand has problem to paste into positioned element.
791 if ( CKEDITOR.env.version > 7 ) {
792 doc.$.execCommand( command );
793 } else {
794 doc.$.selection.createRange().execCommand( command );
795 }
796
797 body.removeListener( command, onExec );
798
799 return enabled;
800 }
801
802 // Cutting off control type element in IE standards breaks the selection entirely. (http://dev.ckeditor.com/ticket/4881)
803 function fixCut() {
804 if ( !CKEDITOR.env.ie || CKEDITOR.env.quirks )
805 return;
806
807 var sel = editor.getSelection(),
808 control, range, dummy;
809
810 if ( ( sel.getType() == CKEDITOR.SELECTION_ELEMENT ) && ( control = sel.getSelectedElement() ) ) {
811 range = sel.getRanges()[ 0 ];
812 dummy = editor.document.createText( '' );
813 dummy.insertBefore( control );
814 range.setStartBefore( dummy );
815 range.setEndAfter( control );
816 sel.selectRanges( [ range ] );
817
818 // Clear up the fix if the paste wasn't succeeded.
819 setTimeout( function() {
820 // Element still online?
821 if ( control.getParent() ) {
822 dummy.remove();
823 sel.selectElement( control );
824 }
825 }, 0 );
826 }
827 }
828
829 // Allow to peek clipboard content by redirecting the
830 // pasting content into a temporary bin and grab the content of it.
831 function getClipboardDataByPastebin( evt, callback ) {
832 var doc = editor.document,
833 editable = editor.editable(),
834 cancel = function( evt ) {
835 evt.cancel();
836 },
837 blurListener;
838
839 // Avoid recursions on 'paste' event or consequent paste too fast. (http://dev.ckeditor.com/ticket/5730)
840 if ( doc.getById( 'cke_pastebin' ) )
841 return;
842
843 var sel = editor.getSelection();
844 var bms = sel.createBookmarks();
845
846 // http://dev.ckeditor.com/ticket/11384. On IE9+ we use native selectionchange (i.e. editor#selectionCheck) to cache the most
847 // recent selection which we then lock on editable blur. See selection.js for more info.
848 // selectionchange fired before getClipboardDataByPastebin() cached selection
849 // before creating bookmark (cached selection will be invalid, because bookmarks modified the DOM),
850 // so we need to fire selectionchange one more time, to store current seleciton.
851 // Selection will be locked when we focus pastebin.
852 if ( CKEDITOR.env.ie )
853 sel.root.fire( 'selectionchange' );
854
855 // Create container to paste into.
856 // For rich content we prefer to use "body" since it holds
857 // the least possibility to be splitted by pasted content, while this may
858 // breaks the text selection on a frame-less editable, "div" would be
859 // the best one in that case.
860 // In another case on old IEs moving the selection into a "body" paste bin causes error panic.
861 // Body can't be also used for Opera which fills it with <br>
862 // what is indistinguishable from pasted <br> (copying <br> in Opera isn't possible,
863 // but it can be copied from other browser).
864 var pastebin = new CKEDITOR.dom.element(
865 ( CKEDITOR.env.webkit || editable.is( 'body' ) ) && !CKEDITOR.env.ie ? 'body' : 'div', doc );
866
867 pastebin.setAttributes( {
868 id: 'cke_pastebin',
869 'data-cke-temp': '1'
870 } );
871
872 var containerOffset = 0,
873 offsetParent,
874 win = doc.getWindow();
875
876 if ( CKEDITOR.env.webkit ) {
877 // It's better to paste close to the real paste destination, so inherited styles
878 // (which Webkits will try to compensate by styling span) differs less from the destination's one.
879 editable.append( pastebin );
880 // Style pastebin like .cke_editable, to minimize differences between origin and destination. (http://dev.ckeditor.com/ticket/9754)
881 pastebin.addClass( 'cke_editable' );
882
883 // Compensate position of offsetParent.
884 if ( !editable.is( 'body' ) ) {
885 // We're not able to get offsetParent from pastebin (body element), so check whether
886 // its parent (editable) is positioned.
887 if ( editable.getComputedStyle( 'position' ) != 'static' )
888 offsetParent = editable;
889 // And if not - safely get offsetParent from editable.
890 else
891 offsetParent = CKEDITOR.dom.element.get( editable.$.offsetParent );
892
893 containerOffset = offsetParent.getDocumentPosition().y;
894 }
895 } else {
896 // Opera and IE doesn't allow to append to html element.
897 editable.getAscendant( CKEDITOR.env.ie ? 'body' : 'html', 1 ).append( pastebin );
898 }
899
900 pastebin.setStyles( {
901 position: 'absolute',
902 // Position the bin at the top (+10 for safety) of viewport to avoid any subsequent document scroll.
903 top: ( win.getScrollPosition().y - containerOffset + 10 ) + 'px',
904 width: '1px',
905 // Caret has to fit in that height, otherwise browsers like Chrome & Opera will scroll window to show it.
906 // Set height equal to viewport's height - 20px (safety gaps), minimum 1px.
907 height: Math.max( 1, win.getViewPaneSize().height - 20 ) + 'px',
908 overflow: 'hidden',
909 // Reset styles that can mess up pastebin position.
910 margin: 0,
911 padding: 0
912 } );
913
914 // Paste fails in Safari when the body tag has 'user-select: none'. (http://dev.ckeditor.com/ticket/12506)
915 if ( CKEDITOR.env.safari )
916 pastebin.setStyles( CKEDITOR.tools.cssVendorPrefix( 'user-select', 'text' ) );
917
918 // Check if the paste bin now establishes new editing host.
919 var isEditingHost = pastebin.getParent().isReadOnly();
920
921 if ( isEditingHost ) {
922 // Hide the paste bin.
923 pastebin.setOpacity( 0 );
924 // And make it editable.
925 pastebin.setAttribute( 'contenteditable', true );
926 }
927 // Transparency is not enough since positioned non-editing host always shows
928 // resize handler, pull it off the screen instead.
929 else {
930 pastebin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-10000px' );
931 }
932
933 editor.on( 'selectionChange', cancel, null, null, 0 );
934
935 // Webkit fill fire blur on editable when moving selection to
936 // pastebin (if body is used). Cancel it because it causes incorrect
937 // selection lock in case of inline editor (http://dev.ckeditor.com/ticket/10644).
938 // The same seems to apply to Firefox (http://dev.ckeditor.com/ticket/10787).
939 if ( CKEDITOR.env.webkit || CKEDITOR.env.gecko )
940 blurListener = editable.once( 'blur', cancel, null, null, -100 );
941
942 // Temporarily move selection to the pastebin.
943 isEditingHost && pastebin.focus();
944 var range = new CKEDITOR.dom.range( pastebin );
945 range.selectNodeContents( pastebin );
946 var selPastebin = range.select();
947
948 // If non-native paste is executed, IE will open security alert and blur editable.
949 // Editable will then lock selection inside itself and after accepting security alert
950 // this selection will be restored. We overwrite stored selection, so it's restored
951 // in pastebin. (http://dev.ckeditor.com/ticket/9552)
952 if ( CKEDITOR.env.ie ) {
953 blurListener = editable.once( 'blur', function() {
954 editor.lockSelection( selPastebin );
955 } );
956 }
957
958 var scrollTop = CKEDITOR.document.getWindow().getScrollPosition().y;
959
960 // Wait a while and grab the pasted contents.
961 setTimeout( function() {
962 // Restore main window's scroll position which could have been changed
963 // by browser in cases described in http://dev.ckeditor.com/ticket/9771.
964 if ( CKEDITOR.env.webkit )
965 CKEDITOR.document.getBody().$.scrollTop = scrollTop;
966
967 // Blur will be fired only on non-native paste. In other case manually remove listener.
968 blurListener && blurListener.removeListener();
969
970 // Restore properly the document focus. (http://dev.ckeditor.com/ticket/8849)
971 if ( CKEDITOR.env.ie )
972 editable.focus();
973
974 // IE7: selection must go before removing pastebin. (http://dev.ckeditor.com/ticket/8691)
975 sel.selectBookmarks( bms );
976 pastebin.remove();
977
978 // Grab the HTML contents.
979 // We need to look for a apple style wrapper on webkit it also adds
980 // a div wrapper if you copy/paste the body of the editor.
981 // Remove hidden div and restore selection.
982 var bogusSpan;
983 if ( CKEDITOR.env.webkit && ( bogusSpan = pastebin.getFirst() ) && ( bogusSpan.is && bogusSpan.hasClass( 'Apple-style-span' ) ) )
984 pastebin = bogusSpan;
985
986 editor.removeListener( 'selectionChange', cancel );
987 callback( pastebin.getHtml() );
988 }, 0 );
989 }
990
991 // Try to get content directly on IE from clipboard, without native event
992 // being fired before. In other words - synthetically get clipboard data, if it's possible.
993 // mainPasteEvent will be fired, so if forced native paste:
994 // * worked, getClipboardDataByPastebin will grab it,
995 // * didn't work, dataValue and dataTransfer will be empty and editor#paste won't be fired.
996 // Clipboard data can be accessed directly only on IEs older than Edge.
997 // On other browsers we should fire beforePaste event and return false.
998 function getClipboardDataDirectly() {
999 if ( clipboard.mainPasteEvent == 'paste' ) {
1000 editor.fire( 'beforePaste', { type: 'auto', method: 'paste' } );
1001 return false;
1002 }
1003
1004 // Prevent IE from pasting at the begining of the document.
1005 editor.focus();
1006
1007 // Command will be handled by 'beforepaste', but as
1008 // execIECommand( 'paste' ) will fire also 'paste' event
1009 // we're canceling it.
1010 preventPasteEventNow();
1011
1012 // http://dev.ckeditor.com/ticket/9247: Lock focus to prevent IE from hiding toolbar for inline editor.
1013 var focusManager = editor.focusManager;
1014 focusManager.lock();
1015
1016 if ( editor.editable().fire( clipboard.mainPasteEvent ) && !execIECommand( 'paste' ) ) {
1017 focusManager.unlock();
1018 return false;
1019 }
1020 focusManager.unlock();
1021
1022 return true;
1023 }
1024
1025 // Listens for some clipboard related keystrokes, so they get customized.
1026 // Needs to be bind to keydown event.
1027 function onKey( event ) {
1028 if ( editor.mode != 'wysiwyg' )
1029 return;
1030
1031 switch ( event.data.keyCode ) {
1032 // Paste
1033 case CKEDITOR.CTRL + 86: // CTRL+V
1034 case CKEDITOR.SHIFT + 45: // SHIFT+INS
1035 var editable = editor.editable();
1036
1037 // Cancel 'paste' event because ctrl+v is for IE handled
1038 // by 'beforepaste'.
1039 preventPasteEventNow();
1040
1041 // Simulate 'beforepaste' event for all browsers using 'paste' as main event.
1042 if ( clipboard.mainPasteEvent == 'paste' ) {
1043 editable.fire( 'beforepaste' );
1044 }
1045
1046 return;
1047
1048 // Cut
1049 case CKEDITOR.CTRL + 88: // CTRL+X
1050 case CKEDITOR.SHIFT + 46: // SHIFT+DEL
1051 // Save Undo snapshot.
1052 editor.fire( 'saveSnapshot' ); // Save before cut
1053 setTimeout( function() {
1054 editor.fire( 'saveSnapshot' ); // Save after cut
1055 }, 50 ); // OSX is slow (http://dev.ckeditor.com/ticket/11416).
1056 }
1057 }
1058
1059 function pasteDataFromClipboard( evt ) {
1060 // Default type is 'auto', but can be changed by beforePaste listeners.
1061 var eventData = {
1062 type: 'auto',
1063 method: 'paste',
1064 dataTransfer: clipboard.initPasteDataTransfer( evt )
1065 };
1066
1067 eventData.dataTransfer.cacheData();
1068
1069 // Fire 'beforePaste' event so clipboard flavor get customized by other plugins.
1070 // If 'beforePaste' is canceled continue executing getClipboardDataByPastebin and then do nothing
1071 // (do not fire 'paste', 'afterPaste' events). This way we can grab all - synthetically
1072 // and natively pasted content and prevent its insertion into editor
1073 // after canceling 'beforePaste' event.
1074 var beforePasteNotCanceled = editor.fire( 'beforePaste', eventData ) !== false;
1075
1076 // Do not use paste bin if the browser let us get HTML or files from dataTranfer.
1077 if ( beforePasteNotCanceled && clipboard.canClipboardApiBeTrusted( eventData.dataTransfer, editor ) ) {
1078 evt.data.preventDefault();
1079 setTimeout( function() {
1080 firePasteEvents( editor, eventData );
1081 }, 0 );
1082 } else {
1083 getClipboardDataByPastebin( evt, function( data ) {
1084 // Clean up.
1085 eventData.dataValue = data.replace( /<span[^>]+data-cke-bookmark[^<]*?<\/span>/ig, '' );
1086
1087 // Fire remaining events (without beforePaste)
1088 beforePasteNotCanceled && firePasteEvents( editor, eventData );
1089 } );
1090 }
1091 }
1092
1093 function setToolbarStates() {
1094 if ( editor.mode != 'wysiwyg' )
1095 return;
1096
1097 var pasteState = stateFromNamedCommand( 'paste' );
1098
1099 editor.getCommand( 'cut' ).setState( stateFromNamedCommand( 'cut' ) );
1100 editor.getCommand( 'copy' ).setState( stateFromNamedCommand( 'copy' ) );
1101 editor.getCommand( 'paste' ).setState( pasteState );
1102 editor.fire( 'pasteState', pasteState );
1103 }
1104
1105 function stateFromNamedCommand( command ) {
1106 if ( inReadOnly && command in { paste: 1, cut: 1 } )
1107 return CKEDITOR.TRISTATE_DISABLED;
1108
1109 if ( command == 'paste' )
1110 return CKEDITOR.TRISTATE_OFF;
1111
1112 // Cut, copy - check if the selection is not empty.
1113 var sel = editor.getSelection(),
1114 ranges = sel.getRanges(),
1115 selectionIsEmpty = sel.getType() == CKEDITOR.SELECTION_NONE || ( ranges.length == 1 && ranges[ 0 ].collapsed );
1116
1117 return selectionIsEmpty ? CKEDITOR.TRISTATE_DISABLED : CKEDITOR.TRISTATE_OFF;
1118 }
1119 }
1120
1121 // Returns:
1122 // * 'htmlifiedtext' if content looks like transformed by browser from plain text.
1123 // See clipboard/paste.html TCs for more info.
1124 // * 'html' if it is not 'htmlifiedtext'.
1125 function recogniseContentType( data ) {
1126 if ( CKEDITOR.env.webkit ) {
1127 // Plain text or ( <div><br></div> and text inside <div> ).
1128 if ( !data.match( /^[^<]*$/g ) && !data.match( /^(<div><br( ?\/)?><\/div>|<div>[^<]*<\/div>)*$/gi ) )
1129 return 'html';
1130 } else if ( CKEDITOR.env.ie ) {
1131 // Text and <br> or ( text and <br> in <p> - paragraphs can be separated by new \r\n ).
1132 if ( !data.match( /^([^<]|<br( ?\/)?>)*$/gi ) && !data.match( /^(<p>([^<]|<br( ?\/)?>)*<\/p>|(\r\n))*$/gi ) )
1133 return 'html';
1134 } else if ( CKEDITOR.env.gecko ) {
1135 // Text or <br>.
1136 if ( !data.match( /^([^<]|<br( ?\/)?>)*$/gi ) )
1137 return 'html';
1138 } else {
1139 return 'html';
1140 }
1141
1142 return 'htmlifiedtext';
1143 }
1144
1145 // This function transforms what browsers produce when
1146 // pasting plain text into editable element (see clipboard/paste.html TCs
1147 // for more info) into correct HTML (similar to that produced by text2Html).
1148 function htmlifiedTextHtmlification( config, data ) {
1149 function repeatParagraphs( repeats ) {
1150 // Repeat blocks floor((n+1)/2) times.
1151 // Even number of repeats - add <br> at the beginning of last <p>.
1152 return CKEDITOR.tools.repeat( '</p><p>', ~~( repeats / 2 ) ) + ( repeats % 2 == 1 ? '<br>' : '' );
1153 }
1154
1155 // Replace adjacent white-spaces (EOLs too - Fx sometimes keeps them) with one space.
1156 data = data.replace( /\s+/g, ' ' )
1157 // Remove spaces from between tags.
1158 .replace( /> +</g, '><' )
1159 // Normalize XHTML syntax and upper cased <br> tags.
1160 .replace( /<br ?\/>/gi, '<br>' );
1161
1162 // IE - lower cased tags.
1163 data = data.replace( /<\/?[A-Z]+>/g, function( match ) {
1164 return match.toLowerCase();
1165 } );
1166
1167 // Don't touch single lines (no <br|p|div>) - nothing to do here.
1168 if ( data.match( /^[^<]$/ ) )
1169 return data;
1170
1171 // Webkit.
1172 if ( CKEDITOR.env.webkit && data.indexOf( '<div>' ) > -1 ) {
1173 // One line break at the beginning - insert <br>
1174 data = data.replace( /^(<div>(<br>|)<\/div>)(?!$|(<div>(<br>|)<\/div>))/g, '<br>' )
1175 // Two or more - reduce number of new lines by one.
1176 .replace( /^(<div>(<br>|)<\/div>){2}(?!$)/g, '<div></div>' );
1177
1178 // Two line breaks create one paragraph in Webkit.
1179 if ( data.match( /<div>(<br>|)<\/div>/ ) ) {
1180 data = '<p>' + data.replace( /(<div>(<br>|)<\/div>)+/g, function( match ) {
1181 return repeatParagraphs( match.split( '</div><div>' ).length + 1 );
1182 } ) + '</p>';
1183 }
1184
1185 // One line break create br.
1186 data = data.replace( /<\/div><div>/g, '<br>' );
1187
1188 // Remove remaining divs.
1189 data = data.replace( /<\/?div>/g, '' );
1190 }
1191
1192 // Opera and Firefox and enterMode != BR.
1193 if ( CKEDITOR.env.gecko && config.enterMode != CKEDITOR.ENTER_BR ) {
1194 // Remove bogus <br> - Fx generates two <brs> for one line break.
1195 // For two line breaks it still produces two <brs>, but it's better to ignore this case than the first one.
1196 if ( CKEDITOR.env.gecko )
1197 data = data.replace( /^<br><br>$/, '<br>' );
1198
1199 // This line satisfy edge case when for Opera we have two line breaks
1200 //data = data.replace( /)
1201
1202 if ( data.indexOf( '<br><br>' ) > -1 ) {
1203 // Two line breaks create one paragraph, three - 2, four - 3, etc.
1204 data = '<p>' + data.replace( /(<br>){2,}/g, function( match ) {
1205 return repeatParagraphs( match.length / 4 );
1206 } ) + '</p>';
1207 }
1208 }
1209
1210 return switchEnterMode( config, data );
1211 }
1212
1213 function filtersFactoryFactory() {
1214 var filters = {};
1215
1216 function setUpTags() {
1217 var tags = {};
1218
1219 for ( var tag in CKEDITOR.dtd ) {
1220 if ( tag.charAt( 0 ) != '$' && tag != 'div' && tag != 'span' ) {
1221 tags[ tag ] = 1;
1222 }
1223 }
1224
1225 return tags;
1226 }
1227
1228 function createSemanticContentFilter() {
1229 var filter = new CKEDITOR.filter();
1230
1231 filter.allow( {
1232 $1: {
1233 elements: setUpTags(),
1234 attributes: true,
1235 styles: false,
1236 classes: false
1237 }
1238 } );
1239
1240 return filter;
1241 }
1242
1243 return {
1244 get: function( type ) {
1245 if ( type == 'plain-text' ) {
1246 // Does this look confusing to you? Did we forget about enter mode?
1247 // It is a trick that let's us creating one filter for edidtor, regardless of its
1248 // activeEnterMode (which as the name indicates can change during runtime).
1249 //
1250 // How does it work?
1251 // The active enter mode is passed to the filter.applyTo method.
1252 // The filter first marks all elements except <br> as disallowed and then tries to remove
1253 // them. However, it cannot remove e.g. a <p> element completely, because it's a basic structural element,
1254 // so it tries to replace it with an element created based on the active enter mode, eventually doing nothing.
1255 //
1256 // Now you can sleep well.
1257 return filters.plainText || ( filters.plainText = new CKEDITOR.filter( 'br' ) );
1258 } else if ( type == 'semantic-content' ) {
1259 return filters.semanticContent || ( filters.semanticContent = createSemanticContentFilter() );
1260 } else if ( type ) {
1261 // Create filter based on rules (string or object).
1262 return new CKEDITOR.filter( type );
1263 }
1264
1265 return null;
1266 }
1267 };
1268 }
1269
1270 function filterContent( editor, data, filter ) {
1271 var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data ),
1272 writer = new CKEDITOR.htmlParser.basicWriter();
1273
1274 filter.applyTo( fragment, true, false, editor.activeEnterMode );
1275 fragment.writeHtml( writer );
1276
1277 return writer.getHtml();
1278 }
1279
1280 function switchEnterMode( config, data ) {
1281 if ( config.enterMode == CKEDITOR.ENTER_BR ) {
1282 data = data.replace( /(<\/p><p>)+/g, function( match ) {
1283 return CKEDITOR.tools.repeat( '<br>', match.length / 7 * 2 );
1284 } ).replace( /<\/?p>/g, '' );
1285 } else if ( config.enterMode == CKEDITOR.ENTER_DIV ) {
1286 data = data.replace( /<(\/)?p>/g, '<$1div>' );
1287 }
1288
1289 return data;
1290 }
1291
1292 function preventDefaultSetDropEffectToNone( evt ) {
1293 evt.data.preventDefault();
1294 evt.data.$.dataTransfer.dropEffect = 'none';
1295 }
1296
1297 function initDragDrop( editor ) {
1298 var clipboard = CKEDITOR.plugins.clipboard;
1299
1300 editor.on( 'contentDom', function() {
1301 var editable = editor.editable(),
1302 dropTarget = CKEDITOR.plugins.clipboard.getDropTarget( editor ),
1303 top = editor.ui.space( 'top' ),
1304 bottom = editor.ui.space( 'bottom' );
1305
1306 // -------------- DRAGOVER TOP & BOTTOM --------------
1307
1308 // Not allowing dragging on toolbar and bottom (http://dev.ckeditor.com/ticket/12613).
1309 clipboard.preventDefaultDropOnElement( top );
1310 clipboard.preventDefaultDropOnElement( bottom );
1311
1312 // -------------- DRAGSTART --------------
1313 // Listed on dragstart to mark internal and cross-editor drag & drop
1314 // and save range and selected HTML.
1315
1316 editable.attachListener( dropTarget, 'dragstart', fireDragEvent );
1317
1318 // Make sure to reset data transfer (in case dragend was not called or was canceled).
1319 editable.attachListener( editor, 'dragstart', clipboard.resetDragDataTransfer, clipboard, null, 1 );
1320
1321 // Create a dataTransfer object and save it globally.
1322 editable.attachListener( editor, 'dragstart', function( evt ) {
1323 clipboard.initDragDataTransfer( evt, editor );
1324 }, null, null, 2 );
1325
1326 editable.attachListener( editor, 'dragstart', function() {
1327 // Save drag range globally for cross editor D&D.
1328 var dragRange = clipboard.dragRange = editor.getSelection().getRanges()[ 0 ];
1329
1330 // Store number of children, so we can later tell if any text node was split on drop. (http://dev.ckeditor.com/ticket/13011, http://dev.ckeditor.com/ticket/13447)
1331 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
1332 clipboard.dragStartContainerChildCount = dragRange ? getContainerChildCount( dragRange.startContainer ) : null;
1333 clipboard.dragEndContainerChildCount = dragRange ? getContainerChildCount( dragRange.endContainer ) : null;
1334 }
1335 }, null, null, 100 );
1336
1337 // -------------- DRAGEND --------------
1338 // Clean up on dragend.
1339
1340 editable.attachListener( dropTarget, 'dragend', fireDragEvent );
1341
1342 // Init data transfer if someone wants to use it in dragend.
1343 editable.attachListener( editor, 'dragend', clipboard.initDragDataTransfer, clipboard, null, 1 );
1344
1345 // When drag & drop is done we need to reset dataTransfer so the future
1346 // external drop will be not recognize as internal.
1347 editable.attachListener( editor, 'dragend', clipboard.resetDragDataTransfer, clipboard, null, 100 );
1348
1349 // -------------- DRAGOVER --------------
1350 // We need to call preventDefault on dragover because otherwise if
1351 // we drop image it will overwrite document.
1352
1353 editable.attachListener( dropTarget, 'dragover', function( evt ) {
1354 // Edge requires this handler to have `preventDefault()` regardless of the situation.
1355 if ( CKEDITOR.env.edge ) {
1356 evt.data.preventDefault();
1357 return;
1358 }
1359
1360 var target = evt.data.getTarget();
1361
1362 // Prevent reloading page when dragging image on empty document (http://dev.ckeditor.com/ticket/12619).
1363 if ( target && target.is && target.is( 'html' ) ) {
1364 evt.data.preventDefault();
1365 return;
1366 }
1367
1368 // If we do not prevent default dragover on IE the file path
1369 // will be loaded and we will lose content. On the other hand
1370 // if we prevent it the cursor will not we shown, so we prevent
1371 // dragover only on IE, on versions which support file API and only
1372 // if the event contains files.
1373 if ( CKEDITOR.env.ie &&
1374 CKEDITOR.plugins.clipboard.isFileApiSupported &&
1375 evt.data.$.dataTransfer.types.contains( 'Files' ) ) {
1376 evt.data.preventDefault();
1377 }
1378 } );
1379
1380 // -------------- DROP --------------
1381
1382 editable.attachListener( dropTarget, 'drop', function( evt ) {
1383 // Do nothing if event was already prevented. (http://dev.ckeditor.com/ticket/13879)
1384 if ( evt.data.$.defaultPrevented ) {
1385 return;
1386 }
1387
1388 // Cancel native drop.
1389 evt.data.preventDefault();
1390
1391 var target = evt.data.getTarget(),
1392 readOnly = target.isReadOnly();
1393
1394 // Do nothing if drop on non editable element (http://dev.ckeditor.com/ticket/13015).
1395 // The <html> tag isn't editable (body is), but we want to allow drop on it
1396 // (so it is possible to drop below editor contents).
1397 if ( readOnly && !( target.type == CKEDITOR.NODE_ELEMENT && target.is( 'html' ) ) ) {
1398 return;
1399 }
1400
1401 // Getting drop position is one of the most complex parts.
1402 var dropRange = clipboard.getRangeAtDropPosition( evt, editor ),
1403 dragRange = clipboard.dragRange;
1404
1405 // Do nothing if it was not possible to get drop range.
1406 if ( !dropRange ) {
1407 return;
1408 }
1409
1410 // Fire drop.
1411 fireDragEvent( evt, dragRange, dropRange );
1412 }, null, null, 9999 );
1413
1414 // Create dataTransfer or get it, if it was created before.
1415 editable.attachListener( editor, 'drop', clipboard.initDragDataTransfer, clipboard, null, 1 );
1416
1417 // Execute drop action, fire paste.
1418 editable.attachListener( editor, 'drop', function( evt ) {
1419 var data = evt.data;
1420
1421 if ( !data ) {
1422 return;
1423 }
1424
1425 // Let user modify drag and drop range.
1426 var dropRange = data.dropRange,
1427 dragRange = data.dragRange,
1428 dataTransfer = data.dataTransfer;
1429
1430 if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_INTERNAL ) {
1431 // Execute drop with a timeout because otherwise selection, after drop,
1432 // on IE is in the drag position, instead of drop position.
1433 setTimeout( function() {
1434 clipboard.internalDrop( dragRange, dropRange, dataTransfer, editor );
1435 }, 0 );
1436 } else if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) {
1437 crossEditorDrop( dragRange, dropRange, dataTransfer );
1438 } else {
1439 externalDrop( dropRange, dataTransfer );
1440 }
1441 }, null, null, 9999 );
1442
1443 // Cross editor drag and drop (drag in one Editor and drop in the other).
1444 function crossEditorDrop( dragRange, dropRange, dataTransfer ) {
1445 // Paste event should be fired before delete contents because otherwise
1446 // Chrome have a problem with drop range (Chrome split the drop
1447 // range container so the offset is bigger then container length).
1448 dropRange.select();
1449 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
1450
1451 // Remove dragged content and make a snapshot.
1452 dataTransfer.sourceEditor.fire( 'saveSnapshot' );
1453
1454 dataTransfer.sourceEditor.editable().extractHtmlFromRange( dragRange );
1455
1456 // Make some selection before saving snapshot, otherwise error will be thrown, because
1457 // there will be no valid selection after content is removed.
1458 dataTransfer.sourceEditor.getSelection().selectRanges( [ dragRange ] );
1459 dataTransfer.sourceEditor.fire( 'saveSnapshot' );
1460 }
1461
1462 // Drop from external source.
1463 function externalDrop( dropRange, dataTransfer ) {
1464 // Paste content into the drop position.
1465 dropRange.select();
1466
1467 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
1468
1469 // Usually we reset DataTranfer on dragend,
1470 // but dragend is called on the same element as dragstart
1471 // so it will not be called on on external drop.
1472 clipboard.resetDragDataTransfer();
1473 }
1474
1475 // Fire drag/drop events (dragstart, dragend, drop).
1476 function fireDragEvent( evt, dragRange, dropRange ) {
1477 var eventData = {
1478 $: evt.data.$,
1479 target: evt.data.getTarget()
1480 };
1481
1482 if ( dragRange ) {
1483 eventData.dragRange = dragRange;
1484 }
1485 if ( dropRange ) {
1486 eventData.dropRange = dropRange;
1487 }
1488
1489 if ( editor.fire( evt.name, eventData ) === false ) {
1490 evt.data.preventDefault();
1491 }
1492 }
1493
1494 function getContainerChildCount( container ) {
1495 if ( container.type != CKEDITOR.NODE_ELEMENT ) {
1496 container = container.getParent();
1497 }
1498
1499 return container.getChildCount();
1500 }
1501 } );
1502 }
1503
1504 /**
1505 * @singleton
1506 * @class CKEDITOR.plugins.clipboard
1507 */
1508 CKEDITOR.plugins.clipboard = {
1509 /**
1510 * True if the environment allows to set data on copy or cut manually. This value is false in IE, because this browser
1511 * shows the security dialog window when the script tries to set clipboard data and on iOS, because custom data is
1512 * not saved to clipboard there.
1513 *
1514 * @since 4.5
1515 * @readonly
1516 * @property {Boolean}
1517 */
1518 isCustomCopyCutSupported: !CKEDITOR.env.ie && !CKEDITOR.env.iOS,
1519
1520 /**
1521 * True if the environment supports MIME types and custom data types in dataTransfer/cliboardData getData/setData methods.
1522 *
1523 * @since 4.5
1524 * @readonly
1525 * @property {Boolean}
1526 */
1527 isCustomDataTypesSupported: !CKEDITOR.env.ie,
1528
1529 /**
1530 * True if the environment supports File API.
1531 *
1532 * @since 4.5
1533 * @readonly
1534 * @property {Boolean}
1535 */
1536 isFileApiSupported: !CKEDITOR.env.ie || CKEDITOR.env.version > 9,
1537
1538 /**
1539 * Main native paste event editable should listen to.
1540 *
1541 * **Note:** Safari does not like the {@link CKEDITOR.editor#beforePaste} event &mdash; it sometimes does not
1542 * handle <kbd>Ctrl+C</kbd> properly. This is probably caused by some race condition between events.
1543 * Chrome, Firefox and Edge work well with both events, so it is better to use {@link CKEDITOR.editor#paste}
1544 * which will handle pasting from e.g. browsers' menu bars.
1545 * IE7/8 does not like the {@link CKEDITOR.editor#paste} event for which it is throwing random errors.
1546 *
1547 * @since 4.5
1548 * @readonly
1549 * @property {String}
1550 */
1551 mainPasteEvent: ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ? 'beforepaste' : 'paste',
1552
1553 /**
1554 * Returns `true` if it is expected that a browser provides HTML data through the Clipboard API.
1555 * If not, this method returns `false` and as a result CKEditor will use the paste bin. Read more in
1556 * the [Clipboard Integration](http://docs.ckeditor.com/#!/guide/dev_clipboard-section-clipboard-api) guide.
1557 *
1558 * @since 4.5.2
1559 * @returns {Boolean}
1560 */
1561 canClipboardApiBeTrusted: function( dataTransfer, editor ) {
1562 // If it's an internal or cross-editor data transfer, then it means that custom cut/copy/paste support works
1563 // and that the data were put manually on the data transfer so we can be sure that it's available.
1564 if ( dataTransfer.getTransferType( editor ) != CKEDITOR.DATA_TRANSFER_EXTERNAL ) {
1565 return true;
1566 }
1567
1568 // In Chrome we can trust Clipboard API, with the exception of Chrome on Android (in both - mobile and desktop modes), where
1569 // clipboard API is not available so we need to check it (http://dev.ckeditor.com/ticket/13187).
1570 if ( CKEDITOR.env.chrome && !dataTransfer.isEmpty() ) {
1571 return true;
1572 }
1573
1574 // Because of a Firefox bug HTML data are not available in some cases (e.g. paste from Word), in such cases we
1575 // need to use the pastebin (http://dev.ckeditor.com/ticket/13528, https://bugzilla.mozilla.org/show_bug.cgi?id=1183686).
1576 if ( CKEDITOR.env.gecko && ( dataTransfer.getData( 'text/html' ) || dataTransfer.getFilesCount() ) ) {
1577 return true;
1578 }
1579
1580 // Safari fixed clipboard in 10.1 (https://bugs.webkit.org/show_bug.cgi?id=19893) (http://dev.ckeditor.com/ticket/16982).
1581 // However iOS version still doesn't work well enough (https://bugs.webkit.org/show_bug.cgi?id=19893#c34).
1582 if ( CKEDITOR.env.safari && CKEDITOR.env.version >= 603 && !CKEDITOR.env.iOS ) {
1583 return true;
1584 }
1585
1586 // In older Safari and IE HTML data is not available though the Clipboard API.
1587 // In Edge things are a bit messy at the moment -
1588 // https://connect.microsoft.com/IE/feedback/details/1572456/edge-clipboard-api-text-html-content-messed-up-in-event-clipboarddata
1589 // It is safer to use the paste bin in unknown cases.
1590 return false;
1591 },
1592
1593 /**
1594 * Returns the element that should be used as the target for the drop event.
1595 *
1596 * @since 4.5
1597 * @param {CKEDITOR.editor} editor The editor instance.
1598 * @returns {CKEDITOR.dom.domObject} the element that should be used as the target for the drop event.
1599 */
1600 getDropTarget: function( editor ) {
1601 var editable = editor.editable();
1602
1603 // http://dev.ckeditor.com/ticket/11123 Firefox needs to listen on document, because otherwise event won't be fired.
1604 // http://dev.ckeditor.com/ticket/11086 IE8 cannot listen on document.
1605 if ( ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) || editable.isInline() ) {
1606 return editable;
1607 } else {
1608 return editor.document;
1609 }
1610 },
1611
1612 /**
1613 * IE 8 & 9 split text node on drop so the first node contains the
1614 * text before the drop position and the second contains the rest. If you
1615 * drag the content from the same node you will be not be able to get
1616 * it (the range becomes invalid), so you need to join them back.
1617 *
1618 * Note that the first node in IE 8 & 9 is the original node object
1619 * but with shortened content.
1620 *
1621 * Before:
1622 * --- Text Node A ----------------------------------
1623 * /\
1624 * Drag position
1625 *
1626 * After (IE 8 & 9):
1627 * --- Text Node A ----- --- Text Node B -----------
1628 * /\ /\
1629 * Drop position Drag position
1630 * (invalid)
1631 *
1632 * After (other browsers):
1633 * --- Text Node A ----------------------------------
1634 * /\ /\
1635 * Drop position Drag position
1636 *
1637 * **Note:** This function is in the public scope for tests usage only.
1638 *
1639 * @since 4.5
1640 * @private
1641 * @param {CKEDITOR.dom.range} dragRange The drag range.
1642 * @param {CKEDITOR.dom.range} dropRange The drop range.
1643 * @param {Number} preDragStartContainerChildCount The number of children of the drag range start container before the drop.
1644 * @param {Number} preDragEndContainerChildCount The number of children of the drag range end container before the drop.
1645 */
1646 fixSplitNodesAfterDrop: function( dragRange, dropRange, preDragStartContainerChildCount, preDragEndContainerChildCount ) {
1647 var dropContainer = dropRange.startContainer;
1648
1649 if (
1650 typeof preDragEndContainerChildCount != 'number' ||
1651 typeof preDragStartContainerChildCount != 'number'
1652 ) {
1653 return;
1654 }
1655
1656 // We are only concerned about ranges anchored in elements.
1657 if ( dropContainer.type != CKEDITOR.NODE_ELEMENT ) {
1658 return;
1659 }
1660
1661 if ( handleContainer( dragRange.startContainer, dropContainer, preDragStartContainerChildCount ) ) {
1662 return;
1663 }
1664
1665 if ( handleContainer( dragRange.endContainer, dropContainer, preDragEndContainerChildCount ) ) {
1666 return;
1667 }
1668
1669 function handleContainer( dragContainer, dropContainer, preChildCount ) {
1670 var dragElement = dragContainer;
1671 if ( dragElement.type == CKEDITOR.NODE_TEXT ) {
1672 dragElement = dragContainer.getParent();
1673 }
1674
1675 if ( dragElement.equals( dropContainer ) && preChildCount != dropContainer.getChildCount() ) {
1676 applyFix( dropRange );
1677 return true;
1678 }
1679 }
1680
1681 function applyFix( dropRange ) {
1682 var nodeBefore = dropRange.startContainer.getChild( dropRange.startOffset - 1 ),
1683 nodeAfter = dropRange.startContainer.getChild( dropRange.startOffset );
1684
1685 if (
1686 nodeBefore && nodeBefore.type == CKEDITOR.NODE_TEXT &&
1687 nodeAfter && nodeAfter.type == CKEDITOR.NODE_TEXT
1688 ) {
1689 var offset = nodeBefore.getLength();
1690
1691 nodeBefore.setText( nodeBefore.getText() + nodeAfter.getText() );
1692 nodeAfter.remove();
1693
1694 dropRange.setStart( nodeBefore, offset );
1695 dropRange.collapse( true );
1696 }
1697 }
1698 },
1699
1700 /**
1701 * Checks whether turning the drag range into bookmarks will invalidate the drop range.
1702 * This usually happens when the drop range shares the container with the drag range and is
1703 * located after the drag range, but there are countless edge cases.
1704 *
1705 * This function is stricly related to {@link #internalDrop} which toggles
1706 * order in which it creates bookmarks for both ranges based on a value returned
1707 * by this method. In some cases this method returns a value which is not necessarily
1708 * true in terms of what it was meant to check, but it is convenient, because
1709 * we know how it is interpreted in {@link #internalDrop}, so the correct
1710 * behavior of the entire algorithm is assured.
1711 *
1712 * **Note:** This function is in the public scope for tests usage only.
1713 *
1714 * @since 4.5
1715 * @private
1716 * @param {CKEDITOR.dom.range} dragRange The first range to compare.
1717 * @param {CKEDITOR.dom.range} dropRange The second range to compare.
1718 * @returns {Boolean} `true` if the first range is before the second range.
1719 */
1720 isDropRangeAffectedByDragRange: function( dragRange, dropRange ) {
1721 var dropContainer = dropRange.startContainer,
1722 dropOffset = dropRange.endOffset;
1723
1724 // Both containers are the same and drop offset is at the same position or later.
1725 // " A L] A " " M A "
1726 // ^ ^
1727 if ( dragRange.endContainer.equals( dropContainer ) && dragRange.endOffset <= dropOffset ) {
1728 return true;
1729 }
1730
1731 // Bookmark for drag start container will mess up with offsets.
1732 // " O [L A " " M A "
1733 // ^ ^
1734 if (
1735 dragRange.startContainer.getParent().equals( dropContainer ) &&
1736 dragRange.startContainer.getIndex() < dropOffset
1737 ) {
1738 return true;
1739 }
1740
1741 // Bookmark for drag end container will mess up with offsets.
1742 // " O] L A " " M A "
1743 // ^ ^
1744 if (
1745 dragRange.endContainer.getParent().equals( dropContainer ) &&
1746 dragRange.endContainer.getIndex() < dropOffset
1747 ) {
1748 return true;
1749 }
1750
1751 return false;
1752 },
1753
1754 /**
1755 * Internal drag and drop (drag and drop in the same editor instance).
1756 *
1757 * **Note:** This function is in the public scope for tests usage only.
1758 *
1759 * @since 4.5
1760 * @private
1761 * @param {CKEDITOR.dom.range} dragRange The first range to compare.
1762 * @param {CKEDITOR.dom.range} dropRange The second range to compare.
1763 * @param {CKEDITOR.plugins.clipboard.dataTransfer} dataTransfer
1764 * @param {CKEDITOR.editor} editor
1765 */
1766 internalDrop: function( dragRange, dropRange, dataTransfer, editor ) {
1767 var clipboard = CKEDITOR.plugins.clipboard,
1768 editable = editor.editable(),
1769 dragBookmark, dropBookmark, isDropRangeAffected;
1770
1771 // Save and lock snapshot so there will be only
1772 // one snapshot for both remove and insert content.
1773 editor.fire( 'saveSnapshot' );
1774 editor.fire( 'lockSnapshot', { dontUpdate: 1 } );
1775
1776 if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
1777 this.fixSplitNodesAfterDrop(
1778 dragRange,
1779 dropRange,
1780 clipboard.dragStartContainerChildCount,
1781 clipboard.dragEndContainerChildCount
1782 );
1783 }
1784
1785 // Because we manipulate multiple ranges we need to do it carefully,
1786 // changing one range (event creating a bookmark) may make other invalid.
1787 // We need to change ranges into bookmarks so we can manipulate them easily in the future.
1788 // We can change the range which is later in the text before we change the preceding range.
1789 // We call isDropRangeAffectedByDragRange to test the order of ranges.
1790 isDropRangeAffected = this.isDropRangeAffectedByDragRange( dragRange, dropRange );
1791 if ( !isDropRangeAffected ) {
1792 dragBookmark = dragRange.createBookmark( false );
1793 }
1794 dropBookmark = dropRange.clone().createBookmark( false );
1795 if ( isDropRangeAffected ) {
1796 dragBookmark = dragRange.createBookmark( false );
1797 }
1798
1799 // Check if drop range is inside range.
1800 // This is an edge case when we drop something on editable's margin/padding.
1801 // That space is not treated as a part of the range we drag, so it is possible to drop there.
1802 // When we drop, browser tries to find closest drop position and it finds it inside drag range. (http://dev.ckeditor.com/ticket/13453)
1803 var startNode = dragBookmark.startNode,
1804 endNode = dragBookmark.endNode,
1805 dropNode = dropBookmark.startNode,
1806 dropInsideDragRange =
1807 // Must check endNode because dragRange could be collapsed in some edge cases (simulated DnD).
1808 endNode &&
1809 ( startNode.getPosition( dropNode ) & CKEDITOR.POSITION_PRECEDING ) &&
1810 ( endNode.getPosition( dropNode ) & CKEDITOR.POSITION_FOLLOWING );
1811
1812 // If the drop range happens to be inside drag range change it's position to the beginning of the drag range.
1813 if ( dropInsideDragRange ) {
1814 // We only change position of bookmark span that is connected with dropBookmark.
1815 // dropRange will be overwritten and set to the dropBookmark later.
1816 dropNode.insertBefore( startNode );
1817 }
1818
1819 // No we can safely delete content for the drag range...
1820 dragRange = editor.createRange();
1821 dragRange.moveToBookmark( dragBookmark );
1822 editable.extractHtmlFromRange( dragRange, 1 );
1823
1824 // ...and paste content into the drop position.
1825 dropRange = editor.createRange();
1826 dropRange.moveToBookmark( dropBookmark );
1827
1828 // We do not select drop range, because of may be in the place we can not set the selection
1829 // (e.g. between blocks, in case of block widget D&D). We put range to the paste event instead.
1830 firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop', range: dropRange }, 1 );
1831
1832 editor.fire( 'unlockSnapshot' );
1833 },
1834
1835 /**
1836 * Gets the range from the `drop` event.
1837 *
1838 * @since 4.5
1839 * @param {Object} domEvent A native DOM drop event object.
1840 * @param {CKEDITOR.editor} editor The source editor instance.
1841 * @returns {CKEDITOR.dom.range} range at drop position.
1842 */
1843 getRangeAtDropPosition: function( dropEvt, editor ) {
1844 var $evt = dropEvt.data.$,
1845 x = $evt.clientX,
1846 y = $evt.clientY,
1847 $range,
1848 defaultRange = editor.getSelection( true ).getRanges()[ 0 ],
1849 range = editor.createRange();
1850
1851 // Make testing possible.
1852 if ( dropEvt.data.testRange )
1853 return dropEvt.data.testRange;
1854
1855 // Webkits.
1856 if ( document.caretRangeFromPoint && editor.document.$.caretRangeFromPoint( x, y ) ) {
1857 $range = editor.document.$.caretRangeFromPoint( x, y );
1858 range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );
1859 range.collapse( true );
1860 }
1861 // FF.
1862 else if ( $evt.rangeParent ) {
1863 range.setStart( CKEDITOR.dom.node( $evt.rangeParent ), $evt.rangeOffset );
1864 range.collapse( true );
1865 }
1866 // IEs 9+.
1867 // We check if editable is focused to make sure that it's an internal DnD. External DnD must use the second
1868 // mechanism because of http://dev.ckeditor.com/ticket/13472#comment:6.
1869 else if ( CKEDITOR.env.ie && CKEDITOR.env.version > 8 && defaultRange && editor.editable().hasFocus ) {
1870 // On IE 9+ range by default is where we expected it.
1871 // defaultRange may be undefined if dragover was canceled (file drop).
1872 return defaultRange;
1873 }
1874 // IE 8 and all IEs if !defaultRange or external DnD.
1875 else if ( document.body.createTextRange ) {
1876 // To use this method we need a focus (which may be somewhere else in case of external drop).
1877 editor.focus();
1878
1879 $range = editor.document.getBody().$.createTextRange();
1880 try {
1881 var sucess = false;
1882
1883 // If user drop between text line IEs moveToPoint throws exception:
1884 //
1885 // Lorem ipsum pulvinar purus et euismod
1886 //
1887 // dolor sit amet,| consectetur adipiscing
1888 // *
1889 // vestibulum tincidunt augue eget tempus.
1890 //
1891 // * - drop position
1892 // | - expected cursor position
1893 //
1894 // So we try to call moveToPoint with +-1px up to +-20px above or
1895 // below original drop position to find nearest good drop position.
1896 for ( var i = 0; i < 20 && !sucess; i++ ) {
1897 if ( !sucess ) {
1898 try {
1899 $range.moveToPoint( x, y - i );
1900 sucess = true;
1901 } catch ( err ) {
1902 }
1903 }
1904 if ( !sucess ) {
1905 try {
1906 $range.moveToPoint( x, y + i );
1907 sucess = true;
1908 } catch ( err ) {
1909 }
1910 }
1911 }
1912
1913 if ( sucess ) {
1914 var id = 'cke-temp-' + ( new Date() ).getTime();
1915 $range.pasteHTML( '<span id="' + id + '">\u200b</span>' );
1916
1917 var span = editor.document.getById( id );
1918 range.moveToPosition( span, CKEDITOR.POSITION_BEFORE_START );
1919 span.remove();
1920 } else {
1921 // If the fist method does not succeed we might be next to
1922 // the short element (like header):
1923 //
1924 // Lorem ipsum pulvinar purus et euismod.
1925 //
1926 //
1927 // SOME HEADER| *
1928 //
1929 //
1930 // vestibulum tincidunt augue eget tempus.
1931 //
1932 // * - drop position
1933 // | - expected cursor position
1934 //
1935 // In such situation elementFromPoint returns proper element. Using getClientRect
1936 // it is possible to check if the cursor should be at the beginning or at the end
1937 // of paragraph.
1938 var $element = editor.document.$.elementFromPoint( x, y ),
1939 element = new CKEDITOR.dom.element( $element ),
1940 rect;
1941
1942 if ( !element.equals( editor.editable() ) && element.getName() != 'html' ) {
1943 rect = element.getClientRect();
1944
1945 if ( x < rect.left ) {
1946 range.setStartAt( element, CKEDITOR.POSITION_AFTER_START );
1947 range.collapse( true );
1948 } else {
1949 range.setStartAt( element, CKEDITOR.POSITION_BEFORE_END );
1950 range.collapse( true );
1951 }
1952 }
1953 // If drop happens on no element elementFromPoint returns html or body.
1954 //
1955 // * |Lorem ipsum pulvinar purus et euismod.
1956 //
1957 // vestibulum tincidunt augue eget tempus.
1958 //
1959 // * - drop position
1960 // | - expected cursor position
1961 //
1962 // In such case we can try to use default selection. If startContainer is not
1963 // 'editable' element it is probably proper selection.
1964 else if ( defaultRange && defaultRange.startContainer &&
1965 !defaultRange.startContainer.equals( editor.editable() ) ) {
1966 return defaultRange;
1967
1968 // Otherwise we can not find any drop position and we have to return null
1969 // and cancel drop event.
1970 } else {
1971 return null;
1972 }
1973
1974 }
1975 } catch ( err ) {
1976 return null;
1977 }
1978 } else {
1979 return null;
1980 }
1981
1982 return range;
1983 },
1984
1985 /**
1986 * This function tries to link the `evt.data.dataTransfer` property of the {@link CKEDITOR.editor#dragstart},
1987 * {@link CKEDITOR.editor#dragend} and {@link CKEDITOR.editor#drop} events to a single
1988 * {@link CKEDITOR.plugins.clipboard.dataTransfer} object.
1989 *
1990 * This method is automatically used by the core of the drag and drop functionality and
1991 * usually does not have to be called manually when using the drag and drop events.
1992 *
1993 * This method behaves differently depending on whether the drag and drop events were fired
1994 * artificially (to represent a non-native drag and drop) or whether they were caused by the native drag and drop.
1995 *
1996 * If the native event is not available, then it will create a new {@link CKEDITOR.plugins.clipboard.dataTransfer}
1997 * instance (if it does not exist already) and will link it to this and all following event objects until
1998 * the {@link #resetDragDataTransfer} method is called. It means that all three drag and drop events must be fired
1999 * in order to ensure that the data transfer is bound correctly.
2000 *
2001 * If the native event is available, then the {@link CKEDITOR.plugins.clipboard.dataTransfer} is identified
2002 * by its ID and a new instance is assigned to the `evt.data.dataTransfer` only if the ID changed or
2003 * the {@link #resetDragDataTransfer} method was called.
2004 *
2005 * @since 4.5
2006 * @param {CKEDITOR.dom.event} [evt] A drop event object.
2007 * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
2008 */
2009 initDragDataTransfer: function( evt, sourceEditor ) {
2010 // Create a new dataTransfer object based on the drop event.
2011 // If this event was used on dragstart to create dataTransfer
2012 // both dataTransfer objects will have the same id.
2013 var nativeDataTransfer = evt.data.$ ? evt.data.$.dataTransfer : null,
2014 dataTransfer = new this.dataTransfer( nativeDataTransfer, sourceEditor );
2015
2016 if ( !nativeDataTransfer ) {
2017 // No native event.
2018 if ( this.dragData ) {
2019 dataTransfer = this.dragData;
2020 } else {
2021 this.dragData = dataTransfer;
2022 }
2023 } else {
2024 // Native event. If there is the same id we will replace dataTransfer with the one
2025 // created on drag, because it contains drag editor, drag content and so on.
2026 // Otherwise (in case of drag from external source) we save new object to
2027 // the global clipboard.dragData.
2028 if ( this.dragData && dataTransfer.id == this.dragData.id ) {
2029 dataTransfer = this.dragData;
2030 } else {
2031 this.dragData = dataTransfer;
2032 }
2033 }
2034
2035 evt.data.dataTransfer = dataTransfer;
2036 },
2037
2038 /**
2039 * Removes the global {@link #dragData} so the next call to {@link #initDragDataTransfer}
2040 * always creates a new instance of {@link CKEDITOR.plugins.clipboard.dataTransfer}.
2041 *
2042 * @since 4.5
2043 */
2044 resetDragDataTransfer: function() {
2045 this.dragData = null;
2046 },
2047
2048 /**
2049 * Global object storing the data transfer of the current drag and drop operation.
2050 * Do not use it directly, use {@link #initDragDataTransfer} and {@link #resetDragDataTransfer}.
2051 *
2052 * Note: This object is global (meaning that it is not related to a single editor instance)
2053 * in order to handle drag and drop from one editor into another.
2054 *
2055 * @since 4.5
2056 * @private
2057 * @property {CKEDITOR.plugins.clipboard.dataTransfer} dragData
2058 */
2059
2060 /**
2061 * Range object to save the drag range and remove its content after the drop.
2062 *
2063 * @since 4.5
2064 * @private
2065 * @property {CKEDITOR.dom.range} dragRange
2066 */
2067
2068 /**
2069 * Initializes and links data transfer objects based on the paste event. If the data
2070 * transfer object was already initialized on this event, the function will
2071 * return that object. In IE it is not possible to link copy/cut and paste events
2072 * so the method always returns a new object. The same happens if there is no paste event
2073 * passed to the method.
2074 *
2075 * @since 4.5
2076 * @param {CKEDITOR.dom.event} [evt] A paste event object.
2077 * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
2078 * @returns {CKEDITOR.plugins.clipboard.dataTransfer} The data transfer object.
2079 */
2080 initPasteDataTransfer: function( evt, sourceEditor ) {
2081 if ( !this.isCustomCopyCutSupported ) {
2082 // Edge does not support custom copy/cut, but it have some useful data in the clipboardData (http://dev.ckeditor.com/ticket/13755).
2083 return new this.dataTransfer( ( CKEDITOR.env.edge && evt && evt.data.$ && evt.data.$.clipboardData ) || null, sourceEditor );
2084 } else if ( evt && evt.data && evt.data.$ ) {
2085 var dataTransfer = new this.dataTransfer( evt.data.$.clipboardData, sourceEditor );
2086
2087 if ( this.copyCutData && dataTransfer.id == this.copyCutData.id ) {
2088 dataTransfer = this.copyCutData;
2089 dataTransfer.$ = evt.data.$.clipboardData;
2090 } else {
2091 this.copyCutData = dataTransfer;
2092 }
2093
2094 return dataTransfer;
2095 } else {
2096 return new this.dataTransfer( null, sourceEditor );
2097 }
2098 },
2099
2100 /**
2101 * Prevents dropping on the specified element.
2102 *
2103 * @since 4.5
2104 * @param {CKEDITOR.dom.element} element The element on which dropping should be disabled.
2105 */
2106 preventDefaultDropOnElement: function( element ) {
2107 element && element.on( 'dragover', preventDefaultSetDropEffectToNone );
2108 }
2109 };
2110
2111 // Data type used to link drag and drop events.
2112 //
2113 // In IE URL data type is buggie and there is no way to mark drag & drop without
2114 // modifying text data (which would be displayed if user drop content to the textarea)
2115 // so we just read dragged text.
2116 //
2117 // In Chrome and Firefox we can use custom data types.
2118 var clipboardIdDataType = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ? 'cke/id' : 'Text';
2119 /**
2120 * Facade for the native `dataTransfer`/`clipboadData` object to hide all differences
2121 * between browsers.
2122 *
2123 * @since 4.5
2124 * @class CKEDITOR.plugins.clipboard.dataTransfer
2125 * @constructor Creates a class instance.
2126 * @param {Object} [nativeDataTransfer] A native data transfer object.
2127 * @param {CKEDITOR.editor} [editor] The source editor instance. If the editor is defined, dataValue will
2128 * be created based on the editor content and the type will be 'html'.
2129 */
2130 CKEDITOR.plugins.clipboard.dataTransfer = function( nativeDataTransfer, editor ) {
2131 if ( nativeDataTransfer ) {
2132 this.$ = nativeDataTransfer;
2133 }
2134
2135 this._ = {
2136 metaRegExp: /^<meta.*?>/i,
2137 bodyRegExp: /<body(?:[\s\S]*?)>([\s\S]*)<\/body>/i,
2138 fragmentRegExp: /<!--(?:Start|End)Fragment-->/g,
2139
2140 data: {},
2141 files: [],
2142
2143 normalizeType: function( type ) {
2144 type = type.toLowerCase();
2145
2146 if ( type == 'text' || type == 'text/plain' ) {
2147 return 'Text'; // IE support only Text and URL;
2148 } else if ( type == 'url' ) {
2149 return 'URL'; // IE support only Text and URL;
2150 } else {
2151 return type;
2152 }
2153 }
2154 };
2155
2156 // Check if ID is already created.
2157 this.id = this.getData( clipboardIdDataType );
2158
2159 // If there is no ID we need to create it. Different browsers needs different ID.
2160 if ( !this.id ) {
2161 if ( clipboardIdDataType == 'Text' ) {
2162 // For IE10+ only Text data type is supported and we have to compare dragged
2163 // and dropped text. If the ID is not set it means that empty string was dragged
2164 // (ex. image with no alt). We change null to empty string.
2165 this.id = '';
2166 } else {
2167 // String for custom data type.
2168 this.id = 'cke-' + CKEDITOR.tools.getUniqueId();
2169 }
2170 }
2171
2172 // In IE10+ we can not use any data type besides text, so we do not call setData.
2173 if ( clipboardIdDataType != 'Text' ) {
2174 // Try to set ID so it will be passed from the drag to the drop event.
2175 // On some browsers with some event it is not possible to setData so we
2176 // need to catch exceptions.
2177 try {
2178 this.$.setData( clipboardIdDataType, this.id );
2179 } catch ( err ) {}
2180 }
2181
2182 if ( editor ) {
2183 this.sourceEditor = editor;
2184
2185 this.setData( 'text/html', editor.getSelectedHtml( 1 ) );
2186
2187 // Without setData( 'text', ... ) on dragstart there is no drop event in Safari.
2188 // Also 'text' data is empty as drop to the textarea does not work if we do not put there text.
2189 if ( clipboardIdDataType != 'Text' && !this.getData( 'text/plain' ) ) {
2190 this.setData( 'text/plain', editor.getSelection().getSelectedText() );
2191 }
2192 }
2193
2194 /**
2195 * Data transfer ID used to bind all dataTransfer
2196 * objects based on the same event (e.g. in drag and drop events).
2197 *
2198 * @readonly
2199 * @property {String} id
2200 */
2201
2202 /**
2203 * A native DOM event object.
2204 *
2205 * @readonly
2206 * @property {Object} $
2207 */
2208
2209 /**
2210 * Source editor &mdash; the editor where the drag starts.
2211 * Might be undefined if the drag starts outside the editor (e.g. when dropping files to the editor).
2212 *
2213 * @readonly
2214 * @property {CKEDITOR.editor} sourceEditor
2215 */
2216
2217 /**
2218 * Private properties and methods.
2219 *
2220 * @private
2221 * @property {Object} _
2222 */
2223 };
2224
2225 /**
2226 * Data transfer operation (drag and drop or copy and paste) started and ended in the same
2227 * editor instance.
2228 *
2229 * @since 4.5
2230 * @readonly
2231 * @property {Number} [=1]
2232 * @member CKEDITOR
2233 */
2234 CKEDITOR.DATA_TRANSFER_INTERNAL = 1;
2235
2236 /**
2237 * Data transfer operation (drag and drop or copy and paste) started in one editor
2238 * instance and ended in another.
2239 *
2240 * @since 4.5
2241 * @readonly
2242 * @property {Number} [=2]
2243 * @member CKEDITOR
2244 */
2245 CKEDITOR.DATA_TRANSFER_CROSS_EDITORS = 2;
2246
2247 /**
2248 * Data transfer operation (drag and drop or copy and paste) started outside of the editor.
2249 * The source of the data may be a textarea, HTML, another application, etc.
2250 *
2251 * @since 4.5
2252 * @readonly
2253 * @property {Number} [=3]
2254 * @member CKEDITOR
2255 */
2256 CKEDITOR.DATA_TRANSFER_EXTERNAL = 3;
2257
2258 CKEDITOR.plugins.clipboard.dataTransfer.prototype = {
2259 /**
2260 * Facade for the native `getData` method.
2261 *
2262 * @param {String} type The type of data to retrieve.
2263 * @param {Boolean} [getNative=false] Indicates if the whole, original content of the dataTransfer should be returned.
2264 * Introduced in CKEditor 4.7.0.
2265 * @returns {String} type Stored data for the given type or an empty string if the data for that type does not exist.
2266 */
2267 getData: function( type, getNative ) {
2268 function isEmpty( data ) {
2269 return data === undefined || data === null || data === '';
2270 }
2271
2272 function filterUnwantedCharacters( data ) {
2273 if ( typeof data !== 'string' ) {
2274 return data;
2275 }
2276
2277 var htmlEnd = data.indexOf( '</html>' );
2278
2279 if ( htmlEnd !== -1 ) {
2280 // Just cut everything after `</html>`, so everything after htmlEnd index + length of `</html>`.
2281 // Required to workaround bug: https://bugs.chromium.org/p/chromium/issues/detail?id=696978
2282 return data.substring( 0, htmlEnd + 7 );
2283 }
2284
2285 return data;
2286 }
2287
2288 type = this._.normalizeType( type );
2289
2290 var data = this._.data[ type ],
2291 result;
2292
2293 if ( isEmpty( data ) ) {
2294 try {
2295 data = this.$.getData( type );
2296 } catch ( e ) {}
2297 }
2298
2299 if ( isEmpty( data ) ) {
2300 data = '';
2301 }
2302
2303 // Some browsers add <meta http-equiv="content-type" content="text/html; charset=utf-8"> at the begging of the HTML data
2304 // or surround it with <html><head>...</head><body>(some content)<!--StartFragment--> and <!--EndFragment-->(some content)</body></html>
2305 // This code removes meta tags and returns only the contents of the <body> element if found. Note that
2306 // some significant content may be placed outside Start/EndFragment comments so it's kept.
2307 //
2308 // See http://dev.ckeditor.com/ticket/13583 for more details.
2309 // Additionally http://dev.ckeditor.com/ticket/16847 adds a flag allowing to get the whole, original content.
2310 if ( type == 'text/html' && !getNative ) {
2311 data = data.replace( this._.metaRegExp, '' );
2312
2313 // Keep only contents of the <body> element
2314 result = this._.bodyRegExp.exec( data );
2315 if ( result && result.length ) {
2316 data = result[ 1 ];
2317
2318 // Remove also comments.
2319 data = data.replace( this._.fragmentRegExp, '' );
2320 }
2321 }
2322 // Firefox on Linux put files paths as a text/plain data if there are files
2323 // in the dataTransfer object. We need to hide it, because files should be
2324 // handled on paste only if dataValue is empty.
2325 else if ( type == 'Text' && CKEDITOR.env.gecko && this.getFilesCount() &&
2326 data.substring( 0, 7 ) == 'file://' ) {
2327 data = '';
2328 }
2329
2330 return filterUnwantedCharacters( data );
2331 },
2332
2333 /**
2334 * Facade for the native `setData` method.
2335 *
2336 * @param {String} type The type of data to retrieve.
2337 * @param {String} value The data to add.
2338 */
2339 setData: function( type, value ) {
2340 type = this._.normalizeType( type );
2341
2342 this._.data[ type ] = value;
2343
2344 // There is "Unexpected call to method or property access." error if you try
2345 // to set data of unsupported type on IE.
2346 if ( !CKEDITOR.plugins.clipboard.isCustomDataTypesSupported && type != 'URL' && type != 'Text' ) {
2347 return;
2348 }
2349
2350 // If we use the text type to bind the ID, then if someone tries to set the text, we must also
2351 // update ID accordingly. http://dev.ckeditor.com/ticket/13468.
2352 if ( clipboardIdDataType == 'Text' && type == 'Text' ) {
2353 this.id = value;
2354 }
2355
2356 try {
2357 this.$.setData( type, value );
2358 } catch ( e ) {}
2359 },
2360
2361 /**
2362 * Gets the data transfer type.
2363 *
2364 * @param {CKEDITOR.editor} targetEditor The drop/paste target editor instance.
2365 * @returns {Number} Possible values: {@link CKEDITOR#DATA_TRANSFER_INTERNAL},
2366 * {@link CKEDITOR#DATA_TRANSFER_CROSS_EDITORS}, {@link CKEDITOR#DATA_TRANSFER_EXTERNAL}.
2367 */
2368 getTransferType: function( targetEditor ) {
2369 if ( !this.sourceEditor ) {
2370 return CKEDITOR.DATA_TRANSFER_EXTERNAL;
2371 } else if ( this.sourceEditor == targetEditor ) {
2372 return CKEDITOR.DATA_TRANSFER_INTERNAL;
2373 } else {
2374 return CKEDITOR.DATA_TRANSFER_CROSS_EDITORS;
2375 }
2376 },
2377
2378 /**
2379 * Copies the data from the native data transfer to a private cache.
2380 * This function is needed because the data from the native data transfer
2381 * is available only synchronously to the event listener. It is not possible
2382 * to get the data asynchronously, after a timeout, and the {@link CKEDITOR.editor#paste}
2383 * event is fired asynchronously &mdash; hence the need for caching the data.
2384 */
2385 cacheData: function() {
2386 if ( !this.$ ) {
2387 return;
2388 }
2389
2390 var that = this,
2391 i, file;
2392
2393 function getAndSetData( type ) {
2394 type = that._.normalizeType( type );
2395
2396 var data = that.getData( type, true );
2397 if ( data ) {
2398 that._.data[ type ] = data;
2399 }
2400 }
2401
2402 // Copy data.
2403 if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
2404 if ( this.$.types ) {
2405 for ( i = 0; i < this.$.types.length; i++ ) {
2406 getAndSetData( this.$.types[ i ] );
2407 }
2408 }
2409 } else {
2410 getAndSetData( 'Text' );
2411 getAndSetData( 'URL' );
2412 }
2413
2414 // Copy files references.
2415 file = this._getImageFromClipboard();
2416 if ( ( this.$ && this.$.files ) || file ) {
2417 this._.files = [];
2418
2419 // Edge have empty files property with no length (http://dev.ckeditor.com/ticket/13755).
2420 if ( this.$.files && this.$.files.length ) {
2421 for ( i = 0; i < this.$.files.length; i++ ) {
2422 this._.files.push( this.$.files[ i ] );
2423 }
2424 }
2425
2426 // Don't include $.items if both $.files and $.items contains files, because,
2427 // according to spec and browsers behavior, they contain the same files.
2428 if ( this._.files.length === 0 && file ) {
2429 this._.files.push( file );
2430 }
2431 }
2432 },
2433
2434 /**
2435 * Gets the number of files in the dataTransfer object.
2436 *
2437 * @returns {Number} The number of files.
2438 */
2439 getFilesCount: function() {
2440 if ( this._.files.length ) {
2441 return this._.files.length;
2442 }
2443
2444 if ( this.$ && this.$.files && this.$.files.length ) {
2445 return this.$.files.length;
2446 }
2447
2448 return this._getImageFromClipboard() ? 1 : 0;
2449 },
2450
2451 /**
2452 * Gets the file at the index given.
2453 *
2454 * @param {Number} i Index.
2455 * @returns {File} File instance.
2456 */
2457 getFile: function( i ) {
2458 if ( this._.files.length ) {
2459 return this._.files[ i ];
2460 }
2461
2462 if ( this.$ && this.$.files && this.$.files.length ) {
2463 return this.$.files[ i ];
2464 }
2465
2466 // File or null if the file was not found.
2467 return i === 0 ? this._getImageFromClipboard() : undefined;
2468 },
2469
2470 /**
2471 * Checks if the data transfer contains any data.
2472 *
2473 * @returns {Boolean} `true` if the object contains no data.
2474 */
2475 isEmpty: function() {
2476 var typesToCheck = {},
2477 type;
2478
2479 // If dataTransfer contains files it is not empty.
2480 if ( this.getFilesCount() ) {
2481 return false;
2482 }
2483
2484 // Add custom types.
2485 for ( type in this._.data ) {
2486 typesToCheck[ type ] = 1;
2487 }
2488
2489 // Add native types.
2490 if ( this.$ ) {
2491 if ( CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ) {
2492 if ( this.$.types ) {
2493 for ( var i = 0; i < this.$.types.length; i++ ) {
2494 typesToCheck[ this.$.types[ i ] ] = 1;
2495 }
2496 }
2497 } else {
2498 typesToCheck.Text = 1;
2499 typesToCheck.URL = 1;
2500 }
2501 }
2502
2503 // Remove ID.
2504 if ( clipboardIdDataType != 'Text' ) {
2505 typesToCheck[ clipboardIdDataType ] = 0;
2506 }
2507
2508 for ( type in typesToCheck ) {
2509 if ( typesToCheck[ type ] && this.getData( type ) !== '' ) {
2510 return false;
2511 }
2512 }
2513
2514 return true;
2515 },
2516
2517 /**
2518 * When the content of the clipboard is pasted in Chrome, the clipboard data object has an empty `files` property,
2519 * but it is possible to get the file as `items[0].getAsFile();` (http://dev.ckeditor.com/ticket/12961).
2520 *
2521 * @private
2522 * @returns {File} File instance or `null` if not found.
2523 */
2524 _getImageFromClipboard: function() {
2525 var file;
2526
2527 if ( this.$ && this.$.items && this.$.items[ 0 ] ) {
2528 try {
2529 file = this.$.items[ 0 ].getAsFile();
2530 // Duck typing
2531 if ( file && file.type ) {
2532 return file;
2533 }
2534 } catch ( err ) {
2535 // noop
2536 }
2537 }
2538
2539 return undefined;
2540 }
2541 };
2542} )();
2543
2544/**
2545 * The default content type that is used when pasted data cannot be clearly recognized as HTML or text.
2546 *
2547 * For example: `'foo'` may come from a plain text editor or a website. It is not possible to recognize the content
2548 * type in this case, so the default type will be used. At the same time it is clear that `'<b>example</b> text'` is
2549 * HTML and its origin is a web page, email or another rich text editor.
2550 *
2551 * **Note:** If content type is text, then styles of the paste context are preserved.
2552 *
2553 * CKEDITOR.config.clipboard_defaultContentType = 'text';
2554 *
2555 * See also the {@link CKEDITOR.editor#paste} event and read more about the integration with clipboard
2556 * in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2557 *
2558 * @since 4.0
2559 * @cfg {'html'/'text'} [clipboard_defaultContentType='html']
2560 * @member CKEDITOR.config
2561 */
2562
2563/**
2564 * Fired after the user initiated a paste action, but before the data is inserted into the editor.
2565 * The listeners to this event are able to process the content before its insertion into the document.
2566 *
2567 * Read more about the integration with clipboard in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2568 *
2569 * See also:
2570 *
2571 * * the {@link CKEDITOR.config#pasteFilter} option,
2572 * * the {@link CKEDITOR.editor#drop} event,
2573 * * the {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2574 *
2575 * @since 3.1
2576 * @event paste
2577 * @member CKEDITOR.editor
2578 * @param {CKEDITOR.editor} editor This editor instance.
2579 * @param data
2580 * @param {String} data.type The type of data in `data.dataValue`. Usually `'html'` or `'text'`, but for listeners
2581 * with a priority smaller than `6` it may also be `'auto'` which means that the content type has not been recognised yet
2582 * (this will be done by the content type sniffer that listens with priority `6`).
2583 * @param {String} data.dataValue HTML to be pasted.
2584 * @param {String} data.method Indicates the data transfer method. It could be drag and drop or copy and paste.
2585 * Possible values: `'drop'`, `'paste'`. Introduced in CKEditor 4.5.
2586 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer Facade for the native dataTransfer object
2587 * which provides access to various data types and files, and passes some data between linked events
2588 * (like drag and drop). Introduced in CKEditor 4.5.
2589 * @param {Boolean} [data.dontFilter=false] Whether the {@link CKEDITOR.editor#pasteFilter paste filter} should not
2590 * be applied to data. This option has no effect when `data.type` equals `'text'` which means that for instance
2591 * {@link CKEDITOR.config#forcePasteAsPlainText} has a higher priority. Introduced in CKEditor 4.5.
2592 */
2593
2594/**
2595 * Fired before the {@link #paste} event. Allows to preset data type.
2596 *
2597 * **Note:** This event is deprecated. Add a `0` priority listener for the
2598 * {@link #paste} event instead.
2599 *
2600 * @deprecated
2601 * @event beforePaste
2602 * @member CKEDITOR.editor
2603 */
2604
2605/**
2606 * Fired after the {@link #paste} event if content was modified. Note that if the paste
2607 * event does not insert any data, the `afterPaste` event will not be fired.
2608 *
2609 * @event afterPaste
2610 * @member CKEDITOR.editor
2611 */
2612
2613/**
2614 * Facade for the native `drop` event. Fired when the native `drop` event occurs.
2615 *
2616 * **Note:** To manipulate dropped data, use the {@link CKEDITOR.editor#paste} event.
2617 * Use the `drop` event only to control drag and drop operations (e.g. to prevent the ability to drop some content).
2618 *
2619 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2620 *
2621 * See also:
2622 *
2623 * * The {@link CKEDITOR.editor#paste} event,
2624 * * The {@link CKEDITOR.editor#dragstart} and {@link CKEDITOR.editor#dragend} events,
2625 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2626 *
2627 * @since 4.5
2628 * @event drop
2629 * @member CKEDITOR.editor
2630 * @param {CKEDITOR.editor} editor This editor instance.
2631 * @param data
2632 * @param {Object} data.$ Native drop event.
2633 * @param {CKEDITOR.dom.node} data.target Drop target.
2634 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2635 * @param {CKEDITOR.dom.range} data.dragRange Drag range, lets you manipulate the drag range.
2636 * Note that dragged HTML is saved as `text/html` data on `dragstart` so if you change the drag range
2637 * on drop, dropped HTML will not change. You need to change it manually using
2638 * {@link CKEDITOR.plugins.clipboard.dataTransfer#setData dataTransfer.setData}.
2639 * @param {CKEDITOR.dom.range} data.dropRange Drop range, lets you manipulate the drop range.
2640 */
2641
2642/**
2643 * Facade for the native `dragstart` event. Fired when the native `dragstart` event occurs.
2644 *
2645 * This event can be canceled in order to block the drag start operation. It can also be fired to mimic the start of the drag and drop
2646 * operation. For instance, the `widget` plugin uses this option to integrate its custom block widget drag and drop with
2647 * the entire system.
2648 *
2649 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2650 *
2651 * See also:
2652 *
2653 * * The {@link CKEDITOR.editor#paste} event,
2654 * * The {@link CKEDITOR.editor#drop} and {@link CKEDITOR.editor#dragend} events,
2655 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2656 *
2657 * @since 4.5
2658 * @event dragstart
2659 * @member CKEDITOR.editor
2660 * @param {CKEDITOR.editor} editor This editor instance.
2661 * @param data
2662 * @param {Object} data.$ Native dragstart event.
2663 * @param {CKEDITOR.dom.node} data.target Drag target.
2664 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2665 */
2666
2667/**
2668 * Facade for the native `dragend` event. Fired when the native `dragend` event occurs.
2669 *
2670 * Read more about integration with drag and drop in the [Clipboard Deep Dive guide](#!/guide/dev_clipboard).
2671 *
2672 * See also:
2673 *
2674 * * The {@link CKEDITOR.editor#paste} event,
2675 * * The {@link CKEDITOR.editor#drop} and {@link CKEDITOR.editor#dragend} events,
2676 * * The {@link CKEDITOR.plugins.clipboard.dataTransfer} class.
2677 *
2678 * @since 4.5
2679 * @event dragend
2680 * @member CKEDITOR.editor
2681 * @param {CKEDITOR.editor} editor This editor instance.
2682 * @param data
2683 * @param {Object} data.$ Native dragend event.
2684 * @param {CKEDITOR.dom.node} data.target Drag target.
2685 * @param {CKEDITOR.plugins.clipboard.dataTransfer} data.dataTransfer DataTransfer facade.
2686 */
2687
2688/**
2689 * Defines a filter which is applied to external data pasted or dropped into the editor. Possible values are:
2690 *
2691 * * `'plain-text'` &ndash; Content will be pasted as a plain text.
2692 * * `'semantic-content'` &ndash; Known tags (except `div`, `span`) with all attributes (except
2693 * `style` and `class`) will be kept.
2694 * * `'h1 h2 p div'` &ndash; Custom rules compatible with {@link CKEDITOR.filter}.
2695 * * `null` &ndash; Content will not be filtered by the paste filter (but it still may be filtered
2696 * by [Advanced Content Filter](#!/guide/dev_advanced_content_filter)). This value can be used to
2697 * disable the paste filter in Chrome and Safari, where this option defaults to `'semantic-content'`.
2698 *
2699 * Example:
2700 *
2701 * config.pasteFilter = 'plain-text';
2702 *
2703 * Custom setting:
2704 *
2705 * config.pasteFilter = 'h1 h2 p ul ol li; img[!src, alt]; a[!href]';
2706 *
2707 * Based on this configuration option, a proper {@link CKEDITOR.filter} instance will be defined and assigned to the editor
2708 * as a {@link CKEDITOR.editor#pasteFilter}. You can tweak the paste filter settings on the fly on this object
2709 * as well as delete or replace it.
2710 *
2711 * var editor = CKEDITOR.replace( 'editor', {
2712 * pasteFilter: 'semantic-content'
2713 * } );
2714 *
2715 * editor.on( 'instanceReady', function() {
2716 * // The result of this will be that all semantic content will be preserved
2717 * // except tables.
2718 * editor.pasteFilter.disallow( 'table' );
2719 * } );
2720 *
2721 * Note that the paste filter is applied only to **external** data. There are three data sources:
2722 *
2723 * * copied and pasted in the same editor (internal),
2724 * * copied from one editor and pasted into another (cross-editor),
2725 * * coming from all other sources like websites, MS Word, etc. (external).
2726 *
2727 * If {@link CKEDITOR.config#allowedContent Advanced Content Filter} is not disabled, then
2728 * it will also be applied to pasted and dropped data. The paste filter job is to "normalize"
2729 * external data which often needs to be handled differently than content produced by the editor.
2730 *
2731 * This setting defaults to `'semantic-content'` in Chrome, Opera and Safari (all Blink and Webkit based browsers)
2732 * due to messy HTML which these browsers keep in the clipboard. In other browsers it defaults to `null`.
2733 *
2734 * @since 4.5
2735 * @cfg {String} [pasteFilter='semantic-content' in Chrome and Safari and `null` in other browsers]
2736 * @member CKEDITOR.config
2737 */
2738
2739/**
2740 * {@link CKEDITOR.filter Content filter} which is used when external data is pasted or dropped into the editor
2741 * or a forced paste as plain text occurs.
2742 *
2743 * This object might be used on the fly to define rules for pasted external content.
2744 * This object is available and used if the {@link CKEDITOR.plugins.clipboard clipboard} plugin is enabled and
2745 * {@link CKEDITOR.config#pasteFilter} or {@link CKEDITOR.config#forcePasteAsPlainText} was defined.
2746 *
2747 * To enable the filter:
2748 *
2749 * var editor = CKEDITOR.replace( 'editor', {
2750 * pasteFilter: 'plain-text'
2751 * } );
2752 *
2753 * You can also modify the filter on the fly later on:
2754 *
2755 * editor.pasteFilter = new CKEDITOR.filter( 'p h1 h2; a[!href]' );
2756 *
2757 * Note that the paste filter is only applied to **external** data. There are three data sources:
2758 *
2759 * * copied and pasted in the same editor (internal),
2760 * * copied from one editor and pasted into another (cross-editor),
2761 * * coming from all other sources like websites, MS Word, etc. (external).
2762 *
2763 * If {@link CKEDITOR.config#allowedContent Advanced Content Filter} is not disabled, then
2764 * it will also be applied to pasted and dropped data. The paste filter job is to "normalize"
2765 * external data which often needs to be handled differently than content produced by the editor.
2766 *
2767 * @since 4.5
2768 * @readonly
2769 * @property {CKEDITOR.filter} [pasteFilter]
2770 * @member CKEDITOR.editor
2771 */
2772
2773/**
2774 * Duration of the notification displayed after pasting was blocked by the browser.
2775 *
2776 * @since 4.7.0
2777 * @cfg {Number} [clipboard_notificationDuration=10000]
2778 * @member CKEDITOR.config
2779 */
2780CKEDITOR.config.clipboard_notificationDuration = 10000;