Project

General

Profile

1
/*
2
 *
3
 * File Name: fckplugin.js
4
 * 	Plugin to add flash files using SwfObject 2
5
 *
6
 * File Authors:
7
 * 		Alfonso Martínez de Lizarrondo
8
 *
9
 * Developed for InControlSolutions
10
 *
11
 * Version: 1.5
12
 */
13

    
14

    
15
/**
16
	FCKCommentsProcessor
17
	---------------------------
18
	It's run after a document has been loaded, it detects all the protected source elements
19

    
20
	In order to use it, you add your comment parser with
21
	FCKCommentsProcessor.AddParser( function )
22
*/
23
if (typeof FCKCommentsProcessor === 'undefined')
24
{
25
	var FCKCommentsProcessor = FCKDocumentProcessor.AppendNew() ;
26
	FCKCommentsProcessor.ProcessDocument = function( oDoc )
27
	{
28
		if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
29
			return ;
30

    
31
		if ( !oDoc )
32
			return ;
33

    
34
	//Find all the comments: <!--{PS..0}-->
35
	//try to choose the best approach according to the browser:
36
		if ( oDoc.evaluate )
37
			this.findCommentsXPath( oDoc );
38
		else
39
		{
40
			if (oDoc.all)
41
				this.findCommentsIE( oDoc.body ) ;
42
			else
43
				this.findComments( oDoc.body ) ;
44
		}
45

    
46
	}
47

    
48
	FCKCommentsProcessor.findCommentsXPath = function(oDoc) {
49
		var nodesSnapshot = oDoc.evaluate('//body//comment()', oDoc.body, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null );
50

    
51
		for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ )
52
		{
53
			this.parseComment( nodesSnapshot.snapshotItem(i) ) ;
54
		}
55
	}
56

    
57
	FCKCommentsProcessor.findCommentsIE = function(oNode) {
58
		var aComments = oNode.getElementsByTagName( '!' );
59
		for(var i=aComments.length-1; i >=0 ; i--)
60
		{
61
			var comment = aComments[i] ;
62
			if (comment.nodeType == 8 ) // oNode.COMMENT_NODE)
63
				this.parseComment( comment ) ;
64
		}
65
	}
66

    
67
	// Fallback function, iterate all the nodes and its children searching for comments.
68
	FCKCommentsProcessor.findComments = function( oNode )
69
	{
70
		if (oNode.nodeType == 8 ) // oNode.COMMENT_NODE)
71
		{
72
			this.parseComment( oNode ) ;
73
		}
74
		else
75
		{
76
			if (oNode.hasChildNodes())
77
			{
78
				var children = oNode.childNodes ;
79
				for (var i = children.length-1; i >=0 ; i--)
80
					this.findComments( children[ i ] );
81
			}
82
		}
83
	}
84

    
85
	// We get a comment node
86
	// Check that it's one that we are interested on:
87
	FCKCommentsProcessor.parseComment = function( oNode )
88
	{
89
		var value = oNode.nodeValue ;
90

    
91
		// Difference between 2.4.3 and 2.5
92
		var prefix = ( FCKConfig.ProtectedSource._CodeTag || 'PS\\.\\.' ) ;
93

    
94
		var regex = new RegExp( "\\{" + prefix + "(\\d+)\\}", "g" ) ;
95

    
96
		if ( regex.test( value ) )
97
		{
98
			var index = RegExp.$1 ;
99
			var content = FCKTempBin.Elements[ index ] ;
100

    
101
			// Now call the registered parser handlers.
102
			var oCalls = this.ParserHandlers ;
103
			if ( oCalls )
104
			{
105
				for ( var i = 0 ; i < oCalls.length ; i++ )
106
					oCalls[ i ]( oNode, content, index ) ;
107

    
108
			}
109

    
110
		}
111
	}
112

    
113
	/**
114
		The users of the object will add a parser here, the callback function gets two parameters:
115
			oNode: it's the node in the editorDocument that holds the position of our content
116
			oContent: it's the node (removed from the document) that holds the original contents
117
			index: the reference in the FCKTempBin of our content
118
	*/
119
	FCKCommentsProcessor.AddParser = function( handlerFunction )
120
	{
121
		if ( !this.ParserHandlers )
122
			this.ParserHandlers = [ handlerFunction ] ;
123
		else
124
		{
125
			// Check that the event handler isn't already registered with the same listener
126
			// It doesn't detect function pointers belonging to an object (at least in Gecko)
127
			if ( this.ParserHandlers.IndexOf( handlerFunction ) == -1 )
128
				this.ParserHandlers.push( handlerFunction ) ;
129
		}
130
	}
