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