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 	/*
  9 	 * It is possible to set things in three different places.
 10 	 * 1. As attributes in the object tag.
 11 	 * 2. As param tags under the object tag.
 12 	 * 3. As attributes in the embed tag.
 13 	 * It is possible for a single attribute to be present in more than one place.
 14 	 * So let's define a mapping between a sementic attribute and its syntactic
 15 	 * equivalents.
 16 	 * Then we'll set and retrieve attribute values according to the mapping,
 17 	 * instead of having to check and set each syntactic attribute every time.
 18 	 *
 19 	 * Reference: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
 20 	 */
 21 	var ATTRTYPE_OBJECT = 1,
 22 		ATTRTYPE_PARAM = 2,
 23 		ATTRTYPE_EMBED = 4;
 24
 25 	var attributesMap =
 26 	{
 27 		id : [ { type : ATTRTYPE_OBJECT, name : CKEDITOR.env.ie ? '_cke_saved_id' : 'id' } ],
 28 		classid : [ { type : ATTRTYPE_OBJECT, name : 'classid' } ],
 29 		codebase : [ { type : ATTRTYPE_OBJECT, name : 'codebase'} ],
 30 		pluginspage : [ { type : ATTRTYPE_EMBED, name : 'pluginspage' } ],
 31 		src : [ { type : ATTRTYPE_PARAM, name : 'movie' }, { type : ATTRTYPE_EMBED, name : 'src' } ],
 32 		name : [ { type : ATTRTYPE_EMBED, name : 'name' } ],
 33 		align : [ { type : ATTRTYPE_OBJECT, name : 'align' } ],
 34 		title : [ { type : ATTRTYPE_OBJECT, name : 'title' }, { type : ATTRTYPE_EMBED, name : 'title' } ],
 35 		'class' : [ { type : ATTRTYPE_OBJECT, name : 'class' }, { type : ATTRTYPE_EMBED, name : 'class'} ],
 36 		width : [ { type : ATTRTYPE_OBJECT, name : 'width' }, { type : ATTRTYPE_EMBED, name : 'width' } ],
 37 		height : [ { type : ATTRTYPE_OBJECT, name : 'height' }, { type : ATTRTYPE_EMBED, name : 'height' } ],
 38 		hSpace : [ { type : ATTRTYPE_OBJECT, name : 'hSpace' }, { type : ATTRTYPE_EMBED, name : 'hSpace' } ],
 39 		vSpace : [ { type : ATTRTYPE_OBJECT, name : 'vSpace' }, { type : ATTRTYPE_EMBED, name : 'vSpace' } ],
 40 		style : [ { type : ATTRTYPE_OBJECT, name : 'style' }, { type : ATTRTYPE_EMBED, name : 'style' } ],
 41 		type : [ { type : ATTRTYPE_EMBED, name : 'type' } ]
 42 	};
 43
 44 	var names = [ 'play', 'loop', 'menu', 'quality', 'scale', 'salign', 'wmode', 'bgcolor', 'base', 'flashvars', 'allowScriptAccess',
 45 		'allowFullScreen' ];
 46 	for ( var i = 0 ; i < names.length ; i++ )
 47 		attributesMap[ names[i] ] = [ { type : ATTRTYPE_EMBED, name : names[i] }, { type : ATTRTYPE_PARAM, name : names[i] } ];
 48 	names = [ 'allowFullScreen', 'play', 'loop', 'menu' ];
 49 	for ( var i = 0 ; i < names.length ; i++ )
 50 		attributesMap[ names[i] ][0]['default'] = attributesMap[ names[i] ][1]['default'] = true;
 51
 52 	function loadValue( objectNode, embedNode, paramMap )
 53 	{
 54 		var attributes = attributesMap[ this.id ];
 55 		if ( !attributes )
 56 			return;
 57
 58 		var isCheckbox = ( this instanceof CKEDITOR.ui.dialog.checkbox );
 59 		for ( var i = 0 ; i < attributes.length ; i++ )
 60 		{
 61 			var attrDef = attributes[ i ];
 62 			switch ( attrDef.type )
 63 			{
 64 				case ATTRTYPE_OBJECT:
 65 					if ( !objectNode )
 66 						continue;
 67 					if ( objectNode.getAttribute( attrDef.name ) != null )
 68 					{
 69 						var value = objectNode.getAttribute( attrDef.name );
 70 						if ( isCheckbox )
 71 							this.setValue( value.toLowerCase() == 'true' );
 72 						else
 73 							this.setValue( value );
 74 						return;
 75 					}
 76 					else if ( isCheckbox )
 77 						this.setValue( !!attrDef[ 'default' ] );
 78 				case ATTRTYPE_PARAM:
 79 					if ( !objectNode )
 80 						continue;
 81 					if ( attrDef.name in paramMap )
 82 					{
 83 						var value = paramMap[ attrDef.name ];
 84 						if ( isCheckbox )
 85 							this.setValue( value.toLowerCase() == 'true' );
 86 						else
 87 							this.setValue( value );
 88 						return;
 89 					}
 90 					else if ( isCheckbox )
 91 						this.setValue( !!attrDef[ 'default' ] );
 92 				case ATTRTYPE_EMBED:
 93 					if ( !embedNode )
 94 						continue;
 95 					if ( embedNode.getAttribute( attrDef.name ) != null )
 96 					{
 97 						var value = embedNode.getAttribute( attrDef.name );
 98 						if ( isCheckbox )
 99 							this.setValue( value.toLowerCase() == 'true' );
100 						else
101 							this.setValue( value );
102 						return;
103 					}
104 					else if ( isCheckbox )
105 						this.setValue( !!attrDef[ 'default' ] );
106 				default:
107 			}
108 		}
109 	}
110
111 	function commitValue( objectNode, embedNode, paramMap )
112 	{
113 		var attributes = attributesMap[ this.id ];
114 		if ( !attributes )
115 			return;
116
117 		var isRemove = ( this.getValue() === '' ),
118 			isCheckbox = ( this instanceof CKEDITOR.ui.dialog.checkbox );
119
120 		for ( var i = 0 ; i < attributes.length ; i++ )
121 		{
122 			var attrDef = attributes[i];
123 			switch ( attrDef.type )
124 			{
125 				case ATTRTYPE_OBJECT:
126 					if ( !objectNode )
127 						continue;
128 					var value = this.getValue();
129 					if ( isRemove || isCheckbox && value === attrDef[ 'default' ] )
130 						objectNode.removeAttribute( attrDef.name );
131 					else
132 						objectNode.setAttribute( attrDef.name, value );
133 					break;
134 				case ATTRTYPE_PARAM:
135 					if ( !objectNode )
136 						continue;
137 					var value = this.getValue();
138 					if ( isRemove || isCheckbox && value === attrDef[ 'default' ] )
139 					{
140 						if ( attrDef.name in paramMap )
141 							paramMap[ attrDef.name ].remove();
142 					}
143 					else
144 					{
145 						if ( attrDef.name in paramMap )
146 							paramMap[ attrDef.name ].setAttribute( 'value', value );
147 						else
148 						{
149 							var param = CKEDITOR.dom.element.createFromHtml( '<cke:param></cke:param>', objectNode.getDocument() );
150 							param.setAttributes( { name : attrDef.name, value : value } );
151 							if ( objectNode.getChildCount() < 1 )
152 								param.appendTo( objectNode );
153 							else
154 								param.insertBefore( objectNode.getFirst() );
155 						}
156 					}
157 					break;
158 				case ATTRTYPE_EMBED:
159 					if ( !embedNode )
160 						continue;
161 					var value = this.getValue();
162 					if ( isRemove || isCheckbox && value === attrDef[ 'default' ])
163 						embedNode.removeAttribute( attrDef.name );
164 					else
165 						embedNode.setAttribute( attrDef.name, value );
166 				default:
167 			}
168 		}
169 	}
170
171 	CKEDITOR.dialog.add( 'flash', function( editor )
172 	{
173 		var makeObjectTag = !editor.config.flashEmbedTagOnly,
174 			makeEmbedTag = editor.config.flashAddEmbedTag || editor.config.flashEmbedTagOnly;
175
176 		var previewAreaHtml = '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.image.preview ) +'<br>' +
177 			'<div id="FlashPreviewLoader" style="display:none"><div class="loading"> </div></div>' +
178 			'<div id="FlashPreviewBox"></div></div>';
179
180 		return {
181 			title : editor.lang.flash.title,
182 			minWidth : 450,
183 			minHeight : 400,
184 			onLoad : function()
185 			{
186 				if ( editor.config.flashUploadTab == false )
187 					this.hidePage( 'Upload' );		// Hide Upload tab.
188
189 				if ( editor.config.flashBrowseServer == false )
190 					this.getContentElement( 'info', 'browse' ).getElement().hide();
191 			},
192 			onShow : function()
193 			{
194 				// Clear previously saved elements.
195 				this.fakeImage = this.objectNode = this.embedNode = null;
196
197 				// Try to detect any embed or object tag that has Flash parameters.
198 				var fakeImage = this.getSelectedElement();
199 				if ( fakeImage && fakeImage.getAttribute( '_cke_real_element_type' ) && fakeImage.getAttribute( '_cke_real_element_type' ) == 'flash' )
200 				{
201 					this.fakeImage = fakeImage;
202
203 					var realElement = editor.restoreRealElement( fakeImage ),
204 						objectNode = null, embedNode = null, paramMap = {};
205 					if ( realElement.getName() == 'cke:object' )
206 					{
207 						objectNode = realElement;
208 						var embedList = objectNode.getElementsByTag( 'embed', 'cke' );
209 						if ( embedList.count() > 0 )
210 							embedNode = embedList.getItem( 0 );
211 						var paramList = objectNode.getElementsByTag( 'param', 'cke' );
212 						for ( var i = 0, length = paramList.count() ; i < length ; i++ )
213 						{
214 							var item = paramList.getItem( i ),
215 								name = item.getAttribute( 'name' ),
216 								value = item.getAttribute( 'value' );
217 							paramMap[ name ] = value;
218 						}
219 					}
220 					else if ( realElement.getName() == 'cke:embed' )
221 						embedNode = realElement;
222
223 					this.objectNode = objectNode;
224 					this.embedNode = embedNode;
225
226 					this.setupContent( objectNode, embedNode, paramMap, fakeImage );
227 				}
228 			},
229 			onOk : function()
230 			{
231 				// If there's no selected object or embed, create one. Otherwise, reuse the
232 				// selected object and embed nodes.
233 				var objectNode = null,
234 					embedNode = null,
235 					paramMap = null;
236 				if ( !this.fakeImage )
237 				{
238 					if ( makeObjectTag )
239 					{
240 						objectNode = CKEDITOR.dom.element.createFromHtml( '<cke:object></cke:object>', editor.document );
241 						var attributes = {
242 							classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
243 							codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'
244 						};
245 						objectNode.setAttributes( attributes );
246 					}
247 					if ( makeEmbedTag )
248 					{
249 						embedNode = CKEDITOR.dom.element.createFromHtml( '<cke:embed></cke:embed>', editor.document );
250 						embedNode.setAttributes(
251 							{
252 								type : 'application/x-shockwave-flash',
253 								pluginspage : 'http://www.macromedia.com/go/getflashplayer'
254 							} );
255 						if ( objectNode )
256 							embedNode.appendTo( objectNode );
257 					}
258 				}
259 				else
260 				{
261 					objectNode = this.objectNode;
262 					embedNode = this.embedNode;
263 				}
264
265 				// Produce the paramMap if there's an object tag.
266 				if ( objectNode )
267 				{
268 					paramMap = {};
269 					var paramList = objectNode.getElementsByTag( 'param', 'cke' );
270 					for ( var i = 0, length = paramList.count() ; i < length ; i++ )
271 						paramMap[ paramList.getItem( i ).getAttribute( 'name' ) ] = paramList.getItem( i );
272 				}
273
274 				// Apply or remove flash parameters.
275 				var extraStyles = {};
276 				this.commitContent( objectNode, embedNode, paramMap, extraStyles );
277
278 				// Refresh the fake image.
279 				var newFakeImage = editor.createFakeElement( objectNode || embedNode, 'cke_flash', 'flash', true );
280 				newFakeImage.setStyles( extraStyles );
281 				if ( this.fakeImage )
282 					newFakeImage.replace( this.fakeImage );
283 				else
284 				{
285 					this.restoreSelection();
286 					editor.insertElement( newFakeImage );
287 				}
288 			},
289 			contents : [
290 				{
291 					id : 'info',
292 					label : editor.lang.common.generalTab,
293 					accessKey : 'I',
294 					elements :
295 					[
296 						{
297 							type : 'vbox',
298 							padding : 0,
299 							children :
300 							[
301 								{
302 									type : 'html',
303 									html : '<span>' + CKEDITOR.tools.htmlEncode( editor.lang.image.url ) + '</span>'
304 								},
305 								{
306 									type : 'hbox',
307 									widths : [ '280px', '110px' ],
308 									align : 'right',
309 									children :
310 									[
311 										{
312 											id : 'src',
313 											type : 'text',
314 											label : '',
315 											validate : CKEDITOR.dialog.validate.notEmpty( editor.lang.flash.validateSrc ),
316 											setup : loadValue,
317 											commit : commitValue,
318 											onLoad : function()
319 											{
320 												var dialog = this.getDialog();
321 												var previewElement = dialog.getContentElement( 'info', 'preview' ).getElement().getChild( 3 );
322 												this.getInputElement().on( 'change', function()
323 													{
324 														previewElement.setHtml( '<embed height="100%" width="100%" src="'
325 																+ CKEDITOR.tools.htmlEncode( this.getValue() )
326 																+ '" type="application/x-shockwave-flash"></embed>' );
327 													} );
328 											}
329 										},
330 										{
331 											type : 'button',
332 											id : 'browse',
333 											align : 'center',
334 											label : editor.lang.common.browseServer
335 										}
336 									]
337 								}
338 							]
339 						},
340 						{
341 							type : 'hbox',
342 							widths : [ '25%', '25%', '25%', '25%', '25%' ],
343 							children :
344 							[
345 								{
346 									type : 'text',
347 									id : 'width',
348 									label : editor.lang.flash.width,
349 									validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateWidth ),
350 									setup : function( objectNode, embedNode, paramMap, fakeImage )
351 									{
352 										loadValue.apply( this, arguments );
353 										if ( fakeImage )
354 										{
355 											var fakeImageWidth = parseInt( fakeImage.$.style.width, 10 );
356 											if ( !isNaN( fakeImageWidth ) )
357 												this.setValue( fakeImageWidth );
358 										}
359 									},
360 									commit : function( objectNode, embedNode, paramMap, extraStyles )
361 									{
362 										commitValue.apply( this, arguments );
363 										if ( this.getValue() != '' )
364 											extraStyles.width = this.getValue() + 'px';
365 									}
366 								},
367 								{
368 									type : 'text',
369 									id : 'height',
370 									label : editor.lang.flash.height,
371 									validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateHeight ),
372 									setup : function( objectNode, embedNode, paramMap, fakeImage )
373 									{
374 										loadValue.apply( this, arguments );
375 										if ( fakeImage )
376 										{
377 											var fakeImageHeight = parseInt( fakeImage.$.style.height, 10 );
378 											if ( !isNaN( fakeImageHeight ) )
379 												this.setValue( fakeImageHeight );
380 										}
381 									},
382 									commit : function( objectNode, embedNode, paramMap, extraStyles )
383 									{
384 										commitValue.apply( this, arguments );
385 										if ( this.getValue() != '' )
386 											extraStyles.height = this.getValue() + 'px';
387 									}
388 								},
389 								{
390 									type : 'text',
391 									id : 'hSpace',
392 									label : editor.lang.flash.hSpace,
393 									validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateHSpace ),
394 									setup : loadValue,
395 									commit : commitValue
396 								},
397 								{
398 									type : 'text',
399 									id : 'vSpace',
400 									label : editor.lang.flash.vSpace,
401 									validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateVSpace ),
402 									setup : loadValue,
403 									commit : commitValue
404 								}
405 							]
406 						},
407
408 						{
409 							type : 'vbox',
410 							children :
411 							[
412 								{
413 									type : 'html',
414 									id : 'preview',
415 									style : 'width:95%;',
416 									html : previewAreaHtml
417 								}
418 							]
419 						}
420 					]
421 				},
422 				{
423 					id : 'Upload',
424 					label : editor.lang.common.upload,
425 					elements :
426 					[
427 						{
428 							type : 'file',
429 							id : 'upload',
430 							label : editor.lang.common.upload,
431 							action : editor.config.image_uploadAction,
432 							size : 38
433 						},
434 						{
435 							type : 'fileButton',
436 							id : 'uploadButton',
437 							label : editor.lang.common.uploadSubmit,
438 							'for' : [ 'Upload', 'upload' ]
439 						}
440 					]
441 				},
442 				{
443 					id : 'properties',
444 					label : editor.lang.flash.propertiesTab,
445 					elements :
446 					[
447 						{
448 							type : 'hbox',
449 							widths : [ '50%', '50%' ],
450 							children :
451 							[
452 								{
453 									id : 'scale',
454 									type : 'select',
455 									label : editor.lang.flash.scale,
456 									'default' : '',
457 									style : 'width : 100%;',
458 									items :
459 									[
460 										[ editor.lang.common.notSet , ''],
461 										[ editor.lang.flash.scaleAll, 'showall' ],
462 										[ editor.lang.flash.scaleNoBorder, 'noborder' ],
463 										[ editor.lang.flash.scaleFit, 'exactfit' ]
464 									],
465 									setup : loadValue,
466 									commit : commitValue
467 								},
468 								{
469 									id : 'allowScriptAccess',
470 									type : 'select',
471 									label : editor.lang.flash.access,
472 									'default' : '',
473 									style : 'width : 100%;',
474 									items :
475 									[
476 										[ editor.lang.common.notSet , ''],
477 										[ editor.lang.flash.accessAlways, 'always' ],
478 										[ editor.lang.flash.accessSameDomain, 'samedomain' ],
479 										[ editor.lang.flash.accessNever, 'never' ]
480 									],
481 									setup : loadValue,
482 									commit : commitValue
483 								}
484 							]
485 						},
486 						{
487 							type : 'hbox',
488 							widths : [ '50%', '50%' ],
489 							children :
490 							[
491 								{
492 									id : 'wmode',
493 									type : 'select',
494 									label : editor.lang.flash.windowMode,
495 									'default' : '',
496 									style : 'width : 100%;',
497 									items :
498 									[
499 										[ editor.lang.common.notSet , ''],
500 										[ 'window' ],
501 										[ 'opaque' ],
502 										[ 'transparent' ]
503 									],
504 									setup : loadValue,
505 									commit : commitValue
506 								},
507 								{
508 									id : 'quality',
509 									type : 'select',
510 									label : editor.lang.flash.quality,
511 									'default' : 'high',
512 									style : 'width : 100%;',
513 									items :
514 									[
515 										[ editor.lang.common.notSet , ''],
516 										[ 'best' ],
517 										[ 'high' ],
518 										[ 'autohigh' ],
519 										[ 'medium' ],
520 										[ 'autolow' ],
521 										[ 'low' ]
522 									],
523 									setup : loadValue,
524 									commit : commitValue
525 								},
526 							]
527 						},
528 						{
529 							type : 'hbox',
530 							widths : [ '50%', '50%' ],
531 							children :
532 							[
533 								{
534 									id : 'align',
535 									type : 'select',
536 									label : editor.lang.flash.align,
537 									'default' : '',
538 									style : 'width : 100%;',
539 									items :
540 									[
541 										[ editor.lang.common.notSet , ''],
542 										[ editor.lang.image.alignLeft , 'left'],
543 										[ editor.lang.image.alignAbsBottom , 'absBottom'],
544 										[ editor.lang.image.alignAbsMiddle , 'absMiddle'],
545 										[ editor.lang.image.alignBaseline , 'baseline'],
546 										[ editor.lang.image.alignBottom , 'bottom'],
547 										[ editor.lang.image.alignMiddle , 'middle'],
548 										[ editor.lang.image.alignRight , 'right'],
549 										[ editor.lang.image.alignTextTop , 'textTop'],
550 										[ editor.lang.image.alignTop , 'top']
551 									],
552 									setup : loadValue,
553 									commit : commitValue
554 								},
555 								{
556 									type : 'html',
557 									html : '<div></div>'
558 								}
559 							]
560 						},
561 						{
562 							type : 'vbox',
563 							padding : 0,
564 							children :
565 							[
566 								{
567 									type : 'html',
568 									html : CKEDITOR.tools.htmlEncode( editor.lang.flash.flashvars )
569 								},
570 								{
571 									type : 'checkbox',
572 									id : 'menu',
573 									label : editor.lang.flash.chkMenu,
574 									'default' : true,
575 									setup : loadValue,
576 									commit : commitValue
577 								},
578 								{
579 									type : 'checkbox',
580 									id : 'play',
581 									label : editor.lang.flash.chkPlay,
582 									'default' : true,
583 									setup : loadValue,
584 									commit : commitValue
585 								},
586 								{
587 									type : 'checkbox',
588 									id : 'loop',
589 									label : editor.lang.flash.chkLoop,
590 									'default' : true,
591 									setup : loadValue,
592 									commit : commitValue
593 								},
594 								{
595 									type : 'checkbox',
596 									id : 'allowFullScreen',
597 									label : editor.lang.flash.chkFull,
598 									'default' : true,
599 									setup : loadValue,
600 									commit : commitValue
601 								}
602 							]
603 						}
604 					]
605 				},
606 				{
607 					id : 'advanced',
608 					label : editor.lang.common.advancedTab,
609 					elements :
610 					[
611 						{
612 							type : 'hbox',
613 							widths : [ '45%', '55%' ],
614 							children :
615 							[
616 								{
617 									type : 'text',
618 									id : 'id',
619 									label : editor.lang.common.id,
620 									setup : loadValue,
621 									commit : commitValue
622 								},
623 								{
624 									type : 'text',
625 									id : 'title',
626 									label : editor.lang.common.advisoryTitle,
627 									setup : loadValue,
628 									commit : commitValue
629 								}
630 							]
631 						},
632 						{
633 							type : 'hbox',
634 							widths : [ '45%', '55%' ],
635 							children :
636 							[
637 								{
638 									type : 'text',
639 									id : 'bgcolor',
640 									label : editor.lang.flash.bgcolor,
641 									setup : loadValue,
642 									commit : commitValue
643 								},
644 								{
645 									type : 'text',
646 									id : 'class',
647 									label : editor.lang.common.cssClass,
648 									setup : loadValue,
649 									commit : commitValue
650 								}
651 							]
652 						},
653 						{
654 							type : 'text',
655 							id : 'style',
656 							label : editor.lang.common.cssStyle,
657 							setup : loadValue,
658 							commit : commitValue
659 						}
660 					]
661 				}
662 			]
663 		};
664 	} );
665 })();
666