~ubuntu-it-wiki/wiki-ubuntu-it/wiki-repo

149 by Leo Iannacone
Added applets for gui editor
1
/*
2
 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
3
 * Copyright (C) 2003-2010 Frederico Caldeira Knabben
4
 *
5
 * == BEGIN LICENSE ==
6
 *
7
 * Licensed under the terms of any of the following licenses at your
8
 * choice:
9
 *
10
 *  - GNU General Public License Version 2 or later (the "GPL")
11
 *    http://www.gnu.org/licenses/gpl.html
12
 *
13
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
14
 *    http://www.gnu.org/licenses/lgpl.html
15
 *
16
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
17
 *    http://www.mozilla.org/MPL/MPL-1.1.html
18
 *
19
 * == END LICENSE ==
20
 *
21
 * FCKEditingArea Class: renders an editable area.
22
 */
23
24
/**
25
 * @constructor
26
 * @param {String} targetElement The element that will hold the editing area. Any child element present in the target will be deleted.
27
 */
28
var FCKEditingArea = function( targetElement )
29
{
30
	this.TargetElement = targetElement ;
31
	this.Mode = FCK_EDITMODE_WYSIWYG ;
32
33
	if ( FCK.IECleanup )
34
		FCK.IECleanup.AddItem( this, FCKEditingArea_Cleanup ) ;
35
}
36
37
38
/**
39
 * @param {String} html The complete HTML for the page, including DOCTYPE and the <html> tag.
40
 */