131
}
132
/**
133
	END of FCKCommentsProcessor
134
	---------------------------
135
*/
136

    
137
/**
138
  @desc  inject the function
139
  @author  Aimingoo&Riceball
140
*/
141
function Inject( aOrgFunc, aBeforeExec, aAtferExec ) {
142
  return function() {
143
    if (typeof(aBeforeExec) == 'function') arguments = aBeforeExec.apply(this, arguments) || arguments;
144
    //convert arguments object to array
145
    var Result, args = [].slice.call(arguments);
146
    args.push(aOrgFunc.apply(this, args));
147
    if (typeof(aAtferExec) == 'function') Result = aAtferExec.apply(this, args);
148
    return (typeof(Result) != 'undefined')?Result:args.pop();
149
  } ;
150
}
151

    
152
// If it hasn't been set, then use a version hosted by Google.
153
if (typeof FCKConfig.swfObjectPath === 'undefined')
154
	FCKConfig.swfObjectPath = "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js" ;
155

    
156

    
157
// Replace the default flash dialog:
158
FCKCommands.LoadedCommands[ 'Flash' ] = new FCKDialogCommand( 'Flash', FCKLang.DlgFlashTitle, FCKPlugins.Items['swfobject'].Path + 'dialog/fck_flash.html', 450, 390 ) ;
159

    
160
// Check if the comment it's one of our scripts:
161
FCKCommentsProcessor.AddParser(  function( oNode, oContent, index)
162
{
163
		if ( FCK.SwfobjectHandler.detectScript( oContent ) )
164
		{
165
			var oSWF = FCK.SwfobjectHandler.createNew() ;
166
			oSWF.parse( oContent ) ;
167
			oSWF.createHtmlElement( oNode, index ) ;
168
		}
169
		else
170
		{
171
			if ( FCK.SwfobjectHandler.detectSwfObjectScript( oContent ) )
172
				oNode.parentNode.removeChild( oNode );
173
		}
174
} );
175

    
176
// Context menu
177
FCK.ContextMenu.RegisterListener( {
178
	AddItems : function( menu, tag, tagName )
179
	{
180
		// under what circumstances do we display this option
181
		if ( tagName == 'IMG' && tag.getAttribute( 'swfobjectnumber' ) )
182
		{
183
//			menu.AddSeparator() ;
184
			// No other options:
185
			menu.RemoveAllItems() ;
186
			// the command needs the registered command name, the title for the context menu, and the icon path
187
			menu.AddItem( 'Flash', FCKLang.FlashProperties, 38 ) ;
188
		}
189
	}}
190
);
191

    
192
// Double click
193
FCK.RegisterDoubleClickHandler( function( oNode )
194
{
195
	if ( !oNode.getAttribute( 'swfobjectnumber' ))
196
		return ;
197

    
198
	FCK.Commands.GetCommand( 'Flash' ).Execute() ;
199
}, 'IMG' ) ;
200

    
201

    
202
// Object that handles the common functions about all the players
203
FCK.SwfobjectHandler = {
204
	// Object to store a reference to each player
205
	Items: {},
206

    
207
	getItem: function(id){
208
		return this.Items[id];
209
	},
210

    
211
	// Verify that the node is a script generated by this plugin.
212
	detectScript: function( script )
213
	{
214
		// We only know about version 1:
215
		if ( !(/FCK swfobject v1\.(\d+)/.test(script)) )
216
			return false;
217

    
218
		return true ;
219
	},
220

    
221
	// Detects both the google script as well as our ending block
222
	// both must be removed and then added later only if neccesary
223
	detectSwfObjectScript: function( script )
224
	{
225
		return (/<script.*>\/\/swfobject plugin<\/script>/.test(script) ) ;
226
	},
227

    
228
	SwfObjectScript : function()
229
	{
230
		return (FCKConfig.swfObjectPath === '' ? '' : '\r\n<script src="' + FCKConfig.swfObjectPath + '" type="text/javascript">//swfobject plugin<\/script>'	) ;
231
	}() ,
232

    
233
	// This can be called from the dialog
234
	createNew: function()
235
	{
236
		var item = new swfobject() ;
237
		this.Items[ item.number ] = item;
238
		return item;
239
	},
240

    
241
	// We will use this to track the number of maps that are generated
242
	// This way we know if we must add the Google Script or not.
243
	// We store their names so they are called properly from BuildEndingScript
244
	CreatedItemsNames : [],
245

    
246
	// Function that will be injected into the normal core
247
	GetXHTMLAfter: function( node, includeNode, format, Result )
248
	{
249
/*
250
		if (FCK.SwfobjectHandler.CreatedItemsNames.length > 0)
251
		{
252
			Result += FCK.SwfobjectHandler.BuildEndingScript() ;
253
		}
254
*/
255
		// Reset the counter each time the GetXHTML function is called
256
		FCK.SwfobjectHandler.CreatedItemsNames = [];
257

    
258
		return Result ;
259
	},
260

    
261
	// Store any previous processor so nothing breaks
262
	previousProcessor: FCKXHtml.TagProcessors[ 'img' ]
263
}
264

    
265

    
266

    
267

    
268

    
269
// Our object that will handle parsing of the script and creating the new one.
270
var swfobject = function()
271
{
272
	var now = new Date() ;
273
	this.number = '' + now.getFullYear() + now.getMonth() + now.getDate() + now.getHours() + now.getMinutes() + now.getSeconds() ;
274

    
275
	this.file = '';
276
	this.width = FCKConfig.swfobject_Width || '';
277
	this.height = FCKConfig.swfobject_Height || '';
278
	this.version = FCKConfig.swfObject_FlashVersion || '7.0.0' ;
279
	this.expressInstall = FCKConfig.swfObject_ExpressInstall || false ;
280
	if (this.expressInstall) this.expressInstall = '"' + this.expressInstall + '"' ;
281

    
282
	this.flashvars = {};
283
	this.params = {scale:'',play:true,menu:true,loop:true,allowfullscreen:false,wmode:'',allowscriptaccess:''};
284
	this.attributes = {id:'',"class":'',style:'',title:''};
285

    
286
	this.WrapperClass = FCKConfig.swfobject_WrapperClass || '' ;
287
}
288

    
289

    
290
swfobject.prototype.createHtmlElement = function( oReplacedNode, index)
291
{
292
	var oFakeNode = FCK.EditorDocument.createElement( 'IMG' ) ;
293

    
294
	// Are we creating a new map?
295
	if ( !oReplacedNode )
296
	{
297
    index = FCKTempBin.AddElement( this.BuildScript() ) ;
298
		var prefix = ( FCKConfig.ProtectedSource._CodeTag || 'PS..' ) ;
299
		oReplacedNode = FCK.EditorDocument.createComment( '{' + prefix + index + '}' ) ;
300
		FCK.InsertElement(oReplacedNode);
301
	}
302
//	oFakeNode.contentEditable = false ;
303
//	oFakeNode.setAttribute( '_fckfakelement', 'true', 0 ) ;
304

    
305
	oFakeNode.setAttribute( '_fckrealelement', FCKTempBin.AddElement( oReplacedNode ), 0 ) ;
306
	oFakeNode.setAttribute( '_fckBinNode', index, 0 ) ;
307

    
308
	oFakeNode.src = FCKConfig.FullBasePath + 'images/spacer.gif' ;
309
	oFakeNode.style.display = 'block' ;
310
	oFakeNode.style.border = '1px solid black' ;
311
	oFakeNode.style.background = 'white center center url("' + FCKPlugins.Items['swfobject'].Path + 'images/preview.png' + '") no-repeat' ;
312

    
313
	oFakeNode.setAttribute("SwfObjectNumber", this.number, 0) ;
314

    
315
	oReplacedNode.parentNode.insertBefore( oFakeNode, oReplacedNode ) ;
316
	oReplacedNode.parentNode.removeChild( oReplacedNode ) ;
317

    
318
	// dimensions
319
	this.updateHTMLElement( oFakeNode );
320

    
321
	return oFakeNode ;
322
}
323

    
324
swfobject.prototype.updateScript = function( oFakeNode )
325
{
326
	this.updateDimensions( oFakeNode ) ;
327

    
328
	var index = oFakeNode.getAttribute( '_fckBinNode' );
329
	FCKTempBin.Elements[ index ] =  this.BuildScript() ;
330
}
331

    
332
swfobject.prototype.updateHTMLElement = function( oFakeNode )
333
{
334
	oFakeNode.width = this.width ;
335
	oFakeNode.height = this.height ;
336

    
337
	// The wrapper class is applied to the IMG not to a wrapping DIV !!!
338
	if ( this.WrapperClass !== '')
339
		oFakeNode.className = this.WrapperClass ;
340
}
341

    
342
// Read the dimensions back from the fake node (the user might have manually resized it)
343
swfobject.prototype.updateDimensions = function( oFakeNode )
344
{
345
	var iWidth, iHeight ;
346
	var regexSize = /^\s*(\d+)px\s*$/i ;
347

    
348
	if ( oFakeNode.style.width )
349
	{
350
		var aMatchW  = oFakeNode.style.width.match( regexSize ) ;
351
		if ( aMatchW )
352
		{
353
			iWidth = aMatchW[1] ;
354
			oFakeNode.style.width = '' ;
355
			oFakeNode.width = iWidth ;
356
		}
357
	}
358

    
359
	if ( oFakeNode.style.height )
360
	{
361
		var aMatchH  = oFakeNode.style.height.match( regexSize ) ;
362
		if ( aMatchH )
363
		{
364
			iHeight = aMatchH[1] ;
365
			oFakeNode.style.height = '' ;
366
			oFakeNode.height = iHeight ;
367
		}
368
	}
369

    
370
	this.width	= iWidth ? iWidth : oFakeNode.width ;
371
	this.height	= iHeight ? iHeight : oFakeNode.height ;
372
}
373

    
374
swfobject.prototype.parse = function( script )
375
{
376
	function parseValue(value)
377
	{
378
		if (value==="true")
379
			return true;
380
		if (value==="false")
381
			return false;
382
		return value ;
383
	}
384

    
385
	// We only know about version 1:
386
	if ( !(/FCK swfobject v1\.(\d+)/.test(script)) )
387
		return false;
388

    
389
	var version = parseInt(RegExp.$1, 10) ;
390

    
391
	// dimensions:
392
	var regexpDimensions = /<div id="flash(\d+)" style="width\:\s*(\d+)px; height\:\s*(\d+)px;">/ ;
393
	if (regexpDimensions.test( script ) )
394
	{
395
		delete FCK.SwfobjectHandler.Items[this.number] ;
396
		this.number = RegExp.$1 ;
397
		FCK.SwfobjectHandler.Items[this.number] = this ;
398

    
399
		this.width = RegExp.$2 ;
400
		this.height = RegExp.$3 ;
401
	}
402

    
403
	var regexpWrapper = /<div class=("|')(.*)\1.*\/\/wrapper/ ;
404
	if (regexpWrapper.test( script ) )
405
		this.WrapperClass = RegExp.$2 ;
406
	else
407
		this.WrapperClass = '' ;
408

    
409
// swfobject.embedSWF("/userfiles/flash/gridlock.swf", "flash200881416419", 300, 100, "7.0.0", "", flashvars, params, attributes);
410
	var regexpFile = /swfobject\.embedSWF\("(.*?)",/ ;
411
	if (regexpFile.test( script ) )
412
		this.file = RegExp.$1 ;
413

    
414
	// parse automatically all the variables.
415
	var regexpParams = /params\["(.*)"\]="(.*)"/g ;
416
	var regexpAttributes = /attributes\["(.*)"\]="(.*)"/g ;
417
	var regexpFlashvars = /flashvars\["(.*)"\]="(.*)"/g ;
418
	if (version<3)
419
	{
420
		regexpParams = /params.(.*)="(.*)"/g ;
421
		regexpAttributes = /attributes.(.*)="(.*)"/g ;
422
		regexpFlashvars = /flashvars.(.*)="(.*)"/g ;
423
	}
424

    
425
	while( (result = regexpParams.exec(script)) )
426
	{
427
		this.params[result[1]] = parseValue(result[2]) ;
428
	}
429

    
430
	while( (result = regexpAttributes.exec(script)) )
431
	{
432
		this.attributes[result[1]] = parseValue(result[2]) ;
433
	}
434

    
435
	while( (result = regexpFlashvars.exec(script)) )
436
	{
437
		this.flashvars[result[1]] = parseValue(result[2]) ;
438
	}
439

    
440
	return true;
441
}
442

    
443
swfobject.prototype.BuildScript = function()
444
{
445
	var versionMarker = '/* FCK swfobject v1.5 */' ;
446

    
447
	var v, aScript = [] ;
448
	aScript.push('\r\n<script type="text/javascript">') ;
449
	aScript.push('/*<![CDATA[*/');
450
	aScript.push( versionMarker ) ;
451

    
452
	if ( this.WrapperClass !== '')
453
		aScript.push('document.write(\'<div class="' + this.WrapperClass + '">\'); //wrapper');
454

    
455
	aScript.push('document.write(\'<div id="flash' + this.number + '" style="width:' + this.width + 'px; height:' + this.height + 'px;"><a href="http://www.macromedia.com/go/getflashplayer">Get the Flash Player<\\\/a> to see this player.<\\\/div>\');');
456

    
457
	if ( this.WrapperClass !== '')
458
		aScript.push('document.write(\'<\\\/div>\'); ');
459

    
460

    
461
	aScript.push('var params={};');
462
	aScript.push('var attributes={};');
463
	aScript.push('var flashvars = {};');
464

    
465
	for(v in this.params)
466
	{
467
		if (this.params[v]!=='')
468
			aScript.push('	params["' + v + '"]="' + this.params[v] + '";');
469
	}
470

    
471
	for(v in this.attributes)
472
	{
473
		if (this.attributes[v]!=='')
474
			aScript.push('	attributes["' + v + '"]="' + this.attributes[v] + '";');
475
	}
476

    
477
	for(v in this.flashvars)
478
	{
479
		if (this.flashvars[v]!=='')
480
			aScript.push('	flashvars["' + v + '"]="' + this.flashvars[v] + '";');
481
	}
482

    
483
	aScript.push('swfobject.embedSWF("' + this.file + '", "flash' + this.number + '", ' + this.width + ', ' + this.height + ', "' + this.version + '", ' + this.expressInstall + ', flashvars, params, attributes);') ;
484

    
485
	aScript.push('/*]]>*/');
486
	aScript.push('</script>');
487

    
488
	return aScript.join('\r\n');
489
}
490

    
491

    
492

    
493

    
494
// Modifications of the core routines of FCKeditor:
495

    
496
FCKXHtml.GetXHTML = Inject(FCKXHtml.GetXHTML, null, FCK.SwfobjectHandler.GetXHTMLAfter ) ;
497

    
498
FCKXHtml.TagProcessors.img = function( node, htmlNode, xmlNode )
499
{
500
	if ( htmlNode.getAttribute( 'SwfObjectNumber' ) )
501
	{
502
		var oMap = FCK.SwfobjectHandler.getItem( htmlNode.getAttribute( 'SwfObjectNumber' ) ) ;
503
		FCK.SwfobjectHandler.CreatedItemsNames.push( oMap.number ) ;
504

    
505
		oMap.updateScript( htmlNode );
506
		node = FCK.GetRealElement( htmlNode ) ;
507
		if ( FCK.SwfobjectHandler.CreatedItemsNames.length == 1 )
508
		{
509
			// If it is the first map, insert the google maps script
510
			var index = FCKTempBin.AddElement( FCK.SwfobjectHandler.SwfObjectScript ) ;
511
			var prefix = ( FCKConfig.ProtectedSource._CodeTag || 'PS..' ) ;
512
			oScriptCommentNode = xmlNode.ownerDocument.createComment( '{' + prefix + index + '}' ) ;
513
			xmlNode.appendChild( oScriptCommentNode ) ;
514
		}
515

    
516
		return xmlNode.ownerDocument.createComment( node.nodeValue ) ;
517
	}
518

    
519
	if (typeof FCK.SwfobjectHandler.previousProcessor == 'function')
520
		node = FCK.SwfobjectHandler.previousProcessor( node, htmlNode, xmlNode ) ;
521
	else
522
		node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
523

    
524
	return node ;
525
};
526

    
527

    
528
// Returns an array with the available classes defined in the Styles
529
function GetAvailableClasses( nodeName )
530
{
531
	var styles = FCK.Styles.GetStyles() ;
532
	var aClasses = [{name:'', classname:''}];
533

    
534
	for ( var styleName in styles )
535
	{
536
		var style = styles[styleName] ;
537
		if (style.IsCore)
538
			continue;
539

    
540
		if (style.Element == nodeName)
541
		{
542
			if (style._StyleDesc.Attributes && style._StyleDesc.Attributes['class'] )
543
				aClasses.push( {name:styleName, classname:style._StyleDesc.Attributes['class']} ) ;
544
		}
545
	}
546

    
547
	return aClasses ;
548
}
(1-1/3)