about summary refs log tree commit diff stats
path: root/app/assets/javascripts/ckeditor/plugins/image2/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/ckeditor/plugins/image2/dialogs')
-rw-r--r--app/assets/javascripts/ckeditor/plugins/image2/dialogs/image2.js553
1 files changed, 0 insertions, 553 deletions
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
12CKEDITOR.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} );