diff options
author | Star Rauchenberger <fefferburbia@gmail.com> | 2023-10-11 11:39:16 -0400 |
---|---|---|
committer | Star Rauchenberger <fefferburbia@gmail.com> | 2023-10-11 11:39:16 -0400 |
commit | 3a628945ade35f3ba351ba90e271608520753174 (patch) | |
tree | 05c496db4cf11aec1e334336858bf3fafff0c9e0 /app/assets/javascripts/ckeditor | |
parent | ffcc44d1a73ae1191e835fa625f2f8a7e3e25bda (diff) | |
download | thoughts-3a628945ade35f3ba351ba90e271608520753174.tar.gz thoughts-3a628945ade35f3ba351ba90e271608520753174.tar.bz2 thoughts-3a628945ade35f3ba351ba90e271608520753174.zip |
Removed ckeditor
Diffstat (limited to 'app/assets/javascripts/ckeditor')
148 files changed, 0 insertions, 11446 deletions
diff --git a/app/assets/javascripts/ckeditor/config.js b/app/assets/javascripts/ckeditor/config.js deleted file mode 100644 index 7ff7731..0000000 --- a/app/assets/javascripts/ckeditor/config.js +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.html or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | CKEDITOR.editorConfig = function( config ) | ||
7 | { | ||
8 | // Define changes to default configuration here. For example: | ||
9 | config.language = 'en'; | ||
10 | // config.uiColor = '#AADC6E'; | ||
11 | config.height = "512px"; | ||
12 | |||
13 | config.extraPlugins = "lineutils,widgetselection,widget,image2"; | ||
14 | |||
15 | /* Filebrowser routes */ | ||
16 | // The location of an external file browser, that should be launched when "Browse Server" button is pressed. | ||
17 | config.filebrowserBrowseUrl = "/ckeditor/attachment_files"; | ||
18 | |||
19 | // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Flash dialog. | ||
20 | config.filebrowserFlashBrowseUrl = "/ckeditor/attachment_files"; | ||
21 | |||
22 | // The location of a script that handles file uploads in the Flash dialog. | ||
23 | config.filebrowserFlashUploadUrl = "/ckeditor/attachment_files"; | ||
24 | |||
25 | // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Link tab of Image dialog. | ||
26 | config.filebrowserImageBrowseLinkUrl = "/ckeditor/pictures"; | ||
27 | |||
28 | // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Image dialog. | ||
29 | config.filebrowserImageBrowseUrl = "/ckeditor/pictures"; | ||
30 | |||
31 | // The location of a script that handles file uploads in the Image dialog. | ||
32 | config.filebrowserImageUploadUrl = "/ckeditor/pictures?"; | ||
33 | |||
34 | // The location of a script that handles file uploads. | ||
35 | config.filebrowserUploadUrl = "/ckeditor/attachment_files"; | ||
36 | |||
37 | config.allowedContent = true; | ||
38 | |||
39 | // Toolbar groups configuration. | ||
40 | config.toolbar = [ | ||
41 | { name: 'document', groups: [ 'mode', 'document', 'doctools' ], items: [ 'Source', 'Maximize' ] }, | ||
42 | { name: 'clipboard', groups: [ 'clipboard', 'undo' ], items: [ 'Cut', 'Copy', 'Paste', 'PasteText', '-', 'Undo', 'Redo' ] }, | ||
43 | { name: 'editing', groups: [ 'find' ], items: [ 'Find', 'Replace' ] }, | ||
44 | // { name: 'forms', items: [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] }, | ||
45 | { name: 'links', items: [ 'Link', 'Unlink', 'Anchor' ] }, | ||
46 | { name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule' ] }, | ||
47 | { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] }, | ||
48 | '/', | ||
49 | { name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] }, | ||
50 | { name: 'colors', items: [ 'TextColor', 'BGColor' ] }, | ||
51 | { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] } | ||
52 | ]; | ||
53 | |||
54 | config.toolbar_mini = [ | ||
55 | { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi' ], items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] }, | ||
56 | { name: 'styles', items: [ 'Font', 'FontSize' ] }, | ||
57 | { name: 'colors', items: [ 'TextColor', 'BGColor' ] }, | ||
58 | { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ], items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat' ] }, | ||
59 | { name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule', 'SpecialChar' ] } | ||
60 | ]; | ||
61 | }; | ||
diff --git a/app/assets/javascripts/ckeditor/contents.css b/app/assets/javascripts/ckeditor/contents.css deleted file mode 100644 index 920f2ca..0000000 --- a/app/assets/javascripts/ckeditor/contents.css +++ /dev/null | |||
@@ -1,208 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | body | ||
7 | { | ||
8 | /* Font */ | ||
9 | font-family: sans-serif, Arial, Verdana, "Trebuchet MS"; | ||
10 | font-size: 12px; | ||
11 | |||
12 | /* Text color */ | ||
13 | color: #333; | ||
14 | |||
15 | /* Remove the background color to make it transparent */ | ||
16 | background-color: #fff; | ||
17 | |||
18 | margin: 20px; | ||
19 | } | ||
20 | |||
21 | .cke_editable | ||
22 | { | ||
23 | font-size: 13px; | ||
24 | line-height: 1.6; | ||
25 | |||
26 | /* Fix for missing scrollbars with RTL texts. (#10488) */ | ||
27 | word-wrap: break-word; | ||
28 | } | ||
29 | |||
30 | blockquote | ||
31 | { | ||
32 | font-style: italic; | ||
33 | font-family: Georgia, Times, "Times New Roman", serif; | ||
34 | padding: 2px 0; | ||
35 | border-style: solid; | ||
36 | border-color: #ccc; | ||
37 | border-width: 0; | ||
38 | } | ||
39 | |||
40 | .cke_contents_ltr blockquote | ||
41 | { | ||
42 | padding-left: 20px; | ||
43 | padding-right: 8px; | ||
44 | border-left-width: 5px; | ||
45 | } | ||
46 | |||
47 | .cke_contents_rtl blockquote | ||
48 | { | ||
49 | padding-left: 8px; | ||
50 | padding-right: 20px; | ||
51 | border-right-width: 5px; | ||
52 | } | ||
53 | |||
54 | a | ||
55 | { | ||
56 | color: #0782C1; | ||
57 | } | ||
58 | |||
59 | ol,ul,dl | ||
60 | { | ||
61 | /* IE7: reset rtl list margin. (#7334) */ | ||
62 | *margin-right: 0px; | ||
63 | /* preserved spaces for list items with text direction other than the list. (#6249,#8049)*/ | ||
64 | padding: 0 40px; | ||
65 | } | ||
66 | |||
67 | h1,h2,h3,h4,h5,h6 | ||
68 | { | ||
69 | font-weight: normal; | ||
70 | line-height: 1.2; | ||
71 | } | ||
72 | |||
73 | hr | ||
74 | { | ||
75 | border: 0px; | ||
76 | border-top: 1px solid #ccc; | ||
77 | } | ||
78 | |||
79 | img.right | ||
80 | { | ||
81 | border: 1px solid #ccc; | ||
82 | float: right; | ||
83 | margin-left: 15px; | ||
84 | padding: 5px; | ||
85 | } | ||
86 | |||
87 | img.left | ||
88 | { | ||
89 | border: 1px solid #ccc; | ||
90 | float: left; | ||
91 | margin-right: 15px; | ||
92 | padding: 5px; | ||
93 | } | ||
94 | |||
95 | pre | ||
96 | { | ||
97 | white-space: pre-wrap; /* CSS 2.1 */ | ||
98 | word-wrap: break-word; /* IE7 */ | ||
99 | -moz-tab-size: 4; | ||
100 | tab-size: 4; | ||
101 | } | ||
102 | |||
103 | .marker | ||
104 | { | ||
105 | background-color: Yellow; | ||
106 | } | ||
107 | |||
108 | span[lang] | ||
109 | { | ||
110 | font-style: italic; | ||
111 | } | ||
112 | |||
113 | figure | ||
114 | { | ||
115 | text-align: center; | ||
116 | border: solid 1px #ccc; | ||
117 | border-radius: 2px; | ||
118 | background: rgba(0,0,0,0.05); | ||
119 | padding: 10px; | ||
120 | margin: 10px 20px; | ||
121 | display: inline-block; | ||
122 | } | ||
123 | |||
124 | figure > figcaption | ||
125 | { | ||
126 | text-align: center; | ||
127 | display: block; /* For IE8 */ | ||
128 | } | ||
129 | |||
130 | a > img { | ||
131 | padding: 1px; | ||
132 | margin: 1px; | ||
133 | border: none; | ||
134 | outline: 1px solid #0782C1; | ||
135 | } | ||
136 | |||
137 | /* Widget Styles */ | ||
138 | .code-featured | ||
139 | { | ||
140 | border: 5px solid red; | ||
141 | } | ||
142 | |||
143 | .math-featured | ||
144 | { | ||
145 | padding: 20px; | ||
146 | box-shadow: 0 0 2px rgba(200, 0, 0, 1); | ||
147 | background-color: rgba(255, 0, 0, 0.05); | ||
148 | margin: 10px; | ||
149 | } | ||
150 | |||
151 | .image-clean | ||
152 | { | ||
153 | border: 0; | ||
154 | background: none; | ||
155 | padding: 0; | ||
156 | } | ||
157 | |||
158 | .image-clean > figcaption | ||
159 | { | ||
160 | font-size: .9em; | ||
161 | text-align: right; | ||
162 | } | ||
163 | |||
164 | .image-grayscale | ||
165 | { | ||
166 | background-color: white; | ||
167 | color: #666; | ||
168 | } | ||
169 | |||
170 | .image-grayscale img, img.image-grayscale | ||
171 | { | ||
172 | filter: grayscale(100%); | ||
173 | } | ||
174 | |||
175 | .embed-240p | ||
176 | { | ||
177 | max-width: 426px; | ||
178 | max-height: 240px; | ||
179 | margin:0 auto; | ||
180 | } | ||
181 | |||
182 | .embed-360p | ||
183 | { | ||
184 | max-width: 640px; | ||
185 | max-height: 360px; | ||
186 | margin:0 auto; | ||
187 | } | ||
188 | |||
189 | .embed-480p | ||
190 | { | ||
191 | max-width: 854px; | ||
192 | max-height: 480px; | ||
193 | margin:0 auto; | ||
194 | } | ||
195 | |||
196 | .embed-720p | ||
197 | { | ||
198 | max-width: 1280px; | ||
199 | max-height: 720px; | ||
200 | margin:0 auto; | ||
201 | } | ||
202 | |||
203 | .embed-1080p | ||
204 | { | ||
205 | max-width: 1920px; | ||
206 | max-height: 1080px; | ||
207 | margin:0 auto; | ||
208 | } | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image1.jpg b/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image1.jpg deleted file mode 100644 index 2fe79eb..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image1.jpg +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image2.jpg b/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image2.jpg deleted file mode 100644 index 453ece5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/dev/assets/image2.jpg +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/dev/contents.css b/app/assets/javascripts/ckeditor/plugins/image2/dev/contents.css deleted file mode 100644 index ef29f02..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/dev/contents.css +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | .cke_widget_wrapper:hover:after { | ||
7 | content: "id: " attr(data-cke-widget-id); | ||
8 | position: absolute; | ||
9 | top: 0; | ||
10 | right: 0; | ||
11 | padding: 2px 4px; | ||
12 | background: #EEE; | ||
13 | border: solid 1px #DDD; | ||
14 | border-radius: 2px; | ||
15 | color: #BBB; | ||
16 | font: bold 10px sans-serif; | ||
17 | } | ||
18 | |||
19 | .align-left { | ||
20 | float: left; | ||
21 | margin-right: 20px; | ||
22 | } | ||
23 | |||
24 | .align-right { | ||
25 | float: right; | ||
26 | margin-left: 20px; | ||
27 | } | ||
28 | |||
29 | .align-center { | ||
30 | text-align: center; | ||
31 | } | ||
32 | |||
33 | .align-center > figure { | ||
34 | display: inline-block; | ||
35 | } | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/dev/image2.html b/app/assets/javascripts/ckeditor/plugins/image2/dev/image2.html deleted file mode 100644 index 1070a6e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/dev/image2.html +++ /dev/null | |||
@@ -1,339 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>Widget Image — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <script src="../../../dev/console/console.js"></script> | ||
12 | <script src="../../../dev/console/focusconsole.js"></script> | ||
13 | <script src="../../widget/dev/console.js"></script> | ||
14 | <script> | ||
15 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | ||
16 | CKEDITOR.tools.enableHtml5Elements( document ); | ||
17 | |||
18 | var editor; | ||
19 | |||
20 | // The instanceReady event is fired, when an instance of CKEditor has finished | ||
21 | // its initialization. | ||
22 | CKEDITOR.on( 'instanceReady', function( ev ) { | ||
23 | editor = ev.editor; | ||
24 | |||
25 | // Show this "on" button. | ||
26 | document.getElementById( 'readOnlyOn' ).style.display = ''; | ||
27 | |||
28 | // Event fired when the readOnly property changes. | ||
29 | editor.on( 'readOnly', function() { | ||
30 | document.getElementById( 'readOnlyOn' ).style.display = this.readOnly ? 'none' : ''; | ||
31 | document.getElementById( 'readOnlyOff' ).style.display = this.readOnly ? '' : 'none'; | ||
32 | }); | ||
33 | }); | ||
34 | |||
35 | function toggleReadOnly( isReadOnly ) { | ||
36 | // Change the read-only state of the editor. | ||
37 | // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-method-setReadOnly | ||
38 | editor.setReadOnly( isReadOnly ); | ||
39 | } | ||
40 | |||
41 | </script> | ||
42 | <link href="../../../samples/old/sample.css" rel="stylesheet"> | ||
43 | |||
44 | <style> | ||
45 | |||
46 | body { | ||
47 | font-size: 13px; | ||
48 | } | ||
49 | .editable { | ||
50 | padding: 20px; | ||
51 | border: 2px solid #dfdfdf; | ||
52 | overflow: auto; | ||
53 | } | ||
54 | |||
55 | body p { | ||
56 | line-height: 1.8em; | ||
57 | } | ||
58 | |||
59 | /* Reset some styles from sample.css */ | ||
60 | .cke_editable.cke_editable_inline | ||
61 | { | ||
62 | cursor: auto; | ||
63 | } | ||
64 | .cke_editable.cke_editable_inline.cke_focus | ||
65 | { | ||
66 | box-shadow: none; | ||
67 | background: inherit; | ||
68 | cursor: auto; | ||
69 | } | ||
70 | |||
71 | </style> | ||
72 | <link href="contents.css" rel="stylesheet"> | ||
73 | <link href="../../../contents.css" rel="stylesheet"> | ||
74 | </head> | ||
75 | <body> | ||
76 | <h1 class="samples"> | ||
77 | <a href="../../../samples/old/index.html">CKEditor Samples</a> » Widget Image | ||
78 | </h1> | ||
79 | |||
80 | <h2>Classic (iframe-based) Sample</h2> | ||
81 | |||
82 | <textarea id="editor1" cols="10" rows="10"> | ||
83 | <h1>Apollo 11</h1> | ||
84 | |||
85 | <figure class="image" style="float: right"> | ||
86 | <img alt="Saturn V" src="assets/image1.jpg" width="200" data-foo="*********" data-bar="@@@@@@@@" /> | ||
87 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
88 | </figure> | ||
89 | |||
90 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p> | ||
91 | |||
92 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
93 | |||
94 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
95 | |||
96 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
97 | |||
98 | <blockquote> | ||
99 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
100 | </blockquote> | ||
101 | |||
102 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
103 | |||
104 | <blockquote> | ||
105 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
106 | </blockquote> | ||
107 | |||
108 | <figure class="image" style="float: right"> | ||
109 | <img alt="The Eagle" src="assets/image2.jpg" style="width: 200px" /> | ||
110 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
111 | </figure> | ||
112 | |||
113 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
114 | |||
115 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
116 | |||
117 | <ol> | ||
118 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
119 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
120 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
121 | </ol> | ||
122 | |||
123 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
124 | |||
125 | <p style="text-align:center"> | ||
126 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
127 | </p> | ||
128 | |||
129 | <hr /> | ||
130 | <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
131 | </textarea> | ||
132 | |||
133 | <h2>Inline Sample</h2> | ||
134 | |||
135 | <div id="editor2" contenteditable="true" class="editable"> | ||
136 | <h2>Apollo 11</h2> | ||
137 | |||
138 | <figure class="image" style="float: right"> | ||
139 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
140 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
141 | </figure> | ||
142 | |||
143 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p> | ||
144 | |||
145 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
146 | |||
147 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
148 | |||
149 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
150 | |||
151 | <blockquote> | ||
152 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
153 | </blockquote> | ||
154 | |||
155 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
156 | |||
157 | <blockquote> | ||
158 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
159 | </blockquote> | ||
160 | |||
161 | <figure class="image" style="float: right"> | ||
162 | <img alt="The Eagle" src="assets/image2.jpg" style="width: 200px" /> | ||
163 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
164 | </figure> | ||
165 | |||
166 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
167 | |||
168 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
169 | |||
170 | <ol> | ||
171 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
172 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
173 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
174 | </ol> | ||
175 | |||
176 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
177 | |||
178 | <p style="text-align:center"> | ||
179 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
180 | </p> | ||
181 | |||
182 | <hr /> | ||
183 | <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
184 | </div> | ||
185 | |||
186 | <h2>Div Editing Area Sample</h2> | ||
187 | |||
188 | <textarea id="editor3" cols="10" rows="10"> | ||
189 | <h1>Apollo 11</h1> | ||
190 | |||
191 | <figure class="caption" style="float: right"> | ||
192 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
193 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
194 | </figure> | ||
195 | |||
196 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p> | ||
197 | |||
198 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
199 | |||
200 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
201 | |||
202 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
203 | |||
204 | <blockquote> | ||
205 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
206 | </blockquote> | ||
207 | |||
208 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
209 | |||
210 | <blockquote> | ||
211 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
212 | </blockquote> | ||
213 | |||
214 | <figure class="caption" style="float: right"> | ||
215 | <img alt="The Eagle" src="assets/image2.jpg" style="width: 200px" /> | ||
216 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
217 | </figure> | ||
218 | |||
219 | <h2>Technical Details <a id="tech-details" name="tech-details"></a></h2> | ||
220 | |||
221 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
222 | |||
223 | <ol> | ||
224 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
225 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
226 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
227 | </ol> | ||
228 | |||
229 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
230 | |||
231 | <p style="text-align:center"> | ||
232 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
233 | </p> | ||
234 | |||
235 | <hr /> | ||
236 | <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
237 | </textarea> | ||
238 | |||
239 | <h2>alignClasses samples</h2> | ||
240 | |||
241 | <textarea id="editor4" cols="10" rows="10"> | ||
242 | <h1>Apollo 11</h1> | ||
243 | |||
244 | <figure class="align-left image"> | ||
245 | <img alt="Saturn V" src="assets/image1.jpg" width="200" data-foo="*********" data-bar="@@@@@@@@" /> | ||
246 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
247 | </figure> | ||
248 | |||
249 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p> | ||
250 | |||
251 | <blockquote> | ||
252 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
253 | </blockquote> | ||
254 | |||
255 | <figure class="align-right image"> | ||
256 | <img alt="The Eagle" src="assets/image2.jpg" style="width: 200px" /> | ||
257 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
258 | </figure> | ||
259 | |||
260 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
261 | |||
262 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
263 | |||
264 | <ol> | ||
265 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
266 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
267 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
268 | </ol> | ||
269 | |||
270 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
271 | |||
272 | <p class="align-center"> | ||
273 | <img alt="Saturn V" src="assets/image1.jpg" width="200" /> | ||
274 | </p> | ||
275 | |||
276 | <hr /> | ||
277 | <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
278 | </textarea> | ||
279 | |||
280 | <p> | ||
281 | <input id="readOnlyOn" onclick="toggleReadOnly( true );" type="button" value="Make it read-only" style="display:none"> | ||
282 | <input id="readOnlyOff" onclick="toggleReadOnly( false );" type="button" value="Make it editable again" style="display:none"> | ||
283 | </p> | ||
284 | |||
285 | <script> | ||
286 | |||
287 | CKEDITOR.disableAutoInline = true; | ||
288 | |||
289 | CKEDITOR.replace( 'editor1', { | ||
290 | extraPlugins: 'image2', | ||
291 | height: 600, | ||
292 | contentsCss: [ '../../../contents.css', 'contents.css' ], | ||
293 | extraAllowedContent: 'img[data-foo,data-bar]', | ||
294 | |||
295 | filebrowserBrowseUrl: '/ckfinder/ckfinder.html', | ||
296 | filebrowserImageBrowseUrl: '/ckfinder/ckfinder.html?Type=Images', | ||
297 | filebrowserUploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files', | ||
298 | filebrowserImageUploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Images', | ||
299 | } ); | ||
300 | |||
301 | CKEDITOR.inline( 'editor2', { | ||
302 | extraPlugins: 'image2,sourcedialog' | ||
303 | } ); | ||
304 | |||
305 | CKEDITOR.replace( 'editor3', { | ||
306 | extraPlugins: 'image2,divarea', | ||
307 | height: 600 | ||
308 | } ); | ||
309 | |||
310 | CKEDITOR.replace( 'editor4', { | ||
311 | extraPlugins: 'image2', | ||
312 | image2_alignClasses: [ 'align-left', 'align-center', 'align-right' ], | ||
313 | contentsCss: [ '../../../contents.css', 'contents.css' ], | ||
314 | height: 600 | ||
315 | } ); | ||
316 | |||
317 | CKCONSOLE.create( 'widget', { editor: 'editor1' } ); | ||
318 | CKCONSOLE.create( 'focus', { editor: 'editor1' } ); | ||
319 | CKCONSOLE.create( 'widget', { editor: 'editor2', folded: true } ); | ||
320 | CKCONSOLE.create( 'focus', { editor: 'editor2', folded: true } ); | ||
321 | CKCONSOLE.create( 'widget', { editor: 'editor3' } ); | ||
322 | CKCONSOLE.create( 'focus', { editor: 'editor3' } ); | ||
323 | CKCONSOLE.create( 'widget', { editor: 'editor4' } ); | ||
324 | CKCONSOLE.create( 'focus', { editor: 'editor4' } ); | ||
325 | |||
326 | </script> | ||
327 | |||
328 | <div id="footer"> | ||
329 | <hr> | ||
330 | <p> | ||
331 | CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a> | ||
332 | </p> | ||
333 | <p id="copy"> | ||
334 | Copyright © 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico | ||
335 | Knabben. All rights reserved. | ||
336 | </p> | ||
337 | </div> | ||
338 | </body> | ||
339 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/dialogs/image2.js b/app/assets/javascripts/ckeditor/plugins/image2/dialogs/image2.js deleted file mode 100644 index cb393a3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/dialogs/image2.js +++ /dev/null | |||
@@ -1,553 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview Image plugin based on Widgets API | ||
8 | */ | ||
9 | |||
10 | 'use strict'; | ||
11 | |||
12 | CKEDITOR.dialog.add( 'image2', function( editor ) { | ||
13 | |||
14 | // RegExp: 123, 123px, empty string "" | ||
15 | var regexGetSizeOrEmpty = /(^\s*(\d+)(px)?\s*$)|^$/i, | ||
16 | |||
17 | lockButtonId = CKEDITOR.tools.getNextId(), | ||
18 | resetButtonId = CKEDITOR.tools.getNextId(), | ||
19 | |||
20 | lang = editor.lang.image2, | ||
21 | commonLang = editor.lang.common, | ||
22 | |||
23 | lockResetStyle = 'margin-top:18px;width:40px;height:20px;', | ||
24 | lockResetHtml = new CKEDITOR.template( | ||
25 | '<div>' + | ||
26 | '<a href="javascript:void(0)" tabindex="-1" title="' + lang.lockRatio + '" class="cke_btn_locked" id="{lockButtonId}" role="checkbox">' + | ||
27 | '<span class="cke_icon"></span>' + | ||
28 | '<span class="cke_label">' + lang.lockRatio + '</span>' + | ||
29 | '</a>' + | ||
30 | |||
31 | '<a href="javascript:void(0)" tabindex="-1" title="' + lang.resetSize + '" class="cke_btn_reset" id="{resetButtonId}" role="button">' + | ||
32 | '<span class="cke_label">' + lang.resetSize + '</span>' + | ||
33 | '</a>' + | ||
34 | '</div>' ).output( { | ||
35 | lockButtonId: lockButtonId, | ||
36 | resetButtonId: resetButtonId | ||
37 | } ), | ||
38 | |||
39 | helpers = CKEDITOR.plugins.image2, | ||
40 | |||
41 | // Editor instance configuration. | ||
42 | config = editor.config, | ||
43 | |||
44 | hasFileBrowser = !!( config.filebrowserImageBrowseUrl || config.filebrowserBrowseUrl ), | ||
45 | |||
46 | // Content restrictions defined by the widget which | ||
47 | // impact on dialog structure and presence of fields. | ||
48 | features = editor.widgets.registered.image.features, | ||
49 | |||
50 | // Functions inherited from image2 plugin. | ||
51 | getNatural = helpers.getNatural, | ||
52 | |||
53 | // Global variables referring to the dialog's context. | ||
54 | doc, widget, image, | ||
55 | |||
56 | // Global variable referring to this dialog's image pre-loader. | ||
57 | preLoader, | ||
58 | |||
59 | // Global variables holding the original size of the image. | ||
60 | domWidth, domHeight, | ||
61 | |||
62 | // Global variables related to image pre-loading. | ||
63 | preLoadedWidth, preLoadedHeight, srcChanged, | ||
64 | |||
65 | // Global variables related to size locking. | ||
66 | lockRatio, userDefinedLock, | ||
67 | |||
68 | // Global variables referring to dialog fields and elements. | ||
69 | lockButton, resetButton, widthField, heightField, | ||
70 | |||
71 | natural; | ||
72 | |||
73 | // Validates dimension. Allowed values are: | ||
74 | // "123px", "123", "" (empty string) | ||
75 | function validateDimension() { | ||
76 | var match = this.getValue().match( regexGetSizeOrEmpty ), | ||
77 | isValid = !!( match && parseInt( match[ 1 ], 10 ) !== 0 ); | ||
78 | |||
79 | if ( !isValid ) | ||
80 | alert( commonLang[ 'invalid' + CKEDITOR.tools.capitalize( this.id ) ] ); // jshint ignore:line | ||
81 | |||
82 | return isValid; | ||
83 | } | ||
84 | |||
85 | // Creates a function that pre-loads images. The callback function passes | ||
86 | // [image, width, height] or null if loading failed. | ||
87 | // | ||
88 | // @returns {Function} | ||
89 | function createPreLoader() { | ||
90 | var image = doc.createElement( 'img' ), | ||
91 | listeners = []; | ||
92 | |||
93 | function addListener( event, callback ) { | ||
94 | listeners.push( image.once( event, function( evt ) { | ||
95 | removeListeners(); | ||
96 | callback( evt ); | ||
97 | } ) ); | ||
98 | } | ||
99 | |||
100 | function removeListeners() { | ||
101 | var l; | ||
102 | |||
103 | while ( ( l = listeners.pop() ) ) | ||
104 | l.removeListener(); | ||
105 | } | ||
106 | |||
107 | // @param {String} src. | ||
108 | // @param {Function} callback. | ||
109 | return function( src, callback, scope ) { | ||
110 | addListener( 'load', function() { | ||
111 | // Don't use image.$.(width|height) since it's buggy in IE9-10 (http://dev.ckeditor.com/ticket/11159) | ||
112 | var dimensions = getNatural( image ); | ||
113 | |||
114 | callback.call( scope, image, dimensions.width, dimensions.height ); | ||
115 | } ); | ||
116 | |||
117 | addListener( 'error', function() { | ||
118 | callback( null ); | ||
119 | } ); | ||
120 | |||
121 | addListener( 'abort', function() { | ||
122 | callback( null ); | ||
123 | } ); | ||
124 | |||
125 | image.setAttribute( 'src', | ||
126 | ( config.baseHref || '' ) + src + '?' + Math.random().toString( 16 ).substring( 2 ) ); | ||
127 | }; | ||
128 | } | ||
129 | |||
130 | // This function updates width and height fields once the | ||
131 | // "src" field is altered. Along with dimensions, also the | ||
132 | // dimensions lock is adjusted. | ||
133 | function onChangeSrc() { | ||
134 | var value = this.getValue(); | ||
135 | |||
136 | toggleDimensions( false ); | ||
137 | |||
138 | // Remember that src is different than default. | ||
139 | if ( value !== widget.data.src ) { | ||
140 | // Update dimensions of the image once it's preloaded. | ||
141 | preLoader( value, function( image, width, height ) { | ||
142 | // Re-enable width and height fields. | ||
143 | toggleDimensions( true ); | ||
144 | |||
145 | // There was problem loading the image. Unlock ratio. | ||
146 | if ( !image ) | ||
147 | return toggleLockRatio( false ); | ||
148 | |||
149 | // Fill width field with the width of the new image. | ||
150 | widthField.setValue( editor.config.image2_prefillDimensions === false ? 0 : width ); | ||
151 | |||
152 | // Fill height field with the height of the new image. | ||
153 | heightField.setValue( editor.config.image2_prefillDimensions === false ? 0 : height ); | ||
154 | |||
155 | // Cache the new width. | ||
156 | preLoadedWidth = width; | ||
157 | |||
158 | // Cache the new height. | ||
159 | preLoadedHeight = height; | ||
160 | |||
161 | // Check for new lock value if image exist. | ||
162 | toggleLockRatio( helpers.checkHasNaturalRatio( image ) ); | ||
163 | } ); | ||
164 | |||
165 | srcChanged = true; | ||
166 | } | ||
167 | |||
168 | // Value is the same as in widget data but is was | ||
169 | // modified back in time. Roll back dimensions when restoring | ||
170 | // default src. | ||
171 | else if ( srcChanged ) { | ||
172 | // Re-enable width and height fields. | ||
173 | toggleDimensions( true ); | ||
174 | |||
175 | // Restore width field with cached width. | ||
176 | widthField.setValue( domWidth ); | ||
177 | |||
178 | // Restore height field with cached height. | ||
179 | heightField.setValue( domHeight ); | ||
180 | |||
181 | // Src equals default one back again. | ||
182 | srcChanged = false; | ||
183 | } | ||
184 | |||
185 | // Value is the same as in widget data and it hadn't | ||
186 | // been modified. | ||
187 | else { | ||
188 | // Re-enable width and height fields. | ||
189 | toggleDimensions( true ); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | function onChangeDimension() { | ||
194 | // If ratio is un-locked, then we don't care what's next. | ||
195 | if ( !lockRatio ) | ||
196 | return; | ||
197 | |||
198 | var value = this.getValue(); | ||
199 | |||
200 | // No reason to auto-scale or unlock if the field is empty. | ||
201 | if ( !value ) | ||
202 | return; | ||
203 | |||
204 | // If the value of the field is invalid (e.g. with %), unlock ratio. | ||
205 | if ( !value.match( regexGetSizeOrEmpty ) ) | ||
206 | toggleLockRatio( false ); | ||
207 | |||
208 | // No automatic re-scale when dimension is '0'. | ||
209 | if ( value === '0' ) | ||
210 | return; | ||
211 | |||
212 | var isWidth = this.id == 'width', | ||
213 | // If dialog opened for the new image, domWidth and domHeight | ||
214 | // will be empty. Use dimensions from pre-loader in such case instead. | ||
215 | width = domWidth || preLoadedWidth, | ||
216 | height = domHeight || preLoadedHeight; | ||
217 | |||
218 | // If changing width, then auto-scale height. | ||
219 | if ( isWidth ) | ||
220 | value = Math.round( height * ( value / width ) ); | ||
221 | |||
222 | // If changing height, then auto-scale width. | ||
223 | else | ||
224 | value = Math.round( width * ( value / height ) ); | ||
225 | |||
226 | // If the value is a number, apply it to the other field. | ||
227 | if ( !isNaN( value ) ) | ||
228 | ( isWidth ? heightField : widthField ).setValue( value ); | ||
229 | } | ||
230 | |||
231 | // Set-up function for lock and reset buttons: | ||
232 | // * Adds lock and reset buttons to focusables. Check if button exist first | ||
233 | // because it may be disabled e.g. due to ACF restrictions. | ||
234 | // * Register mouseover and mouseout event listeners for UI manipulations. | ||
235 | // * Register click event listeners for buttons. | ||
236 | function onLoadLockReset() { | ||
237 | var dialog = this.getDialog(); | ||
238 | |||
239 | function setupMouseClasses( el ) { | ||
240 | el.on( 'mouseover', function() { | ||
241 | this.addClass( 'cke_btn_over' ); | ||
242 | }, el ); | ||
243 | |||
244 | el.on( 'mouseout', function() { | ||
245 | this.removeClass( 'cke_btn_over' ); | ||
246 | }, el ); | ||
247 | } | ||
248 | |||
249 | // Create references to lock and reset buttons for this dialog instance. | ||
250 | lockButton = doc.getById( lockButtonId ); | ||
251 | resetButton = doc.getById( resetButtonId ); | ||
252 | |||
253 | // Activate (Un)LockRatio button | ||
254 | if ( lockButton ) { | ||
255 | // Consider that there's an additional focusable field | ||
256 | // in the dialog when the "browse" button is visible. | ||
257 | dialog.addFocusable( lockButton, 4 + hasFileBrowser ); | ||
258 | |||
259 | lockButton.on( 'click', function( evt ) { | ||
260 | toggleLockRatio(); | ||
261 | evt.data && evt.data.preventDefault(); | ||
262 | }, this.getDialog() ); | ||
263 | |||
264 | setupMouseClasses( lockButton ); | ||
265 | } | ||
266 | |||
267 | // Activate the reset size button. | ||
268 | if ( resetButton ) { | ||
269 | // Consider that there's an additional focusable field | ||
270 | // in the dialog when the "browse" button is visible. | ||
271 | dialog.addFocusable( resetButton, 5 + hasFileBrowser ); | ||
272 | |||
273 | // Fills width and height fields with the original dimensions of the | ||
274 | // image (stored in widget#data since widget#init). | ||
275 | resetButton.on( 'click', function( evt ) { | ||
276 | // If there's a new image loaded, reset button should revert | ||
277 | // cached dimensions of pre-loaded DOM element. | ||
278 | if ( srcChanged ) { | ||
279 | widthField.setValue( preLoadedWidth ); | ||
280 | heightField.setValue( preLoadedHeight ); | ||
281 | } | ||
282 | |||
283 | // If the old image remains, reset button should revert | ||
284 | // dimensions as loaded when the dialog was first shown. | ||
285 | else { | ||
286 | widthField.setValue( domWidth ); | ||
287 | heightField.setValue( domHeight ); | ||
288 | } | ||
289 | |||
290 | evt.data && evt.data.preventDefault(); | ||
291 | }, this ); | ||
292 | |||
293 | setupMouseClasses( resetButton ); | ||
294 | } | ||
295 | } | ||
296 | |||
297 | function toggleLockRatio( enable ) { | ||
298 | // No locking if there's no radio (i.e. due to ACF). | ||
299 | if ( !lockButton ) | ||
300 | return; | ||
301 | |||
302 | if ( typeof enable == 'boolean' ) { | ||
303 | // If user explicitly wants to decide whether | ||
304 | // to lock or not, don't do anything. | ||
305 | if ( userDefinedLock ) | ||
306 | return; | ||
307 | |||
308 | lockRatio = enable; | ||
309 | } | ||
310 | |||
311 | // Undefined. User changed lock value. | ||
312 | else { | ||
313 | var width = widthField.getValue(), | ||
314 | height; | ||
315 | |||
316 | userDefinedLock = true; | ||
317 | lockRatio = !lockRatio; | ||
318 | |||
319 | // Automatically adjust height to width to match | ||
320 | // the original ratio (based on dom- dimensions). | ||
321 | if ( lockRatio && width ) { | ||
322 | height = domHeight / domWidth * width; | ||
323 | |||
324 | if ( !isNaN( height ) ) | ||
325 | heightField.setValue( Math.round( height ) ); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | lockButton[ lockRatio ? 'removeClass' : 'addClass' ]( 'cke_btn_unlocked' ); | ||
330 | lockButton.setAttribute( 'aria-checked', lockRatio ); | ||
331 | |||
332 | // Ratio button hc presentation - WHITE SQUARE / BLACK SQUARE | ||
333 | if ( CKEDITOR.env.hc ) { | ||
334 | var icon = lockButton.getChild( 0 ); | ||
335 | icon.setHtml( lockRatio ? CKEDITOR.env.ie ? '\u25A0' : '\u25A3' : CKEDITOR.env.ie ? '\u25A1' : '\u25A2' ); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | function toggleDimensions( enable ) { | ||
340 | var method = enable ? 'enable' : 'disable'; | ||
341 | |||
342 | widthField[ method ](); | ||
343 | heightField[ method ](); | ||
344 | } | ||
345 | |||
346 | var srcBoxChildren = [ | ||
347 | { | ||
348 | id: 'src', | ||
349 | type: 'text', | ||
350 | label: commonLang.url, | ||
351 | onKeyup: onChangeSrc, | ||
352 | onChange: onChangeSrc, | ||
353 | setup: function( widget ) { | ||
354 | this.setValue( widget.data.src ); | ||
355 | }, | ||
356 | commit: function( widget ) { | ||
357 | widget.setData( 'src', this.getValue() ); | ||
358 | }, | ||
359 | validate: CKEDITOR.dialog.validate.notEmpty( lang.urlMissing ) | ||
360 | } | ||
361 | ]; | ||
362 | |||
363 | // Render the "Browse" button on demand to avoid an "empty" (hidden child) | ||
364 | // space in dialog layout that distorts the UI. | ||
365 | if ( hasFileBrowser ) { | ||
366 | srcBoxChildren.push( { | ||
367 | type: 'button', | ||
368 | id: 'browse', | ||
369 | // v-align with the 'txtUrl' field. | ||
370 | // TODO: We need something better than a fixed size here. | ||
371 | style: 'display:inline-block;margin-top:14px;', | ||
372 | align: 'center', | ||
373 | label: editor.lang.common.browseServer, | ||
374 | hidden: true, | ||
375 | filebrowser: 'info:src' | ||
376 | } ); | ||
377 | } | ||
378 | |||
379 | return { | ||
380 | title: lang.title, | ||
381 | minWidth: 250, | ||
382 | minHeight: 100, | ||
383 | onLoad: function() { | ||
384 | // Create a "global" reference to the document for this dialog instance. | ||
385 | doc = this._.element.getDocument(); | ||
386 | |||
387 | // Create a pre-loader used for determining dimensions of new images. | ||
388 | preLoader = createPreLoader(); | ||
389 | }, | ||
390 | onShow: function() { | ||
391 | // Create a "global" reference to edited widget. | ||
392 | widget = this.widget; | ||
393 | |||
394 | // Create a "global" reference to widget's image. | ||
395 | image = widget.parts.image; | ||
396 | |||
397 | // Reset global variables. | ||
398 | srcChanged = userDefinedLock = lockRatio = false; | ||
399 | |||
400 | // Natural dimensions of the image. | ||
401 | natural = getNatural( image ); | ||
402 | |||
403 | // Get the natural width of the image. | ||
404 | preLoadedWidth = domWidth = natural.width; | ||
405 | |||
406 | // Get the natural height of the image. | ||
407 | preLoadedHeight = domHeight = natural.height; | ||
408 | }, | ||
409 | contents: [ | ||
410 | { | ||
411 | id: 'info', | ||
412 | label: lang.infoTab, | ||
413 | elements: [ | ||
414 | { | ||
415 | type: 'vbox', | ||
416 | padding: 0, | ||
417 | children: [ | ||
418 | { | ||
419 | type: 'hbox', | ||
420 | widths: [ '100%' ], | ||
421 | className: 'cke_dialog_image_url', | ||
422 | children: srcBoxChildren | ||
423 | } | ||
424 | ] | ||
425 | }, | ||
426 | { | ||
427 | id: 'alt', | ||
428 | type: 'text', | ||
429 | label: lang.alt, | ||
430 | setup: function( widget ) { | ||
431 | this.setValue( widget.data.alt ); | ||
432 | }, | ||
433 | commit: function( widget ) { | ||
434 | widget.setData( 'alt', this.getValue() ); | ||
435 | }, | ||
436 | validate: editor.config.image2_altRequired === true ? CKEDITOR.dialog.validate.notEmpty( lang.altMissing ) : null | ||
437 | }, | ||
438 | { | ||
439 | type: 'hbox', | ||
440 | widths: [ '25%', '25%', '50%' ], | ||
441 | requiredContent: features.dimension.requiredContent, | ||
442 | children: [ | ||
443 | { | ||
444 | type: 'text', | ||
445 | width: '45px', | ||
446 | id: 'width', | ||
447 | label: commonLang.width, | ||
448 | validate: validateDimension, | ||
449 | onKeyUp: onChangeDimension, | ||
450 | onLoad: function() { | ||
451 | widthField = this; | ||
452 | }, | ||
453 | setup: function( widget ) { | ||
454 | this.setValue( widget.data.width ); | ||
455 | }, | ||
456 | commit: function( widget ) { | ||
457 | widget.setData( 'width', this.getValue() ); | ||
458 | } | ||
459 | }, | ||
460 | { | ||
461 | type: 'text', | ||
462 | id: 'height', | ||
463 | width: '45px', | ||
464 | label: commonLang.height, | ||
465 | validate: validateDimension, | ||
466 | onKeyUp: onChangeDimension, | ||
467 | onLoad: function() { | ||
468 | heightField = this; | ||
469 | }, | ||
470 | setup: function( widget ) { | ||
471 | this.setValue( widget.data.height ); | ||
472 | }, | ||
473 | commit: function( widget ) { | ||
474 | widget.setData( 'height', this.getValue() ); | ||
475 | } | ||
476 | }, | ||
477 | { | ||
478 | id: 'lock', | ||
479 | type: 'html', | ||
480 | style: lockResetStyle, | ||
481 | onLoad: onLoadLockReset, | ||
482 | setup: function( widget ) { | ||
483 | toggleLockRatio( widget.data.lock ); | ||
484 | }, | ||
485 | commit: function( widget ) { | ||
486 | widget.setData( 'lock', lockRatio ); | ||
487 | }, | ||
488 | html: lockResetHtml | ||
489 | } | ||
490 | ] | ||
491 | }, | ||
492 | { | ||
493 | type: 'hbox', | ||
494 | id: 'alignment', | ||
495 | requiredContent: features.align.requiredContent, | ||
496 | children: [ | ||
497 | { | ||
498 | id: 'align', | ||
499 | type: 'radio', | ||
500 | items: [ | ||
501 | [ commonLang.alignNone, 'none' ], | ||
502 | [ commonLang.alignLeft, 'left' ], | ||
503 | [ commonLang.alignCenter, 'center' ], | ||
504 | [ commonLang.alignRight, 'right' ] | ||
505 | ], | ||
506 | label: commonLang.align, | ||
507 | setup: function( widget ) { | ||
508 | this.setValue( widget.data.align ); | ||
509 | }, | ||
510 | commit: function( widget ) { | ||
511 | widget.setData( 'align', this.getValue() ); | ||
512 | } | ||
513 | } | ||
514 | ] | ||
515 | }, | ||
516 | { | ||
517 | id: 'hasCaption', | ||
518 | type: 'checkbox', | ||
519 | label: lang.captioned, | ||
520 | requiredContent: features.caption.requiredContent, | ||
521 | setup: function( widget ) { | ||
522 | this.setValue( widget.data.hasCaption ); | ||
523 | }, | ||
524 | commit: function( widget ) { | ||
525 | widget.setData( 'hasCaption', this.getValue() ); | ||
526 | } | ||
527 | } | ||
528 | ] | ||
529 | }, | ||
530 | { | ||
531 | id: 'Upload', | ||
532 | hidden: true, | ||
533 | filebrowser: 'uploadButton', | ||
534 | label: lang.uploadTab, | ||
535 | elements: [ | ||
536 | { | ||
537 | type: 'file', | ||
538 | id: 'upload', | ||
539 | label: lang.btnUpload, | ||
540 | style: 'height:40px' | ||
541 | }, | ||
542 | { | ||
543 | type: 'fileButton', | ||
544 | id: 'uploadButton', | ||
545 | filebrowser: 'info:src', | ||
546 | label: lang.btnUpload, | ||
547 | 'for': [ 'Upload', 'upload' ] | ||
548 | } | ||
549 | ] | ||
550 | } | ||
551 | ] | ||
552 | }; | ||
553 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/icons/hidpi/image.png b/app/assets/javascripts/ckeditor/plugins/image2/icons/hidpi/image.png deleted file mode 100644 index d0f21ae..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/icons/hidpi/image.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/icons/image.png b/app/assets/javascripts/ckeditor/plugins/image2/icons/image.png deleted file mode 100644 index 8ea9725..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/icons/image.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/af.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/af.js deleted file mode 100644 index be02258..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/af.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'af', { | ||
6 | alt: 'Alternatiewe teks', | ||
7 | btnUpload: 'Stuur na bediener', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Afbeelding informasie', | ||
11 | lockRatio: 'Vaste proporsie', | ||
12 | menu: 'Afbeelding eienskappe', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Herstel grootte', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Afbeelding eienskappe', | ||
18 | uploadTab: 'Oplaai', | ||
19 | urlMissing: 'Die URL na die afbeelding ontbreek.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ar.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ar.js deleted file mode 100644 index 729ba5e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ar.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ar', { | ||
6 | alt: 'عنوان الصورة', | ||
7 | btnUpload: 'أرسلها للخادم', | ||
8 | captioned: 'صورة ذات اسم', | ||
9 | captionPlaceholder: 'تسمية', | ||
10 | infoTab: 'معلومات الصورة', | ||
11 | lockRatio: 'تناسق الحجم', | ||
12 | menu: 'خصائص الصورة', | ||
13 | pathName: 'صورة', | ||
14 | pathNameCaption: 'تسمية', | ||
15 | resetSize: 'إستعادة الحجم الأصلي', | ||
16 | resizer: 'انقر ثم اسحب للتحجيم', | ||
17 | title: 'خصائص الصورة', | ||
18 | uploadTab: 'رفع', | ||
19 | urlMissing: 'عنوان مصدر الصورة مفقود', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/az.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/az.js deleted file mode 100644 index 8422f43..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/az.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'az', { | ||
6 | alt: 'Alternativ mətn', | ||
7 | btnUpload: 'Serverə göndər', | ||
8 | captioned: 'Altyazı olan şəkil', | ||
9 | captionPlaceholder: 'Altyazı', | ||
10 | infoTab: 'Şəkil haqqında məlumat', | ||
11 | lockRatio: 'Ölçülərin nisbəti saxla', | ||
12 | menu: 'Şəklin seçimləri', | ||
13 | pathName: 'Şəkil', | ||
14 | pathNameCaption: 'Altyazı', | ||
15 | resetSize: 'Ölçüləri qaytar', | ||
16 | resizer: 'Ölçülər dəyişmək üçün tıklayın və aparın', | ||
17 | title: 'Şəklin seçimləri', | ||
18 | uploadTab: 'Serverə yüklə', | ||
19 | urlMissing: 'Şəklin ünvanı yanlışdır.', | ||
20 | altMissing: 'Alternativ mətn tapılmayıb' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/bg.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/bg.js deleted file mode 100644 index 66cec57..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/bg.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'bg', { | ||
6 | alt: 'Алтернативен текст', | ||
7 | btnUpload: 'Изпрати я на сървъра', | ||
8 | captioned: 'Надписано изображение', | ||
9 | captionPlaceholder: 'Надпис', | ||
10 | infoTab: 'Детайли за изображението', | ||
11 | lockRatio: 'Заключване на съотношението', | ||
12 | menu: 'Настройки на изображението', | ||
13 | pathName: 'изображение', | ||
14 | pathNameCaption: 'надпис', | ||
15 | resetSize: 'Нулиране на размер', | ||
16 | resizer: 'Кликни и влачи, за да преоразмериш', | ||
17 | title: 'Настройки на изображението', | ||
18 | uploadTab: 'Качване', | ||
19 | urlMissing: 'URL адреса на изображението липсва.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/bn.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/bn.js deleted file mode 100644 index cc057b6..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/bn.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'bn', { | ||
6 | alt: 'বিকল্প টেক্সট', | ||
7 | btnUpload: 'ইহাকে সার্ভারে প্রেরন কর', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'ছবির তথ্য', | ||
11 | lockRatio: 'অনুপাত লক কর', | ||
12 | menu: 'ছবির প্রোপার্টি', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'সাইজ পূর্বাবস্থায় ফিরিয়ে দাও', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'ছবির প্রোপার্টি', | ||
18 | uploadTab: 'আপলোড', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/bs.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/bs.js deleted file mode 100644 index d0c57c8..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/bs.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'bs', { | ||
6 | alt: 'Tekst na slici', | ||
7 | btnUpload: 'Šalji na server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Info slike', | ||
11 | lockRatio: 'Zakljuèaj odnos', | ||
12 | menu: 'Svojstva slike', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Resetuj dimenzije', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Svojstva slike', | ||
18 | uploadTab: 'Šalji', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ca.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ca.js deleted file mode 100644 index 66feadc..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ca.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ca', { | ||
6 | alt: 'Text alternatiu', | ||
7 | btnUpload: 'Envia-la al servidor', | ||
8 | captioned: 'Imatge amb subtítol', | ||
9 | captionPlaceholder: 'Títol', | ||
10 | infoTab: 'Informació de la imatge', | ||
11 | lockRatio: 'Bloqueja les proporcions', | ||
12 | menu: 'Propietats de la imatge', | ||
13 | pathName: 'imatge', | ||
14 | pathNameCaption: 'subtítol', | ||
15 | resetSize: 'Restaura la mida', | ||
16 | resizer: 'Clicar i arrossegar per redimensionar', | ||
17 | title: 'Propietats de la imatge', | ||
18 | uploadTab: 'Puja', | ||
19 | urlMissing: 'Falta la URL de la imatge.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/cs.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/cs.js deleted file mode 100644 index c50394e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/cs.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'cs', { | ||
6 | alt: 'Alternativní text', | ||
7 | btnUpload: 'Odeslat na server', | ||
8 | captioned: 'Obrázek s popisem', | ||
9 | captionPlaceholder: 'Popis', | ||
10 | infoTab: 'Informace o obrázku', | ||
11 | lockRatio: 'Zámek', | ||
12 | menu: 'Vlastnosti obrázku', | ||
13 | pathName: 'Obrázek', | ||
14 | pathNameCaption: 'Popis', | ||
15 | resetSize: 'Původní velikost', | ||
16 | resizer: 'Klepněte a táhněte pro změnu velikosti', | ||
17 | title: 'Vlastnosti obrázku', | ||
18 | uploadTab: 'Odeslat', | ||
19 | urlMissing: 'Zadané URL zdroje obrázku nebylo nalezeno.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/cy.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/cy.js deleted file mode 100644 index 7051680..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/cy.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'cy', { | ||
6 | alt: 'Testun Amgen', | ||
7 | btnUpload: 'Anfon i\'r Gweinydd', | ||
8 | captioned: 'Delwedd â phennawd', | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Gwyb Delwedd', | ||
11 | lockRatio: 'Cloi Cymhareb', | ||
12 | menu: 'Priodweddau Delwedd', | ||
13 | pathName: 'delwedd', | ||
14 | pathNameCaption: 'pennawd', | ||
15 | resetSize: 'Ailosod Maint', | ||
16 | resizer: 'Clicio a llusgo i ail-meintio', | ||
17 | title: 'Priodweddau Delwedd', | ||
18 | uploadTab: 'Lanlwytho', | ||
19 | urlMissing: 'URL gwreiddiol y ddelwedd ar goll.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/da.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/da.js deleted file mode 100644 index 3d7c443..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/da.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'da', { | ||
6 | alt: 'Alternativ tekst', | ||
7 | btnUpload: 'Upload fil til serveren', | ||
8 | captioned: 'Tekstet billede', | ||
9 | captionPlaceholder: 'Tekst', | ||
10 | infoTab: 'Generelt', | ||
11 | lockRatio: 'Lås størrelsesforhold', | ||
12 | menu: 'Egenskaber for billede', | ||
13 | pathName: 'billede', | ||
14 | pathNameCaption: 'tekst', | ||
15 | resetSize: 'Nulstil størrelse', | ||
16 | resizer: 'Klik og træk for at ændre størrelsen', | ||
17 | title: 'Egenskaber for billede', | ||
18 | uploadTab: 'Upload', | ||
19 | urlMissing: 'Kilde på billed-URL mangler', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/de-ch.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/de-ch.js deleted file mode 100644 index ec55d1f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/de-ch.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'de-ch', { | ||
6 | alt: 'Alternativer Text', | ||
7 | btnUpload: 'Zum Server senden', | ||
8 | captioned: 'Bild mit Überschrift', | ||
9 | captionPlaceholder: 'Überschrift', | ||
10 | infoTab: 'Bildinfo', | ||
11 | lockRatio: 'Größenverhältnis beibehalten', | ||
12 | menu: 'Bildeigenschaften', | ||
13 | pathName: 'Bild', | ||
14 | pathNameCaption: 'Überschrift', | ||
15 | resetSize: 'Grösse zurücksetzen', | ||
16 | resizer: 'Zum Vergrössern auswählen und ziehen', | ||
17 | title: 'Bild-Eigenschaften', | ||
18 | uploadTab: 'Hochladen', | ||
19 | urlMissing: 'Bildquellen-URL fehlt.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/de.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/de.js deleted file mode 100644 index 0b5b6f6..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/de.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'de', { | ||
6 | alt: 'Alternativer Text', | ||
7 | btnUpload: 'Zum Server senden', | ||
8 | captioned: 'Bild mit Überschrift', | ||
9 | captionPlaceholder: 'Überschrift', | ||
10 | infoTab: 'Bildinfo', | ||
11 | lockRatio: 'Größenverhältnis beibehalten', | ||
12 | menu: 'Bildeigenschaften', | ||
13 | pathName: 'Bild', | ||
14 | pathNameCaption: 'Überschrift', | ||
15 | resetSize: 'Größe zurücksetzen', | ||
16 | resizer: 'Zum Vergrößern auswählen und ziehen', | ||
17 | title: 'Bild-Eigenschaften', | ||
18 | uploadTab: 'Hochladen', | ||
19 | urlMissing: 'Bildquellen-URL fehlt.', | ||
20 | altMissing: 'Alternativer Text fehlt.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/el.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/el.js deleted file mode 100644 index 8167636..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/el.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'el', { | ||
6 | alt: 'Εναλλακτικό Κείμενο', | ||
7 | btnUpload: 'Αποστολή στον Διακομιστή', | ||
8 | captioned: 'Εικόνα με λεζάντα', | ||
9 | captionPlaceholder: 'Λεζάντα', | ||
10 | infoTab: 'Πληροφορίες Εικόνας', | ||
11 | lockRatio: 'Κλείδωμα Αναλογίας', | ||
12 | menu: 'Ιδιότητες Εικόνας', | ||
13 | pathName: 'εικόνα', | ||
14 | pathNameCaption: 'λεζάντα', | ||
15 | resetSize: 'Επαναφορά Αρχικού Μεγέθους', | ||
16 | resizer: 'Κάνετε κλικ και σύρετε το ποντίκι για να αλλάξετε το μέγεθος', | ||
17 | title: 'Ιδιότητες Εικόνας', | ||
18 | uploadTab: 'Αποστολή', | ||
19 | urlMissing: 'Λείπει το πηγαίο URL της εικόνας.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-au.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/en-au.js deleted file mode 100644 index f51ffa3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-au.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'en-au', { | ||
6 | alt: 'Alternative Text', | ||
7 | btnUpload: 'Send it to the Server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Image Info', | ||
11 | lockRatio: 'Lock Ratio', | ||
12 | menu: 'Image Properties', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Reset Size', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Image Properties', | ||
18 | uploadTab: 'Upload', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-ca.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/en-ca.js deleted file mode 100644 index 79dabcf..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-ca.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'en-ca', { | ||
6 | alt: 'Alternative Text', | ||
7 | btnUpload: 'Send it to the Server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Image Info', | ||
11 | lockRatio: 'Lock Ratio', | ||
12 | menu: 'Image Properties', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Reset Size', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Image Properties', | ||
18 | uploadTab: 'Upload', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-gb.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/en-gb.js deleted file mode 100644 index 99c4f80..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/en-gb.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'en-gb', { | ||
6 | alt: 'Alternative Text', | ||
7 | btnUpload: 'Send it to the Server', | ||
8 | captioned: 'Captioned image', | ||
9 | captionPlaceholder: 'Caption', | ||
10 | infoTab: 'Image Info', | ||
11 | lockRatio: 'Lock Ratio', | ||
12 | menu: 'Image Properties', | ||
13 | pathName: 'image', | ||
14 | pathNameCaption: 'caption', | ||
15 | resetSize: 'Reset Size', | ||
16 | resizer: 'Click and drag to resize', | ||
17 | title: 'Image Properties', | ||
18 | uploadTab: 'Upload', | ||
19 | urlMissing: 'Image source URL is missing.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/en.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/en.js deleted file mode 100644 index 61abe6f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/en.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'en', { | ||
6 | alt: 'Alternative Text', | ||
7 | btnUpload: 'Send it to the Server', | ||
8 | captioned: 'Captioned image', | ||
9 | captionPlaceholder: 'Caption', | ||
10 | infoTab: 'Image Info', | ||
11 | lockRatio: 'Lock Ratio', | ||
12 | menu: 'Image Properties', | ||
13 | pathName: 'image', | ||
14 | pathNameCaption: 'caption', | ||
15 | resetSize: 'Reset Size', | ||
16 | resizer: 'Click and drag to resize', | ||
17 | title: 'Image Properties', | ||
18 | uploadTab: 'Upload', | ||
19 | urlMissing: 'Image source URL is missing.', | ||
20 | altMissing: 'Alternative text is missing.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/eo.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/eo.js deleted file mode 100644 index 604b91a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/eo.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'eo', { | ||
6 | alt: 'Anstataŭiga Teksto', | ||
7 | btnUpload: 'Sendu al Servilo', | ||
8 | captioned: 'Bildo kun apudskribo', | ||
9 | captionPlaceholder: 'Apudskribo', | ||
10 | infoTab: 'Informoj pri Bildo', | ||
11 | lockRatio: 'Konservi Proporcion', | ||
12 | menu: 'Atributoj de Bildo', | ||
13 | pathName: 'bildo', | ||
14 | pathNameCaption: 'apudskribo', | ||
15 | resetSize: 'Origina Grando', | ||
16 | resizer: 'Kliki kaj treni por ŝanĝi la grandon', | ||
17 | title: 'Atributoj de Bildo', | ||
18 | uploadTab: 'Alŝuti', | ||
19 | urlMissing: 'La fontretadreso de la bildo mankas.', | ||
20 | altMissing: 'Alternativa teksto mankas.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/es-mx.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/es-mx.js deleted file mode 100644 index 7005bd2..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/es-mx.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'es-mx', { | ||
6 | alt: 'Texto alternativo', | ||
7 | btnUpload: 'Enviar al servidor', | ||
8 | captioned: 'Imagen subtitulada', | ||
9 | captionPlaceholder: 'Subtítulo', | ||
10 | infoTab: 'Información de la imagen', | ||
11 | lockRatio: 'Bloquear aspecto', | ||
12 | menu: 'Propiedades de la imagen', | ||
13 | pathName: 'imagen', | ||
14 | pathNameCaption: 'subtítulo', | ||
15 | resetSize: 'Reiniciar tamaño', | ||
16 | resizer: 'Presiona y arrastra para redimensionar', | ||
17 | title: 'Propiedades de imagen', | ||
18 | uploadTab: 'Cargar', | ||
19 | urlMissing: 'Falta la URL de origen de la imagen.', | ||
20 | altMissing: 'Falta texto alternativo.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/es.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/es.js deleted file mode 100644 index 9a02c33..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/es.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'es', { | ||
6 | alt: 'Texto Alternativo', | ||
7 | btnUpload: 'Enviar al Servidor', | ||
8 | captioned: 'Imagen subtitulada', | ||
9 | captionPlaceholder: 'Leyenda', | ||
10 | infoTab: 'Información de Imagen', | ||
11 | lockRatio: 'Proporcional', | ||
12 | menu: 'Propiedades de Imagen', | ||
13 | pathName: 'image', | ||
14 | pathNameCaption: 'subtítulo', | ||
15 | resetSize: 'Tamaño Original', | ||
16 | resizer: 'Dar clic y arrastrar para cambiar tamaño', | ||
17 | title: 'Propiedades de Imagen', | ||
18 | uploadTab: 'Cargar', | ||
19 | urlMissing: 'Debe indicar la URL de la imagen.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/et.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/et.js deleted file mode 100644 index 02ee064..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/et.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'et', { | ||
6 | alt: 'Alternatiivne tekst', | ||
7 | btnUpload: 'Saada serverisse', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Pildi info', | ||
11 | lockRatio: 'Lukusta kuvasuhe', | ||
12 | menu: 'Pildi omadused', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Lähtesta suurus', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Pildi omadused', | ||
18 | uploadTab: 'Lae üles', | ||
19 | urlMissing: 'Pildi lähte-URL on puudu.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/eu.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/eu.js deleted file mode 100644 index 9ac8268..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/eu.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'eu', { | ||
6 | alt: 'Ordezko testua', | ||
7 | btnUpload: 'Bidali zerbitzarira', | ||
8 | captioned: 'Argazki oina', | ||
9 | captionPlaceholder: 'Argazki oina', | ||
10 | infoTab: 'Irudiaren informazioa', | ||
11 | lockRatio: 'Blokeatu erlazioa', | ||
12 | menu: 'Irudiaren propietateak', | ||
13 | pathName: 'Irudia', | ||
14 | pathNameCaption: 'Argazki oina', | ||
15 | resetSize: 'Berrezarri tamaina', | ||
16 | resizer: 'Klikatu eta arrastatu tamainaz aldatzeko', | ||
17 | title: 'Irudiaren propietateak', | ||
18 | uploadTab: 'Kargatu', | ||
19 | urlMissing: 'Irudiaren iturburuaren URLa falta da.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/fa.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/fa.js deleted file mode 100644 index 23db9ed..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/fa.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'fa', { | ||
6 | alt: 'متن جایگزین', | ||
7 | btnUpload: 'به سرور بفرست', | ||
8 | captioned: 'تصویر زیرنویس شده', | ||
9 | captionPlaceholder: 'عنوان', | ||
10 | infoTab: 'اطلاعات تصویر', | ||
11 | lockRatio: 'قفل کردن نسبت', | ||
12 | menu: 'ویژگیهای تصویر', | ||
13 | pathName: 'تصویر', | ||
14 | pathNameCaption: 'عنوان', | ||
15 | resetSize: 'بازنشانی اندازه', | ||
16 | resizer: 'کلیک و کشیدن برای تغییر اندازه', | ||
17 | title: 'ویژگیهای تصویر', | ||
18 | uploadTab: 'بالاگذاری', | ||
19 | urlMissing: 'آدرس URL اصلی تصویر یافت نشد.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/fi.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/fi.js deleted file mode 100644 index cb89f0a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/fi.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'fi', { | ||
6 | alt: 'Vaihtoehtoinen teksti', | ||
7 | btnUpload: 'Lähetä palvelimelle', | ||
8 | captioned: 'Kuva kuvatekstillä', | ||
9 | captionPlaceholder: 'Kuvateksti', | ||
10 | infoTab: 'Kuvan tiedot', | ||
11 | lockRatio: 'Lukitse suhteet', | ||
12 | menu: 'Kuvan ominaisuudet', | ||
13 | pathName: 'kuva', | ||
14 | pathNameCaption: 'kuvateksti', | ||
15 | resetSize: 'Alkuperäinen koko', | ||
16 | resizer: 'Klikkaa ja raahaa muuttaaksesi kokoa', | ||
17 | title: 'Kuvan ominaisuudet', | ||
18 | uploadTab: 'Lisää tiedosto', | ||
19 | urlMissing: 'Kuvan lähdeosoite puuttuu.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/fo.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/fo.js deleted file mode 100644 index 86c001a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/fo.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'fo', { | ||
6 | alt: 'Alternativur tekstur', | ||
7 | btnUpload: 'Send til ambætaran', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Myndaupplýsingar', | ||
11 | lockRatio: 'Læs lutfallið', | ||
12 | menu: 'Myndaeginleikar', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Upprunastødd', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Myndaeginleikar', | ||
18 | uploadTab: 'Send til ambætaran', | ||
19 | urlMissing: 'URL til mynd manglar.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/fr-ca.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/fr-ca.js deleted file mode 100644 index 38afd99..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/fr-ca.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'fr-ca', { | ||
6 | alt: 'Texte alternatif', | ||
7 | btnUpload: 'Envoyer sur le serveur', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Informations sur l\'image2', | ||
11 | lockRatio: 'Verrouiller les proportions', | ||
12 | menu: 'Propriétés de l\'image2', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Taille originale', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Propriétés de l\'image2', | ||
18 | uploadTab: 'Téléverser', | ||
19 | urlMissing: 'L\'URL de la source de l\'image est manquant.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/fr.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/fr.js deleted file mode 100644 index 5c14790..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/fr.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'fr', { | ||
6 | alt: 'Texte alternatif', | ||
7 | btnUpload: 'Envoyer sur le serveur', | ||
8 | captioned: 'Image légendée', | ||
9 | captionPlaceholder: 'Légende', | ||
10 | infoTab: 'Informations sur l\'image', | ||
11 | lockRatio: 'Conserver les proportions', | ||
12 | menu: 'Propriétés de l\'image', | ||
13 | pathName: 'image', | ||
14 | pathNameCaption: 'légende', | ||
15 | resetSize: 'Réinitialiser la taille', | ||
16 | resizer: 'Cliquer et glisser pour redimensionner', | ||
17 | title: 'Propriétés de l\'image', | ||
18 | uploadTab: 'Téléverser', | ||
19 | urlMissing: 'L\'URL source de l\'image est manquante.', | ||
20 | altMissing: 'Vous n\'avez pas indiqué de texte de remplacement.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/gl.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/gl.js deleted file mode 100644 index a2a824c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/gl.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'gl', { | ||
6 | alt: 'Texto alternativo', | ||
7 | btnUpload: 'Enviar ao servidor', | ||
8 | captioned: 'Imaxe con lenda', | ||
9 | captionPlaceholder: 'Lenda', | ||
10 | infoTab: 'Información da imaxe', | ||
11 | lockRatio: 'Proporcional', | ||
12 | menu: 'Propiedades da imaxe', | ||
13 | pathName: 'Imaxe', | ||
14 | pathNameCaption: 'lenda', | ||
15 | resetSize: 'Tamaño orixinal', | ||
16 | resizer: 'Prema e arrastre para axustar o tamaño', | ||
17 | title: 'Propiedades da imaxe', | ||
18 | uploadTab: 'Cargar', | ||
19 | urlMissing: 'Non se atopa o URL da imaxe.', | ||
20 | altMissing: 'Non foi posíbel atopar o texto alternativo.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/gu.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/gu.js deleted file mode 100644 index 25a0cf3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/gu.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'gu', { | ||
6 | alt: 'ઑલ્ટર્નટ ટેક્સ્ટ', | ||
7 | btnUpload: 'આ સર્વરને મોકલવું', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'ચિત્ર ની જાણકારી', | ||
11 | lockRatio: 'લૉક ગુણોત્તર', | ||
12 | menu: 'ચિત્રના ગુણ', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'રીસેટ સાઇઝ', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'ચિત્રના ગુણ', | ||
18 | uploadTab: 'અપલોડ', | ||
19 | urlMissing: 'ઈમેજની મૂળ URL છે નહી.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/he.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/he.js deleted file mode 100644 index 49bef06..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/he.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'he', { | ||
6 | alt: 'טקסט חלופי', | ||
7 | btnUpload: 'שליחה לשרת', | ||
8 | captioned: 'כותרת תמונה', | ||
9 | captionPlaceholder: 'כותרת', | ||
10 | infoTab: 'מידע על התמונה', | ||
11 | lockRatio: 'נעילת היחס', | ||
12 | menu: 'תכונות התמונה', | ||
13 | pathName: 'תמונה', | ||
14 | pathNameCaption: 'כותרת', | ||
15 | resetSize: 'איפוס הגודל', | ||
16 | resizer: 'לחץ וגרור לשינוי הגודל', | ||
17 | title: 'מאפייני התמונה', | ||
18 | uploadTab: 'העלאה', | ||
19 | urlMissing: 'כתובת התמונה חסרה.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/hi.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/hi.js deleted file mode 100644 index 029ff92..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/hi.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'hi', { | ||
6 | alt: 'वैकल्पिक टेक्स्ट', | ||
7 | btnUpload: 'इसे सर्वर को भेजें', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'तस्वीर की जानकारी', | ||
11 | lockRatio: 'लॉक अनुपात', | ||
12 | menu: 'तस्वीर प्रॉपर्टीज़', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'रीसॅट साइज़', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'तस्वीर प्रॉपर्टीज़', | ||
18 | uploadTab: 'अपलोड', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/hr.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/hr.js deleted file mode 100644 index 6d05047..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/hr.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'hr', { | ||
6 | alt: 'Alternativni tekst', | ||
7 | btnUpload: 'Pošalji na server', | ||
8 | captioned: 'Titl slike', | ||
9 | captionPlaceholder: 'Titl', | ||
10 | infoTab: 'Info slike', | ||
11 | lockRatio: 'Zaključaj odnos', | ||
12 | menu: 'Svojstva slika', | ||
13 | pathName: 'slika', | ||
14 | pathNameCaption: 'titl', | ||
15 | resetSize: 'Obriši veličinu', | ||
16 | resizer: 'Odaberi i povuci za promjenu veličine', | ||
17 | title: 'Svojstva slika', | ||
18 | uploadTab: 'Pošalji', | ||
19 | urlMissing: 'Nedostaje URL slike.', | ||
20 | altMissing: 'Nedostaje alternativni tekst.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/hu.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/hu.js deleted file mode 100644 index d1f6484..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/hu.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'hu', { | ||
6 | alt: 'Buborék szöveg', | ||
7 | btnUpload: 'Küldés a szerverre', | ||
8 | captioned: 'Feliratozott kép', | ||
9 | captionPlaceholder: 'Képfelirat', | ||
10 | infoTab: 'Alaptulajdonságok', | ||
11 | lockRatio: 'Arány megtartása', | ||
12 | menu: 'Kép tulajdonságai', | ||
13 | pathName: 'kép', | ||
14 | pathNameCaption: 'felirat', | ||
15 | resetSize: 'Eredeti méret', | ||
16 | resizer: 'Kattints és húzz az átméretezéshez', | ||
17 | title: 'Kép tulajdonságai', | ||
18 | uploadTab: 'Feltöltés', | ||
19 | urlMissing: 'Hiányzik a kép URL-je', | ||
20 | altMissing: 'Az alternatív szöveg hiányzik.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/id.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/id.js deleted file mode 100644 index dd783c4..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/id.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'id', { | ||
6 | alt: 'Teks alternatif', | ||
7 | btnUpload: 'Kirim ke Server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Info Gambar', | ||
11 | lockRatio: 'Lock Ratio', // MISSING | ||
12 | menu: 'Image Properties', // MISSING | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Atur Ulang Ukuran', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Image Properties', // MISSING | ||
18 | uploadTab: 'Unggah', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/is.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/is.js deleted file mode 100644 index a4a002d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/is.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'is', { | ||
6 | alt: 'Baklægur texti', | ||
7 | btnUpload: 'Hlaða upp', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Almennt', | ||
11 | lockRatio: 'Festa stærðarhlutfall', | ||
12 | menu: 'Eigindi myndar', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Reikna stærð', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Eigindi myndar', | ||
18 | uploadTab: 'Senda upp', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/it.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/it.js deleted file mode 100644 index 95ae97a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/it.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'it', { | ||
6 | alt: 'Testo alternativo', | ||
7 | btnUpload: 'Invia al server', | ||
8 | captioned: 'Immagine con didascalia', | ||
9 | captionPlaceholder: 'Didascalia', | ||
10 | infoTab: 'Informazioni immagine', | ||
11 | lockRatio: 'Blocca rapporto', | ||
12 | menu: 'Proprietà immagine', | ||
13 | pathName: 'immagine', | ||
14 | pathNameCaption: 'didascalia', | ||
15 | resetSize: 'Reimposta dimensione', | ||
16 | resizer: 'Fare clic e trascinare per ridimensionare', | ||
17 | title: 'Proprietà immagine', | ||
18 | uploadTab: 'Carica', | ||
19 | urlMissing: 'Manca l\'URL dell\'immagine.', | ||
20 | altMissing: 'Testo alternativo mancante.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ja.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ja.js deleted file mode 100644 index 4cf0ad8..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ja.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ja', { | ||
6 | alt: '代替テキスト', | ||
7 | btnUpload: 'サーバーに送信', | ||
8 | captioned: 'キャプションを付ける', | ||
9 | captionPlaceholder: 'キャプション', | ||
10 | infoTab: '画像情報', | ||
11 | lockRatio: '比率を固定', | ||
12 | menu: '画像のプロパティ', | ||
13 | pathName: 'image', | ||
14 | pathNameCaption: 'caption', | ||
15 | resetSize: 'サイズをリセット', | ||
16 | resizer: 'ドラッグしてリサイズ', | ||
17 | title: '画像のプロパティ', | ||
18 | uploadTab: 'アップロード', | ||
19 | urlMissing: '画像のURLを入力してください。', | ||
20 | altMissing: '代替テキストを入力してください。' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ka.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ka.js deleted file mode 100644 index 64e06d0..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ka.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ka', { | ||
6 | alt: 'სანაცვლო ტექსტი', | ||
7 | btnUpload: 'სერვერისთვის გაგზავნა', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'სურათის ინფორმცია', | ||
11 | lockRatio: 'პროპორციის შენარჩუნება', | ||
12 | menu: 'სურათის პარამეტრები', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'ზომის დაბრუნება', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'სურათის პარამეტრები', | ||
18 | uploadTab: 'აქაჩვა', | ||
19 | urlMissing: 'სურათის URL არაა შევსებული.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/km.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/km.js deleted file mode 100644 index ea193ed..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/km.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'km', { | ||
6 | alt: 'អត្ថបទជំនួស', | ||
7 | btnUpload: 'បញ្ជូនទៅកាន់ម៉ាស៊ីនផ្តល់សេវា', | ||
8 | captioned: 'រូបដែលមានចំណងជើង', | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'ពត៌មានអំពីរូបភាព', | ||
11 | lockRatio: 'ចាក់សោផលធៀប', | ||
12 | menu: 'លក្ខណៈសម្បត្តិរូបភាព', | ||
13 | pathName: 'រូបភាព', | ||
14 | pathNameCaption: 'ចំណងជើង', | ||
15 | resetSize: 'កំណត់ទំហំឡើងវិញ', | ||
16 | resizer: 'ចុចហើយទាញដើម្បីប្ដូរទំហំ', | ||
17 | title: 'លក្ខណៈសម្បត្តិរូបភាប', | ||
18 | uploadTab: 'ផ្ទុកឡើង', | ||
19 | urlMissing: 'ខ្វះ URL ប្រភពរូបភាព។', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ko.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ko.js deleted file mode 100644 index 85d843d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ko.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ko', { | ||
6 | alt: '대체 문자열', | ||
7 | btnUpload: '서버로 전송', | ||
8 | captioned: '이미지 설명 넣기', | ||
9 | captionPlaceholder: '설명', | ||
10 | infoTab: '이미지 정보', | ||
11 | lockRatio: '비율 유지', | ||
12 | menu: '이미지 속성', | ||
13 | pathName: '이미지', | ||
14 | pathNameCaption: '설명', | ||
15 | resetSize: '원래 크기로', | ||
16 | resizer: '크기를 조절하려면 클릭 후 드래그 하세요', | ||
17 | title: '이미지 속성', | ||
18 | uploadTab: '업로드', | ||
19 | urlMissing: '이미지 원본 주소(URL)가 없습니다.', | ||
20 | altMissing: '대체 문자가 없습니다.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ku.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ku.js deleted file mode 100644 index c8b06a1..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ku.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ku', { | ||
6 | alt: 'جێگرەوەی دەق', | ||
7 | btnUpload: 'ناردنی بۆ ڕاژه', | ||
8 | captioned: 'وێنەی بەسەردێر', | ||
9 | captionPlaceholder: 'سەردێر', | ||
10 | infoTab: 'زانیاری وێنه', | ||
11 | lockRatio: 'داخستنی ڕێژه', | ||
12 | menu: 'خاسیەتی وێنه', | ||
13 | pathName: 'وێنە', | ||
14 | pathNameCaption: 'سەردێر', | ||
15 | resetSize: 'ڕێکخستنەوەی قەباره', | ||
16 | resizer: 'کرتەبکە و ڕایبکێشە بۆ قەبارە گۆڕین', | ||
17 | title: 'خاسیەتی وێنه', | ||
18 | uploadTab: 'بارکردن', | ||
19 | urlMissing: 'سەرچاوەی بەستەری وێنه بزره', | ||
20 | altMissing: 'جێگرەوەی دەق لەدەست چووە.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/lt.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/lt.js deleted file mode 100644 index 73514ee..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/lt.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'lt', { | ||
6 | alt: 'Alternatyvus Tekstas', | ||
7 | btnUpload: 'Siųsti į serverį', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Vaizdo informacija', | ||
11 | lockRatio: 'Išlaikyti proporciją', | ||
12 | menu: 'Vaizdo savybės', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Atstatyti dydį', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Vaizdo savybės', | ||
18 | uploadTab: 'Siųsti', | ||
19 | urlMissing: 'Paveiksliuko nuorodos nėra.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/lv.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/lv.js deleted file mode 100644 index aa5f8d3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/lv.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'lv', { | ||
6 | alt: 'Alternatīvais teksts', | ||
7 | btnUpload: 'Nosūtīt serverim', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Informācija par attēlu', | ||
11 | lockRatio: 'Nemainīga Augstuma/Platuma attiecība', | ||
12 | menu: 'Attēla īpašības', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Atjaunot sākotnējo izmēru', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Attēla īpašības', | ||
18 | uploadTab: 'Augšupielādēt', | ||
19 | urlMissing: 'Trūkst attēla atrašanās adrese.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/mk.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/mk.js deleted file mode 100644 index 8edd69a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/mk.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'mk', { | ||
6 | alt: 'Алтернативен текст', | ||
7 | btnUpload: 'Прикачи на сервер', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Информации за сликата', | ||
11 | lockRatio: 'Зачувај пропорција', | ||
12 | menu: 'Својства на сликата', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Ресетирај големина', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Својства на сликата', | ||
18 | uploadTab: 'Прикачи', | ||
19 | urlMissing: 'Недостасува URL-то на сликата.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/mn.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/mn.js deleted file mode 100644 index e985509..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/mn.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'mn', { | ||
6 | alt: 'Зургийг орлох бичвэр', | ||
7 | btnUpload: 'Үүнийг сервэррүү илгээ', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Зурагны мэдээлэл', | ||
11 | lockRatio: 'Радио түгжих', | ||
12 | menu: 'Зураг', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'хэмжээ дахин оноох', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Зураг', | ||
18 | uploadTab: 'Илгээж ачаалах', | ||
19 | urlMissing: 'Зургийн эх сурвалжийн хаяг (URL) байхгүй байна.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ms.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ms.js deleted file mode 100644 index 50d73d9..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ms.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ms', { | ||
6 | alt: 'Text Alternatif', | ||
7 | btnUpload: 'Hantar ke Server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Info Imej', | ||
11 | lockRatio: 'Tetapkan Nisbah', | ||
12 | menu: 'Ciri-ciri Imej', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Saiz Set Semula', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Ciri-ciri Imej', | ||
18 | uploadTab: 'Muat Naik', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/nb.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/nb.js deleted file mode 100644 index dce7f1e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/nb.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'nb', { | ||
6 | alt: 'Alternativ tekst', | ||
7 | btnUpload: 'Send det til serveren', | ||
8 | captioned: 'Bilde med bildetekst', | ||
9 | captionPlaceholder: 'Bildetekst', | ||
10 | infoTab: 'Bildeinformasjon', | ||
11 | lockRatio: 'Lås forhold', | ||
12 | menu: 'Bildeegenskaper', | ||
13 | pathName: 'bilde', | ||
14 | pathNameCaption: 'bildetekst', | ||
15 | resetSize: 'Tilbakestill størrelse', | ||
16 | resizer: 'Klikk og dra for å endre størrelse', | ||
17 | title: 'Bildeegenskaper', | ||
18 | uploadTab: 'Last opp', | ||
19 | urlMissing: 'Bildets adresse mangler.', | ||
20 | altMissing: 'Alternativ tekst mangler.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/nl.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/nl.js deleted file mode 100644 index 925e0aa..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/nl.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'nl', { | ||
6 | alt: 'Alternatieve tekst', | ||
7 | btnUpload: 'Naar server verzenden', | ||
8 | captioned: 'Afbeelding met onderschrift', | ||
9 | captionPlaceholder: 'Onderschrift', | ||
10 | infoTab: 'Afbeeldingsinformatie', | ||
11 | lockRatio: 'Verhouding vergrendelen', | ||
12 | menu: 'Eigenschappen afbeelding', | ||
13 | pathName: 'afbeelding', | ||
14 | pathNameCaption: 'onderschrift', | ||
15 | resetSize: 'Afmetingen herstellen', | ||
16 | resizer: 'Klik en sleep om te herschalen', | ||
17 | title: 'Afbeeldingseigenschappen', | ||
18 | uploadTab: 'Uploaden', | ||
19 | urlMissing: 'De URL naar de afbeelding ontbreekt.', | ||
20 | altMissing: 'Alternatieve tekst ontbreekt.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/no.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/no.js deleted file mode 100644 index 1d43e04..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/no.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'no', { | ||
6 | alt: 'Alternativ tekst', | ||
7 | btnUpload: 'Send det til serveren', | ||
8 | captioned: 'Bilde med bildetekst', | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Bildeinformasjon', | ||
11 | lockRatio: 'Lås forhold', | ||
12 | menu: 'Bildeegenskaper', | ||
13 | pathName: 'bilde', | ||
14 | pathNameCaption: 'bildetekst', | ||
15 | resetSize: 'Tilbakestill størrelse', | ||
16 | resizer: 'Klikk og dra for å endre størrelse', | ||
17 | title: 'Bildeegenskaper', | ||
18 | uploadTab: 'Last opp', | ||
19 | urlMissing: 'Bildets adresse mangler.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/oc.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/oc.js deleted file mode 100644 index 1b75050..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/oc.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'oc', { | ||
6 | alt: 'Tèxte alternatiu', | ||
7 | btnUpload: 'Mandar sul servidor', | ||
8 | captioned: 'Imatge amb legenda', | ||
9 | captionPlaceholder: 'Legenda', | ||
10 | infoTab: 'Informacions sus l\'imatge', | ||
11 | lockRatio: 'Conservar las proporcions', | ||
12 | menu: 'Proprietats de l\'imatge', | ||
13 | pathName: 'imatge', | ||
14 | pathNameCaption: 'legenda', | ||
15 | resetSize: 'Reïnicializar la talha', | ||
16 | resizer: 'Clicar e lisar per redimensionar', | ||
17 | title: 'Proprietats de l\'imatge', | ||
18 | uploadTab: 'Mandar', | ||
19 | urlMissing: 'L\'URL font de l\'imatge es mancanta.', | ||
20 | altMissing: 'Lo tèxte alternatiu es mancant.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/pl.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/pl.js deleted file mode 100644 index 17e4d95..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/pl.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'pl', { | ||
6 | alt: 'Tekst zastępczy', | ||
7 | btnUpload: 'Wyślij', | ||
8 | captioned: 'Obrazek z podpisem', | ||
9 | captionPlaceholder: 'Podpis', | ||
10 | infoTab: 'Informacje o obrazku', | ||
11 | lockRatio: 'Zablokuj proporcje', | ||
12 | menu: 'Właściwości obrazka', | ||
13 | pathName: 'obrazek', | ||
14 | pathNameCaption: 'podpis', | ||
15 | resetSize: 'Przywróć rozmiar', | ||
16 | resizer: 'Kliknij i przeciągnij, by zmienić rozmiar.', | ||
17 | title: 'Właściwości obrazka', | ||
18 | uploadTab: 'Wyślij', | ||
19 | urlMissing: 'Podaj adres URL obrazka.', | ||
20 | altMissing: 'Podaj tekst zastępczy obrazka.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/pt-br.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/pt-br.js deleted file mode 100644 index 63d0023..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/pt-br.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'pt-br', { | ||
6 | alt: 'Texto Alternativo', | ||
7 | btnUpload: 'Enviar para o Servidor', | ||
8 | captioned: 'Legenda da Imagem', | ||
9 | captionPlaceholder: 'Legenda', | ||
10 | infoTab: 'Informações da Imagem', | ||
11 | lockRatio: 'Travar Proporções', | ||
12 | menu: 'Formatar Imagem', | ||
13 | pathName: 'Imagem', | ||
14 | pathNameCaption: 'Legenda', | ||
15 | resetSize: 'Redefinir para o Tamanho Original', | ||
16 | resizer: 'Click e arraste para redimensionar', | ||
17 | title: 'Formatar Imagem', | ||
18 | uploadTab: 'Enviar ao Servidor', | ||
19 | urlMissing: 'URL da imagem está faltando.', | ||
20 | altMissing: 'Texto alternativo não informado.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/pt.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/pt.js deleted file mode 100644 index 2621a07..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/pt.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'pt', { | ||
6 | alt: 'Texto alternativo', | ||
7 | btnUpload: 'Enviar para o servidor', | ||
8 | captioned: 'Imagem legendada', | ||
9 | captionPlaceholder: 'Legenda', | ||
10 | infoTab: 'Informação da imagem', | ||
11 | lockRatio: 'Proporcional', | ||
12 | menu: 'Propriedades da imagem', | ||
13 | pathName: 'imagem', | ||
14 | pathNameCaption: 'legenda', | ||
15 | resetSize: 'Tamanho original', | ||
16 | resizer: 'Clique e arraste para redimensionar', | ||
17 | title: 'Propriedades da imagem', | ||
18 | uploadTab: 'Carregar', | ||
19 | urlMissing: 'O URL de origem da imagem está em falta.', | ||
20 | altMissing: 'Texto alternativo em falta.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ro.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ro.js deleted file mode 100644 index ed14bee..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ro.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ro', { | ||
6 | alt: 'Text alternativ', | ||
7 | btnUpload: 'Trimite la server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Informaţii despre imagine', | ||
11 | lockRatio: 'Păstrează proporţiile', | ||
12 | menu: 'Proprietăţile imaginii', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Resetează mărimea', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Proprietăţile imaginii', | ||
18 | uploadTab: 'Încarcă', | ||
19 | urlMissing: 'Sursa URL a imaginii lipsește.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ru.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ru.js deleted file mode 100644 index eeafd51..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ru.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ru', { | ||
6 | alt: 'Альтернативный текст', | ||
7 | btnUpload: 'Загрузить на сервер', | ||
8 | captioned: 'Отображать название', | ||
9 | captionPlaceholder: 'Название', | ||
10 | infoTab: 'Данные об изображении', | ||
11 | lockRatio: 'Сохранять пропорции', | ||
12 | menu: 'Свойства изображения', | ||
13 | pathName: 'изображение', | ||
14 | pathNameCaption: 'название', | ||
15 | resetSize: 'Вернуть обычные размеры', | ||
16 | resizer: 'Нажмите и растяните', | ||
17 | title: 'Свойства изображения', | ||
18 | uploadTab: 'Загрузка файла', | ||
19 | urlMissing: 'Не указана ссылка на изображение.', | ||
20 | altMissing: 'Не задан альтернативный текст' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/si.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/si.js deleted file mode 100644 index d86b2d6..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/si.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'si', { | ||
6 | alt: 'විකල්ප ', | ||
7 | btnUpload: 'සේවාදායකය වෙත යොමුකිරිම', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'රුපයේ තොරතුරු', | ||
11 | lockRatio: 'නවතන අනුපාතය ', | ||
12 | menu: 'රුපයේ ගුණ', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'නැවතත් විශාලත්වය වෙනස් කිරීම', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'රුපයේ ', | ||
18 | uploadTab: 'උඩුගතකිරීම', | ||
19 | urlMissing: 'රුප මුලාශ්ර URL නැත.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sk.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sk.js deleted file mode 100644 index dac2032..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sk.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sk', { | ||
6 | alt: 'Alternatívny text', | ||
7 | btnUpload: 'Odoslať to na server', | ||
8 | captioned: 'Opísaný obrázok', | ||
9 | captionPlaceholder: 'Popis', | ||
10 | infoTab: 'Informácie o obrázku', | ||
11 | lockRatio: 'Pomer zámky', | ||
12 | menu: 'Vlastnosti obrázka', | ||
13 | pathName: 'obrázok', | ||
14 | pathNameCaption: 'popis', | ||
15 | resetSize: 'Pôvodná veľkosť', | ||
16 | resizer: 'Kliknite a potiahnite pre zmenu veľkosti', | ||
17 | title: 'Vlastnosti obrázka', | ||
18 | uploadTab: 'Nahrať', | ||
19 | urlMissing: 'Chýba URL zdroja obrázka.', | ||
20 | altMissing: 'Chýba alternatívny text.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sl.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sl.js deleted file mode 100644 index 548ad59..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sl.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sl', { | ||
6 | alt: 'Nadomestno besedilo', | ||
7 | btnUpload: 'Pošlji na strežnik', | ||
8 | captioned: 'Slika z napisom', | ||
9 | captionPlaceholder: 'Napis', | ||
10 | infoTab: 'Podatki o sliki', | ||
11 | lockRatio: 'Zakleni razmerje', | ||
12 | menu: 'Lastnosti slike', | ||
13 | pathName: 'slika', | ||
14 | pathNameCaption: 'napis', | ||
15 | resetSize: 'Ponastavi velikost', | ||
16 | resizer: 'Kliknite in povlecite, da spremenite velikost', | ||
17 | title: 'Lastnosti slike', | ||
18 | uploadTab: 'Naloži', | ||
19 | urlMissing: 'Manjka vir (URL) slike.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sq.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sq.js deleted file mode 100644 index e10f33c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sq.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sq', { | ||
6 | alt: 'Tekst Alternativ', | ||
7 | btnUpload: 'Dërgo në server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Informacione mbi Fotografinë', | ||
11 | lockRatio: 'Mbyll Racionin', | ||
12 | menu: 'Karakteristikat e Fotografisë', | ||
13 | pathName: 'foto', | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Rikthe Madhësinë', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Karakteristikat e Fotografisë', | ||
18 | uploadTab: 'Ngarko', | ||
19 | urlMissing: 'Mungon URL e burimit të fotografisë.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sr-latn.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sr-latn.js deleted file mode 100644 index cd0975b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sr-latn.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sr-latn', { | ||
6 | alt: 'Alternativni tekst', | ||
7 | btnUpload: 'Pošalji na server', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Info slike', | ||
11 | lockRatio: 'Zaključaj odnos', | ||
12 | menu: 'Osobine slika', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Resetuj veličinu', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Osobine slika', | ||
18 | uploadTab: 'Pošalji', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sr.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sr.js deleted file mode 100644 index 9544b91..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sr.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sr', { | ||
6 | alt: 'Алтернативни текст', | ||
7 | btnUpload: 'Пошаљи на сервер', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'Инфо слике', | ||
11 | lockRatio: 'Закључај однос', | ||
12 | menu: 'Особине слика', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'Ресетуј величину', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'Особине слика', | ||
18 | uploadTab: 'Пошаљи', | ||
19 | urlMissing: 'Недостаје УРЛ слике.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/sv.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/sv.js deleted file mode 100644 index 36fd8cb..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/sv.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'sv', { | ||
6 | alt: 'Alternativ text', | ||
7 | btnUpload: 'Skicka till server', | ||
8 | captioned: 'Rubricerad bild', | ||
9 | captionPlaceholder: 'Bildtext', | ||
10 | infoTab: 'Bildinformation', | ||
11 | lockRatio: 'Lås höjd/bredd förhållanden', | ||
12 | menu: 'Bildegenskaper', | ||
13 | pathName: 'bild', | ||
14 | pathNameCaption: 'rubrik', | ||
15 | resetSize: 'Återställ storlek', | ||
16 | resizer: 'Klicka och drag för att ändra storlek', | ||
17 | title: 'Bildegenskaper', | ||
18 | uploadTab: 'Ladda upp', | ||
19 | urlMissing: 'Bildkällans URL saknas.', | ||
20 | altMissing: 'Alternativ text saknas' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/th.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/th.js deleted file mode 100644 index 48d99a9..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/th.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'th', { | ||
6 | alt: 'คำประกอบรูปภาพ', | ||
7 | btnUpload: 'อัพโหลดไฟล์ไปเก็บไว้ที่เครื่องแม่ข่าย (เซิร์ฟเวอร์)', | ||
8 | captioned: 'Captioned image', // MISSING | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'ข้อมูลของรูปภาพ', | ||
11 | lockRatio: 'กำหนดอัตราส่วน กว้าง-สูง แบบคงที่', | ||
12 | menu: 'คุณสมบัติของ รูปภาพ', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'กำหนดรูปเท่าขนาดจริง', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'คุณสมบัติของ รูปภาพ', | ||
18 | uploadTab: 'อัพโหลดไฟล์', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/tr.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/tr.js deleted file mode 100644 index c358582..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/tr.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'tr', { | ||
6 | alt: 'Alternatif Yazı', | ||
7 | btnUpload: 'Sunucuya Yolla', | ||
8 | captioned: 'Başlıklı resim', | ||
9 | captionPlaceholder: 'Başlık', | ||
10 | infoTab: 'Resim Bilgisi', | ||
11 | lockRatio: 'Oranı Kilitle', | ||
12 | menu: 'Resim Özellikleri', | ||
13 | pathName: 'Resim', | ||
14 | pathNameCaption: 'başlık', | ||
15 | resetSize: 'Boyutu Başa Döndür', | ||
16 | resizer: 'Boyutlandırmak için, tıklayın ve sürükleyin', | ||
17 | title: 'Resim Özellikleri', | ||
18 | uploadTab: 'Karşıya Yükle', | ||
19 | urlMissing: 'Resmin URL kaynağı bulunamadı.', | ||
20 | altMissing: 'Alternatif yazı eksik.' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/tt.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/tt.js deleted file mode 100644 index 2c0dca5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/tt.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'tt', { | ||
6 | alt: 'Альтернатив текст', | ||
7 | btnUpload: 'Серверга җибәрү', | ||
8 | captioned: 'Исеме куелган рәсем', | ||
9 | captionPlaceholder: 'Исем', | ||
10 | infoTab: 'Рәсем тасвирламасы', | ||
11 | lockRatio: 'Lock Ratio', // MISSING | ||
12 | menu: 'Рәсем үзлекләре', | ||
13 | pathName: 'рәсем', | ||
14 | pathNameCaption: 'исем', | ||
15 | resetSize: 'Баштагы зурлык', | ||
16 | resizer: 'Күчереп куер өчен басып шудырыгыз', | ||
17 | title: 'Рәсем үзлекләре', | ||
18 | uploadTab: 'Йөкләү', | ||
19 | urlMissing: 'Image source URL is missing.', // MISSING | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/ug.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/ug.js deleted file mode 100644 index af146f2..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/ug.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'ug', { | ||
6 | alt: 'تېكىست ئالماشتۇر', | ||
7 | btnUpload: 'مۇلازىمېتىرغا يۈكلە', | ||
8 | captioned: 'ماۋزۇلۇق سۈرەت', | ||
9 | captionPlaceholder: 'Caption', // MISSING | ||
10 | infoTab: 'سۈرەت', | ||
11 | lockRatio: 'نىسبەتنى قۇلۇپلا', | ||
12 | menu: 'سۈرەت خاسلىقى', | ||
13 | pathName: 'image', // MISSING | ||
14 | pathNameCaption: 'caption', // MISSING | ||
15 | resetSize: 'ئەسلى چوڭلۇق', | ||
16 | resizer: 'Click and drag to resize', // MISSING | ||
17 | title: 'سۈرەت خاسلىقى', | ||
18 | uploadTab: 'يۈكلە', | ||
19 | urlMissing: 'سۈرەتنىڭ ئەسلى ھۆججەت ئادرېسى كەم', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/uk.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/uk.js deleted file mode 100644 index 1cf3cac..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/uk.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'uk', { | ||
6 | alt: 'Альтернативний текст', | ||
7 | btnUpload: 'Надіслати на сервер', | ||
8 | captioned: 'Підписане зображення', | ||
9 | captionPlaceholder: 'Заголовок', | ||
10 | infoTab: 'Інформація про зображення', | ||
11 | lockRatio: 'Зберегти пропорції', | ||
12 | menu: 'Властивості зображення', | ||
13 | pathName: 'Зображення', | ||
14 | pathNameCaption: 'заголовок', | ||
15 | resetSize: 'Очистити поля розмірів', | ||
16 | resizer: 'Клікніть та потягніть для зміни розмірів', | ||
17 | title: 'Властивості зображення', | ||
18 | uploadTab: 'Надіслати', | ||
19 | urlMissing: 'Вкажіть URL зображення.', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/vi.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/vi.js deleted file mode 100644 index 7a40fbf..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/vi.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'vi', { | ||
6 | alt: 'Chú thích ảnh', | ||
7 | btnUpload: 'Tải lên máy chủ', | ||
8 | captioned: 'Ảnh có chú thích', | ||
9 | captionPlaceholder: 'Nhãn', | ||
10 | infoTab: 'Thông tin của ảnh', | ||
11 | lockRatio: 'Giữ nguyên tỷ lệ', | ||
12 | menu: 'Thuộc tính của ảnh', | ||
13 | pathName: 'ảnh', | ||
14 | pathNameCaption: 'chú thích', | ||
15 | resetSize: 'Kích thước gốc', | ||
16 | resizer: 'Kéo rê để thay đổi kích cỡ', | ||
17 | title: 'Thuộc tính của ảnh', | ||
18 | uploadTab: 'Tải lên', | ||
19 | urlMissing: 'Thiếu đường dẫn hình ảnh', | ||
20 | altMissing: 'Alternative text is missing.' // MISSING | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/zh-cn.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/zh-cn.js deleted file mode 100644 index 48c436f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/zh-cn.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'zh-cn', { | ||
6 | alt: '替换文本', | ||
7 | btnUpload: '上传到服务器', | ||
8 | captioned: '带标题图像', | ||
9 | captionPlaceholder: '标题', | ||
10 | infoTab: '图像信息', | ||
11 | lockRatio: '锁定比例', | ||
12 | menu: '图像属性', | ||
13 | pathName: '图像', | ||
14 | pathNameCaption: '标题', | ||
15 | resetSize: '原始尺寸', | ||
16 | resizer: '点击并拖拽以改变尺寸', | ||
17 | title: '图像属性', | ||
18 | uploadTab: '上传', | ||
19 | urlMissing: '缺少图像源文件地址', | ||
20 | altMissing: '缺少替换文本' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/lang/zh.js b/app/assets/javascripts/ckeditor/plugins/image2/lang/zh.js deleted file mode 100644 index 1578b41..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/lang/zh.js +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'image2', 'zh', { | ||
6 | alt: '替代文字', | ||
7 | btnUpload: '傳送至伺服器', | ||
8 | captioned: '已加標題之圖片', | ||
9 | captionPlaceholder: '標題', | ||
10 | infoTab: '影像資訊', | ||
11 | lockRatio: '固定比例', | ||
12 | menu: '影像屬性', | ||
13 | pathName: '圖片', | ||
14 | pathNameCaption: '標題', | ||
15 | resetSize: '重設大小', | ||
16 | resizer: '拖曳以改變大小', | ||
17 | title: '影像屬性', | ||
18 | uploadTab: '上傳', | ||
19 | urlMissing: '遺失圖片來源之 URL ', | ||
20 | altMissing: '替代文字遺失。' | ||
21 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/plugin.js b/app/assets/javascripts/ckeditor/plugins/image2/plugin.js deleted file mode 100644 index 3a55255..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/plugin.js +++ /dev/null | |||
@@ -1,1712 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | 'use strict'; | ||
7 | |||
8 | ( function() { | ||
9 | |||
10 | var template = '<img alt="" src="" />', | ||
11 | templateBlock = new CKEDITOR.template( | ||
12 | '<figure class="{captionedClass}">' + | ||
13 | template + | ||
14 | '<figcaption>{captionPlaceholder}</figcaption>' + | ||
15 | '</figure>' ), | ||
16 | alignmentsObj = { left: 0, center: 1, right: 2 }, | ||
17 | regexPercent = /^\s*(\d+\%)\s*$/i; | ||
18 | |||
19 | CKEDITOR.plugins.add( 'image2', { | ||
20 | // jscs:disable maximumLineLength | ||
21 | lang: 'af,ar,az,bg,bn,bs,ca,cs,cy,da,de,de-ch,el,en,en-au,en-ca,en-gb,eo,es,es-mx,et,eu,fa,fi,fo,fr,fr-ca,gl,gu,he,hi,hr,hu,id,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,oc,pl,pt,pt-br,ro,ru,si,sk,sl,sq,sr,sr-latn,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% | ||
22 | // jscs:enable maximumLineLength | ||
23 | requires: 'widget,dialog', | ||
24 | icons: 'image', | ||
25 | hidpi: true, | ||
26 | |||
27 | onLoad: function() { | ||
28 | CKEDITOR.addCss( | ||
29 | '.cke_image_nocaption{' + | ||
30 | // This is to remove unwanted space so resize | ||
31 | // wrapper is displayed property. | ||
32 | 'line-height:0' + | ||
33 | '}' + | ||
34 | '.cke_editable.cke_image_sw, .cke_editable.cke_image_sw *{cursor:sw-resize !important}' + | ||
35 | '.cke_editable.cke_image_se, .cke_editable.cke_image_se *{cursor:se-resize !important}' + | ||
36 | '.cke_image_resizer{' + | ||
37 | 'display:none;' + | ||
38 | 'position:absolute;' + | ||
39 | 'width:10px;' + | ||
40 | 'height:10px;' + | ||
41 | 'bottom:-5px;' + | ||
42 | 'right:-5px;' + | ||
43 | 'background:#000;' + | ||
44 | 'outline:1px solid #fff;' + | ||
45 | // Prevent drag handler from being misplaced (http://dev.ckeditor.com/ticket/11207). | ||
46 | 'line-height:0;' + | ||
47 | 'cursor:se-resize;' + | ||
48 | '}' + | ||
49 | '.cke_image_resizer_wrapper{' + | ||
50 | 'position:relative;' + | ||
51 | 'display:inline-block;' + | ||
52 | 'line-height:0;' + | ||
53 | '}' + | ||
54 | // Bottom-left corner style of the resizer. | ||
55 | '.cke_image_resizer.cke_image_resizer_left{' + | ||
56 | 'right:auto;' + | ||
57 | 'left:-5px;' + | ||
58 | 'cursor:sw-resize;' + | ||
59 | '}' + | ||
60 | '.cke_widget_wrapper:hover .cke_image_resizer,' + | ||
61 | '.cke_image_resizer.cke_image_resizing{' + | ||
62 | 'display:block' + | ||
63 | '}' + | ||
64 | // Expand widget wrapper when linked inline image. | ||
65 | '.cke_widget_wrapper>a{' + | ||
66 | 'display:inline-block' + | ||
67 | '}' ); | ||
68 | }, | ||
69 | |||
70 | init: function( editor ) { | ||
71 | // Adapts configuration from original image plugin. Should be removed | ||
72 | // when we'll rename image2 to image. | ||
73 | var config = editor.config, | ||
74 | lang = editor.lang.image2, | ||
75 | image = widgetDef( editor ); | ||
76 | |||
77 | // Since filebrowser plugin discovers config properties by dialog (plugin?) | ||
78 | // names (sic!), this hack will be necessary as long as Image2 is not named | ||
79 | // Image. And since Image2 will never be Image, for sure some filebrowser logic | ||
80 | // got to be refined. | ||
81 | config.filebrowserImage2BrowseUrl = config.filebrowserImageBrowseUrl; | ||
82 | config.filebrowserImage2UploadUrl = config.filebrowserImageUploadUrl; | ||
83 | |||
84 | // Add custom elementspath names to widget definition. | ||
85 | image.pathName = lang.pathName; | ||
86 | image.editables.caption.pathName = lang.pathNameCaption; | ||
87 | |||
88 | // Register the widget. | ||
89 | editor.widgets.add( 'image', image ); | ||
90 | |||
91 | // Add toolbar button for this plugin. | ||
92 | editor.ui.addButton && editor.ui.addButton( 'Image', { | ||
93 | label: editor.lang.common.image, | ||
94 | command: 'image', | ||
95 | toolbar: 'insert,10' | ||
96 | } ); | ||
97 | |||
98 | // Register context menu option for editing widget. | ||
99 | if ( editor.contextMenu ) { | ||
100 | editor.addMenuGroup( 'image', 10 ); | ||
101 | |||
102 | editor.addMenuItem( 'image', { | ||
103 | label: lang.menu, | ||
104 | command: 'image', | ||
105 | group: 'image' | ||
106 | } ); | ||
107 | } | ||
108 | |||
109 | CKEDITOR.dialog.add( 'image2', this.path + 'dialogs/image2.js' ); | ||
110 | }, | ||
111 | |||
112 | afterInit: function( editor ) { | ||
113 | // Integrate with align commands (justify plugin). | ||
114 | var align = { left: 1, right: 1, center: 1, block: 1 }, | ||
115 | integrate = alignCommandIntegrator( editor ); | ||
116 | |||
117 | for ( var value in align ) | ||
118 | integrate( value ); | ||
119 | |||
120 | // Integrate with link commands (link plugin). | ||
121 | linkCommandIntegrator( editor ); | ||
122 | } | ||
123 | } ); | ||
124 | |||
125 | // Wiget states (forms) depending on alignment and configuration. | ||
126 | // | ||
127 | // Non-captioned widget (inline styles) | ||
128 | // ┌──────┬───────────────────────────────┬─────────────────────────────┐ | ||
129 | // │Align │Internal form │Data │ | ||
130 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
131 | // │none │<wrapper> │<img /> │ | ||
132 | // │ │ <img /> │ │ | ||
133 | // │ │</wrapper> │ │ | ||
134 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
135 | // │left │<wrapper style=”float:left”> │<img style=”float:left” /> │ | ||
136 | // │ │ <img /> │ │ | ||
137 | // │ │</wrapper> │ │ | ||
138 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
139 | // │center│<wrapper> │<p style=”text-align:center”>│ | ||
140 | // │ │ <p style=”text-align:center”> │ <img /> │ | ||
141 | // │ │ <img /> │</p> │ | ||
142 | // │ │ </p> │ │ | ||
143 | // │ │</wrapper> │ │ | ||
144 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
145 | // │right │<wrapper style=”float:right”> │<img style=”float:right” /> │ | ||
146 | // │ │ <img /> │ │ | ||
147 | // │ │</wrapper> │ │ | ||
148 | // └──────┴───────────────────────────────┴─────────────────────────────┘ | ||
149 | // | ||
150 | // Non-captioned widget (config.image2_alignClasses defined) | ||
151 | // ┌──────┬───────────────────────────────┬─────────────────────────────┐ | ||
152 | // │Align │Internal form │Data │ | ||
153 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
154 | // │none │<wrapper> │<img /> │ | ||
155 | // │ │ <img /> │ │ | ||
156 | // │ │</wrapper> │ │ | ||
157 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
158 | // │left │<wrapper class=”left”> │<img class=”left” /> │ | ||
159 | // │ │ <img /> │ │ | ||
160 | // │ │</wrapper> │ │ | ||
161 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
162 | // │center│<wrapper> │<p class=”center”> │ | ||
163 | // │ │ <p class=”center”> │ <img /> │ | ||
164 | // │ │ <img /> │</p> │ | ||
165 | // │ │ </p> │ │ | ||
166 | // │ │</wrapper> │ │ | ||
167 | // ├──────┼───────────────────────────────┼─────────────────────────────┤ | ||
168 | // │right │<wrapper class=”right”> │<img class=”right” /> │ | ||
169 | // │ │ <img /> │ │ | ||
170 | // │ │</wrapper> │ │ | ||
171 | // └──────┴───────────────────────────────┴─────────────────────────────┘ | ||
172 | // | ||
173 | // Captioned widget (inline styles) | ||
174 | // ┌──────┬────────────────────────────────────────┬────────────────────────────────────────┐ | ||
175 | // │Align │Internal form │Data │ | ||
176 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
177 | // │none │<wrapper> │<figure /> │ | ||
178 | // │ │ <figure /> │ │ | ||
179 | // │ │</wrapper> │ │ | ||
180 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
181 | // │left │<wrapper style=”float:left”> │<figure style=”float:left” /> │ | ||
182 | // │ │ <figure /> │ │ | ||
183 | // │ │</wrapper> │ │ | ||
184 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
185 | // │center│<wrapper style=”text-align:center”> │<div style=”text-align:center”> │ | ||
186 | // │ │ <figure style=”display:inline-block” />│ <figure style=”display:inline-block” />│ | ||
187 | // │ │</wrapper> │</p> │ | ||
188 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
189 | // │right │<wrapper style=”float:right”> │<figure style=”float:right” /> │ | ||
190 | // │ │ <figure /> │ │ | ||
191 | // │ │</wrapper> │ │ | ||
192 | // └──────┴────────────────────────────────────────┴────────────────────────────────────────┘ | ||
193 | // | ||
194 | // Captioned widget (config.image2_alignClasses defined) | ||
195 | // ┌──────┬────────────────────────────────────────┬────────────────────────────────────────┐ | ||
196 | // │Align │Internal form │Data │ | ||
197 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
198 | // │none │<wrapper> │<figure /> │ | ||
199 | // │ │ <figure /> │ │ | ||
200 | // │ │</wrapper> │ │ | ||
201 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
202 | // │left │<wrapper class=”left”> │<figure class=”left” /> │ | ||
203 | // │ │ <figure /> │ │ | ||
204 | // │ │</wrapper> │ │ | ||
205 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
206 | // │center│<wrapper class=”center”> │<div class=”center”> │ | ||
207 | // │ │ <figure /> │ <figure /> │ | ||
208 | // │ │</wrapper> │</p> │ | ||
209 | // ├──────┼────────────────────────────────────────┼────────────────────────────────────────┤ | ||
210 | // │right │<wrapper class=”right”> │<figure class=”right” /> │ | ||
211 | // │ │ <figure /> │ │ | ||
212 | // │ │</wrapper> │ │ | ||
213 | // └──────┴────────────────────────────────────────┴────────────────────────────────────────┘ | ||
214 | // | ||
215 | // @param {CKEDITOR.editor} | ||
216 | // @returns {Object} | ||
217 | function widgetDef( editor ) { | ||
218 | var alignClasses = editor.config.image2_alignClasses, | ||
219 | captionedClass = editor.config.image2_captionedClass; | ||
220 | |||
221 | function deflate() { | ||
222 | if ( this.deflated ) | ||
223 | return; | ||
224 | |||
225 | // Remember whether widget was focused before destroyed. | ||
226 | if ( editor.widgets.focused == this.widget ) | ||
227 | this.focused = true; | ||
228 | |||
229 | editor.widgets.destroy( this.widget ); | ||
230 | |||
231 | // Mark widget was destroyed. | ||
232 | this.deflated = true; | ||
233 | } | ||
234 | |||
235 | function inflate() { | ||
236 | var editable = editor.editable(), | ||
237 | doc = editor.document; | ||
238 | |||
239 | // Create a new widget. This widget will be either captioned | ||
240 | // non-captioned, block or inline according to what is the | ||
241 | // new state of the widget. | ||
242 | if ( this.deflated ) { | ||
243 | this.widget = editor.widgets.initOn( this.element, 'image', this.widget.data ); | ||
244 | |||
245 | // Once widget was re-created, it may become an inline element without | ||
246 | // block wrapper (i.e. when unaligned, end not captioned). Let's do some | ||
247 | // sort of autoparagraphing here (http://dev.ckeditor.com/ticket/10853). | ||
248 | if ( this.widget.inline && !( new CKEDITOR.dom.elementPath( this.widget.wrapper, editable ).block ) ) { | ||
249 | var block = doc.createElement( editor.activeEnterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ); | ||
250 | block.replace( this.widget.wrapper ); | ||
251 | this.widget.wrapper.move( block ); | ||
252 | } | ||
253 | |||
254 | // The focus must be transferred from the old one (destroyed) | ||
255 | // to the new one (just created). | ||
256 | if ( this.focused ) { | ||
257 | this.widget.focus(); | ||
258 | delete this.focused; | ||
259 | } | ||
260 | |||
261 | delete this.deflated; | ||
262 | } | ||
263 | |||
264 | // If now widget was destroyed just update wrapper's alignment. | ||
265 | // According to the new state. | ||
266 | else { | ||
267 | setWrapperAlign( this.widget, alignClasses ); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | return { | ||
272 | allowedContent: getWidgetAllowedContent( editor ), | ||
273 | |||
274 | requiredContent: 'img[src,alt]', | ||
275 | |||
276 | features: getWidgetFeatures( editor ), | ||
277 | |||
278 | styleableElements: 'img figure', | ||
279 | |||
280 | // This widget converts style-driven dimensions to attributes. | ||
281 | contentTransformations: [ | ||
282 | [ 'img[width]: sizeToAttribute' ] | ||
283 | ], | ||
284 | |||
285 | // This widget has an editable caption. | ||
286 | editables: { | ||
287 | caption: { | ||
288 | selector: 'figcaption', | ||
289 | allowedContent: 'br em strong sub sup u s; a[!href,target]' | ||
290 | } | ||
291 | }, | ||
292 | |||
293 | parts: { | ||
294 | image: 'img', | ||
295 | caption: 'figcaption' | ||
296 | // parts#link defined in widget#init | ||
297 | }, | ||
298 | |||
299 | // The name of this widget's dialog. | ||
300 | dialog: 'image2', | ||
301 | |||
302 | // Template of the widget: plain image. | ||
303 | template: template, | ||
304 | |||
305 | data: function() { | ||
306 | var features = this.features; | ||
307 | |||
308 | // Image can't be captioned when figcaption is disallowed (http://dev.ckeditor.com/ticket/11004). | ||
309 | if ( this.data.hasCaption && !editor.filter.checkFeature( features.caption ) ) | ||
310 | this.data.hasCaption = false; | ||
311 | |||
312 | // Image can't be aligned when floating is disallowed (http://dev.ckeditor.com/ticket/11004). | ||
313 | if ( this.data.align != 'none' && !editor.filter.checkFeature( features.align ) ) | ||
314 | this.data.align = 'none'; | ||
315 | |||
316 | // Convert the internal form of the widget from the old state to the new one. | ||
317 | this.shiftState( { | ||
318 | widget: this, | ||
319 | element: this.element, | ||
320 | oldData: this.oldData, | ||
321 | newData: this.data, | ||
322 | deflate: deflate, | ||
323 | inflate: inflate | ||
324 | } ); | ||
325 | |||
326 | // Update widget.parts.link since it will not auto-update unless widget | ||
327 | // is destroyed and re-inited. | ||
328 | if ( !this.data.link ) { | ||
329 | if ( this.parts.link ) | ||
330 | delete this.parts.link; | ||
331 | } else { | ||
332 | if ( !this.parts.link ) | ||
333 | this.parts.link = this.parts.image.getParent(); | ||
334 | } | ||
335 | |||
336 | this.parts.image.setAttributes( { | ||
337 | src: this.data.src, | ||
338 | |||
339 | // This internal is required by the editor. | ||
340 | 'data-cke-saved-src': this.data.src, | ||
341 | |||
342 | alt: this.data.alt | ||
343 | } ); | ||
344 | |||
345 | // If shifting non-captioned -> captioned, remove classes | ||
346 | // related to styles from <img/>. | ||
347 | if ( this.oldData && !this.oldData.hasCaption && this.data.hasCaption ) { | ||
348 | for ( var c in this.data.classes ) | ||
349 | this.parts.image.removeClass( c ); | ||
350 | } | ||
351 | |||
352 | // Set dimensions of the image according to gathered data. | ||
353 | // Do it only when the attributes are allowed (http://dev.ckeditor.com/ticket/11004). | ||
354 | if ( editor.filter.checkFeature( features.dimension ) ) | ||
355 | setDimensions( this ); | ||
356 | |||
357 | // Cache current data. | ||
358 | this.oldData = CKEDITOR.tools.extend( {}, this.data ); | ||
359 | }, | ||
360 | |||
361 | init: function() { | ||
362 | var helpers = CKEDITOR.plugins.image2, | ||
363 | image = this.parts.image, | ||
364 | data = { | ||
365 | hasCaption: !!this.parts.caption, | ||
366 | src: image.getAttribute( 'src' ), | ||
367 | alt: image.getAttribute( 'alt' ) || '', | ||
368 | width: image.getAttribute( 'width' ) || '', | ||
369 | height: image.getAttribute( 'height' ) || '', | ||
370 | |||
371 | // Lock ratio is on by default (http://dev.ckeditor.com/ticket/10833). | ||
372 | lock: this.ready ? helpers.checkHasNaturalRatio( image ) : true | ||
373 | }; | ||
374 | |||
375 | // If we used 'a' in widget#parts definition, it could happen that | ||
376 | // selected element is a child of widget.parts#caption. Since there's no clever | ||
377 | // way to solve it with CSS selectors, it's done like that. (http://dev.ckeditor.com/ticket/11783). | ||
378 | var link = image.getAscendant( 'a' ); | ||
379 | |||
380 | if ( link && this.wrapper.contains( link ) ) | ||
381 | this.parts.link = link; | ||
382 | |||
383 | // Depending on configuration, read style/class from element and | ||
384 | // then remove it. Removed style/class will be set on wrapper in #data listener. | ||
385 | // Note: Center alignment is detected during upcast, so only left/right cases | ||
386 | // are checked below. | ||
387 | if ( !data.align ) { | ||
388 | var alignElement = data.hasCaption ? this.element : image; | ||
389 | |||
390 | // Read the initial left/right alignment from the class set on element. | ||
391 | if ( alignClasses ) { | ||
392 | if ( alignElement.hasClass( alignClasses[ 0 ] ) ) { | ||
393 | data.align = 'left'; | ||
394 | } else if ( alignElement.hasClass( alignClasses[ 2 ] ) ) { | ||
395 | data.align = 'right'; | ||
396 | } | ||
397 | |||
398 | if ( data.align ) { | ||
399 | alignElement.removeClass( alignClasses[ alignmentsObj[ data.align ] ] ); | ||
400 | } else { | ||
401 | data.align = 'none'; | ||
402 | } | ||
403 | } | ||
404 | // Read initial float style from figure/image and then remove it. | ||
405 | else { | ||
406 | data.align = alignElement.getStyle( 'float' ) || 'none'; | ||
407 | alignElement.removeStyle( 'float' ); | ||
408 | } | ||
409 | } | ||
410 | |||
411 | // Update data.link object with attributes if the link has been discovered. | ||
412 | if ( editor.plugins.link && this.parts.link ) { | ||
413 | data.link = helpers.getLinkAttributesParser()( editor, this.parts.link ); | ||
414 | |||
415 | // Get rid of cke_widget_* classes in data. Otherwise | ||
416 | // they might appear in link dialog. | ||
417 | var advanced = data.link.advanced; | ||
418 | if ( advanced && advanced.advCSSClasses ) { | ||
419 | advanced.advCSSClasses = CKEDITOR.tools.trim( advanced.advCSSClasses.replace( /cke_\S+/, '' ) ); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | // Get rid of extra vertical space when there's no caption. | ||
424 | // It will improve the look of the resizer. | ||
425 | this.wrapper[ ( data.hasCaption ? 'remove' : 'add' ) + 'Class' ]( 'cke_image_nocaption' ); | ||
426 | |||
427 | this.setData( data ); | ||
428 | |||
429 | // Setup dynamic image resizing with mouse. | ||
430 | // Don't initialize resizer when dimensions are disallowed (http://dev.ckeditor.com/ticket/11004). | ||
431 | if ( editor.filter.checkFeature( this.features.dimension ) && editor.config.image2_disableResizer !== true ) | ||
432 | setupResizer( this ); | ||
433 | |||
434 | this.shiftState = helpers.stateShifter( this.editor ); | ||
435 | |||
436 | // Add widget editing option to its context menu. | ||
437 | this.on( 'contextMenu', function( evt ) { | ||
438 | evt.data.image = CKEDITOR.TRISTATE_OFF; | ||
439 | |||
440 | // Integrate context menu items for link. | ||
441 | // Note that widget may be wrapped in a link, which | ||
442 | // does not belong to that widget (http://dev.ckeditor.com/ticket/11814). | ||
443 | if ( this.parts.link || this.wrapper.getAscendant( 'a' ) ) | ||
444 | evt.data.link = evt.data.unlink = CKEDITOR.TRISTATE_OFF; | ||
445 | } ); | ||
446 | |||
447 | // Pass the reference to this widget to the dialog. | ||
448 | this.on( 'dialog', function( evt ) { | ||
449 | evt.data.widget = this; | ||
450 | }, this ); | ||
451 | }, | ||
452 | |||
453 | // Overrides default method to handle internal mutability of Image2. | ||
454 | // @see CKEDITOR.plugins.widget#addClass | ||
455 | addClass: function( className ) { | ||
456 | getStyleableElement( this ).addClass( className ); | ||
457 | }, | ||
458 | |||
459 | // Overrides default method to handle internal mutability of Image2. | ||
460 | // @see CKEDITOR.plugins.widget#hasClass | ||
461 | hasClass: function( className ) { | ||
462 | return getStyleableElement( this ).hasClass( className ); | ||
463 | }, | ||
464 | |||
465 | // Overrides default method to handle internal mutability of Image2. | ||
466 | // @see CKEDITOR.plugins.widget#removeClass | ||
467 | removeClass: function( className ) { | ||
468 | getStyleableElement( this ).removeClass( className ); | ||
469 | }, | ||
470 | |||
471 | // Overrides default method to handle internal mutability of Image2. | ||
472 | // @see CKEDITOR.plugins.widget#getClasses | ||
473 | getClasses: ( function() { | ||
474 | var classRegex = new RegExp( '^(' + [].concat( captionedClass, alignClasses ).join( '|' ) + ')$' ); | ||
475 | |||
476 | return function() { | ||
477 | var classes = this.repository.parseElementClasses( getStyleableElement( this ).getAttribute( 'class' ) ); | ||
478 | |||
479 | // Neither config.image2_captionedClass nor config.image2_alignClasses | ||
480 | // do not belong to style classes. | ||
481 | for ( var c in classes ) { | ||
482 | if ( classRegex.test( c ) ) | ||
483 | delete classes[ c ]; | ||
484 | } | ||
485 | |||
486 | return classes; | ||
487 | }; | ||
488 | } )(), | ||
489 | |||
490 | upcast: upcastWidgetElement( editor ), | ||
491 | downcast: downcastWidgetElement( editor ), | ||
492 | |||
493 | getLabel: function() { | ||
494 | var label = ( this.data.alt || '' ) + ' ' + this.pathName; | ||
495 | |||
496 | return this.editor.lang.widget.label.replace( /%1/, label ); | ||
497 | } | ||
498 | }; | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * A set of Enhanced Image (image2) plugin helpers. | ||
503 | * | ||
504 | * @class | ||
505 | * @singleton | ||
506 | */ | ||
507 | CKEDITOR.plugins.image2 = { | ||
508 | stateShifter: function( editor ) { | ||
509 | // Tag name used for centering non-captioned widgets. | ||
510 | var doc = editor.document, | ||
511 | alignClasses = editor.config.image2_alignClasses, | ||
512 | captionedClass = editor.config.image2_captionedClass, | ||
513 | editable = editor.editable(), | ||
514 | |||
515 | // The order that stateActions get executed. It matters! | ||
516 | shiftables = [ 'hasCaption', 'align', 'link' ]; | ||
517 | |||
518 | // Atomic procedures, one per state variable. | ||
519 | var stateActions = { | ||
520 | align: function( shift, oldValue, newValue ) { | ||
521 | var el = shift.element; | ||
522 | |||
523 | // Alignment changed. | ||
524 | if ( shift.changed.align ) { | ||
525 | // No caption in the new state. | ||
526 | if ( !shift.newData.hasCaption ) { | ||
527 | // Changed to "center" (non-captioned). | ||
528 | if ( newValue == 'center' ) { | ||
529 | shift.deflate(); | ||
530 | shift.element = wrapInCentering( editor, el ); | ||
531 | } | ||
532 | |||
533 | // Changed to "non-center" from "center" while caption removed. | ||
534 | if ( !shift.changed.hasCaption && oldValue == 'center' && newValue != 'center' ) { | ||
535 | shift.deflate(); | ||
536 | shift.element = unwrapFromCentering( el ); | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | |||
541 | // Alignment remains and "center" removed caption. | ||
542 | else if ( newValue == 'center' && shift.changed.hasCaption && !shift.newData.hasCaption ) { | ||
543 | shift.deflate(); | ||
544 | shift.element = wrapInCentering( editor, el ); | ||
545 | } | ||
546 | |||
547 | // Finally set display for figure. | ||
548 | if ( !alignClasses && el.is( 'figure' ) ) { | ||
549 | if ( newValue == 'center' ) | ||
550 | el.setStyle( 'display', 'inline-block' ); | ||
551 | else | ||
552 | el.removeStyle( 'display' ); | ||
553 | } | ||
554 | }, | ||
555 | |||
556 | hasCaption: function( shift, oldValue, newValue ) { | ||
557 | // This action is for real state change only. | ||
558 | if ( !shift.changed.hasCaption ) | ||
559 | return; | ||
560 | |||
561 | // Get <img/> or <a><img/></a> from widget. Note that widget element might itself | ||
562 | // be what we're looking for. Also element can be <p style="text-align:center"><a>...</a></p>. | ||
563 | var imageOrLink; | ||
564 | if ( shift.element.is( { img: 1, a: 1 } ) ) | ||
565 | imageOrLink = shift.element; | ||
566 | else | ||
567 | imageOrLink = shift.element.findOne( 'a,img' ); | ||
568 | |||
569 | // Switching hasCaption always destroys the widget. | ||
570 | shift.deflate(); | ||
571 | |||
572 | // There was no caption, but the caption is to be added. | ||
573 | if ( newValue ) { | ||
574 | // Create new <figure> from widget template. | ||
575 | var figure = CKEDITOR.dom.element.createFromHtml( templateBlock.output( { | ||
576 | captionedClass: captionedClass, | ||
577 | captionPlaceholder: editor.lang.image2.captionPlaceholder | ||
578 | } ), doc ); | ||
579 | |||
580 | // Replace element with <figure>. | ||
581 | replaceSafely( figure, shift.element ); | ||
582 | |||
583 | // Use old <img/> or <a><img/></a> instead of the one from the template, | ||
584 | // so we won't lose additional attributes. | ||
585 | imageOrLink.replace( figure.findOne( 'img' ) ); | ||
586 | |||
587 | // Update widget's element. | ||
588 | shift.element = figure; | ||
589 | } | ||
590 | |||
591 | // The caption was present, but now it's to be removed. | ||
592 | else { | ||
593 | // Unwrap <img/> or <a><img/></a> from figure. | ||
594 | imageOrLink.replace( shift.element ); | ||
595 | |||
596 | // Update widget's element. | ||
597 | shift.element = imageOrLink; | ||
598 | } | ||
599 | }, | ||
600 | |||
601 | link: function( shift, oldValue, newValue ) { | ||
602 | if ( shift.changed.link ) { | ||
603 | var img = shift.element.is( 'img' ) ? | ||
604 | shift.element : shift.element.findOne( 'img' ), | ||
605 | link = shift.element.is( 'a' ) ? | ||
606 | shift.element : shift.element.findOne( 'a' ), | ||
607 | // Why deflate: | ||
608 | // If element is <img/>, it will be wrapped into <a>, | ||
609 | // which becomes a new widget.element. | ||
610 | // If element is <a><img/></a>, it will be unlinked | ||
611 | // so <img/> becomes a new widget.element. | ||
612 | needsDeflate = ( shift.element.is( 'a' ) && !newValue ) || ( shift.element.is( 'img' ) && newValue ), | ||
613 | newEl; | ||
614 | |||
615 | if ( needsDeflate ) | ||
616 | shift.deflate(); | ||
617 | |||
618 | // If unlinked the image, returned element is <img>. | ||
619 | if ( !newValue ) | ||
620 | newEl = unwrapFromLink( link ); | ||
621 | else { | ||
622 | // If linked the image, returned element is <a>. | ||
623 | if ( !oldValue ) | ||
624 | newEl = wrapInLink( img, shift.newData.link ); | ||
625 | |||
626 | // Set and remove all attributes associated with this state. | ||
627 | var attributes = CKEDITOR.plugins.image2.getLinkAttributesGetter()( editor, newValue ); | ||
628 | |||
629 | if ( !CKEDITOR.tools.isEmpty( attributes.set ) ) | ||
630 | ( newEl || link ).setAttributes( attributes.set ); | ||
631 | |||
632 | if ( attributes.removed.length ) | ||
633 | ( newEl || link ).removeAttributes( attributes.removed ); | ||
634 | } | ||
635 | |||
636 | if ( needsDeflate ) | ||
637 | shift.element = newEl; | ||
638 | } | ||
639 | } | ||
640 | }; | ||
641 | |||
642 | function wrapInCentering( editor, element ) { | ||
643 | var attribsAndStyles = {}; | ||
644 | |||
645 | if ( alignClasses ) | ||
646 | attribsAndStyles.attributes = { 'class': alignClasses[ 1 ] }; | ||
647 | else | ||
648 | attribsAndStyles.styles = { 'text-align': 'center' }; | ||
649 | |||
650 | // There's no gentle way to center inline element with CSS, so create p/div | ||
651 | // that wraps widget contents and does the trick either with style or class. | ||
652 | var center = doc.createElement( | ||
653 | editor.activeEnterMode == CKEDITOR.ENTER_P ? 'p' : 'div', attribsAndStyles ); | ||
654 | |||
655 | // Replace element with centering wrapper. | ||
656 | replaceSafely( center, element ); | ||
657 | element.move( center ); | ||
658 | |||
659 | return center; | ||
660 | } | ||
661 | |||
662 | function unwrapFromCentering( element ) { | ||
663 | var imageOrLink = element.findOne( 'a,img' ); | ||
664 | |||
665 | imageOrLink.replace( element ); | ||
666 | |||
667 | return imageOrLink; | ||
668 | } | ||
669 | |||
670 | // Wraps <img/> -> <a><img/></a>. | ||
671 | // Returns reference to <a>. | ||
672 | // | ||
673 | // @param {CKEDITOR.dom.element} img | ||
674 | // @param {Object} linkData | ||
675 | // @returns {CKEDITOR.dom.element} | ||
676 | function wrapInLink( img, linkData ) { | ||
677 | var link = doc.createElement( 'a', { | ||
678 | attributes: { | ||
679 | href: linkData.url | ||
680 | } | ||
681 | } ); | ||
682 | |||
683 | link.replace( img ); | ||
684 | img.move( link ); | ||
685 | |||
686 | return link; | ||
687 | } | ||
688 | |||
689 | // De-wraps <a><img/></a> -> <img/>. | ||
690 | // Returns the reference to <img/> | ||
691 | // | ||
692 | // @param {CKEDITOR.dom.element} link | ||
693 | // @returns {CKEDITOR.dom.element} | ||
694 | function unwrapFromLink( link ) { | ||
695 | var img = link.findOne( 'img' ); | ||
696 | |||
697 | img.replace( link ); | ||
698 | |||
699 | return img; | ||
700 | } | ||
701 | |||
702 | function replaceSafely( replacing, replaced ) { | ||
703 | if ( replaced.getParent() ) { | ||
704 | var range = editor.createRange(); | ||
705 | |||
706 | range.moveToPosition( replaced, CKEDITOR.POSITION_BEFORE_START ); | ||
707 | |||
708 | // Remove old element. Do it before insertion to avoid a case when | ||
709 | // element is moved from 'replaced' element before it, what creates | ||
710 | // a tricky case which insertElementIntorRange does not handle. | ||
711 | replaced.remove(); | ||
712 | |||
713 | editable.insertElementIntoRange( replacing, range ); | ||
714 | } | ||
715 | else { | ||
716 | replacing.replace( replaced ); | ||
717 | } | ||
718 | } | ||
719 | |||
720 | return function( shift ) { | ||
721 | var name, i; | ||
722 | |||
723 | shift.changed = {}; | ||
724 | |||
725 | for ( i = 0; i < shiftables.length; i++ ) { | ||
726 | name = shiftables[ i ]; | ||
727 | |||
728 | shift.changed[ name ] = shift.oldData ? | ||
729 | shift.oldData[ name ] !== shift.newData[ name ] : false; | ||
730 | } | ||
731 | |||
732 | // Iterate over possible state variables. | ||
733 | for ( i = 0; i < shiftables.length; i++ ) { | ||
734 | name = shiftables[ i ]; | ||
735 | |||
736 | stateActions[ name ]( shift, | ||
737 | shift.oldData ? shift.oldData[ name ] : null, | ||
738 | shift.newData[ name ] ); | ||
739 | } | ||
740 | |||
741 | shift.inflate(); | ||
742 | }; | ||
743 | }, | ||
744 | |||
745 | /** | ||
746 | * Checks whether the current image ratio matches the natural one | ||
747 | * by comparing dimensions. | ||
748 | * | ||
749 | * @param {CKEDITOR.dom.element} image | ||
750 | * @returns {Boolean} | ||
751 | */ | ||
752 | checkHasNaturalRatio: function( image ) { | ||
753 | var $ = image.$, | ||
754 | natural = this.getNatural( image ); | ||
755 | |||
756 | // The reason for two alternative comparisons is that the rounding can come from | ||
757 | // both dimensions, e.g. there are two cases: | ||
758 | // 1. height is computed as a rounded relation of the real height and the value of width, | ||
759 | // 2. width is computed as a rounded relation of the real width and the value of heigh. | ||
760 | return Math.round( $.clientWidth / natural.width * natural.height ) == $.clientHeight || | ||
761 | Math.round( $.clientHeight / natural.height * natural.width ) == $.clientWidth; | ||
762 | }, | ||
763 | |||
764 | /** | ||
765 | * Returns natural dimensions of the image. For modern browsers | ||
766 | * it uses natural(Width|Height). For old ones (IE8) it creates | ||
767 | * a new image and reads the dimensions. | ||
768 | * | ||
769 | * @param {CKEDITOR.dom.element} image | ||
770 | * @returns {Object} | ||
771 | */ | ||
772 | getNatural: function( image ) { | ||
773 | var dimensions; | ||
774 | |||
775 | if ( image.$.naturalWidth ) { | ||
776 | dimensions = { | ||
777 | width: image.$.naturalWidth, | ||
778 | height: image.$.naturalHeight | ||
779 | }; | ||
780 | } else { | ||
781 | var img = new Image(); | ||
782 | img.src = image.getAttribute( 'src' ); | ||
783 | |||
784 | dimensions = { | ||
785 | width: img.width, | ||
786 | height: img.height | ||
787 | }; | ||
788 | } | ||
789 | |||
790 | return dimensions; | ||
791 | }, | ||
792 | |||
793 | /** | ||
794 | * Returns an attribute getter function. Default getter comes from the Link plugin | ||
795 | * and is documented by {@link CKEDITOR.plugins.link#getLinkAttributes}. | ||
796 | * | ||
797 | * **Note:** It is possible to override this method and use a custom getter e.g. | ||
798 | * in the absence of the Link plugin. | ||
799 | * | ||
800 | * **Note:** If a custom getter is used, a data model format it produces | ||
801 | * must be compatible with {@link CKEDITOR.plugins.link#getLinkAttributes}. | ||
802 | * | ||
803 | * **Note:** A custom getter must understand the data model format produced by | ||
804 | * {@link #getLinkAttributesParser} to work correctly. | ||
805 | * | ||
806 | * @returns {Function} A function that gets (composes) link attributes. | ||
807 | * @since 4.5.5 | ||
808 | */ | ||
809 | getLinkAttributesGetter: function() { | ||
810 | // http://dev.ckeditor.com/ticket/13885 | ||
811 | return CKEDITOR.plugins.link.getLinkAttributes; | ||
812 | }, | ||
813 | |||
814 | /** | ||
815 | * Returns an attribute parser function. Default parser comes from the Link plugin | ||
816 | * and is documented by {@link CKEDITOR.plugins.link#parseLinkAttributes}. | ||
817 | * | ||
818 | * **Note:** It is possible to override this method and use a custom parser e.g. | ||
819 | * in the absence of the Link plugin. | ||
820 | * | ||
821 | * **Note:** If a custom parser is used, a data model format produced by the parser | ||
822 | * must be compatible with {@link #getLinkAttributesGetter}. | ||
823 | * | ||
824 | * **Note:** If a custom parser is used, it should be compatible with the | ||
825 | * {@link CKEDITOR.plugins.link#parseLinkAttributes} data model format. Otherwise the | ||
826 | * Link plugin dialog may not be populated correctly with parsed data. However | ||
827 | * as long as Enhanced Image is **not** used with the Link plugin dialog, any custom data model | ||
828 | * will work, being stored as an internal property of Enhanced Image widget's data only. | ||
829 | * | ||
830 | * @returns {Function} A function that parses attributes. | ||
831 | * @since 4.5.5 | ||
832 | */ | ||
833 | getLinkAttributesParser: function() { | ||
834 | // http://dev.ckeditor.com/ticket/13885 | ||
835 | return CKEDITOR.plugins.link.parseLinkAttributes; | ||
836 | } | ||
837 | }; | ||
838 | |||
839 | function setWrapperAlign( widget, alignClasses ) { | ||
840 | var wrapper = widget.wrapper, | ||
841 | align = widget.data.align, | ||
842 | hasCaption = widget.data.hasCaption; | ||
843 | |||
844 | if ( alignClasses ) { | ||
845 | // Remove all align classes first. | ||
846 | for ( var i = 3; i--; ) | ||
847 | wrapper.removeClass( alignClasses[ i ] ); | ||
848 | |||
849 | if ( align == 'center' ) { | ||
850 | // Avoid touching non-captioned, centered widgets because | ||
851 | // they have the class set on the element instead of wrapper: | ||
852 | // | ||
853 | // <div class="cke_widget_wrapper"> | ||
854 | // <p class="center-class"> | ||
855 | // <img /> | ||
856 | // </p> | ||
857 | // </div> | ||
858 | if ( hasCaption ) { | ||
859 | wrapper.addClass( alignClasses[ 1 ] ); | ||
860 | } | ||
861 | } else if ( align != 'none' ) { | ||
862 | wrapper.addClass( alignClasses[ alignmentsObj[ align ] ] ); | ||
863 | } | ||
864 | } else { | ||
865 | if ( align == 'center' ) { | ||
866 | if ( hasCaption ) | ||
867 | wrapper.setStyle( 'text-align', 'center' ); | ||
868 | else | ||
869 | wrapper.removeStyle( 'text-align' ); | ||
870 | |||
871 | wrapper.removeStyle( 'float' ); | ||
872 | } | ||
873 | else { | ||
874 | if ( align == 'none' ) | ||
875 | wrapper.removeStyle( 'float' ); | ||
876 | else | ||
877 | wrapper.setStyle( 'float', align ); | ||
878 | |||
879 | wrapper.removeStyle( 'text-align' ); | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | |||
884 | // Returns a function that creates widgets from all <img> and | ||
885 | // <figure class="{config.image2_captionedClass}"> elements. | ||
886 | // | ||
887 | // @param {CKEDITOR.editor} editor | ||
888 | // @returns {Function} | ||
889 | function upcastWidgetElement( editor ) { | ||
890 | var isCenterWrapper = centerWrapperChecker( editor ), | ||
891 | captionedClass = editor.config.image2_captionedClass; | ||
892 | |||
893 | // @param {CKEDITOR.htmlParser.element} el | ||
894 | // @param {Object} data | ||
895 | return function( el, data ) { | ||
896 | var dimensions = { width: 1, height: 1 }, | ||
897 | name = el.name, | ||
898 | image; | ||
899 | |||
900 | // http://dev.ckeditor.com/ticket/11110 Don't initialize on pasted fake objects. | ||
901 | if ( el.attributes[ 'data-cke-realelement' ] ) | ||
902 | return; | ||
903 | |||
904 | // If a center wrapper is found, there are 3 possible cases: | ||
905 | // | ||
906 | // 1. <div style="text-align:center"><figure>...</figure></div>. | ||
907 | // In this case centering is done with a class set on widget.wrapper. | ||
908 | // Simply replace centering wrapper with figure (it's no longer necessary). | ||
909 | // | ||
910 | // 2. <p style="text-align:center"><img/></p>. | ||
911 | // Nothing to do here: <p> remains for styling purposes. | ||
912 | // | ||
913 | // 3. <div style="text-align:center"><img/></div>. | ||
914 | // Nothing to do here (2.) but that case is only possible in enterMode different | ||
915 | // than ENTER_P. | ||
916 | if ( isCenterWrapper( el ) ) { | ||
917 | if ( name == 'div' ) { | ||
918 | var figure = el.getFirst( 'figure' ); | ||
919 | |||
920 | // Case #1. | ||
921 | if ( figure ) { | ||
922 | el.replaceWith( figure ); | ||
923 | el = figure; | ||
924 | } | ||
925 | } | ||
926 | // Cases #2 and #3 (handled transparently) | ||
927 | |||
928 | // If there's a centering wrapper, save it in data. | ||
929 | data.align = 'center'; | ||
930 | |||
931 | // Image can be wrapped in link <a><img/></a>. | ||
932 | image = el.getFirst( 'img' ) || el.getFirst( 'a' ).getFirst( 'img' ); | ||
933 | } | ||
934 | |||
935 | // No center wrapper has been found. | ||
936 | else if ( name == 'figure' && el.hasClass( captionedClass ) ) { | ||
937 | image = el.getFirst( 'img' ) || el.getFirst( 'a' ).getFirst( 'img' ); | ||
938 | |||
939 | // Upcast linked image like <a><img/></a>. | ||
940 | } else if ( isLinkedOrStandaloneImage( el ) ) { | ||
941 | image = el.name == 'a' ? el.children[ 0 ] : el; | ||
942 | } | ||
943 | |||
944 | if ( !image ) | ||
945 | return; | ||
946 | |||
947 | // If there's an image, then cool, we got a widget. | ||
948 | // Now just remove dimension attributes expressed with %. | ||
949 | for ( var d in dimensions ) { | ||
950 | var dimension = image.attributes[ d ]; | ||
951 | |||
952 | if ( dimension && dimension.match( regexPercent ) ) | ||
953 | delete image.attributes[ d ]; | ||
954 | } | ||
955 | |||
956 | return el; | ||
957 | }; | ||
958 | } | ||
959 | |||
960 | // Returns a function which transforms the widget to the external format | ||
961 | // according to the current configuration. | ||
962 | // | ||
963 | // @param {CKEDITOR.editor} | ||
964 | function downcastWidgetElement( editor ) { | ||
965 | var alignClasses = editor.config.image2_alignClasses; | ||
966 | |||
967 | // @param {CKEDITOR.htmlParser.element} el | ||
968 | return function( el ) { | ||
969 | // In case of <a><img/></a>, <img/> is the element to hold | ||
970 | // inline styles or classes (image2_alignClasses). | ||
971 | var attrsHolder = el.name == 'a' ? el.getFirst() : el, | ||
972 | attrs = attrsHolder.attributes, | ||
973 | align = this.data.align; | ||
974 | |||
975 | // De-wrap the image from resize handle wrapper. | ||
976 | // Only block widgets have one. | ||
977 | if ( !this.inline ) { | ||
978 | var resizeWrapper = el.getFirst( 'span' ); | ||
979 | |||
980 | if ( resizeWrapper ) | ||
981 | resizeWrapper.replaceWith( resizeWrapper.getFirst( { img: 1, a: 1 } ) ); | ||
982 | } | ||
983 | |||
984 | if ( align && align != 'none' ) { | ||
985 | var styles = CKEDITOR.tools.parseCssText( attrs.style || '' ); | ||
986 | |||
987 | // When the widget is captioned (<figure>) and internally centering is done | ||
988 | // with widget's wrapper style/class, in the external data representation, | ||
989 | // <figure> must be wrapped with an element holding an style/class: | ||
990 | // | ||
991 | // <div style="text-align:center"> | ||
992 | // <figure class="image" style="display:inline-block">...</figure> | ||
993 | // </div> | ||
994 | // or | ||
995 | // <div class="some-center-class"> | ||
996 | // <figure class="image">...</figure> | ||
997 | // </div> | ||
998 | // | ||
999 | if ( align == 'center' && el.name == 'figure' ) { | ||
1000 | el = el.wrapWith( new CKEDITOR.htmlParser.element( 'div', | ||
1001 | alignClasses ? { 'class': alignClasses[ 1 ] } : { style: 'text-align:center' } ) ); | ||
1002 | } | ||
1003 | |||
1004 | // If left/right, add float style to the downcasted element. | ||
1005 | else if ( align in { left: 1, right: 1 } ) { | ||
1006 | if ( alignClasses ) | ||
1007 | attrsHolder.addClass( alignClasses[ alignmentsObj[ align ] ] ); | ||
1008 | else | ||
1009 | styles[ 'float' ] = align; | ||
1010 | } | ||
1011 | |||
1012 | // Update element styles. | ||
1013 | if ( !alignClasses && !CKEDITOR.tools.isEmpty( styles ) ) | ||
1014 | attrs.style = CKEDITOR.tools.writeCssText( styles ); | ||
1015 | } | ||
1016 | |||
1017 | return el; | ||
1018 | }; | ||
1019 | } | ||
1020 | |||
1021 | // Returns a function that checks if an element is a centering wrapper. | ||
1022 | // | ||
1023 | // @param {CKEDITOR.editor} editor | ||
1024 | // @returns {Function} | ||
1025 | function centerWrapperChecker( editor ) { | ||
1026 | var captionedClass = editor.config.image2_captionedClass, | ||
1027 | alignClasses = editor.config.image2_alignClasses, | ||
1028 | validChildren = { figure: 1, a: 1, img: 1 }; | ||
1029 | |||
1030 | return function( el ) { | ||
1031 | // Wrapper must be either <div> or <p>. | ||
1032 | if ( !( el.name in { div: 1, p: 1 } ) ) | ||
1033 | return false; | ||
1034 | |||
1035 | var children = el.children; | ||
1036 | |||
1037 | // Centering wrapper can have only one child. | ||
1038 | if ( children.length !== 1 ) | ||
1039 | return false; | ||
1040 | |||
1041 | var child = children[ 0 ]; | ||
1042 | |||
1043 | // Only <figure> or <img /> can be first (only) child of centering wrapper, | ||
1044 | // regardless of its type. | ||
1045 | if ( !( child.name in validChildren ) ) | ||
1046 | return false; | ||
1047 | |||
1048 | // If centering wrapper is <p>, only <img /> can be the child. | ||
1049 | // <p style="text-align:center"><img /></p> | ||
1050 | if ( el.name == 'p' ) { | ||
1051 | if ( !isLinkedOrStandaloneImage( child ) ) | ||
1052 | return false; | ||
1053 | } | ||
1054 | // Centering <div> can hold <img/> or <figure>, depending on enterMode. | ||
1055 | else { | ||
1056 | // If a <figure> is the first (only) child, it must have a class. | ||
1057 | // <div style="text-align:center"><figure>...</figure><div> | ||
1058 | if ( child.name == 'figure' ) { | ||
1059 | if ( !child.hasClass( captionedClass ) ) | ||
1060 | return false; | ||
1061 | } else { | ||
1062 | // Centering <div> can hold <img/> or <a><img/></a> only when enterMode | ||
1063 | // is ENTER_(BR|DIV). | ||
1064 | // <div style="text-align:center"><img /></div> | ||
1065 | // <div style="text-align:center"><a><img /></a></div> | ||
1066 | if ( editor.enterMode == CKEDITOR.ENTER_P ) | ||
1067 | return false; | ||
1068 | |||
1069 | // Regardless of enterMode, a child which is not <figure> must be | ||
1070 | // either <img/> or <a><img/></a>. | ||
1071 | if ( !isLinkedOrStandaloneImage( child ) ) | ||
1072 | return false; | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | // Centering wrapper got to be... centering. If image2_alignClasses are defined, | ||
1077 | // check for centering class. Otherwise, check the style. | ||
1078 | if ( alignClasses ? el.hasClass( alignClasses[ 1 ] ) : | ||
1079 | CKEDITOR.tools.parseCssText( el.attributes.style || '', true )[ 'text-align' ] == 'center' ) | ||
1080 | return true; | ||
1081 | |||
1082 | return false; | ||
1083 | }; | ||
1084 | } | ||
1085 | |||
1086 | // Checks whether element is <img/> or <a><img/></a>. | ||
1087 | // | ||
1088 | // @param {CKEDITOR.htmlParser.element} | ||
1089 | function isLinkedOrStandaloneImage( el ) { | ||
1090 | if ( el.name == 'img' ) | ||
1091 | return true; | ||
1092 | else if ( el.name == 'a' ) | ||
1093 | return el.children.length == 1 && el.getFirst( 'img' ); | ||
1094 | |||
1095 | return false; | ||
1096 | } | ||
1097 | |||
1098 | // Sets width and height of the widget image according to current widget data. | ||
1099 | // | ||
1100 | // @param {CKEDITOR.plugins.widget} widget | ||
1101 | function setDimensions( widget ) { | ||
1102 | var data = widget.data, | ||
1103 | dimensions = { width: data.width, height: data.height }, | ||
1104 | image = widget.parts.image; | ||
1105 | |||
1106 | for ( var d in dimensions ) { | ||
1107 | if ( dimensions[ d ] ) | ||
1108 | image.setAttribute( d, dimensions[ d ] ); | ||
1109 | else | ||
1110 | image.removeAttribute( d ); | ||
1111 | } | ||
1112 | } | ||
1113 | |||
1114 | // Defines all features related to drag-driven image resizing. | ||
1115 | // | ||
1116 | // @param {CKEDITOR.plugins.widget} widget | ||
1117 | function setupResizer( widget ) { | ||
1118 | var editor = widget.editor, | ||
1119 | editable = editor.editable(), | ||
1120 | doc = editor.document, | ||
1121 | |||
1122 | // Store the resizer in a widget for testing (http://dev.ckeditor.com/ticket/11004). | ||
1123 | resizer = widget.resizer = doc.createElement( 'span' ); | ||
1124 | |||
1125 | resizer.addClass( 'cke_image_resizer' ); | ||
1126 | resizer.setAttribute( 'title', editor.lang.image2.resizer ); | ||
1127 | resizer.append( new CKEDITOR.dom.text( '\u200b', doc ) ); | ||
1128 | |||
1129 | // Inline widgets don't need a resizer wrapper as an image spans the entire widget. | ||
1130 | if ( !widget.inline ) { | ||
1131 | var imageOrLink = widget.parts.link || widget.parts.image, | ||
1132 | oldResizeWrapper = imageOrLink.getParent(), | ||
1133 | resizeWrapper = doc.createElement( 'span' ); | ||
1134 | |||
1135 | resizeWrapper.addClass( 'cke_image_resizer_wrapper' ); | ||
1136 | resizeWrapper.append( imageOrLink ); | ||
1137 | resizeWrapper.append( resizer ); | ||
1138 | widget.element.append( resizeWrapper, true ); | ||
1139 | |||
1140 | // Remove the old wrapper which could came from e.g. pasted HTML | ||
1141 | // and which could be corrupted (e.g. resizer span has been lost). | ||
1142 | if ( oldResizeWrapper.is( 'span' ) ) | ||
1143 | oldResizeWrapper.remove(); | ||
1144 | } else { | ||
1145 | widget.wrapper.append( resizer ); | ||
1146 | } | ||
1147 | |||
1148 | // Calculate values of size variables and mouse offsets. | ||
1149 | resizer.on( 'mousedown', function( evt ) { | ||
1150 | var image = widget.parts.image, | ||
1151 | |||
1152 | // "factor" can be either 1 or -1. I.e.: For right-aligned images, we need to | ||
1153 | // subtract the difference to get proper width, etc. Without "factor", | ||
1154 | // resizer starts working the opposite way. | ||
1155 | factor = widget.data.align == 'right' ? -1 : 1, | ||
1156 | |||
1157 | // The x-coordinate of the mouse relative to the screen | ||
1158 | // when button gets pressed. | ||
1159 | startX = evt.data.$.screenX, | ||
1160 | startY = evt.data.$.screenY, | ||
1161 | |||
1162 | // The initial dimensions and aspect ratio of the image. | ||
1163 | startWidth = image.$.clientWidth, | ||
1164 | startHeight = image.$.clientHeight, | ||
1165 | ratio = startWidth / startHeight, | ||
1166 | |||
1167 | listeners = [], | ||
1168 | |||
1169 | // A class applied to editable during resizing. | ||
1170 | cursorClass = 'cke_image_s' + ( !~factor ? 'w' : 'e' ), | ||
1171 | |||
1172 | nativeEvt, newWidth, newHeight, updateData, | ||
1173 | moveDiffX, moveDiffY, moveRatio; | ||
1174 | |||
1175 | // Save the undo snapshot first: before resizing. | ||
1176 | editor.fire( 'saveSnapshot' ); | ||
1177 | |||
1178 | // Mousemove listeners are removed on mouseup. | ||
1179 | attachToDocuments( 'mousemove', onMouseMove, listeners ); | ||
1180 | |||
1181 | // Clean up the mousemove listener. Update widget data if valid. | ||
1182 | attachToDocuments( 'mouseup', onMouseUp, listeners ); | ||
1183 | |||
1184 | // The entire editable will have the special cursor while resizing goes on. | ||
1185 | editable.addClass( cursorClass ); | ||
1186 | |||
1187 | // This is to always keep the resizer element visible while resizing. | ||
1188 | resizer.addClass( 'cke_image_resizing' ); | ||
1189 | |||
1190 | // Attaches an event to a global document if inline editor. | ||
1191 | // Additionally, if classic (`iframe`-based) editor, also attaches the same event to `iframe`'s document. | ||
1192 | function attachToDocuments( name, callback, collection ) { | ||
1193 | var globalDoc = CKEDITOR.document, | ||
1194 | listeners = []; | ||
1195 | |||
1196 | if ( !doc.equals( globalDoc ) ) | ||
1197 | listeners.push( globalDoc.on( name, callback ) ); | ||
1198 | |||
1199 | listeners.push( doc.on( name, callback ) ); | ||
1200 | |||
1201 | if ( collection ) { | ||
1202 | for ( var i = listeners.length; i--; ) | ||
1203 | collection.push( listeners.pop() ); | ||
1204 | } | ||
1205 | } | ||
1206 | |||
1207 | // Calculate with first, and then adjust height, preserving ratio. | ||
1208 | function adjustToX() { | ||
1209 | newWidth = startWidth + factor * moveDiffX; | ||
1210 | newHeight = Math.round( newWidth / ratio ); | ||
1211 | } | ||
1212 | |||
1213 | // Calculate height first, and then adjust width, preserving ratio. | ||
1214 | function adjustToY() { | ||
1215 | newHeight = startHeight - moveDiffY; | ||
1216 | newWidth = Math.round( newHeight * ratio ); | ||
1217 | } | ||
1218 | |||
1219 | // This is how variables refer to the geometry. | ||
1220 | // Note: x corresponds to moveOffset, this is the position of mouse | ||
1221 | // Note: o corresponds to [startX, startY]. | ||
1222 | // | ||
1223 | // +--------------+--------------+ | ||
1224 | // | | | | ||
1225 | // | I | II | | ||
1226 | // | | | | ||
1227 | // +------------- o -------------+ _ _ _ | ||
1228 | // | | | ^ | ||
1229 | // | VI | III | | moveDiffY | ||
1230 | // | | x _ _ _ _ _ v | ||
1231 | // +--------------+---------|----+ | ||
1232 | // | | | ||
1233 | // <-------> | ||
1234 | // moveDiffX | ||
1235 | function onMouseMove( evt ) { | ||
1236 | nativeEvt = evt.data.$; | ||
1237 | |||
1238 | // This is how far the mouse is from the point the button was pressed. | ||
1239 | moveDiffX = nativeEvt.screenX - startX; | ||
1240 | moveDiffY = startY - nativeEvt.screenY; | ||
1241 | |||
1242 | // This is the aspect ratio of the move difference. | ||
1243 | moveRatio = Math.abs( moveDiffX / moveDiffY ); | ||
1244 | |||
1245 | // Left, center or none-aligned widget. | ||
1246 | if ( factor == 1 ) { | ||
1247 | if ( moveDiffX <= 0 ) { | ||
1248 | // Case: IV. | ||
1249 | if ( moveDiffY <= 0 ) | ||
1250 | adjustToX(); | ||
1251 | |||
1252 | // Case: I. | ||
1253 | else { | ||
1254 | if ( moveRatio >= ratio ) | ||
1255 | adjustToX(); | ||
1256 | else | ||
1257 | adjustToY(); | ||
1258 | } | ||
1259 | } else { | ||
1260 | // Case: III. | ||
1261 | if ( moveDiffY <= 0 ) { | ||
1262 | if ( moveRatio >= ratio ) | ||
1263 | adjustToY(); | ||
1264 | else | ||
1265 | adjustToX(); | ||
1266 | } | ||
1267 | |||
1268 | // Case: II. | ||
1269 | else { | ||
1270 | adjustToY(); | ||
1271 | } | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | // Right-aligned widget. It mirrors behaviours, so I becomes II, | ||
1276 | // IV becomes III and vice-versa. | ||
1277 | else { | ||
1278 | if ( moveDiffX <= 0 ) { | ||
1279 | // Case: IV. | ||
1280 | if ( moveDiffY <= 0 ) { | ||
1281 | if ( moveRatio >= ratio ) | ||
1282 | adjustToY(); | ||
1283 | else | ||
1284 | adjustToX(); | ||
1285 | } | ||
1286 | |||
1287 | // Case: I. | ||
1288 | else { | ||
1289 | adjustToY(); | ||
1290 | } | ||
1291 | } else { | ||
1292 | // Case: III. | ||
1293 | if ( moveDiffY <= 0 ) | ||
1294 | adjustToX(); | ||
1295 | |||
1296 | // Case: II. | ||
1297 | else { | ||
1298 | if ( moveRatio >= ratio ) { | ||
1299 | adjustToX(); | ||
1300 | } else { | ||
1301 | adjustToY(); | ||
1302 | } | ||
1303 | } | ||
1304 | } | ||
1305 | } | ||
1306 | |||
1307 | // Don't update attributes if less than 10. | ||
1308 | // This is to prevent images to visually disappear. | ||
1309 | if ( newWidth >= 15 && newHeight >= 15 ) { | ||
1310 | image.setAttributes( { width: newWidth, height: newHeight } ); | ||
1311 | updateData = true; | ||
1312 | } else { | ||
1313 | updateData = false; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1317 | function onMouseUp() { | ||
1318 | var l; | ||
1319 | |||
1320 | while ( ( l = listeners.pop() ) ) | ||
1321 | l.removeListener(); | ||
1322 | |||
1323 | // Restore default cursor by removing special class. | ||
1324 | editable.removeClass( cursorClass ); | ||
1325 | |||
1326 | // This is to bring back the regular behaviour of the resizer. | ||
1327 | resizer.removeClass( 'cke_image_resizing' ); | ||
1328 | |||
1329 | if ( updateData ) { | ||
1330 | widget.setData( { width: newWidth, height: newHeight } ); | ||
1331 | |||
1332 | // Save another undo snapshot: after resizing. | ||
1333 | editor.fire( 'saveSnapshot' ); | ||
1334 | } | ||
1335 | |||
1336 | // Don't update data twice or more. | ||
1337 | updateData = false; | ||
1338 | } | ||
1339 | } ); | ||
1340 | |||
1341 | // Change the position of the widget resizer when data changes. | ||
1342 | widget.on( 'data', function() { | ||
1343 | resizer[ widget.data.align == 'right' ? 'addClass' : 'removeClass' ]( 'cke_image_resizer_left' ); | ||
1344 | } ); | ||
1345 | } | ||
1346 | |||
1347 | // Integrates widget alignment setting with justify | ||
1348 | // plugin's commands (execution and refreshment). | ||
1349 | // @param {CKEDITOR.editor} editor | ||
1350 | // @param {String} value 'left', 'right', 'center' or 'block' | ||
1351 | function alignCommandIntegrator( editor ) { | ||
1352 | var execCallbacks = [], | ||
1353 | enabled; | ||
1354 | |||
1355 | return function( value ) { | ||
1356 | var command = editor.getCommand( 'justify' + value ); | ||
1357 | |||
1358 | // Most likely, the justify plugin isn't loaded. | ||
1359 | if ( !command ) | ||
1360 | return; | ||
1361 | |||
1362 | // This command will be manually refreshed along with | ||
1363 | // other commands after exec. | ||
1364 | execCallbacks.push( function() { | ||
1365 | command.refresh( editor, editor.elementPath() ); | ||
1366 | } ); | ||
1367 | |||
1368 | if ( value in { right: 1, left: 1, center: 1 } ) { | ||
1369 | command.on( 'exec', function( evt ) { | ||
1370 | var widget = getFocusedWidget( editor ); | ||
1371 | |||
1372 | if ( widget ) { | ||
1373 | widget.setData( 'align', value ); | ||
1374 | |||
1375 | // Once the widget changed its align, all the align commands | ||
1376 | // must be refreshed: the event is to be cancelled. | ||
1377 | for ( var i = execCallbacks.length; i--; ) | ||
1378 | execCallbacks[ i ](); | ||
1379 | |||
1380 | evt.cancel(); | ||
1381 | } | ||
1382 | } ); | ||
1383 | } | ||
1384 | |||
1385 | command.on( 'refresh', function( evt ) { | ||
1386 | var widget = getFocusedWidget( editor ), | ||
1387 | allowed = { right: 1, left: 1, center: 1 }; | ||
1388 | |||
1389 | if ( !widget ) | ||
1390 | return; | ||
1391 | |||
1392 | // Cache "enabled" on first use. This is because filter#checkFeature may | ||
1393 | // not be available during plugin's afterInit in the future — a moment when | ||
1394 | // alignCommandIntegrator is called. | ||
1395 | if ( enabled === undefined ) | ||
1396 | enabled = editor.filter.checkFeature( editor.widgets.registered.image.features.align ); | ||
1397 | |||
1398 | // Don't allow justify commands when widget alignment is disabled (http://dev.ckeditor.com/ticket/11004). | ||
1399 | if ( !enabled ) | ||
1400 | this.setState( CKEDITOR.TRISTATE_DISABLED ); | ||
1401 | else { | ||
1402 | this.setState( | ||
1403 | ( widget.data.align == value ) ? ( | ||
1404 | CKEDITOR.TRISTATE_ON | ||
1405 | ) : ( | ||
1406 | ( value in allowed ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED | ||
1407 | ) | ||
1408 | ); | ||
1409 | } | ||
1410 | |||
1411 | evt.cancel(); | ||
1412 | } ); | ||
1413 | }; | ||
1414 | } | ||
1415 | |||
1416 | function linkCommandIntegrator( editor ) { | ||
1417 | // Nothing to integrate with if link is not loaded. | ||
1418 | if ( !editor.plugins.link ) | ||
1419 | return; | ||
1420 | |||
1421 | CKEDITOR.on( 'dialogDefinition', function( evt ) { | ||
1422 | var dialog = evt.data; | ||
1423 | |||
1424 | if ( dialog.name == 'link' ) { | ||
1425 | var def = dialog.definition; | ||
1426 | |||
1427 | var onShow = def.onShow, | ||
1428 | onOk = def.onOk; | ||
1429 | |||
1430 | def.onShow = function() { | ||
1431 | var widget = getFocusedWidget( editor ), | ||
1432 | displayTextField = this.getContentElement( 'info', 'linkDisplayText' ).getElement().getParent().getParent(); | ||
1433 | |||
1434 | // Widget cannot be enclosed in a link, i.e. | ||
1435 | // <a>foo<inline widget/>bar</a> | ||
1436 | if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) { | ||
1437 | this.setupContent( widget.data.link || {} ); | ||
1438 | |||
1439 | // Hide the display text in case of linking image2 widget. | ||
1440 | displayTextField.hide(); | ||
1441 | } else { | ||
1442 | // Make sure that display text is visible, as it might be hidden by image2 integration | ||
1443 | // before. | ||
1444 | displayTextField.show(); | ||
1445 | onShow.apply( this, arguments ); | ||
1446 | } | ||
1447 | }; | ||
1448 | |||
1449 | // Set widget data if linking the widget using | ||
1450 | // link dialog (instead of default action). | ||
1451 | // State shifter handles data change and takes | ||
1452 | // care of internal DOM structure of linked widget. | ||
1453 | def.onOk = function() { | ||
1454 | var widget = getFocusedWidget( editor ); | ||
1455 | |||
1456 | // Widget cannot be enclosed in a link, i.e. | ||
1457 | // <a>foo<inline widget/>bar</a> | ||
1458 | if ( widget && ( widget.inline ? !widget.wrapper.getAscendant( 'a' ) : 1 ) ) { | ||
1459 | var data = {}; | ||
1460 | |||
1461 | // Collect data from fields. | ||
1462 | this.commitContent( data ); | ||
1463 | |||
1464 | // Set collected data to widget. | ||
1465 | widget.setData( 'link', data ); | ||
1466 | } else { | ||
1467 | onOk.apply( this, arguments ); | ||
1468 | } | ||
1469 | }; | ||
1470 | } | ||
1471 | } ); | ||
1472 | |||
1473 | // Overwrite default behaviour of unlink command. | ||
1474 | editor.getCommand( 'unlink' ).on( 'exec', function( evt ) { | ||
1475 | var widget = getFocusedWidget( editor ); | ||
1476 | |||
1477 | // Override unlink only when link truly belongs to the widget. | ||
1478 | // If wrapped inline widget in a link, let default unlink work (http://dev.ckeditor.com/ticket/11814). | ||
1479 | if ( !widget || !widget.parts.link ) | ||
1480 | return; | ||
1481 | |||
1482 | widget.setData( 'link', null ); | ||
1483 | |||
1484 | // Selection (which is fake) may not change if unlinked image in focused widget, | ||
1485 | // i.e. if captioned image. Let's refresh command state manually here. | ||
1486 | this.refresh( editor, editor.elementPath() ); | ||
1487 | |||
1488 | evt.cancel(); | ||
1489 | } ); | ||
1490 | |||
1491 | // Overwrite default refresh of unlink command. | ||
1492 | editor.getCommand( 'unlink' ).on( 'refresh', function( evt ) { | ||
1493 | var widget = getFocusedWidget( editor ); | ||
1494 | |||
1495 | if ( !widget ) | ||
1496 | return; | ||
1497 | |||
1498 | // Note that widget may be wrapped in a link, which | ||
1499 | // does not belong to that widget (http://dev.ckeditor.com/ticket/11814). | ||
1500 | this.setState( widget.data.link || widget.wrapper.getAscendant( 'a' ) ? | ||
1501 | CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED ); | ||
1502 | |||
1503 | evt.cancel(); | ||
1504 | } ); | ||
1505 | } | ||
1506 | |||
1507 | // Returns the focused widget, if of the type specific for this plugin. | ||
1508 | // If no widget is focused, `null` is returned. | ||
1509 | // | ||
1510 | // @param {CKEDITOR.editor} | ||
1511 | // @returns {CKEDITOR.plugins.widget} | ||
1512 | function getFocusedWidget( editor ) { | ||
1513 | var widget = editor.widgets.focused; | ||
1514 | |||
1515 | if ( widget && widget.name == 'image' ) | ||
1516 | return widget; | ||
1517 | |||
1518 | return null; | ||
1519 | } | ||
1520 | |||
1521 | // Returns a set of widget allowedContent rules, depending | ||
1522 | // on configurations like config#image2_alignClasses or | ||
1523 | // config#image2_captionedClass. | ||
1524 | // | ||
1525 | // @param {CKEDITOR.editor} | ||
1526 | // @returns {Object} | ||
1527 | function getWidgetAllowedContent( editor ) { | ||
1528 | var alignClasses = editor.config.image2_alignClasses, | ||
1529 | rules = { | ||
1530 | // Widget may need <div> or <p> centering wrapper. | ||
1531 | div: { | ||
1532 | match: centerWrapperChecker( editor ) | ||
1533 | }, | ||
1534 | p: { | ||
1535 | match: centerWrapperChecker( editor ) | ||
1536 | }, | ||
1537 | img: { | ||
1538 | attributes: '!src,alt,width,height' | ||
1539 | }, | ||
1540 | figure: { | ||
1541 | classes: '!' + editor.config.image2_captionedClass | ||
1542 | }, | ||
1543 | figcaption: true | ||
1544 | }; | ||
1545 | |||
1546 | if ( alignClasses ) { | ||
1547 | // Centering class from the config. | ||
1548 | rules.div.classes = alignClasses[ 1 ]; | ||
1549 | rules.p.classes = rules.div.classes; | ||
1550 | |||
1551 | // Left/right classes from the config. | ||
1552 | rules.img.classes = alignClasses[ 0 ] + ',' + alignClasses[ 2 ]; | ||
1553 | rules.figure.classes += ',' + rules.img.classes; | ||
1554 | } else { | ||
1555 | // Centering with text-align. | ||
1556 | rules.div.styles = 'text-align'; | ||
1557 | rules.p.styles = 'text-align'; | ||
1558 | |||
1559 | rules.img.styles = 'float'; | ||
1560 | rules.figure.styles = 'float,display'; | ||
1561 | } | ||
1562 | |||
1563 | return rules; | ||
1564 | } | ||
1565 | |||
1566 | // Returns a set of widget feature rules, depending | ||
1567 | // on editor configuration. Note that the following may not cover | ||
1568 | // all the possible cases since requiredContent supports a single | ||
1569 | // tag only. | ||
1570 | // | ||
1571 | // @param {CKEDITOR.editor} | ||
1572 | // @returns {Object} | ||
1573 | function getWidgetFeatures( editor ) { | ||
1574 | var alignClasses = editor.config.image2_alignClasses, | ||
1575 | features = { | ||
1576 | dimension: { | ||
1577 | requiredContent: 'img[width,height]' | ||
1578 | }, | ||
1579 | align: { | ||
1580 | requiredContent: 'img' + | ||
1581 | ( alignClasses ? '(' + alignClasses[ 0 ] + ')' : '{float}' ) | ||
1582 | }, | ||
1583 | caption: { | ||
1584 | requiredContent: 'figcaption' | ||
1585 | } | ||
1586 | }; | ||
1587 | |||
1588 | return features; | ||
1589 | } | ||
1590 | |||
1591 | // Returns element which is styled, considering current | ||
1592 | // state of the widget. | ||
1593 | // | ||
1594 | // @see CKEDITOR.plugins.widget#applyStyle | ||
1595 | // @param {CKEDITOR.plugins.widget} widget | ||
1596 | // @returns {CKEDITOR.dom.element} | ||
1597 | function getStyleableElement( widget ) { | ||
1598 | return widget.data.hasCaption ? widget.element : widget.parts.image; | ||
1599 | } | ||
1600 | } )(); | ||
1601 | |||
1602 | /** | ||
1603 | * A CSS class applied to the `<figure>` element of a captioned image. | ||
1604 | * | ||
1605 | * Read more in the [documentation](#!/guide/dev_captionedimage) and see the | ||
1606 | * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html). | ||
1607 | * | ||
1608 | * // Changes the class to "captionedImage". | ||
1609 | * config.image2_captionedClass = 'captionedImage'; | ||
1610 | * | ||
1611 | * @cfg {String} [image2_captionedClass='image'] | ||
1612 | * @member CKEDITOR.config | ||
1613 | */ | ||
1614 | CKEDITOR.config.image2_captionedClass = 'image'; | ||
1615 | |||
1616 | /** | ||
1617 | * Determines whether dimension inputs should be automatically filled when the image URL changes in the Enhanced Image | ||
1618 | * plugin dialog window. | ||
1619 | * | ||
1620 | * Read more in the [documentation](#!/guide/dev_captionedimage) and see the | ||
1621 | * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html). | ||
1622 | * | ||
1623 | * config.image2_prefillDimensions = false; | ||
1624 | * | ||
1625 | * @since 4.5 | ||
1626 | * @cfg {Boolean} [image2_prefillDimensions=true] | ||
1627 | * @member CKEDITOR.config | ||
1628 | */ | ||
1629 | |||
1630 | /** | ||
1631 | * Disables the image resizer. By default the resizer is enabled. | ||
1632 | * | ||
1633 | * Read more in the [documentation](#!/guide/dev_captionedimage) and see the | ||
1634 | * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html). | ||
1635 | * | ||
1636 | * config.image2_disableResizer = true; | ||
1637 | * | ||
1638 | * @since 4.5 | ||
1639 | * @cfg {Boolean} [image2_disableResizer=false] | ||
1640 | * @member CKEDITOR.config | ||
1641 | */ | ||
1642 | |||
1643 | /** | ||
1644 | * CSS classes applied to aligned images. Useful to take control over the way | ||
1645 | * the images are aligned, i.e. to customize output HTML and integrate external stylesheets. | ||
1646 | * | ||
1647 | * Classes should be defined in an array of three elements, containing left, center, and right | ||
1648 | * alignment classes, respectively. For example: | ||
1649 | * | ||
1650 | * config.image2_alignClasses = [ 'align-left', 'align-center', 'align-right' ]; | ||
1651 | * | ||
1652 | * **Note**: Once this configuration option is set, the plugin will no longer produce inline | ||
1653 | * styles for alignment. It means that e.g. the following HTML will be produced: | ||
1654 | * | ||
1655 | * <img alt="My image" class="custom-center-class" src="foo.png" /> | ||
1656 | * | ||
1657 | * instead of: | ||
1658 | * | ||
1659 | * <img alt="My image" style="float:left" src="foo.png" /> | ||
1660 | * | ||
1661 | * **Note**: Once this configuration option is set, corresponding style definitions | ||
1662 | * must be supplied to the editor: | ||
1663 | * | ||
1664 | * * For [classic editor](#!/guide/dev_framed) it can be done by defining additional | ||
1665 | * styles in the {@link CKEDITOR.config#contentsCss stylesheets loaded by the editor}. The same | ||
1666 | * styles must be provided on the target page where the content will be loaded. | ||
1667 | * * For [inline editor](#!/guide/dev_inline) the styles can be defined directly | ||
1668 | * with `<style> ... <style>` or `<link href="..." rel="stylesheet">`, i.e. within the `<head>` | ||
1669 | * of the page. | ||
1670 | * | ||
1671 | * For example, considering the following configuration: | ||
1672 | * | ||
1673 | * config.image2_alignClasses = [ 'align-left', 'align-center', 'align-right' ]; | ||
1674 | * | ||
1675 | * CSS rules can be defined as follows: | ||
1676 | * | ||
1677 | * .align-left { | ||
1678 | * float: left; | ||
1679 | * } | ||
1680 | * | ||
1681 | * .align-right { | ||
1682 | * float: right; | ||
1683 | * } | ||
1684 | * | ||
1685 | * .align-center { | ||
1686 | * text-align: center; | ||
1687 | * } | ||
1688 | * | ||
1689 | * .align-center > figure { | ||
1690 | * display: inline-block; | ||
1691 | * } | ||
1692 | * | ||
1693 | * Read more in the [documentation](#!/guide/dev_captionedimage) and see the | ||
1694 | * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html). | ||
1695 | * | ||
1696 | * @since 4.4 | ||
1697 | * @cfg {String[]} [image2_alignClasses=null] | ||
1698 | * @member CKEDITOR.config | ||
1699 | */ | ||
1700 | |||
1701 | /** | ||
1702 | * Determines whether alternative text is required for the captioned image. | ||
1703 | * | ||
1704 | * config.image2_altRequired = true; | ||
1705 | * | ||
1706 | * Read more in the [documentation](#!/guide/dev_captionedimage) and see the | ||
1707 | * [SDK sample](http://sdk.ckeditor.com/samples/captionedimage.html). | ||
1708 | * | ||
1709 | * @since 4.6.0 | ||
1710 | * @cfg {Boolean} [image2_altRequired=false] | ||
1711 | * @member CKEDITOR.config | ||
1712 | */ | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image1.jpg b/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image1.jpg deleted file mode 100644 index ca491e3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image1.jpg +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image2.jpg b/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image2.jpg deleted file mode 100644 index 3dd6d61..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/samples/assets/image2.jpg +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/image2/samples/image2.html b/app/assets/javascripts/ckeditor/plugins/image2/samples/image2.html deleted file mode 100644 index 9c3ef13..0000000 --- a/app/assets/javascripts/ckeditor/plugins/image2/samples/image2.html +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>New Image plugin — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <script> | ||
12 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | ||
13 | CKEDITOR.tools.enableHtml5Elements( document ); | ||
14 | </script> | ||
15 | <link href="../../../samples/old/sample.css" rel="stylesheet"> | ||
16 | <meta name="ckeditor-sample-name" content="New Image plugin"> | ||
17 | <meta name="ckeditor-sample-group" content="Plugins"> | ||
18 | <meta name="ckeditor-sample-description" content="Using the new Image plugin to insert captioned images and adjust their dimensions."> | ||
19 | <meta name="ckeditor-sample-isnew" content="1"> | ||
20 | </head> | ||
21 | <body> | ||
22 | <h1 class="samples"> | ||
23 | <a href="../../../samples/old/index.html">CKEditor Samples</a> » New Image plugin | ||
24 | </h1> | ||
25 | <div class="warning deprecated"> | ||
26 | This sample is not maintained anymore. Check out its <a href="http://sdk.ckeditor.com/samples/captionedimage.html">brand new version in CKEditor SDK</a>. | ||
27 | </div> | ||
28 | |||
29 | <div class="description"> | ||
30 | <p> | ||
31 | This editor is using the new <strong>Image</strong> (<code>image2</code>) plugin, which implements a dynamic <em>click-and-drag</em> resizing | ||
32 | and easy captioning of the images. | ||
33 | </p> | ||
34 | <p> | ||
35 | To use the new plugin, extend <code><a class="samples" href="http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-extraPlugins">config.extraPlugins</a></code>: | ||
36 | </p> | ||
37 | <pre class="samples"> | ||
38 | CKEDITOR.replace( '<em>textarea_id</em>', { | ||
39 | <strong>extraPlugins: 'image2'</strong> | ||
40 | } ); | ||
41 | </pre> | ||
42 | </div> | ||
43 | |||
44 | <textarea id="editor1" cols="10" rows="10"> | ||
45 | <h1>Apollo 11</h1><figure class="image" style="float: right"><img alt="Saturn V" src="assets/image1.jpg" width="200" /><figcaption>Roll out of Saturn V on launch pad</figcaption></figure><p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p><p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5&nbsp;kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p><h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2><p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p><blockquote><p>One small step for [a] man, one giant leap for mankind.</p></blockquote><p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p><blockquote><p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p></blockquote><figure class="image" style="float: right"><img alt="The Eagle" src="assets/image2.jpg" style="width: 200px" /><figcaption>The Eagle in lunar orbit</figcaption></figure><h2>Technical details <a id="tech-details" name="tech-details"></a></h2><p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>&#39;s Apollo program. The Apollo spacecraft had three parts:</p><ol><li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li><li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li><li><strong>Lunar Module</strong> for landing on the Moon.</li></ol><p>After being sent to the Moon by the Saturn V&#39;s upper stage, the astronauts separated the spacecraft from it and travelled for three days until they entered into lunar orbit. Armstrong and Aldrin then moved into the Lunar Module and landed in the <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p><hr /><p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
46 | </textarea> | ||
47 | |||
48 | <script> | ||
49 | |||
50 | CKEDITOR.replace( 'editor1', { | ||
51 | extraPlugins: 'image2', | ||
52 | height: 450 | ||
53 | } ); | ||
54 | |||
55 | </script> | ||
56 | |||
57 | <div id="footer"> | ||
58 | <hr> | ||
59 | <p> | ||
60 | CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a> | ||
61 | </p> | ||
62 | <p id="copy"> | ||
63 | Copyright © 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico | ||
64 | Knabben. All rights reserved. | ||
65 | </p> | ||
66 | </div> | ||
67 | </body> | ||
68 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/lineutils/dev/dnd.html b/app/assets/javascripts/ckeditor/plugins/lineutils/dev/dnd.html deleted file mode 100644 index 971d9cd..0000000 --- a/app/assets/javascripts/ckeditor/plugins/lineutils/dev/dnd.html +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>Widget Drag & Drop with Lineutils — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <script> | ||
12 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | ||
13 | CKEDITOR.tools.enableHtml5Elements( document ); | ||
14 | </script> | ||
15 | <link href="../../../samples/old/sample.css" rel="stylesheet"> | ||
16 | <link href="../../image2/samples/contents.css" rel="stylesheet"> | ||
17 | </head> | ||
18 | <body> | ||
19 | <h1 class="samples"> | ||
20 | <a href="../../../samples/old/index.html">CKEditor Samples</a> » Widget Drag & Drop with Lineutils | ||
21 | </h1> | ||
22 | |||
23 | <h3>Classic (iframe-based) Editor</h3> | ||
24 | |||
25 | <textarea id="editor1" cols="10" rows="10"> | ||
26 | <h1>Apollo 11</h1> | ||
27 | |||
28 | <figure class="caption" style="float:right"><img alt="Saturn V" src="../../image2/samples/assets/image1.jpg" width="200" /> | ||
29 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
30 | </figure> | ||
31 | |||
32 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on July 20, 1969, at 20:18 UTC. Armstrong became the first to step onto the lunar surface 6 hours later on July 21 at 02:56 UTC.</p> | ||
33 | |||
34 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
35 | |||
36 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
37 | |||
38 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
39 | |||
40 | <blockquote> | ||
41 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
42 | </blockquote> | ||
43 | |||
44 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
45 | |||
46 | <div style="text-align:center"> | ||
47 | <figure class="caption" style="display:inline-block"><img alt="The Eagle" height="123" src="../../image2/samples/assets/image2.jpg" width="136" /> | ||
48 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
49 | </figure> | ||
50 | </div> | ||
51 | |||
52 | <blockquote> | ||
53 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
54 | </blockquote> | ||
55 | |||
56 | <figure class="caption" style="float:right"><img alt="The Eagle" src="../../image2/samples/assets/image2.jpg" width="200" /> | ||
57 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
58 | </figure> | ||
59 | |||
60 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
61 | |||
62 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
63 | |||
64 | <ol> | ||
65 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
66 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
67 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
68 | </ol> | ||
69 | |||
70 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
71 | |||
72 | <figure class="caption"><img alt="Saturn V" height="129" src="../../image2/samples/assets/image1.jpg" width="101" /> | ||
73 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
74 | </figure> | ||
75 | |||
76 | <hr /> | ||
77 | <p style="text-align:right"><small>Source: <a href="http://en.wikipedia.org/wiki/Apollo_11">Wikipedia.org</a></small></p> | ||
78 | |||
79 | </textarea> | ||
80 | |||
81 | <h3>Inline Editor</h3> | ||
82 | |||
83 | <div id="editor2" contenteditable="true" style="outline: 2px solid #ccc"> | ||
84 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
85 | <tbody> | ||
86 | <tr> | ||
87 | <td>This table</td> | ||
88 | <td>is the</td> | ||
89 | <td>very first</td> | ||
90 | <td>element of the document.</td> | ||
91 | </tr> | ||
92 | <tr> | ||
93 | <td>We are still</td> | ||
94 | <td>able to acces</td> | ||
95 | <td>the space before it.</td> | ||
96 | <td style="padding: 25px"> | ||
97 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
98 | <tbody> | ||
99 | <tr> | ||
100 | <td>This table is inside of a cell of another table.</td> | ||
101 | </tr> | ||
102 | <tr> | ||
103 | <td>We can type either before or after it though.</td> | ||
104 | </tr> | ||
105 | </tbody> | ||
106 | </table> | ||
107 | </td> | ||
108 | </tr> | ||
109 | </tbody> | ||
110 | </table> | ||
111 | |||
112 | <hr /> | ||
113 | <hr /> | ||
114 | <ol style="width: 300px"> | ||
115 | <li>This numbered list...</li> | ||
116 | <li>...is a neighbour of a horizontal line...</li> | ||
117 | <li style="padding: 20px;"> | ||
118 | <ol> | ||
119 | <li>Nested list!</li> | ||
120 | </ol> | ||
121 | </li> | ||
122 | </ol> | ||
123 | |||
124 | <figure class="caption"><img alt="Saturn V" src="../../image2/samples/assets/image1.jpg" width="100" /> | ||
125 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
126 | </figure> | ||
127 | |||
128 | <ul style="width: 450px"> | ||
129 | <li>We can type between the lists...</li> | ||
130 | <li>...thanks to <strong>Magicline</strong>.</li> | ||
131 | </ul> | ||
132 | |||
133 | <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p> | ||
134 | |||
135 | <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p> | ||
136 | |||
137 | <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p> | ||
138 | |||
139 | <div id="last" style="padding: 10px; text-align: center;"> | ||
140 | <p>This text is wrapped in a <tt>DIV</tt> element. We can type after this element though.</p> | ||
141 | </div> | ||
142 | </div> | ||
143 | |||
144 | <script> | ||
145 | |||
146 | CKEDITOR.replace( 'editor1', { | ||
147 | extraPlugins: 'image2', | ||
148 | height: 450, | ||
149 | removePlugins: 'image,forms', | ||
150 | contentsCss: [ '../../../contents.css', '../../image2/samples/contents.css' ] | ||
151 | } ); | ||
152 | |||
153 | CKEDITOR.inline( 'editor2', { | ||
154 | extraPlugins: 'image2', | ||
155 | height: 450, | ||
156 | removePlugins: 'image,forms' | ||
157 | } ); | ||
158 | |||
159 | </script> | ||
160 | |||
161 | <div id="footer"> | ||
162 | <hr> | ||
163 | <p> | ||
164 | CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a> | ||
165 | </p> | ||
166 | <p id="copy"> | ||
167 | Copyright © 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico | ||
168 | Knabben. All rights reserved. | ||
169 | </p> | ||
170 | </div> | ||
171 | </body> | ||
172 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/lineutils/dev/magicfinger.html b/app/assets/javascripts/ckeditor/plugins/lineutils/dev/magicfinger.html deleted file mode 100644 index 7f2b632..0000000 --- a/app/assets/javascripts/ckeditor/plugins/lineutils/dev/magicfinger.html +++ /dev/null | |||
@@ -1,285 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>Lineutils — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <link href="../../../samples/old/sample.css" rel="stylesheet"> | ||
12 | </head> | ||
13 | <body> | ||
14 | <h1 class="samples"> | ||
15 | <a href="../../../samples/old/index.html">CKEditor Samples</a> » Lineutils | ||
16 | </h1> | ||
17 | |||
18 | <h3>Classic (iframe-based) Editor</h3> | ||
19 | |||
20 | <textarea id="editor1" cols="10" rows="10"> | ||
21 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
22 | <tbody> | ||
23 | <tr> | ||
24 | <td>This table</td> | ||
25 | <td>is the</td> | ||
26 | <td>very first</td> | ||
27 | <td>element of the document.</td> | ||
28 | </tr> | ||
29 | <tr> | ||
30 | <td>We are still</td> | ||
31 | <td>able to acces</td> | ||
32 | <td>the space before it.</td> | ||
33 | <td style="padding: 25px"> | ||
34 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
35 | <tbody> | ||
36 | <tr> | ||
37 | <td>This table is inside of a cell of another table.</td> | ||
38 | </tr> | ||
39 | <tr> | ||
40 | <td>We can type either before or after it though.</td> | ||
41 | </tr> | ||
42 | </tbody> | ||
43 | </table> | ||
44 | </td> | ||
45 | </tr> | ||
46 | </tbody> | ||
47 | </table> | ||
48 | |||
49 | <p>Two succesive horizontal lines (<tt>HR</tt> tags). We can access the space in between:</p> | ||
50 | |||
51 | <hr /> | ||
52 | <hr /> | ||
53 | <ol style="width: 300px"> | ||
54 | <li>This numbered list...</li> | ||
55 | <li>...is a neighbour of a horizontal line...</li> | ||
56 | <li style="padding: 20px;"> | ||
57 | <ol> | ||
58 | <li>Nested list!</li> | ||
59 | </ol> | ||
60 | </li> | ||
61 | </ol> | ||
62 | |||
63 | <ul style="width: 450px"> | ||
64 | <li>We can type between the lists...</li> | ||
65 | <li>...thanks to <strong>Magicline</strong>.</li> | ||
66 | </ul> | ||
67 | |||
68 | <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p> | ||
69 | |||
70 | <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p> | ||
71 | |||
72 | <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p> | ||
73 | |||
74 | <div id="last" style="padding: 10px; text-align: center;"> | ||
75 | <p>This text is wrapped in a <tt>DIV</tt> element. We can type after this element though.</p> | ||
76 | </div> | ||
77 | </textarea> | ||
78 | |||
79 | <h3>Inline Editor</h3> | ||
80 | |||
81 | <div id="editor2" contenteditable="true" style="outline: 2px solid #ccc"> | ||
82 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
83 | <tbody> | ||
84 | <tr> | ||
85 | <td>This table</td> | ||
86 | <td>is the</td> | ||
87 | <td>very first</td> | ||
88 | <td>element of the document.</td> | ||
89 | </tr> | ||
90 | <tr> | ||
91 | <td>We are still</td> | ||
92 | <td>able to acces</td> | ||
93 | <td>the space before it.</td> | ||
94 | <td style="padding: 25px"> | ||
95 | <table border="0" cellpadding="1" cellspacing="1" style="width: 100%; "> | ||
96 | <tbody> | ||
97 | <tr> | ||
98 | <td>This table is inside of a cell of another table.</td> | ||
99 | </tr> | ||
100 | <tr> | ||
101 | <td>We can type either before or after it though.</td> | ||
102 | </tr> | ||
103 | </tbody> | ||
104 | </table> | ||
105 | </td> | ||
106 | </tr> | ||
107 | </tbody> | ||
108 | </table> | ||
109 | |||
110 | <p>Two succesive horizontal lines (<tt>HR</tt> tags). We can access the space in between:</p> | ||
111 | |||
112 | <hr /> | ||
113 | <hr /> | ||
114 | <ol style="width: 300px"> | ||
115 | <li>This numbered list...</li> | ||
116 | <li>...is a neighbour of a horizontal line...</li> | ||
117 | <li style="padding: 20px;"> | ||
118 | <ol> | ||
119 | <li>Nested list!</li> | ||
120 | </ol> | ||
121 | </li> | ||
122 | </ol> | ||
123 | |||
124 | <ul style="width: 450px"> | ||
125 | <li>We can type between the lists...</li> | ||
126 | <li>...thanks to <strong>Magicline</strong>.</li> | ||
127 | </ul> | ||
128 | |||
129 | <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p> | ||
130 | |||
131 | <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p> | ||
132 | |||
133 | <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p> | ||
134 | |||
135 | <div id="last" style="padding: 10px; text-align: center;"> | ||
136 | <p>This text is wrapped in a <tt>DIV</tt> element. We can type after this element though.</p> | ||
137 | </div> | ||
138 | </div> | ||
139 | |||
140 | <h3>Extreme inline</h3> | ||
141 | |||
142 | <div id="editor3" contenteditable="true" style="left: 123px; outline: 1px solid red; border: 15px solid green; position: relative; top: 30; left: 30px;"> | ||
143 | <div style="padding: 20px; background: gray; width: 300px" class="1">Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim.</div> | ||
144 | <div style="background: violet; padding: 30px;" class="static"> | ||
145 | Position static | ||
146 | <div style="background: green; padding: 30px; border: 14px solid orange">foo</div> | ||
147 | </div> | ||
148 | <dl class="2"> | ||
149 | <dt>Key</dt><dd>Value</dd> | ||
150 | </dl> | ||
151 | <div>Whatever</div> | ||
152 | <hr id="hr"> | ||
153 | <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p> | ||
154 | <hr> | ||
155 | <hr> | ||
156 | <p>Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies</p> | ||
157 | <div style="background: green; padding: 30px; width: 200px">foo</div> | ||
158 | </div> | ||
159 | |||
160 | <h3>Classic (iframe-based) Editor, H-scroll</h3> | ||
161 | |||
162 | <textarea id="editor4" cols="10" rows="10"> | ||
163 | <hr /> | ||
164 | <hr /> | ||
165 | <ol style="width: 1500px"> | ||
166 | <li>This numbered list...</li> | ||
167 | <li>...is a neighbour of a horizontal line...</li> | ||
168 | <li style="padding: 20px;"> | ||
169 | <ol> | ||
170 | <li>Nested list!</li> | ||
171 | </ol> | ||
172 | </li> | ||
173 | </ol> | ||
174 | |||
175 | <ul style="width: 450px"> | ||
176 | <li>We can type between the lists...</li> | ||
177 | <li>...thanks to <strong>Magicline</strong>.</li> | ||
178 | </ul> | ||
179 | |||
180 | <p>Lorem ipsum dolor sit amet dui. Morbi vel turpis. Nullam et leo. Etiam rutrum, urna tellus dui vel tincidunt mattis egestas, justo fringilla vel, massa. Phasellus.</p> | ||
181 | |||
182 | <p>Quisque iaculis, dui lectus varius vitae, tortor. Proin lacus. Pellentesque ac lacus. Aenean nonummy commodo nec, pede. Etiam blandit risus elit.</p> | ||
183 | |||
184 | <p>Ut pretium. Vestibulum rutrum in, adipiscing elit. Sed in quam in purus sem vitae pede. Pellentesque bibendum, urna sem vel risus. Vivamus posuere metus. Aliquam gravida iaculis nisl. Nam enim. Aliquam erat ac lacus tellus ac felis.</p> | ||
185 | |||
186 | <div id="last" style="padding: 10px; text-align: center;"> | ||
187 | <p>This text is wrapped in a <tt>DIV</tt> element. We can type after this element though.</p> | ||
188 | </div> | ||
189 | </textarea> | ||
190 | |||
191 | <script> | ||
192 | |||
193 | CKEDITOR.addCss( | ||
194 | '.cke_editable * { outline: 1px solid #BCEBFF }' | ||
195 | ); | ||
196 | |||
197 | function callback() { | ||
198 | var helpers = CKEDITOR.plugins.lineutils; | ||
199 | var liner = new helpers.liner( this ); | ||
200 | var locator = new helpers.locator( this ); | ||
201 | var finder = new helpers.finder( this, { | ||
202 | lookups: { | ||
203 | 'is block and first child': function( el ) { | ||
204 | if ( el.is( CKEDITOR.dtd.$listItem ) ) | ||
205 | return; | ||
206 | |||
207 | if ( el.is( CKEDITOR.dtd.$block ) ) | ||
208 | return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER; | ||
209 | } | ||
210 | } | ||
211 | } ).start( function( relations, x, y ) { | ||
212 | locator.locate( relations ); | ||
213 | |||
214 | var locations = locator.locations, | ||
215 | uid, type; | ||
216 | |||
217 | liner.prepare( relations, locations ); | ||
218 | |||
219 | for ( uid in locations ) { | ||
220 | for ( type in locations[ uid ] ) | ||
221 | liner.placeLine( { uid: uid, type: type } ); | ||
222 | } | ||
223 | |||
224 | liner.cleanup(); | ||
225 | } ); | ||
226 | } | ||
227 | |||
228 | CKEDITOR.disableAutoInline = true; | ||
229 | |||
230 | CKEDITOR.replace( 'editor1', { | ||
231 | extraPlugins: 'lineutils', | ||
232 | height: 450, | ||
233 | removePlugins: 'magicline', | ||
234 | allowedContent: true, | ||
235 | contentsCss: [ '../../../contents.css' ], | ||
236 | on: { | ||
237 | contentDom: callback | ||
238 | } | ||
239 | } ); | ||
240 | |||
241 | CKEDITOR.inline( 'editor2', { | ||
242 | extraPlugins: 'lineutils', | ||
243 | removePlugins: 'magicline', | ||
244 | allowedContent: true, | ||
245 | contentsCss: [ '../../../contents.css' ], | ||
246 | on: { | ||
247 | contentDom: callback | ||
248 | } | ||
249 | } ); | ||
250 | |||
251 | CKEDITOR.inline( 'editor3', { | ||
252 | extraPlugins: 'lineutils', | ||
253 | removePlugins: 'magicline', | ||
254 | allowedContent: true, | ||
255 | contentsCss: [ '../../../contents.css' ], | ||
256 | on: { | ||
257 | contentDom: callback | ||
258 | } | ||
259 | } ); | ||
260 | |||
261 | CKEDITOR.replace( 'editor4', { | ||
262 | extraPlugins: 'lineutils', | ||
263 | removePlugins: 'magicline', | ||
264 | allowedContent: true, | ||
265 | contentsCss: [ '../../../contents.css' ], | ||
266 | on: { | ||
267 | contentDom: callback | ||
268 | } | ||
269 | } ); | ||
270 | |||
271 | |||
272 | </script> | ||
273 | |||
274 | <div id="footer"> | ||
275 | <hr> | ||
276 | <p> | ||
277 | CKEditor - The text editor for the Internet - <a class="samples" href="http://ckeditor.com/">http://ckeditor.com</a> | ||
278 | </p> | ||
279 | <p id="copy"> | ||
280 | Copyright © 2003-2017, <a class="samples" href="http://cksource.com/">CKSource</a> - Frederico | ||
281 | Knabben. All rights reserved. | ||
282 | </p> | ||
283 | </div> | ||
284 | </body> | ||
285 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/lineutils/plugin.js b/app/assets/javascripts/ckeditor/plugins/lineutils/plugin.js deleted file mode 100644 index 75d0da8..0000000 --- a/app/assets/javascripts/ckeditor/plugins/lineutils/plugin.js +++ /dev/null | |||
@@ -1,1018 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview A set of utilities to find and create horizontal spaces in edited content. | ||
8 | */ | ||
9 | |||
10 | 'use strict'; | ||
11 | |||
12 | ( function() { | ||
13 | |||
14 | CKEDITOR.plugins.add( 'lineutils' ); | ||
15 | |||
16 | /** | ||
17 | * Determines a position relative to an element in DOM (before). | ||
18 | * | ||
19 | * @readonly | ||
20 | * @property {Number} [=0] | ||
21 | * @member CKEDITOR | ||
22 | */ | ||
23 | CKEDITOR.LINEUTILS_BEFORE = 1; | ||
24 | |||
25 | /** | ||
26 | * Determines a position relative to an element in DOM (after). | ||
27 | * | ||
28 | * @readonly | ||
29 | * @property {Number} [=2] | ||
30 | * @member CKEDITOR | ||
31 | */ | ||
32 | CKEDITOR.LINEUTILS_AFTER = 2; | ||
33 | |||
34 | /** | ||
35 | * Determines a position relative to an element in DOM (inside). | ||
36 | * | ||
37 | * @readonly | ||
38 | * @property {Number} [=4] | ||
39 | * @member CKEDITOR | ||
40 | */ | ||
41 | CKEDITOR.LINEUTILS_INSIDE = 4; | ||
42 | |||
43 | /** | ||
44 | * A utility that traverses the DOM tree and discovers elements | ||
45 | * (relations) matching user-defined lookups. | ||
46 | * | ||
47 | * @private | ||
48 | * @class CKEDITOR.plugins.lineutils.finder | ||
49 | * @constructor Creates a Finder class instance. | ||
50 | * @param {CKEDITOR.editor} editor Editor instance that the Finder belongs to. | ||
51 | * @param {Object} def Finder's definition. | ||
52 | * @since 4.3 | ||
53 | */ | ||
54 | function Finder( editor, def ) { | ||
55 | CKEDITOR.tools.extend( this, { | ||
56 | editor: editor, | ||
57 | editable: editor.editable(), | ||
58 | doc: editor.document, | ||
59 | win: editor.window | ||
60 | }, def, true ); | ||
61 | |||
62 | this.inline = this.editable.isInline(); | ||
63 | |||
64 | if ( !this.inline ) { | ||
65 | this.frame = this.win.getFrame(); | ||
66 | } | ||
67 | |||
68 | this.target = this[ this.inline ? 'editable' : 'doc' ]; | ||
69 | } | ||
70 | |||
71 | Finder.prototype = { | ||
72 | /** | ||
73 | * Initializes searching for elements with every mousemove event fired. | ||
74 | * To stop searching use {@link #stop}. | ||
75 | * | ||
76 | * @param {Function} [callback] Function executed on every iteration. | ||
77 | */ | ||
78 | start: function( callback ) { | ||
79 | var that = this, | ||
80 | editor = this.editor, | ||
81 | doc = this.doc, | ||
82 | el, elfp, x, y; | ||
83 | |||
84 | var moveBuffer = CKEDITOR.tools.eventsBuffer( 50, function() { | ||
85 | if ( editor.readOnly || editor.mode != 'wysiwyg' ) | ||
86 | return; | ||
87 | |||
88 | that.relations = {}; | ||
89 | |||
90 | // Sometimes it happens that elementFromPoint returns null (especially on IE). | ||
91 | // Any further traversal makes no sense if there's no start point. Abort. | ||
92 | // Note: In IE8 elementFromPoint may return zombie nodes of undefined nodeType, | ||
93 | // so rejecting those as well. | ||
94 | if ( !( elfp = doc.$.elementFromPoint( x, y ) ) || !elfp.nodeType ) { | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | el = new CKEDITOR.dom.element( elfp ); | ||
99 | |||
100 | that.traverseSearch( el ); | ||
101 | |||
102 | if ( !isNaN( x + y ) ) { | ||
103 | that.pixelSearch( el, x, y ); | ||
104 | } | ||
105 | |||
106 | callback && callback( that.relations, x, y ); | ||
107 | } ); | ||
108 | |||
109 | // Searching starting from element from point on mousemove. | ||
110 | this.listener = this.editable.attachListener( this.target, 'mousemove', function( evt ) { | ||
111 | x = evt.data.$.clientX; | ||
112 | y = evt.data.$.clientY; | ||
113 | |||
114 | moveBuffer.input(); | ||
115 | } ); | ||
116 | |||
117 | this.editable.attachListener( this.inline ? this.editable : this.frame, 'mouseout', function() { | ||
118 | moveBuffer.reset(); | ||
119 | } ); | ||
120 | }, | ||
121 | |||
122 | /** | ||
123 | * Stops observing mouse events attached by {@link #start}. | ||
124 | */ | ||
125 | stop: function() { | ||
126 | if ( this.listener ) { | ||
127 | this.listener.removeListener(); | ||
128 | } | ||
129 | }, | ||
130 | |||
131 | /** | ||
132 | * Returns a range representing the relation, according to its element | ||
133 | * and type. | ||
134 | * | ||
135 | * @param {Object} location Location containing a unique identifier and type. | ||
136 | * @returns {CKEDITOR.dom.range} Range representing the relation. | ||
137 | */ | ||
138 | getRange: ( function() { | ||
139 | var where = {}; | ||
140 | |||
141 | where[ CKEDITOR.LINEUTILS_BEFORE ] = CKEDITOR.POSITION_BEFORE_START; | ||
142 | where[ CKEDITOR.LINEUTILS_AFTER ] = CKEDITOR.POSITION_AFTER_END; | ||
143 | where[ CKEDITOR.LINEUTILS_INSIDE ] = CKEDITOR.POSITION_AFTER_START; | ||
144 | |||
145 | return function( location ) { | ||
146 | var range = this.editor.createRange(); | ||
147 | |||
148 | range.moveToPosition( this.relations[ location.uid ].element, where[ location.type ] ); | ||
149 | |||
150 | return range; | ||
151 | }; | ||
152 | } )(), | ||
153 | |||
154 | /** | ||
155 | * Stores given relation in a {@link #relations} object. Processes the relation | ||
156 | * to normalize and avoid duplicates. | ||
157 | * | ||
158 | * @param {CKEDITOR.dom.element} el Element of the relation. | ||
159 | * @param {Number} type Relation, one of `CKEDITOR.LINEUTILS_AFTER`, `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_INSIDE`. | ||
160 | */ | ||
161 | store: ( function() { | ||
162 | function merge( el, type, relations ) { | ||
163 | var uid = el.getUniqueId(); | ||
164 | |||
165 | if ( uid in relations ) { | ||
166 | relations[ uid ].type |= type; | ||
167 | } else { | ||
168 | relations[ uid ] = { element: el, type: type }; | ||
169 | } | ||
170 | } | ||
171 | |||
172 | return function( el, type ) { | ||
173 | var alt; | ||
174 | |||
175 | // Normalization to avoid duplicates: | ||
176 | // CKEDITOR.LINEUTILS_AFTER becomes CKEDITOR.LINEUTILS_BEFORE of el.getNext(). | ||
177 | if ( is( type, CKEDITOR.LINEUTILS_AFTER ) && isStatic( alt = el.getNext() ) && alt.isVisible() ) { | ||
178 | merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations ); | ||
179 | type ^= CKEDITOR.LINEUTILS_AFTER; | ||
180 | } | ||
181 | |||
182 | // Normalization to avoid duplicates: | ||
183 | // CKEDITOR.LINEUTILS_INSIDE becomes CKEDITOR.LINEUTILS_BEFORE of el.getFirst(). | ||
184 | if ( is( type, CKEDITOR.LINEUTILS_INSIDE ) && isStatic( alt = el.getFirst() ) && alt.isVisible() ) { | ||
185 | merge( alt, CKEDITOR.LINEUTILS_BEFORE, this.relations ); | ||
186 | type ^= CKEDITOR.LINEUTILS_INSIDE; | ||
187 | } | ||
188 | |||
189 | merge( el, type, this.relations ); | ||
190 | }; | ||
191 | } )(), | ||
192 | |||
193 | /** | ||
194 | * Traverses the DOM tree towards root, checking all ancestors | ||
195 | * with lookup rules, avoiding duplicates. Stores positive relations | ||
196 | * in the {@link #relations} object. | ||
197 | * | ||
198 | * @param {CKEDITOR.dom.element} el Element which is the starting point. | ||
199 | */ | ||
200 | traverseSearch: function( el ) { | ||
201 | var l, type, uid; | ||
202 | |||
203 | // Go down DOM towards root (or limit). | ||
204 | do { | ||
205 | uid = el.$[ 'data-cke-expando' ]; | ||
206 | |||
207 | // This element was already visited and checked. | ||
208 | if ( uid && uid in this.relations ) { | ||
209 | continue; | ||
210 | } | ||
211 | |||
212 | if ( el.equals( this.editable ) ) { | ||
213 | return; | ||
214 | } | ||
215 | |||
216 | if ( isStatic( el ) ) { | ||
217 | // Collect all addresses yielded by lookups for that element. | ||
218 | for ( l in this.lookups ) { | ||
219 | |||
220 | if ( ( type = this.lookups[ l ]( el ) ) ) { | ||
221 | this.store( el, type ); | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | } while ( !isLimit( el ) && ( el = el.getParent() ) ); | ||
226 | }, | ||
227 | |||
228 | /** | ||
229 | * Iterates vertically pixel-by-pixel within a given element starting | ||
230 | * from given coordinates, searching for elements in the neighborhood. | ||
231 | * Once an element is found it is processed by {@link #traverseSearch}. | ||
232 | * | ||
233 | * @param {CKEDITOR.dom.element} el Element which is the starting point. | ||
234 | * @param {Number} [x] Horizontal mouse coordinate relative to the viewport. | ||
235 | * @param {Number} [y] Vertical mouse coordinate relative to the viewport. | ||
236 | */ | ||
237 | pixelSearch: ( function() { | ||
238 | var contains = CKEDITOR.env.ie || CKEDITOR.env.webkit ? | ||
239 | function( el, found ) { | ||
240 | return el.contains( found ); | ||
241 | } : function( el, found ) { | ||
242 | return !!( el.compareDocumentPosition( found ) & 16 ); | ||
243 | }; | ||
244 | |||
245 | // Iterates pixel-by-pixel from starting coordinates, moving by defined | ||
246 | // step and getting elementFromPoint in every iteration. Iteration stops when: | ||
247 | // * A valid element is found. | ||
248 | // * Condition function returns `false` (i.e. reached boundaries of viewport). | ||
249 | // * No element is found (i.e. coordinates out of viewport). | ||
250 | // * Element found is ascendant of starting element. | ||
251 | // | ||
252 | // @param {Object} doc Native DOM document. | ||
253 | // @param {Object} el Native DOM element. | ||
254 | // @param {Number} xStart Horizontal starting coordinate to use. | ||
255 | // @param {Number} yStart Vertical starting coordinate to use. | ||
256 | // @param {Number} step Step of the algorithm. | ||
257 | // @param {Function} condition A condition relative to current vertical coordinate. | ||
258 | function iterate( el, xStart, yStart, step, condition ) { | ||
259 | var y = yStart, | ||
260 | tryouts = 0, | ||
261 | found; | ||
262 | |||
263 | while ( condition( y ) ) { | ||
264 | y += step; | ||
265 | |||
266 | // If we try and we try, and still nothing's found, let's end | ||
267 | // that party. | ||
268 | if ( ++tryouts == 25 ) { | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | found = this.doc.$.elementFromPoint( xStart, y ); | ||
273 | |||
274 | // Nothing found. This is crazy... but... | ||
275 | // It might be that a line, which is in different document, | ||
276 | // covers that pixel (elementFromPoint is doc-sensitive). | ||
277 | // Better let's have another try. | ||
278 | if ( !found ) { | ||
279 | continue; | ||
280 | } | ||
281 | |||
282 | // Still in the same element. | ||
283 | else if ( found == el ) { | ||
284 | tryouts = 0; | ||
285 | continue; | ||
286 | } | ||
287 | |||
288 | // Reached the edge of an element and found an ancestor or... | ||
289 | // A line, that covers that pixel. Better let's have another try. | ||
290 | else if ( !contains( el, found ) ) { | ||
291 | continue; | ||
292 | } | ||
293 | |||
294 | tryouts = 0; | ||
295 | |||
296 | // Found a valid element. Stop iterating. | ||
297 | if ( isStatic( ( found = new CKEDITOR.dom.element( found ) ) ) ) { | ||
298 | return found; | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | |||
303 | return function( el, x, y ) { | ||
304 | var paneHeight = this.win.getViewPaneSize().height, | ||
305 | |||
306 | // Try to find an element iterating *up* from the starting point. | ||
307 | neg = iterate.call( this, el.$, x, y, -1, function( y ) { | ||
308 | return y > 0; | ||
309 | } ), | ||
310 | |||
311 | // Try to find an element iterating *down* from the starting point. | ||
312 | pos = iterate.call( this, el.$, x, y, 1, function( y ) { | ||
313 | return y < paneHeight; | ||
314 | } ); | ||
315 | |||
316 | if ( neg ) { | ||
317 | this.traverseSearch( neg ); | ||
318 | |||
319 | // Iterate towards DOM root until neg is a direct child of el. | ||
320 | while ( !neg.getParent().equals( el ) ) { | ||
321 | neg = neg.getParent(); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | if ( pos ) { | ||
326 | this.traverseSearch( pos ); | ||
327 | |||
328 | // Iterate towards DOM root until pos is a direct child of el. | ||
329 | while ( !pos.getParent().equals( el ) ) { | ||
330 | pos = pos.getParent(); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | // Iterate forwards starting from neg and backwards from | ||
335 | // pos to harvest all children of el between those elements. | ||
336 | // Stop when neg and pos meet each other or there's none of them. | ||
337 | // TODO (?) reduce number of hops forwards/backwards. | ||
338 | while ( neg || pos ) { | ||
339 | if ( neg ) { | ||
340 | neg = neg.getNext( isStatic ); | ||
341 | } | ||
342 | |||
343 | if ( !neg || neg.equals( pos ) ) { | ||
344 | break; | ||
345 | } | ||
346 | |||
347 | this.traverseSearch( neg ); | ||
348 | |||
349 | if ( pos ) { | ||
350 | pos = pos.getPrevious( isStatic ); | ||
351 | } | ||
352 | |||
353 | if ( !pos || pos.equals( neg ) ) { | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | this.traverseSearch( pos ); | ||
358 | } | ||
359 | }; | ||
360 | } )(), | ||
361 | |||
362 | /** | ||
363 | * Unlike {@link #traverseSearch}, it collects **all** elements from editable's DOM tree | ||
364 | * and runs lookups for every one of them, collecting relations. | ||
365 | * | ||
366 | * @returns {Object} {@link #relations}. | ||
367 | */ | ||
368 | greedySearch: function() { | ||
369 | this.relations = {}; | ||
370 | |||
371 | var all = this.editable.getElementsByTag( '*' ), | ||
372 | i = 0, | ||
373 | el, type, l; | ||
374 | |||
375 | while ( ( el = all.getItem( i++ ) ) ) { | ||
376 | // Don't consider editable, as it might be inline, | ||
377 | // and i.e. checking it's siblings is pointless. | ||
378 | if ( el.equals( this.editable ) ) { | ||
379 | continue; | ||
380 | } | ||
381 | |||
382 | // On IE8 element.getElementsByTagName returns comments... sic! (http://dev.ckeditor.com/ticket/13176) | ||
383 | if ( el.type != CKEDITOR.NODE_ELEMENT ) { | ||
384 | continue; | ||
385 | } | ||
386 | |||
387 | // Don't visit non-editable internals, for example widget's | ||
388 | // guts (above wrapper, below nested). Still check editable limits, | ||
389 | // as they are siblings with editable contents. | ||
390 | if ( !el.hasAttribute( 'contenteditable' ) && el.isReadOnly() ) { | ||
391 | continue; | ||
392 | } | ||
393 | |||
394 | if ( isStatic( el ) && el.isVisible() ) { | ||
395 | // Collect all addresses yielded by lookups for that element. | ||
396 | for ( l in this.lookups ) { | ||
397 | if ( ( type = this.lookups[ l ]( el ) ) ) { | ||
398 | this.store( el, type ); | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | return this.relations; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * Relations express elements in DOM that match user-defined {@link #lookups}. | ||
409 | * Every relation has its own `type` that determines whether | ||
410 | * it refers to the space before, after or inside the `element`. | ||
411 | * This object stores relations found by {@link #traverseSearch} or {@link #greedySearch}, structured | ||
412 | * in the following way: | ||
413 | * | ||
414 | * relations: { | ||
415 | * // Unique identifier of the element. | ||
416 | * Number: { | ||
417 | * // Element of this relation. | ||
418 | * element: {@link CKEDITOR.dom.element} | ||
419 | * // Conjunction of CKEDITOR.LINEUTILS_BEFORE, CKEDITOR.LINEUTILS_AFTER and CKEDITOR.LINEUTILS_INSIDE. | ||
420 | * type: Number | ||
421 | * }, | ||
422 | * ... | ||
423 | * } | ||
424 | * | ||
425 | * @property {Object} relations | ||
426 | * @readonly | ||
427 | */ | ||
428 | |||
429 | /** | ||
430 | * A set of user-defined functions used by Finder to check if an element | ||
431 | * is a valid relation, belonging to {@link #relations}. | ||
432 | * When the criterion is met, lookup returns a logical conjunction of `CKEDITOR.LINEUTILS_BEFORE`, | ||
433 | * `CKEDITOR.LINEUTILS_AFTER` or `CKEDITOR.LINEUTILS_INSIDE`. | ||
434 | * | ||
435 | * Lookups are passed along with Finder's definition. | ||
436 | * | ||
437 | * lookups: { | ||
438 | * 'some lookup': function( el ) { | ||
439 | * if ( someCondition ) | ||
440 | * return CKEDITOR.LINEUTILS_BEFORE; | ||
441 | * }, | ||
442 | * ... | ||
443 | * } | ||
444 | * | ||
445 | * @property {Object} lookups | ||
446 | */ | ||
447 | }; | ||
448 | |||
449 | |||
450 | /** | ||
451 | * A utility that analyses relations found by | ||
452 | * CKEDITOR.plugins.lineutils.finder and locates them | ||
453 | * in the viewport as horizontal lines of specific coordinates. | ||
454 | * | ||
455 | * @private | ||
456 | * @class CKEDITOR.plugins.lineutils.locator | ||
457 | * @constructor Creates a Locator class instance. | ||
458 | * @param {CKEDITOR.editor} editor Editor instance that Locator belongs to. | ||
459 | * @since 4.3 | ||
460 | */ | ||
461 | function Locator( editor, def ) { | ||
462 | CKEDITOR.tools.extend( this, def, { | ||
463 | editor: editor | ||
464 | }, true ); | ||
465 | } | ||
466 | |||
467 | Locator.prototype = { | ||
468 | /** | ||
469 | * Locates the Y coordinate for all types of every single relation and stores | ||
470 | * them in an object. | ||
471 | * | ||
472 | * @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}. | ||
473 | * @returns {Object} {@link #locations}. | ||
474 | */ | ||
475 | locate: ( function() { | ||
476 | function locateSibling( rel, type ) { | ||
477 | var sib = rel.element[ type === CKEDITOR.LINEUTILS_BEFORE ? 'getPrevious' : 'getNext' ](); | ||
478 | |||
479 | // Return the middle point between siblings. | ||
480 | if ( sib && isStatic( sib ) ) { | ||
481 | rel.siblingRect = sib.getClientRect(); | ||
482 | |||
483 | if ( type == CKEDITOR.LINEUTILS_BEFORE ) { | ||
484 | return ( rel.siblingRect.bottom + rel.elementRect.top ) / 2; | ||
485 | } else { | ||
486 | return ( rel.elementRect.bottom + rel.siblingRect.top ) / 2; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | // If there's no sibling, use the edge of an element. | ||
491 | else { | ||
492 | if ( type == CKEDITOR.LINEUTILS_BEFORE ) { | ||
493 | return rel.elementRect.top; | ||
494 | } else { | ||
495 | return rel.elementRect.bottom; | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | |||
500 | return function( relations ) { | ||
501 | var rel; | ||
502 | |||
503 | this.locations = {}; | ||
504 | |||
505 | for ( var uid in relations ) { | ||
506 | rel = relations[ uid ]; | ||
507 | rel.elementRect = rel.element.getClientRect(); | ||
508 | |||
509 | if ( is( rel.type, CKEDITOR.LINEUTILS_BEFORE ) ) { | ||
510 | this.store( uid, CKEDITOR.LINEUTILS_BEFORE, locateSibling( rel, CKEDITOR.LINEUTILS_BEFORE ) ); | ||
511 | } | ||
512 | |||
513 | if ( is( rel.type, CKEDITOR.LINEUTILS_AFTER ) ) { | ||
514 | this.store( uid, CKEDITOR.LINEUTILS_AFTER, locateSibling( rel, CKEDITOR.LINEUTILS_AFTER ) ); | ||
515 | } | ||
516 | |||
517 | // The middle point of the element. | ||
518 | if ( is( rel.type, CKEDITOR.LINEUTILS_INSIDE ) ) { | ||
519 | this.store( uid, CKEDITOR.LINEUTILS_INSIDE, ( rel.elementRect.top + rel.elementRect.bottom ) / 2 ); | ||
520 | } | ||
521 | } | ||
522 | |||
523 | return this.locations; | ||
524 | }; | ||
525 | } )(), | ||
526 | |||
527 | /** | ||
528 | * Calculates distances from every location to given vertical coordinate | ||
529 | * and sorts locations according to that distance. | ||
530 | * | ||
531 | * @param {Number} y The vertical coordinate used for sorting, used as a reference. | ||
532 | * @param {Number} [howMany] Determines the number of "closest locations" to be returned. | ||
533 | * @returns {Array} Sorted, array representation of {@link #locations}. | ||
534 | */ | ||
535 | sort: ( function() { | ||
536 | var locations, sorted, | ||
537 | dist, i; | ||
538 | |||
539 | function distance( y, uid, type ) { | ||
540 | return Math.abs( y - locations[ uid ][ type ] ); | ||
541 | } | ||
542 | |||
543 | return function( y, howMany ) { | ||
544 | locations = this.locations; | ||
545 | sorted = []; | ||
546 | |||
547 | for ( var uid in locations ) { | ||
548 | for ( var type in locations[ uid ] ) { | ||
549 | dist = distance( y, uid, type ); | ||
550 | |||
551 | // An array is empty. | ||
552 | if ( !sorted.length ) { | ||
553 | sorted.push( { uid: +uid, type: type, dist: dist } ); | ||
554 | } else { | ||
555 | // Sort the array on fly when it's populated. | ||
556 | for ( i = 0; i < sorted.length; i++ ) { | ||
557 | if ( dist < sorted[ i ].dist ) { | ||
558 | sorted.splice( i, 0, { uid: +uid, type: type, dist: dist } ); | ||
559 | break; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | // Nothing was inserted, so the distance is bigger than | ||
564 | // any of already calculated: push to the end. | ||
565 | if ( i == sorted.length ) { | ||
566 | sorted.push( { uid: +uid, type: type, dist: dist } ); | ||
567 | } | ||
568 | } | ||
569 | } | ||
570 | } | ||
571 | |||
572 | if ( typeof howMany != 'undefined' ) { | ||
573 | return sorted.slice( 0, howMany ); | ||
574 | } else { | ||
575 | return sorted; | ||
576 | } | ||
577 | }; | ||
578 | } )(), | ||
579 | |||
580 | /** | ||
581 | * Stores the location in a collection. | ||
582 | * | ||
583 | * @param {Number} uid Unique identifier of the relation. | ||
584 | * @param {Number} type One of `CKEDITOR.LINEUTILS_BEFORE`, `CKEDITOR.LINEUTILS_AFTER` and `CKEDITOR.LINEUTILS_INSIDE`. | ||
585 | * @param {Number} y Vertical position of the relation. | ||
586 | */ | ||
587 | store: function( uid, type, y ) { | ||
588 | if ( !this.locations[ uid ] ) { | ||
589 | this.locations[ uid ] = {}; | ||
590 | } | ||
591 | |||
592 | this.locations[ uid ][ type ] = y; | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * @readonly | ||
597 | * @property {Object} locations | ||
598 | */ | ||
599 | }; | ||
600 | |||
601 | var tipCss = { | ||
602 | display: 'block', | ||
603 | width: '0px', | ||
604 | height: '0px', | ||
605 | 'border-color': 'transparent', | ||
606 | 'border-style': 'solid', | ||
607 | position: 'absolute', | ||
608 | top: '-6px' | ||
609 | }, | ||
610 | |||
611 | lineStyle = { | ||
612 | height: '0px', | ||
613 | 'border-top': '1px dashed red', | ||
614 | position: 'absolute', | ||
615 | 'z-index': 9999 | ||
616 | }, | ||
617 | |||
618 | lineTpl = | ||
619 | '<div data-cke-lineutils-line="1" class="cke_reset_all" style="{lineStyle}">' + | ||
620 | '<span style="{tipLeftStyle}"> </span>' + | ||
621 | '<span style="{tipRightStyle}"> </span>' + | ||
622 | '</div>'; | ||
623 | |||
624 | /** | ||
625 | * A utility that draws horizontal lines in DOM according to locations | ||
626 | * returned by CKEDITOR.plugins.lineutils.locator. | ||
627 | * | ||
628 | * @private | ||
629 | * @class CKEDITOR.plugins.lineutils.liner | ||
630 | * @constructor Creates a Liner class instance. | ||
631 | * @param {CKEDITOR.editor} editor Editor instance that Liner belongs to. | ||
632 | * @param {Object} def Liner's definition. | ||
633 | * @since 4.3 | ||
634 | */ | ||
635 | function Liner( editor, def ) { | ||
636 | var editable = editor.editable(); | ||
637 | |||
638 | CKEDITOR.tools.extend( this, { | ||
639 | editor: editor, | ||
640 | editable: editable, | ||
641 | inline: editable.isInline(), | ||
642 | doc: editor.document, | ||
643 | win: editor.window, | ||
644 | container: CKEDITOR.document.getBody(), | ||
645 | winTop: CKEDITOR.document.getWindow() | ||
646 | }, def, true ); | ||
647 | |||
648 | this.hidden = {}; | ||
649 | this.visible = {}; | ||
650 | |||
651 | if ( !this.inline ) { | ||
652 | this.frame = this.win.getFrame(); | ||
653 | } | ||
654 | |||
655 | this.queryViewport(); | ||
656 | |||
657 | // Callbacks must be wrapped. Otherwise they're not attached | ||
658 | // to global DOM objects (i.e. topmost window) for every editor | ||
659 | // because they're treated as duplicates. They belong to the | ||
660 | // same prototype shared among Liner instances. | ||
661 | var queryViewport = CKEDITOR.tools.bind( this.queryViewport, this ), | ||
662 | hideVisible = CKEDITOR.tools.bind( this.hideVisible, this ), | ||
663 | removeAll = CKEDITOR.tools.bind( this.removeAll, this ); | ||
664 | |||
665 | editable.attachListener( this.winTop, 'resize', queryViewport ); | ||
666 | editable.attachListener( this.winTop, 'scroll', queryViewport ); | ||
667 | |||
668 | editable.attachListener( this.winTop, 'resize', hideVisible ); | ||
669 | editable.attachListener( this.win, 'scroll', hideVisible ); | ||
670 | |||
671 | editable.attachListener( this.inline ? editable : this.frame, 'mouseout', function( evt ) { | ||
672 | var x = evt.data.$.clientX, | ||
673 | y = evt.data.$.clientY; | ||
674 | |||
675 | this.queryViewport(); | ||
676 | |||
677 | // Check if mouse is out of the element (iframe/editable). | ||
678 | if ( x <= this.rect.left || x >= this.rect.right || y <= this.rect.top || y >= this.rect.bottom ) { | ||
679 | this.hideVisible(); | ||
680 | } | ||
681 | |||
682 | // Check if mouse is out of the top-window vieport. | ||
683 | if ( x <= 0 || x >= this.winTopPane.width || y <= 0 || y >= this.winTopPane.height ) { | ||
684 | this.hideVisible(); | ||
685 | } | ||
686 | }, this ); | ||
687 | |||
688 | editable.attachListener( editor, 'resize', queryViewport ); | ||
689 | editable.attachListener( editor, 'mode', removeAll ); | ||
690 | editor.on( 'destroy', removeAll ); | ||
691 | |||
692 | this.lineTpl = new CKEDITOR.template( lineTpl ).output( { | ||
693 | lineStyle: CKEDITOR.tools.writeCssText( | ||
694 | CKEDITOR.tools.extend( {}, lineStyle, this.lineStyle, true ) | ||
695 | ), | ||
696 | tipLeftStyle: CKEDITOR.tools.writeCssText( | ||
697 | CKEDITOR.tools.extend( {}, tipCss, { | ||
698 | left: '0px', | ||
699 | 'border-left-color': 'red', | ||
700 | 'border-width': '6px 0 6px 6px' | ||
701 | }, this.tipCss, this.tipLeftStyle, true ) | ||
702 | ), | ||
703 | tipRightStyle: CKEDITOR.tools.writeCssText( | ||
704 | CKEDITOR.tools.extend( {}, tipCss, { | ||
705 | right: '0px', | ||
706 | 'border-right-color': 'red', | ||
707 | 'border-width': '6px 6px 6px 0' | ||
708 | }, this.tipCss, this.tipRightStyle, true ) | ||
709 | ) | ||
710 | } ); | ||
711 | } | ||
712 | |||
713 | Liner.prototype = { | ||
714 | /** | ||
715 | * Permanently removes all lines (both hidden and visible) from DOM. | ||
716 | */ | ||
717 | removeAll: function() { | ||
718 | var l; | ||
719 | |||
720 | for ( l in this.hidden ) { | ||
721 | this.hidden[ l ].remove(); | ||
722 | delete this.hidden[ l ]; | ||
723 | } | ||
724 | |||
725 | for ( l in this.visible ) { | ||
726 | this.visible[ l ].remove(); | ||
727 | delete this.visible[ l ]; | ||
728 | } | ||
729 | }, | ||
730 | |||
731 | /** | ||
732 | * Hides a given line. | ||
733 | * | ||
734 | * @param {CKEDITOR.dom.element} line The line to be hidden. | ||
735 | */ | ||
736 | hideLine: function( line ) { | ||
737 | var uid = line.getUniqueId(); | ||
738 | |||
739 | line.hide(); | ||
740 | |||
741 | this.hidden[ uid ] = line; | ||
742 | delete this.visible[ uid ]; | ||
743 | }, | ||
744 | |||
745 | /** | ||
746 | * Shows a given line. | ||
747 | * | ||
748 | * @param {CKEDITOR.dom.element} line The line to be shown. | ||
749 | */ | ||
750 | showLine: function( line ) { | ||
751 | var uid = line.getUniqueId(); | ||
752 | |||
753 | line.show(); | ||
754 | |||
755 | this.visible[ uid ] = line; | ||
756 | delete this.hidden[ uid ]; | ||
757 | }, | ||
758 | |||
759 | /** | ||
760 | * Hides all visible lines. | ||
761 | */ | ||
762 | hideVisible: function() { | ||
763 | for ( var l in this.visible ) { | ||
764 | this.hideLine( this.visible[ l ] ); | ||
765 | } | ||
766 | }, | ||
767 | |||
768 | /** | ||
769 | * Shows a line at given location. | ||
770 | * | ||
771 | * @param {Object} location Location object containing the unique identifier of the relation | ||
772 | * and its type. Usually returned by {@link CKEDITOR.plugins.lineutils.locator#sort}. | ||
773 | * @param {Function} [callback] A callback to be called once the line is shown. | ||
774 | */ | ||
775 | placeLine: function( location, callback ) { | ||
776 | var styles, line, l; | ||
777 | |||
778 | // No style means that line would be out of viewport. | ||
779 | if ( !( styles = this.getStyle( location.uid, location.type ) ) ) { | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | // Search for any visible line of a different hash first. | ||
784 | // It's faster to re-position visible line than to show it. | ||
785 | for ( l in this.visible ) { | ||
786 | if ( this.visible[ l ].getCustomData( 'hash' ) !== this.hash ) { | ||
787 | line = this.visible[ l ]; | ||
788 | break; | ||
789 | } | ||
790 | } | ||
791 | |||
792 | // Search for any hidden line of a different hash. | ||
793 | if ( !line ) { | ||
794 | for ( l in this.hidden ) { | ||
795 | if ( this.hidden[ l ].getCustomData( 'hash' ) !== this.hash ) { | ||
796 | this.showLine( ( line = this.hidden[ l ] ) ); | ||
797 | break; | ||
798 | } | ||
799 | } | ||
800 | } | ||
801 | |||
802 | // If no line available, add the new one. | ||
803 | if ( !line ) { | ||
804 | this.showLine( ( line = this.addLine() ) ); | ||
805 | } | ||
806 | |||
807 | // Mark the line with current hash. | ||
808 | line.setCustomData( 'hash', this.hash ); | ||
809 | |||
810 | // Mark the line as visible. | ||
811 | this.visible[ line.getUniqueId() ] = line; | ||
812 | |||
813 | line.setStyles( styles ); | ||
814 | |||
815 | callback && callback( line ); | ||
816 | }, | ||
817 | |||
818 | /** | ||
819 | * Creates a style set to be used by the line, representing a particular | ||
820 | * relation (location). | ||
821 | * | ||
822 | * @param {Number} uid Unique identifier of the relation. | ||
823 | * @param {Number} type Type of the relation. | ||
824 | * @returns {Object} An object containing styles. | ||
825 | */ | ||
826 | getStyle: function( uid, type ) { | ||
827 | var rel = this.relations[ uid ], | ||
828 | loc = this.locations[ uid ][ type ], | ||
829 | styles = {}, | ||
830 | hdiff; | ||
831 | |||
832 | // Line should be between two elements. | ||
833 | if ( rel.siblingRect ) { | ||
834 | styles.width = Math.max( rel.siblingRect.width, rel.elementRect.width ); | ||
835 | } | ||
836 | // Line is relative to a single element. | ||
837 | else { | ||
838 | styles.width = rel.elementRect.width; | ||
839 | } | ||
840 | |||
841 | // Let's calculate the vertical position of the line. | ||
842 | if ( this.inline ) { | ||
843 | // (http://dev.ckeditor.com/ticket/13155) | ||
844 | styles.top = loc + this.winTopScroll.y - this.rect.relativeY; | ||
845 | } else { | ||
846 | styles.top = this.rect.top + this.winTopScroll.y + loc; | ||
847 | } | ||
848 | |||
849 | // Check if line would be vertically out of the viewport. | ||
850 | if ( styles.top - this.winTopScroll.y < this.rect.top || styles.top - this.winTopScroll.y > this.rect.bottom ) { | ||
851 | return false; | ||
852 | } | ||
853 | |||
854 | // Now let's calculate the horizontal alignment (left and width). | ||
855 | if ( this.inline ) { | ||
856 | // (http://dev.ckeditor.com/ticket/13155) | ||
857 | styles.left = rel.elementRect.left - this.rect.relativeX; | ||
858 | } else { | ||
859 | if ( rel.elementRect.left > 0 ) | ||
860 | styles.left = this.rect.left + rel.elementRect.left; | ||
861 | |||
862 | // H-scroll case. Left edge of element may be out of viewport. | ||
863 | else { | ||
864 | styles.width += rel.elementRect.left; | ||
865 | styles.left = this.rect.left; | ||
866 | } | ||
867 | |||
868 | // H-scroll case. Right edge of element may be out of viewport. | ||
869 | if ( ( hdiff = styles.left + styles.width - ( this.rect.left + this.winPane.width ) ) > 0 ) { | ||
870 | styles.width -= hdiff; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | // Finally include horizontal scroll of the global window. | ||
875 | styles.left += this.winTopScroll.x; | ||
876 | |||
877 | // Append 'px' to style values. | ||
878 | for ( var style in styles ) { | ||
879 | styles[ style ] = CKEDITOR.tools.cssLength( styles[ style ] ); | ||
880 | } | ||
881 | |||
882 | return styles; | ||
883 | }, | ||
884 | |||
885 | /** | ||
886 | * Adds a new line to DOM. | ||
887 | * | ||
888 | * @returns {CKEDITOR.dom.element} A brand-new line. | ||
889 | */ | ||
890 | addLine: function() { | ||
891 | var line = CKEDITOR.dom.element.createFromHtml( this.lineTpl ); | ||
892 | |||
893 | line.appendTo( this.container ); | ||
894 | |||
895 | return line; | ||
896 | }, | ||
897 | |||
898 | /** | ||
899 | * Assigns a unique hash to the instance that is later used | ||
900 | * to tell unwanted lines from new ones. This method **must** be called | ||
901 | * before a new set of relations is to be visualized so {@link #cleanup} | ||
902 | * eventually hides obsolete lines. This is because lines | ||
903 | * are re-used between {@link #placeLine} calls and the number of | ||
904 | * necessary ones may vary depending on the number of relations. | ||
905 | * | ||
906 | * @param {Object} relations {@link CKEDITOR.plugins.lineutils.finder#relations}. | ||
907 | * @param {Object} locations {@link CKEDITOR.plugins.lineutils.locator#locations}. | ||
908 | */ | ||
909 | prepare: function( relations, locations ) { | ||
910 | this.relations = relations; | ||
911 | this.locations = locations; | ||
912 | this.hash = Math.random(); | ||
913 | }, | ||
914 | |||
915 | /** | ||
916 | * Hides all visible lines that do not belong to current hash | ||
917 | * and no longer represent relations (locations). | ||
918 | * | ||
919 | * See also: {@link #prepare}. | ||
920 | */ | ||
921 | cleanup: function() { | ||
922 | var line; | ||
923 | |||
924 | for ( var l in this.visible ) { | ||
925 | line = this.visible[ l ]; | ||
926 | |||
927 | if ( line.getCustomData( 'hash' ) !== this.hash ) { | ||
928 | this.hideLine( line ); | ||
929 | } | ||
930 | } | ||
931 | }, | ||
932 | |||
933 | /** | ||
934 | * Queries dimensions of the viewport, editable, frame etc. | ||
935 | * that are used for correct positioning of the line. | ||
936 | */ | ||
937 | queryViewport: function() { | ||
938 | this.winPane = this.win.getViewPaneSize(); | ||
939 | this.winTopScroll = this.winTop.getScrollPosition(); | ||
940 | this.winTopPane = this.winTop.getViewPaneSize(); | ||
941 | |||
942 | // (http://dev.ckeditor.com/ticket/13155) | ||
943 | this.rect = this.getClientRect( this.inline ? this.editable : this.frame ); | ||
944 | }, | ||
945 | |||
946 | /** | ||
947 | * Returns `boundingClientRect` of an element, shifted by the position | ||
948 | * of `container` when the container is not `static` (http://dev.ckeditor.com/ticket/13155). | ||
949 | * | ||
950 | * See also: {@link CKEDITOR.dom.element#getClientRect}. | ||
951 | * | ||
952 | * @param {CKEDITOR.dom.element} el A DOM element. | ||
953 | * @returns {Object} A shifted rect, extended by `relativeY` and `relativeX` properties. | ||
954 | */ | ||
955 | getClientRect: function( el ) { | ||
956 | var rect = el.getClientRect(), | ||
957 | relativeContainerDocPosition = this.container.getDocumentPosition(), | ||
958 | relativeContainerComputedPosition = this.container.getComputedStyle( 'position' ); | ||
959 | |||
960 | // Static or not, those values are used to offset the position of the line so they cannot be undefined. | ||
961 | rect.relativeX = rect.relativeY = 0; | ||
962 | |||
963 | if ( relativeContainerComputedPosition != 'static' ) { | ||
964 | // Remember the offset used to shift the clientRect. | ||
965 | rect.relativeY = relativeContainerDocPosition.y; | ||
966 | rect.relativeX = relativeContainerDocPosition.x; | ||
967 | |||
968 | rect.top -= rect.relativeY; | ||
969 | rect.bottom -= rect.relativeY; | ||
970 | rect.left -= rect.relativeX; | ||
971 | rect.right -= rect.relativeX; | ||
972 | } | ||
973 | |||
974 | return rect; | ||
975 | } | ||
976 | }; | ||
977 | |||
978 | function is( type, flag ) { | ||
979 | return type & flag; | ||
980 | } | ||
981 | |||
982 | var floats = { left: 1, right: 1, center: 1 }, | ||
983 | positions = { absolute: 1, fixed: 1 }; | ||
984 | |||
985 | function isElement( node ) { | ||
986 | return node && node.type == CKEDITOR.NODE_ELEMENT; | ||
987 | } | ||
988 | |||
989 | function isFloated( el ) { | ||
990 | return !!( floats[ el.getComputedStyle( 'float' ) ] || floats[ el.getAttribute( 'align' ) ] ); | ||
991 | } | ||
992 | |||
993 | function isPositioned( el ) { | ||
994 | return !!positions[ el.getComputedStyle( 'position' ) ]; | ||
995 | } | ||
996 | |||
997 | function isLimit( node ) { | ||
998 | return isElement( node ) && node.getAttribute( 'contenteditable' ) == 'true'; | ||
999 | } | ||
1000 | |||
1001 | function isStatic( node ) { | ||
1002 | return isElement( node ) && !isFloated( node ) && !isPositioned( node ); | ||
1003 | } | ||
1004 | |||
1005 | /** | ||
1006 | * Global namespace storing definitions and global helpers for the Line Utilities plugin. | ||
1007 | * | ||
1008 | * @private | ||
1009 | * @class | ||
1010 | * @singleton | ||
1011 | * @since 4.3 | ||
1012 | */ | ||
1013 | CKEDITOR.plugins.lineutils = { | ||
1014 | finder: Finder, | ||
1015 | locator: Locator, | ||
1016 | liner: Liner | ||
1017 | }; | ||
1018 | } )(); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/contents.css b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/contents.css deleted file mode 100644 index c2b51d3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/contents.css +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | .mediumBorder { | ||
2 | border-width: 2px; | ||
3 | } | ||
4 | .thickBorder { | ||
5 | border-width: 5px; | ||
6 | } | ||
7 | img.thickBorder, img.mediumBorder { | ||
8 | border-style: solid; | ||
9 | border-color: #CCC; | ||
10 | } | ||
11 | .important.soMuch { | ||
12 | margin: 25px; | ||
13 | padding: 25px; | ||
14 | background: red; | ||
15 | border: none; | ||
16 | } | ||
17 | |||
18 | span.redMarker { | ||
19 | background-color: red; | ||
20 | } | ||
21 | .invisible { | ||
22 | opacity: 0.1; | ||
23 | } \ No newline at end of file | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/sample.jpg b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/sample.jpg deleted file mode 100644 index a4a77fa..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/sample.jpg +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/contents.css b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/contents.css deleted file mode 100644 index dba3015..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/contents.css +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | .simplebox { | ||
2 | padding: 8px; | ||
3 | margin: 10px; | ||
4 | background: #eee; | ||
5 | border-radius: 8px; | ||
6 | border: 1px solid #ddd; | ||
7 | box-shadow: 0 1px 1px #fff inset, 0 -1px 0px #ccc inset; | ||
8 | } | ||
9 | .simplebox-title, .simplebox-content { | ||
10 | box-shadow: 0 1px 1px #ddd inset; | ||
11 | border: 1px solid #cccccc; | ||
12 | border-radius: 5px; | ||
13 | background: #fff; | ||
14 | } | ||
15 | .simplebox-title { | ||
16 | margin: 0 0 8px; | ||
17 | padding: 5px 8px; | ||
18 | } | ||
19 | .simplebox-content { | ||
20 | padding: 0 8px; | ||
21 | } | ||
22 | .simplebox-content::after { | ||
23 | content: ''; | ||
24 | display: block; | ||
25 | clear: both; | ||
26 | } | ||
27 | .simplebox.align-right { | ||
28 | float: right; | ||
29 | } | ||
30 | .simplebox.align-left { | ||
31 | float: left; | ||
32 | } | ||
33 | .simplebox.align-center { | ||
34 | margin-left: auto; | ||
35 | margin-right: auto; | ||
36 | } \ No newline at end of file | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js deleted file mode 100644 index f0cdb4d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/dialogs/simplebox.js +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | // Note: This automatic widget to dialog window binding (the fact that every field is set up from the widget | ||
2 | // and is committed to the widget) is only possible when the dialog is opened by the Widgets System | ||
3 | // (i.e. the widgetDef.dialog property is set). | ||
4 | // When you are opening the dialog window by yourself, you need to take care of this by yourself too. | ||
5 | |||
6 | CKEDITOR.dialog.add( 'simplebox', function( editor ) { | ||
7 | return { | ||
8 | title: 'Edit Simple Box', | ||
9 | minWidth: 200, | ||
10 | minHeight: 100, | ||
11 | contents: [ | ||
12 | { | ||
13 | id: 'info', | ||
14 | elements: [ | ||
15 | { | ||
16 | id: 'align', | ||
17 | type: 'select', | ||
18 | label: 'Align', | ||
19 | items: [ | ||
20 | [ editor.lang.common.notSet, '' ], | ||
21 | [ editor.lang.common.alignLeft, 'left' ], | ||
22 | [ editor.lang.common.alignRight, 'right' ], | ||
23 | [ editor.lang.common.alignCenter, 'center' ] | ||
24 | ], | ||
25 | // When setting up this field, set its value to the "align" value from widget data. | ||
26 | // Note: Align values used in the widget need to be the same as those defined in the "items" array above. | ||
27 | setup: function( widget ) { | ||
28 | this.setValue( widget.data.align ); | ||
29 | }, | ||
30 | // When committing (saving) this field, set its value to the widget data. | ||
31 | commit: function( widget ) { | ||
32 | widget.setData( 'align', this.getValue() ); | ||
33 | } | ||
34 | }, | ||
35 | { | ||
36 | id: 'width', | ||
37 | type: 'text', | ||
38 | label: 'Width', | ||
39 | width: '50px', | ||
40 | setup: function( widget ) { | ||
41 | this.setValue( widget.data.width ); | ||
42 | }, | ||
43 | commit: function( widget ) { | ||
44 | widget.setData( 'width', this.getValue() ); | ||
45 | } | ||
46 | } | ||
47 | ] | ||
48 | } | ||
49 | ] | ||
50 | }; | ||
51 | } ); \ No newline at end of file | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/icons/simplebox.png b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/icons/simplebox.png deleted file mode 100644 index 6a5e313..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/icons/simplebox.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/plugin.js b/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/plugin.js deleted file mode 100644 index 3e7c99c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/assets/simplebox/plugin.js +++ /dev/null | |||
@@ -1,114 +0,0 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | // Register the plugin within the editor. | ||
4 | CKEDITOR.plugins.add( 'simplebox', { | ||
5 | // This plugin requires the Widgets System defined in the 'widget' plugin. | ||
6 | requires: 'widget,dialog', | ||
7 | |||
8 | // Register the icon used for the toolbar button. It must be the same | ||
9 | // as the name of the widget. | ||
10 | icons: 'simplebox', | ||
11 | |||
12 | // The plugin initialization logic goes inside this method. | ||
13 | init: function( editor ) { | ||
14 | // Register the editing dialog. | ||
15 | CKEDITOR.dialog.add( 'simplebox', this.path + 'dialogs/simplebox.js' ); | ||
16 | |||
17 | // Register the simplebox widget. | ||
18 | editor.widgets.add( 'simplebox', { | ||
19 | // Allow all HTML elements, classes, and styles that this widget requires. | ||
20 | // Read more about the Advanced Content Filter here: | ||
21 | // * http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter | ||
22 | // * http://docs.ckeditor.com/#!/guide/plugin_sdk_integration_with_acf | ||
23 | allowedContent: | ||
24 | 'div(!simplebox,align-left,align-right,align-center){width};' + | ||
25 | 'div(!simplebox-content); h2(!simplebox-title)', | ||
26 | |||
27 | // Minimum HTML which is required by this widget to work. | ||
28 | requiredContent: 'div(simplebox)', | ||
29 | |||
30 | // Define two nested editable areas. | ||
31 | editables: { | ||
32 | title: { | ||
33 | // Define CSS selector used for finding the element inside widget element. | ||
34 | selector: '.simplebox-title', | ||
35 | // Define content allowed in this nested editable. Its content will be | ||
36 | // filtered accordingly and the toolbar will be adjusted when this editable | ||
37 | // is focused. | ||
38 | allowedContent: 'br strong em' | ||
39 | }, | ||
40 | content: { | ||
41 | selector: '.simplebox-content' | ||
42 | } | ||
43 | }, | ||
44 | |||
45 | // Define the template of a new Simple Box widget. | ||
46 | // The template will be used when creating new instances of the Simple Box widget. | ||
47 | template: | ||
48 | '<div class="simplebox">' + | ||
49 | '<h2 class="simplebox-title">Title</h2>' + | ||
50 | '<div class="simplebox-content"><p>Content...</p></div>' + | ||
51 | '</div>', | ||
52 | |||
53 | // Define the label for a widget toolbar button which will be automatically | ||
54 | // created by the Widgets System. This button will insert a new widget instance | ||
55 | // created from the template defined above, or will edit selected widget | ||
56 | // (see second part of this tutorial to learn about editing widgets). | ||
57 | // | ||
58 | // Note: In order to be able to translate your widget you should use the | ||
59 | // editor.lang.simplebox.* property. A string was used directly here to simplify this tutorial. | ||
60 | button: 'Create a simple box', | ||
61 | |||
62 | // Set the widget dialog window name. This enables the automatic widget-dialog binding. | ||
63 | // This dialog window will be opened when creating a new widget or editing an existing one. | ||
64 | dialog: 'simplebox', | ||
65 | |||
66 | // Check the elements that need to be converted to widgets. | ||
67 | // | ||
68 | // Note: The "element" argument is an instance of http://docs.ckeditor.com/#!/api/CKEDITOR.htmlParser.element | ||
69 | // so it is not a real DOM element yet. This is caused by the fact that upcasting is performed | ||
70 | // during data processing which is done on DOM represented by JavaScript objects. | ||
71 | upcast: function( element ) { | ||
72 | // Return "true" (that element needs to converted to a Simple Box widget) | ||
73 | // for all <div> elements with a "simplebox" class. | ||
74 | return element.name == 'div' && element.hasClass( 'simplebox' ); | ||
75 | }, | ||
76 | |||
77 | // When a widget is being initialized, we need to read the data ("align" and "width") | ||
78 | // from DOM and set it by using the widget.setData() method. | ||
79 | // More code which needs to be executed when DOM is available may go here. | ||
80 | init: function() { | ||
81 | var width = this.element.getStyle( 'width' ); | ||
82 | if ( width ) | ||
83 | this.setData( 'width', width ); | ||
84 | |||
85 | if ( this.element.hasClass( 'align-left' ) ) | ||
86 | this.setData( 'align', 'left' ); | ||
87 | if ( this.element.hasClass( 'align-right' ) ) | ||
88 | this.setData( 'align', 'right' ); | ||
89 | if ( this.element.hasClass( 'align-center' ) ) | ||
90 | this.setData( 'align', 'center' ); | ||
91 | }, | ||
92 | |||
93 | // Listen on the widget#data event which is fired every time the widget data changes | ||
94 | // and updates the widget's view. | ||
95 | // Data may be changed by using the widget.setData() method, which we use in the | ||
96 | // Simple Box dialog window. | ||
97 | data: function() { | ||
98 | // Check whether "width" widget data is set and remove or set "width" CSS style. | ||
99 | // The style is set on widget main element (div.simplebox). | ||
100 | if ( !this.data.width ) | ||
101 | this.element.removeStyle( 'width' ); | ||
102 | else | ||
103 | this.element.setStyle( 'width', this.data.width ); | ||
104 | |||
105 | // Brutally remove all align classes and set a new one if "align" widget data is set. | ||
106 | this.element.removeClass( 'align-left' ); | ||
107 | this.element.removeClass( 'align-right' ); | ||
108 | this.element.removeClass( 'align-center' ); | ||
109 | if ( this.data.align ) | ||
110 | this.element.addClass( 'align-' + this.data.align ); | ||
111 | } | ||
112 | } ); | ||
113 | } | ||
114 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/console.js b/app/assets/javascripts/ckeditor/plugins/widget/dev/console.js deleted file mode 100644 index 1404a2c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/console.js +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /* global CKCONSOLE */ | ||
7 | |||
8 | 'use strict'; | ||
9 | |||
10 | ( function() { | ||
11 | |||
12 | CKCONSOLE.add( 'widget', { | ||
13 | panels: [ | ||
14 | { | ||
15 | type: 'box', | ||
16 | content: '<ul class="ckconsole_list ckconsole_value" data-value="instances"></ul>', | ||
17 | |||
18 | refresh: function( editor ) { | ||
19 | var instances = obj2Array( editor.widgets.instances ); | ||
20 | |||
21 | return { | ||
22 | header: 'Instances (' + instances.length + ')', | ||
23 | instances: generateInstancesList( instances ) | ||
24 | }; | ||
25 | }, | ||
26 | |||
27 | refreshOn: function( editor, refresh ) { | ||
28 | editor.widgets.on( 'instanceCreated', function( evt ) { | ||
29 | refresh(); | ||
30 | |||
31 | evt.data.on( 'data', refresh ); | ||
32 | } ); | ||
33 | |||
34 | editor.widgets.on( 'instanceDestroyed', refresh ); | ||
35 | } | ||
36 | }, | ||
37 | |||
38 | { | ||
39 | type: 'box', | ||
40 | content: | ||
41 | '<ul class="ckconsole_list">' + | ||
42 | '<li>focused: <span class="ckconsole_value" data-value="focused"></span></li>' + | ||
43 | '<li>selected: <span class="ckconsole_value" data-value="selected"></span></li>' + | ||
44 | '</ul>', | ||
45 | |||
46 | refresh: function( editor ) { | ||
47 | var focused = editor.widgets.focused, | ||
48 | selected = editor.widgets.selected, | ||
49 | selectedIds = []; | ||
50 | |||
51 | for ( var i = 0; i < selected.length; ++i ) | ||
52 | selectedIds.push( selected[ i ].id ); | ||
53 | |||
54 | return { | ||
55 | header: 'Focus & selection', | ||
56 | focused: focused ? 'id: ' + focused.id : '-', | ||
57 | selected: selectedIds.length ? 'id: ' + selectedIds.join( ', id: ' ) : '-' | ||
58 | }; | ||
59 | }, | ||
60 | |||
61 | refreshOn: function( editor, refresh ) { | ||
62 | editor.on( 'selectionCheck', refresh, null, null, 999 ); | ||
63 | } | ||
64 | }, | ||
65 | |||
66 | { | ||
67 | type: 'log', | ||
68 | |||
69 | on: function( editor, log, logFn ) { | ||
70 | // Add all listeners with high priorities to log | ||
71 | // messages in the correct order when one event depends on another. | ||
72 | // E.g. selectionChange triggers widget selection - if this listener | ||
73 | // for selectionChange will be executed later than that one, then order | ||
74 | // will be incorrect. | ||
75 | |||
76 | editor.on( 'selectionChange', function( evt ) { | ||
77 | var msg = 'selection change', | ||
78 | sel = evt.data.selection, | ||
79 | el = sel.getSelectedElement(), | ||
80 | widget; | ||
81 | |||
82 | if ( el && ( widget = editor.widgets.getByElement( el, true ) ) ) | ||
83 | msg += ' (id: ' + widget.id + ')'; | ||
84 | |||
85 | log( msg ); | ||
86 | }, null, null, 1 ); | ||
87 | |||
88 | editor.widgets.on( 'instanceDestroyed', function( evt ) { | ||
89 | log( 'instance destroyed (id: ' + evt.data.id + ')' ); | ||
90 | }, null, null, 1 ); | ||
91 | |||
92 | editor.widgets.on( 'instanceCreated', function( evt ) { | ||
93 | log( 'instance created (id: ' + evt.data.id + ')' ); | ||
94 | }, null, null, 1 ); | ||
95 | |||
96 | editor.widgets.on( 'widgetFocused', function( evt ) { | ||
97 | log( 'widget focused (id: ' + evt.data.widget.id + ')' ); | ||
98 | }, null, null, 1 ); | ||
99 | |||
100 | editor.widgets.on( 'widgetBlurred', function( evt ) { | ||
101 | log( 'widget blurred (id: ' + evt.data.widget.id + ')' ); | ||
102 | }, null, null, 1 ); | ||
103 | |||
104 | editor.widgets.on( 'checkWidgets', logFn( 'checking widgets' ), null, null, 1 ); | ||
105 | editor.widgets.on( 'checkSelection', logFn( 'checking selection' ), null, null, 1 ); | ||
106 | } | ||
107 | } | ||
108 | ] | ||
109 | } ); | ||
110 | |||
111 | function generateInstancesList( instances ) { | ||
112 | var html = '', | ||
113 | instance; | ||
114 | |||
115 | for ( var i = 0; i < instances.length; ++i ) { | ||
116 | instance = instances[ i ]; | ||
117 | html += itemTpl.output( { id: instance.id, name: instance.name, data: JSON.stringify( instance.data ) } ); | ||
118 | } | ||
119 | return html; | ||
120 | } | ||
121 | |||
122 | function obj2Array( obj ) { | ||
123 | var arr = []; | ||
124 | for ( var id in obj ) | ||
125 | arr.push( obj[ id ] ); | ||
126 | |||
127 | return arr; | ||
128 | } | ||
129 | |||
130 | var itemTpl = new CKEDITOR.template( '<li>id: <code>{id}</code>, name: <code>{name}</code>, data: <code>{data}</code></li>' ); | ||
131 | } )(); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/nestedwidgets.html b/app/assets/javascripts/ckeditor/plugins/widget/dev/nestedwidgets.html deleted file mode 100644 index 0bc998b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/nestedwidgets.html +++ /dev/null | |||
@@ -1,134 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>Nested widgets — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <script src="../../../dev/console/console.js"></script> | ||
12 | <script src="../../../dev/console/focusconsole.js"></script> | ||
13 | <script src="console.js"></script> | ||
14 | <link rel="stylesheet" href="../../../samples/old/sample.css"> | ||
15 | <link rel="stylesheet" href="../../../contents.css"> | ||
16 | <link rel="stylesheet" href="assets/simplebox/contents.css"> | ||
17 | </head> | ||
18 | <body> | ||
19 | <h1 class="samples">Nested widgets</h1> | ||
20 | |||
21 | <h2>Classic (iframe-based) Sample</h2> | ||
22 | <textarea cols="80" id="editor1" name="editor1" rows="10"> | ||
23 | <h1>Simple Box Sample</h1> | ||
24 | |||
25 | <div class="simplebox align-right" style="width: 60%"> | ||
26 | <h2 class="simplebox-title">Title</h2> | ||
27 | <div class="simplebox-content"> | ||
28 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
29 | |||
30 | <figure class="image" style="float: right"> | ||
31 | <img alt="The Eagle" src="assets/sample.jpg" width="150" /> | ||
32 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
33 | </figure> | ||
34 | |||
35 | <ul> | ||
36 | <li>Foo!</li> | ||
37 | <li>Bar!</li> | ||
38 | </ul> | ||
39 | |||
40 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
41 | </div> | ||
42 | </div> | ||
43 | |||
44 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
45 | |||
46 | <p>Pellentesque vitae eleifend nisl, non accumsan tellus. Maecenas nec libero non tellus tincidunt mollis porttitor sed arcu. Donec ultricies nulla vitae eros lacinia, vel congue sem auctor. Vivamus convallis, urna ac tincidunt malesuada, lectus erat convallis metus, a hendrerit massa augue accumsan magna. Nulla mattis tellus elit, nec congue magna scelerisque eget. Aliquam posuere nisi augue, posuere sodales nisi iaculis eu. Donec fermentum urna id nibh sagittis fermentum sit amet sed enim. Aliquam neque elit, pretium elementum nunc a, faucibus accumsan lorem. Etiam pulvinar odio et hendrerit tincidunt. Suspendisse tempus eros lacus, in convallis velit mollis ut. Aenean congue, justo eleifend ultricies malesuada, nunc nunc molestie mauris, eget placerat libero eros vel nisi. Quisque diam arcu, mollis ac laoreet vitae, varius et sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis in vehicula sapien. Nunc feugiat porta elit nec volutpat.</p> | ||
47 | |||
48 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
49 | |||
50 | <div class="simplebox align-center" style="width: 750px"> | ||
51 | <h2 class="simplebox-title">Title</h2> | ||
52 | <div class="simplebox-content"> | ||
53 | <p><img alt="The Eagle" src="assets/sample.jpg" width="150" style="float: left" /><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
54 | |||
55 | <ul> | ||
56 | <li>Foo!</li> | ||
57 | <li>Bar!</li> | ||
58 | </ul> | ||
59 | </div> | ||
60 | </div> | ||
61 | |||
62 | <p>Ut eget ipsum a sapien porta ultrices. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus mi lacus, pharetra eu bibendum blandit, tristique sit amet leo. Integer eu nulla nec magna vulputate blandit. Praesent mattis quis ante eget adipiscing. Nulla vel tempus risus, in placerat velit. Mauris sed nibh at elit posuere laoreet. Morbi non sapien sed nunc fringilla imperdiet.</p> | ||
63 | </textarea> | ||
64 | |||
65 | <h2>Inline Sample</h2> | ||
66 | <div id="editor2" contenteditable="true"> | ||
67 | <h1>Simple Box Sample</h1> | ||
68 | |||
69 | <div class="simplebox align-right" style="width: 60%"> | ||
70 | <h2 class="simplebox-title">Title</h2> | ||
71 | <div class="simplebox-content"> | ||
72 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
73 | |||
74 | <figure class="image" style="float: right"> | ||
75 | <img alt="The Eagle" src="assets/sample.jpg" width="150" /> | ||
76 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
77 | </figure> | ||
78 | |||
79 | <ul> | ||
80 | <li>Foo!</li> | ||
81 | <li>Bar!</li> | ||
82 | </ul> | ||
83 | |||
84 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
85 | </div> | ||
86 | </div> | ||
87 | |||
88 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
89 | |||
90 | <p>Pellentesque vitae eleifend nisl, non accumsan tellus. Maecenas nec libero non tellus tincidunt mollis porttitor sed arcu. Donec ultricies nulla vitae eros lacinia, vel congue sem auctor. Vivamus convallis, urna ac tincidunt malesuada, lectus erat convallis metus, a hendrerit massa augue accumsan magna. Nulla mattis tellus elit, nec congue magna scelerisque eget. Aliquam posuere nisi augue, posuere sodales nisi iaculis eu. Donec fermentum urna id nibh sagittis fermentum sit amet sed enim. Aliquam neque elit, pretium elementum nunc a, faucibus accumsan lorem. Etiam pulvinar odio et hendrerit tincidunt. Suspendisse tempus eros lacus, in convallis velit mollis ut. Aenean congue, justo eleifend ultricies malesuada, nunc nunc molestie mauris, eget placerat libero eros vel nisi. Quisque diam arcu, mollis ac laoreet vitae, varius et sem. Interdum et malesuada fames ac ante ipsum primis in faucibus. Duis in vehicula sapien. Nunc feugiat porta elit nec volutpat.</p> | ||
91 | |||
92 | <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sit amet orci ut nisi adipiscing ultrices. Sed pellentesque iaculis malesuada. Pellentesque scelerisque, purus non porta dictum, neque urna bibendum dolor, eget tristique ipsum metus fringilla dolor. Nullam sed accumsan sapien. Vestibulum in placerat magna. Sed justo lacus, volutpat rhoncus odio luctus, ornare adipiscing mauris. Vivamus erat sem, egestas et lectus eget, varius cursus odio. Duis posuere lacus sit amet urna bibendum, id iaculis eros ultrices. Vestibulum a ultrices ante.</p> | ||
93 | |||
94 | <div class="simplebox align-center" style="width: 750px"> | ||
95 | <h2 class="simplebox-title">Title</h2> | ||
96 | <div class="simplebox-content"> | ||
97 | <p><img alt="The Eagle" src="assets/sample.jpg" width="150" style="float: left" /><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
98 | |||
99 | <ul> | ||
100 | <li>Foo!</li> | ||
101 | <li>Bar!</li> | ||
102 | </ul> | ||
103 | </div> | ||
104 | </div> | ||
105 | |||
106 | <p>Ut eget ipsum a sapien porta ultrices. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus mi lacus, pharetra eu bibendum blandit, tristique sit amet leo. Integer eu nulla nec magna vulputate blandit. Praesent mattis quis ante eget adipiscing. Nulla vel tempus risus, in placerat velit. Mauris sed nibh at elit posuere laoreet. Morbi non sapien sed nunc fringilla imperdiet.</p> | ||
107 | </div> | ||
108 | |||
109 | <script> | ||
110 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | ||
111 | CKEDITOR.tools.enableHtml5Elements( document ); | ||
112 | |||
113 | CKEDITOR.plugins.addExternal( 'simplebox', 'plugins/widget/dev/assets/simplebox/' ); | ||
114 | |||
115 | CKEDITOR.replace( 'editor1', { | ||
116 | extraPlugins: 'simplebox,placeholder,image2', | ||
117 | removePlugins: 'forms,bidi', | ||
118 | contentsCss: [ '../../../contents.css', 'assets/simplebox/contents.css' ], | ||
119 | height: 500 | ||
120 | } ); | ||
121 | |||
122 | CKEDITOR.inline( 'editor2', { | ||
123 | extraPlugins: 'simplebox,placeholder,image2', | ||
124 | removePlugins: 'forms,bidi' | ||
125 | } ); | ||
126 | |||
127 | CKCONSOLE.create( 'widget', { editor: 'editor1' } ); | ||
128 | CKCONSOLE.create( 'focus', { editor: 'editor1' } ); | ||
129 | CKCONSOLE.create( 'widget', { editor: 'editor2', folded: true } ); | ||
130 | CKCONSOLE.create( 'focus', { editor: 'editor2', folded: true } ); | ||
131 | |||
132 | </script> | ||
133 | </body> | ||
134 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/dev/widgetstyles.html b/app/assets/javascripts/ckeditor/plugins/widget/dev/widgetstyles.html deleted file mode 100644 index da58e44..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/dev/widgetstyles.html +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <!-- | ||
3 | Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. | ||
4 | For licensing, see LICENSE.md or http://ckeditor.com/license | ||
5 | --> | ||
6 | <html> | ||
7 | <head> | ||
8 | <meta charset="utf-8"> | ||
9 | <title>Applying styles to widgets — CKEditor Sample</title> | ||
10 | <script src="../../../ckeditor.js"></script> | ||
11 | <link rel="stylesheet" href="../../../samples/old/sample.css"> | ||
12 | <link rel="stylesheet" href="../../../contents.css"> | ||
13 | <link rel="stylesheet" href="assets/contents.css"> | ||
14 | </head> | ||
15 | <body> | ||
16 | <h1 class="samples">Applying styles to widgets</h1> | ||
17 | |||
18 | <h2>Classic (iframe-based) Sample</h2> | ||
19 | <textarea cols="80" id="editor1" name="editor1" rows="10"> | ||
20 | <h1>Apollo 11</h1> | ||
21 | |||
22 | <figure class="image" style="float: right"> | ||
23 | <img alt="Saturn V" src="../../../samples/assets/sample.jpg" width="150" /> | ||
24 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
25 | </figure> | ||
26 | |||
27 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
28 | |||
29 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
30 | |||
31 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
32 | |||
33 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
34 | |||
35 | <blockquote> | ||
36 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
37 | </blockquote> | ||
38 | |||
39 | <p><span class="math-tex">\( \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \)</span></p> | ||
40 | |||
41 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
42 | |||
43 | <blockquote> | ||
44 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
45 | </blockquote> | ||
46 | |||
47 | <figure class="image" style="float: right"> | ||
48 | <img alt="The Eagle" src="../../../samples/assets/sample.jpg" width="150" /> | ||
49 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
50 | </figure> | ||
51 | |||
52 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
53 | |||
54 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
55 | |||
56 | <ol> | ||
57 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
58 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
59 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
60 | </ol> | ||
61 | |||
62 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
63 | </textarea> | ||
64 | |||
65 | <h2>Inline Sample</h2> | ||
66 | <div id="editor2" contenteditable="true"> | ||
67 | <h1>Apollo 11</h1> | ||
68 | |||
69 | <figure class="image" style="float: right"> | ||
70 | <img alt="Saturn V" src="../../../samples/assets/sample.jpg" width="150" /> | ||
71 | <figcaption>Roll out of Saturn V on launch pad</figcaption> | ||
72 | </figure> | ||
73 | |||
74 | <p><strong>Apollo 11</strong> was the spaceflight that landed the first humans, Americans <a href="http://en.wikipedia.org/wiki/Neil_Armstrong" title="Neil Armstrong">Neil Armstrong</a> and <a href="http://en.wikipedia.org/wiki/Buzz_Aldrin" title="Buzz Aldrin">Buzz Aldrin</a>, on the Moon on [[July 20, 1969, at 20:18 UTC]]. Armstrong became the first to step onto the lunar surface 6 hours later on [[July 21 at 02:56 UTC]].</p> | ||
75 | |||
76 | <p>Armstrong spent about <s>three and a half</s> two and a half hours outside the spacecraft, Aldrin slightly less; and together they collected 47.5 pounds (21.5 kg) of lunar material for return to Earth. A third member of the mission, <a href="http://en.wikipedia.org/wiki/Michael_Collins_(astronaut)" title="Michael Collins (astronaut)">Michael Collins</a>, piloted the <a href="http://en.wikipedia.org/wiki/Apollo_Command/Service_Module" title="Apollo Command/Service Module">command</a> spacecraft alone in lunar orbit until Armstrong and Aldrin returned to it for the trip back to Earth.</p> | ||
77 | |||
78 | <h2>Broadcasting and <em>quotes</em> <a id="quotes" name="quotes"></a></h2> | ||
79 | |||
80 | <p>Broadcast on live TV to a world-wide audience, Armstrong stepped onto the lunar surface and described the event as:</p> | ||
81 | |||
82 | <blockquote> | ||
83 | <p>One small step for [a] man, one giant leap for mankind.</p> | ||
84 | </blockquote> | ||
85 | |||
86 | <p><span class="math-tex">\( \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right) \)</span></p> | ||
87 | |||
88 | <p>Apollo 11 effectively ended the <a href="http://en.wikipedia.org/wiki/Space_Race" title="Space Race">Space Race</a> and fulfilled a national goal proposed in 1961 by the late U.S. President <a href="http://en.wikipedia.org/wiki/John_F._Kennedy" title="John F. Kennedy">John F. Kennedy</a> in a speech before the United States Congress:</p> | ||
89 | |||
90 | <blockquote> | ||
91 | <p>[...] before this decade is out, of landing a man on the Moon and returning him safely to the Earth.</p> | ||
92 | </blockquote> | ||
93 | |||
94 | <figure class="image" style="float: right"> | ||
95 | <img alt="The Eagle" src="../../../samples/assets/sample.jpg" width="150" /> | ||
96 | <figcaption>The Eagle in lunar orbit</figcaption> | ||
97 | </figure> | ||
98 | |||
99 | <h2>Technical details <a id="tech-details" name="tech-details"></a></h2> | ||
100 | |||
101 | <p>Launched by a <strong>Saturn V</strong> rocket from <a href="http://en.wikipedia.org/wiki/Kennedy_Space_Center" title="Kennedy Space Center">Kennedy Space Center</a> in Merritt Island, Florida on July 16, Apollo 11 was the fifth manned mission of <a href="http://en.wikipedia.org/wiki/NASA" title="NASA">NASA</a>'s Apollo program. The Apollo spacecraft had three parts:</p> | ||
102 | |||
103 | <ol> | ||
104 | <li><strong>Command Module</strong> with a cabin for the three astronauts which was the only part which landed back on Earth</li> | ||
105 | <li><strong>Service Module</strong> which supported the Command Module with propulsion, electrical power, oxygen and water</li> | ||
106 | <li><strong>Lunar Module</strong> for landing on the Moon.</li> | ||
107 | </ol> | ||
108 | |||
109 | <p>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 <a href="http://en.wikipedia.org/wiki/Mare_Tranquillitatis" title="Mare Tranquillitatis">Sea of Tranquility</a>. They stayed a total of about 21 and a half hours on the lunar surface. After lifting off in the upper part of the Lunar Module and rejoining Collins in the Command Module, they returned to Earth and landed in the <a href="http://en.wikipedia.org/wiki/Pacific_Ocean" title="Pacific Ocean">Pacific Ocean</a> on July 24.</p> | ||
110 | </div> | ||
111 | |||
112 | <script> | ||
113 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) | ||
114 | CKEDITOR.tools.enableHtml5Elements( document ); | ||
115 | |||
116 | CKEDITOR.disableAutoInline = true; | ||
117 | |||
118 | var stylesSet = [ | ||
119 | { name: 'Medium border', type: 'widget', widget: 'image', attributes: { 'class': 'mediumBorder' } }, | ||
120 | { name: 'Thick border', type: 'widget', widget: 'image', attributes: { 'class': 'thickBorder' } }, | ||
121 | { name: 'So important', type: 'widget', widget: 'image', attributes: { 'class': 'important soMuch' } }, | ||
122 | |||
123 | { name: 'Red marker', type: 'widget', widget: 'placeholder', attributes: { 'class': 'redMarker' } }, | ||
124 | { name: 'Invisible Placeholder', type: 'widget', widget: 'placeholder', attributes: { 'class': 'invisible' } }, | ||
125 | |||
126 | { name: 'Invisible Mathjax', type: 'widget', widget: 'mathjax', attributes: { 'class': 'invisible' } } | ||
127 | ]; | ||
128 | |||
129 | CKEDITOR.replace( 'editor1', { | ||
130 | extraPlugins: 'placeholder,image2,mathjax', | ||
131 | contentsCss: [ '../../../contents.css', 'assets/contents.css' ], | ||
132 | stylesSet: stylesSet, | ||
133 | height: 300 | ||
134 | } ); | ||
135 | |||
136 | CKEDITOR.inline( 'editor2', { | ||
137 | extraPlugins: 'placeholder,image2,mathjax', | ||
138 | stylesSet: stylesSet, | ||
139 | height: 300 | ||
140 | } ); | ||
141 | |||
142 | </script> | ||
143 | </body> | ||
144 | </html> | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/images/handle.png b/app/assets/javascripts/ckeditor/plugins/widget/images/handle.png deleted file mode 100644 index ba8cda5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/images/handle.png +++ /dev/null | |||
Binary files differ | |||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/af.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/af.js deleted file mode 100644 index c05e1b1..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/af.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'af', { | ||
6 | 'move': 'Klik en trek on te beweeg', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ar.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ar.js deleted file mode 100644 index f53676a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ar.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ar', { | ||
6 | 'move': 'إضغط و إسحب للتحريك', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/az.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/az.js deleted file mode 100644 index ed7d2e5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/az.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'az', { | ||
6 | 'move': 'Tıklayın və aparın', | ||
7 | 'label': '%1 vidjet' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/bg.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/bg.js deleted file mode 100644 index 8b1ad01..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/bg.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'bg', { | ||
6 | 'move': 'Кликни и влачи, за да преместиш', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ca.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ca.js deleted file mode 100644 index 7572f0e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ca.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ca', { | ||
6 | 'move': 'Clicar i arrossegar per moure', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/cs.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/cs.js deleted file mode 100644 index ba16149..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/cs.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'cs', { | ||
6 | 'move': 'Klepněte a táhněte pro přesunutí', | ||
7 | 'label': 'Ovládací prvek %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/cy.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/cy.js deleted file mode 100644 index 9bbc89a..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/cy.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'cy', { | ||
6 | 'move': 'Clcio a llusgo i symud', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/da.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/da.js deleted file mode 100644 index a6a1bb7..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/da.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'da', { | ||
6 | 'move': 'Klik og træk for at flytte', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/de-ch.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/de-ch.js deleted file mode 100644 index d409bb6..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/de-ch.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'de-ch', { | ||
6 | 'move': 'Zum Verschieben anwählen und ziehen', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/de.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/de.js deleted file mode 100644 index eb05fb8..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/de.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'de', { | ||
6 | 'move': 'Zum Verschieben anwählen und ziehen', | ||
7 | 'label': '%1 Steuerelement' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/el.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/el.js deleted file mode 100644 index 4ea9504..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/el.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'el', { | ||
6 | 'move': 'Κάνετε κλικ και σύρετε το ποντίκι για να μετακινήστε', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/en-gb.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/en-gb.js deleted file mode 100644 index ad1a209..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/en-gb.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'en-gb', { | ||
6 | 'move': 'Click and drag to move', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/en.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/en.js deleted file mode 100644 index d2a43cb..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/en.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'en', { | ||
6 | 'move': 'Click and drag to move', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/eo.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/eo.js deleted file mode 100644 index 5801514..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/eo.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'eo', { | ||
6 | 'move': 'klaki kaj treni por movi', | ||
7 | 'label': '%1 fenestraĵo' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/es-mx.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/es-mx.js deleted file mode 100644 index 028901d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/es-mx.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'es-mx', { | ||
6 | 'move': 'Presiona y arrastra para mover', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/es.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/es.js deleted file mode 100644 index 89d1639..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/es.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'es', { | ||
6 | 'move': 'Dar clic y arrastrar para mover', | ||
7 | 'label': 'reproductor %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/eu.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/eu.js deleted file mode 100644 index 5a3d126..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/eu.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'eu', { | ||
6 | 'move': 'Klikatu eta arrastatu lekuz aldatzeko', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/fa.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/fa.js deleted file mode 100644 index 16c27bf..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/fa.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'fa', { | ||
6 | 'move': 'کلیک و کشیدن برای جابجایی', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/fi.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/fi.js deleted file mode 100644 index a4d6e2f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/fi.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'fi', { | ||
6 | 'move': 'Siirrä klikkaamalla ja raahaamalla', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/fr.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/fr.js deleted file mode 100644 index f7f87e8..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/fr.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'fr', { | ||
6 | 'move': 'Cliquer et glisser pour déplacer', | ||
7 | 'label': 'Élément %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/gl.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/gl.js deleted file mode 100644 index a480371..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/gl.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'gl', { | ||
6 | 'move': 'Prema e arrastre para mover', | ||
7 | 'label': 'Trebello %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/he.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/he.js deleted file mode 100644 index 08da4df..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/he.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'he', { | ||
6 | 'move': 'לחץ וגרור להזזה', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/hr.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/hr.js deleted file mode 100644 index c0b8b31..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/hr.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'hr', { | ||
6 | 'move': 'Klikni i povuci za pomicanje', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/hu.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/hu.js deleted file mode 100644 index 597e11d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/hu.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'hu', { | ||
6 | 'move': 'Kattints és húzd a mozgatáshoz', | ||
7 | 'label': '%1 modul' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/id.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/id.js deleted file mode 100644 index b1cf39b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/id.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'id', { | ||
6 | 'move': 'Tekan dan geser untuk memindahkan', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/it.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/it.js deleted file mode 100644 index 707481f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/it.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'it', { | ||
6 | 'move': 'Fare clic e trascinare per spostare', | ||
7 | 'label': 'Widget %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ja.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ja.js deleted file mode 100644 index 7c329d0..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ja.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ja', { | ||
6 | 'move': 'ドラッグして移動', | ||
7 | 'label': '%1 ウィジェット' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/km.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/km.js deleted file mode 100644 index 08ec7aa..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/km.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'km', { | ||
6 | 'move': 'ចុចហើយទាញដើម្បីផ្លាស់ទី', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ko.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ko.js deleted file mode 100644 index 8c62287..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ko.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ko', { | ||
6 | 'move': '움직이려면 클릭 후 드래그 하세요', | ||
7 | 'label': '%1 위젯' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ku.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ku.js deleted file mode 100644 index 2ff829b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ku.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ku', { | ||
6 | 'move': 'کرتەبکە و ڕایبکێشە بۆ جوڵاندن', | ||
7 | 'label': '%1 ویجێت' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/lv.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/lv.js deleted file mode 100644 index de6167b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/lv.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'lv', { | ||
6 | 'move': 'Klikšķina un velc, lai pārvietotu', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/nb.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/nb.js deleted file mode 100644 index dfba027..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/nb.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'nb', { | ||
6 | 'move': 'Klikk og dra for å flytte', | ||
7 | 'label': 'Widget %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/nl.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/nl.js deleted file mode 100644 index 188f48c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/nl.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'nl', { | ||
6 | 'move': 'Klik en sleep om te verplaatsen', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/no.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/no.js deleted file mode 100644 index 62a93d9..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/no.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'no', { | ||
6 | 'move': 'Klikk og dra for å flytte', | ||
7 | 'label': 'Widget %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/oc.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/oc.js deleted file mode 100644 index 6a559e0..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/oc.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'oc', { | ||
6 | 'move': 'Clicar e lisar per desplaçar', | ||
7 | 'label': 'Element %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/pl.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/pl.js deleted file mode 100644 index 6486765..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/pl.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'pl', { | ||
6 | 'move': 'Kliknij i przeciągnij, by przenieść.', | ||
7 | 'label': 'Widget %1' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/pt-br.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/pt-br.js deleted file mode 100644 index 7f44722..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/pt-br.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'pt-br', { | ||
6 | 'move': 'Click e arraste para mover', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/pt.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/pt.js deleted file mode 100644 index 97ada9d..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/pt.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'pt', { | ||
6 | 'move': 'Clique e arraste para mover', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ru.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ru.js deleted file mode 100644 index 68d612b..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ru.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ru', { | ||
6 | 'move': 'Нажмите и перетащите, чтобы переместить', | ||
7 | 'label': '%1 виджет' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/sk.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/sk.js deleted file mode 100644 index cd75ecb..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/sk.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'sk', { | ||
6 | 'move': 'Kliknite a potiahnite pre presunutie', | ||
7 | 'label': '%1 widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/sl.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/sl.js deleted file mode 100644 index 64b8ae5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/sl.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'sl', { | ||
6 | 'move': 'Kliknite in povlecite, da premaknete', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/sq.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/sq.js deleted file mode 100644 index 4c725c3..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/sq.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'sq', { | ||
6 | 'move': 'Kliko dhe tërhiqe për ta lëvizur', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/sv.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/sv.js deleted file mode 100644 index a7e228f..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/sv.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'sv', { | ||
6 | 'move': 'Klicka och drag för att flytta', | ||
7 | 'label': '%1-widget' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/tr.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/tr.js deleted file mode 100644 index f25b1ea..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/tr.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'tr', { | ||
6 | 'move': 'Taşımak için, tıklayın ve sürükleyin', | ||
7 | 'label': '%1 Grafik Beleşeni' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/tt.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/tt.js deleted file mode 100644 index 1772db5..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/tt.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'tt', { | ||
6 | 'move': 'Күчереп куер өчен басып шудырыгыз', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/ug.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/ug.js deleted file mode 100644 index 9f39366..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/ug.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'ug', { | ||
6 | 'move': 'يۆتكەشتە چېكىپ سۆرەڭ', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/uk.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/uk.js deleted file mode 100644 index 4eb2d2e..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/uk.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'uk', { | ||
6 | 'move': 'Клікніть і потягніть для переміщення', | ||
7 | 'label': '%1 віджет' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/vi.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/vi.js deleted file mode 100644 index 76f5680..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/vi.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'vi', { | ||
6 | 'move': 'Nhấp chuột và kéo để di chuyển', | ||
7 | 'label': '%1 widget' // MISSING | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/zh-cn.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/zh-cn.js deleted file mode 100644 index 93f393c..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/zh-cn.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'zh-cn', { | ||
6 | 'move': '点击并拖拽以移动', | ||
7 | 'label': '%1 小部件' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/lang/zh.js b/app/assets/javascripts/ckeditor/plugins/widget/lang/zh.js deleted file mode 100644 index a89a616..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/lang/zh.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | CKEDITOR.plugins.setLang( 'widget', 'zh', { | ||
6 | 'move': '拖曳以移動', | ||
7 | 'label': '%1 小工具' | ||
8 | } ); | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widget/plugin.js b/app/assets/javascripts/ckeditor/plugins/widget/plugin.js deleted file mode 100644 index fbed1bf..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widget/plugin.js +++ /dev/null | |||
@@ -1,4126 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview [Widget](http://ckeditor.com/addon/widget) plugin. | ||
8 | */ | ||
9 | |||
10 | 'use strict'; | ||
11 | |||
12 | ( function() { | ||
13 | var DRAG_HANDLER_SIZE = 15; | ||
14 | |||
15 | CKEDITOR.plugins.add( 'widget', { | ||
16 | // jscs:disable maximumLineLength | ||
17 | lang: 'af,ar,az,bg,ca,cs,cy,da,de,de-ch,el,en,en-gb,eo,es,es-mx,eu,fa,fi,fr,gl,he,hr,hu,id,it,ja,km,ko,ku,lv,nb,nl,no,oc,pl,pt,pt-br,ru,sk,sl,sq,sv,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE% | ||
18 | // jscs:enable maximumLineLength | ||
19 | requires: 'lineutils,clipboard,widgetselection', | ||
20 | onLoad: function() { | ||
21 | CKEDITOR.addCss( | ||
22 | '.cke_widget_wrapper{' + | ||
23 | 'position:relative;' + | ||
24 | 'outline:none' + | ||
25 | '}' + | ||
26 | '.cke_widget_inline{' + | ||
27 | 'display:inline-block' + | ||
28 | '}' + | ||
29 | '.cke_widget_wrapper:hover>.cke_widget_element{' + | ||
30 | 'outline:2px solid yellow;' + | ||
31 | 'cursor:default' + | ||
32 | '}' + | ||
33 | '.cke_widget_wrapper:hover .cke_widget_editable{' + | ||
34 | 'outline:2px solid yellow' + | ||
35 | '}' + | ||
36 | '.cke_widget_wrapper.cke_widget_focused>.cke_widget_element,' + | ||
37 | // We need higher specificity than hover style. | ||
38 | '.cke_widget_wrapper .cke_widget_editable.cke_widget_editable_focused{' + | ||
39 | 'outline:2px solid #ace' + | ||
40 | '}' + | ||
41 | '.cke_widget_editable{' + | ||
42 | 'cursor:text' + | ||
43 | '}' + | ||
44 | '.cke_widget_drag_handler_container{' + | ||
45 | 'position:absolute;' + | ||
46 | 'width:' + DRAG_HANDLER_SIZE + 'px;' + | ||
47 | 'height:0;' + | ||
48 | // Initially drag handler should not be visible, until its position will be | ||
49 | // calculated (http://dev.ckeditor.com/ticket/11177). | ||
50 | // We need to hide unpositined handlers, so they don't extend | ||
51 | // widget's outline far to the left (http://dev.ckeditor.com/ticket/12024). | ||
52 | 'display:none;' + | ||
53 | 'opacity:0.75;' + | ||
54 | 'transition:height 0s 0.2s;' + // Delay hiding drag handler. | ||
55 | // Prevent drag handler from being misplaced (http://dev.ckeditor.com/ticket/11198). | ||
56 | 'line-height:0' + | ||
57 | '}' + | ||
58 | '.cke_widget_wrapper:hover>.cke_widget_drag_handler_container{' + | ||
59 | 'height:' + DRAG_HANDLER_SIZE + 'px;' + | ||
60 | 'transition:none' + | ||
61 | '}' + | ||
62 | '.cke_widget_drag_handler_container:hover{' + | ||
63 | 'opacity:1' + | ||
64 | '}' + | ||
65 | 'img.cke_widget_drag_handler{' + | ||
66 | 'cursor:move;' + | ||
67 | 'width:' + DRAG_HANDLER_SIZE + 'px;' + | ||
68 | 'height:' + DRAG_HANDLER_SIZE + 'px;' + | ||
69 | 'display:inline-block' + | ||
70 | '}' + | ||
71 | '.cke_widget_mask{' + | ||
72 | 'position:absolute;' + | ||
73 | 'top:0;' + | ||
74 | 'left:0;' + | ||
75 | 'width:100%;' + | ||
76 | 'height:100%;' + | ||
77 | 'display:block' + | ||
78 | '}' + | ||
79 | '.cke_editable.cke_widget_dragging, .cke_editable.cke_widget_dragging *{' + | ||
80 | 'cursor:move !important' + | ||
81 | '}' | ||
82 | ); | ||
83 | }, | ||
84 | |||
85 | beforeInit: function( editor ) { | ||
86 | /** | ||
87 | * An instance of widget repository. It contains all | ||
88 | * {@link CKEDITOR.plugins.widget.repository#registered registered widget definitions} and | ||
89 | * {@link CKEDITOR.plugins.widget.repository#instances initialized instances}. | ||
90 | * | ||
91 | * editor.widgets.add( 'someName', { | ||
92 | * // Widget definition... | ||
93 | * } ); | ||
94 | * | ||
95 | * editor.widgets.registered.someName; // -> Widget definition | ||
96 | * | ||
97 | * @since 4.3 | ||
98 | * @readonly | ||
99 | * @property {CKEDITOR.plugins.widget.repository} widgets | ||
100 | * @member CKEDITOR.editor | ||
101 | */ | ||
102 | editor.widgets = new Repository( editor ); | ||
103 | }, | ||
104 | |||
105 | afterInit: function( editor ) { | ||
106 | addWidgetButtons( editor ); | ||
107 | setupContextMenu( editor ); | ||
108 | } | ||
109 | } ); | ||
110 | |||
111 | /** | ||
112 | * Widget repository. It keeps track of all {@link #registered registered widget definitions} and | ||
113 | * {@link #instances initialized instances}. An instance of the repository is available under | ||
114 | * the {@link CKEDITOR.editor#widgets} property. | ||
115 | * | ||
116 | * @class CKEDITOR.plugins.widget.repository | ||
117 | * @mixins CKEDITOR.event | ||
118 | * @constructor Creates a widget repository instance. Note that the widget plugin automatically | ||
119 | * creates a repository instance which is available under the {@link CKEDITOR.editor#widgets} property. | ||
120 | * @param {CKEDITOR.editor} editor The editor instance for which the repository will be created. | ||
121 | */ | ||
122 | function Repository( editor ) { | ||
123 | /** | ||
124 | * The editor instance for which this repository was created. | ||
125 | * | ||
126 | * @readonly | ||
127 | * @property {CKEDITOR.editor} editor | ||
128 | */ | ||
129 | this.editor = editor; | ||
130 | |||
131 | /** | ||
132 | * A hash of registered widget definitions (definition name => {@link CKEDITOR.plugins.widget.definition}). | ||
133 | * | ||
134 | * To register a definition use the {@link #add} method. | ||
135 | * | ||
136 | * @readonly | ||
137 | */ | ||
138 | this.registered = {}; | ||
139 | |||
140 | /** | ||
141 | * An object containing initialized widget instances (widget id => {@link CKEDITOR.plugins.widget}). | ||
142 | * | ||
143 | * @readonly | ||
144 | */ | ||
145 | this.instances = {}; | ||
146 | |||
147 | /** | ||
148 | * An array of selected widget instances. | ||
149 | * | ||
150 | * @readonly | ||
151 | * @property {CKEDITOR.plugins.widget[]} selected | ||
152 | */ | ||
153 | this.selected = []; | ||
154 | |||
155 | /** | ||
156 | * The focused widget instance. See also {@link CKEDITOR.plugins.widget#event-focus} | ||
157 | * and {@link CKEDITOR.plugins.widget#event-blur} events. | ||
158 | * | ||
159 | * editor.on( 'selectionChange', function() { | ||
160 | * if ( editor.widgets.focused ) { | ||
161 | * // Do something when a widget is focused... | ||
162 | * } | ||
163 | * } ); | ||
164 | * | ||
165 | * @readonly | ||
166 | * @property {CKEDITOR.plugins.widget} focused | ||
167 | */ | ||
168 | this.focused = null; | ||
169 | |||
170 | /** | ||
171 | * The widget instance that contains the nested editable which is currently focused. | ||
172 | * | ||
173 | * @readonly | ||
174 | * @property {CKEDITOR.plugins.widget} widgetHoldingFocusedEditable | ||
175 | */ | ||
176 | this.widgetHoldingFocusedEditable = null; | ||
177 | |||
178 | this._ = { | ||
179 | nextId: 0, | ||
180 | upcasts: [], | ||
181 | upcastCallbacks: [], | ||
182 | filters: {} | ||
183 | }; | ||
184 | |||
185 | setupWidgetsLifecycle( this ); | ||
186 | setupSelectionObserver( this ); | ||
187 | setupMouseObserver( this ); | ||
188 | setupKeyboardObserver( this ); | ||
189 | setupDragAndDrop( this ); | ||
190 | setupNativeCutAndCopy( this ); | ||
191 | } | ||
192 | |||
193 | Repository.prototype = { | ||
194 | /** | ||
195 | * Minimum interval between selection checks. | ||
196 | * | ||
197 | * @private | ||
198 | */ | ||
199 | MIN_SELECTION_CHECK_INTERVAL: 500, | ||
200 | |||
201 | /** | ||
202 | * Adds a widget definition to the repository. Fires the {@link CKEDITOR.editor#widgetDefinition} event | ||
203 | * which allows to modify the widget definition which is going to be registered. | ||
204 | * | ||
205 | * @param {String} name The name of the widget definition. | ||
206 | * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget definition. | ||
207 | * @returns {CKEDITOR.plugins.widget.definition} | ||
208 | */ | ||
209 | add: function( name, widgetDef ) { | ||
210 | // Create prototyped copy of original widget definition, so we won't modify it. | ||
211 | widgetDef = CKEDITOR.tools.prototypedCopy( widgetDef ); | ||
212 | widgetDef.name = name; | ||
213 | |||
214 | widgetDef._ = widgetDef._ || {}; | ||
215 | |||
216 | this.editor.fire( 'widgetDefinition', widgetDef ); | ||
217 | |||
218 | if ( widgetDef.template ) | ||
219 | widgetDef.template = new CKEDITOR.template( widgetDef.template ); | ||
220 | |||
221 | addWidgetCommand( this.editor, widgetDef ); | ||
222 | addWidgetProcessors( this, widgetDef ); | ||
223 | |||
224 | this.registered[ name ] = widgetDef; | ||
225 | |||
226 | return widgetDef; | ||
227 | }, | ||
228 | |||
229 | /** | ||
230 | * Adds a callback for element upcasting. Each callback will be executed | ||
231 | * for every element which is later tested by upcast methods. If a callback | ||
232 | * returns `false`, the element will not be upcasted. | ||
233 | * | ||
234 | * // Images with the "banner" class will not be upcasted (e.g. to the image widget). | ||
235 | * editor.widgets.addUpcastCallback( function( element ) { | ||
236 | * if ( element.name == 'img' && element.hasClass( 'banner' ) ) | ||
237 | * return false; | ||
238 | * } ); | ||
239 | * | ||
240 | * @param {Function} callback | ||
241 | * @param {CKEDITOR.htmlParser.element} callback.element | ||
242 | */ | ||
243 | addUpcastCallback: function( callback ) { | ||
244 | this._.upcastCallbacks.push( callback ); | ||
245 | }, | ||
246 | |||
247 | /** | ||
248 | * Checks the selection to update widget states (selection and focus). | ||
249 | * | ||
250 | * This method is triggered by the {@link #event-checkSelection} event. | ||
251 | */ | ||
252 | checkSelection: function() { | ||
253 | var sel = this.editor.getSelection(), | ||
254 | selectedElement = sel.getSelectedElement(), | ||
255 | updater = stateUpdater( this ), | ||
256 | widget; | ||
257 | |||
258 | // Widget is focused so commit and finish checking. | ||
259 | if ( selectedElement && ( widget = this.getByElement( selectedElement, true ) ) ) | ||
260 | return updater.focus( widget ).select( widget ).commit(); | ||
261 | |||
262 | var range = sel.getRanges()[ 0 ]; | ||
263 | |||
264 | // No ranges or collapsed range mean that nothing is selected, so commit and finish checking. | ||
265 | if ( !range || range.collapsed ) | ||
266 | return updater.commit(); | ||
267 | |||
268 | // Range is not empty, so create walker checking for wrappers. | ||
269 | var walker = new CKEDITOR.dom.walker( range ), | ||
270 | wrapper; | ||
271 | |||
272 | walker.evaluator = Widget.isDomWidgetWrapper; | ||
273 | |||
274 | while ( ( wrapper = walker.next() ) ) | ||
275 | updater.select( this.getByElement( wrapper ) ); | ||
276 | |||
277 | updater.commit(); | ||
278 | }, | ||
279 | |||
280 | /** | ||
281 | * Checks if all widget instances are still present in the DOM. | ||
282 | * Destroys those instances that are not present. | ||
283 | * Reinitializes widgets on widget wrappers for which widget instances | ||
284 | * cannot be found. Takes nested widgets into account, too. | ||
285 | * | ||
286 | * This method triggers the {@link #event-checkWidgets} event whose listeners | ||
287 | * can cancel the method's execution or modify its options. | ||
288 | * | ||
289 | * @param [options] The options object. | ||
290 | * @param {Boolean} [options.initOnlyNew] Initializes widgets only on newly wrapped | ||
291 | * widget elements (those which still have the `cke_widget_new` class). When this option is | ||
292 | * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure) | ||
293 | * will not be reinitialized. This makes the check faster. | ||
294 | * @param {Boolean} [options.focusInited] If only one widget is initialized by | ||
295 | * the method, it will be focused. | ||
296 | */ | ||
297 | checkWidgets: function( options ) { | ||
298 | this.fire( 'checkWidgets', CKEDITOR.tools.copy( options || {} ) ); | ||
299 | }, | ||
300 | |||
301 | /** | ||
302 | * Removes the widget from the editor and moves the selection to the closest | ||
303 | * editable position if the widget was focused before. | ||
304 | * | ||
305 | * @param {CKEDITOR.plugins.widget} widget The widget instance to be deleted. | ||
306 | */ | ||
307 | del: function( widget ) { | ||
308 | if ( this.focused === widget ) { | ||
309 | var editor = widget.editor, | ||
310 | range = editor.createRange(), | ||
311 | found; | ||
312 | |||
313 | // If haven't found place for caret on the default side, | ||
314 | // try to find it on the other side. | ||
315 | if ( !( found = range.moveToClosestEditablePosition( widget.wrapper, true ) ) ) | ||
316 | found = range.moveToClosestEditablePosition( widget.wrapper, false ); | ||
317 | |||
318 | if ( found ) | ||
319 | editor.getSelection().selectRanges( [ range ] ); | ||
320 | } | ||
321 | |||
322 | widget.wrapper.remove(); | ||
323 | this.destroy( widget, true ); | ||
324 | }, | ||
325 | |||
326 | /** | ||
327 | * Destroys the widget instance and all its nested widgets (widgets inside its nested editables). | ||
328 | * | ||
329 | * @param {CKEDITOR.plugins.widget} widget The widget instance to be destroyed. | ||
330 | * @param {Boolean} [offline] Whether the widget is offline (detached from the DOM tree) — | ||
331 | * in this case the DOM (attributes, classes, etc.) will not be cleaned up. | ||
332 | */ | ||
333 | destroy: function( widget, offline ) { | ||
334 | if ( this.widgetHoldingFocusedEditable === widget ) | ||
335 | setFocusedEditable( this, widget, null, offline ); | ||
336 | |||
337 | widget.destroy( offline ); | ||
338 | delete this.instances[ widget.id ]; | ||
339 | this.fire( 'instanceDestroyed', widget ); | ||
340 | }, | ||
341 | |||
342 | /** | ||
343 | * Destroys all widget instances. | ||
344 | * | ||
345 | * @param {Boolean} [offline] Whether the widgets are offline (detached from the DOM tree) — | ||
346 | * in this case the DOM (attributes, classes, etc.) will not be cleaned up. | ||
347 | * @param {CKEDITOR.dom.element} [container] The container within widgets will be destroyed. | ||
348 | * This option will be ignored if the `offline` flag was set to `true`, because in such case | ||
349 | * it is not possible to find widgets within the passed block. | ||
350 | */ | ||
351 | destroyAll: function( offline, container ) { | ||
352 | var widget, | ||
353 | id, | ||
354 | instances = this.instances; | ||
355 | |||
356 | if ( container && !offline ) { | ||
357 | var wrappers = container.find( '.cke_widget_wrapper' ), | ||
358 | l = wrappers.count(), | ||
359 | i = 0; | ||
360 | |||
361 | // Length is constant, because this is not a live node list. | ||
362 | // Note: since querySelectorAll returns nodes in document order, | ||
363 | // outer widgets are always placed before their nested widgets and therefore | ||
364 | // are destroyed before them. | ||
365 | for ( ; i < l; ++i ) { | ||
366 | widget = this.getByElement( wrappers.getItem( i ), true ); | ||
367 | // Widget might not be found, because it could be a nested widget, | ||
368 | // which would be destroyed when destroying its parent. | ||
369 | if ( widget ) | ||
370 | this.destroy( widget ); | ||
371 | } | ||
372 | |||
373 | return; | ||
374 | } | ||
375 | |||
376 | for ( id in instances ) { | ||
377 | widget = instances[ id ]; | ||
378 | this.destroy( widget, offline ); | ||
379 | } | ||
380 | }, | ||
381 | |||
382 | /** | ||
383 | * Finalizes a process of widget creation. This includes: | ||
384 | * | ||
385 | * * inserting widget element into editor, | ||
386 | * * marking widget instance as ready (see {@link CKEDITOR.plugins.widget#event-ready}), | ||
387 | * * focusing widget instance. | ||
388 | * | ||
389 | * This method is used by the default widget's command and is called | ||
390 | * after widget's dialog (if set) is closed. It may also be used in a | ||
391 | * customized process of widget creation and insertion. | ||
392 | * | ||
393 | * widget.once( 'edit', function() { | ||
394 | * // Finalize creation only of not ready widgets. | ||
395 | * if ( widget.isReady() ) | ||
396 | * return; | ||
397 | * | ||
398 | * // Cancel edit event to prevent automatic widget insertion. | ||
399 | * evt.cancel(); | ||
400 | * | ||
401 | * CustomDialog.open( widget.data, function saveCallback( savedData ) { | ||
402 | * // Cache the container, because widget may be destroyed while saving data, | ||
403 | * // if this process will require some deep transformations. | ||
404 | * var container = widget.wrapper.getParent(); | ||
405 | * | ||
406 | * widget.setData( savedData ); | ||
407 | * | ||
408 | * // Widget will be retrieved from container and inserted into editor. | ||
409 | * editor.widgets.finalizeCreation( container ); | ||
410 | * } ); | ||
411 | * } ); | ||
412 | * | ||
413 | * @param {CKEDITOR.dom.element/CKEDITOR.dom.documentFragment} container The element | ||
414 | * or document fragment which contains widget wrapper. The container is used, so before | ||
415 | * finalizing creation the widget can be freely transformed (even destroyed and reinitialized). | ||
416 | */ | ||
417 | finalizeCreation: function( container ) { | ||
418 | var wrapper = container.getFirst(); | ||
419 | if ( wrapper && Widget.isDomWidgetWrapper( wrapper ) ) { | ||
420 | this.editor.insertElement( wrapper ); | ||
421 | |||
422 | var widget = this.getByElement( wrapper ); | ||
423 | // Fire postponed #ready event. | ||
424 | widget.ready = true; | ||
425 | widget.fire( 'ready' ); | ||
426 | widget.focus(); | ||
427 | } | ||
428 | }, | ||
429 | |||
430 | /** | ||
431 | * Finds a widget instance which contains a given element. The element will be the {@link CKEDITOR.plugins.widget#wrapper wrapper} | ||
432 | * of the returned widget or a descendant of this {@link CKEDITOR.plugins.widget#wrapper wrapper}. | ||
433 | * | ||
434 | * editor.widgets.getByElement( someWidget.wrapper ); // -> someWidget | ||
435 | * editor.widgets.getByElement( someWidget.parts.caption ); // -> someWidget | ||
436 | * | ||
437 | * // Check wrapper only: | ||
438 | * editor.widgets.getByElement( someWidget.wrapper, true ); // -> someWidget | ||
439 | * editor.widgets.getByElement( someWidget.parts.caption, true ); // -> null | ||
440 | * | ||
441 | * @param {CKEDITOR.dom.element} element The element to be checked. | ||
442 | * @param {Boolean} [checkWrapperOnly] If set to `true`, the method will not check wrappers' descendants. | ||
443 | * @returns {CKEDITOR.plugins.widget} The widget instance or `null`. | ||
444 | */ | ||
445 | getByElement: ( function() { | ||
446 | var validWrapperElements = { div: 1, span: 1 }; | ||
447 | function getWidgetId( element ) { | ||
448 | return element.is( validWrapperElements ) && element.data( 'cke-widget-id' ); | ||
449 | } | ||
450 | |||
451 | return function( element, checkWrapperOnly ) { | ||
452 | if ( !element ) | ||
453 | return null; | ||
454 | |||
455 | var id = getWidgetId( element ); | ||
456 | |||
457 | // There's no need to check element parents if element is a wrapper. | ||
458 | if ( !checkWrapperOnly && !id ) { | ||
459 | var limit = this.editor.editable(); | ||
460 | |||
461 | // Try to find a closest ascendant which is a widget wrapper. | ||
462 | do { | ||
463 | element = element.getParent(); | ||
464 | } while ( element && !element.equals( limit ) && !( id = getWidgetId( element ) ) ); | ||
465 | } | ||
466 | |||
467 | return this.instances[ id ] || null; | ||
468 | }; | ||
469 | } )(), | ||
470 | |||
471 | /** | ||
472 | * Initializes a widget on a given element if the widget has not been initialized on it yet. | ||
473 | * | ||
474 | * @param {CKEDITOR.dom.element} element The future widget element. | ||
475 | * @param {String/CKEDITOR.plugins.widget.definition} [widgetDef] Name of a widget or a widget definition. | ||
476 | * The widget definition should be previously registered by using the | ||
477 | * {@link CKEDITOR.plugins.widget.repository#add} method. | ||
478 | * @param [startupData] Widget startup data (has precedence over default one). | ||
479 | * @returns {CKEDITOR.plugins.widget} The widget instance or `null` if a widget could not be initialized on | ||
480 | * a given element. | ||
481 | */ | ||
482 | initOn: function( element, widgetDef, startupData ) { | ||
483 | if ( !widgetDef ) | ||
484 | widgetDef = this.registered[ element.data( 'widget' ) ]; | ||
485 | else if ( typeof widgetDef == 'string' ) | ||
486 | widgetDef = this.registered[ widgetDef ]; | ||
487 | |||
488 | if ( !widgetDef ) | ||
489 | return null; | ||
490 | |||
491 | // Wrap element if still wasn't wrapped (was added during runtime by method that skips dataProcessor). | ||
492 | var wrapper = this.wrapElement( element, widgetDef.name ); | ||
493 | |||
494 | if ( wrapper ) { | ||
495 | // Check if widget wrapper is new (widget hasn't been initialized on it yet). | ||
496 | // This class will be removed by widget constructor to avoid locking snapshot twice. | ||
497 | if ( wrapper.hasClass( 'cke_widget_new' ) ) { | ||
498 | var widget = new Widget( this, this._.nextId++, element, widgetDef, startupData ); | ||
499 | |||
500 | // Widget could be destroyed when initializing it. | ||
501 | if ( widget.isInited() ) { | ||
502 | this.instances[ widget.id ] = widget; | ||
503 | |||
504 | return widget; | ||
505 | } else { | ||
506 | return null; | ||
507 | } | ||
508 | } | ||
509 | |||
510 | // Widget already has been initialized, so try to get widget by element. | ||
511 | // Note - it may happen that other instance will returned than the one created above, | ||
512 | // if for example widget was destroyed and reinitialized. | ||
513 | return this.getByElement( element ); | ||
514 | } | ||
515 | |||
516 | // No wrapper means that there's no widget for this element. | ||
517 | return null; | ||
518 | }, | ||
519 | |||
520 | /** | ||
521 | * Initializes widgets on all elements which were wrapped by {@link #wrapElement} and | ||
522 | * have not been initialized yet. | ||
523 | * | ||
524 | * @param {CKEDITOR.dom.element} [container=editor.editable()] The container which will be checked for not | ||
525 | * initialized widgets. Defaults to editor's {@link CKEDITOR.editor#editable editable} element. | ||
526 | * @returns {CKEDITOR.plugins.widget[]} Array of widget instances which have been initialized. | ||
527 | * Note: Only first-level widgets are returned — without nested widgets. | ||
528 | */ | ||
529 | initOnAll: function( container ) { | ||
530 | var newWidgets = ( container || this.editor.editable() ).find( '.cke_widget_new' ), | ||
531 | newInstances = [], | ||
532 | instance; | ||
533 | |||
534 | for ( var i = newWidgets.count(); i--; ) { | ||
535 | instance = this.initOn( newWidgets.getItem( i ).getFirst( Widget.isDomWidgetElement ) ); | ||
536 | if ( instance ) | ||
537 | newInstances.push( instance ); | ||
538 | } | ||
539 | |||
540 | return newInstances; | ||
541 | }, | ||
542 | |||
543 | /** | ||
544 | * Allows to listen to events on specific types of widgets, even if they are not created yet. | ||
545 | * | ||
546 | * Please note that this method inherits parameters from the {@link CKEDITOR.event#method-on} method with one | ||
547 | * extra parameter at the beginning which is the widget name. | ||
548 | * | ||
549 | * editor.widgets.onWidget( 'image', 'action', function( evt ) { | ||
550 | * // Event `action` occurs on `image` widget. | ||
551 | * } ); | ||
552 | * | ||
553 | * @since 4.5 | ||
554 | * @param {String} widgetName | ||
555 | * @param {String} eventName | ||
556 | * @param {Function} listenerFunction | ||
557 | * @param {Object} [scopeObj] | ||
558 | * @param {Object} [listenerData] | ||
559 | * @param {Number} [priority=10] | ||
560 | */ | ||
561 | onWidget: function( widgetName ) { | ||
562 | var args = Array.prototype.slice.call( arguments ); | ||
563 | |||
564 | args.shift(); | ||
565 | |||
566 | for ( var i in this.instances ) { | ||
567 | var instance = this.instances[ i ]; | ||
568 | |||
569 | if ( instance.name == widgetName ) { | ||
570 | instance.on.apply( instance, args ); | ||
571 | } | ||
572 | } | ||
573 | |||
574 | this.on( 'instanceCreated', function( evt ) { | ||
575 | var widget = evt.data; | ||
576 | |||
577 | if ( widget.name == widgetName ) { | ||
578 | widget.on.apply( widget, args ); | ||
579 | } | ||
580 | } ); | ||
581 | }, | ||
582 | |||
583 | /** | ||
584 | * Parses element classes string and returns an object | ||
585 | * whose keys contain class names. Skips all `cke_*` classes. | ||
586 | * | ||
587 | * This method is used by the {@link CKEDITOR.plugins.widget#getClasses} method and | ||
588 | * may be used when overriding that method. | ||
589 | * | ||
590 | * @since 4.4 | ||
591 | * @param {String} classes String (value of `class` attribute). | ||
592 | * @returns {Object} Object containing classes or `null` if no classes found. | ||
593 | */ | ||
594 | parseElementClasses: function( classes ) { | ||
595 | if ( !classes ) | ||
596 | return null; | ||
597 | |||
598 | classes = CKEDITOR.tools.trim( classes ).split( /\s+/ ); | ||
599 | |||
600 | var cl, | ||
601 | obj = {}, | ||
602 | hasClasses = 0; | ||
603 | |||
604 | while ( ( cl = classes.pop() ) ) { | ||
605 | if ( cl.indexOf( 'cke_' ) == -1 ) | ||
606 | obj[ cl ] = hasClasses = 1; | ||
607 | } | ||
608 | |||
609 | return hasClasses ? obj : null; | ||
610 | }, | ||
611 | |||
612 | /** | ||
613 | * Wraps an element with a widget's non-editable container. | ||
614 | * | ||
615 | * If this method is called on an {@link CKEDITOR.htmlParser.element}, then it will | ||
616 | * also take care of fixing the DOM after wrapping (the wrapper may not be allowed in element's parent). | ||
617 | * | ||
618 | * @param {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} element The widget element to be wrapped. | ||
619 | * @param {String} [widgetName] The name of the widget definition. Defaults to element's `data-widget` | ||
620 | * attribute value. | ||
621 | * @returns {CKEDITOR.dom.element/CKEDITOR.htmlParser.element} The wrapper element or `null` if | ||
622 | * the widget definition of this name is not registered. | ||
623 | */ | ||
624 | wrapElement: function( element, widgetName ) { | ||
625 | var wrapper = null, | ||
626 | widgetDef, | ||
627 | isInline; | ||
628 | |||
629 | if ( element instanceof CKEDITOR.dom.element ) { | ||
630 | widgetName = widgetName || element.data( 'widget' ); | ||
631 | widgetDef = this.registered[ widgetName ]; | ||
632 | |||
633 | if ( !widgetDef ) | ||
634 | return null; | ||
635 | |||
636 | // Do not wrap already wrapped element. | ||
637 | wrapper = element.getParent(); | ||
638 | if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.data( 'cke-widget-wrapper' ) ) | ||
639 | return wrapper; | ||
640 | |||
641 | // If attribute isn't already set (e.g. for pasted widget), set it. | ||
642 | if ( !element.hasAttribute( 'data-cke-widget-keep-attr' ) ) | ||
643 | element.data( 'cke-widget-keep-attr', element.data( 'widget' ) ? 1 : 0 ); | ||
644 | |||
645 | element.data( 'widget', widgetName ); | ||
646 | |||
647 | isInline = isWidgetInline( widgetDef, element.getName() ); | ||
648 | |||
649 | wrapper = new CKEDITOR.dom.element( isInline ? 'span' : 'div' ); | ||
650 | wrapper.setAttributes( getWrapperAttributes( isInline, widgetName ) ); | ||
651 | |||
652 | wrapper.data( 'cke-display-name', widgetDef.pathName ? widgetDef.pathName : element.getName() ); | ||
653 | |||
654 | // Replace element unless it is a detached one. | ||
655 | if ( element.getParent( true ) ) | ||
656 | wrapper.replace( element ); | ||
657 | element.appendTo( wrapper ); | ||
658 | } | ||
659 | else if ( element instanceof CKEDITOR.htmlParser.element ) { | ||
660 | widgetName = widgetName || element.attributes[ 'data-widget' ]; | ||
661 | widgetDef = this.registered[ widgetName ]; | ||
662 | |||
663 | if ( !widgetDef ) | ||
664 | return null; | ||
665 | |||
666 | wrapper = element.parent; | ||
667 | if ( wrapper && wrapper.type == CKEDITOR.NODE_ELEMENT && wrapper.attributes[ 'data-cke-widget-wrapper' ] ) | ||
668 | return wrapper; | ||
669 | |||
670 | // If attribute isn't already set (e.g. for pasted widget), set it. | ||
671 | if ( !( 'data-cke-widget-keep-attr' in element.attributes ) ) | ||
672 | element.attributes[ 'data-cke-widget-keep-attr' ] = element.attributes[ 'data-widget' ] ? 1 : 0; | ||
673 | if ( widgetName ) | ||
674 | element.attributes[ 'data-widget' ] = widgetName; | ||
675 | |||
676 | isInline = isWidgetInline( widgetDef, element.name ); | ||
677 | |||
678 | wrapper = new CKEDITOR.htmlParser.element( isInline ? 'span' : 'div', getWrapperAttributes( isInline, widgetName ) ); | ||
679 | wrapper.attributes[ 'data-cke-display-name' ] = widgetDef.pathName ? widgetDef.pathName : element.name; | ||
680 | |||
681 | var parent = element.parent, | ||
682 | index; | ||
683 | |||
684 | // Don't detach already detached element. | ||
685 | if ( parent ) { | ||
686 | index = element.getIndex(); | ||
687 | element.remove(); | ||
688 | } | ||
689 | |||
690 | wrapper.add( element ); | ||
691 | |||
692 | // Insert wrapper fixing DOM (splitting parents if wrapper is not allowed inside them). | ||
693 | parent && insertElement( parent, index, wrapper ); | ||
694 | } | ||
695 | |||
696 | return wrapper; | ||
697 | }, | ||
698 | |||
699 | // Expose for tests. | ||
700 | _tests_createEditableFilter: createEditableFilter | ||
701 | }; | ||
702 | |||
703 | CKEDITOR.event.implementOn( Repository.prototype ); | ||
704 | |||
705 | /** | ||
706 | * An event fired when a widget instance is created, but before it is fully initialized. | ||
707 | * | ||
708 | * @event instanceCreated | ||
709 | * @param {CKEDITOR.plugins.widget} data The widget instance. | ||
710 | */ | ||
711 | |||
712 | /** | ||
713 | * An event fired when a widget instance was destroyed. | ||
714 | * | ||
715 | * See also {@link CKEDITOR.plugins.widget#event-destroy}. | ||
716 | * | ||
717 | * @event instanceDestroyed | ||
718 | * @param {CKEDITOR.plugins.widget} data The widget instance. | ||
719 | */ | ||
720 | |||
721 | /** | ||
722 | * An event fired to trigger the selection check. | ||
723 | * | ||
724 | * See the {@link #method-checkSelection} method. | ||
725 | * | ||
726 | * @event checkSelection | ||
727 | */ | ||
728 | |||
729 | /** | ||
730 | * An event fired by the the {@link #method-checkWidgets} method. | ||
731 | * | ||
732 | * It can be canceled in order to stop the {@link #method-checkWidgets} | ||
733 | * method execution or the event listener can modify the method's options. | ||
734 | * | ||
735 | * @event checkWidgets | ||
736 | * @param [data] | ||
737 | * @param {Boolean} [data.initOnlyNew] Initialize widgets only on newly wrapped | ||
738 | * widget elements (those which still have the `cke_widget_new` class). When this option is | ||
739 | * set to `true`, widgets which were invalidated (e.g. by replacing with a cloned DOM structure) | ||
740 | * will not be reinitialized. This makes the check faster. | ||
741 | * @param {Boolean} [data.focusInited] If only one widget is initialized by | ||
742 | * the method, it will be focused. | ||
743 | */ | ||
744 | |||
745 | |||
746 | /** | ||
747 | * An instance of a widget. Together with {@link CKEDITOR.plugins.widget.repository} these | ||
748 | * two classes constitute the core of the Widget System. | ||
749 | * | ||
750 | * Note that neither the repository nor the widget instances can be created by using their constructors. | ||
751 | * A repository instance is automatically set up by the Widget plugin and is accessible under | ||
752 | * {@link CKEDITOR.editor#widgets}, while widget instances are created and destroyed by the repository. | ||
753 | * | ||
754 | * To create a widget, first you need to {@link CKEDITOR.plugins.widget.repository#add register} its | ||
755 | * {@link CKEDITOR.plugins.widget.definition definition}: | ||
756 | * | ||
757 | * editor.widgets.add( 'simplebox', { | ||
758 | * upcast: function( element ) { | ||
759 | * // Defines which elements will become widgets. | ||
760 | * if ( element.hasClass( 'simplebox' ) ) | ||
761 | * return true; | ||
762 | * }, | ||
763 | * init: function() { | ||
764 | * // ... | ||
765 | * } | ||
766 | * } ); | ||
767 | * | ||
768 | * Once the widget definition is registered, widgets will be automatically | ||
769 | * created when loading data: | ||
770 | * | ||
771 | * editor.setData( '<div class="simplebox">foo</div>', function() { | ||
772 | * console.log( editor.widgets.instances ); // -> An object containing one instance. | ||
773 | * } ); | ||
774 | * | ||
775 | * It is also possible to create instances during runtime by using a command | ||
776 | * (if a {@link CKEDITOR.plugins.widget.definition#template} property was defined): | ||
777 | * | ||
778 | * // You can execute an automatically defined command to | ||
779 | * // insert a new simplebox widget or edit the one currently focused. | ||
780 | * editor.execCommand( 'simplebox' ); | ||
781 | * | ||
782 | * Note: Since CKEditor 4.5 widget's `startupData` can be passed as the command argument: | ||
783 | * | ||
784 | * editor.execCommand( 'simplebox', { | ||
785 | * startupData: { | ||
786 | * align: 'left' | ||
787 | * } | ||
788 | * } ); | ||
789 | * | ||
790 | * A widget can also be created in a completely custom way: | ||
791 | * | ||
792 | * var element = editor.document.createElement( 'div' ); | ||
793 | * editor.insertElement( element ); | ||
794 | * var widget = editor.widgets.initOn( element, 'simplebox' ); | ||
795 | * | ||
796 | * @since 4.3 | ||
797 | * @class CKEDITOR.plugins.widget | ||
798 | * @mixins CKEDITOR.event | ||
799 | * @extends CKEDITOR.plugins.widget.definition | ||
800 | * @constructor Creates an instance of the widget class. Do not use it directly, but instead initialize widgets | ||
801 | * by using the {@link CKEDITOR.plugins.widget.repository#initOn} method or by the upcasting system. | ||
802 | * @param {CKEDITOR.plugins.widget.repository} widgetsRepo | ||
803 | * @param {Number} id Unique ID of this widget instance. | ||
804 | * @param {CKEDITOR.dom.element} element The widget element. | ||
805 | * @param {CKEDITOR.plugins.widget.definition} widgetDef Widget's registered definition. | ||
806 | * @param [startupData] Initial widget data. This data object will overwrite the default data and | ||
807 | * the data loaded from the DOM. | ||
808 | */ | ||
809 | function Widget( widgetsRepo, id, element, widgetDef, startupData ) { | ||
810 | var editor = widgetsRepo.editor; | ||
811 | |||
812 | // Extend this widget with widgetDef-specific methods and properties. | ||
813 | CKEDITOR.tools.extend( this, widgetDef, { | ||
814 | /** | ||
815 | * The editor instance. | ||
816 | * | ||
817 | * @readonly | ||
818 | * @property {CKEDITOR.editor} | ||
819 | */ | ||
820 | editor: editor, | ||
821 | |||
822 | /** | ||
823 | * This widget's unique (per editor instance) ID. | ||
824 | * | ||
825 | * @readonly | ||
826 | * @property {Number} | ||
827 | */ | ||
828 | id: id, | ||
829 | |||
830 | /** | ||
831 | * Whether this widget is an inline widget (based on an inline element unless | ||
832 | * forced otherwise by {@link CKEDITOR.plugins.widget.definition#inline}). | ||
833 | * | ||
834 | * **Note:** This option does not allow to turn a block element into an inline widget. | ||
835 | * However, it makes it possible to turn an inline element into a block widget or to | ||
836 | * force a correct type in case when automatic recognition fails. | ||
837 | * | ||
838 | * @readonly | ||
839 | * @property {Boolean} | ||
840 | */ | ||
841 | inline: element.getParent().getName() == 'span', | ||
842 | |||
843 | /** | ||
844 | * The widget element — the element on which the widget was initialized. | ||
845 | * | ||
846 | * @readonly | ||
847 | * @property {CKEDITOR.dom.element} element | ||
848 | */ | ||
849 | element: element, | ||
850 | |||
851 | /** | ||
852 | * Widget's data object. | ||
853 | * | ||
854 | * The data can only be set by using the {@link #setData} method. | ||
855 | * Changes made to the data fire the {@link #event-data} event. | ||
856 | * | ||
857 | * @readonly | ||
858 | */ | ||
859 | data: CKEDITOR.tools.extend( {}, typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults ), | ||
860 | |||
861 | /** | ||
862 | * Indicates if a widget is data-ready. Set to `true` when data from all sources | ||
863 | * ({@link CKEDITOR.plugins.widget.definition#defaults}, set in the | ||
864 | * {@link #init} method, loaded from the widget's element and startup data coming from the constructor) | ||
865 | * are finally loaded. This is immediately followed by the first {@link #event-data}. | ||
866 | * | ||
867 | * @readonly | ||
868 | */ | ||
869 | dataReady: false, | ||
870 | |||
871 | /** | ||
872 | * Whether a widget instance was initialized. This means that: | ||
873 | * | ||
874 | * * An instance was created, | ||
875 | * * Its properties were set, | ||
876 | * * The `init` method was executed. | ||
877 | * | ||
878 | * **Note**: The first {@link #event-data} event could not be fired yet which | ||
879 | * means that the widget's DOM has not been set up yet. Wait for the {@link #event-ready} | ||
880 | * event to be notified when a widget is fully initialized and ready. | ||
881 | * | ||
882 | * **Note**: Use the {@link #isInited} method to check whether a widget is initialized and | ||
883 | * has not been destroyed. | ||
884 | * | ||
885 | * @readonly | ||
886 | */ | ||
887 | inited: false, | ||
888 | |||
889 | /** | ||
890 | * Whether a widget instance is ready. This means that the widget is {@link #inited} and | ||
891 | * that its DOM was finally set up. | ||
892 | * | ||
893 | * **Note:** Use the {@link #isReady} method to check whether a widget is ready and | ||
894 | * has not been destroyed. | ||
895 | * | ||
896 | * @readonly | ||
897 | */ | ||
898 | ready: false, | ||
899 | |||
900 | // Revert what widgetDef could override (automatic #edit listener). | ||
901 | edit: Widget.prototype.edit, | ||
902 | |||
903 | /** | ||
904 | * The nested editable element which is currently focused. | ||
905 | * | ||
906 | * @readonly | ||
907 | * @property {CKEDITOR.plugins.widget.nestedEditable} | ||
908 | */ | ||
909 | focusedEditable: null, | ||
910 | |||
911 | /** | ||
912 | * The widget definition from which this instance was created. | ||
913 | * | ||
914 | * @readonly | ||
915 | * @property {CKEDITOR.plugins.widget.definition} definition | ||
916 | */ | ||
917 | definition: widgetDef, | ||
918 | |||
919 | /** | ||
920 | * Link to the widget repository which created this instance. | ||
921 | * | ||
922 | * @readonly | ||
923 | * @property {CKEDITOR.plugins.widget.repository} repository | ||
924 | */ | ||
925 | repository: widgetsRepo, | ||
926 | |||
927 | draggable: widgetDef.draggable !== false, | ||
928 | |||
929 | // WAAARNING: Overwrite widgetDef's priv object, because otherwise violent unicorn's gonna visit you. | ||
930 | _: { | ||
931 | downcastFn: ( widgetDef.downcast && typeof widgetDef.downcast == 'string' ) ? | ||
932 | widgetDef.downcasts[ widgetDef.downcast ] : widgetDef.downcast | ||
933 | } | ||
934 | }, true ); | ||
935 | |||
936 | /** | ||
937 | * An object of widget component elements. | ||
938 | * | ||
939 | * For every `partName => selector` pair in {@link CKEDITOR.plugins.widget.definition#parts}, | ||
940 | * one `partName => element` pair is added to this object during the widget initialization. | ||
941 | * | ||
942 | * @readonly | ||
943 | * @property {Object} parts | ||
944 | */ | ||
945 | |||
946 | /** | ||
947 | * The template which will be used to create a new widget element (when the widget's command is executed). | ||
948 | * It will be populated with {@link #defaults default values}. | ||
949 | * | ||
950 | * @readonly | ||
951 | * @property {CKEDITOR.template} template | ||
952 | */ | ||
953 | |||
954 | /** | ||
955 | * The widget wrapper — a non-editable `div` or `span` element (depending on {@link #inline}) | ||
956 | * which is a parent of the {@link #element} and widget compontents like the drag handler and the {@link #mask}. | ||
957 | * It is the outermost widget element. | ||
958 | * | ||
959 | * @readonly | ||
960 | * @property {CKEDITOR.dom.element} wrapper | ||
961 | */ | ||
962 | |||
963 | widgetsRepo.fire( 'instanceCreated', this ); | ||
964 | |||
965 | setupWidget( this, widgetDef ); | ||
966 | |||
967 | this.init && this.init(); | ||
968 | |||
969 | // Finally mark widget as inited. | ||
970 | this.inited = true; | ||
971 | |||
972 | setupWidgetData( this, startupData ); | ||
973 | |||
974 | // If at some point (e.g. in #data listener) widget hasn't been destroyed | ||
975 | // and widget is already attached to document then fire #ready. | ||
976 | if ( this.isInited() && editor.editable().contains( this.wrapper ) ) { | ||
977 | this.ready = true; | ||
978 | this.fire( 'ready' ); | ||
979 | } | ||
980 | } | ||
981 | |||
982 | Widget.prototype = { | ||
983 | /** | ||
984 | * Adds a class to the widget element. This method is used by | ||
985 | * the {@link #applyStyle} method and should be overridden by widgets | ||
986 | * which should handle classes differently (e.g. add them to other elements). | ||
987 | * | ||
988 | * Since 4.6.0 this method also adds a corresponding class prefixed with {@link #WRAPPER_CLASS_PREFIX} | ||
989 | * to the widget wrapper element. | ||
990 | * | ||
991 | * **Note**: This method should not be used directly. Use the {@link #setData} method to | ||
992 | * set the `classes` property. Read more in the {@link #setData} documentation. | ||
993 | * | ||
994 | * See also: {@link #removeClass}, {@link #hasClass}, {@link #getClasses}. | ||
995 | * | ||
996 | * @since 4.4 | ||
997 | * @param {String} className The class name to be added. | ||
998 | */ | ||
999 | addClass: function( className ) { | ||
1000 | this.element.addClass( className ); | ||
1001 | this.wrapper.addClass( Widget.WRAPPER_CLASS_PREFIX + className ); | ||
1002 | }, | ||
1003 | |||
1004 | /** | ||
1005 | * Applies the specified style to the widget. It is highly recommended to use the | ||
1006 | * {@link CKEDITOR.editor#applyStyle} or {@link CKEDITOR.style#apply} methods instead of | ||
1007 | * using this method directly, because unlike editor's and style's methods, this one | ||
1008 | * does not perform any checks. | ||
1009 | * | ||
1010 | * By default this method handles only classes defined in the style. It clones existing | ||
1011 | * classes which are stored in the {@link #property-data widget data}'s `classes` property, | ||
1012 | * adds new classes, and calls the {@link #setData} method if at least one new class was added. | ||
1013 | * Then, using the {@link #event-data} event listener widget applies modifications passing | ||
1014 | * new classes to the {@link #addClass} method. | ||
1015 | * | ||
1016 | * If you need to handle classes differently than in the default way, you can override the | ||
1017 | * {@link #addClass} and related methods. You can also handle other style properties than `classes` | ||
1018 | * by overriding this method. | ||
1019 | * | ||
1020 | * See also: {@link #checkStyleActive}, {@link #removeStyle}. | ||
1021 | * | ||
1022 | * @since 4.4 | ||
1023 | * @param {CKEDITOR.style} style The custom widget style to be applied. | ||
1024 | */ | ||
1025 | applyStyle: function( style ) { | ||
1026 | applyRemoveStyle( this, style, 1 ); | ||
1027 | }, | ||
1028 | |||
1029 | /** | ||
1030 | * Checks if the specified style is applied to this widget. It is highly recommended to use the | ||
1031 | * {@link CKEDITOR.style#checkActive} method instead of using this method directly, | ||
1032 | * because unlike style's method, this one does not perform any checks. | ||
1033 | * | ||
1034 | * By default this method handles only classes defined in the style and passes | ||
1035 | * them to the {@link #hasClass} method. You can override these methods to handle classes | ||
1036 | * differently or to handle more of the style properties. | ||
1037 | * | ||
1038 | * See also: {@link #applyStyle}, {@link #removeStyle}. | ||
1039 | * | ||
1040 | * @since 4.4 | ||
1041 | * @param {CKEDITOR.style} style The custom widget style to be checked. | ||
1042 | * @returns {Boolean} Whether the style is applied to this widget. | ||
1043 | */ | ||
1044 | checkStyleActive: function( style ) { | ||
1045 | var classes = getStyleClasses( style ), | ||
1046 | cl; | ||
1047 | |||
1048 | if ( !classes ) | ||
1049 | return false; | ||
1050 | |||
1051 | while ( ( cl = classes.pop() ) ) { | ||
1052 | if ( !this.hasClass( cl ) ) | ||
1053 | return false; | ||
1054 | } | ||
1055 | return true; | ||
1056 | }, | ||
1057 | |||
1058 | /** | ||
1059 | * Destroys this widget instance. | ||
1060 | * | ||
1061 | * Use {@link CKEDITOR.plugins.widget.repository#destroy} when possible instead of this method. | ||
1062 | * | ||
1063 | * This method fires the {#event-destroy} event. | ||
1064 | * | ||
1065 | * @param {Boolean} [offline] Whether a widget is offline (detached from the DOM tree) — | ||
1066 | * in this case the DOM (attributes, classes, etc.) will not be cleaned up. | ||
1067 | */ | ||
1068 | destroy: function( offline ) { | ||
1069 | this.fire( 'destroy' ); | ||
1070 | |||
1071 | if ( this.editables ) { | ||
1072 | for ( var name in this.editables ) | ||
1073 | this.destroyEditable( name, offline ); | ||
1074 | } | ||
1075 | |||
1076 | if ( !offline ) { | ||
1077 | if ( this.element.data( 'cke-widget-keep-attr' ) == '0' ) | ||
1078 | this.element.removeAttribute( 'data-widget' ); | ||
1079 | this.element.removeAttributes( [ 'data-cke-widget-data', 'data-cke-widget-keep-attr' ] ); | ||
1080 | this.element.removeClass( 'cke_widget_element' ); | ||
1081 | this.element.replace( this.wrapper ); | ||
1082 | } | ||
1083 | |||
1084 | this.wrapper = null; | ||
1085 | }, | ||
1086 | |||
1087 | /** | ||
1088 | * Destroys a nested editable and all nested widgets. | ||
1089 | * | ||
1090 | * @param {String} editableName Nested editable name. | ||
1091 | * @param {Boolean} [offline] See {@link #method-destroy} method. | ||
1092 | */ | ||
1093 | destroyEditable: function( editableName, offline ) { | ||
1094 | var editable = this.editables[ editableName ]; | ||
1095 | |||
1096 | editable.removeListener( 'focus', onEditableFocus ); | ||
1097 | editable.removeListener( 'blur', onEditableBlur ); | ||
1098 | this.editor.focusManager.remove( editable ); | ||
1099 | |||
1100 | if ( !offline ) { | ||
1101 | this.repository.destroyAll( false, editable ); | ||
1102 | editable.removeClass( 'cke_widget_editable' ); | ||
1103 | editable.removeClass( 'cke_widget_editable_focused' ); | ||
1104 | editable.removeAttributes( [ 'contenteditable', 'data-cke-widget-editable', 'data-cke-enter-mode' ] ); | ||
1105 | } | ||
1106 | |||
1107 | delete this.editables[ editableName ]; | ||
1108 | }, | ||
1109 | |||
1110 | /** | ||
1111 | * Starts widget editing. | ||
1112 | * | ||
1113 | * This method fires the {@link CKEDITOR.plugins.widget#event-edit} event | ||
1114 | * which may be canceled in order to prevent it from opening a dialog window. | ||
1115 | * | ||
1116 | * The dialog window name is obtained from the event's data `dialog` property or | ||
1117 | * from {@link CKEDITOR.plugins.widget.definition#dialog}. | ||
1118 | * | ||
1119 | * @returns {Boolean} Returns `true` if a dialog window was opened. | ||
1120 | */ | ||
1121 | edit: function() { | ||
1122 | var evtData = { dialog: this.dialog }, | ||
1123 | that = this; | ||
1124 | |||
1125 | // Edit event was blocked or there's no dialog to be automatically opened. | ||
1126 | if ( this.fire( 'edit', evtData ) === false || !evtData.dialog ) | ||
1127 | return false; | ||
1128 | |||
1129 | this.editor.openDialog( evtData.dialog, function( dialog ) { | ||
1130 | var showListener, | ||
1131 | okListener; | ||
1132 | |||
1133 | // Allow to add a custom dialog handler. | ||
1134 | if ( that.fire( 'dialog', dialog ) === false ) | ||
1135 | return; | ||
1136 | |||
1137 | showListener = dialog.on( 'show', function() { | ||
1138 | dialog.setupContent( that ); | ||
1139 | } ); | ||
1140 | |||
1141 | okListener = dialog.on( 'ok', function() { | ||
1142 | // Commit dialog's fields, but prevent from | ||
1143 | // firing data event for every field. Fire only one, | ||
1144 | // bulk event at the end. | ||
1145 | var dataChanged, | ||
1146 | dataListener = that.on( 'data', function( evt ) { | ||
1147 | dataChanged = 1; | ||
1148 | evt.cancel(); | ||
1149 | }, null, null, 0 ); | ||
1150 | |||
1151 | // Create snapshot preceeding snapshot with changed widget... | ||
1152 | // TODO it should not be required, but it is and I found similar | ||
1153 | // code in dialog#ok listener in dialog/plugin.js. | ||
1154 | that.editor.fire( 'saveSnapshot' ); | ||
1155 | dialog.commitContent( that ); | ||
1156 | |||
1157 | dataListener.removeListener(); | ||
1158 | if ( dataChanged ) { | ||
1159 | that.fire( 'data', that.data ); | ||
1160 | that.editor.fire( 'saveSnapshot' ); | ||
1161 | } | ||
1162 | } ); | ||
1163 | |||
1164 | dialog.once( 'hide', function() { | ||
1165 | showListener.removeListener(); | ||
1166 | okListener.removeListener(); | ||
1167 | } ); | ||
1168 | } ); | ||
1169 | |||
1170 | return true; | ||
1171 | }, | ||
1172 | |||
1173 | /** | ||
1174 | * Returns widget element classes parsed to an object. This method | ||
1175 | * is used to populate the `classes` property of widget's {@link #property-data}. | ||
1176 | * | ||
1177 | * This method reuses {@link CKEDITOR.plugins.widget.repository#parseElementClasses}. | ||
1178 | * It should be overriden if a widget should handle classes differently (e.g. on other elements). | ||
1179 | * | ||
1180 | * See also: {@link #removeClass}, {@link #addClass}, {@link #hasClass}. | ||
1181 | * | ||
1182 | * @since 4.4 | ||
1183 | * @returns {Object} | ||
1184 | */ | ||
1185 | getClasses: function() { | ||
1186 | return this.repository.parseElementClasses( this.element.getAttribute( 'class' ) ); | ||
1187 | }, | ||
1188 | |||
1189 | /** | ||
1190 | * Checks if the widget element has specified class. This method is used by | ||
1191 | * the {@link #checkStyleActive} method and should be overriden by widgets | ||
1192 | * which should handle classes differently (e.g. on other elements). | ||
1193 | * | ||
1194 | * See also: {@link #removeClass}, {@link #addClass}, {@link #getClasses}. | ||
1195 | * | ||
1196 | * @since 4.4 | ||
1197 | * @param {String} className The class to be checked. | ||
1198 | * @param {Boolean} Whether a widget has specified class. | ||
1199 | */ | ||
1200 | hasClass: function( className ) { | ||
1201 | return this.element.hasClass( className ); | ||
1202 | }, | ||
1203 | |||
1204 | /** | ||
1205 | * Initializes a nested editable. | ||
1206 | * | ||
1207 | * **Note**: Only elements from {@link CKEDITOR.dtd#$editable} may become editables. | ||
1208 | * | ||
1209 | * @param {String} editableName The nested editable name. | ||
1210 | * @param {CKEDITOR.plugins.widget.nestedEditable.definition} definition The definition of the nested editable. | ||
1211 | * @returns {Boolean} Whether an editable was successfully initialized. | ||
1212 | */ | ||
1213 | initEditable: function( editableName, definition ) { | ||
1214 | // Don't fetch just first element which matched selector but look for a correct one. (http://dev.ckeditor.com/ticket/13334) | ||
1215 | var editable = this._findOneNotNested( definition.selector ); | ||
1216 | |||
1217 | if ( editable && editable.is( CKEDITOR.dtd.$editable ) ) { | ||
1218 | editable = new NestedEditable( this.editor, editable, { | ||
1219 | filter: createEditableFilter.call( this.repository, this.name, editableName, definition ) | ||
1220 | } ); | ||
1221 | this.editables[ editableName ] = editable; | ||
1222 | |||
1223 | editable.setAttributes( { | ||
1224 | contenteditable: 'true', | ||
1225 | 'data-cke-widget-editable': editableName, | ||
1226 | 'data-cke-enter-mode': editable.enterMode | ||
1227 | } ); | ||
1228 | |||
1229 | if ( editable.filter ) | ||
1230 | editable.data( 'cke-filter', editable.filter.id ); | ||
1231 | |||
1232 | editable.addClass( 'cke_widget_editable' ); | ||
1233 | // This class may be left when d&ding widget which | ||
1234 | // had focused editable. Clean this class here, not in | ||
1235 | // cleanUpWidgetElement for performance and code size reasons. | ||
1236 | editable.removeClass( 'cke_widget_editable_focused' ); | ||
1237 | |||
1238 | if ( definition.pathName ) | ||
1239 | editable.data( 'cke-display-name', definition.pathName ); | ||
1240 | |||
1241 | this.editor.focusManager.add( editable ); | ||
1242 | editable.on( 'focus', onEditableFocus, this ); | ||
1243 | CKEDITOR.env.ie && editable.on( 'blur', onEditableBlur, this ); | ||
1244 | |||
1245 | // Finally, process editable's data. This data wasn't processed when loading | ||
1246 | // editor's data, becuase they need to be processed separately, with its own filters and settings. | ||
1247 | editable._.initialSetData = true; | ||
1248 | editable.setData( editable.getHtml() ); | ||
1249 | |||
1250 | return true; | ||
1251 | } | ||
1252 | |||
1253 | return false; | ||
1254 | }, | ||
1255 | |||
1256 | /** | ||
1257 | * Looks inside wrapper element to find a node that | ||
1258 | * matches given selector and is not nested in other widget. (http://dev.ckeditor.com/ticket/13334) | ||
1259 | * | ||
1260 | * @since 4.5 | ||
1261 | * @private | ||
1262 | * @param {String} selector Selector to match. | ||
1263 | * @returns {CKEDITOR.dom.element} Matched element or `null` if a node has not been found. | ||
1264 | */ | ||
1265 | _findOneNotNested: function( selector ) { | ||
1266 | var matchedElements = this.wrapper.find( selector ), | ||
1267 | match, | ||
1268 | closestWrapper; | ||
1269 | |||
1270 | for ( var i = 0; i < matchedElements.count(); i++ ) { | ||
1271 | match = matchedElements.getItem( i ); | ||
1272 | closestWrapper = match.getAscendant( Widget.isDomWidgetWrapper ); | ||
1273 | |||
1274 | // The closest ascendant-wrapper of this match defines to which widget | ||
1275 | // this match belongs. If the ascendant is this widget's wrapper | ||
1276 | // it means that the match is not nested in other widget. | ||
1277 | if ( this.wrapper.equals( closestWrapper ) ) { | ||
1278 | return match; | ||
1279 | } | ||
1280 | } | ||
1281 | |||
1282 | return null; | ||
1283 | }, | ||
1284 | |||
1285 | /** | ||
1286 | * Checks if a widget has already been initialized and has not been destroyed yet. | ||
1287 | * | ||
1288 | * See {@link #inited} for more details. | ||
1289 | * | ||
1290 | * @returns {Boolean} | ||
1291 | */ | ||
1292 | isInited: function() { | ||
1293 | return !!( this.wrapper && this.inited ); | ||
1294 | }, | ||
1295 | |||
1296 | /** | ||
1297 | * Checks if a widget is ready and has not been destroyed yet. | ||
1298 | * | ||
1299 | * See {@link #property-ready} for more details. | ||
1300 | * | ||
1301 | * @returns {Boolean} | ||
1302 | */ | ||
1303 | isReady: function() { | ||
1304 | return this.isInited() && this.ready; | ||
1305 | }, | ||
1306 | |||
1307 | /** | ||
1308 | * Focuses a widget by selecting it. | ||
1309 | */ | ||
1310 | focus: function() { | ||
1311 | var sel = this.editor.getSelection(); | ||
1312 | |||
1313 | // Fake the selection before focusing editor, to avoid unpreventable viewports scrolling | ||
1314 | // on Webkit/Blink/IE which is done because there's no selection or selection was somewhere else than widget. | ||
1315 | if ( sel ) { | ||
1316 | var isDirty = this.editor.checkDirty(); | ||
1317 | |||
1318 | sel.fake( this.wrapper ); | ||
1319 | |||
1320 | !isDirty && this.editor.resetDirty(); | ||
1321 | } | ||
1322 | |||
1323 | // Always focus editor (not only when focusManger.hasFocus is false) (because of http://dev.ckeditor.com/ticket/10483). | ||
1324 | this.editor.focus(); | ||
1325 | }, | ||
1326 | |||
1327 | /** | ||
1328 | * Removes a class from the widget element. This method is used by | ||
1329 | * the {@link #removeStyle} method and should be overriden by widgets | ||
1330 | * which should handle classes differently (e.g. on other elements). | ||
1331 | * | ||
1332 | * **Note**: This method should not be used directly. Use the {@link #setData} method to | ||
1333 | * set the `classes` property. Read more in the {@link #setData} documentation. | ||
1334 | * | ||
1335 | * See also: {@link #hasClass}, {@link #addClass}. | ||
1336 | * | ||
1337 | * @since 4.4 | ||
1338 | * @param {String} className The class to be removed. | ||
1339 | */ | ||
1340 | removeClass: function( className ) { | ||
1341 | this.element.removeClass( className ); | ||
1342 | this.wrapper.removeClass( Widget.WRAPPER_CLASS_PREFIX + className ); | ||
1343 | }, | ||
1344 | |||
1345 | /** | ||
1346 | * Removes the specified style from the widget. It is highly recommended to use the | ||
1347 | * {@link CKEDITOR.editor#removeStyle} or {@link CKEDITOR.style#remove} methods instead of | ||
1348 | * using this method directly, because unlike editor's and style's methods, this one | ||
1349 | * does not perform any checks. | ||
1350 | * | ||
1351 | * Read more about how applying/removing styles works in the {@link #applyStyle} method documentation. | ||
1352 | * | ||
1353 | * See also {@link #checkStyleActive}, {@link #applyStyle}, {@link #getClasses}. | ||
1354 | * | ||
1355 | * @since 4.4 | ||
1356 | * @param {CKEDITOR.style} style The custom widget style to be removed. | ||
1357 | */ | ||
1358 | removeStyle: function( style ) { | ||
1359 | applyRemoveStyle( this, style, 0 ); | ||
1360 | }, | ||
1361 | |||
1362 | /** | ||
1363 | * Sets widget value(s) in the {@link #property-data} object. | ||
1364 | * If the given value(s) modifies current ones, the {@link #event-data} event is fired. | ||
1365 | * | ||
1366 | * this.setData( 'align', 'left' ); | ||
1367 | * this.data.align; // -> 'left' | ||
1368 | * | ||
1369 | * this.setData( { align: 'right', opened: false } ); | ||
1370 | * this.data.align; // -> 'right' | ||
1371 | * this.data.opened; // -> false | ||
1372 | * | ||
1373 | * Set values are stored in {@link #element}'s attribute (`data-cke-widget-data`), | ||
1374 | * in a JSON string, therefore {@link #property-data} should contain | ||
1375 | * only serializable data. | ||
1376 | * | ||
1377 | * **Note:** A special data property, `classes`, exists. It contains an object with | ||
1378 | * classes which were returned by the {@link #getClasses} method during the widget initialization. | ||
1379 | * This property is then used by the {@link #applyStyle} and {@link #removeStyle} methods. | ||
1380 | * When it is changed (the reference to object must be changed!), the widget updates its classes by | ||
1381 | * using the {@link #addClass} and {@link #removeClass} methods. | ||
1382 | * | ||
1383 | * // Adding a new class. | ||
1384 | * var classes = CKEDITOR.tools.clone( widget.data.classes ); | ||
1385 | * classes.newClass = 1; | ||
1386 | * widget.setData( 'classes', classes ); | ||
1387 | * | ||
1388 | * // Removing a class. | ||
1389 | * var classes = CKEDITOR.tools.clone( widget.data.classes ); | ||
1390 | * delete classes.newClass; | ||
1391 | * widget.setData( 'classes', classes ); | ||
1392 | * | ||
1393 | * @param {String/Object} keyOrData | ||
1394 | * @param {Object} value | ||
1395 | * @chainable | ||
1396 | */ | ||
1397 | setData: function( key, value ) { | ||
1398 | var data = this.data, | ||
1399 | modified = 0; | ||
1400 | |||
1401 | if ( typeof key == 'string' ) { | ||
1402 | if ( data[ key ] !== value ) { | ||
1403 | data[ key ] = value; | ||
1404 | modified = 1; | ||
1405 | } | ||
1406 | } | ||
1407 | else { | ||
1408 | var newData = key; | ||
1409 | |||
1410 | for ( key in newData ) { | ||
1411 | if ( data[ key ] !== newData[ key ] ) { | ||
1412 | modified = 1; | ||
1413 | data[ key ] = newData[ key ]; | ||
1414 | } | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | // Block firing data event and overwriting data element before setupWidgetData is executed. | ||
1419 | if ( modified && this.dataReady ) { | ||
1420 | writeDataToElement( this ); | ||
1421 | this.fire( 'data', data ); | ||
1422 | } | ||
1423 | |||
1424 | return this; | ||
1425 | }, | ||
1426 | |||
1427 | /** | ||
1428 | * Changes the widget's focus state. This method is executed automatically after | ||
1429 | * a widget was focused by the {@link #method-focus} method or the selection was moved | ||
1430 | * out of the widget. | ||
1431 | * | ||
1432 | * This is a low-level method which is not integrated with e.g. the undo manager. | ||
1433 | * Use the {@link #method-focus} method instead. | ||
1434 | * | ||
1435 | * @param {Boolean} selected Whether to select or deselect this widget. | ||
1436 | * @chainable | ||
1437 | */ | ||
1438 | setFocused: function( focused ) { | ||
1439 | this.wrapper[ focused ? 'addClass' : 'removeClass' ]( 'cke_widget_focused' ); | ||
1440 | this.fire( focused ? 'focus' : 'blur' ); | ||
1441 | return this; | ||
1442 | }, | ||
1443 | |||
1444 | /** | ||
1445 | * Changes the widget's select state. This method is executed automatically after | ||
1446 | * a widget was selected by the {@link #method-focus} method or the selection | ||
1447 | * was moved out of the widget. | ||
1448 | * | ||
1449 | * This is a low-level method which is not integrated with e.g. the undo manager. | ||
1450 | * Use the {@link #method-focus} method instead or simply change the selection. | ||
1451 | * | ||
1452 | * @param {Boolean} selected Whether to select or deselect this widget. | ||
1453 | * @chainable | ||
1454 | */ | ||
1455 | setSelected: function( selected ) { | ||
1456 | this.wrapper[ selected ? 'addClass' : 'removeClass' ]( 'cke_widget_selected' ); | ||
1457 | this.fire( selected ? 'select' : 'deselect' ); | ||
1458 | return this; | ||
1459 | }, | ||
1460 | |||
1461 | /** | ||
1462 | * Repositions drag handler according to the widget's element position. Should be called from events, like mouseover. | ||
1463 | */ | ||
1464 | updateDragHandlerPosition: function() { | ||
1465 | var editor = this.editor, | ||
1466 | domElement = this.element.$, | ||
1467 | oldPos = this._.dragHandlerOffset, | ||
1468 | newPos = { | ||
1469 | x: domElement.offsetLeft, | ||
1470 | y: domElement.offsetTop - DRAG_HANDLER_SIZE | ||
1471 | }; | ||
1472 | |||
1473 | if ( oldPos && newPos.x == oldPos.x && newPos.y == oldPos.y ) | ||
1474 | return; | ||
1475 | |||
1476 | // We need to make sure that dirty state is not changed (http://dev.ckeditor.com/ticket/11487). | ||
1477 | var initialDirty = editor.checkDirty(); | ||
1478 | |||
1479 | editor.fire( 'lockSnapshot' ); | ||
1480 | this.dragHandlerContainer.setStyles( { | ||
1481 | top: newPos.y + 'px', | ||
1482 | left: newPos.x + 'px', | ||
1483 | display: 'block' | ||
1484 | } ); | ||
1485 | editor.fire( 'unlockSnapshot' ); | ||
1486 | !initialDirty && editor.resetDirty(); | ||
1487 | |||
1488 | this._.dragHandlerOffset = newPos; | ||
1489 | } | ||
1490 | }; | ||
1491 | |||
1492 | CKEDITOR.event.implementOn( Widget.prototype ); | ||
1493 | |||
1494 | /** | ||
1495 | * Gets the {@link #isDomNestedEditable nested editable} | ||
1496 | * (returned as a {@link CKEDITOR.dom.element}, not as a {@link CKEDITOR.plugins.widget.nestedEditable}) | ||
1497 | * closest to the `node` or the `node` if it is a nested editable itself. | ||
1498 | * | ||
1499 | * @since 4.5 | ||
1500 | * @static | ||
1501 | * @param {CKEDITOR.dom.element} guard Stop ancestor search on this node (usually editor's editable). | ||
1502 | * @param {CKEDITOR.dom.node} node Start the search from this node. | ||
1503 | * @returns {CKEDITOR.dom.element/null} Element or `null` if not found. | ||
1504 | */ | ||
1505 | Widget.getNestedEditable = function( guard, node ) { | ||
1506 | if ( !node || node.equals( guard ) ) | ||
1507 | return null; | ||
1508 | |||
1509 | if ( Widget.isDomNestedEditable( node ) ) | ||
1510 | return node; | ||
1511 | |||
1512 | return Widget.getNestedEditable( guard, node.getParent() ); | ||
1513 | }; | ||
1514 | |||
1515 | /** | ||
1516 | * Checks whether the `node` is a widget's drag handle element. | ||
1517 | * | ||
1518 | * @since 4.5 | ||
1519 | * @static | ||
1520 | * @param {CKEDITOR.dom.node} node | ||
1521 | * @returns {Boolean} | ||
1522 | */ | ||
1523 | Widget.isDomDragHandler = function( node ) { | ||
1524 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-drag-handler' ); | ||
1525 | }; | ||
1526 | |||
1527 | /** | ||
1528 | * Checks whether the `node` is a container of the widget's drag handle element. | ||
1529 | * | ||
1530 | * @since 4.5 | ||
1531 | * @static | ||
1532 | * @param {CKEDITOR.dom.node} node | ||
1533 | * @returns {Boolean} | ||
1534 | */ | ||
1535 | Widget.isDomDragHandlerContainer = function( node ) { | ||
1536 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasClass( 'cke_widget_drag_handler_container' ); | ||
1537 | }; | ||
1538 | |||
1539 | /** | ||
1540 | * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#editables nested editable}. | ||
1541 | * Note that this function only checks whether it is the right element, not whether | ||
1542 | * the passed `node` is an instance of {@link CKEDITOR.plugins.widget.nestedEditable}. | ||
1543 | * | ||
1544 | * @since 4.5 | ||
1545 | * @static | ||
1546 | * @param {CKEDITOR.dom.node} node | ||
1547 | * @returns {Boolean} | ||
1548 | */ | ||
1549 | Widget.isDomNestedEditable = function( node ) { | ||
1550 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-editable' ); | ||
1551 | }; | ||
1552 | |||
1553 | /** | ||
1554 | * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}. | ||
1555 | * | ||
1556 | * @since 4.5 | ||
1557 | * @static | ||
1558 | * @param {CKEDITOR.dom.node} node | ||
1559 | * @returns {Boolean} | ||
1560 | */ | ||
1561 | Widget.isDomWidgetElement = function( node ) { | ||
1562 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-widget' ); | ||
1563 | }; | ||
1564 | |||
1565 | /** | ||
1566 | * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}. | ||
1567 | * | ||
1568 | * @since 4.5 | ||
1569 | * @static | ||
1570 | * @param {CKEDITOR.dom.element} node | ||
1571 | * @returns {Boolean} | ||
1572 | */ | ||
1573 | Widget.isDomWidgetWrapper = function( node ) { | ||
1574 | return node.type == CKEDITOR.NODE_ELEMENT && node.hasAttribute( 'data-cke-widget-wrapper' ); | ||
1575 | }; | ||
1576 | |||
1577 | /** | ||
1578 | * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#element widget element}. | ||
1579 | * | ||
1580 | * @since 4.5 | ||
1581 | * @static | ||
1582 | * @param {CKEDITOR.htmlParser.node} node | ||
1583 | * @returns {Boolean} | ||
1584 | */ | ||
1585 | Widget.isParserWidgetElement = function( node ) { | ||
1586 | return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-widget' ]; | ||
1587 | }; | ||
1588 | |||
1589 | /** | ||
1590 | * Checks whether the `node` is a {@link CKEDITOR.plugins.widget#wrapper widget wrapper}. | ||
1591 | * | ||
1592 | * @since 4.5 | ||
1593 | * @static | ||
1594 | * @param {CKEDITOR.htmlParser.element} node | ||
1595 | * @returns {Boolean} | ||
1596 | */ | ||
1597 | Widget.isParserWidgetWrapper = function( node ) { | ||
1598 | return node.type == CKEDITOR.NODE_ELEMENT && !!node.attributes[ 'data-cke-widget-wrapper' ]; | ||
1599 | }; | ||
1600 | |||
1601 | /** | ||
1602 | * Prefix added to wrapper classes. Each class added to the widget element by the {@link #addClass} | ||
1603 | * method will also be added to the wrapper prefixed with it. | ||
1604 | * | ||
1605 | * @since 4.6.0 | ||
1606 | * @static | ||
1607 | * @readonly | ||
1608 | * @property {String} [='cke_widget_wrapper_'] | ||
1609 | */ | ||
1610 | Widget.WRAPPER_CLASS_PREFIX = 'cke_widget_wrapper_'; | ||
1611 | |||
1612 | /** | ||
1613 | * An event fired when a widget is ready (fully initialized). This event is fired after: | ||
1614 | * | ||
1615 | * * {@link #init} is called, | ||
1616 | * * The first {@link #event-data} event is fired, | ||
1617 | * * A widget is attached to the document. | ||
1618 | * | ||
1619 | * Therefore, in case of widget creation with a command which opens a dialog window, this event | ||
1620 | * will be delayed after the dialog window is closed and the widget is finally inserted into the document. | ||
1621 | * | ||
1622 | * **Note**: If your widget does not use automatic dialog window binding (i.e. you open the dialog window manually) | ||
1623 | * or another situation in which the widget wrapper is not attached to document at the time when it is | ||
1624 | * initialized occurs, you need to take care of firing {@link #event-ready} yourself. | ||
1625 | * | ||
1626 | * See also {@link #property-ready} and {@link #property-inited} properties, and | ||
1627 | * {@link #isReady} and {@link #isInited} methods. | ||
1628 | * | ||
1629 | * @event ready | ||
1630 | */ | ||
1631 | |||
1632 | /** | ||
1633 | * An event fired when a widget is about to be destroyed, but before it is | ||
1634 | * fully torn down. | ||
1635 | * | ||
1636 | * @event destroy | ||
1637 | */ | ||
1638 | |||
1639 | /** | ||
1640 | * An event fired when a widget is focused. | ||
1641 | * | ||
1642 | * Widget can be focused by executing {@link #method-focus}. | ||
1643 | * | ||
1644 | * @event focus | ||
1645 | */ | ||
1646 | |||
1647 | /** | ||
1648 | * An event fired when a widget is blurred. | ||
1649 | * | ||
1650 | * @event blur | ||
1651 | */ | ||
1652 | |||
1653 | /** | ||
1654 | * An event fired when a widget is selected. | ||
1655 | * | ||
1656 | * @event select | ||
1657 | */ | ||
1658 | |||
1659 | /** | ||
1660 | * An event fired when a widget is deselected. | ||
1661 | * | ||
1662 | * @event deselect | ||
1663 | */ | ||
1664 | |||
1665 | /** | ||
1666 | * An event fired by the {@link #method-edit} method. It can be canceled | ||
1667 | * in order to stop the default action (opening a dialog window and/or | ||
1668 | * {@link CKEDITOR.plugins.widget.repository#finalizeCreation finalizing widget creation}). | ||
1669 | * | ||
1670 | * @event edit | ||
1671 | * @param data | ||
1672 | * @param {String} data.dialog Defaults to {@link CKEDITOR.plugins.widget.definition#dialog} | ||
1673 | * and can be changed or set by the listener. | ||
1674 | */ | ||
1675 | |||
1676 | /** | ||
1677 | * An event fired when a dialog window for widget editing is opened. | ||
1678 | * This event can be canceled in order to handle the editing dialog in a custom manner. | ||
1679 | * | ||
1680 | * @event dialog | ||
1681 | * @param {CKEDITOR.dialog} data The opened dialog window instance. | ||
1682 | */ | ||
1683 | |||
1684 | /** | ||
1685 | * An event fired when a key is pressed on a focused widget. | ||
1686 | * This event is forwarded from the {@link CKEDITOR.editor#key} event and | ||
1687 | * has the ability to block editor keystrokes if it is canceled. | ||
1688 | * | ||
1689 | * @event key | ||
1690 | * @param data | ||
1691 | * @param {Number} data.keyCode A number representing the key code (or combination). | ||
1692 | */ | ||
1693 | |||
1694 | /** | ||
1695 | * An event fired when a widget is double clicked. | ||
1696 | * | ||
1697 | * **Note:** If a default editing action is executed on double click (i.e. a widget has a | ||
1698 | * {@link CKEDITOR.plugins.widget.definition#dialog dialog} defined and the {@link #event-doubleclick} event was not | ||
1699 | * canceled), this event will be automatically canceled, so a listener added with the default priority (10) | ||
1700 | * will not be executed. Use a listener with low priority (e.g. 5) to be sure that it will be executed. | ||
1701 | * | ||
1702 | * widget.on( 'doubleclick', function( evt ) { | ||
1703 | * console.log( 'widget#doubleclick' ); | ||
1704 | * }, null, null, 5 ); | ||
1705 | * | ||
1706 | * If your widget handles double click in a special way (so the default editing action is not executed), | ||
1707 | * make sure you cancel this event, because otherwise it will be propagated to {@link CKEDITOR.editor#doubleclick} | ||
1708 | * and another feature may step in (e.g. a Link dialog window may be opened if your widget was inside a link). | ||
1709 | * | ||
1710 | * @event doubleclick | ||
1711 | * @param data | ||
1712 | * @param {CKEDITOR.dom.element} data.element The double-clicked element. | ||
1713 | */ | ||
1714 | |||
1715 | /** | ||
1716 | * An event fired when the context menu is opened for a widget. | ||
1717 | * | ||
1718 | * @event contextMenu | ||
1719 | * @param data The object containing context menu options to be added | ||
1720 | * for this widget. See {@link CKEDITOR.plugins.contextMenu#addListener}. | ||
1721 | */ | ||
1722 | |||
1723 | /** | ||
1724 | * An event fired when the widget data changed. See the {@link #setData} method and the {@link #property-data} property. | ||
1725 | * | ||
1726 | * @event data | ||
1727 | */ | ||
1728 | |||
1729 | |||
1730 | |||
1731 | /** | ||
1732 | * The wrapper class for editable elements inside widgets. | ||
1733 | * | ||
1734 | * Do not use directly. Use {@link CKEDITOR.plugins.widget.definition#editables} or | ||
1735 | * {@link CKEDITOR.plugins.widget#initEditable}. | ||
1736 | * | ||
1737 | * @class CKEDITOR.plugins.widget.nestedEditable | ||
1738 | * @extends CKEDITOR.dom.element | ||
1739 | * @constructor | ||
1740 | * @param {CKEDITOR.editor} editor | ||
1741 | * @param {CKEDITOR.dom.element} element | ||
1742 | * @param config | ||
1743 | * @param {CKEDITOR.filter} [config.filter] | ||
1744 | */ | ||
1745 | function NestedEditable( editor, element, config ) { | ||
1746 | // Call the base constructor. | ||
1747 | CKEDITOR.dom.element.call( this, element.$ ); | ||
1748 | this.editor = editor; | ||
1749 | this._ = {}; | ||
1750 | var filter = this.filter = config.filter; | ||
1751 | |||
1752 | // If blockless editable - always use BR mode. | ||
1753 | if ( !CKEDITOR.dtd[ this.getName() ].p ) | ||
1754 | this.enterMode = this.shiftEnterMode = CKEDITOR.ENTER_BR; | ||
1755 | else { | ||
1756 | this.enterMode = filter ? filter.getAllowedEnterMode( editor.enterMode ) : editor.enterMode; | ||
1757 | this.shiftEnterMode = filter ? filter.getAllowedEnterMode( editor.shiftEnterMode, true ) : editor.shiftEnterMode; | ||
1758 | } | ||
1759 | } | ||
1760 | |||
1761 | NestedEditable.prototype = CKEDITOR.tools.extend( CKEDITOR.tools.prototypedCopy( CKEDITOR.dom.element.prototype ), { | ||
1762 | /** | ||
1763 | * Sets the editable data. The data will be passed through the {@link CKEDITOR.editor#dataProcessor} | ||
1764 | * and the {@link CKEDITOR.editor#filter}. This ensures that the data was filtered and prepared to be | ||
1765 | * edited like the {@link CKEDITOR.editor#method-setData editor data}. | ||
1766 | * | ||
1767 | * Before content is changed, all nested widgets are destroyed. Afterwards, after new content is loaded, | ||
1768 | * all nested widgets are initialized. | ||
1769 | * | ||
1770 | * @param {String} data | ||
1771 | */ | ||
1772 | setData: function( data ) { | ||
1773 | // For performance reasons don't call destroyAll when initializing a nested editable, | ||
1774 | // because there are no widgets inside. | ||
1775 | if ( !this._.initialSetData ) { | ||
1776 | // Destroy all nested widgets before setting data. | ||
1777 | this.editor.widgets.destroyAll( false, this ); | ||
1778 | } | ||
1779 | this._.initialSetData = false; | ||
1780 | |||
1781 | data = this.editor.dataProcessor.toHtml( data, { | ||
1782 | context: this.getName(), | ||
1783 | filter: this.filter, | ||
1784 | enterMode: this.enterMode | ||
1785 | } ); | ||
1786 | this.setHtml( data ); | ||
1787 | |||
1788 | this.editor.widgets.initOnAll( this ); | ||
1789 | }, | ||
1790 | |||
1791 | /** | ||
1792 | * Gets the editable data. Like {@link #setData}, this method will process and filter the data. | ||
1793 | * | ||
1794 | * @returns {String} | ||
1795 | */ | ||
1796 | getData: function() { | ||
1797 | return this.editor.dataProcessor.toDataFormat( this.getHtml(), { | ||
1798 | context: this.getName(), | ||
1799 | filter: this.filter, | ||
1800 | enterMode: this.enterMode | ||
1801 | } ); | ||
1802 | } | ||
1803 | } ); | ||
1804 | |||
1805 | /** | ||
1806 | * The editor instance. | ||
1807 | * | ||
1808 | * @readonly | ||
1809 | * @property {CKEDITOR.editor} editor | ||
1810 | */ | ||
1811 | |||
1812 | /** | ||
1813 | * The filter instance if allowed content rules were defined. | ||
1814 | * | ||
1815 | * @readonly | ||
1816 | * @property {CKEDITOR.filter} filter | ||
1817 | */ | ||
1818 | |||
1819 | /** | ||
1820 | * The enter mode active in this editable. | ||
1821 | * It is determined from editable's name (whether it is a blockless editable), | ||
1822 | * its allowed content rules (if defined) and the default editor's mode. | ||
1823 | * | ||
1824 | * @readonly | ||
1825 | * @property {Number} enterMode | ||
1826 | */ | ||
1827 | |||
1828 | /** | ||
1829 | * The shift enter move active in this editable. | ||
1830 | * | ||
1831 | * @readonly | ||
1832 | * @property {Number} shiftEnterMode | ||
1833 | */ | ||
1834 | |||
1835 | |||
1836 | // | ||
1837 | // REPOSITORY helpers ----------------------------------------------------- | ||
1838 | // | ||
1839 | |||
1840 | function addWidgetButtons( editor ) { | ||
1841 | var widgets = editor.widgets.registered, | ||
1842 | widget, | ||
1843 | widgetName, | ||
1844 | widgetButton; | ||
1845 | |||
1846 | for ( widgetName in widgets ) { | ||
1847 | widget = widgets[ widgetName ]; | ||
1848 | |||
1849 | // Create button if defined. | ||
1850 | widgetButton = widget.button; | ||
1851 | if ( widgetButton && editor.ui.addButton ) { | ||
1852 | editor.ui.addButton( CKEDITOR.tools.capitalize( widget.name, true ), { | ||
1853 | label: widgetButton, | ||
1854 | command: widget.name, | ||
1855 | toolbar: 'insert,10' | ||
1856 | } ); | ||
1857 | } | ||
1858 | } | ||
1859 | } | ||
1860 | |||
1861 | // Create a command creating and editing widget. | ||
1862 | // | ||
1863 | // @param editor | ||
1864 | // @param {CKEDITOR.plugins.widget.definition} widgetDef | ||
1865 | function addWidgetCommand( editor, widgetDef ) { | ||
1866 | editor.addCommand( widgetDef.name, { | ||
1867 | exec: function( editor, commandData ) { | ||
1868 | var focused = editor.widgets.focused; | ||
1869 | // If a widget of the same type is focused, start editing. | ||
1870 | if ( focused && focused.name == widgetDef.name ) | ||
1871 | focused.edit(); | ||
1872 | // Otherwise... | ||
1873 | // ... use insert method is was defined. | ||
1874 | else if ( widgetDef.insert ) | ||
1875 | widgetDef.insert(); | ||
1876 | // ... or create a brand-new widget from template. | ||
1877 | else if ( widgetDef.template ) { | ||
1878 | var defaults = typeof widgetDef.defaults == 'function' ? widgetDef.defaults() : widgetDef.defaults, | ||
1879 | element = CKEDITOR.dom.element.createFromHtml( widgetDef.template.output( defaults ) ), | ||
1880 | instance, | ||
1881 | wrapper = editor.widgets.wrapElement( element, widgetDef.name ), | ||
1882 | temp = new CKEDITOR.dom.documentFragment( wrapper.getDocument() ); | ||
1883 | |||
1884 | // Append wrapper to a temporary document. This will unify the environment | ||
1885 | // in which #data listeners work when creating and editing widget. | ||
1886 | temp.append( wrapper ); | ||
1887 | instance = editor.widgets.initOn( element, widgetDef, commandData && commandData.startupData ); | ||
1888 | |||
1889 | // Instance could be destroyed during initialization. | ||
1890 | // In this case finalize creation if some new widget | ||
1891 | // was left in temporary document fragment. | ||
1892 | if ( !instance ) { | ||
1893 | finalizeCreation(); | ||
1894 | return; | ||
1895 | } | ||
1896 | |||
1897 | // Listen on edit to finalize widget insertion. | ||
1898 | // | ||
1899 | // * If dialog was set, then insert widget after dialog was successfully saved or destroy this | ||
1900 | // temporary instance. | ||
1901 | // * If dialog wasn't set and edit wasn't canceled, insert widget. | ||
1902 | var editListener = instance.once( 'edit', function( evt ) { | ||
1903 | if ( evt.data.dialog ) { | ||
1904 | instance.once( 'dialog', function( evt ) { | ||
1905 | var dialog = evt.data, | ||
1906 | okListener, | ||
1907 | cancelListener; | ||
1908 | |||
1909 | // Finalize creation AFTER (20) new data was set. | ||
1910 | okListener = dialog.once( 'ok', finalizeCreation, null, null, 20 ); | ||
1911 | |||
1912 | cancelListener = dialog.once( 'cancel', function( evt ) { | ||
1913 | if ( !( evt.data && evt.data.hide === false ) ) { | ||
1914 | editor.widgets.destroy( instance, true ); | ||
1915 | } | ||
1916 | } ); | ||
1917 | |||
1918 | dialog.once( 'hide', function() { | ||
1919 | okListener.removeListener(); | ||
1920 | cancelListener.removeListener(); | ||
1921 | } ); | ||
1922 | } ); | ||
1923 | } else { | ||
1924 | // Dialog hasn't been set, so insert widget now. | ||
1925 | finalizeCreation(); | ||
1926 | } | ||
1927 | }, null, null, 999 ); | ||
1928 | |||
1929 | instance.edit(); | ||
1930 | |||
1931 | // Remove listener in case someone canceled it before this | ||
1932 | // listener was executed. | ||
1933 | editListener.removeListener(); | ||
1934 | } | ||
1935 | |||
1936 | function finalizeCreation() { | ||
1937 | editor.widgets.finalizeCreation( temp ); | ||
1938 | } | ||
1939 | }, | ||
1940 | |||
1941 | allowedContent: widgetDef.allowedContent, | ||
1942 | requiredContent: widgetDef.requiredContent, | ||
1943 | contentForms: widgetDef.contentForms, | ||
1944 | contentTransformations: widgetDef.contentTransformations | ||
1945 | } ); | ||
1946 | } | ||
1947 | |||
1948 | function addWidgetProcessors( widgetsRepo, widgetDef ) { | ||
1949 | var upcast = widgetDef.upcast, | ||
1950 | upcasts, | ||
1951 | priority = widgetDef.upcastPriority || 10; | ||
1952 | |||
1953 | if ( !upcast ) | ||
1954 | return; | ||
1955 | |||
1956 | // Multiple upcasts defined in string. | ||
1957 | if ( typeof upcast == 'string' ) { | ||
1958 | upcasts = upcast.split( ',' ); | ||
1959 | while ( upcasts.length ) { | ||
1960 | addUpcast( widgetDef.upcasts[ upcasts.pop() ], widgetDef.name, priority ); | ||
1961 | } | ||
1962 | } | ||
1963 | // Single rule which is automatically activated. | ||
1964 | else { | ||
1965 | addUpcast( upcast, widgetDef.name, priority ); | ||
1966 | } | ||
1967 | |||
1968 | function addUpcast( upcast, name, priority ) { | ||
1969 | // Find index of the first higher (in terms of value) priority upcast. | ||
1970 | var index = CKEDITOR.tools.getIndex( widgetsRepo._.upcasts, function( element ) { | ||
1971 | return element[ 2 ] > priority; | ||
1972 | } ); | ||
1973 | // Add at the end if it is the highest priority so far. | ||
1974 | if ( index < 0 ) { | ||
1975 | index = widgetsRepo._.upcasts.length; | ||
1976 | } | ||
1977 | |||
1978 | widgetsRepo._.upcasts.splice( index, 0, [ upcast, name, priority ] ); | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | function blurWidget( widgetsRepo, widget ) { | ||
1983 | widgetsRepo.focused = null; | ||
1984 | |||
1985 | if ( widget.isInited() ) { | ||
1986 | var isDirty = widget.editor.checkDirty(); | ||
1987 | |||
1988 | // Widget could be destroyed in the meantime - e.g. data could be set. | ||
1989 | widgetsRepo.fire( 'widgetBlurred', { widget: widget } ); | ||
1990 | widget.setFocused( false ); | ||
1991 | |||
1992 | !isDirty && widget.editor.resetDirty(); | ||
1993 | } | ||
1994 | } | ||
1995 | |||
1996 | function checkWidgets( evt ) { | ||
1997 | var options = evt.data; | ||
1998 | |||
1999 | if ( this.editor.mode != 'wysiwyg' ) | ||
2000 | return; | ||
2001 | |||
2002 | var editable = this.editor.editable(), | ||
2003 | instances = this.instances, | ||
2004 | newInstances, i, count, wrapper, notYetInitialized; | ||
2005 | |||
2006 | if ( !editable ) | ||
2007 | return; | ||
2008 | |||
2009 | // Remove widgets which have no corresponding elements in DOM. | ||
2010 | for ( i in instances ) { | ||
2011 | // http://dev.ckeditor.com/ticket/13410 Remove widgets that are ready. This prevents from destroying widgets that are during loading process. | ||
2012 | if ( instances[ i ].isReady() && !editable.contains( instances[ i ].wrapper ) ) | ||
2013 | this.destroy( instances[ i ], true ); | ||
2014 | } | ||
2015 | |||
2016 | // Init on all (new) if initOnlyNew option was passed. | ||
2017 | if ( options && options.initOnlyNew ) | ||
2018 | newInstances = this.initOnAll(); | ||
2019 | else { | ||
2020 | var wrappers = editable.find( '.cke_widget_wrapper' ); | ||
2021 | newInstances = []; | ||
2022 | |||
2023 | // Create widgets on existing wrappers if they do not exists. | ||
2024 | for ( i = 0, count = wrappers.count(); i < count; i++ ) { | ||
2025 | wrapper = wrappers.getItem( i ); | ||
2026 | notYetInitialized = !this.getByElement( wrapper, true ); | ||
2027 | |||
2028 | // Check if: | ||
2029 | // * there's no instance for this widget | ||
2030 | // * wrapper is not inside some temporary element like copybin (http://dev.ckeditor.com/ticket/11088) | ||
2031 | // * it was a nested widget's wrapper which has been detached from DOM, | ||
2032 | // when nested editable has been initialized (it overwrites its innerHTML | ||
2033 | // and initializes nested widgets). | ||
2034 | if ( notYetInitialized && !findParent( wrapper, isDomTemp ) && editable.contains( wrapper ) ) { | ||
2035 | // Add cke_widget_new class because otherwise | ||
2036 | // widget will not be created on such wrapper. | ||
2037 | wrapper.addClass( 'cke_widget_new' ); | ||
2038 | newInstances.push( this.initOn( wrapper.getFirst( Widget.isDomWidgetElement ) ) ); | ||
2039 | } | ||
2040 | } | ||
2041 | } | ||
2042 | |||
2043 | // If only single widget was initialized and focusInited was passed, focus it. | ||
2044 | if ( options && options.focusInited && newInstances.length == 1 ) | ||
2045 | newInstances[ 0 ].focus(); | ||
2046 | } | ||
2047 | |||
2048 | // Unwraps widget element and clean up element. | ||
2049 | // | ||
2050 | // This function is used to clean up pasted widgets. | ||
2051 | // It should have similar result to widget#destroy plus | ||
2052 | // some additional adjustments, specific for pasting. | ||
2053 | // | ||
2054 | // @param {CKEDITOR.htmlParser.element} el | ||
2055 | function cleanUpWidgetElement( el ) { | ||
2056 | var parent = el.parent; | ||
2057 | if ( parent.type == CKEDITOR.NODE_ELEMENT && parent.attributes[ 'data-cke-widget-wrapper' ] ) | ||
2058 | parent.replaceWith( el ); | ||
2059 | } | ||
2060 | |||
2061 | // Similar to cleanUpWidgetElement, but works on DOM and finds | ||
2062 | // widget elements by its own. | ||
2063 | // | ||
2064 | // Unlike cleanUpWidgetElement it will wrap element back. | ||
2065 | // | ||
2066 | // @param {CKEDITOR.dom.element} container | ||
2067 | function cleanUpAllWidgetElements( widgetsRepo, container ) { | ||
2068 | var wrappers = container.find( '.cke_widget_wrapper' ), | ||
2069 | wrapper, element, | ||
2070 | i = 0, | ||
2071 | l = wrappers.count(); | ||
2072 | |||
2073 | for ( ; i < l; ++i ) { | ||
2074 | wrapper = wrappers.getItem( i ); | ||
2075 | element = wrapper.getFirst( Widget.isDomWidgetElement ); | ||
2076 | // If wrapper contains widget element - unwrap it and wrap again. | ||
2077 | if ( element.type == CKEDITOR.NODE_ELEMENT && element.data( 'widget' ) ) { | ||
2078 | element.replace( wrapper ); | ||
2079 | widgetsRepo.wrapElement( element ); | ||
2080 | } else { | ||
2081 | // Otherwise - something is wrong... clean this up. | ||
2082 | wrapper.remove(); | ||
2083 | } | ||
2084 | } | ||
2085 | } | ||
2086 | |||
2087 | // Creates {@link CKEDITOR.filter} instance for given widget, editable and rules. | ||
2088 | // | ||
2089 | // Once filter for widget-editable pair is created it is cached, so the same instance | ||
2090 | // will be returned when method is executed again. | ||
2091 | // | ||
2092 | // @param {String} widgetName | ||
2093 | // @param {String} editableName | ||
2094 | // @param {CKEDITOR.plugins.widget.nestedEditableDefinition} editableDefinition The nested editable definition. | ||
2095 | // @returns {CKEDITOR.filter} Filter instance or `null` if rules are not defined. | ||
2096 | // @context CKEDITOR.plugins.widget.repository | ||
2097 | function createEditableFilter( widgetName, editableName, editableDefinition ) { | ||
2098 | if ( !editableDefinition.allowedContent ) | ||
2099 | return null; | ||
2100 | |||
2101 | var editables = this._.filters[ widgetName ]; | ||
2102 | |||
2103 | if ( !editables ) | ||
2104 | this._.filters[ widgetName ] = editables = {}; | ||
2105 | |||
2106 | var filter = editables[ editableName ]; | ||
2107 | |||
2108 | if ( !filter ) | ||
2109 | editables[ editableName ] = filter = new CKEDITOR.filter( editableDefinition.allowedContent ); | ||
2110 | |||
2111 | return filter; | ||
2112 | } | ||
2113 | |||
2114 | // Creates an iterator function which when executed on all | ||
2115 | // elements in DOM tree will gather elements that should be wrapped | ||
2116 | // and initialized as widgets. | ||
2117 | function createUpcastIterator( widgetsRepo ) { | ||
2118 | var toBeWrapped = [], | ||
2119 | upcasts = widgetsRepo._.upcasts, | ||
2120 | upcastCallbacks = widgetsRepo._.upcastCallbacks; | ||
2121 | |||
2122 | return { | ||
2123 | toBeWrapped: toBeWrapped, | ||
2124 | |||
2125 | iterator: function( element ) { | ||
2126 | var upcast, upcasted, | ||
2127 | data, | ||
2128 | i, | ||
2129 | upcastsLength, | ||
2130 | upcastCallbacksLength; | ||
2131 | |||
2132 | // Wrapper found - find widget element, add it to be | ||
2133 | // cleaned up (unwrapped) and wrapped and stop iterating in this branch. | ||
2134 | if ( 'data-cke-widget-wrapper' in element.attributes ) { | ||
2135 | element = element.getFirst( Widget.isParserWidgetElement ); | ||
2136 | |||
2137 | if ( element ) | ||
2138 | toBeWrapped.push( [ element ] ); | ||
2139 | |||
2140 | // Do not iterate over descendants. | ||
2141 | return false; | ||
2142 | } | ||
2143 | // Widget element found - add it to be cleaned up (just in case) | ||
2144 | // and wrapped and stop iterating in this branch. | ||
2145 | else if ( 'data-widget' in element.attributes ) { | ||
2146 | toBeWrapped.push( [ element ] ); | ||
2147 | |||
2148 | // Do not iterate over descendants. | ||
2149 | return false; | ||
2150 | } | ||
2151 | else if ( ( upcastsLength = upcasts.length ) ) { | ||
2152 | // Ignore elements with data-cke-widget-upcasted to avoid multiple upcasts (http://dev.ckeditor.com/ticket/11533). | ||
2153 | // Do not iterate over descendants. | ||
2154 | if ( element.attributes[ 'data-cke-widget-upcasted' ] ) | ||
2155 | return false; | ||
2156 | |||
2157 | // Check element with upcast callbacks first. | ||
2158 | // If any of them return false abort upcasting. | ||
2159 | for ( i = 0, upcastCallbacksLength = upcastCallbacks.length; i < upcastCallbacksLength; ++i ) { | ||
2160 | if ( upcastCallbacks[ i ]( element ) === false ) | ||
2161 | return; | ||
2162 | // Return nothing in order to continue iterating over ascendants. | ||
2163 | // See http://dev.ckeditor.com/ticket/11186#comment:6 | ||
2164 | } | ||
2165 | |||
2166 | for ( i = 0; i < upcastsLength; ++i ) { | ||
2167 | upcast = upcasts[ i ]; | ||
2168 | data = {}; | ||
2169 | |||
2170 | if ( ( upcasted = upcast[ 0 ]( element, data ) ) ) { | ||
2171 | // If upcast function returned element, upcast this one. | ||
2172 | // It can be e.g. a new element wrapping the original one. | ||
2173 | if ( upcasted instanceof CKEDITOR.htmlParser.element ) | ||
2174 | element = upcasted; | ||
2175 | |||
2176 | // Set initial data attr with data from upcast method. | ||
2177 | element.attributes[ 'data-cke-widget-data' ] = encodeURIComponent( JSON.stringify( data ) ); | ||
2178 | element.attributes[ 'data-cke-widget-upcasted' ] = 1; | ||
2179 | |||
2180 | toBeWrapped.push( [ element, upcast[ 1 ] ] ); | ||
2181 | |||
2182 | // Do not iterate over descendants. | ||
2183 | return false; | ||
2184 | } | ||
2185 | } | ||
2186 | } | ||
2187 | } | ||
2188 | }; | ||
2189 | } | ||
2190 | |||
2191 | // Finds a first parent that matches query. | ||
2192 | // | ||
2193 | // @param {CKEDITOR.dom.element} element | ||
2194 | // @param {Function} query | ||
2195 | function findParent( element, query ) { | ||
2196 | var parent = element; | ||
2197 | |||
2198 | while ( ( parent = parent.getParent() ) ) { | ||
2199 | if ( query( parent ) ) | ||
2200 | return true; | ||
2201 | } | ||
2202 | return false; | ||
2203 | } | ||
2204 | |||
2205 | function getWrapperAttributes( inlineWidget, name ) { | ||
2206 | return { | ||
2207 | // tabindex="-1" means that it can receive focus by code. | ||
2208 | tabindex: -1, | ||
2209 | contenteditable: 'false', | ||
2210 | 'data-cke-widget-wrapper': 1, | ||
2211 | 'data-cke-filter': 'off', | ||
2212 | // Class cke_widget_new marks widgets which haven't been initialized yet. | ||
2213 | 'class': 'cke_widget_wrapper cke_widget_new cke_widget_' + | ||
2214 | ( inlineWidget ? 'inline' : 'block' ) + | ||
2215 | ( name ? ' cke_widget_' + name : '' ) | ||
2216 | }; | ||
2217 | } | ||
2218 | |||
2219 | // Inserts element at given index. | ||
2220 | // It will check DTD and split ancestor elements up to the first | ||
2221 | // that can contain this element. | ||
2222 | // | ||
2223 | // @param {CKEDITOR.htmlParser.element} parent | ||
2224 | // @param {Number} index | ||
2225 | // @param {CKEDITOR.htmlParser.element} element | ||
2226 | function insertElement( parent, index, element ) { | ||
2227 | // Do not split doc fragment... | ||
2228 | if ( parent.type == CKEDITOR.NODE_ELEMENT ) { | ||
2229 | var parentAllows = CKEDITOR.dtd[ parent.name ]; | ||
2230 | // Parent element is known (included in DTD) and cannot contain | ||
2231 | // this element. | ||
2232 | if ( parentAllows && !parentAllows[ element.name ] ) { | ||
2233 | var parent2 = parent.split( index ), | ||
2234 | parentParent = parent.parent; | ||
2235 | |||
2236 | // Element will now be inserted at right parent's index. | ||
2237 | index = parent2.getIndex(); | ||
2238 | |||
2239 | // If left part of split is empty - remove it. | ||
2240 | if ( !parent.children.length ) { | ||
2241 | index -= 1; | ||
2242 | parent.remove(); | ||
2243 | } | ||
2244 | |||
2245 | // If right part of split is empty - remove it. | ||
2246 | if ( !parent2.children.length ) | ||
2247 | parent2.remove(); | ||
2248 | |||
2249 | // Try inserting as grandpas' children. | ||
2250 | return insertElement( parentParent, index, element ); | ||
2251 | } | ||
2252 | } | ||
2253 | |||
2254 | // Finally we can add this element. | ||
2255 | parent.add( element, index ); | ||
2256 | } | ||
2257 | |||
2258 | // Checks whether for the given widget definition and element widget should be created in inline or block mode. | ||
2259 | // | ||
2260 | // See also: {@link CKEDITOR.plugins.widget.definition#inline} and {@link CKEDITOR.plugins.widget#element}. | ||
2261 | // | ||
2262 | // @param {CKEDITOR.plugins.widget.definition} widgetDef The widget definition. | ||
2263 | // @param {String} elementName The name of the widget element. | ||
2264 | // @returns {Boolean} | ||
2265 | function isWidgetInline( widgetDef, elementName ) { | ||
2266 | return typeof widgetDef.inline == 'boolean' ? widgetDef.inline : !!CKEDITOR.dtd.$inline[ elementName ]; | ||
2267 | } | ||
2268 | |||
2269 | // @param {CKEDITOR.dom.element} | ||
2270 | // @returns {Boolean} | ||
2271 | function isDomTemp( element ) { | ||
2272 | return element.hasAttribute( 'data-cke-temp' ); | ||
2273 | } | ||
2274 | |||
2275 | function onEditableKey( widget, keyCode ) { | ||
2276 | var focusedEditable = widget.focusedEditable, | ||
2277 | range; | ||
2278 | |||
2279 | // CTRL+A. | ||
2280 | if ( keyCode == CKEDITOR.CTRL + 65 ) { | ||
2281 | var bogus = focusedEditable.getBogus(); | ||
2282 | |||
2283 | range = widget.editor.createRange(); | ||
2284 | range.selectNodeContents( focusedEditable ); | ||
2285 | // Exclude bogus if exists. | ||
2286 | if ( bogus ) | ||
2287 | range.setEndAt( bogus, CKEDITOR.POSITION_BEFORE_START ); | ||
2288 | |||
2289 | range.select(); | ||
2290 | // Cancel event - block default. | ||
2291 | return false; | ||
2292 | } | ||
2293 | // DEL or BACKSPACE. | ||
2294 | else if ( keyCode == 8 || keyCode == 46 ) { | ||
2295 | var ranges = widget.editor.getSelection().getRanges(); | ||
2296 | |||
2297 | range = ranges[ 0 ]; | ||
2298 | |||
2299 | // Block del or backspace if at editable's boundary. | ||
2300 | return !( ranges.length == 1 && range.collapsed && | ||
2301 | range.checkBoundaryOfElement( focusedEditable, CKEDITOR[ keyCode == 8 ? 'START' : 'END' ] ) ); | ||
2302 | } | ||
2303 | } | ||
2304 | |||
2305 | function setFocusedEditable( widgetsRepo, widget, editableElement, offline ) { | ||
2306 | var editor = widgetsRepo.editor; | ||
2307 | |||
2308 | editor.fire( 'lockSnapshot' ); | ||
2309 | |||
2310 | if ( editableElement ) { | ||
2311 | var editableName = editableElement.data( 'cke-widget-editable' ), | ||
2312 | editableInstance = widget.editables[ editableName ]; | ||
2313 | |||
2314 | widgetsRepo.widgetHoldingFocusedEditable = widget; | ||
2315 | widget.focusedEditable = editableInstance; | ||
2316 | editableElement.addClass( 'cke_widget_editable_focused' ); | ||
2317 | |||
2318 | if ( editableInstance.filter ) | ||
2319 | editor.setActiveFilter( editableInstance.filter ); | ||
2320 | editor.setActiveEnterMode( editableInstance.enterMode, editableInstance.shiftEnterMode ); | ||
2321 | } else { | ||
2322 | if ( !offline ) | ||
2323 | widget.focusedEditable.removeClass( 'cke_widget_editable_focused' ); | ||
2324 | |||
2325 | widget.focusedEditable = null; | ||
2326 | widgetsRepo.widgetHoldingFocusedEditable = null; | ||
2327 | editor.setActiveFilter( null ); | ||
2328 | editor.setActiveEnterMode( null, null ); | ||
2329 | } | ||
2330 | |||
2331 | editor.fire( 'unlockSnapshot' ); | ||
2332 | } | ||
2333 | |||
2334 | function setupContextMenu( editor ) { | ||
2335 | if ( !editor.contextMenu ) | ||
2336 | return; | ||
2337 | |||
2338 | editor.contextMenu.addListener( function( element ) { | ||
2339 | var widget = editor.widgets.getByElement( element, true ); | ||
2340 | |||
2341 | if ( widget ) | ||
2342 | return widget.fire( 'contextMenu', {} ); | ||
2343 | } ); | ||
2344 | } | ||
2345 | |||
2346 | // And now we've got two problems - original problem and RegExp. | ||
2347 | // Some softeners: | ||
2348 | // * FF tends to copy all blocks up to the copybin container. | ||
2349 | // * IE tends to copy only the copybin, without its container. | ||
2350 | // * We use spans on IE and blockless editors, but divs in other cases. | ||
2351 | var pasteReplaceRegex = new RegExp( | ||
2352 | '^' + | ||
2353 | '(?:<(?:div|span)(?: data-cke-temp="1")?(?: id="cke_copybin")?(?: data-cke-temp="1")?>)?' + | ||
2354 | '(?:<(?:div|span)(?: style="[^"]+")?>)?' + | ||
2355 | '<span [^>]*data-cke-copybin-start="1"[^>]*>.?</span>([\\s\\S]+)<span [^>]*data-cke-copybin-end="1"[^>]*>.?</span>' + | ||
2356 | '(?:</(?:div|span)>)?' + | ||
2357 | '(?:</(?:div|span)>)?' + | ||
2358 | '$', | ||
2359 | // IE8 prefers uppercase when browsers stick to lowercase HTML (http://dev.ckeditor.com/ticket/13460). | ||
2360 | 'i' | ||
2361 | ); | ||
2362 | |||
2363 | function pasteReplaceFn( match, wrapperHtml ) { | ||
2364 | // Avoid polluting pasted data with any whitspaces, | ||
2365 | // what's going to break check whether only one widget was pasted. | ||
2366 | return CKEDITOR.tools.trim( wrapperHtml ); | ||
2367 | } | ||
2368 | |||
2369 | function setupDragAndDrop( widgetsRepo ) { | ||
2370 | var editor = widgetsRepo.editor, | ||
2371 | lineutils = CKEDITOR.plugins.lineutils; | ||
2372 | |||
2373 | // These listeners handle inline and block widgets drag and drop. | ||
2374 | // The only thing we need to do to make block widgets custom drag and drop functionality | ||
2375 | // is to fire those events with the right properties (like the target which must be the drag handle). | ||
2376 | editor.on( 'dragstart', function( evt ) { | ||
2377 | var target = evt.data.target; | ||
2378 | |||
2379 | if ( Widget.isDomDragHandler( target ) ) { | ||
2380 | var widget = widgetsRepo.getByElement( target ); | ||
2381 | |||
2382 | evt.data.dataTransfer.setData( 'cke/widget-id', widget.id ); | ||
2383 | |||
2384 | // IE needs focus. | ||
2385 | editor.focus(); | ||
2386 | |||
2387 | // and widget need to be focused on drag start (http://dev.ckeditor.com/ticket/12172#comment:10). | ||
2388 | widget.focus(); | ||
2389 | } | ||
2390 | } ); | ||
2391 | |||
2392 | editor.on( 'drop', function( evt ) { | ||
2393 | var dataTransfer = evt.data.dataTransfer, | ||
2394 | id = dataTransfer.getData( 'cke/widget-id' ), | ||
2395 | transferType = dataTransfer.getTransferType( editor ), | ||
2396 | dragRange = editor.createRange(), | ||
2397 | sourceWidget; | ||
2398 | |||
2399 | // Disable cross-editor drag & drop for widgets - http://dev.ckeditor.com/ticket/13599. | ||
2400 | if ( id !== '' && transferType === CKEDITOR.DATA_TRANSFER_CROSS_EDITORS ) { | ||
2401 | evt.cancel(); | ||
2402 | return; | ||
2403 | } | ||
2404 | |||
2405 | if ( id === '' || transferType != CKEDITOR.DATA_TRANSFER_INTERNAL ) { | ||
2406 | return; | ||
2407 | } | ||
2408 | |||
2409 | sourceWidget = widgetsRepo.instances[ id ]; | ||
2410 | if ( !sourceWidget ) { | ||
2411 | return; | ||
2412 | } | ||
2413 | |||
2414 | dragRange.setStartBefore( sourceWidget.wrapper ); | ||
2415 | dragRange.setEndAfter( sourceWidget.wrapper ); | ||
2416 | evt.data.dragRange = dragRange; | ||
2417 | |||
2418 | // [IE8-9] Reset state of the clipboard#fixSplitNodesAfterDrop fix because by setting evt.data.dragRange | ||
2419 | // (see above) after drop happened we do not need it. That fix is needed only if dragRange was created | ||
2420 | // before drop (before text node was split). | ||
2421 | delete CKEDITOR.plugins.clipboard.dragStartContainerChildCount; | ||
2422 | delete CKEDITOR.plugins.clipboard.dragEndContainerChildCount; | ||
2423 | |||
2424 | evt.data.dataTransfer.setData( 'text/html', editor.editable().getHtmlFromRange( dragRange ).getHtml() ); | ||
2425 | editor.widgets.destroy( sourceWidget, true ); | ||
2426 | } ); | ||
2427 | |||
2428 | editor.on( 'contentDom', function() { | ||
2429 | var editable = editor.editable(); | ||
2430 | |||
2431 | // Register Lineutils's utilities as properties of repo. | ||
2432 | CKEDITOR.tools.extend( widgetsRepo, { | ||
2433 | finder: new lineutils.finder( editor, { | ||
2434 | lookups: { | ||
2435 | // Element is block but not list item and not in nested editable. | ||
2436 | 'default': function( el ) { | ||
2437 | if ( el.is( CKEDITOR.dtd.$listItem ) ) | ||
2438 | return; | ||
2439 | |||
2440 | if ( !el.is( CKEDITOR.dtd.$block ) ) | ||
2441 | return; | ||
2442 | |||
2443 | // Allow drop line inside, but never before or after nested editable (http://dev.ckeditor.com/ticket/12006). | ||
2444 | if ( Widget.isDomNestedEditable( el ) ) | ||
2445 | return; | ||
2446 | |||
2447 | // Do not allow droping inside the widget being dragged (http://dev.ckeditor.com/ticket/13397). | ||
2448 | if ( widgetsRepo._.draggedWidget.wrapper.contains( el ) ) { | ||
2449 | return; | ||
2450 | } | ||
2451 | |||
2452 | // If element is nested editable, make sure widget can be dropped there (http://dev.ckeditor.com/ticket/12006). | ||
2453 | var nestedEditable = Widget.getNestedEditable( editable, el ); | ||
2454 | if ( nestedEditable ) { | ||
2455 | var draggedWidget = widgetsRepo._.draggedWidget; | ||
2456 | |||
2457 | // Don't let the widget to be dropped into its own nested editable. | ||
2458 | if ( widgetsRepo.getByElement( nestedEditable ) == draggedWidget ) | ||
2459 | return; | ||
2460 | |||
2461 | var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ], | ||
2462 | draggedRequiredContent = draggedWidget.requiredContent; | ||
2463 | |||
2464 | // There will be no relation if the filter of nested editable does not allow | ||
2465 | // requiredContent of dragged widget. | ||
2466 | if ( filter && draggedRequiredContent && !filter.check( draggedRequiredContent ) ) | ||
2467 | return; | ||
2468 | } | ||
2469 | |||
2470 | return CKEDITOR.LINEUTILS_BEFORE | CKEDITOR.LINEUTILS_AFTER; | ||
2471 | } | ||
2472 | } | ||
2473 | } ), | ||
2474 | locator: new lineutils.locator( editor ), | ||
2475 | liner: new lineutils.liner( editor, { | ||
2476 | lineStyle: { | ||
2477 | cursor: 'move !important', | ||
2478 | 'border-top-color': '#666' | ||
2479 | }, | ||
2480 | tipLeftStyle: { | ||
2481 | 'border-left-color': '#666' | ||
2482 | }, | ||
2483 | tipRightStyle: { | ||
2484 | 'border-right-color': '#666' | ||
2485 | } | ||
2486 | } ) | ||
2487 | }, true ); | ||
2488 | } ); | ||
2489 | } | ||
2490 | |||
2491 | // Setup mouse observer which will trigger: | ||
2492 | // * widget focus on widget click, | ||
2493 | // * widget#doubleclick forwarded from editor#doubleclick. | ||
2494 | function setupMouseObserver( widgetsRepo ) { | ||
2495 | var editor = widgetsRepo.editor; | ||
2496 | |||
2497 | editor.on( 'contentDom', function() { | ||
2498 | var editable = editor.editable(), | ||
2499 | evtRoot = editable.isInline() ? editable : editor.document, | ||
2500 | widget, | ||
2501 | mouseDownOnDragHandler; | ||
2502 | |||
2503 | editable.attachListener( evtRoot, 'mousedown', function( evt ) { | ||
2504 | var target = evt.data.getTarget(); | ||
2505 | |||
2506 | // http://dev.ckeditor.com/ticket/10887 Clicking scrollbar in IE8 will invoke event with empty target object. | ||
2507 | if ( !target.type ) | ||
2508 | return false; | ||
2509 | |||
2510 | widget = widgetsRepo.getByElement( target ); | ||
2511 | mouseDownOnDragHandler = 0; // Reset. | ||
2512 | |||
2513 | // Widget was clicked, but not editable nested in it. | ||
2514 | if ( widget ) { | ||
2515 | // Ignore mousedown on drag and drop handler if the widget is inline. | ||
2516 | // Block widgets are handled by Lineutils. | ||
2517 | if ( widget.inline && target.type == CKEDITOR.NODE_ELEMENT && target.hasAttribute( 'data-cke-widget-drag-handler' ) ) { | ||
2518 | mouseDownOnDragHandler = 1; | ||
2519 | |||
2520 | // When drag handler is pressed we have to clear current selection if it wasn't already on this widget. | ||
2521 | // Otherwise, the selection may be in a fillingChar, which prevents dragging a widget. (http://dev.ckeditor.com/ticket/13284, see comment 8 and 9.) | ||
2522 | if ( widgetsRepo.focused != widget ) | ||
2523 | editor.getSelection().removeAllRanges(); | ||
2524 | |||
2525 | return; | ||
2526 | } | ||
2527 | |||
2528 | if ( !Widget.getNestedEditable( widget.wrapper, target ) ) { | ||
2529 | evt.data.preventDefault(); | ||
2530 | if ( !CKEDITOR.env.ie ) | ||
2531 | widget.focus(); | ||
2532 | } else { | ||
2533 | // Reset widget so mouseup listener is not confused. | ||
2534 | widget = null; | ||
2535 | } | ||
2536 | } | ||
2537 | } ); | ||
2538 | |||
2539 | // Focus widget on mouseup if mousedown was fired on drag handler. | ||
2540 | // Note: mouseup won't be fired at all if widget was dragged and dropped, so | ||
2541 | // this code will be executed only when drag handler was clicked. | ||
2542 | editable.attachListener( evtRoot, 'mouseup', function() { | ||
2543 | // Check if widget is not destroyed (if widget is destroyed the wrapper will be null). | ||
2544 | if ( mouseDownOnDragHandler && widget && widget.wrapper ) { | ||
2545 | mouseDownOnDragHandler = 0; | ||
2546 | widget.focus(); | ||
2547 | } | ||
2548 | } ); | ||
2549 | |||
2550 | // On IE it is not enough to block mousedown. If widget wrapper (element with | ||
2551 | // contenteditable=false attribute) is clicked directly (it is a target), | ||
2552 | // then after mouseup/click IE will select that element. | ||
2553 | // It is not possible to prevent that default action, | ||
2554 | // so we force fake selection after everything happened. | ||
2555 | if ( CKEDITOR.env.ie ) { | ||
2556 | editable.attachListener( evtRoot, 'mouseup', function() { | ||
2557 | setTimeout( function() { | ||
2558 | // Check if widget is not destroyed (if widget is destroyed the wrapper will be null) and | ||
2559 | // in editable contains widget (it could be dragged and removed). | ||
2560 | if ( widget && widget.wrapper && editable.contains( widget.wrapper ) ) { | ||
2561 | widget.focus(); | ||
2562 | widget = null; | ||
2563 | } | ||
2564 | } ); | ||
2565 | } ); | ||
2566 | } | ||
2567 | } ); | ||
2568 | |||
2569 | editor.on( 'doubleclick', function( evt ) { | ||
2570 | var widget = widgetsRepo.getByElement( evt.data.element ); | ||
2571 | |||
2572 | // Not in widget or in nested editable. | ||
2573 | if ( !widget || Widget.getNestedEditable( widget.wrapper, evt.data.element ) ) | ||
2574 | return; | ||
2575 | |||
2576 | return widget.fire( 'doubleclick', { element: evt.data.element } ); | ||
2577 | }, null, null, 1 ); | ||
2578 | } | ||
2579 | |||
2580 | // Setup editor#key observer which will forward it | ||
2581 | // to focused widget. | ||
2582 | function setupKeyboardObserver( widgetsRepo ) { | ||
2583 | var editor = widgetsRepo.editor; | ||
2584 | |||
2585 | editor.on( 'key', function( evt ) { | ||
2586 | var focused = widgetsRepo.focused, | ||
2587 | widgetHoldingFocusedEditable = widgetsRepo.widgetHoldingFocusedEditable, | ||
2588 | ret; | ||
2589 | |||
2590 | if ( focused ) | ||
2591 | ret = focused.fire( 'key', { keyCode: evt.data.keyCode } ); | ||
2592 | else if ( widgetHoldingFocusedEditable ) | ||
2593 | ret = onEditableKey( widgetHoldingFocusedEditable, evt.data.keyCode ); | ||
2594 | |||
2595 | return ret; | ||
2596 | }, null, null, 1 ); | ||
2597 | } | ||
2598 | |||
2599 | // Setup copybin on native copy and cut events in order to handle copy and cut commands | ||
2600 | // if user accepted security alert on IEs. | ||
2601 | // Note: when copying or cutting using keystroke, copySingleWidget will be first executed | ||
2602 | // by the keydown listener. Conflict between two calls will be resolved by copy_bin existence check. | ||
2603 | function setupNativeCutAndCopy( widgetsRepo ) { | ||
2604 | var editor = widgetsRepo.editor; | ||
2605 | |||
2606 | editor.on( 'contentDom', function() { | ||
2607 | var editable = editor.editable(); | ||
2608 | |||
2609 | editable.attachListener( editable, 'copy', eventListener ); | ||
2610 | editable.attachListener( editable, 'cut', eventListener ); | ||
2611 | } ); | ||
2612 | |||
2613 | function eventListener( evt ) { | ||
2614 | if ( widgetsRepo.focused ) | ||
2615 | copySingleWidget( widgetsRepo.focused, evt.name == 'cut' ); | ||
2616 | } | ||
2617 | } | ||
2618 | |||
2619 | // Setup selection observer which will trigger: | ||
2620 | // * widget select & focus on selection change, | ||
2621 | // * nested editable focus (related properites and classes) on selection change, | ||
2622 | // * deselecting and blurring all widgets on data, | ||
2623 | // * blurring widget on editor blur. | ||
2624 | function setupSelectionObserver( widgetsRepo ) { | ||
2625 | var editor = widgetsRepo.editor; | ||
2626 | |||
2627 | editor.on( 'selectionCheck', function() { | ||
2628 | widgetsRepo.fire( 'checkSelection' ); | ||
2629 | } ); | ||
2630 | |||
2631 | widgetsRepo.on( 'checkSelection', widgetsRepo.checkSelection, widgetsRepo ); | ||
2632 | |||
2633 | editor.on( 'selectionChange', function( evt ) { | ||
2634 | var nestedEditable = Widget.getNestedEditable( editor.editable(), evt.data.selection.getStartElement() ), | ||
2635 | newWidget = nestedEditable && widgetsRepo.getByElement( nestedEditable ), | ||
2636 | oldWidget = widgetsRepo.widgetHoldingFocusedEditable; | ||
2637 | |||
2638 | if ( oldWidget ) { | ||
2639 | if ( oldWidget !== newWidget || !oldWidget.focusedEditable.equals( nestedEditable ) ) { | ||
2640 | setFocusedEditable( widgetsRepo, oldWidget, null ); | ||
2641 | |||
2642 | if ( newWidget && nestedEditable ) | ||
2643 | setFocusedEditable( widgetsRepo, newWidget, nestedEditable ); | ||
2644 | } | ||
2645 | } | ||
2646 | // It may happen that there's no widget even if editable was found - | ||
2647 | // e.g. if selection was automatically set in editable although widget wasn't initialized yet. | ||
2648 | else if ( newWidget && nestedEditable ) { | ||
2649 | setFocusedEditable( widgetsRepo, newWidget, nestedEditable ); | ||
2650 | } | ||
2651 | } ); | ||
2652 | |||
2653 | // Invalidate old widgets early - immediately on dataReady. | ||
2654 | editor.on( 'dataReady', function() { | ||
2655 | // Deselect and blur all widgets. | ||
2656 | stateUpdater( widgetsRepo ).commit(); | ||
2657 | } ); | ||
2658 | |||
2659 | editor.on( 'blur', function() { | ||
2660 | var widget; | ||
2661 | |||
2662 | if ( ( widget = widgetsRepo.focused ) ) | ||
2663 | blurWidget( widgetsRepo, widget ); | ||
2664 | |||
2665 | if ( ( widget = widgetsRepo.widgetHoldingFocusedEditable ) ) | ||
2666 | setFocusedEditable( widgetsRepo, widget, null ); | ||
2667 | } ); | ||
2668 | } | ||
2669 | |||
2670 | // Set up actions like: | ||
2671 | // * processing in toHtml/toDataFormat, | ||
2672 | // * pasting handling, | ||
2673 | // * insertion handling, | ||
2674 | // * editable reload handling (setData, mode switch, undo/redo), | ||
2675 | // * DOM invalidation handling, | ||
2676 | // * widgets checks. | ||
2677 | function setupWidgetsLifecycle( widgetsRepo ) { | ||
2678 | setupWidgetsLifecycleStart( widgetsRepo ); | ||
2679 | setupWidgetsLifecycleEnd( widgetsRepo ); | ||
2680 | |||
2681 | widgetsRepo.on( 'checkWidgets', checkWidgets ); | ||
2682 | widgetsRepo.editor.on( 'contentDomInvalidated', widgetsRepo.checkWidgets, widgetsRepo ); | ||
2683 | } | ||
2684 | |||
2685 | function setupWidgetsLifecycleEnd( widgetsRepo ) { | ||
2686 | var editor = widgetsRepo.editor, | ||
2687 | downcastingSessions = {}; | ||
2688 | |||
2689 | // Listen before htmlDP#htmlFilter is applied to cache all widgets, because we'll | ||
2690 | // loose data-cke-* attributes. | ||
2691 | editor.on( 'toDataFormat', function( evt ) { | ||
2692 | // To avoid conflicts between htmlDP#toDF calls done at the same time | ||
2693 | // (e.g. nestedEditable#getData called during downcasting some widget) | ||
2694 | // mark every toDataFormat event chain with the downcasting session id. | ||
2695 | var id = CKEDITOR.tools.getNextNumber(), | ||
2696 | toBeDowncasted = []; | ||
2697 | evt.data.downcastingSessionId = id; | ||
2698 | downcastingSessions[ id ] = toBeDowncasted; | ||
2699 | |||
2700 | evt.data.dataValue.forEach( function( element ) { | ||
2701 | var attrs = element.attributes, | ||
2702 | widget, widgetElement; | ||
2703 | |||
2704 | // Wrapper. | ||
2705 | // Perform first part of downcasting (cleanup) and cache widgets, | ||
2706 | // because after applying DP's filter all data-cke-* attributes will be gone. | ||
2707 | if ( 'data-cke-widget-id' in attrs ) { | ||
2708 | widget = widgetsRepo.instances[ attrs[ 'data-cke-widget-id' ] ]; | ||
2709 | if ( widget ) { | ||
2710 | widgetElement = element.getFirst( Widget.isParserWidgetElement ); | ||
2711 | toBeDowncasted.push( { | ||
2712 | wrapper: element, | ||
2713 | element: widgetElement, | ||
2714 | widget: widget, | ||
2715 | editables: {} | ||
2716 | } ); | ||
2717 | |||
2718 | // If widget did not have data-cke-widget attribute before upcasting remove it. | ||
2719 | if ( widgetElement.attributes[ 'data-cke-widget-keep-attr' ] != '1' ) | ||
2720 | delete widgetElement.attributes[ 'data-widget' ]; | ||
2721 | } | ||
2722 | } | ||
2723 | // Nested editable. | ||
2724 | else if ( 'data-cke-widget-editable' in attrs ) { | ||
2725 | // Save the reference to this nested editable in the closest widget to be downcasted. | ||
2726 | // Nested editables are downcasted in the successive toDataFormat to create an opportunity | ||
2727 | // for dataFilter's "excludeNestedEditable" option to do its job (that option relies on | ||
2728 | // contenteditable="true" attribute) (http://dev.ckeditor.com/ticket/11372). | ||
2729 | toBeDowncasted[ toBeDowncasted.length - 1 ].editables[ attrs[ 'data-cke-widget-editable' ] ] = element; | ||
2730 | |||
2731 | // Don't check children - there won't be next wrapper or nested editable which we | ||
2732 | // should process in this session. | ||
2733 | return false; | ||
2734 | } | ||
2735 | }, CKEDITOR.NODE_ELEMENT, true ); | ||
2736 | }, null, null, 8 ); | ||
2737 | |||
2738 | // Listen after dataProcessor.htmlFilter and ACF were applied | ||
2739 | // so wrappers securing widgets' contents are removed after all filtering was done. | ||
2740 | editor.on( 'toDataFormat', function( evt ) { | ||
2741 | // Ignore some unmarked sessions. | ||
2742 | if ( !evt.data.downcastingSessionId ) | ||
2743 | return; | ||
2744 | |||
2745 | var toBeDowncasted = downcastingSessions[ evt.data.downcastingSessionId ], | ||
2746 | toBe, widget, widgetElement, retElement, editableElement, e; | ||
2747 | |||
2748 | while ( ( toBe = toBeDowncasted.shift() ) ) { | ||
2749 | widget = toBe.widget; | ||
2750 | widgetElement = toBe.element; | ||
2751 | retElement = widget._.downcastFn && widget._.downcastFn.call( widget, widgetElement ); | ||
2752 | |||
2753 | // Replace nested editables' content with their output data. | ||
2754 | for ( e in toBe.editables ) { | ||
2755 | editableElement = toBe.editables[ e ]; | ||
2756 | |||
2757 | delete editableElement.attributes.contenteditable; | ||
2758 | editableElement.setHtml( widget.editables[ e ].getData() ); | ||
2759 | } | ||
2760 | |||
2761 | // Returned element always defaults to widgetElement. | ||
2762 | if ( !retElement ) | ||
2763 | retElement = widgetElement; | ||
2764 | |||
2765 | toBe.wrapper.replaceWith( retElement ); | ||
2766 | } | ||
2767 | }, null, null, 13 ); | ||
2768 | |||
2769 | |||
2770 | editor.on( 'contentDomUnload', function() { | ||
2771 | widgetsRepo.destroyAll( true ); | ||
2772 | } ); | ||
2773 | } | ||
2774 | |||
2775 | function setupWidgetsLifecycleStart( widgetsRepo ) { | ||
2776 | var editor = widgetsRepo.editor, | ||
2777 | processedWidgetOnly, | ||
2778 | snapshotLoaded; | ||
2779 | |||
2780 | // Listen after ACF (so data are filtered), | ||
2781 | // but before dataProcessor.dataFilter was applied (so we can secure widgets' internals). | ||
2782 | editor.on( 'toHtml', function( evt ) { | ||
2783 | var upcastIterator = createUpcastIterator( widgetsRepo ), | ||
2784 | toBeWrapped; | ||
2785 | |||
2786 | evt.data.dataValue.forEach( upcastIterator.iterator, CKEDITOR.NODE_ELEMENT, true ); | ||
2787 | |||
2788 | // Clean up and wrap all queued elements. | ||
2789 | while ( ( toBeWrapped = upcastIterator.toBeWrapped.pop() ) ) { | ||
2790 | cleanUpWidgetElement( toBeWrapped[ 0 ] ); | ||
2791 | widgetsRepo.wrapElement( toBeWrapped[ 0 ], toBeWrapped[ 1 ] ); | ||
2792 | } | ||
2793 | |||
2794 | // Used to determine whether only widget was pasted. | ||
2795 | if ( evt.data.protectedWhitespaces ) { | ||
2796 | // Whitespaces are protected by wrapping content with spans. Take the middle node only. | ||
2797 | processedWidgetOnly = evt.data.dataValue.children.length == 3 && | ||
2798 | Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 1 ] ); | ||
2799 | } else { | ||
2800 | processedWidgetOnly = evt.data.dataValue.children.length == 1 && | ||
2801 | Widget.isParserWidgetWrapper( evt.data.dataValue.children[ 0 ] ); | ||
2802 | } | ||
2803 | }, null, null, 8 ); | ||
2804 | |||
2805 | editor.on( 'dataReady', function() { | ||
2806 | // Clean up all widgets loaded from snapshot. | ||
2807 | if ( snapshotLoaded ) | ||
2808 | cleanUpAllWidgetElements( widgetsRepo, editor.editable() ); | ||
2809 | snapshotLoaded = 0; | ||
2810 | |||
2811 | // Some widgets were destroyed on contentDomUnload, | ||
2812 | // some on loadSnapshot, but that does not include | ||
2813 | // e.g. setHtml on inline editor or widgets removed just | ||
2814 | // before setting data. | ||
2815 | widgetsRepo.destroyAll( true ); | ||
2816 | widgetsRepo.initOnAll(); | ||
2817 | } ); | ||
2818 | |||
2819 | // Set flag so dataReady will know that additional | ||
2820 | // cleanup is needed, because snapshot containing widgets was loaded. | ||
2821 | editor.on( 'loadSnapshot', function( evt ) { | ||
2822 | // Primitive but sufficient check which will prevent from executing | ||
2823 | // heavier cleanUpAllWidgetElements if not needed. | ||
2824 | if ( ( /data-cke-widget/ ).test( evt.data ) ) | ||
2825 | snapshotLoaded = 1; | ||
2826 | |||
2827 | widgetsRepo.destroyAll( true ); | ||
2828 | }, null, null, 9 ); | ||
2829 | |||
2830 | // Handle pasted single widget. | ||
2831 | editor.on( 'paste', function( evt ) { | ||
2832 | var data = evt.data; | ||
2833 | |||
2834 | data.dataValue = data.dataValue.replace( pasteReplaceRegex, pasteReplaceFn ); | ||
2835 | |||
2836 | // If drag'n'drop kind of paste into nested editable (data.range), selection is set AFTER | ||
2837 | // data is pasted, which means editor has no chance to change activeFilter's context. | ||
2838 | // As a result, pasted data is filtered with default editor's filter instead of NE's and | ||
2839 | // funny things get inserted. Changing the filter by analysis of the paste range below (http://dev.ckeditor.com/ticket/13186). | ||
2840 | if ( data.range ) { | ||
2841 | // Check if pasting into nested editable. | ||
2842 | var nestedEditable = Widget.getNestedEditable( editor.editable(), data.range.startContainer ); | ||
2843 | |||
2844 | if ( nestedEditable ) { | ||
2845 | // Retrieve the filter from NE's data and set it active before editor.insertHtml is done | ||
2846 | // in clipboard plugin. | ||
2847 | var filter = CKEDITOR.filter.instances[ nestedEditable.data( 'cke-filter' ) ]; | ||
2848 | |||
2849 | if ( filter ) { | ||
2850 | editor.setActiveFilter( filter ); | ||
2851 | } | ||
2852 | } | ||
2853 | } | ||
2854 | } ); | ||
2855 | |||
2856 | // Listen with high priority to check widgets after data was inserted. | ||
2857 | editor.on( 'afterInsertHtml', function( evt ) { | ||
2858 | if ( evt.data.intoRange ) { | ||
2859 | widgetsRepo.checkWidgets( { initOnlyNew: true } ); | ||
2860 | } else { | ||
2861 | editor.fire( 'lockSnapshot' ); | ||
2862 | // Init only new for performance reason. | ||
2863 | // Focus inited if only widget was processed. | ||
2864 | widgetsRepo.checkWidgets( { initOnlyNew: true, focusInited: processedWidgetOnly } ); | ||
2865 | |||
2866 | editor.fire( 'unlockSnapshot' ); | ||
2867 | } | ||
2868 | } ); | ||
2869 | } | ||
2870 | |||
2871 | // Helper for coordinating which widgets should be | ||
2872 | // selected/deselected and which one should be focused/blurred. | ||
2873 | function stateUpdater( widgetsRepo ) { | ||
2874 | var currentlySelected = widgetsRepo.selected, | ||
2875 | toBeSelected = [], | ||
2876 | toBeDeselected = currentlySelected.slice( 0 ), | ||
2877 | focused = null; | ||
2878 | |||
2879 | return { | ||
2880 | select: function( widget ) { | ||
2881 | if ( CKEDITOR.tools.indexOf( currentlySelected, widget ) < 0 ) | ||
2882 | toBeSelected.push( widget ); | ||
2883 | |||
2884 | var index = CKEDITOR.tools.indexOf( toBeDeselected, widget ); | ||
2885 | if ( index >= 0 ) | ||
2886 | toBeDeselected.splice( index, 1 ); | ||
2887 | |||
2888 | return this; | ||
2889 | }, | ||
2890 | |||
2891 | focus: function( widget ) { | ||
2892 | focused = widget; | ||
2893 | return this; | ||
2894 | }, | ||
2895 | |||
2896 | commit: function() { | ||
2897 | var focusedChanged = widgetsRepo.focused !== focused, | ||
2898 | widget, isDirty; | ||
2899 | |||
2900 | widgetsRepo.editor.fire( 'lockSnapshot' ); | ||
2901 | |||
2902 | if ( focusedChanged && ( widget = widgetsRepo.focused ) ) | ||
2903 | blurWidget( widgetsRepo, widget ); | ||
2904 | |||
2905 | while ( ( widget = toBeDeselected.pop() ) ) { | ||
2906 | currentlySelected.splice( CKEDITOR.tools.indexOf( currentlySelected, widget ), 1 ); | ||
2907 | // Widget could be destroyed in the meantime - e.g. data could be set. | ||
2908 | if ( widget.isInited() ) { | ||
2909 | isDirty = widget.editor.checkDirty(); | ||
2910 | |||
2911 | widget.setSelected( false ); | ||
2912 | |||
2913 | !isDirty && widget.editor.resetDirty(); | ||
2914 | } | ||
2915 | } | ||
2916 | |||
2917 | if ( focusedChanged && focused ) { | ||
2918 | isDirty = widgetsRepo.editor.checkDirty(); | ||
2919 | |||
2920 | widgetsRepo.focused = focused; | ||
2921 | widgetsRepo.fire( 'widgetFocused', { widget: focused } ); | ||
2922 | focused.setFocused( true ); | ||
2923 | |||
2924 | !isDirty && widgetsRepo.editor.resetDirty(); | ||
2925 | } | ||
2926 | |||
2927 | while ( ( widget = toBeSelected.pop() ) ) { | ||
2928 | currentlySelected.push( widget ); | ||
2929 | widget.setSelected( true ); | ||
2930 | } | ||
2931 | |||
2932 | widgetsRepo.editor.fire( 'unlockSnapshot' ); | ||
2933 | } | ||
2934 | }; | ||
2935 | } | ||
2936 | |||
2937 | |||
2938 | // | ||
2939 | // WIDGET helpers --------------------------------------------------------- | ||
2940 | // | ||
2941 | |||
2942 | // LEFT, RIGHT, UP, DOWN, DEL, BACKSPACE - unblock default fake sel handlers. | ||
2943 | var keystrokesNotBlockedByWidget = { 37: 1, 38: 1, 39: 1, 40: 1, 8: 1, 46: 1 }; | ||
2944 | |||
2945 | // Applies or removes style's classes from widget. | ||
2946 | // @param {CKEDITOR.style} style Custom widget style. | ||
2947 | // @param {Boolean} apply Whether to apply or remove style. | ||
2948 | function applyRemoveStyle( widget, style, apply ) { | ||
2949 | var changed = 0, | ||
2950 | classes = getStyleClasses( style ), | ||
2951 | updatedClasses = widget.data.classes || {}, | ||
2952 | cl; | ||
2953 | |||
2954 | // Ee... Something is wrong with this style. | ||
2955 | if ( !classes ) | ||
2956 | return; | ||
2957 | |||
2958 | // Clone, because we need to break reference. | ||
2959 | updatedClasses = CKEDITOR.tools.clone( updatedClasses ); | ||
2960 | |||
2961 | while ( ( cl = classes.pop() ) ) { | ||
2962 | if ( apply ) { | ||
2963 | if ( !updatedClasses[ cl ] ) | ||
2964 | changed = updatedClasses[ cl ] = 1; | ||
2965 | } else { | ||
2966 | if ( updatedClasses[ cl ] ) { | ||
2967 | delete updatedClasses[ cl ]; | ||
2968 | changed = 1; | ||
2969 | } | ||
2970 | } | ||
2971 | } | ||
2972 | if ( changed ) | ||
2973 | widget.setData( 'classes', updatedClasses ); | ||
2974 | } | ||
2975 | |||
2976 | function cancel( evt ) { | ||
2977 | evt.cancel(); | ||
2978 | } | ||
2979 | |||
2980 | function copySingleWidget( widget, isCut ) { | ||
2981 | var editor = widget.editor, | ||
2982 | doc = editor.document; | ||
2983 | |||
2984 | // We're still handling previous copy/cut. | ||
2985 | // When keystroke is used to copy/cut this will also prevent | ||
2986 | // conflict with copySingleWidget called again for native copy/cut event. | ||
2987 | if ( doc.getById( 'cke_copybin' ) ) | ||
2988 | return; | ||
2989 | |||
2990 | // [IE] Use span for copybin and its container to avoid bug with expanding editable height by | ||
2991 | // absolutely positioned element. | ||
2992 | var copybinName = ( editor.blockless || CKEDITOR.env.ie ) ? 'span' : 'div', | ||
2993 | copybin = doc.createElement( copybinName ), | ||
2994 | copybinContainer = doc.createElement( copybinName ), | ||
2995 | // IE8 always jumps to the end of document. | ||
2996 | needsScrollHack = CKEDITOR.env.ie && CKEDITOR.env.version < 9; | ||
2997 | |||
2998 | copybinContainer.setAttributes( { | ||
2999 | id: 'cke_copybin', | ||
3000 | 'data-cke-temp': '1' | ||
3001 | } ); | ||
3002 | |||
3003 | // Position copybin element outside current viewport. | ||
3004 | copybin.setStyles( { | ||
3005 | position: 'absolute', | ||
3006 | width: '1px', | ||
3007 | height: '1px', | ||
3008 | overflow: 'hidden' | ||
3009 | } ); | ||
3010 | |||
3011 | copybin.setStyle( editor.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-5000px' ); | ||
3012 | |||
3013 | var range = editor.createRange(); | ||
3014 | range.setStartBefore( widget.wrapper ); | ||
3015 | range.setEndAfter( widget.wrapper ); | ||
3016 | |||
3017 | copybin.setHtml( | ||
3018 | '<span data-cke-copybin-start="1">\u200b</span>' + | ||
3019 | editor.editable().getHtmlFromRange( range ).getHtml() + | ||
3020 | '<span data-cke-copybin-end="1">\u200b</span>' ); | ||
3021 | |||
3022 | // Save snapshot with the current state. | ||
3023 | editor.fire( 'saveSnapshot' ); | ||
3024 | |||
3025 | // Ignore copybin. | ||
3026 | editor.fire( 'lockSnapshot' ); | ||
3027 | |||
3028 | copybinContainer.append( copybin ); | ||
3029 | editor.editable().append( copybinContainer ); | ||
3030 | |||
3031 | var listener1 = editor.on( 'selectionChange', cancel, null, null, 0 ), | ||
3032 | listener2 = widget.repository.on( 'checkSelection', cancel, null, null, 0 ); | ||
3033 | |||
3034 | if ( needsScrollHack ) { | ||
3035 | var docElement = doc.getDocumentElement().$, | ||
3036 | scrollTop = docElement.scrollTop; | ||
3037 | } | ||
3038 | |||
3039 | // Once the clone of the widget is inside of copybin, select | ||
3040 | // the entire contents. This selection will be copied by the | ||
3041 | // native browser's clipboard system. | ||
3042 | range = editor.createRange(); | ||
3043 | range.selectNodeContents( copybin ); | ||
3044 | range.select(); | ||
3045 | |||
3046 | if ( needsScrollHack ) | ||
3047 | docElement.scrollTop = scrollTop; | ||
3048 | |||
3049 | setTimeout( function() { | ||
3050 | // [IE] Focus widget before removing copybin to avoid scroll jump. | ||
3051 | if ( !isCut ) | ||
3052 | widget.focus(); | ||
3053 | |||
3054 | copybinContainer.remove(); | ||
3055 | |||
3056 | listener1.removeListener(); | ||
3057 | listener2.removeListener(); | ||
3058 | |||
3059 | editor.fire( 'unlockSnapshot' ); | ||
3060 | |||
3061 | if ( isCut ) { | ||
3062 | widget.repository.del( widget ); | ||
3063 | editor.fire( 'saveSnapshot' ); | ||
3064 | } | ||
3065 | }, 100 ); // Use 100ms, so Chrome (@Mac) will be able to grab the content. | ||
3066 | } | ||
3067 | |||
3068 | // Extracts classes array from style instance. | ||
3069 | function getStyleClasses( style ) { | ||
3070 | var attrs = style.getDefinition().attributes, | ||
3071 | classes = attrs && attrs[ 'class' ]; | ||
3072 | |||
3073 | return classes ? classes.split( /\s+/ ) : null; | ||
3074 | } | ||
3075 | |||
3076 | // [IE] Force keeping focus because IE sometimes forgets to fire focus on main editable | ||
3077 | // when blurring nested editable. | ||
3078 | // @context widget | ||
3079 | function onEditableBlur() { | ||
3080 | var active = CKEDITOR.document.getActive(), | ||
3081 | editor = this.editor, | ||
3082 | editable = editor.editable(); | ||
3083 | |||
3084 | // If focus stays within editor override blur and set currentActive because it should be | ||
3085 | // automatically changed to editable on editable#focus but it is not fired. | ||
3086 | if ( ( editable.isInline() ? editable : editor.document.getWindow().getFrame() ).equals( active ) ) | ||
3087 | editor.focusManager.focus( editable ); | ||
3088 | } | ||
3089 | |||
3090 | // Force selectionChange when editable was focused. | ||
3091 | // Similar to hack in selection.js#~620. | ||
3092 | // @context widget | ||
3093 | function onEditableFocus() { | ||
3094 | // Gecko does not support 'DOMFocusIn' event on which we unlock selection | ||
3095 | // in selection.js to prevent selection locking when entering nested editables. | ||
3096 | if ( CKEDITOR.env.gecko ) | ||
3097 | this.editor.unlockSelection(); | ||
3098 | |||
3099 | // We don't need to force selectionCheck on Webkit, because on Webkit | ||
3100 | // we do that on DOMFocusIn in selection.js. | ||
3101 | if ( !CKEDITOR.env.webkit ) { | ||
3102 | this.editor.forceNextSelectionCheck(); | ||
3103 | this.editor.selectionChange( 1 ); | ||
3104 | } | ||
3105 | } | ||
3106 | |||
3107 | // Setup listener on widget#data which will update (remove/add) classes | ||
3108 | // by comparing newly set classes with the old ones. | ||
3109 | function setupDataClassesListener( widget ) { | ||
3110 | // Note: previousClasses and newClasses may be null! | ||
3111 | // Tip: for ( cl in null ) is correct. | ||
3112 | var previousClasses = null; | ||
3113 | |||
3114 | widget.on( 'data', function() { | ||
3115 | var newClasses = this.data.classes, | ||
3116 | cl; | ||
3117 | |||
3118 | // When setting new classes one need to remember | ||
3119 | // that he must break reference. | ||
3120 | if ( previousClasses == newClasses ) | ||
3121 | return; | ||
3122 | |||
3123 | for ( cl in previousClasses ) { | ||
3124 | // Avoid removing and adding classes again. | ||
3125 | if ( !( newClasses && newClasses[ cl ] ) ) | ||
3126 | this.removeClass( cl ); | ||
3127 | } | ||
3128 | for ( cl in newClasses ) | ||
3129 | this.addClass( cl ); | ||
3130 | |||
3131 | previousClasses = newClasses; | ||
3132 | } ); | ||
3133 | } | ||
3134 | |||
3135 | // Add a listener to data event that will set/change widget's label (http://dev.ckeditor.com/ticket/14539). | ||
3136 | function setupA11yListener( widget ) { | ||
3137 | // Note, the function gets executed in a context of widget instance. | ||
3138 | function getLabelDefault() { | ||
3139 | return this.editor.lang.widget.label.replace( /%1/, this.pathName || this.element.getName() ); | ||
3140 | } | ||
3141 | |||
3142 | // Setting a listener on data is enough, there's no need to perform it on widget initialization, as | ||
3143 | // setupWidgetData fires this event anyway. | ||
3144 | widget.on( 'data', function() { | ||
3145 | // In some cases widget might get destroyed in an earlier data listener. For instance, image2 plugin, does | ||
3146 | // so when changing its internal state. | ||
3147 | if ( !widget.wrapper ) { | ||
3148 | return; | ||
3149 | } | ||
3150 | |||
3151 | var label = this.getLabel ? this.getLabel() : getLabelDefault.call( this ); | ||
3152 | |||
3153 | widget.wrapper.setAttribute( 'role', 'region' ); | ||
3154 | widget.wrapper.setAttribute( 'aria-label', label ); | ||
3155 | }, null, null, 9999 ); | ||
3156 | } | ||
3157 | |||
3158 | function setupDragHandler( widget ) { | ||
3159 | if ( !widget.draggable ) | ||
3160 | return; | ||
3161 | |||
3162 | var editor = widget.editor, | ||
3163 | // Use getLast to find wrapper's direct descendant (http://dev.ckeditor.com/ticket/12022). | ||
3164 | container = widget.wrapper.getLast( Widget.isDomDragHandlerContainer ), | ||
3165 | img; | ||
3166 | |||
3167 | // Reuse drag handler if already exists (http://dev.ckeditor.com/ticket/11281). | ||
3168 | if ( container ) | ||
3169 | img = container.findOne( 'img' ); | ||
3170 | else { | ||
3171 | container = new CKEDITOR.dom.element( 'span', editor.document ); | ||
3172 | container.setAttributes( { | ||
3173 | 'class': 'cke_reset cke_widget_drag_handler_container', | ||
3174 | // Split background and background-image for IE8 which will break on rgba(). | ||
3175 | style: 'background:rgba(220,220,220,0.5);background-image:url(' + editor.plugins.widget.path + 'images/handle.png)' | ||
3176 | } ); | ||
3177 | |||
3178 | img = new CKEDITOR.dom.element( 'img', editor.document ); | ||
3179 | img.setAttributes( { | ||
3180 | 'class': 'cke_reset cke_widget_drag_handler', | ||
3181 | 'data-cke-widget-drag-handler': '1', | ||
3182 | src: CKEDITOR.tools.transparentImageData, | ||
3183 | width: DRAG_HANDLER_SIZE, | ||
3184 | title: editor.lang.widget.move, | ||
3185 | height: DRAG_HANDLER_SIZE, | ||
3186 | role: 'presentation' | ||
3187 | } ); | ||
3188 | widget.inline && img.setAttribute( 'draggable', 'true' ); | ||
3189 | |||
3190 | container.append( img ); | ||
3191 | widget.wrapper.append( container ); | ||
3192 | } | ||
3193 | |||
3194 | // Preventing page reload when dropped content on widget wrapper (http://dev.ckeditor.com/ticket/13015). | ||
3195 | // Widget is not editable so by default drop on it isn't allowed what means that | ||
3196 | // browser handles it (there's no editable#drop event). If there's no drop event we cannot block | ||
3197 | // the drop, so page is reloaded. This listener enables drop on widget wrappers. | ||
3198 | widget.wrapper.on( 'dragover', function( evt ) { | ||
3199 | evt.data.preventDefault(); | ||
3200 | } ); | ||
3201 | |||
3202 | widget.wrapper.on( 'mouseenter', widget.updateDragHandlerPosition, widget ); | ||
3203 | setTimeout( function() { | ||
3204 | widget.on( 'data', widget.updateDragHandlerPosition, widget ); | ||
3205 | }, 50 ); | ||
3206 | |||
3207 | if ( !widget.inline ) { | ||
3208 | img.on( 'mousedown', onBlockWidgetDrag, widget ); | ||
3209 | |||
3210 | // On IE8 'dragstart' is propagated to editable, so editor#dragstart is fired twice on block widgets. | ||
3211 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) { | ||
3212 | img.on( 'dragstart', function( evt ) { | ||
3213 | evt.data.preventDefault( true ); | ||
3214 | } ); | ||
3215 | } | ||
3216 | } | ||
3217 | |||
3218 | widget.dragHandlerContainer = container; | ||
3219 | } | ||
3220 | |||
3221 | function onBlockWidgetDrag( evt ) { | ||
3222 | var finder = this.repository.finder, | ||
3223 | locator = this.repository.locator, | ||
3224 | liner = this.repository.liner, | ||
3225 | editor = this.editor, | ||
3226 | editable = editor.editable(), | ||
3227 | listeners = [], | ||
3228 | sorted = [], | ||
3229 | locations, | ||
3230 | y; | ||
3231 | |||
3232 | // Mark dragged widget for repository#finder. | ||
3233 | this.repository._.draggedWidget = this; | ||
3234 | |||
3235 | // Harvest all possible relations and display some closest. | ||
3236 | var relations = finder.greedySearch(), | ||
3237 | |||
3238 | buffer = CKEDITOR.tools.eventsBuffer( 50, function() { | ||
3239 | locations = locator.locate( relations ); | ||
3240 | |||
3241 | // There's only a single line displayed for D&D. | ||
3242 | sorted = locator.sort( y, 1 ); | ||
3243 | |||
3244 | if ( sorted.length ) { | ||
3245 | liner.prepare( relations, locations ); | ||
3246 | liner.placeLine( sorted[ 0 ] ); | ||
3247 | liner.cleanup(); | ||
3248 | } | ||
3249 | } ); | ||
3250 | |||
3251 | // Let's have the "dragging cursor" over entire editable. | ||
3252 | editable.addClass( 'cke_widget_dragging' ); | ||
3253 | |||
3254 | // Cache mouse position so it is re-used in events buffer. | ||
3255 | listeners.push( editable.on( 'mousemove', function( evt ) { | ||
3256 | y = evt.data.$.clientY; | ||
3257 | buffer.input(); | ||
3258 | } ) ); | ||
3259 | |||
3260 | // Fire drag start as it happens during the native D&D. | ||
3261 | editor.fire( 'dragstart', { target: evt.sender } ); | ||
3262 | |||
3263 | function onMouseUp() { | ||
3264 | var l; | ||
3265 | |||
3266 | buffer.reset(); | ||
3267 | |||
3268 | // Stop observing events. | ||
3269 | while ( ( l = listeners.pop() ) ) | ||
3270 | l.removeListener(); | ||
3271 | |||
3272 | onBlockWidgetDrop.call( this, sorted, evt.sender ); | ||
3273 | } | ||
3274 | |||
3275 | // Mouseup means "drop". This is when the widget is being detached | ||
3276 | // from DOM and placed at range determined by the line (location). | ||
3277 | listeners.push( editor.document.once( 'mouseup', onMouseUp, this ) ); | ||
3278 | |||
3279 | // Prevent calling 'onBlockWidgetDrop' twice in the inline editor. | ||
3280 | // `removeListener` does not work if it is called at the same time event is fired. | ||
3281 | if ( !editable.isInline() ) { | ||
3282 | // Mouseup may occur when user hovers the line, which belongs to | ||
3283 | // the outer document. This is, of course, a valid listener too. | ||
3284 | listeners.push( CKEDITOR.document.once( 'mouseup', onMouseUp, this ) ); | ||
3285 | } | ||
3286 | } | ||
3287 | |||
3288 | function onBlockWidgetDrop( sorted, dragTarget ) { | ||
3289 | var finder = this.repository.finder, | ||
3290 | liner = this.repository.liner, | ||
3291 | editor = this.editor, | ||
3292 | editable = this.editor.editable(); | ||
3293 | |||
3294 | if ( !CKEDITOR.tools.isEmpty( liner.visible ) ) { | ||
3295 | // Retrieve range for the closest location. | ||
3296 | var dropRange = finder.getRange( sorted[ 0 ] ); | ||
3297 | |||
3298 | // Focus widget (it could lost focus after mousedown+mouseup) | ||
3299 | // and save this state as the one where we want to be taken back when undoing. | ||
3300 | this.focus(); | ||
3301 | |||
3302 | // Drag range will be set in the drop listener. | ||
3303 | editor.fire( 'drop', { | ||
3304 | dropRange: dropRange, | ||
3305 | target: dropRange.startContainer | ||
3306 | } ); | ||
3307 | } | ||
3308 | |||
3309 | // Clean-up custom cursor for editable. | ||
3310 | editable.removeClass( 'cke_widget_dragging' ); | ||
3311 | |||
3312 | // Clean-up all remaining lines. | ||
3313 | liner.hideVisible(); | ||
3314 | |||
3315 | // Clean-up drag & drop. | ||
3316 | editor.fire( 'dragend', { target: dragTarget } ); | ||
3317 | } | ||
3318 | |||
3319 | function setupEditables( widget ) { | ||
3320 | var editableName, | ||
3321 | editableDef, | ||
3322 | definedEditables = widget.editables; | ||
3323 | |||
3324 | widget.editables = {}; | ||
3325 | |||
3326 | if ( !widget.editables ) | ||
3327 | return; | ||
3328 | |||
3329 | for ( editableName in definedEditables ) { | ||
3330 | editableDef = definedEditables[ editableName ]; | ||
3331 | widget.initEditable( editableName, typeof editableDef == 'string' ? { selector: editableDef } : editableDef ); | ||
3332 | } | ||
3333 | } | ||
3334 | |||
3335 | function setupMask( widget ) { | ||
3336 | if ( !widget.mask ) | ||
3337 | return; | ||
3338 | |||
3339 | // Reuse mask if already exists (http://dev.ckeditor.com/ticket/11281). | ||
3340 | var img = widget.wrapper.findOne( '.cke_widget_mask' ); | ||
3341 | |||
3342 | if ( !img ) { | ||
3343 | img = new CKEDITOR.dom.element( 'img', widget.editor.document ); | ||
3344 | img.setAttributes( { | ||
3345 | src: CKEDITOR.tools.transparentImageData, | ||
3346 | 'class': 'cke_reset cke_widget_mask' | ||
3347 | } ); | ||
3348 | widget.wrapper.append( img ); | ||
3349 | } | ||
3350 | |||
3351 | widget.mask = img; | ||
3352 | } | ||
3353 | |||
3354 | // Replace parts object containing: | ||
3355 | // partName => selector pairs | ||
3356 | // with: | ||
3357 | // partName => element pairs | ||
3358 | function setupParts( widget ) { | ||
3359 | if ( widget.parts ) { | ||
3360 | var parts = {}, | ||
3361 | el, partName; | ||
3362 | |||
3363 | for ( partName in widget.parts ) { | ||
3364 | el = widget.wrapper.findOne( widget.parts[ partName ] ); | ||
3365 | parts[ partName ] = el; | ||
3366 | } | ||
3367 | widget.parts = parts; | ||
3368 | } | ||
3369 | } | ||
3370 | |||
3371 | function setupWidget( widget, widgetDef ) { | ||
3372 | setupWrapper( widget ); | ||
3373 | setupParts( widget ); | ||
3374 | setupEditables( widget ); | ||
3375 | setupMask( widget ); | ||
3376 | setupDragHandler( widget ); | ||
3377 | setupDataClassesListener( widget ); | ||
3378 | setupA11yListener( widget ); | ||
3379 | |||
3380 | // http://dev.ckeditor.com/ticket/11145: [IE8] Non-editable content of widget is draggable. | ||
3381 | if ( CKEDITOR.env.ie && CKEDITOR.env.version < 9 ) { | ||
3382 | widget.wrapper.on( 'dragstart', function( evt ) { | ||
3383 | var target = evt.data.getTarget(); | ||
3384 | |||
3385 | // Allow text dragging inside nested editables or dragging inline widget's drag handler. | ||
3386 | if ( !Widget.getNestedEditable( widget, target ) && !( widget.inline && Widget.isDomDragHandler( target ) ) ) | ||
3387 | evt.data.preventDefault(); | ||
3388 | } ); | ||
3389 | } | ||
3390 | |||
3391 | widget.wrapper.removeClass( 'cke_widget_new' ); | ||
3392 | widget.element.addClass( 'cke_widget_element' ); | ||
3393 | |||
3394 | widget.on( 'key', function( evt ) { | ||
3395 | var keyCode = evt.data.keyCode; | ||
3396 | |||
3397 | // ENTER. | ||
3398 | if ( keyCode == 13 ) { | ||
3399 | widget.edit(); | ||
3400 | // CTRL+C or CTRL+X. | ||
3401 | } else if ( keyCode == CKEDITOR.CTRL + 67 || keyCode == CKEDITOR.CTRL + 88 ) { | ||
3402 | copySingleWidget( widget, keyCode == CKEDITOR.CTRL + 88 ); | ||
3403 | return; // Do not preventDefault. | ||
3404 | } else if ( keyCode in keystrokesNotBlockedByWidget || ( CKEDITOR.CTRL & keyCode ) || ( CKEDITOR.ALT & keyCode ) ) { | ||
3405 | // Pass chosen keystrokes to other plugins or default fake sel handlers. | ||
3406 | // Pass all CTRL/ALT keystrokes. | ||
3407 | return; | ||
3408 | } | ||
3409 | |||
3410 | return false; | ||
3411 | }, null, null, 999 ); | ||
3412 | // Listen with high priority so it's possible | ||
3413 | // to overwrite this callback. | ||
3414 | |||
3415 | widget.on( 'doubleclick', function( evt ) { | ||
3416 | if ( widget.edit() ) { | ||
3417 | // We have to cancel event if edit method opens a dialog, otherwise | ||
3418 | // link plugin may open extra dialog (http://dev.ckeditor.com/ticket/12140). | ||
3419 | evt.cancel(); | ||
3420 | } | ||
3421 | } ); | ||
3422 | |||
3423 | if ( widgetDef.data ) | ||
3424 | widget.on( 'data', widgetDef.data ); | ||
3425 | |||
3426 | if ( widgetDef.edit ) | ||
3427 | widget.on( 'edit', widgetDef.edit ); | ||
3428 | } | ||
3429 | |||
3430 | function setupWidgetData( widget, startupData ) { | ||
3431 | var widgetDataAttr = widget.element.data( 'cke-widget-data' ); | ||
3432 | |||
3433 | if ( widgetDataAttr ) | ||
3434 | widget.setData( JSON.parse( decodeURIComponent( widgetDataAttr ) ) ); | ||
3435 | if ( startupData ) | ||
3436 | widget.setData( startupData ); | ||
3437 | |||
3438 | // Populate classes if they are not preset. | ||
3439 | if ( !widget.data.classes ) | ||
3440 | widget.setData( 'classes', widget.getClasses() ); | ||
3441 | |||
3442 | // Unblock data and... | ||
3443 | widget.dataReady = true; | ||
3444 | |||
3445 | // Write data to element because this was blocked when data wasn't ready. | ||
3446 | writeDataToElement( widget ); | ||
3447 | |||
3448 | // Fire data event first time, because this was blocked when data wasn't ready. | ||
3449 | widget.fire( 'data', widget.data ); | ||
3450 | } | ||
3451 | |||
3452 | function setupWrapper( widget ) { | ||
3453 | // Retrieve widget wrapper. Assign an id to it. | ||
3454 | var wrapper = widget.wrapper = widget.element.getParent(); | ||
3455 | wrapper.setAttribute( 'data-cke-widget-id', widget.id ); | ||
3456 | } | ||
3457 | |||
3458 | function writeDataToElement( widget ) { | ||
3459 | widget.element.data( 'cke-widget-data', encodeURIComponent( JSON.stringify( widget.data ) ) ); | ||
3460 | } | ||
3461 | |||
3462 | // | ||
3463 | // WIDGET STYLE HANDLER --------------------------------------------------- | ||
3464 | // | ||
3465 | |||
3466 | ( function() { | ||
3467 | // Styles categorized by group. It is used to prevent applying styles for the same group being used together. | ||
3468 | var styleGroups = {}; | ||
3469 | |||
3470 | /** | ||
3471 | * The class representing a widget style. It is an {@link CKEDITOR#STYLE_OBJECT object} like | ||
3472 | * the styles handler for widgets. | ||
3473 | * | ||
3474 | * **Note:** This custom style handler does not support all methods of the {@link CKEDITOR.style} class. | ||
3475 | * Not supported methods: {@link #applyToRange}, {@link #removeFromRange}, {@link #applyToObject}. | ||
3476 | * | ||
3477 | * @since 4.4 | ||
3478 | * @class CKEDITOR.style.customHandlers.widget | ||
3479 | * @extends CKEDITOR.style | ||
3480 | */ | ||
3481 | CKEDITOR.style.addCustomHandler( { | ||
3482 | type: 'widget', | ||
3483 | |||
3484 | setup: function( styleDefinition ) { | ||
3485 | /** | ||
3486 | * The name of widget to which this style can be applied. | ||
3487 | * It is extracted from style definition's `widget` property. | ||
3488 | * | ||
3489 | * @property {String} widget | ||
3490 | */ | ||
3491 | this.widget = styleDefinition.widget; | ||
3492 | |||
3493 | /** | ||
3494 | * An array of groups that this style belongs to. | ||
3495 | * Styles assigned to the same group cannot be combined. | ||
3496 | * | ||
3497 | * @since 4.6.2 | ||
3498 | * @property {Array} group | ||
3499 | */ | ||
3500 | this.group = typeof styleDefinition.group == 'string' ? [ styleDefinition.group ] : styleDefinition.group; | ||
3501 | |||
3502 | // Store style categorized by its group. | ||
3503 | // It is used to prevent enabling two styles from same group. | ||
3504 | if ( this.group ) { | ||
3505 | saveStyleGroup( this ); | ||
3506 | } | ||
3507 | }, | ||
3508 | |||
3509 | apply: function( editor ) { | ||
3510 | var widget; | ||
3511 | |||
3512 | // Before CKEditor 4.4 wasn't a required argument, so we need to | ||
3513 | // handle a case when it wasn't provided. | ||
3514 | if ( !( editor instanceof CKEDITOR.editor ) ) | ||
3515 | return; | ||
3516 | |||
3517 | // Theoretically we could bypass checkApplicable, get widget from | ||
3518 | // widgets.focused and check its name, what would be faster, but then | ||
3519 | // this custom style would work differently than the default style | ||
3520 | // which checks if it's applicable before applying or removing itself. | ||
3521 | if ( this.checkApplicable( editor.elementPath(), editor ) ) { | ||
3522 | widget = editor.widgets.focused; | ||
3523 | |||
3524 | // Remove other styles from the same group. | ||
3525 | if ( this.group ) { | ||
3526 | this.removeStylesFromSameGroup( editor ); | ||
3527 | } | ||
3528 | |||
3529 | widget.applyStyle( this ); | ||
3530 | } | ||
3531 | }, | ||
3532 | |||
3533 | remove: function( editor ) { | ||
3534 | // Before CKEditor 4.4 wasn't a required argument, so we need to | ||
3535 | // handle a case when it wasn't provided. | ||
3536 | if ( !( editor instanceof CKEDITOR.editor ) ) | ||
3537 | return; | ||
3538 | |||
3539 | if ( this.checkApplicable( editor.elementPath(), editor ) ) | ||
3540 | editor.widgets.focused.removeStyle( this ); | ||
3541 | }, | ||
3542 | |||
3543 | /** | ||
3544 | * Removes all styles that belong to the same group as this style. This method will neither add nor remove | ||
3545 | * the current style. | ||
3546 | * Returns `true` if any style was removed, otherwise returns `false`. | ||
3547 | * | ||
3548 | * @since 4.6.2 | ||
3549 | * @param {CKEDITOR.editor} editor | ||
3550 | * @returns {Boolean} | ||
3551 | */ | ||
3552 | removeStylesFromSameGroup: function( editor ) { | ||
3553 | var stylesFromSameGroup, | ||
3554 | path, | ||
3555 | removed = false; | ||
3556 | |||
3557 | // Before CKEditor 4.4 wasn't a required argument, so we need to | ||
3558 | // handle a case when it wasn't provided. | ||
3559 | if ( !( editor instanceof CKEDITOR.editor ) ) | ||
3560 | return false; | ||
3561 | |||
3562 | path = editor.elementPath(); | ||
3563 | if ( this.checkApplicable( path, editor ) ) { | ||
3564 | // Iterate over each group. | ||
3565 | for ( var i = 0, l = this.group.length; i < l; i++ ) { | ||
3566 | stylesFromSameGroup = styleGroups[ this.widget ][ this.group[ i ] ]; | ||
3567 | // Iterate over each style from group. | ||
3568 | for ( var j = 0; j < stylesFromSameGroup.length; j++ ) { | ||
3569 | if ( stylesFromSameGroup[ j ] !== this && stylesFromSameGroup[ j ].checkActive( path, editor ) ) { | ||
3570 | editor.widgets.focused.removeStyle( stylesFromSameGroup[ j ] ); | ||
3571 | removed = true; | ||
3572 | } | ||
3573 | } | ||
3574 | } | ||
3575 | } | ||
3576 | |||
3577 | return removed; | ||
3578 | }, | ||
3579 | |||
3580 | checkActive: function( elementPath, editor ) { | ||
3581 | return this.checkElementMatch( elementPath.lastElement, 0, editor ); | ||
3582 | }, | ||
3583 | |||
3584 | checkApplicable: function( elementPath, editor ) { | ||
3585 | // Before CKEditor 4.4 wasn't a required argument, so we need to | ||
3586 | // handle a case when it wasn't provided. | ||
3587 | if ( !( editor instanceof CKEDITOR.editor ) ) | ||
3588 | return false; | ||
3589 | |||
3590 | return this.checkElement( elementPath.lastElement ); | ||
3591 | }, | ||
3592 | |||
3593 | checkElementMatch: checkElementMatch, | ||
3594 | |||
3595 | checkElementRemovable: checkElementMatch, | ||
3596 | |||
3597 | /** | ||
3598 | * Checks if an element is a {@link CKEDITOR.plugins.widget#wrapper wrapper} of a | ||
3599 | * widget whose name matches the {@link #widget widget name} specified in the style definition. | ||
3600 | * | ||
3601 | * @param {CKEDITOR.dom.element} element | ||
3602 | * @returns {Boolean} | ||
3603 | */ | ||
3604 | checkElement: function( element ) { | ||
3605 | if ( !Widget.isDomWidgetWrapper( element ) ) | ||
3606 | return false; | ||
3607 | |||
3608 | var widgetElement = element.getFirst( Widget.isDomWidgetElement ); | ||
3609 | return widgetElement && widgetElement.data( 'widget' ) == this.widget; | ||
3610 | }, | ||
3611 | |||
3612 | buildPreview: function( label ) { | ||
3613 | return label || this._.definition.name; | ||
3614 | }, | ||
3615 | |||
3616 | /** | ||
3617 | * Returns allowed content rules which should be registered for this style. | ||
3618 | * Uses widget's {@link CKEDITOR.plugins.widget.definition#styleableElements} to make a rule | ||
3619 | * allowing classes on specified elements or use widget's | ||
3620 | * {@link CKEDITOR.plugins.widget.definition#styleToAllowedContentRules} method to transform a style | ||
3621 | * into allowed content rules. | ||
3622 | * | ||
3623 | * @param {CKEDITOR.editor} The editor instance. | ||
3624 | * @returns {CKEDITOR.filter.allowedContentRules} | ||
3625 | */ | ||
3626 | toAllowedContentRules: function( editor ) { | ||
3627 | if ( !editor ) | ||
3628 | return null; | ||
3629 | |||
3630 | var widgetDef = editor.widgets.registered[ this.widget ], | ||
3631 | classes, | ||
3632 | rule = {}; | ||
3633 | |||
3634 | if ( !widgetDef ) | ||
3635 | return null; | ||
3636 | |||
3637 | if ( widgetDef.styleableElements ) { | ||
3638 | classes = this.getClassesArray(); | ||
3639 | if ( !classes ) | ||
3640 | return null; | ||
3641 | |||
3642 | rule[ widgetDef.styleableElements ] = { | ||
3643 | classes: classes, | ||
3644 | propertiesOnly: true | ||
3645 | }; | ||
3646 | return rule; | ||
3647 | } | ||
3648 | if ( widgetDef.styleToAllowedContentRules ) | ||
3649 | return widgetDef.styleToAllowedContentRules( this ); | ||
3650 | return null; | ||
3651 | }, | ||
3652 | |||
3653 | /** | ||
3654 | * Returns classes defined in the style in form of an array. | ||
3655 | * | ||
3656 | * @returns {String[]} | ||
3657 | */ | ||
3658 | getClassesArray: function() { | ||
3659 | var classes = this._.definition.attributes && this._.definition.attributes[ 'class' ]; | ||
3660 | |||
3661 | return classes ? CKEDITOR.tools.trim( classes ).split( /\s+/ ) : null; | ||
3662 | }, | ||
3663 | |||
3664 | /** | ||
3665 | * Not implemented. | ||
3666 | * | ||
3667 | * @method applyToRange | ||
3668 | */ | ||
3669 | applyToRange: notImplemented, | ||
3670 | |||
3671 | /** | ||
3672 | * Not implemented. | ||
3673 | * | ||
3674 | * @method removeFromRange | ||
3675 | */ | ||
3676 | removeFromRange: notImplemented, | ||
3677 | |||
3678 | /** | ||
3679 | * Not implemented. | ||
3680 | * | ||
3681 | * @method applyToObject | ||
3682 | */ | ||
3683 | applyToObject: notImplemented | ||
3684 | } ); | ||
3685 | |||
3686 | function notImplemented() {} | ||
3687 | |||
3688 | // @context style | ||
3689 | function checkElementMatch( element, fullMatch, editor ) { | ||
3690 | // Before CKEditor 4.4 wasn't a required argument, so we need to | ||
3691 | // handle a case when it wasn't provided. | ||
3692 | if ( !editor ) | ||
3693 | return false; | ||
3694 | |||
3695 | if ( !this.checkElement( element ) ) | ||
3696 | return false; | ||
3697 | |||
3698 | var widget = editor.widgets.getByElement( element, true ); | ||
3699 | return widget && widget.checkStyleActive( this ); | ||
3700 | } | ||
3701 | |||
3702 | // Save and categorize style by its group. | ||
3703 | function saveStyleGroup( style ) { | ||
3704 | var widgetName = style.widget, | ||
3705 | group; | ||
3706 | |||
3707 | if ( !styleGroups[ widgetName ] ) { | ||
3708 | styleGroups[ widgetName ] = {}; | ||
3709 | } | ||
3710 | |||
3711 | for ( var i = 0, l = style.group.length; i < l; i++ ) { | ||
3712 | group = style.group[ i ]; | ||
3713 | if ( !styleGroups[ widgetName ][ group ] ) { | ||
3714 | styleGroups[ widgetName ][ group ] = []; | ||
3715 | } | ||
3716 | |||
3717 | styleGroups[ widgetName ][ group ].push( style ); | ||
3718 | } | ||
3719 | } | ||
3720 | |||
3721 | } )(); | ||
3722 | |||
3723 | // | ||
3724 | // EXPOSE PUBLIC API ------------------------------------------------------ | ||
3725 | // | ||
3726 | |||
3727 | CKEDITOR.plugins.widget = Widget; | ||
3728 | Widget.repository = Repository; | ||
3729 | Widget.nestedEditable = NestedEditable; | ||
3730 | } )(); | ||
3731 | |||
3732 | /** | ||
3733 | * An event fired when a widget definition is registered by the {@link CKEDITOR.plugins.widget.repository#add} method. | ||
3734 | * It is possible to modify the definition being registered. | ||
3735 | * | ||
3736 | * @event widgetDefinition | ||
3737 | * @member CKEDITOR.editor | ||
3738 | * @param {CKEDITOR.plugins.widget.definition} data Widget definition. | ||
3739 | */ | ||
3740 | |||
3741 | /** | ||
3742 | * This is an abstract class that describes the definition of a widget. | ||
3743 | * It is a type of {@link CKEDITOR.plugins.widget.repository#add} method's second argument. | ||
3744 | * | ||
3745 | * Widget instances inherit from registered widget definitions, although not in a prototypal way. | ||
3746 | * They are simply extended with corresponding widget definitions. Note that not all properties of | ||
3747 | * the widget definition become properties of a widget. Some, like {@link #data} or {@link #edit}, become | ||
3748 | * widget's events listeners. | ||
3749 | * | ||
3750 | * @class CKEDITOR.plugins.widget.definition | ||
3751 | * @abstract | ||
3752 | * @mixins CKEDITOR.feature | ||
3753 | */ | ||
3754 | |||
3755 | /** | ||
3756 | * Widget definition name. It is automatically set when the definition is | ||
3757 | * {@link CKEDITOR.plugins.widget.repository#add registered}. | ||
3758 | * | ||
3759 | * @property {String} name | ||
3760 | */ | ||
3761 | |||
3762 | /** | ||
3763 | * The method executed while initializing a widget, after a widget instance | ||
3764 | * is created, but before it is ready. It is executed before the first | ||
3765 | * {@link CKEDITOR.plugins.widget#event-data} is fired so it is common to | ||
3766 | * use the `init` method to populate widget data with information loaded from | ||
3767 | * the DOM, like for exmaple: | ||
3768 | * | ||
3769 | * init: function() { | ||
3770 | * this.setData( 'width', this.element.getStyle( 'width' ) ); | ||
3771 | * | ||
3772 | * if ( this.parts.caption.getStyle( 'display' ) != 'none' ) | ||
3773 | * this.setData( 'showCaption', true ); | ||
3774 | * } | ||
3775 | * | ||
3776 | * @property {Function} init | ||
3777 | */ | ||
3778 | |||
3779 | /** | ||
3780 | * The function to be used to upcast an element to this widget or a | ||
3781 | * comma-separated list of upcast methods from the {@link #upcasts} object. | ||
3782 | * | ||
3783 | * The upcast function **is not** executed in the widget context (because the widget | ||
3784 | * does not exist yet) and two arguments are passed: | ||
3785 | * | ||
3786 | * * `element` ({@link CKEDITOR.htmlParser.element}) – The element to be checked. | ||
3787 | * * `data` (`Object`) – The object which can be extended with data which will then be passed to the widget. | ||
3788 | * | ||
3789 | * An element will be upcasted if a function returned `true` or an instance of | ||
3790 | * a {@link CKEDITOR.htmlParser.element} if upcasting meant DOM structure changes | ||
3791 | * (in this case the widget will be initialized on the returned element). | ||
3792 | * | ||
3793 | * @property {String/Function} upcast | ||
3794 | */ | ||
3795 | |||
3796 | /** | ||
3797 | * The object containing functions which can be used to upcast this widget. | ||
3798 | * Only those pointed by the {@link #upcast} property will be used. | ||
3799 | * | ||
3800 | * In most cases it is appropriate to use {@link #upcast} directly, | ||
3801 | * because majority of widgets need just one method. | ||
3802 | * However, in some cases the widget author may want to expose more than one variant | ||
3803 | * and then this property may be used. | ||
3804 | * | ||
3805 | * upcasts: { | ||
3806 | * // This function may upcast only figure elements. | ||
3807 | * figure: function() { | ||
3808 | * // ... | ||
3809 | * }, | ||
3810 | * // This function may upcast only image elements. | ||
3811 | * image: function() { | ||
3812 | * // ... | ||
3813 | * }, | ||
3814 | * // More variants... | ||
3815 | * } | ||
3816 | * | ||
3817 | * // Then, widget user may choose which upcast methods will be enabled. | ||
3818 | * editor.on( 'widgetDefinition', function( evt ) { | ||
3819 | * if ( evt.data.name == 'image' ) | ||
3820 | * evt.data.upcast = 'figure,image'; // Use both methods. | ||
3821 | * } ); | ||
3822 | * | ||
3823 | * @property {Object} upcasts | ||
3824 | */ | ||
3825 | |||
3826 | /** | ||
3827 | * The {@link #upcast} method(s) priority. The upcast with a lower priority number will be called before | ||
3828 | * the one with a higher number. The default priority is `10`. | ||
3829 | * | ||
3830 | * @since 4.5 | ||
3831 | * @property {Number} [upcastPriority=10] | ||
3832 | */ | ||
3833 | |||
3834 | /** | ||
3835 | * The function to be used to downcast this widget or | ||
3836 | * a name of the downcast option from the {@link #downcasts} object. | ||
3837 | * | ||
3838 | * The downcast funciton will be executed in the {@link CKEDITOR.plugins.widget} context | ||
3839 | * and with `widgetElement` ({@link CKEDITOR.htmlParser.element}) argument which is | ||
3840 | * the widget's main element. | ||
3841 | * | ||
3842 | * The function may return an instance of the {@link CKEDITOR.htmlParser.node} class if the widget | ||
3843 | * needs to be downcasted to a different node than the widget's main element. | ||
3844 | * | ||
3845 | * @property {String/Function} downcast | ||
3846 | */ | ||
3847 | |||
3848 | /** | ||
3849 | * The object containing functions which can be used to downcast this widget. | ||
3850 | * Only the one pointed by the {@link #downcast} property will be used. | ||
3851 | * | ||
3852 | * In most cases it is appropriate to use {@link #downcast} directly, | ||
3853 | * because majority of widgets have just one variant of downcasting (or none at all). | ||
3854 | * However, in some cases the widget author may want to expose more than one variant | ||
3855 | * and then this property may be used. | ||
3856 | * | ||
3857 | * downcasts: { | ||
3858 | * // This downcast may transform the widget into the figure element. | ||
3859 | * figure: function() { | ||
3860 | * // ... | ||
3861 | * }, | ||
3862 | * // This downcast may transform the widget into the image element with data-* attributes. | ||
3863 | * image: function() { | ||
3864 | * // ... | ||
3865 | * } | ||
3866 | * } | ||
3867 | * | ||
3868 | * // Then, the widget user may choose one of the downcast options when setting up his editor. | ||
3869 | * editor.on( 'widgetDefinition', function( evt ) { | ||
3870 | * if ( evt.data.name == 'image' ) | ||
3871 | * evt.data.downcast = 'figure'; | ||
3872 | * } ); | ||
3873 | * | ||
3874 | * @property downcasts | ||
3875 | */ | ||
3876 | |||
3877 | /** | ||
3878 | * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-edit} event listener. | ||
3879 | * This means that it will be executed when a widget is being edited. | ||
3880 | * See the {@link CKEDITOR.plugins.widget#method-edit} method. | ||
3881 | * | ||
3882 | * @property {Function} edit | ||
3883 | */ | ||
3884 | |||
3885 | /** | ||
3886 | * If set, it will be added as the {@link CKEDITOR.plugins.widget#event-data} event listener. | ||
3887 | * This means that it will be executed every time the {@link CKEDITOR.plugins.widget#property-data widget data} changes. | ||
3888 | * | ||
3889 | * @property {Function} data | ||
3890 | */ | ||
3891 | |||
3892 | /** | ||
3893 | * The method to be executed when the widget's command is executed in order to insert a new widget | ||
3894 | * (widget of this type is not focused). If not defined, then the default action will be | ||
3895 | * performed which means that: | ||
3896 | * | ||
3897 | * * An instance of the widget will be created in a detached {@link CKEDITOR.dom.documentFragment document fragment}, | ||
3898 | * * The {@link CKEDITOR.plugins.widget#method-edit} method will be called to trigger widget editing, | ||
3899 | * * The widget element will be inserted into DOM. | ||
3900 | * | ||
3901 | * @property {Function} insert | ||
3902 | */ | ||
3903 | |||
3904 | /** | ||
3905 | * The name of a dialog window which will be opened on {@link CKEDITOR.plugins.widget#method-edit}. | ||
3906 | * If not defined, then the {@link CKEDITOR.plugins.widget#method-edit} method will not perform any action and | ||
3907 | * widget's command will insert a new widget without opening a dialog window first. | ||
3908 | * | ||
3909 | * @property {String} dialog | ||
3910 | */ | ||
3911 | |||
3912 | /** | ||
3913 | * The template which will be used to create a new widget element (when the widget's command is executed). | ||
3914 | * This string is populated with {@link #defaults default values} by using the {@link CKEDITOR.template} format. | ||
3915 | * Therefore it has to be a valid {@link CKEDITOR.template} argument. | ||
3916 | * | ||
3917 | * @property {String} template | ||
3918 | */ | ||
3919 | |||
3920 | /** | ||
3921 | * The data object which will be used to populate the data of a newly created widget. | ||
3922 | * See {@link CKEDITOR.plugins.widget#property-data}. | ||
3923 | * | ||
3924 | * defaults: { | ||
3925 | * showCaption: true, | ||
3926 | * align: 'none' | ||
3927 | * } | ||
3928 | * | ||
3929 | * @property defaults | ||
3930 | */ | ||
3931 | |||
3932 | /** | ||
3933 | * An object containing definitions of widget components (part name => CSS selector). | ||
3934 | * | ||
3935 | * parts: { | ||
3936 | * image: 'img', | ||
3937 | * caption: 'div.caption' | ||
3938 | * } | ||
3939 | * | ||
3940 | * @property parts | ||
3941 | */ | ||
3942 | |||
3943 | /** | ||
3944 | * An object containing definitions of nested editables (editable name => {@link CKEDITOR.plugins.widget.nestedEditable.definition}). | ||
3945 | * Note that editables *have to* be defined in the same order as they are in DOM / {@link CKEDITOR.plugins.widget.definition#template template}. | ||
3946 | * Otherwise errors will occur when nesting widgets inside each other. | ||
3947 | * | ||
3948 | * editables: { | ||
3949 | * header: 'h1', | ||
3950 | * content: { | ||
3951 | * selector: 'div.content', | ||
3952 | * allowedContent: 'p strong em; a[!href]' | ||
3953 | * } | ||
3954 | * } | ||
3955 | * | ||
3956 | * @property editables | ||
3957 | */ | ||
3958 | |||
3959 | /** | ||
3960 | * The function used to obtain an accessibility label for the widget. It might be used to make | ||
3961 | * the widget labels as precise as possible, since it has access to the widget instance. | ||
3962 | * | ||
3963 | * If not specified, the default implementation will use the {@link #pathName} or the main | ||
3964 | * {@link CKEDITOR.plugins.widget#element element} tag name. | ||
3965 | * | ||
3966 | * @property {Function} getLabel | ||
3967 | */ | ||
3968 | |||
3969 | /** | ||
3970 | * The widget name displayed in the elements path. | ||
3971 | * | ||
3972 | * @property {String} pathName | ||
3973 | */ | ||
3974 | |||
3975 | /** | ||
3976 | * If set to `true`, the widget's element will be covered with a transparent mask. | ||
3977 | * This will prevent its content from being clickable, which matters in case | ||
3978 | * of special elements like embedded Flash or iframes that generate a separate "context". | ||
3979 | * | ||
3980 | * @property {Boolean} mask | ||
3981 | */ | ||
3982 | |||
3983 | /** | ||
3984 | * If set to `true/false`, it will force the widget to be either an inline or a block widget. | ||
3985 | * If not set, the widget type will be determined from the widget element. | ||
3986 | * | ||
3987 | * Widget type influences whether a block (`div`) or an inline (`span`) element is used | ||
3988 | * for the wrapper. | ||
3989 | * | ||
3990 | * @property {Boolean} inline | ||
3991 | */ | ||
3992 | |||
3993 | /** | ||
3994 | * The label for the widget toolbar button. | ||
3995 | * | ||
3996 | * editor.widgets.add( 'simplebox', { | ||
3997 | * button: 'Create a simple box' | ||
3998 | * } ); | ||
3999 | * | ||
4000 | * editor.widgets.add( 'simplebox', { | ||
4001 | * button: editor.lang.simplebox.title | ||
4002 | * } ); | ||
4003 | * | ||
4004 | * @property {String} button | ||
4005 | */ | ||
4006 | |||
4007 | /** | ||
4008 | * Whether widget should be draggable. Defaults to `true`. | ||
4009 | * If set to `false` drag handler will not be displayed when hovering widget. | ||
4010 | * | ||
4011 | * @property {Boolean} draggable | ||
4012 | */ | ||
4013 | |||
4014 | /** | ||
4015 | * Names of element(s) (separated by spaces) for which the {@link CKEDITOR.filter} should allow classes | ||
4016 | * defined in the widget styles. For example if your widget is upcasted from a simple `<div>` | ||
4017 | * element, then in order to make it styleable you can set: | ||
4018 | * | ||
4019 | * editor.widgets.add( 'customWidget', { | ||
4020 | * upcast: function( element ) { | ||
4021 | * return element.name == 'div'; | ||
4022 | * }, | ||
4023 | * | ||
4024 | * // ... | ||
4025 | * | ||
4026 | * styleableElements: 'div' | ||
4027 | * } ); | ||
4028 | * | ||
4029 | * Then, when the following style is defined: | ||
4030 | * | ||
4031 | * { | ||
4032 | * name: 'Thick border', type: 'widget', widget: 'customWidget', | ||
4033 | * attributes: { 'class': 'thickBorder' } | ||
4034 | * } | ||
4035 | * | ||
4036 | * a rule allowing the `thickBorder` class for `div` elements will be registered in the {@link CKEDITOR.filter}. | ||
4037 | * | ||
4038 | * If you need to have more freedom when transforming widget style to allowed content rules, | ||
4039 | * you can use the {@link #styleToAllowedContentRules} callback. | ||
4040 | * | ||
4041 | * @since 4.4 | ||
4042 | * @property {String} styleableElements | ||
4043 | */ | ||
4044 | |||
4045 | /** | ||
4046 | * Function transforming custom widget's {@link CKEDITOR.style} instance into | ||
4047 | * {@link CKEDITOR.filter.allowedContentRules}. It may be used when a static | ||
4048 | * {@link #styleableElements} property is not enough to inform the {@link CKEDITOR.filter} | ||
4049 | * what HTML features should be enabled when allowing the given style. | ||
4050 | * | ||
4051 | * In most cases, when style's classes just have to be added to element name(s) used by | ||
4052 | * the widget element, it is recommended to use simpler {@link #styleableElements} property. | ||
4053 | * | ||
4054 | * In order to get parsed classes from the style definition you can use | ||
4055 | * {@link CKEDITOR.style.customHandlers.widget#getClassesArray}. | ||
4056 | * | ||
4057 | * For example, if you want to use the [object format of allowed content rules](#!/guide/dev_allowed_content_rules-section-object-format), | ||
4058 | * to specify `match` validator, your implementation could look like this: | ||
4059 | * | ||
4060 | * editor.widgets.add( 'customWidget', { | ||
4061 | * // ... | ||
4062 | * | ||
4063 | * styleToAllowedContentRules: funciton( style ) { | ||
4064 | * // Retrieve classes defined in the style. | ||
4065 | * var classes = style.getClassesArray(); | ||
4066 | * | ||
4067 | * // Do something crazy - for example return allowed content rules in object format, | ||
4068 | * // with custom match property and propertiesOnly flag. | ||
4069 | * return { | ||
4070 | * h1: { | ||
4071 | * match: isWidgetElement, | ||
4072 | * propertiesOnly: true, | ||
4073 | * classes: classes | ||
4074 | * } | ||
4075 | * }; | ||
4076 | * } | ||
4077 | * } ); | ||
4078 | * | ||
4079 | * @since 4.4 | ||
4080 | * @property {Function} styleToAllowedContentRules | ||
4081 | * @param {CKEDITOR.style.customHandlers.widget} style The style to be transformed. | ||
4082 | * @returns {CKEDITOR.filter.allowedContentRules} | ||
4083 | */ | ||
4084 | |||
4085 | /** | ||
4086 | * This is an abstract class that describes the definition of a widget's nested editable. | ||
4087 | * It is a type of values in the {@link CKEDITOR.plugins.widget.definition#editables} object. | ||
4088 | * | ||
4089 | * In the simplest case the definition is a string which is a CSS selector used to | ||
4090 | * find an element that will become a nested editable inside the widget. Note that | ||
4091 | * the widget element can be a nested editable, too. | ||
4092 | * | ||
4093 | * In the more advanced case a definition is an object with a required `selector` property. | ||
4094 | * | ||
4095 | * editables: { | ||
4096 | * header: 'h1', | ||
4097 | * content: { | ||
4098 | * selector: 'div.content', | ||
4099 | * allowedContent: 'p strong em; a[!href]' | ||
4100 | * } | ||
4101 | * } | ||
4102 | * | ||
4103 | * @class CKEDITOR.plugins.widget.nestedEditable.definition | ||
4104 | * @abstract | ||
4105 | */ | ||
4106 | |||
4107 | /** | ||
4108 | * The CSS selector used to find an element which will become a nested editable. | ||
4109 | * | ||
4110 | * @property {String} selector | ||
4111 | */ | ||
4112 | |||
4113 | /** | ||
4114 | * The [Advanced Content Filter](#!/guide/dev_advanced_content_filter) rules | ||
4115 | * which will be used to limit the content allowed in this nested editable. | ||
4116 | * This option is similar to {@link CKEDITOR.config#allowedContent} and one can | ||
4117 | * use it to limit the editor features available in the nested editable. | ||
4118 | * | ||
4119 | * @property {CKEDITOR.filter.allowedContentRules} allowedContent | ||
4120 | */ | ||
4121 | |||
4122 | /** | ||
4123 | * Nested editable name displayed in elements path. | ||
4124 | * | ||
4125 | * @property {String} pathName | ||
4126 | */ | ||
diff --git a/app/assets/javascripts/ckeditor/plugins/widgetselection/plugin.js b/app/assets/javascripts/ckeditor/plugins/widgetselection/plugin.js deleted file mode 100644 index e21ea88..0000000 --- a/app/assets/javascripts/ckeditor/plugins/widgetselection/plugin.js +++ /dev/null | |||
@@ -1,366 +0,0 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview A plugin created to handle ticket http://dev.ckeditor.com/ticket/11064. While the issue is caused by native WebKit/Blink behaviour, | ||
8 | * this plugin can be easily detached or modified when the issue is fixed in the browsers without changing the core. | ||
9 | * When Ctrl/Cmd + A is pressed to select all content it does not work due to a bug in | ||
10 | * Webkit/Blink if a non-editable element is at the beginning or the end of the content. | ||
11 | */ | ||
12 | |||
13 | ( function() { | ||
14 | 'use strict'; | ||
15 | |||
16 | CKEDITOR.plugins.add( 'widgetselection', { | ||
17 | |||
18 | init: function( editor ) { | ||
19 | if ( CKEDITOR.env.webkit ) { | ||
20 | var widgetselection = CKEDITOR.plugins.widgetselection; | ||
21 | |||
22 | editor.on( 'contentDom', function( evt ) { | ||
23 | |||
24 | var editor = evt.editor, | ||
25 | doc = editor.document, | ||
26 | editable = editor.editable(); | ||
27 | |||
28 | editable.attachListener( doc, 'keydown', function( evt ) { | ||
29 | var data = evt.data.$; | ||
30 | |||
31 | // Ctrl/Cmd + A | ||
32 | if ( evt.data.getKey() == 65 && ( CKEDITOR.env.mac && data.metaKey || !CKEDITOR.env.mac && data.ctrlKey ) ) { | ||
33 | |||
34 | // Defer the call so the selection is already changed by the pressed keys. | ||
35 | CKEDITOR.tools.setTimeout( function() { | ||
36 | |||
37 | // Manage filler elements on keydown. If there is no need | ||
38 | // to add fillers, we need to check and clean previously used once. | ||
39 | if ( !widgetselection.addFillers( editable ) ) { | ||
40 | widgetselection.removeFillers( editable ); | ||
41 | } | ||
42 | }, 0 ); | ||
43 | } | ||
44 | }, null, null, -1 ); | ||
45 | |||
46 | // Check and clean previously used fillers. | ||
47 | editor.on( 'selectionCheck', function( evt ) { | ||
48 | widgetselection.removeFillers( evt.editor.editable() ); | ||
49 | } ); | ||
50 | |||
51 | // Remove fillers on paste before data gets inserted into editor. | ||
52 | editor.on( 'paste', function( evt ) { | ||
53 | evt.data.dataValue = widgetselection.cleanPasteData( evt.data.dataValue ); | ||
54 | } ); | ||
55 | |||
56 | if ( 'selectall' in editor.plugins ) { | ||
57 | widgetselection.addSelectAllIntegration( editor ); | ||
58 | } | ||
59 | } ); | ||
60 | } | ||
61 | } | ||
62 | } ); | ||
63 | |||
64 | /** | ||
65 | * A set of helper methods for the Widget Selection plugin. | ||
66 | * | ||
67 | * @property widgetselection | ||
68 | * @member CKEDITOR.plugins | ||
69 | * @since 4.6.1 | ||
70 | */ | ||
71 | CKEDITOR.plugins.widgetselection = { | ||
72 | |||
73 | /** | ||
74 | * The start filler element reference. | ||
75 | * | ||
76 | * @property {CKEDITOR.dom.element} | ||
77 | * @member CKEDITOR.plugins.widgetselection | ||
78 | * @private | ||
79 | */ | ||
80 | startFiller: null, | ||
81 | |||
82 | /** | ||
83 | * The end filler element reference. | ||
84 | * | ||
85 | * @property {CKEDITOR.dom.element} | ||
86 | * @member CKEDITOR.plugins.widgetselection | ||
87 | * @private | ||
88 | */ | ||
89 | endFiller: null, | ||
90 | |||
91 | /** | ||
92 | * An attribute which identifies the filler element. | ||
93 | * | ||
94 | * @property {String} | ||
95 | * @member CKEDITOR.plugins.widgetselection | ||
96 | * @private | ||
97 | */ | ||
98 | fillerAttribute: 'data-cke-filler-webkit', | ||
99 | |||
100 | /** | ||
101 | * The default content of the filler element. Note: The filler needs to have `visible` content. | ||
102 | * Unprintable elements or empty content do not help as a workaround. | ||
103 | * | ||
104 | * @property {String} | ||
105 | * @member CKEDITOR.plugins.widgetselection | ||
106 | * @private | ||
107 | */ | ||
108 | fillerContent: ' ', | ||
109 | |||
110 | /** | ||
111 | * Tag name which is used to create fillers. | ||
112 | * | ||
113 | * @property {String} | ||
114 | * @member CKEDITOR.plugins.widgetselection | ||
115 | * @private | ||
116 | */ | ||
117 | fillerTagName: 'div', | ||
118 | |||
119 | /** | ||
120 | * Adds a filler before or after a non-editable element at the beginning or the end of the `editable`. | ||
121 | * | ||
122 | * @param {CKEDITOR.editable} editable | ||
123 | * @returns {Boolean} | ||
124 | * @member CKEDITOR.plugins.widgetselection | ||
125 | */ | ||
126 | addFillers: function( editable ) { | ||
127 | var editor = editable.editor; | ||
128 | |||
129 | // Whole content should be selected, if not fix the selection manually. | ||
130 | if ( !this.isWholeContentSelected( editable ) && editable.getChildCount() > 0 ) { | ||
131 | |||
132 | var firstChild = editable.getFirst( filterTempElements ), | ||
133 | lastChild = editable.getLast( filterTempElements ); | ||
134 | |||
135 | // Check if first element is editable. If not prepend with filler. | ||
136 | if ( firstChild && firstChild.type == CKEDITOR.NODE_ELEMENT && !firstChild.isEditable() ) { | ||
137 | this.startFiller = this.createFiller(); | ||
138 | editable.append( this.startFiller, 1 ); | ||
139 | } | ||
140 | |||
141 | // Check if last element is editable. If not append filler. | ||
142 | if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && !lastChild.isEditable() ) { | ||
143 | this.endFiller = this.createFiller( true ); | ||
144 | editable.append( this.endFiller, 0 ); | ||
145 | } | ||
146 | |||
147 | // Reselect whole content after any filler was added. | ||
148 | if ( this.hasFiller( editable ) ) { | ||
149 | var rangeAll = editor.createRange(); | ||
150 | rangeAll.selectNodeContents( editable ); | ||
151 | rangeAll.select(); | ||
152 | return true; | ||
153 | } | ||
154 | } | ||
155 | return false; | ||
156 | }, | ||
157 | |||
158 | /** | ||
159 | * Removes filler elements or updates their references. | ||
160 | * | ||
161 | * It will **not remove** filler elements if the whole content is selected, as it would break the | ||
162 | * selection. | ||
163 | * | ||
164 | * @param {CKEDITOR.editable} editable | ||
165 | * @member CKEDITOR.plugins.widgetselection | ||
166 | */ | ||
167 | removeFillers: function( editable ) { | ||
168 | // If startFiller or endFiller exists and not entire content is selected it means the selection | ||
169 | // just changed from selected all. We need to remove fillers and set proper selection/content. | ||
170 | if ( this.hasFiller( editable ) && !this.isWholeContentSelected( editable ) ) { | ||
171 | |||
172 | var startFillerContent = editable.findOne( this.fillerTagName + '[' + this.fillerAttribute + '=start]' ), | ||
173 | endFillerContent = editable.findOne( this.fillerTagName + '[' + this.fillerAttribute + '=end]' ); | ||
174 | |||
175 | if ( this.startFiller && startFillerContent && this.startFiller.equals( startFillerContent ) ) { | ||
176 | this.removeFiller( this.startFiller, editable ); | ||
177 | } else { | ||
178 | // The start filler is still present but it is a different element than previous one. It means the | ||
179 | // undo recreating entirely selected content was performed. We need to update filler reference. | ||
180 | this.startFiller = startFillerContent; | ||
181 | } | ||
182 | |||
183 | if ( this.endFiller && endFillerContent && this.endFiller.equals( endFillerContent ) ) { | ||
184 | this.removeFiller( this.endFiller, editable ); | ||
185 | } else { | ||
186 | // Same as with start filler. | ||
187 | this.endFiller = endFillerContent; | ||
188 | } | ||
189 | } | ||
190 | }, | ||
191 | |||
192 | /** | ||
193 | * Removes fillers from the paste data. | ||
194 | * | ||
195 | * @param {String} data | ||
196 | * @returns {String} | ||
197 | * @member CKEDITOR.plugins.widgetselection | ||
198 | * @private | ||
199 | */ | ||
200 | cleanPasteData: function( data ) { | ||
201 | if ( data && data.length ) { | ||
202 | data = data | ||
203 | .replace( this.createFillerRegex(), '' ) | ||
204 | .replace( this.createFillerRegex( true ), '' ); | ||
205 | } | ||
206 | return data; | ||
207 | }, | ||
208 | |||
209 | /** | ||
210 | * Checks if the entire content of the given editable is selected. | ||
211 | * | ||
212 | * @param {CKEDITOR.editable} editable | ||
213 | * @returns {Boolean} | ||
214 | * @member CKEDITOR.plugins.widgetselection | ||
215 | * @private | ||
216 | */ | ||
217 | isWholeContentSelected: function( editable ) { | ||
218 | |||
219 | var range = editable.editor.getSelection().getRanges()[ 0 ]; | ||
220 | if ( range ) { | ||
221 | |||
222 | if ( range && range.collapsed ) { | ||
223 | return false; | ||
224 | |||
225 | } else { | ||
226 | var rangeClone = range.clone(); | ||
227 | rangeClone.enlarge( CKEDITOR.ENLARGE_ELEMENT ); | ||
228 | |||
229 | return !!( rangeClone && editable && rangeClone.startContainer && rangeClone.endContainer && | ||
230 | rangeClone.startOffset === 0 && rangeClone.endOffset === editable.getChildCount() && | ||
231 | rangeClone.startContainer.equals( editable ) && rangeClone.endContainer.equals( editable ) ); | ||
232 | } | ||
233 | } | ||
234 | return false; | ||
235 | }, | ||
236 | |||
237 | /** | ||
238 | * Checks if there is any filler element in the given editable. | ||
239 | * | ||
240 | * @param {CKEDITOR.editable} editable | ||
241 | * @returns {Boolean} | ||
242 | * @member CKEDITOR.plugins.widgetselection | ||
243 | * @private | ||
244 | */ | ||
245 | hasFiller: function( editable ) { | ||
246 | return editable.find( this.fillerTagName + '[' + this.fillerAttribute + ']' ).count() > 0; | ||
247 | }, | ||
248 | |||
249 | /** | ||
250 | * Creates a filler element. | ||
251 | * | ||
252 | * @param {Boolean} [onEnd] If filler will be placed on end or beginning of the content. | ||
253 | * @returns {CKEDITOR.dom.element} | ||
254 | * @member CKEDITOR.plugins.widgetselection | ||
255 | * @private | ||
256 | */ | ||
257 | createFiller: function( onEnd ) { | ||
258 | var filler = new CKEDITOR.dom.element( this.fillerTagName ); | ||
259 | filler.setHtml( this.fillerContent ); | ||
260 | filler.setAttribute( this.fillerAttribute, onEnd ? 'end' : 'start' ); | ||
261 | filler.setAttribute( 'data-cke-temp', 1 ); | ||
262 | filler.setStyles( { | ||
263 | display: 'block', | ||
264 | width: 0, | ||
265 | height: 0, | ||
266 | padding: 0, | ||
267 | border: 0, | ||
268 | margin: 0, | ||
269 | position: 'absolute', | ||
270 | top: 0, | ||
271 | left: '-9999px', | ||
272 | opacity: 0, | ||
273 | overflow: 'hidden' | ||
274 | } ); | ||
275 | |||
276 | return filler; | ||
277 | }, | ||
278 | |||
279 | /** | ||
280 | * Removes the specific filler element from the given editable. If the filler contains any content (typed or pasted), | ||
281 | * it replaces the current editable content. If not, the caret is placed before the first or after the last editable | ||
282 | * element (depends if the filler was at the beginning or the end). | ||
283 | * | ||
284 | * @param {CKEDITOR.dom.element} filler | ||
285 | * @param {CKEDITOR.editable} editable | ||
286 | * @member CKEDITOR.plugins.widgetselection | ||
287 | * @private | ||
288 | */ | ||
289 | removeFiller: function( filler, editable ) { | ||
290 | if ( filler ) { | ||
291 | var editor = editable.editor, | ||
292 | currentRange = editable.editor.getSelection().getRanges()[ 0 ], | ||
293 | currentPath = currentRange.startPath(), | ||
294 | range = editor.createRange(), | ||
295 | insertedHtml, | ||
296 | fillerOnStart, | ||
297 | manuallyHandleCaret; | ||
298 | |||
299 | if ( currentPath.contains( filler ) ) { | ||
300 | insertedHtml = filler.getHtml(); | ||
301 | manuallyHandleCaret = true; | ||
302 | } | ||
303 | |||
304 | fillerOnStart = filler.getAttribute( this.fillerAttribute ) == 'start'; | ||
305 | filler.remove(); | ||
306 | filler = null; | ||
307 | |||
308 | if ( insertedHtml && insertedHtml.length > 0 && insertedHtml != this.fillerContent ) { | ||
309 | editable.insertHtmlIntoRange( insertedHtml, editor.getSelection().getRanges()[ 0 ] ); | ||
310 | range.setStartAt( editable.getChild( editable.getChildCount() - 1 ), CKEDITOR.POSITION_BEFORE_END ); | ||
311 | editor.getSelection().selectRanges( [ range ] ); | ||
312 | |||
313 | } else if ( manuallyHandleCaret ) { | ||
314 | if ( fillerOnStart ) { | ||
315 | range.setStartAt( editable.getFirst().getNext(), CKEDITOR.POSITION_AFTER_START ); | ||
316 | } else { | ||
317 | range.setEndAt( editable.getLast().getPrevious(), CKEDITOR.POSITION_BEFORE_END ); | ||
318 | } | ||
319 | editable.editor.getSelection().selectRanges( [ range ] ); | ||
320 | } | ||
321 | } | ||
322 | }, | ||
323 | |||
324 | /** | ||
325 | * Creates a regular expression which will match the filler HTML in the text. | ||
326 | * | ||
327 | * @param {Boolean} [onEnd] Whether a regular expression should be created for the filler at the beginning or | ||
328 | * the end of the content. | ||
329 | * @returns {RegExp} | ||
330 | * @member CKEDITOR.plugins.widgetselection | ||
331 | * @private | ||
332 | */ | ||
333 | createFillerRegex: function( onEnd ) { | ||
334 | var matcher = this.createFiller( onEnd ).getOuterHtml() | ||
335 | .replace( /style="[^"]*"/gi, 'style="[^"]*"' ) | ||
336 | .replace( />[^<]*</gi, '>[^<]*<' ); | ||
337 | |||
338 | return new RegExp( ( !onEnd ? '^' : '' ) + matcher + ( onEnd ? '$' : '' ) ); | ||
339 | }, | ||
340 | |||
341 | /** | ||
342 | * Adds an integration for the [Select All](http://ckeditor.com/addon/selectall) plugin to the given `editor`. | ||
343 | * | ||
344 | * @private | ||
345 | * @param {CKEDITOR.editor} editor | ||
346 | * @member CKEDITOR.plugins.widgetselection | ||
347 | */ | ||
348 | addSelectAllIntegration: function( editor ) { | ||
349 | var widgetselection = this; | ||
350 | |||
351 | editor.editable().attachListener( editor, 'beforeCommandExec', function( evt ) { | ||
352 | var editable = editor.editable(); | ||
353 | |||
354 | if ( evt.data.name == 'selectAll' && editable ) { | ||
355 | widgetselection.addFillers( editable ); | ||
356 | } | ||
357 | }, null, null, 9999 ); | ||
358 | } | ||
359 | }; | ||
360 | |||
361 | |||
362 | function filterTempElements( el ) { | ||
363 | return el.getName && !el.hasAttribute( 'data-cke-temp' ); | ||
364 | } | ||
365 | |||
366 | } )(); | ||