1 | /* |
---|
2 | * FCKeditor - The text editor for Internet - http://www.fckeditor.net |
---|
3 | * Copyright (C) 2003-2009 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 | * Utility functions. |
---|
22 | */ |
---|
23 | |
---|
24 | var FCKTools = new Object() ; |
---|
25 | |
---|
26 | FCKTools.CreateBogusBR = function( targetDocument ) |
---|
27 | { |
---|
28 | var eBR = targetDocument.createElement( 'br' ) ; |
---|
29 | // eBR.setAttribute( '_moz_editor_bogus_node', 'TRUE' ) ; |
---|
30 | eBR.setAttribute( 'type', '_moz' ) ; |
---|
31 | return eBR ; |
---|
32 | } |
---|
33 | |
---|
34 | /** |
---|
35 | * Fixes relative URL entries defined inside CSS styles by appending a prefix |
---|
36 | * to them. |
---|
37 | * @param (String) cssStyles The CSS styles definition possibly containing url() |
---|
38 | * paths. |
---|
39 | * @param (String) urlFixPrefix The prefix to append to relative URLs. |
---|
40 | */ |
---|
41 | FCKTools.FixCssUrls = function( urlFixPrefix, cssStyles ) |
---|
42 | { |
---|
43 | if ( !urlFixPrefix || urlFixPrefix.length == 0 ) |
---|
44 | return cssStyles ; |
---|
45 | |
---|
46 | return cssStyles.replace( /url\s*\(([\s'"]*)(.*?)([\s"']*)\)/g, function( match, opener, path, closer ) |
---|
47 | { |
---|
48 | if ( /^\/|^\w?:/.test( path ) ) |
---|
49 | return match ; |
---|
50 | else |
---|
51 | return 'url(' + opener + urlFixPrefix + path + closer + ')' ; |
---|
52 | } ) ; |
---|
53 | } |
---|
54 | |
---|
55 | FCKTools._GetUrlFixedCss = function( cssStyles, urlFixPrefix ) |
---|
56 | { |
---|
57 | var match = cssStyles.match( /^([^|]+)\|([\s\S]*)/ ) ; |
---|
58 | |
---|
59 | if ( match ) |
---|
60 | return FCKTools.FixCssUrls( match[1], match[2] ) ; |
---|
61 | else |
---|
62 | return cssStyles ; |
---|
63 | } |
---|
64 | |
---|
65 | /** |
---|
66 | * Appends a <link css> or <style> element to the document. |
---|
67 | * @param (Object) documentElement The DOM document object to which append the |
---|
68 | * stylesheet. |
---|
69 | * @param (Variant) cssFileOrDef A String pointing to the CSS file URL or an |
---|
70 | * Array with many CSS file URLs or the CSS definitions for the <style> |
---|
71 | * element. |
---|
72 | * @return {Array} An array containing all elements created in the target |
---|
73 | * document. It may include <link> or <style> elements, depending on the |
---|
74 | * value passed with cssFileOrDef. |
---|
75 | */ |
---|
76 | FCKTools.AppendStyleSheet = function( domDocument, cssFileOrArrayOrDef ) |
---|
77 | { |
---|
78 | if ( !cssFileOrArrayOrDef ) |
---|
79 | return [] ; |
---|
80 | |
---|
81 | if ( typeof( cssFileOrArrayOrDef ) == 'string' ) |
---|
82 | { |
---|
83 | // Test if the passed argument is an URL. |
---|
84 | if ( /[\\\/\.][^{}]*$/.test( cssFileOrArrayOrDef ) ) |
---|
85 | { |
---|
86 | // The string may have several URLs separated by comma. |
---|
87 | return this.AppendStyleSheet( domDocument, cssFileOrArrayOrDef.split(',') ) ; |
---|
88 | } |
---|
89 | else |
---|
90 | return [ this.AppendStyleString( domDocument, FCKTools._GetUrlFixedCss( cssFileOrArrayOrDef ) ) ] ; |
---|
91 | } |
---|
92 | else |
---|
93 | { |
---|
94 | var styles = [] ; |
---|
95 | for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ ) |
---|
96 | styles.push( this._AppendStyleSheet( domDocument, cssFileOrArrayOrDef[i] ) ) ; |
---|
97 | return styles ; |
---|
98 | } |
---|
99 | } |
---|
100 | |
---|
101 | FCKTools.GetStyleHtml = (function() |
---|
102 | { |
---|
103 | var getStyle = function( styleDef, markTemp ) |
---|
104 | { |
---|
105 | if ( styleDef.length == 0 ) |
---|
106 | return '' ; |
---|
107 | |
---|
108 | var temp = markTemp ? ' _fcktemp="true"' : '' ; |
---|
109 | return '<' + 'style type="text/css"' + temp + '>' + styleDef + '<' + '/style>' ; |
---|
110 | } |
---|
111 | |
---|
112 | var getLink = function( cssFileUrl, markTemp ) |
---|
113 | { |
---|
114 | if ( cssFileUrl.length == 0 ) |
---|
115 | return '' ; |
---|
116 | |
---|
117 | var temp = markTemp ? ' _fcktemp="true"' : '' ; |
---|
118 | return '<' + 'link href="' + cssFileUrl + '" type="text/css" rel="stylesheet" ' + temp + '/>' ; |
---|
119 | } |
---|
120 | |
---|
121 | return function( cssFileOrArrayOrDef, markTemp ) |
---|
122 | { |
---|
123 | if ( !cssFileOrArrayOrDef ) |
---|
124 | return '' ; |
---|
125 | |
---|
126 | if ( typeof( cssFileOrArrayOrDef ) == 'string' ) |
---|
127 | { |
---|
128 | // Test if the passed argument is an URL. |
---|
129 | if ( /[\\\/\.][^{}]*$/.test( cssFileOrArrayOrDef ) ) |
---|
130 | { |
---|
131 | // The string may have several URLs separated by comma. |
---|
132 | return this.GetStyleHtml( cssFileOrArrayOrDef.split(','), markTemp ) ; |
---|
133 | } |
---|
134 | else |
---|
135 | return getStyle( this._GetUrlFixedCss( cssFileOrArrayOrDef ), markTemp ) ; |
---|
136 | } |
---|
137 | else |
---|
138 | { |
---|
139 | var html = '' ; |
---|
140 | |
---|
141 | for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ ) |
---|
142 | html += getLink( cssFileOrArrayOrDef[i], markTemp ) ; |
---|
143 | |
---|
144 | return html ; |
---|
145 | } |
---|
146 | } |
---|
147 | })() ; |
---|
148 | |
---|
149 | FCKTools.GetElementDocument = function ( element ) |
---|
150 | { |
---|
151 | return element.ownerDocument || element.document ; |
---|
152 | } |
---|
153 | |
---|
154 | // Get the window object where the element is placed in. |
---|
155 | FCKTools.GetElementWindow = function( element ) |
---|
156 | { |
---|
157 | return this.GetDocumentWindow( this.GetElementDocument( element ) ) ; |
---|
158 | } |
---|
159 | |
---|
160 | FCKTools.GetDocumentWindow = function( document ) |
---|
161 | { |
---|
162 | // With Safari, there is not way to retrieve the window from the document, so we must fix it. |
---|
163 | if ( FCKBrowserInfo.IsSafari && !document.parentWindow ) |
---|
164 | this.FixDocumentParentWindow( window.top ) ; |
---|
165 | |
---|
166 | return document.parentWindow || document.defaultView ; |
---|
167 | } |
---|
168 | |
---|
169 | /* |
---|
170 | This is a Safari specific function that fix the reference to the parent |
---|
171 | window from the document object. |
---|
172 | */ |
---|
173 | FCKTools.FixDocumentParentWindow = function( targetWindow ) |
---|
174 | { |
---|
175 | if ( targetWindow.document ) |
---|
176 | targetWindow.document.parentWindow = targetWindow ; |
---|
177 | |
---|
178 | for ( var i = 0 ; i < targetWindow.frames.length ; i++ ) |
---|
179 | FCKTools.FixDocumentParentWindow( targetWindow.frames[i] ) ; |
---|
180 | } |
---|
181 | |
---|
182 | FCKTools.HTMLEncode = function( text ) |
---|
183 | { |
---|
184 | if ( !text ) |
---|
185 | return '' ; |
---|
186 | |
---|
187 | text = text.replace( /&/g, '&' ) ; |
---|
188 | text = text.replace( /</g, '<' ) ; |
---|
189 | text = text.replace( />/g, '>' ) ; |
---|
190 | |
---|
191 | return text ; |
---|
192 | } |
---|
193 | |
---|
194 | FCKTools.HTMLDecode = function( text ) |
---|
195 | { |
---|
196 | if ( !text ) |
---|
197 | return '' ; |
---|
198 | |
---|
199 | text = text.replace( />/g, '>' ) ; |
---|
200 | text = text.replace( /</g, '<' ) ; |
---|
201 | text = text.replace( /&/g, '&' ) ; |
---|
202 | |
---|
203 | return text ; |
---|
204 | } |
---|
205 | |
---|
206 | FCKTools._ProcessLineBreaksForPMode = function( oEditor, text, liState, node, strArray ) |
---|
207 | { |
---|
208 | var closeState = 0 ; |
---|
209 | var blockStartTag = "<p>" ; |
---|
210 | var blockEndTag = "</p>" ; |
---|
211 | var lineBreakTag = "<br />" ; |
---|
212 | if ( liState ) |
---|
213 | { |
---|
214 | blockStartTag = "<li>" ; |
---|
215 | blockEndTag = "</li>" ; |
---|
216 | closeState = 1 ; |
---|
217 | } |
---|
218 | |
---|
219 | // Are we currently inside a <p> tag now? |
---|
220 | // If yes, close it at the next double line break. |
---|
221 | while ( node && node != oEditor.FCK.EditorDocument.body ) |
---|
222 | { |
---|
223 | if ( node.tagName.toLowerCase() == 'p' ) |
---|
224 | { |
---|
225 | closeState = 1 ; |
---|
226 | break; |
---|
227 | } |
---|
228 | node = node.parentNode ; |
---|
229 | } |
---|
230 | |
---|
231 | for ( var i = 0 ; i < text.length ; i++ ) |
---|
232 | { |
---|
233 | var c = text.charAt( i ) ; |
---|
234 | if ( c == '\r' ) |
---|
235 | continue ; |
---|
236 | |
---|
237 | if ( c != '\n' ) |
---|
238 | { |
---|
239 | strArray.push( c ) ; |
---|
240 | continue ; |
---|
241 | } |
---|
242 | |
---|
243 | // Now we have encountered a line break. |
---|
244 | // Check if the next character is also a line break. |
---|
245 | var n = text.charAt( i + 1 ) ; |
---|
246 | if ( n == '\r' ) |
---|
247 | { |
---|
248 | i++ ; |
---|
249 | n = text.charAt( i + 1 ) ; |
---|
250 | } |
---|
251 | if ( n == '\n' ) |
---|
252 | { |
---|
253 | i++ ; // ignore next character - we have already processed it. |
---|
254 | if ( closeState ) |
---|
255 | strArray.push( blockEndTag ) ; |
---|
256 | strArray.push( blockStartTag ) ; |
---|
257 | closeState = 1 ; |
---|
258 | } |
---|
259 | else |
---|
260 | strArray.push( lineBreakTag ) ; |
---|
261 | } |
---|
262 | } |
---|
263 | |
---|
264 | FCKTools._ProcessLineBreaksForDivMode = function( oEditor, text, liState, node, strArray ) |
---|
265 | { |
---|
266 | var closeState = 0 ; |
---|
267 | var blockStartTag = "<div>" ; |
---|
268 | var blockEndTag = "</div>" ; |
---|
269 | if ( liState ) |
---|
270 | { |
---|
271 | blockStartTag = "<li>" ; |
---|
272 | blockEndTag = "</li>" ; |
---|
273 | closeState = 1 ; |
---|
274 | } |
---|
275 | |
---|
276 | // Are we currently inside a <div> tag now? |
---|
277 | // If yes, close it at the next double line break. |
---|
278 | while ( node && node != oEditor.FCK.EditorDocument.body ) |
---|
279 | { |
---|
280 | if ( node.tagName.toLowerCase() == 'div' ) |
---|
281 | { |
---|
282 | closeState = 1 ; |
---|
283 | break ; |
---|
284 | } |
---|
285 | node = node.parentNode ; |
---|
286 | } |
---|
287 | |
---|
288 | for ( var i = 0 ; i < text.length ; i++ ) |
---|
289 | { |
---|
290 | var c = text.charAt( i ) ; |
---|
291 | if ( c == '\r' ) |
---|
292 | continue ; |
---|
293 | |
---|
294 | if ( c != '\n' ) |
---|
295 | { |
---|
296 | strArray.push( c ) ; |
---|
297 | continue ; |
---|
298 | } |
---|
299 | |
---|
300 | if ( closeState ) |
---|
301 | { |
---|
302 | if ( strArray[ strArray.length - 1 ] == blockStartTag ) |
---|
303 | { |
---|
304 | // A div tag must have some contents inside for it to be visible. |
---|
305 | strArray.push( " " ) ; |
---|
306 | } |
---|
307 | strArray.push( blockEndTag ) ; |
---|
308 | } |
---|
309 | strArray.push( blockStartTag ) ; |
---|
310 | closeState = 1 ; |
---|
311 | } |
---|
312 | if ( closeState ) |
---|
313 | strArray.push( blockEndTag ) ; |
---|
314 | } |
---|
315 | |
---|
316 | FCKTools._ProcessLineBreaksForBrMode = function( oEditor, text, liState, node, strArray ) |
---|
317 | { |
---|
318 | var closeState = 0 ; |
---|
319 | var blockStartTag = "<br />" ; |
---|
320 | var blockEndTag = "" ; |
---|
321 | if ( liState ) |
---|
322 | { |
---|
323 | blockStartTag = "<li>" ; |
---|
324 | blockEndTag = "</li>" ; |
---|
325 | closeState = 1 ; |
---|
326 | } |
---|
327 | |
---|
328 | for ( var i = 0 ; i < text.length ; i++ ) |
---|
329 | { |
---|
330 | var c = text.charAt( i ) ; |
---|
331 | if ( c == '\r' ) |
---|
332 | continue ; |
---|
333 | |
---|
334 | if ( c != '\n' ) |
---|
335 | { |
---|
336 | strArray.push( c ) ; |
---|
337 | continue ; |
---|
338 | } |
---|
339 | |
---|
340 | if ( closeState && blockEndTag.length ) |
---|
341 | strArray.push ( blockEndTag ) ; |
---|
342 | strArray.push( blockStartTag ) ; |
---|
343 | closeState = 1 ; |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | FCKTools.ProcessLineBreaks = function( oEditor, oConfig, text ) |
---|
348 | { |
---|
349 | var enterMode = oConfig.EnterMode.toLowerCase() ; |
---|
350 | var strArray = [] ; |
---|
351 | |
---|
352 | // Is the caret or selection inside an <li> tag now? |
---|
353 | var liState = 0 ; |
---|
354 | var range = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ; |
---|
355 | range.MoveToSelection() ; |
---|
356 | var node = range._Range.startContainer ; |
---|
357 | while ( node && node.nodeType != 1 ) |
---|
358 | node = node.parentNode ; |
---|
359 | if ( node && node.tagName.toLowerCase() == 'li' ) |
---|
360 | liState = 1 ; |
---|
361 | |
---|
362 | if ( enterMode == 'p' ) |
---|
363 | this._ProcessLineBreaksForPMode( oEditor, text, liState, node, strArray ) ; |
---|
364 | else if ( enterMode == 'div' ) |
---|
365 | this._ProcessLineBreaksForDivMode( oEditor, text, liState, node, strArray ) ; |
---|
366 | else if ( enterMode == 'br' ) |
---|
367 | this._ProcessLineBreaksForBrMode( oEditor, text, liState, node, strArray ) ; |
---|
368 | return strArray.join( "" ) ; |
---|
369 | } |
---|
370 | |
---|
371 | /** |
---|
372 | * Adds an option to a SELECT element. |
---|
373 | */ |
---|
374 | FCKTools.AddSelectOption = function( selectElement, optionText, optionValue ) |
---|
375 | { |
---|
376 | var oOption = FCKTools.GetElementDocument( selectElement ).createElement( "OPTION" ) ; |
---|
377 | |
---|
378 | oOption.text = optionText ; |
---|
379 | oOption.value = optionValue ; |
---|
380 | |
---|
381 | selectElement.options.add(oOption) ; |
---|
382 | |
---|
383 | return oOption ; |
---|
384 | } |
---|
385 | |
---|
386 | FCKTools.RunFunction = function( func, thisObject, paramsArray, timerWindow ) |
---|
387 | { |
---|
388 | if ( func ) |
---|
389 | this.SetTimeout( func, 0, thisObject, paramsArray, timerWindow ) ; |
---|
390 | } |
---|
391 | |
---|
392 | FCKTools.SetTimeout = function( func, milliseconds, thisObject, paramsArray, timerWindow ) |
---|
393 | { |
---|
394 | return ( timerWindow || window ).setTimeout( |
---|
395 | function() |
---|
396 | { |
---|
397 | if ( paramsArray ) |
---|
398 | func.apply( thisObject, [].concat( paramsArray ) ) ; |
---|
399 | else |
---|
400 | func.apply( thisObject ) ; |
---|
401 | }, |
---|
402 | milliseconds ) ; |
---|
403 | } |
---|
404 | |
---|
405 | FCKTools.SetInterval = function( func, milliseconds, thisObject, paramsArray, timerWindow ) |
---|
406 | { |
---|
407 | return ( timerWindow || window ).setInterval( |
---|
408 | function() |
---|
409 | { |
---|
410 | func.apply( thisObject, paramsArray || [] ) ; |
---|
411 | }, |
---|
412 | milliseconds ) ; |
---|
413 | } |
---|
414 | |
---|
415 | FCKTools.ConvertStyleSizeToHtml = function( size ) |
---|
416 | { |
---|
417 | return size.EndsWith( '%' ) ? size : parseInt( size, 10 ) ; |
---|
418 | } |
---|
419 | |
---|
420 | FCKTools.ConvertHtmlSizeToStyle = function( size ) |
---|
421 | { |
---|
422 | return size.EndsWith( '%' ) ? size : ( size + 'px' ) ; |
---|
423 | } |
---|
424 | |
---|
425 | // START iCM MODIFICATIONS |
---|
426 | // Amended to accept a list of one or more ascensor tag names |
---|
427 | // Amended to check the element itself before working back up through the parent hierarchy |
---|
428 | FCKTools.GetElementAscensor = function( element, ascensorTagNames ) |
---|
429 | { |
---|
430 | // var e = element.parentNode ; |
---|
431 | var e = element ; |
---|
432 | var lstTags = "," + ascensorTagNames.toUpperCase() + "," ; |
---|
433 | |
---|
434 | while ( e ) |
---|
435 | { |
---|
436 | if ( lstTags.indexOf( "," + e.nodeName.toUpperCase() + "," ) != -1 ) |
---|
437 | return e ; |
---|
438 | |
---|
439 | e = e.parentNode ; |
---|
440 | } |
---|
441 | return null ; |
---|
442 | } |
---|
443 | // END iCM MODIFICATIONS |
---|
444 | |
---|
445 | FCKTools.CreateEventListener = function( func, params ) |
---|
446 | { |
---|
447 | var f = function() |
---|
448 | { |
---|
449 | var aAllParams = [] ; |
---|
450 | |
---|
451 | for ( var i = 0 ; i < arguments.length ; i++ ) |
---|
452 | aAllParams.push( arguments[i] ) ; |
---|
453 | |
---|
454 | func.apply( this, aAllParams.concat( params ) ) ; |
---|
455 | } |
---|
456 | |
---|
457 | return f ; |
---|
458 | } |
---|
459 | |
---|
460 | FCKTools.IsStrictMode = function( document ) |
---|
461 | { |
---|
462 | // There is no compatMode in Safari, but it seams that it always behave as |
---|
463 | // CSS1Compat, so let's assume it as the default for that browser. |
---|
464 | return ( 'CSS1Compat' == ( document.compatMode || ( FCKBrowserInfo.IsSafari ? 'CSS1Compat' : null ) ) ) ; |
---|
465 | } |
---|
466 | |
---|
467 | // Transforms a "arguments" object to an array. |
---|
468 | FCKTools.ArgumentsToArray = function( args, startIndex, maxLength ) |
---|
469 | { |
---|
470 | startIndex = startIndex || 0 ; |
---|
471 | maxLength = maxLength || args.length ; |
---|
472 | |
---|
473 | var argsArray = new Array() ; |
---|
474 | |
---|
475 | for ( var i = startIndex ; i < startIndex + maxLength && i < args.length ; i++ ) |
---|
476 | argsArray.push( args[i] ) ; |
---|
477 | |
---|
478 | return argsArray ; |
---|
479 | } |
---|
480 | |
---|
481 | FCKTools.CloneObject = function( sourceObject ) |
---|
482 | { |
---|
483 | var fCloneCreator = function() {} ; |
---|
484 | fCloneCreator.prototype = sourceObject ; |
---|
485 | return new fCloneCreator ; |
---|
486 | } |
---|
487 | |
---|
488 | // Appends a bogus <br> at the end of the element, if not yet available. |
---|
489 | FCKTools.AppendBogusBr = function( element ) |
---|
490 | { |
---|
491 | if ( !element ) |
---|
492 | return ; |
---|
493 | |
---|
494 | var eLastChild = this.GetLastItem( element.getElementsByTagName('br') ) ; |
---|
495 | |
---|
496 | if ( !eLastChild || ( eLastChild.getAttribute( 'type', 2 ) != '_moz' && eLastChild.getAttribute( '_moz_dirty' ) == null ) ) |
---|
497 | { |
---|
498 | var doc = this.GetElementDocument( element ) ; |
---|
499 | |
---|
500 | if ( FCKBrowserInfo.IsOpera ) |
---|
501 | element.appendChild( doc.createTextNode('') ) ; |
---|
502 | else |
---|
503 | element.appendChild( this.CreateBogusBR( doc ) ) ; |
---|
504 | } |
---|
505 | } |
---|
506 | |
---|
507 | FCKTools.GetLastItem = function( list ) |
---|
508 | { |
---|
509 | if ( list.length > 0 ) |
---|
510 | return list[ list.length - 1 ] ; |
---|
511 | |
---|
512 | return null ; |
---|
513 | } |
---|
514 | |
---|
515 | FCKTools.GetDocumentPosition = function( w, node ) |
---|
516 | { |
---|
517 | var x = 0 ; |
---|
518 | var y = 0 ; |
---|
519 | var curNode = node ; |
---|
520 | var prevNode = null ; |
---|
521 | var curWindow = FCKTools.GetElementWindow( curNode ) ; |
---|
522 | while ( curNode && !( curWindow == w && ( curNode == w.document.body || curNode == w.document.documentElement ) ) ) |
---|
523 | { |
---|
524 | x += curNode.offsetLeft - curNode.scrollLeft ; |
---|
525 | y += curNode.offsetTop - curNode.scrollTop ; |
---|
526 | |
---|
527 | if ( ! FCKBrowserInfo.IsOpera ) |
---|
528 | { |
---|
529 | var scrollNode = prevNode ; |
---|
530 | while ( scrollNode && scrollNode != curNode ) |
---|
531 | { |
---|
532 | x -= scrollNode.scrollLeft ; |
---|
533 | y -= scrollNode.scrollTop ; |
---|
534 | scrollNode = scrollNode.parentNode ; |
---|
535 | } |
---|
536 | } |
---|
537 | |
---|
538 | prevNode = curNode ; |
---|
539 | if ( curNode.offsetParent ) |
---|
540 | curNode = curNode.offsetParent ; |
---|
541 | else |
---|
542 | { |
---|
543 | if ( curWindow != w ) |
---|
544 | { |
---|
545 | curNode = curWindow.frameElement ; |
---|
546 | prevNode = null ; |
---|
547 | if ( curNode ) |
---|
548 | curWindow = curNode.contentWindow.parent ; |
---|
549 | } |
---|
550 | else |
---|
551 | curNode = null ; |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | // document.body is a special case when it comes to offsetTop and offsetLeft values. |
---|
556 | // 1. It matters if document.body itself is a positioned element; |
---|
557 | // 2. It matters is when we're in IE and the element has no positioned ancestor. |
---|
558 | // Otherwise the values should be ignored. |
---|
559 | if ( FCKDomTools.GetCurrentElementStyle( w.document.body, 'position') != 'static' |
---|
560 | || ( FCKBrowserInfo.IsIE && FCKDomTools.GetPositionedAncestor( node ) == null ) ) |
---|
561 | { |
---|
562 | x += w.document.body.offsetLeft ; |
---|
563 | y += w.document.body.offsetTop ; |
---|
564 | } |
---|
565 | |
---|
566 | return { "x" : x, "y" : y } ; |
---|
567 | } |
---|
568 | |
---|
569 | FCKTools.GetWindowPosition = function( w, node ) |
---|
570 | { |
---|
571 | var pos = this.GetDocumentPosition( w, node ) ; |
---|
572 | var scroll = FCKTools.GetScrollPosition( w ) ; |
---|
573 | pos.x -= scroll.X ; |
---|
574 | pos.y -= scroll.Y ; |
---|
575 | return pos ; |
---|
576 | } |
---|
577 | |
---|
578 | FCKTools.ProtectFormStyles = function( formNode ) |
---|
579 | { |
---|
580 | if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' ) |
---|
581 | return [] ; |
---|
582 | var hijackRecord = [] ; |
---|
583 | var hijackNames = [ 'style', 'className' ] ; |
---|
584 | for ( var i = 0 ; i < hijackNames.length ; i++ ) |
---|
585 | { |
---|
586 | var name = hijackNames[i] ; |
---|
587 | if ( formNode.elements.namedItem( name ) ) |
---|
588 | { |
---|
589 | var hijackNode = formNode.elements.namedItem( name ) ; |
---|
590 | hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] ) ; |
---|
591 | formNode.removeChild( hijackNode ) ; |
---|
592 | } |
---|
593 | } |
---|
594 | return hijackRecord ; |
---|
595 | } |
---|
596 | |
---|
597 | FCKTools.RestoreFormStyles = function( formNode, hijackRecord ) |
---|
598 | { |
---|
599 | if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' ) |
---|
600 | return ; |
---|
601 | if ( hijackRecord.length > 0 ) |
---|
602 | { |
---|
603 | for ( var i = hijackRecord.length - 1 ; i >= 0 ; i-- ) |
---|
604 | { |
---|
605 | var node = hijackRecord[i][0] ; |
---|
606 | var sibling = hijackRecord[i][1] ; |
---|
607 | if ( sibling ) |
---|
608 | formNode.insertBefore( node, sibling ) ; |
---|
609 | else |
---|
610 | formNode.appendChild( node ) ; |
---|
611 | } |
---|
612 | } |
---|
613 | } |
---|
614 | |
---|
615 | // Perform a one-step DFS walk. |
---|
616 | FCKTools.GetNextNode = function( node, limitNode ) |
---|
617 | { |
---|
618 | if ( node.firstChild ) |
---|
619 | return node.firstChild ; |
---|
620 | else if ( node.nextSibling ) |
---|
621 | return node.nextSibling ; |
---|
622 | else |
---|
623 | { |
---|
624 | var ancestor = node.parentNode ; |
---|
625 | while ( ancestor ) |
---|
626 | { |
---|
627 | if ( ancestor == limitNode ) |
---|
628 | return null ; |
---|
629 | if ( ancestor.nextSibling ) |
---|
630 | return ancestor.nextSibling ; |
---|
631 | else |
---|
632 | ancestor = ancestor.parentNode ; |
---|
633 | } |
---|
634 | } |
---|
635 | return null ; |
---|
636 | } |
---|
637 | |
---|
638 | FCKTools.GetNextTextNode = function( textnode, limitNode, checkStop ) |
---|
639 | { |
---|
640 | node = this.GetNextNode( textnode, limitNode ) ; |
---|
641 | if ( checkStop && node && checkStop( node ) ) |
---|
642 | return null ; |
---|
643 | while ( node && node.nodeType != 3 ) |
---|
644 | { |
---|
645 | node = this.GetNextNode( node, limitNode ) ; |
---|
646 | if ( checkStop && node && checkStop( node ) ) |
---|
647 | return null ; |
---|
648 | } |
---|
649 | return node ; |
---|
650 | } |
---|
651 | |
---|
652 | /** |
---|
653 | * Merge all objects passed by argument into a single object. |
---|
654 | */ |
---|
655 | FCKTools.Merge = function() |
---|
656 | { |
---|
657 | var args = arguments ; |
---|
658 | var o = args[0] ; |
---|
659 | |
---|
660 | for ( var i = 1 ; i < args.length ; i++ ) |
---|
661 | { |
---|
662 | var arg = args[i] ; |
---|
663 | for ( var p in arg ) |
---|
664 | o[p] = arg[p] ; |
---|
665 | } |
---|
666 | |
---|
667 | return o ; |
---|
668 | } |
---|
669 | |
---|
670 | /** |
---|
671 | * Check if the passed argument is a real Array. It may not working when |
---|
672 | * calling it cross windows. |
---|
673 | */ |
---|
674 | FCKTools.IsArray = function( it ) |
---|
675 | { |
---|
676 | return ( it instanceof Array ) ; |
---|
677 | } |
---|
678 | |
---|
679 | /** |
---|
680 | * Appends a "length" property to an object, containing the number of |
---|
681 | * properties available on it, excluded the append property itself. |
---|
682 | */ |
---|
683 | FCKTools.AppendLengthProperty = function( targetObject, propertyName ) |
---|
684 | { |
---|
685 | var counter = 0 ; |
---|
686 | |
---|
687 | for ( var n in targetObject ) |
---|
688 | counter++ ; |
---|
689 | |
---|
690 | return targetObject[ propertyName || 'length' ] = counter ; |
---|
691 | } |
---|
692 | |
---|
693 | /** |
---|
694 | * Gets the browser parsed version of a css text (style attribute value). On |
---|
695 | * some cases, the browser makes changes to the css text, returning a different |
---|
696 | * value. For example, hexadecimal colors get transformed to rgb(). |
---|
697 | */ |
---|
698 | FCKTools.NormalizeCssText = function( unparsedCssText ) |
---|
699 | { |
---|
700 | // Injects the style in a temporary span object, so the browser parses it, |
---|
701 | // retrieving its final format. |
---|
702 | var tempSpan = document.createElement( 'span' ) ; |
---|
703 | tempSpan.style.cssText = unparsedCssText ; |
---|
704 | return tempSpan.style.cssText ; |
---|
705 | } |
---|
706 | |
---|
707 | /** |
---|
708 | * Binding the "this" reference to an object for a function. |
---|
709 | */ |
---|
710 | FCKTools.Bind = function( subject, func ) |
---|
711 | { |
---|
712 | return function(){ return func.apply( subject, arguments ) ; } ; |
---|
713 | } |
---|
714 | |
---|
715 | /** |
---|
716 | * Retrieve the correct "empty iframe" URL for the current browser, which |
---|
717 | * causes the minimum fuzz (e.g. security warnings in HTTPS, DNS error in |
---|
718 | * IE5.5, etc.) for that browser, making the iframe ready to DOM use whithout |
---|
719 | * having to loading an external file. |
---|
720 | */ |
---|
721 | FCKTools.GetVoidUrl = function() |
---|
722 | { |
---|
723 | if ( FCK_IS_CUSTOM_DOMAIN ) |
---|
724 | return "javascript: void( function(){" + |
---|
725 | "document.open();" + |
---|
726 | "document.write('<html><head><title></title></head><body></body></html>');" + |
---|
727 | "document.domain = '" + FCK_RUNTIME_DOMAIN + "';" + |
---|
728 | "document.close();" + |
---|
729 | "}() ) ;"; |
---|
730 | |
---|
731 | if ( FCKBrowserInfo.IsIE ) |
---|
732 | { |
---|
733 | if ( FCKBrowserInfo.IsIE7 || !FCKBrowserInfo.IsIE6 ) |
---|
734 | return "" ; // IE7+ / IE5.5 |
---|
735 | else |
---|
736 | return "javascript: '';" ; // IE6+ |
---|
737 | } |
---|
738 | |
---|
739 | return "javascript: void(0);" ; // All other browsers. |
---|
740 | } |
---|
741 | |
---|
742 | FCKTools.ResetStyles = function( element ) |
---|
743 | { |
---|
744 | element.style.cssText = 'margin:0;' + |
---|
745 | 'padding:0;' + |
---|
746 | 'border:0;' + |
---|
747 | 'background-color:transparent;' + |
---|
748 | 'background-image:none;' ; |
---|
749 | } |
---|