From c63493c899de714b05b0521bb38aab60d19030ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Isma=C3=ABl=20Bouya?=
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Content content content. Styled by Test internal D&D in the editor, dropping content from an external source (helpers, MS Word) and D&D between editors. Keep in mind that internal D&D is the most complex operation because editor have to handle two ranges at the same time. Apollo 11 was the spaceflight that landed the first humans, Americans Neil Armstrong and Buzz Aldrin, 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. Armstrong spent about Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as: One small step for [a] man, one giant leap for mankind. Apollo 11 effectively ended the Space Race and fulfilled a national goal proposed in 1961 by the late U.S. President John F. Kennedy in a speech before the United States Congress: [...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth. Launched by a Saturn V rocket from Kennedy Space Center in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of NASA's Apollo program. The Apollo spacecraft had three parts: After being sent to the Moon by the Saturn V'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 Sea of Tranquility. 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 Pacific Ocean on July 24. Source: Wikipedia.org -> (br.cke-pasted-remove will be removed later)
+ data = data.replace( /^ (?: |\r\n)?<(\w+)/g, function( match, elementName ) {
+ if ( elementName.toLowerCase() in blockElements ) {
+ evt.data.preSniffing = 'html'; // Mark as not a text.
+ return '<' + elementName;
+ }
+ return match;
+ } );
+ } else if ( CKEDITOR.env.webkit ) {
+ // %1
%2
',
+ itemTpl = 'strikethrough style to the text.
+ *
+ * Read more in the [documentation](#!/guide/dev_basicstyles)
+ * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
+ *
+ * CKEDITOR.config.coreStyles_strike = {
+ * element: 'span',
+ * attributes: { 'class': 'Strikethrough' },
+ * overrides: 'strike'
+ * };
+ *
+ * @cfg
+ * @member CKEDITOR.config
+ */
+CKEDITOR.config.coreStyles_strike = { element: 's', overrides: 'strike' };
+
+/**
+ * The style definition that applies the subscript style to the text.
+ *
+ * Read more in the [documentation](#!/guide/dev_basicstyles)
+ * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
+ *
+ * CKEDITOR.config.coreStyles_subscript = {
+ * element: 'span',
+ * attributes: { 'class': 'Subscript' },
+ * overrides: 'sub'
+ * };
+ *
+ * @cfg
+ * @member CKEDITOR.config
+ */
+CKEDITOR.config.coreStyles_subscript = { element: 'sub' };
+
+/**
+ * The style definition that applies the superscript style to the text.
+ *
+ * Read more in the [documentation](#!/guide/dev_basicstyles)
+ * and see the [SDK sample](http://sdk.ckeditor.com/samples/basicstyles.html).
+ *
+ * CKEDITOR.config.coreStyles_superscript = {
+ * element: 'span',
+ * attributes: { 'class': 'Superscript' },
+ * overrides: 'sup'
+ * };
+ *
+ * @cfg
+ * @member CKEDITOR.config
+ */
+CKEDITOR.config.coreStyles_superscript = { element: 'sup' };
diff --git a/sources/plugins/button/lang/af.js b/sources/plugins/button/lang/af.js
new file mode 100644
index 0000000..6ccebfa
--- /dev/null
+++ b/sources/plugins/button/lang/af.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'af', {
+ selectedLabel: '%1 uitgekies'
+} );
diff --git a/sources/plugins/button/lang/ar.js b/sources/plugins/button/lang/ar.js
new file mode 100644
index 0000000..025068d
--- /dev/null
+++ b/sources/plugins/button/lang/ar.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ar', {
+ selectedLabel: '%1 (محدد)'
+} );
diff --git a/sources/plugins/button/lang/az.js b/sources/plugins/button/lang/az.js
new file mode 100644
index 0000000..30ac85e
--- /dev/null
+++ b/sources/plugins/button/lang/az.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'az', {
+ selectedLabel: '%1 (seçilib)'
+} );
diff --git a/sources/plugins/button/lang/bg.js b/sources/plugins/button/lang/bg.js
new file mode 100644
index 0000000..0b146bb
--- /dev/null
+++ b/sources/plugins/button/lang/bg.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'bg', {
+ selectedLabel: '%1 (Избрано)'
+} );
diff --git a/sources/plugins/button/lang/ca.js b/sources/plugins/button/lang/ca.js
new file mode 100644
index 0000000..0891d49
--- /dev/null
+++ b/sources/plugins/button/lang/ca.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ca', {
+ selectedLabel: '%1 (Seleccionat)'
+} );
diff --git a/sources/plugins/button/lang/cs.js b/sources/plugins/button/lang/cs.js
new file mode 100644
index 0000000..552a05c
--- /dev/null
+++ b/sources/plugins/button/lang/cs.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'cs', {
+ selectedLabel: '%1 (Vybráno)'
+} );
diff --git a/sources/plugins/button/lang/da.js b/sources/plugins/button/lang/da.js
new file mode 100644
index 0000000..255dcc5
--- /dev/null
+++ b/sources/plugins/button/lang/da.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'da', {
+ selectedLabel: '%1 (Valgt)'
+} );
diff --git a/sources/plugins/button/lang/de-ch.js b/sources/plugins/button/lang/de-ch.js
new file mode 100644
index 0000000..63430d7
--- /dev/null
+++ b/sources/plugins/button/lang/de-ch.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'de-ch', {
+ selectedLabel: '%1 (Ausgewählt)'
+} );
diff --git a/sources/plugins/button/lang/de.js b/sources/plugins/button/lang/de.js
new file mode 100644
index 0000000..dca3daa
--- /dev/null
+++ b/sources/plugins/button/lang/de.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'de', {
+ selectedLabel: '%1 (Ausgewählt)'
+} );
diff --git a/sources/plugins/button/lang/el.js b/sources/plugins/button/lang/el.js
new file mode 100644
index 0000000..1718816
--- /dev/null
+++ b/sources/plugins/button/lang/el.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'el', {
+ selectedLabel: '%1 (Επιλεγμένο)'
+} );
diff --git a/sources/plugins/button/lang/en-gb.js b/sources/plugins/button/lang/en-gb.js
new file mode 100644
index 0000000..d7daefc
--- /dev/null
+++ b/sources/plugins/button/lang/en-gb.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'en-gb', {
+ selectedLabel: '%1 (Selected)'
+} );
diff --git a/sources/plugins/button/lang/en.js b/sources/plugins/button/lang/en.js
new file mode 100644
index 0000000..d5c4088
--- /dev/null
+++ b/sources/plugins/button/lang/en.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'en', {
+ selectedLabel: '%1 (Selected)'
+} );
diff --git a/sources/plugins/button/lang/eo.js b/sources/plugins/button/lang/eo.js
new file mode 100644
index 0000000..acf0c13
--- /dev/null
+++ b/sources/plugins/button/lang/eo.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'eo', {
+ selectedLabel: '%1 (Selektita)'
+} );
diff --git a/sources/plugins/button/lang/es.js b/sources/plugins/button/lang/es.js
new file mode 100644
index 0000000..cb46c6f
--- /dev/null
+++ b/sources/plugins/button/lang/es.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'es', {
+ selectedLabel: '%1 (Seleccionado)'
+} );
diff --git a/sources/plugins/button/lang/eu.js b/sources/plugins/button/lang/eu.js
new file mode 100644
index 0000000..c49d92a
--- /dev/null
+++ b/sources/plugins/button/lang/eu.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'eu', {
+ selectedLabel: '%1 (hautatuta)'
+} );
diff --git a/sources/plugins/button/lang/fa.js b/sources/plugins/button/lang/fa.js
new file mode 100644
index 0000000..358c88a
--- /dev/null
+++ b/sources/plugins/button/lang/fa.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'fa', {
+ selectedLabel: '%1 (انتخاب شده)'
+} );
diff --git a/sources/plugins/button/lang/fi.js b/sources/plugins/button/lang/fi.js
new file mode 100644
index 0000000..4822e74
--- /dev/null
+++ b/sources/plugins/button/lang/fi.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'fi', {
+ selectedLabel: '%1 (Valittu)'
+} );
diff --git a/sources/plugins/button/lang/fr.js b/sources/plugins/button/lang/fr.js
new file mode 100644
index 0000000..1b1c6d3
--- /dev/null
+++ b/sources/plugins/button/lang/fr.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'fr', {
+ selectedLabel: '%1 (Sélectionné)'
+} );
diff --git a/sources/plugins/button/lang/gl.js b/sources/plugins/button/lang/gl.js
new file mode 100644
index 0000000..3e4e0b7
--- /dev/null
+++ b/sources/plugins/button/lang/gl.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'gl', {
+ selectedLabel: '%1 (seleccionado)'
+} );
diff --git a/sources/plugins/button/lang/he.js b/sources/plugins/button/lang/he.js
new file mode 100644
index 0000000..c67afb6
--- /dev/null
+++ b/sources/plugins/button/lang/he.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'he', {
+ selectedLabel: '1% (סומן)'
+} );
diff --git a/sources/plugins/button/lang/hu.js b/sources/plugins/button/lang/hu.js
new file mode 100644
index 0000000..0dffac1
--- /dev/null
+++ b/sources/plugins/button/lang/hu.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'hu', {
+ selectedLabel: '%1 (Kiválasztva)'
+} );
diff --git a/sources/plugins/button/lang/id.js b/sources/plugins/button/lang/id.js
new file mode 100644
index 0000000..f973ffc
--- /dev/null
+++ b/sources/plugins/button/lang/id.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'id', {
+ selectedLabel: '%1(Dipilih)'
+} );
diff --git a/sources/plugins/button/lang/it.js b/sources/plugins/button/lang/it.js
new file mode 100644
index 0000000..359dc9a
--- /dev/null
+++ b/sources/plugins/button/lang/it.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'it', {
+ selectedLabel: '%1 (selezionato)'
+} );
diff --git a/sources/plugins/button/lang/ja.js b/sources/plugins/button/lang/ja.js
new file mode 100644
index 0000000..e2b064f
--- /dev/null
+++ b/sources/plugins/button/lang/ja.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ja', {
+ selectedLabel: '%1 (選択中)'
+} );
diff --git a/sources/plugins/button/lang/km.js b/sources/plugins/button/lang/km.js
new file mode 100644
index 0000000..9437a2f
--- /dev/null
+++ b/sources/plugins/button/lang/km.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'km', {
+ selectedLabel: '%1 (បានជ្រើសរើស)'
+} );
diff --git a/sources/plugins/button/lang/ko.js b/sources/plugins/button/lang/ko.js
new file mode 100644
index 0000000..64ad966
--- /dev/null
+++ b/sources/plugins/button/lang/ko.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ko', {
+ selectedLabel: '%1 (선택됨)'
+} );
diff --git a/sources/plugins/button/lang/ku.js b/sources/plugins/button/lang/ku.js
new file mode 100644
index 0000000..d342dd0
--- /dev/null
+++ b/sources/plugins/button/lang/ku.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ku', {
+ selectedLabel: '%1 (هەڵبژێردراو)'
+} );
diff --git a/sources/plugins/button/lang/lt.js b/sources/plugins/button/lang/lt.js
new file mode 100644
index 0000000..b492bd5
--- /dev/null
+++ b/sources/plugins/button/lang/lt.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'lt', {
+ selectedLabel: '%1 (Pasirinkta)'
+} );
diff --git a/sources/plugins/button/lang/nb.js b/sources/plugins/button/lang/nb.js
new file mode 100644
index 0000000..8d38121
--- /dev/null
+++ b/sources/plugins/button/lang/nb.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'nb', {
+ selectedLabel: '%1 (Valgt)'
+} );
diff --git a/sources/plugins/button/lang/nl.js b/sources/plugins/button/lang/nl.js
new file mode 100644
index 0000000..3e00f80
--- /dev/null
+++ b/sources/plugins/button/lang/nl.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'nl', {
+ selectedLabel: '%1 (Geselecteerd)'
+} );
diff --git a/sources/plugins/button/lang/no.js b/sources/plugins/button/lang/no.js
new file mode 100644
index 0000000..e6252b1
--- /dev/null
+++ b/sources/plugins/button/lang/no.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'no', {
+ selectedLabel: '%1 (Valgt)'
+} );
diff --git a/sources/plugins/button/lang/oc.js b/sources/plugins/button/lang/oc.js
new file mode 100644
index 0000000..cb91761
--- /dev/null
+++ b/sources/plugins/button/lang/oc.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'oc', {
+ selectedLabel: '%1 (Seleccionat)'
+} );
diff --git a/sources/plugins/button/lang/pl.js b/sources/plugins/button/lang/pl.js
new file mode 100644
index 0000000..304d07a
--- /dev/null
+++ b/sources/plugins/button/lang/pl.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'pl', {
+ selectedLabel: '%1 (Wybrany)'
+} );
diff --git a/sources/plugins/button/lang/pt-br.js b/sources/plugins/button/lang/pt-br.js
new file mode 100644
index 0000000..e3fdf84
--- /dev/null
+++ b/sources/plugins/button/lang/pt-br.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'pt-br', {
+ selectedLabel: '%1 (Selecionado)'
+} );
diff --git a/sources/plugins/button/lang/pt.js b/sources/plugins/button/lang/pt.js
new file mode 100644
index 0000000..e02c45a
--- /dev/null
+++ b/sources/plugins/button/lang/pt.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'pt', {
+ selectedLabel: '%1 (Selecionado)'
+} );
diff --git a/sources/plugins/button/lang/ro.js b/sources/plugins/button/lang/ro.js
new file mode 100644
index 0000000..0669dd5
--- /dev/null
+++ b/sources/plugins/button/lang/ro.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ro', {
+ selectedLabel: '%1 (Selectat)'
+} );
diff --git a/sources/plugins/button/lang/ru.js b/sources/plugins/button/lang/ru.js
new file mode 100644
index 0000000..085f6ee
--- /dev/null
+++ b/sources/plugins/button/lang/ru.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ru', {
+ selectedLabel: '%1 (Выбрано)'
+} );
diff --git a/sources/plugins/button/lang/sk.js b/sources/plugins/button/lang/sk.js
new file mode 100644
index 0000000..12bec80
--- /dev/null
+++ b/sources/plugins/button/lang/sk.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'sk', {
+ selectedLabel: '%1 (Vybrané)'
+} );
diff --git a/sources/plugins/button/lang/sl.js b/sources/plugins/button/lang/sl.js
new file mode 100644
index 0000000..c6633ae
--- /dev/null
+++ b/sources/plugins/button/lang/sl.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'sl', {
+ selectedLabel: '%1 (Izbrano)'
+} );
diff --git a/sources/plugins/button/lang/sq.js b/sources/plugins/button/lang/sq.js
new file mode 100644
index 0000000..2e53e4c
--- /dev/null
+++ b/sources/plugins/button/lang/sq.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'sq', {
+ selectedLabel: '%1 (Përzgjedhur)'
+} );
diff --git a/sources/plugins/button/lang/sv.js b/sources/plugins/button/lang/sv.js
new file mode 100644
index 0000000..b89e475
--- /dev/null
+++ b/sources/plugins/button/lang/sv.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'sv', {
+ selectedLabel: '%1 (Vald)'
+} );
diff --git a/sources/plugins/button/lang/tr.js b/sources/plugins/button/lang/tr.js
new file mode 100644
index 0000000..30d3670
--- /dev/null
+++ b/sources/plugins/button/lang/tr.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'tr', {
+ selectedLabel: '%1 (Seçilmiş)'
+} );
diff --git a/sources/plugins/button/lang/tt.js b/sources/plugins/button/lang/tt.js
new file mode 100644
index 0000000..6324922
--- /dev/null
+++ b/sources/plugins/button/lang/tt.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'tt', {
+ selectedLabel: '%1 (Сайланган)'
+} );
diff --git a/sources/plugins/button/lang/ug.js b/sources/plugins/button/lang/ug.js
new file mode 100644
index 0000000..fa3a90c
--- /dev/null
+++ b/sources/plugins/button/lang/ug.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'ug', {
+ selectedLabel: '%1 (تاللاندى)'
+} );
diff --git a/sources/plugins/button/lang/uk.js b/sources/plugins/button/lang/uk.js
new file mode 100644
index 0000000..7b49fe2
--- /dev/null
+++ b/sources/plugins/button/lang/uk.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'uk', {
+ selectedLabel: '%1 (Вибрано)'
+} );
diff --git a/sources/plugins/button/lang/vi.js b/sources/plugins/button/lang/vi.js
new file mode 100644
index 0000000..b6a5911
--- /dev/null
+++ b/sources/plugins/button/lang/vi.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'vi', {
+ selectedLabel: '%1 (Đã chọn)'
+} );
diff --git a/sources/plugins/button/lang/zh-cn.js b/sources/plugins/button/lang/zh-cn.js
new file mode 100644
index 0000000..fade7d7
--- /dev/null
+++ b/sources/plugins/button/lang/zh-cn.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'zh-cn', {
+ selectedLabel: '已选中 %1 项'
+} );
diff --git a/sources/plugins/button/lang/zh.js b/sources/plugins/button/lang/zh.js
new file mode 100644
index 0000000..7479462
--- /dev/null
+++ b/sources/plugins/button/lang/zh.js
@@ -0,0 +1,8 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.plugins.setLang( 'button', 'zh', {
+ selectedLabel: '%1 (已選取)'
+} );
diff --git a/sources/plugins/button/plugin.js b/sources/plugins/button/plugin.js
new file mode 100644
index 0000000..6d2db33
--- /dev/null
+++ b/sources/plugins/button/plugin.js
@@ -0,0 +1,389 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+( function() {
+ var template = '' +
+ '{label}' +
+ '{ariaShortcut}' +
+ '{arrowHtml}' +
+ '';
+
+ var templateArrow = ' ' +
+ ' ';
+
+ var btnArrowTpl = CKEDITOR.addTemplate( 'buttonArrow', templateArrow ),
+ btnTpl = CKEDITOR.addTemplate( 'button', template );
+
+ CKEDITOR.plugins.add( 'button', {
+ lang: 'af,ar,az,bg,ca,cs,da,de,de-ch,el,en,en-gb,eo,es,eu,fa,fi,fr,gl,he,hu,id,it,ja,km,ko,ku,lt,nb,nl,no,oc,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
+ beforeInit: function( editor ) {
+ editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );
+ }
+ } );
+
+ /**
+ * Button UI element.
+ *
+ * @readonly
+ * @property {String} [='button']
+ * @member CKEDITOR
+ */
+ CKEDITOR.UI_BUTTON = 'button';
+
+ /**
+ * Represents a button UI element. This class should not be called directly. To
+ * create new buttons use {@link CKEDITOR.ui#addButton} instead.
+ *
+ * @class
+ * @constructor Creates a button class instance.
+ * @param {Object} definition The button definition.
+ */
+ CKEDITOR.ui.button = function( definition ) {
+ CKEDITOR.tools.extend( this, definition,
+ // Set defaults.
+ {
+ title: definition.label,
+ click: definition.click ||
+ function( editor ) {
+ editor.execCommand( definition.command );
+ }
+ } );
+
+ this._ = {};
+ };
+
+ /**
+ * Represents the button handler object.
+ *
+ * @class
+ * @singleton
+ * @extends CKEDITOR.ui.handlerDefinition
+ */
+ CKEDITOR.ui.button.handler = {
+ /**
+ * Transforms a button definition in a {@link CKEDITOR.ui.button} instance.
+ *
+ * @member CKEDITOR.ui.button.handler
+ * @param {Object} definition
+ * @returns {CKEDITOR.ui.button}
+ */
+ create: function( definition ) {
+ return new CKEDITOR.ui.button( definition );
+ }
+ };
+
+ /** @class CKEDITOR.ui.button */
+ CKEDITOR.ui.button.prototype = {
+ /**
+ * Renders the button.
+ *
+ * @param {CKEDITOR.editor} editor The editor instance which this button is
+ * to be used by.
+ * @param {Array} output The output array to which the HTML code related to
+ * this button should be appended.
+ */
+ render: function( editor, output ) {
+ function updateState() {
+ // "this" is a CKEDITOR.ui.button instance.
+ var mode = editor.mode;
+
+ if ( mode ) {
+ // Restore saved button state.
+ var state = this.modes[ mode ] ? modeStates[ mode ] !== undefined ? modeStates[ mode ] : CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
+
+ state = editor.readOnly && !this.readOnly ? CKEDITOR.TRISTATE_DISABLED : state;
+
+ this.setState( state );
+
+ // Let plugin to disable button.
+ if ( this.refresh )
+ this.refresh();
+ }
+ }
+
+ var env = CKEDITOR.env,
+ id = this._.id = CKEDITOR.tools.getNextId(),
+ stateName = '',
+ command = this.command,
+ // Get the command name.
+ clickFn,
+ keystroke,
+ shortcut;
+
+ this._.editor = editor;
+
+ var instance = {
+ id: id,
+ button: this,
+ editor: editor,
+ focus: function() {
+ var element = CKEDITOR.document.getById( id );
+ element.focus();
+ },
+ execute: function() {
+ this.button.click( editor );
+ },
+ attach: function( editor ) {
+ this.button.attach( editor );
+ }
+ };
+
+ var keydownFn = CKEDITOR.tools.addFunction( function( ev ) {
+ if ( instance.onkey ) {
+ ev = new CKEDITOR.dom.event( ev );
+ return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
+ }
+ } );
+
+ var focusFn = CKEDITOR.tools.addFunction( function( ev ) {
+ var retVal;
+
+ if ( instance.onfocus )
+ retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );
+
+ return retVal;
+ } );
+
+ var selLocked = 0;
+
+ instance.clickFn = clickFn = CKEDITOR.tools.addFunction( function() {
+
+ // Restore locked selection in Opera.
+ if ( selLocked ) {
+ editor.unlockSelection( 1 );
+ selLocked = 0;
+ }
+ instance.execute();
+
+ // Fixed iOS focus issue when your press disabled button (#12381).
+ if ( env.iOS ) {
+ editor.focus();
+ }
+ } );
+
+
+ // Indicate a mode sensitive button.
+ if ( this.modes ) {
+ var modeStates = {};
+
+ editor.on( 'beforeModeUnload', function() {
+ if ( editor.mode && this._.state != CKEDITOR.TRISTATE_DISABLED )
+ modeStates[ editor.mode ] = this._.state;
+ }, this );
+
+ // Update status when activeFilter, mode or readOnly changes.
+ editor.on( 'activeFilterChange', updateState, this );
+ editor.on( 'mode', updateState, this );
+ // If this button is sensitive to readOnly state, update it accordingly.
+ !this.readOnly && editor.on( 'readOnly', updateState, this );
+
+ } else if ( command ) {
+ // Get the command instance.
+ command = editor.getCommand( command );
+
+ if ( command ) {
+ command.on( 'state', function() {
+ this.setState( command.state );
+ }, this );
+
+ stateName += ( command.state == CKEDITOR.TRISTATE_ON ? 'on' : command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' : 'off' );
+ }
+ }
+
+ // For button that has text-direction awareness on selection path.
+ if ( this.directional ) {
+ editor.on( 'contentDirChanged', function( evt ) {
+ var el = CKEDITOR.document.getById( this._.id ),
+ icon = el.getFirst();
+
+ var pathDir = evt.data;
+
+ // Make a minor direction change to become style-able for the skin icon.
+ if ( pathDir != editor.lang.dir )
+ el.addClass( 'cke_' + pathDir );
+ else
+ el.removeClass( 'cke_ltr' ).removeClass( 'cke_rtl' );
+
+ // Inline style update for the plugin icon.
+ icon.setAttribute( 'style', CKEDITOR.skin.getIconStyle( iconName, pathDir == 'rtl', this.icon, this.iconOffset ) );
+ }, this );
+ }
+
+ if ( !command ) {
+ stateName += 'off';
+ } else {
+ keystroke = editor.getCommandKeystroke( command );
+
+ if ( keystroke ) {
+ shortcut = CKEDITOR.tools.keystrokeToString( editor.lang.common.keyboard, keystroke );
+ }
+ }
+
+ var name = this.name || this.command,
+ iconName = name;
+
+ // Check if we're pointing to an icon defined by another command. (#9555)
+ if ( this.icon && !( /\./ ).test( this.icon ) ) {
+ iconName = this.icon;
+ this.icon = null;
+ }
+
+ var params = {
+ id: id,
+ name: name,
+ iconName: iconName,
+ label: this.label,
+ cls: this.className || '',
+ state: stateName,
+ ariaDisabled: stateName == 'disabled' ? 'true' : 'false',
+ title: this.title + ( shortcut ? ' (' + shortcut.display + ')' : '' ),
+ ariaShortcut: shortcut ? editor.lang.common.keyboardShortcut + ' ' + shortcut.aria : '',
+ titleJs: env.gecko && !env.hc ? '' : ( this.title || '' ).replace( "'", '' ),
+ hasArrow: this.hasArrow ? 'true' : 'false',
+ keydownFn: keydownFn,
+ focusFn: focusFn,
+ clickFn: clickFn,
+ style: CKEDITOR.skin.getIconStyle( iconName, ( editor.lang.dir == 'rtl' ), this.icon, this.iconOffset ),
+ arrowHtml: this.hasArrow ? btnArrowTpl.output() : ''
+ };
+
+ btnTpl.output( params, output );
+
+ if ( this.onRender )
+ this.onRender();
+
+ return instance;
+ },
+
+ /**
+ * Sets the button state.
+ *
+ * @param {Number} state Indicates the button state. One of {@link CKEDITOR#TRISTATE_ON},
+ * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.
+ */
+ setState: function( state ) {
+ if ( this._.state == state )
+ return false;
+
+ this._.state = state;
+
+ var element = CKEDITOR.document.getById( this._.id );
+
+ if ( element ) {
+ element.setState( state, 'cke_button' );
+
+ state == CKEDITOR.TRISTATE_DISABLED ?
+ element.setAttribute( 'aria-disabled', true ) :
+ element.removeAttribute( 'aria-disabled' );
+
+ if ( !this.hasArrow ) {
+ // Note: aria-pressed attribute should not be added to menuButton instances. (#11331)
+ state == CKEDITOR.TRISTATE_ON ?
+ element.setAttribute( 'aria-pressed', true ) :
+ element.removeAttribute( 'aria-pressed' );
+ } else {
+ var newLabel = state == CKEDITOR.TRISTATE_ON ?
+ this._.editor.lang.button.selectedLabel.replace( /%1/g, this.label ) : this.label;
+ CKEDITOR.document.getById( this._.id + '_label' ).setText( newLabel );
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Gets the button state.
+ *
+ * @returns {Number} The button state. One of {@link CKEDITOR#TRISTATE_ON},
+ * {@link CKEDITOR#TRISTATE_OFF}, or {@link CKEDITOR#TRISTATE_DISABLED}.
+ */
+ getState: function() {
+ return this._.state;
+ },
+
+ /**
+ * Returns this button's {@link CKEDITOR.feature} instance.
+ *
+ * It may be this button instance if it has at least one of
+ * `allowedContent` and `requiredContent` properties. Otherwise,
+ * if a command is bound to this button by the `command` property, then
+ * that command will be returned.
+ *
+ * This method implements the {@link CKEDITOR.feature#toFeature} interface method.
+ *
+ * @since 4.1
+ * @param {CKEDITOR.editor} Editor instance.
+ * @returns {CKEDITOR.feature} The feature.
+ */
+ toFeature: function( editor ) {
+ if ( this._.feature )
+ return this._.feature;
+
+ var feature = this;
+
+ // If button isn't a feature, return command if is bound.
+ if ( !this.allowedContent && !this.requiredContent && this.command )
+ feature = editor.getCommand( this.command ) || feature;
+
+ return this._.feature = feature;
+ }
+ };
+
+ /**
+ * Adds a button definition to the UI elements list.
+ *
+ * editorInstance.ui.addButton( 'MyBold', {
+ * label: 'My Bold',
+ * command: 'bold',
+ * toolbar: 'basicstyles,1'
+ * } );
+ *
+ * @member CKEDITOR.ui
+ * @param {String} name The button name.
+ * @param {Object} definition The button definition.
+ * @param {String} definition.label The textual part of the button (if visible) and its tooltip.
+ * @param {String} definition.command The command to be executed once the button is activated.
+ * @param {String} definition.toolbar The {@link CKEDITOR.config#toolbarGroups toolbar group} into which
+ * the button will be added. An optional index value (separated by a comma) determines the button position within the group.
+ */
+ CKEDITOR.ui.prototype.addButton = function( name, definition ) {
+ this.add( name, CKEDITOR.UI_BUTTON, definition );
+ };
+
+} )();
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 @@
+
+
+
+
+
+
+ CKEditor Sample — clipboard plugin playground
+
+ Editor 6
+ .someClass
.' +
+ '
',
+
+ refresh: function() {
+ return {
+ header: 'Paste',
+ type: pasteType,
+ value: pasteValue
+ };
+ },
+
+ refreshOn: function( editor, refresh ) {
+ editor.on( 'paste', function( evt ) {
+ pasteType = evt.data.type;
+ pasteValue = CKEDITOR.tools.htmlEncode( evt.data.dataValue );
+ refresh();
+ } );
+ }
+ },
+ {
+ type: 'log',
+ on: function( editor, log, logFn ) {
+ editor.on( 'paste', function( evt ) {
+ logFn( 'paste; type:' + evt.data.type )();
+ } );
+ }
+ }
+ ]
+ } );
+} )();
diff --git a/sources/plugins/clipboard/dev/dnd.html b/sources/plugins/clipboard/dev/dnd.html
new file mode 100644
index 0000000..2dfb2be
--- /dev/null
+++ b/sources/plugins/clipboard/dev/dnd.html
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+ Manual test for #11460
+
+ Description (hide/show)
+ Expected behavior:
+
+
+ Drag scenarios:
+
+
+ Drop scenarios:
+
+
+ Known issues (not part of this ticket):
+
+
+ Helpers (hide/show)
+
+Aenean cursus egestas ipsum.
+
+ Classic editor (hide/show)
+ Inline editor (hide/show)
+
+
+ Apollo 11
three and a half two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, Michael Collins, piloted the command spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.Broadcasting and quotes
+
+
+
+
+
+
+
+ Technical details
+
+
+
+
+
+
+
+
+ Position
+ Astronaut
+
+
+ Commander
+ Neil A. Armstrong
+
+
+ Command Module Pilot
+ Michael Collins
+
+
+
+ Lunar Module Pilot
+ Edwin "Buzz" E. Aldrin, Jr.
+
+
+
+
+
Brug i stedet tastaturet til at kopiere teksten (Ctrl/Cmd+C).',
+ cut: 'Klip',
+ cutError: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.
Brug i stedet tastaturet til at klippe teksten (Ctrl/Cmd+X).',
+ paste: 'Indsæt',
+ pasteArea: 'Indsæt område',
+ pasteMsg: 'Indsæt i feltet herunder (Ctrl/Cmd+V) og klik på OK.',
+ securityMsg: 'Din browsers sikkerhedsindstillinger tillader ikke editoren at få automatisk adgang til udklipsholderen.
Du skal indsætte udklipsholderens indhold i dette vindue igen.',
+ title: 'Indsæt'
+} );
diff --git a/sources/plugins/clipboard/lang/de-ch.js b/sources/plugins/clipboard/lang/de-ch.js
new file mode 100644
index 0000000..325b100
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de-ch.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'de-ch', {
+ copy: 'Kopieren',
+ copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
+ cut: 'Ausschneiden',
+ 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).',
+ paste: 'Einfügen',
+ pasteArea: 'Einfügebereich',
+ pasteMsg: 'Bitte fügen Sie den Text in der folgenden Box über die Tastatur (mit Strg+V) ein und bestätigen Sie mit OK.',
+ securityMsg: 'Aufgrund von Sicherheitsbeschränkungen Ihres Browsers kann der Editor nicht direkt auf die Zwischenablage zugreifen. Bitte fügen Sie den Inhalt erneut in diesem Fenster ein.',
+ title: 'Einfügen'
+} );
diff --git a/sources/plugins/clipboard/lang/de.js b/sources/plugins/clipboard/lang/de.js
new file mode 100644
index 0000000..2d6b30b
--- /dev/null
+++ b/sources/plugins/clipboard/lang/de.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'de', {
+ copy: 'Kopieren',
+ copyError: 'Die Sicherheitseinstellungen Ihres Browsers lassen es nicht zu, den Text automatisch kopieren. Bitte benutzen Sie die System-Zwischenablage über STRG-C (kopieren).',
+ cut: 'Ausschneiden',
+ 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).',
+ paste: 'Einfügen',
+ pasteArea: 'Einfügebereich',
+ pasteMsg: 'Bitte fügen Sie den Text in der folgenden Box über die Tastatur (mit Strg+V) ein und bestätigen Sie mit OK.',
+ securityMsg: 'Aufgrund von Sicherheitsbeschränkungen Ihres Browsers kann der Editor nicht direkt auf die Zwischenablage zugreifen. Bitte fügen Sie den Inhalt erneut in diesem Fenster ein.',
+ title: 'Einfügen'
+} );
diff --git a/sources/plugins/clipboard/lang/el.js b/sources/plugins/clipboard/lang/el.js
new file mode 100644
index 0000000..0528840
--- /dev/null
+++ b/sources/plugins/clipboard/lang/el.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'el', {
+ copy: 'Αντιγραφή',
+ copyError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αντιγραφής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+C).',
+ cut: 'Αποκοπή',
+ cutError: 'Οι ρυθμίσεις ασφαλείας του περιηγητή σας δεν επιτρέπουν την επιλεγμένη εργασία αποκοπής. Παρακαλώ χρησιμοποιείστε το πληκτρολόγιο (Ctrl/Cmd+X).',
+ paste: 'Επικόλληση',
+ pasteArea: 'Περιοχή Επικόλλησης',
+ pasteMsg: 'Παρακαλώ επικολλήστε στο ακόλουθο κουτί χρησιμοποιώντας το πληκτρολόγιο (Ctrl/Cmd+V) και πατήστε OK.',
+ securityMsg: 'Λόγων των ρυθμίσεων ασφάλειας του περιηγητή σας, ο επεξεργαστής δεν μπορεί να έχει πρόσβαση στην μνήμη επικόλλησης. Χρειάζεται να επικολλήσετε ξανά σε αυτό το παράθυρο.',
+ title: 'Επικόλληση'
+} );
diff --git a/sources/plugins/clipboard/lang/en-au.js b/sources/plugins/clipboard/lang/en-au.js
new file mode 100644
index 0000000..5c497fb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-au.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'en-au', {
+ copy: 'Copy',
+ copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
+ cut: 'Cut',
+ cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
+ paste: 'Paste',
+ pasteArea: 'Paste Area', // MISSING
+ pasteMsg: 'Please paste inside the following box using the keyboard (Ctrl/Cmd+V) and hit OK',
+ securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
+ title: 'Paste'
+} );
diff --git a/sources/plugins/clipboard/lang/en-ca.js b/sources/plugins/clipboard/lang/en-ca.js
new file mode 100644
index 0000000..036ebab
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-ca.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'en-ca', {
+ copy: 'Copy',
+ copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
+ cut: 'Cut',
+ cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
+ paste: 'Paste',
+ pasteArea: 'Paste Area', // MISSING
+ pasteMsg: 'Please paste inside the following box using the keyboard (Ctrl/Cmd+V) and hit OK',
+ securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
+ title: 'Paste'
+} );
diff --git a/sources/plugins/clipboard/lang/en-gb.js b/sources/plugins/clipboard/lang/en-gb.js
new file mode 100644
index 0000000..bb511ce
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en-gb.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'en-gb', {
+ copy: 'Copy',
+ copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
+ cut: 'Cut',
+ cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
+ paste: 'Paste',
+ pasteArea: 'Paste Area',
+ pasteMsg: 'Please paste inside the following box using the keyboard (Ctrl/Cmd+V) and hit OK',
+ securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
+ title: 'Paste'
+} );
diff --git a/sources/plugins/clipboard/lang/en.js b/sources/plugins/clipboard/lang/en.js
new file mode 100644
index 0000000..4db6960
--- /dev/null
+++ b/sources/plugins/clipboard/lang/en.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'en', {
+ copy: 'Copy',
+ copyError: 'Your browser security settings don\'t permit the editor to automatically execute copying operations. Please use the keyboard for that (Ctrl/Cmd+C).',
+ cut: 'Cut',
+ cutError: 'Your browser security settings don\'t permit the editor to automatically execute cutting operations. Please use the keyboard for that (Ctrl/Cmd+X).',
+ paste: 'Paste',
+ pasteArea: 'Paste Area',
+ pasteMsg: 'Please paste inside the following box using the keyboard (Ctrl/Cmd+V) and hit OK',
+ securityMsg: 'Because of your browser security settings, the editor is not able to access your clipboard data directly. You are required to paste it again in this window.',
+ title: 'Paste'
+} );
diff --git a/sources/plugins/clipboard/lang/eo.js b/sources/plugins/clipboard/lang/eo.js
new file mode 100644
index 0000000..2df4150
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eo.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'eo', {
+ copy: 'Kopii',
+ copyError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras kopiajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-C).',
+ cut: 'Eltondi',
+ cutError: 'La sekurecagordo de via TTT-legilo ne permesas, ke la redaktilo faras eltondajn operaciojn. Bonvolu uzi la klavaron por tio (Ctrl/Cmd-X).',
+ paste: 'Interglui',
+ pasteArea: 'Intergluoareo',
+ pasteMsg: 'Bonvolu glui la tekston en la jenan areon per uzado de la klavaro (Ctrl/Cmd+V) kaj premu OK',
+ securityMsg: 'Pro la sekurecagordo de via TTT-legilo, la redaktilo ne povas rekte atingi viajn datenojn en la poŝo. Bonvolu denove interglui la datenojn en tiun fenestron.',
+ title: 'Interglui'
+} );
diff --git a/sources/plugins/clipboard/lang/es.js b/sources/plugins/clipboard/lang/es.js
new file mode 100644
index 0000000..c455992
--- /dev/null
+++ b/sources/plugins/clipboard/lang/es.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'es', {
+ copy: 'Copiar',
+ 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).',
+ cut: 'Cortar',
+ 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).',
+ paste: 'Pegar',
+ pasteArea: 'Zona de pegado',
+ pasteMsg: 'Por favor pegue dentro del cuadro utilizando el teclado (Ctrl/Cmd+V);\r\nluego presione Aceptar.',
+ securityMsg: 'Debido a la configuración de seguridad de su navegador, el editor no tiene acceso al portapapeles.\r\nEs necesario que lo pegue de nuevo en esta ventana.',
+ title: 'Pegar'
+} );
diff --git a/sources/plugins/clipboard/lang/et.js b/sources/plugins/clipboard/lang/et.js
new file mode 100644
index 0000000..7d86b30
--- /dev/null
+++ b/sources/plugins/clipboard/lang/et.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'et', {
+ copy: 'Kopeeri',
+ copyError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt kopeerida. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+C).',
+ cut: 'Lõika',
+ cutError: 'Sinu veebisirvija turvaseaded ei luba redaktoril automaatselt lõigata. Palun kasutage selleks klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+X).',
+ paste: 'Aseta',
+ pasteArea: 'Asetamise ala',
+ pasteMsg: 'Palun aseta tekst järgnevasse kasti kasutades klaviatuuri klahvikombinatsiooni (Ctrl/Cmd+V) ja vajuta seejärel OK.',
+ securityMsg: 'Sinu veebisirvija turvaseadete tõttu ei oma redaktor otsest ligipääsu lõikelaua andmetele. Sa pead asetama need uuesti siia aknasse.',
+ title: 'Asetamine'
+} );
diff --git a/sources/plugins/clipboard/lang/eu.js b/sources/plugins/clipboard/lang/eu.js
new file mode 100644
index 0000000..93240b5
--- /dev/null
+++ b/sources/plugins/clipboard/lang/eu.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'eu', {
+ copy: 'Kopiatu',
+ copyError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki kopiatzea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+C).',
+ cut: 'Ebaki',
+ cutError: 'Zure web nabigatzailearen segurtasun ezarpenek ez dute baimentzen testuak automatikoki moztea. Mesedez teklatua erabil ezazu (Ctrl/Cmd+X).',
+ paste: 'Itsatsi',
+ pasteArea: 'Itsasteko area',
+ pasteMsg: 'Mesedez teklatua erabiliz (Ctrl/Cmd+V) ondorengo eremuan testua itsatsi eta sakatu Ados.',
+ securityMsg: 'Nabigatzailearen segurtasun ezarpenak direla eta, editoreak ezin du arbela zuzenean erabili. Leiho honetan berriro itsatsi behar duzu.',
+ title: 'Itsatsi'
+} );
diff --git a/sources/plugins/clipboard/lang/fa.js b/sources/plugins/clipboard/lang/fa.js
new file mode 100644
index 0000000..8abee21
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fa.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'fa', {
+ copy: 'رونوشت',
+ copyError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای کپی کردن را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+C).',
+ cut: 'برش',
+ cutError: 'تنظیمات امنیتی مرورگر شما اجازه نمیدهد که ویرایشگر به طور خودکار عملکردهای برش را انجام دهد. لطفا با دکمههای صفحه کلید این کار را انجام دهید (Ctrl/Cmd+X).',
+ paste: 'چسباندن',
+ pasteArea: 'محل چسباندن',
+ pasteMsg: 'لطفا متن را با کلیدهای (Ctrl/Cmd+V) در این جعبهٴ متنی بچسبانید و پذیرش را بزنید.',
+ securityMsg: 'به خاطر تنظیمات امنیتی مرورگر شما، ویرایشگر نمیتواند دسترسی مستقیم به دادههای clipboard داشته باشد. شما باید دوباره آنرا در این پنجره بچسبانید.',
+ title: 'چسباندن'
+} );
diff --git a/sources/plugins/clipboard/lang/fi.js b/sources/plugins/clipboard/lang/fi.js
new file mode 100644
index 0000000..d165fb3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fi.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'fi', {
+ copy: 'Kopioi',
+ copyError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa kopioimista. Käytä näppäimistöä kopioimiseen (Ctrl+C).',
+ cut: 'Leikkaa',
+ cutError: 'Selaimesi turva-asetukset eivät salli editorin toteuttaa leikkaamista. Käytä näppäimistöä leikkaamiseen (Ctrl+X).',
+ paste: 'Liitä',
+ pasteArea: 'Leikealue',
+ pasteMsg: 'Liitä painamalla (Ctrl+V) ja painamalla OK.',
+ securityMsg: 'Selaimesi turva-asetukset eivät salli editorin käyttää leikepöytää suoraan. Sinun pitää suorittaa liittäminen tässä ikkunassa.',
+ title: 'Liitä'
+} );
diff --git a/sources/plugins/clipboard/lang/fo.js b/sources/plugins/clipboard/lang/fo.js
new file mode 100644
index 0000000..5c1ec8a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fo.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'fo', {
+ copy: 'Avrita',
+ copyError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at avrita tekstin. Vinarliga nýt knappaborðið til at avrita tekstin (Ctrl/Cmd+C).',
+ cut: 'Kvett',
+ cutError: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í at kvetta tekstin. Vinarliga nýt knappaborðið til at kvetta tekstin (Ctrl/Cmd+X).',
+ paste: 'Innrita',
+ pasteArea: 'Avritingarumráði',
+ pasteMsg: 'Vinarliga koyr tekstin í hendan rútin við knappaborðinum (Ctrl/Cmd+V) og klikk á Góðtak.',
+ securityMsg: 'Trygdaruppseting alnótskagans forðar tekstviðgeranum í beinleiðis atgongd til avritingarminnið. Tygum mugu royna aftur í hesum rútinum.',
+ title: 'Innrita'
+} );
diff --git a/sources/plugins/clipboard/lang/fr-ca.js b/sources/plugins/clipboard/lang/fr-ca.js
new file mode 100644
index 0000000..3425f56
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr-ca.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'fr-ca', {
+ copy: 'Copier',
+ 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).',
+ cut: 'Couper',
+ 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).',
+ paste: 'Coller',
+ pasteArea: 'Coller la zone',
+ pasteMsg: 'Veuillez coller dans la zone ci-dessous en utilisant le clavier (Ctrl/Cmd+V) et appuyer sur OK.',
+ securityMsg: 'A cause des paramètres de sécurité de votre navigateur, l\'éditeur ne peut accéder au presse-papier directement. Vous devez coller à nouveau le contenu dans cette fenêtre.',
+ title: 'Coller'
+} );
diff --git a/sources/plugins/clipboard/lang/fr.js b/sources/plugins/clipboard/lang/fr.js
new file mode 100644
index 0000000..bb8349f
--- /dev/null
+++ b/sources/plugins/clipboard/lang/fr.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'fr', {
+ copy: 'Copier',
+ 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).',
+ cut: 'Couper',
+ 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).',
+ paste: 'Coller',
+ pasteArea: 'Coller la zone',
+ pasteMsg: 'Veuillez coller le texte dans la zone suivante en utilisant le raccourci clavier (Ctrl/Cmd+V) et cliquez sur OK.',
+ securityMsg: 'Les paramètres de sécurité de votre navigateur empêchent l\'éditeur d\'accéder directement aux données du presse-papier. Vous devez les coller à nouveau dans cette fenêtre.',
+ title: 'Coller'
+} );
diff --git a/sources/plugins/clipboard/lang/gl.js b/sources/plugins/clipboard/lang/gl.js
new file mode 100644
index 0000000..3c89dd0
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gl.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'gl', {
+ copy: 'Copiar',
+ 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).',
+ cut: 'Cortar',
+ 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).',
+ paste: 'Pegar',
+ pasteArea: 'Zona de pegado',
+ pasteMsg: 'Pegue dentro do seguinte cadro usando o teclado (Ctrl/Cmd+V) e prema en Aceptar',
+ securityMsg: 'Por mor da configuración de seguranza do seu navegador, o editor non ten acceso ao portapapeis. É necesario pegalo novamente nesta xanela.',
+ title: 'Pegar'
+} );
diff --git a/sources/plugins/clipboard/lang/gu.js b/sources/plugins/clipboard/lang/gu.js
new file mode 100644
index 0000000..fcf039a
--- /dev/null
+++ b/sources/plugins/clipboard/lang/gu.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'gu', {
+ copy: 'નકલ',
+ copyError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કોપી કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+C) का प्रयोग करें।',
+ cut: 'કાપવું',
+ cutError: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસ કટ કરવાની પરવાનગી નથી આપતી. (Ctrl/Cmd+X) નો ઉપયોગ કરો.',
+ paste: 'પેસ્ટ',
+ pasteArea: 'પેસ્ટ કરવાની જગ્યા',
+ pasteMsg: 'Ctrl/Cmd+V નો પ્રયોગ કરી પેસ્ટ કરો',
+ securityMsg: 'તમારા બ્રાઉઝર ની સુરક્ષિત સેટિંગસના કારણે,એડિટર તમારા કિલ્પબોર્ડ ડેટા ને કોપી નથી કરી શકતો. તમારે આ વિન્ડોમાં ફરીથી પેસ્ટ કરવું પડશે.',
+ title: 'પેસ્ટ'
+} );
diff --git a/sources/plugins/clipboard/lang/he.js b/sources/plugins/clipboard/lang/he.js
new file mode 100644
index 0000000..a3726c3
--- /dev/null
+++ b/sources/plugins/clipboard/lang/he.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'he', {
+ copy: 'העתקה',
+ copyError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות העתקה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+C).',
+ cut: 'גזירה',
+ cutError: 'הגדרות האבטחה בדפדפן שלך לא מאפשרות לעורך לבצע פעולות גזירה אוטומטיות. יש להשתמש במקלדת לשם כך (Ctrl/Cmd+X).',
+ paste: 'הדבקה',
+ pasteArea: 'איזור הדבקה',
+ pasteMsg: 'נא להדביק בתוך הקופסה באמצעות (Ctrl/Cmd+V) וללחוץ על אישור.',
+ securityMsg: 'עקב הגדרות אבטחה בדפדפן, לא ניתן לגשת אל לוח הגזירים (Clipboard) בצורה ישירה. נא להדביק שוב בחלון זה.',
+ title: 'הדבקה'
+} );
diff --git a/sources/plugins/clipboard/lang/hi.js b/sources/plugins/clipboard/lang/hi.js
new file mode 100644
index 0000000..738b0b9
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hi.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'hi', {
+ copy: 'कॉपी',
+ copyError: 'आपके ब्राआउज़र की सुरक्षा सॅटिन्ग्स ने कॉपी करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+C) का प्रयोग करें।',
+ cut: 'कट',
+ cutError: 'आपके ब्राउज़र की सुरक्षा सॅटिन्ग्स ने कट करने की अनुमति नहीं प्रदान की है। (Ctrl/Cmd+X) का प्रयोग करें।',
+ paste: 'पेस्ट',
+ pasteArea: 'Paste Area', // MISSING
+ pasteMsg: 'Ctrl/Cmd+V का प्रयोग करके पेस्ट करें और ठीक है करें.',
+ securityMsg: 'आपके ब्राउज़र की सुरक्षा आपके ब्राउज़र की सुरKश सैटिंग के कारण, एडिटर आपके क्लिपबोर्ड डेटा को नहीं पा सकता है. आपको उसे इस विन्डो में दोबारा पेस्ट करना होगा.',
+ title: 'पेस्ट'
+} );
diff --git a/sources/plugins/clipboard/lang/hr.js b/sources/plugins/clipboard/lang/hr.js
new file mode 100644
index 0000000..7366069
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hr.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'hr', {
+ copy: 'Kopiraj',
+ copyError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog kopiranja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+C).',
+ cut: 'Izreži',
+ cutError: 'Sigurnosne postavke Vašeg pretraživača ne dozvoljavaju operacije automatskog izrezivanja. Molimo koristite kraticu na tipkovnici (Ctrl/Cmd+X).',
+ paste: 'Zalijepi',
+ pasteArea: 'Prostor za ljepljenje',
+ pasteMsg: 'Molimo zaljepite unutar doljnjeg okvira koristeći tipkovnicu (Ctrl/Cmd+V) i kliknite OK.',
+ securityMsg: 'Zbog sigurnosnih postavki Vašeg pretraživača, editor nema direktan pristup Vašem međuspremniku. Potrebno je ponovno zalijepiti tekst u ovaj prozor.',
+ title: 'Zalijepi'
+} );
diff --git a/sources/plugins/clipboard/lang/hu.js b/sources/plugins/clipboard/lang/hu.js
new file mode 100644
index 0000000..b124e35
--- /dev/null
+++ b/sources/plugins/clipboard/lang/hu.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'hu', {
+ copy: 'Másolás',
+ 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).',
+ cut: 'Kivágás',
+ 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).',
+ paste: 'Beillesztés',
+ pasteArea: 'Beszúrás mező',
+ pasteMsg: 'Másolja be az alábbi mezőbe a Ctrl/Cmd+V billentyűk lenyomásával, majd nyomjon Rendben-t.',
+ securityMsg: 'A böngésző biztonsági beállításai miatt a szerkesztő nem képes hozzáférni a vágólap adataihoz. Illeszd be újra ebben az ablakban.',
+ title: 'Beillesztés'
+} );
diff --git a/sources/plugins/clipboard/lang/id.js b/sources/plugins/clipboard/lang/id.js
new file mode 100644
index 0000000..e7b40ad
--- /dev/null
+++ b/sources/plugins/clipboard/lang/id.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'id', {
+ copy: 'Salin',
+ copyError: 'Pengaturan keamanan peramban anda tidak mengizinkan editor untuk mengeksekusi operasi menyalin secara otomatis. Mohon gunakan papan tuts (Ctrl/Cmd+C)',
+ cut: 'Potong',
+ 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
+ paste: 'Tempel',
+ pasteArea: 'Area Tempel',
+ pasteMsg: 'Please paste inside the following box using the keyboard (Ctrl/Cmd+V) and hit OK', // MISSING
+ securityMsg: 'Karena pengaturan keamanan peramban anda, editor tida dapat mengakses data clipboard anda secara langsung. Anda harus mem-paste kembali pada halaman ini',
+ title: 'Tempel'
+} );
diff --git a/sources/plugins/clipboard/lang/is.js b/sources/plugins/clipboard/lang/is.js
new file mode 100644
index 0000000..6b36cef
--- /dev/null
+++ b/sources/plugins/clipboard/lang/is.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'is', {
+ copy: 'Afrita',
+ copyError: 'Öryggisstillingar vafrans þíns leyfa ekki afritun texta með músaraðgerð. Notaðu lyklaborðið í afrita (Ctrl/Cmd+C).',
+ cut: 'Klippa',
+ cutError: 'Öryggisstillingar vafrans þíns leyfa ekki klippingu texta með músaraðgerð. Notaðu lyklaborðið í klippa (Ctrl/Cmd+X).',
+ paste: 'Líma',
+ pasteArea: 'Paste Area', // MISSING
+ pasteMsg: 'Límdu í svæðið hér að neðan og (Ctrl/Cmd+V) og smelltu á OK.',
+ securityMsg: 'Vegna öryggisstillinga í vafranum þínum fær ritillinn ekki beinan aðgang að klippuborðinu. Þú verður að líma innihaldið aftur inn í þennan glugga.',
+ title: 'Líma'
+} );
diff --git a/sources/plugins/clipboard/lang/it.js b/sources/plugins/clipboard/lang/it.js
new file mode 100644
index 0000000..21f8815
--- /dev/null
+++ b/sources/plugins/clipboard/lang/it.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'it', {
+ copy: 'Copia',
+ copyError: 'Le impostazioni di sicurezza del browser non permettono di copiare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+C).',
+ cut: 'Taglia',
+ cutError: 'Le impostazioni di sicurezza del browser non permettono di tagliare automaticamente il testo. Usa la tastiera (Ctrl/Cmd+X).',
+ paste: 'Incolla',
+ pasteArea: 'Incolla',
+ pasteMsg: 'Incolla il testo all\'interno dell\'area sottostante usando la scorciatoia di tastiere (Ctrl/Cmd+V) e premi OK.',
+ securityMsg: 'A causa delle impostazioni di sicurezza del browser,l\'editor non è in grado di accedere direttamente agli appunti. E\' pertanto necessario incollarli di nuovo in questa finestra.',
+ title: 'Incolla'
+} );
diff --git a/sources/plugins/clipboard/lang/ja.js b/sources/plugins/clipboard/lang/ja.js
new file mode 100644
index 0000000..f099380
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ja.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'ja', {
+ copy: 'コピー',
+ copyError: 'ブラウザーのセキュリティ設定によりエディタのコピー操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+C)を使用してください。',
+ cut: '切り取り',
+ cutError: 'ブラウザーのセキュリティ設定によりエディタの切り取り操作を自動で実行することができません。実行するには手動でキーボードの(Ctrl/Cmd+X)を使用してください。',
+ paste: '貼り付け',
+ pasteArea: '貼り付け場所',
+ pasteMsg: 'キーボード(Ctrl/Cmd+V)を使用して、次の入力エリア内で貼り付けて、OKを押してください。',
+ securityMsg: 'ブラウザのセキュリティ設定により、エディタはクリップボードデータに直接アクセスすることができません。このウィンドウは貼り付け操作を行う度に表示されます。',
+ title: '貼り付け'
+} );
diff --git a/sources/plugins/clipboard/lang/ka.js b/sources/plugins/clipboard/lang/ka.js
new file mode 100644
index 0000000..e1af8cb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ka.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'ka', {
+ copy: 'ასლი',
+ copyError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ასლის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+C).',
+ cut: 'ამოჭრა',
+ cutError: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა ამოჭრის ოპერაციის ავტომატურად განხორციელების საშუალებას. გამოიყენეთ კლავიატურა ამისთვის (Ctrl/Cmd+X).',
+ paste: 'ჩასმა',
+ pasteArea: 'ჩასმის არე',
+ pasteMsg: 'ჩასვით ამ არის შიგნით კლავიატურის გამოყენებით (Ctrl/Cmd+V) და დააჭირეთ OK-ს',
+ securityMsg: 'თქვენი ბროუზერის უსაფრთხოების პარამეტრები არ იძლევა clipboard-ის მონაცემების წვდომის უფლებას. კიდევ უნდა ჩასვათ ტექსტი ამ ფანჯარაში.',
+ title: 'ჩასმა'
+} );
diff --git a/sources/plugins/clipboard/lang/km.js b/sources/plugins/clipboard/lang/km.js
new file mode 100644
index 0000000..32c30cb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/km.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'km', {
+ copy: 'ចម្លង',
+ copyError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះមិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ ចំលងអត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+C)។',
+ cut: 'កាត់យក',
+ cutError: 'ការកំណត់សុវត្ថភាពរបស់កម្មវិធីរុករករបស់លោកអ្នក នេះមិនអាចធ្វើកម្មវិធីតាក់តែងអត្ថបទ កាត់អត្ថបទយកដោយស្វ័យប្រវត្តបានឡើយ ។ សូមប្រើប្រាស់បន្សំ ឃីដូចនេះ (Ctrl/Cmd+X) ។',
+ paste: 'បិទភ្ជាប់',
+ pasteArea: 'តំបន់បិទភ្ជាប់',
+ pasteMsg: 'សូមចំលងអត្ថបទទៅដាក់ក្នុងប្រអប់ដូចខាងក្រោមដោយប្រើប្រាស់ ឃី (Ctrl/Cmd+V) ហើយចុច OK ។',
+ securityMsg: 'ព្រោះតែការកំណត់សុវត្ថិភាព ប្រអប់សរសេរមិនអាចចាប់យកទិន្នន័យពីក្តារតម្បៀតខ្ទាស់អ្នកដោយផ្ទាល់បានទេ។ អ្នកត្រូវចំលងដាក់វាម្តងទៀត ក្នុងផ្ទាំងនេះ។',
+ title: 'បិទភ្ជាប់'
+} );
diff --git a/sources/plugins/clipboard/lang/ko.js b/sources/plugins/clipboard/lang/ko.js
new file mode 100644
index 0000000..0a0d1e9
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ko.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'ko', {
+ copy: '복사',
+ copyError: '브라우저의 보안설정 때문에 복사할 수 없습니다. 키보드(Ctrl/Cmd+C)를 이용해서 복사하십시오.',
+ cut: '잘라내기',
+ cutError: '브라우저의 보안설정 때문에 잘라내기 기능을 실행할 수 없습니다. 키보드(Ctrl/Cmd+X)를 이용해서 잘라내기 하십시오',
+ paste: '붙여넣기',
+ pasteArea: '붙여넣기 범위',
+ pasteMsg: '키보드(Ctrl/Cmd+V)를 이용해서 상자안에 붙여넣고 확인 를 누르세요.',
+ securityMsg: '브라우저 보안 설정으로 인해, 클립보드에 직접 접근할 수 없습니다. 이 창에 다시 붙여넣기 하십시오.',
+ title: '붙여넣기'
+} );
diff --git a/sources/plugins/clipboard/lang/ku.js b/sources/plugins/clipboard/lang/ku.js
new file mode 100644
index 0000000..86e1778
--- /dev/null
+++ b/sources/plugins/clipboard/lang/ku.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'ku', {
+ copy: 'لەبەرگرتنەوە',
+ copyError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بەسەرنووسەکە لە لکاندنی دەقی خۆکارارنە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+C).',
+ cut: 'بڕین',
+ cutError: 'پارێزی وێبگەڕەکەت ڕێگەنادات بە سەرنووسەکە لەبڕینی خۆکارانە. تکایە لەبری ئەمە ئەم فەرمانە بەکاربهێنە بەداگرتنی کلیلی (Ctrl/Cmd+X).',
+ paste: 'لکاندن',
+ pasteArea: 'ناوچەی لکاندن',
+ pasteMsg: 'تکایە بیلکێنە لەناوەوەی ئەم سنوقە لەڕێی تەختەکلیلەکەت بە بەکارهێنانی کلیلی (Ctrl/Cmd+V) دووای کلیکی باشە بکە.',
+ securityMsg: 'بەهۆی شێوەپێدانی پارێزی وێبگەڕەکەت، سەرنووسەکه ناتوانێت دەستبگەیەنێت بەهەڵگیراوەکە ڕاستەوخۆ. بۆیه پێویسته دووباره بیلکێنیت لەم پەنجەرەیه.',
+ title: 'لکاندن'
+} );
diff --git a/sources/plugins/clipboard/lang/lt.js b/sources/plugins/clipboard/lang/lt.js
new file mode 100644
index 0000000..86ecbbb
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lt.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'lt', {
+ copy: 'Kopijuoti',
+ 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).',
+ cut: 'Iškirpti',
+ 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).',
+ paste: 'Įdėti',
+ pasteArea: 'Įkelti dalį',
+ pasteMsg: 'Žemiau esančiame įvedimo lauke įdėkite tekstą, naudodami klaviatūrą (Ctrl/Cmd+V) ir paspauskite mygtuką OK.',
+ securityMsg: 'Dėl jūsų naršyklės saugumo nustatymų, redaktorius negali tiesiogiai pasiekti laikinosios atminties. Jums reikia nukopijuoti dar kartą į šį langą.',
+ title: 'Įdėti'
+} );
diff --git a/sources/plugins/clipboard/lang/lv.js b/sources/plugins/clipboard/lang/lv.js
new file mode 100644
index 0000000..c762fc6
--- /dev/null
+++ b/sources/plugins/clipboard/lang/lv.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'lv', {
+ copy: 'Kopēt',
+ 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.',
+ cut: 'Izgriezt',
+ 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.',
+ paste: 'Ielīmēt',
+ pasteArea: 'Ielīmēšanas zona',
+ pasteMsg: 'Lūdzu, ievietojiet tekstu šajā laukumā, izmantojot klaviatūru (Ctrl/Cmd+V) un apstipriniet ar Darīts!.',
+ securityMsg: 'Jūsu pārlūka drošības uzstādījumu dēļ, nav iespējams tieši piekļūt jūsu starpliktuvei. Jums jāielīmē atkārtoti šajā logā.',
+ title: 'Ievietot'
+} );
diff --git a/sources/plugins/clipboard/lang/mk.js b/sources/plugins/clipboard/lang/mk.js
new file mode 100644
index 0000000..eb16066
--- /dev/null
+++ b/sources/plugins/clipboard/lang/mk.js
@@ -0,0 +1,15 @@
+/*
+Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.md or http://ckeditor.com/license
+*/
+CKEDITOR.plugins.setLang( 'clipboard', 'mk', {
+ copy: 'Копирај (Copy)',
+ copyError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши копирање. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
+ cut: 'Исечи (Cut)',
+ cutError: 'Опциите за безбедност на вашиот прелистувач не дозволуваат уредувачот автоматски да изврши сечење. Ве молиме употребете ја тастатурата. (Ctrl/Cmd+C)',
+ paste: 'Залепи (Paste)',
+ pasteArea: 'Простор за залепување',
+ pasteMsg: 'Ве молиме да залепите во следниот квадрат користејќи ја тастатурата (';
+ editor.fire( 'paste', evt.data );
+ }, false );
+
+ // Proceed with normal flow if reading file was aborted.
+ fileReader.addEventListener( 'abort', function() {
+ editor.fire( 'paste', evt.data );
+ }, false );
+
+ // Proceed with normal flow if reading file failed.
+ fileReader.addEventListener( 'error', function() {
+ editor.fire( 'paste', evt.data );
+ }, false );
+
+ fileReader.readAsDataURL( file );
+
+ latestId = dataObj.dataTransfer.id;
+
+ evt.stop();
+ }
+ }
+ }, null, null, 1 );
+ }
+
+ editor.on( 'paste', function( evt ) {
+ // Init `dataTransfer` if `paste` event was fired without it, so it will be always available.
+ if ( !evt.data.dataTransfer ) {
+ evt.data.dataTransfer = new CKEDITOR.plugins.clipboard.dataTransfer();
+ }
+
+ // If dataValue is already set (manually or by paste bin), so do not override it.
+ if ( evt.data.dataValue ) {
+ return;
+ }
+
+ var dataTransfer = evt.data.dataTransfer,
+ // IE support only text data and throws exception if we try to get html data.
+ // This html data object may also be empty if we drag content of the textarea.
+ value = dataTransfer.getData( 'text/html' );
+
+ if ( value ) {
+ evt.data.dataValue = value;
+ evt.data.type = 'html';
+ } else {
+ // Try to get text data otherwise.
+ value = dataTransfer.getData( 'text/plain' );
+
+ if ( value ) {
+ evt.data.dataValue = editor.editable().transformPlainTextToHtml( value );
+ evt.data.type = 'text';
+ }
+ }
+ }, null, null, 1 );
+
+ editor.on( 'paste', function( evt ) {
+ var data = evt.data.dataValue,
+ blockElements = CKEDITOR.dtd.$block;
+
+ // Filter webkit garbage.
+ if ( data.indexOf( 'Apple-' ) > -1 ) {
+ // Replace special webkit's with simple space, because webkit
+ // produces them even for normal spaces.
+ data = data.replace( / <\/span>/gi, ' ' );
+
+ // Strip around white-spaces when not in forced 'html' content type.
+ // This spans are created only when pasting plain text into Webkit,
+ // but for safety reasons remove them always.
+ if ( evt.data.type != 'html' ) {
+ data = data.replace( /]*>([^<]*)<\/span>/gi, function( all, spaces ) {
+ // Replace tabs with 4 spaces like Fx does.
+ return spaces.replace( /\t/g, ' ' );
+ } );
+ }
+
+ // This br is produced only when copying & pasting HTML content.
+ if ( data.indexOf( '
' ) > -1 ) {
+ evt.data.startsWithEOL = 1;
+ evt.data.preSniffing = 'html'; // Mark as not text.
+ data = data.replace( /
/, '' );
+ }
+
+ // Remove all other classes.
+ data = data.replace( /(<[^>]+) class="Apple-[^"]*"/gi, '$1' );
+ }
+
+ // Strip editable that was copied from inside. (#9534)
+ if ( data.match( /^<[^<]+cke_(editable|contents)/i ) ) {
+ var tmp,
+ editable_wrapper,
+ wrapper = new CKEDITOR.dom.element( 'div' );
+
+ wrapper.setHtml( data );
+ // Verify for sure and check for nested editor UI parts. (#9675)
+ while ( wrapper.getChildCount() == 1 &&
+ ( tmp = wrapper.getFirst() ) &&
+ tmp.type == CKEDITOR.NODE_ELEMENT && // Make sure first-child is element.
+ ( tmp.hasClass( 'cke_editable' ) || tmp.hasClass( 'cke_contents' ) ) ) {
+ wrapper = editable_wrapper = tmp;
+ }
+
+ // If editable wrapper was found strip it and bogus
(added on FF).
+ if ( editable_wrapper )
+ data = editable_wrapper.getHtml().replace( /
$/i, '' );
+ }
+
+ if ( CKEDITOR.env.ie ) {
+ //
- paragraphs can be separated by new \r\n ).
+ if ( !data.match( /^([^<]|
)*$/gi ) && !data.match( /^(
([^<]|
)*<\/p>|(\r\n))*$/gi ) )
+ return 'html';
+ } else if ( CKEDITOR.env.gecko ) {
+ // Text or
.
+ if ( !data.match( /^([^<]|
)*$/gi ) )
+ return 'html';
+ } else {
+ return 'html';
+ }
+
+ return 'htmlifiedtext';
+ }
+
+ // This function transforms what browsers produce when
+ // pasting plain text into editable element (see clipboard/paste.html TCs
+ // for more info) into correct HTML (similar to that produced by text2Html).
+ function htmlifiedTextHtmlification( config, data ) {
+ function repeatParagraphs( repeats ) {
+ // Repeat blocks floor((n+1)/2) times.
+ // Even number of repeats - add
at the beginning of last
. + return CKEDITOR.tools.repeat( '
', ~~( repeats / 2 ) ) + ( repeats % 2 == 1 ? '
' : '' );
+ }
+
+ // Replace adjacent white-spaces (EOLs too - Fx sometimes keeps them) with one space.
+ data = data.replace( /\s+/g, ' ' )
+ // Remove spaces from between tags.
+ .replace( /> +<' )
+ // Normalize XHTML syntax and upper cased
tags.
+ .replace( /
/gi, '
' );
+
+ // IE - lower cased tags.
+ data = data.replace( /<\/?[A-Z]+>/g, function( match ) {
+ return match.toLowerCase();
+ } );
+
+ // Don't touch single lines (no
) - nothing to do here.
+ if ( data.match( /^[^<]$/ ) )
+ return data;
+
+ // Webkit.
+ if ( CKEDITOR.env.webkit && data.indexOf( '
' + data.replace( /(
' + data.replace( /(
){2,}/g, function( match ) {
+ return repeatParagraphs( match.length / 4 );
+ } ) + '
element completely, because it's a basic structural element, + // so it tries to replace it with an element created based on the active enter mode, eventually doing nothing. + // + // Now you can sleep well. + return filters.plainText || ( filters.plainText = new CKEDITOR.filter( 'br' ) ); + } else if ( type == 'semantic-content' ) { + return filters.semanticContent || ( filters.semanticContent = createSemanticContentFilter() ); + } else if ( type ) { + // Create filter based on rules (string or object). + return new CKEDITOR.filter( type ); + } + + return null; + } + }; + } + + function filterContent( editor, data, filter ) { + var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data ), + writer = new CKEDITOR.htmlParser.basicWriter(); + + filter.applyTo( fragment, true, false, editor.activeEnterMode ); + fragment.writeHtml( writer ); + + return writer.getHtml(); + } + + function switchEnterMode( config, data ) { + if ( config.enterMode == CKEDITOR.ENTER_BR ) { + data = data.replace( /(<\/p>
)+/g, function( match ) {
+ return CKEDITOR.tools.repeat( ' This is some sample HTML content.
+ This sample shows how to use the
+ CKEditor Dialog API
+ to customize CKEditor dialog windows without changing the original editor code.
+ The following customizations are being done in the example below:
+
+ For details on how to create this setup check the source code of this sample page.
+ A custom dialog is added to the editors using the The below editor modify the dialog definition of the above added dialog using the
', match.length / 7 * 2 );
+ } ).replace( /<\/?p>/g, '' );
+ } else if ( config.enterMode == CKEDITOR.ENTER_DIV ) {
+ data = data.replace( /<(\/)?p>/g, '<$1div>' );
+ }
+
+ return data;
+ }
+
+ function preventDefaultSetDropEffectToNone( evt ) {
+ evt.data.preventDefault();
+ evt.data.$.dataTransfer.dropEffect = 'none';
+ }
+
+ function initDragDrop( editor ) {
+ var clipboard = CKEDITOR.plugins.clipboard;
+
+ editor.on( 'contentDom', function() {
+ var editable = editor.editable(),
+ dropTarget = CKEDITOR.plugins.clipboard.getDropTarget( editor ),
+ top = editor.ui.space( 'top' ),
+ bottom = editor.ui.space( 'bottom' );
+
+ // -------------- DRAGOVER TOP & BOTTOM --------------
+
+ // Not allowing dragging on toolbar and bottom (#12613).
+ clipboard.preventDefaultDropOnElement( top );
+ clipboard.preventDefaultDropOnElement( bottom );
+
+ // -------------- DRAGSTART --------------
+ // Listed on dragstart to mark internal and cross-editor drag & drop
+ // and save range and selected HTML.
+
+ editable.attachListener( dropTarget, 'dragstart', fireDragEvent );
+
+ // Make sure to reset data transfer (in case dragend was not called or was canceled).
+ editable.attachListener( editor, 'dragstart', clipboard.resetDragDataTransfer, clipboard, null, 1 );
+
+ // Create a dataTransfer object and save it globally.
+ editable.attachListener( editor, 'dragstart', function( evt ) {
+ clipboard.initDragDataTransfer( evt, editor );
+ }, null, null, 2 );
+
+ editable.attachListener( editor, 'dragstart', function() {
+ // Save drag range globally for cross editor D&D.
+ var dragRange = clipboard.dragRange = editor.getSelection().getRanges()[ 0 ];
+
+ // Store number of children, so we can later tell if any text node was split on drop. (#13011, #13447)
+ if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
+ clipboard.dragStartContainerChildCount = dragRange ? getContainerChildCount( dragRange.startContainer ) : null;
+ clipboard.dragEndContainerChildCount = dragRange ? getContainerChildCount( dragRange.endContainer ) : null;
+ }
+ }, null, null, 100 );
+
+ // -------------- DRAGEND --------------
+ // Clean up on dragend.
+
+ editable.attachListener( dropTarget, 'dragend', fireDragEvent );
+
+ // Init data transfer if someone wants to use it in dragend.
+ editable.attachListener( editor, 'dragend', clipboard.initDragDataTransfer, clipboard, null, 1 );
+
+ // When drag & drop is done we need to reset dataTransfer so the future
+ // external drop will be not recognize as internal.
+ editable.attachListener( editor, 'dragend', clipboard.resetDragDataTransfer, clipboard, null, 100 );
+
+ // -------------- DRAGOVER --------------
+ // We need to call preventDefault on dragover because otherwise if
+ // we drop image it will overwrite document.
+
+ editable.attachListener( dropTarget, 'dragover', function( evt ) {
+ var target = evt.data.getTarget();
+
+ // Prevent reloading page when dragging image on empty document (#12619).
+ if ( target && target.is && target.is( 'html' ) ) {
+ evt.data.preventDefault();
+ return;
+ }
+
+ // If we do not prevent default dragover on IE the file path
+ // will be loaded and we will lose content. On the other hand
+ // if we prevent it the cursor will not we shown, so we prevent
+ // dragover only on IE, on versions which support file API and only
+ // if the event contains files.
+ if ( CKEDITOR.env.ie &&
+ CKEDITOR.plugins.clipboard.isFileApiSupported &&
+ evt.data.$.dataTransfer.types.contains( 'Files' ) ) {
+ evt.data.preventDefault();
+ }
+ } );
+
+ // -------------- DROP --------------
+
+ editable.attachListener( dropTarget, 'drop', function( evt ) {
+ // Do nothing if event was already prevented. (#13879)
+ if ( evt.data.$.defaultPrevented ) {
+ return;
+ }
+
+ // Cancel native drop.
+ evt.data.preventDefault();
+
+ var target = evt.data.getTarget(),
+ readOnly = target.isReadOnly();
+
+ // Do nothing if drop on non editable element (#13015).
+ // The tag isn't editable (body is), but we want to allow drop on it
+ // (so it is possible to drop below editor contents).
+ if ( readOnly && !( target.type == CKEDITOR.NODE_ELEMENT && target.is( 'html' ) ) ) {
+ return;
+ }
+
+ // Getting drop position is one of the most complex parts.
+ var dropRange = clipboard.getRangeAtDropPosition( evt, editor ),
+ dragRange = clipboard.dragRange;
+
+ // Do nothing if it was not possible to get drop range.
+ if ( !dropRange ) {
+ return;
+ }
+
+ // Fire drop.
+ fireDragEvent( evt, dragRange, dropRange );
+ }, null, null, 9999 );
+
+ // Create dataTransfer or get it, if it was created before.
+ editable.attachListener( editor, 'drop', clipboard.initDragDataTransfer, clipboard, null, 1 );
+
+ // Execute drop action, fire paste.
+ editable.attachListener( editor, 'drop', function( evt ) {
+ var data = evt.data;
+
+ if ( !data ) {
+ return;
+ }
+
+ // Let user modify drag and drop range.
+ var dropRange = data.dropRange,
+ dragRange = data.dragRange,
+ dataTransfer = data.dataTransfer;
+
+ if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_INTERNAL ) {
+ // Execute drop with a timeout because otherwise selection, after drop,
+ // on IE is in the drag position, instead of drop position.
+ setTimeout( function() {
+ clipboard.internalDrop( dragRange, dropRange, dataTransfer, editor );
+ }, 0 );
+ } else if ( dataTransfer.getTransferType( editor ) == CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) {
+ crossEditorDrop( dragRange, dropRange, dataTransfer );
+ } else {
+ externalDrop( dropRange, dataTransfer );
+ }
+ }, null, null, 9999 );
+
+ // Cross editor drag and drop (drag in one Editor and drop in the other).
+ function crossEditorDrop( dragRange, dropRange, dataTransfer ) {
+ // Paste event should be fired before delete contents because otherwise
+ // Chrome have a problem with drop range (Chrome split the drop
+ // range container so the offset is bigger then container length).
+ dropRange.select();
+ firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
+
+ // Remove dragged content and make a snapshot.
+ dataTransfer.sourceEditor.fire( 'saveSnapshot' );
+
+ dataTransfer.sourceEditor.editable().extractHtmlFromRange( dragRange );
+
+ // Make some selection before saving snapshot, otherwise error will be thrown, because
+ // there will be no valid selection after content is removed.
+ dataTransfer.sourceEditor.getSelection().selectRanges( [ dragRange ] );
+ dataTransfer.sourceEditor.fire( 'saveSnapshot' );
+ }
+
+ // Drop from external source.
+ function externalDrop( dropRange, dataTransfer ) {
+ // Paste content into the drop position.
+ dropRange.select();
+
+ firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop' }, 1 );
+
+ // Usually we reset DataTranfer on dragend,
+ // but dragend is called on the same element as dragstart
+ // so it will not be called on on external drop.
+ clipboard.resetDragDataTransfer();
+ }
+
+ // Fire drag/drop events (dragstart, dragend, drop).
+ function fireDragEvent( evt, dragRange, dropRange ) {
+ var eventData = {
+ $: evt.data.$,
+ target: evt.data.getTarget()
+ };
+
+ if ( dragRange ) {
+ eventData.dragRange = dragRange;
+ }
+ if ( dropRange ) {
+ eventData.dropRange = dropRange;
+ }
+
+ if ( editor.fire( evt.name, eventData ) === false ) {
+ evt.data.preventDefault();
+ }
+ }
+
+ function getContainerChildCount( container ) {
+ if ( container.type != CKEDITOR.NODE_ELEMENT ) {
+ container = container.getParent();
+ }
+
+ return container.getChildCount();
+ }
+ } );
+ }
+
+ /**
+ * @singleton
+ * @class CKEDITOR.plugins.clipboard
+ */
+ CKEDITOR.plugins.clipboard = {
+ /**
+ * True if the environment allows to set data on copy or cut manually. This value is false in IE, because this browser
+ * shows the security dialog window when the script tries to set clipboard data and on iOS, because custom data is
+ * not saved to clipboard there.
+ *
+ * @since 4.5
+ * @readonly
+ * @property {Boolean}
+ */
+ isCustomCopyCutSupported: !CKEDITOR.env.ie && !CKEDITOR.env.iOS,
+
+ /**
+ * True if the environment supports MIME types and custom data types in dataTransfer/cliboardData getData/setData methods.
+ *
+ * @since 4.5
+ * @readonly
+ * @property {Boolean}
+ */
+ isCustomDataTypesSupported: !CKEDITOR.env.ie,
+
+ /**
+ * True if the environment supports File API.
+ *
+ * @since 4.5
+ * @readonly
+ * @property {Boolean}
+ */
+ isFileApiSupported: !CKEDITOR.env.ie || CKEDITOR.env.version > 9,
+
+ /**
+ * Main native paste event editable should listen to.
+ *
+ * **Note:** Safari does not like the {@link CKEDITOR.editor#beforePaste} event — it sometimes does not
+ * handle Ctrl+C properly. This is probably caused by some race condition between events.
+ * Chrome, Firefox and Edge work well with both events, so it is better to use {@link CKEDITOR.editor#paste}
+ * which will handle pasting from e.g. browsers' menu bars.
+ * IE7/8 does not like the {@link CKEDITOR.editor#paste} event for which it is throwing random errors.
+ *
+ * @since 4.5
+ * @readonly
+ * @property {String}
+ */
+ mainPasteEvent: ( CKEDITOR.env.ie && !CKEDITOR.env.edge ) ? 'beforepaste' : 'paste',
+
+ /**
+ * Returns `true` if it is expected that a browser provides HTML data through the Clipboard API.
+ * If not, this method returns `false` and as a result CKEditor will use the paste bin. Read more in
+ * the [Clipboard Integration](http://docs.ckeditor.com/#!/guide/dev_clipboard-section-clipboard-api) guide.
+ *
+ * @since 4.5.2
+ * @returns {Boolean}
+ */
+ canClipboardApiBeTrusted: function( dataTransfer, editor ) {
+ // If it's an internal or cross-editor data transfer, then it means that custom cut/copy/paste support works
+ // and that the data were put manually on the data transfer so we can be sure that it's available.
+ if ( dataTransfer.getTransferType( editor ) != CKEDITOR.DATA_TRANSFER_EXTERNAL ) {
+ return true;
+ }
+
+ // In Chrome we can trust Clipboard API, with the exception of Chrome on Android (in both - mobile and desktop modes), where
+ // clipboard API is not available so we need to check it (#13187).
+ if ( CKEDITOR.env.chrome && !dataTransfer.isEmpty() ) {
+ return true;
+ }
+
+ // Because of a Firefox bug HTML data are not available in some cases (e.g. paste from Word), in such cases we
+ // need to use the pastebin (#13528, https://bugzilla.mozilla.org/show_bug.cgi?id=1183686).
+ if ( CKEDITOR.env.gecko && ( dataTransfer.getData( 'text/html' ) || dataTransfer.getFilesCount() ) ) {
+ return true;
+ }
+
+ // In Safari and IE HTML data is not available though the Clipboard API.
+ // In Edge things are a bit messy at the moment -
+ // https://connect.microsoft.com/IE/feedback/details/1572456/edge-clipboard-api-text-html-content-messed-up-in-event-clipboarddata
+ // It is safer to use the paste bin in unknown cases.
+ return false;
+ },
+
+ /**
+ * Returns the element that should be used as the target for the drop event.
+ *
+ * @since 4.5
+ * @param {CKEDITOR.editor} editor The editor instance.
+ * @returns {CKEDITOR.dom.domObject} the element that should be used as the target for the drop event.
+ */
+ getDropTarget: function( editor ) {
+ var editable = editor.editable();
+
+ // #11123 Firefox needs to listen on document, because otherwise event won't be fired.
+ // #11086 IE8 cannot listen on document.
+ if ( ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) || editable.isInline() ) {
+ return editable;
+ } else {
+ return editor.document;
+ }
+ },
+
+ /**
+ * IE 8 & 9 split text node on drop so the first node contains the
+ * text before the drop position and the second contains the rest. If you
+ * drag the content from the same node you will be not be able to get
+ * it (the range becomes invalid), so you need to join them back.
+ *
+ * Note that the first node in IE 8 & 9 is the original node object
+ * but with shortened content.
+ *
+ * Before:
+ * --- Text Node A ----------------------------------
+ * /\
+ * Drag position
+ *
+ * After (IE 8 & 9):
+ * --- Text Node A ----- --- Text Node B -----------
+ * /\ /\
+ * Drop position Drag position
+ * (invalid)
+ *
+ * After (other browsers):
+ * --- Text Node A ----------------------------------
+ * /\ /\
+ * Drop position Drag position
+ *
+ * **Note:** This function is in the public scope for tests usage only.
+ *
+ * @since 4.5
+ * @private
+ * @param {CKEDITOR.dom.range} dragRange The drag range.
+ * @param {CKEDITOR.dom.range} dropRange The drop range.
+ * @param {Number} preDragStartContainerChildCount The number of children of the drag range start container before the drop.
+ * @param {Number} preDragEndContainerChildCount The number of children of the drag range end container before the drop.
+ */
+ fixSplitNodesAfterDrop: function( dragRange, dropRange, preDragStartContainerChildCount, preDragEndContainerChildCount ) {
+ var dropContainer = dropRange.startContainer;
+
+ if (
+ typeof preDragEndContainerChildCount != 'number' ||
+ typeof preDragStartContainerChildCount != 'number'
+ ) {
+ return;
+ }
+
+ // We are only concerned about ranges anchored in elements.
+ if ( dropContainer.type != CKEDITOR.NODE_ELEMENT ) {
+ return;
+ }
+
+ if ( handleContainer( dragRange.startContainer, dropContainer, preDragStartContainerChildCount ) ) {
+ return;
+ }
+
+ if ( handleContainer( dragRange.endContainer, dropContainer, preDragEndContainerChildCount ) ) {
+ return;
+ }
+
+ function handleContainer( dragContainer, dropContainer, preChildCount ) {
+ var dragElement = dragContainer;
+ if ( dragElement.type == CKEDITOR.NODE_TEXT ) {
+ dragElement = dragContainer.getParent();
+ }
+
+ if ( dragElement.equals( dropContainer ) && preChildCount != dropContainer.getChildCount() ) {
+ applyFix( dropRange );
+ return true;
+ }
+ }
+
+ function applyFix( dropRange ) {
+ var nodeBefore = dropRange.startContainer.getChild( dropRange.startOffset - 1 ),
+ nodeAfter = dropRange.startContainer.getChild( dropRange.startOffset );
+
+ if (
+ nodeBefore && nodeBefore.type == CKEDITOR.NODE_TEXT &&
+ nodeAfter && nodeAfter.type == CKEDITOR.NODE_TEXT
+ ) {
+ var offset = nodeBefore.getLength();
+
+ nodeBefore.setText( nodeBefore.getText() + nodeAfter.getText() );
+ nodeAfter.remove();
+
+ dropRange.setStart( nodeBefore, offset );
+ dropRange.collapse( true );
+ }
+ }
+ },
+
+ /**
+ * Checks whether turning the drag range into bookmarks will invalidate the drop range.
+ * This usually happens when the drop range shares the container with the drag range and is
+ * located after the drag range, but there are countless edge cases.
+ *
+ * This function is stricly related to {@link #internalDrop} which toggles
+ * order in which it creates bookmarks for both ranges based on a value returned
+ * by this method. In some cases this method returns a value which is not necessarily
+ * true in terms of what it was meant to check, but it is convenient, because
+ * we know how it is interpreted in {@link #internalDrop}, so the correct
+ * behavior of the entire algorithm is assured.
+ *
+ * **Note:** This function is in the public scope for tests usage only.
+ *
+ * @since 4.5
+ * @private
+ * @param {CKEDITOR.dom.range} dragRange The first range to compare.
+ * @param {CKEDITOR.dom.range} dropRange The second range to compare.
+ * @returns {Boolean} `true` if the first range is before the second range.
+ */
+ isDropRangeAffectedByDragRange: function( dragRange, dropRange ) {
+ var dropContainer = dropRange.startContainer,
+ dropOffset = dropRange.endOffset;
+
+ // Both containers are the same and drop offset is at the same position or later.
+ // " A L] A " " M A "
+ // ^ ^
+ if ( dragRange.endContainer.equals( dropContainer ) && dragRange.endOffset <= dropOffset ) {
+ return true;
+ }
+
+ // Bookmark for drag start container will mess up with offsets.
+ // " O [L A " " M A "
+ // ^ ^
+ if (
+ dragRange.startContainer.getParent().equals( dropContainer ) &&
+ dragRange.startContainer.getIndex() < dropOffset
+ ) {
+ return true;
+ }
+
+ // Bookmark for drag end container will mess up with offsets.
+ // " O] L A " " M A "
+ // ^ ^
+ if (
+ dragRange.endContainer.getParent().equals( dropContainer ) &&
+ dragRange.endContainer.getIndex() < dropOffset
+ ) {
+ return true;
+ }
+
+ return false;
+ },
+
+ /**
+ * Internal drag and drop (drag and drop in the same editor instance).
+ *
+ * **Note:** This function is in the public scope for tests usage only.
+ *
+ * @since 4.5
+ * @private
+ * @param {CKEDITOR.dom.range} dragRange The first range to compare.
+ * @param {CKEDITOR.dom.range} dropRange The second range to compare.
+ * @param {CKEDITOR.plugins.clipboard.dataTransfer} dataTransfer
+ * @param {CKEDITOR.editor} editor
+ */
+ internalDrop: function( dragRange, dropRange, dataTransfer, editor ) {
+ var clipboard = CKEDITOR.plugins.clipboard,
+ editable = editor.editable(),
+ dragBookmark, dropBookmark, isDropRangeAffected;
+
+ // Save and lock snapshot so there will be only
+ // one snapshot for both remove and insert content.
+ editor.fire( 'saveSnapshot' );
+ editor.fire( 'lockSnapshot', { dontUpdate: 1 } );
+
+ if ( CKEDITOR.env.ie && CKEDITOR.env.version < 10 ) {
+ this.fixSplitNodesAfterDrop(
+ dragRange,
+ dropRange,
+ clipboard.dragStartContainerChildCount,
+ clipboard.dragEndContainerChildCount
+ );
+ }
+
+ // Because we manipulate multiple ranges we need to do it carefully,
+ // changing one range (event creating a bookmark) may make other invalid.
+ // We need to change ranges into bookmarks so we can manipulate them easily in the future.
+ // We can change the range which is later in the text before we change the preceding range.
+ // We call isDropRangeAffectedByDragRange to test the order of ranges.
+ isDropRangeAffected = this.isDropRangeAffectedByDragRange( dragRange, dropRange );
+ if ( !isDropRangeAffected ) {
+ dragBookmark = dragRange.createBookmark( false );
+ }
+ dropBookmark = dropRange.clone().createBookmark( false );
+ if ( isDropRangeAffected ) {
+ dragBookmark = dragRange.createBookmark( false );
+ }
+
+ // Check if drop range is inside range.
+ // This is an edge case when we drop something on editable's margin/padding.
+ // That space is not treated as a part of the range we drag, so it is possible to drop there.
+ // When we drop, browser tries to find closest drop position and it finds it inside drag range. (#13453)
+ var startNode = dragBookmark.startNode,
+ endNode = dragBookmark.endNode,
+ dropNode = dropBookmark.startNode,
+ dropInsideDragRange =
+ // Must check endNode because dragRange could be collapsed in some edge cases (simulated DnD).
+ endNode &&
+ ( startNode.getPosition( dropNode ) & CKEDITOR.POSITION_PRECEDING ) &&
+ ( endNode.getPosition( dropNode ) & CKEDITOR.POSITION_FOLLOWING );
+
+ // If the drop range happens to be inside drag range change it's position to the beginning of the drag range.
+ if ( dropInsideDragRange ) {
+ // We only change position of bookmark span that is connected with dropBookmark.
+ // dropRange will be overwritten and set to the dropBookmark later.
+ dropNode.insertBefore( startNode );
+ }
+
+ // No we can safely delete content for the drag range...
+ dragRange = editor.createRange();
+ dragRange.moveToBookmark( dragBookmark );
+ editable.extractHtmlFromRange( dragRange, 1 );
+
+ // ...and paste content into the drop position.
+ dropRange = editor.createRange();
+ dropRange.moveToBookmark( dropBookmark );
+
+ // We do not select drop range, because of may be in the place we can not set the selection
+ // (e.g. between blocks, in case of block widget D&D). We put range to the paste event instead.
+ firePasteEvents( editor, { dataTransfer: dataTransfer, method: 'drop', range: dropRange }, 1 );
+
+ editor.fire( 'unlockSnapshot' );
+ },
+
+ /**
+ * Gets the range from the `drop` event.
+ *
+ * @since 4.5
+ * @param {Object} domEvent A native DOM drop event object.
+ * @param {CKEDITOR.editor} editor The source editor instance.
+ * @returns {CKEDITOR.dom.range} range at drop position.
+ */
+ getRangeAtDropPosition: function( dropEvt, editor ) {
+ var $evt = dropEvt.data.$,
+ x = $evt.clientX,
+ y = $evt.clientY,
+ $range,
+ defaultRange = editor.getSelection( true ).getRanges()[ 0 ],
+ range = editor.createRange();
+
+ // Make testing possible.
+ if ( dropEvt.data.testRange )
+ return dropEvt.data.testRange;
+
+ // Webkits.
+ if ( document.caretRangeFromPoint ) {
+ $range = editor.document.$.caretRangeFromPoint( x, y );
+ range.setStart( CKEDITOR.dom.node( $range.startContainer ), $range.startOffset );
+ range.collapse( true );
+ }
+ // FF.
+ else if ( $evt.rangeParent ) {
+ range.setStart( CKEDITOR.dom.node( $evt.rangeParent ), $evt.rangeOffset );
+ range.collapse( true );
+ }
+ // IEs 9+.
+ // We check if editable is focused to make sure that it's an internal DnD. External DnD must use the second
+ // mechanism because of http://dev.ckeditor.com/ticket/13472#comment:6.
+ else if ( CKEDITOR.env.ie && CKEDITOR.env.version > 8 && defaultRange && editor.editable().hasFocus ) {
+ // On IE 9+ range by default is where we expected it.
+ // defaultRange may be undefined if dragover was canceled (file drop).
+ return defaultRange;
+ }
+ // IE 8 and all IEs if !defaultRange or external DnD.
+ else if ( document.body.createTextRange ) {
+ // To use this method we need a focus (which may be somewhere else in case of external drop).
+ editor.focus();
+
+ $range = editor.document.getBody().$.createTextRange();
+ try {
+ var sucess = false;
+
+ // If user drop between text line IEs moveToPoint throws exception:
+ //
+ // Lorem ipsum pulvinar purus et euismod
+ //
+ // dolor sit amet,| consectetur adipiscing
+ // *
+ // vestibulum tincidunt augue eget tempus.
+ //
+ // * - drop position
+ // | - expected cursor position
+ //
+ // So we try to call moveToPoint with +-1px up to +-20px above or
+ // below original drop position to find nearest good drop position.
+ for ( var i = 0; i < 20 && !sucess; i++ ) {
+ if ( !sucess ) {
+ try {
+ $range.moveToPoint( x, y - i );
+ sucess = true;
+ } catch ( err ) {
+ }
+ }
+ if ( !sucess ) {
+ try {
+ $range.moveToPoint( x, y + i );
+ sucess = true;
+ } catch ( err ) {
+ }
+ }
+ }
+
+ if ( sucess ) {
+ var id = 'cke-temp-' + ( new Date() ).getTime();
+ $range.pasteHTML( '\u200b' );
+
+ var span = editor.document.getById( id );
+ range.moveToPosition( span, CKEDITOR.POSITION_BEFORE_START );
+ span.remove();
+ } else {
+ // If the fist method does not succeed we might be next to
+ // the short element (like header):
+ //
+ // Lorem ipsum pulvinar purus et euismod.
+ //
+ //
+ // SOME HEADER| *
+ //
+ //
+ // vestibulum tincidunt augue eget tempus.
+ //
+ // * - drop position
+ // | - expected cursor position
+ //
+ // In such situation elementFromPoint returns proper element. Using getClientRect
+ // it is possible to check if the cursor should be at the beginning or at the end
+ // of paragraph.
+ var $element = editor.document.$.elementFromPoint( x, y ),
+ element = new CKEDITOR.dom.element( $element ),
+ rect;
+
+ if ( !element.equals( editor.editable() ) && element.getName() != 'html' ) {
+ rect = element.getClientRect();
+
+ if ( x < rect.left ) {
+ range.setStartAt( element, CKEDITOR.POSITION_AFTER_START );
+ range.collapse( true );
+ } else {
+ range.setStartAt( element, CKEDITOR.POSITION_BEFORE_END );
+ range.collapse( true );
+ }
+ }
+ // If drop happens on no element elementFromPoint returns html or body.
+ //
+ // * |Lorem ipsum pulvinar purus et euismod.
+ //
+ // vestibulum tincidunt augue eget tempus.
+ //
+ // * - drop position
+ // | - expected cursor position
+ //
+ // In such case we can try to use default selection. If startContainer is not
+ // 'editable' element it is probably proper selection.
+ else if ( defaultRange && defaultRange.startContainer &&
+ !defaultRange.startContainer.equals( editor.editable() ) ) {
+ return defaultRange;
+
+ // Otherwise we can not find any drop position and we have to return null
+ // and cancel drop event.
+ } else {
+ return null;
+ }
+
+ }
+ } catch ( err ) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+
+ return range;
+ },
+
+ /**
+ * This function tries to link the `evt.data.dataTransfer` property of the {@link CKEDITOR.editor#dragstart},
+ * {@link CKEDITOR.editor#dragend} and {@link CKEDITOR.editor#drop} events to a single
+ * {@link CKEDITOR.plugins.clipboard.dataTransfer} object.
+ *
+ * This method is automatically used by the core of the drag and drop functionality and
+ * usually does not have to be called manually when using the drag and drop events.
+ *
+ * This method behaves differently depending on whether the drag and drop events were fired
+ * artificially (to represent a non-native drag and drop) or whether they were caused by the native drag and drop.
+ *
+ * If the native event is not available, then it will create a new {@link CKEDITOR.plugins.clipboard.dataTransfer}
+ * instance (if it does not exist already) and will link it to this and all following event objects until
+ * the {@link #resetDragDataTransfer} method is called. It means that all three drag and drop events must be fired
+ * in order to ensure that the data transfer is bound correctly.
+ *
+ * If the native event is available, then the {@link CKEDITOR.plugins.clipboard.dataTransfer} is identified
+ * by its ID and a new instance is assigned to the `evt.data.dataTransfer` only if the ID changed or
+ * the {@link #resetDragDataTransfer} method was called.
+ *
+ * @since 4.5
+ * @param {CKEDITOR.dom.event} [evt] A drop event object.
+ * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
+ */
+ initDragDataTransfer: function( evt, sourceEditor ) {
+ // Create a new dataTransfer object based on the drop event.
+ // If this event was used on dragstart to create dataTransfer
+ // both dataTransfer objects will have the same id.
+ var nativeDataTransfer = evt.data.$ ? evt.data.$.dataTransfer : null,
+ dataTransfer = new this.dataTransfer( nativeDataTransfer, sourceEditor );
+
+ if ( !nativeDataTransfer ) {
+ // No native event.
+ if ( this.dragData ) {
+ dataTransfer = this.dragData;
+ } else {
+ this.dragData = dataTransfer;
+ }
+ } else {
+ // Native event. If there is the same id we will replace dataTransfer with the one
+ // created on drag, because it contains drag editor, drag content and so on.
+ // Otherwise (in case of drag from external source) we save new object to
+ // the global clipboard.dragData.
+ if ( this.dragData && dataTransfer.id == this.dragData.id ) {
+ dataTransfer = this.dragData;
+ } else {
+ this.dragData = dataTransfer;
+ }
+ }
+
+ evt.data.dataTransfer = dataTransfer;
+ },
+
+ /**
+ * Removes the global {@link #dragData} so the next call to {@link #initDragDataTransfer}
+ * always creates a new instance of {@link CKEDITOR.plugins.clipboard.dataTransfer}.
+ *
+ * @since 4.5
+ */
+ resetDragDataTransfer: function() {
+ this.dragData = null;
+ },
+
+ /**
+ * Global object storing the data transfer of the current drag and drop operation.
+ * Do not use it directly, use {@link #initDragDataTransfer} and {@link #resetDragDataTransfer}.
+ *
+ * Note: This object is global (meaning that it is not related to a single editor instance)
+ * in order to handle drag and drop from one editor into another.
+ *
+ * @since 4.5
+ * @private
+ * @property {CKEDITOR.plugins.clipboard.dataTransfer} dragData
+ */
+
+ /**
+ * Range object to save the drag range and remove its content after the drop.
+ *
+ * @since 4.5
+ * @private
+ * @property {CKEDITOR.dom.range} dragRange
+ */
+
+ /**
+ * Initializes and links data transfer objects based on the paste event. If the data
+ * transfer object was already initialized on this event, the function will
+ * return that object. In IE it is not possible to link copy/cut and paste events
+ * so the method always returns a new object. The same happens if there is no paste event
+ * passed to the method.
+ *
+ * @since 4.5
+ * @param {CKEDITOR.dom.event} [evt] A paste event object.
+ * @param {CKEDITOR.editor} [sourceEditor] The source editor instance.
+ * @returns {CKEDITOR.plugins.clipboard.dataTransfer} The data transfer object.
+ */
+ initPasteDataTransfer: function( evt, sourceEditor ) {
+ if ( !this.isCustomCopyCutSupported ) {
+ // Edge does not support custom copy/cut, but it have some useful data in the clipboardData (#13755).
+ return new this.dataTransfer( ( CKEDITOR.env.edge && evt && evt.data.$ && evt.data.$.clipboardData ) || null, sourceEditor );
+ } else if ( evt && evt.data && evt.data.$ ) {
+ var dataTransfer = new this.dataTransfer( evt.data.$.clipboardData, sourceEditor );
+
+ if ( this.copyCutData && dataTransfer.id == this.copyCutData.id ) {
+ dataTransfer = this.copyCutData;
+ dataTransfer.$ = evt.data.$.clipboardData;
+ } else {
+ this.copyCutData = dataTransfer;
+ }
+
+ return dataTransfer;
+ } else {
+ return new this.dataTransfer( null, sourceEditor );
+ }
+ },
+
+ /**
+ * Prevents dropping on the specified element.
+ *
+ * @since 4.5
+ * @param {CKEDITOR.dom.element} element The element on which dropping should be disabled.
+ */
+ preventDefaultDropOnElement: function( element ) {
+ element && element.on( 'dragover', preventDefaultSetDropEffectToNone );
+ }
+ };
+
+ // Data type used to link drag and drop events.
+ //
+ // In IE URL data type is buggie and there is no way to mark drag & drop without
+ // modifying text data (which would be displayed if user drop content to the textarea)
+ // so we just read dragged text.
+ //
+ // In Chrome and Firefox we can use custom data types.
+ var clipboardIdDataType = CKEDITOR.plugins.clipboard.isCustomDataTypesSupported ? 'cke/id' : 'Text';
+ /**
+ * Facade for the native `dataTransfer`/`clipboadData` object to hide all differences
+ * between browsers.
+ *
+ * @since 4.5
+ * @class CKEDITOR.plugins.clipboard.dataTransfer
+ * @constructor Creates a class instance.
+ * @param {Object} [nativeDataTransfer] A native data transfer object.
+ * @param {CKEDITOR.editor} [editor] The source editor instance. If the editor is defined, dataValue will
+ * be created based on the editor content and the type will be 'html'.
+ */
+ CKEDITOR.plugins.clipboard.dataTransfer = function( nativeDataTransfer, editor ) {
+ if ( nativeDataTransfer ) {
+ this.$ = nativeDataTransfer;
+ }
+
+ this._ = {
+ metaRegExp: /^This is some sample HTML content.
'
+ * }
+ *
+ * // Example 2:
+ * // Complete sample with document.getById() call when the "Ok" button is clicked.
+ * var dialogDefinition = {
+ * title: 'Sample dialog',
+ * minWidth: 300,
+ * minHeight: 200,
+ * onOk: function() {
+ * // "this" is now a CKEDITOR.dialog object.
+ * var document = this.getElement().getDocument();
+ * // document = CKEDITOR.dom.document
+ * var element = document.getById( 'myDiv' );
+ * if ( element )
+ * alert( element.getHtml() );
+ * },
+ * contents: [
+ * {
+ * id: 'tab1',
+ * label: '',
+ * title: '',
+ * elements: [
+ * {
+ * type: 'html',
+ * html: '' +
+ '
' +
+ ' ' +
+ '' +
+ ' ' +
+ '
' +
+ '' +
+ ' ' +
+ '' +
+ ' ' +
+ ' ' +
+ '' +
+ ' ' ];
+ for ( i = 0; i < childHtmlList.length; i++ ) {
+ var className = 'cke_dialog_ui_hbox_child',
+ styles = [];
+ if ( i === 0 ) {
+ className = 'cke_dialog_ui_hbox_first';
+ }
+ if ( i == childHtmlList.length - 1 ) {
+ className = 'cke_dialog_ui_hbox_last';
+ }
+
+ html.push( ' ' );
+ return html.join( '' );
+ };
+
+ var attribs = { role: 'presentation' };
+ elementDefinition && elementDefinition.align && ( attribs.align = elementDefinition.align );
+
+ CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type: 'hbox' }, htmlList, 'table', styles, attribs, innerHTML );
+ },
+
+ /**
+ * Vertical layout box for dialog UI elements.
+ *
+ * @class CKEDITOR.ui.dialog.vbox
+ * @extends CKEDITOR.ui.dialog.hbox
+ * @constructor Creates a vbox class instance.
+ * @param {CKEDITOR.dialog} dialog Parent dialog object.
+ * @param {Array} childObjList
+ * Array of {@link CKEDITOR.ui.dialog.uiElement} objects inside this container.
+ * @param {Array} childHtmlList
+ * Array of HTML code that correspond to the HTML output of all the
+ * objects in childObjList.
+ * @param {Array} htmlList Array of HTML code that this element will output to.
+ * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
+ * The element definition. Accepted fields:
+ *
+ * * `width` (Optional) The width of the layout.
+ * * `heights` (Optional) The heights of individual cells.
+ * * `align` (Optional) The alignment of the layout.
+ * * `padding` (Optional) The padding width inside child cells.
+ * * `expand` (Optional) Whether the layout should expand
+ * vertically to fill its container.
+ */
+ vbox: function( dialog, childObjList, childHtmlList, htmlList, elementDefinition ) {
+ if ( arguments.length < 3 )
+ return;
+
+ this._ || ( this._ = {} );
+
+ var children = this._.children = childObjList,
+ width = elementDefinition && elementDefinition.width || null,
+ heights = elementDefinition && elementDefinition.heights || null;
+ /** @ignore */
+ var innerHTML = function() {
+ var html = [ ' 0 ) {
+ html.push( 'style="' + styles.join( '; ' ) + '" ' );
+ }
+ html.push( '>', childHtmlList[ i ], ' ' );
+ }
+ html.push( '' );
+ for ( var i = 0; i < childHtmlList.length; i++ ) {
+ var styles = [];
+ html.push( '
' );
+ return html.join( '' );
+ };
+ CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition || { type: 'vbox' }, htmlList, 'div', null, { role: 'presentation' }, innerHTML );
+ }
+ };
+ } )();
+
+ /** @class CKEDITOR.ui.dialog.uiElement */
+ CKEDITOR.ui.dialog.uiElement.prototype = {
+ /**
+ * Gets the root DOM element of this dialog UI object.
+ *
+ * uiElement.getElement().hide();
+ *
+ * @returns {CKEDITOR.dom.element} Root DOM element of UI object.
+ */
+ getElement: function() {
+ return CKEDITOR.document.getById( this.domId );
+ },
+
+ /**
+ * Gets the DOM element that the user inputs values.
+ *
+ * This function is used by {@link #setValue}, {@link #getValue} and {@link #focus}. It should
+ * be overrided in child classes where the input element isn't the root
+ * element.
+ *
+ * var rawValue = textInput.getInputElement().$.value;
+ *
+ * @returns {CKEDITOR.dom.element} The element where the user input values.
+ */
+ getInputElement: function() {
+ return this.getElement();
+ },
+
+ /**
+ * Gets the parent dialog object containing this UI element.
+ *
+ * var dialog = uiElement.getDialog();
+ *
+ * @returns {CKEDITOR.dialog} Parent dialog object.
+ */
+ getDialog: function() {
+ return this._.dialog;
+ },
+
+ /**
+ * Sets the value of this dialog UI object.
+ *
+ * uiElement.setValue( 'Dingo' );
+ *
+ * @chainable
+ * @param {Object} value The new value.
+ * @param {Boolean} noChangeEvent Internal commit, to supress `change` event on this element.
+ */
+ setValue: function( value, noChangeEvent ) {
+ this.getInputElement().setValue( value );
+ !noChangeEvent && this.fire( 'change', { value: value } );
+ return this;
+ },
+
+ /**
+ * Gets the current value of this dialog UI object.
+ *
+ * var myValue = uiElement.getValue();
+ *
+ * @returns {Object} The current value.
+ */
+ getValue: function() {
+ return this.getInputElement().getValue();
+ },
+
+ /**
+ * Tells whether the UI object's value has changed.
+ *
+ * if ( uiElement.isChanged() )
+ * confirm( 'Value changed! Continue?' );
+ *
+ * @returns {Boolean} `true` if changed, `false` if not changed.
+ */
+ isChanged: function() {
+ // Override in input classes.
+ return false;
+ },
+
+ /**
+ * Selects the parent tab of this element. Usually called by focus() or overridden focus() methods.
+ *
+ * focus : function() {
+ * this.selectParentTab();
+ * // do something else.
+ * }
+ *
+ * @chainable
+ */
+ selectParentTab: function() {
+ var element = this.getInputElement(),
+ cursor = element,
+ tabId;
+ while ( ( cursor = cursor.getParent() ) && cursor.$.className.search( 'cke_dialog_page_contents' ) == -1 ) {
+
+ }
+
+ // Some widgets don't have parent tabs (e.g. OK and Cancel buttons).
+ if ( !cursor )
+ return this;
+
+ tabId = cursor.getAttribute( 'name' );
+ // Avoid duplicate select.
+ if ( this._.dialog._.currentTabId != tabId )
+ this._.dialog.selectPage( tabId );
+ return this;
+ },
+
+ /**
+ * Puts the focus to the UI object. Switches tabs if the UI object isn't in the active tab page.
+ *
+ * uiElement.focus();
+ *
+ * @chainable
+ */
+ focus: function() {
+ this.selectParentTab().getInputElement().focus();
+ return this;
+ },
+
+ /**
+ * Registers the `on*` event handlers defined in the element definition.
+ *
+ * The default behavior of this function is:
+ *
+ * 1. If the on* event is defined in the class's eventProcesors list,
+ * then the registration is delegated to the corresponding function
+ * in the eventProcessors list.
+ * 2. If the on* event is not defined in the eventProcessors list, then
+ * register the event handler under the corresponding DOM event of
+ * the UI element's input DOM element (as defined by the return value
+ * of {@link #getInputElement}).
+ *
+ * This function is only called at UI element instantiation, but can
+ * be overridded in child classes if they require more flexibility.
+ *
+ * @chainable
+ * @param {CKEDITOR.dialog.definition.uiElement} definition The UI element
+ * definition.
+ */
+ registerEvents: function( definition ) {
+ var regex = /^on([A-Z]\w+)/,
+ match;
+
+ var registerDomEvent = function( uiElement, dialog, eventName, func ) {
+ dialog.on( 'load', function() {
+ uiElement.getInputElement().on( eventName, func, uiElement );
+ } );
+ };
+
+ for ( var i in definition ) {
+ if ( !( match = i.match( regex ) ) )
+ continue;
+ if ( this.eventProcessors[ i ] )
+ this.eventProcessors[ i ].call( this, this._.dialog, definition[ i ] );
+ else
+ registerDomEvent( this, this._.dialog, match[ 1 ].toLowerCase(), definition[ i ] );
+ }
+
+ return this;
+ },
+
+ /**
+ * The event processor list used by
+ * {@link CKEDITOR.ui.dialog.uiElement#getInputElement} at UI element
+ * instantiation. The default list defines three `on*` events:
+ *
+ * 1. `onLoad` - Called when the element's parent dialog opens for the
+ * first time.
+ * 2. `onShow` - Called whenever the element's parent dialog opens.
+ * 3. `onHide` - Called whenever the element's parent dialog closes.
+ *
+ * // This connects the 'click' event in CKEDITOR.ui.dialog.button to onClick
+ * // handlers in the UI element's definitions.
+ * CKEDITOR.ui.dialog.button.eventProcessors = CKEDITOR.tools.extend( {},
+ * CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,
+ * { onClick : function( dialog, func ) { this.on( 'click', func ); } },
+ * true
+ * );
+ *
+ * @property {Object}
+ */
+ eventProcessors: {
+ onLoad: function( dialog, func ) {
+ dialog.on( 'load', func, this );
+ },
+
+ onShow: function( dialog, func ) {
+ dialog.on( 'show', func, this );
+ },
+
+ onHide: function( dialog, func ) {
+ dialog.on( 'hide', func, this );
+ }
+ },
+
+ /**
+ * The default handler for a UI element's access key down event, which
+ * tries to put focus to the UI element.
+ *
+ * Can be overridded in child classes for more sophisticaed behavior.
+ *
+ * @param {CKEDITOR.dialog} dialog The parent dialog object.
+ * @param {String} key The key combination pressed. Since access keys
+ * are defined to always include the `CTRL` key, its value should always
+ * include a `'CTRL+'` prefix.
+ */
+ accessKeyDown: function() {
+ this.focus();
+ },
+
+ /**
+ * The default handler for a UI element's access key up event, which
+ * does nothing.
+ *
+ * Can be overridded in child classes for more sophisticated behavior.
+ *
+ * @param {CKEDITOR.dialog} dialog The parent dialog object.
+ * @param {String} key The key combination pressed. Since access keys
+ * are defined to always include the `CTRL` key, its value should always
+ * include a `'CTRL+'` prefix.
+ */
+ accessKeyUp: function() {},
+
+ /**
+ * Disables a UI element.
+ */
+ disable: function() {
+ var element = this.getElement(),
+ input = this.getInputElement();
+ input.setAttribute( 'disabled', 'true' );
+ element.addClass( 'cke_disabled' );
+ },
+
+ /**
+ * Enables a UI element.
+ */
+ enable: function() {
+ var element = this.getElement(),
+ input = this.getInputElement();
+ input.removeAttribute( 'disabled' );
+ element.removeClass( 'cke_disabled' );
+ },
+
+ /**
+ * Determines whether an UI element is enabled or not.
+ *
+ * @returns {Boolean} Whether the UI element is enabled.
+ */
+ isEnabled: function() {
+ return !this.getElement().hasClass( 'cke_disabled' );
+ },
+
+ /**
+ * Determines whether an UI element is visible or not.
+ *
+ * @returns {Boolean} Whether the UI element is visible.
+ */
+ isVisible: function() {
+ return this.getInputElement().isVisible();
+ },
+
+ /**
+ * Determines whether an UI element is focus-able or not.
+ * Focus-able is defined as being both visible and enabled.
+ *
+ * @returns {Boolean} Whether the UI element can be focused.
+ */
+ isFocusable: function() {
+ if ( !this.isEnabled() || !this.isVisible() )
+ return false;
+ return true;
+ }
+ };
+
+ /** @class CKEDITOR.ui.dialog.hbox */
+ CKEDITOR.ui.dialog.hbox.prototype = CKEDITOR.tools.extend( new CKEDITOR.ui.dialog.uiElement(), {
+ /**
+ * Gets a child UI element inside this container.
+ *
+ * var checkbox = hbox.getChild( [0,1] );
+ * checkbox.setValue( true );
+ *
+ * @param {Array/Number} indices An array or a single number to indicate the child's
+ * position in the container's descendant tree. Omit to get all the children in an array.
+ * @returns {Array/CKEDITOR.ui.dialog.uiElement} Array of all UI elements in the container
+ * if no argument given, or the specified UI element if indices is given.
+ */
+ getChild: function( indices ) {
+ // If no arguments, return a clone of the children array.
+ if ( arguments.length < 1 )
+ return this._.children.concat();
+
+ // If indices isn't array, make it one.
+ if ( !indices.splice )
+ indices = [ indices ];
+
+ // Retrieve the child element according to tree position.
+ if ( indices.length < 2 )
+ return this._.children[ indices[ 0 ] ];
+ else
+ return ( this._.children[ indices[ 0 ] ] && this._.children[ indices[ 0 ] ].getChild ) ? this._.children[ indices[ 0 ] ].getChild( indices.slice( 1, indices.length ) ) : null;
+ }
+ }, true );
+
+ CKEDITOR.ui.dialog.vbox.prototype = new CKEDITOR.ui.dialog.hbox();
+
+ ( function() {
+ var commonBuilder = {
+ build: function( dialog, elementDefinition, output ) {
+ var children = elementDefinition.children,
+ child,
+ childHtmlList = [],
+ childObjList = [];
+ for ( var i = 0;
+ ( i < children.length && ( child = children[ i ] ) ); i++ ) {
+ var childHtml = [];
+ childHtmlList.push( childHtml );
+ childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
+ }
+ return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
+ }
+ };
+
+ CKEDITOR.dialog.addUIElement( 'hbox', commonBuilder );
+ CKEDITOR.dialog.addUIElement( 'vbox', commonBuilder );
+ } )();
+
+ /**
+ * Generic dialog command. It opens a specific dialog when executed.
+ *
+ * // Register the "link" command, which opens the "link" dialog.
+ * editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) );
+ *
+ * @class
+ * @constructor Creates a dialogCommand class instance.
+ * @extends CKEDITOR.commandDefinition
+ * @param {String} dialogName The name of the dialog to open when executing
+ * this command.
+ * @param {Object} [ext] Additional command definition's properties.
+ */
+ CKEDITOR.dialogCommand = function( dialogName, ext ) {
+ this.dialogName = dialogName;
+ CKEDITOR.tools.extend( this, ext, true );
+ };
+
+ CKEDITOR.dialogCommand.prototype = {
+ exec: function( editor ) {
+ editor.openDialog( this.dialogName );
+ },
+
+ // Dialog commands just open a dialog ui, thus require no undo logic,
+ // undo support should dedicate to specific dialog implementation.
+ canUndo: false,
+
+ editorFocus: 1
+ };
+
+ ( function() {
+ var notEmptyRegex = /^([a]|[^a])+$/,
+ integerRegex = /^\d*$/,
+ numberRegex = /^\d*(?:\.\d+)?$/,
+ htmlLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|\%)?)?$/,
+ cssLengthRegex = /^(((\d*(\.\d+))|(\d*))(px|em|ex|in|cm|mm|pt|pc|\%)?)?$/i,
+ inlineStyleRegex = /^(\s*[\w-]+\s*:\s*[^:;]+(?:;|$))*$/;
+
+ CKEDITOR.VALIDATE_OR = 1;
+ CKEDITOR.VALIDATE_AND = 2;
+
+ CKEDITOR.dialog.validate = {
+ functions: function() {
+ var args = arguments;
+ return function() {
+ /**
+ * It's important for validate functions to be able to accept the value
+ * as argument in addition to this.getValue(), so that it is possible to
+ * combine validate functions together to make more sophisticated
+ * validators.
+ */
+ var value = this && this.getValue ? this.getValue() : args[ 0 ];
+
+ var msg,
+ relation = CKEDITOR.VALIDATE_AND,
+ functions = [],
+ i;
+
+ for ( i = 0; i < args.length; i++ ) {
+ if ( typeof args[ i ] == 'function' )
+ functions.push( args[ i ] );
+ else
+ break;
+ }
+
+ if ( i < args.length && typeof args[ i ] == 'string' ) {
+ msg = args[ i ];
+ i++;
+ }
+
+ if ( i < args.length && typeof args[ i ] == 'number' )
+ relation = args[ i ];
+
+ var passed = ( relation == CKEDITOR.VALIDATE_AND ? true : false );
+ for ( i = 0; i < functions.length; i++ ) {
+ if ( relation == CKEDITOR.VALIDATE_AND )
+ passed = passed && functions[ i ]( value );
+ else
+ passed = passed || functions[ i ]( value );
+ }
+
+ return !passed ? msg : true;
+ };
+ },
+
+ regex: function( regex, msg ) {
+ /*
+ * Can be greatly shortened by deriving from functions validator if code size
+ * turns out to be more important than performance.
+ */
+ return function() {
+ var value = this && this.getValue ? this.getValue() : arguments[ 0 ];
+ return !regex.test( value ) ? msg : true;
+ };
+ },
+
+ notEmpty: function( msg ) {
+ return this.regex( notEmptyRegex, msg );
+ },
+
+ integer: function( msg ) {
+ return this.regex( integerRegex, msg );
+ },
+
+ 'number': function( msg ) {
+ return this.regex( numberRegex, msg );
+ },
+
+ 'cssLength': function( msg ) {
+ return this.functions( function( val ) {
+ return cssLengthRegex.test( CKEDITOR.tools.trim( val ) );
+ }, msg );
+ },
+
+ 'htmlLength': function( msg ) {
+ return this.functions( function( val ) {
+ return htmlLengthRegex.test( CKEDITOR.tools.trim( val ) );
+ }, msg );
+ },
+
+ 'inlineStyle': function( msg ) {
+ return this.functions( function( val ) {
+ return inlineStyleRegex.test( CKEDITOR.tools.trim( val ) );
+ }, msg );
+ },
+
+ equals: function( value, msg ) {
+ return this.functions( function( val ) {
+ return val == value;
+ }, msg );
+ },
+
+ notEqual: function( value, msg ) {
+ return this.functions( function( val ) {
+ return val != value;
+ }, msg );
+ }
+ };
+
+ CKEDITOR.on( 'instanceDestroyed', function( evt ) {
+ // Remove dialog cover on last instance destroy.
+ if ( CKEDITOR.tools.isEmpty( CKEDITOR.instances ) ) {
+ var currentTopDialog;
+ while ( ( currentTopDialog = CKEDITOR.dialog._.currentTop ) )
+ currentTopDialog.hide();
+ removeCovers();
+ }
+
+ var dialogs = evt.editor._.storedDialogs;
+ for ( var name in dialogs )
+ dialogs[ name ].destroy();
+
+ } );
+
+ } )();
+
+ // Extend the CKEDITOR.editor class with dialog specific functions.
+ CKEDITOR.tools.extend( CKEDITOR.editor.prototype, {
+ /**
+ * Loads and opens a registered dialog.
+ *
+ * CKEDITOR.instances.editor1.openDialog( 'smiley' );
+ *
+ * @member CKEDITOR.editor
+ * @param {String} dialogName The registered name of the dialog.
+ * @param {Function} callback The function to be invoked after dialog instance created.
+ * @returns {CKEDITOR.dialog} The dialog object corresponding to the dialog displayed.
+ * `null` if the dialog name is not registered.
+ * @see CKEDITOR.dialog#add
+ */
+ openDialog: function( dialogName, callback ) {
+ var dialog = null, dialogDefinitions = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];
+
+ if ( CKEDITOR.dialog._.currentTop === null )
+ showCover( this );
+
+ // If the dialogDefinition is already loaded, open it immediately.
+ if ( typeof dialogDefinitions == 'function' ) {
+ var storedDialogs = this._.storedDialogs || ( this._.storedDialogs = {} );
+
+ dialog = storedDialogs[ dialogName ] || ( storedDialogs[ dialogName ] = new CKEDITOR.dialog( this, dialogName ) );
+
+ callback && callback.call( dialog, dialog );
+ dialog.show();
+
+ } else if ( dialogDefinitions == 'failed' ) {
+ hideCover( this );
+ throw new Error( '[CKEDITOR.dialog.openDialog] Dialog "' + dialogName + '" failed when loading definition.' );
+ } else if ( typeof dialogDefinitions == 'string' ) {
+
+ CKEDITOR.scriptLoader.load( CKEDITOR.getUrl( dialogDefinitions ),
+ function() {
+ var dialogDefinition = CKEDITOR.dialog._.dialogDefinitions[ dialogName ];
+ // In case of plugin error, mark it as loading failed.
+ if ( typeof dialogDefinition != 'function' )
+ CKEDITOR.dialog._.dialogDefinitions[ dialogName ] = 'failed';
+
+ this.openDialog( dialogName, callback );
+ }, this, 0, 1 );
+ }
+
+ CKEDITOR.skin.loadPart( 'dialog' );
+
+ return dialog;
+ }
+ } );
+} )();
+
+CKEDITOR.plugins.add( 'dialog', {
+ requires: 'dialogui',
+ init: function( editor ) {
+ editor.on( 'doubleclick', function( evt ) {
+ if ( evt.data.dialog )
+ editor.openDialog( evt.data.dialog );
+ }, null, null, 999 );
+ }
+} );
+
+// Dialog related configurations.
+
+/**
+ * The color of the dialog background cover. It should be a valid CSS color string.
+ *
+ * config.dialog_backgroundCoverColor = 'rgb(255, 254, 253)';
+ *
+ * @cfg {String} [dialog_backgroundCoverColor='white']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * The opacity of the dialog background cover. It should be a number within the
+ * range `[0.0, 1.0]`.
+ *
+ * config.dialog_backgroundCoverOpacity = 0.7;
+ *
+ * @cfg {Number} [dialog_backgroundCoverOpacity=0.5]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * If the dialog has more than one tab, put focus into the first tab as soon as dialog is opened.
+ *
+ * config.dialog_startupFocusTab = true;
+ *
+ * @cfg {Boolean} [dialog_startupFocusTab=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * The distance of magnetic borders used in moving and resizing dialogs,
+ * measured in pixels.
+ *
+ * config.dialog_magnetDistance = 30;
+ *
+ * @cfg {Number} [dialog_magnetDistance=20]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * The guideline to follow when generating the dialog buttons. There are 3 possible options:
+ *
+ * * `'OS'` - the buttons will be displayed in the default order of the user's OS;
+ * * `'ltr'` - for Left-To-Right order;
+ * * `'rtl'` - for Right-To-Left order.
+ *
+ * Example:
+ *
+ * config.dialog_buttonsOrder = 'rtl';
+ *
+ * @since 3.5
+ * @cfg {String} [dialog_buttonsOrder='OS']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * The dialog contents to removed. It's a string composed by dialog name and tab name with a colon between them.
+ *
+ * Separate each pair with semicolon (see example).
+ *
+ * **Note:** All names are case-sensitive.
+ *
+ * **Note:** Be cautious when specifying dialog tabs that are mandatory,
+ * like `'info'`, dialog functionality might be broken because of this!
+ *
+ * config.removeDialogTabs = 'flash:advanced;image:Link';
+ *
+ * @since 3.5
+ * @cfg {String} [removeDialogTabs='']
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Tells if user should not be asked to confirm close, if any dialog field was modified.
+ * By default it is set to `false` meaning that the confirmation dialog will be shown.
+ *
+ * config.dialog_noConfirmCancel = true;
+ *
+ * @since 4.3
+ * @cfg {Boolean} [dialog_noConfirmCancel=false]
+ * @member CKEDITOR.config
+ */
+
+/**
+ * Event fired when a dialog definition is about to be used to create a dialog into
+ * an editor instance. This event makes it possible to customize the definition
+ * before creating it.
+ *
+ * Note that this event is called only the first time a specific dialog is
+ * opened. Successive openings will use the cached dialog, and this event will
+ * not get fired.
+ *
+ * @event dialogDefinition
+ * @member CKEDITOR
+ * @param {CKEDITOR.dialog.definition} data The dialog defination that
+ * is being loaded.
+ * @param {CKEDITOR.editor} editor The editor instance that will use the dialog.
+ */
+
+/**
+ * Event fired when a tab is going to be selected in a dialog.
+ *
+ * @event selectPage
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {String} data.page The id of the page that it's gonna be selected.
+ * @param {String} data.currentPage The id of the current page.
+ */
+
+/**
+ * Event fired when the user tries to dismiss a dialog.
+ *
+ * @event cancel
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {Boolean} data.hide Whether the event should proceed or not.
+ */
+
+/**
+ * Event fired when the user tries to confirm a dialog.
+ *
+ * @event ok
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {Boolean} data.hide Whether the event should proceed or not.
+ */
+
+/**
+ * Event fired when a dialog is shown.
+ *
+ * @event show
+ * @member CKEDITOR.dialog
+ */
+
+/**
+ * Event fired when a dialog is shown.
+ *
+ * @event dialogShow
+ * @member CKEDITOR.editor
+ * @param {CKEDITOR.editor} editor This editor instance.
+ * @param {CKEDITOR.dialog} data The opened dialog instance.
+ */
+
+/**
+ * Event fired when a dialog is hidden.
+ *
+ * @event hide
+ * @member CKEDITOR.dialog
+ */
+
+/**
+ * Event fired when a dialog is hidden.
+ *
+ * @event dialogHide
+ * @member CKEDITOR.editor
+ * @param {CKEDITOR.editor} editor This editor instance.
+ * @param {CKEDITOR.dialog} data The hidden dialog instance.
+ */
+
+/**
+ * Event fired when a dialog is being resized. The event is fired on
+ * both the {@link CKEDITOR.dialog} object and the dialog instance
+ * since 3.5.3, previously it was only available in the global object.
+ *
+ * @static
+ * @event resize
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {CKEDITOR.dialog} data.dialog The dialog being resized (if
+ * it is fired on the dialog itself, this parameter is not sent).
+ * @param {String} data.skin The skin name.
+ * @param {Number} data.width The new width.
+ * @param {Number} data.height The new height.
+ */
+
+/**
+ * Event fired when a dialog is being resized. The event is fired on
+ * both the {@link CKEDITOR.dialog} object and the dialog instance
+ * since 3.5.3, previously it was only available in the global object.
+ *
+ * @since 3.5
+ * @event resize
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {Number} data.width The new width.
+ * @param {Number} data.height The new height.
+ */
+
+/**
+ * Event fired when the dialog state changes, usually by {@link CKEDITOR.dialog#setState}.
+ *
+ * @since 4.5
+ * @event state
+ * @member CKEDITOR.dialog
+ * @param data
+ * @param {Number} data The new state. Either {@link CKEDITOR#DIALOG_STATE_IDLE} or {@link CKEDITOR#DIALOG_STATE_BUSY}.
+ */
diff --git a/sources/plugins/dialog/samples/assets/my_dialog.js b/sources/plugins/dialog/samples/assets/my_dialog.js
new file mode 100644
index 0000000..6239dea
--- /dev/null
+++ b/sources/plugins/dialog/samples/assets/my_dialog.js
@@ -0,0 +1,49 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+CKEDITOR.dialog.add( 'myDialog', function() {
+ return {
+ title: 'My Dialog',
+ minWidth: 400,
+ minHeight: 200,
+ contents: [
+ {
+ id: 'tab1',
+ label: 'First Tab',
+ title: 'First Tab',
+ elements: [
+ {
+ id: 'input1',
+ type: 'text',
+ label: 'Text Field'
+ },
+ {
+ id: 'select1',
+ type: 'select',
+ label: 'Select Field',
+ items: [
+ [ 'option1', 'value1' ],
+ [ 'option2', 'value2' ]
+ ]
+ }
+ ]
+ },
+ {
+ id: 'tab2',
+ label: 'Second Tab',
+ title: 'Second Tab',
+ elements: [
+ {
+ id: 'button1',
+ type: 'button',
+ label: 'Button Field'
+ }
+ ]
+ }
+ ]
+ };
+} );
+
+// %LEAVE_UNMINIFIED% %REMOVE_LINE%
diff --git a/sources/plugins/dialog/samples/dialog.html b/sources/plugins/dialog/samples/dialog.html
new file mode 100644
index 0000000..0f22a1a
--- /dev/null
+++ b/sources/plugins/dialog/samples/dialog.html
@@ -0,0 +1,190 @@
+
+
+
+
+
+ ' );
+ }
+ html.push( ' 0 )
+ html.push( 'style="', styles.join( '; ' ), '" ' );
+ html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[ i ], '
+ CKEditor Samples » Using CKEditor Dialog API
+
+ pluginsLoaded
event, from an external dialog definition file:
+
+
+
+ dialogDefinition
event:
+
+
+
+
+
+
diff --git a/sources/plugins/dialogadvtab/plugin.js b/sources/plugins/dialogadvtab/plugin.js
new file mode 100644
index 0000000..460b534
--- /dev/null
+++ b/sources/plugins/dialogadvtab/plugin.js
@@ -0,0 +1,196 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+( function() {
+
+ function setupAdvParams( element ) {
+ var attrName = this.att;
+
+ var value = element && element.hasAttribute( attrName ) && element.getAttribute( attrName ) || '';
+
+ if ( value !== undefined )
+ this.setValue( value );
+ }
+
+ function commitAdvParams() {
+ // Dialogs may use different parameters in the commit list, so, by
+ // definition, we take the first CKEDITOR.dom.element available.
+ var element;
+
+ for ( var i = 0; i < arguments.length; i++ ) {
+ if ( arguments[ i ] instanceof CKEDITOR.dom.element ) {
+ element = arguments[ i ];
+ break;
+ }
+ }
+
+ if ( element ) {
+ var attrName = this.att,
+ value = this.getValue();
+
+ if ( value )
+ element.setAttribute( attrName, value );
+ else
+ element.removeAttribute( attrName, value );
+ }
+ }
+
+ var defaultTabConfig = { id: 1, dir: 1, classes: 1, styles: 1 };
+
+ CKEDITOR.plugins.add( 'dialogadvtab', {
+ requires: 'dialog',
+
+ // Returns allowed content rule for the content created by this plugin.
+ allowedContent: function( tabConfig ) {
+ if ( !tabConfig )
+ tabConfig = defaultTabConfig;
+
+ var allowedAttrs = [];
+ if ( tabConfig.id )
+ allowedAttrs.push( 'id' );
+ if ( tabConfig.dir )
+ allowedAttrs.push( 'dir' );
+
+ var allowed = '';
+
+ if ( allowedAttrs.length )
+ allowed += '[' + allowedAttrs.join( ',' ) + ']';
+
+ if ( tabConfig.classes )
+ allowed += '(*)';
+ if ( tabConfig.styles )
+ allowed += '{*}';
+
+ return allowed;
+ },
+
+ // @param tabConfig
+ // id, dir, classes, styles
+ createAdvancedTab: function( editor, tabConfig, element ) {
+ if ( !tabConfig )
+ tabConfig = defaultTabConfig;
+
+ var lang = editor.lang.common;
+
+ var result = {
+ id: 'advanced',
+ label: lang.advancedTab,
+ title: lang.advancedTab,
+ elements: [ {
+ type: 'vbox',
+ padding: 1,
+ children: []
+ } ]
+ };
+
+ var contents = [];
+
+ if ( tabConfig.id || tabConfig.dir ) {
+ if ( tabConfig.id ) {
+ contents.push( {
+ id: 'advId',
+ att: 'id',
+ type: 'text',
+ requiredContent: element ? element + '[id]' : null,
+ label: lang.id,
+ setup: setupAdvParams,
+ commit: commitAdvParams
+ } );
+ }
+
+ if ( tabConfig.dir ) {
+ contents.push( {
+ id: 'advLangDir',
+ att: 'dir',
+ type: 'select',
+ requiredContent: element ? element + '[dir]' : null,
+ label: lang.langDir,
+ 'default': '',
+ style: 'width:100%',
+ items: [
+ [ lang.notSet, '' ],
+ [ lang.langDirLTR, 'ltr' ],
+ [ lang.langDirRTL, 'rtl' ]
+ ],
+ setup: setupAdvParams,
+ commit: commitAdvParams
+ } );
+ }
+
+ result.elements[ 0 ].children.push( {
+ type: 'hbox',
+ widths: [ '50%', '50%' ],
+ children: [].concat( contents )
+ } );
+ }
+
+ if ( tabConfig.styles || tabConfig.classes ) {
+ contents = [];
+
+ if ( tabConfig.styles ) {
+ contents.push( {
+ id: 'advStyles',
+ att: 'style',
+ type: 'text',
+ requiredContent: element ? element + '{cke-xyz}' : null,
+ label: lang.styles,
+ 'default': '',
+
+ validate: CKEDITOR.dialog.validate.inlineStyle( lang.invalidInlineStyle ),
+ onChange: function() {},
+
+ getStyle: function( name, defaultValue ) {
+ var match = this.getValue().match( new RegExp( '(?:^|;)\\s*' + name + '\\s*:\\s*([^;]*)', 'i' ) );
+ return match ? match[ 1 ] : defaultValue;
+ },
+
+ updateStyle: function( name, value ) {
+ var styles = this.getValue();
+
+ var tmp = editor.document.createElement( 'span' );
+ tmp.setAttribute( 'style', styles );
+ tmp.setStyle( name, value );
+ styles = CKEDITOR.tools.normalizeCssText( tmp.getAttribute( 'style' ) );
+
+ this.setValue( styles, 1 );
+ },
+
+ setup: setupAdvParams,
+
+ commit: commitAdvParams
+
+ } );
+ }
+
+ if ( tabConfig.classes ) {
+ contents.push( {
+ type: 'hbox',
+ widths: [ '45%', '55%' ],
+ children: [ {
+ id: 'advCSSClasses',
+ att: 'class',
+ type: 'text',
+ requiredContent: element ? element + '(cke-xyz)' : null,
+ label: lang.cssClasses,
+ 'default': '',
+ setup: setupAdvParams,
+ commit: commitAdvParams
+
+ } ]
+ } );
+ }
+
+ result.elements[ 0 ].children.push( {
+ type: 'hbox',
+ widths: [ '50%', '50%' ],
+ children: [].concat( contents )
+ } );
+ }
+
+ return result;
+ }
+ } );
+
+} )();
diff --git a/sources/plugins/dialogui/plugin.js b/sources/plugins/dialogui/plugin.js
new file mode 100644
index 0000000..cf91407
--- /dev/null
+++ b/sources/plugins/dialogui/plugin.js
@@ -0,0 +1,1530 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or http://ckeditor.com/license
+ */
+
+/**
+ * @fileOverview The Dialog User Interface plugin.
+ */
+
+CKEDITOR.plugins.add( 'dialogui', {
+ onLoad: function() {
+
+ var initPrivateObject = function( elementDefinition ) {
+ this._ || ( this._ = {} );
+ this._[ 'default' ] = this._.initValue = elementDefinition[ 'default' ] || '';
+ this._.required = elementDefinition.required || false;
+ var args = [ this._ ];
+ for ( var i = 1; i < arguments.length; i++ )
+ args.push( arguments[ i ] );
+ args.push( true );
+ CKEDITOR.tools.extend.apply( CKEDITOR.tools, args );
+ return this._;
+ },
+ textBuilder = {
+ build: function( dialog, elementDefinition, output ) {
+ return new CKEDITOR.ui.dialog.textInput( dialog, elementDefinition, output );
+ }
+ },
+ commonBuilder = {
+ build: function( dialog, elementDefinition, output ) {
+ return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, elementDefinition, output );
+ }
+ },
+ containerBuilder = {
+ build: function( dialog, elementDefinition, output ) {
+ var children = elementDefinition.children,
+ child,
+ childHtmlList = [],
+ childObjList = [];
+ for ( var i = 0;
+ ( i < children.length && ( child = children[ i ] ) ); i++ ) {
+ var childHtml = [];
+ childHtmlList.push( childHtml );
+ childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) );
+ }
+ return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition );
+ }
+ },
+ commonPrototype = {
+ isChanged: function() {
+ return this.getValue() != this.getInitValue();
+ },
+
+ reset: function( noChangeEvent ) {
+ this.setValue( this.getInitValue(), noChangeEvent );
+ },
+
+ setInitValue: function() {
+ this._.initValue = this.getValue();
+ },
+
+ resetInitValue: function() {
+ this._.initValue = this._[ 'default' ];
+ },
+
+ getInitValue: function() {
+ return this._.initValue;
+ }
+ },
+ commonEventProcessors = CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors, {
+ onChange: function( dialog, func ) {
+ if ( !this._.domOnChangeRegistered ) {
+ dialog.on( 'load', function() {
+ this.getInputElement().on( 'change', function() {
+ // Make sure 'onchange' doesn't get fired after dialog closed. (#5719)
+ if ( !dialog.parts.dialog.isVisible() )
+ return;
+
+ this.fire( 'change', { value: this.getValue() } );
+ }, this );
+ }, this );
+ this._.domOnChangeRegistered = true;
+ }
+
+ this.on( 'change', func );
+ }
+ }, true ),
+ eventRegex = /^on([A-Z]\w+)/,
+ cleanInnerDefinition = function( def ) {
+ // An inner UI element should not have the parent's type, title or events.
+ for ( var i in def ) {
+ if ( eventRegex.test( i ) || i == 'title' || i == 'type' )
+ delete def[ i ];
+ }
+ return def;
+ },
+ // @context {CKEDITOR.dialog.uiElement} UI element (textarea or textInput)
+ // @param {CKEDITOR.dom.event} evt
+ toggleBidiKeyUpHandler = function( evt ) {
+ var keystroke = evt.data.getKeystroke();
+
+ // ALT + SHIFT + Home for LTR direction.
+ if ( keystroke == CKEDITOR.SHIFT + CKEDITOR.ALT + 36 )
+ this.setDirectionMarker( 'ltr' );
+
+ // ALT + SHIFT + End for RTL direction.
+ else if ( keystroke == CKEDITOR.SHIFT + CKEDITOR.ALT + 35 )
+ this.setDirectionMarker( 'rtl' );
+ };
+
+ CKEDITOR.tools.extend( CKEDITOR.ui.dialog, {
+ /**
+ * Base class for all dialog window elements with a textual label on the left.
+ *
+ * @class CKEDITOR.ui.dialog.labeledElement
+ * @extends CKEDITOR.ui.dialog.uiElement
+ * @constructor Creates a labeledElement class instance.
+ * @param {CKEDITOR.dialog} dialog Parent dialog window object.
+ * @param {CKEDITOR.dialog.definition.uiElement} elementDefinition
+ * The element definition. Accepted fields:
+ *
+ * * `label` (Required) The label string.
+ * * `labelLayout` (Optional) Put 'horizontal' here if the
+ * label element is to be laid out horizontally. Otherwise a vertical
+ * layout will be used.
+ * * `widths` (Optional) This applies only to horizontal
+ * layouts — a two-element array of lengths to specify the widths of the
+ * label and the content element.
+ * * `role` (Optional) Value for the `role` attribute.
+ * * `includeLabel` (Optional) If set to `true`, the `aria-labelledby` attribute
+ * will be included.
+ *
+ * @param {Array} htmlList The list of HTML code to output to.
+ * @param {Function} contentHtml
+ * A function returning the HTML code string to be added inside the content
+ * cell.
+ */
+ labeledElement: function( dialog, elementDefinition, htmlList, contentHtml ) {
+ if ( arguments.length < 4 )
+ return;
+
+ var _ = initPrivateObject.call( this, elementDefinition );
+ _.labelId = CKEDITOR.tools.getNextId() + '_label';
+ this._.children = [];
+
+ var innerHTML = function() {
+ var html = [],
+ requiredClass = elementDefinition.required ? ' cke_required' : '';
+ if ( elementDefinition.labelLayout != 'horizontal' ) {
+ html.push(
+ '',
+ ' or inline
+ // container's width, so need to wrap it inside a