41
FCKEditingArea.prototype.Start = function( html, secondCall )
42
{
43
	var eTargetElement	= this.TargetElement ;
44
	var oTargetDocument	= FCKTools.GetElementDocument( eTargetElement ) ;
45
46
	// Remove all child nodes from the target.
47
	while( eTargetElement.firstChild )
48
		eTargetElement.removeChild( eTargetElement.firstChild ) ;
49
50
	if ( this.Mode == FCK_EDITMODE_WYSIWYG )
51
	{
52
		// For FF, document.domain must be set only when different, otherwhise
53
		// we'll strangely have "Permission denied" issues.
54
		if ( FCK_IS_CUSTOM_DOMAIN )
55
			html = '<script>document.domain="' + FCK_RUNTIME_DOMAIN + '";</script>' + html ;
56
57
		// IE has a bug with the <base> tag... it must have a </base> closer,
58
		// otherwise the all successive tags will be set as children nodes of the <base>.
59
		if ( FCKBrowserInfo.IsIE )
60
			html = html.replace( /(<base[^>]*?)\s*\/?>(?!\s*<\/base>)/gi, '$1></base>' ) ;
61
		else if ( !secondCall )
62
		{
63
			// Gecko moves some tags out of the body to the head, so we must use
64
			// innerHTML to set the body contents (SF BUG 1526154).
65
66
			// Extract the BODY contents from the html.
67
			var oMatchBefore = html.match( FCKRegexLib.BeforeBody ) ;
68
			var oMatchAfter = html.match( FCKRegexLib.AfterBody ) ;
69
70
			if ( oMatchBefore && oMatchAfter )
71
			{
72
				var sBody = html.substr( oMatchBefore[1].length,
73
					       html.length - oMatchBefore[1].length - oMatchAfter[1].length ) ;	// This is the BODY tag contents.
74
75
				html =
76
					oMatchBefore[1] +			// This is the HTML until the <body...> tag, inclusive.
77
					'&nbsp;' +
78
					oMatchAfter[1] ;			// This is the HTML from the </body> tag, inclusive.
79
80
				// If nothing in the body, place a BOGUS tag so the cursor will appear.
81
				if ( FCKBrowserInfo.IsGecko && ( sBody.length == 0 || FCKRegexLib.EmptyParagraph.test( sBody ) ) )
82
					sBody = '<br type="_moz">' ;
83
84
				this._BodyHTML = sBody ;
85
86
			}
87
			else
88
				this._BodyHTML = html ;			// Invalid HTML input.
89
		}
90
91
		// Create the editing area IFRAME.
92
		var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ;
93
94
		// IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
95
		// See #1055.
96
		var sOverrideError = '<script type="text/javascript" _fcktemp="true">window.onerror=function(){return true;};</script>' ;
97
98
		oIFrame.frameBorder = 0 ;
99
		oIFrame.style.width = oIFrame.style.height = '100%' ;
100
101
		if ( FCK_IS_CUSTOM_DOMAIN && FCKBrowserInfo.IsIE )
102
		{
103
			window._FCKHtmlToLoad = html.replace( /<head>/i, '<head>' + sOverrideError ) ;
104
			oIFrame.src = 'javascript:void( (function(){' +
105
				'document.open() ;' +
106
				'document.domain="' + document.domain + '" ;' +
107
				'document.write( window.parent._FCKHtmlToLoad );' +
108
				'document.close() ;' +
109
				'window.parent._FCKHtmlToLoad = null ;' +
110
				'})() )' ;
111
		}
112
		else if ( !FCKBrowserInfo.IsGecko )
113
		{
114
			// Firefox will render the tables inside the body in Quirks mode if the
115
			// source of the iframe is set to javascript. see #515
116
			oIFrame.src = 'javascript:void(0)' ;
117
		}
118
119
		// Append the new IFRAME to the target. For IE, it must be done after
120
		// setting the "src", to avoid the "secure/unsecure" message under HTTPS.
121
		eTargetElement.appendChild( oIFrame ) ;
122
123
		// Get the window and document objects used to interact with the newly created IFRAME.
124
		this.Window = oIFrame.contentWindow ;
125
126
		// IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
127
		// TODO: This error handler is not being fired.
128
		// this.Window.onerror = function() { alert( 'Error!' ) ; return true ; }
129
130
		if ( !FCK_IS_CUSTOM_DOMAIN || !FCKBrowserInfo.IsIE )
131
		{
132
			var oDoc = this.Window.document ;
133
134
			oDoc.open() ;
135
			oDoc.write( html.replace( /<head>/i, '<head>' + sOverrideError ) ) ;
136
			oDoc.close() ;
137
		}
138
139
		if ( FCKBrowserInfo.IsAIR )
140
			FCKAdobeAIR.EditingArea_Start( oDoc, html ) ;
141
142
		// Firefox 1.0.x is buggy... ohh yes... so let's do it two times and it
143
		// will magically work.
144
		if ( FCKBrowserInfo.IsGecko10 && !secondCall )
145
		{
146
			this.Start( html, true ) ;
147
			return ;
148
		}
149
150
		if ( oIFrame.readyState && oIFrame.readyState != 'completed' )
151
		{
152
			var editArea = this ;
153
154
			// Using a IE alternative for DOMContentLoaded, similar to the
155
			// solution proposed at http://javascript.nwbox.com/IEContentLoaded/
156
			setTimeout( function()
157
					{
158
						try
159
						{
160
							editArea.Window.document.documentElement.doScroll("left") ;
161
						}
162
						catch(e)
163
						{
164
							setTimeout( arguments.callee, 0 ) ;
165
							return ;
166
						}
167
						editArea.Window._FCKEditingArea = editArea ;
168
						FCKEditingArea_CompleteStart.call( editArea.Window ) ;
169
					}, 0 ) ;
170
		}
171
		else
172
		{
173
			this.Window._FCKEditingArea = this ;
174
175
			// FF 1.0.x is buggy... we must wait a lot to enable editing because
176
			// sometimes the content simply disappears, for example when pasting
177
			// "bla1!<img src='some_url'>!bla2" in the source and then switching
178
			// back to design.
179
			if ( FCKBrowserInfo.IsGecko10 )
180
				this.Window.setTimeout( FCKEditingArea_CompleteStart, 500 ) ;
181
			else
182
				FCKEditingArea_CompleteStart.call( this.Window ) ;
183
		}
184
	}
185
	else
186
	{
187
		var eTextarea = this.Textarea = oTargetDocument.createElement( 'textarea' ) ;
188
		eTextarea.className = 'SourceField' ;
189
		eTextarea.dir = 'ltr' ;
190
		FCKDomTools.SetElementStyles( eTextarea,
191
			{
192
				width	: '100%',
193
				height	: '100%',
194
				border	: 'none',
195
				resize	: 'none',
196
				outline	: 'none'
197
			} ) ;
198
		eTargetElement.appendChild( eTextarea ) ;
199
200
		eTextarea.value = html  ;
201
202
		// Fire the "OnLoad" event.
203
		FCKTools.RunFunction( this.OnLoad ) ;
204
	}
205
}
206
207
// "this" here is FCKEditingArea.Window
208
function FCKEditingArea_CompleteStart()
209
{
210
	// On Firefox, the DOM takes a little to become available. So we must wait for it in a loop.
211
	if ( !this.document.body )
212
	{
213
		this.setTimeout( FCKEditingArea_CompleteStart, 50 ) ;
214
		return ;
215
	}
216
217
	var oEditorArea = this._FCKEditingArea ;
218
219
	// Save this reference to be re-used later.
220
	oEditorArea.Document = oEditorArea.Window.document ;
221
222
	oEditorArea.MakeEditable() ;
223
224
	// Fire the "OnLoad" event.
225
	FCKTools.RunFunction( oEditorArea.OnLoad ) ;
226
}
227
228
FCKEditingArea.prototype.MakeEditable = function()
229
{
230
	var oDoc = this.Document ;
231
232
	if ( FCKBrowserInfo.IsIE )
233
	{
234
		// Kludge for #141 and #523
235
		oDoc.body.disabled = true ;
236
		oDoc.body.contentEditable = true ;
237
		oDoc.body.removeAttribute( "disabled" ) ;
238
239
		/* The following commands don't throw errors, but have no effect.
240
		oDoc.execCommand( 'AutoDetect', false, false ) ;
241
		oDoc.execCommand( 'KeepSelection', false, true ) ;
242
		*/
243
	}
244
	else
245
	{
246
		try
247
		{
248
			// Disable Firefox 2 Spell Checker.
249
			oDoc.body.spellcheck = ( this.FFSpellChecker !== false ) ;
250
251
			if ( this._BodyHTML )
252
			{
253
				oDoc.body.innerHTML = this._BodyHTML ;
254
				oDoc.body.offsetLeft ;		// Don't remove, this is a hack to fix Opera 9.50, see #2264.
255
				this._BodyHTML = null ;
256
			}
257
258
			oDoc.designMode = 'on' ;
259
260
			// Tell Gecko (Firefox 1.5+) to enable or not live resizing of objects (by Alfonso Martinez)
261
			oDoc.execCommand( 'enableObjectResizing', false, !FCKConfig.DisableObjectResizing ) ;
262
263
			// Disable the standard table editing features of Firefox.
264
			oDoc.execCommand( 'enableInlineTableEditing', false, !FCKConfig.DisableFFTableHandles ) ;
265
		}
266
		catch (e)
267
		{
268
			// In Firefox if the iframe is initially hidden it can't be set to designMode and it raises an exception
269
			// So we set up a DOM Mutation event Listener on the HTML, as it will raise several events when the document is  visible again
270
			FCKTools.AddEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
271
		}
272
273
	}
274
}
275
276
// This function processes the notifications of the DOM Mutation event on the document
277
// We use it to know that the document will be ready to be editable again (or we hope so)
278
function FCKEditingArea_Document_AttributeNodeModified( evt )
279
{
280
	var editingArea = evt.currentTarget.contentWindow._FCKEditingArea ;
281
282
	// We want to run our function after the events no longer fire, so we can know that it's a stable situation
283
	if ( editingArea._timer )
284
		window.clearTimeout( editingArea._timer ) ;
285
286
	editingArea._timer = FCKTools.SetTimeout( FCKEditingArea_MakeEditableByMutation, 1000, editingArea ) ;
287
}
288
289
// This function ideally should be called after the document is visible, it does clean up of the
290
// mutation tracking and tries again to make the area editable.
291
function FCKEditingArea_MakeEditableByMutation()
292
{
293
	// Clean up
294
	delete this._timer ;
295
	// Now we don't want to keep on getting this event
296
	FCKTools.RemoveEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
297
	// Let's try now to set the editing area editable
298
	// If it fails it will set up the Mutation Listener again automatically
299
	this.MakeEditable() ;
300
}
301
302
FCKEditingArea.prototype.Focus = function()
303
{
304
	try
305
	{
306
		if ( this.Mode == FCK_EDITMODE_WYSIWYG )
307
		{
308
			if ( FCKBrowserInfo.IsIE )
309
				this._FocusIE() ;
310
			else
311
				this.Window.focus() ;
312
		}
313
		else
314
		{
315
			var oDoc = FCKTools.GetElementDocument( this.Textarea ) ;
316
			if ( (!oDoc.hasFocus || oDoc.hasFocus() ) && oDoc.activeElement == this.Textarea )
317
				return ;
318
319
			this.Textarea.focus() ;
320
		}
321
	}
322
	catch(e) {}
323
}
324
325
FCKEditingArea.prototype._FocusIE = function()
326
{
327
	// In IE it can happen that the document is in theory focused but the
328
	// active element is outside of it.
329
	this.Document.body.setActive() ;
330
331
	this.Window.focus() ;
332
333
	// Kludge for #141... yet more code to workaround IE bugs
334
	var range = this.Document.selection.createRange() ;
335
336
	var parentNode = range.parentElement() ;
337
	var parentTag = parentNode.nodeName.toLowerCase() ;
338
339
	// Only apply the fix when in a block, and the block is empty.
340
	if ( parentNode.childNodes.length > 0 ||
341
		 !( FCKListsLib.BlockElements[parentTag] ||
342
		    FCKListsLib.NonEmptyBlockElements[parentTag] ) )
343
	{
344
		return ;
345
	}
346
347
	// Force the selection to happen, in this way we guarantee the focus will
348
	// be there.
349
	range = new FCKDomRange( this.Window ) ;
350
	range.MoveToElementEditStart( parentNode ) ;
351
	range.Select() ;
352
}
353
354
function FCKEditingArea_Cleanup()
355
{
356
	if ( this.Document )
357
	{
358
		// Avoid IE crash if an object is selected on unload #2201
359
		this.Document.selection.empty() ;
360
		this.Document.body.innerHTML = "" ;
361
	}
362
	this.TargetElement = null ;
363
	this.IFrame = null ;
364
	this.Document = null ;
365
	this.Textarea = null ;
366
367
	if ( this.Window )
368
	{
369
		this.Window._FCKEditingArea = null ;
370
		this.Window = null ;
371
	}
372
}