1 /*
  2 Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
  3 For licensing, see LICENSE.html or http://ckeditor.com/license
  4 */
  5
  6 (function()
  7 {
  8 	// Load image preview.
  9 	var IMAGE = 1,
 10 		LINK = 2,
 11 		PREVIEW = 4,
 12 		CLEANUP = 8,
 13 		regexGetSize = /^\s*(\d+)((px)|\%)?\s*$/i,
 14 		regexGetSizeOrEmpty = /(^\s*(\d+)((px)|\%)?\s*$)|^$/i;
 15
 16 	var onSizeChange = function()
 17 	{
 18 		var value = this.getValue(),	// This = input element.
 19 			dialog = this.getDialog(),
 20 			aMatch  =  value.match( regexGetSize );	// Check value
 21 		if ( aMatch )
 22 		{
 23 			if ( aMatch[2] == '%' )			// % is allowed - > unlock ratio.
 24 				switchLockRatio( dialog, false );	// Unlock.
 25 			value = aMatch[1];
 26 		}
 27
 28 		// Only if ratio is locked
 29 		if ( dialog.lockRatio )
 30 		{
 31 			var oImageOriginal = dialog.originalElement;
 32 			if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
 33 			{
 34 				if ( this.id == 'txtHeight' )
 35 				{
 36 					if ( value && value != '0' )
 37 						value = Math.round( oImageOriginal.$.width * ( value  / oImageOriginal.$.height ) );
 38 					if ( !isNaN( value ) )
 39 						dialog.setValueOf( 'info', 'txtWidth', value );
 40 				}
 41 				else		//this.id = txtWidth.
 42 				{
 43 					if ( value && value != '0' )
 44 						value = Math.round( oImageOriginal.$.height * ( value  / oImageOriginal.$.width ) );
 45 					if ( !isNaN( value ) )
 46 						dialog.setValueOf( 'info', 'txtHeight', value );
 47 				}
 48 			}
 49 		}
 50 		updatePreview( dialog );
 51 	};
 52
 53 	var updatePreview = function( dialog )
 54 	{
 55 		//Don't load before onShow.
 56 		if ( !dialog.originalElement || !dialog.preview )
 57 			return 1;
 58
 59 		// Read attributes and update imagePreview;
 60 		dialog.commitContent( PREVIEW, dialog.preview );
 61 		return 0;
 62 	};
 63
 64 	var switchLockRatio = function( dialog, value )
 65 	{
 66 		var oImageOriginal = dialog.originalElement,
 67 			ratioButton = CKEDITOR.document.getById( 'btnLockSizes' );
 68
 69 		if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
 70 		{
 71 			if ( value == 'check' )			// Check image ratio and original image ratio.
 72 			{
 73 				var width = dialog.getValueOf( 'info', 'txtWidth' ),
 74 					height = dialog.getValueOf( 'info', 'txtHeight' ),
 75 					originalRatio = oImageOriginal.$.width * 1000 / oImageOriginal.$.height,
 76 					thisRatio = width * 1000 / height;
 77 				dialog.lockRatio  = false;		// Default: unlock ratio
 78
 79 				if ( !width && !height )
 80 					dialog.lockRatio = true;
 81 				else if ( !isNaN( originalRatio ) && !isNaN( thisRatio ) )
 82 				{
 83 					if ( Math.round( originalRatio ) == Math.round( thisRatio ) )
 84 						dialog.lockRatio = true;
 85 				}
 86 			}
 87 			else if ( value != undefined )
 88 				dialog.lockRatio = value;
 89 			else
 90 				dialog.lockRatio = !dialog.lockRatio;
 91 		}
 92 		else if ( value != 'check' )		// I can't lock ratio if ratio is unknown.
 93 			dialog.lockRatio = false;
 94
 95 		if ( dialog.lockRatio )
 96 			ratioButton.removeClass( 'cke_btn_unlocked' );
 97 		else
 98 			ratioButton.addClass( 'cke_btn_unlocked' );
 99
100 		return dialog.lockRatio;
101 	};
102
103 	var resetSize = function( dialog )
104 	{
105 		var oImageOriginal = dialog.originalElement;
106 		if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
107 		{
108 			dialog.setValueOf( 'info', 'txtWidth', oImageOriginal.$.width );
109 			dialog.setValueOf( 'info', 'txtHeight', oImageOriginal.$.height );
110 		}
111 		updatePreview( dialog );
112 	};
113
114 	var setupDimension = function( type, element )
115 	{
116 		if ( type != IMAGE )
117 			return;
118
119 		function checkDimension( size, defaultValue )
120 		{
121 			var aMatch  =  size.match( regexGetSize );
122 			if ( aMatch )
123 			{
124 				if ( aMatch[2] == '%' )				// % is allowed.
125 				{
126 					aMatch[1] += '%';
127 					switchLockRatio( dialog, false );	// Unlock ratio
128 				}
129 				return aMatch[1];
130 			}
131 			return defaultValue;
132 		}
133
134 		var dialog = this.getDialog(),
135 			value = '',
136 			dimension = (( this.id == 'txtWidth' )? 'width' : 'height' ),
137 			size = element.getAttribute( dimension );
138
139 		if ( size )
140 			value = checkDimension( size, value );
141 		value = checkDimension( element.$.style[ dimension ], value );
142
143 		this.setValue( value );
144 	};
145
146 	var imageDialog = function( editor, dialogType )
147 	{
148 		var onImgLoadEvent = function()
149 		{
150 			// Image is ready.
151 			var original = this.originalElement;
152 			original.setCustomData( 'isReady', 'true' );
153 			original.removeListener( 'load', onImgLoadEvent );
154 			original.removeListener( 'error', onImgLoadErrorEvent );
155 			original.removeListener( 'abort', onImgLoadErrorEvent );
156
157 			// Hide loader
158 			CKEDITOR.document.getById( 'ImagePreviewLoader' ).setStyle( 'display', 'none' );
159
160 			// New image -> new domensions
161 			if ( !this.dontResetSize )
162 				resetSize( this );
163
164 			if ( this.firstLoad )
165 				switchLockRatio( this, 'check' );
166 			this.firstLoad = false;
167 			this.dontResetSize = false;
168 		};
169
170 		var onImgLoadErrorEvent = function()
171 		{
172 			// Error. Image is not loaded.
173 			var original = this.originalElement;
174 			original.removeListener( 'load', onImgLoadEvent );
175 			original.removeListener( 'error', onImgLoadErrorEvent );
176 			original.removeListener( 'abort', onImgLoadErrorEvent );
177
178 			// Set Error image.
179 			var noimage = CKEDITOR.getUrl( editor.skinPath + 'images/noimage.png' );
180
181 			if ( this.preview )
182 				this.preview.setAttribute( 'src', noimage );
183
184 			// Hide loader
185 			CKEDITOR.document.getById( 'ImagePreviewLoader' ).setStyle( 'display', 'none' );
186 			switchLockRatio( this, false );	// Unlock.
187 		};
188 		return {
189 			title : ( dialogType == 'image' ) ? editor.lang.image.title : editor.lang.image.titleButton,
190 			minWidth : 420,
191 			minHeight : 310,
192 			onShow : function()
193 			{
194 				this.imageElement = false;
195 				this.linkElement = false;
196
197 				// Default: create a new element.
198 				this.imageEditMode = false;
199 				this.linkEditMode = false;
200
201 				this.lockRatio = true;
202 				this.dontResetSize = false;
203 				this.firstLoad = true;
204 				this.addLink = false;
205
206 				//Hide loader.
207 				CKEDITOR.document.getById( 'ImagePreviewLoader' ).setStyle( 'display', 'none' );
208 				// Preview
209 				this.preview = CKEDITOR.document.getById( 'previewImage' );
210
211 				var editor = this.getParentEditor(),
212 					element = this.getParentEditor().getSelection().getSelectedElement();
213
214 				// Copy of the image
215 				this.originalElement = editor.document.createElement( 'img' );
216 				this.originalElement.setAttribute( 'alt', '' );
217 				this.originalElement.setCustomData( 'isReady', 'false' );
218
219 				if ( element && element.getName() == 'a' )
220 				{
221 					this.linkElement = element;
222 					this.linkEditMode = true;
223
224 					// Look for Image element.
225 					var linkChildren = element.getChildren();
226 					if ( linkChildren.count() == 1 )			// 1 child.
227 					{
228 						var childTagName = linkChildren.getItem( 0 ).getName();
229 						if ( childTagName == 'img' || childTagName == 'input' )
230 						{
231 							this.imageElement = linkChildren.getItem( 0 );
232 							if ( this.imageElement.getName() == 'img' )
233 								this.imageEditMode = 'img';
234 							else if ( this.imageElement.getName() == 'input' )
235 								this.imageEditMode = 'input';
236 						}
237 					}
238 					// Fill out all fields.
239 					if ( dialogType == 'image' )
240 						this.setupContent( LINK, element );
241 				}
242 				else if ( element && element.getName() == 'img' && !element.getAttribute( '_cke_protected_html' ) )
243 					this.imageEditMode = 'img';
244 				else if ( element && element.getName() == 'input' && element.getAttribute( 'type' ) && element.getAttribute( 'type' ) == 'image' )
245 					this.imageEditMode = 'input';
246
247 				if ( this.imageEditMode || this.imageElement )
248 				{
249 					if ( !this.imageElement )
250 						this.imageElement = element;
251
252 					// Fill out all fields.
253 					this.setupContent( IMAGE, this.imageElement );
254
255 					// Refresh LockRatio button
256 					switchLockRatio ( this, true );
257 				}
258 			},
259 			onOk : function()
260 			{
261 				// Edit existing Image.
262 				if ( this.imageEditMode )
263 				{
264 					var imgTagName = this.imageEditMode,
265 						removeObj = this.imageElement;
266
267 					// Image dialog and Input element.
268 					if ( dialogType == 'image' && imgTagName == 'input' && confirm( editor.lang.image.button2Img ) )
269 					{
270 						// Replace INPUT-> IMG
271 						imgTagName = 'img';
272 						this.imageElement = editor.document.createElement( 'img' );
273 						this.imageElement.setAttribute( 'alt', '' );
274 						removeObj.insertBeforeMe( this.imageElement );
275 						removeObj.remove( false );
276
277 					}
278 					// ImageButton dialog and Image element.
279 					else if ( dialogType != 'image' && imgTagName == 'img' && confirm( editor.lang.image.img2Button ))
280 					{
281 						// Replace IMG -> INPUT
282 						imgTagName = 'input';
283 						this.imageElement = editor.document.createElement( 'input' );
284 						this.imageElement.setAttributes(
285 							{
286 								type : 'image',
287 								alt : ''
288 							}
289 						);
290 						removeObj.insertBeforeMe( this.imageElement );
291 						removeObj.remove( false );
292 					}
293 				}
294 				else	// Create a new image.
295 				{
296 					// Image dialog -> create IMG element.
297 					if ( dialogType == 'image' )
298 						this.imageElement = editor.document.createElement( 'img' );
299 					else
300 					{
301 						this.imageElement = editor.document.createElement( 'input' );
302 						this.imageElement.setAttribute ( 'type' ,'image' );
303 					}
304 					this.imageElement.setAttribute( 'alt', '' );
305 				}
306
307 				// Create a new link.
308 				if ( !this.linkEditMode )
309 					this.linkElement = editor.document.createElement( 'a' );
310
311 				// Set attributes.
312 				this.commitContent( IMAGE, this.imageElement );
313 				this.commitContent( LINK, this.linkElement );
314
315 				// Insert a new Image.
316 				if ( !this.imageEditMode )
317 				{
318 					if ( this.addLink )
319 					{
320 						//Insert a new Link.
321 						if ( !this.linkEditMode )
322 						{
323 							this.linkElement.append( this.imageElement, false );
324 							editor.insertElement( this.linkElement );
325 						}
326 						else 	//Link already exists, image not.
327 							this.linkElement.append( this.imageElement, false );
328 					}
329 					else
330 						editor.insertElement( this.imageElement );
331 				}
332 				else		// Image already exists.
333 				{
334 					//Add a new link element.
335 					if ( !this.linkEditMode && this.addLink )
336 					{
337 						this.imageElement.insertBeforeMe( this.linkElement );
338 						this.imageElement.appendTo( this.linkElement );
339 					}
340 					//Remove Link, Image exists.
341 					else if ( this.linkEditMode && !this.addLink )
342 						this.linkElement.remove( true );
343 				}
344 			},
345 			onLoad : function()
346 			{
347 				if ( dialogType != 'image' )
348 					this.hidePage( 'Link' );		//Hide Link tab.
349 			},
350 			onHide : function()
351 			{
352 				if ( this.preview )
353 					this.commitContent( CLEANUP, this.preview );
354
355 				if ( this.originalElement )
356 				{
357 					this.originalElement.removeListener( 'load', onImgLoadEvent );
358 					this.originalElement.removeListener( 'error', onImgLoadErrorEvent );
359 					this.originalElement.removeListener( 'abort', onImgLoadErrorEvent );
360 					this.originalElement.remove();
361 					this.originalElement = false;		// Dialog is closed.
362 				}
363 			},
364 			contents : [
365 				{
366 					id : 'info',
367 					label : editor.lang.image.infoTab,
368 					accessKey : 'I',
369 					elements :
370 					[
371 						{
372 							type : 'vbox',
373 							padding : 0,
374 							children :
375 							[
376 								{
377 									type : 'html',
378 									html : '<span>' + CKEDITOR.tools.htmlEncode( editor.lang.image.url ) + '</span>'
379 								},
380 								{
381 									type : 'hbox',
382 									widths : [ '280px', '110px' ],
383 									align : 'right',
384 									children :
385 									[
386 										{
387 											id : 'txtUrl',
388 											type : 'text',
389 											label : '',
390 											onChange : function()
391 											{
392 												var dialog = this.getDialog(),
393 													newUrl = this.getValue();
394
395 												//Update original image
396 												if ( newUrl.length > 0 )	//Prevent from load before onShow
397 												{
398 													dialog = this.getDialog();
399 													var original = dialog.originalElement;
400
401 													original.setCustomData( 'isReady', 'false' );
402 													// Show loader
403 													var loader = CKEDITOR.document.getById( 'ImagePreviewLoader' );
404 													if ( loader )
405 														loader.setStyle( 'display', '' );
406
407 													original.on( 'load', onImgLoadEvent, dialog );
408 													original.on( 'error', onImgLoadErrorEvent, dialog );
409 													original.on( 'abort', onImgLoadErrorEvent, dialog );
410 													original.setAttribute( 'src', newUrl );
411 													dialog.preview.setAttribute( 'src', newUrl );
412
413 													updatePreview( dialog );
414 												}
415 											},
416 											setup : function( type, element )
417 											{
418 												if ( type == IMAGE )
419 												{
420 													var dialog = this.getDialog();
421 													var url = element.getAttribute( '_cke_saved_src' );
422 													if ( !url )
423 														url = element.getAttribute( 'src' );
424 													dialog.dontResetSize = true;
425 													this.setValue( url );		// And call this.onChange()
426 													this.focus();
427 												}
428 											},
429 											commit : function( type, element )
430 											{
431 												if ( type == IMAGE && ( this.getValue() || this.isChanged() ) )
432 												{
433 													element.setAttribute( '_cke_saved_src', decodeURI( this.getValue() ) );
434 													element.setAttribute( 'src', decodeURI( this.getValue() ) );
435 												}
436 												else if ( type == CLEANUP )
437 												{
438 													element.setAttribute( 'src', '' );	// If removeAttribute doesn't work.
439 													element.removeAttribute( 'src' );
440 												}
441 											}
442 										},
443 										{
444 											type : 'button',
445 											id : 'browse',
446 											align : 'center',
447 											label : editor.lang.common.browseServer,
448 											hidden : true,
449 											filebrowser : 'info:txtUrl'
450 										}
451 									]
452 								}
453 							]
454 						},
455 						{
456 							id : 'txtAlt',
457 							type : 'text',
458 							label : editor.lang.image.alt,
459 							accessKey : 'A',
460 							'default' : '',
461 							onChange : function()
462 							{
463 								updatePreview( this.getDialog() );
464 							},
465 							setup : function( type, element )
466 							{
467 								if ( type == IMAGE )
468 									this.setValue( element.getAttribute( 'alt' ) );
469 							},
470 							commit : function( type, element )
471 							{
472 								if ( type == IMAGE )
473 								{
474 									if ( this.getValue() || this.isChanged() )
475 										element.setAttribute( 'alt', this.getValue() );
476 								}
477 								else if ( type == PREVIEW )
478 								{
479 									element.setAttribute( 'alt', this.getValue() );
480 								}
481 								else if ( type == CLEANUP )
482 								{
483 									element.removeAttribute( 'alt' );
484 								}
485 							}
486 						},
487 						{
488 							type : 'hbox',
489 							widths : [ '140px', '240px' ],
490 							children :
491 							[
492 								{
493 									type : 'vbox',
494 									padding : 10,
495 									children :
496 									[
497 										{
498 											type : 'hbox',
499 											widths : [ '70%', '30%' ],
500 											children :
501 											[
502 												{
503 													type : 'vbox',
504 													padding : 1,
505 													children :
506 													[
507 														{
508 															type : 'text',
509 															id : 'txtWidth',
510 															labelLayout : 'horizontal',
511 															label : editor.lang.image.width,
512 															onKeyUp : onSizeChange,
513 															validate: function()
514 															{
515 																var aMatch  =  this.getValue().match( regexGetSizeOrEmpty );
516 																if ( !aMatch )
517 																	alert( editor.lang.common.validateNumberFailed );
518 																return !!aMatch;
519 															},
520 															setup : setupDimension,
521 															commit : function( type, element )
522 															{
523 																if ( type == IMAGE )
524 																{
525 																	var value = this.getValue();
526 																	if ( value )
527 																		element.setAttribute( 'width', value );
528 																	else if ( !value && this.isChanged() )
529 																		element.removeAttribute( 'width' );
530 																}
531 																else if ( type == PREVIEW )
532 																{
533 																	value = this.getValue();
534 																	var aMatch = value.match( regexGetSize );
535 																	if ( !aMatch )
536 																	{
537 																		var oImageOriginal = this.getDialog().originalElement;
538 																		if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
539 																			element.setStyle( 'width',  oImageOriginal.$.width + 'px');
540 																	}
541 																	else
542 																		element.setStyle( 'width', value + 'px');
543 																}
544 																else if ( type == CLEANUP )
545 																{
546 																	element.setStyle( 'width', '0px' );	// If removeAttribute doesn't work.
547 																	element.removeAttribute( 'width' );
548 																	element.removeStyle( 'width' );
549 																}
550 															}
551 														},
552 														{
553 															type : 'text',
554 															id : 'txtHeight',
555 															labelLayout : 'horizontal',
556 															label : editor.lang.image.height,
557 															onKeyUp : onSizeChange,
558 															validate: function()
559 															{
560 																var aMatch = this.getValue().match( regexGetSizeOrEmpty );
561 																if ( !aMatch )
562 																	alert( editor.lang.common.validateNumberFailed );
563 																return !!aMatch;
564 															},
565 															setup : setupDimension,
566 															commit : function( type, element )
567 															{
568 																if ( type == IMAGE )
569 																{
570 																	var value = this.getValue();
571 																	if ( value )
572 																		element.setAttribute( 'height', value );
573 																	else if ( !value && this.isChanged() )
574 																		element.removeAttribute( 'height' );
575 																}
576 																else if ( type == PREVIEW )
577 																{
578 																	value = this.getValue();
579 																	var aMatch = value.match( regexGetSize );
580 																	if ( !aMatch )
581 																	{
582 																		var oImageOriginal = this.getDialog().originalElement;
583 																		if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' )
584 																			element.setStyle( 'height',  oImageOriginal.$.height + 'px');
585 																	}
586 																	else
587 																		element.setStyle( 'height', value + 'px');
588 																}
589 																else if ( type == CLEANUP )
590 																{
591 																	element.setStyle( 'height', '0px' );	// If removeAttribute doesn't work.
592 																	element.removeAttribute( 'height' );
593 																	element.removeStyle( 'height' );
594 																}
595 															}
596 														}
597 													]
598 												},
599 												{
600 													type : 'html',
601 													style : 'position:relative;top:10px;height:50px;',
602 													onLoad : function()
603 													{
604 														// Activate Reset button
605 														var	resetButton = CKEDITOR.document.getById( 'btnResetSize' ),
606 															ratioButton = CKEDITOR.document.getById( 'btnLockSizes' );
607 														if ( resetButton )
608 														{
609 															resetButton.on( 'click', function()
610 																{
611 																	resetSize( this );
612 																}, this.getDialog() );
613 															resetButton.on( 'mouseover', function()
614 																{
615 																	this.addClass( 'BtnOver' );
616 																}, resetButton );
617 															resetButton.on( 'mouseout', function()
618 																{
619 																	this.removeClass( 'BtnOver' );
620 																}, resetButton );
621 														}
622 														// Activate (Un)LockRatio button
623 														if ( ratioButton )
624 														{
625 															ratioButton.on( 'click', function()
626 																{
627 																	var locked = switchLockRatio( this ),
628 																		oImageOriginal = this.originalElement,
629 																		width = this.getValueOf( 'info', 'txtWidth' );
630
631 																	if ( oImageOriginal.getCustomData( 'isReady' ) == 'true' && width )
632 																	{
633 																		var height = oImageOriginal.$.height / oImageOriginal.$.width * width;
634 																		if ( !isNaN( height ) )
635 																		{
636 																			this.setValueOf( 'info', 'txtHeight', Math.round( height ) );
637 																			updatePreview( this );
638 																		}
639 																	}
640 																}, this.getDialog() );
641 															ratioButton.on( 'mouseover', function()
642 																{
643 																	this.addClass( 'BtnOver' );
644 																}, ratioButton );
645 															ratioButton.on( 'mouseout', function()
646 																{
647 																	this.removeClass( 'BtnOver' );
648 																}, ratioButton );
649 														}
650 													},
651 													html : '<div>'+
652 														'<div title="' + editor.lang.image.lockRatio +
653 														'" class="cke_btn_locked" id="btnLockSizes"></div>' +
654 														'<div title="' + editor.lang.image.resetSize +
655 														'" class="cke_btn_reset" id="btnResetSize"></div>'+
656 														'</div>'
657 												}
658 											]
659 										},
660 										{
661 											type : 'vbox',
662 											padding : 1,
663 											children :
664 											[
665 												{
666 													type : 'text',
667 													id : 'txtBorder',
668 													labelLayout : 'horizontal',
669 													label : editor.lang.image.border,
670 													'default' : '',
671 													onKeyUp : function()
672 													{
673 														updatePreview( this.getDialog() );
674 													},
675 													validate: function()
676 													{
677 														var func = CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed );
678 														return func.apply( this );
679 													},
680 													setup : function( type, element )
681 													{
682 														if ( type == IMAGE )
683 															this.setValue( element.getAttribute( 'border' ) );
684 													},
685 													commit : function( type, element )
686 													{
687 														if ( type == IMAGE )
688 														{
689 															if ( this.getValue() || this.isChanged() )
690 																element.setAttribute( 'border', this.getValue() );
691 														}
692 														else if ( type == PREVIEW )
693 														{
694 															var value = parseInt( this.getValue(), 10 );
695 															value = isNaN( value ) ? 0 : value;
696 															element.setAttribute( 'border', value );
697 															element.setStyle( 'border', value + 'px solid black' );
698 														}
699 														else if ( type == CLEANUP )
700 														{
701 															element.removeAttribute( 'border' );
702 															element.removeStyle( 'border' );
703 														}
704 													}
705 												},
706 												{
707 													type : 'text',
708 													id : 'txtHSpace',
709 													labelLayout : 'horizontal',
710 													label : editor.lang.image.hSpace,
711 													'default' : '',
712 													onKeyUp : function()
713 													{
714 														updatePreview( this.getDialog() );
715 													},
716 													validate: function()
717 													{
718 														var func = CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed );
719 														return func.apply( this );
720 													},
721 													setup : function( type, element )
722 													{
723 														if ( type == IMAGE )
724 														{
725 															var value = element.getAttribute( 'hspace' );
726 															if ( value != -1 )				// In IE empty = -1.
727 																this.setValue( value );
728 														}
729 													},
730 													commit : function( type, element )
731 													{
732 														if ( type == IMAGE )
733 														{
734 															if ( this.getValue() || this.isChanged() )
735 																element.setAttribute( 'hspace', this.getValue() );
736 														}
737 														else if ( type == PREVIEW )
738 														{
739 															var value = parseInt( this.getValue(), 10 );
740 															value = isNaN( value ) ? 0 : value;
741 															element.setAttribute( 'hspace', value );
742 															element.setStyle( 'margin-left', value + 'px' );
743 															element.setStyle( 'margin-right', value + 'px' );
744 														}
745 														else if ( type == CLEANUP )
746 														{
747 															element.removeAttribute( 'hspace' );
748 															element.removeStyle( 'margin-left' );
749 															element.removeStyle( 'margin-right' );
750 														}
751 													}
752 												},
753 												{
754 													type : 'text',
755 													id : 'txtVSpace',
756 													labelLayout : 'horizontal',
757 													label : editor.lang.image.vSpace,
758 													'default' : '',
759 													onKeyUp : function()
760 													{
761 														updatePreview( this.getDialog() );
762 													},
763 													validate: function()
764 													{
765 														var func = CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed );
766 														return func.apply( this );
767 													},
768 													setup : function( type, element )
769 													{
770 														if ( type == IMAGE )
771 															this.setValue( element.getAttribute( 'vspace' ) );
772 													},
773 													commit : function( type, element )
774 													{
775 														if ( type == IMAGE )
776 														{
777 															if ( this.getValue() || this.isChanged() )
778 																element.setAttribute( 'vspace', this.getValue() );
779 														}
780 														else if ( type == PREVIEW )
781 														{
782 															var value = parseInt( this.getValue(), 10 );
783 															value = isNaN( value ) ? 0 : value;
784 															element.setAttribute( 'vspace', this.getValue() );
785 															element.setStyle( 'margin-top', value + 'px' );
786 															element.setStyle( 'margin-bottom', value + 'px' );
787 														}
788 														else if ( type == CLEANUP )
789 														{
790 															element.removeAttribute( 'vspace' );
791 															element.removeStyle( 'margin-top' );
792 															element.removeStyle( 'margin-bottom' );
793 														}
794 													}
795 												},
796 												{
797 													id : 'cmbAlign',
798 													type : 'select',
799 													labelLayout : 'horizontal',
800 													widths : [ '35%','65%' ],
801 													style : 'width:100%',
802 													label : editor.lang.image.align,
803 													'default' : '',
804 													items :
805 													[
806 														[ editor.lang.common.notSet , ''],
807 														[ editor.lang.image.alignLeft , 'left'],
808 														[ editor.lang.image.alignAbsBottom , 'absBottom'],
809 														[ editor.lang.image.alignAbsMiddle , 'absMiddle'],
810 														[ editor.lang.image.alignBaseline , 'baseline'],
811 														[ editor.lang.image.alignBottom , 'bottom'],
812 														[ editor.lang.image.alignMiddle , 'middle'],
813 														[ editor.lang.image.alignRight , 'right'],
814 														[ editor.lang.image.alignTextTop , 'textTop'],
815 														[ editor.lang.image.alignTop , 'top']
816 													],
817 													onChange : function()
818 													{
819 														updatePreview( this.getDialog() );
820 													},
821 													setup : function( type, element )
822 													{
823 														if ( type == IMAGE )
824 															this.setValue( element.getAttribute( 'align' ) );
825 													},
826 													commit : function( type, element )
827 													{
828 														var value = this.getValue();
829 														if ( type == IMAGE )
830 														{
831 															if ( value || this.isChanged() )
832 																element.setAttribute( 'align', value );
833 														}
834 														else if ( type == PREVIEW )
835 														{
836 															element.setAttribute( 'align', this.getValue() );
837
838 															if ( value == 'absMiddle' || value == 'middle' )
839 																element.setStyle( 'vertical-align', 'middle' );
840 															else if ( value == 'top' || value == 'textTop' )
841 																element.setStyle( 'vertical-align', 'top' );
842 															else
843 																element.removeStyle( 'vertical-align' );
844
845 															if ( value == 'right' || value == 'left' )
846 																element.setStyle( 'styleFloat', value );
847 															else
848 																element.removeStyle( 'styleFloat' );
849
850 														}
851 														else if ( type == CLEANUP )
852 														{
853 															element.removeAttribute( 'align' );
854 														}
855 													}
856 												}
857 											]
858 										}
859 									]
860 								},
861 								{
862 									type : 'vbox',
863 									height : '250px',
864 									children :
865 									[
866 										{
867 											type : 'html',
868 											style : 'width:95%;',
869 											html : '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.image.preview ) +'<br>'+
870 											'<div id="ImagePreviewLoader" style="display:none"><div class="loading"> </div></div>'+
871 											'<div id="ImagePreviewBox">'+
872 											'<a href="javascript:void(0)" target="_blank" onclick="return false;" id="previewLink">'+
873 											'<img id="previewImage" src="" alt="" /></a>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. '+
874 											'Maecenas feugiat consequat diam. Maecenas metus. Vivamus diam purus, cursus a, commodo non, facilisis vitae, '+
875 											'nulla. Aenean dictum lacinia tortor. Nunc iaculis, nibh non iaculis aliquam, orci felis euismod neque, sed ornare massa mauris sed velit. Nulla pretium mi et risus. Fusce mi pede, tempor id, cursus ac, ullamcorper nec, enim. Sed tortor. Curabitur molestie. Duis velit augue, condimentum at, ultrices a, luctus ut, orci. Donec pellentesque egestas eros. Integer cursus, augue in cursus faucibus, eros pede bibendum sem, in tempus tellus justo quis ligula. Etiam eget tortor. Vestibulum rutrum, est ut placerat elementum, lectus nisl aliquam velit, tempor aliquam eros nunc nonummy metus. In eros metus, gravida a, gravida sed, lobortis id, turpis. Ut ultrices, ipsum at venenatis fringilla, sem nulla lacinia tellus, eget aliquet turpis mauris non enim. Nam turpis. Suspendisse lacinia. Curabitur ac tortor ut ipsum egestas elementum. Nunc imperdiet gravida mauris.' +
876 											'</div>'+'</div>'
877 										}
878 									]
879 								}
880 							]
881 						}
882 					]
883 				},
884 				{
885 					id : 'Link',
886 					label : editor.lang.link.title,
887 					padding : 0,
888 					elements :
889 					[
890 						{
891 							id : 'txtUrl',
892 							type : 'text',
893 							label : editor.lang.image.url,
894 							style : 'width: 100%',
895 							'default' : '',
896 							setup : function( type, element )
897 							{
898 								if ( type == LINK )
899 								{
900 									var href = element.getAttribute( '_cke_saved_href' );
901 									if ( !href )
902 										href = element.getAttribute( 'href' );
903 									this.setValue( href );
904 								}
905 							},
906 							commit : function( type, element )
907 							{
908 								if ( type == LINK )
909 								{
910 									if ( this.getValue() || this.isChanged() )
911 									{
912 										element.setAttribute( '_cke_saved_href', decodeURI( this.getValue() ) );
913 										element.setAttribute( 'href', 'javascript:void(0)/*' +
914 											CKEDITOR.tools.getNextNumber() + '*/' );
915
916 										if ( this.getValue() || !editor.config.image_removeLinkByEmptyURL )
917 											this.getDialog().addLink = true;
918 									}
919 								}
920 							}
921 						},
922 						{
923 							type : 'button',
924 							id : 'browse',
925 							filebrowser : 'Link:txtUrl',
926 							style : 'float:right',
927 							hidden : true,
928 							label : editor.lang.common.browseServer
929 						},
930 						{
931 							id : 'cmbTarget',
932 							type : 'select',
933 							label : editor.lang.link.target,
934 							'default' : '',
935 							items :
936 							[
937 								[ editor.lang.link.targetNotSet , ''],
938 								[ editor.lang.link.targetNew , '_blank'],
939 								[ editor.lang.link.targetTop , '_top'],
940 								[ editor.lang.link.targetSelf , '_self'],
941 								[ editor.lang.link.targetParent , '_parent']
942 							],
943 							setup : function( type, element )
944 							{
945 								if ( type == LINK )
946 									this.setValue( element.getAttribute( 'target' ) );
947 							},
948 							commit : function( type, element )
949 							{
950 								if ( type == LINK )
951 								{
952 									if ( this.getValue() || this.isChanged() )
953 										element.setAttribute( 'target', this.getValue() );
954 								}
955 							}
956 						}
957 					]
958 				},
959 				{
960 					id : 'Upload',
961 					hidden : true,
962 					filebrowser : 'uploadButton',
963 					label : editor.lang.image.upload,
964 					elements :
965 					[
966 						{
967 							type : 'file',
968 							id : 'upload',
969 							label : editor.lang.image.btnUpload,
970 							size : 38
971 						},
972 						{
973 							type : 'fileButton',
974 							id : 'uploadButton',
975 							filebrowser : 'info:txtUrl',
976 							label : editor.lang.image.btnUpload,
977 							'for' : [ 'Upload', 'upload' ]
978 						}
979 					]
980 				},
981 				{
982 					id : 'advanced',
983 					label : editor.lang.common.advancedTab,
984 					elements :
985 					[
986 						{
987 							type : 'hbox',
988 							widths : [ '50%', '25%', '25%' ],
989 							children :
990 							[
991 								{
992 									type : 'text',
993 									id : 'linkId',
994 									label : editor.lang.common.id,
995 									setup : function( type, element )
996 									{
997 										if ( type == IMAGE )
998 											this.setValue( element.getAttribute( 'id' ) );
999 									},
1000 									commit : function( type, element )
1001 									{
1002 										if ( type == IMAGE )
1003 										{
1004 											if ( this.getValue() || this.isChanged() )
1005 												element.setAttribute( 'id', this.getValue() );
1006 										}
1007 									}
1008 								},
1009 								{
1010 									id : 'cmbLangDir',
1011 									type : 'select',
1012 									style : 'width : 100%;',
1013 									label : editor.lang.common.langDir,
1014 									'default' : '',
1015 									items :
1016 									[
1017 										[ editor.lang.common.notSet, '' ],
1018 										[ editor.lang.common.langDirLtr, 'ltr' ],
1019 										[ editor.lang.common.langDirRtl, 'rtl' ]
1020 									],
1021 									setup : function( type, element )
1022 									{
1023 										if ( type == IMAGE )
1024 											this.setValue( element.getAttribute( 'dir' ) );
1025 									},
1026 									commit : function( type, element )
1027 									{
1028 										if ( type == IMAGE )
1029 										{
1030 											if ( this.getValue() || this.isChanged() )
1031 												element.setAttribute( 'dir', this.getValue() );
1032 										}
1033 									}
1034 								},
1035 								{
1036 									type : 'text',
1037 									id : 'txtLangCode',
1038 									label : editor.lang.common.langCode,
1039 									'default' : '',
1040 									setup : function( type, element )
1041 									{
1042 										if ( type == IMAGE )
1043 											this.setValue( element.getAttribute( 'lang' ) );
1044 									},
1045 									commit : function( type, element )
1046 									{
1047 										if ( type == IMAGE )
1048 										{
1049 											if ( this.getValue() || this.isChanged() )
1050 												element.setAttribute( 'lang', this.getValue() );
1051 										}
1052 									}
1053 								}
1054 							]
1055 						},
1056 						{
1057 							type : 'text',
1058 							id : 'txtGenLongDescr',
1059 							label : editor.lang.common.longDescr,
1060 							setup : function( type, element )
1061 							{
1062 								if ( type == IMAGE )
1063 									this.setValue( element.getAttribute( 'longDesc' ) );
1064 							},
1065 							commit : function( type, element )
1066 							{
1067 								if ( type == IMAGE )
1068 								{
1069 									if ( this.getValue() || this.isChanged() )
1070 										element.setAttribute( 'longDesc', this.getValue() );
1071 								}
1072 							}
1073 						},
1074 						{
1075 							type : 'hbox',
1076 							widths : [ '50%', '50%' ],
1077 							children :
1078 							[
1079 								{
1080 									type : 'text',
1081 									id : 'txtGenClass',
1082 									label : editor.lang.common.cssClass,
1083 									'default' : '',
1084 									setup : function( type, element )
1085 									{
1086 										if ( type == IMAGE )
1087 											this.setValue( element.getAttribute( 'class' ) );
1088 									},
1089 									commit : function( type, element )
1090 									{
1091 										if ( type == IMAGE )
1092 										{
1093 											if ( this.getValue() || this.isChanged() )
1094 												element.setAttribute( 'class', this.getValue() );
1095 										}
1096 									}
1097 								},
1098 								{
1099 									type : 'text',
1100 									id : 'txtGenTitle',
1101 									label : editor.lang.common.advisoryTitle,
1102 									'default' : '',
1103 									onChange : function()
1104 									{
1105 										updatePreview( this.getDialog() );
1106 									},
1107 									setup : function( type, element )
1108 									{
1109 										if ( type == IMAGE )
1110 											this.setValue( element.getAttribute( 'title' ) );
1111 									},
1112 									commit : function( type, element )
1113 									{
1114 										if ( type == IMAGE )
1115 										{
1116 											if ( this.getValue() || this.isChanged() )
1117 												element.setAttribute( 'title', this.getValue() );
1118 										}
1119 										else if ( type == PREVIEW )
1120 										{
1121 											element.setAttribute( 'title', this.getValue() );
1122 										}
1123 										else if ( type == CLEANUP )
1124 										{
1125 											element.removeAttribute( 'title' );
1126 										}
1127 									}
1128 								}
1129 							]
1130 						},
1131 						{
1132 							type : 'text',
1133 							id : 'txtdlgGenStyle',
1134 							label : editor.lang.common.cssStyle,
1135 							'default' : '',
1136 							setup : function( type, element )
1137 							{
1138 								if ( type == IMAGE )
1139 								{
1140 									var genStyle = element.getAttribute( 'style' );
1141 									if ( !genStyle && element.$.style.cssText )
1142 										genStyle = element.$.style.cssText;
1143 									this.setValue( genStyle );
1144
1145 									var height = element.$.style.height,
1146 										width = element.$.style.width,
1147 										aMatchH  = ( height ? height : '' ).match( regexGetSize ),
1148 										aMatchW  = ( width ? width : '').match( regexGetSize );
1149
1150 									this.attributesInStyle =
1151 									{
1152 										height : !!aMatchH,
1153 										width : !!aMatchW
1154 									};
1155 								}
1156 							},
1157 							commit : function( type, element )
1158 							{
1159 								if ( type == IMAGE && ( this.getValue() || this.isChanged() ) )
1160 								{
1161 									element.setAttribute( 'style', this.getValue() );
1162
1163 									// Set STYLE dimensions.
1164 									var height = element.getAttribute( 'height' ),
1165 										width = element.getAttribute( 'width' );
1166
1167 									if ( this.attributesInStyle && this.attributesInStyle.height )
1168 									{
1169 										if ( height )
1170 										{
1171 											if ( height.match( regexGetSize )[2] == '%' )			// % is allowed
1172 												element.setStyle( 'height', height + '%' );
1173 											else
1174 												element.setStyle( 'height', height + 'px' );
1175 										}
1176 										else
1177 											element.removeStyle( 'height' );
1178 									}
1179 									if ( this.attributesInStyle && this.attributesInStyle.width )
1180 									{
1181 										if ( width )
1182 										{
1183 											if ( width.match( regexGetSize )[2] == '%' )			// % is allowed
1184 												element.setStyle( 'width', width + '%' );
1185 											else
1186 												element.setStyle( 'width', width + 'px' );
1187 										}
1188 										else
1189 											element.removeStyle( 'width' );
1190 									}
1191 								}
1192 							}
1193 						}
1194 					]
1195 				}
1196 			]
1197 		};
1198 	};
1199
1200 	CKEDITOR.dialog.add( 'image', function( editor )
1201 		{
1202 			return imageDialog( editor, 'image' );
1203 		});
1204
1205 	CKEDITOR.dialog.add( 'imagebutton', function( editor )
1206 		{
1207 			return imageDialog( editor, 'imagebutton' );
1208 		});
1209 })();
1210