var tinymce = {
majorVersion : '3' ,
minorVersion : '2.3' ,
releaseDate : '2009-04-23' ,
_init : function ( ) {
var t = this , d = document , w = window , na = navigator , ua = na . userAgent , i , nl , n , base , p , v ;
// Browser checks
t . isOpera = w . opera && opera . buildNumber ;
t . isWebKit = /WebKit/ . test ( ua ) ;
t . isIE = ! t . isWebKit && ! t . isOpera && ( /MSIE/gi ) . test ( ua ) && ( /Explorer/gi ) . test ( na . appName ) ;
t . isIE6 = t . isIE && /MSIE [56]/ . test ( ua ) ;
t . isGecko = ! t . isWebKit && /Gecko/ . test ( ua ) ;
t . isMac = ua . indexOf ( 'Mac' ) != - 1 ;
t . isAir = /adobeair/i . test ( ua ) ;
// TinyMCE .NET webcontrol might be setting the values for TinyMCE
if ( w . tinyMCEPreInit ) {
t . suffix = tinyMCEPreInit . suffix ;
t . baseURL = tinyMCEPreInit . base ;
t . query = tinyMCEPreInit . query ;
return ;
}
// Get suffix and base
t . suffix = '' ;
// If base element found, add that infront of baseURL
nl = d . getElementsByTagName ( 'base' ) ;
for ( i = 0 ; i < nl . length ; i ++ ) {
if ( v = nl [ i ] . href ) {
// Host only value like http://site.com or http://site.com:8008
if ( /^https?:\/\/[^\/]+$/ . test ( v ) )
v += '/' ;
base = v ? v . match ( /.*\// ) [ 0 ] : '' ; // Get only directory
}
}
function getBase ( n ) {
if ( n . src && /tiny_mce(|_dev|_src|_gzip|_jquery|_prototype).js/ . test ( n . src ) ) {
if ( /_(src|dev)\.js/g . test ( n . src ) )
t . suffix = '_src' ;
if ( ( p = n . src . indexOf ( '?' ) ) != - 1 )
t . query = n . src . substring ( p + 1 ) ;
t . baseURL = n . src . substring ( 0 , n . src . lastIndexOf ( '/' ) ) ;
// If path to script is relative and a base href was found add that one infront
if ( base && t . baseURL . indexOf ( '://' ) == - 1 )
t . baseURL = base + t . baseURL ;
return t . baseURL ;
}
return null ;
} ;
// Check document
nl = d . getElementsByTagName ( 'script' ) ;
for ( i = 0 ; i < nl . length ; i ++ ) {
if ( getBase ( nl [ i ] ) )
return ;
}
// Check head
n = d . getElementsByTagName ( 'head' ) [ 0 ] ;
if ( n ) {
nl = n . getElementsByTagName ( 'script' ) ;
for ( i = 0 ; i < nl . length ; i ++ ) {
if ( getBase ( nl [ i ] ) )
return ;
}
}
return ;
} ,
is : function ( o , t ) {
var n = typeof ( o ) ;
if ( ! t )
return n != 'undefined' ;
if ( t == 'array' && ( o . hasOwnProperty && o instanceof Array ) )
return true ;
return n == t ;
} ,
each : function ( o , cb , s ) {
var n , l ;
if ( ! o )
return 0 ;
s = s || o ;
if ( typeof ( o . length ) != 'undefined' ) {
// Indexed arrays, needed for Safari
for ( n = 0 , l = o . length ; n < l ; n ++ ) {
if ( cb . call ( s , o [ n ] , n , o ) === false )
return 0 ;
}
} else {
// Hashtables
for ( n in o ) {
if ( o . hasOwnProperty ( n ) ) {
if ( cb . call ( s , o [ n ] , n , o ) === false )
return 0 ;
}
}
}
return 1 ;
} ,
map : function ( a , f ) {
var o = [ ] ;
tinymce . each ( a , function ( v ) {
o . push ( f ( v ) ) ;
} ) ;
return o ;
} ,
grep : function ( a , f ) {
var o = [ ] ;
tinymce . each ( a , function ( v ) {
if ( ! f || f ( v ) )
o . push ( v ) ;
} ) ;
return o ;
} ,
inArray : function ( a , v ) {
var i , l ;
if ( a ) {
for ( i = 0 , l = a . length ; i < l ; i ++ ) {
if ( a [ i ] === v )
return i ;
}
}
return - 1 ;
} ,
extend : function ( o , e ) {
var i , a = arguments ;
for ( i = 1 ; i < a . length ; i ++ ) {
e = a [ i ] ;
tinymce . each ( e , function ( v , n ) {
if ( typeof ( v ) !== 'undefined' )
o [ n ] = v ;
} ) ;
}
return o ;
} ,
trim : function ( s ) {
return ( s ? '' + s : '' ) . replace ( /^\s*|\s*$/g , '' ) ;
} ,
create : function ( s , p ) {
var t = this , sp , ns , cn , scn , c , de = 0 ;
// Parse : <prefix> <class>:<super class>
s = /^((static) )?([\w.]+)(:([\w.]+))?/ . exec ( s ) ;
cn = s [ 3 ] . match ( /(^|\.)(\w+)$/i ) [ 2 ] ; // Class name
// Create namespace for new class
ns = t . createNS ( s [ 3 ] . replace ( /\.\w+$/ , '' ) ) ;
// Class already exists
if ( ns [ cn ] )
return ;
// Make pure static class
if ( s [ 2 ] == 'static' ) {
ns [ cn ] = p ;
if ( this . onCreate )
this . onCreate ( s [ 2 ] , s [ 3 ] , ns [ cn ] ) ;
return ;
}
// Create default constructor
if ( ! p [ cn ] ) {
p [ cn ] = function ( ) { } ;
de = 1 ;
}
// Add constructor and methods
ns [ cn ] = p [ cn ] ;
t . extend ( ns [ cn ] . prototype , p ) ;
// Extend
if ( s [ 5 ] ) {
sp = t . resolve ( s [ 5 ] ) . prototype ;
scn = s [ 5 ] . match ( /\.(\w+)$/i ) [ 1 ] ; // Class name
// Extend constructor
c = ns [ cn ] ;
if ( de ) {
// Add passthrough constructor
ns [ cn ] = function ( ) {
return sp [ scn ] . apply ( this , arguments ) ;
} ;
} else {
// Add inherit constructor
ns [ cn ] = function ( ) {
this . parent = sp [ scn ] ;
return c . apply ( this , arguments ) ;
} ;
}
ns [ cn ] . prototype [ cn ] = ns [ cn ] ;
// Add super methods
t . each ( sp , function ( f , n ) {
ns [ cn ] . prototype [ n ] = sp [ n ] ;
} ) ;
// Add overridden methods
t . each ( p , function ( f , n ) {
// Extend methods if needed
if ( sp [ n ] ) {
ns [ cn ] . prototype [ n ] = function ( ) {
this . parent = sp [ n ] ;
return f . apply ( this , arguments ) ;
} ;
} else {
if ( n != cn )
ns [ cn ] . prototype [ n ] = f ;
}
} ) ;
}
// Add static methods
t . each ( p [ 'static' ] , function ( f , n ) {
ns [ cn ] [ n ] = f ;
} ) ;
if ( this . onCreate )
this . onCreate ( s [ 2 ] , s [ 3 ] , ns [ cn ] . prototype ) ;
} ,
walk : function ( o , f , n , s ) {
s = s || this ;
if ( o ) {
if ( n )
o = o [ n ] ;
tinymce . each ( o , function ( o , i ) {
if ( f . call ( s , o , i , n ) === false )
return false ;
tinymce . walk ( o , f , n , s ) ;
} ) ;
}
} ,
createNS : function ( n , o ) {
var i , v ;
o = o || window ;
n = n . split ( '.' ) ;
for ( i = 0 ; i < n . length ; i ++ ) {
v = n [ i ] ;
if ( ! o [ v ] )
o [ v ] = { } ;
o = o [ v ] ;
}
return o ;
} ,
resolve : function ( n , o ) {
var i , l ;
o = o || window ;
n = n . split ( '.' ) ;
for ( i = 0 , l = n . length ; i < l ; i ++ ) {
o = o [ n [ i ] ] ;
if ( ! o )
break ;
}
return o ;
} ,
addUnload : function ( f , s ) {
var t = this , w = window ;
f = { func : f , scope : s || this } ;
if ( ! t . unloads ) {
function unload ( ) {
var li = t . unloads , o , n ;
if ( li ) {
// Call unload handlers
for ( n in li ) {
o = li [ n ] ;
if ( o && o . func )
o . func . call ( o . scope , 1 ) ; // Send in one arg to distinct unload and user destroy
}
// Detach unload function
if ( w . detachEvent ) {
w . detachEvent ( 'onbeforeunload' , fakeUnload ) ;
w . detachEvent ( 'onunload' , unload ) ;
} else if ( w . removeEventListener )
w . removeEventListener ( 'unload' , unload , false ) ;
// Destroy references
t . unloads = o = li = w = unload = 0 ;
// Run garbarge collector on IE
if ( window . CollectGarbage )
window . CollectGarbage ( ) ;
}
} ;
function fakeUnload ( ) {
var d = document ;
// Is there things still loading, then do some magic
if ( d . readyState == 'interactive' ) {
function stop ( ) {
// Prevent memory leak
d . detachEvent ( 'onstop' , stop ) ;
// Call unload handler
if ( unload )
unload ( ) ;
d = 0 ;
} ;
// Fire unload when the currently loading page is stopped
if ( d )
d . attachEvent ( 'onstop' , stop ) ;
// Remove onstop listener after a while to prevent the unload function
// to execute if the user presses cancel in an onbeforeunload
// confirm dialog and then presses the browser stop button
window . setTimeout ( function ( ) {
if ( d )
d . detachEvent ( 'onstop' , stop ) ;
} , 0 ) ;
}
} ;
// Attach unload handler
if ( w . attachEvent ) {
w . attachEvent ( 'onunload' , unload ) ;
w . attachEvent ( 'onbeforeunload' , fakeUnload ) ;
} else if ( w . addEventListener )
w . addEventListener ( 'unload' , unload , false ) ;
// Setup initial unload handler array
t . unloads = [ f ] ;
} else
t . unloads . push ( f ) ;
return f ;
} ,
removeUnload : function ( f ) {
var u = this . unloads , r = null ;
tinymce . each ( u , function ( o , i ) {
if ( o && o . func == f ) {
u . splice ( i , 1 ) ;
r = f ;
return false ;
}
} ) ;
return r ;
} ,
explode : function ( s , d ) {
return s ? tinymce . map ( s . split ( d || ',' ) , tinymce . trim ) : s ;
} ,
_addVer : function ( u ) {
var v ;
if ( ! this . query )
return u ;
v = ( u . indexOf ( '?' ) == - 1 ? '?' : '&' ) + this . query ;
if ( u . indexOf ( '#' ) == - 1 )
return u + v ;
return u . replace ( '#' , v + '#' ) ;
}
} ;
// Required for GZip AJAX loading
window . tinymce = tinymce ;
// Initialize the API
tinymce . _init ( ) ;
tinymce . create ( 'tinymce.util.Dispatcher' , {
scope : null ,
listeners : null ,
Dispatcher : function ( s ) {
this . scope = s || this ;
this . listeners = [ ] ;
} ,
add : function ( cb , s ) {
this . listeners . push ( { cb : cb , scope : s || this . scope } ) ;
return cb ;
} ,
addToTop : function ( cb , s ) {
this . listeners . unshift ( { cb : cb , scope : s || this . scope } ) ;
return cb ;
} ,
remove : function ( cb ) {
var l = this . listeners , o = null ;
tinymce . each ( l , function ( c , i ) {
if ( cb == c . cb ) {
o = cb ;
l . splice ( i , 1 ) ;
return false ;
}
} ) ;
return o ;
} ,
dispatch : function ( ) {
var s , a = arguments , i , li = this . listeners , c ;
// Needs to be a real loop since the listener count might change while looping
// And this is also more efficient
for ( i = 0 ; i < li . length ; i ++ ) {
c = li [ i ] ;
s = c . cb . apply ( c . scope , a ) ;
if ( s === false )
break ;
}
return s ;
}
} ) ;
( function ( ) {
var each = tinymce . each ;
tinymce . create ( 'tinymce.util.URI' , {
URI : function ( u , s ) {
var t = this , o , a , b ;
// Default settings
s = t . settings = s || { } ;
// Strange app protocol or local anchor
if ( /^(mailto|tel|news|javascript|about):/i . test ( u ) || /^\s*#/ . test ( u ) ) {
t . source = u ;
return ;
}
// Absolute path with no host, fake host and protocol
if ( u . indexOf ( '/' ) === 0 && u . indexOf ( '//' ) !== 0 )
u = ( s . base _uri ? s . base _uri . protocol || 'http' : 'http' ) + '://mce_host' + u ;
// Relative path
if ( u . indexOf ( ':/' ) === - 1 && u . indexOf ( '//' ) !== 0 )
u = ( s . base _uri . protocol || 'http' ) + '://mce_host' + t . toAbsPath ( s . base _uri . path , u ) ;
// Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
u = u . replace ( /@@/g , '(mce_at)' ) ; // Zope 3 workaround, they use @@something
u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ . exec ( u ) ;
each ( [ "source" , "protocol" , "authority" , "userInfo" , "user" , "password" , "host" , "port" , "relative" , "path" , "directory" , "file" , "query" , "anchor" ] , function ( v , i ) {
var s = u [ i ] ;
// Zope 3 workaround, they use @@something
if ( s )
s = s . replace ( /\(mce_at\)/g , '@@' ) ;
t [ v ] = s ;
} ) ;
if ( b = s . base _uri ) {
if ( ! t . protocol )
t . protocol = b . protocol ;
if ( ! t . userInfo )
t . userInfo = b . userInfo ;
if ( ! t . port && t . host == 'mce_host' )
t . port = b . port ;
if ( ! t . host || t . host == 'mce_host' )
t . host = b . host ;
t . source = '' ;
}
//t.path = t.path || '/';
} ,
setPath : function ( p ) {
var t = this ;
p = /^(.*?)\/?(\w+)?$/ . exec ( p ) ;
// Update path parts
t . path = p [ 0 ] ;
t . directory = p [ 1 ] ;
t . file = p [ 2 ] ;
// Rebuild source
t . source = '' ;
t . getURI ( ) ;
} ,
toRelative : function ( u ) {
var t = this , o ;
if ( u === "./" )
return u ;
u = new tinymce . util . URI ( u , { base _uri : t } ) ;
// Not on same domain/port or protocol
if ( ( u . host != 'mce_host' && t . host != u . host && u . host ) || t . port != u . port || t . protocol != u . protocol )
return u . getURI ( ) ;
o = t . toRelPath ( t . path , u . path ) ;
// Add query
if ( u . query )
o += '?' + u . query ;
// Add anchor
if ( u . anchor )
o += '#' + u . anchor ;
return o ;
} ,
toAbsolute : function ( u , nh ) {
var u = new tinymce . util . URI ( u , { base _uri : this } ) ;
return u . getURI ( this . host == u . host ? nh : 0 ) ;
} ,
toRelPath : function ( base , path ) {
var items , bp = 0 , out = '' , i , l ;
// Split the paths
base = base . substring ( 0 , base . lastIndexOf ( '/' ) ) ;
base = base . split ( '/' ) ;
items = path . split ( '/' ) ;
if ( base . length >= items . length ) {
for ( i = 0 , l = base . length ; i < l ; i ++ ) {
if ( i >= items . length || base [ i ] != items [ i ] ) {
bp = i + 1 ;
break ;
}
}
}
if ( base . length < items . length ) {
for ( i = 0 , l = items . length ; i < l ; i ++ ) {
if ( i >= base . length || base [ i ] != items [ i ] ) {
bp = i + 1 ;
break ;
}
}
}
if ( bp == 1 )
return path ;
for ( i = 0 , l = base . length - ( bp - 1 ) ; i < l ; i ++ )
out += "../" ;
for ( i = bp - 1 , l = items . length ; i < l ; i ++ ) {
if ( i != bp - 1 )
out += "/" + items [ i ] ;
else
out += items [ i ] ;
}
return out ;
} ,
toAbsPath : function ( base , path ) {
var i , nb = 0 , o = [ ] , tr ;
// Split paths
tr = /\/$/ . test ( path ) ? '/' : '' ;
base = base . split ( '/' ) ;
path = path . split ( '/' ) ;
// Remove empty chunks
each ( base , function ( k ) {
if ( k )
o . push ( k ) ;
} ) ;
base = o ;
// Merge relURLParts chunks
for ( i = path . length - 1 , o = [ ] ; i >= 0 ; i -- ) {
// Ignore empty or .
if ( path [ i ] . length == 0 || path [ i ] == "." )
continue ;
// Is parent
if ( path [ i ] == '..' ) {
nb ++ ;
continue ;
}
// Move up
if ( nb > 0 ) {
nb -- ;
continue ;
}
o . push ( path [ i ] ) ;
}
i = base . length - nb ;
// If /a/b/c or /
if ( i <= 0 )
return '/' + o . reverse ( ) . join ( '/' ) + tr ;
return '/' + base . slice ( 0 , i ) . join ( '/' ) + '/' + o . reverse ( ) . join ( '/' ) + tr ;
} ,
getURI : function ( nh ) {
var s , t = this ;
// Rebuild source
if ( ! t . source || nh ) {
s = '' ;
if ( ! nh ) {
if ( t . protocol )
s += t . protocol + '://' ;
if ( t . userInfo )
s += t . userInfo + '@' ;
if ( t . host )
s += t . host ;
if ( t . port )
s += ':' + t . port ;
}
if ( t . path )
s += t . path ;
if ( t . query )
s += '?' + t . query ;
if ( t . anchor )
s += '#' + t . anchor ;
t . source = s ;
}
return t . source ;
}
} ) ;
} ) ( ) ;
( function ( ) {
var each = tinymce . each ;
tinymce . create ( 'static tinymce.util.Cookie' , {
getHash : function ( n ) {
var v = this . get ( n ) , h ;
if ( v ) {
each ( v . split ( '&' ) , function ( v ) {
v = v . split ( '=' ) ;
h = h || { } ;
h [ unescape ( v [ 0 ] ) ] = unescape ( v [ 1 ] ) ;
} ) ;
}
return h ;
} ,
setHash : function ( n , v , e , p , d , s ) {
var o = '' ;
each ( v , function ( v , k ) {
o += ( ! o ? '' : '&' ) + escape ( k ) + '=' + escape ( v ) ;
} ) ;
this . set ( n , o , e , p , d , s ) ;
} ,
get : function ( n ) {
var c = document . cookie , e , p = n + "=" , b ;
// Strict mode
if ( ! c )
return ;
b = c . indexOf ( "; " + p ) ;
if ( b == - 1 ) {
b = c . indexOf ( p ) ;
if ( b != 0 )
return null ;
} else
b += 2 ;
e = c . indexOf ( ";" , b ) ;
if ( e == - 1 )
e = c . length ;
return unescape ( c . substring ( b + p . length , e ) ) ;
} ,
set : function ( n , v , e , p , d , s ) {
document . cookie = n + "=" + escape ( v ) +
( ( e ) ? "; expires=" + e . toGMTString ( ) : "" ) +
( ( p ) ? "; path=" + escape ( p ) : "" ) +
( ( d ) ? "; domain=" + d : "" ) +
( ( s ) ? "; secure" : "" ) ;
} ,
remove : function ( n , p ) {
var d = new Date ( ) ;
d . setTime ( d . getTime ( ) - 1000 ) ;
this . set ( n , '' , d , p , d ) ;
}
} ) ;
} ) ( ) ;
tinymce . create ( 'static tinymce.util.JSON' , {
serialize : function ( o ) {
var i , v , s = tinymce . util . JSON . serialize , t ;
if ( o == null )
return 'null' ;
t = typeof o ;
if ( t == 'string' ) {
v = '\bb\tt\nn\ff\rr\""\'\'\\\\' ;
return '"' + o . replace ( /([\u0080-\uFFFF\x00-\x1f\"])/g , function ( a , b ) {
i = v . indexOf ( b ) ;
if ( i + 1 )
return '\\' + v . charAt ( i + 1 ) ;
a = b . charCodeAt ( ) . toString ( 16 ) ;
return '\\u' + '0000' . substring ( a . length ) + a ;
} ) + '"' ;
}
if ( t == 'object' ) {
if ( o . hasOwnProperty && o instanceof Array ) {
for ( i = 0 , v = '[' ; i < o . length ; i ++ )
v += ( i > 0 ? ',' : '' ) + s ( o [ i ] ) ;
return v + ']' ;
}
v = '{' ;
for ( i in o )
v += typeof o [ i ] != 'function' ? ( v . length > 1 ? ',"' : '"' ) + i + '":' + s ( o [ i ] ) : '' ;
return v + '}' ;
}
return '' + o ;
} ,
parse : function ( s ) {
try {
return eval ( '(' + s + ')' ) ;
} catch ( ex ) {
// Ignore
}
}
} ) ;
tinymce . create ( 'static tinymce.util.XHR' , {
send : function ( o ) {
var x , t , w = window , c = 0 ;
// Default settings
o . scope = o . scope || this ;
o . success _scope = o . success _scope || o . scope ;
o . error _scope = o . error _scope || o . scope ;
o . async = o . async === false ? false : true ;
o . data = o . data || '' ;
function get ( s ) {
x = 0 ;
try {
x = new ActiveXObject ( s ) ;
} catch ( ex ) {
}
return x ;
} ;
x = w . XMLHttpRequest ? new XMLHttpRequest ( ) : get ( 'Microsoft.XMLHTTP' ) || get ( 'Msxml2.XMLHTTP' ) ;
if ( x ) {
if ( x . overrideMimeType )
x . overrideMimeType ( o . content _type ) ;
x . open ( o . type || ( o . data ? 'POST' : 'GET' ) , o . url , o . async ) ;
if ( o . content _type )
x . setRequestHeader ( 'Content-Type' , o . content _type ) ;
x . send ( o . data ) ;
function ready ( ) {
if ( ! o . async || x . readyState == 4 || c ++ > 10000 ) {
if ( o . success && c < 10000 && x . status == 200 )
o . success . call ( o . success _scope , '' + x . responseText , x , o ) ;
else if ( o . error )
o . error . call ( o . error _scope , c > 10000 ? 'TIMED_OUT' : 'GENERAL' , x , o ) ;
x = null ;
} else
w . setTimeout ( ready , 10 ) ;
} ;
// Syncronous request
if ( ! o . async )
return ready ( ) ;
// Wait for response, onReadyStateChange can not be used since it leaks memory in IE
t = w . setTimeout ( ready , 10 ) ;
}
}
} ) ;
( function ( ) {
var extend = tinymce . extend , JSON = tinymce . util . JSON , XHR = tinymce . util . XHR ;
tinymce . create ( 'tinymce.util.JSONRequest' , {
JSONRequest : function ( s ) {
this . settings = extend ( {
} , s ) ;
this . count = 0 ;
} ,
send : function ( o ) {
var ecb = o . error , scb = o . success ;
o = extend ( this . settings , o ) ;
o . success = function ( c , x ) {
c = JSON . parse ( c ) ;
if ( typeof ( c ) == 'undefined' ) {
c = {
error : 'JSON Parse error.'
} ;
}
if ( c . error )
ecb . call ( o . error _scope || o . scope , c . error , x ) ;
else
scb . call ( o . success _scope || o . scope , c . result ) ;
} ;
o . error = function ( ty , x ) {
ecb . call ( o . error _scope || o . scope , ty , x ) ;
} ;
o . data = JSON . serialize ( {
id : o . id || 'c' + ( this . count ++ ) ,
method : o . method ,
params : o . params
} ) ;
// JSON content type for Ruby on rails. Bug: #1883287
o . content _type = 'application/json' ;
XHR . send ( o ) ;
} ,
'static' : {
sendRPC : function ( o ) {
return new tinymce . util . JSONRequest ( ) . send ( o ) ;
}
}
} ) ;
} ( ) ) ; ( function ( tinymce ) {
// Shorten names
var each = tinymce . each , is = tinymce . is ;
var isWebKit = tinymce . isWebKit , isIE = tinymce . isIE ;
tinymce . create ( 'tinymce.dom.DOMUtils' , {
doc : null ,
root : null ,
files : null ,
pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/ ,
props : {
"for" : "htmlFor" ,
"class" : "className" ,
className : "className" ,
checked : "checked" ,
disabled : "disabled" ,
maxlength : "maxLength" ,
readonly : "readOnly" ,
selected : "selected" ,
value : "value" ,
id : "id" ,
name : "name" ,
type : "type"
} ,
DOMUtils : function ( d , s ) {
var t = this ;
t . doc = d ;
t . win = window ;
t . files = { } ;
t . cssFlicker = false ;
t . counter = 0 ;
t . boxModel = ! tinymce . isIE || d . compatMode == "CSS1Compat" ;
t . stdMode = d . documentMode === 8 ;
this . settings = s = tinymce . extend ( {
keep _values : false ,
hex _colors : 1 ,
process _html : 1
} , s ) ;
// Fix IE6SP2 flicker and check it failed for pre SP2
if ( tinymce . isIE6 ) {
try {
d . execCommand ( 'BackgroundImageCache' , false , true ) ;
} catch ( e ) {
t . cssFlicker = true ;
}
}
tinymce . addUnload ( t . destroy , t ) ;
} ,
getRoot : function ( ) {
var t = this , s = t . settings ;
return ( s && t . get ( s . root _element ) ) || t . doc . body ;
} ,
getViewPort : function ( w ) {
var d , b ;
w = ! w ? this . win : w ;
d = w . document ;
b = this . boxModel ? d . documentElement : d . body ;
// Returns viewport size excluding scrollbars
return {
x : w . pageXOffset || b . scrollLeft ,
y : w . pageYOffset || b . scrollTop ,
w : w . innerWidth || b . clientWidth ,
h : w . innerHeight || b . clientHeight
} ;
} ,
getRect : function ( e ) {
var p , t = this , sr ;
e = t . get ( e ) ;
p = t . getPos ( e ) ;
sr = t . getSize ( e ) ;
return {
x : p . x ,
y : p . y ,
w : sr . w ,
h : sr . h
} ;
} ,
getSize : function ( e ) {
var t = this , w , h ;
e = t . get ( e ) ;
w = t . getStyle ( e , 'width' ) ;
h = t . getStyle ( e , 'height' ) ;
// Non pixel value, then force offset/clientWidth
if ( w . indexOf ( 'px' ) === - 1 )
w = 0 ;
// Non pixel value, then force offset/clientWidth
if ( h . indexOf ( 'px' ) === - 1 )
h = 0 ;
return {
w : parseInt ( w ) || e . offsetWidth || e . clientWidth ,
h : parseInt ( h ) || e . offsetHeight || e . clientHeight
} ;
} ,
is : function ( n , patt ) {
return tinymce . dom . Sizzle . matches ( patt , n . nodeType ? [ n ] : n ) . length > 0 ;
} ,
getParent : function ( n , f , r ) {
return this . getParents ( n , f , r , false ) ;
} ,
getParents : function ( n , f , r , c ) {
var t = this , na , se = t . settings , o = [ ] ;
n = t . get ( n ) ;
c = c === undefined ;
if ( se . strict _root )
r = r || t . getRoot ( ) ;
// Wrap node name as func
if ( is ( f , 'string' ) ) {
na = f ;
if ( f === '*' ) {
f = function ( n ) { return n . nodeType == 1 ; } ;
} else {
f = function ( n ) {
return t . is ( n , na ) ;
} ;
}
}
while ( n ) {
if ( n == r || ! n . nodeType || n . nodeType === 9 )
break ;
if ( ! f || f ( n ) ) {
if ( c )
o . push ( n ) ;
else
return n ;
}
n = n . parentNode ;
}
return c ? o : null ;
} ,
get : function ( e ) {
var n ;
if ( e && this . doc && typeof ( e ) == 'string' ) {
n = e ;
e = this . doc . getElementById ( e ) ;
// IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
if ( e && e . id !== n )
return this . doc . getElementsByName ( n ) [ 1 ] ;
}
return e ;
} ,
select : function ( pa , s ) {
var t = this ;
return tinymce . dom . Sizzle ( pa , t . get ( s ) || t . get ( t . settings . root _element ) || t . doc , [ ] ) ;
} ,
add : function ( p , n , a , h , c ) {
var t = this ;
return this . run ( p , function ( p ) {
var e , k ;
e = is ( n , 'string' ) ? t . doc . createElement ( n ) : n ;
t . setAttribs ( e , a ) ;
if ( h ) {
if ( h . nodeType )
e . appendChild ( h ) ;
else
t . setHTML ( e , h ) ;
}
return ! c ? p . appendChild ( e ) : e ;
} ) ;
} ,
create : function ( n , a , h ) {
return this . add ( this . doc . createElement ( n ) , n , a , h , 1 ) ;
} ,
createHTML : function ( n , a , h ) {
var o = '' , t = this , k ;
o += '<' + n ;
for ( k in a ) {
if ( a . hasOwnProperty ( k ) )
o += ' ' + k + '="' + t . encode ( a [ k ] ) + '"' ;
}
if ( tinymce . is ( h ) )
return o + '>' + h + '</' + n + '>' ;
return o + ' />' ;
} ,
remove : function ( n , k ) {
var t = this ;
return this . run ( n , function ( n ) {
var p , g , i ;
p = n . parentNode ;
if ( ! p )
return null ;
if ( k ) {
for ( i = n . childNodes . length - 1 ; i >= 0 ; i -- )
t . insertAfter ( n . childNodes [ i ] , n ) ;
//each(n.childNodes, function(c) {
// p.insertBefore(c.cloneNode(true), n);
//});
}
// Fix IE psuedo leak
if ( t . fixPsuedoLeaks ) {
p = n . cloneNode ( true ) ;
k = 'IELeakGarbageBin' ;
g = t . get ( k ) || t . add ( t . doc . body , 'div' , { id : k , style : 'display:none' } ) ;
g . appendChild ( n ) ;
g . innerHTML = '' ;
return p ;
}
return p . removeChild ( n ) ;
} ) ;
} ,
setStyle : function ( n , na , v ) {
var t = this ;
return t . run ( n , function ( e ) {
var s , i ;
s = e . style ;
// Camelcase it, if needed
na = na . replace ( /-(\D)/g , function ( a , b ) {
return b . toUpperCase ( ) ;
} ) ;
// Default px suffix on these
if ( t . pixelStyles . test ( na ) && ( tinymce . is ( v , 'number' ) || /^[\-0-9\.]+$/ . test ( v ) ) )
v += 'px' ;
switch ( na ) {
case 'opacity' :
// IE specific opacity
if ( isIE ) {
s . filter = v === '' ? '' : "alpha(opacity=" + ( v * 100 ) + ")" ;
if ( ! n . currentStyle || ! n . currentStyle . hasLayout )
s . display = 'inline-block' ;
}
// Fix for older browsers
s [ na ] = s [ '-moz-opacity' ] = s [ '-khtml-opacity' ] = v || '' ;
break ;
case 'float' :
isIE ? s . styleFloat = v : s . cssFloat = v ;
break ;
default :
s [ na ] = v || '' ;
}
// Force update of the style data
if ( t . settings . update _styles )
t . setAttrib ( e , 'mce_style' ) ;
} ) ;
} ,
getStyle : function ( n , na , c ) {
n = this . get ( n ) ;
if ( ! n )
return false ;
// Gecko
if ( this . doc . defaultView && c ) {
// Remove camelcase
na = na . replace ( /[A-Z]/g , function ( a ) {
return '-' + a ;
} ) ;
try {
return this . doc . defaultView . getComputedStyle ( n , null ) . getPropertyValue ( na ) ;
} catch ( ex ) {
// Old safari might fail
return null ;
}
}
// Camelcase it, if needed
na = na . replace ( /-(\D)/g , function ( a , b ) {
return b . toUpperCase ( ) ;
} ) ;
if ( na == 'float' )
na = isIE ? 'styleFloat' : 'cssFloat' ;
// IE & Opera
if ( n . currentStyle && c )
return n . currentStyle [ na ] ;
return n . style [ na ] ;
} ,
setStyles : function ( e , o ) {
var t = this , s = t . settings , ol ;
ol = s . update _styles ;
s . update _styles = 0 ;
each ( o , function ( v , n ) {
t . setStyle ( e , n , v ) ;
} ) ;
// Update style info
s . update _styles = ol ;
if ( s . update _styles )
t . setAttrib ( e , s . cssText ) ;
} ,
setAttrib : function ( e , n , v ) {
var t = this ;
// Whats the point
if ( ! e || ! n )
return ;
// Strict XML mode
if ( t . settings . strict )
n = n . toLowerCase ( ) ;
return this . run ( e , function ( e ) {
var s = t . settings ;
switch ( n ) {
case "style" :
if ( ! is ( v , 'string' ) ) {
each ( v , function ( v , n ) {
t . setStyle ( e , n , v ) ;
} ) ;
return ;
}
// No mce_style for elements with these since they might get resized by the user
if ( s . keep _values ) {
if ( v && ! t . _isRes ( v ) )
e . setAttribute ( 'mce_style' , v , 2 ) ;
else
e . removeAttribute ( 'mce_style' , 2 ) ;
}
e . style . cssText = v ;
break ;
case "class" :
e . className = v || '' ; // Fix IE null bug
break ;
case "src" :
case "href" :
if ( s . keep _values ) {
if ( s . url _converter )
v = s . url _converter . call ( s . url _converter _scope || t , v , n , e ) ;
t . setAttrib ( e , 'mce_' + n , v , 2 ) ;
}
break ;
case "shape" :
e . setAttribute ( 'mce_style' , v ) ;
break ;
}
if ( is ( v ) && v !== null && v . length !== 0 )
e . setAttribute ( n , '' + v , 2 ) ;
else
e . removeAttribute ( n , 2 ) ;
} ) ;
} ,
setAttribs : function ( e , o ) {
var t = this ;
return this . run ( e , function ( e ) {
each ( o , function ( v , n ) {
t . setAttrib ( e , n , v ) ;
} ) ;
} ) ;
} ,
getAttrib : function ( e , n , dv ) {
var v , t = this ;
e = t . get ( e ) ;
if ( ! e || e . nodeType !== 1 )
return false ;
if ( ! is ( dv ) )
dv = '' ;
// Try the mce variant for these
if ( /^(src|href|style|coords|shape)$/ . test ( n ) ) {
v = e . getAttribute ( "mce_" + n ) ;
if ( v )
return v ;
}
if ( isIE && t . props [ n ] ) {
v = e [ t . props [ n ] ] ;
v = v && v . nodeValue ? v . nodeValue : v ;
}
if ( ! v )
v = e . getAttribute ( n , 2 ) ;
if ( n === 'style' ) {
v = v || e . style . cssText ;
if ( v ) {
v = t . serializeStyle ( t . parseStyle ( v ) ) ;
if ( t . settings . keep _values && ! t . _isRes ( v ) )
e . setAttribute ( 'mce_style' , v ) ;
}
}
// Remove Apple and WebKit stuff
if ( isWebKit && n === "class" && v )
v = v . replace ( /(apple|webkit)\-[a-z\-]+/gi , '' ) ;
// Handle IE issues
if ( isIE ) {
switch ( n ) {
case 'rowspan' :
case 'colspan' :
// IE returns 1 as default value
if ( v === 1 )
v = '' ;
break ;
case 'size' :
// IE returns +0 as default value for size
if ( v === '+0' || v === 20 || v === 0 )
v = '' ;
break ;
case 'width' :
case 'height' :
case 'vspace' :
case 'checked' :
case 'disabled' :
case 'readonly' :
if ( v === 0 )
v = '' ;
break ;
case 'hspace' :
// IE returns -1 as default value
if ( v === - 1 )
v = '' ;
break ;
case 'maxlength' :
case 'tabindex' :
// IE returns default value
if ( v === 32768 || v === 2147483647 || v === '32768' )
v = '' ;
break ;
case 'multiple' :
case 'compact' :
case 'noshade' :
case 'nowrap' :
if ( v === 65535 )
return n ;
return dv ;
case 'shape' :
v = v . toLowerCase ( ) ;
break ;
default :
// IE has odd anonymous function for event attributes
if ( n . indexOf ( 'on' ) === 0 && v )
v = ( '' + v ) . replace ( /^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/ , '$1' ) ;
}
}
return ( v !== undefined && v !== null && v !== '' ) ? '' + v : dv ;
} ,
getPos : function ( n , ro ) {
var t = this , x = 0 , y = 0 , e , d = t . doc , r ;
n = t . get ( n ) ;
ro = ro || d . body ;
if ( n ) {
// Use getBoundingClientRect on IE, Opera has it but it's not perfect
if ( isIE && ! t . stdMode ) {
n = n . getBoundingClientRect ( ) ;
e = t . boxModel ? d . documentElement : d . body ;
x = t . getStyle ( t . select ( 'html' ) [ 0 ] , 'borderWidth' ) ; // Remove border
x = ( x == 'medium' || t . boxModel && ! t . isIE6 ) && 2 || x ;
n . top += t . win . self != t . win . top ? 2 : 0 ; // IE adds some strange extra cord if used in a frameset
return { x : n . left + e . scrollLeft - x , y : n . top + e . scrollTop - x } ;
}
r = n ;
while ( r && r != ro && r . nodeType ) {
x += r . offsetLeft || 0 ;
y += r . offsetTop || 0 ;
r = r . offsetParent ;
}
r = n . parentNode ;
while ( r && r != ro && r . nodeType ) {
x -= r . scrollLeft || 0 ;
y -= r . scrollTop || 0 ;
r = r . parentNode ;
}
}
return { x : x , y : y } ;
} ,
parseStyle : function ( st ) {
var t = this , s = t . settings , o = { } ;
if ( ! st )
return o ;
function compress ( p , s , ot ) {
var t , r , b , l ;
// Get values and check it it needs compressing
t = o [ p + '-top' + s ] ;
if ( ! t )
return ;
r = o [ p + '-right' + s ] ;
if ( t != r )
return ;
b = o [ p + '-bottom' + s ] ;
if ( r != b )
return ;
l = o [ p + '-left' + s ] ;
if ( b != l )
return ;
// Compress
o [ ot ] = l ;
delete o [ p + '-top' + s ] ;
delete o [ p + '-right' + s ] ;
delete o [ p + '-bottom' + s ] ;
delete o [ p + '-left' + s ] ;
} ;
function compress2 ( ta , a , b , c ) {
var t ;
t = o [ a ] ;
if ( ! t )
return ;
t = o [ b ] ;
if ( ! t )
return ;
t = o [ c ] ;
if ( ! t )
return ;
// Compress
o [ ta ] = o [ a ] + ' ' + o [ b ] + ' ' + o [ c ] ;
delete o [ a ] ;
delete o [ b ] ;
delete o [ c ] ;
} ;
st = st . replace ( /&(#?[a-z0-9]+);/g , '&$1_MCE_SEMI_' ) ; // Protect entities
each ( st . split ( ';' ) , function ( v ) {
var sv , ur = [ ] ;
if ( v ) {
v = v . replace ( /_MCE_SEMI_/g , ';' ) ; // Restore entities
v = v . replace ( /url\([^\)]+\)/g , function ( v ) { ur . push ( v ) ; return 'url(' + ur . length + ')' ; } ) ;
v = v . split ( ':' ) ;
sv = tinymce . trim ( v [ 1 ] ) ;
sv = sv . replace ( /url\(([^\)]+)\)/g , function ( a , b ) { return ur [ parseInt ( b ) - 1 ] ; } ) ;
sv = sv . replace ( /rgb\([^\)]+\)/g , function ( v ) {
return t . toHex ( v ) ;
} ) ;
if ( s . url _converter ) {
sv = sv . replace ( /url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g , function ( x , c ) {
return 'url(' + s . url _converter . call ( s . url _converter _scope || t , t . decode ( c ) , 'style' , null ) + ')' ;
} ) ;
}
o [ tinymce . trim ( v [ 0 ] ) . toLowerCase ( ) ] = sv ;
}
} ) ;
compress ( "border" , "" , "border" ) ;
compress ( "border" , "-width" , "border-width" ) ;
compress ( "border" , "-color" , "border-color" ) ;
compress ( "border" , "-style" , "border-style" ) ;
compress ( "padding" , "" , "padding" ) ;
compress ( "margin" , "" , "margin" ) ;
compress2 ( 'border' , 'border-width' , 'border-style' , 'border-color' ) ;
if ( isIE ) {
// Remove pointless border
if ( o . border == 'medium none' )
o . border = '' ;
}
return o ;
} ,
serializeStyle : function ( o ) {
var s = '' ;
each ( o , function ( v , k ) {
if ( k && v ) {
if ( tinymce . isGecko && k . indexOf ( '-moz-' ) === 0 )
return ;
switch ( k ) {
case 'color' :
case 'background-color' :
v = v . toLowerCase ( ) ;
break ;
}
s += ( s ? ' ' : '' ) + k + ': ' + v + ';' ;
}
} ) ;
return s ;
} ,
loadCSS : function ( u ) {
var t = this , d = t . doc ;
if ( ! u )
u = '' ;
each ( u . split ( ',' ) , function ( u ) {
if ( t . files [ u ] )
return ;
t . files [ u ] = true ;
t . add ( t . select ( 'head' ) [ 0 ] , 'link' , { rel : 'stylesheet' , href : tinymce . _addVer ( u ) } ) ;
} ) ;
} ,
addClass : function ( e , c ) {
return this . run ( e , function ( e ) {
var o ;
if ( ! c )
return 0 ;
if ( this . hasClass ( e , c ) )
return e . className ;
o = this . removeClass ( e , c ) ;
return e . className = ( o != '' ? ( o + ' ' ) : '' ) + c ;
} ) ;
} ,
removeClass : function ( e , c ) {
var t = this , re ;
return t . run ( e , function ( e ) {
var v ;
if ( t . hasClass ( e , c ) ) {
if ( ! re )
re = new RegExp ( "(^|\\s+)" + c + "(\\s+|$)" , "g" ) ;
v = e . className . replace ( re , ' ' ) ;
return e . className = tinymce . trim ( v != ' ' ? v : '' ) ;
}
return e . className ;
} ) ;
} ,
hasClass : function ( n , c ) {
n = this . get ( n ) ;
if ( ! n || ! c )
return false ;
return ( ' ' + n . className + ' ' ) . indexOf ( ' ' + c + ' ' ) !== - 1 ;
} ,
show : function ( e ) {
return this . setStyle ( e , 'display' , 'block' ) ;
} ,
hide : function ( e ) {
return this . setStyle ( e , 'display' , 'none' ) ;
} ,
isHidden : function ( e ) {
e = this . get ( e ) ;
return ! e || e . style . display == 'none' || this . getStyle ( e , 'display' ) == 'none' ;
} ,
uniqueId : function ( p ) {
return ( ! p ? 'mce_' : p ) + ( this . counter ++ ) ;
} ,
setHTML : function ( e , h ) {
var t = this ;
return this . run ( e , function ( e ) {
var x , i , nl , n , p , x ;
h = t . processHTML ( h ) ;
if ( isIE ) {
function set ( ) {
try {
// IE will remove comments from the beginning
// unless you padd the contents with something
e . innerHTML = '<br />' + h ;
e . removeChild ( e . firstChild ) ;
} catch ( ex ) {
// IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p
// This seems to fix this problem
// Remove all child nodes
while ( e . firstChild )
e . firstChild . removeNode ( ) ;
// Create new div with HTML contents and a BR infront to keep comments
x = t . create ( 'div' ) ;
x . innerHTML = '<br />' + h ;
// Add all children from div to target
each ( x . childNodes , function ( n , i ) {
// Skip br element
if ( i )
e . appendChild ( n ) ;
} ) ;
}
} ;
// IE has a serious bug when it comes to paragraphs it can produce an invalid
// DOM tree if contents like this <p><ul><li>Item 1</li></ul></p> is inserted
// It seems to be that IE doesn't like a root block element placed inside another root block element
if ( t . settings . fix _ie _paragraphs )
h = h . replace ( /<p><\/p>|<p([^>]+)><\/p>|<p[^\/+]\/>/gi , '<p$1 mce_keep="true"> </p>' ) ;
set ( ) ;
if ( t . settings . fix _ie _paragraphs ) {
// Check for odd paragraphs this is a sign of a broken DOM
nl = e . getElementsByTagName ( "p" ) ;
for ( i = nl . length - 1 , x = 0 ; i >= 0 ; i -- ) {
n = nl [ i ] ;
if ( ! n . hasChildNodes ( ) ) {
if ( ! n . mce _keep ) {
x = 1 ; // Is broken
break ;
}
n . removeAttribute ( 'mce_keep' ) ;
}
}
}
// Time to fix the madness IE left us
if ( x ) {
// So if we replace the p elements with divs and mark them and then replace them back to paragraphs
// after we use innerHTML we can fix the DOM tree
h = h . replace ( /<p ([^>]+)>|<p>/g , '<div $1 mce_tmp="1">' ) ;
h = h . replace ( /<\/p>/g , '</div>' ) ;
// Set the new HTML with DIVs
set ( ) ;
// Replace all DIV elements with he mce_tmp attibute back to paragraphs
// This is needed since IE has a annoying bug see above for details
// This is a slow process but it has to be done. :(
if ( t . settings . fix _ie _paragraphs ) {
nl = e . getElementsByTagName ( "DIV" ) ;
for ( i = nl . length - 1 ; i >= 0 ; i -- ) {
n = nl [ i ] ;
// Is it a temp div
if ( n . mce _tmp ) {
// Create new paragraph
p = t . doc . createElement ( 'p' ) ;
// Copy all attributes
n . cloneNode ( false ) . outerHTML . replace ( /([a-z0-9\-_]+)=/gi , function ( a , b ) {
var v ;
if ( b !== 'mce_tmp' ) {
v = n . getAttribute ( b ) ;
if ( ! v && b === 'class' )
v = n . className ;
p . setAttribute ( b , v ) ;
}
} ) ;
// Append all children to new paragraph
for ( x = 0 ; x < n . childNodes . length ; x ++ )
p . appendChild ( n . childNodes [ x ] . cloneNode ( true ) ) ;
// Replace div with new paragraph
n . swapNode ( p ) ;
}
}
}
}
} else
e . innerHTML = h ;
return h ;
} ) ;
} ,
processHTML : function ( h ) {
var t = this , s = t . settings ;
if ( ! s . process _html )
return h ;
// Convert strong and em to b and i in FF since it can't handle them
if ( tinymce . isGecko ) {
h = h . replace ( /<(\/?)strong>|<strong( [^>]+)>/gi , '<$1b$2>' ) ;
h = h . replace ( /<(\/?)em>|<em( [^>]+)>/gi , '<$1i$2>' ) ;
} else if ( isIE ) {
h = h . replace ( /'/g , ''' ) ; // IE can't handle apos
h = h . replace ( /\s+(disabled|checked|readonly|selected)\s*=\s*[\"\']?(false|0)[\"\']?/gi , '' ) ; // IE doesn't handle default values correct
}
// Fix some issues
h = h . replace ( /<a( )([^>]+)\/>|<a\/>/gi , '<a$1$2></a>' ) ; // Force open
// Store away src and href in mce_src and mce_href since browsers mess them up
if ( s . keep _values ) {
// Wrap scripts and styles in comments for serialization purposes
if ( /<script|style/ . test ( h ) ) {
function trim ( s ) {
// Remove prefix and suffix code for element
s = s . replace ( /(<!--\[CDATA\[|\]\]-->)/g , '\n' ) ;
s = s . replace ( /^[\r\n]*|[\r\n]*$/g , '' ) ;
s = s . replace ( /^\s*(\/\/\s*<!--|\/\/\s*<!\[CDATA\[|<!--|<!\[CDATA\[)[\r\n]*/g , '' ) ;
s = s . replace ( /\s*(\/\/\s*\]\]>|\/\/\s*-->|\]\]>|-->|\]\]-->)\s*$/g , '' ) ;
return s ;
} ;
// Preserve script elements
h = h . replace ( /<script([^>]+|)>([\s\S]*?)<\/script>/g , function ( v , a , b ) {
// Remove prefix and suffix code for script element
b = trim ( b ) ;
// Force type attribute
if ( ! a )
a = ' type="text/javascript"' ;
// Wrap contents in a comment
if ( b )
b = '<!--\n' + b + '\n// -->' ;
// Output fake element
return '<mce:script' + a + '>' + b + '</mce:script>' ;
} ) ;
// Preserve style elements
h = h . replace ( /<style([^>]+|)>([\s\S]*?)<\/style>/g , function ( v , a , b ) {
b = trim ( b ) ;
return '<mce:style' + a + '><!--\n' + b + '\n--></mce:style><style' + a + ' mce_bogus="1">' + b + '</style>' ;
} ) ;
}
h = h . replace ( /<!\[CDATA\[([\s\S]+)\]\]>/g , '<!--[CDATA[$1]]-->' ) ;
// Process all tags with src, href or style
h = h . replace ( /<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi , function ( a , n ) {
function handle ( m , b , c ) {
var u = c ;
// Tag already got a mce_ version
if ( a . indexOf ( 'mce_' + b ) != - 1 )
return m ;
if ( b == 'style' ) {
// No mce_style for elements with these since they might get resized by the user
if ( t . _isRes ( c ) )
return m ;
if ( s . hex _colors ) {
u = u . replace ( /rgb\([^\)]+\)/g , function ( v ) {
return t . toHex ( v ) ;
} ) ;
}
if ( s . url _converter ) {
u = u . replace ( /url\([\'\"]?([^\)\'\"]+)\)/g , function ( x , c ) {
return 'url(' + t . encode ( s . url _converter . call ( s . url _converter _scope || t , t . decode ( c ) , b , n ) ) + ')' ;
} ) ;
}
} else if ( b != 'coords' && b != 'shape' ) {
if ( s . url _converter )
u = t . encode ( s . url _converter . call ( s . url _converter _scope || t , t . decode ( c ) , b , n ) ) ;
}
return ' ' + b + '="' + c + '" mce_' + b + '="' + u + '"' ;
} ;
a = a . replace ( / (src|href|style|coords|shape)=[\"]([^\"]+)[\"]/gi , handle ) ; // W3C
a = a . replace ( / (src|href|style|coords|shape)=[\']([^\']+)[\']/gi , handle ) ; // W3C
return a . replace ( / (src|href|style|coords|shape)=([^\s\"\'>]+)/gi , handle ) ; // IE
} ) ;
}
return h ;
} ,
getOuterHTML : function ( e ) {
var d ;
e = this . get ( e ) ;
if ( ! e )
return null ;
if ( e . outerHTML !== undefined )
return e . outerHTML ;
d = ( e . ownerDocument || this . doc ) . createElement ( "body" ) ;
d . appendChild ( e . cloneNode ( true ) ) ;
return d . innerHTML ;
} ,
setOuterHTML : function ( e , h , d ) {
var t = this ;
return this . run ( e , function ( e ) {
var n , tp ;
e = t . get ( e ) ;
d = d || e . ownerDocument || t . doc ;
if ( isIE && e . nodeType == 1 )
e . outerHTML = h ;
else {
tp = d . createElement ( "body" ) ;
tp . innerHTML = h ;
n = tp . lastChild ;
while ( n ) {
t . insertAfter ( n . cloneNode ( true ) , e ) ;
n = n . previousSibling ;
}
t . remove ( e ) ;
}
} ) ;
} ,
decode : function ( s ) {
var e , n , v ;
// Look for entities to decode
if ( /&[^;]+;/ . test ( s ) ) {
// Decode the entities using a div element not super efficient but less code
e = this . doc . createElement ( "div" ) ;
e . innerHTML = s ;
n = e . firstChild ;
v = '' ;
if ( n ) {
do {
v += n . nodeValue ;
} while ( n . nextSibling ) ;
}
return v || s ;
}
return s ;
} ,
encode : function ( s ) {
return s ? ( '' + s ) . replace ( /[<>&\"]/g , function ( c , b ) {
switch ( c ) {
case '&' :
return '&' ;
case '"' :
return '"' ;
case '<' :
return '<' ;
case '>' :
return '>' ;
}
return c ;
} ) : s ;
} ,
insertAfter : function ( n , r ) {
var t = this ;
r = t . get ( r ) ;
return this . run ( n , function ( n ) {
var p , ns ;
p = r . parentNode ;
ns = r . nextSibling ;
if ( ns )
p . insertBefore ( n , ns ) ;
else
p . appendChild ( n ) ;
return n ;
} ) ;
} ,
isBlock : function ( n ) {
if ( n . nodeType && n . nodeType !== 1 )
return false ;
n = n . nodeName || n ;
return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TR|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/ . test ( n ) ;
} ,
replace : function ( n , o , k ) {
var t = this ;
if ( is ( o , 'array' ) )
n = n . cloneNode ( true ) ;
return t . run ( o , function ( o ) {
if ( k ) {
each ( o . childNodes , function ( c ) {
n . appendChild ( c . cloneNode ( true ) ) ;
} ) ;
}
// Fix IE psuedo leak for elements since replacing elements if fairly common
// Will break parentNode for some unknown reason
if ( t . fixPsuedoLeaks && o . nodeType === 1 ) {
o . parentNode . insertBefore ( n , o ) ;
t . remove ( o ) ;
return n ;
}
return o . parentNode . replaceChild ( n , o ) ;
} ) ;
} ,
findCommonAncestor : function ( a , b ) {
var ps = a , pe ;
while ( ps ) {
pe = b ;
while ( pe && ps != pe )
pe = pe . parentNode ;
if ( ps == pe )
break ;
ps = ps . parentNode ;
}
if ( ! ps && a . ownerDocument )
return a . ownerDocument . documentElement ;
return ps ;
} ,
toHex : function ( s ) {
var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i . exec ( s ) ;
function hex ( s ) {
s = parseInt ( s ) . toString ( 16 ) ;
return s . length > 1 ? s : '0' + s ; // 0 -> 00
} ;
if ( c ) {
s = '#' + hex ( c [ 1 ] ) + hex ( c [ 2 ] ) + hex ( c [ 3 ] ) ;
return s ;
}
return s ;
} ,
getClasses : function ( ) {
var t = this , cl = [ ] , i , lo = { } , f = t . settings . class _filter , ov ;
if ( t . classes )
return t . classes ;
function addClasses ( s ) {
// IE style imports
each ( s . imports , function ( r ) {
addClasses ( r ) ;
} ) ;
each ( s . cssRules || s . rules , function ( r ) {
// Real type or fake it on IE
switch ( r . type || 1 ) {
// Rule
case 1 :
if ( r . selectorText ) {
each ( r . selectorText . split ( ',' ) , function ( v ) {
v = v . replace ( /^\s*|\s*$|^\s\./g , "" ) ;
// Is internal or it doesn't contain a class
if ( /\.mce/ . test ( v ) || ! /\.[\w\-]+$/ . test ( v ) )
return ;
// Remove everything but class name
ov = v ;
v = v . replace ( /.*\.([a-z0-9_\-]+).*/i , '$1' ) ;
// Filter classes
if ( f && ! ( v = f ( v , ov ) ) )
return ;
if ( ! lo [ v ] ) {
cl . push ( { 'class' : v } ) ;
lo [ v ] = 1 ;
}
} ) ;
}
break ;
// Import
case 3 :
addClasses ( r . styleSheet ) ;
break ;
}
} ) ;
} ;
try {
each ( t . doc . styleSheets , addClasses ) ;
} catch ( ex ) {
// Ignore
}
if ( cl . length > 0 )
t . classes = cl ;
return cl ;
} ,
run : function ( e , f , s ) {
var t = this , o ;
if ( t . doc && typeof ( e ) === 'string' )
e = t . get ( e ) ;
if ( ! e )
return false ;
s = s || this ;
if ( ! e . nodeType && ( e . length || e . length === 0 ) ) {
o = [ ] ;
each ( e , function ( e , i ) {
if ( e ) {
if ( typeof ( e ) == 'string' )
e = t . doc . getElementById ( e ) ;
o . push ( f . call ( s , e , i ) ) ;
}
} ) ;
return o ;
}
return f . call ( s , e ) ;
} ,
getAttribs : function ( n ) {
var o ;
n = this . get ( n ) ;
if ( ! n )
return [ ] ;
if ( isIE ) {
o = [ ] ;
// Object will throw exception in IE
if ( n . nodeName == 'OBJECT' )
return n . attributes ;
// It's crazy that this is faster in IE but it's because it returns all attributes all the time
n . cloneNode ( false ) . outerHTML . replace ( /([a-z0-9\:\-_]+)=/gi , function ( a , b ) {
o . push ( { specified : 1 , nodeName : b } ) ;
} ) ;
return o ;
}
return n . attributes ;
} ,
destroy : function ( s ) {
var t = this ;
t . win = t . doc = t . root = null ;
// Manual destroy then remove unload handler
if ( ! s )
tinymce . removeUnload ( t . destroy ) ;
} ,
createRng : function ( ) {
var d = this . doc ;
return d . createRange ? d . createRange ( ) : new tinymce . dom . Range ( this ) ;
} ,
split : function ( pe , e , re ) {
var t = this , r = t . createRng ( ) , bef , aft , pa ;
// W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sence
// but we don't want that in our code since it serves no purpose
// For example if this is chopped:
// <p>text 1<span><b>CHOP</b></span>text 2</p>
// would produce:
// <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p>
// this function will then trim of empty edges and produce:
// <p>text 1</p><b>CHOP</b><p>text 2</p>
function trimEdge ( n , na ) {
n = n [ na ] ;
if ( n && n [ na ] && n [ na ] . nodeType == 1 && isEmpty ( n [ na ] ) )
t . remove ( n [ na ] ) ;
} ;
function isEmpty ( n ) {
n = t . getOuterHTML ( n ) ;
n = n . replace ( /<(img|hr|table)/gi , '-' ) ; // Keep these convert them to - chars
n = n . replace ( /<[^>]+>/g , '' ) ; // Remove all tags
return n . replace ( /[ \t\r\n]+| | /g , '' ) == '' ;
} ;
if ( pe && e ) {
// Get before chunk
r . setStartBefore ( pe ) ;
r . setEndBefore ( e ) ;
bef = r . extractContents ( ) ;
// Get after chunk
r = t . createRng ( ) ;
r . setStartAfter ( e ) ;
r . setEndAfter ( pe ) ;
aft = r . extractContents ( ) ;
// Insert chunks and remove parent
pa = pe . parentNode ;
// Remove right side edge of the before contents
trimEdge ( bef , 'lastChild' ) ;
if ( ! isEmpty ( bef ) )
pa . insertBefore ( bef , pe ) ;
if ( re )
pa . replaceChild ( re , e ) ;
else
pa . insertBefore ( e , pe ) ;
// Remove left site edge of the after contents
trimEdge ( aft , 'firstChild' ) ;
if ( ! isEmpty ( aft ) )
pa . insertBefore ( aft , pe ) ;
t . remove ( pe ) ;
return re || e ;
}
} ,
_isRes : function ( c ) {
// Is live resizble element
return /^(top|left|bottom|right|width|height)/i . test ( c ) || /;\s*(top|left|bottom|right|width|height)/i . test ( c ) ;
}
/ *
walk : function ( n , f , s ) {
var d = this . doc , w ;
if ( d . createTreeWalker ) {
w = d . createTreeWalker ( n , NodeFilter . SHOW _TEXT , null , false ) ;
while ( ( n = w . nextNode ( ) ) != null )
f . call ( s || this , n ) ;
} else
tinymce . walk ( n , f , 'childNodes' , s ) ;
}
* /
/ *
toRGB : function ( s ) {
var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/ . exec ( s ) ;
if ( c ) {
// #FFF -> #FFFFFF
if ( ! is ( c [ 3 ] ) )
c [ 3 ] = c [ 2 ] = c [ 1 ] ;
return "rgb(" + parseInt ( c [ 1 ] , 16 ) + "," + parseInt ( c [ 2 ] , 16 ) + "," + parseInt ( c [ 3 ] , 16 ) + ")" ;
}
return s ;
}
* /
} ) ;
// Setup page DOM
tinymce . DOM = new tinymce . dom . DOMUtils ( document , { process _html : 0 } ) ;
} ) ( tinymce ) ;
( function ( ns ) {
// Traverse constants
var EXTRACT = 0 , CLONE = 1 , DELETE = 2 , extend = tinymce . extend ;
function indexOf ( child , parent ) {
var i , node ;
if ( child . parentNode != parent )
return - 1 ;
for ( node = parent . firstChild , i = 0 ; node != child ; node = node . nextSibling )
i ++ ;
return i ;
} ;
function nodeIndex ( n ) {
var i = 0 ;
while ( n . previousSibling ) {
i ++ ;
n = n . previousSibling ;
}
return i ;
} ;
function getSelectedNode ( container , offset ) {
var child ;
if ( container . nodeType == 3 /* TEXT_NODE */ )
return container ;
if ( offset < 0 )
return container ;
child = container . firstChild ;
while ( child != null && offset > 0 ) {
-- offset ;
child = child . nextSibling ;
}
if ( child != null )
return child ;
return container ;
} ;
// Range constructor
function Range ( dom ) {
var d = dom . doc ;
extend ( this , {
dom : dom ,
// Inital states
startContainer : d ,
startOffset : 0 ,
endContainer : d ,
endOffset : 0 ,
collapsed : true ,
commonAncestorContainer : d ,
// Range constants
START _TO _START : 0 ,
START _TO _END : 1 ,
END _TO _END : 2 ,
END _TO _START : 3
} ) ;
} ;
// Add range methods
extend ( Range . prototype , {
setStart : function ( n , o ) {
this . _setEndPoint ( true , n , o ) ;
} ,
setEnd : function ( n , o ) {
this . _setEndPoint ( false , n , o ) ;
} ,
setStartBefore : function ( n ) {
this . setStart ( n . parentNode , nodeIndex ( n ) ) ;
} ,
setStartAfter : function ( n ) {
this . setStart ( n . parentNode , nodeIndex ( n ) + 1 ) ;
} ,
setEndBefore : function ( n ) {
this . setEnd ( n . parentNode , nodeIndex ( n ) ) ;
} ,
setEndAfter : function ( n ) {
this . setEnd ( n . parentNode , nodeIndex ( n ) + 1 ) ;
} ,
collapse : function ( ts ) {
var t = this ;
if ( ts ) {
t . endContainer = t . startContainer ;
t . endOffset = t . startOffset ;
} else {
t . startContainer = t . endContainer ;
t . startOffset = t . endOffset ;
}
t . collapsed = true ;
} ,
selectNode : function ( n ) {
this . setStartBefore ( n ) ;
this . setEndAfter ( n ) ;
} ,
selectNodeContents : function ( n ) {
this . setStart ( n , 0 ) ;
this . setEnd ( n , n . nodeType === 1 ? n . childNodes . length : n . nodeValue . length ) ;
} ,
compareBoundaryPoints : function ( h , r ) {
var t = this , sc = t . startContainer , so = t . startOffset , ec = t . endContainer , eo = t . endOffset ;
// Check START_TO_START
if ( h === 0 )
return t . _compareBoundaryPoints ( sc , so , sc , so ) ;
// Check START_TO_END
if ( h === 1 )
return t . _compareBoundaryPoints ( sc , so , ec , eo ) ;
// Check END_TO_END
if ( h === 2 )
return t . _compareBoundaryPoints ( ec , eo , ec , eo ) ;
// Check END_TO_START
if ( h === 3 )
return t . _compareBoundaryPoints ( ec , eo , sc , so ) ;
} ,
deleteContents : function ( ) {
this . _traverse ( DELETE ) ;
} ,
extractContents : function ( ) {
return this . _traverse ( EXTRACT ) ;
} ,
cloneContents : function ( ) {
return this . _traverse ( CLONE ) ;
} ,
insertNode : function ( n ) {
var t = this , nn , o ;
// Node is TEXT_NODE or CDATA
if ( n . nodeType === 3 || n . nodeType === 4 ) {
nn = t . startContainer . splitText ( t . startOffset ) ;
t . startContainer . parentNode . insertBefore ( n , nn ) ;
} else {
// Insert element node
if ( t . startContainer . childNodes . length > 0 )
o = t . startContainer . childNodes [ t . startOffset ] ;
t . startContainer . insertBefore ( n , o ) ;
}
} ,
surroundContents : function ( n ) {
var t = this , f = t . extractContents ( ) ;
t . insertNode ( n ) ;
n . appendChild ( f ) ;
t . selectNode ( n ) ;
} ,
cloneRange : function ( ) {
var t = this ;
return extend ( new Range ( t . dom ) , {
startContainer : t . startContainer ,
startOffset : t . startOffset ,
endContainer : t . endContainer ,
endOffset : t . endOffset ,
collapsed : t . collapsed ,
commonAncestorContainer : t . commonAncestorContainer
} ) ;
} ,
/ *
detach : function ( ) {
// Not implemented
} ,
* /
// Internal methods
_isCollapsed : function ( ) {
return ( this . startContainer == this . endContainer && this . startOffset == this . endOffset ) ;
} ,
_compareBoundaryPoints : function ( containerA , offsetA , containerB , offsetB ) {
var c , offsetC , n , cmnRoot , childA , childB ;
// In the first case the boundary-points have the same container. A is before B
// if its offset is less than the offset of B, A is equal to B if its offset is
// equal to the offset of B, and A is after B if its offset is greater than the
// offset of B.
if ( containerA == containerB ) {
if ( offsetA == offsetB ) {
return 0 ; // equal
} else if ( offsetA < offsetB ) {
return - 1 ; // before
} else {
return 1 ; // after
}
}
// In the second case a child node C of the container of A is an ancestor
// container of B. In this case, A is before B if the offset of A is less than or
// equal to the index of the child node C and A is after B otherwise.
c = containerB ;
while ( c && c . parentNode != containerA ) {
c = c . parentNode ;
}
if ( c ) {
offsetC = 0 ;
n = containerA . firstChild ;
while ( n != c && offsetC < offsetA ) {
offsetC ++ ;
n = n . nextSibling ;
}
if ( offsetA <= offsetC ) {
return - 1 ; // before
} else {
return 1 ; // after
}
}
// In the third case a child node C of the container of B is an ancestor container
// of A. In this case, A is before B if the index of the child node C is less than
// the offset of B and A is after B otherwise.
c = containerA ;
while ( c && c . parentNode != containerB ) {
c = c . parentNode ;
}
if ( c ) {
offsetC = 0 ;
n = containerB . firstChild ;
while ( n != c && offsetC < offsetB ) {
offsetC ++ ;
n = n . nextSibling ;
}
if ( offsetC < offsetB ) {
return - 1 ; // before
} else {
return 1 ; // after
}
}
// In the fourth case, none of three other cases hold: the containers of A and B
// are siblings or descendants of sibling nodes. In this case, A is before B if
// the container of A is before the container of B in a pre-order traversal of the
// Ranges' context tree and A is after B otherwise.
cmnRoot = this . dom . findCommonAncestor ( containerA , containerB ) ;
childA = containerA ;
while ( childA && childA . parentNode != cmnRoot ) {
childA = childA . parentNode ;
}
if ( ! childA ) {
childA = cmnRoot ;
}
childB = containerB ;
while ( childB && childB . parentNode != cmnRoot ) {
childB = childB . parentNode ;
}
if ( ! childB ) {
childB = cmnRoot ;
}
if ( childA == childB ) {
return 0 ; // equal
}
n = cmnRoot . firstChild ;
while ( n ) {
if ( n == childA ) {
return - 1 ; // before
}
if ( n == childB ) {
return 1 ; // after
}
n = n . nextSibling ;
}
} ,
_setEndPoint : function ( st , n , o ) {
var t = this , ec , sc ;
if ( st ) {
t . startContainer = n ;
t . startOffset = o ;
} else {
t . endContainer = n ;
t . endOffset = o ;
}
// If one boundary-point of a Range is set to have a root container
// other than the current one for the Range, the Range is collapsed to
// the new position. This enforces the restriction that both boundary-
// points of a Range must have the same root container.
ec = t . endContainer ;
while ( ec . parentNode )
ec = ec . parentNode ;
sc = t . startContainer ;
while ( sc . parentNode )
sc = sc . parentNode ;
if ( sc != ec ) {
t . collapse ( st ) ;
} else {
// The start position of a Range is guaranteed to never be after the
// end position. To enforce this restriction, if the start is set to
// be at a position after the end, the Range is collapsed to that
// position.
if ( t . _compareBoundaryPoints ( t . startContainer , t . startOffset , t . endContainer , t . endOffset ) > 0 )
t . collapse ( st ) ;
}
t . collapsed = t . _isCollapsed ( ) ;
t . commonAncestorContainer = t . dom . findCommonAncestor ( t . startContainer , t . endContainer ) ;
} ,
// This code is heavily "inspired" by the Apache Xerces implementation. I hope they don't mind. :)
_traverse : function ( how ) {
var t = this , c , endContainerDepth = 0 , startContainerDepth = 0 , p , depthDiff , startNode , endNode , sp , ep ;
if ( t . startContainer == t . endContainer )
return t . _traverseSameContainer ( how ) ;
for ( c = t . endContainer , p = c . parentNode ; p != null ; c = p , p = p . parentNode ) {
if ( p == t . startContainer )
return t . _traverseCommonStartContainer ( c , how ) ;
++ endContainerDepth ;
}
for ( c = t . startContainer , p = c . parentNode ; p != null ; c = p , p = p . parentNode ) {
if ( p == t . endContainer )
return t . _traverseCommonEndContainer ( c , how ) ;
++ startContainerDepth ;
}
depthDiff = startContainerDepth - endContainerDepth ;
startNode = t . startContainer ;
while ( depthDiff > 0 ) {
startNode = startNode . parentNode ;
depthDiff -- ;
}
endNode = t . endContainer ;
while ( depthDiff < 0 ) {
endNode = endNode . parentNode ;
depthDiff ++ ;
}
// ascend the ancestor hierarchy until we have a common parent.
for ( sp = startNode . parentNode , ep = endNode . parentNode ; sp != ep ; sp = sp . parentNode , ep = ep . parentNode ) {
startNode = sp ;
endNode = ep ;
}
return t . _traverseCommonAncestors ( startNode , endNode , how ) ;
} ,
_traverseSameContainer : function ( how ) {
var t = this , frag , s , sub , n , cnt , sibling , xferNode ;
if ( how != DELETE )
frag = t . dom . doc . createDocumentFragment ( ) ;
// If selection is empty, just return the fragment
if ( t . startOffset == t . endOffset )
return frag ;
// Text node needs special case handling
if ( t . startContainer . nodeType == 3 /* TEXT_NODE */ ) {
// get the substring
s = t . startContainer . nodeValue ;
sub = s . substring ( t . startOffset , t . endOffset ) ;
// set the original text node to its new value
if ( how != CLONE ) {
t . startContainer . deleteData ( t . startOffset , t . endOffset - t . startOffset ) ;
// Nothing is partially selected, so collapse to start point
t . collapse ( true ) ;
}
if ( how == DELETE )
return null ;
frag . appendChild ( t . dom . doc . createTextNode ( sub ) ) ;
return frag ;
}
// Copy nodes between the start/end offsets.
n = getSelectedNode ( t . startContainer , t . startOffset ) ;
cnt = t . endOffset - t . startOffset ;
while ( cnt > 0 ) {
sibling = n . nextSibling ;
xferNode = t . _traverseFullySelected ( n , how ) ;
if ( frag )
frag . appendChild ( xferNode ) ;
-- cnt ;
n = sibling ;
}
// Nothing is partially selected, so collapse to start point
if ( how != CLONE )
t . collapse ( true ) ;
return frag ;
} ,
_traverseCommonStartContainer : function ( endAncestor , how ) {
var t = this , frag , n , endIdx , cnt , sibling , xferNode ;
if ( how != DELETE )
frag = t . dom . doc . createDocumentFragment ( ) ;
n = t . _traverseRightBoundary ( endAncestor , how ) ;
if ( frag )
frag . appendChild ( n ) ;
endIdx = indexOf ( endAncestor , t . startContainer ) ;
cnt = endIdx - t . startOffset ;
if ( cnt <= 0 ) {
// Collapse to just before the endAncestor, which
// is partially selected.
if ( how != CLONE ) {
t . setEndBefore ( endAncestor ) ;
t . collapse ( false ) ;
}
return frag ;
}
n = endAncestor . previousSibling ;
while ( cnt > 0 ) {
sibling = n . previousSibling ;
xferNode = t . _traverseFullySelected ( n , how ) ;
if ( frag )
frag . insertBefore ( xferNode , frag . firstChild ) ;
-- cnt ;
n = sibling ;
}
// Collapse to just before the endAncestor, which
// is partially selected.
if ( how != CLONE ) {
t . setEndBefore ( endAncestor ) ;
t . collapse ( false ) ;
}
return frag ;
} ,
_traverseCommonEndContainer : function ( startAncestor , how ) {
var t = this , frag , startIdx , n , cnt , sibling , xferNode ;
if ( how != DELETE )
frag = t . dom . doc . createDocumentFragment ( ) ;
n = t . _traverseLeftBoundary ( startAncestor , how ) ;
if ( frag )
frag . appendChild ( n ) ;
startIdx = indexOf ( startAncestor , t . endContainer ) ;
++ startIdx ; // Because we already traversed it....
cnt = t . endOffset - startIdx ;
n = startAncestor . nextSibling ;
while ( cnt > 0 ) {
sibling = n . nextSibling ;
xferNode = t . _traverseFullySelected ( n , how ) ;
if ( frag )
frag . appendChild ( xferNode ) ;
-- cnt ;
n = sibling ;
}
if ( how != CLONE ) {
t . setStartAfter ( startAncestor ) ;
t . collapse ( true ) ;
}
return frag ;
} ,
_traverseCommonAncestors : function ( startAncestor , endAncestor , how ) {
var t = this , n , frag , commonParent , startOffset , endOffset , cnt , sibling , nextSibling ;
if ( how != DELETE )
frag = t . dom . doc . createDocumentFragment ( ) ;
n = t . _traverseLeftBoundary ( startAncestor , how ) ;
if ( frag )
frag . appendChild ( n ) ;
commonParent = startAncestor . parentNode ;
startOffset = indexOf ( startAncestor , commonParent ) ;
endOffset = indexOf ( endAncestor , commonParent ) ;
++ startOffset ;
cnt = endOffset - startOffset ;
sibling = startAncestor . nextSibling ;
while ( cnt > 0 ) {
nextSibling = sibling . nextSibling ;
n = t . _traverseFullySelected ( sibling , how ) ;
if ( frag )
frag . appendChild ( n ) ;
sibling = nextSibling ;
-- cnt ;
}
n = t . _traverseRightBoundary ( endAncestor , how ) ;
if ( frag )
frag . appendChild ( n ) ;
if ( how != CLONE ) {
t . setStartAfter ( startAncestor ) ;
t . collapse ( true ) ;
}
return frag ;
} ,
_traverseRightBoundary : function ( root , how ) {
var t = this , next = getSelectedNode ( t . endContainer , t . endOffset - 1 ) , parent , clonedParent , prevSibling , clonedChild , clonedGrandParent ;
var isFullySelected = next != t . endContainer ;
if ( next == root )
return t . _traverseNode ( next , isFullySelected , false , how ) ;
parent = next . parentNode ;
clonedParent = t . _traverseNode ( parent , false , false , how ) ;
while ( parent != null ) {
while ( next != null ) {
prevSibling = next . previousSibling ;
clonedChild = t . _traverseNode ( next , isFullySelected , false , how ) ;
if ( how != DELETE )
clonedParent . insertBefore ( clonedChild , clonedParent . firstChild ) ;
isFullySelected = true ;
next = prevSibling ;
}
if ( parent == root )
return clonedParent ;
next = parent . previousSibling ;
parent = parent . parentNode ;
clonedGrandParent = t . _traverseNode ( parent , false , false , how ) ;
if ( how != DELETE )
clonedGrandParent . appendChild ( clonedParent ) ;
clonedParent = clonedGrandParent ;
}
// should never occur
return null ;
} ,
_traverseLeftBoundary : function ( root , how ) {
var t = this , next = getSelectedNode ( t . startContainer , t . startOffset ) ;
var isFullySelected = next != t . startContainer , parent , clonedParent , nextSibling , clonedChild , clonedGrandParent ;
if ( next == root )
return t . _traverseNode ( next , isFullySelected , true , how ) ;
parent = next . parentNode ;
clonedParent = t . _traverseNode ( parent , false , true , how ) ;
while ( parent != null ) {
while ( next != null ) {
nextSibling = next . nextSibling ;
clonedChild = t . _traverseNode ( next , isFullySelected , true , how ) ;
if ( how != DELETE )
clonedParent . appendChild ( clonedChild ) ;
isFullySelected = true ;
next = nextSibling ;
}
if ( parent == root )
return clonedParent ;
next = parent . nextSibling ;
parent = parent . parentNode ;
clonedGrandParent = t . _traverseNode ( parent , false , true , how ) ;
if ( how != DELETE )
clonedGrandParent . appendChild ( clonedParent ) ;
clonedParent = clonedGrandParent ;
}
// should never occur
return null ;
} ,
_traverseNode : function ( n , isFullySelected , isLeft , how ) {
var t = this , txtValue , newNodeValue , oldNodeValue , offset , newNode ;
if ( isFullySelected )
return t . _traverseFullySelected ( n , how ) ;
if ( n . nodeType == 3 /* TEXT_NODE */ ) {
txtValue = n . nodeValue ;
if ( isLeft ) {
offset = t . startOffset ;
newNodeValue = txtValue . substring ( offset ) ;
oldNodeValue = txtValue . substring ( 0 , offset ) ;
} else {
offset = t . endOffset ;
newNodeValue = txtValue . substring ( 0 , offset ) ;
oldNodeValue = txtValue . substring ( offset ) ;
}
if ( how != CLONE )
n . nodeValue = oldNodeValue ;
if ( how == DELETE )
return null ;
newNode = n . cloneNode ( false ) ;
newNode . nodeValue = newNodeValue ;
return newNode ;
}
if ( how == DELETE )
return null ;
return n . cloneNode ( false ) ;
} ,
_traverseFullySelected : function ( n , how ) {
var t = this ;
if ( how != DELETE )
return how == CLONE ? n . cloneNode ( true ) : n ;
n . parentNode . removeChild ( n ) ;
return null ;
}
} ) ;
ns . Range = Range ;
} ) ( tinymce . dom ) ;
( function ( ) {
function Selection ( selection ) {
var t = this , invisibleChar = '\uFEFF' , range , lastIERng ;
function compareRanges ( rng1 , rng2 ) {
if ( rng1 && rng2 ) {
// Both are control ranges and the selected element matches
if ( rng1 . item && rng2 . item && rng1 . item ( 0 ) === rng2 . item ( 0 ) )
return 1 ;
// Both are text ranges and the range matches
if ( rng1 . isEqual && rng2 . isEqual && rng2 . isEqual ( rng1 ) )
return 1 ;
}
return 0 ;
} ;
function getRange ( ) {
var dom = selection . dom , ieRange = selection . getRng ( ) , domRange = dom . createRng ( ) , startPos , endPos , element , sc , ec , collapsed ;
function findIndex ( element ) {
var nl = element . parentNode . childNodes , i ;
for ( i = nl . length - 1 ; i >= 0 ; i -- ) {
if ( nl [ i ] == element )
return i ;
}
return - 1 ;
} ;
function findEndPoint ( start ) {
var rng = ieRange . duplicate ( ) , parent , i , nl , n , offset = 0 , index = 0 , pos , tmpRng ;
// Insert marker character
rng . collapse ( start ) ;
parent = rng . parentElement ( ) ;
rng . pasteHTML ( invisibleChar ) ; // Needs to be a pasteHTML instead of .text = since IE has a bug with nodeValue
// Find marker character
nl = parent . childNodes ;
for ( i = 0 ; i < nl . length ; i ++ ) {
n = nl [ i ] ;
// Calculate node index excluding text node fragmentation
if ( i > 0 && ( n . nodeType !== 3 || nl [ i - 1 ] . nodeType !== 3 ) )
index ++ ;
// If text node then calculate offset
if ( n . nodeType === 3 ) {
// Look for marker
pos = n . nodeValue . indexOf ( invisibleChar ) ;
if ( pos !== - 1 ) {
offset += pos ;
break ;
}
offset += n . nodeValue . length ;
} else
offset = 0 ;
}
// Remove marker character
rng . moveStart ( 'character' , - 1 ) ;
rng . text = '' ;
return { index : index , offset : offset , parent : parent } ;
} ;
// If selection is outside the current document just return an empty range
element = ieRange . item ? ieRange . item ( 0 ) : ieRange . parentElement ( ) ;
if ( element . ownerDocument != dom . doc )
return domRange ;
// Handle control selection or text selection of a image
if ( ieRange . item || ! element . hasChildNodes ( ) ) {
domRange . setStart ( element . parentNode , findIndex ( element ) ) ;
domRange . setEnd ( domRange . startContainer , domRange . startOffset + 1 ) ;
return domRange ;
}
// Check collapsed state
collapsed = selection . isCollapsed ( ) ;
// Find start and end pos index and offset
startPos = findEndPoint ( true ) ;
endPos = findEndPoint ( false ) ;
// Normalize the elements to avoid fragmented dom
startPos . parent . normalize ( ) ;
endPos . parent . normalize ( ) ;
// Set start container and offset
sc = startPos . parent . childNodes [ Math . min ( startPos . index , startPos . parent . childNodes . length - 1 ) ] ;
if ( sc . nodeType != 3 )
domRange . setStart ( startPos . parent , startPos . index ) ;
else
domRange . setStart ( startPos . parent . childNodes [ startPos . index ] , startPos . offset ) ;
// Set end container and offset
ec = endPos . parent . childNodes [ Math . min ( endPos . index , endPos . parent . childNodes . length - 1 ) ] ;
if ( ec . nodeType != 3 ) {
if ( ! collapsed )
endPos . index ++ ;
domRange . setEnd ( endPos . parent , endPos . index ) ;
} else
domRange . setEnd ( endPos . parent . childNodes [ endPos . index ] , endPos . offset ) ;
// If not collapsed then make sure offsets are valid
if ( ! collapsed ) {
sc = domRange . startContainer ;
if ( sc . nodeType == 1 )
domRange . setStart ( sc , Math . min ( domRange . startOffset , sc . childNodes . length ) ) ;
ec = domRange . endContainer ;
if ( ec . nodeType == 1 )
domRange . setEnd ( ec , Math . min ( domRange . endOffset , ec . childNodes . length ) ) ;
}
// Restore selection to new range
t . addRange ( domRange ) ;
return domRange ;
} ;
this . addRange = function ( rng ) {
var ieRng , body = selection . dom . doc . body , startPos , endPos , sc , so , ec , eo ;
// Setup some shorter versions
sc = rng . startContainer ;
so = rng . startOffset ;
ec = rng . endContainer ;
eo = rng . endOffset ;
ieRng = body . createTextRange ( ) ;
// Find element
sc = sc . nodeType == 1 ? sc . childNodes [ Math . min ( so , sc . childNodes . length - 1 ) ] : sc ;
ec = ec . nodeType == 1 ? ec . childNodes [ Math . min ( so == eo ? eo : eo - 1 , ec . childNodes . length - 1 ) ] : ec ;
// Single element selection
if ( sc == ec && sc . nodeType == 1 ) {
// Make control selection for some elements
if ( /^(IMG|TABLE)$/ . test ( sc . nodeName ) && so != eo ) {
ieRng = body . createControlRange ( ) ;
ieRng . addElement ( sc ) ;
} else {
ieRng = body . createTextRange ( ) ;
// Padd empty elements with invisible character
if ( ! sc . hasChildNodes ( ) && sc . canHaveHTML )
sc . innerHTML = invisibleChar ;
// Select element contents
ieRng . moveToElementText ( sc ) ;
// If it's only containing a padding remove it so the caret remains
if ( sc . innerHTML == invisibleChar ) {
ieRng . collapse ( true ) ;
sc . removeChild ( sc . firstChild ) ;
}
}
if ( so == eo )
ieRng . collapse ( eo <= rng . endContainer . childNodes . length - 1 ) ;
ieRng . select ( ) ;
return ;
}
function getCharPos ( container , offset ) {
var nodeVal , rng , pos ;
if ( container . nodeType != 3 )
return - 1 ;
nodeVal = container . nodeValue ;
rng = body . createTextRange ( ) ;
// Insert marker at offset position
container . nodeValue = nodeVal . substring ( 0 , offset ) + invisibleChar + nodeVal . substring ( offset ) ;
// Find char pos of marker and remove it
rng . moveToElementText ( container . parentNode ) ;
rng . findText ( invisibleChar ) ;
pos = Math . abs ( rng . moveStart ( 'character' , - 0xFFFFF ) ) ;
container . nodeValue = nodeVal ;
return pos ;
} ;
// Collapsed range
if ( rng . collapsed ) {
pos = getCharPos ( sc , so ) ;
ieRng = body . createTextRange ( ) ;
ieRng . move ( 'character' , pos ) ;
ieRng . select ( ) ;
return ;
} else {
// If same text container
if ( sc == ec && sc . nodeType == 3 ) {
startPos = getCharPos ( sc , so ) ;
ieRng . move ( 'character' , startPos ) ;
ieRng . moveEnd ( 'character' , eo - so ) ;
ieRng . select ( ) ;
return ;
}
// Get caret positions
startPos = getCharPos ( sc , so ) ;
endPos = getCharPos ( ec , eo ) ;
ieRng = body . createTextRange ( ) ;
// Move start of range to start character position or start element
if ( startPos == - 1 ) {
ieRng . moveToElementText ( sc ) ;
startPos = 0 ;
} else
ieRng . move ( 'character' , startPos ) ;
// Move end of range to end character position or end element
tmpRng = body . createTextRange ( ) ;
if ( endPos == - 1 )
tmpRng . moveToElementText ( ec ) ;
else
tmpRng . move ( 'character' , endPos ) ;
ieRng . setEndPoint ( 'EndToEnd' , tmpRng ) ;
ieRng . select ( ) ;
return ;
}
} ;
this . getRangeAt = function ( ) {
// Setup new range if the cache is empty
if ( ! range || ! compareRanges ( lastIERng , selection . getRng ( ) ) ) {
range = getRange ( ) ;
// Store away text range for next call
lastIERng = selection . getRng ( ) ;
}
// Return cached range
return range ;
} ;
this . destroy = function ( ) {
// Destroy cached range and last IE range to avoid memory leaks
lastIERng = range = null ;
} ;
} ;
// Expose the selection object
tinymce . dom . TridentSelection = Selection ;
} ) ( ) ;
/ *
* Sizzle CSS Selector Engine - v1 . 0
* Copyright 2009 , The Dojo Foundation
* Released under the MIT , BSD , and GPL Licenses .
* More information : http : //sizzlejs.com/
* /
( function ( ) {
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g ,
done = 0 ,
toString = Object . prototype . toString ,
hasDuplicate = false ;
var Sizzle = function ( selector , context , results , seed ) {
results = results || [ ] ;
var origContext = context = context || document ;
if ( context . nodeType !== 1 && context . nodeType !== 9 ) {
return [ ] ;
}
if ( ! selector || typeof selector !== "string" ) {
return results ;
}
var parts = [ ] , m , set , checkSet , check , mode , extra , prune = true , contextXML = isXML ( context ) ;
// Reset the position of the chunker regexp (start from head)
chunker . lastIndex = 0 ;
while ( ( m = chunker . exec ( selector ) ) !== null ) {
parts . push ( m [ 1 ] ) ;
if ( m [ 2 ] ) {
extra = RegExp . rightContext ;
break ;
}
}
if ( parts . length > 1 && origPOS . exec ( selector ) ) {
if ( parts . length === 2 && Expr . relative [ parts [ 0 ] ] ) {
set = posProcess ( parts [ 0 ] + parts [ 1 ] , context ) ;
} else {
set = Expr . relative [ parts [ 0 ] ] ?
[ context ] :
Sizzle ( parts . shift ( ) , context ) ;
while ( parts . length ) {
selector = parts . shift ( ) ;
if ( Expr . relative [ selector ] )
selector += parts . shift ( ) ;
set = posProcess ( selector , set ) ;
}
}
} else {
// Take a shortcut and set the context if the root selector is an ID
// (but not if it'll be faster if the inner selector is an ID)
if ( ! seed && parts . length > 1 && context . nodeType === 9 && ! contextXML &&
Expr . match . ID . test ( parts [ 0 ] ) && ! Expr . match . ID . test ( parts [ parts . length - 1 ] ) ) {
var ret = Sizzle . find ( parts . shift ( ) , context , contextXML ) ;
context = ret . expr ? Sizzle . filter ( ret . expr , ret . set ) [ 0 ] : ret . set [ 0 ] ;
}
if ( context ) {
var ret = seed ?
{ expr : parts . pop ( ) , set : makeArray ( seed ) } :
Sizzle . find ( parts . pop ( ) , parts . length === 1 && ( parts [ 0 ] === "~" || parts [ 0 ] === "+" ) && context . parentNode ? context . parentNode : context , contextXML ) ;
set = ret . expr ? Sizzle . filter ( ret . expr , ret . set ) : ret . set ;
if ( parts . length > 0 ) {
checkSet = makeArray ( set ) ;
} else {
prune = false ;
}
while ( parts . length ) {
var cur = parts . pop ( ) , pop = cur ;
if ( ! Expr . relative [ cur ] ) {
cur = "" ;
} else {
pop = parts . pop ( ) ;
}
if ( pop == null ) {
pop = context ;
}
Expr . relative [ cur ] ( checkSet , pop , contextXML ) ;
}
} else {
checkSet = parts = [ ] ;
}
}
if ( ! checkSet ) {
checkSet = set ;
}
if ( ! checkSet ) {
throw "Syntax error, unrecognized expression: " + ( cur || selector ) ;
}
if ( toString . call ( checkSet ) === "[object Array]" ) {
if ( ! prune ) {
results . push . apply ( results , checkSet ) ;
} else if ( context && context . nodeType === 1 ) {
for ( var i = 0 ; checkSet [ i ] != null ; i ++ ) {
if ( checkSet [ i ] && ( checkSet [ i ] === true || checkSet [ i ] . nodeType === 1 && contains ( context , checkSet [ i ] ) ) ) {
results . push ( set [ i ] ) ;
}
}
} else {
for ( var i = 0 ; checkSet [ i ] != null ; i ++ ) {
if ( checkSet [ i ] && checkSet [ i ] . nodeType === 1 ) {
results . push ( set [ i ] ) ;
}
}
}
} else {
makeArray ( checkSet , results ) ;
}
if ( extra ) {
Sizzle ( extra , origContext , results , seed ) ;
Sizzle . uniqueSort ( results ) ;
}
return results ;
} ;
Sizzle . uniqueSort = function ( results ) {
if ( sortOrder ) {
hasDuplicate = false ;
results . sort ( sortOrder ) ;
if ( hasDuplicate ) {
for ( var i = 1 ; i < results . length ; i ++ ) {
if ( results [ i ] === results [ i - 1 ] ) {
results . splice ( i -- , 1 ) ;
}
}
}
}
} ;
Sizzle . matches = function ( expr , set ) {
return Sizzle ( expr , null , null , set ) ;
} ;
Sizzle . find = function ( expr , context , isXML ) {
var set , match ;
if ( ! expr ) {
return [ ] ;
}
for ( var i = 0 , l = Expr . order . length ; i < l ; i ++ ) {
var type = Expr . order [ i ] , match ;
if ( ( match = Expr . match [ type ] . exec ( expr ) ) ) {
var left = RegExp . leftContext ;
if ( left . substr ( left . length - 1 ) !== "\\" ) {
match [ 1 ] = ( match [ 1 ] || "" ) . replace ( /\\/g , "" ) ;
set = Expr . find [ type ] ( match , context , isXML ) ;
if ( set != null ) {
expr = expr . replace ( Expr . match [ type ] , "" ) ;
break ;
}
}
}
}
if ( ! set ) {
set = context . getElementsByTagName ( "*" ) ;
}
return { set : set , expr : expr } ;
} ;
Sizzle . filter = function ( expr , set , inplace , not ) {
var old = expr , result = [ ] , curLoop = set , match , anyFound ,
isXMLFilter = set && set [ 0 ] && isXML ( set [ 0 ] ) ;
while ( expr && set . length ) {
for ( var type in Expr . filter ) {
if ( ( match = Expr . match [ type ] . exec ( expr ) ) != null ) {
var filter = Expr . filter [ type ] , found , item ;
anyFound = false ;
if ( curLoop == result ) {
result = [ ] ;
}
if ( Expr . preFilter [ type ] ) {
match = Expr . preFilter [ type ] ( match , curLoop , inplace , result , not , isXMLFilter ) ;
if ( ! match ) {
anyFound = found = true ;
} else if ( match === true ) {
continue ;
}
}
if ( match ) {
for ( var i = 0 ; ( item = curLoop [ i ] ) != null ; i ++ ) {
if ( item ) {
found = filter ( item , match , i , curLoop ) ;
var pass = not ^ ! ! found ;
if ( inplace && found != null ) {
if ( pass ) {
anyFound = true ;
} else {
curLoop [ i ] = false ;
}
} else if ( pass ) {
result . push ( item ) ;
anyFound = true ;
}
}
}
}
if ( found !== undefined ) {
if ( ! inplace ) {
curLoop = result ;
}
expr = expr . replace ( Expr . match [ type ] , "" ) ;
if ( ! anyFound ) {
return [ ] ;
}
break ;
}
}
}
// Improper expression
if ( expr == old ) {
if ( anyFound == null ) {
throw "Syntax error, unrecognized expression: " + expr ;
} else {
break ;
}
}
old = expr ;
}
return curLoop ;
} ;
var Expr = Sizzle . selectors = {
order : [ "ID" , "NAME" , "TAG" ] ,
match : {
ID : /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/ ,
CLASS : /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/ ,
NAME : /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/ ,
ATTR : /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/ ,
TAG : /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/ ,
CHILD : /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/ ,
POS : /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/ ,
PSEUDO : /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
} ,
attrMap : {
"class" : "className" ,
"for" : "htmlFor"
} ,
attrHandle : {
href : function ( elem ) {
return elem . getAttribute ( "href" ) ;
}
} ,
relative : {
"+" : function ( checkSet , part , isXML ) {
var isPartStr = typeof part === "string" ,
isTag = isPartStr && ! /\W/ . test ( part ) ,
isPartStrNotTag = isPartStr && ! isTag ;
if ( isTag && ! isXML ) {
part = part . toUpperCase ( ) ;
}
for ( var i = 0 , l = checkSet . length , elem ; i < l ; i ++ ) {
if ( ( elem = checkSet [ i ] ) ) {
while ( ( elem = elem . previousSibling ) && elem . nodeType !== 1 ) { }
checkSet [ i ] = isPartStrNotTag || elem && elem . nodeName === part ?
elem || false :
elem === part ;
}
}
if ( isPartStrNotTag ) {
Sizzle . filter ( part , checkSet , true ) ;
}
} ,
">" : function ( checkSet , part , isXML ) {
var isPartStr = typeof part === "string" ;
if ( isPartStr && ! /\W/ . test ( part ) ) {
part = isXML ? part : part . toUpperCase ( ) ;
for ( var i = 0 , l = checkSet . length ; i < l ; i ++ ) {
var elem = checkSet [ i ] ;
if ( elem ) {
var parent = elem . parentNode ;
checkSet [ i ] = parent . nodeName === part ? parent : false ;
}
}
} else {
for ( var i = 0 , l = checkSet . length ; i < l ; i ++ ) {
var elem = checkSet [ i ] ;
if ( elem ) {
checkSet [ i ] = isPartStr ?
elem . parentNode :
elem . parentNode === part ;
}
}
if ( isPartStr ) {
Sizzle . filter ( part , checkSet , true ) ;
}
}
} ,
"" : function ( checkSet , part , isXML ) {
var doneName = done ++ , checkFn = dirCheck ;
if ( ! part . match ( /\W/ ) ) {
var nodeCheck = part = isXML ? part : part . toUpperCase ( ) ;
checkFn = dirNodeCheck ;
}
checkFn ( "parentNode" , part , doneName , checkSet , nodeCheck , isXML ) ;
} ,
"~" : function ( checkSet , part , isXML ) {
var doneName = done ++ , checkFn = dirCheck ;
if ( typeof part === "string" && ! part . match ( /\W/ ) ) {
var nodeCheck = part = isXML ? part : part . toUpperCase ( ) ;
checkFn = dirNodeCheck ;
}
checkFn ( "previousSibling" , part , doneName , checkSet , nodeCheck , isXML ) ;
}
} ,
find : {
ID : function ( match , context , isXML ) {
if ( typeof context . getElementById !== "undefined" && ! isXML ) {
var m = context . getElementById ( match [ 1 ] ) ;
return m ? [ m ] : [ ] ;
}
} ,
NAME : function ( match , context , isXML ) {
if ( typeof context . getElementsByName !== "undefined" ) {
var ret = [ ] , results = context . getElementsByName ( match [ 1 ] ) ;
for ( var i = 0 , l = results . length ; i < l ; i ++ ) {
if ( results [ i ] . getAttribute ( "name" ) === match [ 1 ] ) {
ret . push ( results [ i ] ) ;
}
}
return ret . length === 0 ? null : ret ;
}
} ,
TAG : function ( match , context ) {
return context . getElementsByTagName ( match [ 1 ] ) ;
}
} ,
preFilter : {
CLASS : function ( match , curLoop , inplace , result , not , isXML ) {
match = " " + match [ 1 ] . replace ( /\\/g , "" ) + " " ;
if ( isXML ) {
return match ;
}
for ( var i = 0 , elem ; ( elem = curLoop [ i ] ) != null ; i ++ ) {
if ( elem ) {
if ( not ^ ( elem . className && ( " " + elem . className + " " ) . indexOf ( match ) >= 0 ) ) {
if ( ! inplace )
result . push ( elem ) ;
} else if ( inplace ) {
curLoop [ i ] = false ;
}
}
}
return false ;
} ,
ID : function ( match ) {
return match [ 1 ] . replace ( /\\/g , "" ) ;
} ,
TAG : function ( match , curLoop ) {
for ( var i = 0 ; curLoop [ i ] === false ; i ++ ) { }
return curLoop [ i ] && isXML ( curLoop [ i ] ) ? match [ 1 ] : match [ 1 ] . toUpperCase ( ) ;
} ,
CHILD : function ( match ) {
if ( match [ 1 ] == "nth" ) {
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
var test = /(-?)(\d*)n((?:\+|-)?\d*)/ . exec (
match [ 2 ] == "even" && "2n" || match [ 2 ] == "odd" && "2n+1" ||
! /\D/ . test ( match [ 2 ] ) && "0n+" + match [ 2 ] || match [ 2 ] ) ;
// calculate the numbers (first)n+(last) including if they are negative
match [ 2 ] = ( test [ 1 ] + ( test [ 2 ] || 1 ) ) - 0 ;
match [ 3 ] = test [ 3 ] - 0 ;
}
// TODO: Move to normal caching system
match [ 0 ] = done ++ ;
return match ;
} ,
ATTR : function ( match , curLoop , inplace , result , not , isXML ) {
var name = match [ 1 ] . replace ( /\\/g , "" ) ;
if ( ! isXML && Expr . attrMap [ name ] ) {
match [ 1 ] = Expr . attrMap [ name ] ;
}
if ( match [ 2 ] === "~=" ) {
match [ 4 ] = " " + match [ 4 ] + " " ;
}
return match ;
} ,
PSEUDO : function ( match , curLoop , inplace , result , not ) {
if ( match [ 1 ] === "not" ) {
// If we're dealing with a complex expression, or a simple one
if ( match [ 3 ] . match ( chunker ) . length > 1 || /^\w/ . test ( match [ 3 ] ) ) {
match [ 3 ] = Sizzle ( match [ 3 ] , null , null , curLoop ) ;
} else {
var ret = Sizzle . filter ( match [ 3 ] , curLoop , inplace , true ^ not ) ;
if ( ! inplace ) {
result . push . apply ( result , ret ) ;
}
return false ;
}
} else if ( Expr . match . POS . test ( match [ 0 ] ) || Expr . match . CHILD . test ( match [ 0 ] ) ) {
return true ;
}
return match ;
} ,
POS : function ( match ) {
match . unshift ( true ) ;
return match ;
}
} ,
filters : {
enabled : function ( elem ) {
return elem . disabled === false && elem . type !== "hidden" ;
} ,
disabled : function ( elem ) {
return elem . disabled === true ;
} ,
checked : function ( elem ) {
return elem . checked === true ;
} ,
selected : function ( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
elem . parentNode . selectedIndex ;
return elem . selected === true ;
} ,
parent : function ( elem ) {
return ! ! elem . firstChild ;
} ,
empty : function ( elem ) {
return ! elem . firstChild ;
} ,
has : function ( elem , i , match ) {
return ! ! Sizzle ( match [ 3 ] , elem ) . length ;
} ,
header : function ( elem ) {
return /h\d/i . test ( elem . nodeName ) ;
} ,
text : function ( elem ) {
return "text" === elem . type ;
} ,
radio : function ( elem ) {
return "radio" === elem . type ;
} ,
checkbox : function ( elem ) {
return "checkbox" === elem . type ;
} ,
file : function ( elem ) {
return "file" === elem . type ;
} ,
password : function ( elem ) {
return "password" === elem . type ;
} ,
submit : function ( elem ) {
return "submit" === elem . type ;
} ,
image : function ( elem ) {
return "image" === elem . type ;
} ,
reset : function ( elem ) {
return "reset" === elem . type ;
} ,
button : function ( elem ) {
return "button" === elem . type || elem . nodeName . toUpperCase ( ) === "BUTTON" ;
} ,
input : function ( elem ) {
return /input|select|textarea|button/i . test ( elem . nodeName ) ;
}
} ,
setFilters : {
first : function ( elem , i ) {
return i === 0 ;
} ,
last : function ( elem , i , match , array ) {
return i === array . length - 1 ;
} ,
even : function ( elem , i ) {
return i % 2 === 0 ;
} ,
odd : function ( elem , i ) {
return i % 2 === 1 ;
} ,
lt : function ( elem , i , match ) {
return i < match [ 3 ] - 0 ;
} ,
gt : function ( elem , i , match ) {
return i > match [ 3 ] - 0 ;
} ,
nth : function ( elem , i , match ) {
return match [ 3 ] - 0 == i ;
} ,
eq : function ( elem , i , match ) {
return match [ 3 ] - 0 == i ;
}
} ,
filter : {
PSEUDO : function ( elem , match , i , array ) {
var name = match [ 1 ] , filter = Expr . filters [ name ] ;
if ( filter ) {
return filter ( elem , i , match , array ) ;
} else if ( name === "contains" ) {
return ( elem . textContent || elem . innerText || "" ) . indexOf ( match [ 3 ] ) >= 0 ;
} else if ( name === "not" ) {
var not = match [ 3 ] ;
for ( var i = 0 , l = not . length ; i < l ; i ++ ) {
if ( not [ i ] === elem ) {
return false ;
}
}
return true ;
}
} ,
CHILD : function ( elem , match ) {
var type = match [ 1 ] , node = elem ;
switch ( type ) {
case 'only' :
case 'first' :
while ( node = node . previousSibling ) {
if ( node . nodeType === 1 ) return false ;
}
if ( type == 'first' ) return true ;
node = elem ;
case 'last' :
while ( node = node . nextSibling ) {
if ( node . nodeType === 1 ) return false ;
}
return true ;
case 'nth' :
var first = match [ 2 ] , last = match [ 3 ] ;
if ( first == 1 && last == 0 ) {
return true ;
}
var doneName = match [ 0 ] ,
parent = elem . parentNode ;
if ( parent && ( parent . sizcache !== doneName || ! elem . nodeIndex ) ) {
var count = 0 ;
for ( node = parent . firstChild ; node ; node = node . nextSibling ) {
if ( node . nodeType === 1 ) {
node . nodeIndex = ++ count ;
}
}
parent . sizcache = doneName ;
}
var diff = elem . nodeIndex - last ;
if ( first == 0 ) {
return diff == 0 ;
} else {
return ( diff % first == 0 && diff / first >= 0 ) ;
}
}
} ,
ID : function ( elem , match ) {
return elem . nodeType === 1 && elem . getAttribute ( "id" ) === match ;
} ,
TAG : function ( elem , match ) {
return ( match === "*" && elem . nodeType === 1 ) || elem . nodeName === match ;
} ,
CLASS : function ( elem , match ) {
return ( " " + ( elem . className || elem . getAttribute ( "class" ) ) + " " )
. indexOf ( match ) > - 1 ;
} ,
ATTR : function ( elem , match ) {
var name = match [ 1 ] ,
result = Expr . attrHandle [ name ] ?
Expr . attrHandle [ name ] ( elem ) :
elem [ name ] != null ?
elem [ name ] :
elem . getAttribute ( name ) ,
value = result + "" ,
type = match [ 2 ] ,
check = match [ 4 ] ;
return result == null ?
type === "!=" :
type === "=" ?
value === check :
type === "*=" ?
value . indexOf ( check ) >= 0 :
type === "~=" ?
( " " + value + " " ) . indexOf ( check ) >= 0 :
! check ?
value && result !== false :
type === "!=" ?
value != check :
type === "^=" ?
value . indexOf ( check ) === 0 :
type === "$=" ?
value . substr ( value . length - check . length ) === check :
type === "|=" ?
value === check || value . substr ( 0 , check . length + 1 ) === check + "-" :
false ;
} ,
POS : function ( elem , match , i , array ) {
var name = match [ 2 ] , filter = Expr . setFilters [ name ] ;
if ( filter ) {
return filter ( elem , i , match , array ) ;
}
}
}
} ;
var origPOS = Expr . match . POS ;
for ( var type in Expr . match ) {
Expr . match [ type ] = new RegExp ( Expr . match [ type ] . source + /(?![^\[]*\])(?![^\(]*\))/ . source ) ;
}
var makeArray = function ( array , results ) {
array = Array . prototype . slice . call ( array ) ;
if ( results ) {
results . push . apply ( results , array ) ;
return results ;
}
return array ;
} ;
// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
try {
Array . prototype . slice . call ( document . documentElement . childNodes ) ;
// Provide a fallback method if it does not work
} catch ( e ) {
makeArray = function ( array , results ) {
var ret = results || [ ] ;
if ( toString . call ( array ) === "[object Array]" ) {
Array . prototype . push . apply ( ret , array ) ;
} else {
if ( typeof array . length === "number" ) {
for ( var i = 0 , l = array . length ; i < l ; i ++ ) {
ret . push ( array [ i ] ) ;
}
} else {
for ( var i = 0 ; array [ i ] ; i ++ ) {
ret . push ( array [ i ] ) ;
}
}
}
return ret ;
} ;
}
var sortOrder ;
if ( document . documentElement . compareDocumentPosition ) {
sortOrder = function ( a , b ) {
var ret = a . compareDocumentPosition ( b ) & 4 ? - 1 : a === b ? 0 : 1 ;
if ( ret === 0 ) {
hasDuplicate = true ;
}
return ret ;
} ;
} else if ( "sourceIndex" in document . documentElement ) {
sortOrder = function ( a , b ) {
var ret = a . sourceIndex - b . sourceIndex ;
if ( ret === 0 ) {
hasDuplicate = true ;
}
return ret ;
} ;
} else if ( document . createRange ) {
sortOrder = function ( a , b ) {
var aRange = a . ownerDocument . createRange ( ) , bRange = b . ownerDocument . createRange ( ) ;
aRange . setStart ( a , 0 ) ;
aRange . setEnd ( a , 0 ) ;
bRange . setStart ( b , 0 ) ;
bRange . setEnd ( b , 0 ) ;
var ret = aRange . compareBoundaryPoints ( Range . START _TO _END , bRange ) ;
if ( ret === 0 ) {
hasDuplicate = true ;
}
return ret ;
} ;
}
// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
( function ( ) {
// We're going to inject a fake input element with a specified name
var form = document . createElement ( "div" ) ,
id = "script" + ( new Date ) . getTime ( ) ;
form . innerHTML = "<a name='" + id + "'/>" ;
// Inject it into the root element, check its status, and remove it quickly
var root = document . documentElement ;
root . insertBefore ( form , root . firstChild ) ;
// The workaround has to do additional checks after a getElementById
// Which slows things down for other browsers (hence the branching)
if ( ! ! document . getElementById ( id ) ) {
Expr . find . ID = function ( match , context , isXML ) {
if ( typeof context . getElementById !== "undefined" && ! isXML ) {
var m = context . getElementById ( match [ 1 ] ) ;
return m ? m . id === match [ 1 ] || typeof m . getAttributeNode !== "undefined" && m . getAttributeNode ( "id" ) . nodeValue === match [ 1 ] ? [ m ] : undefined : [ ] ;
}
} ;
Expr . filter . ID = function ( elem , match ) {
var node = typeof elem . getAttributeNode !== "undefined" && elem . getAttributeNode ( "id" ) ;
return elem . nodeType === 1 && node && node . nodeValue === match ;
} ;
}
root . removeChild ( form ) ;
} ) ( ) ;
( function ( ) {
// Check to see if the browser returns only elements
// when doing getElementsByTagName("*")
// Create a fake element
var div = document . createElement ( "div" ) ;
div . appendChild ( document . createComment ( "" ) ) ;
// Make sure no comments are found
if ( div . getElementsByTagName ( "*" ) . length > 0 ) {
Expr . find . TAG = function ( match , context ) {
var results = context . getElementsByTagName ( match [ 1 ] ) ;
// Filter out possible comments
if ( match [ 1 ] === "*" ) {
var tmp = [ ] ;
for ( var i = 0 ; results [ i ] ; i ++ ) {
if ( results [ i ] . nodeType === 1 ) {
tmp . push ( results [ i ] ) ;
}
}
results = tmp ;
}
return results ;
} ;
}
// Check to see if an attribute returns normalized href attributes
div . innerHTML = "<a href='#'></a>" ;
if ( div . firstChild && typeof div . firstChild . getAttribute !== "undefined" &&
div . firstChild . getAttribute ( "href" ) !== "#" ) {
Expr . attrHandle . href = function ( elem ) {
return elem . getAttribute ( "href" , 2 ) ;
} ;
}
} ) ( ) ;
if ( document . querySelectorAll ) ( function ( ) {
var oldSizzle = Sizzle , div = document . createElement ( "div" ) ;
div . innerHTML = "<p class='TEST'></p>" ;
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
if ( div . querySelectorAll && div . querySelectorAll ( ".TEST" ) . length === 0 ) {
return ;
}
Sizzle = function ( query , context , extra , seed ) {
context = context || document ;
// Only use querySelectorAll on non-XML documents
// (ID selectors don't work in non-HTML documents)
if ( ! seed && context . nodeType === 9 && ! isXML ( context ) ) {
try {
return makeArray ( context . querySelectorAll ( query ) , extra ) ;
} catch ( e ) { }
}
return oldSizzle ( query , context , extra , seed ) ;
} ;
for ( var prop in oldSizzle ) {
Sizzle [ prop ] = oldSizzle [ prop ] ;
}
} ) ( ) ;
if ( document . getElementsByClassName && document . documentElement . getElementsByClassName ) ( function ( ) {
var div = document . createElement ( "div" ) ;
div . innerHTML = "<div class='test e'></div><div class='test'></div>" ;
// Opera can't find a second classname (in 9.6)
if ( div . getElementsByClassName ( "e" ) . length === 0 )
return ;
// Safari caches class attributes, doesn't catch changes (in 3.2)
div . lastChild . className = "e" ;
if ( div . getElementsByClassName ( "e" ) . length === 1 )
return ;
Expr . order . splice ( 1 , 0 , "CLASS" ) ;
Expr . find . CLASS = function ( match , context , isXML ) {
if ( typeof context . getElementsByClassName !== "undefined" && ! isXML ) {
return context . getElementsByClassName ( match [ 1 ] ) ;
}
} ;
} ) ( ) ;
function dirNodeCheck ( dir , cur , doneName , checkSet , nodeCheck , isXML ) {
var sibDir = dir == "previousSibling" && ! isXML ;
for ( var i = 0 , l = checkSet . length ; i < l ; i ++ ) {
var elem = checkSet [ i ] ;
if ( elem ) {
if ( sibDir && elem . nodeType === 1 ) {
elem . sizcache = doneName ;
elem . sizset = i ;
}
elem = elem [ dir ] ;
var match = false ;
while ( elem ) {
if ( elem . sizcache === doneName ) {
match = checkSet [ elem . sizset ] ;
break ;
}
if ( elem . nodeType === 1 && ! isXML ) {
elem . sizcache = doneName ;
elem . sizset = i ;
}
if ( elem . nodeName === cur ) {
match = elem ;
break ;
}
elem = elem [ dir ] ;
}
checkSet [ i ] = match ;
}
}
}
function dirCheck ( dir , cur , doneName , checkSet , nodeCheck , isXML ) {
var sibDir = dir == "previousSibling" && ! isXML ;
for ( var i = 0 , l = checkSet . length ; i < l ; i ++ ) {
var elem = checkSet [ i ] ;
if ( elem ) {
if ( sibDir && elem . nodeType === 1 ) {
elem . sizcache = doneName ;
elem . sizset = i ;
}
elem = elem [ dir ] ;
var match = false ;
while ( elem ) {
if ( elem . sizcache === doneName ) {
match = checkSet [ elem . sizset ] ;
break ;
}
if ( elem . nodeType === 1 ) {
if ( ! isXML ) {
elem . sizcache = doneName ;
elem . sizset = i ;
}
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true ;
break ;
}
} else if ( Sizzle . filter ( cur , [ elem ] ) . length > 0 ) {
match = elem ;
break ;
}
}
elem = elem [ dir ] ;
}
checkSet [ i ] = match ;
}
}
}
var contains = document . compareDocumentPosition ? function ( a , b ) {
return a . compareDocumentPosition ( b ) & 16 ;
} : function ( a , b ) {
return a !== b && ( a . contains ? a . contains ( b ) : true ) ;
} ;
var isXML = function ( elem ) {
return elem . nodeType === 9 && elem . documentElement . nodeName !== "HTML" ||
! ! elem . ownerDocument && elem . ownerDocument . documentElement . nodeName !== "HTML" ;
} ;
var posProcess = function ( selector , context ) {
var tmpSet = [ ] , later = "" , match ,
root = context . nodeType ? [ context ] : context ;
// Position selectors must be done after the filter
// And so must :not(positional) so we move all PSEUDOs to the end
while ( ( match = Expr . match . PSEUDO . exec ( selector ) ) ) {
later += match [ 0 ] ;
selector = selector . replace ( Expr . match . PSEUDO , "" ) ;
}
selector = Expr . relative [ selector ] ? selector + "*" : selector ;
for ( var i = 0 , l = root . length ; i < l ; i ++ ) {
Sizzle ( selector , root [ i ] , tmpSet ) ;
}
return Sizzle . filter ( later , tmpSet ) ;
} ;
// EXPOSE
window . tinymce . dom . Sizzle = Sizzle ;
} ) ( ) ;
( function ( tinymce ) {
// Shorten names
var each = tinymce . each , DOM = tinymce . DOM , isIE = tinymce . isIE , isWebKit = tinymce . isWebKit , Event ;
tinymce . create ( 'static tinymce.dom.Event' , {
inits : [ ] ,
events : [ ] ,
add : function ( o , n , f , s ) {
var cb , t = this , el = t . events , r ;
// Handle array
if ( o && o . hasOwnProperty && o instanceof Array ) {
r = [ ] ;
each ( o , function ( o ) {
o = DOM . get ( o ) ;
r . push ( t . add ( o , n , f , s ) ) ;
} ) ;
return r ;
}
o = DOM . get ( o ) ;
if ( ! o )
return ;
// Setup event callback
cb = function ( e ) {
e = e || window . event ;
// Patch in target in IE it's W3C valid
if ( e && ! e . target && isIE )
e . target = e . srcElement ;
if ( ! s )
return f ( e ) ;
return f . call ( s , e ) ;
} ;
if ( n == 'unload' ) {
tinymce . unloads . unshift ( { func : cb } ) ;
return cb ;
}
if ( n == 'init' ) {
if ( t . domLoaded )
cb ( ) ;
else
t . inits . push ( cb ) ;
return cb ;
}
// Store away listener reference
el . push ( {
obj : o ,
name : n ,
func : f ,
cfunc : cb ,
scope : s
} ) ;
t . _add ( o , n , cb ) ;
return f ;
} ,
remove : function ( o , n , f ) {
var t = this , a = t . events , s = false , r ;
// Handle array
if ( o && o . hasOwnProperty && o instanceof Array ) {
r = [ ] ;
each ( o , function ( o ) {
o = DOM . get ( o ) ;
r . push ( t . remove ( o , n , f ) ) ;
} ) ;
return r ;
}
o = DOM . get ( o ) ;
each ( a , function ( e , i ) {
if ( e . obj == o && e . name == n && ( ! f || ( e . func == f || e . cfunc == f ) ) ) {
a . splice ( i , 1 ) ;
t . _remove ( o , n , e . cfunc ) ;
s = true ;
return false ;
}
} ) ;
return s ;
} ,
clear : function ( o ) {
var t = this , a = t . events , i , e ;
if ( o ) {
o = DOM . get ( o ) ;
for ( i = a . length - 1 ; i >= 0 ; i -- ) {
e = a [ i ] ;
if ( e . obj === o ) {
t . _remove ( e . obj , e . name , e . cfunc ) ;
e . obj = e . cfunc = null ;
a . splice ( i , 1 ) ;
}
}
}
} ,
cancel : function ( e ) {
if ( ! e )
return false ;
this . stop ( e ) ;
return this . prevent ( e ) ;
} ,
stop : function ( e ) {
if ( e . stopPropagation )
e . stopPropagation ( ) ;
else
e . cancelBubble = true ;
return false ;
} ,
prevent : function ( e ) {
if ( e . preventDefault )
e . preventDefault ( ) ;
else
e . returnValue = false ;
return false ;
} ,
_unload : function ( ) {
var t = Event ;
each ( t . events , function ( e , i ) {
t . _remove ( e . obj , e . name , e . cfunc ) ;
e . obj = e . cfunc = null ;
} ) ;
t . events = [ ] ;
t = null ;
} ,
_add : function ( o , n , f ) {
if ( o . attachEvent )
o . attachEvent ( 'on' + n , f ) ;
else if ( o . addEventListener )
o . addEventListener ( n , f , false ) ;
else
o [ 'on' + n ] = f ;
} ,
_remove : function ( o , n , f ) {
if ( o ) {
try {
if ( o . detachEvent )
o . detachEvent ( 'on' + n , f ) ;
else if ( o . removeEventListener )
o . removeEventListener ( n , f , false ) ;
else
o [ 'on' + n ] = null ;
} catch ( ex ) {
// Might fail with permission denined on IE so we just ignore that
}
}
} ,
_pageInit : function ( ) {
var e = Event ;
// Keep it from running more than once
if ( e . domLoaded )
return ;
e . _remove ( window , 'DOMContentLoaded' , e . _pageInit ) ;
e . domLoaded = true ;
each ( e . inits , function ( c ) {
c ( ) ;
} ) ;
e . inits = [ ] ;
} ,
_wait : function ( ) {
// No need since the document is already loaded
if ( window . tinyMCE _GZ && tinyMCE _GZ . loaded ) {
Event . domLoaded = 1 ;
return ;
}
// Use IE method
if ( document . attachEvent ) {
document . attachEvent ( "onreadystatechange" , function ( ) {
if ( document . readyState === "complete" ) {
document . detachEvent ( "onreadystatechange" , arguments . callee ) ;
Event . _pageInit ( ) ;
}
} ) ;
if ( document . documentElement . doScroll && window == window . top ) {
( function ( ) {
if ( Event . domLoaded )
return ;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
document . documentElement . doScroll ( "left" ) ;
} catch ( ex ) {
setTimeout ( arguments . callee , 0 ) ;
return ;
}
Event . _pageInit ( ) ;
} ) ( ) ;
}
} else if ( document . addEventListener )
Event . _add ( window , 'DOMContentLoaded' , Event . _pageInit , Event ) ;
Event . _add ( window , 'load' , Event . _pageInit , Event ) ;
}
} ) ;
// Shorten name
Event = tinymce . dom . Event ;
// Dispatch DOM content loaded event for IE and Safari
Event . _wait ( ) ;
tinymce . addUnload ( Event . _unload ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var each = tinymce . each ;
tinymce . create ( 'tinymce.dom.Element' , {
Element : function ( id , s ) {
var t = this , dom , el ;
s = s || { } ;
t . id = id ;
t . dom = dom = s . dom || tinymce . DOM ;
t . settings = s ;
// Only IE leaks DOM references, this is a lot faster
if ( ! tinymce . isIE )
el = t . dom . get ( t . id ) ;
each ( [
'getPos' ,
'getRect' ,
'getParent' ,
'add' ,
'setStyle' ,
'getStyle' ,
'setStyles' ,
'setAttrib' ,
'setAttribs' ,
'getAttrib' ,
'addClass' ,
'removeClass' ,
'hasClass' ,
'getOuterHTML' ,
'setOuterHTML' ,
'remove' ,
'show' ,
'hide' ,
'isHidden' ,
'setHTML' ,
'get'
] , function ( k ) {
t [ k ] = function ( ) {
var a = [ id ] , i ;
for ( i = 0 ; i < arguments . length ; i ++ )
a . push ( arguments [ i ] ) ;
a = dom [ k ] . apply ( dom , a ) ;
t . update ( k ) ;
return a ;
} ;
} ) ;
} ,
on : function ( n , f , s ) {
return tinymce . dom . Event . add ( this . id , n , f , s ) ;
} ,
getXY : function ( ) {
return {
x : parseInt ( this . getStyle ( 'left' ) ) ,
y : parseInt ( this . getStyle ( 'top' ) )
} ;
} ,
getSize : function ( ) {
var n = this . dom . get ( this . id ) ;
return {
w : parseInt ( this . getStyle ( 'width' ) || n . clientWidth ) ,
h : parseInt ( this . getStyle ( 'height' ) || n . clientHeight )
} ;
} ,
moveTo : function ( x , y ) {
this . setStyles ( { left : x , top : y } ) ;
} ,
moveBy : function ( x , y ) {
var p = this . getXY ( ) ;
this . moveTo ( p . x + x , p . y + y ) ;
} ,
resizeTo : function ( w , h ) {
this . setStyles ( { width : w , height : h } ) ;
} ,
resizeBy : function ( w , h ) {
var s = this . getSize ( ) ;
this . resizeTo ( s . w + w , s . h + h ) ;
} ,
update : function ( k ) {
var t = this , b , dom = t . dom ;
if ( tinymce . isIE6 && t . settings . blocker ) {
k = k || '' ;
// Ignore getters
if ( k . indexOf ( 'get' ) === 0 || k . indexOf ( 'has' ) === 0 || k . indexOf ( 'is' ) === 0 )
return ;
// Remove blocker on remove
if ( k == 'remove' ) {
dom . remove ( t . blocker ) ;
return ;
}
if ( ! t . blocker ) {
t . blocker = dom . uniqueId ( ) ;
b = dom . add ( t . settings . container || dom . getRoot ( ) , 'iframe' , { id : t . blocker , style : 'position:absolute;' , frameBorder : 0 , src : 'javascript:""' } ) ;
dom . setStyle ( b , 'opacity' , 0 ) ;
} else
b = dom . get ( t . blocker ) ;
dom . setStyle ( b , 'left' , t . getStyle ( 'left' , 1 ) ) ;
dom . setStyle ( b , 'top' , t . getStyle ( 'top' , 1 ) ) ;
dom . setStyle ( b , 'width' , t . getStyle ( 'width' , 1 ) ) ;
dom . setStyle ( b , 'height' , t . getStyle ( 'height' , 1 ) ) ;
dom . setStyle ( b , 'display' , t . getStyle ( 'display' , 1 ) ) ;
dom . setStyle ( b , 'zIndex' , parseInt ( t . getStyle ( 'zIndex' , 1 ) || 0 ) - 1 ) ;
}
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
function trimNl ( s ) {
return s . replace ( /[\n\r]+/g , '' ) ;
} ;
// Shorten names
var is = tinymce . is , isIE = tinymce . isIE , each = tinymce . each ;
tinymce . create ( 'tinymce.dom.Selection' , {
Selection : function ( dom , win , serializer ) {
var t = this ;
t . dom = dom ;
t . win = win ;
t . serializer = serializer ;
// Add events
each ( [
'onBeforeSetContent' ,
'onBeforeGetContent' ,
'onSetContent' ,
'onGetContent'
] , function ( e ) {
t [ e ] = new tinymce . util . Dispatcher ( t ) ;
} ) ;
// No W3C Range support
if ( ! t . win . getSelection )
t . tridentSel = new tinymce . dom . TridentSelection ( t ) ;
// Prevent leaks
tinymce . addUnload ( t . destroy , t ) ;
} ,
getContent : function ( s ) {
var t = this , r = t . getRng ( ) , e = t . dom . create ( "body" ) , se = t . getSel ( ) , wb , wa , n ;
s = s || { } ;
wb = wa = '' ;
s . get = true ;
s . format = s . format || 'html' ;
t . onBeforeGetContent . dispatch ( t , s ) ;
if ( s . format == 'text' )
return t . isCollapsed ( ) ? '' : ( r . text || ( se . toString ? se . toString ( ) : '' ) ) ;
if ( r . cloneContents ) {
n = r . cloneContents ( ) ;
if ( n )
e . appendChild ( n ) ;
} else if ( is ( r . item ) || is ( r . htmlText ) )
e . innerHTML = r . item ? r . item ( 0 ) . outerHTML : r . htmlText ;
else
e . innerHTML = r . toString ( ) ;
// Keep whitespace before and after
if ( /^\s/ . test ( e . innerHTML ) )
wb = ' ' ;
if ( /\s+$/ . test ( e . innerHTML ) )
wa = ' ' ;
s . getInner = true ;
s . content = t . isCollapsed ( ) ? '' : wb + t . serializer . serialize ( e , s ) + wa ;
t . onGetContent . dispatch ( t , s ) ;
return s . content ;
} ,
setContent : function ( h , s ) {
var t = this , r = t . getRng ( ) , c , d = t . win . document ;
s = s || { format : 'html' } ;
s . set = true ;
h = s . content = t . dom . processHTML ( h ) ;
// Dispatch before set content event
t . onBeforeSetContent . dispatch ( t , s ) ;
h = s . content ;
if ( r . insertNode ) {
// Make caret marker since insertNode places the caret in the beginning of text after insert
h += '<span id="__caret">_</span>' ;
// Delete and insert new node
r . deleteContents ( ) ;
r . insertNode ( t . getRng ( ) . createContextualFragment ( h ) ) ;
// Move to caret marker
c = t . dom . get ( '__caret' ) ;
// Make sure we wrap it compleatly, Opera fails with a simple select call
r = d . createRange ( ) ;
r . setStartBefore ( c ) ;
r . setEndAfter ( c ) ;
t . setRng ( r ) ;
// Delete the marker, and hopefully the caret gets placed in the right location
// Removed this since it seems to remove in FF and simply deleting it
// doesn't seem to affect the caret position in any browser
//d.execCommand('Delete', false, null);
// Remove the caret position
t . dom . remove ( '__caret' ) ;
} else {
if ( r . item ) {
// Delete content and get caret text selection
d . execCommand ( 'Delete' , false , null ) ;
r = t . getRng ( ) ;
}
r . pasteHTML ( h ) ;
}
// Dispatch set content event
t . onSetContent . dispatch ( t , s ) ;
} ,
getStart : function ( ) {
var t = this , r = t . getRng ( ) , e ;
if ( isIE ) {
if ( r . item )
return r . item ( 0 ) ;
r = r . duplicate ( ) ;
r . collapse ( 1 ) ;
e = r . parentElement ( ) ;
if ( e && e . nodeName == 'BODY' )
return e . firstChild ;
return e ;
} else {
e = r . startContainer ;
if ( e . nodeName == 'BODY' )
return e . firstChild ;
return t . dom . getParent ( e , '*' ) ;
}
} ,
getEnd : function ( ) {
var t = this , r = t . getRng ( ) , e ;
if ( isIE ) {
if ( r . item )
return r . item ( 0 ) ;
r = r . duplicate ( ) ;
r . collapse ( 0 ) ;
e = r . parentElement ( ) ;
if ( e && e . nodeName == 'BODY' )
return e . lastChild ;
return e ;
} else {
e = r . endContainer ;
if ( e . nodeName == 'BODY' )
return e . lastChild ;
return t . dom . getParent ( e , '*' ) ;
}
} ,
getBookmark : function ( si ) {
var t = this , r = t . getRng ( ) , tr , sx , sy , vp = t . dom . getViewPort ( t . win ) , e , sp , bp , le , c = - 0xFFFFFF , s , ro = t . dom . getRoot ( ) , wb = 0 , wa = 0 , nv ;
sx = vp . x ;
sy = vp . y ;
// Simple bookmark fast but not as persistent
if ( si == 'simple' )
return { rng : r , scrollX : sx , scrollY : sy } ;
// Handle IE
if ( isIE ) {
// Control selection
if ( r . item ) {
e = r . item ( 0 ) ;
each ( t . dom . select ( e . nodeName ) , function ( n , i ) {
if ( e == n ) {
sp = i ;
return false ;
}
} ) ;
return {
tag : e . nodeName ,
index : sp ,
scrollX : sx ,
scrollY : sy
} ;
}
// Text selection
tr = t . dom . doc . body . createTextRange ( ) ;
tr . moveToElementText ( ro ) ;
tr . collapse ( true ) ;
bp = Math . abs ( tr . move ( 'character' , c ) ) ;
tr = r . duplicate ( ) ;
tr . collapse ( true ) ;
sp = Math . abs ( tr . move ( 'character' , c ) ) ;
tr = r . duplicate ( ) ;
tr . collapse ( false ) ;
le = Math . abs ( tr . move ( 'character' , c ) ) - sp ;
return {
start : sp - bp ,
length : le ,
scrollX : sx ,
scrollY : sy
} ;
}
// Handle W3C
e = t . getNode ( ) ;
s = t . getSel ( ) ;
if ( ! s )
return null ;
// Image selection
if ( e && e . nodeName == 'IMG' ) {
return {
scrollX : sx ,
scrollY : sy
} ;
}
// Text selection
function getPos ( r , sn , en ) {
var w = t . dom . doc . createTreeWalker ( r , NodeFilter . SHOW _TEXT , null , false ) , n , p = 0 , d = { } ;
while ( ( n = w . nextNode ( ) ) != null ) {
if ( n == sn )
d . start = p ;
if ( n == en ) {
d . end = p ;
return d ;
}
p += trimNl ( n . nodeValue || '' ) . length ;
}
return null ;
} ;
// Caret or selection
if ( s . anchorNode == s . focusNode && s . anchorOffset == s . focusOffset ) {
e = getPos ( ro , s . anchorNode , s . focusNode ) ;
if ( ! e )
return { scrollX : sx , scrollY : sy } ;
// Count whitespace before
trimNl ( s . anchorNode . nodeValue || '' ) . replace ( /^\s+/ , function ( a ) { wb = a . length ; } ) ;
return {
start : Math . max ( e . start + s . anchorOffset - wb , 0 ) ,
end : Math . max ( e . end + s . focusOffset - wb , 0 ) ,
scrollX : sx ,
scrollY : sy ,
beg : s . anchorOffset - wb == 0
} ;
} else {
e = getPos ( ro , r . startContainer , r . endContainer ) ;
// Count whitespace before start and end container
//(r.startContainer.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
//(r.endContainer.nodeValue || '').replace(/^\s+/, function(a) {wa = a.length;});
if ( ! e )
return { scrollX : sx , scrollY : sy } ;
return {
start : Math . max ( e . start + r . startOffset - wb , 0 ) ,
end : Math . max ( e . end + r . endOffset - wa , 0 ) ,
scrollX : sx ,
scrollY : sy ,
beg : r . startOffset - wb == 0
} ;
}
} ,
moveToBookmark : function ( b ) {
var t = this , r = t . getRng ( ) , s = t . getSel ( ) , ro = t . dom . getRoot ( ) , sd , nvl , nv ;
function getPos ( r , sp , ep ) {
var w = t . dom . doc . createTreeWalker ( r , NodeFilter . SHOW _TEXT , null , false ) , n , p = 0 , d = { } , o , v , wa , wb ;
while ( ( n = w . nextNode ( ) ) != null ) {
wa = wb = 0 ;
nv = n . nodeValue || '' ;
//nv.replace(/^\s+[^\s]/, function(a) {wb = a.length - 1;});
//nv.replace(/[^\s]\s+$/, function(a) {wa = a.length - 1;});
nvl = trimNl ( nv ) . length ;
p += nvl ;
if ( p >= sp && ! d . startNode ) {
o = sp - ( p - nvl ) ;
// Fix for odd quirk in FF
if ( b . beg && o >= nvl )
continue ;
d . startNode = n ;
d . startOffset = o + wb ;
}
if ( p >= ep ) {
d . endNode = n ;
d . endOffset = ep - ( p - nvl ) + wb ;
return d ;
}
}
return null ;
} ;
if ( ! b )
return false ;
t . win . scrollTo ( b . scrollX , b . scrollY ) ;
// Handle explorer
if ( isIE ) {
// Handle simple
if ( r = b . rng ) {
try {
r . select ( ) ;
} catch ( ex ) {
// Ignore
}
return true ;
}
t . win . focus ( ) ;
// Handle control bookmark
if ( b . tag ) {
r = ro . createControlRange ( ) ;
each ( t . dom . select ( b . tag ) , function ( n , i ) {
if ( i == b . index )
r . addElement ( n ) ;
} ) ;
} else {
// Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
try {
// Incorrect bookmark
if ( b . start < 0 )
return true ;
r = s . createRange ( ) ;
r . moveToElementText ( ro ) ;
r . collapse ( true ) ;
r . moveStart ( 'character' , b . start ) ;
r . moveEnd ( 'character' , b . length ) ;
} catch ( ex2 ) {
return true ;
}
}
try {
r . select ( ) ;
} catch ( ex ) {
// Needed for some odd IE bug #1843306
}
return true ;
}
// Handle W3C
if ( ! s )
return false ;
// Handle simple
if ( b . rng ) {
s . removeAllRanges ( ) ;
s . addRange ( b . rng ) ;
} else {
if ( is ( b . start ) && is ( b . end ) ) {
try {
sd = getPos ( ro , b . start , b . end ) ;
if ( sd ) {
r = t . dom . doc . createRange ( ) ;
r . setStart ( sd . startNode , sd . startOffset ) ;
r . setEnd ( sd . endNode , sd . endOffset ) ;
s . removeAllRanges ( ) ;
s . addRange ( r ) ;
}
if ( ! tinymce . isOpera )
t . win . focus ( ) ;
} catch ( ex ) {
// Ignore
}
}
}
} ,
select : function ( n , c ) {
var t = this , r = t . getRng ( ) , s = t . getSel ( ) , b , fn , ln , d = t . win . document ;
function find ( n , start ) {
var walker , o ;
if ( n ) {
walker = d . createTreeWalker ( n , NodeFilter . SHOW _TEXT , null , false ) ;
// Find first/last non empty text node
while ( n = walker . nextNode ( ) ) {
o = n ;
if ( tinymce . trim ( n . nodeValue ) . length != 0 ) {
if ( start )
return n ;
else
o = n ;
}
}
}
return o ;
} ;
if ( isIE ) {
try {
b = d . body ;
if ( /^(IMG|TABLE)$/ . test ( n . nodeName ) ) {
r = b . createControlRange ( ) ;
r . addElement ( n ) ;
} else {
r = b . createTextRange ( ) ;
r . moveToElementText ( n ) ;
}
r . select ( ) ;
} catch ( ex ) {
// Throws illigal agrument in IE some times
}
} else {
if ( c ) {
fn = find ( n , 1 ) || t . dom . select ( 'br:first' , n ) [ 0 ] ;
ln = find ( n , 0 ) || t . dom . select ( 'br:last' , n ) [ 0 ] ;
if ( fn && ln ) {
r = d . createRange ( ) ;
if ( fn . nodeName == 'BR' )
r . setStartBefore ( fn ) ;
else
r . setStart ( fn , 0 ) ;
if ( ln . nodeName == 'BR' )
r . setEndBefore ( ln ) ;
else
r . setEnd ( ln , ln . nodeValue . length ) ;
} else
r . selectNode ( n ) ;
} else
r . selectNode ( n ) ;
t . setRng ( r ) ;
}
return n ;
} ,
isCollapsed : function ( ) {
var t = this , r = t . getRng ( ) , s = t . getSel ( ) ;
if ( ! r || r . item )
return false ;
return ! s || r . boundingWidth == 0 || r . collapsed ;
} ,
collapse : function ( b ) {
var t = this , r = t . getRng ( ) , n ;
// Control range on IE
if ( r . item ) {
n = r . item ( 0 ) ;
r = this . win . document . body . createTextRange ( ) ;
r . moveToElementText ( n ) ;
}
r . collapse ( ! ! b ) ;
t . setRng ( r ) ;
} ,
getSel : function ( ) {
var t = this , w = this . win ;
return w . getSelection ? w . getSelection ( ) : w . document . selection ;
} ,
getRng : function ( w3c ) {
var t = this , s , r ;
// Found tridentSel object then we need to use that one
if ( w3c && t . tridentSel )
return t . tridentSel . getRangeAt ( 0 ) ;
try {
if ( s = t . getSel ( ) )
r = s . rangeCount > 0 ? s . getRangeAt ( 0 ) : ( s . createRange ? s . createRange ( ) : t . win . document . createRange ( ) ) ;
} catch ( ex ) {
// IE throws unspecified error here if TinyMCE is placed in a frame/iframe
}
// No range found then create an empty one
// This can occur when the editor is placed in a hidden container element on Gecko
// Or on IE when there was an exception
if ( ! r )
r = isIE ? t . win . document . body . createTextRange ( ) : t . win . document . createRange ( ) ;
return r ;
} ,
setRng : function ( r ) {
var s , t = this ;
if ( ! t . tridentSel ) {
s = t . getSel ( ) ;
if ( s ) {
s . removeAllRanges ( ) ;
s . addRange ( r ) ;
}
} else {
// Is W3C Range
if ( r . cloneRange ) {
t . tridentSel . addRange ( r ) ;
return ;
}
// Is IE specific range
try {
r . select ( ) ;
} catch ( ex ) {
// Needed for some odd IE bug #1843306
}
}
} ,
setNode : function ( n ) {
var t = this ;
t . setContent ( t . dom . getOuterHTML ( n ) ) ;
return n ;
} ,
getNode : function ( ) {
var t = this , r = t . getRng ( ) , s = t . getSel ( ) , e ;
if ( ! isIE ) {
// Range maybe lost after the editor is made visible again
if ( ! r )
return t . dom . getRoot ( ) ;
e = r . commonAncestorContainer ;
// Handle selection a image or other control like element such as anchors
if ( ! r . collapsed ) {
// If the anchor node is a element instead of a text node then return this element
if ( tinymce . isWebKit && s . anchorNode && s . anchorNode . nodeType == 1 )
return s . anchorNode . childNodes [ s . anchorOffset ] ;
if ( r . startContainer == r . endContainer ) {
if ( r . startOffset - r . endOffset < 2 ) {
if ( r . startContainer . hasChildNodes ( ) )
e = r . startContainer . childNodes [ r . startOffset ] ;
}
}
}
return t . dom . getParent ( e , '*' ) ;
}
return r . item ? r . item ( 0 ) : r . parentElement ( ) ;
} ,
getSelectedBlocks : function ( st , en ) {
var t = this , dom = t . dom , sb , eb , n , bl = [ ] ;
sb = dom . getParent ( st || t . getStart ( ) , dom . isBlock ) ;
eb = dom . getParent ( en || t . getEnd ( ) , dom . isBlock ) ;
if ( sb )
bl . push ( sb ) ;
if ( sb && eb && sb != eb ) {
n = sb ;
while ( ( n = n . nextSibling ) && n != eb ) {
if ( dom . isBlock ( n ) )
bl . push ( n ) ;
}
}
if ( eb && sb != eb )
bl . push ( eb ) ;
return bl ;
} ,
destroy : function ( s ) {
var t = this ;
t . win = null ;
if ( t . tridentSel )
t . tridentSel . destroy ( ) ;
// Manual destroy then remove unload handler
if ( ! s )
tinymce . removeUnload ( t . destroy ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
tinymce . create ( 'tinymce.dom.XMLWriter' , {
node : null ,
XMLWriter : function ( s ) {
// Get XML document
function getXML ( ) {
var i = document . implementation ;
if ( ! i || ! i . createDocument ) {
// Try IE objects
try { return new ActiveXObject ( 'MSXML2.DOMDocument' ) ; } catch ( ex ) { }
try { return new ActiveXObject ( 'Microsoft.XmlDom' ) ; } catch ( ex ) { }
} else
return i . createDocument ( '' , '' , null ) ;
} ;
this . doc = getXML ( ) ;
// Since Opera and WebKit doesn't escape > into > we need to do it our self to normalize the output for all browsers
this . valid = tinymce . isOpera || tinymce . isWebKit ;
this . reset ( ) ;
} ,
reset : function ( ) {
var t = this , d = t . doc ;
if ( d . firstChild )
d . removeChild ( d . firstChild ) ;
t . node = d . appendChild ( d . createElement ( "html" ) ) ;
} ,
writeStartElement : function ( n ) {
var t = this ;
t . node = t . node . appendChild ( t . doc . createElement ( n ) ) ;
} ,
writeAttribute : function ( n , v ) {
if ( this . valid )
v = v . replace ( />/g , '%MCGT%' ) ;
this . node . setAttribute ( n , v ) ;
} ,
writeEndElement : function ( ) {
this . node = this . node . parentNode ;
} ,
writeFullEndElement : function ( ) {
var t = this , n = t . node ;
n . appendChild ( t . doc . createTextNode ( "" ) ) ;
t . node = n . parentNode ;
} ,
writeText : function ( v ) {
if ( this . valid )
v = v . replace ( />/g , '%MCGT%' ) ;
this . node . appendChild ( this . doc . createTextNode ( v ) ) ;
} ,
writeCDATA : function ( v ) {
this . node . appendChild ( this . doc . createCDATA ( v ) ) ;
} ,
writeComment : function ( v ) {
// Fix for bug #2035694
if ( tinymce . isIE )
v = v . replace ( /^\-|\-$/g , ' ' ) ;
this . node . appendChild ( this . doc . createComment ( v . replace ( /\-\-/g , ' ' ) ) ) ;
} ,
getContent : function ( ) {
var h ;
h = this . doc . xml || new XMLSerializer ( ) . serializeToString ( this . doc ) ;
h = h . replace ( /<\?[^?]+\?>|<html>|<\/html>|<html\/>|<!DOCTYPE[^>]+>/g , '' ) ;
h = h . replace ( / ?\/>/g , ' />' ) ;
if ( this . valid )
h = h . replace ( /\%MCGT%/g , '>' ) ;
return h ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
tinymce . create ( 'tinymce.dom.StringWriter' , {
str : null ,
tags : null ,
count : 0 ,
settings : null ,
indent : null ,
StringWriter : function ( s ) {
this . settings = tinymce . extend ( {
indent _char : ' ' ,
indentation : 1
} , s ) ;
this . reset ( ) ;
} ,
reset : function ( ) {
this . indent = '' ;
this . str = "" ;
this . tags = [ ] ;
this . count = 0 ;
} ,
writeStartElement : function ( n ) {
this . _writeAttributesEnd ( ) ;
this . writeRaw ( '<' + n ) ;
this . tags . push ( n ) ;
this . inAttr = true ;
this . count ++ ;
this . elementCount = this . count ;
} ,
writeAttribute : function ( n , v ) {
var t = this ;
t . writeRaw ( " " + t . encode ( n ) + '="' + t . encode ( v ) + '"' ) ;
} ,
writeEndElement : function ( ) {
var n ;
if ( this . tags . length > 0 ) {
n = this . tags . pop ( ) ;
if ( this . _writeAttributesEnd ( 1 ) )
this . writeRaw ( '</' + n + '>' ) ;
if ( this . settings . indentation > 0 )
this . writeRaw ( '\n' ) ;
}
} ,
writeFullEndElement : function ( ) {
if ( this . tags . length > 0 ) {
this . _writeAttributesEnd ( ) ;
this . writeRaw ( '</' + this . tags . pop ( ) + '>' ) ;
if ( this . settings . indentation > 0 )
this . writeRaw ( '\n' ) ;
}
} ,
writeText : function ( v ) {
this . _writeAttributesEnd ( ) ;
this . writeRaw ( this . encode ( v ) ) ;
this . count ++ ;
} ,
writeCDATA : function ( v ) {
this . _writeAttributesEnd ( ) ;
this . writeRaw ( '<![CDATA[' + v + ']]>' ) ;
this . count ++ ;
} ,
writeComment : function ( v ) {
this . _writeAttributesEnd ( ) ;
this . writeRaw ( '<!-- ' + v + '-->' ) ;
this . count ++ ;
} ,
writeRaw : function ( v ) {
this . str += v ;
} ,
encode : function ( s ) {
return s . replace ( /[<>&"]/g , function ( v ) {
switch ( v ) {
case '<' :
return '<' ;
case '>' :
return '>' ;
case '&' :
return '&' ;
case '"' :
return '"' ;
}
return v ;
} ) ;
} ,
getContent : function ( ) {
return this . str ;
} ,
_writeAttributesEnd : function ( s ) {
if ( ! this . inAttr )
return ;
this . inAttr = false ;
if ( s && this . elementCount == this . count ) {
this . writeRaw ( ' />' ) ;
return false ;
}
this . writeRaw ( '>' ) ;
return true ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
// Shorten names
var extend = tinymce . extend , each = tinymce . each , Dispatcher = tinymce . util . Dispatcher , isIE = tinymce . isIE , isGecko = tinymce . isGecko ;
function wildcardToRE ( s ) {
return s . replace ( /([?+*])/g , '.$1' ) ;
} ;
tinymce . create ( 'tinymce.dom.Serializer' , {
Serializer : function ( s ) {
var t = this ;
t . key = 0 ;
t . onPreProcess = new Dispatcher ( t ) ;
t . onPostProcess = new Dispatcher ( t ) ;
try {
t . writer = new tinymce . dom . XMLWriter ( ) ;
} catch ( ex ) {
// IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter
t . writer = new tinymce . dom . StringWriter ( ) ;
}
// Default settings
t . settings = s = extend ( {
dom : tinymce . DOM ,
valid _nodes : 0 ,
node _filter : 0 ,
attr _filter : 0 ,
invalid _attrs : /^(mce_|_moz_)/ ,
closed : /^(br|hr|input|meta|img|link|param|area)$/ ,
entity _encoding : 'named' ,
entities : '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro' ,
bool _attrs : /(checked|disabled|readonly|selected|nowrap)/ ,
valid _elements : '*[*]' ,
extended _valid _elements : 0 ,
valid _child _elements : 0 ,
invalid _elements : 0 ,
fix _table _elements : 1 ,
fix _list _elements : true ,
fix _content _duplication : true ,
convert _fonts _to _spans : false ,
font _size _classes : 0 ,
font _size _style _values : 0 ,
apply _source _formatting : 0 ,
indent _mode : 'simple' ,
indent _char : '\t' ,
indent _levels : 1 ,
remove _linebreaks : 1 ,
remove _redundant _brs : 1 ,
element _format : 'xhtml'
} , s ) ;
t . dom = s . dom ;
if ( s . remove _redundant _brs ) {
t . onPostProcess . add ( function ( se , o ) {
// Remove single BR at end of block elements since they get rendered
o . content = o . content . replace ( /(<br \/>\s*)+<\/(p|h[1-6]|div|li)>/gi , function ( a , b , c ) {
// Check if it's a single element
if ( /^<br \/>\s*<\// . test ( a ) )
return '</' + c + '>' ;
return a ;
} ) ;
} ) ;
}
// Remove XHTML element endings i.e. produce crap :) XHTML is better
if ( s . element _format == 'html' ) {
t . onPostProcess . add ( function ( se , o ) {
o . content = o . content . replace ( /<([^>]+) \/>/g , '<$1>' ) ;
} ) ;
}
if ( s . fix _list _elements ) {
t . onPreProcess . add ( function ( se , o ) {
var nl , x , a = [ 'ol' , 'ul' ] , i , n , p , r = /^(OL|UL)$/ , np ;
function prevNode ( e , n ) {
var a = n . split ( ',' ) , i ;
while ( ( e = e . previousSibling ) != null ) {
for ( i = 0 ; i < a . length ; i ++ ) {
if ( e . nodeName == a [ i ] )
return e ;
}
}
return null ;
} ;
for ( x = 0 ; x < a . length ; x ++ ) {
nl = t . dom . select ( a [ x ] , o . node ) ;
for ( i = 0 ; i < nl . length ; i ++ ) {
n = nl [ i ] ;
p = n . parentNode ;
if ( r . test ( p . nodeName ) ) {
np = prevNode ( n , 'LI' ) ;
if ( ! np ) {
np = t . dom . create ( 'li' ) ;
np . innerHTML = ' ' ;
np . appendChild ( n ) ;
p . insertBefore ( np , p . firstChild ) ;
} else
np . appendChild ( n ) ;
}
}
}
} ) ;
}
if ( s . fix _table _elements ) {
t . onPreProcess . add ( function ( se , o ) {
each ( t . dom . select ( 'p table' , o . node ) , function ( n ) {
t . dom . split ( t . dom . getParent ( n , 'p' ) , n ) ;
} ) ;
} ) ;
}
} ,
setEntities : function ( s ) {
var t = this , a , i , l = { } , re = '' , v ;
// No need to setup more than once
if ( t . entityLookup )
return ;
// Build regex and lookup array
a = s . split ( ',' ) ;
for ( i = 0 ; i < a . length ; i += 2 ) {
v = a [ i ] ;
// Don't add default & " etc.
if ( v == 34 || v == 38 || v == 60 || v == 62 )
continue ;
l [ String . fromCharCode ( a [ i ] ) ] = a [ i + 1 ] ;
v = parseInt ( a [ i ] ) . toString ( 16 ) ;
re += '\\u' + '0000' . substring ( v . length ) + v ;
}
if ( ! re ) {
t . settings . entity _encoding = 'raw' ;
return ;
}
t . entitiesRE = new RegExp ( '[' + re + ']' , 'g' ) ;
t . entityLookup = l ;
} ,
setValidChildRules : function ( s ) {
this . childRules = null ;
this . addValidChildRules ( s ) ;
} ,
addValidChildRules : function ( s ) {
var t = this , inst , intr , bloc ;
if ( ! s )
return ;
inst = 'A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment' ;
intr = 'A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment' ;
bloc = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP' ;
each ( s . split ( ',' ) , function ( s ) {
var p = s . split ( /\[|\]/ ) , re ;
s = '' ;
each ( p [ 1 ] . split ( '|' ) , function ( v ) {
if ( s )
s += '|' ;
switch ( v ) {
case '%itrans' :
v = intr ;
break ;
case '%itrans_na' :
v = intr . substring ( 2 ) ;
break ;
case '%istrict' :
v = inst ;
break ;
case '%istrict_na' :
v = inst . substring ( 2 ) ;
break ;
case '%btrans' :
v = bloc ;
break ;
case '%bstrict' :
v = bloc ;
break ;
}
s += v ;
} ) ;
re = new RegExp ( '^(' + s . toLowerCase ( ) + ')$' , 'i' ) ;
each ( p [ 0 ] . split ( '/' ) , function ( s ) {
t . childRules = t . childRules || { } ;
t . childRules [ s ] = re ;
} ) ;
} ) ;
// Build regex
s = '' ;
each ( t . childRules , function ( v , k ) {
if ( s )
s += '|' ;
s += k ;
} ) ;
t . parentElementsRE = new RegExp ( '^(' + s . toLowerCase ( ) + ')$' , 'i' ) ;
/ * c o n s o l e . d e b u g ( t . p a r e n t E l e m e n t s R E . t o S t r i n g ( ) ) ;
each ( t . childRules , function ( v ) {
console . debug ( v . toString ( ) ) ;
} ) ; * /
} ,
setRules : function ( s ) {
var t = this ;
t . _setup ( ) ;
t . rules = { } ;
t . wildRules = [ ] ;
t . validElements = { } ;
return t . addRules ( s ) ;
} ,
addRules : function ( s ) {
var t = this , dr ;
if ( ! s )
return ;
t . _setup ( ) ;
each ( s . split ( ',' ) , function ( s ) {
var p = s . split ( /\[|\]/ ) , tn = p [ 0 ] . split ( '/' ) , ra , at , wat , va = [ ] ;
// Extend with default rules
if ( dr )
at = tinymce . extend ( [ ] , dr . attribs ) ;
// Parse attributes
if ( p . length > 1 ) {
each ( p [ 1 ] . split ( '|' ) , function ( s ) {
var ar = { } , i ;
at = at || [ ] ;
// Parse attribute rule
s = s . replace ( /::/g , '~' ) ;
s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/ . exec ( s ) ;
s [ 2 ] = s [ 2 ] . replace ( /~/g , ':' ) ;
// Add required attributes
if ( s [ 1 ] == '!' ) {
ra = ra || [ ] ;
ra . push ( s [ 2 ] ) ;
}
// Remove inherited attributes
if ( s [ 1 ] == '-' ) {
for ( i = 0 ; i < at . length ; i ++ ) {
if ( at [ i ] . name == s [ 2 ] ) {
at . splice ( i , 1 ) ;
return ;
}
}
}
switch ( s [ 3 ] ) {
// Add default attrib values
case '=' :
ar . defaultVal = s [ 4 ] || '' ;
break ;
// Add forced attrib values
case ':' :
ar . forcedVal = s [ 4 ] ;
break ;
// Add validation values
case '<' :
ar . validVals = s [ 4 ] . split ( '?' ) ;
break ;
}
if ( /[*.?]/ . test ( s [ 2 ] ) ) {
wat = wat || [ ] ;
ar . nameRE = new RegExp ( '^' + wildcardToRE ( s [ 2 ] ) + '$' ) ;
wat . push ( ar ) ;
} else {
ar . name = s [ 2 ] ;
at . push ( ar ) ;
}
va . push ( s [ 2 ] ) ;
} ) ;
}
// Handle element names
each ( tn , function ( s , i ) {
var pr = s . charAt ( 0 ) , x = 1 , ru = { } ;
// Extend with default rule data
if ( dr ) {
if ( dr . noEmpty )
ru . noEmpty = dr . noEmpty ;
if ( dr . fullEnd )
ru . fullEnd = dr . fullEnd ;
if ( dr . padd )
ru . padd = dr . padd ;
}
// Handle prefixes
switch ( pr ) {
case '-' :
ru . noEmpty = true ;
break ;
case '+' :
ru . fullEnd = true ;
break ;
case '#' :
ru . padd = true ;
break ;
default :
x = 0 ;
}
tn [ i ] = s = s . substring ( x ) ;
t . validElements [ s ] = 1 ;
// Add element name or element regex
if ( /[*.?]/ . test ( tn [ 0 ] ) ) {
ru . nameRE = new RegExp ( '^' + wildcardToRE ( tn [ 0 ] ) + '$' ) ;
t . wildRules = t . wildRules || { } ;
t . wildRules . push ( ru ) ;
} else {
ru . name = tn [ 0 ] ;
// Store away default rule
if ( tn [ 0 ] == '@' )
dr = ru ;
t . rules [ s ] = ru ;
}
ru . attribs = at ;
if ( ra )
ru . requiredAttribs = ra ;
if ( wat ) {
// Build valid attributes regexp
s = '' ;
each ( va , function ( v ) {
if ( s )
s += '|' ;
s += '(' + wildcardToRE ( v ) + ')' ;
} ) ;
ru . validAttribsRE = new RegExp ( '^' + s . toLowerCase ( ) + '$' ) ;
ru . wildAttribs = wat ;
}
} ) ;
} ) ;
// Build valid elements regexp
s = '' ;
each ( t . validElements , function ( v , k ) {
if ( s )
s += '|' ;
if ( k != '@' )
s += k ;
} ) ;
t . validElementsRE = new RegExp ( '^(' + wildcardToRE ( s . toLowerCase ( ) ) + ')$' ) ;
//console.debug(t.validElementsRE.toString());
//console.dir(t.rules);
//console.dir(t.wildRules);
} ,
findRule : function ( n ) {
var t = this , rl = t . rules , i , r ;
t . _setup ( ) ;
// Exact match
r = rl [ n ] ;
if ( r )
return r ;
// Try wildcards
rl = t . wildRules ;
for ( i = 0 ; i < rl . length ; i ++ ) {
if ( rl [ i ] . nameRE . test ( n ) )
return rl [ i ] ;
}
return null ;
} ,
findAttribRule : function ( ru , n ) {
var i , wa = ru . wildAttribs ;
for ( i = 0 ; i < wa . length ; i ++ ) {
if ( wa [ i ] . nameRE . test ( n ) )
return wa [ i ] ;
}
return null ;
} ,
serialize : function ( n , o ) {
var h , t = this ;
t . _setup ( ) ;
o = o || { } ;
o . format = o . format || 'html' ;
t . processObj = o ;
n = n . cloneNode ( true ) ;
t . key = '' + ( parseInt ( t . key ) + 1 ) ;
// Pre process
if ( ! o . no _events ) {
o . node = n ;
t . onPreProcess . dispatch ( t , o ) ;
}
// Serialize HTML DOM into a string
t . writer . reset ( ) ;
t . _serializeNode ( n , o . getInner ) ;
// Post process
o . content = t . writer . getContent ( ) ;
if ( ! o . no _events )
t . onPostProcess . dispatch ( t , o ) ;
t . _postProcess ( o ) ;
o . node = null ;
return tinymce . trim ( o . content ) ;
} ,
// Internal functions
_postProcess : function ( o ) {
var t = this , s = t . settings , h = o . content , sc = [ ] , p ;
if ( o . format == 'html' ) {
// Protect some elements
p = t . _protect ( {
content : h ,
patterns : [
{ pattern : /(<script[^>]*>)(.*?)(<\/script>)/g } ,
{ pattern : /(<style[^>]*>)(.*?)(<\/style>)/g } ,
{ pattern : /(<pre[^>]*>)(.*?)(<\/pre>)/g , encode : 1 } ,
{ pattern : /(<!--\[CDATA\[)(.*?)(\]\]-->)/g }
]
} ) ;
h = p . content ;
// Entity encode
if ( s . entity _encoding !== 'raw' )
h = t . _encode ( h ) ;
// Use BR instead of padded P elements inside editor and use <p> </p> outside editor
/ * i f ( o . s e t )
h = h . replace ( /<p>\s+( | |\u00a0|<br \/>)\s+<\/p>/g , '<p><br /></p>' ) ;
else
h = h . replace ( /<p>\s+( | |\u00a0|<br \/>)\s+<\/p>/g , '<p>$1</p>' ) ; * /
// Since Gecko and Safari keeps whitespace in the DOM we need to
// remove it inorder to match other browsers. But I think Gecko and Safari is right.
// This process is only done when getting contents out from the editor.
if ( ! o . set ) {
// We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char
h = h . replace ( /<p>\s+<\/p>|<p([^>]+)>\s+<\/p>/g , s . entity _encoding == 'numeric' ? '<p$1> </p>' : '<p$1> </p>' ) ;
if ( s . remove _linebreaks ) {
h = h . replace ( /\r?\n|\r/g , ' ' ) ;
h = h . replace ( /(<[^>]+>)\s+/g , '$1 ' ) ;
h = h . replace ( /\s+(<\/[^>]+>)/g , ' $1' ) ;
h = h . replace ( /<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g , '<$1 $2>' ) ; // Trim block start
h = h . replace ( /<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g , '<$1>' ) ; // Trim block start
h = h . replace ( /\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g , '</$1>' ) ; // Trim block end
}
// Simple indentation
if ( s . apply _source _formatting && s . indent _mode == 'simple' ) {
// Add line breaks before and after block elements
h = h . replace ( /<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g , '\n<$1$2$3>\n' ) ;
h = h . replace ( /\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g , '\n<$1$2>' ) ;
h = h . replace ( /<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g , '</$1>\n' ) ;
h = h . replace ( /\n\n/g , '\n' ) ;
}
}
h = t . _unprotect ( h , p ) ;
// Restore CDATA sections
h = h . replace ( /<!--\[CDATA\[([\s\S]+)\]\]-->/g , '<![CDATA[$1]]>' ) ;
// Restore the \u00a0 character if raw mode is enabled
if ( s . entity _encoding == 'raw' )
h = h . replace ( /<p> <\/p>|<p([^>]+)> <\/p>/g , '<p$1>\u00a0</p>' ) ;
}
o . content = h ;
} ,
_serializeNode : function ( n , inn ) {
var t = this , s = t . settings , w = t . writer , hc , el , cn , i , l , a , at , no , v , nn , ru , ar , iv ;
if ( ! s . node _filter || s . node _filter ( n ) ) {
switch ( n . nodeType ) {
case 1 : // Element
if ( n . hasAttribute ? n . hasAttribute ( 'mce_bogus' ) : n . getAttribute ( 'mce_bogus' ) )
return ;
iv = false ;
hc = n . hasChildNodes ( ) ;
nn = n . getAttribute ( 'mce_name' ) || n . nodeName . toLowerCase ( ) ;
// Add correct prefix on IE
if ( isIE ) {
if ( n . scopeName !== 'HTML' && n . scopeName !== 'html' )
nn = n . scopeName + ':' + nn ;
}
// Remove mce prefix on IE needed for the abbr element
if ( nn . indexOf ( 'mce:' ) === 0 )
nn = nn . substring ( 4 ) ;
// Check if valid
if ( ! t . validElementsRE . test ( nn ) || ( t . invalidElementsRE && t . invalidElementsRE . test ( nn ) ) || inn ) {
iv = true ;
break ;
}
if ( isIE ) {
// Fix IE content duplication (DOM can have multiple copies of the same node)
if ( s . fix _content _duplication ) {
if ( n . mce _serialized == t . key )
return ;
n . mce _serialized = t . key ;
}
// IE sometimes adds a / infront of the node name
if ( nn . charAt ( 0 ) == '/' )
nn = nn . substring ( 1 ) ;
} else if ( isGecko ) {
// Ignore br elements
if ( n . nodeName === 'BR' && n . getAttribute ( 'type' ) == '_moz' )
return ;
}
// Check if valid child
if ( t . childRules ) {
if ( t . parentElementsRE . test ( t . elementName ) ) {
if ( ! t . childRules [ t . elementName ] . test ( nn ) ) {
iv = true ;
break ;
}
}
t . elementName = nn ;
}
ru = t . findRule ( nn ) ;
nn = ru . name || nn ;
// Skip empty nodes or empty node name in IE
if ( ( ! hc && ru . noEmpty ) || ( isIE && ! nn ) ) {
iv = true ;
break ;
}
// Check required
if ( ru . requiredAttribs ) {
a = ru . requiredAttribs ;
for ( i = a . length - 1 ; i >= 0 ; i -- ) {
if ( this . dom . getAttrib ( n , a [ i ] ) !== '' )
break ;
}
// None of the required was there
if ( i == - 1 ) {
iv = true ;
break ;
}
}
w . writeStartElement ( nn ) ;
// Add ordered attributes
if ( ru . attribs ) {
for ( i = 0 , at = ru . attribs , l = at . length ; i < l ; i ++ ) {
a = at [ i ] ;
v = t . _getAttrib ( n , a ) ;
if ( v !== null )
w . writeAttribute ( a . name , v ) ;
}
}
// Add wild attributes
if ( ru . validAttribsRE ) {
at = t . dom . getAttribs ( n ) ;
for ( i = at . length - 1 ; i > - 1 ; i -- ) {
no = at [ i ] ;
if ( no . specified ) {
a = no . nodeName . toLowerCase ( ) ;
if ( s . invalid _attrs . test ( a ) || ! ru . validAttribsRE . test ( a ) )
continue ;
ar = t . findAttribRule ( ru , a ) ;
v = t . _getAttrib ( n , ar , a ) ;
if ( v !== null )
w . writeAttribute ( a , v ) ;
}
}
}
// Padd empty nodes with a
if ( ru . padd ) {
// If it has only one bogus child, padd it anyway workaround for <td><br /></td> bug
if ( hc && ( cn = n . firstChild ) && cn . nodeType === 1 && n . childNodes . length === 1 ) {
if ( cn . hasAttribute ? cn . hasAttribute ( 'mce_bogus' ) : cn . getAttribute ( 'mce_bogus' ) )
w . writeText ( '\u00a0' ) ;
} else if ( ! hc )
w . writeText ( '\u00a0' ) ; // No children then padd it
}
break ;
case 3 : // Text
// Check if valid child
if ( t . childRules && t . parentElementsRE . test ( t . elementName ) ) {
if ( ! t . childRules [ t . elementName ] . test ( n . nodeName ) )
return ;
}
return w . writeText ( n . nodeValue ) ;
case 4 : // CDATA
return w . writeCDATA ( n . nodeValue ) ;
case 8 : // Comment
return w . writeComment ( n . nodeValue ) ;
}
} else if ( n . nodeType == 1 )
hc = n . hasChildNodes ( ) ;
if ( hc ) {
cn = n . firstChild ;
while ( cn ) {
t . _serializeNode ( cn ) ;
t . elementName = nn ;
cn = cn . nextSibling ;
}
}
// Write element end
if ( ! iv ) {
if ( hc || ! s . closed . test ( nn ) )
w . writeFullEndElement ( ) ;
else
w . writeEndElement ( ) ;
}
} ,
_protect : function ( o ) {
var t = this ;
o . items = o . items || [ ] ;
function enc ( s ) {
return s . replace ( /[\r\n\\]/g , function ( c ) {
if ( c === '\n' )
return '\\n' ;
else if ( c === '\\' )
return '\\\\' ;
return '\\r' ;
} ) ;
} ;
function dec ( s ) {
return s . replace ( /\\[\\rn]/g , function ( c ) {
if ( c === '\\n' )
return '\n' ;
else if ( c === '\\\\' )
return '\\' ;
return '\r' ;
} ) ;
} ;
each ( o . patterns , function ( p ) {
o . content = dec ( enc ( o . content ) . replace ( p . pattern , function ( x , a , b , c ) {
b = dec ( b ) ;
if ( p . encode )
b = t . _encode ( b ) ;
o . items . push ( b ) ;
return a + '<!--mce:' + ( o . items . length - 1 ) + '-->' + c ;
} ) ) ;
} ) ;
return o ;
} ,
_unprotect : function ( h , o ) {
h = h . replace ( /\<!--mce:([0-9]+)--\>/g , function ( a , b ) {
return o . items [ parseInt ( b ) ] ;
} ) ;
o . items = [ ] ;
return h ;
} ,
_encode : function ( h ) {
var t = this , s = t . settings , l ;
// Entity encode
if ( s . entity _encoding !== 'raw' ) {
if ( s . entity _encoding . indexOf ( 'named' ) != - 1 ) {
t . setEntities ( s . entities ) ;
l = t . entityLookup ;
h = h . replace ( t . entitiesRE , function ( a ) {
var v ;
if ( v = l [ a ] )
a = '&' + v + ';' ;
return a ;
} ) ;
}
if ( s . entity _encoding . indexOf ( 'numeric' ) != - 1 ) {
h = h . replace ( /[\u007E-\uFFFF]/g , function ( a ) {
return '&#' + a . charCodeAt ( 0 ) + ';' ;
} ) ;
}
}
return h ;
} ,
_setup : function ( ) {
var t = this , s = this . settings ;
if ( t . done )
return ;
t . done = 1 ;
t . setRules ( s . valid _elements ) ;
t . addRules ( s . extended _valid _elements ) ;
t . addValidChildRules ( s . valid _child _elements ) ;
if ( s . invalid _elements )
t . invalidElementsRE = new RegExp ( '^(' + wildcardToRE ( s . invalid _elements . replace ( /,/g , '|' ) . toLowerCase ( ) ) + ')$' ) ;
if ( s . attrib _value _filter )
t . attribValueFilter = s . attribValueFilter ;
} ,
_getAttrib : function ( n , a , na ) {
var i , v ;
na = na || a . name ;
if ( a . forcedVal && ( v = a . forcedVal ) ) {
if ( v === '{$uid}' )
return this . dom . uniqueId ( ) ;
return v ;
}
v = this . dom . getAttrib ( n , na ) ;
// Bool attr
if ( this . settings . bool _attrs . test ( na ) && v ) {
v = ( '' + v ) . toLowerCase ( ) ;
if ( v === 'false' || v === '0' )
return null ;
v = na ;
}
switch ( na ) {
case 'rowspan' :
case 'colspan' :
// Whats the point? Remove usless attribute value
if ( v == '1' )
v = '' ;
break ;
}
if ( this . attribValueFilter )
v = this . attribValueFilter ( na , v , n ) ;
if ( a . validVals ) {
for ( i = a . validVals . length - 1 ; i >= 0 ; i -- ) {
if ( v == a . validVals [ i ] )
break ;
}
if ( i == - 1 )
return null ;
}
if ( v === '' && typeof ( a . defaultVal ) != 'undefined' ) {
v = a . defaultVal ;
if ( v === '{$uid}' )
return this . dom . uniqueId ( ) ;
return v ;
} else {
// Remove internal mceItemXX classes when content is extracted from editor
if ( na == 'class' && this . processObj . get )
v = v . replace ( /\s?mceItem\w+\s?/g , '' ) ;
}
if ( v === '' )
return null ;
return v ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var each = tinymce . each , Event = tinymce . dom . Event ;
tinymce . create ( 'tinymce.dom.ScriptLoader' , {
ScriptLoader : function ( s ) {
this . settings = s || { } ;
this . queue = [ ] ;
this . lookup = { } ;
} ,
isDone : function ( u ) {
return this . lookup [ u ] ? this . lookup [ u ] . state == 2 : 0 ;
} ,
markDone : function ( u ) {
this . lookup [ u ] = { state : 2 , url : u } ;
} ,
add : function ( u , cb , s , pr ) {
var t = this , lo = t . lookup , o ;
if ( o = lo [ u ] ) {
// Is loaded fire callback
if ( cb && o . state == 2 )
cb . call ( s || this ) ;
return o ;
}
o = { state : 0 , url : u , func : cb , scope : s || this } ;
if ( pr )
t . queue . unshift ( o ) ;
else
t . queue . push ( o ) ;
lo [ u ] = o ;
return o ;
} ,
load : function ( u , cb , s ) {
var t = this , o ;
if ( o = t . lookup [ u ] ) {
// Is loaded fire callback
if ( cb && o . state == 2 )
cb . call ( s || t ) ;
return o ;
}
function loadScript ( u ) {
if ( Event . domLoaded || t . settings . strict _mode ) {
tinymce . util . XHR . send ( {
url : tinymce . _addVer ( u ) ,
error : t . settings . error ,
async : false ,
success : function ( co ) {
t . eval ( co ) ;
}
} ) ;
} else
document . write ( '<script type="text/javascript" src="' + tinymce . _addVer ( u ) + '"></script>' ) ;
} ;
if ( ! tinymce . is ( u , 'string' ) ) {
each ( u , function ( u ) {
loadScript ( u ) ;
} ) ;
if ( cb )
cb . call ( s || t ) ;
} else {
loadScript ( u ) ;
if ( cb )
cb . call ( s || t ) ;
}
} ,
loadQueue : function ( cb , s ) {
var t = this ;
if ( ! t . queueLoading ) {
t . queueLoading = 1 ;
t . queueCallbacks = [ ] ;
t . loadScripts ( t . queue , function ( ) {
t . queueLoading = 0 ;
if ( cb )
cb . call ( s || t ) ;
each ( t . queueCallbacks , function ( o ) {
o . func . call ( o . scope ) ;
} ) ;
} ) ;
} else if ( cb )
t . queueCallbacks . push ( { func : cb , scope : s || t } ) ;
} ,
eval : function ( co ) {
var w = window ;
// Evaluate script
if ( ! w . execScript ) {
try {
eval . call ( w , co ) ;
} catch ( ex ) {
eval ( co , w ) ; // Firefox 3.0a8
}
} else
w . execScript ( co ) ; // IE
} ,
loadScripts : function ( sc , cb , s ) {
var t = this , lo = t . lookup ;
function done ( o ) {
o . state = 2 ; // Has been loaded
// Run callback
if ( o . func )
o . func . call ( o . scope || t ) ;
} ;
function allDone ( ) {
var l ;
// Check if all files are loaded
l = sc . length ;
each ( sc , function ( o ) {
o = lo [ o . url ] ;
if ( o . state === 2 ) { // It has finished loading
done ( o ) ;
l -- ;
} else
load ( o ) ;
} ) ;
// They are all loaded
if ( l === 0 && cb ) {
cb . call ( s || t ) ;
cb = 0 ;
}
} ;
function load ( o ) {
if ( o . state > 0 )
return ;
o . state = 1 ; // Is loading
tinymce . dom . ScriptLoader . loadScript ( o . url , function ( ) {
done ( o ) ;
allDone ( ) ;
} ) ;
/ *
tinymce . util . XHR . send ( {
url : o . url ,
error : t . settings . error ,
success : function ( co ) {
t . eval ( co ) ;
done ( o ) ;
allDone ( ) ;
}
} ) ;
* /
} ;
each ( sc , function ( o ) {
var u = o . url ;
// Add to queue if needed
if ( ! lo [ u ] ) {
lo [ u ] = o ;
t . queue . push ( o ) ;
} else
o = lo [ u ] ;
// Is already loading or has been loaded
if ( o . state > 0 )
return ;
if ( ! Event . domLoaded && ! t . settings . strict _mode ) {
var ix , ol = '' ;
// Add onload events
if ( cb || o . func ) {
o . state = 1 ; // Is loading
ix = tinymce . dom . ScriptLoader . _addOnLoad ( function ( ) {
done ( o ) ;
allDone ( ) ;
} ) ;
if ( tinymce . isIE )
ol = ' onreadystatechange="' ;
else
ol = ' onload="' ;
ol += 'tinymce.dom.ScriptLoader._onLoad(this,\'' + u + '\',' + ix + ');"' ;
}
document . write ( '<script type="text/javascript" src="' + tinymce . _addVer ( u ) + '"' + ol + '></script>' ) ;
if ( ! o . func )
done ( o ) ;
} else
load ( o ) ;
} ) ;
allDone ( ) ;
} ,
// Static methods
'static' : {
_addOnLoad : function ( f ) {
var t = this ;
t . _funcs = t . _funcs || [ ] ;
t . _funcs . push ( f ) ;
return t . _funcs . length - 1 ;
} ,
_onLoad : function ( e , u , ix ) {
if ( ! tinymce . isIE || e . readyState == 'complete' )
this . _funcs [ ix ] . call ( this ) ;
} ,
loadScript : function ( u , cb ) {
var id = tinymce . DOM . uniqueId ( ) , e ;
function done ( ) {
Event . clear ( id ) ;
tinymce . DOM . remove ( id ) ;
if ( cb ) {
cb . call ( document , u ) ;
cb = 0 ;
}
} ;
if ( tinymce . isIE ) {
/ * E v e n t . a d d ( e , ' r e a d y s t a t e c h a n g e ' , f u n c t i o n ( e ) {
if ( e . target && e . target . readyState == 'complete' )
done ( ) ;
} ) ; * /
tinymce . util . XHR . send ( {
url : tinymce . _addVer ( u ) ,
async : false ,
success : function ( co ) {
window . execScript ( co ) ;
done ( ) ;
}
} ) ;
} else {
e = tinymce . DOM . create ( 'script' , { id : id , type : 'text/javascript' , src : tinymce . _addVer ( u ) } ) ;
Event . add ( e , 'load' , done ) ;
// Check for head or body
( document . getElementsByTagName ( 'head' ) [ 0 ] || document . body ) . appendChild ( e ) ;
}
}
}
} ) ;
// Global script loader
tinymce . ScriptLoader = new tinymce . dom . ScriptLoader ( ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
// Shorten class names
var DOM = tinymce . DOM , is = tinymce . is ;
tinymce . create ( 'tinymce.ui.Control' , {
Control : function ( id , s ) {
this . id = id ;
this . settings = s = s || { } ;
this . rendered = false ;
this . onRender = new tinymce . util . Dispatcher ( this ) ;
this . classPrefix = '' ;
this . scope = s . scope || this ;
this . disabled = 0 ;
this . active = 0 ;
} ,
setDisabled : function ( s ) {
var e ;
if ( s != this . disabled ) {
e = DOM . get ( this . id ) ;
// Add accessibility title for unavailable actions
if ( e && this . settings . unavailable _prefix ) {
if ( s ) {
this . prevTitle = e . title ;
e . title = this . settings . unavailable _prefix + ": " + e . title ;
} else
e . title = this . prevTitle ;
}
this . setState ( 'Disabled' , s ) ;
this . setState ( 'Enabled' , ! s ) ;
this . disabled = s ;
}
} ,
isDisabled : function ( ) {
return this . disabled ;
} ,
setActive : function ( s ) {
if ( s != this . active ) {
this . setState ( 'Active' , s ) ;
this . active = s ;
}
} ,
isActive : function ( ) {
return this . active ;
} ,
setState : function ( c , s ) {
var n = DOM . get ( this . id ) ;
c = this . classPrefix + c ;
if ( s )
DOM . addClass ( n , c ) ;
else
DOM . removeClass ( n , c ) ;
} ,
isRendered : function ( ) {
return this . rendered ;
} ,
renderHTML : function ( ) {
} ,
renderTo : function ( n ) {
DOM . setHTML ( n , this . renderHTML ( ) ) ;
} ,
postRender : function ( ) {
var t = this , b ;
// Set pending states
if ( is ( t . disabled ) ) {
b = t . disabled ;
t . disabled = - 1 ;
t . setDisabled ( b ) ;
}
if ( is ( t . active ) ) {
b = t . active ;
t . active = - 1 ;
t . setActive ( b ) ;
}
} ,
remove : function ( ) {
DOM . remove ( this . id ) ;
this . destroy ( ) ;
} ,
destroy : function ( ) {
tinymce . dom . Event . clear ( this . id ) ;
}
} ) ;
} ) ( tinymce ) ; tinymce . create ( 'tinymce.ui.Container:tinymce.ui.Control' , {
Container : function ( id , s ) {
this . parent ( id , s ) ;
this . controls = [ ] ;
this . lookup = { } ;
} ,
add : function ( c ) {
this . lookup [ c . id ] = c ;
this . controls . push ( c ) ;
return c ;
} ,
get : function ( n ) {
return this . lookup [ n ] ;
}
} ) ;
tinymce . create ( 'tinymce.ui.Separator:tinymce.ui.Control' , {
Separator : function ( id , s ) {
this . parent ( id , s ) ;
this . classPrefix = 'mceSeparator' ;
} ,
renderHTML : function ( ) {
return tinymce . DOM . createHTML ( 'span' , { 'class' : this . classPrefix } ) ;
}
} ) ;
( function ( tinymce ) {
var is = tinymce . is , DOM = tinymce . DOM , each = tinymce . each , walk = tinymce . walk ;
tinymce . create ( 'tinymce.ui.MenuItem:tinymce.ui.Control' , {
MenuItem : function ( id , s ) {
this . parent ( id , s ) ;
this . classPrefix = 'mceMenuItem' ;
} ,
setSelected : function ( s ) {
this . setState ( 'Selected' , s ) ;
this . selected = s ;
} ,
isSelected : function ( ) {
return this . selected ;
} ,
postRender : function ( ) {
var t = this ;
t . parent ( ) ;
// Set pending state
if ( is ( t . selected ) )
t . setSelected ( t . selected ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var is = tinymce . is , DOM = tinymce . DOM , each = tinymce . each , walk = tinymce . walk ;
tinymce . create ( 'tinymce.ui.Menu:tinymce.ui.MenuItem' , {
Menu : function ( id , s ) {
var t = this ;
t . parent ( id , s ) ;
t . items = { } ;
t . collapsed = false ;
t . menuCount = 0 ;
t . onAddItem = new tinymce . util . Dispatcher ( this ) ;
} ,
expand : function ( d ) {
var t = this ;
if ( d ) {
walk ( t , function ( o ) {
if ( o . expand )
o . expand ( ) ;
} , 'items' , t ) ;
}
t . collapsed = false ;
} ,
collapse : function ( d ) {
var t = this ;
if ( d ) {
walk ( t , function ( o ) {
if ( o . collapse )
o . collapse ( ) ;
} , 'items' , t ) ;
}
t . collapsed = true ;
} ,
isCollapsed : function ( ) {
return this . collapsed ;
} ,
add : function ( o ) {
if ( ! o . settings )
o = new tinymce . ui . MenuItem ( o . id || DOM . uniqueId ( ) , o ) ;
this . onAddItem . dispatch ( this , o ) ;
return this . items [ o . id ] = o ;
} ,
addSeparator : function ( ) {
return this . add ( { separator : true } ) ;
} ,
addMenu : function ( o ) {
if ( ! o . collapse )
o = this . createMenu ( o ) ;
this . menuCount ++ ;
return this . add ( o ) ;
} ,
hasMenus : function ( ) {
return this . menuCount !== 0 ;
} ,
remove : function ( o ) {
delete this . items [ o . id ] ;
} ,
removeAll : function ( ) {
var t = this ;
walk ( t , function ( o ) {
if ( o . removeAll )
o . removeAll ( ) ;
else
o . remove ( ) ;
o . destroy ( ) ;
} , 'items' , t ) ;
t . items = { } ;
} ,
createMenu : function ( o ) {
var m = new tinymce . ui . Menu ( o . id || DOM . uniqueId ( ) , o ) ;
m . onAddItem . add ( this . onAddItem . dispatch , this . onAddItem ) ;
return m ;
}
} ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
var is = tinymce . is , DOM = tinymce . DOM , each = tinymce . each , Event = tinymce . dom . Event , Element = tinymce . dom . Element ;
tinymce . create ( 'tinymce.ui.DropMenu:tinymce.ui.Menu' , {
DropMenu : function ( id , s ) {
s = s || { } ;
s . container = s . container || DOM . doc . body ;
s . offset _x = s . offset _x || 0 ;
s . offset _y = s . offset _y || 0 ;
s . vp _offset _x = s . vp _offset _x || 0 ;
s . vp _offset _y = s . vp _offset _y || 0 ;
if ( is ( s . icons ) && ! s . icons )
s [ 'class' ] += ' mceNoIcons' ;
this . parent ( id , s ) ;
this . onShowMenu = new tinymce . util . Dispatcher ( this ) ;
this . onHideMenu = new tinymce . util . Dispatcher ( this ) ;
this . classPrefix = 'mceMenu' ;
} ,
createMenu : function ( s ) {
var t = this , cs = t . settings , m ;
s . container = s . container || cs . container ;
s . parent = t ;
s . constrain = s . constrain || cs . constrain ;
s [ 'class' ] = s [ 'class' ] || cs [ 'class' ] ;
s . vp _offset _x = s . vp _offset _x || cs . vp _offset _x ;
s . vp _offset _y = s . vp _offset _y || cs . vp _offset _y ;
m = new tinymce . ui . DropMenu ( s . id || DOM . uniqueId ( ) , s ) ;
m . onAddItem . add ( t . onAddItem . dispatch , t . onAddItem ) ;
return m ;
} ,
update : function ( ) {
var t = this , s = t . settings , tb = DOM . get ( 'menu_' + t . id + '_tbl' ) , co = DOM . get ( 'menu_' + t . id + '_co' ) , tw , th ;
tw = s . max _width ? Math . min ( tb . clientWidth , s . max _width ) : tb . clientWidth ;
th = s . max _height ? Math . min ( tb . clientHeight , s . max _height ) : tb . clientHeight ;
if ( ! DOM . boxModel )
t . element . setStyles ( { width : tw + 2 , height : th + 2 } ) ;
else
t . element . setStyles ( { width : tw , height : th } ) ;
if ( s . max _width )
DOM . setStyle ( co , 'width' , tw ) ;
if ( s . max _height ) {
DOM . setStyle ( co , 'height' , th ) ;
if ( tb . clientHeight < s . max _height )
DOM . setStyle ( co , 'overflow' , 'hidden' ) ;
}
} ,
showMenu : function ( x , y , px ) {
var t = this , s = t . settings , co , vp = DOM . getViewPort ( ) , w , h , mx , my , ot = 2 , dm , tb , cp = t . classPrefix ;
t . collapse ( 1 ) ;
if ( t . isMenuVisible )
return ;
if ( ! t . rendered ) {
co = DOM . add ( t . settings . container , t . renderNode ( ) ) ;
each ( t . items , function ( o ) {
o . postRender ( ) ;
} ) ;
t . element = new Element ( 'menu_' + t . id , { blocker : 1 , container : s . container } ) ;
} else
co = DOM . get ( 'menu_' + t . id ) ;
// Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
if ( ! tinymce . isOpera )
DOM . setStyles ( co , { left : - 0xFFFF , top : - 0xFFFF } ) ;
DOM . show ( co ) ;
t . update ( ) ;
x += s . offset _x || 0 ;
y += s . offset _y || 0 ;
vp . w -= 4 ;
vp . h -= 4 ;
// Move inside viewport if not submenu
if ( s . constrain ) {
w = co . clientWidth - ot ;
h = co . clientHeight - ot ;
mx = vp . x + vp . w ;
my = vp . y + vp . h ;
if ( ( x + s . vp _offset _x + w ) > mx )
x = px ? px - w : Math . max ( 0 , ( mx - s . vp _offset _x ) - w ) ;
if ( ( y + s . vp _offset _y + h ) > my )
y = Math . max ( 0 , ( my - s . vp _offset _y ) - h ) ;
}
DOM . setStyles ( co , { left : x , top : y } ) ;
t . element . update ( ) ;
t . isMenuVisible = 1 ;
t . mouseClickFunc = Event . add ( co , 'click' , function ( e ) {
var m ;
e = e . target ;
if ( e && ( e = DOM . getParent ( e , 'tr' ) ) && ! DOM . hasClass ( e , cp + 'ItemSub' ) ) {
m = t . items [ e . id ] ;
if ( m . isDisabled ( ) )
return ;
dm = t ;
while ( dm ) {
if ( dm . hideMenu )
dm . hideMenu ( ) ;
dm = dm . settings . parent ;
}
if ( m . settings . onclick )
m . settings . onclick ( e ) ;
return Event . cancel ( e ) ; // Cancel to fix onbeforeunload problem
}
} ) ;
if ( t . hasMenus ( ) ) {
t . mouseOverFunc = Event . add ( co , 'mouseover' , function ( e ) {
var m , r , mi ;
e = e . target ;
if ( e && ( e = DOM . getParent ( e , 'tr' ) ) ) {
m = t . items [ e . id ] ;
if ( t . lastMenu )
t . lastMenu . collapse ( 1 ) ;
if ( m . isDisabled ( ) )
return ;
if ( e && DOM . hasClass ( e , cp + 'ItemSub' ) ) {
//p = DOM.getPos(s.container);
r = DOM . getRect ( e ) ;
m . showMenu ( ( r . x + r . w - ot ) , r . y - ot , r . x ) ;
t . lastMenu = m ;
DOM . addClass ( DOM . get ( m . id ) . firstChild , cp + 'ItemActive' ) ;
}
}
} ) ;
}
t . onShowMenu . dispatch ( t ) ;
if ( s . keyboard _focus ) {
Event . add ( co , 'keydown' , t . _keyHandler , t ) ;
DOM . select ( 'a' , 'menu_' + t . id ) [ 0 ] . focus ( ) ; // Select first link
t . _focusIdx = 0 ;
}
} ,
hideMenu : function ( c ) {
var t = this , co = DOM . get ( 'menu_' + t . id ) , e ;
if ( ! t . isMenuVisible )
return ;
Event . remove ( co , 'mouseover' , t . mouseOverFunc ) ;
Event . remove ( co , 'click' , t . mouseClickFunc ) ;
Event . remove ( co , 'keydown' , t . _keyHandler ) ;
DOM . hide ( co ) ;
t . isMenuVisible = 0 ;
if ( ! c )
t . collapse ( 1 ) ;
if ( t . element )
t . element . hide ( ) ;
if ( e = DOM . get ( t . id ) )
DOM . removeClass ( e . firstChild , t . classPrefix + 'ItemActive' ) ;
t . onHideMenu . dispatch ( t ) ;
} ,
add : function ( o ) {
var t = this , co ;
o = t . parent ( o ) ;
if ( t . isRendered && ( co = DOM . get ( 'menu_' + t . id ) ) )
t . _add ( DOM . select ( 'tbody' , co ) [ 0 ] , o ) ;
return o ;
} ,
collapse : function ( d ) {
this . parent ( d ) ;
this . hideMenu ( 1 ) ;
} ,
remove : function ( o ) {
DOM . remove ( o . id ) ;
this . destroy ( ) ;
return this . parent ( o ) ;
} ,
destroy : function ( ) {
var t = this , co = DOM . get ( 'menu_' + t . id ) ;
Event . remove ( co , 'mouseover' , t . mouseOverFunc ) ;
Event . remove ( co , 'click' , t . mouseClickFunc ) ;
if ( t . element )
t . element . remove ( ) ;
DOM . remove ( co ) ;
} ,
renderNode : function ( ) {
var t = this , s = t . settings , n , tb , co , w ;
w = DOM . create ( 'div' , { id : 'menu_' + t . id , 'class' : s [ 'class' ] , 'style' : 'position:absolute;left:0;top:0;z-index:200000' } ) ;
co = DOM . add ( w , 'div' , { id : 'menu_' + t . id + '_co' , 'class' : t . classPrefix + ( s [ 'class' ] ? ' ' + s [ 'class' ] : '' ) } ) ;
t . element = new Element ( 'menu_' + t . id , { blocker : 1 , container : s . container } ) ;
if ( s . menu _line )
DOM . add ( co , 'span' , { 'class' : t . classPrefix + 'Line' } ) ;
// n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
n = DOM . add ( co , 'table' , { id : 'menu_' + t . id + '_tbl' , border : 0 , cellPadding : 0 , cellSpacing : 0 } ) ;
tb = DOM . add ( n , 'tbody' ) ;
each ( t . items , function ( o ) {
t . _add ( tb , o ) ;
} ) ;
t . rendered = true ;
return w ;
} ,
// Internal functions
_keyHandler : function ( e ) {
var t = this , kc = e . keyCode ;
function focus ( d ) {
var i = t . _focusIdx + d , e = DOM . select ( 'a' , 'menu_' + t . id ) [ i ] ;
if ( e ) {
t . _focusIdx = i ;
e . focus ( ) ;
}
} ;
switch ( kc ) {
case 38 :
focus ( - 1 ) ; // Select first link
return ;
case 40 :
focus ( 1 ) ;
return ;
case 13 :
return ;
case 27 :
return this . hideMenu ( ) ;
}
} ,
_add : function ( tb , o ) {
var n , s = o . settings , a , ro , it , cp = this . classPrefix , ic ;
if ( s . separator ) {
ro = DOM . add ( tb , 'tr' , { id : o . id , 'class' : cp + 'ItemSeparator' } ) ;
DOM . add ( ro , 'td' , { 'class' : cp + 'ItemSeparator' } ) ;
if ( n = ro . previousSibling )
DOM . addClass ( n , 'mceLast' ) ;
return ;
}
n = ro = DOM . add ( tb , 'tr' , { id : o . id , 'class' : cp + 'Item ' + cp + 'ItemEnabled' } ) ;
n = it = DOM . add ( n , 'td' ) ;
n = a = DOM . add ( n , 'a' , { href : 'javascript:;' , onclick : "return false;" , onmousedown : 'return false;' } ) ;
DOM . addClass ( it , s [ 'class' ] ) ;
// n = DOM.add(n, 'span', {'class' : 'item'});
ic = DOM . add ( n , 'span' , { 'class' : 'mceIcon' + ( s . icon ? ' mce_' + s . icon : '' ) } ) ;
if ( s . icon _src )
DOM . add ( ic , 'img' , { src : s . icon _src } ) ;
n = DOM . add ( n , s . element || 'span' , { 'class' : 'mceText' , title : o . settings . title } , o . settings . title ) ;
if ( o . settings . style )
DOM . setAttrib ( n , 'style' , o . settings . style ) ;
if ( tb . childNodes . length == 1 )
DOM . addClass ( ro , 'mceFirst' ) ;
if ( ( n = ro . previousSibling ) && DOM . hasClass ( n , cp + 'ItemSeparator' ) )
DOM . addClass ( ro , 'mceFirst' ) ;
if ( o . collapse )
DOM . addClass ( ro , cp + 'ItemSub' ) ;
if ( n = ro . previousSibling )
DOM . removeClass ( n , 'mceLast' ) ;
DOM . addClass ( ro , 'mceLast' ) ;
}
} ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
var DOM = tinymce . DOM ;
tinymce . create ( 'tinymce.ui.Button:tinymce.ui.Control' , {
Button : function ( id , s ) {
this . parent ( id , s ) ;
this . classPrefix = 'mceButton' ;
} ,
renderHTML : function ( ) {
var cp = this . classPrefix , s = this . settings , h , l ;
l = DOM . encode ( s . label || '' ) ;
h = '<a id="' + this . id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s [ 'class' ] + ( l ? ' ' + cp + 'Labeled' : '' ) + '" onmousedown="return false;" onclick="return false;" title="' + DOM . encode ( s . title ) + '">' ;
if ( s . image )
h += '<img class="mceIcon" src="' + s . image + '" />' + l + '</a>' ;
else
h += '<span class="mceIcon ' + s [ 'class' ] + '"></span>' + ( l ? '<span class="' + cp + 'Label">' + l + '</span>' : '' ) + '</a>' ;
return h ;
} ,
postRender : function ( ) {
var t = this , s = t . settings ;
tinymce . dom . Event . add ( t . id , 'click' , function ( e ) {
if ( ! t . isDisabled ( ) )
return s . onclick . call ( s . scope , e ) ;
} ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , each = tinymce . each , Dispatcher = tinymce . util . Dispatcher ;
tinymce . create ( 'tinymce.ui.ListBox:tinymce.ui.Control' , {
ListBox : function ( id , s ) {
var t = this ;
t . parent ( id , s ) ;
t . items = [ ] ;
t . onChange = new Dispatcher ( t ) ;
t . onPostRender = new Dispatcher ( t ) ;
t . onAdd = new Dispatcher ( t ) ;
t . onRenderMenu = new tinymce . util . Dispatcher ( this ) ;
t . classPrefix = 'mceListBox' ;
} ,
select : function ( va ) {
var t = this , fv , f ;
if ( va == undefined )
return t . selectByIndex ( - 1 ) ;
// Is string or number make function selector
if ( va && va . call )
f = va ;
else {
f = function ( v ) {
return v == va ;
} ;
}
// Do we need to do something?
if ( va != t . selectedValue ) {
// Find item
each ( t . items , function ( o , i ) {
if ( f ( o . value ) ) {
fv = 1 ;
t . selectByIndex ( i ) ;
return false ;
}
} ) ;
if ( ! fv )
t . selectByIndex ( - 1 ) ;
}
} ,
selectByIndex : function ( idx ) {
var t = this , e , o ;
if ( idx != t . selectedIndex ) {
e = DOM . get ( t . id + '_text' ) ;
o = t . items [ idx ] ;
if ( o ) {
t . selectedValue = o . value ;
t . selectedIndex = idx ;
DOM . setHTML ( e , DOM . encode ( o . title ) ) ;
DOM . removeClass ( e , 'mceTitle' ) ;
} else {
DOM . setHTML ( e , DOM . encode ( t . settings . title ) ) ;
DOM . addClass ( e , 'mceTitle' ) ;
t . selectedValue = t . selectedIndex = null ;
}
e = 0 ;
}
} ,
add : function ( n , v , o ) {
var t = this ;
o = o || { } ;
o = tinymce . extend ( o , {
title : n ,
value : v
} ) ;
t . items . push ( o ) ;
t . onAdd . dispatch ( t , o ) ;
} ,
getLength : function ( ) {
return this . items . length ;
} ,
renderHTML : function ( ) {
var h = '' , t = this , s = t . settings , cp = t . classPrefix ;
h = '<table id="' + t . id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + ( s [ 'class' ] ? ( ' ' + s [ 'class' ] ) : '' ) + '"><tbody><tr>' ;
h += '<td>' + DOM . createHTML ( 'a' , { id : t . id + '_text' , href : 'javascript:;' , 'class' : 'mceText' , onclick : "return false;" , onmousedown : 'return false;' } , DOM . encode ( t . settings . title ) ) + '</td>' ;
h += '<td>' + DOM . createHTML ( 'a' , { id : t . id + '_open' , tabindex : - 1 , href : 'javascript:;' , 'class' : 'mceOpen' , onclick : "return false;" , onmousedown : 'return false;' } , '<span></span>' ) + '</td>' ;
h += '</tr></tbody></table>' ;
return h ;
} ,
showMenu : function ( ) {
var t = this , p1 , p2 , e = DOM . get ( this . id ) , m ;
if ( t . isDisabled ( ) || t . items . length == 0 )
return ;
if ( t . menu && t . menu . isMenuVisible )
return t . hideMenu ( ) ;
if ( ! t . isMenuRendered ) {
t . renderMenu ( ) ;
t . isMenuRendered = true ;
}
p1 = DOM . getPos ( this . settings . menu _container ) ;
p2 = DOM . getPos ( e ) ;
m = t . menu ;
m . settings . offset _x = p2 . x ;
m . settings . offset _y = p2 . y ;
m . settings . keyboard _focus = ! tinymce . isOpera ; // Opera is buggy when it comes to auto focus
// Select in menu
if ( t . oldID )
m . items [ t . oldID ] . setSelected ( 0 ) ;
each ( t . items , function ( o ) {
if ( o . value === t . selectedValue ) {
m . items [ o . id ] . setSelected ( 1 ) ;
t . oldID = o . id ;
}
} ) ;
m . showMenu ( 0 , e . clientHeight ) ;
Event . add ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
DOM . addClass ( t . id , t . classPrefix + 'Selected' ) ;
//DOM.get(t.id + '_text').focus();
} ,
hideMenu : function ( e ) {
var t = this ;
// Prevent double toogles by canceling the mouse click event to the button
if ( e && e . type == "mousedown" && ( e . target . id == t . id + '_text' || e . target . id == t . id + '_open' ) )
return ;
if ( ! e || ! DOM . getParent ( e . target , '.mceMenu' ) ) {
DOM . removeClass ( t . id , t . classPrefix + 'Selected' ) ;
Event . remove ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
if ( t . menu )
t . menu . hideMenu ( ) ;
}
} ,
renderMenu : function ( ) {
var t = this , m ;
m = t . settings . control _manager . createDropMenu ( t . id + '_menu' , {
menu _line : 1 ,
'class' : t . classPrefix + 'Menu mceNoIcons' ,
max _width : 150 ,
max _height : 150
} ) ;
m . onHideMenu . add ( t . hideMenu , t ) ;
m . add ( {
title : t . settings . title ,
'class' : 'mceMenuItemTitle' ,
onclick : function ( ) {
if ( t . settings . onselect ( '' ) !== false )
t . select ( '' ) ; // Must be runned after
}
} ) ;
each ( t . items , function ( o ) {
o . id = DOM . uniqueId ( ) ;
o . onclick = function ( ) {
if ( t . settings . onselect ( o . value ) !== false )
t . select ( o . value ) ; // Must be runned after
} ;
m . add ( o ) ;
} ) ;
t . onRenderMenu . dispatch ( t , m ) ;
t . menu = m ;
} ,
postRender : function ( ) {
var t = this , cp = t . classPrefix ;
Event . add ( t . id , 'click' , t . showMenu , t ) ;
Event . add ( t . id + '_text' , 'focus' , function ( e ) {
if ( ! t . _focused ) {
t . keyDownHandler = Event . add ( t . id + '_text' , 'keydown' , function ( e ) {
var idx = - 1 , v , kc = e . keyCode ;
// Find current index
each ( t . items , function ( v , i ) {
if ( t . selectedValue == v . value )
idx = i ;
} ) ;
// Move up/down
if ( kc == 38 )
v = t . items [ idx - 1 ] ;
else if ( kc == 40 )
v = t . items [ idx + 1 ] ;
else if ( kc == 13 ) {
// Fake select on enter
v = t . selectedValue ;
t . selectedValue = null ; // Needs to be null to fake change
t . settings . onselect ( v ) ;
return Event . cancel ( e ) ;
}
if ( v ) {
t . hideMenu ( ) ;
t . select ( v . value ) ;
}
} ) ;
}
t . _focused = 1 ;
} ) ;
Event . add ( t . id + '_text' , 'blur' , function ( ) { Event . remove ( t . id + '_text' , 'keydown' , t . keyDownHandler ) ; t . _focused = 0 ; } ) ;
// Old IE doesn't have hover on all elements
if ( tinymce . isIE6 || ! DOM . boxModel ) {
Event . add ( t . id , 'mouseover' , function ( ) {
if ( ! DOM . hasClass ( t . id , cp + 'Disabled' ) )
DOM . addClass ( t . id , cp + 'Hover' ) ;
} ) ;
Event . add ( t . id , 'mouseout' , function ( ) {
if ( ! DOM . hasClass ( t . id , cp + 'Disabled' ) )
DOM . removeClass ( t . id , cp + 'Hover' ) ;
} ) ;
}
t . onPostRender . dispatch ( t , DOM . get ( t . id ) ) ;
} ,
destroy : function ( ) {
this . parent ( ) ;
Event . clear ( this . id + '_text' ) ;
}
} ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , each = tinymce . each , Dispatcher = tinymce . util . Dispatcher ;
tinymce . create ( 'tinymce.ui.NativeListBox:tinymce.ui.ListBox' , {
NativeListBox : function ( id , s ) {
this . parent ( id , s ) ;
this . classPrefix = 'mceNativeListBox' ;
} ,
setDisabled : function ( s ) {
DOM . get ( this . id ) . disabled = s ;
} ,
isDisabled : function ( ) {
return DOM . get ( this . id ) . disabled ;
} ,
select : function ( va ) {
var t = this , fv , f ;
if ( va == undefined )
return t . selectByIndex ( - 1 ) ;
// Is string or number make function selector
if ( va && va . call )
f = va ;
else {
f = function ( v ) {
return v == va ;
} ;
}
// Do we need to do something?
if ( va != t . selectedValue ) {
// Find item
each ( t . items , function ( o , i ) {
if ( f ( o . value ) ) {
fv = 1 ;
t . selectByIndex ( i ) ;
return false ;
}
} ) ;
if ( ! fv )
t . selectByIndex ( - 1 ) ;
}
} ,
selectByIndex : function ( idx ) {
DOM . get ( this . id ) . selectedIndex = idx + 1 ;
this . selectedValue = this . items [ idx ] ? this . items [ idx ] . value : null ;
} ,
add : function ( n , v , a ) {
var o , t = this ;
a = a || { } ;
a . value = v ;
if ( t . isRendered ( ) )
DOM . add ( DOM . get ( this . id ) , 'option' , a , n ) ;
o = {
title : n ,
value : v ,
attribs : a
} ;
t . items . push ( o ) ;
t . onAdd . dispatch ( t , o ) ;
} ,
getLength : function ( ) {
return DOM . get ( this . id ) . options . length - 1 ;
} ,
renderHTML : function ( ) {
var h , t = this ;
h = DOM . createHTML ( 'option' , { value : '' } , '-- ' + t . settings . title + ' --' ) ;
each ( t . items , function ( it ) {
h += DOM . createHTML ( 'option' , { value : it . value } , it . title ) ;
} ) ;
h = DOM . createHTML ( 'select' , { id : t . id , 'class' : 'mceNativeListBox' } , h ) ;
return h ;
} ,
postRender : function ( ) {
var t = this , ch ;
t . rendered = true ;
function onChange ( e ) {
var v = t . items [ e . target . selectedIndex - 1 ] ;
if ( v && ( v = v . value ) ) {
t . onChange . dispatch ( t , v ) ;
if ( t . settings . onselect )
t . settings . onselect ( v ) ;
}
} ;
Event . add ( t . id , 'change' , onChange ) ;
// Accessibility keyhandler
Event . add ( t . id , 'keydown' , function ( e ) {
var bf ;
Event . remove ( t . id , 'change' , ch ) ;
bf = Event . add ( t . id , 'blur' , function ( ) {
Event . add ( t . id , 'change' , onChange ) ;
Event . remove ( t . id , 'blur' , bf ) ;
} ) ;
if ( e . keyCode == 13 || e . keyCode == 32 ) {
onChange ( e ) ;
return Event . cancel ( e ) ;
}
} ) ;
t . onPostRender . dispatch ( t , DOM . get ( t . id ) ) ;
}
} ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , each = tinymce . each ;
tinymce . create ( 'tinymce.ui.MenuButton:tinymce.ui.Button' , {
MenuButton : function ( id , s ) {
this . parent ( id , s ) ;
this . onRenderMenu = new tinymce . util . Dispatcher ( this ) ;
s . menu _container = s . menu _container || DOM . doc . body ;
} ,
showMenu : function ( ) {
var t = this , p1 , p2 , e = DOM . get ( t . id ) , m ;
if ( t . isDisabled ( ) )
return ;
if ( ! t . isMenuRendered ) {
t . renderMenu ( ) ;
t . isMenuRendered = true ;
}
if ( t . isMenuVisible )
return t . hideMenu ( ) ;
p1 = DOM . getPos ( t . settings . menu _container ) ;
p2 = DOM . getPos ( e ) ;
m = t . menu ;
m . settings . offset _x = p2 . x ;
m . settings . offset _y = p2 . y ;
m . settings . vp _offset _x = p2 . x ;
m . settings . vp _offset _y = p2 . y ;
m . settings . keyboard _focus = t . _focused ;
m . showMenu ( 0 , e . clientHeight ) ;
Event . add ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
t . setState ( 'Selected' , 1 ) ;
t . isMenuVisible = 1 ;
} ,
renderMenu : function ( ) {
var t = this , m ;
m = t . settings . control _manager . createDropMenu ( t . id + '_menu' , {
menu _line : 1 ,
'class' : this . classPrefix + 'Menu' ,
icons : t . settings . icons
} ) ;
m . onHideMenu . add ( t . hideMenu , t ) ;
t . onRenderMenu . dispatch ( t , m ) ;
t . menu = m ;
} ,
hideMenu : function ( e ) {
var t = this ;
// Prevent double toogles by canceling the mouse click event to the button
if ( e && e . type == "mousedown" && DOM . getParent ( e . target , function ( e ) { return e . id === t . id || e . id === t . id + '_open' ; } ) )
return ;
if ( ! e || ! DOM . getParent ( e . target , '.mceMenu' ) ) {
t . setState ( 'Selected' , 0 ) ;
Event . remove ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
if ( t . menu )
t . menu . hideMenu ( ) ;
}
t . isMenuVisible = 0 ;
} ,
postRender : function ( ) {
var t = this , s = t . settings ;
Event . add ( t . id , 'click' , function ( ) {
if ( ! t . isDisabled ( ) ) {
if ( s . onclick )
s . onclick ( t . value ) ;
t . showMenu ( ) ;
}
} ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , each = tinymce . each ;
tinymce . create ( 'tinymce.ui.SplitButton:tinymce.ui.MenuButton' , {
SplitButton : function ( id , s ) {
this . parent ( id , s ) ;
this . classPrefix = 'mceSplitButton' ;
} ,
renderHTML : function ( ) {
var h , t = this , s = t . settings , h1 ;
h = '<tbody><tr>' ;
if ( s . image )
h1 = DOM . createHTML ( 'img ' , { src : s . image , 'class' : 'mceAction ' + s [ 'class' ] } ) ;
else
h1 = DOM . createHTML ( 'span' , { 'class' : 'mceAction ' + s [ 'class' ] } , '' ) ;
h += '<td>' + DOM . createHTML ( 'a' , { id : t . id + '_action' , href : 'javascript:;' , 'class' : 'mceAction ' + s [ 'class' ] , onclick : "return false;" , onmousedown : 'return false;' , title : s . title } , h1 ) + '</td>' ;
h1 = DOM . createHTML ( 'span' , { 'class' : 'mceOpen ' + s [ 'class' ] } ) ;
h += '<td>' + DOM . createHTML ( 'a' , { id : t . id + '_open' , href : 'javascript:;' , 'class' : 'mceOpen ' + s [ 'class' ] , onclick : "return false;" , onmousedown : 'return false;' , title : s . title } , h1 ) + '</td>' ;
h += '</tr></tbody>' ;
return DOM . createHTML ( 'table' , { id : t . id , 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s [ 'class' ] , cellpadding : '0' , cellspacing : '0' , onmousedown : 'return false;' , title : s . title } , h ) ;
} ,
postRender : function ( ) {
var t = this , s = t . settings ;
if ( s . onclick ) {
Event . add ( t . id + '_action' , 'click' , function ( ) {
if ( ! t . isDisabled ( ) )
s . onclick ( t . value ) ;
} ) ;
}
Event . add ( t . id + '_open' , 'click' , t . showMenu , t ) ;
Event . add ( t . id + '_open' , 'focus' , function ( ) { t . _focused = 1 ; } ) ;
Event . add ( t . id + '_open' , 'blur' , function ( ) { t . _focused = 0 ; } ) ;
// Old IE doesn't have hover on all elements
if ( tinymce . isIE6 || ! DOM . boxModel ) {
Event . add ( t . id , 'mouseover' , function ( ) {
if ( ! DOM . hasClass ( t . id , 'mceSplitButtonDisabled' ) )
DOM . addClass ( t . id , 'mceSplitButtonHover' ) ;
} ) ;
Event . add ( t . id , 'mouseout' , function ( ) {
if ( ! DOM . hasClass ( t . id , 'mceSplitButtonDisabled' ) )
DOM . removeClass ( t . id , 'mceSplitButtonHover' ) ;
} ) ;
}
} ,
destroy : function ( ) {
this . parent ( ) ;
Event . clear ( this . id + '_action' ) ;
Event . clear ( this . id + '_open' ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , is = tinymce . is , each = tinymce . each ;
tinymce . create ( 'tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton' , {
ColorSplitButton : function ( id , s ) {
var t = this ;
t . parent ( id , s ) ;
t . settings = s = tinymce . extend ( {
colors : '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF' ,
grid _width : 8 ,
default _color : '#888888'
} , t . settings ) ;
t . onShowMenu = new tinymce . util . Dispatcher ( t ) ;
t . onHideMenu = new tinymce . util . Dispatcher ( t ) ;
t . value = s . default _color ;
} ,
showMenu : function ( ) {
var t = this , r , p , e , p2 ;
if ( t . isDisabled ( ) )
return ;
if ( ! t . isMenuRendered ) {
t . renderMenu ( ) ;
t . isMenuRendered = true ;
}
if ( t . isMenuVisible )
return t . hideMenu ( ) ;
e = DOM . get ( t . id ) ;
DOM . show ( t . id + '_menu' ) ;
DOM . addClass ( e , 'mceSplitButtonSelected' ) ;
p2 = DOM . getPos ( e ) ;
DOM . setStyles ( t . id + '_menu' , {
left : p2 . x ,
top : p2 . y + e . clientHeight ,
zIndex : 200000
} ) ;
e = 0 ;
Event . add ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
if ( t . _focused ) {
t . _keyHandler = Event . add ( t . id + '_menu' , 'keydown' , function ( e ) {
if ( e . keyCode == 27 )
t . hideMenu ( ) ;
} ) ;
DOM . select ( 'a' , t . id + '_menu' ) [ 0 ] . focus ( ) ; // Select first link
}
t . onShowMenu . dispatch ( t ) ;
t . isMenuVisible = 1 ;
} ,
hideMenu : function ( e ) {
var t = this ;
// Prevent double toogles by canceling the mouse click event to the button
if ( e && e . type == "mousedown" && DOM . getParent ( e . target , function ( e ) { return e . id === t . id + '_open' ; } ) )
return ;
if ( ! e || ! DOM . getParent ( e . target , '.mceSplitButtonMenu' ) ) {
DOM . removeClass ( t . id , 'mceSplitButtonSelected' ) ;
Event . remove ( DOM . doc , 'mousedown' , t . hideMenu , t ) ;
Event . remove ( t . id + '_menu' , 'keydown' , t . _keyHandler ) ;
DOM . hide ( t . id + '_menu' ) ;
}
t . onHideMenu . dispatch ( t ) ;
t . isMenuVisible = 0 ;
} ,
renderMenu : function ( ) {
var t = this , m , i = 0 , s = t . settings , n , tb , tr , w ;
w = DOM . add ( s . menu _container , 'div' , { id : t . id + '_menu' , 'class' : s [ 'menu_class' ] + ' ' + s [ 'class' ] , style : 'position:absolute;left:0;top:-1000px;' } ) ;
m = DOM . add ( w , 'div' , { 'class' : s [ 'class' ] + ' mceSplitButtonMenu' } ) ;
DOM . add ( m , 'span' , { 'class' : 'mceMenuLine' } ) ;
n = DOM . add ( m , 'table' , { 'class' : 'mceColorSplitMenu' } ) ;
tb = DOM . add ( n , 'tbody' ) ;
// Generate color grid
i = 0 ;
each ( is ( s . colors , 'array' ) ? s . colors : s . colors . split ( ',' ) , function ( c ) {
c = c . replace ( /^#/ , '' ) ;
if ( ! i -- ) {
tr = DOM . add ( tb , 'tr' ) ;
i = s . grid _width - 1 ;
}
n = DOM . add ( tr , 'td' ) ;
n = DOM . add ( n , 'a' , {
href : 'javascript:;' ,
style : {
backgroundColor : '#' + c
} ,
mce _color : '#' + c
} ) ;
} ) ;
if ( s . more _colors _func ) {
n = DOM . add ( tb , 'tr' ) ;
n = DOM . add ( n , 'td' , { colspan : s . grid _width , 'class' : 'mceMoreColors' } ) ;
n = DOM . add ( n , 'a' , { id : t . id + '_more' , href : 'javascript:;' , onclick : 'return false;' , 'class' : 'mceMoreColors' } , s . more _colors _title ) ;
Event . add ( n , 'click' , function ( e ) {
s . more _colors _func . call ( s . more _colors _scope || this ) ;
return Event . cancel ( e ) ; // Cancel to fix onbeforeunload problem
} ) ;
}
DOM . addClass ( m , 'mceColorSplitMenu' ) ;
Event . add ( t . id + '_menu' , 'click' , function ( e ) {
var c ;
e = e . target ;
if ( e . nodeName == 'A' && ( c = e . getAttribute ( 'mce_color' ) ) )
t . setColor ( c ) ;
return Event . cancel ( e ) ; // Prevent IE auto save warning
} ) ;
return w ;
} ,
setColor : function ( c ) {
var t = this ;
DOM . setStyle ( t . id + '_preview' , 'backgroundColor' , c ) ;
t . value = c ;
t . hideMenu ( ) ;
t . settings . onselect ( c ) ;
} ,
postRender : function ( ) {
var t = this , id = t . id ;
t . parent ( ) ;
DOM . add ( id + '_action' , 'div' , { id : id + '_preview' , 'class' : 'mceColorPreview' } ) ;
DOM . setStyle ( t . id + '_preview' , 'backgroundColor' , t . value ) ;
} ,
destroy : function ( ) {
this . parent ( ) ;
Event . clear ( this . id + '_menu' ) ;
Event . clear ( this . id + '_more' ) ;
DOM . remove ( this . id + '_menu' ) ;
}
} ) ;
} ) ( tinymce ) ;
tinymce . create ( 'tinymce.ui.Toolbar:tinymce.ui.Container' , {
renderHTML : function ( ) {
var t = this , h = '' , c , co , dom = tinymce . DOM , s = t . settings , i , pr , nx , cl ;
cl = t . controls ;
for ( i = 0 ; i < cl . length ; i ++ ) {
// Get current control, prev control, next control and if the control is a list box or not
co = cl [ i ] ;
pr = cl [ i - 1 ] ;
nx = cl [ i + 1 ] ;
// Add toolbar start
if ( i === 0 ) {
c = 'mceToolbarStart' ;
if ( co . Button )
c += ' mceToolbarStartButton' ;
else if ( co . SplitButton )
c += ' mceToolbarStartSplitButton' ;
else if ( co . ListBox )
c += ' mceToolbarStartListBox' ;
h += dom . createHTML ( 'td' , { 'class' : c } , dom . createHTML ( 'span' , null , '<!-- IE -->' ) ) ;
}
// Add toolbar end before list box and after the previous button
// This is to fix the o2k7 editor skins
if ( pr && co . ListBox ) {
if ( pr . Button || pr . SplitButton )
h += dom . createHTML ( 'td' , { 'class' : 'mceToolbarEnd' } , dom . createHTML ( 'span' , null , '<!-- IE -->' ) ) ;
}
// Render control HTML
// IE 8 quick fix, needed to propertly generate a hit area for anchors
if ( dom . stdMode )
h += '<td style="position: relative">' + co . renderHTML ( ) + '</td>' ;
else
h += '<td>' + co . renderHTML ( ) + '</td>' ;
// Add toolbar start after list box and before the next button
// This is to fix the o2k7 editor skins
if ( nx && co . ListBox ) {
if ( nx . Button || nx . SplitButton )
h += dom . createHTML ( 'td' , { 'class' : 'mceToolbarStart' } , dom . createHTML ( 'span' , null , '<!-- IE -->' ) ) ;
}
}
c = 'mceToolbarEnd' ;
if ( co . Button )
c += ' mceToolbarEndButton' ;
else if ( co . SplitButton )
c += ' mceToolbarEndSplitButton' ;
else if ( co . ListBox )
c += ' mceToolbarEndListBox' ;
h += dom . createHTML ( 'td' , { 'class' : c } , dom . createHTML ( 'span' , null , '<!-- IE -->' ) ) ;
return dom . createHTML ( 'table' , { id : t . id , 'class' : 'mceToolbar' + ( s [ 'class' ] ? ' ' + s [ 'class' ] : '' ) , cellpadding : '0' , cellspacing : '0' , align : t . settings . align || '' } , '<tbody><tr>' + h + '</tr></tbody>' ) ;
}
} ) ;
( function ( tinymce ) {
var Dispatcher = tinymce . util . Dispatcher , each = tinymce . each ;
tinymce . create ( 'tinymce.AddOnManager' , {
items : [ ] ,
urls : { } ,
lookup : { } ,
onAdd : new Dispatcher ( this ) ,
get : function ( n ) {
return this . lookup [ n ] ;
} ,
requireLangPack : function ( n ) {
var u , s = tinymce . EditorManager . settings ;
if ( s && s . language ) {
u = this . urls [ n ] + '/langs/' + s . language + '.js' ;
if ( ! tinymce . dom . Event . domLoaded && ! s . strict _mode )
tinymce . ScriptLoader . load ( u ) ;
else
tinymce . ScriptLoader . add ( u ) ;
}
} ,
add : function ( id , o ) {
this . items . push ( o ) ;
this . lookup [ id ] = o ;
this . onAdd . dispatch ( this , id , o ) ;
return o ;
} ,
load : function ( n , u , cb , s ) {
var t = this ;
if ( t . urls [ n ] )
return ;
if ( u . indexOf ( '/' ) != 0 && u . indexOf ( '://' ) == - 1 )
u = tinymce . baseURL + '/' + u ;
t . urls [ n ] = u . substring ( 0 , u . lastIndexOf ( '/' ) ) ;
tinymce . ScriptLoader . add ( u , cb , s ) ;
}
} ) ;
// Create plugin and theme managers
tinymce . PluginManager = new tinymce . AddOnManager ( ) ;
tinymce . ThemeManager = new tinymce . AddOnManager ( ) ;
} ( tinymce ) ) ; ( function ( tinymce ) {
// Shorten names
var each = tinymce . each , extend = tinymce . extend , DOM = tinymce . DOM , Event = tinymce . dom . Event , ThemeManager = tinymce . ThemeManager , PluginManager = tinymce . PluginManager , explode = tinymce . explode ;
tinymce . create ( 'static tinymce.EditorManager' , {
editors : { } ,
i18n : { } ,
activeEditor : null ,
preInit : function ( ) {
var t = this , lo = window . location ;
// Setup some URLs where the editor API is located and where the document is
tinymce . documentBaseURL = lo . href . replace ( /[\?#].*$/ , '' ) . replace ( /[\/\\][^\/]+$/ , '' ) ;
if ( ! /[\/\\]$/ . test ( tinymce . documentBaseURL ) )
tinymce . documentBaseURL += '/' ;
tinymce . baseURL = new tinymce . util . URI ( tinymce . documentBaseURL ) . toAbsolute ( tinymce . baseURL ) ;
tinymce . EditorManager . baseURI = new tinymce . util . URI ( tinymce . baseURL ) ;
// User specified a document.domain value
if ( document . domain && lo . hostname != document . domain )
tinymce . relaxedDomain = document . domain ;
// Add before unload listener
// This was required since IE was leaking memory if you added and removed beforeunload listeners
// with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
t . onBeforeUnload = new tinymce . util . Dispatcher ( t ) ;
// Must be on window or IE will leak if the editor is placed in frame or iframe
Event . add ( window , 'beforeunload' , function ( e ) {
t . onBeforeUnload . dispatch ( t , e ) ;
} ) ;
} ,
init : function ( s ) {
var t = this , pl , sl = tinymce . ScriptLoader , c , e , el = [ ] , ed ;
function execCallback ( se , n , s ) {
var f = se [ n ] ;
if ( ! f )
return ;
if ( tinymce . is ( f , 'string' ) ) {
s = f . replace ( /\.\w+$/ , '' ) ;
s = s ? tinymce . resolve ( s ) : 0 ;
f = tinymce . resolve ( f ) ;
}
return f . apply ( s || this , Array . prototype . slice . call ( arguments , 2 ) ) ;
} ;
s = extend ( {
theme : "simple" ,
language : "en" ,
strict _loading _mode : document . contentType == 'application/xhtml+xml'
} , s ) ;
t . settings = s ;
// If page not loaded and strict mode isn't enabled then load them
if ( ! Event . domLoaded && ! s . strict _loading _mode ) {
// Load language
if ( s . language )
sl . add ( tinymce . baseURL + '/langs/' + s . language + '.js' ) ;
// Load theme
if ( s . theme && s . theme . charAt ( 0 ) != '-' && ! ThemeManager . urls [ s . theme ] )
ThemeManager . load ( s . theme , 'themes/' + s . theme + '/editor_template' + tinymce . suffix + '.js' ) ;
// Load plugins
if ( s . plugins ) {
pl = explode ( s . plugins ) ;
// Load compat2x first
if ( tinymce . inArray ( pl , 'compat2x' ) != - 1 )
PluginManager . load ( 'compat2x' , 'plugins/compat2x/editor_plugin' + tinymce . suffix + '.js' ) ;
// Load rest if plugins
each ( pl , function ( v ) {
if ( v && v . charAt ( 0 ) != '-' && ! PluginManager . urls [ v ] ) {
// Skip safari plugin for other browsers
if ( ! tinymce . isWebKit && v == 'safari' )
return ;
PluginManager . load ( v , 'plugins/' + v + '/editor_plugin' + tinymce . suffix + '.js' ) ;
}
} ) ;
}
sl . loadQueue ( ) ;
}
// Legacy call
Event . add ( document , 'init' , function ( ) {
var l , co ;
execCallback ( s , 'onpageload' ) ;
// Verify that it's a valid browser
if ( s . browsers ) {
l = false ;
each ( explode ( s . browsers ) , function ( v ) {
switch ( v ) {
case 'ie' :
case 'msie' :
if ( tinymce . isIE )
l = true ;
break ;
case 'gecko' :
if ( tinymce . isGecko )
l = true ;
break ;
case 'safari' :
case 'webkit' :
if ( tinymce . isWebKit )
l = true ;
break ;
case 'opera' :
if ( tinymce . isOpera )
l = true ;
break ;
}
} ) ;
// Not a valid one
if ( ! l )
return ;
}
switch ( s . mode ) {
case "exact" :
l = s . elements || '' ;
if ( l . length > 0 ) {
each ( explode ( l ) , function ( v ) {
if ( DOM . get ( v ) ) {
ed = new tinymce . Editor ( v , s ) ;
el . push ( ed ) ;
ed . render ( 1 ) ;
} else {
c = 0 ;
each ( document . forms , function ( f ) {
each ( f . elements , function ( e ) {
if ( e . name === v ) {
v = 'mce_editor_' + c ;
DOM . setAttrib ( e , 'id' , v ) ;
ed = new tinymce . Editor ( v , s ) ;
el . push ( ed ) ;
ed . render ( 1 ) ;
}
} ) ;
} ) ;
}
} ) ;
}
break ;
case "textareas" :
case "specific_textareas" :
function hasClass ( n , c ) {
return c . constructor === RegExp ? c . test ( n . className ) : DOM . hasClass ( n , c ) ;
} ;
each ( DOM . select ( 'textarea' ) , function ( v ) {
if ( s . editor _deselector && hasClass ( v , s . editor _deselector ) )
return ;
if ( ! s . editor _selector || hasClass ( v , s . editor _selector ) ) {
// Can we use the name
e = DOM . get ( v . name ) ;
if ( ! v . id && ! e )
v . id = v . name ;
// Generate unique name if missing or already exists
if ( ! v . id || t . get ( v . id ) )
v . id = DOM . uniqueId ( ) ;
ed = new tinymce . Editor ( v . id , s ) ;
el . push ( ed ) ;
ed . render ( 1 ) ;
}
} ) ;
break ;
}
// Call onInit when all editors are initialized
if ( s . oninit ) {
l = co = 0 ;
each ( el , function ( ed ) {
co ++ ;
if ( ! ed . initialized ) {
// Wait for it
ed . onInit . add ( function ( ) {
l ++ ;
// All done
if ( l == co )
execCallback ( s , 'oninit' ) ;
} ) ;
} else
l ++ ;
// All done
if ( l == co )
execCallback ( s , 'oninit' ) ;
} ) ;
}
} ) ;
} ,
get : function ( id ) {
return this . editors [ id ] ;
} ,
getInstanceById : function ( id ) {
return this . get ( id ) ;
} ,
add : function ( e ) {
this . editors [ e . id ] = e ;
this . _setActive ( e ) ;
return e ;
} ,
remove : function ( e ) {
var t = this ;
// Not in the collection
if ( ! t . editors [ e . id ] )
return null ;
delete t . editors [ e . id ] ;
// Select another editor since the active one was removed
if ( t . activeEditor == e ) {
each ( t . editors , function ( e ) {
t . _setActive ( e ) ;
return false ; // Break
} ) ;
}
e . destroy ( ) ;
return e ;
} ,
execCommand : function ( c , u , v ) {
var t = this , ed = t . get ( v ) , w ;
// Manager commands
switch ( c ) {
case "mceFocus" :
ed . focus ( ) ;
return true ;
case "mceAddEditor" :
case "mceAddControl" :
if ( ! t . get ( v ) )
new tinymce . Editor ( v , t . settings ) . render ( ) ;
return true ;
case "mceAddFrameControl" :
w = v . window ;
// Add tinyMCE global instance and tinymce namespace to specified window
w . tinyMCE = tinyMCE ;
w . tinymce = tinymce ;
tinymce . DOM . doc = w . document ;
tinymce . DOM . win = w ;
ed = new tinymce . Editor ( v . element _id , v ) ;
ed . render ( ) ;
// Fix IE memory leaks
if ( tinymce . isIE ) {
function clr ( ) {
ed . destroy ( ) ;
w . detachEvent ( 'onunload' , clr ) ;
w = w . tinyMCE = w . tinymce = null ; // IE leak
} ;
w . attachEvent ( 'onunload' , clr ) ;
}
v . page _window = null ;
return true ;
case "mceRemoveEditor" :
case "mceRemoveControl" :
if ( ed )
ed . remove ( ) ;
return true ;
case 'mceToggleEditor' :
if ( ! ed ) {
t . execCommand ( 'mceAddControl' , 0 , v ) ;
return true ;
}
if ( ed . isHidden ( ) )
ed . show ( ) ;
else
ed . hide ( ) ;
return true ;
}
// Run command on active editor
if ( t . activeEditor )
return t . activeEditor . execCommand ( c , u , v ) ;
return false ;
} ,
execInstanceCommand : function ( id , c , u , v ) {
var ed = this . get ( id ) ;
if ( ed )
return ed . execCommand ( c , u , v ) ;
return false ;
} ,
triggerSave : function ( ) {
each ( this . editors , function ( e ) {
e . save ( ) ;
} ) ;
} ,
addI18n : function ( p , o ) {
var lo , i18n = this . i18n ;
if ( ! tinymce . is ( p , 'string' ) ) {
each ( p , function ( o , lc ) {
each ( o , function ( o , g ) {
each ( o , function ( o , k ) {
if ( g === 'common' )
i18n [ lc + '.' + k ] = o ;
else
i18n [ lc + '.' + g + '.' + k ] = o ;
} ) ;
} ) ;
} ) ;
} else {
each ( o , function ( o , k ) {
i18n [ p + '.' + k ] = o ;
} ) ;
}
} ,
// Private methods
_setActive : function ( e ) {
this . selectedInstance = this . activeEditor = e ;
}
} ) ;
tinymce . EditorManager . preInit ( ) ;
} ) ( tinymce ) ;
// Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call
var tinyMCE = window . tinyMCE = tinymce . EditorManager ;
( function ( tinymce ) {
var DOM = tinymce . DOM , Event = tinymce . dom . Event , extend = tinymce . extend , Dispatcher = tinymce . util . Dispatcher ;
var each = tinymce . each , isGecko = tinymce . isGecko , isIE = tinymce . isIE , isWebKit = tinymce . isWebKit ;
var is = tinymce . is , ThemeManager = tinymce . ThemeManager , PluginManager = tinymce . PluginManager , EditorManager = tinymce . EditorManager ;
var inArray = tinymce . inArray , grep = tinymce . grep , explode = tinymce . explode ;
tinymce . create ( 'tinymce.Editor' , {
Editor : function ( id , s ) {
var t = this ;
t . id = t . editorId = id ;
t . execCommands = { } ;
t . queryStateCommands = { } ;
t . queryValueCommands = { } ;
t . plugins = { } ;
// Add events to the editor
each ( [
'onPreInit' ,
'onBeforeRenderUI' ,
'onPostRender' ,
'onInit' ,
'onRemove' ,
'onActivate' ,
'onDeactivate' ,
'onClick' ,
'onEvent' ,
'onMouseUp' ,
'onMouseDown' ,
'onDblClick' ,
'onKeyDown' ,
'onKeyUp' ,
'onKeyPress' ,
'onContextMenu' ,
'onSubmit' ,
'onReset' ,
'onPaste' ,
'onPreProcess' ,
'onPostProcess' ,
'onBeforeSetContent' ,
'onBeforeGetContent' ,
'onSetContent' ,
'onGetContent' ,
'onLoadContent' ,
'onSaveContent' ,
'onNodeChange' ,
'onChange' ,
'onBeforeExecCommand' ,
'onExecCommand' ,
'onUndo' ,
'onRedo' ,
'onVisualAid' ,
'onSetProgressState'
] , function ( e ) {
t [ e ] = new Dispatcher ( t ) ;
} ) ;
// Default editor config
t . settings = s = extend ( {
id : id ,
language : 'en' ,
docs _language : 'en' ,
theme : 'simple' ,
skin : 'default' ,
delta _width : 0 ,
delta _height : 0 ,
popup _css : '' ,
plugins : '' ,
document _base _url : tinymce . documentBaseURL ,
add _form _submit _trigger : 1 ,
submit _patch : 1 ,
add _unload _trigger : 1 ,
convert _urls : 1 ,
relative _urls : 1 ,
remove _script _host : 1 ,
table _inline _editing : 0 ,
object _resizing : 1 ,
cleanup : 1 ,
accessibility _focus : 1 ,
custom _shortcuts : 1 ,
custom _undo _redo _keyboard _shortcuts : 1 ,
custom _undo _redo _restore _selection : 1 ,
custom _undo _redo : 1 ,
doctype : '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' ,
visual _table _class : 'mceItemTable' ,
visual : 1 ,
inline _styles : true ,
convert _fonts _to _spans : true ,
font _size _style _values : 'xx-small,x-small,small,medium,large,x-large,xx-large' ,
apply _source _formatting : 1 ,
directionality : 'ltr' ,
forced _root _block : 'p' ,
valid _elements : '@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong/b,em/i,strike,u,#p[align],-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border=0|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big' ,
hidden _input : 1 ,
padd _empty _editor : 1 ,
render _ui : 1 ,
init _theme : 1 ,
force _p _newlines : 1 ,
indentation : '30px' ,
keep _styles : 1 ,
fix _table _elements : 1 ,
removeformat _selector : 'span,b,strong,em,i,font,u,strike'
} , s ) ;
// Setup URIs
t . documentBaseURI = new tinymce . util . URI ( s . document _base _url || tinymce . documentBaseURL , {
base _uri : tinyMCE . baseURI
} ) ;
t . baseURI = EditorManager . baseURI ;
// Call setup
t . execCallback ( 'setup' , t ) ;
} ,
render : function ( nst ) {
var t = this , s = t . settings , id = t . id , sl = tinymce . ScriptLoader ;
// Page is not loaded yet, wait for it
if ( ! Event . domLoaded ) {
Event . add ( document , 'init' , function ( ) {
t . render ( ) ;
} ) ;
return ;
}
// Force strict loading mode if render us called by user and not internally
if ( ! nst ) {
s . strict _loading _mode = 1 ;
tinyMCE . settings = s ;
}
// Element not found, then skip initialization
if ( ! t . getElement ( ) )
return ;
if ( s . strict _loading _mode ) {
sl . settings . strict _mode = s . strict _loading _mode ;
tinymce . DOM . settings . strict = 1 ;
}
// Add hidden input for non input elements inside form elements
if ( ! /TEXTAREA|INPUT/i . test ( t . getElement ( ) . nodeName ) && s . hidden _input && DOM . getParent ( id , 'form' ) )
DOM . insertAfter ( DOM . create ( 'input' , { type : 'hidden' , name : id } ) , id ) ;
if ( tinymce . WindowManager )
t . windowManager = new tinymce . WindowManager ( t ) ;
if ( s . encoding == 'xml' ) {
t . onGetContent . add ( function ( ed , o ) {
if ( o . save )
o . content = DOM . encode ( o . content ) ;
} ) ;
}
if ( s . add _form _submit _trigger ) {
t . onSubmit . addToTop ( function ( ) {
if ( t . initialized ) {
t . save ( ) ;
t . isNotDirty = 1 ;
}
} ) ;
}
if ( s . add _unload _trigger ) {
t . _beforeUnload = tinyMCE . onBeforeUnload . add ( function ( ) {
if ( t . initialized && ! t . destroyed && ! t . isHidden ( ) )
t . save ( { format : 'raw' , no _events : true } ) ;
} ) ;
}
tinymce . addUnload ( t . destroy , t ) ;
if ( s . submit _patch ) {
t . onBeforeRenderUI . add ( function ( ) {
var n = t . getElement ( ) . form ;
if ( ! n )
return ;
// Already patched
if ( n . _mceOldSubmit )
return ;
// Check page uses id="submit" or name="submit" for it's submit button
if ( ! n . submit . nodeType && ! n . submit . length ) {
t . formElement = n ;
n . _mceOldSubmit = n . submit ;
n . submit = function ( ) {
// Save all instances
EditorManager . triggerSave ( ) ;
t . isNotDirty = 1 ;
return t . formElement . _mceOldSubmit ( t . formElement ) ;
} ;
}
n = null ;
} ) ;
}
// Load scripts
function loadScripts ( ) {
if ( s . language )
sl . add ( tinymce . baseURL + '/langs/' + s . language + '.js' ) ;
if ( s . theme && s . theme . charAt ( 0 ) != '-' && ! ThemeManager . urls [ s . theme ] )
ThemeManager . load ( s . theme , 'themes/' + s . theme + '/editor_template' + tinymce . suffix + '.js' ) ;
each ( explode ( s . plugins ) , function ( p ) {
if ( p && p . charAt ( 0 ) != '-' && ! PluginManager . urls [ p ] ) {
// Skip safari plugin for other browsers
if ( ! isWebKit && p == 'safari' )
return ;
PluginManager . load ( p , 'plugins/' + p + '/editor_plugin' + tinymce . suffix + '.js' ) ;
}
} ) ;
// Init when que is loaded
sl . loadQueue ( function ( ) {
if ( ! t . removed )
t . init ( ) ;
} ) ;
} ;
// Load compat2x first
if ( s . plugins . indexOf ( 'compat2x' ) != - 1 ) {
PluginManager . load ( 'compat2x' , 'plugins/compat2x/editor_plugin' + tinymce . suffix + '.js' ) ;
sl . loadQueue ( loadScripts ) ;
} else
loadScripts ( ) ;
} ,
init : function ( ) {
var n , t = this , s = t . settings , w , h , e = t . getElement ( ) , o , ti , u , bi , bc , re ;
EditorManager . add ( t ) ;
// Create theme
if ( s . theme ) {
s . theme = s . theme . replace ( /-/ , '' ) ;
o = ThemeManager . get ( s . theme ) ;
t . theme = new o ( ) ;
if ( t . theme . init && s . init _theme )
t . theme . init ( t , ThemeManager . urls [ s . theme ] || tinymce . documentBaseURL . replace ( /\/$/ , '' ) ) ;
}
// Create all plugins
each ( explode ( s . plugins . replace ( /\-/g , '' ) ) , function ( p ) {
var c = PluginManager . get ( p ) , u = PluginManager . urls [ p ] || tinymce . documentBaseURL . replace ( /\/$/ , '' ) , po ;
if ( c ) {
po = new c ( t , u ) ;
t . plugins [ p ] = po ;
if ( po . init )
po . init ( t , u ) ;
}
} ) ;
// Setup popup CSS path(s)
if ( s . popup _css !== false ) {
if ( s . popup _css )
s . popup _css = t . documentBaseURI . toAbsolute ( s . popup _css ) ;
else
s . popup _css = t . baseURI . toAbsolute ( "themes/" + s . theme + "/skins/" + s . skin + "/dialog.css" ) ;
}
if ( s . popup _css _add )
s . popup _css += ',' + t . documentBaseURI . toAbsolute ( s . popup _css _add ) ;
// Setup control factory
t . controlManager = new tinymce . ControlManager ( t ) ;
t . undoManager = new tinymce . UndoManager ( t ) ;
// Pass through
t . undoManager . onAdd . add ( function ( um , l ) {
if ( ! l . initial )
return t . onChange . dispatch ( t , l , um ) ;
} ) ;
t . undoManager . onUndo . add ( function ( um , l ) {
return t . onUndo . dispatch ( t , l , um ) ;
} ) ;
t . undoManager . onRedo . add ( function ( um , l ) {
return t . onRedo . dispatch ( t , l , um ) ;
} ) ;
if ( s . custom _undo _redo ) {
t . onExecCommand . add ( function ( ed , cmd , ui , val , a ) {
if ( cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && ( ! a || ! a . skip _undo ) )
t . undoManager . add ( ) ;
} ) ;
}
t . onExecCommand . add ( function ( ed , c ) {
// Don't refresh the select lists until caret move
if ( ! /^(FontName|FontSize)$/ . test ( c ) )
t . nodeChanged ( ) ;
} ) ;
// Remove ghost selections on images and tables in Gecko
if ( isGecko ) {
function repaint ( a , o ) {
if ( ! o || ! o . initial )
t . execCommand ( 'mceRepaint' ) ;
} ;
t . onUndo . add ( repaint ) ;
t . onRedo . add ( repaint ) ;
t . onSetContent . add ( repaint ) ;
}
// Enables users to override the control factory
t . onBeforeRenderUI . dispatch ( t , t . controlManager ) ;
// Measure box
if ( s . render _ui ) {
w = s . width || e . style . width || e . offsetWidth ;
h = s . height || e . style . height || e . offsetHeight ;
t . orgDisplay = e . style . display ;
re = /^[0-9\.]+(|px)$/i ;
if ( re . test ( '' + w ) )
w = Math . max ( parseInt ( w ) + ( o . deltaWidth || 0 ) , 100 ) ;
if ( re . test ( '' + h ) )
h = Math . max ( parseInt ( h ) + ( o . deltaHeight || 0 ) , 100 ) ;
// Render UI
o = t . theme . renderUI ( {
targetNode : e ,
width : w ,
height : h ,
deltaWidth : s . delta _width ,
deltaHeight : s . delta _height
} ) ;
t . editorContainer = o . editorContainer ;
}
// Resize editor
DOM . setStyles ( o . sizeContainer || o . editorContainer , {
width : w ,
height : h
} ) ;
h = ( o . iframeHeight || h ) + ( typeof ( h ) == 'number' ? ( o . deltaHeight || 0 ) : '' ) ;
if ( h < 100 )
h = 100 ;
t . iframeHTML = s . doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + t . documentBaseURI . getURI ( ) + '" />' ;
t . iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' ;
if ( tinymce . relaxedDomain )
t . iframeHTML += '<script type="text/javascript">document.domain = "' + tinymce . relaxedDomain + '";</script>' ;
bi = s . body _id || 'tinymce' ;
if ( bi . indexOf ( '=' ) != - 1 ) {
bi = t . getParam ( 'body_id' , '' , 'hash' ) ;
bi = bi [ t . id ] || bi ;
}
bc = s . body _class || '' ;
if ( bc . indexOf ( '=' ) != - 1 ) {
bc = t . getParam ( 'body_class' , '' , 'hash' ) ;
bc = bc [ t . id ] || '' ;
}
t . iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '"></body></html>' ;
// Domain relaxing enabled, then set document domain
if ( tinymce . relaxedDomain ) {
// We need to write the contents here in IE since multiple writes messes up refresh button and back button
if ( isIE || ( tinymce . isOpera && parseFloat ( opera . version ( ) ) >= 9.5 ) )
u = 'javascript:(function(){document.open();document.domain="' + document . domain + '";var ed = window.parent.tinyMCE.get("' + t . id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()' ;
else if ( tinymce . isOpera )
u = 'javascript:(function(){document.open();document.domain="' + document . domain + '";document.close();ed.setupIframe();})()' ;
}
// Create iframe
n = DOM . add ( o . iframeContainer , 'iframe' , {
id : t . id + "_ifr" ,
src : u || 'javascript:""' , // Workaround for HTTPS warning in IE6/7
frameBorder : '0' ,
style : {
width : '100%' ,
height : h
}
} ) ;
t . contentAreaContainer = o . iframeContainer ;
DOM . get ( o . editorContainer ) . style . display = t . orgDisplay ;
DOM . get ( t . id ) . style . display = 'none' ;
if ( ! isIE || ! tinymce . relaxedDomain )
t . setupIframe ( ) ;
e = n = o = null ; // Cleanup
} ,
setupIframe : function ( ) {
var t = this , s = t . settings , e = DOM . get ( t . id ) , d = t . getDoc ( ) , h , b ;
// Setup iframe body
if ( ! isIE || ! tinymce . relaxedDomain ) {
d . open ( ) ;
d . write ( t . iframeHTML ) ;
d . close ( ) ;
}
// Design mode needs to be added here Ctrl+A will fail otherwise
if ( ! isIE ) {
try {
if ( ! s . readonly )
d . designMode = 'On' ;
} catch ( ex ) {
// Will fail on Gecko if the editor is placed in an hidden container element
// The design mode will be set ones the editor is focused
}
}
// IE needs to use contentEditable or it will display non secure items for HTTPS
if ( isIE ) {
// It will not steal focus if we hide it while setting contentEditable
b = t . getBody ( ) ;
DOM . hide ( b ) ;
if ( ! s . readonly )
b . contentEditable = true ;
DOM . show ( b ) ;
}
// Setup objects
t . dom = new tinymce . DOM . DOMUtils ( t . getDoc ( ) , {
keep _values : true ,
url _converter : t . convertURL ,
url _converter _scope : t ,
hex _colors : s . force _hex _style _colors ,
class _filter : s . class _filter ,
update _styles : 1 ,
fix _ie _paragraphs : 1
} ) ;
t . serializer = new tinymce . dom . Serializer ( {
entity _encoding : s . entity _encoding ,
entities : s . entities ,
valid _elements : s . verify _html === false ? '*[*]' : s . valid _elements ,
extended _valid _elements : s . extended _valid _elements ,
valid _child _elements : s . valid _child _elements ,
invalid _elements : s . invalid _elements ,
fix _table _elements : s . fix _table _elements ,
fix _list _elements : s . fix _list _elements ,
fix _content _duplication : s . fix _content _duplication ,
convert _fonts _to _spans : s . convert _fonts _to _spans ,
font _size _classes : s . font _size _classes ,
font _size _style _values : s . font _size _style _values ,
apply _source _formatting : s . apply _source _formatting ,
remove _linebreaks : s . remove _linebreaks ,
element _format : s . element _format ,
dom : t . dom
} ) ;
t . selection = new tinymce . dom . Selection ( t . dom , t . getWin ( ) , t . serializer ) ;
t . forceBlocks = new tinymce . ForceBlocks ( t , {
forced _root _block : s . forced _root _block
} ) ;
t . editorCommands = new tinymce . EditorCommands ( t ) ;
// Pass through
t . serializer . onPreProcess . add ( function ( se , o ) {
return t . onPreProcess . dispatch ( t , o , se ) ;
} ) ;
t . serializer . onPostProcess . add ( function ( se , o ) {
return t . onPostProcess . dispatch ( t , o , se ) ;
} ) ;
t . onPreInit . dispatch ( t ) ;
if ( ! s . gecko _spellcheck )
t . getBody ( ) . spellcheck = 0 ;
if ( ! s . readonly )
t . _addEvents ( ) ;
t . controlManager . onPostRender . dispatch ( t , t . controlManager ) ;
t . onPostRender . dispatch ( t ) ;
if ( s . directionality )
t . getBody ( ) . dir = s . directionality ;
if ( s . nowrap )
t . getBody ( ) . style . whiteSpace = "nowrap" ;
if ( s . auto _resize )
t . onNodeChange . add ( t . resizeToContent , t ) ;
if ( s . custom _elements ) {
function handleCustom ( ed , o ) {
each ( explode ( s . custom _elements ) , function ( v ) {
var n ;
if ( v . indexOf ( '~' ) === 0 ) {
v = v . substring ( 1 ) ;
n = 'span' ;
} else
n = 'div' ;
o . content = o . content . replace ( new RegExp ( '<(' + v + ')([^>]*)>' , 'g' ) , '<' + n + ' mce_name="$1"$2>' ) ;
o . content = o . content . replace ( new RegExp ( '</(' + v + ')>' , 'g' ) , '</' + n + '>' ) ;
} ) ;
} ;
t . onBeforeSetContent . add ( handleCustom ) ;
t . onPostProcess . add ( function ( ed , o ) {
if ( o . set )
handleCustom ( ed , o )
} ) ;
}
if ( s . handle _node _change _callback ) {
t . onNodeChange . add ( function ( ed , cm , n ) {
t . execCallback ( 'handle_node_change_callback' , t . id , n , - 1 , - 1 , true , t . selection . isCollapsed ( ) ) ;
} ) ;
}
if ( s . save _callback ) {
t . onSaveContent . add ( function ( ed , o ) {
var h = t . execCallback ( 'save_callback' , t . id , o . content , t . getBody ( ) ) ;
if ( h )
o . content = h ;
} ) ;
}
if ( s . onchange _callback ) {
t . onChange . add ( function ( ed , l ) {
t . execCallback ( 'onchange_callback' , t , l ) ;
} ) ;
}
if ( s . convert _newlines _to _brs ) {
t . onBeforeSetContent . add ( function ( ed , o ) {
if ( o . initial )
o . content = o . content . replace ( /\r?\n/g , '<br />' ) ;
} ) ;
}
if ( s . fix _nesting && isIE ) {
t . onBeforeSetContent . add ( function ( ed , o ) {
o . content = t . _fixNesting ( o . content ) ;
} ) ;
}
if ( s . preformatted ) {
t . onPostProcess . add ( function ( ed , o ) {
o . content = o . content . replace ( /^\s*<pre.*?>/ , '' ) ;
o . content = o . content . replace ( /<\/pre>\s*$/ , '' ) ;
if ( o . set )
o . content = '<pre class="mceItemHidden">' + o . content + '</pre>' ;
} ) ;
}
if ( s . verify _css _classes ) {
t . serializer . attribValueFilter = function ( n , v ) {
var s , cl ;
if ( n == 'class' ) {
// Build regexp for classes
if ( ! t . classesRE ) {
cl = t . dom . getClasses ( ) ;
if ( cl . length > 0 ) {
s = '' ;
each ( cl , function ( o ) {
s += ( s ? '|' : '' ) + o [ 'class' ] ;
} ) ;
t . classesRE = new RegExp ( '(' + s + ')' , 'gi' ) ;
}
}
return ! t . classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g . test ( v ) || t . classesRE . test ( v ) ? v : '' ;
}
return v ;
} ;
}
if ( s . convert _fonts _to _spans )
t . _convertFonts ( ) ;
if ( s . inline _styles )
t . _convertInlineElements ( ) ;
if ( s . cleanup _callback ) {
t . onBeforeSetContent . add ( function ( ed , o ) {
o . content = t . execCallback ( 'cleanup_callback' , 'insert_to_editor' , o . content , o ) ;
} ) ;
t . onPreProcess . add ( function ( ed , o ) {
if ( o . set )
t . execCallback ( 'cleanup_callback' , 'insert_to_editor_dom' , o . node , o ) ;
if ( o . get )
t . execCallback ( 'cleanup_callback' , 'get_from_editor_dom' , o . node , o ) ;
} ) ;
t . onPostProcess . add ( function ( ed , o ) {
if ( o . set )
o . content = t . execCallback ( 'cleanup_callback' , 'insert_to_editor' , o . content , o ) ;
if ( o . get )
o . content = t . execCallback ( 'cleanup_callback' , 'get_from_editor' , o . content , o ) ;
} ) ;
}
if ( s . save _callback ) {
t . onGetContent . add ( function ( ed , o ) {
if ( o . save )
o . content = t . execCallback ( 'save_callback' , t . id , o . content , t . getBody ( ) ) ;
} ) ;
}
if ( s . handle _event _callback ) {
t . onEvent . add ( function ( ed , e , o ) {
if ( t . execCallback ( 'handle_event_callback' , e , ed , o ) === false )
Event . cancel ( e ) ;
} ) ;
}
// Add visual aids when new contents is added
t . onSetContent . add ( function ( ) {
t . addVisual ( t . getBody ( ) ) ;
} ) ;
// Remove empty contents
if ( s . padd _empty _editor ) {
t . onPostProcess . add ( function ( ed , o ) {
o . content = o . content . replace ( /^(<p[^>]*>( | |\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/ , '' ) ;
} ) ;
}
if ( isGecko ) {
// Fix gecko link bug, when a link is placed at the end of block elements there is
// no way to move the caret behind the link. This fix adds a bogus br element after the link
function fixLinks ( ed , o ) {
each ( ed . dom . select ( 'a' ) , function ( n ) {
var pn = n . parentNode ;
if ( ed . dom . isBlock ( pn ) && pn . lastChild === n )
ed . dom . add ( pn , 'br' , { 'mce_bogus' : 1 } ) ;
} ) ;
} ;
t . onExecCommand . add ( function ( ed , cmd ) {
if ( cmd === 'CreateLink' )
fixLinks ( ed ) ;
} ) ;
t . onSetContent . add ( t . selection . onSetContent . add ( fixLinks ) ) ;
if ( ! s . readonly ) {
try {
// Design mode must be set here once again to fix a bug where
// Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again
d . designMode = 'Off' ;
d . designMode = 'On' ;
} catch ( ex ) {
// Will fail on Gecko if the editor is placed in an hidden container element
// The design mode will be set ones the editor is focused
}
}
}
// A small timeout was needed since firefox will remove. Bug: #1838304
setTimeout ( function ( ) {
if ( t . removed )
return ;
t . load ( { initial : true , format : ( s . cleanup _on _startup ? 'html' : 'raw' ) } ) ;
t . startContent = t . getContent ( { format : 'raw' } ) ;
t . undoManager . add ( { initial : true } ) ;
t . initialized = true ;
t . onInit . dispatch ( t ) ;
t . execCallback ( 'setupcontent_callback' , t . id , t . getBody ( ) , t . getDoc ( ) ) ;
t . execCallback ( 'init_instance_callback' , t ) ;
t . focus ( true ) ;
t . nodeChanged ( { initial : 1 } ) ;
// Load specified content CSS last
if ( s . content _css ) {
tinymce . each ( explode ( s . content _css ) , function ( u ) {
t . dom . loadCSS ( t . documentBaseURI . toAbsolute ( u ) ) ;
} ) ;
}
// Handle auto focus
if ( s . auto _focus ) {
setTimeout ( function ( ) {
var ed = EditorManager . get ( s . auto _focus ) ;
ed . selection . select ( ed . getBody ( ) , 1 ) ;
ed . selection . collapse ( 1 ) ;
ed . getWin ( ) . focus ( ) ;
} , 100 ) ;
}
} , 1 ) ;
e = null ;
} ,
focus : function ( sf ) {
var oed , t = this , ce = t . settings . content _editable ;
if ( ! sf ) {
// Is not content editable or the selection is outside the area in IE
// the IE statement is needed to avoid bluring if element selections inside layers since
// the layer is like it's own document in IE
if ( ! ce && ( ! isIE || t . selection . getNode ( ) . ownerDocument != t . getDoc ( ) ) )
t . getWin ( ) . focus ( ) ;
}
if ( EditorManager . activeEditor != t ) {
if ( ( oed = EditorManager . activeEditor ) != null )
oed . onDeactivate . dispatch ( oed , t ) ;
t . onActivate . dispatch ( t , oed ) ;
}
EditorManager . _setActive ( t ) ;
} ,
execCallback : function ( n ) {
var t = this , f = t . settings [ n ] , s ;
if ( ! f )
return ;
// Look through lookup
if ( t . callbackLookup && ( s = t . callbackLookup [ n ] ) ) {
f = s . func ;
s = s . scope ;
}
if ( is ( f , 'string' ) ) {
s = f . replace ( /\.\w+$/ , '' ) ;
s = s ? tinymce . resolve ( s ) : 0 ;
f = tinymce . resolve ( f ) ;
t . callbackLookup = t . callbackLookup || { } ;
t . callbackLookup [ n ] = { func : f , scope : s } ;
}
return f . apply ( s || t , Array . prototype . slice . call ( arguments , 1 ) ) ;
} ,
translate : function ( s ) {
var c = this . settings . language || 'en' , i18n = EditorManager . i18n ;
if ( ! s )
return '' ;
return i18n [ c + '.' + s ] || s . replace ( /{\#([^}]+)\}/g , function ( a , b ) {
return i18n [ c + '.' + b ] || '{#' + b + '}' ;
} ) ;
} ,
getLang : function ( n , dv ) {
return EditorManager . i18n [ ( this . settings . language || 'en' ) + '.' + n ] || ( is ( dv ) ? dv : '{#' + n + '}' ) ;
} ,
getParam : function ( n , dv , ty ) {
var tr = tinymce . trim , v = is ( this . settings [ n ] ) ? this . settings [ n ] : dv , o ;
if ( ty === 'hash' ) {
o = { } ;
if ( is ( v , 'string' ) ) {
each ( v . indexOf ( '=' ) > 0 ? v . split ( /[;,](?![^=;,]*(?:[;,]|$))/ ) : v . split ( ',' ) , function ( v ) {
v = v . split ( '=' ) ;
if ( v . length > 1 )
o [ tr ( v [ 0 ] ) ] = tr ( v [ 1 ] ) ;
else
o [ tr ( v [ 0 ] ) ] = tr ( v ) ;
} ) ;
} else
o = v ;
return o ;
}
return v ;
} ,
nodeChanged : function ( o ) {
var t = this , s = t . selection , n = s . getNode ( ) || t . getBody ( ) ;
// Fix for bug #1896577 it seems that this can not be fired while the editor is loading
if ( t . initialized ) {
t . onNodeChange . dispatch (
t ,
o ? o . controlManager || t . controlManager : t . controlManager ,
isIE && n . ownerDocument != t . getDoc ( ) ? t . getBody ( ) : n , // Fix for IE initial state
s . isCollapsed ( ) ,
o
) ;
}
} ,
addButton : function ( n , s ) {
var t = this ;
t . buttons = t . buttons || { } ;
t . buttons [ n ] = s ;
} ,
addCommand : function ( n , f , s ) {
this . execCommands [ n ] = { func : f , scope : s || this } ;
} ,
addQueryStateHandler : function ( n , f , s ) {
this . queryStateCommands [ n ] = { func : f , scope : s || this } ;
} ,
addQueryValueHandler : function ( n , f , s ) {
this . queryValueCommands [ n ] = { func : f , scope : s || this } ;
} ,
addShortcut : function ( pa , desc , cmd _func , sc ) {
var t = this , c ;
if ( ! t . settings . custom _shortcuts )
return false ;
t . shortcuts = t . shortcuts || { } ;
if ( is ( cmd _func , 'string' ) ) {
c = cmd _func ;
cmd _func = function ( ) {
t . execCommand ( c , false , null ) ;
} ;
}
if ( is ( cmd _func , 'object' ) ) {
c = cmd _func ;
cmd _func = function ( ) {
t . execCommand ( c [ 0 ] , c [ 1 ] , c [ 2 ] ) ;
} ;
}
each ( explode ( pa ) , function ( pa ) {
var o = {
func : cmd _func ,
scope : sc || this ,
desc : desc ,
alt : false ,
ctrl : false ,
shift : false
} ;
each ( explode ( pa , '+' ) , function ( v ) {
switch ( v ) {
case 'alt' :
case 'ctrl' :
case 'shift' :
o [ v ] = true ;
break ;
default :
o . charCode = v . charCodeAt ( 0 ) ;
o . keyCode = v . toUpperCase ( ) . charCodeAt ( 0 ) ;
}
} ) ;
t . shortcuts [ ( o . ctrl ? 'ctrl' : '' ) + ',' + ( o . alt ? 'alt' : '' ) + ',' + ( o . shift ? 'shift' : '' ) + ',' + o . keyCode ] = o ;
} ) ;
return true ;
} ,
execCommand : function ( cmd , ui , val , a ) {
var t = this , s = 0 , o , st ;
if ( ! /^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/ . test ( cmd ) && ( ! a || ! a . skip _focus ) )
t . focus ( ) ;
o = { } ;
t . onBeforeExecCommand . dispatch ( t , cmd , ui , val , o ) ;
if ( o . terminate )
return false ;
// Command callback
if ( t . execCallback ( 'execcommand_callback' , t . id , t . selection . getNode ( ) , cmd , ui , val ) ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
return true ;
}
// Registred commands
if ( o = t . execCommands [ cmd ] ) {
st = o . func . call ( o . scope , ui , val ) ;
// Fall through on true
if ( st !== true ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
return st ;
}
}
// Plugin commands
each ( t . plugins , function ( p ) {
if ( p . execCommand && p . execCommand ( cmd , ui , val ) ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
s = 1 ;
return false ;
}
} ) ;
if ( s )
return true ;
// Theme commands
if ( t . theme && t . theme . execCommand && t . theme . execCommand ( cmd , ui , val ) ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
return true ;
}
// Execute global commands
if ( tinymce . GlobalCommands . execCommand ( t , cmd , ui , val ) ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
return true ;
}
// Editor commands
if ( t . editorCommands . execCommand ( cmd , ui , val ) ) {
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
return true ;
}
// Browser commands
t . getDoc ( ) . execCommand ( cmd , ui , val ) ;
t . onExecCommand . dispatch ( t , cmd , ui , val , a ) ;
} ,
queryCommandState : function ( c ) {
var t = this , o , s ;
// Is hidden then return undefined
if ( t . _isHidden ( ) )
return ;
// Registred commands
if ( o = t . queryStateCommands [ c ] ) {
s = o . func . call ( o . scope ) ;
// Fall though on true
if ( s !== true )
return s ;
}
// Registred commands
o = t . editorCommands . queryCommandState ( c ) ;
if ( o !== - 1 )
return o ;
// Browser commands
try {
return this . getDoc ( ) . queryCommandState ( c ) ;
} catch ( ex ) {
// Fails sometimes see bug: 1896577
}
} ,
queryCommandValue : function ( c ) {
var t = this , o , s ;
// Is hidden then return undefined
if ( t . _isHidden ( ) )
return ;
// Registred commands
if ( o = t . queryValueCommands [ c ] ) {
s = o . func . call ( o . scope ) ;
// Fall though on true
if ( s !== true )
return s ;
}
// Registred commands
o = t . editorCommands . queryCommandValue ( c ) ;
if ( is ( o ) )
return o ;
// Browser commands
try {
return this . getDoc ( ) . queryCommandValue ( c ) ;
} catch ( ex ) {
// Fails sometimes see bug: 1896577
}
} ,
show : function ( ) {
var t = this ;
DOM . show ( t . getContainer ( ) ) ;
DOM . hide ( t . id ) ;
t . load ( ) ;
} ,
hide : function ( ) {
var t = this , d = t . getDoc ( ) ;
// Fixed bug where IE has a blinking cursor left from the editor
if ( isIE && d )
d . execCommand ( 'SelectAll' ) ;
// We must save before we hide so Safari doesn't crash
t . save ( ) ;
DOM . hide ( t . getContainer ( ) ) ;
DOM . setStyle ( t . id , 'display' , t . orgDisplay ) ;
} ,
isHidden : function ( ) {
return ! DOM . isHidden ( this . id ) ;
} ,
setProgressState : function ( b , ti , o ) {
this . onSetProgressState . dispatch ( this , b , ti , o ) ;
return b ;
} ,
resizeToContent : function ( ) {
var t = this ;
DOM . setStyle ( t . id + "_ifr" , 'height' , t . getBody ( ) . scrollHeight ) ;
} ,
load : function ( o ) {
var t = this , e = t . getElement ( ) , h ;
if ( e ) {
o = o || { } ;
o . load = true ;
// Double encode existing entities in the value
h = t . setContent ( is ( e . value ) ? e . value : e . innerHTML , o ) ;
o . element = e ;
if ( ! o . no _events )
t . onLoadContent . dispatch ( t , o ) ;
o . element = e = null ;
return h ;
}
} ,
save : function ( o ) {
var t = this , e = t . getElement ( ) , h , f ;
if ( ! e || ! t . initialized )
return ;
o = o || { } ;
o . save = true ;
// Add undo level will trigger onchange event
if ( ! o . no _events ) {
t . undoManager . typing = 0 ;
t . undoManager . add ( ) ;
}
o . element = e ;
h = o . content = t . getContent ( o ) ;
if ( ! o . no _events )
t . onSaveContent . dispatch ( t , o ) ;
h = o . content ;
if ( ! /TEXTAREA|INPUT/i . test ( e . nodeName ) ) {
e . innerHTML = h ;
// Update hidden form element
if ( f = DOM . getParent ( t . id , 'form' ) ) {
each ( f . elements , function ( e ) {
if ( e . name == t . id ) {
e . value = h ;
return false ;
}
} ) ;
}
} else
e . value = h ;
o . element = e = null ;
return h ;
} ,
setContent : function ( h , o ) {
var t = this ;
o = o || { } ;
o . format = o . format || 'html' ;
o . set = true ;
o . content = h ;
if ( ! o . no _events )
t . onBeforeSetContent . dispatch ( t , o ) ;
// Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
// It will also be impossible to place the caret in the editor unless there is a BR element present
if ( ! tinymce . isIE && ( h . length === 0 || /^\s+$/ . test ( h ) ) ) {
o . content = t . dom . setHTML ( t . getBody ( ) , '<br mce_bogus="1" />' ) ;
o . format = 'raw' ;
}
o . content = t . dom . setHTML ( t . getBody ( ) , tinymce . trim ( o . content ) ) ;
if ( o . format != 'raw' && t . settings . cleanup ) {
o . getInner = true ;
o . content = t . dom . setHTML ( t . getBody ( ) , t . serializer . serialize ( t . getBody ( ) , o ) ) ;
}
if ( ! o . no _events )
t . onSetContent . dispatch ( t , o ) ;
return o . content ;
} ,
getContent : function ( o ) {
var t = this , h ;
o = o || { } ;
o . format = o . format || 'html' ;
o . get = true ;
if ( ! o . no _events )
t . onBeforeGetContent . dispatch ( t , o ) ;
if ( o . format != 'raw' && t . settings . cleanup ) {
o . getInner = true ;
h = t . serializer . serialize ( t . getBody ( ) , o ) ;
} else
h = t . getBody ( ) . innerHTML ;
h = h . replace ( /^\s*|\s*$/g , '' ) ;
o . content = h ;
if ( ! o . no _events )
t . onGetContent . dispatch ( t , o ) ;
return o . content ;
} ,
isDirty : function ( ) {
var t = this ;
return tinymce . trim ( t . startContent ) != tinymce . trim ( t . getContent ( { format : 'raw' , no _events : 1 } ) ) && ! t . isNotDirty ;
} ,
getContainer : function ( ) {
var t = this ;
if ( ! t . container )
t . container = DOM . get ( t . editorContainer || t . id + '_parent' ) ;
return t . container ;
} ,
getContentAreaContainer : function ( ) {
return this . contentAreaContainer ;
} ,
getElement : function ( ) {
return DOM . get ( this . settings . content _element || this . id ) ;
} ,
getWin : function ( ) {
var t = this , e ;
if ( ! t . contentWindow ) {
e = DOM . get ( t . id + "_ifr" ) ;
if ( e )
t . contentWindow = e . contentWindow ;
}
return t . contentWindow ;
} ,
getDoc : function ( ) {
var t = this , w ;
if ( ! t . contentDocument ) {
w = t . getWin ( ) ;
if ( w )
t . contentDocument = w . document ;
}
return t . contentDocument ;
} ,
getBody : function ( ) {
return this . bodyElement || this . getDoc ( ) . body ;
} ,
convertURL : function ( u , n , e ) {
var t = this , s = t . settings ;
// Use callback instead
if ( s . urlconverter _callback )
return t . execCallback ( 'urlconverter_callback' , u , e , true , n ) ;
// Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
if ( ! s . convert _urls || ( e && e . nodeName == 'LINK' ) || u . indexOf ( 'file:' ) === 0 )
return u ;
// Convert to relative
if ( s . relative _urls )
return t . documentBaseURI . toRelative ( u ) ;
// Convert to absolute
u = t . documentBaseURI . toAbsolute ( u , s . remove _script _host ) ;
return u ;
} ,
addVisual : function ( e ) {
var t = this , s = t . settings ;
e = e || t . getBody ( ) ;
if ( ! is ( t . hasVisual ) )
t . hasVisual = s . visual ;
each ( t . dom . select ( 'table,a' , e ) , function ( e ) {
var v ;
switch ( e . nodeName ) {
case 'TABLE' :
v = t . dom . getAttrib ( e , 'border' ) ;
if ( ! v || v == '0' ) {
if ( t . hasVisual )
t . dom . addClass ( e , s . visual _table _class ) ;
else
t . dom . removeClass ( e , s . visual _table _class ) ;
}
return ;
case 'A' :
v = t . dom . getAttrib ( e , 'name' ) ;
if ( v ) {
if ( t . hasVisual )
t . dom . addClass ( e , 'mceItemAnchor' ) ;
else
t . dom . removeClass ( e , 'mceItemAnchor' ) ;
}
return ;
}
} ) ;
t . onVisualAid . dispatch ( t , e , t . hasVisual ) ;
} ,
remove : function ( ) {
var t = this , e = t . getContainer ( ) ;
t . removed = 1 ; // Cancels post remove event execution
t . hide ( ) ;
t . execCallback ( 'remove_instance_callback' , t ) ;
t . onRemove . dispatch ( t ) ;
// Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command
t . onExecCommand . listeners = [ ] ;
EditorManager . remove ( t ) ;
DOM . remove ( e ) ;
} ,
destroy : function ( s ) {
var t = this ;
// One time is enough
if ( t . destroyed )
return ;
if ( ! s ) {
tinymce . removeUnload ( t . destroy ) ;
tinyMCE . onBeforeUnload . remove ( t . _beforeUnload ) ;
// Manual destroy
if ( t . theme && t . theme . destroy )
t . theme . destroy ( ) ;
// Destroy controls, selection and dom
t . controlManager . destroy ( ) ;
t . selection . destroy ( ) ;
t . dom . destroy ( ) ;
// Remove all events
// Don't clear the window or document if content editable
// is enabled since other instances might still be present
if ( ! t . settings . content _editable ) {
Event . clear ( t . getWin ( ) ) ;
Event . clear ( t . getDoc ( ) ) ;
}
Event . clear ( t . getBody ( ) ) ;
Event . clear ( t . formElement ) ;
}
if ( t . formElement ) {
t . formElement . submit = t . formElement . _mceOldSubmit ;
t . formElement . _mceOldSubmit = null ;
}
t . contentAreaContainer = t . formElement = t . container = t . settings . content _element = t . bodyElement = t . contentDocument = t . contentWindow = null ;
if ( t . selection )
t . selection = t . selection . win = t . selection . dom = t . selection . dom . doc = null ;
t . destroyed = 1 ;
} ,
// Internal functions
_addEvents : function ( ) {
// 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset
var t = this , i , s = t . settings , lo = {
mouseup : 'onMouseUp' ,
mousedown : 'onMouseDown' ,
click : 'onClick' ,
keyup : 'onKeyUp' ,
keydown : 'onKeyDown' ,
keypress : 'onKeyPress' ,
submit : 'onSubmit' ,
reset : 'onReset' ,
contextmenu : 'onContextMenu' ,
dblclick : 'onDblClick' ,
paste : 'onPaste' // Doesn't work in all browsers yet
} ;
function eventHandler ( e , o ) {
var ty = e . type ;
// Don't fire events when it's removed
if ( t . removed )
return ;
// Generic event handler
if ( t . onEvent . dispatch ( t , e , o ) !== false ) {
// Specific event handler
t [ lo [ e . fakeType || e . type ] ] . dispatch ( t , e , o ) ;
}
} ;
// Add DOM events
each ( lo , function ( v , k ) {
switch ( k ) {
case 'contextmenu' :
if ( tinymce . isOpera ) {
// Fake contextmenu on Opera
Event . add ( t . getBody ( ) , 'mousedown' , function ( e ) {
if ( e . ctrlKey ) {
e . fakeType = 'contextmenu' ;
eventHandler ( e ) ;
}
} ) ;
} else
Event . add ( t . getBody ( ) , k , eventHandler ) ;
break ;
case 'paste' :
Event . add ( t . getBody ( ) , k , function ( e ) {
eventHandler ( e ) ;
} ) ;
break ;
case 'submit' :
case 'reset' :
Event . add ( t . getElement ( ) . form || DOM . getParent ( t . id , 'form' ) , k , eventHandler ) ;
break ;
default :
Event . add ( s . content _editable ? t . getBody ( ) : t . getDoc ( ) , k , eventHandler ) ;
}
} ) ;
Event . add ( s . content _editable ? t . getBody ( ) : ( isGecko ? t . getDoc ( ) : t . getWin ( ) ) , 'focus' , function ( e ) {
t . focus ( true ) ;
} ) ;
// Fixes bug where a specified document_base_uri could result in broken images
// This will also fix drag drop of images in Gecko
if ( tinymce . isGecko ) {
// Convert all images to absolute URLs
/ * t . o n S e t C o n t e n t . a d d ( f u n c t i o n ( e d , o ) {
each ( ed . dom . select ( 'img' ) , function ( e ) {
var v ;
if ( v = e . getAttribute ( 'mce_src' ) )
e . src = t . documentBaseURI . toAbsolute ( v ) ;
} )
} ) ; * /
Event . add ( t . getDoc ( ) , 'DOMNodeInserted' , function ( e ) {
var v ;
e = e . target ;
if ( e . nodeType === 1 && e . nodeName === 'IMG' && ( v = e . getAttribute ( 'mce_src' ) ) )
e . src = t . documentBaseURI . toAbsolute ( v ) ;
} ) ;
}
// Set various midas options in Gecko
if ( isGecko ) {
function setOpts ( ) {
var t = this , d = t . getDoc ( ) , s = t . settings ;
if ( isGecko && ! s . readonly ) {
if ( t . _isHidden ( ) ) {
try {
if ( ! s . content _editable )
d . designMode = 'On' ;
} catch ( ex ) {
// Fails if it's hidden
}
}
try {
// Try new Gecko method
d . execCommand ( "styleWithCSS" , 0 , false ) ;
} catch ( ex ) {
// Use old method
if ( ! t . _isHidden ( ) )
try { d . execCommand ( "useCSS" , 0 , true ) ; } catch ( ex ) { }
}
if ( ! s . table _inline _editing )
try { d . execCommand ( 'enableInlineTableEditing' , false , false ) ; } catch ( ex ) { }
if ( ! s . object _resizing )
try { d . execCommand ( 'enableObjectResizing' , false , false ) ; } catch ( ex ) { }
}
} ;
t . onBeforeExecCommand . add ( setOpts ) ;
t . onMouseDown . add ( setOpts ) ;
}
// Add node change handlers
t . onMouseUp . add ( t . nodeChanged ) ;
t . onClick . add ( t . nodeChanged ) ;
t . onKeyUp . add ( function ( ed , e ) {
var c = e . keyCode ;
if ( ( c >= 33 && c <= 36 ) || ( c >= 37 && c <= 40 ) || c == 13 || c == 45 || c == 46 || c == 8 || ( tinymce . isMac && ( c == 91 || c == 93 ) ) || e . ctrlKey )
t . nodeChanged ( ) ;
} ) ;
// Add reset handler
t . onReset . add ( function ( ) {
t . setContent ( t . startContent , { format : 'raw' } ) ;
} ) ;
// Add shortcuts
if ( s . custom _shortcuts ) {
if ( s . custom _undo _redo _keyboard _shortcuts ) {
t . addShortcut ( 'ctrl+z' , t . getLang ( 'undo_desc' ) , 'Undo' ) ;
t . addShortcut ( 'ctrl+y' , t . getLang ( 'redo_desc' ) , 'Redo' ) ;
}
// Add default shortcuts for gecko
if ( isGecko ) {
t . addShortcut ( 'ctrl+b' , t . getLang ( 'bold_desc' ) , 'Bold' ) ;
t . addShortcut ( 'ctrl+i' , t . getLang ( 'italic_desc' ) , 'Italic' ) ;
t . addShortcut ( 'ctrl+u' , t . getLang ( 'underline_desc' ) , 'Underline' ) ;
}
// BlockFormat shortcuts keys
for ( i = 1 ; i <= 6 ; i ++ )
t . addShortcut ( 'ctrl+' + i , '' , [ 'FormatBlock' , false , '<h' + i + '>' ] ) ;
t . addShortcut ( 'ctrl+7' , '' , [ 'FormatBlock' , false , '<p>' ] ) ;
t . addShortcut ( 'ctrl+8' , '' , [ 'FormatBlock' , false , '<div>' ] ) ;
t . addShortcut ( 'ctrl+9' , '' , [ 'FormatBlock' , false , '<address>' ] ) ;
function find ( e ) {
var v = null ;
if ( ! e . altKey && ! e . ctrlKey && ! e . metaKey )
return v ;
each ( t . shortcuts , function ( o ) {
if ( tinymce . isMac && o . ctrl != e . metaKey )
return ;
else if ( ! tinymce . isMac && o . ctrl != e . ctrlKey )
return ;
if ( o . alt != e . altKey )
return ;
if ( o . shift != e . shiftKey )
return ;
if ( e . keyCode == o . keyCode || ( e . charCode && e . charCode == o . charCode ) ) {
v = o ;
return false ;
}
} ) ;
return v ;
} ;
t . onKeyUp . add ( function ( ed , e ) {
var o = find ( e ) ;
if ( o )
return Event . cancel ( e ) ;
} ) ;
t . onKeyPress . add ( function ( ed , e ) {
var o = find ( e ) ;
if ( o )
return Event . cancel ( e ) ;
} ) ;
t . onKeyDown . add ( function ( ed , e ) {
var o = find ( e ) ;
if ( o ) {
o . func . call ( o . scope ) ;
return Event . cancel ( e ) ;
}
} ) ;
}
if ( tinymce . isIE ) {
// Fix so resize will only update the width and height attributes not the styles of an image
// It will also block mceItemNoResize items
Event . add ( t . getDoc ( ) , 'controlselect' , function ( e ) {
var re = t . resizeInfo , cb ;
e = e . target ;
// Don't do this action for non image elements
if ( e . nodeName !== 'IMG' )
return ;
if ( re )
Event . remove ( re . node , re . ev , re . cb ) ;
if ( ! t . dom . hasClass ( e , 'mceItemNoResize' ) ) {
ev = 'resizeend' ;
cb = Event . add ( e , ev , function ( e ) {
var v ;
e = e . target ;
if ( v = t . dom . getStyle ( e , 'width' ) ) {
t . dom . setAttrib ( e , 'width' , v . replace ( /[^0-9%]+/g , '' ) ) ;
t . dom . setStyle ( e , 'width' , '' ) ;
}
if ( v = t . dom . getStyle ( e , 'height' ) ) {
t . dom . setAttrib ( e , 'height' , v . replace ( /[^0-9%]+/g , '' ) ) ;
t . dom . setStyle ( e , 'height' , '' ) ;
}
} ) ;
} else {
ev = 'resizestart' ;
cb = Event . add ( e , 'resizestart' , Event . cancel , Event ) ;
}
re = t . resizeInfo = {
node : e ,
ev : ev ,
cb : cb
} ;
} ) ;
t . onKeyDown . add ( function ( ed , e ) {
switch ( e . keyCode ) {
case 8 :
// Fix IE control + backspace browser bug
if ( t . selection . getRng ( ) . item ) {
t . selection . getRng ( ) . item ( 0 ) . removeNode ( ) ;
return Event . cancel ( e ) ;
}
}
} ) ;
/ * i f ( t . d o m . b o x M o d e l ) {
t . getBody ( ) . style . height = '100%' ;
Event . add ( t . getWin ( ) , 'resize' , function ( e ) {
var docElm = t . getDoc ( ) . documentElement ;
docElm . style . height = ( docElm . offsetHeight - 10 ) + 'px' ;
} ) ;
} * /
}
if ( tinymce . isOpera ) {
t . onClick . add ( function ( ed , e ) {
Event . prevent ( e ) ;
} ) ;
}
// Add custom undo/redo handlers
if ( s . custom _undo _redo ) {
function addUndo ( ) {
t . undoManager . typing = 0 ;
t . undoManager . add ( ) ;
} ;
// Add undo level on editor blur
if ( tinymce . isIE ) {
Event . add ( t . getWin ( ) , 'blur' , function ( e ) {
var n ;
// Check added for fullscreen bug
if ( t . selection ) {
n = t . selection . getNode ( ) ;
// Add undo level is selection was lost to another document
if ( ! t . removed && n . ownerDocument && n . ownerDocument != t . getDoc ( ) )
addUndo ( ) ;
}
} ) ;
} else {
Event . add ( t . getDoc ( ) , 'blur' , function ( ) {
if ( t . selection && ! t . removed )
addUndo ( ) ;
} ) ;
}
t . onMouseDown . add ( addUndo ) ;
t . onKeyUp . add ( function ( ed , e ) {
if ( ( e . keyCode >= 33 && e . keyCode <= 36 ) || ( e . keyCode >= 37 && e . keyCode <= 40 ) || e . keyCode == 13 || e . keyCode == 45 || e . ctrlKey ) {
t . undoManager . typing = 0 ;
t . undoManager . add ( ) ;
}
} ) ;
t . onKeyDown . add ( function ( ed , e ) {
// Is caracter positon keys
if ( ( e . keyCode >= 33 && e . keyCode <= 36 ) || ( e . keyCode >= 37 && e . keyCode <= 40 ) || e . keyCode == 13 || e . keyCode == 45 ) {
if ( t . undoManager . typing ) {
t . undoManager . add ( ) ;
t . undoManager . typing = 0 ;
}
return ;
}
if ( ! t . undoManager . typing ) {
t . undoManager . add ( ) ;
t . undoManager . typing = 1 ;
}
} ) ;
}
} ,
_convertInlineElements : function ( ) {
var t = this , s = t . settings , dom = t . dom , v , e , na , st , sp ;
function convert ( ed , o ) {
if ( ! s . inline _styles )
return ;
if ( o . get ) {
each ( t . dom . select ( 'table,u,strike' , o . node ) , function ( n ) {
switch ( n . nodeName ) {
case 'TABLE' :
if ( v = dom . getAttrib ( n , 'height' ) ) {
dom . setStyle ( n , 'height' , v ) ;
dom . setAttrib ( n , 'height' , '' ) ;
}
break ;
case 'U' :
case 'STRIKE' :
//sp = dom.create('span', {style : dom.getAttrib(n, 'style')});
n . style . textDecoration = n . nodeName == 'U' ? 'underline' : 'line-through' ;
dom . setAttrib ( n , 'mce_style' , '' ) ;
dom . setAttrib ( n , 'mce_name' , 'span' ) ;
break ;
}
} ) ;
} else if ( o . set ) {
each ( t . dom . select ( 'table,span' , o . node ) . reverse ( ) , function ( n ) {
if ( n . nodeName == 'TABLE' ) {
if ( v = dom . getStyle ( n , 'height' ) )
dom . setAttrib ( n , 'height' , v . replace ( /[^0-9%]+/g , '' ) ) ;
} else {
// Convert spans to elements
if ( n . style . textDecoration == 'underline' )
na = 'u' ;
else if ( n . style . textDecoration == 'line-through' )
na = 'strike' ;
else
na = '' ;
if ( na ) {
n . style . textDecoration = '' ;
dom . setAttrib ( n , 'mce_style' , '' ) ;
e = dom . create ( na , {
style : dom . getAttrib ( n , 'style' )
} ) ;
dom . replace ( e , n , 1 ) ;
}
}
} ) ;
}
} ;
t . onPreProcess . add ( convert ) ;
if ( ! s . cleanup _on _startup ) {
t . onSetContent . add ( function ( ed , o ) {
if ( o . initial )
convert ( t , { node : t . getBody ( ) , set : 1 } ) ;
} ) ;
}
} ,
_convertFonts : function ( ) {
var t = this , s = t . settings , dom = t . dom , fz , fzn , sl , cl ;
// No need
if ( ! s . inline _styles )
return ;
// Font pt values and font size names
fz = [ 8 , 10 , 12 , 14 , 18 , 24 , 36 ] ;
fzn = [ 'xx-small' , 'x-small' , 'small' , 'medium' , 'large' , 'x-large' , 'xx-large' ] ;
if ( sl = s . font _size _style _values )
sl = explode ( sl ) ;
if ( cl = s . font _size _classes )
cl = explode ( cl ) ;
function process ( no ) {
var n , sp , nl , x ;
// Keep unit tests happy
if ( ! s . inline _styles )
return ;
nl = t . dom . select ( 'font' , no ) ;
for ( x = nl . length - 1 ; x >= 0 ; x -- ) {
n = nl [ x ] ;
sp = dom . create ( 'span' , {
style : dom . getAttrib ( n , 'style' ) ,
'class' : dom . getAttrib ( n , 'class' )
} ) ;
dom . setStyles ( sp , {
fontFamily : dom . getAttrib ( n , 'face' ) ,
color : dom . getAttrib ( n , 'color' ) ,
backgroundColor : n . style . backgroundColor
} ) ;
if ( n . size ) {
if ( sl )
dom . setStyle ( sp , 'fontSize' , sl [ parseInt ( n . size ) - 1 ] ) ;
else
dom . setAttrib ( sp , 'class' , cl [ parseInt ( n . size ) - 1 ] ) ;
}
dom . setAttrib ( sp , 'mce_style' , '' ) ;
dom . replace ( sp , n , 1 ) ;
}
} ;
// Run on cleanup
t . onPreProcess . add ( function ( ed , o ) {
if ( o . get )
process ( o . node ) ;
} ) ;
t . onSetContent . add ( function ( ed , o ) {
if ( o . initial )
process ( o . node ) ;
} ) ;
} ,
_isHidden : function ( ) {
var s ;
if ( ! isGecko )
return 0 ;
// Weird, wheres that cursor selection?
s = this . selection . getSel ( ) ;
return ( ! s || ! s . rangeCount || s . rangeCount == 0 ) ;
} ,
// Fix for bug #1867292
_fixNesting : function ( s ) {
var d = [ ] , i ;
s = s . replace ( /<(\/)?([^\s>]+)[^>]*?>/g , function ( a , b , c ) {
var e ;
// Handle end element
if ( b === '/' ) {
if ( ! d . length )
return '' ;
if ( c !== d [ d . length - 1 ] . tag ) {
for ( i = d . length - 1 ; i >= 0 ; i -- ) {
if ( d [ i ] . tag === c ) {
d [ i ] . close = 1 ;
break ;
}
}
return '' ;
} else {
d . pop ( ) ;
if ( d . length && d [ d . length - 1 ] . close ) {
a = a + '</' + d [ d . length - 1 ] . tag + '>' ;
d . pop ( ) ;
}
}
} else {
// Ignore these
if ( /^(br|hr|input|meta|img|link|param)$/i . test ( c ) )
return a ;
// Ignore closed ones
if ( /\/>$/ . test ( a ) )
return a ;
d . push ( { tag : c } ) ; // Push start element
}
return a ;
} ) ;
// End all open tags
for ( i = d . length - 1 ; i >= 0 ; i -- )
s += '</' + d [ i ] . tag + '>' ;
return s ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var each = tinymce . each , isIE = tinymce . isIE , isGecko = tinymce . isGecko , isOpera = tinymce . isOpera , isWebKit = tinymce . isWebKit ;
tinymce . create ( 'tinymce.EditorCommands' , {
EditorCommands : function ( ed ) {
this . editor = ed ;
} ,
execCommand : function ( cmd , ui , val ) {
var t = this , ed = t . editor , f ;
switch ( cmd ) {
// Ignore these
case 'mceResetDesignMode' :
case 'mceBeginUndoLevel' :
return true ;
// Ignore these
case 'unlink' :
t . UnLink ( ) ;
return true ;
// Bundle these together
case 'JustifyLeft' :
case 'JustifyCenter' :
case 'JustifyRight' :
case 'JustifyFull' :
t . mceJustify ( cmd , cmd . substring ( 7 ) . toLowerCase ( ) ) ;
return true ;
default :
f = this [ cmd ] ;
if ( f ) {
f . call ( this , ui , val ) ;
return true ;
}
}
return false ;
} ,
Indent : function ( ) {
var ed = this . editor , d = ed . dom , s = ed . selection , e , iv , iu ;
// Setup indent level
iv = ed . settings . indentation ;
iu = /[a-z%]+$/i . exec ( iv ) ;
iv = parseInt ( iv ) ;
if ( ed . settings . inline _styles && ( ! this . queryStateInsertUnorderedList ( ) && ! this . queryStateInsertOrderedList ( ) ) ) {
each ( s . getSelectedBlocks ( ) , function ( e ) {
d . setStyle ( e , 'paddingLeft' , ( parseInt ( e . style . paddingLeft || 0 ) + iv ) + iu ) ;
} ) ;
return ;
}
ed . getDoc ( ) . execCommand ( 'Indent' , false , null ) ;
if ( isIE ) {
d . getParent ( s . getNode ( ) , function ( n ) {
if ( n . nodeName == 'BLOCKQUOTE' ) {
n . dir = n . style . cssText = '' ;
}
} ) ;
}
} ,
Outdent : function ( ) {
var ed = this . editor , d = ed . dom , s = ed . selection , e , v , iv , iu ;
// Setup indent level
iv = ed . settings . indentation ;
iu = /[a-z%]+$/i . exec ( iv ) ;
iv = parseInt ( iv ) ;
if ( ed . settings . inline _styles && ( ! this . queryStateInsertUnorderedList ( ) && ! this . queryStateInsertOrderedList ( ) ) ) {
each ( s . getSelectedBlocks ( ) , function ( e ) {
v = Math . max ( 0 , parseInt ( e . style . paddingLeft || 0 ) - iv ) ;
d . setStyle ( e , 'paddingLeft' , v ? v + iu : '' ) ;
} ) ;
return ;
}
ed . getDoc ( ) . execCommand ( 'Outdent' , false , null ) ;
} ,
/ *
mceSetAttribute : function ( u , v ) {
var ed = this . editor , d = ed . dom , e ;
if ( e = d . getParent ( ed . selection . getNode ( ) , d . isBlock ) )
d . setAttrib ( e , v . name , v . value ) ;
} ,
* /
mceSetContent : function ( u , v ) {
this . editor . setContent ( v ) ;
} ,
mceToggleVisualAid : function ( ) {
var ed = this . editor ;
ed . hasVisual = ! ed . hasVisual ;
ed . addVisual ( ) ;
} ,
mceReplaceContent : function ( u , v ) {
var s = this . editor . selection ;
s . setContent ( v . replace ( /\{\$selection\}/g , s . getContent ( { format : 'text' } ) ) ) ;
} ,
mceInsertLink : function ( u , v ) {
var ed = this . editor , s = ed . selection , e = ed . dom . getParent ( s . getNode ( ) , 'a' ) ;
if ( tinymce . is ( v , 'string' ) )
v = { href : v } ;
function set ( e ) {
each ( v , function ( v , k ) {
ed . dom . setAttrib ( e , k , v ) ;
} ) ;
} ;
if ( ! e ) {
ed . execCommand ( 'CreateLink' , false , 'javascript:mctmp(0);' ) ;
each ( ed . dom . select ( 'a[href=javascript:mctmp(0);]' ) , function ( e ) {
set ( e ) ;
} ) ;
} else {
if ( v . href )
set ( e ) ;
else
ed . dom . remove ( e , 1 ) ;
}
} ,
UnLink : function ( ) {
var ed = this . editor , s = ed . selection ;
if ( s . isCollapsed ( ) )
s . select ( s . getNode ( ) ) ;
ed . getDoc ( ) . execCommand ( 'unlink' , false , null ) ;
s . collapse ( 0 ) ;
} ,
FontName : function ( u , v ) {
var t = this , ed = t . editor , s = ed . selection , e ;
if ( ! v ) {
if ( s . isCollapsed ( ) )
s . select ( s . getNode ( ) ) ;
} else {
if ( ed . settings . convert _fonts _to _spans )
t . _applyInlineStyle ( 'span' , { style : { fontFamily : v } } ) ;
else
ed . getDoc ( ) . execCommand ( 'FontName' , false , v ) ;
}
} ,
FontSize : function ( u , v ) {
var ed = this . editor , s = ed . settings , fc , fs ;
// Use style options instead
if ( s . convert _fonts _to _spans && v >= 1 && v <= 7 ) {
fs = tinymce . explode ( s . font _size _style _values ) ;
fc = tinymce . explode ( s . font _size _classes ) ;
if ( fc )
v = fc [ v - 1 ] || v ;
else
v = fs [ v - 1 ] || v ;
}
if ( v >= 1 && v <= 7 )
ed . getDoc ( ) . execCommand ( 'FontSize' , false , v ) ;
else
this . _applyInlineStyle ( 'span' , { style : { fontSize : v } } ) ;
} ,
queryCommandValue : function ( c ) {
var f = this [ 'queryValue' + c ] ;
if ( f )
return f . call ( this , c ) ;
return false ;
} ,
queryCommandState : function ( cmd ) {
var f ;
switch ( cmd ) {
// Bundle these together
case 'JustifyLeft' :
case 'JustifyCenter' :
case 'JustifyRight' :
case 'JustifyFull' :
return this . queryStateJustify ( cmd , cmd . substring ( 7 ) . toLowerCase ( ) ) ;
default :
if ( f = this [ 'queryState' + cmd ] )
return f . call ( this , cmd ) ;
}
return - 1 ;
} ,
_queryState : function ( c ) {
try {
return this . editor . getDoc ( ) . queryCommandState ( c ) ;
} catch ( ex ) {
// Ignore exception
}
} ,
_queryVal : function ( c ) {
try {
return this . editor . getDoc ( ) . queryCommandValue ( c ) ;
} catch ( ex ) {
// Ignore exception
}
} ,
queryValueFontSize : function ( ) {
var ed = this . editor , v = 0 , p ;
if ( p = ed . dom . getParent ( ed . selection . getNode ( ) , 'span' ) )
v = p . style . fontSize ;
if ( ! v && ( isOpera || isWebKit ) ) {
if ( p = ed . dom . getParent ( ed . selection . getNode ( ) , 'font' ) )
v = p . size ;
return v ;
}
return v || this . _queryVal ( 'FontSize' ) ;
} ,
queryValueFontName : function ( ) {
var ed = this . editor , v = 0 , p ;
if ( p = ed . dom . getParent ( ed . selection . getNode ( ) , 'font' ) )
v = p . face ;
if ( p = ed . dom . getParent ( ed . selection . getNode ( ) , 'span' ) )
v = p . style . fontFamily . replace ( /, /g , ',' ) . replace ( /[\'\"]/g , '' ) . toLowerCase ( ) ;
if ( ! v )
v = this . _queryVal ( 'FontName' ) ;
return v ;
} ,
mceJustify : function ( c , v ) {
var ed = this . editor , se = ed . selection , n = se . getNode ( ) , nn = n . nodeName , bl , nb , dom = ed . dom , rm ;
if ( ed . settings . inline _styles && this . queryStateJustify ( c , v ) )
rm = 1 ;
bl = dom . getParent ( n , ed . dom . isBlock ) ;
if ( nn == 'IMG' ) {
if ( v == 'full' )
return ;
if ( rm ) {
if ( v == 'center' )
dom . setStyle ( bl || n . parentNode , 'textAlign' , '' ) ;
dom . setStyle ( n , 'float' , '' ) ;
this . mceRepaint ( ) ;
return ;
}
if ( v == 'center' ) {
// Do not change table elements
if ( bl && /^(TD|TH)$/ . test ( bl . nodeName ) )
bl = 0 ;
if ( ! bl || bl . childNodes . length > 1 ) {
nb = dom . create ( 'p' ) ;
nb . appendChild ( n . cloneNode ( false ) ) ;
if ( bl )
dom . insertAfter ( nb , bl ) ;
else
dom . insertAfter ( nb , n ) ;
dom . remove ( n ) ;
n = nb . firstChild ;
bl = nb ;
}
dom . setStyle ( bl , 'textAlign' , v ) ;
dom . setStyle ( n , 'float' , '' ) ;
} else {
dom . setStyle ( n , 'float' , v ) ;
dom . setStyle ( bl || n . parentNode , 'textAlign' , '' ) ;
}
this . mceRepaint ( ) ;
return ;
}
// Handle the alignment outselfs, less quirks in all browsers
if ( ed . settings . inline _styles && ed . settings . forced _root _block ) {
if ( rm )
v = '' ;
each ( se . getSelectedBlocks ( dom . getParent ( se . getStart ( ) , dom . isBlock ) , dom . getParent ( se . getEnd ( ) , dom . isBlock ) ) , function ( e ) {
dom . setAttrib ( e , 'align' , '' ) ;
dom . setStyle ( e , 'textAlign' , v == 'full' ? 'justify' : v ) ;
} ) ;
return ;
} else if ( ! rm )
ed . getDoc ( ) . execCommand ( c , false , null ) ;
if ( ed . settings . inline _styles ) {
if ( rm ) {
dom . getParent ( ed . selection . getNode ( ) , function ( n ) {
if ( n . style && n . style . textAlign )
dom . setStyle ( n , 'textAlign' , '' ) ;
} ) ;
return ;
}
each ( dom . select ( '*' ) , function ( n ) {
var v = n . align ;
if ( v ) {
if ( v == 'full' )
v = 'justify' ;
dom . setStyle ( n , 'textAlign' , v ) ;
dom . setAttrib ( n , 'align' , '' ) ;
}
} ) ;
}
} ,
mceSetCSSClass : function ( u , v ) {
this . mceSetStyleInfo ( 0 , { command : 'setattrib' , name : 'class' , value : v } ) ;
} ,
getSelectedElement : function ( ) {
var t = this , ed = t . editor , dom = ed . dom , se = ed . selection , r = se . getRng ( ) , r1 , r2 , sc , ec , so , eo , e , sp , ep , re ;
if ( se . isCollapsed ( ) || r . item )
return se . getNode ( ) ;
// Setup regexp
re = ed . settings . merge _styles _invalid _parents ;
if ( tinymce . is ( re , 'string' ) )
re = new RegExp ( re , 'i' ) ;
if ( isIE ) {
r1 = r . duplicate ( ) ;
r1 . collapse ( true ) ;
sc = r1 . parentElement ( ) ;
r2 = r . duplicate ( ) ;
r2 . collapse ( false ) ;
ec = r2 . parentElement ( ) ;
if ( sc != ec ) {
r1 . move ( 'character' , 1 ) ;
sc = r1 . parentElement ( ) ;
}
if ( sc == ec ) {
r1 = r . duplicate ( ) ;
r1 . moveToElementText ( sc ) ;
if ( r1 . compareEndPoints ( 'StartToStart' , r ) == 0 && r1 . compareEndPoints ( 'EndToEnd' , r ) == 0 )
return re && re . test ( sc . nodeName ) ? null : sc ;
}
} else {
function getParent ( n ) {
return dom . getParent ( n , '*' ) ;
} ;
sc = r . startContainer ;
ec = r . endContainer ;
so = r . startOffset ;
eo = r . endOffset ;
if ( ! r . collapsed ) {
if ( sc == ec ) {
if ( so - eo < 2 ) {
if ( sc . hasChildNodes ( ) ) {
sp = sc . childNodes [ so ] ;
return re && re . test ( sp . nodeName ) ? null : sp ;
}
}
}
}
if ( sc . nodeType != 3 || ec . nodeType != 3 )
return null ;
if ( so == 0 ) {
sp = getParent ( sc ) ;
if ( sp && sp . firstChild != sc )
sp = null ;
}
if ( so == sc . nodeValue . length ) {
e = sc . nextSibling ;
if ( e && e . nodeType == 1 )
sp = sc . nextSibling ;
}
if ( eo == 0 ) {
e = ec . previousSibling ;
if ( e && e . nodeType == 1 )
ep = e ;
}
if ( eo == ec . nodeValue . length ) {
ep = getParent ( ec ) ;
if ( ep && ep . lastChild != ec )
ep = null ;
}
// Same element
if ( sp == ep )
return re && sp && re . test ( sp . nodeName ) ? null : sp ;
}
return null ;
} ,
mceSetStyleInfo : function ( u , v ) {
var t = this , ed = t . editor , d = ed . getDoc ( ) , dom = ed . dom , e , b , s = ed . selection , nn = v . wrapper || 'span' , b = s . getBookmark ( ) , re ;
function set ( n , e ) {
if ( n . nodeType == 1 ) {
switch ( v . command ) {
case 'setattrib' :
return dom . setAttrib ( n , v . name , v . value ) ;
case 'setstyle' :
return dom . setStyle ( n , v . name , v . value ) ;
case 'removeformat' :
return dom . setAttrib ( n , 'class' , '' ) ;
}
}
} ;
// Setup regexp
re = ed . settings . merge _styles _invalid _parents ;
if ( tinymce . is ( re , 'string' ) )
re = new RegExp ( re , 'i' ) ;
// Set style info on selected element
if ( ( e = t . getSelectedElement ( ) ) && ! ed . settings . force _span _wrappers )
set ( e , 1 ) ;
else {
// Generate wrappers and set styles on them
d . execCommand ( 'FontName' , false , '__' ) ;
each ( dom . select ( 'span,font' ) , function ( n ) {
var sp , e ;
if ( dom . getAttrib ( n , 'face' ) == '__' || n . style . fontFamily === '__' ) {
sp = dom . create ( nn , { mce _new : '1' } ) ;
set ( sp ) ;
each ( n . childNodes , function ( n ) {
sp . appendChild ( n . cloneNode ( true ) ) ;
} ) ;
dom . replace ( sp , n ) ;
}
} ) ;
}
// Remove wrappers inside new ones
each ( dom . select ( nn ) . reverse ( ) , function ( n ) {
var p = n . parentNode ;
// Check if it's an old span in a new wrapper
if ( ! dom . getAttrib ( n , 'mce_new' ) ) {
// Find new wrapper
p = dom . getParent ( n , '*[mce_new]' ) ;
if ( p )
dom . remove ( n , 1 ) ;
}
} ) ;
// Merge wrappers with parent wrappers
each ( dom . select ( nn ) . reverse ( ) , function ( n ) {
var p = n . parentNode ;
if ( ! p || ! dom . getAttrib ( n , 'mce_new' ) )
return ;
if ( ed . settings . force _span _wrappers && p . nodeName != 'SPAN' )
return ;
// Has parent of the same type and only child
if ( p . nodeName == nn . toUpperCase ( ) && p . childNodes . length == 1 )
return dom . remove ( p , 1 ) ;
// Has parent that is more suitable to have the class and only child
if ( n . nodeType == 1 && ( ! re || ! re . test ( p . nodeName ) ) && p . childNodes . length == 1 ) {
set ( p ) ; // Set style info on parent instead
dom . setAttrib ( n , 'class' , '' ) ;
}
} ) ;
// Remove empty wrappers
each ( dom . select ( nn ) . reverse ( ) , function ( n ) {
if ( dom . getAttrib ( n , 'mce_new' ) || ( dom . getAttribs ( n ) . length <= 1 && n . className === '' ) ) {
if ( ! dom . getAttrib ( n , 'class' ) && ! dom . getAttrib ( n , 'style' ) )
return dom . remove ( n , 1 ) ;
dom . setAttrib ( n , 'mce_new' , '' ) ; // Remove mce_new marker
}
} ) ;
s . moveToBookmark ( b ) ;
} ,
queryStateJustify : function ( c , v ) {
var ed = this . editor , n = ed . selection . getNode ( ) , dom = ed . dom ;
if ( n && n . nodeName == 'IMG' ) {
if ( dom . getStyle ( n , 'float' ) == v )
return 1 ;
return n . parentNode . style . textAlign == v ;
}
n = dom . getParent ( ed . selection . getStart ( ) , function ( n ) {
return n . nodeType == 1 && n . style . textAlign ;
} ) ;
if ( v == 'full' )
v = 'justify' ;
if ( ed . settings . inline _styles )
return ( n && n . style . textAlign == v ) ;
return this . _queryState ( c ) ;
} ,
ForeColor : function ( ui , v ) {
var ed = this . editor ;
if ( ed . settings . convert _fonts _to _spans ) {
this . _applyInlineStyle ( 'span' , { style : { color : v } } ) ;
return ;
} else
ed . getDoc ( ) . execCommand ( 'ForeColor' , false , v ) ;
} ,
HiliteColor : function ( ui , val ) {
var t = this , ed = t . editor , d = ed . getDoc ( ) ;
if ( ed . settings . convert _fonts _to _spans ) {
this . _applyInlineStyle ( 'span' , { style : { backgroundColor : val } } ) ;
return ;
}
function set ( s ) {
if ( ! isGecko )
return ;
try {
// Try new Gecko method
d . execCommand ( "styleWithCSS" , 0 , s ) ;
} catch ( ex ) {
// Use old
d . execCommand ( "useCSS" , 0 , ! s ) ;
}
} ;
if ( isGecko || isOpera ) {
set ( true ) ;
d . execCommand ( 'hilitecolor' , false , val ) ;
set ( false ) ;
} else
d . execCommand ( 'BackColor' , false , val ) ;
} ,
FormatBlock : function ( ui , val ) {
var t = this , ed = t . editor , s = ed . selection , dom = ed . dom , bl , nb , b ;
function isBlock ( n ) {
return /^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/ . test ( n . nodeName ) ;
} ;
bl = dom . getParent ( s . getNode ( ) , function ( n ) {
return isBlock ( n ) ;
} ) ;
// IE has an issue where it removes the parent div if you change format on the paragrah in <div><p>Content</p></div>
// FF and Opera doesn't change parent DIV elements if you switch format
if ( bl ) {
if ( ( isIE && isBlock ( bl . parentNode ) ) || bl . nodeName == 'DIV' ) {
// Rename block element
nb = ed . dom . create ( val ) ;
each ( dom . getAttribs ( bl ) , function ( v ) {
dom . setAttrib ( nb , v . nodeName , dom . getAttrib ( bl , v . nodeName ) ) ;
} ) ;
b = s . getBookmark ( ) ;
dom . replace ( nb , bl , 1 ) ;
s . moveToBookmark ( b ) ;
ed . nodeChanged ( ) ;
return ;
}
}
val = ed . settings . forced _root _block ? ( val || '<p>' ) : val ;
if ( val . indexOf ( '<' ) == - 1 )
val = '<' + val + '>' ;
if ( tinymce . isGecko )
val = val . replace ( /<(div|blockquote|code|dt|dd|dl|samp)>/gi , '$1' ) ;
ed . getDoc ( ) . execCommand ( 'FormatBlock' , false , val ) ;
} ,
mceCleanup : function ( ) {
var ed = this . editor , s = ed . selection , b = s . getBookmark ( ) ;
ed . setContent ( ed . getContent ( ) ) ;
s . moveToBookmark ( b ) ;
} ,
mceRemoveNode : function ( ui , val ) {
var ed = this . editor , s = ed . selection , b , n = val || s . getNode ( ) ;
// Make sure that the body node isn't removed
if ( n == ed . getBody ( ) )
return ;
b = s . getBookmark ( ) ;
ed . dom . remove ( n , 1 ) ;
s . moveToBookmark ( b ) ;
ed . nodeChanged ( ) ;
} ,
mceSelectNodeDepth : function ( ui , val ) {
var ed = this . editor , s = ed . selection , c = 0 ;
ed . dom . getParent ( s . getNode ( ) , function ( n ) {
if ( n . nodeType == 1 && c ++ == val ) {
s . select ( n ) ;
ed . nodeChanged ( ) ;
return false ;
}
} , ed . getBody ( ) ) ;
} ,
mceSelectNode : function ( u , v ) {
this . editor . selection . select ( v ) ;
} ,
mceInsertContent : function ( ui , val ) {
this . editor . selection . setContent ( val ) ;
} ,
mceInsertRawHTML : function ( ui , val ) {
var ed = this . editor ;
ed . selection . setContent ( 'tiny_mce_marker' ) ;
ed . setContent ( ed . getContent ( ) . replace ( /tiny_mce_marker/g , val ) ) ;
} ,
mceRepaint : function ( ) {
var s , b , e = this . editor ;
if ( tinymce . isGecko ) {
try {
s = e . selection ;
b = s . getBookmark ( true ) ;
if ( s . getSel ( ) )
s . getSel ( ) . selectAllChildren ( e . getBody ( ) ) ;
s . collapse ( true ) ;
s . moveToBookmark ( b ) ;
} catch ( ex ) {
// Ignore
}
}
} ,
queryStateUnderline : function ( ) {
var ed = this . editor , n = ed . selection . getNode ( ) ;
if ( n && n . nodeName == 'A' )
return false ;
return this . _queryState ( 'Underline' ) ;
} ,
queryStateOutdent : function ( ) {
var ed = this . editor , n ;
if ( ed . settings . inline _styles ) {
if ( ( n = ed . dom . getParent ( ed . selection . getStart ( ) , ed . dom . isBlock ) ) && parseInt ( n . style . paddingLeft ) > 0 )
return true ;
if ( ( n = ed . dom . getParent ( ed . selection . getEnd ( ) , ed . dom . isBlock ) ) && parseInt ( n . style . paddingLeft ) > 0 )
return true ;
}
return this . queryStateInsertUnorderedList ( ) || this . queryStateInsertOrderedList ( ) || ( ! ed . settings . inline _styles && ! ! ed . dom . getParent ( ed . selection . getNode ( ) , 'BLOCKQUOTE' ) ) ;
} ,
queryStateInsertUnorderedList : function ( ) {
return this . editor . dom . getParent ( this . editor . selection . getNode ( ) , 'UL' ) ;
} ,
queryStateInsertOrderedList : function ( ) {
return this . editor . dom . getParent ( this . editor . selection . getNode ( ) , 'OL' ) ;
} ,
queryStatemceBlockQuote : function ( ) {
return ! ! this . editor . dom . getParent ( this . editor . selection . getStart ( ) , function ( n ) { return n . nodeName === 'BLOCKQUOTE' ; } ) ;
} ,
_applyInlineStyle : function ( na , at , op ) {
var t = this , ed = t . editor , dom = ed . dom , bm , lo = { } , kh , found ;
na = na . toUpperCase ( ) ;
if ( op && op . check _classes && at [ 'class' ] )
op . check _classes . push ( at [ 'class' ] ) ;
function removeEmpty ( ) {
each ( dom . select ( na ) . reverse ( ) , function ( n ) {
var c = 0 ;
// Check if there is any attributes
each ( dom . getAttribs ( n ) , function ( an ) {
if ( an . nodeName . substring ( 0 , 1 ) != '_' && dom . getAttrib ( n , an . nodeName ) != '' ) {
//console.log(dom.getOuterHTML(n), dom.getAttrib(n, an.nodeName));
c ++ ;
}
} ) ;
// No attributes then remove the element and keep the children
if ( c == 0 )
dom . remove ( n , 1 ) ;
} ) ;
} ;
function replaceFonts ( ) {
var bm ;
each ( dom . select ( 'span,font' ) , function ( n ) {
if ( n . style . fontFamily == 'mceinline' || n . face == 'mceinline' ) {
if ( ! bm )
bm = ed . selection . getBookmark ( ) ;
at . _mce _new = '1' ;
dom . replace ( dom . create ( na , at ) , n , 1 ) ;
}
} ) ;
// Remove redundant elements
each ( dom . select ( na + '[_mce_new]' ) , function ( n ) {
function removeStyle ( n ) {
if ( n . nodeType == 1 ) {
each ( at . style , function ( v , k ) {
dom . setStyle ( n , k , '' ) ;
} ) ;
// Remove spans with the same class or marked classes
if ( at [ 'class' ] && n . className && op ) {
each ( op . check _classes , function ( c ) {
if ( dom . hasClass ( n , c ) )
dom . removeClass ( n , c ) ;
} ) ;
}
}
} ;
// Remove specified style information from child elements
each ( dom . select ( na , n ) , removeStyle ) ;
// Remove the specified style information on parent if current node is only child (IE)
if ( n . parentNode && n . parentNode . nodeType == 1 && n . parentNode . childNodes . length == 1 )
removeStyle ( n . parentNode ) ;
// Remove the child elements style info if a parent already has it
dom . getParent ( n . parentNode , function ( pn ) {
if ( pn . nodeType == 1 ) {
if ( at . style ) {
each ( at . style , function ( v , k ) {
var sv ;
if ( ! lo [ k ] && ( sv = dom . getStyle ( pn , k ) ) ) {
if ( sv === v )
dom . setStyle ( n , k , '' ) ;
lo [ k ] = 1 ;
}
} ) ;
}
// Remove spans with the same class or marked classes
if ( at [ 'class' ] && pn . className && op ) {
each ( op . check _classes , function ( c ) {
if ( dom . hasClass ( pn , c ) )
dom . removeClass ( n , c ) ;
} ) ;
}
}
return false ;
} ) ;
n . removeAttribute ( '_mce_new' ) ;
} ) ;
removeEmpty ( ) ;
ed . selection . moveToBookmark ( bm ) ;
return ! ! bm ;
} ;
// Create inline elements
ed . focus ( ) ;
ed . getDoc ( ) . execCommand ( 'FontName' , false , 'mceinline' ) ;
replaceFonts ( ) ;
if ( kh = t . _applyInlineStyle . keyhandler ) {
ed . onKeyUp . remove ( kh ) ;
ed . onKeyPress . remove ( kh ) ;
ed . onKeyDown . remove ( kh ) ;
ed . onSetContent . remove ( t . _applyInlineStyle . chandler ) ;
}
if ( ed . selection . isCollapsed ( ) ) {
// IE will format the current word so this code can't be executed on that browser
if ( ! isIE ) {
each ( dom . getParents ( ed . selection . getNode ( ) , 'span' ) , function ( n ) {
each ( at . style , function ( v , k ) {
var kv ;
if ( kv = dom . getStyle ( n , k ) ) {
if ( kv == v ) {
dom . setStyle ( n , k , '' ) ;
found = 2 ;
return false ;
}
found = 1 ;
return false ;
}
} ) ;
if ( found )
return false ;
} ) ;
if ( found == 2 ) {
bm = ed . selection . getBookmark ( ) ;
removeEmpty ( ) ;
ed . selection . moveToBookmark ( bm ) ;
// Node change needs to be detached since the onselect event
// for the select box will run the onclick handler after onselect call. Todo: Add a nicer fix!
window . setTimeout ( function ( ) {
ed . nodeChanged ( ) ;
} , 1 ) ;
return ;
}
}
// Start collecting styles
t . _pendingStyles = tinymce . extend ( t . _pendingStyles || { } , at . style ) ;
t . _applyInlineStyle . chandler = ed . onSetContent . add ( function ( ) {
delete t . _pendingStyles ;
} ) ;
t . _applyInlineStyle . keyhandler = kh = function ( e ) {
// Use pending styles
if ( t . _pendingStyles ) {
at . style = t . _pendingStyles ;
delete t . _pendingStyles ;
}
if ( replaceFonts ( ) ) {
ed . onKeyDown . remove ( t . _applyInlineStyle . keyhandler ) ;
ed . onKeyPress . remove ( t . _applyInlineStyle . keyhandler ) ;
}
if ( e . type == 'keyup' )
ed . onKeyUp . remove ( t . _applyInlineStyle . keyhandler ) ;
} ;
ed . onKeyDown . add ( kh ) ;
ed . onKeyPress . add ( kh ) ;
ed . onKeyUp . add ( kh ) ;
} else
t . _pendingStyles = 0 ;
}
} ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
tinymce . create ( 'tinymce.UndoManager' , {
index : 0 ,
data : null ,
typing : 0 ,
UndoManager : function ( ed ) {
var t = this , Dispatcher = tinymce . util . Dispatcher ;
t . editor = ed ;
t . data = [ ] ;
t . onAdd = new Dispatcher ( this ) ;
t . onUndo = new Dispatcher ( this ) ;
t . onRedo = new Dispatcher ( this ) ;
} ,
add : function ( l ) {
var t = this , i , ed = t . editor , b , s = ed . settings , la ;
l = l || { } ;
l . content = l . content || ed . getContent ( { format : 'raw' , no _events : 1 } ) ;
// Add undo level if needed
l . content = l . content . replace ( /^\s*|\s*$/g , '' ) ;
la = t . data [ t . index > 0 && ( t . index == 0 || t . index == t . data . length ) ? t . index - 1 : t . index ] ;
if ( ! l . initial && la && l . content == la . content )
return null ;
// Time to compress
if ( s . custom _undo _redo _levels ) {
if ( t . data . length > s . custom _undo _redo _levels ) {
for ( i = 0 ; i < t . data . length - 1 ; i ++ )
t . data [ i ] = t . data [ i + 1 ] ;
t . data . length -- ;
t . index = t . data . length ;
}
}
if ( s . custom _undo _redo _restore _selection && ! l . initial )
l . bookmark = b = l . bookmark || ed . selection . getBookmark ( ) ;
if ( t . index < t . data . length )
t . index ++ ;
// Only initial marked undo levels should be allowed as first item
// This to workaround a bug with Firefox and the blur event
if ( t . data . length === 0 && ! l . initial )
return null ;
// Add level
t . data . length = t . index + 1 ;
t . data [ t . index ++ ] = l ;
if ( l . initial )
t . index = 0 ;
// Set initial bookmark use first real undo level
if ( t . data . length == 2 && t . data [ 0 ] . initial )
t . data [ 0 ] . bookmark = b ;
t . onAdd . dispatch ( t , l ) ;
ed . isNotDirty = 0 ;
//console.dir(t.data);
return l ;
} ,
undo : function ( ) {
var t = this , ed = t . editor , l = l , i ;
if ( t . typing ) {
t . add ( ) ;
t . typing = 0 ;
}
if ( t . index > 0 ) {
// If undo on last index then take snapshot
if ( t . index == t . data . length && t . index > 1 ) {
i = t . index ;
t . typing = 0 ;
if ( ! t . add ( ) )
t . index = i ;
-- t . index ;
}
l = t . data [ -- t . index ] ;
ed . setContent ( l . content , { format : 'raw' } ) ;
ed . selection . moveToBookmark ( l . bookmark ) ;
t . onUndo . dispatch ( t , l ) ;
}
return l ;
} ,
redo : function ( ) {
var t = this , ed = t . editor , l = null ;
if ( t . index < t . data . length - 1 ) {
l = t . data [ ++ t . index ] ;
ed . setContent ( l . content , { format : 'raw' } ) ;
ed . selection . moveToBookmark ( l . bookmark ) ;
t . onRedo . dispatch ( t , l ) ;
}
return l ;
} ,
clear : function ( ) {
var t = this ;
t . data = [ ] ;
t . index = 0 ;
t . typing = 0 ;
t . add ( { initial : true } ) ;
} ,
hasUndo : function ( ) {
return this . index != 0 || this . typing ;
} ,
hasRedo : function ( ) {
return this . index < this . data . length - 1 ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
// Shorten names
var Event , isIE , isGecko , isOpera , each , extend ;
Event = tinymce . dom . Event ;
isIE = tinymce . isIE ;
isGecko = tinymce . isGecko ;
isOpera = tinymce . isOpera ;
each = tinymce . each ;
extend = tinymce . extend ;
function isEmpty ( n ) {
n = n . innerHTML ;
n = n . replace ( /<\w+ .*?mce_\w+\"?=.*?>/gi , '-' ) ; // Keep tags with mce_ attribs
n = n . replace ( /<(img|hr|table)/gi , '-' ) ; // Keep these convert them to - chars
n = n . replace ( /<[^>]+>/g , '' ) ; // Remove all tags
return n . replace ( /[ \t\r\n]+/g , '' ) == '' ;
} ;
tinymce . create ( 'tinymce.ForceBlocks' , {
ForceBlocks : function ( ed ) {
var t = this , s = ed . settings , elm ;
t . editor = ed ;
t . dom = ed . dom ;
elm = ( s . forced _root _block || 'p' ) . toLowerCase ( ) ;
s . element = elm . toUpperCase ( ) ;
ed . onPreInit . add ( t . setup , t ) ;
t . reOpera = new RegExp ( '(\\u00a0| | )<\/' + elm + '>' , 'gi' ) ;
t . rePadd = new RegExp ( '<p( )([^>]+)><\\\/p>|<p( )([^>]+)\\\/>|<p( )([^>]+)>\\s+<\\\/p>|<p><\\\/p>|<p\\\/>|<p>\\s+<\\\/p>' . replace ( /p/g , elm ) , 'gi' ) ;
t . reNbsp2BR1 = new RegExp ( '<p( )([^>]+)>[\\s\\u00a0]+<\\\/p>|<p>[\\s\\u00a0]+<\\\/p>' . replace ( /p/g , elm ) , 'gi' ) ;
t . reNbsp2BR2 = new RegExp ( '<%p()([^>]+)>( | )<\\\/%p>|<%p>( | )<\\\/%p>' . replace ( /%p/g , elm ) , 'gi' ) ;
t . reBR2Nbsp = new RegExp ( '<p( )([^>]+)>\\s*<br \\\/>\\s*<\\\/p>|<p>\\s*<br \\\/>\\s*<\\\/p>' . replace ( /p/g , elm ) , 'gi' ) ;
function padd ( ed , o ) {
if ( isOpera )
o . content = o . content . replace ( t . reOpera , '</' + elm + '>' ) ;
o . content = o . content . replace ( t . rePadd , '<' + elm + '$1$2$3$4$5$6>\u00a0</' + elm + '>' ) ;
if ( ! isIE && ! isOpera && o . set ) {
// Use instead of BR in padded paragraphs
o . content = o . content . replace ( t . reNbsp2BR1 , '<' + elm + '$1$2><br /></' + elm + '>' ) ;
o . content = o . content . replace ( t . reNbsp2BR2 , '<' + elm + '$1$2><br /></' + elm + '>' ) ;
} else
o . content = o . content . replace ( t . reBR2Nbsp , '<' + elm + '$1$2>\u00a0</' + elm + '>' ) ;
} ;
ed . onBeforeSetContent . add ( padd ) ;
ed . onPostProcess . add ( padd ) ;
if ( s . forced _root _block ) {
ed . onInit . add ( t . forceRoots , t ) ;
ed . onSetContent . add ( t . forceRoots , t ) ;
ed . onBeforeGetContent . add ( t . forceRoots , t ) ;
}
} ,
setup : function ( ) {
var t = this , ed = t . editor , s = ed . settings ;
// Force root blocks when typing and when getting output
if ( s . forced _root _block ) {
ed . onKeyUp . add ( t . forceRoots , t ) ;
ed . onPreProcess . add ( t . forceRoots , t ) ;
}
if ( s . force _br _newlines ) {
// Force IE to produce BRs on enter
if ( isIE ) {
ed . onKeyPress . add ( function ( ed , e ) {
var n , s = ed . selection ;
if ( e . keyCode == 13 && s . getNode ( ) . nodeName != 'LI' ) {
s . setContent ( '<br id="__" /> ' , { format : 'raw' } ) ;
n = ed . dom . get ( '__' ) ;
n . removeAttribute ( 'id' ) ;
s . select ( n ) ;
s . collapse ( ) ;
return Event . cancel ( e ) ;
}
} ) ;
}
return ;
}
if ( ! isIE && s . force _p _newlines ) {
/ * e d . o n P r e P r o c e s s . a d d ( f u n c t i o n ( e d , o ) {
each ( ed . dom . select ( 'br' , o . node ) , function ( n ) {
var p = n . parentNode ;
// Replace <p><br /></p> with <p> </p>
if ( p && p . nodeName == 'p' && ( p . childNodes . length == 1 || p . lastChild == n ) ) {
p . replaceChild ( ed . getDoc ( ) . createTextNode ( '\u00a0' ) , n ) ;
}
} ) ;
} ) ; * /
ed . onKeyPress . add ( function ( ed , e ) {
if ( e . keyCode == 13 && ! e . shiftKey ) {
if ( ! t . insertPara ( e ) )
Event . cancel ( e ) ;
}
} ) ;
if ( isGecko ) {
ed . onKeyDown . add ( function ( ed , e ) {
if ( ( e . keyCode == 8 || e . keyCode == 46 ) && ! e . shiftKey )
t . backspaceDelete ( e , e . keyCode == 8 ) ;
} ) ;
}
}
function ren ( rn , na ) {
var ne = ed . dom . create ( na ) ;
each ( rn . attributes , function ( a ) {
if ( a . specified && a . nodeValue )
ne . setAttribute ( a . nodeName . toLowerCase ( ) , a . nodeValue ) ;
} ) ;
each ( rn . childNodes , function ( n ) {
ne . appendChild ( n . cloneNode ( true ) ) ;
} ) ;
rn . parentNode . replaceChild ( ne , rn ) ;
return ne ;
} ;
// IE specific fixes
if ( isIE ) {
// Remove empty inline elements within block elements
// For example: <p><strong><em></em></strong></p>
ed . onPreProcess . add ( function ( ed , o ) {
each ( ed . dom . select ( 'p,h1,h2,h3,h4,h5,h6,div' , o . node ) , function ( p ) {
if ( isEmpty ( p ) )
p . innerHTML = '' ;
} ) ;
} ) ;
// Replaces IE:s auto generated paragraphs with the specified element name
if ( s . element != 'P' ) {
ed . onKeyPress . add ( function ( ed , e ) {
t . lastElm = ed . selection . getNode ( ) . nodeName ;
} ) ;
ed . onKeyUp . add ( function ( ed , e ) {
var bl , sel = ed . selection , n = sel . getNode ( ) , b = ed . getBody ( ) ;
if ( b . childNodes . length === 1 && n . nodeName == 'P' ) {
n = ren ( n , s . element ) ;
sel . select ( n ) ;
sel . collapse ( ) ;
ed . nodeChanged ( ) ;
} else if ( e . keyCode == 13 && ! e . shiftKey && t . lastElm != 'P' ) {
bl = ed . dom . getParent ( n , 'p' ) ;
if ( bl ) {
ren ( bl , s . element ) ;
ed . nodeChanged ( ) ;
}
}
} ) ;
}
}
} ,
find : function ( n , t , s ) {
var ed = this . editor , w = ed . getDoc ( ) . createTreeWalker ( n , 4 , null , false ) , c = - 1 ;
while ( n = w . nextNode ( ) ) {
c ++ ;
// Index by node
if ( t == 0 && n == s )
return c ;
// Node by index
if ( t == 1 && c == s )
return n ;
}
return - 1 ;
} ,
forceRoots : function ( ed , e ) {
var t = this , ed = t . editor , b = ed . getBody ( ) , d = ed . getDoc ( ) , se = ed . selection , s = se . getSel ( ) , r = se . getRng ( ) , si = - 2 , ei , so , eo , tr , c = - 0xFFFFFF ;
var nx , bl , bp , sp , le , nl = b . childNodes , i , n , eid ;
// Fix for bug #1863847
//if (e && e.keyCode == 13)
// return true;
// Wrap non blocks into blocks
for ( i = nl . length - 1 ; i >= 0 ; i -- ) {
nx = nl [ i ] ;
// Is text or non block element
if ( nx . nodeType == 3 || ( ! t . dom . isBlock ( nx ) && nx . nodeType != 8 ) ) {
if ( ! bl ) {
// Create new block but ignore whitespace
if ( nx . nodeType != 3 || /[^\s]/g . test ( nx . nodeValue ) ) {
// Store selection
if ( si == - 2 && r ) {
if ( ! isIE ) {
// If selection is element then mark it
if ( r . startContainer . nodeType == 1 && ( n = r . startContainer . childNodes [ r . startOffset ] ) && n . nodeType == 1 ) {
// Save the id of the selected element
eid = n . getAttribute ( "id" ) ;
n . setAttribute ( "id" , "__mce" ) ;
} else {
// If element is inside body, might not be the case in contentEdiable mode
if ( ed . dom . getParent ( r . startContainer , function ( e ) { return e === b ; } ) ) {
so = r . startOffset ;
eo = r . endOffset ;
si = t . find ( b , 0 , r . startContainer ) ;
ei = t . find ( b , 0 , r . endContainer ) ;
}
}
} else {
tr = d . body . createTextRange ( ) ;
tr . moveToElementText ( b ) ;
tr . collapse ( 1 ) ;
bp = tr . move ( 'character' , c ) * - 1 ;
tr = r . duplicate ( ) ;
tr . collapse ( 1 ) ;
sp = tr . move ( 'character' , c ) * - 1 ;
tr = r . duplicate ( ) ;
tr . collapse ( 0 ) ;
le = ( tr . move ( 'character' , c ) * - 1 ) - sp ;
si = sp - bp ;
ei = le ;
}
}
bl = ed . dom . create ( ed . settings . forced _root _block ) ;
bl . appendChild ( nx . cloneNode ( 1 ) ) ;
nx . parentNode . replaceChild ( bl , nx ) ;
}
} else {
if ( bl . hasChildNodes ( ) )
bl . insertBefore ( nx , bl . firstChild ) ;
else
bl . appendChild ( nx ) ;
}
} else
bl = null ; // Time to create new block
}
// Restore selection
if ( si != - 2 ) {
if ( ! isIE ) {
bl = b . getElementsByTagName ( ed . settings . element ) [ 0 ] ;
r = d . createRange ( ) ;
// Select last location or generated block
if ( si != - 1 )
r . setStart ( t . find ( b , 1 , si ) , so ) ;
else
r . setStart ( bl , 0 ) ;
// Select last location or generated block
if ( ei != - 1 )
r . setEnd ( t . find ( b , 1 , ei ) , eo ) ;
else
r . setEnd ( bl , 0 ) ;
if ( s ) {
s . removeAllRanges ( ) ;
s . addRange ( r ) ;
}
} else {
try {
r = s . createRange ( ) ;
r . moveToElementText ( b ) ;
r . collapse ( 1 ) ;
r . moveStart ( 'character' , si ) ;
r . moveEnd ( 'character' , ei ) ;
r . select ( ) ;
} catch ( ex ) {
// Ignore
}
}
} else if ( ! isIE && ( n = ed . dom . get ( '__mce' ) ) ) {
// Restore the id of the selected element
if ( eid )
n . setAttribute ( 'id' , eid ) ;
else
n . removeAttribute ( 'id' ) ;
// Move caret before selected element
r = d . createRange ( ) ;
r . setStartBefore ( n ) ;
r . setEndBefore ( n ) ;
se . setRng ( r ) ;
}
} ,
getParentBlock : function ( n ) {
var d = this . dom ;
return d . getParent ( n , d . isBlock ) ;
} ,
insertPara : function ( e ) {
var t = this , ed = t . editor , dom = ed . dom , d = ed . getDoc ( ) , se = ed . settings , s = ed . selection . getSel ( ) , r = s . getRangeAt ( 0 ) , b = d . body ;
var rb , ra , dir , sn , so , en , eo , sb , eb , bn , bef , aft , sc , ec , n , vp = dom . getViewPort ( ed . getWin ( ) ) , y , ch , car ;
// If root blocks are forced then use Operas default behavior since it's really good
// Removed due to bug: #1853816
// if (se.forced_root_block && isOpera)
// return true;
// Setup before range
rb = d . createRange ( ) ;
// If is before the first block element and in body, then move it into first block element
rb . setStart ( s . anchorNode , s . anchorOffset ) ;
rb . collapse ( true ) ;
// Setup after range
ra = d . createRange ( ) ;
// If is before the first block element and in body, then move it into first block element
ra . setStart ( s . focusNode , s . focusOffset ) ;
ra . collapse ( true ) ;
// Setup start/end points
dir = rb . compareBoundaryPoints ( rb . START _TO _END , ra ) < 0 ;
sn = dir ? s . anchorNode : s . focusNode ;
so = dir ? s . anchorOffset : s . focusOffset ;
en = dir ? s . focusNode : s . anchorNode ;
eo = dir ? s . focusOffset : s . anchorOffset ;
// If selection is in empty table cell
if ( sn === en && /^(TD|TH)$/ . test ( sn . nodeName ) ) {
dom . remove ( sn . firstChild ) ; // Remove BR
// Create two new block elements
ed . dom . add ( sn , se . element , null , '<br />' ) ;
aft = ed . dom . add ( sn , se . element , null , '<br />' ) ;
// Move caret into the last one
r = d . createRange ( ) ;
r . selectNodeContents ( aft ) ;
r . collapse ( 1 ) ;
ed . selection . setRng ( r ) ;
return false ;
}
// If the caret is in an invalid location in FF we need to move it into the first block
if ( sn == b && en == b && b . firstChild && ed . dom . isBlock ( b . firstChild ) ) {
sn = en = sn . firstChild ;
so = eo = 0 ;
rb = d . createRange ( ) ;
rb . setStart ( sn , 0 ) ;
ra = d . createRange ( ) ;
ra . setStart ( en , 0 ) ;
}
// Never use body as start or end node
sn = sn . nodeName == "HTML" ? d . body : sn ; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
sn = sn . nodeName == "BODY" ? sn . firstChild : sn ;
en = en . nodeName == "HTML" ? d . body : en ; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
en = en . nodeName == "BODY" ? en . firstChild : en ;
// Get start and end blocks
sb = t . getParentBlock ( sn ) ;
eb = t . getParentBlock ( en ) ;
bn = sb ? sb . nodeName : se . element ; // Get block name to create
// Return inside list use default browser behavior
if ( t . dom . getParent ( sb , 'ol,ul,pre' ) )
return true ;
// If caption or absolute layers then always generate new blocks within
if ( sb && ( sb . nodeName == 'CAPTION' || /absolute|relative|fixed/gi . test ( dom . getStyle ( sb , 'position' , 1 ) ) ) ) {
bn = se . element ;
sb = null ;
}
// If caption or absolute layers then always generate new blocks within
if ( eb && ( eb . nodeName == 'CAPTION' || /absolute|relative|fixed/gi . test ( dom . getStyle ( sb , 'position' , 1 ) ) ) ) {
bn = se . element ;
eb = null ;
}
// Use P instead
if ( /(TD|TABLE|TH|CAPTION)/ . test ( bn ) || ( sb && bn == "DIV" && /left|right/gi . test ( dom . getStyle ( sb , 'float' , 1 ) ) ) ) {
bn = se . element ;
sb = eb = null ;
}
// Setup new before and after blocks
bef = ( sb && sb . nodeName == bn ) ? sb . cloneNode ( 0 ) : ed . dom . create ( bn ) ;
aft = ( eb && eb . nodeName == bn ) ? eb . cloneNode ( 0 ) : ed . dom . create ( bn ) ;
// Remove id from after clone
aft . removeAttribute ( 'id' ) ;
// Is header and cursor is at the end, then force paragraph under
if ( /^(H[1-6])$/ . test ( bn ) && sn . nodeValue && so == sn . nodeValue . length )
aft = ed . dom . create ( se . element ) ;
// Find start chop node
n = sc = sn ;
do {
if ( n == b || n . nodeType == 9 || t . dom . isBlock ( n ) || /(TD|TABLE|TH|CAPTION)/ . test ( n . nodeName ) )
break ;
sc = n ;
} while ( ( n = n . previousSibling ? n . previousSibling : n . parentNode ) ) ;
// Find end chop node
n = ec = en ;
do {
if ( n == b || n . nodeType == 9 || t . dom . isBlock ( n ) || /(TD|TABLE|TH|CAPTION)/ . test ( n . nodeName ) )
break ;
ec = n ;
} while ( ( n = n . nextSibling ? n . nextSibling : n . parentNode ) ) ;
// Place first chop part into before block element
if ( sc . nodeName == bn )
rb . setStart ( sc , 0 ) ;
else
rb . setStartBefore ( sc ) ;
rb . setEnd ( sn , so ) ;
bef . appendChild ( rb . cloneContents ( ) || d . createTextNode ( '' ) ) ; // Empty text node needed for Safari
// Place secnd chop part within new block element
try {
ra . setEndAfter ( ec ) ;
} catch ( ex ) {
//console.debug(s.focusNode, s.focusOffset);
}
ra . setStart ( en , eo ) ;
aft . appendChild ( ra . cloneContents ( ) || d . createTextNode ( '' ) ) ; // Empty text node needed for Safari
// Create range around everything
r = d . createRange ( ) ;
if ( ! sc . previousSibling && sc . parentNode . nodeName == bn ) {
r . setStartBefore ( sc . parentNode ) ;
} else {
if ( rb . startContainer . nodeName == bn && rb . startOffset == 0 )
r . setStartBefore ( rb . startContainer ) ;
else
r . setStart ( rb . startContainer , rb . startOffset ) ;
}
if ( ! ec . nextSibling && ec . parentNode . nodeName == bn )
r . setEndAfter ( ec . parentNode ) ;
else
r . setEnd ( ra . endContainer , ra . endOffset ) ;
// Delete and replace it with new block elements
r . deleteContents ( ) ;
if ( isOpera )
ed . getWin ( ) . scrollTo ( 0 , vp . y ) ;
// Never wrap blocks in blocks
if ( bef . firstChild && bef . firstChild . nodeName == bn )
bef . innerHTML = bef . firstChild . innerHTML ;
if ( aft . firstChild && aft . firstChild . nodeName == bn )
aft . innerHTML = aft . firstChild . innerHTML ;
// Padd empty blocks
if ( isEmpty ( bef ) )
bef . innerHTML = '<br />' ;
function appendStyles ( e , en ) {
var nl = [ ] , nn , n , i ;
e . innerHTML = '' ;
// Make clones of style elements
if ( se . keep _styles ) {
n = en ;
do {
// We only want style specific elements
if ( /^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/ . test ( n . nodeName ) ) {
nn = n . cloneNode ( false ) ;
dom . setAttrib ( nn , 'id' , '' ) ; // Remove ID since it needs to be unique
nl . push ( nn ) ;
}
} while ( n = n . parentNode ) ;
}
// Append style elements to aft
if ( nl . length > 0 ) {
for ( i = nl . length - 1 , nn = e ; i >= 0 ; i -- )
nn = nn . appendChild ( nl [ i ] ) ;
// Padd most inner style element
nl [ 0 ] . innerHTML = isOpera ? ' ' : '<br />' ; // Extra space for Opera so that the caret can move there
return nl [ 0 ] ; // Move caret to most inner element
} else
e . innerHTML = isOpera ? ' ' : '<br />' ; // Extra space for Opera so that the caret can move there
} ;
// Fill empty afterblook with current style
if ( isEmpty ( aft ) )
car = appendStyles ( aft , en ) ;
// Opera needs this one backwards for older versions
if ( isOpera && parseFloat ( opera . version ( ) ) < 9.5 ) {
r . insertNode ( bef ) ;
r . insertNode ( aft ) ;
} else {
r . insertNode ( aft ) ;
r . insertNode ( bef ) ;
}
// Normalize
aft . normalize ( ) ;
bef . normalize ( ) ;
function first ( n ) {
return d . createTreeWalker ( n , NodeFilter . SHOW _TEXT , null , false ) . nextNode ( ) || n ;
} ;
// Move cursor and scroll into view
r = d . createRange ( ) ;
r . selectNodeContents ( isGecko ? first ( car || aft ) : car || aft ) ;
r . collapse ( 1 ) ;
s . removeAllRanges ( ) ;
s . addRange ( r ) ;
// scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs
y = ed . dom . getPos ( aft ) . y ;
ch = aft . clientHeight ;
// Is element within viewport
if ( y < vp . y || y + ch > vp . y + vp . h ) {
ed . getWin ( ) . scrollTo ( 0 , y < vp . y ? y : y - vp . h + 25 ) ; // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks
//console.debug('SCROLL!', 'vp.y: ' + vp.y, 'y' + y, 'vp.h' + vp.h, 'clientHeight' + aft.clientHeight, 'yyy: ' + (y < vp.y ? y : y - vp.h + aft.clientHeight));
}
return false ;
} ,
backspaceDelete : function ( e , bs ) {
var t = this , ed = t . editor , b = ed . getBody ( ) , n , se = ed . selection , r = se . getRng ( ) , sc = r . startContainer , n , w , tn ;
// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
// This workaround removes the element by hand and moves the caret to the previous element
if ( sc && ed . dom . isBlock ( sc ) && ! /^(TD|TH)$/ . test ( sc . nodeName ) && bs ) {
if ( sc . childNodes . length == 0 || ( sc . childNodes . length == 1 && sc . firstChild . nodeName == 'BR' ) ) {
// Find previous block element
n = sc ;
while ( ( n = n . previousSibling ) && ! ed . dom . isBlock ( n ) ) ;
if ( n ) {
if ( sc != b . firstChild ) {
// Find last text node
w = ed . dom . doc . createTreeWalker ( n , NodeFilter . SHOW _TEXT , null , false ) ;
while ( tn = w . nextNode ( ) )
n = tn ;
// Place caret at the end of last text node
r = ed . getDoc ( ) . createRange ( ) ;
r . setStart ( n , n . nodeValue ? n . nodeValue . length : 0 ) ;
r . setEnd ( n , n . nodeValue ? n . nodeValue . length : 0 ) ;
se . setRng ( r ) ;
// Remove the target container
ed . dom . remove ( sc ) ;
}
return Event . cancel ( e ) ;
}
}
}
// Gecko generates BR elements here and there, we don't like those so lets remove them
function handler ( e ) {
var pr ;
e = e . target ;
// A new BR was created in a block element, remove it
if ( e && e . parentNode && e . nodeName == 'BR' && ( n = t . getParentBlock ( e ) ) ) {
pr = e . previousSibling ;
Event . remove ( b , 'DOMNodeInserted' , handler ) ;
// Is there whitespace at the end of the node before then we might need the pesky BR
// to place the caret at a correct location see bug: #2013943
if ( pr && pr . nodeType == 3 && /\s+$/ . test ( pr . nodeValue ) )
return ;
// Only remove BR elements that got inserted in the middle of the text
if ( e . previousSibling || e . nextSibling )
ed . dom . remove ( e ) ;
}
} ;
// Listen for new nodes
Event . _add ( b , 'DOMNodeInserted' , handler ) ;
// Remove listener
window . setTimeout ( function ( ) {
Event . _remove ( b , 'DOMNodeInserted' , handler ) ;
} , 1 ) ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
// Shorten names
var DOM = tinymce . DOM , Event = tinymce . dom . Event , each = tinymce . each , extend = tinymce . extend ;
tinymce . create ( 'tinymce.ControlManager' , {
ControlManager : function ( ed , s ) {
var t = this , i ;
s = s || { } ;
t . editor = ed ;
t . controls = { } ;
t . onAdd = new tinymce . util . Dispatcher ( t ) ;
t . onPostRender = new tinymce . util . Dispatcher ( t ) ;
t . prefix = s . prefix || ed . id + '_' ;
t . _cls = { } ;
t . onPostRender . add ( function ( ) {
each ( t . controls , function ( c ) {
c . postRender ( ) ;
} ) ;
} ) ;
} ,
get : function ( id ) {
return this . controls [ this . prefix + id ] || this . controls [ id ] ;
} ,
setActive : function ( id , s ) {
var c = null ;
if ( c = this . get ( id ) )
c . setActive ( s ) ;
return c ;
} ,
setDisabled : function ( id , s ) {
var c = null ;
if ( c = this . get ( id ) )
c . setDisabled ( s ) ;
return c ;
} ,
add : function ( c ) {
var t = this ;
if ( c ) {
t . controls [ c . id ] = c ;
t . onAdd . dispatch ( c , t ) ;
}
return c ;
} ,
createControl : function ( n ) {
var c , t = this , ed = t . editor ;
each ( ed . plugins , function ( p ) {
if ( p . createControl ) {
c = p . createControl ( n , t ) ;
if ( c )
return false ;
}
} ) ;
switch ( n ) {
case "|" :
case "separator" :
return t . createSeparator ( ) ;
}
if ( ! c && ed . buttons && ( c = ed . buttons [ n ] ) )
return t . createButton ( n , c ) ;
return t . add ( c ) ;
} ,
createDropMenu : function ( id , s , cc ) {
var t = this , ed = t . editor , c , bm , v , cls ;
s = extend ( {
'class' : 'mceDropDown' ,
constrain : ed . settings . constrain _menus
} , s ) ;
s [ 'class' ] = s [ 'class' ] + ' ' + ed . getParam ( 'skin' ) + 'Skin' ;
if ( v = ed . getParam ( 'skin_variant' ) )
s [ 'class' ] += ' ' + ed . getParam ( 'skin' ) + 'Skin' + v . substring ( 0 , 1 ) . toUpperCase ( ) + v . substring ( 1 ) ;
id = t . prefix + id ;
cls = cc || t . _cls . dropmenu || tinymce . ui . DropMenu ;
c = t . controls [ id ] = new cls ( id , s ) ;
c . onAddItem . add ( function ( c , o ) {
var s = o . settings ;
s . title = ed . getLang ( s . title , s . title ) ;
if ( ! s . onclick ) {
s . onclick = function ( v ) {
ed . execCommand ( s . cmd , s . ui || false , s . value ) ;
} ;
}
} ) ;
ed . onRemove . add ( function ( ) {
c . destroy ( ) ;
} ) ;
// Fix for bug #1897785, #1898007
if ( tinymce . isIE ) {
c . onShowMenu . add ( function ( ) {
// IE 8 needs focus in order to store away a range with the current collapsed caret location
ed . focus ( ) ;
bm = ed . selection . getBookmark ( 1 ) ;
} ) ;
c . onHideMenu . add ( function ( ) {
if ( bm ) {
ed . selection . moveToBookmark ( bm ) ;
bm = 0 ;
}
} ) ;
}
return t . add ( c ) ;
} ,
createListBox : function ( id , s , cc ) {
var t = this , ed = t . editor , cmd , c , cls ;
if ( t . get ( id ) )
return null ;
s . title = ed . translate ( s . title ) ;
s . scope = s . scope || ed ;
if ( ! s . onselect ) {
s . onselect = function ( v ) {
ed . execCommand ( s . cmd , s . ui || false , v || s . value ) ;
} ;
}
s = extend ( {
title : s . title ,
'class' : 'mce_' + id ,
scope : s . scope ,
control _manager : t
} , s ) ;
id = t . prefix + id ;
if ( ed . settings . use _native _selects )
c = new tinymce . ui . NativeListBox ( id , s ) ;
else {
cls = cc || t . _cls . listbox || tinymce . ui . ListBox ;
c = new cls ( id , s ) ;
}
t . controls [ id ] = c ;
// Fix focus problem in Safari
if ( tinymce . isWebKit ) {
c . onPostRender . add ( function ( c , n ) {
// Store bookmark on mousedown
Event . add ( n , 'mousedown' , function ( ) {
ed . bookmark = ed . selection . getBookmark ( 'simple' ) ;
} ) ;
// Restore on focus, since it might be lost
Event . add ( n , 'focus' , function ( ) {
ed . selection . moveToBookmark ( ed . bookmark ) ;
ed . bookmark = null ;
} ) ;
} ) ;
}
if ( c . hideMenu )
ed . onMouseDown . add ( c . hideMenu , c ) ;
return t . add ( c ) ;
} ,
createButton : function ( id , s , cc ) {
var t = this , ed = t . editor , o , c , cls ;
if ( t . get ( id ) )
return null ;
s . title = ed . translate ( s . title ) ;
s . label = ed . translate ( s . label ) ;
s . scope = s . scope || ed ;
if ( ! s . onclick && ! s . menu _button ) {
s . onclick = function ( ) {
ed . execCommand ( s . cmd , s . ui || false , s . value ) ;
} ;
}
s = extend ( {
title : s . title ,
'class' : 'mce_' + id ,
unavailable _prefix : ed . getLang ( 'unavailable' , '' ) ,
scope : s . scope ,
control _manager : t
} , s ) ;
id = t . prefix + id ;
if ( s . menu _button ) {
cls = cc || t . _cls . menubutton || tinymce . ui . MenuButton ;
c = new cls ( id , s ) ;
ed . onMouseDown . add ( c . hideMenu , c ) ;
} else {
cls = t . _cls . button || tinymce . ui . Button ;
c = new cls ( id , s ) ;
}
return t . add ( c ) ;
} ,
createMenuButton : function ( id , s , cc ) {
s = s || { } ;
s . menu _button = 1 ;
return this . createButton ( id , s , cc ) ;
} ,
createSplitButton : function ( id , s , cc ) {
var t = this , ed = t . editor , cmd , c , cls ;
if ( t . get ( id ) )
return null ;
s . title = ed . translate ( s . title ) ;
s . scope = s . scope || ed ;
if ( ! s . onclick ) {
s . onclick = function ( v ) {
ed . execCommand ( s . cmd , s . ui || false , v || s . value ) ;
} ;
}
if ( ! s . onselect ) {
s . onselect = function ( v ) {
ed . execCommand ( s . cmd , s . ui || false , v || s . value ) ;
} ;
}
s = extend ( {
title : s . title ,
'class' : 'mce_' + id ,
scope : s . scope ,
control _manager : t
} , s ) ;
id = t . prefix + id ;
cls = cc || t . _cls . splitbutton || tinymce . ui . SplitButton ;
c = t . add ( new cls ( id , s ) ) ;
ed . onMouseDown . add ( c . hideMenu , c ) ;
return c ;
} ,
createColorSplitButton : function ( id , s , cc ) {
var t = this , ed = t . editor , cmd , c , cls , bm ;
if ( t . get ( id ) )
return null ;
s . title = ed . translate ( s . title ) ;
s . scope = s . scope || ed ;
if ( ! s . onclick ) {
s . onclick = function ( v ) {
if ( tinymce . isIE )
bm = ed . selection . getBookmark ( 1 ) ;
ed . execCommand ( s . cmd , s . ui || false , v || s . value ) ;
} ;
}
if ( ! s . onselect ) {
s . onselect = function ( v ) {
ed . execCommand ( s . cmd , s . ui || false , v || s . value ) ;
} ;
}
s = extend ( {
title : s . title ,
'class' : 'mce_' + id ,
'menu_class' : ed . getParam ( 'skin' ) + 'Skin' ,
scope : s . scope ,
more _colors _title : ed . getLang ( 'more_colors' )
} , s ) ;
id = t . prefix + id ;
cls = cc || t . _cls . colorsplitbutton || tinymce . ui . ColorSplitButton ;
c = new cls ( id , s ) ;
ed . onMouseDown . add ( c . hideMenu , c ) ;
// Remove the menu element when the editor is removed
ed . onRemove . add ( function ( ) {
c . destroy ( ) ;
} ) ;
// Fix for bug #1897785, #1898007
if ( tinymce . isIE ) {
c . onHideMenu . add ( function ( ) {
if ( bm ) {
ed . selection . moveToBookmark ( bm ) ;
bm = 0 ;
}
} ) ;
}
return t . add ( c ) ;
} ,
createToolbar : function ( id , s , cc ) {
var c , t = this , cls ;
id = t . prefix + id ;
cls = cc || t . _cls . toolbar || tinymce . ui . Toolbar ;
c = new cls ( id , s ) ;
if ( t . get ( id ) )
return null ;
return t . add ( c ) ;
} ,
createSeparator : function ( cc ) {
var cls = cc || this . _cls . separator || tinymce . ui . Separator ;
return new cls ( ) ;
} ,
setControlType : function ( n , c ) {
return this . _cls [ n . toLowerCase ( ) ] = c ;
} ,
destroy : function ( ) {
each ( this . controls , function ( c ) {
c . destroy ( ) ;
} ) ;
this . controls = null ;
}
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
var Dispatcher = tinymce . util . Dispatcher , each = tinymce . each , isIE = tinymce . isIE , isOpera = tinymce . isOpera ;
tinymce . create ( 'tinymce.WindowManager' , {
WindowManager : function ( ed ) {
var t = this ;
t . editor = ed ;
t . onOpen = new Dispatcher ( t ) ;
t . onClose = new Dispatcher ( t ) ;
t . params = { } ;
t . features = { } ;
} ,
open : function ( s , p ) {
var t = this , f = '' , x , y , mo = t . editor . settings . dialog _type == 'modal' , w , sw , sh , vp = tinymce . DOM . getViewPort ( ) , u ;
// Default some options
s = s || { } ;
p = p || { } ;
sw = isOpera ? vp . w : screen . width ; // Opera uses windows inside the Opera window
sh = isOpera ? vp . h : screen . height ;
s . name = s . name || 'mc_' + new Date ( ) . getTime ( ) ;
s . width = parseInt ( s . width || 320 ) ;
s . height = parseInt ( s . height || 240 ) ;
s . resizable = true ;
s . left = s . left || parseInt ( sw / 2.0 ) - ( s . width / 2.0 ) ;
s . top = s . top || parseInt ( sh / 2.0 ) - ( s . height / 2.0 ) ;
p . inline = false ;
p . mce _width = s . width ;
p . mce _height = s . height ;
p . mce _auto _focus = s . auto _focus ;
if ( mo ) {
if ( isIE ) {
s . center = true ;
s . help = false ;
s . dialogWidth = s . width + 'px' ;
s . dialogHeight = s . height + 'px' ;
s . scroll = s . scrollbars || false ;
}
}
// Build features string
each ( s , function ( v , k ) {
if ( tinymce . is ( v , 'boolean' ) )
v = v ? 'yes' : 'no' ;
if ( ! /^(name|url)$/ . test ( k ) ) {
if ( isIE && mo )
f += ( f ? ';' : '' ) + k + ':' + v ;
else
f += ( f ? ',' : '' ) + k + '=' + v ;
}
} ) ;
t . features = s ;
t . params = p ;
t . onOpen . dispatch ( t , s , p ) ;
u = s . url || s . file ;
u = tinymce . _addVer ( u ) ;
try {
if ( isIE && mo ) {
w = 1 ;
window . showModalDialog ( u , window , f ) ;
} else
w = window . open ( u , s . name , f ) ;
} catch ( ex ) {
// Ignore
}
if ( ! w )
alert ( t . editor . getLang ( 'popup_blocked' ) ) ;
} ,
close : function ( w ) {
w . close ( ) ;
this . onClose . dispatch ( this ) ;
} ,
createInstance : function ( cl , a , b , c , d , e ) {
var f = tinymce . resolve ( cl ) ;
return new f ( a , b , c , d , e ) ;
} ,
confirm : function ( t , cb , s , w ) {
w = w || window ;
cb . call ( s || this , w . confirm ( this . _decode ( this . editor . getLang ( t , t ) ) ) ) ;
} ,
alert : function ( tx , cb , s , w ) {
var t = this ;
w = w || window ;
w . alert ( t . _decode ( t . editor . getLang ( tx , tx ) ) ) ;
if ( cb )
cb . call ( s || t ) ;
} ,
// Internal functions
_decode : function ( s ) {
return tinymce . DOM . decode ( s ) . replace ( /\\n/g , '\n' ) ;
}
} ) ;
} ( tinymce ) ) ; ( function ( tinymce ) {
tinymce . CommandManager = function ( ) {
var execCommands = { } , queryStateCommands = { } , queryValueCommands = { } ;
function add ( collection , cmd , func , scope ) {
if ( typeof ( cmd ) == 'string' )
cmd = [ cmd ] ;
tinymce . each ( cmd , function ( cmd ) {
collection [ cmd . toLowerCase ( ) ] = { func : func , scope : scope } ;
} ) ;
} ;
tinymce . extend ( this , {
add : function ( cmd , func , scope ) {
add ( execCommands , cmd , func , scope ) ;
} ,
addQueryStateHandler : function ( cmd , func , scope ) {
add ( queryStateCommands , cmd , func , scope ) ;
} ,
addQueryValueHandler : function ( cmd , func , scope ) {
add ( queryValueCommands , cmd , func , scope ) ;
} ,
execCommand : function ( scope , cmd , ui , value , args ) {
if ( cmd = execCommands [ cmd . toLowerCase ( ) ] ) {
if ( cmd . func . call ( scope || cmd . scope , ui , value , args ) !== false )
return true ;
}
} ,
queryCommandValue : function ( ) {
if ( cmd = queryValueCommands [ cmd . toLowerCase ( ) ] )
return cmd . func . call ( scope || cmd . scope , ui , value , args ) ;
} ,
queryCommandState : function ( ) {
if ( cmd = queryStateCommands [ cmd . toLowerCase ( ) ] )
return cmd . func . call ( scope || cmd . scope , ui , value , args ) ;
}
} ) ;
} ;
tinymce . GlobalCommands = new tinymce . CommandManager ( ) ;
} ) ( tinymce ) ; ( function ( tinymce ) {
function processRange ( dom , start , end , callback ) {
var ancestor , n , startPoint , endPoint , sib ;
function findEndPoint ( n , c ) {
do {
if ( n . parentNode == c )
return n ;
n = n . parentNode ;
} while ( n ) ;
} ;
function process ( n ) {
callback ( n ) ;
tinymce . walk ( n , callback , 'childNodes' ) ;
} ;
// Find common ancestor and end points
ancestor = dom . findCommonAncestor ( start , end ) ;
startPoint = findEndPoint ( start , ancestor ) || start ;
endPoint = findEndPoint ( end , ancestor ) || end ;
// Process left leaf
for ( n = start ; n && n != startPoint ; n = n . parentNode ) {
for ( sib = n . nextSibling ; sib ; sib = sib . nextSibling )
process ( sib ) ;
}
// Process middle from start to end point
if ( startPoint != endPoint ) {
for ( n = startPoint . nextSibling ; n && n != endPoint ; n = n . nextSibling )
process ( n ) ;
} else
process ( startPoint ) ;
// Process right leaf
for ( n = end ; n && n != endPoint ; n = n . parentNode ) {
for ( sib = n . previousSibling ; sib ; sib = sib . previousSibling )
process ( sib ) ;
}
} ;
tinymce . GlobalCommands . add ( 'RemoveFormat' , function ( ) {
var ed = this , dom = ed . dom , s = ed . selection , r = s . getRng ( 1 ) , nodes = [ ] , bm , start , end , sc , so , ec , eo , n ;
function findFormatRoot ( n ) {
var sp ;
dom . getParent ( n , function ( n ) {
if ( dom . is ( n , ed . getParam ( 'removeformat_selector' ) ) )
sp = n ;
return dom . isBlock ( n ) ;
} , ed . getBody ( ) ) ;
return sp ;
} ;
function collect ( n ) {
if ( dom . is ( n , ed . getParam ( 'removeformat_selector' ) ) )
nodes . push ( n ) ;
} ;
function walk ( n ) {
collect ( n ) ;
tinymce . walk ( n , collect , 'childNodes' ) ;
} ;
bm = s . getBookmark ( ) ;
sc = r . startContainer ;
ec = r . endContainer ;
so = r . startOffset ;
eo = r . endOffset ;
sc = sc . nodeType == 1 ? sc . childNodes [ Math . min ( so , sc . childNodes . length - 1 ) ] : sc ;
ec = ec . nodeType == 1 ? ec . childNodes [ Math . min ( so == eo ? eo : eo - 1 , ec . childNodes . length - 1 ) ] : ec ;
// Same container
if ( sc == ec ) { // TEXT_NODE
start = findFormatRoot ( sc ) ;
// Handle single text node
if ( sc . nodeType == 3 ) {
if ( start && start . nodeType == 1 ) { // ELEMENT
n = sc . splitText ( so ) ;
n . splitText ( eo - so ) ;
dom . split ( start , n ) ;
s . moveToBookmark ( bm ) ;
}
return ;
}
// Handle single element
walk ( dom . split ( start , sc ) || sc ) ;
} else {
// Find start/end format root
start = findFormatRoot ( sc ) ;
end = findFormatRoot ( ec ) ;
// Split start text node
if ( start ) {
if ( sc . nodeType == 3 ) { // TEXT
// Since IE doesn't support white space nodes in the DOM we need to
// add this invisible character so that the splitText function can split the contents
if ( so == sc . nodeValue . length )
sc . nodeValue += '\uFEFF' ; // Yet another pesky IE fix
sc = sc . splitText ( so ) ;
}
}
// Split end text node
if ( end ) {
if ( ec . nodeType == 3 ) // TEXT
ec . splitText ( eo ) ;
}
// If the start and end format root is the same then we need to wrap
// the end node in a span since the split calls might change the reference
// Example: <p><b><em>x[yz<span>---</span>12]3</em></b></p>
if ( start && start == end )
dom . replace ( dom . create ( 'span' , { id : '__end' } , ec . cloneNode ( true ) ) , ec ) ;
// Split all start containers down to the format root
if ( start )
start = dom . split ( start , sc ) ;
else
start = sc ;
// If there is a span wrapper use that one instead
if ( n = dom . get ( '__end' ) ) {
ec = n ;
end = findFormatRoot ( ec ) ;
}
// Split all end containers down to the format root
if ( end )
end = dom . split ( end , ec ) ;
else
end = ec ;
// Collect nodes in between
processRange ( dom , start , end , collect ) ;
// Remove invisible character for IE workaround if we find it
if ( sc . nodeValue == '\uFEFF' )
sc . nodeValue = '' ;
// Process start/end container elements
walk ( ec ) ;
walk ( sc ) ;
}
// Remove all collected nodes
tinymce . each ( nodes , function ( n ) {
dom . remove ( n , 1 ) ;
} ) ;
// Remove leftover wrapper
dom . remove ( '__end' , 1 ) ;
s . moveToBookmark ( bm ) ;
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
tinymce . GlobalCommands . add ( 'mceBlockQuote' , function ( ) {
var ed = this , s = ed . selection , dom = ed . dom , sb , eb , n , bm , bq , r , bq2 , i , nl ;
function getBQ ( e ) {
return dom . getParent ( e , function ( n ) { return n . nodeName === 'BLOCKQUOTE' ; } ) ;
} ;
// Get start/end block
sb = dom . getParent ( s . getStart ( ) , dom . isBlock ) ;
eb = dom . getParent ( s . getEnd ( ) , dom . isBlock ) ;
// Remove blockquote(s)
if ( bq = getBQ ( sb ) ) {
if ( sb != eb || sb . childNodes . length > 1 || ( sb . childNodes . length == 1 && sb . firstChild . nodeName != 'BR' ) )
bm = s . getBookmark ( ) ;
// Move all elements after the end block into new bq
if ( getBQ ( eb ) ) {
bq2 = bq . cloneNode ( false ) ;
while ( n = eb . nextSibling )
bq2 . appendChild ( n . parentNode . removeChild ( n ) ) ;
}
// Add new bq after
if ( bq2 )
dom . insertAfter ( bq2 , bq ) ;
// Move all selected blocks after the current bq
nl = s . getSelectedBlocks ( sb , eb ) ;
for ( i = nl . length - 1 ; i >= 0 ; i -- ) {
dom . insertAfter ( nl [ i ] , bq ) ;
}
// Empty bq, then remove it
if ( /^\s*$/ . test ( bq . innerHTML ) )
dom . remove ( bq , 1 ) ; // Keep children so boomark restoration works correctly
// Empty bq, then remote it
if ( bq2 && /^\s*$/ . test ( bq2 . innerHTML ) )
dom . remove ( bq2 , 1 ) ; // Keep children so boomark restoration works correctly
if ( ! bm ) {
// Move caret inside empty block element
if ( ! tinymce . isIE ) {
r = ed . getDoc ( ) . createRange ( ) ;
r . setStart ( sb , 0 ) ;
r . setEnd ( sb , 0 ) ;
s . setRng ( r ) ;
} else {
s . select ( sb ) ;
s . collapse ( 0 ) ;
// IE misses the empty block some times element so we must move back the caret
if ( dom . getParent ( s . getStart ( ) , dom . isBlock ) != sb ) {
r = s . getRng ( ) ;
r . move ( 'character' , - 1 ) ;
r . select ( ) ;
}
}
} else
ed . selection . moveToBookmark ( bm ) ;
return ;
}
// Since IE can start with a totally empty document we need to add the first bq and paragraph
if ( tinymce . isIE && ! sb && ! eb ) {
ed . getDoc ( ) . execCommand ( 'Indent' ) ;
n = getBQ ( s . getNode ( ) ) ;
n . style . margin = n . dir = '' ; // IE adds margin and dir to bq
return ;
}
if ( ! sb || ! eb )
return ;
// If empty paragraph node then do not use bookmark
if ( sb != eb || sb . childNodes . length > 1 || ( sb . childNodes . length == 1 && sb . firstChild . nodeName != 'BR' ) )
bm = s . getBookmark ( ) ;
// Move selected block elements into a bq
tinymce . each ( s . getSelectedBlocks ( getBQ ( s . getStart ( ) ) , getBQ ( s . getEnd ( ) ) ) , function ( e ) {
// Found existing BQ add to this one
if ( e . nodeName == 'BLOCKQUOTE' && ! bq ) {
bq = e ;
return ;
}
// No BQ found, create one
if ( ! bq ) {
bq = dom . create ( 'blockquote' ) ;
e . parentNode . insertBefore ( bq , e ) ;
}
// Add children from existing BQ
if ( e . nodeName == 'BLOCKQUOTE' && bq ) {
n = e . firstChild ;
while ( n ) {
bq . appendChild ( n . cloneNode ( true ) ) ;
n = n . nextSibling ;
}
dom . remove ( e ) ;
return ;
}
// Add non BQ element to BQ
bq . appendChild ( dom . remove ( e ) ) ;
} ) ;
if ( ! bm ) {
// Move caret inside empty block element
if ( ! tinymce . isIE ) {
r = ed . getDoc ( ) . createRange ( ) ;
r . setStart ( sb , 0 ) ;
r . setEnd ( sb , 0 ) ;
s . setRng ( r ) ;
} else {
s . select ( sb ) ;
s . collapse ( 1 ) ;
}
} else
s . moveToBookmark ( bm ) ;
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
tinymce . each ( [ 'Cut' , 'Copy' , 'Paste' ] , function ( cmd ) {
tinymce . GlobalCommands . add ( cmd , function ( ) {
var ed = this , doc = ed . getDoc ( ) ;
try {
doc . execCommand ( cmd , false , null ) ;
// On WebKit the command will just be ignored if it's not enabled
if ( ! doc . queryCommandSupported ( cmd ) )
throw 'Error' ;
} catch ( ex ) {
ed . windowManager . alert ( ed . getLang ( 'clipboard_no_support' ) ) ;
}
} ) ;
} ) ;
} ) ( tinymce ) ;
( function ( tinymce ) {
tinymce . GlobalCommands . add ( 'InsertHorizontalRule' , function ( ) {
if ( tinymce . isOpera )
return this . getDoc ( ) . execCommand ( 'InsertHorizontalRule' , false , '' ) ;
this . selection . setContent ( '<hr />' ) ;
} ) ;
} ) ( tinymce ) ;
( function ( ) {
var cmds = tinymce . GlobalCommands ;
cmds . add ( [ 'mceEndUndoLevel' , 'mceAddUndoLevel' ] , function ( ) {
this . undoManager . add ( ) ;
} ) ;
cmds . add ( 'Undo' , function ( ) {
var ed = this ;
if ( ed . settings . custom _undo _redo ) {
ed . undoManager . undo ( ) ;
ed . nodeChanged ( ) ;
return true ;
}
return false ; // Run browser command
} ) ;
cmds . add ( 'Redo' , function ( ) {
var ed = this ;
if ( ed . settings . custom _undo _redo ) {
ed . undoManager . redo ( ) ;
ed . nodeChanged ( ) ;
return true ;
}
return false ; // Run browser command
} ) ;
} ) ( ) ;