[ Index ]
 

Code source de WordPress 2.1.2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/wp-includes/js/tinymce/ -> tiny_mce.js (source)

   1  
   2  /* file:jscripts/tiny_mce/classes/TinyMCE_Engine.class.js */
   3  
   4  function TinyMCE_Engine() {
   5      var ua;
   6  
   7      this.majorVersion = "2";
   8      this.minorVersion = "0.8";
   9      this.releaseDate = "2006-10-23";
  10  
  11      this.instances = new Array();
  12      this.switchClassCache = new Array();
  13      this.windowArgs = new Array();
  14      this.loadedFiles = new Array();
  15      this.pendingFiles = new Array();
  16      this.loadingIndex = 0;
  17      this.configs = new Array();
  18      this.currentConfig = 0;
  19      this.eventHandlers = new Array();
  20      this.log = new Array();
  21      this.undoLevels = [];
  22      this.undoIndex = 0;
  23      this.typingUndoIndex = -1;
  24  
  25      // Browser check
  26      ua = navigator.userAgent;
  27      this.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
  28      this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1);
  29      this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1);
  30      this.isMSIE7 = this.isMSIE && (ua.indexOf('MSIE 7') != -1);
  31      this.isGecko = ua.indexOf('Gecko') != -1;
  32      this.isSafari = ua.indexOf('Safari') != -1;
  33      this.isOpera = ua.indexOf('Opera') != -1;
  34      this.isMac = ua.indexOf('Mac') != -1;
  35      this.isNS7 = ua.indexOf('Netscape/7') != -1;
  36      this.isNS71 = ua.indexOf('Netscape/7.1') != -1;
  37      this.dialogCounter = 0;
  38      this.plugins = new Array();
  39      this.themes = new Array();
  40      this.menus = new Array();
  41      this.loadedPlugins = new Array();
  42      this.buttonMap = new Array();
  43      this.isLoaded = false;
  44  
  45      // Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those
  46      if (this.isOpera) {
  47          this.isMSIE = true;
  48          this.isGecko = false;
  49          this.isSafari =  false;
  50      }
  51  
  52      this.isIE = this.isMSIE;
  53      this.isRealIE = this.isMSIE && !this.isOpera;
  54  
  55      // TinyMCE editor id instance counter
  56      this.idCounter = 0;
  57  };
  58  
  59  TinyMCE_Engine.prototype = {
  60      init : function(settings) {
  61          var theme, nl, baseHREF = "", i;
  62  
  63          // IE 5.0x is no longer supported since 5.5, 6.0 and 7.0 now exists. We can't support old browsers forever, sorry.
  64          if (this.isMSIE5_0)
  65              return;
  66  
  67          this.settings = settings;
  68  
  69          // Check if valid browser has execcommand support
  70          if (typeof(document.execCommand) == 'undefined')
  71              return;
  72  
  73          // Get script base path
  74          if (!tinyMCE.baseURL) {
  75              var elements = document.getElementsByTagName('script');
  76  
  77              // If base element found, add that infront of baseURL
  78              nl = document.getElementsByTagName('base');
  79              for (i=0; i<nl.length; i++) {
  80                  if (nl[i].href)
  81                      baseHREF = nl[i].href;
  82              }
  83  
  84              for (var i=0; i<elements.length; i++) {
  85                  if (elements[i].src && (elements[i].src.indexOf("tiny_mce.js") != -1 || elements[i].src.indexOf("tiny_mce_dev.js") != -1 || elements[i].src.indexOf("tiny_mce_src.js") != -1 || elements[i].src.indexOf("tiny_mce_gzip") != -1)) {
  86                      var src = elements[i].src;
  87  
  88                      tinyMCE.srcMode = (src.indexOf('_src') != -1 || src.indexOf('_dev') != -1) ? '_src' : '';
  89                      tinyMCE.gzipMode = src.indexOf('_gzip') != -1;
  90                      src = src.substring(0, src.lastIndexOf('/'));
  91  
  92                      if (settings.exec_mode == "src" || settings.exec_mode == "normal")
  93                          tinyMCE.srcMode = settings.exec_mode == "src" ? '_src' : '';
  94  
  95                      // Force it absolute if page has a base href
  96                      if (baseHREF != "" && src.indexOf('://') == -1)
  97                          tinyMCE.baseURL = baseHREF + src;
  98                      else
  99                          tinyMCE.baseURL = src;
 100  
 101                      break;
 102                  }
 103              }
 104          }
 105  
 106          // Get document base path
 107          this.documentBasePath = document.location.href;
 108          if (this.documentBasePath.indexOf('?') != -1)
 109              this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.indexOf('?'));
 110          this.documentURL = this.documentBasePath;
 111          this.documentBasePath = this.documentBasePath.substring(0, this.documentBasePath.lastIndexOf('/'));
 112  
 113          // If not HTTP absolute
 114          if (tinyMCE.baseURL.indexOf('://') == -1 && tinyMCE.baseURL.charAt(0) != '/') {
 115              // If site absolute
 116              tinyMCE.baseURL = this.documentBasePath + "/" + tinyMCE.baseURL;
 117          }
 118  
 119          // Set default values on settings
 120          this._def("mode", "none");
 121          this._def("theme", "advanced");
 122          this._def("plugins", "", true);
 123          this._def("language", "en");
 124          this._def("docs_language", this.settings['language']);
 125          this._def("elements", "");
 126          this._def("textarea_trigger", "mce_editable");
 127          this._def("editor_selector", "");
 128          this._def("editor_deselector", "mceNoEditor");
 129          this._def("valid_elements", "+a[id|style|rel|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|style],-ul[class|style],-li[class|style],br,img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align],-sub[style|class],-sup[style|class],-blockquote[dir|style],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|style|dir|id|lang|bgcolor|background|bordercolor],-tr[id|lang|dir|class|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor],tbody[id|class],thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],-span[style|class|align],-pre[class|align|style],address[class|align|style],-h1[id|style|dir|class|align],-h2[id|style|dir|class|align],-h3[id|style|dir|class|align],-h4[id|style|dir|class|align],-h5[id|style|dir|class|align],-h6[id|style|dir|class|align],hr[class|style],-font[face|size|style|id|class|dir|color],dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],cite[title|id|class|style|dir|lang],abbr[title|id|class|style|dir|lang],acronym[title|id|class|style|dir|lang],del[title|id|class|style|dir|lang|datetime|cite],ins[title|id|class|style|dir|lang|datetime|cite]");
 130          this._def("extended_valid_elements", "");
 131          this._def("invalid_elements", "");
 132          this._def("encoding", "");
 133          this._def("urlconverter_callback", tinyMCE.getParam("urlconvertor_callback", "TinyMCE_Engine.prototype.convertURL"));
 134          this._def("save_callback", "");
 135          this._def("debug", false);
 136          this._def("force_br_newlines", false);
 137          this._def("force_p_newlines", true);
 138          this._def("add_form_submit_trigger", true);
 139          this._def("relative_urls", true);
 140          this._def("remove_script_host", true);
 141          this._def("focus_alert", true);
 142          this._def("document_base_url", this.documentURL);
 143          this._def("visual", true);
 144          this._def("visual_table_class", "mceVisualAid");
 145          this._def("setupcontent_callback", "");
 146          this._def("fix_content_duplication", true);
 147          this._def("custom_undo_redo", true);
 148          this._def("custom_undo_redo_levels", -1);
 149          this._def("custom_undo_redo_keyboard_shortcuts", true);
 150          this._def("custom_undo_redo_restore_selection", true);
 151          this._def("custom_undo_redo_global", false);
 152          this._def("verify_html", true);
 153          this._def("apply_source_formatting", false);
 154          this._def("directionality", "ltr");
 155          this._def("cleanup_on_startup", false);
 156          this._def("inline_styles", false);
 157          this._def("convert_newlines_to_brs", false);
 158          this._def("auto_reset_designmode", true);
 159          this._def("entities", "39,#39,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,34,quot,38,amp,60,lt,62,gt,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", true);
 160          this._def("entity_encoding", "named");
 161          this._def("cleanup_callback", "");
 162          this._def("add_unload_trigger", true);
 163          this._def("ask", false);
 164          this._def("nowrap", false);
 165          this._def("auto_resize", false);
 166          this._def("auto_focus", false);
 167          this._def("cleanup", true);
 168          this._def("remove_linebreaks", true);
 169          this._def("button_tile_map", false);
 170          this._def("submit_patch", true);
 171          this._def("browsers", "msie,safari,gecko,opera", true);
 172          this._def("dialog_type", "window");
 173          this._def("accessibility_warnings", true);
 174          this._def("accessibility_focus", true);
 175          this._def("merge_styles_invalid_parents", "");
 176          this._def("force_hex_style_colors", true);
 177          this._def("trim_span_elements", true);
 178          this._def("convert_fonts_to_spans", false);
 179          this._def("doctype", '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">');
 180          this._def("font_size_classes", '');
 181          this._def("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large', true);
 182          this._def("event_elements", 'a,img', true);
 183          this._def("convert_urls", true);
 184          this._def("table_inline_editing", false);
 185          this._def("object_resizing", true);
 186          this._def("custom_shortcuts", true);
 187          this._def("convert_on_click", false);
 188          this._def("content_css", '');
 189          this._def("fix_list_elements", false);
 190          this._def("fix_table_elements", false);
 191          this._def("strict_loading_mode", document.contentType == 'application/xhtml+xml');
 192          this._def("hidden_tab_class", '');
 193          this._def("display_tab_class", '');
 194          this._def("gecko_spellcheck", false);
 195  
 196          // Force strict loading mode to false on non Gecko browsers
 197          if (this.isMSIE && !this.isOpera)
 198              this.settings.strict_loading_mode = false;
 199  
 200          // Browser check IE
 201          if (this.isMSIE && this.settings['browsers'].indexOf('msie') == -1)
 202              return;
 203  
 204          // Browser check Gecko
 205          if (this.isGecko && this.settings['browsers'].indexOf('gecko') == -1)
 206              return;
 207  
 208          // Browser check Safari
 209          if (this.isSafari && this.settings['browsers'].indexOf('safari') == -1)
 210              return;
 211  
 212          // Browser check Opera
 213          if (this.isOpera && this.settings['browsers'].indexOf('opera') == -1)
 214              return;
 215  
 216          // If not super absolute make it so
 217          baseHREF = tinyMCE.settings['document_base_url'];
 218          var h = document.location.href;
 219          var p = h.indexOf('://');
 220          if (p > 0 && document.location.protocol != "file:") {
 221              p = h.indexOf('/', p + 3);
 222              h = h.substring(0, p);
 223  
 224              if (baseHREF.indexOf('://') == -1)
 225                  baseHREF = h + baseHREF;
 226  
 227              tinyMCE.settings['document_base_url'] = baseHREF;
 228              tinyMCE.settings['document_base_prefix'] = h;
 229          }
 230  
 231          // Trim away query part
 232          if (baseHREF.indexOf('?') != -1)
 233              baseHREF = baseHREF.substring(0, baseHREF.indexOf('?'));
 234  
 235          this.settings['base_href'] = baseHREF.substring(0, baseHREF.lastIndexOf('/')) + "/";
 236  
 237          theme = this.settings['theme'];
 238          this.inlineStrict = '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';
 239          this.inlineTransitional = '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';
 240          this.blockElms = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';
 241          this.blockRegExp = new RegExp("^(" + this.blockElms + ")$", "i");
 242          this.posKeyCodes = new Array(13,45,36,35,33,34,37,38,39,40);
 243          this.uniqueURL = 'javascript:TINYMCE_UNIQUEURL();'; // Make unique URL non real URL
 244          this.uniqueTag = '<div id="mceTMPElement" style="display: none">TMP</div>';
 245          this.callbacks = new Array('onInit', 'getInfo', 'getEditorTemplate', 'setupContent', 'onChange', 'onPageLoad', 'handleNodeChange', 'initInstance', 'execCommand', 'getControlHTML', 'handleEvent', 'cleanup');
 246  
 247          // Theme url
 248          this.settings['theme_href'] = tinyMCE.baseURL + "/themes/" + theme;
 249  
 250          if (!tinyMCE.isIE || tinyMCE.isOpera)
 251              this.settings['force_br_newlines'] = false;
 252  
 253          if (tinyMCE.getParam("popups_css", false)) {
 254              var cssPath = tinyMCE.getParam("popups_css", "");
 255  
 256              // Is relative
 257              if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
 258                  this.settings['popups_css'] = this.documentBasePath + "/" + cssPath;
 259              else
 260                  this.settings['popups_css'] = cssPath;
 261          } else
 262              this.settings['popups_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css";
 263  
 264          if (tinyMCE.getParam("editor_css", false)) {
 265              var cssPath = tinyMCE.getParam("editor_css", "");
 266  
 267              // Is relative
 268              if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/')
 269                  this.settings['editor_css'] = this.documentBasePath + "/" + cssPath;
 270              else
 271                  this.settings['editor_css'] = cssPath;
 272          } else {
 273              if (this.settings.editor_css != '')
 274                  this.settings['editor_css'] = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css";
 275          }
 276  
 277          if (tinyMCE.settings['debug']) {
 278              var msg = "Debug: \n";
 279  
 280              msg += "baseURL: " + this.baseURL + "\n";
 281              msg += "documentBasePath: " + this.documentBasePath + "\n";
 282              msg += "content_css: " + this.settings['content_css'] + "\n";
 283              msg += "popups_css: " + this.settings['popups_css'] + "\n";
 284              msg += "editor_css: " + this.settings['editor_css'] + "\n";
 285  
 286              alert(msg);
 287          }
 288  
 289          // Only do this once
 290          if (this.configs.length == 0) {
 291              if (typeof(TinyMCECompressed) == "undefined") {
 292                  tinyMCE.addEvent(window, "DOMContentLoaded", TinyMCE_Engine.prototype.onLoad);
 293  
 294                  if (tinyMCE.isRealIE) {
 295                      if (document.body)
 296                          tinyMCE.addEvent(document.body, "readystatechange", TinyMCE_Engine.prototype.onLoad);
 297                      else
 298                          tinyMCE.addEvent(document, "readystatechange", TinyMCE_Engine.prototype.onLoad);
 299                  }
 300  
 301                  tinyMCE.addEvent(window, "load", TinyMCE_Engine.prototype.onLoad);
 302                  tinyMCE._addUnloadEvents();
 303              }
 304          }
 305  
 306          this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings['theme'] + '/editor_template' + tinyMCE.srcMode + '.js');
 307          this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings['language'] +  '.js');
 308          this.loadCSS(this.settings['editor_css']);
 309  
 310          // Add plugins
 311          var p = tinyMCE.getParam('plugins', '', true, ',');
 312          if (p.length > 0) {
 313              for (var i=0; i<p.length; i++) {
 314                  if (p[i].charAt(0) != '-')
 315                      this.loadScript(tinyMCE.baseURL + '/plugins/' + p[i] + '/editor_plugin' + tinyMCE.srcMode + '.js');
 316              }
 317          }
 318  
 319          // Setup entities
 320          if (tinyMCE.getParam('entity_encoding') == 'named') {
 321              settings['cleanup_entities'] = new Array();
 322              var entities = tinyMCE.getParam('entities', '', true, ',');
 323              for (var i=0; i<entities.length; i+=2)
 324                  settings['cleanup_entities']['c' + entities[i]] = entities[i+1];
 325          }
 326  
 327          // Save away this config
 328          settings['index'] = this.configs.length;
 329          this.configs[this.configs.length] = settings;
 330  
 331          // Start loading first one in chain
 332          this.loadNextScript();
 333  
 334          // Force flicker free CSS backgrounds in IE
 335          if (this.isIE && !this.isOpera) {
 336              try {
 337                  document.execCommand('BackgroundImageCache', false, true);
 338              } catch (e) {
 339              }
 340          }
 341      },
 342  
 343      _addUnloadEvents : function() {
 344          if (tinyMCE.isIE) {
 345              if (tinyMCE.settings['add_unload_trigger']) {
 346                  tinyMCE.addEvent(window, "unload", TinyMCE_Engine.prototype.unloadHandler);
 347                  tinyMCE.addEvent(window.document, "beforeunload", TinyMCE_Engine.prototype.unloadHandler);
 348              }
 349          } else {
 350              if (tinyMCE.settings['add_unload_trigger'])
 351                  tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);});
 352          }
 353      },
 354  
 355      _def : function(key, def_val, t) {
 356          var v = tinyMCE.getParam(key, def_val);
 357  
 358          v = t ? v.replace(/\s+/g, "") : v;
 359  
 360          this.settings[key] = v;
 361      },
 362  
 363      hasPlugin : function(n) {
 364          return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
 365      },
 366  
 367      addPlugin : function(n, p) {
 368          var op = this.plugins[n];
 369  
 370          // Use the previous plugin object base URL used when loading external plugins
 371          p.baseURL = op ? op.baseURL : tinyMCE.baseURL + "/plugins/" + n;
 372          this.plugins[n] = p;
 373  
 374          this.loadNextScript();
 375      },
 376  
 377      setPluginBaseURL : function(n, u) {
 378          var op = this.plugins[n];
 379  
 380          if (op)
 381              op.baseURL = u;
 382          else
 383              this.plugins[n] = {baseURL : u};
 384      },
 385  
 386      loadPlugin : function(n, u) {
 387          u = u.indexOf('.js') != -1 ? u.substring(0, u.lastIndexOf('/')) : u;
 388          u = u.charAt(u.length-1) == '/' ? u.substring(0, u.length-1) : u;
 389          this.plugins[n] = {baseURL : u};
 390          this.loadScript(u + "/editor_plugin" + (tinyMCE.srcMode ? '_src' : '') + ".js");
 391      },
 392  
 393      hasTheme : function(n) {
 394          return typeof(this.themes[n]) != "undefined" && this.themes[n] != null;
 395      },
 396  
 397      addTheme : function(n, t) {
 398          this.themes[n] = t;
 399  
 400          this.loadNextScript();
 401      },
 402  
 403      addMenu : function(n, m) {
 404          this.menus[n] = m;
 405      },
 406  
 407      hasMenu : function(n) {
 408          return typeof(this.plugins[n]) != "undefined" && this.plugins[n] != null;
 409      },
 410  
 411      loadScript : function(url) {
 412          var i;
 413  
 414          for (i=0; i<this.loadedFiles.length; i++) {
 415              if (this.loadedFiles[i] == url)
 416                  return;
 417          }
 418  
 419          if (tinyMCE.settings.strict_loading_mode)
 420              this.pendingFiles[this.pendingFiles.length] = url;
 421          else
 422              document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + url + '"></script>');
 423  
 424          this.loadedFiles[this.loadedFiles.length] = url;
 425      },
 426  
 427      loadNextScript : function() {
 428          var d = document, se;
 429  
 430          if (!tinyMCE.settings.strict_loading_mode)
 431              return;
 432  
 433          if (this.loadingIndex < this.pendingFiles.length) {
 434              se = d.createElementNS('http://www.w3.org/1999/xhtml', 'script');
 435              se.setAttribute('language', 'javascript');
 436              se.setAttribute('type', 'text/javascript');
 437              se.setAttribute('src', this.pendingFiles[this.loadingIndex++]);
 438  
 439              d.getElementsByTagName("head")[0].appendChild(se);
 440          } else
 441              this.loadingIndex = -1; // Done with loading
 442      },
 443  
 444      loadCSS : function(url) {
 445          var ar = url.replace(/\s+/, '').split(',');
 446          var lflen = 0, csslen = 0;
 447          var skip = false;
 448          var x = 0, i = 0, nl, le;
 449  
 450          for (x = 0,csslen = ar.length; x<csslen; x++) {
 451              if (ar[x] != null && ar[x] != 'null' && ar[x].length > 0) {
 452                  /* Make sure it doesn't exist. */
 453                  for (i=0, lflen=this.loadedFiles.length; i<lflen; i++) {
 454                      if (this.loadedFiles[i] == ar[x]) {
 455                          skip = true;
 456                          break;
 457                      }
 458                  }
 459  
 460                  if (!skip) {
 461                      if (tinyMCE.settings.strict_loading_mode) {
 462                          nl = document.getElementsByTagName("head");
 463  
 464                          le = document.createElement('link');
 465                          le.setAttribute('href', ar[x]);
 466                          le.setAttribute('rel', 'stylesheet');
 467                          le.setAttribute('type', 'text/css');
 468  
 469                          nl[0].appendChild(le);            
 470                      } else
 471                          document.write('<link href="' + ar[x] + '" rel="stylesheet" type="text/css" />');
 472  
 473                      this.loadedFiles[this.loadedFiles.length] = ar[x];
 474                  }
 475              }
 476          }
 477      },
 478  
 479      importCSS : function(doc, css) {
 480          var css_ary = css.replace(/\s+/, '').split(',');
 481          var csslen, elm, headArr, x, css_file;
 482  
 483          for (x = 0, csslen = css_ary.length; x<csslen; x++) {
 484              css_file = css_ary[x];
 485  
 486              if (css_file != null && css_file != 'null' && css_file.length > 0) {
 487                  // Is relative, make absolute
 488                  if (css_file.indexOf('://') == -1 && css_file.charAt(0) != '/')
 489                      css_file = this.documentBasePath + "/" + css_file;
 490  
 491                  if (typeof(doc.createStyleSheet) == "undefined") {
 492                      elm = doc.createElement("link");
 493  
 494                      elm.rel = "stylesheet";
 495                      elm.href = css_file;
 496  
 497                      if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0)
 498                          headArr[0].appendChild(elm);
 499                  } else
 500                      doc.createStyleSheet(css_file);
 501              }
 502          }
 503      },
 504  
 505      confirmAdd : function(e, settings) {
 506          var elm = tinyMCE.isIE ? event.srcElement : e.target;
 507          var elementId = elm.name ? elm.name : elm.id;
 508  
 509          tinyMCE.settings = settings;
 510  
 511          if (tinyMCE.settings['convert_on_click'] || (!elm.getAttribute('mce_noask') && confirm(tinyMCELang['lang_edit_confirm'])))
 512              tinyMCE.addMCEControl(elm, elementId);
 513  
 514          elm.setAttribute('mce_noask', 'true');
 515      },
 516  
 517      updateContent : function(form_element_name) {
 518          // Find MCE instance linked to given form element and copy it's value
 519          var formElement = document.getElementById(form_element_name);
 520          for (var n in tinyMCE.instances) {
 521              var inst = tinyMCE.instances[n];
 522              if (!tinyMCE.isInstance(inst))
 523                  continue;
 524  
 525              inst.switchSettings();
 526  
 527              if (inst.formElement == formElement) {
 528                  var doc = inst.getDoc();
 529          
 530                  tinyMCE._setHTML(doc, inst.formElement.value);
 531  
 532                  if (!tinyMCE.isIE)
 533                      doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid);
 534              }
 535          }
 536      },
 537  
 538      addMCEControl : function(replace_element, form_element_name, target_document) {
 539          var id = "mce_editor_" + tinyMCE.idCounter++;
 540          var inst = new TinyMCE_Control(tinyMCE.settings);
 541  
 542          inst.editorId = id;
 543          this.instances[id] = inst;
 544  
 545          inst._onAdd(replace_element, form_element_name, target_document);
 546      },
 547  
 548      removeInstance : function(ti) {
 549          var t = [], n, i;
 550  
 551          // Remove from instances
 552          for (n in tinyMCE.instances) {
 553              i = tinyMCE.instances[n];
 554  
 555              if (tinyMCE.isInstance(i) && ti != i)
 556                      t[n] = i;
 557          }
 558  
 559          tinyMCE.instances = t;
 560  
 561          // Remove from global undo/redo
 562          n = [];
 563          t = tinyMCE.undoLevels;
 564  
 565          for (i=0; i<t.length; i++) {
 566              if (t[i] != ti)
 567                  n.push(t[i]);
 568          }
 569  
 570          tinyMCE.undoLevels = n;
 571          tinyMCE.undoIndex = n.length;
 572  
 573          return ti;
 574      },
 575  
 576      removeMCEControl : function(editor_id) {
 577          var inst = tinyMCE.getInstanceById(editor_id), h, re, ot, tn;
 578  
 579          if (inst) {
 580              inst.switchSettings();
 581  
 582              editor_id = inst.editorId;
 583              h = tinyMCE.getContent(editor_id);
 584  
 585              this.removeInstance(inst);
 586  
 587              tinyMCE.selectedElement = null;
 588              tinyMCE.selectedInstance = null;
 589  
 590              // Remove element
 591              re = document.getElementById(editor_id + "_parent");
 592              ot = inst.oldTargetElement;
 593              tn = ot.nodeName.toLowerCase();
 594  
 595              if (tn == "textarea" || tn == "input") {
 596                  re.parentNode.removeChild(re);
 597                  ot.style.display = "inline";
 598                  ot.value = h;
 599              } else {
 600                  ot.innerHTML = h;
 601                  ot.style.display = 'block';
 602                  re.parentNode.insertBefore(ot, re);
 603                  re.parentNode.removeChild(re);
 604              }
 605          }
 606      },
 607  
 608      triggerSave : function(skip_cleanup, skip_callback) {
 609          var inst, n;
 610  
 611          // Default to false
 612          if (typeof(skip_cleanup) == "undefined")
 613              skip_cleanup = false;
 614  
 615          // Default to false
 616          if (typeof(skip_callback) == "undefined")
 617              skip_callback = false;
 618  
 619          // Cleanup and set all form fields
 620          for (n in tinyMCE.instances) {
 621              inst = tinyMCE.instances[n];
 622  
 623              if (!tinyMCE.isInstance(inst))
 624                  continue;
 625  
 626              inst.triggerSave(skip_cleanup, skip_callback);
 627          }
 628      },
 629  
 630      resetForm : function(form_index) {
 631          var i, inst, n, formObj = document.forms[form_index];
 632  
 633          for (n in tinyMCE.instances) {
 634              inst = tinyMCE.instances[n];
 635  
 636              if (!tinyMCE.isInstance(inst))
 637                  continue;
 638  
 639              inst.switchSettings();
 640  
 641              for (i=0; i<formObj.elements.length; i++) {
 642                  if (inst.formTargetElementId == formObj.elements[i].name)
 643                      inst.getBody().innerHTML = inst.startContent;
 644              }
 645          }
 646      },
 647  
 648      execInstanceCommand : function(editor_id, command, user_interface, value, focus) {
 649          var inst = tinyMCE.getInstanceById(editor_id), r;
 650  
 651          if (inst) {
 652              r = inst.selection.getRng();
 653  
 654              if (typeof(focus) == "undefined")
 655                  focus = true;
 656  
 657              // IE bug lost focus on images in absolute divs Bug #1534575
 658              if (focus && (!r || !r.item))
 659                  inst.contentWindow.focus();
 660  
 661              // Reset design mode if lost
 662              inst.autoResetDesignMode();
 663  
 664              this.selectedElement = inst.getFocusElement();
 665              inst.select();
 666              tinyMCE.execCommand(command, user_interface, value);
 667  
 668              // Cancel event so it doesn't call onbeforeonunlaod
 669              if (tinyMCE.isIE && window.event != null)
 670                  tinyMCE.cancelEvent(window.event);
 671          }
 672      },
 673  
 674      execCommand : function(command, user_interface, value) {
 675          var inst = tinyMCE.selectedInstance;
 676  
 677          // Default input
 678          user_interface = user_interface ? user_interface : false;
 679          value = value ? value : null;
 680  
 681          if (inst)
 682              inst.switchSettings();
 683  
 684          switch (command) {
 685              case "Undo":
 686                  if (this.getParam('custom_undo_redo_global')) {
 687                      if (this.undoIndex > 0) {
 688                          tinyMCE.nextUndoRedoAction = 'Undo';
 689                          inst = this.undoLevels[--this.undoIndex];
 690                          inst.select();
 691  
 692                          if (!tinyMCE.nextUndoRedoInstanceId)
 693                              inst.execCommand('Undo');
 694                      }
 695                  } else
 696                      inst.execCommand('Undo');
 697                  return true;
 698  
 699              case "Redo":
 700                  if (this.getParam('custom_undo_redo_global')) {
 701                      if (this.undoIndex <= this.undoLevels.length - 1) {
 702                          tinyMCE.nextUndoRedoAction = 'Redo';
 703                          inst = this.undoLevels[this.undoIndex++];
 704                          inst.select();
 705  
 706                          if (!tinyMCE.nextUndoRedoInstanceId)
 707                              inst.execCommand('Redo');
 708                      }
 709                  } else
 710                      inst.execCommand('Redo');
 711  
 712                  return true;
 713  
 714              case 'mceFocus':
 715                  var inst = tinyMCE.getInstanceById(value);
 716                  if (inst)
 717                      inst.getWin().focus();
 718              return;
 719  
 720              case "mceAddControl":
 721              case "mceAddEditor":
 722                  tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
 723                  return;
 724  
 725              case "mceAddFrameControl":
 726                  tinyMCE.addMCEControl(tinyMCE._getElementById(value['element'], value['document']), value['element'], value['document']);
 727                  return;
 728  
 729              case "mceRemoveControl":
 730              case "mceRemoveEditor":
 731                  tinyMCE.removeMCEControl(value);
 732                  return;
 733  
 734              case "mceResetDesignMode":
 735                  // Resets the designmode state of the editors in Gecko
 736                  if (!tinyMCE.isIE) {
 737                      for (var n in tinyMCE.instances) {
 738                          if (!tinyMCE.isInstance(tinyMCE.instances[n]))
 739                              continue;
 740  
 741                          try {
 742                              tinyMCE.instances[n].getDoc().designMode = "on";
 743                          } catch (e) {
 744                              // Ignore any errors
 745                          }
 746                      }
 747                  }
 748  
 749                  return;
 750          }
 751  
 752          if (inst) {
 753              inst.execCommand(command, user_interface, value);
 754          } else if (tinyMCE.settings['focus_alert'])
 755              alert(tinyMCELang['lang_focus_alert']);
 756      },
 757  
 758      _createIFrame : function(replace_element, doc, win) {
 759          var iframe, id = replace_element.getAttribute("id");
 760          var aw, ah;
 761  
 762          if (typeof(doc) == "undefined")
 763              doc = document;
 764  
 765          if (typeof(win) == "undefined")
 766              win = window;
 767  
 768          iframe = doc.createElement("iframe");
 769  
 770          aw = "" + tinyMCE.settings['area_width'];
 771          ah = "" + tinyMCE.settings['area_height'];
 772  
 773          if (aw.indexOf('%') == -1) {
 774              aw = parseInt(aw);
 775              aw = (isNaN(aw) || aw < 0) ? 300 : aw;
 776              aw = aw + "px";
 777          }
 778  
 779          if (ah.indexOf('%') == -1) {
 780              ah = parseInt(ah);
 781              ah = (isNaN(ah) || ah < 0) ? 240 : ah;
 782              ah = ah + "px";
 783          }
 784  
 785          iframe.setAttribute("id", id);
 786          iframe.setAttribute("name", id);
 787          iframe.setAttribute("class", "mceEditorIframe");
 788          iframe.setAttribute("border", "0");
 789          iframe.setAttribute("frameBorder", "0");
 790          iframe.setAttribute("marginWidth", "0");
 791          iframe.setAttribute("marginHeight", "0");
 792          iframe.setAttribute("leftMargin", "0");
 793          iframe.setAttribute("topMargin", "0");
 794          iframe.setAttribute("width", aw);
 795          iframe.setAttribute("height", ah);
 796          iframe.setAttribute("allowtransparency", "true");
 797          iframe.className = 'mceEditorIframe';
 798  
 799          if (tinyMCE.settings["auto_resize"])
 800              iframe.setAttribute("scrolling", "no");
 801  
 802          // Must have a src element in MSIE HTTPs breaks aswell as absoute URLs
 803          if (tinyMCE.isRealIE)
 804              iframe.setAttribute("src", this.settings['default_document']);
 805  
 806          iframe.style.width = aw;
 807          iframe.style.height = ah;
 808  
 809          // Ugly hack for Gecko problem in strict mode
 810          if (tinyMCE.settings.strict_loading_mode)
 811              iframe.style.marginBottom = '-5px';
 812  
 813          // MSIE 5.0 issue
 814          if (tinyMCE.isRealIE)
 815              replace_element.outerHTML = iframe.outerHTML;
 816          else
 817              replace_element.parentNode.replaceChild(iframe, replace_element);
 818  
 819          if (tinyMCE.isRealIE)
 820              return win.frames[id];
 821          else
 822              return iframe;
 823      },
 824  
 825      setupContent : function(editor_id) {
 826          var inst = tinyMCE.instances[editor_id], i;
 827          var doc = inst.getDoc();
 828          var head = doc.getElementsByTagName('head').item(0);
 829          var content = inst.startContent;
 830  
 831          // HTML values get XML encoded in strict mode
 832          if (tinyMCE.settings.strict_loading_mode) {
 833              content = content.replace(/&lt;/g, '<');
 834              content = content.replace(/&gt;/g, '>');
 835              content = content.replace(/&quot;/g, '"');
 836              content = content.replace(/&amp;/g, '&');
 837          }
 838  
 839          inst.switchSettings();
 840  
 841          // Not loaded correctly hit it again, Mozilla bug #997860
 842          if (!tinyMCE.isIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") {
 843              // This part will remove the designMode status
 844              // Failes first time in Firefox 1.5b2 on Mac
 845              try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {}
 846              window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000);
 847              return;
 848          }
 849  
 850          if (!head) {
 851              window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10);
 852              return;
 853          }
 854  
 855          // Import theme specific content CSS the user specific
 856          tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings['theme'] + "/css/editor_content.css");
 857          tinyMCE.importCSS(inst.getDoc(), inst.settings['content_css']);
 858          tinyMCE.dispatchCallback(inst, 'init_instance_callback', 'initInstance', inst);
 859  
 860          // Setup keyboard shortcuts
 861          if (tinyMCE.getParam('custom_undo_redo_keyboard_shortcuts')) {
 862              inst.addShortcut('ctrl', 'z', 'lang_undo_desc', 'Undo');
 863              inst.addShortcut('ctrl', 'y', 'lang_redo_desc', 'Redo');
 864          }
 865  
 866          // BlockFormat shortcuts keys
 867          for (i=1; i<=6; i++)
 868              inst.addShortcut('ctrl', '' + i, '', 'FormatBlock', false, '<h' + i + '>');
 869  
 870          inst.addShortcut('ctrl', '7', '', 'FormatBlock', false, '<p>');
 871          inst.addShortcut('ctrl', '8', '', 'FormatBlock', false, '<div>');
 872          inst.addShortcut('ctrl', '9', '', 'FormatBlock', false, '<address>');
 873  
 874          // Add default shortcuts for gecko
 875          if (tinyMCE.isGecko) {
 876              inst.addShortcut('ctrl', 'b', 'lang_bold_desc', 'Bold');
 877              inst.addShortcut('ctrl', 'i', 'lang_italic_desc', 'Italic');
 878              inst.addShortcut('ctrl', 'u', 'lang_underline_desc', 'Underline');
 879          }
 880  
 881          // Setup span styles
 882          if (tinyMCE.getParam("convert_fonts_to_spans"))
 883              inst.getBody().setAttribute('id', 'mceSpanFonts');
 884  
 885          if (tinyMCE.settings['nowrap'])
 886              doc.body.style.whiteSpace = "nowrap";
 887  
 888          doc.body.dir = this.settings['directionality'];
 889          doc.editorId = editor_id;
 890  
 891          // Add on document element in Mozilla
 892          if (!tinyMCE.isIE)
 893              doc.documentElement.editorId = editor_id;
 894  
 895          inst.setBaseHREF(tinyMCE.settings['base_href']);
 896  
 897          // Replace new line characters to BRs
 898          if (tinyMCE.settings['convert_newlines_to_brs']) {
 899              content = tinyMCE.regexpReplace(content, "\r\n", "<br />", "gi");
 900              content = tinyMCE.regexpReplace(content, "\r", "<br />", "gi");
 901              content = tinyMCE.regexpReplace(content, "\n", "<br />", "gi");
 902          }
 903  
 904          // Open closed anchors
 905      //    content = content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
 906  
 907          // Call custom cleanup code
 908          content = tinyMCE.storeAwayURLs(content);
 909          content = tinyMCE._customCleanup(inst, "insert_to_editor", content);
 910  
 911          if (tinyMCE.isIE) {
 912              // Ugly!!!
 913              window.setInterval('try{tinyMCE.getCSSClasses(tinyMCE.instances["' + editor_id + '"].getDoc(), "' + editor_id + '");}catch(e){}', 500);
 914  
 915              if (tinyMCE.settings["force_br_newlines"])
 916                  doc.styleSheets[0].addRule("p", "margin: 0;");
 917  
 918              var body = inst.getBody();
 919              body.editorId = editor_id;
 920          }
 921  
 922          content = tinyMCE.cleanupHTMLCode(content);
 923  
 924          // Fix for bug #958637
 925          if (!tinyMCE.isIE) {
 926              var contentElement = inst.getDoc().createElement("body");
 927              var doc = inst.getDoc();
 928  
 929              contentElement.innerHTML = content;
 930  
 931              // Remove weridness!
 932              if (tinyMCE.isGecko && tinyMCE.settings['remove_lt_gt'])
 933                  content = content.replace(new RegExp('&lt;&gt;', 'g'), "");
 934  
 935              if (tinyMCE.settings['cleanup_on_startup'])
 936                  tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement));
 937              else
 938                  tinyMCE.setInnerHTML(inst.getBody(), content);
 939  
 940              tinyMCE.convertAllRelativeURLs(inst.getBody());
 941          } else {
 942              if (tinyMCE.settings['cleanup_on_startup']) {
 943                  tinyMCE._setHTML(inst.getDoc(), content);
 944  
 945                  // Produces permission denied error in MSIE 5.5
 946                  eval('try {tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody()));} catch(e) {}');
 947              } else
 948                  tinyMCE._setHTML(inst.getDoc(), content);
 949          }
 950  
 951          // Fix for bug #957681
 952          //inst.getDoc().designMode = inst.getDoc().designMode;
 953  
 954          // Setup element references
 955          var parentElm = inst.targetDoc.getElementById(inst.editorId + '_parent');
 956          inst.formElement = tinyMCE.isGecko ? parentElm.previousSibling : parentElm.nextSibling;
 957  
 958          tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings['visual'], inst);
 959          tinyMCE.dispatchCallback(inst, 'setupcontent_callback', 'setupContent', editor_id, inst.getBody(), inst.getDoc());
 960  
 961          // Re-add design mode on mozilla
 962          if (!tinyMCE.isIE)
 963              tinyMCE.addEventHandlers(inst);
 964  
 965          // Add blur handler
 966          if (tinyMCE.isIE) {
 967              tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE_Engine.prototype._eventPatch);
 968              tinyMCE.addEvent(inst.getBody(), "beforedeactivate", TinyMCE_Engine.prototype._eventPatch); // Bug #1439953
 969  
 970              // Workaround for drag drop/copy paste base href bug
 971              if (!tinyMCE.isOpera) {
 972                  tinyMCE.addEvent(doc.body, "mousemove", TinyMCE_Engine.prototype.onMouseMove);
 973                  tinyMCE.addEvent(doc.body, "beforepaste", TinyMCE_Engine.prototype._eventPatch);
 974                  tinyMCE.addEvent(doc.body, "drop", TinyMCE_Engine.prototype._eventPatch);
 975              }
 976          }
 977  
 978          // Trigger node change, this call locks buttons for tables and so forth
 979          inst.select();
 980          tinyMCE.selectedElement = inst.contentWindow.document.body;
 981  
 982          // Call custom DOM cleanup
 983          tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody());
 984          tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody());
 985          tinyMCE._setEventsEnabled(inst.getBody(), false);
 986          tinyMCE.cleanupAnchors(inst.getDoc());
 987  
 988          if (tinyMCE.getParam("convert_fonts_to_spans"))
 989              tinyMCE.convertSpansToFonts(inst.getDoc());
 990  
 991          inst.startContent = tinyMCE.trim(inst.getBody().innerHTML);
 992          inst.undoRedo.add({ content : inst.startContent });
 993  
 994          // Cleanup any mess left from storyAwayURLs
 995          if (tinyMCE.isGecko) {
 996              // Remove mce_src from textnodes and comments
 997              tinyMCE.selectNodes(inst.getBody(), function(n) {
 998                  if (n.nodeType == 3 || n.nodeType == 8)
 999                      n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");
1000  
1001                  return false;
1002              });
1003          }
1004  
1005          // Remove Gecko spellchecking
1006          if (tinyMCE.isGecko)
1007              inst.getBody().spellcheck = tinyMCE.getParam("gecko_spellcheck");
1008  
1009          // Cleanup any mess left from storyAwayURLs
1010          tinyMCE._removeInternal(inst.getBody());
1011  
1012          inst.select();
1013          tinyMCE.triggerNodeChange(false, true);
1014      },
1015  
1016      storeAwayURLs : function(s) {
1017          // Remove all mce_src, mce_href and replace them with new ones
1018      //    s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
1019      //    s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), '');
1020  
1021          if (!s.match(/(mce_src|mce_href)/gi, s)) {
1022              s = s.replace(new RegExp('src\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'src="$1" mce_src="$1"');
1023              s = s.replace(new RegExp('href\\s*=\\s*\"([^ >\"]*)\"', 'gi'), 'href="$1" mce_href="$1"');
1024          }
1025  
1026          return s;
1027      },
1028  
1029      _removeInternal : function(n) {
1030          if (tinyMCE.isGecko) {
1031              // Remove mce_src from textnodes and comments
1032              tinyMCE.selectNodes(n, function(n) {
1033                  if (n.nodeType == 3 || n.nodeType == 8)
1034                      n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), "");
1035  
1036                  return false;
1037              });
1038          }
1039      },
1040  
1041      handleEvent : function(e) {
1042          var inst = tinyMCE.selectedInstance;
1043  
1044          // Remove odd, error
1045          if (typeof(tinyMCE) == "undefined")
1046              return true;
1047  
1048          //tinyMCE.debug(e.type + " " + e.target.nodeName + " " + (e.relatedTarget ? e.relatedTarget.nodeName : ""));
1049  
1050          if (tinyMCE.executeCallback(tinyMCE.selectedInstance, 'handle_event_callback', 'handleEvent', e))
1051              return false;
1052  
1053          switch (e.type) {
1054              case "beforedeactivate": // Was added due to bug #1439953
1055              case "blur":
1056                  if (tinyMCE.selectedInstance)
1057                      tinyMCE.selectedInstance.execCommand('mceEndTyping');
1058  
1059                  tinyMCE.hideMenus();
1060  
1061                  return;
1062  
1063              // Workaround for drag drop/copy paste base href bug
1064              case "drop":
1065              case "beforepaste":
1066                  if (tinyMCE.selectedInstance)
1067                      tinyMCE.selectedInstance.setBaseHREF(null);
1068  
1069                  // Fixes odd MSIE bug where drag/droping elements in a iframe with height 100% breaks
1070                  // This logic forces the width/height to be in pixels while the user is drag/dropping
1071                  if (tinyMCE.isRealIE) {
1072                      var ife = tinyMCE.selectedInstance.iframeElement;
1073  
1074                      /*if (ife.style.width.indexOf('%') != -1) {
1075                          ife._oldWidth = ife.width.height;
1076                          ife.style.width = ife.clientWidth;
1077                      }*/
1078  
1079                      if (ife.style.height.indexOf('%') != -1) {
1080                          ife._oldHeight = ife.style.height;
1081                          ife.style.height = ife.clientHeight;
1082                      }
1083                  }
1084  
1085                  window.setTimeout("tinyMCE.selectedInstance.setBaseHREF(tinyMCE.settings['base_href']);tinyMCE._resetIframeHeight();", 1);
1086                  return;
1087  
1088              case "submit":
1089                  tinyMCE.triggerSave();
1090                  tinyMCE.isNotDirty = true;
1091                  return;
1092  
1093              case "reset":
1094                  var formObj = tinyMCE.isIE ? window.event.srcElement : e.target;
1095  
1096                  for (var i=0; i<document.forms.length; i++) {
1097                      if (document.forms[i] == formObj)
1098                          window.setTimeout('tinyMCE.resetForm(' + i + ');', 10);
1099                  }
1100  
1101                  return;
1102  
1103              case "keypress":
1104                  if (inst && inst.handleShortcut(e))
1105                      return false;
1106  
1107                  if (e.target.editorId) {
1108                      tinyMCE.instances[e.target.editorId].select();
1109                  } else {
1110                      if (e.target.ownerDocument.editorId)
1111                          tinyMCE.instances[e.target.ownerDocument.editorId].select();
1112                  }
1113  
1114                  if (tinyMCE.selectedInstance)
1115                      tinyMCE.selectedInstance.switchSettings();
1116  
1117                  // Insert P element
1118                  if ((tinyMCE.isGecko || tinyMCE.isOpera || tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && e.keyCode == 13 && !e.shiftKey) {
1119                      // Insert P element instead of BR
1120                      if (TinyMCE_ForceParagraphs._insertPara(tinyMCE.selectedInstance, e)) {
1121                          // Cancel event
1122                          tinyMCE.execCommand("mceAddUndoLevel");
1123                          return tinyMCE.cancelEvent(e);
1124                      }
1125                  }
1126  
1127                  // Handle backspace
1128                  if ((tinyMCE.isGecko && !tinyMCE.isSafari) && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
1129                      // Insert P element instead of BR
1130                      if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
1131                          // Cancel event
1132                          tinyMCE.execCommand("mceAddUndoLevel");
1133                          return tinyMCE.cancelEvent(e);
1134                      }
1135                  }
1136  
1137                  // Return key pressed
1138                  if (tinyMCE.isIE && tinyMCE.settings['force_br_newlines'] && e.keyCode == 13) {
1139                      if (e.target.editorId)
1140                          tinyMCE.instances[e.target.editorId].select();
1141  
1142                      if (tinyMCE.selectedInstance) {
1143                          var sel = tinyMCE.selectedInstance.getDoc().selection;
1144                          var rng = sel.createRange();
1145  
1146                          if (tinyMCE.getParentElement(rng.parentElement(), "li") != null)
1147                              return false;
1148  
1149                          // Cancel event
1150                          e.returnValue = false;
1151                          e.cancelBubble = true;
1152  
1153                          // Insert BR element
1154                          rng.pasteHTML("<br />");
1155                          rng.collapse(false);
1156                          rng.select();
1157  
1158                          tinyMCE.execCommand("mceAddUndoLevel");
1159                          tinyMCE.triggerNodeChange(false);
1160                          return false;
1161                      }
1162                  }
1163  
1164                  // Backspace or delete
1165                  if (e.keyCode == 8 || e.keyCode == 46) {
1166                      tinyMCE.selectedElement = e.target;
1167                      tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a");
1168                      tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img");
1169                      tinyMCE.triggerNodeChange(false);
1170                  }
1171  
1172                  return false;
1173              break;
1174  
1175              case "keyup":
1176              case "keydown":
1177                  tinyMCE.hideMenus();
1178                  tinyMCE.hasMouseMoved = false;
1179  
1180                  if (inst && inst.handleShortcut(e))
1181                      return false;
1182  
1183                  if (e.target.editorId)
1184                      tinyMCE.instances[e.target.editorId].select();
1185  
1186                  if (tinyMCE.selectedInstance)
1187                      tinyMCE.selectedInstance.switchSettings();
1188  
1189                  var inst = tinyMCE.selectedInstance;
1190  
1191                  // Handle backspace
1192                  if (tinyMCE.isGecko && tinyMCE.settings['force_p_newlines'] && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) {
1193                      // Insert P element instead of BR
1194                      if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) {
1195                          // Cancel event
1196                          tinyMCE.execCommand("mceAddUndoLevel");
1197                          e.preventDefault();
1198                          return false;
1199                      }
1200                  }
1201  
1202                  tinyMCE.selectedElement = null;
1203                  tinyMCE.selectedNode = null;
1204                  var elm = tinyMCE.selectedInstance.getFocusElement();
1205                  tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a");
1206                  tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img");
1207                  tinyMCE.selectedElement = elm;
1208  
1209                  // Update visualaids on tabs
1210                  if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9)
1211                      tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings['visual'], tinyMCE.selectedInstance);
1212  
1213                  // Fix empty elements on return/enter, check where enter occured
1214                  if (tinyMCE.isIE && e.type == "keydown" && e.keyCode == 13)
1215                      tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement();
1216  
1217                  // Fix empty elements on return/enter
1218                  if (tinyMCE.isIE && e.type == "keyup" && e.keyCode == 13) {
1219                      var elm = tinyMCE.enterKeyElement;
1220                      if (elm) {
1221                          var re = new RegExp('^HR|IMG|BR$','g'); // Skip these
1222                          var dre = new RegExp('^H[1-6]$','g'); // Add double on these
1223  
1224                          if (!elm.hasChildNodes() && !re.test(elm.nodeName)) {
1225                              if (dre.test(elm.nodeName))
1226                                  elm.innerHTML = "&nbsp;&nbsp;";
1227                              else
1228                                  elm.innerHTML = "&nbsp;";
1229                          }
1230                      }
1231                  }
1232  
1233                  // Check if it's a position key
1234                  var keys = tinyMCE.posKeyCodes;
1235                  var posKey = false;
1236                  for (var i=0; i<keys.length; i++) {
1237                      if (keys[i] == e.keyCode) {
1238                          posKey = true;
1239                          break;
1240                      }
1241                  }
1242  
1243                  // MSIE custom key handling
1244                  if (tinyMCE.isIE && tinyMCE.settings['custom_undo_redo']) {
1245                      var keys = new Array(8,46); // Backspace,Delete
1246  
1247                      for (var i=0; i<keys.length; i++) {
1248                          if (keys[i] == e.keyCode) {
1249                              if (e.type == "keyup")
1250                                  tinyMCE.triggerNodeChange(false);
1251                          }
1252                      }
1253                  }
1254  
1255                  // If Ctrl key
1256                  if (e.keyCode == 17)
1257                      return true;
1258  
1259                  // Handle Undo/Redo when typing content
1260  
1261                  if (tinyMCE.isGecko) {
1262                      // Start typing (not a position key or ctrl key, but ctrl+x and ctrl+p is ok)
1263                      if (!posKey && e.type == "keyup" && !e.ctrlKey || (e.ctrlKey && (e.keyCode == 86 || e.keyCode == 88)))
1264                          tinyMCE.execCommand("mceStartTyping");
1265                  } else {
1266                      // IE seems to be working better with this setting
1267                      if (!posKey && e.type == "keyup")
1268                          tinyMCE.execCommand("mceStartTyping");
1269                  }
1270  
1271                  // Store undo bookmark
1272                  if (e.type == "keydown" && (posKey || e.ctrlKey) && inst)
1273                      inst.undoBookmark = inst.selection.getBookmark();
1274  
1275                  // End typing (position key) or some Ctrl event
1276                  if (e.type == "keyup" && (posKey || e.ctrlKey))
1277                      tinyMCE.execCommand("mceEndTyping");
1278  
1279                  if (posKey && e.type == "keyup")
1280                      tinyMCE.triggerNodeChange(false);
1281  
1282                  if (tinyMCE.isIE && e.ctrlKey)
1283                      window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
1284              break;
1285  
1286              case "mousedown":
1287              case "mouseup":
1288              case "click":
1289              case "dblclick":
1290              case "focus":
1291                  tinyMCE.hideMenus();
1292  
1293                  if (tinyMCE.selectedInstance) {
1294                      tinyMCE.selectedInstance.switchSettings();
1295                      tinyMCE.selectedInstance.isFocused = true;
1296                  }
1297  
1298                  // Check instance event trigged on
1299                  var targetBody = tinyMCE.getParentElement(e.target, "html");
1300                  for (var instanceName in tinyMCE.instances) {
1301                      if (!tinyMCE.isInstance(tinyMCE.instances[instanceName]))
1302                          continue;
1303  
1304                      var inst = tinyMCE.instances[instanceName];
1305  
1306                      // Reset design mode if lost (on everything just in case)
1307                      inst.autoResetDesignMode();
1308  
1309                      // Use HTML element since users might click outside of body element
1310                      if (inst.getBody().parentNode == targetBody) {
1311                          inst.select();
1312                          tinyMCE.selectedElement = e.target;
1313                          tinyMCE.linkElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "a");
1314                          tinyMCE.imgElement = tinyMCE.getParentElement(tinyMCE.selectedElement, "img");
1315                          break;
1316                      }
1317                  }
1318  
1319                  // Add first bookmark location
1320                  if (!tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark && (e.type == "mouseup" || e.type == "dblclick"))
1321                      tinyMCE.selectedInstance.undoRedo.undoLevels[0].bookmark = tinyMCE.selectedInstance.selection.getBookmark();
1322  
1323                  // Reset selected node
1324                  if (e.type != "focus")
1325                      tinyMCE.selectedNode = null;
1326  
1327                  tinyMCE.triggerNodeChange(false);
1328                  tinyMCE.execCommand("mceEndTyping");
1329  
1330                  if (e.type == "mouseup")
1331                      tinyMCE.execCommand("mceAddUndoLevel");
1332  
1333                  // Just in case
1334                  if (!tinyMCE.selectedInstance && e.target.editorId)
1335                      tinyMCE.instances[e.target.editorId].select();
1336  
1337                  return false;
1338              break;
1339          }
1340      },
1341  
1342      getButtonHTML : function(id, lang, img, cmd, ui, val) {
1343          var h = '', m, x, io = '';
1344  
1345          cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';
1346  
1347          if (typeof(ui) != "undefined" && ui != null)
1348              cmd += ',' + ui;
1349  
1350          if (typeof(val) != "undefined" && val != null)
1351              cmd += ",'" + val + "'";
1352  
1353          cmd += ');';
1354  
1355          // Patch for IE7 bug with hover out not restoring correctly
1356          if (tinyMCE.isRealIE)
1357              io = 'onmouseover="tinyMCE.lastHover = this;"';
1358  
1359          // Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
1360          if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = this.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
1361              // Tiled button
1362              x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);
1363              h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceTiledButton mceButtonNormal" target="_self">';
1364              h += '<img src="{$themeurl}/images/spacer.gif" style="background-position: ' + x + 'px 0" title="{$' + lang + '}" />';
1365              h += '</a>';
1366          } else {
1367              // Normal button
1368              h += '<a id="{$editor_id}_' + id + '" href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" ' + io + ' class="mceButtonNormal" target="_self">';
1369              h += '<img src="' + img + '" title="{$' + lang + '}" />';
1370              h += '</a>';
1371          }
1372  
1373          return h;
1374      },
1375  
1376      getMenuButtonHTML : function(id, lang, img, mcmd, cmd, ui, val) {
1377          var h = '', m, x;
1378  
1379          mcmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + mcmd + '\');';
1380          cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\'';
1381  
1382          if (typeof(ui) != "undefined" && ui != null)
1383              cmd += ',' + ui;
1384  
1385          if (typeof(val) != "undefined" && val != null)
1386              cmd += ",'" + val + "'";
1387  
1388          cmd += ');';
1389  
1390          // Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled
1391          if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = tinyMCE.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) {
1392              x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20);
1393  
1394              if (tinyMCE.isRealIE)
1395                  h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
1396              else
1397                  h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton">';
1398  
1399              h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceTiledButton mceMenuButtonNormal" target="_self">';
1400              h += '<img src="{$themeurl}/images/spacer.gif" style="width: 20px; height: 20px; background-position: ' + x + 'px 0" title="{$' + lang + '}" /></a>';
1401              h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
1402              h += '</a></span>';
1403          } else {
1404              if (tinyMCE.isRealIE)
1405                  h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton" onmouseover="tinyMCE._menuButtonEvent(\'over\',this);tinyMCE.lastHover = this;" onmouseout="tinyMCE._menuButtonEvent(\'out\',this);">';
1406              else
1407                  h += '<span id="{$editor_id}_' + id + '" class="mceMenuButton">';
1408  
1409              h += '<a href="javascript:' + cmd + '" onclick="' + cmd + 'return false;" onmousedown="return false;" class="mceMenuButtonNormal" target="_self">';
1410              h += '<img src="' + img + '" title="{$' + lang + '}" /></a>';
1411              h += '<a href="javascript:' + mcmd + '" onclick="' + mcmd + 'return false;" onmousedown="return false;"><img src="{$themeurl}/images/button_menu.gif" title="{$' + lang + '}" class="mceMenuButton" />';
1412              h += '</a></span>';
1413          }
1414  
1415          return h;
1416      },
1417  
1418      _menuButtonEvent : function(e, o) {
1419          if (o.className == 'mceMenuButtonFocus')
1420              return;
1421  
1422          if (e == 'over')
1423              o.className = o.className + ' mceMenuHover';
1424          else
1425              o.className = o.className.replace(/\s.*$/, '');
1426      },
1427  
1428      addButtonMap : function(m) {
1429          var i, a = m.replace(/\s+/, '').split(',');
1430  
1431          for (i=0; i<a.length; i++)
1432              this.buttonMap[a[i]] = i;
1433      },
1434  
1435      submitPatch : function() {
1436          tinyMCE.triggerSave();
1437          tinyMCE.isNotDirty = true;
1438          this.mceOldSubmit();
1439      },
1440  
1441      onLoad : function() {
1442          var r;
1443  
1444          // Wait for everything to be loaded first
1445          if (tinyMCE.settings.strict_loading_mode && this.loadingIndex != -1) {
1446              window.setTimeout('tinyMCE.onLoad();', 1);
1447              return;
1448          }
1449  
1450          if (tinyMCE.isRealIE && window.event.type == "readystatechange" && document.readyState != "complete")
1451              return true;
1452  
1453          if (tinyMCE.isLoaded)
1454              return true;
1455  
1456          tinyMCE.isLoaded = true;
1457  
1458          // IE produces JS error if TinyMCE is placed in a frame
1459          // It seems to have something to do with the selection not beeing
1460          // correctly initialized in IE so this hack solves the problem
1461          if (tinyMCE.isRealIE && document.body) {
1462              r = document.body.createTextRange();
1463              r.collapse(true);
1464              r.select();
1465          }
1466  
1467          tinyMCE.dispatchCallback(null, 'onpageload', 'onPageLoad');
1468  
1469          for (var c=0; c<tinyMCE.configs.length; c++) {
1470              tinyMCE.settings = tinyMCE.configs[c];
1471  
1472              var selector = tinyMCE.getParam("editor_selector");
1473              var deselector = tinyMCE.getParam("editor_deselector");
1474              var elementRefAr = new Array();
1475  
1476              // Add submit triggers
1477              if (document.forms && tinyMCE.settings['add_form_submit_trigger'] && !tinyMCE.submitTriggers) {
1478                  for (var i=0; i<document.forms.length; i++) {
1479                      var form = document.forms[i];
1480  
1481                      tinyMCE.addEvent(form, "submit", TinyMCE_Engine.prototype.handleEvent);
1482                      tinyMCE.addEvent(form, "reset", TinyMCE_Engine.prototype.handleEvent);
1483                      tinyMCE.submitTriggers = true; // Do it only once
1484  
1485                      // Patch the form.submit function
1486                      if (tinyMCE.settings['submit_patch']) {
1487                          try {
1488                              form.mceOldSubmit = form.submit;
1489                              form.submit = TinyMCE_Engine.prototype.submitPatch;
1490                          } catch (e) {
1491                              // Do nothing
1492                          }
1493                      }
1494                  }
1495              }
1496  
1497              // Add editor instances based on mode
1498              var mode = tinyMCE.settings['mode'];
1499              switch (mode) {
1500                  case "exact":
1501                      var elements = tinyMCE.getParam('elements', '', true, ',');
1502  
1503                      for (var i=0; i<elements.length; i++) {
1504                          var element = tinyMCE._getElementById(elements[i]);
1505                          var trigger = element ? element.getAttribute(tinyMCE.settings['textarea_trigger']) : "";
1506  
1507                          if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(element, "class")))
1508                              continue;
1509  
1510                          if (trigger == "false")
1511                              continue;
1512  
1513                          if ((tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) && element) {
1514                              elementRefAr[elementRefAr.length] = element;
1515                              continue;
1516                          }
1517  
1518                          if (element)
1519                              tinyMCE.addMCEControl(element, elements[i]);
1520                          else if (tinyMCE.settings['debug'])
1521                              alert("Error: Could not find element by id or name: " + elements[i]);
1522                      }
1523                  break;
1524  
1525                  case "specific_textareas":
1526                  case "textareas":
1527                      var nodeList = document.getElementsByTagName("textarea");
1528  
1529                      for (var i=0; i<nodeList.length; i++) {
1530                          var elm = nodeList.item(i);
1531                          var trigger = elm.getAttribute(tinyMCE.settings['textarea_trigger']);
1532  
1533                          if (selector != '' && !new RegExp('\\b' + selector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
1534                              continue;
1535  
1536                          if (selector != '')
1537                              trigger = selector != "" ? "true" : "";
1538  
1539                          if (new RegExp('\\b' + deselector + '\\b').test(tinyMCE.getAttrib(elm, "class")))
1540                              continue;
1541  
1542                          if ((mode == "specific_textareas" && trigger == "true") || (mode == "textareas" && trigger != "false"))
1543                              elementRefAr[elementRefAr.length] = elm;
1544                      }
1545                  break;
1546              }
1547  
1548              for (var i=0; i<elementRefAr.length; i++) {
1549                  var element = elementRefAr[i];
1550                  var elementId = element.name ? element.name : element.id;
1551  
1552                  if (tinyMCE.settings['ask'] || tinyMCE.settings['convert_on_click']) {
1553                      // Focus breaks in Mozilla
1554                      if (tinyMCE.isGecko) {
1555                          var settings = tinyMCE.settings;
1556  
1557                          tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
1558  
1559                          if (element.nodeName != "TEXTAREA" && element.nodeName != "INPUT")
1560                              tinyMCE.addEvent(element, "click", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
1561                          // tinyMCE.addEvent(element, "mouseover", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);});
1562                      } else {
1563                          var settings = tinyMCE.settings;
1564  
1565                          tinyMCE.addEvent(element, "focus", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
1566                          tinyMCE.addEvent(element, "click", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
1567                          // tinyMCE.addEvent(element, "mouseenter", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); });
1568                      }
1569                  } else
1570                      tinyMCE.addMCEControl(element, elementId);
1571              }
1572  
1573              // Handle auto focus
1574              if (tinyMCE.settings['auto_focus']) {
1575                  window.setTimeout(function () {
1576                      var inst = tinyMCE.getInstanceById(tinyMCE.settings['auto_focus']);
1577                      inst.selection.selectNode(inst.getBody(), true, true);
1578                      inst.contentWindow.focus();
1579                  }, 100);
1580              }
1581  
1582              tinyMCE.dispatchCallback(null, 'oninit', 'onInit');
1583          }
1584      },
1585  
1586      isInstance : function(o) {
1587          return o != null && typeof(o) == "object" && o.isTinyMCE_Control;
1588      },
1589  
1590      getParam : function(name, default_value, strip_whitespace, split_chr) {
1591          var value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
1592  
1593          // Fix bool values
1594          if (value == "true" || value == "false")
1595              return (value == "true");
1596  
1597          if (strip_whitespace)
1598              value = tinyMCE.regexpReplace(value, "[ \t\r\n]", "");
1599  
1600          if (typeof(split_chr) != "undefined" && split_chr != null) {
1601              value = value.split(split_chr);
1602              var outArray = new Array();
1603  
1604              for (var i=0; i<value.length; i++) {
1605                  if (value[i] && value[i] != "")
1606                      outArray[outArray.length] = value[i];
1607              }
1608  
1609              value = outArray;
1610          }
1611  
1612          return value;
1613      },
1614  
1615      getLang : function(name, default_value, parse_entities, va) {
1616          var v = (typeof(tinyMCELang[name]) == "undefined") ? default_value : tinyMCELang[name], n;
1617  
1618          if (parse_entities)
1619              v = tinyMCE.entityDecode(v);
1620  
1621          if (va) {
1622              for (n in va)
1623                  v = this.replaceVar(v, n, va[n]);
1624          }
1625  
1626          return v;
1627      },
1628  
1629      entityDecode : function(s) {
1630          var e = document.createElement("div");
1631  
1632          e.innerHTML = s;
1633  
1634          return e.firstChild.nodeValue;
1635      },
1636  
1637      addToLang : function(prefix, ar) {
1638          for (var key in ar) {
1639              if (typeof(ar[key]) == 'function')
1640                  continue;
1641  
1642              tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = ar[key];
1643          }
1644  
1645          this.loadNextScript();
1646  
1647      //    for (var key in ar)
1648      //        tinyMCELang[(key.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix != '' ? (prefix + "_") : '') + key] = "|" + ar[key] + "|";
1649      },
1650  
1651      triggerNodeChange : function(focus, setup_content) {
1652          if (tinyMCE.selectedInstance) {
1653              var inst = tinyMCE.selectedInstance;
1654              var editorId = inst.editorId;
1655              var elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement();
1656              var undoIndex = -1, doc;
1657              var undoLevels = -1;
1658              var anySelection = false;
1659              var selectedText = inst.selection.getSelectedText();
1660  
1661              if (tinyMCE.settings.auto_resize)
1662                  inst.resizeToContent();
1663  
1664              if (setup_content && tinyMCE.isGecko && inst.isHidden())
1665                  elm = inst.getBody();
1666  
1667              inst.switchSettings();
1668  
1669              if (tinyMCE.selectedElement)
1670                  anySelection = (tinyMCE.selectedElement.nodeName.toLowerCase() == "img") || (selectedText && selectedText.length > 0);
1671  
1672              if (tinyMCE.settings['custom_undo_redo']) {
1673                  undoIndex = inst.undoRedo.undoIndex;
1674                  undoLevels = inst.undoRedo.undoLevels.length;
1675              }
1676  
1677              tinyMCE.dispatchCallback(inst, 'handle_node_change_callback', 'handleNodeChange', editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content);
1678          }
1679  
1680          if (this.selectedInstance && (typeof(focus) == "undefined" || focus))
1681              this.selectedInstance.contentWindow.focus();
1682      },
1683  
1684      _customCleanup : function(inst, type, content) {
1685          var pl, po, i;
1686  
1687          // Call custom cleanup
1688          var customCleanup = tinyMCE.settings['cleanup_callback'];
1689          if (customCleanup != "" && eval("typeof(" + customCleanup + ")") != "undefined")
1690              content = eval(customCleanup + "(type, content, inst);");
1691  
1692          // Trigger theme cleanup
1693          po = tinyMCE.themes[tinyMCE.settings['theme']];
1694          if (po && po.cleanup)
1695              content = po.cleanup(type, content, inst);
1696  
1697          // Trigger plugin cleanups
1698          pl = inst.plugins;
1699          for (i=0; i<pl.length; i++) {
1700              po = tinyMCE.plugins[pl[i]];
1701  
1702              if (po && po.cleanup)
1703                  content = po.cleanup(type, content, inst);
1704          }
1705  
1706          return content;
1707      },
1708  
1709      setContent : function(h) {
1710          if (tinyMCE.selectedInstance) {
1711              tinyMCE.selectedInstance.execCommand('mceSetContent', false, h);
1712              tinyMCE.selectedInstance.repaint();
1713          }
1714      },
1715  
1716      importThemeLanguagePack : function(name) {
1717          if (typeof(name) == "undefined")
1718              name = tinyMCE.settings['theme'];
1719  
1720          tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings['language'] + '.js');
1721      },
1722  
1723      importPluginLanguagePack : function(name) {
1724          var b = tinyMCE.baseURL + '/plugins/' + name;
1725  
1726          if (this.plugins[name])
1727              b = this.plugins[name].baseURL;
1728  
1729          tinyMCE.loadScript(b + '/langs/' + tinyMCE.settings['language'] +  '.js');
1730      },
1731  
1732      applyTemplate : function(h, as) {
1733          return h.replace(new RegExp('\\{\\$([a-z0-9_]+)\\}', 'gi'), function(m, s) {
1734              if (s.indexOf('lang_') == 0 && tinyMCELang[s])
1735                  return tinyMCELang[s];
1736  
1737              if (as && as[s])
1738                  return as[s];
1739  
1740              if (tinyMCE.settings[s])
1741                  return tinyMCE.settings[s];
1742  
1743              if (m == 'themeurl')
1744                  return tinyMCE.themeURL;
1745  
1746              return m;
1747          });
1748      },
1749  
1750      replaceVar : function(h, r, v) {
1751          return h.replace(new RegExp('{\\\$' + r + '}', 'g'), v);
1752      },
1753  
1754      openWindow : function(template, args) {
1755          var html, width, height, x, y, resizable, scrollbars, url;
1756  
1757          args['mce_template_file'] = template['file'];
1758          args['mce_width'] = template['width'];
1759          args['mce_height'] = template['height'];
1760          tinyMCE.windowArgs = args;
1761  
1762          html = template['html'];
1763          if (!(width = parseInt(template['width'])))
1764              width = 320;
1765  
1766          if (!(height = parseInt(template['height'])))
1767              height = 200;
1768  
1769          // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
1770          if (tinyMCE.isIE)
1771              height += 40;
1772          else
1773              height += 20;
1774  
1775          x = parseInt(screen.width / 2.0) - (width / 2.0);
1776          y = parseInt(screen.height / 2.0) - (height / 2.0);
1777  
1778          resizable = (args && args['resizable']) ? args['resizable'] : "no";
1779          scrollbars = (args && args['scrollbars']) ? args['scrollbars'] : "no";
1780  
1781          if (template['file'].charAt(0) != '/' && template['file'].indexOf('://') == -1)
1782              url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template['file'];
1783          else
1784              url = template['file'];
1785  
1786          // Replace all args as variables in URL
1787          for (var name in args) {
1788              if (typeof(args[name]) == 'function')
1789                  continue;
1790  
1791              url = tinyMCE.replaceVar(url, name, escape(args[name]));
1792          }
1793  
1794          if (html) {
1795              html = tinyMCE.replaceVar(html, "css", this.settings['popups_css']);
1796              html = tinyMCE.applyTemplate(html, args);
1797  
1798              var win = window.open("", "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=yes,minimizable=" + resizable + ",modal=yes,width=" + width + ",height=" + height + ",resizable=" + resizable);
1799              if (win == null) {
1800                  alert(tinyMCELang['lang_popup_blocked']);
1801                  return;
1802              }
1803  
1804              win.document.write(html);
1805              win.document.close();
1806              win.resizeTo(width, height);
1807              win.focus();
1808          } else {
1809              if ((tinyMCE.isRealIE) && resizable != 'yes' && tinyMCE.settings["dialog_type"] == "modal") {
1810                  height += 10;
1811  
1812                  var features = "resizable:" + resizable 
1813                      + ";scroll:"
1814                      + scrollbars + ";status:yes;center:yes;help:no;dialogWidth:"
1815                      + width + "px;dialogHeight:" + height + "px;";
1816  
1817                  window.showModalDialog(url, window, features);
1818              } else {
1819                  var modal = (resizable == "yes") ? "no" : "yes";
1820  
1821                  if (tinyMCE.isGecko && tinyMCE.isMac)
1822                      modal = "no";
1823  
1824                  if (template['close_previous'] != "no")
1825                      try {tinyMCE.lastWindow.close();} catch (ex) {}
1826  
1827                  var win = window.open(url, "mcePopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable);
1828                  if (win == null) {
1829                      alert(tinyMCELang['lang_popup_blocked']);
1830                      return;
1831                  }
1832  
1833                  if (template['close_previous'] != "no")
1834                      tinyMCE.lastWindow = win;
1835  
1836                  eval('try { win.resizeTo(width, height); } catch(e) { }');
1837  
1838                  // Make it bigger if statusbar is forced
1839                  if (tinyMCE.isGecko) {
1840                      if (win.document.defaultView.statusbar.visible)
1841                          win.resizeBy(0, tinyMCE.isMac ? 10 : 24);
1842                  }
1843  
1844                  win.focus();
1845              }
1846          }
1847      },
1848  
1849      closeWindow : function(win) {
1850          win.close();
1851      },
1852  
1853      getVisualAidClass : function(class_name, state) {
1854          var aidClass = tinyMCE.settings['visual_table_class'];
1855  
1856          if (typeof(state) == "undefined")
1857              state = tinyMCE.settings['visual'];
1858  
1859          // Split
1860          var classNames = new Array();
1861          var ar = class_name.split(' ');
1862          for (var i=0; i<ar.length; i++) {
1863              if (ar[i] == aidClass)
1864                  ar[i] = "";
1865  
1866              if (ar[i] != "")
1867                  classNames[classNames.length] = ar[i];
1868          }
1869  
1870          if (state)
1871              classNames[classNames.length] = aidClass;
1872  
1873          // Glue
1874          var className = "";
1875          for (var i=0; i<classNames.length; i++) {
1876              if (i > 0)
1877                  className += " ";
1878  
1879              className += classNames[i];
1880          }
1881  
1882          return className;
1883      },
1884  
1885      handleVisualAid : function(el, deep, state, inst, skip_dispatch) {
1886          if (!el)
1887              return;
1888  
1889          if (!skip_dispatch)
1890              tinyMCE.dispatchCallback(inst, 'handle_visual_aid_callback', 'handleVisualAid', el, deep, state, inst);
1891  
1892          var tableElement = null;
1893  
1894          switch (el.nodeName) {
1895              case "TABLE":
1896                  var oldW = el.style.width;
1897                  var oldH = el.style.height;
1898                  var bo = tinyMCE.getAttrib(el, "border");
1899  
1900                  bo = bo == "" || bo == "0" ? true : false;
1901  
1902                  tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo));
1903  
1904                  el.style.width = oldW;
1905                  el.style.height = oldH;
1906  
1907                  for (var y=0; y<el.rows.length; y++) {
1908                      for (var x=0; x<el.rows[y].cells.length; x++) {
1909                          var cn = tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el.rows[y].cells[x], "class"), state && bo);
1910                          tinyMCE.setAttrib(el.rows[y].cells[x], "class", cn);
1911                      }
1912                  }
1913  
1914                  break;
1915  
1916              case "A":
1917                  var anchorName = tinyMCE.getAttrib(el, "name");
1918  
1919                  if (anchorName != '' && state) {
1920                      el.title = anchorName;
1921                      tinyMCE.addCSSClass(el, 'mceItemAnchor');
1922                  } else if (anchorName != '' && !state)
1923                      el.className = '';
1924  
1925                  break;
1926          }
1927  
1928          if (deep && el.hasChildNodes()) {
1929              for (var i=0; i<el.childNodes.length; i++)
1930                  tinyMCE.handleVisualAid(el.childNodes[i], deep, state, inst, true);
1931          }
1932      },
1933  
1934      /*
1935      applyClassesToFonts : function(doc, size) {
1936          var f = doc.getElementsByTagName("font");
1937          for (var i=0; i<f.length; i++) {
1938              var s = tinyMCE.getAttrib(f[i], "size");
1939  
1940              if (s != "")
1941                  tinyMCE.setAttrib(f[i], 'class', "mceItemFont" + s);
1942          }
1943  
1944          if (typeof(size) != "undefined") {
1945              var css = "";
1946  
1947              for (var x=0; x<doc.styleSheets.length; x++) {
1948                  for (var i=0; i<doc.styleSheets[x].rules.length; i++) {
1949                      if (doc.styleSheets[x].rules[i].selectorText == '#mceSpanFonts .mceItemFont' + size) {
1950                          css = doc.styleSheets[x].rules[i].style.cssText;
1951                          break;
1952                      }
1953                  }
1954  
1955                  if (css != "")
1956                      break;
1957              }
1958  
1959              if (doc.styleSheets[0].rules[0].selectorText == "FONT")
1960                  doc.styleSheets[0].removeRule(0);
1961  
1962              doc.styleSheets[0].addRule("FONT", css, 0);
1963          }
1964      },
1965      */
1966  
1967      fixGeckoBaseHREFBug : function(m, e, h) {
1968          var xsrc, xhref;
1969  
1970          if (tinyMCE.isGecko) {
1971              if (m == 1) {
1972                  h = h.replace(/\ssrc=/gi, " mce_tsrc=");
1973                  h = h.replace(/\shref=/gi, " mce_thref=");
1974  
1975                  return h;
1976              } else {
1977                  // Why bother if there is no src or href broken
1978                  if (!new RegExp('(src|href)=', 'g').test(h))
1979                      return h;
1980  
1981                  // Restore src and href that gets messed up by Gecko
1982                  tinyMCE.selectElements(e, 'A,IMG,SELECT,AREA,IFRAME,BASE,INPUT,SCRIPT,EMBED,OBJECT,LINK', function (n) {
1983                      xsrc = tinyMCE.getAttrib(n, "mce_tsrc");
1984                      xhref = tinyMCE.getAttrib(n, "mce_thref");
1985  
1986                      if (xsrc != "") {
1987                          try {
1988                              n.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xsrc);
1989                          } catch (e) {
1990                              // Ignore, Firefox cast exception if local file wasn't found
1991                          }
1992  
1993                          n.removeAttribute("mce_tsrc");
1994                      }
1995  
1996                      if (xhref != "") {
1997                          try {
1998                              n.href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], xhref);
1999                          } catch (e) {
2000                              // Ignore, Firefox cast exception if local file wasn't found
2001                          }
2002  
2003                          n.removeAttribute("mce_thref");
2004                      }
2005  
2006                      return false;
2007                  });
2008  
2009                  // Restore text/comment nodes
2010                  tinyMCE.selectNodes(e, function(n) {
2011                      if (n.nodeType == 3 || n.nodeType == 8) {
2012                          n.nodeValue = n.nodeValue.replace(/\smce_tsrc=/gi, " src=");
2013                          n.nodeValue = n.nodeValue.replace(/\smce_thref=/gi, " href=");
2014                      }
2015  
2016                      return false;
2017                  });
2018              }
2019          }
2020  
2021          return h;
2022      },
2023  
2024      _setHTML : function(doc, html_content) {
2025          // Force closed anchors open
2026          //html_content = html_content.replace(new RegExp('<a(.*?)/>', 'gi'), '<a$1></a>');
2027  
2028          html_content = tinyMCE.cleanupHTMLCode(html_content);
2029  
2030          // Try innerHTML if it fails use pasteHTML in MSIE
2031          try {
2032              tinyMCE.setInnerHTML(doc.body, html_content);
2033          } catch (e) {
2034              if (this.isMSIE)
2035                  doc.body.createTextRange().pasteHTML(html_content);
2036          }
2037  
2038          // Content duplication bug fix
2039          if (tinyMCE.isIE && tinyMCE.settings['fix_content_duplication']) {
2040              // Remove P elements in P elements
2041              var paras = doc.getElementsByTagName("P");
2042              for (var i=0; i<paras.length; i++) {
2043                  var node = paras[i];
2044                  while ((node = node.parentNode) != null) {
2045                      if (node.nodeName == "P")
2046                          node.outerHTML = node.innerHTML;
2047                  }
2048              }
2049  
2050              // Content duplication bug fix (Seems to be word crap)
2051              var html = doc.body.innerHTML;
2052  /*
2053              if (html.indexOf('="mso') != -1) {
2054                  for (var i=0; i<doc.body.all.length; i++) {
2055                      var el = doc.body.all[i];
2056                      el.removeAttribute("className","",0);
2057                      el.removeAttribute("style","",0);
2058                  }
2059  
2060                  html = doc.body.innerHTML;
2061                  html = tinyMCE.regexpReplace(html, "<o:p><\/o:p>", "<br />");
2062                  html = tinyMCE.regexpReplace(html, "<o:p>&nbsp;<\/o:p>", "");
2063                  html = tinyMCE.regexpReplace(html, "<st1:.*?>", "");
2064                  html = tinyMCE.regexpReplace(html, "<p><\/p>", "");
2065                  html = tinyMCE.regexpReplace(html, "<p><\/p>\r\n<p><\/p>", "");
2066                  html = tinyMCE.regexpReplace(html, "<p>&nbsp;<\/p>", "<br />");
2067                  html = tinyMCE.regexpReplace(html, "<p>\s*(<p>\s*)?", "<p>");
2068                  html = tinyMCE.regexpReplace(html, "<\/p>\s*(<\/p>\s*)?", "</p>");
2069              }*/
2070  
2071              // Always set the htmlText output
2072              tinyMCE.setInnerHTML(doc.body, html);
2073          }
2074  
2075          tinyMCE.cleanupAnchors(doc);
2076  
2077          if (tinyMCE.getParam("convert_fonts_to_spans"))
2078              tinyMCE.convertSpansToFonts(doc);
2079      },
2080  
2081      getEditorId : function(form_element) {
2082          var inst = this.getInstanceById(form_element);
2083          if (!inst)
2084              return null;
2085  
2086          return inst.editorId;
2087      },
2088  
2089      getInstanceById : function(editor_id) {
2090          var inst = this.instances[editor_id];
2091          if (!inst) {
2092              for (var n in tinyMCE.instances) {
2093                  var instance = tinyMCE.instances[n];
2094                  if (!tinyMCE.isInstance(instance))
2095                      continue;
2096  
2097                  if (instance.formTargetElementId == editor_id) {
2098                      inst = instance;
2099                      break;
2100                  }
2101              }
2102          }
2103  
2104          return inst;
2105      },
2106  
2107      queryInstanceCommandValue : function(editor_id, command) {
2108          var inst = tinyMCE.getInstanceById(editor_id);
2109          if (inst)
2110              return inst.queryCommandValue(command);
2111  
2112          return false;
2113      },
2114  
2115      queryInstanceCommandState : function(editor_id, command) {
2116          var inst = tinyMCE.getInstanceById(editor_id);
2117          if (inst)
2118              return inst.queryCommandState(command);
2119  
2120          return null;
2121      },
2122  
2123      setWindowArg : function(n, v) {
2124          this.windowArgs[n] = v;
2125      },
2126  
2127      getWindowArg : function(n, d) {
2128          return (typeof(this.windowArgs[n]) == "undefined") ? d : this.windowArgs[n];
2129      },
2130  
2131      getCSSClasses : function(editor_id, doc) {
2132          var output = new Array();
2133  
2134          // Is cached, use that
2135          if (typeof(tinyMCE.cssClasses) != "undefined")
2136              return tinyMCE.cssClasses;
2137  
2138          if (typeof(editor_id) == "undefined" && typeof(doc) == "undefined") {
2139              var instance;
2140  
2141              for (var instanceName in tinyMCE.instances) {
2142                  instance = tinyMCE.instances[instanceName];
2143                  if (!tinyMCE.isInstance(instance))
2144                      continue;
2145  
2146                  break;
2147              }
2148  
2149              doc = instance.getDoc();
2150          }
2151  
2152          if (typeof(doc) == "undefined") {
2153              var instance = tinyMCE.getInstanceById(editor_id);
2154              doc = instance.getDoc();
2155          }
2156  
2157          if (doc) {
2158              var styles = doc.styleSheets;
2159  
2160              if (styles && styles.length > 0) {
2161                  for (var x=0; x<styles.length; x++) {
2162                      var csses = null;
2163  
2164                      // Just ignore any errors
2165                      eval("try {var csses = tinyMCE.isIE ? doc.styleSheets(" + x + ").rules : styles[" + x + "].cssRules;} catch(e) {}");
2166                      if (!csses)
2167                          return new Array();
2168  
2169                      for (var i=0; i<csses.length; i++) {
2170                          var selectorText = csses[i].selectorText;
2171  
2172                          // Can be multiple rules per selector
2173                          if (selectorText) {
2174                              var rules = selectorText.split(',');
2175                              for (var c=0; c<rules.length; c++) {
2176                                  var rule = rules[c];
2177  
2178                                  // Strip spaces between selectors
2179                                  while (rule.indexOf(' ') == 0)
2180                                      rule = rule.substring(1);
2181  
2182                                  // Invalid rule
2183                                  if (rule.indexOf(' ') != -1 || rule.indexOf(':') != -1 || rule.indexOf('mceItem') != -1)
2184                                      continue;
2185  
2186                                  if (rule.indexOf(tinyMCE.settings['visual_table_class']) != -1 || rule.indexOf('mceEditable') != -1 || rule.indexOf('mceNonEditable') != -1)
2187                                      continue;
2188  
2189                                  // Is class rule
2190                                  if (rule.indexOf('.') != -1) {
2191                                      var cssClass = rule.substring(rule.indexOf('.') + 1);
2192                                      var addClass = true;
2193  
2194                                      for (var p=0; p<output.length && addClass; p++) {
2195                                          if (output[p] == cssClass)
2196                                              addClass = false;
2197                                      }
2198  
2199                                      if (addClass)
2200                                          output[output.length] = cssClass;
2201                                  }
2202                              }
2203                          }
2204                      }
2205                  }
2206              }
2207          }
2208  
2209          // Cache em
2210          if (output.length > 0)
2211              tinyMCE.cssClasses = output;
2212  
2213          return output;
2214      },
2215  
2216      regexpReplace : function(in_str, reg_exp, replace_str, opts) {
2217          if (in_str == null)
2218              return in_str;
2219  
2220          if (typeof(opts) == "undefined")
2221              opts = 'g';
2222  
2223          var re = new RegExp(reg_exp, opts);
2224          return in_str.replace(re, replace_str);
2225      },
2226  
2227      trim : function(s) {
2228          return s.replace(/^\s*|\s*$/g, "");
2229      },
2230  
2231      cleanupEventStr : function(s) {
2232          s = "" + s;
2233          s = s.replace('function anonymous()\n{\n', '');
2234          s = s.replace('\n}', '');
2235          s = s.replace(/^return true;/gi, ''); // Remove event blocker
2236  
2237          return s;
2238      },
2239  
2240      getControlHTML : function(c) {
2241          var i, l, n, o, v;
2242  
2243          l = tinyMCE.plugins;
2244          for (n in l) {
2245              o = l[n];
2246  
2247              if (o.getControlHTML && (v = o.getControlHTML(c)) != '')
2248                  return tinyMCE.replaceVar(v, "pluginurl", o.baseURL);
2249          }
2250  
2251          o = tinyMCE.themes[tinyMCE.settings['theme']];
2252          if (o.getControlHTML && (v = o.getControlHTML(c)) != '')
2253              return v;
2254  
2255          return '';
2256      },
2257  
2258      evalFunc : function(f, idx, a, o) {
2259          var s = '(', i;
2260  
2261          for (i=idx; i<a.length; i++) {
2262              s += 'a[' + i + ']';
2263  
2264              if (i < a.length-1)
2265                  s += ',';
2266          }
2267  
2268          s += ');';
2269  
2270          return o ? eval("o." + f + s) : eval("f" + s);
2271      },
2272  
2273      dispatchCallback : function(i, p, n) {
2274          return this.callFunc(i, p, n, 0, this.dispatchCallback.arguments);
2275      },
2276  
2277      executeCallback : function(i, p, n) {
2278          return this.callFunc(i, p, n, 1, this.executeCallback.arguments);
2279      },
2280  
2281      execCommandCallback : function(i, p, n) {
2282          return this.callFunc(i, p, n, 2, this.execCommandCallback.arguments);
2283      },
2284  
2285      callFunc : function(ins, p, n, m, a) {
2286          var l, i, on, o, s, v;
2287  
2288          s = m == 2;
2289  
2290          l = tinyMCE.getParam(p, '');
2291  
2292          if (l != '' && (v = tinyMCE.evalFunc(typeof(l) == "function" ? l : eval(l), 3, a)) == s && m > 0)
2293              return true;
2294  
2295          if (ins != null) {
2296              for (i=0, l = ins.plugins; i<l.length; i++) {
2297                  o = tinyMCE.plugins[l[i]];
2298  
2299                  if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
2300                      return true;
2301              }
2302          }
2303  
2304          l = tinyMCE.themes;
2305          for (on in l) {
2306              o = l[on];
2307  
2308              if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0)
2309                  return true;
2310          }
2311  
2312          return false;
2313      },
2314  
2315      xmlEncode : function(s) {
2316          return s ? ('' + s).replace(new RegExp('[<>&"\']', 'g'), function (c, b) {
2317              switch (c) {
2318                  case '&':
2319                      return '&amp;';
2320  
2321                  case '"':
2322                      return '&quot;';
2323  
2324                  case '\'':
2325                      return '&#39;'; // &apos; is not working in MSIE
2326  
2327                  case '<':
2328                      return '&lt;';
2329  
2330                  case '>':
2331                      return '&gt;';
2332              }
2333  
2334              return c;
2335          }) : s;
2336      },
2337  
2338      extend : function(p, np) {
2339          var o = {};
2340  
2341          o.parent = p;
2342  
2343          for (n in p)
2344              o[n] = p[n];
2345  
2346          for (n in np)
2347              o[n] = np[n];
2348  
2349          return o;
2350      },
2351  
2352      hideMenus : function() {
2353          var e = tinyMCE.lastSelectedMenuBtn;
2354  
2355          if (tinyMCE.lastMenu) {
2356              tinyMCE.lastMenu.hide();
2357              tinyMCE.lastMenu = null;
2358          }
2359  
2360          if (e) {
2361              tinyMCE.switchClass(e, tinyMCE.lastMenuBtnClass);
2362              tinyMCE.lastSelectedMenuBtn = null;
2363          }
2364      }
2365  
2366      };
2367  
2368  // Global instances
2369  var TinyMCE = TinyMCE_Engine; // Compatiblity with gzip compressors
2370  var tinyMCE = new TinyMCE_Engine();
2371  var tinyMCELang = {};
2372  
2373  /* file:jscripts/tiny_mce/classes/TinyMCE_Control.class.js */
2374  
2375  function TinyMCE_Control(settings) {
2376      var t, i, to, fu, p, x, fn, fu, pn, s = settings;
2377  
2378      this.undoRedoLevel = true;
2379      this.isTinyMCE_Control = true;
2380  
2381      // Default settings
2382      this.settings = s;
2383      this.settings['theme'] = tinyMCE.getParam("theme", "default");
2384      this.settings['width'] = tinyMCE.getParam("width", -1);
2385      this.settings['height'] = tinyMCE.getParam("height", -1);
2386      this.selection = new TinyMCE_Selection(this);
2387      this.undoRedo = new TinyMCE_UndoRedo(this);
2388      this.cleanup = new TinyMCE_Cleanup();
2389      this.shortcuts = new Array();
2390      this.hasMouseMoved = false;
2391      this.foreColor = this.backColor = "#999999";
2392      this.data = {};
2393  
2394      this.cleanup.init({
2395          valid_elements : s.valid_elements,
2396          extended_valid_elements : s.extended_valid_elements,
2397          valid_child_elements : s.valid_child_elements,
2398          entities : s.entities,
2399          entity_encoding : s.entity_encoding,
2400          debug : s.cleanup_debug,
2401          url_converter : 'TinyMCE_Cleanup.prototype._urlConverter',
2402          indent : s.apply_source_formatting,
2403          invalid_elements : s.invalid_elements,
2404          verify_html : s.verify_html,
2405          fix_content_duplication : s.fix_content_duplication
2406      });
2407  
2408      // Wrap old theme
2409      t = this.settings['theme'];
2410      if (!tinyMCE.hasTheme(t)) {
2411          fn = tinyMCE.callbacks;
2412          to = {};
2413  
2414          for (i=0; i<fn.length; i++) {
2415              if ((fu = window['TinyMCE_' + t + "_" + fn[i]]))
2416                  to[fn[i]] = fu;
2417          }
2418  
2419          tinyMCE.addTheme(t, to);
2420      }
2421  
2422      // Wrap old plugins
2423      this.plugins = new Array();
2424      p = tinyMCE.getParam('plugins', '', true, ',');
2425      if (p.length > 0) {
2426          for (i=0; i<p.length; i++) {
2427              pn = p[i];
2428  
2429              if (pn.charAt(0) == '-')
2430                  pn = pn.substring(1);
2431  
2432              if (!tinyMCE.hasPlugin(pn)) {
2433                  fn = tinyMCE.callbacks;
2434                  to = {};
2435  
2436                  for (x=0; x<fn.length; x++) {
2437                      if ((fu = window['TinyMCE_' + pn + "_" + fn[x]]))
2438                          to[fn[x]] = fu;
2439                  }
2440  
2441                  tinyMCE.addPlugin(pn, to);
2442              }
2443  
2444              this.plugins[this.plugins.length] = pn; 
2445          }
2446      }
2447  };
2448  
2449  TinyMCE_Control.prototype = {
2450      selection : null,
2451  
2452      settings : null,
2453  
2454      cleanup : null,
2455  
2456      getData : function(na) {
2457          var o = this.data[na];
2458  
2459          if (!o)
2460              o = this.data[na] = {};
2461  
2462          return o;
2463      },
2464  
2465      hasPlugin : function(n) {
2466          var i;
2467  
2468          for (i=0; i<this.plugins.length; i++) {
2469              if (this.plugins[i] == n)
2470                  return true;
2471          }
2472  
2473          return false;
2474      },
2475  
2476      addPlugin : function(n, p) {
2477          if (!this.hasPlugin(n)) {
2478              tinyMCE.addPlugin(n, p);
2479              this.plugins[this.plugins.length] = n;
2480          }
2481      },
2482  
2483      repaint : function() {
2484          var s, b, ex;
2485  
2486          if (tinyMCE.isRealIE)
2487              return;
2488  
2489          try {
2490              s = this.selection;
2491              b = s.getBookmark(true);
2492              this.getBody().style.display = 'none';
2493              this.getDoc().execCommand('selectall', false, null);
2494              this.getSel().collapseToStart();
2495              this.getBody().style.display = 'block';
2496              s.moveToBookmark(b);
2497          } catch (ex) {
2498              // Ignore
2499          }
2500      },
2501  
2502      switchSettings : function() {
2503          if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings['index']) {
2504              tinyMCE.settings = this.settings;
2505              tinyMCE.currentConfig = this.settings['index'];
2506          }
2507      },
2508  
2509      select : function() {
2510          var oldInst = tinyMCE.selectedInstance;
2511  
2512          if (oldInst != this) {
2513              if (oldInst)
2514                  oldInst.execCommand('mceEndTyping');
2515  
2516              tinyMCE.dispatchCallback(this, 'select_instance_callback', 'selectInstance', this, oldInst);
2517              tinyMCE.selectedInstance = this;
2518          }
2519      },
2520  
2521      getBody : function() {
2522          return this.contentBody ? this.contentBody : this.getDoc().body;
2523      },
2524  
2525      getDoc : function() {
2526  //        return this.contentDocument ? this.contentDocument : this.contentWindow.document; // Removed due to IE 5.5 ?
2527          return this.contentWindow.document;
2528      },
2529  
2530      getWin : function() {
2531          return this.contentWindow;
2532      },
2533  
2534      getContainerWin : function() {
2535          return this.containerWindow ? this.containerWindow : window;
2536      },
2537  
2538      getViewPort : function() {
2539          return tinyMCE.getViewPort(this.getWin());
2540      },
2541  
2542      getParentNode : function(n, f) {
2543          return tinyMCE.getParentNode(n, f, this.getBody());
2544      },
2545  
2546      getParentElement : function(n, na, f) {
2547          return tinyMCE.getParentElement(n, na, f, this.getBody());
2548      },
2549  
2550      getParentBlockElement : function(n) {
2551          return tinyMCE.getParentBlockElement(n, this.getBody());
2552      },
2553  
2554      resizeToContent : function() {
2555          var d = this.getDoc(), b = d.body, de = d.documentElement;
2556  
2557          this.iframeElement.style.height = (tinyMCE.isRealIE) ? b.scrollHeight : de.offsetHeight + 'px';
2558      },
2559  
2560      addShortcut : function(m, k, d, cmd, ui, va) {
2561          var n = typeof(k) == "number", ie = tinyMCE.isIE, c, sc, i, scl = this.shortcuts;
2562  
2563          if (!tinyMCE.getParam('custom_shortcuts'))
2564              return false;
2565  
2566          m = m.toLowerCase();
2567          k = ie && !n ? k.toUpperCase() : k;
2568          c = n ? null : k.charCodeAt(0);
2569          d = d && d.indexOf('lang_') == 0 ? tinyMCE.getLang(d) : d;
2570  
2571          sc = {
2572              alt : m.indexOf('alt') != -1,
2573              ctrl : m.indexOf('ctrl') != -1,
2574              shift : m.indexOf('shift') != -1,
2575              charCode : c,
2576              keyCode : n ? k : (ie ? c : null),
2577              desc : d,
2578              cmd : cmd,
2579              ui : ui,
2580              val : va
2581          };
2582  
2583          for (i=0; i<scl.length; i++) {
2584              if (sc.alt == scl[i].alt && sc.ctrl == scl[i].ctrl && sc.shift == scl[i].shift
2585                  && sc.charCode == scl[i].charCode && sc.keyCode == scl[i].keyCode) {
2586                  return false;
2587              }
2588          }
2589  
2590          scl[scl.length] = sc;
2591  
2592          return true;
2593      },
2594  
2595      handleShortcut : function(e) {
2596          var i, s = this.shortcuts, o;
2597  
2598          for (i=0; i<s.length; i++) {
2599              o = s[i];
2600  
2601              if (o.alt == e.altKey && o.ctrl == e.ctrlKey && (o.keyCode == e.keyCode || o.charCode == e.charCode)) {
2602                  if (o.cmd && (e.type == "keydown" || (e.type == "keypress" && !tinyMCE.isOpera)))
2603                      tinyMCE.execCommand(o.cmd, o.ui, o.val);
2604  
2605                  tinyMCE.cancelEvent(e);
2606                  return true;
2607              }
2608          }
2609  
2610          return false;
2611      },
2612  
2613      autoResetDesignMode : function() {
2614          // Add fix for tab/style.display none/block problems in Gecko
2615          if (!tinyMCE.isIE && this.isHidden() && tinyMCE.getParam('auto_reset_designmode'))
2616              eval('try { this.getDoc().designMode = "On"; this.useCSS = false; } catch(e) {}');
2617      },
2618  
2619      isHidden : function() {
2620          var s;
2621  
2622          if (tinyMCE.isIE)
2623              return false;
2624  
2625          s = this.getSel();
2626  
2627          // Weird, wheres that cursor selection?
2628          return (!s || !s.rangeCount || s.rangeCount == 0);
2629      },
2630  
2631      isDirty : function() {
2632          // Is content modified and not in a submit procedure
2633          return tinyMCE.trim(this.startContent) != tinyMCE.trim(this.getBody().innerHTML) && !tinyMCE.isNotDirty;
2634      },
2635  
2636      _mergeElements : function(scmd, pa, ch, override) {
2637          if (scmd == "removeformat") {
2638              pa.className = "";
2639              pa.style.cssText = "";
2640              ch.className = "";
2641              ch.style.cssText = "";
2642              return;
2643          }
2644  
2645          var st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style"));
2646          var stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style"));
2647          var className = tinyMCE.getAttrib(pa, "class");
2648  
2649          // Removed class adding due to bug #1478272
2650          className = tinyMCE.getAttrib(ch, "class");
2651  
2652          if (override) {
2653              for (var n in st) {
2654                  if (typeof(st[n]) == 'function')
2655                      continue;
2656  
2657                  stc[n] = st[n];
2658              }
2659          } else {
2660              for (var n in stc) {
2661                  if (typeof(stc[n]) == 'function')
2662                      continue;
2663  
2664                  st[n] = stc[n];
2665              }
2666          }
2667  
2668          tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st));
2669          tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className));
2670          ch.className = "";
2671          ch.style.cssText = "";
2672          ch.removeAttribute("class");
2673          ch.removeAttribute("style");
2674      },
2675  
2676      _setUseCSS : function(b) {
2677          var d = this.getDoc();
2678  
2679          try {d.execCommand("useCSS", false, !b);} catch (ex) {}
2680          try {d.execCommand("styleWithCSS", false, b);} catch (ex) {}
2681  
2682          if (!tinyMCE.getParam("table_inline_editing"))
2683              try {d.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {}
2684  
2685          if (!tinyMCE.getParam("object_resizing"))
2686              try {d.execCommand('enableObjectResizing', false, "false");} catch (ex) {}
2687      },
2688  
2689      execCommand : function(command, user_interface, value) {
2690          var doc = this.getDoc(), win = this.getWin(), focusElm = this.getFocusElement();
2691  
2692          // Is not a undo specific command
2693          if (!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command))
2694              this.undoBookmark = null;
2695  
2696          // Mozilla issue
2697          if (!tinyMCE.isIE && !this.useCSS) {
2698              this._setUseCSS(false);
2699              this.useCSS = true;
2700          }
2701  
2702          //debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value);
2703          this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks
2704  
2705          if (tinyMCE.execCommandCallback(this, 'execcommand_callback', 'execCommand', this.editorId, this.getBody(), command, user_interface, value))
2706              return;
2707  
2708          // Fix align on images
2709          if (focusElm && focusElm.nodeName == "IMG") {
2710              var align = focusElm.getAttribute('align');
2711              var img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm;
2712  
2713              switch (command) {
2714                  case "JustifyLeft":
2715                      if (align == 'left')
2716                          img.removeAttribute('align');
2717                      else
2718                          img.setAttribute('align', 'left');
2719  
2720                      // Remove the div
2721                      var div = focusElm.parentNode;
2722                      if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
2723                          div.parentNode.replaceChild(img, div);
2724  
2725                      this.selection.selectNode(img);
2726                      this.repaint();
2727                      tinyMCE.triggerNodeChange();
2728                      return;
2729  
2730                  case "JustifyCenter":
2731                      img.removeAttribute('align');
2732  
2733                      // Is centered
2734                      var div = tinyMCE.getParentElement(focusElm, "div");
2735                      if (div && div.style.textAlign == "center") {
2736                          // Remove div
2737                          if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
2738                              div.parentNode.replaceChild(img, div);
2739                      } else {
2740                          // Add div
2741                          var div = this.getDoc().createElement("div");
2742                          div.style.textAlign = 'center';
2743                          div.appendChild(img);
2744                          focusElm.parentNode.replaceChild(div, focusElm);
2745                      }
2746  
2747                      this.selection.selectNode(img);
2748                      this.repaint();
2749                      tinyMCE.triggerNodeChange();
2750                      return;
2751  
2752                  case "JustifyRight":
2753                      if (align == 'right')
2754                          img.removeAttribute('align');
2755                      else
2756                          img.setAttribute('align', 'right');
2757  
2758                      // Remove the div
2759                      var div = focusElm.parentNode;
2760                      if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode)
2761                          div.parentNode.replaceChild(img, div);
2762  
2763                      this.selection.selectNode(img);
2764                      this.repaint();
2765                      tinyMCE.triggerNodeChange();
2766                      return;
2767              }
2768          }
2769  
2770          if (tinyMCE.settings['force_br_newlines']) {
2771              var alignValue = "";
2772  
2773              if (doc.selection.type != "Control") {
2774                  switch (command) {
2775                          case "JustifyLeft":
2776                              alignValue = "left";
2777                              break;
2778  
2779                          case "JustifyCenter":
2780                              alignValue = "center";
2781                              break;
2782  
2783                          case "JustifyFull":
2784                              alignValue = "justify";
2785                              break;
2786  
2787                          case "JustifyRight":
2788                              alignValue = "right";
2789                              break;
2790                  }
2791  
2792                  if (alignValue != "") {
2793                      var rng = doc.selection.createRange();
2794  
2795                      if ((divElm = tinyMCE.getParentElement(rng.parentElement(), "div")) != null)
2796                          divElm.setAttribute("align", alignValue);
2797                      else if (rng.pasteHTML && rng.htmlText.length > 0)
2798                          rng.pasteHTML('<div align="' + alignValue + '">' + rng.htmlText + "</div>");
2799  
2800                      tinyMCE.triggerNodeChange();
2801                      return;
2802                  }
2803              }
2804          }
2805  
2806          switch (command) {
2807              case "mceRepaint":
2808                  this.repaint();
2809                  return true;
2810  
2811              case "unlink":
2812                  // Unlink if caret is inside link
2813                  if (tinyMCE.isGecko && this.getSel().isCollapsed) {
2814                      focusElm = tinyMCE.getParentElement(focusElm, 'A');
2815  
2816                      if (focusElm && this.getRng(0).endOffset > 0 && this.getRng(0).endOffset != focusElm.innerHTML.length)
2817                          this.selection.selectNode(focusElm, false);
2818                  }
2819  
2820                  this.getDoc().execCommand(command, user_interface, value);
2821  
2822                  tinyMCE.isGecko && this.getSel().collapseToEnd();
2823  
2824                  tinyMCE.triggerNodeChange();
2825  
2826                  return true;
2827  
2828              case "FormatBlock":
2829                  if (!this.cleanup.isValid(value))
2830                      return true;
2831  
2832                  this.getDoc().execCommand(command, user_interface, value);
2833                  tinyMCE.triggerNodeChange();
2834                  break;
2835  
2836              case "InsertUnorderedList":
2837              case "InsertOrderedList":
2838                  this.getDoc().execCommand(command, user_interface, value);
2839                  tinyMCE.triggerNodeChange();
2840                  break;
2841  
2842              case "Strikethrough":
2843                  this.getDoc().execCommand(command, user_interface, value);
2844                  tinyMCE.triggerNodeChange();
2845                  break;
2846  
2847              case "mceSelectNode":
2848                  this.selection.selectNode(value);
2849                  tinyMCE.triggerNodeChange();
2850                  tinyMCE.selectedNode = value;
2851                  break;
2852  
2853              case "FormatBlock":
2854                  if (value == null || value == "") {
2855                      var elm = tinyMCE.getParentElement(this.getFocusElement(), "p,div,h1,h2,h3,h4,h5,h6,pre,address,blockquote,dt,dl,dd,samp");
2856  
2857                      if (elm)
2858                          this.execCommand("mceRemoveNode", false, elm);
2859                  } else {
2860                      if (tinyMCE.isGecko && new RegExp('<(div|blockquote|code|dt|dd|dl|samp)>', 'gi').test(value))
2861                          value = value.replace(/[^a-z]/gi, '');
2862  
2863                      if (tinyMCE.isIE && new RegExp('blockquote|code|samp', 'gi').test(value)) {
2864                          var b = this.selection.getBookmark();
2865                          this.getDoc().execCommand("FormatBlock", false, '<p>');
2866                          tinyMCE.renameElement(tinyMCE.getParentBlockElement(this.getFocusElement()), value);
2867                          this.selection.moveToBookmark(b);
2868                      } else
2869                          this.getDoc().execCommand("FormatBlock", false, value);
2870                  }
2871  
2872                  tinyMCE.triggerNodeChange();
2873  
2874                  break;
2875  
2876              case "mceRemoveNode":
2877                  if (!value)
2878                      value = tinyMCE.getParentElement(this.getFocusElement());
2879  
2880                  if (tinyMCE.isIE) {
2881                      value.outerHTML = value.innerHTML;
2882                  } else {
2883                      var rng = value.ownerDocument.createRange();
2884                      rng.setStartBefore(value);
2885                      rng.setEndAfter(value);
2886                      rng.deleteContents();
2887                      rng.insertNode(rng.createContextualFragment(value.innerHTML));
2888                  }
2889  
2890                  tinyMCE.triggerNodeChange();
2891  
2892                  break;
2893  
2894              case "mceSelectNodeDepth":
2895                  var parentNode = this.getFocusElement();
2896                  for (var i=0; parentNode; i++) {
2897                      if (parentNode.nodeName.toLowerCase() == "body")
2898                          break;
2899  
2900                      if (parentNode.nodeName.toLowerCase() == "#text") {
2901                          i--;
2902                          parentNode = parentNode.parentNode;
2903                          continue;
2904                      }
2905  
2906                      if (i == value) {
2907                          this.selection.selectNode(parentNode, false);
2908                          tinyMCE.triggerNodeChange();
2909                          tinyMCE.selectedNode = parentNode;
2910                          return;
2911                      }
2912  
2913                      parentNode = parentNode.parentNode;
2914                  }
2915  
2916                  break;
2917  
2918              case "SetStyleInfo":
2919                  var rng = this.getRng();
2920                  var sel = this.getSel();
2921                  var scmd = value['command'];
2922                  var sname = value['name'];
2923                  var svalue = value['value'] == null ? '' : value['value'];
2924                  //var svalue = value['value'] == null ? '' : value['value'];
2925                  var wrapper = value['wrapper'] ? value['wrapper'] : "span";
2926                  var parentElm = null;
2927                  var invalidRe = new RegExp("^BODY|HTML$", "g");
2928                  var invalidParentsRe = tinyMCE.settings['merge_styles_invalid_parents'] != '' ? new RegExp(tinyMCE.settings['merge_styles_invalid_parents'], "gi") : null;
2929  
2930                  // Whole element selected check
2931                  if (tinyMCE.isIE) {
2932                      // Control range
2933                      if (rng.item)
2934                          parentElm = rng.item(0);
2935                      else {
2936                          var pelm = rng.parentElement();
2937                          var prng = doc.selection.createRange();
2938                          prng.moveToElementText(pelm);
2939  
2940                          if (rng.htmlText == prng.htmlText || rng.boundingWidth == 0) {
2941                              if (invalidParentsRe == null || !invalidParentsRe.test(pelm.nodeName))
2942                                  parentElm = pelm;
2943                          }
2944                      }
2945                  } else {
2946                      var felm = this.getFocusElement();
2947                      if (sel.isCollapsed || (new RegExp('td|tr|tbody|table', 'gi').test(felm.nodeName) && sel.anchorNode == felm.parentNode))
2948                          parentElm = felm;
2949                  }
2950  
2951                  // Whole element selected
2952                  if (parentElm && !invalidRe.test(parentElm.nodeName)) {
2953                      if (scmd == "setstyle")
2954                          tinyMCE.setStyleAttrib(parentElm, sname, svalue);
2955  
2956                      if (scmd == "setattrib")
2957                          tinyMCE.setAttrib(parentElm, sname, svalue);
2958  
2959                      if (scmd == "removeformat") {
2960                          parentElm.style.cssText = '';
2961                          tinyMCE.setAttrib(parentElm, 'class', '');
2962                      }
2963  
2964                      // Remove style/attribs from all children
2965                      var ch = tinyMCE.getNodeTree(parentElm, new Array(), 1);
2966                      for (var z=0; z<ch.length; z++) {
2967                          if (ch[z] == parentElm)
2968                              continue;
2969  
2970                          if (scmd == "setstyle")
2971                              tinyMCE.setStyleAttrib(ch[z], sname, '');
2972  
2973                          if (scmd == "setattrib")
2974                              tinyMCE.setAttrib(ch[z], sname, '');
2975  
2976                          if (scmd == "removeformat") {
2977                              ch[z].style.cssText = '';
2978                              tinyMCE.setAttrib(ch[z], 'class', '');
2979                          }
2980                      }
2981                  } else {
2982                      this._setUseCSS(false); // Bug in FF when running in fullscreen
2983                      doc.execCommand("FontName", false, "#mce_temp_font#");
2984                      var elementArray = tinyMCE.getElementsByAttributeValue(this.getBody(), "font", "face", "#mce_temp_font#");
2985  
2986                      // Change them all
2987                      for (var x=0; x<elementArray.length; x++) {
2988                          elm = elementArray[x];
2989                          if (elm) {
2990                              var spanElm = doc.createElement(wrapper);
2991  
2992                              if (scmd == "setstyle")
2993                                  tinyMCE.setStyleAttrib(spanElm, sname, svalue);
2994  
2995                              if (scmd == "setattrib")
2996                                  tinyMCE.setAttrib(spanElm, sname, svalue);
2997  
2998                              if (scmd == "removeformat") {
2999                                  spanElm.style.cssText = '';
3000                                  tinyMCE.setAttrib(spanElm, 'class', '');
3001                              }
3002  
3003                              if (elm.hasChildNodes()) {
3004                                  for (var i=0; i<elm.childNodes.length; i++)
3005                                      spanElm.appendChild(elm.childNodes[i].cloneNode(true));
3006                              }
3007  
3008                              spanElm.setAttribute("mce_new", "true");
3009                              elm.parentNode.replaceChild(spanElm, elm);
3010  
3011                              // Remove style/attribs from all children
3012                              var ch = tinyMCE.getNodeTree(spanElm, new Array(), 1);
3013                              for (var z=0; z<ch.length; z++) {
3014                                  if (ch[z] == spanElm)
3015                                      continue;
3016  
3017                                  if (scmd == "setstyle")
3018                                      tinyMCE.setStyleAttrib(ch[z], sname, '');
3019  
3020                                  if (scmd == "setattrib")
3021                                      tinyMCE.setAttrib(ch[z], sname, '');
3022  
3023                                  if (scmd == "removeformat") {
3024                                      ch[z].style.cssText = '';
3025                                      tinyMCE.setAttrib(ch[z], 'class', '');
3026                                  }
3027                              }
3028                          }
3029                      }
3030                  }
3031  
3032                  // Cleaup wrappers
3033                  var nodes = doc.getElementsByTagName(wrapper);
3034                  for (var i=nodes.length-1; i>=0; i--) {
3035                      var elm = nodes[i];
3036                      var isNew = tinyMCE.getAttrib(elm, "mce_new") == "true";
3037  
3038                      elm.removeAttribute("mce_new");
3039  
3040                      // Is only child a element
3041                      if (elm.childNodes && elm.childNodes.length == 1 && elm.childNodes[0].nodeType == 1) {
3042                          //tinyMCE.debug("merge1" + isNew);
3043                          this._mergeElements(scmd, elm, elm.childNodes[0], isNew);
3044                          continue;
3045                      }
3046  
3047                      // Is I the only child
3048                      if (elm.parentNode.childNodes.length == 1 && !invalidRe.test(elm.nodeName) && !invalidRe.test(elm.parentNode.nodeName)) {
3049                          //tinyMCE.debug("merge2" + isNew + "," + elm.nodeName + "," + elm.parentNode.nodeName);
3050                          if (invalidParentsRe == null || !invalidParentsRe.test(elm.parentNode.nodeName))
3051                              this._mergeElements(scmd, elm.parentNode, elm, false);
3052                      }
3053                  }
3054  
3055                  // Remove empty wrappers
3056                  var nodes = doc.getElementsByTagName(wrapper);
3057                  for (var i=nodes.length-1; i>=0; i--) {
3058                      var elm = nodes[i];
3059                      var isEmpty = true;
3060  
3061                      // Check if it has any attribs
3062                      var tmp = doc.createElement("body");
3063                      tmp.appendChild(elm.cloneNode(false));
3064  
3065                      // Is empty span, remove it
3066                      tmp.innerHTML = tmp.innerHTML.replace(new RegExp('style=""|class=""', 'gi'), '');
3067                      //tinyMCE.debug(tmp.innerHTML);
3068                      if (new RegExp('<span>', 'gi').test(tmp.innerHTML)) {
3069                          for (var x=0; x<elm.childNodes.length; x++) {
3070                              if (elm.parentNode != null)
3071                                  elm.parentNode.insertBefore(elm.childNodes[x].cloneNode(true), elm);
3072                          }
3073  
3074                          elm.parentNode.removeChild(elm);
3075                      }
3076                  }
3077  
3078                  // Re add the visual aids
3079                  if (scmd == "removeformat")
3080                      tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
3081  
3082                  tinyMCE.triggerNodeChange();
3083  
3084                  break;
3085  
3086              case "FontName":
3087                  if (value == null) {
3088                      var s = this.getSel();
3089  
3090                      // Find font and select it
3091                      if (tinyMCE.isGecko && s.isCollapsed) {
3092                          var f = tinyMCE.getParentElement(this.getFocusElement(), "font");
3093  
3094                          if (f != null)
3095                              this.selection.selectNode(f, false);
3096                      }
3097  
3098                      // Remove format
3099                      this.getDoc().execCommand("RemoveFormat", false, null);
3100  
3101                      // Collapse range if font was found
3102                      if (f != null && tinyMCE.isGecko) {
3103                          var r = this.getRng().cloneRange();
3104                          r.collapse(true);
3105                          s.removeAllRanges();
3106                          s.addRange(r);
3107                      }
3108                  } else
3109                      this.getDoc().execCommand('FontName', false, value);
3110  
3111                  if (tinyMCE.isGecko)
3112                      window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
3113  
3114                  return;
3115  
3116              case "FontSize":
3117                  this.getDoc().execCommand('FontSize', false, value);
3118  
3119                  if (tinyMCE.isGecko)
3120                      window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
3121  
3122                  return;
3123  
3124              case "forecolor":
3125                  value = value == null ? this.foreColor : value;
3126                  value = tinyMCE.trim(value);
3127                  value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
3128  
3129                  this.foreColor = value;
3130                  this.getDoc().execCommand('forecolor', false, value);
3131                  break;
3132  
3133              case "HiliteColor":
3134                  value = value == null ? this.backColor : value;
3135                  value = tinyMCE.trim(value);
3136                  value = value.charAt(0) != '#' ? (isNaN('0x' + value) ? value : '#' + value) : value;
3137                  this.backColor = value;
3138  
3139                  if (tinyMCE.isGecko) {
3140                      this._setUseCSS(true);
3141                      this.getDoc().execCommand('hilitecolor', false, value);
3142                      this._setUseCSS(false);
3143                  } else
3144                      this.getDoc().execCommand('BackColor', false, value);
3145                  break;
3146  
3147              case "Cut":
3148              case "Copy":
3149              case "Paste":
3150                  var cmdFailed = false;
3151  
3152                  // Try executing command
3153                  eval('try {this.getDoc().execCommand(command, user_interface, value);} catch (e) {cmdFailed = true;}');
3154  
3155                  if (tinyMCE.isOpera && cmdFailed)
3156                      alert('Currently not supported by your browser, use keyboard shortcuts instead.');
3157  
3158                  // Alert error in gecko if command failed
3159                  if (tinyMCE.isGecko && cmdFailed) {
3160                      // Confirm more info
3161                      if (confirm(tinyMCE.entityDecode(tinyMCE.getLang('lang_clipboard_msg'))))
3162                          window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal');
3163  
3164                      return;
3165                  } else
3166                      tinyMCE.triggerNodeChange();
3167              break;
3168  
3169              case "mceSetContent":
3170                  if (!value)
3171                      value = "";
3172  
3173                  // Call custom cleanup code
3174                  value = tinyMCE.storeAwayURLs(value);
3175                  value = tinyMCE._customCleanup(this, "insert_to_editor", value);
3176  
3177                  if (this.getBody().nodeName == 'BODY')
3178                      tinyMCE._setHTML(doc, value);
3179                  else
3180                      this.getBody().innerHTML = value;
3181  
3182                  tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, doc, this.settings, this.getBody(), false, false, false, true));
3183                  tinyMCE.convertAllRelativeURLs(this.getBody());
3184  
3185                  // Cleanup any mess left from storyAwayURLs
3186                  tinyMCE._removeInternal(this.getBody());
3187  
3188                  // When editing always use fonts internaly
3189                  if (tinyMCE.getParam("convert_fonts_to_spans"))
3190                      tinyMCE.convertSpansToFonts(doc);
3191  
3192                  tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
3193                  tinyMCE._setEventsEnabled(this.getBody(), false);
3194                  return true;
3195  
3196              case "mceCleanup":
3197                  var b = this.selection.getBookmark();
3198                  tinyMCE._setHTML(this.contentDocument, this.getBody().innerHTML);
3199                  tinyMCE.setInnerHTML(this.getBody(), tinyMCE._cleanupHTML(this, this.contentDocument, this.settings, this.getBody(), this.visualAid));
3200                  tinyMCE.convertAllRelativeURLs(doc.body);
3201  
3202                  // When editing always use fonts internaly
3203                  if (tinyMCE.getParam("convert_fonts_to_spans"))
3204                      tinyMCE.convertSpansToFonts(doc);
3205  
3206                  tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
3207                  tinyMCE._setEventsEnabled(this.getBody(), false);
3208                  this.repaint();
3209                  this.selection.moveToBookmark(b);
3210                  tinyMCE.triggerNodeChange();
3211              break;
3212  
3213              case "mceReplaceContent":
3214                  // Force empty string
3215                  if (!value)
3216                      value = '';
3217  
3218                  this.getWin().focus();
3219  
3220                  var selectedText = "";
3221  
3222                  if (tinyMCE.isIE) {
3223                      var rng = doc.selection.createRange();
3224                      selectedText = rng.text;
3225                  } else
3226                      selectedText = this.getSel().toString();
3227  
3228                  if (selectedText.length > 0) {
3229                      value = tinyMCE.replaceVar(value, "selection", selectedText);
3230                      tinyMCE.execCommand('mceInsertContent', false, value);
3231                  }
3232  
3233                  tinyMCE.triggerNodeChange();
3234              break;
3235  
3236              case "mceSetAttribute":
3237                  if (typeof(value) == 'object') {
3238                      var targetElms = (typeof(value['targets']) == "undefined") ? "p,img,span,div,td,h1,h2,h3,h4,h5,h6,pre,address" : value['targets'];
3239                      var targetNode = tinyMCE.getParentElement(this.getFocusElement(), targetElms);
3240  
3241                      if (targetNode) {
3242                          targetNode.setAttribute(value['name'], value['value']);
3243                          tinyMCE.triggerNodeChange();
3244                      }
3245                  }
3246              break;
3247  
3248              case "mceSetCSSClass":
3249                  this.execCommand("SetStyleInfo", false, {command : "setattrib", name : "class", value : value});
3250              break;
3251  
3252              case "mceInsertRawHTML":
3253                  var key = 'tiny_mce_marker';
3254  
3255                  this.execCommand('mceBeginUndoLevel');
3256  
3257                  // Insert marker key
3258                  this.execCommand('mceInsertContent', false, key);
3259  
3260                  // Store away scroll pos
3261                  var scrollX = this.getBody().scrollLeft + this.getDoc().documentElement.scrollLeft;
3262                  var scrollY = this.getBody().scrollTop + this.getDoc().documentElement.scrollTop;
3263  
3264                  // Find marker and replace with RAW HTML
3265                  var html = this.getBody().innerHTML;
3266                  if ((pos = html.indexOf(key)) != -1)
3267                      tinyMCE.setInnerHTML(this.getBody(), html.substring(0, pos) + value + html.substring(pos + key.length));
3268  
3269                  // Restore scoll pos
3270                  this.contentWindow.scrollTo(scrollX, scrollY);
3271  
3272                  this.execCommand('mceEndUndoLevel');
3273  
3274                  break;
3275  
3276              case "mceInsertContent":
3277                  // Force empty string
3278                  if (!value)
3279                      value = '';
3280  
3281                  var insertHTMLFailed = false;
3282  
3283                  // Removed since it produced problems in IE
3284                  // this.getWin().focus();
3285  
3286                  if (tinyMCE.isGecko || tinyMCE.isOpera) {
3287                      try {
3288                          // Is plain text or HTML, &amp;, &nbsp; etc will be encoded wrong in FF
3289                          if (value.indexOf('<') == -1 && !value.match(/(&#38;|&#160;|&#60;|&#62;)/g)) {
3290                              var r = this.getRng();
3291                              var n = this.getDoc().createTextNode(tinyMCE.entityDecode(value));
3292                              var s = this.getSel();
3293                              var r2 = r.cloneRange();
3294  
3295                              // Insert text at cursor position
3296                              s.removeAllRanges();
3297                              r.deleteContents();
3298                              r.insertNode(n);
3299  
3300                              // Move the cursor to the end of text
3301                              r2.selectNode(n);
3302                              r2.collapse(false);
3303                              s.removeAllRanges();
3304                              s.addRange(r2);
3305                          } else {
3306                              value = tinyMCE.fixGeckoBaseHREFBug(1, this.getDoc(), value);
3307                              this.getDoc().execCommand('inserthtml', false, value);
3308                              tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
3309                          }
3310                      } catch (ex) {
3311                          insertHTMLFailed = true;
3312                      }
3313  
3314                      if (!insertHTMLFailed) {
3315                          tinyMCE.triggerNodeChange();
3316                          return;
3317                      }
3318                  }
3319  
3320                  if (!tinyMCE.isIE) {
3321                      var isHTML = value.indexOf('<') != -1;
3322                      var sel = this.getSel();
3323                      var rng = this.getRng();
3324  
3325                      if (isHTML) {
3326                          if (tinyMCE.isSafari) {
3327                              var tmpRng = this.getDoc().createRange();
3328  
3329                              tmpRng.setStart(this.getBody(), 0);
3330                              tmpRng.setEnd(this.getBody(), 0);
3331  
3332                              value = tmpRng.createContextualFragment(value);
3333                          } else
3334                              value = rng.createContextualFragment(value);
3335                      } else {
3336                          // Setup text node
3337                          var el = document.createElement("div");
3338                          el.innerHTML = value;
3339                          value = el.firstChild.nodeValue;
3340                          value = doc.createTextNode(value);
3341                      }
3342  
3343                      // Insert plain text in Safari
3344                      if (tinyMCE.isSafari && !isHTML) {
3345                          this.execCommand('InsertText', false, value.nodeValue);
3346                          tinyMCE.triggerNodeChange();
3347                          return true;
3348                      } else if (tinyMCE.isSafari && isHTML) {
3349                          rng.deleteContents();
3350                          rng.insertNode(value);
3351                          tinyMCE.triggerNodeChange();
3352                          return true;
3353                      }
3354  
3355                      rng.deleteContents();
3356  
3357                      // If target node is text do special treatment, (Mozilla 1.3 fix)
3358                      if (rng.startContainer.nodeType == 3) {
3359                          var node = rng.startContainer.splitText(rng.startOffset);
3360                          node.parentNode.insertBefore(value, node); 
3361                      } else
3362                          rng.insertNode(value);
3363  
3364                      if (!isHTML) {
3365                          // Removes weird selection trails
3366                          sel.selectAllChildren(doc.body);
3367                          sel.removeAllRanges();
3368  
3369                          // Move cursor to end of content
3370                          var rng = doc.createRange();
3371  
3372                          rng.selectNode(value);
3373                          rng.collapse(false);
3374  
3375                          sel.addRange(rng);
3376                      } else
3377                          rng.collapse(false);
3378  
3379                      tinyMCE.fixGeckoBaseHREFBug(2, this.getDoc(), value);
3380                  } else {
3381                      var rng = doc.selection.createRange(), tmpRng = null;
3382                      var c = value.indexOf('<!--') != -1;
3383  
3384                      // Fix comment bug, add tag before comments
3385                      if (c)
3386                          value = tinyMCE.uniqueTag + value;
3387  
3388                      //    tmpRng = rng.duplicate(); // Store away range (Fixes Undo bookmark bug in IE)
3389  
3390                      if (rng.item)
3391                          rng.item(0).outerHTML = value;
3392                      else
3393                          rng.pasteHTML(value);
3394  
3395                      //if (tmpRng)
3396                      //    tmpRng.select(); // Restore range  (Fixes Undo bookmark bug in IE)
3397  
3398                      // Remove unique tag
3399                      if (c) {
3400                          var e = this.getDoc().getElementById('mceTMPElement');
3401                          e.parentNode.removeChild(e);
3402                      }
3403                  }
3404  
3405                  tinyMCE.execCommand("mceAddUndoLevel");
3406                  tinyMCE.triggerNodeChange();
3407              break;
3408  
3409              case "mceStartTyping":
3410                  if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex == -1) {
3411                      this.undoRedo.typingUndoIndex = this.undoRedo.undoIndex;
3412                      tinyMCE.typingUndoIndex = tinyMCE.undoIndex;
3413                      this.execCommand('mceAddUndoLevel');
3414                  }
3415                  break;
3416  
3417              case "mceEndTyping":
3418                  if (tinyMCE.settings['custom_undo_redo'] && this.undoRedo.typingUndoIndex != -1) {
3419                      this.execCommand('mceAddUndoLevel');
3420                      this.undoRedo.typingUndoIndex = -1;
3421                  }
3422  
3423                  tinyMCE.typingUndoIndex = -1;
3424                  break;
3425  
3426              case "mceBeginUndoLevel":
3427                  this.undoRedoLevel = false;
3428                  break;
3429  
3430              case "mceEndUndoLevel":
3431                  this.undoRedoLevel = true;
3432                  this.execCommand('mceAddUndoLevel');
3433                  break;
3434  
3435              case "mceAddUndoLevel":
3436                  if (tinyMCE.settings['custom_undo_redo'] && this.undoRedoLevel) {
3437                      if (this.undoRedo.add())
3438                          tinyMCE.triggerNodeChange(false);
3439                  }
3440                  break;
3441  
3442              case "Undo":
3443                  if (tinyMCE.settings['custom_undo_redo']) {
3444                      tinyMCE.execCommand("mceEndTyping");
3445                      this.undoRedo.undo();
3446                      tinyMCE.triggerNodeChange();
3447                  } else
3448                      this.getDoc().execCommand(command, user_interface, value);
3449                  break;
3450  
3451              case "Redo":
3452                  if (tinyMCE.settings['custom_undo_redo']) {
3453                      tinyMCE.execCommand("mceEndTyping");
3454                      this.undoRedo.redo();
3455                      tinyMCE.triggerNodeChange();
3456                  } else
3457                      this.getDoc().execCommand(command, user_interface, value);
3458                  break;
3459  
3460              case "mceToggleVisualAid":
3461                  this.visualAid = !this.visualAid;
3462                  tinyMCE.handleVisualAid(this.getBody(), true, this.visualAid, this);
3463                  tinyMCE.triggerNodeChange();
3464                  break;
3465  
3466              case "Indent":
3467                  this.getDoc().execCommand(command, user_interface, value);
3468                  tinyMCE.triggerNodeChange();
3469  
3470                  if (tinyMCE.isIE) {
3471                      var n = tinyMCE.getParentElement(this.getFocusElement(), "blockquote");
3472                      do {
3473                          if (n && n.nodeName == "BLOCKQUOTE") {
3474                              n.removeAttribute("dir");
3475                              n.removeAttribute("style");
3476                          }
3477                      } while (n != null && (n = n.parentNode) != null);
3478                  }
3479                  break;
3480  
3481              case "removeformat":
3482                  var text = this.selection.getSelectedText();
3483  
3484                  if (tinyMCE.isOpera) {
3485                      this.getDoc().execCommand("RemoveFormat", false, null);
3486                      return;
3487                  }
3488  
3489                  if (tinyMCE.isIE) {
3490                      try {
3491                          var rng = doc.selection.createRange();
3492                          rng.execCommand("RemoveFormat", false, null);
3493                      } catch (e) {
3494                          // Do nothing
3495                      }
3496  
3497                      this.execCommand("SetStyleInfo", false, {command : "removeformat"});
3498                  } else {
3499                      this.getDoc().execCommand(command, user_interface, value);
3500  
3501                      this.execCommand("SetStyleInfo", false, {command : "removeformat"});
3502                  }
3503  
3504                  // Remove class
3505                  if (text.length == 0)
3506                      this.execCommand("mceSetCSSClass", false, "");
3507  
3508                  tinyMCE.triggerNodeChange();
3509                  break;
3510  
3511              default:
3512                  this.getDoc().execCommand(command, user_interface, value);
3513  
3514                  if (tinyMCE.isGecko)
3515                      window.setTimeout('tinyMCE.triggerNodeChange(false);', 1);
3516                  else
3517                      tinyMCE.triggerNodeChange();
3518          }
3519  
3520          // Add undo level after modification
3521          if (command != "mceAddUndoLevel" && command != "Undo" && command != "Redo" && command != "mceStartTyping" && command != "mceEndTyping")
3522              tinyMCE.execCommand("mceAddUndoLevel");
3523      },
3524  
3525      queryCommandValue : function(c) {
3526          try {
3527              return this.getDoc().queryCommandValue(c);
3528          } catch (e) {
3529              return null;
3530          }
3531      },
3532  
3533      queryCommandState : function(c) {
3534          return this.getDoc().queryCommandState(c);
3535      },
3536  
3537      _onAdd : function(replace_element, form_element_name, target_document) {
3538          var hc, th, to, editorTemplate;
3539  
3540          th = this.settings['theme'];
3541          to = tinyMCE.themes[th];
3542  
3543          var targetDoc = target_document ? target_document : document;
3544  
3545          this.targetDoc = targetDoc;
3546  
3547          tinyMCE.themeURL = tinyMCE.baseURL + "/themes/" + this.settings['theme'];
3548          this.settings['themeurl'] = tinyMCE.themeURL;
3549  
3550          if (!replace_element) {
3551              alert("Error: Could not find the target element.");
3552              return false;
3553          }
3554  
3555          if (to.getEditorTemplate)
3556              editorTemplate = to.getEditorTemplate(this.settings, this.editorId);
3557  
3558          var deltaWidth = editorTemplate['delta_width'] ? editorTemplate['delta_width'] : 0;
3559          var deltaHeight = editorTemplate['delta_height'] ? editorTemplate['delta_height'] : 0;
3560          var html = '<span id="' + this.editorId + '_parent" class="mceEditorContainer">' + editorTemplate['html'];
3561  
3562          html = tinyMCE.replaceVar(html, "editor_id", this.editorId);
3563          this.settings['default_document'] = tinyMCE.baseURL + "/blank.htm";
3564  
3565          this.settings['old_width'] = this.settings['width'];
3566          this.settings['old_height'] = this.settings['height'];
3567  
3568          // Set default width, height
3569          if (this.settings['width'] == -1)
3570              this.settings['width'] = replace_element.offsetWidth;
3571  
3572          if (this.settings['height'] == -1)
3573              this.settings['height'] = replace_element.offsetHeight;
3574  
3575          // Try the style width
3576          if (this.settings['width'] == 0)
3577              this.settings['width'] = replace_element.style.width;
3578  
3579          // Try the style height
3580          if (this.settings['height'] == 0)
3581              this.settings['height'] = replace_element.style.height; 
3582  
3583          // If no width/height then default to 320x240, better than nothing
3584          if (this.settings['width'] == 0)
3585              this.settings['width'] = 320;
3586  
3587          if (this.settings['height'] == 0)
3588              this.settings['height'] = 240;
3589  
3590          this.settings['area_width'] = parseInt(this.settings['width']);
3591          this.settings['area_height'] = parseInt(this.settings['height']);
3592          this.settings['area_width'] += deltaWidth;
3593          this.settings['area_height'] += deltaHeight;
3594  
3595          this.settings['width_style'] = "" + this.settings['width'];
3596          this.settings['height_style'] = "" + this.settings['height'];
3597  
3598          // Special % handling
3599          if (("" + this.settings['width']).indexOf('%') != -1)
3600              this.settings['area_width'] = "100%";
3601          else
3602              this.settings['width_style'] += 'px';
3603  
3604          if (("" + this.settings['height']).indexOf('%') != -1)
3605              this.settings['area_height'] = "100%";
3606          else
3607              this.settings['height_style'] += 'px';
3608  
3609          if (("" + replace_element.style.width).indexOf('%') != -1) {
3610              this.settings['width'] = replace_element.style.width;
3611              this.settings['area_width'] = "100%";
3612              this.settings['width_style'] = "100%";
3613          }
3614  
3615          if (("" + replace_element.style.height).indexOf('%') != -1) {
3616              this.settings['height'] = replace_element.style.height;
3617              this.settings['area_height'] = "100%";
3618              this.settings['height_style'] = "100%";
3619          }
3620  
3621          html = tinyMCE.applyTemplate(html);
3622  
3623          this.settings['width'] = this.settings['old_width'];
3624          this.settings['height'] = this.settings['old_height'];
3625  
3626          this.visualAid = this.settings['visual'];
3627          this.formTargetElementId = form_element_name;
3628  
3629          // Get replace_element contents
3630          if (replace_element.nodeName == "TEXTAREA" || replace_element.nodeName == "INPUT")
3631              this.startContent = replace_element.value;
3632          else
3633              this.startContent = replace_element.innerHTML;
3634  
3635          // If not text area or input
3636          if (replace_element.nodeName != "TEXTAREA" && replace_element.nodeName != "INPUT") {
3637              this.oldTargetElement = replace_element;
3638  
3639              // Debug mode
3640              if (tinyMCE.settings['debug']) {
3641                  hc = '<textarea wrap="off" id="' + form_element_name + '" name="' + form_element_name + '" cols="100" rows="15"></textarea>';
3642              } else {
3643                  hc = '<input type="hidden" id="' + form_element_name + '" name="' + form_element_name + '" />';
3644                  this.oldTargetElement.style.display = "none";
3645              }
3646  
3647              html += '</span>';
3648  
3649              if (tinyMCE.isGecko)
3650                  html = hc + html;
3651              else
3652                  html += hc;
3653  
3654              // Output HTML and set editable
3655              if (tinyMCE.isGecko) {
3656                  var rng = replace_element.ownerDocument.createRange();
3657                  rng.setStartBefore(replace_element);
3658  
3659                  var fragment = rng.createContextualFragment(html);
3660                  tinyMCE.insertAfter(fragment, replace_element);
3661              } else
3662                  replace_element.insertAdjacentHTML("beforeBegin", html);
3663          } else {
3664              html += '</span>';
3665  
3666              // Just hide the textarea element
3667              this.oldTargetElement = replace_element;
3668  
3669              if (!tinyMCE.settings['debug'])
3670                  this.oldTargetElement.style.display = "none";
3671  
3672              // Output HTML and set editable
3673              if (tinyMCE.isGecko) {
3674                  var rng = replace_element.ownerDocument.createRange();
3675                  rng.setStartBefore(replace_element);
3676  
3677                  var fragment = rng.createContextualFragment(html);
3678                  tinyMCE.insertAfter(fragment, replace_element);
3679              } else
3680                  replace_element.insertAdjacentHTML("beforeBegin", html);
3681          }
3682  
3683          // Setup iframe
3684          var dynamicIFrame = false;
3685          var tElm = targetDoc.getElementById(this.editorId);
3686  
3687          if (!tinyMCE.isIE) {
3688              // Node case is preserved in XML strict mode
3689              if (tElm && (tElm.nodeName == "SPAN" || tElm.nodeName == "span")) {
3690                  tElm = tinyMCE._createIFrame(tElm, targetDoc);
3691                  dynamicIFrame = true;
3692              }
3693  
3694              this.targetElement = tElm;
3695              this.iframeElement = tElm;
3696              this.contentDocument = tElm.contentDocument;
3697              this.contentWindow = tElm.contentWindow;
3698  
3699              //this.getDoc().designMode = "on";
3700          } else {
3701              if (tElm && tElm.nodeName == "SPAN")
3702                  tElm = tinyMCE._createIFrame(tElm, targetDoc, targetDoc.parentWindow);
3703              else
3704                  tElm = targetDoc.frames[this.editorId];
3705  
3706              this.targetElement = tElm;
3707              this.iframeElement = targetDoc.getElementById(this.editorId);
3708  
3709              if (tinyMCE.isOpera) {
3710                  this.contentDocument = this.iframeElement.contentDocument;
3711                  this.contentWindow = this.iframeElement.contentWindow;
3712                  dynamicIFrame = true;
3713              } else {
3714                  this.contentDocument = tElm.window.document;
3715                  this.contentWindow = tElm.window;
3716              }
3717  
3718              this.getDoc().designMode = "on";
3719          }
3720  
3721          // Setup base HTML
3722          var doc = this.contentDocument;
3723          if (dynamicIFrame) {
3724              var html = tinyMCE.getParam('doctype') + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + tinyMCE.settings['base_href'] + '" /><title>blank_page</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body class="mceContentBody"></body></html>';
3725  
3726              try {
3727                  if (!this.isHidden())
3728                      this.getDoc().designMode = "on";
3729  
3730                  doc.open();
3731                  doc.write(html);
3732                  doc.close();
3733              } catch (e) {
3734                  // Failed Mozilla 1.3
3735                  this.getDoc().location.href = tinyMCE.baseURL + "/blank.htm";
3736              }
3737          }
3738  
3739          // This timeout is needed in MSIE 5.5 for some odd reason
3740          // it seems that the document.frames isn't initialized yet?
3741          if (tinyMCE.isIE)
3742              window.setTimeout("tinyMCE.addEventHandlers(tinyMCE.instances[\"" + this.editorId + "\"]);", 1);
3743  
3744          tinyMCE.setupContent(this.editorId, true);
3745  
3746          return true;
3747      },
3748  
3749      setBaseHREF : function(u) {
3750          var h, b, d, nl;
3751  
3752          d = this.getDoc();
3753          nl = d.getElementsByTagName("base");
3754          b = nl.length > 0 ? nl[0] : null;
3755  
3756          if (!b) {
3757              nl = d.getElementsByTagName("head");
3758              h = nl.length > 0 ? nl[0] : null;
3759  
3760              b = d.createElement("base");
3761              b.setAttribute('href', u);
3762              h.appendChild(b);
3763          } else {
3764              if (u == "" || u == null)
3765                  b.parentNode.removeChild(b);
3766              else
3767                  b.setAttribute('href', u);
3768          }
3769      },
3770  
3771      getHTML : function(r) {
3772          var h, d = this.getDoc(), b = this.getBody();
3773  
3774          if (r)
3775              return b.innerHTML;
3776  
3777          h = tinyMCE._cleanupHTML(this, d, this.settings, b, false, true, false, true);
3778  
3779          if (tinyMCE.getParam("convert_fonts_to_spans"))
3780              tinyMCE.convertSpansToFonts(d);
3781  
3782          return h;
3783      },
3784  
3785      setHTML : function(h) {
3786          this.execCommand('mceSetContent', false, h);
3787          this.repaint();
3788      },
3789  
3790      getFocusElement : function() {
3791          return this.selection.getFocusElement();
3792      },
3793  
3794      getSel : function() {
3795          return this.selection.getSel();
3796      },
3797  
3798      getRng : function() {
3799          return this.selection.getRng();
3800      },
3801  
3802      triggerSave : function(skip_cleanup, skip_callback) {
3803          var e, nl = [], i, s;
3804  
3805          this.switchSettings();
3806          s = tinyMCE.settings;
3807  
3808          // Force hidden tabs visible while serializing
3809          if (tinyMCE.isRealIE) {
3810              e = this.iframeElement;
3811  
3812              do {
3813                  if (e.style && e.style.display == 'none') {
3814                      e.style.display = 'block';
3815                      nl[nl.length] = {elm : e, type : 'style'};
3816                  }
3817  
3818                  if (e.style && s.hidden_tab_class.length > 0 && e.className.indexOf(s.hidden_tab_class) != -1) {
3819                      e.className = s.display_tab_class;
3820                      nl[nl.length] = {elm : e, type : 'class'};
3821                  }
3822              } while ((e = e.parentNode) != null)
3823          }
3824  
3825          tinyMCE.settings['preformatted'] = false;
3826  
3827          // Default to false
3828          if (typeof(skip_cleanup) == "undefined")
3829              skip_cleanup = false;
3830  
3831          // Default to false
3832          if (typeof(skip_callback) == "undefined")
3833              skip_callback = false;
3834  
3835          tinyMCE._setHTML(this.getDoc(), this.getBody().innerHTML);
3836  
3837          // Remove visual aids when cleanup is disabled
3838          if (this.settings['cleanup'] == false) {
3839              tinyMCE.handleVisualAid(this.getBody(), true, false, this);
3840              tinyMCE._setEventsEnabled(this.getBody(), true);
3841          }
3842  
3843          tinyMCE._customCleanup(this, "submit_content_dom", this.contentWindow.document.body);
3844          var htm = skip_cleanup ? this.getBody().innerHTML : tinyMCE._cleanupHTML(this, this.getDoc(), this.settings, this.getBody(), tinyMCE.visualAid, true, true);
3845          htm = tinyMCE._customCleanup(this, "submit_content", htm);
3846  
3847          if (!skip_callback && tinyMCE.settings['save_callback'] != "")
3848              var content = eval(tinyMCE.settings['save_callback'] + "(this.formTargetElementId,htm,this.getBody());");
3849  
3850          // Use callback content if available
3851          if ((typeof(content) != "undefined") && content != null)
3852              htm = content;
3853  
3854          // Replace some weird entities (Bug: #1056343)
3855          htm = tinyMCE.regexpReplace(htm, "&#40;", "(", "gi");
3856          htm = tinyMCE.regexpReplace(htm, "&#41;", ")", "gi");
3857          htm = tinyMCE.regexpReplace(htm, "&#59;", ";", "gi");
3858          htm = tinyMCE.regexpReplace(htm, "&#34;", "&quot;", "gi");
3859          htm = tinyMCE.regexpReplace(htm, "&#94;", "^", "gi");
3860  
3861          if (this.formElement)
3862              this.formElement.value = htm;
3863  
3864          if (tinyMCE.isSafari && this.formElement)
3865              this.formElement.innerText = htm;
3866  
3867          // Hide them again (tabs in MSIE)
3868          for (i=0; i<nl.length; i++) {
3869              if (nl[i].type == 'style')
3870                  nl[i].elm.style.display = 'none';
3871              else
3872                  nl[i].elm.className = s.hidden_tab_class;
3873          }
3874      }
3875  
3876      };
3877  
3878  /* file:jscripts/tiny_mce/classes/TinyMCE_Cleanup.class.js */
3879  
3880  TinyMCE_Engine.prototype.cleanupHTMLCode = function(s) {
3881      s = s.replace(new RegExp('<p \\/>', 'gi'), '<p>&nbsp;</p>');
3882      s = s.replace(new RegExp('<p>\\s*<\\/p>', 'gi'), '<p>&nbsp;</p>');
3883  
3884      // Fix close BR elements
3885      s = s.replace(new RegExp('<br>\\s*<\\/br>', 'gi'), '<br />');
3886  
3887      // Open closed tags like <b/> to <b></b>
3888      s = s.replace(new RegExp('<(h[1-6]|p|div|address|pre|form|table|li|ol|ul|td|b|font|em|strong|i|strike|u|span|a|ul|ol|li|blockquote)([a-z]*)([^\\\\|>]*)\\/>', 'gi'), '<$1$2$3></$1$2>');
3889  
3890      // Remove trailing space <b > to <b>
3891      s = s.replace(new RegExp('\\s+></', 'gi'), '></');
3892  
3893      // Close tags <img></img> to <img/>
3894      s = s.replace(new RegExp('<(img|br|hr)([^>]*)><\\/(img|br|hr)>', 'gi'), '<$1$2 />');
3895  
3896      // Weird MSIE bug, <p><hr /></p> breaks runtime?
3897      if (tinyMCE.isIE)
3898          s = s.replace(new RegExp('<p><hr \\/><\\/p>', 'gi'), "<hr>");
3899  
3900      // Weird tags will make IE error #bug: 1538495
3901      if (tinyMCE.isIE)
3902          s = s.replace(/<!(\s*)\/>/g, '');
3903  
3904      // Convert relative anchors to absolute URLs ex: #something to file.htm#something
3905      // Removed: Since local document anchors should never be forced absolute example edit.php?id=something
3906      //if (tinyMCE.getParam('convert_urls'))
3907      //    s = s.replace(new RegExp('(href=\"{0,1})(\\s*#)', 'gi'), '$1' + tinyMCE.settings['document_base_url'] + "#");
3908  
3909      return s;
3910  };
3911  
3912  TinyMCE_Engine.prototype.parseStyle = function(str) {
3913      var ar = new Array();
3914  
3915      if (str == null)
3916          return ar;
3917  
3918      var st = str.split(';');
3919  
3920      tinyMCE.clearArray(ar);
3921  
3922      for (var i=0; i<st.length; i++) {
3923          if (st[i] == '')
3924              continue;
3925  
3926          var re = new RegExp('^\\s*([^:]*):\\s*(.*)\\s*$');
3927          var pa = st[i].replace(re, '$1||$2').split('||');
3928  //tinyMCE.debug(str, pa[0] + "=" + pa[1], st[i].replace(re, '$1||$2'));
3929          if (pa.length == 2)
3930              ar[pa[0].toLowerCase()] = pa[1];
3931      }
3932  
3933      return ar;
3934  };
3935  
3936  TinyMCE_Engine.prototype.compressStyle = function(ar, pr, sf, res) {
3937      var box = new Array();
3938  
3939      box[0] = ar[pr + '-top' + sf];
3940      box[1] = ar[pr + '-left' + sf];
3941      box[2] = ar[pr + '-right' + sf];
3942      box[3] = ar[pr + '-bottom' + sf];
3943  
3944      for (var i=0; i<box.length; i++) {
3945          if (box[i] == null)
3946              return;
3947  
3948          for (var a=0; a<box.length; a++) {
3949              if (box[a] != box[i])
3950                  return;
3951          }
3952      }
3953  
3954      // They are all the same
3955      ar[res] = box[0];
3956      ar[pr + '-top' + sf] = null;
3957      ar[pr + '-left' + sf] = null;
3958      ar[pr + '-right' + sf] = null;
3959      ar[pr + '-bottom' + sf] = null;
3960  };
3961  
3962  TinyMCE_Engine.prototype.serializeStyle = function(ar) {
3963      var str = "";
3964  
3965      // Compress box
3966      tinyMCE.compressStyle(ar, "border", "", "border");
3967      tinyMCE.compressStyle(ar, "border", "-width", "border-width");
3968      tinyMCE.compressStyle(ar, "border", "-color", "border-color");
3969      tinyMCE.compressStyle(ar, "border", "-style", "border-style");
3970      tinyMCE.compressStyle(ar, "padding", "", "padding");
3971      tinyMCE.compressStyle(ar, "margin", "", "margin");
3972  
3973      for (var key in ar) {
3974          var val = ar[key];
3975  
3976          if (typeof(val) == 'function')
3977              continue;
3978  
3979          if (key.indexOf('mso-') == 0)
3980              continue;
3981  
3982          if (val != null && val != '') {
3983              val = '' + val; // Force string
3984  
3985              // Fix style URL
3986              val = val.replace(new RegExp("url\\(\\'?([^\\']*)\\'?\\)", 'gi'), "url('$1')");
3987  
3988              // Convert URL
3989              if (val.indexOf('url(') != -1 && tinyMCE.getParam('convert_urls')) {
3990                  var m = new RegExp("url\\('(.*?)'\\)").exec(val);
3991  
3992                  if (m.length > 1)
3993                      val = "url('" + eval(tinyMCE.getParam('urlconverter_callback') + "(m[1], null, true);") + "')";
3994              }
3995  
3996              // Force HEX colors
3997              if (tinyMCE.getParam("force_hex_style_colors"))
3998                  val = tinyMCE.convertRGBToHex(val, true);
3999  
4000              if (val != "url('')")
4001                  str += key.toLowerCase() + ": " + val + "; ";
4002          }
4003      }
4004  
4005      if (new RegExp('; $').test(str))
4006          str = str.substring(0, str.length - 2);
4007  
4008      return str;
4009  };
4010  
4011  TinyMCE_Engine.prototype.convertRGBToHex = function(s, k) {
4012      if (s.toLowerCase().indexOf('rgb') != -1) {
4013          var re = new RegExp("(.*?)rgb\\s*?\\(\\s*?([0-9]+).*?,\\s*?([0-9]+).*?,\\s*?([0-9]+).*?\\)(.*?)", "gi");
4014          var rgb = s.replace(re, "$1,$2,$3,$4,$5").split(',');
4015          if (rgb.length == 5) {
4016              r = parseInt(rgb[1]).toString(16);
4017              g = parseInt(rgb[2]).toString(16);
4018              b = parseInt(rgb[3]).toString(16);
4019  
4020              r = r.length == 1 ? '0' + r : r;
4021              g = g.length == 1 ? '0' + g : g;
4022              b = b.length == 1 ? '0' + b : b;
4023  
4024              s = "#" + r + g + b;
4025  
4026              if (k)
4027                  s = rgb[0] + s + rgb[4];
4028          }
4029      }
4030  
4031      return s;
4032  };
4033  
4034  TinyMCE_Engine.prototype.convertHexToRGB = function(s) {
4035      if (s.indexOf('#') != -1) {
4036          s = s.replace(new RegExp('[^0-9A-F]', 'gi'), '');
4037          return "rgb(" + parseInt(s.substring(0, 2), 16) + "," + parseInt(s.substring(2, 4), 16) + "," + parseInt(s.substring(4, 6), 16) + ")";
4038      }
4039  
4040      return s;
4041  };
4042  
4043  TinyMCE_Engine.prototype.convertSpansToFonts = function(doc) {
4044      var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
4045  
4046      var h = doc.body.innerHTML;
4047      h = h.replace(/<span/gi, '<font');
4048      h = h.replace(/<\/span/gi, '</font');
4049      tinyMCE.setInnerHTML(doc.body, h);
4050  
4051      var s = doc.getElementsByTagName("font");
4052      for (var i=0; i<s.length; i++) {
4053          var size = tinyMCE.trim(s[i].style.fontSize).toLowerCase();
4054          var fSize = 0;
4055  
4056          for (var x=0; x<sizes.length; x++) {
4057              if (sizes[x] == size) {
4058                  fSize = x + 1;
4059                  break;
4060              }
4061          }
4062  
4063          if (fSize > 0) {
4064              tinyMCE.setAttrib(s[i], 'size', fSize);
4065              s[i].style.fontSize = '';
4066          }
4067  
4068          var fFace = s[i].style.fontFamily;
4069          if (fFace != null && fFace != "") {
4070              tinyMCE.setAttrib(s[i], 'face', fFace);
4071              s[i].style.fontFamily = '';
4072          }
4073  
4074          var fColor = s[i].style.color;
4075          if (fColor != null && fColor != "") {
4076              tinyMCE.setAttrib(s[i], 'color', tinyMCE.convertRGBToHex(fColor));
4077              s[i].style.color = '';
4078          }
4079      }
4080  };
4081  
4082  TinyMCE_Engine.prototype.convertFontsToSpans = function(doc) {
4083      var sizes = tinyMCE.getParam('font_size_style_values').replace(/\s+/, '').split(',');
4084  
4085      var h = doc.body.innerHTML;
4086      h = h.replace(/<font/gi, '<span');
4087      h = h.replace(/<\/font/gi, '</span');
4088      tinyMCE.setInnerHTML(doc.body, h);
4089  
4090      var fsClasses = tinyMCE.getParam('font_size_classes');
4091      if (fsClasses != '')
4092          fsClasses = fsClasses.replace(/\s+/, '').split(',');
4093      else
4094          fsClasses = null;
4095  
4096      var s = doc.getElementsByTagName("span");
4097      for (var i=0; i<s.length; i++) {
4098          var fSize, fFace, fColor;
4099  
4100          fSize = tinyMCE.getAttrib(s[i], 'size');
4101          fFace = tinyMCE.getAttrib(s[i], 'face');
4102          fColor = tinyMCE.getAttrib(s[i], 'color');
4103  
4104          if (fSize != "") {
4105              fSize = parseInt(fSize);
4106  
4107              if (fSize > 0 && fSize < 8) {
4108                  if (fsClasses != null)
4109                      tinyMCE.setAttrib(s[i], 'class', fsClasses[fSize-1]);
4110                  else
4111                      s[i].style.fontSize = sizes[fSize-1];
4112              }
4113  
4114              s[i].removeAttribute('size');
4115          }
4116  
4117          if (fFace != "") {
4118              s[i].style.fontFamily = fFace;
4119              s[i].removeAttribute('face');
4120          }
4121  
4122          if (fColor != "") {
4123              s[i].style.color = fColor;
4124              s[i].removeAttribute('color');
4125          }
4126      }
4127  };
4128  
4129  TinyMCE_Engine.prototype.cleanupAnchors = function(doc) {
4130      var i, cn, x, an = doc.getElementsByTagName("a");
4131  
4132      // Loops backwards due to bug #1467987
4133      for (i=an.length-1; i>=0; i--) {
4134          if (tinyMCE.getAttrib(an[i], "name") != "" && tinyMCE.getAttrib(an[i], "href") == "") {
4135              cn = an[i].childNodes;
4136  
4137              for (x=cn.length-1; x>=0; x--)
4138                  tinyMCE.insertAfter(cn[x], an[i]);
4139          }
4140      }
4141  };
4142  
4143  TinyMCE_Engine.prototype.getContent = function(editor_id) {
4144      if (typeof(editor_id) != "undefined")
4145           tinyMCE.getInstanceById(editor_id).select();
4146  
4147      if (tinyMCE.selectedInstance)
4148          return tinyMCE.selectedInstance.getHTML();
4149  
4150      return null;
4151  };
4152  
4153  TinyMCE_Engine.prototype._fixListElements = function(d) {
4154      var nl, x, a = ['ol', 'ul'], i, n, p, r = new RegExp('^(OL|UL)$'), np;
4155  
4156      for (x=0; x<a.length; x++) {
4157          nl = d.getElementsByTagName(a[x]);
4158  
4159          for (i=0; i<nl.length; i++) {
4160              n = nl[i];
4161              p = n.parentNode;
4162  
4163              if (r.test(p.nodeName)) {
4164                  np = tinyMCE.prevNode(n, 'LI');
4165  
4166                  if (!np) {
4167                      np = d.createElement('li');
4168                      np.innerHTML = '&nbsp;';
4169                      np.appendChild(n);
4170                      p.insertBefore(np, p.firstChild);
4171                  } else
4172                      np.appendChild(n);
4173              }
4174          }
4175      }
4176  };
4177  
4178  TinyMCE_Engine.prototype._fixTables = function(d) {
4179      var nl, i, n, p, np, x, t;
4180  
4181      nl = d.getElementsByTagName('table');
4182      for (i=0; i<nl.length; i++) {
4183          n = nl[i];
4184  
4185          if ((p = tinyMCE.getParentElement(n, 'p,div,h1,h2,h3,h4,h5,h6')) != null) {
4186              np = p.cloneNode(false);
4187              np.removeAttribute('id');
4188  
4189              t = n;
4190  
4191              while ((n = n.nextSibling))
4192                  np.appendChild(n);
4193  
4194              tinyMCE.insertAfter(np, p);
4195              tinyMCE.insertAfter(t, p);
4196          }
4197      }
4198  };
4199  
4200  TinyMCE_Engine.prototype._cleanupHTML = function(inst, doc, config, elm, visual, on_save, on_submit, inn) {
4201      var h, d, t1, t2, t3, t4, t5, c, s, nb;
4202  
4203      if (!tinyMCE.getParam('cleanup'))
4204          return elm.innerHTML;
4205  
4206      on_save = typeof(on_save) == 'undefined' ? false : on_save;
4207  
4208      c = inst.cleanup;
4209      s = inst.settings;
4210      d = c.settings.debug;
4211  
4212      if (d)
4213          t1 = new Date().getTime();
4214  
4215      if (tinyMCE.getParam("convert_fonts_to_spans"))
4216          tinyMCE.convertFontsToSpans(doc);
4217  
4218      if (tinyMCE.getParam("fix_list_elements"))
4219          tinyMCE._fixListElements(doc);
4220  
4221      if (tinyMCE.getParam("fix_table_elements"))
4222          tinyMCE._fixTables(doc);
4223  
4224      // Call custom cleanup code
4225      tinyMCE._customCleanup(inst, on_save ? "get_from_editor_dom" : "insert_to_editor_dom", doc.body);
4226  
4227      if (d)
4228          t2 = new Date().getTime();
4229  
4230      c.settings.on_save = on_save;
4231      //for (var i=0; i<100; i++)
4232  
4233      c.idCount = 0;
4234      c.serializationId++;
4235      c.serializedNodes = new Array();
4236      c.sourceIndex = -1;
4237  
4238      if (s.cleanup_serializer == "xml")
4239          h = c.serializeNodeAsXML(elm, inn);
4240      else
4241          h = c.serializeNodeAsHTML(elm, inn);
4242  
4243      if (d)
4244          t3 = new Date().getTime();
4245  
4246      // Post processing
4247      nb = tinyMCE.getParam('entity_encoding') == 'numeric' ? '&#160;' : '&nbsp;';
4248      h = h.replace(/<\/?(body|head|html)[^>]*>/gi, '');
4249      h = h.replace(new RegExp(' (rowspan="1"|colspan="1")', 'g'), '');
4250      h = h.replace(/<p><hr \/><\/p>/g, '<hr />');
4251      h = h.replace(/<p>(&nbsp;|&#160;)<\/p><hr \/><p>(&nbsp;|&#160;)<\/p>/g, '<hr />');
4252      h = h.replace(/<td>\s*<br \/>\s*<\/td>/g, '<td>' + nb + '</td>');
4253      h = h.replace(/<p>\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
4254      h = h.replace(/<br \/>$/, ''); // Remove last BR for Gecko
4255      h = h.replace(/<br \/><\/p>/g, '</p>'); // Remove last BR in P tags for Gecko
4256      h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*(&nbsp;|&#160;)\s*<\/p>/g, '<p>' + nb + '</p>');
4257      h = h.replace(/<p>\s*(&nbsp;|&#160;)\s*<br \/>\s*<\/p>/g, '<p>' + nb + '</p>');
4258      h = h.replace(/<p>\s*<br \/>\s*&nbsp;\s*<\/p>/g, '<p>' + nb + '</p>');
4259      h = h.replace(new RegExp('<a>(.*?)<\\/a>', 'g'), '$1');
4260      h = h.replace(/<p([^>]*)>\s*<\/p>/g, '<p$1>' + nb + '</p>');
4261  
4262      // Clean body
4263      if (/^\s*(<br \/>|<p>&nbsp;<\/p>|<p>&#160;<\/p>|<p><\/p>)\s*$/.test(h))
4264          h = '';
4265  
4266      // If preformatted
4267      if (s.preformatted) {
4268          h = h.replace(/^<pre>/, '');
4269          h = h.replace(/<\/pre>$/, '');
4270          h = '<pre>' + h + '</pre>';
4271      }
4272  
4273      // Gecko specific processing
4274      if (tinyMCE.isGecko) {
4275          h = h.replace(/<o:p _moz-userdefined="" \/>/g, '');
4276          h = h.replace(/<td([^>]*)>\s*<br \/>\s*<\/td>/g, '<td$1>' + nb + '</td>');
4277      }
4278  
4279      if (s.force_br_newlines)
4280          h = h.replace(/<p>(&nbsp;|&#160;)<\/p>/g, '<br />');
4281  
4282      // Call custom cleanup code
4283      h = tinyMCE._customCleanup(inst, on_save ? "get_from_editor" : "insert_to_editor", h);
4284  
4285      // Remove internal classes
4286      if (on_save) {
4287          h = h.replace(new RegExp(' ?(mceItem[a-zA-Z0-9]*|' + s.visual_table_class + ')', 'g'), '');
4288          h = h.replace(new RegExp(' ?class=""', 'g'), '');
4289      }
4290  
4291      if (s.remove_linebreaks && !c.settings.indent)
4292          h = h.replace(/\n|\r/g, ' ');
4293  
4294      if (d)
4295          t4 = new Date().getTime();
4296  
4297      if (on_save && c.settings.indent)
4298          h = c.formatHTML(h);
4299  
4300      // If encoding (not recommended option)
4301      if (on_submit && (s.encoding == "xml" || s.encoding == "html"))
4302          h = c.xmlEncode(h);
4303  
4304      if (d)
4305          t5 = new Date().getTime();
4306  
4307      if (c.settings.debug)
4308          tinyMCE.debug("Cleanup in ms: Pre=" + (t2-t1) + ", Serialize: " + (t3-t2) + ", Post: " + (t4-t3) + ", Format: " + (t5-t4) + ", Sum: " + (t5-t1) + ".");
4309  
4310      return h;
4311  };
4312  
4313  function TinyMCE_Cleanup() {
4314      this.isIE = (navigator.appName == "Microsoft Internet Explorer");
4315      this.rules = tinyMCE.clearArray(new Array());
4316  
4317      // Default config
4318      this.settings = {
4319          indent_elements : 'head,table,tbody,thead,tfoot,form,tr,ul,ol,blockquote,object',
4320          newline_before_elements : 'h1,h2,h3,h4,h5,h6,pre,address,div,ul,ol,li,meta,option,area,title,link,base,script,td',
4321          newline_after_elements : 'br,hr,p,pre,address,div,ul,ol,meta,option,area,link,base,script',
4322          newline_before_after_elements : 'html,head,body,table,thead,tbody,tfoot,tr,form,ul,ol,blockquote,p,object,param,hr,div',
4323          indent_char : '\t',
4324          indent_levels : 1,
4325          entity_encoding : 'raw',
4326          valid_elements : '*[*]',
4327          entities : '',
4328          url_converter : '',
4329          invalid_elements : '',
4330          verify_html : false
4331      };
4332  
4333      this.vElements = tinyMCE.clearArray(new Array());
4334      this.vElementsRe = '';
4335      this.closeElementsRe = /^(IMG|BR|HR|LINK|META|BASE|INPUT|AREA)$/;
4336      this.codeElementsRe = /^(SCRIPT|STYLE)$/;
4337      this.serializationId = 0;
4338      this.mceAttribs = {
4339          href : 'mce_href',
4340          src : 'mce_src',
4341          type : 'mce_type'
4342      };
4343  }
4344  
4345  TinyMCE_Cleanup.prototype = {
4346      init : function(s) {
4347          var n, a, i, ir, or, st;
4348  
4349          for (n in s)
4350              this.settings[n] = s[n];
4351  
4352          // Setup code formating
4353          s = this.settings;
4354  
4355          // Setup regexps
4356          this.inRe = this._arrayToRe(s.indent_elements.split(','), '', '^<(', ')[^>]*');
4357          this.ouRe = this._arrayToRe(s.indent_elements.split(','), '', '^<\\/(', ')[^>]*');
4358          this.nlBeforeRe = this._arrayToRe(s.newline_before_elements.split(','), 'gi', '<(',  ')([^>]*)>');
4359          this.nlAfterRe = this._arrayToRe(s.newline_after_elements.split(','), 'gi', '<(',  ')([^>]*)>');
4360          this.nlBeforeAfterRe = this._arrayToRe(s.newline_before_after_elements.split(','), 'gi', '<(\\/?)(', ')([^>]*)>');
4361          this.serializedNodes = [];
4362  
4363          if (s.invalid_elements != '')
4364              this.iveRe = this._arrayToRe(s.invalid_elements.toUpperCase().split(','), 'g', '^(', ')$');
4365          else
4366              this.iveRe = null;
4367  
4368          // Setup separator
4369          st = '';
4370          for (i=0; i<s.indent_levels; i++)
4371              st += s.indent_char;
4372  
4373          this.inStr = st;
4374  
4375          // If verify_html if false force *[*]
4376          if (!s.verify_html) {
4377              s.valid_elements = '*[*]';
4378              s.extended_valid_elements = '';
4379          }
4380  
4381          this.fillStr = s.entity_encoding == "named" ? "&nbsp;" : "&#160;";
4382          this.idCount = 0;
4383      },
4384  
4385      addRuleStr : function(s) {
4386          var r = this.parseRuleStr(s);
4387          var n;
4388  
4389          for (n in r) {
4390              if (r[n])
4391                  this.rules[n] = r[n];
4392          }
4393  
4394          this.vElements = tinyMCE.clearArray(new Array());
4395  
4396          for (n in this.rules) {
4397              if (this.rules[n])
4398                  this.vElements[this.vElements.length] = this.rules[n].tag;
4399          }
4400  
4401          this.vElementsRe = this._arrayToRe(this.vElements, '');
4402      },
4403  
4404      isValid : function(n) {
4405          this._setupRules(); // Will initialize cleanup rules
4406  
4407          // Clean the name up a bit
4408          n = n.replace(/[^a-z0-9]+/gi, '').toUpperCase();
4409  
4410          return !tinyMCE.getParam('cleanup') || this.vElementsRe.test(n);
4411      },
4412  
4413      addChildRemoveRuleStr : function(s) {
4414          var x, y, p, i, t, tn, ta, cl, r;
4415  
4416          if (!s)
4417              return;
4418  
4419          ta = s.split(',');
4420          for (x=0; x<ta.length; x++) {
4421              s = ta[x];
4422  
4423              // Split tag/children
4424              p = this.split(/\[|\]/, s);
4425              if (p == null || p.length < 1)
4426                  t = s.toUpperCase();
4427              else
4428                  t = p[0].toUpperCase();
4429  
4430              // Handle all tag names
4431              tn = this.split('/', t);
4432              for (y=0; y<tn.length; y++) {
4433                  r = "^(";
4434  
4435                  // Build regex
4436                  cl = this.split(/\|/, p[1]);
4437                  for (i=0; i<cl.length; i++) {
4438                      if (cl[i] == '%istrict')
4439                          r += tinyMCE.inlineStrict;
4440                      else if (cl[i] == '%itrans')
4441                          r += tinyMCE.inlineTransitional;
4442                      else if (cl[i] == '%istrict_na')
4443                          r += tinyMCE.inlineStrict.substring(2);
4444                      else if (cl[i] == '%itrans_na')
4445                          r += tinyMCE.inlineTransitional.substring(2);
4446                      else if (cl[i] == '%btrans')
4447                          r += tinyMCE.blockElms;
4448                      else if (cl[i] == '%strict')
4449                          r += tinyMCE.blockStrict;
4450                      else
4451                          r += (cl[i].charAt(0) != '#' ? cl[i].toUpperCase() : cl[i]);
4452  
4453                      r += (i != cl.length - 1 ? '|' : '');
4454                  }
4455  
4456                  r += ')$';
4457  //tinyMCE.debug(t + "=" + r);
4458                  if (this.childRules == null)
4459                      this.childRules = tinyMCE.clearArray(new Array());
4460  
4461                  this.childRules[tn[y]] = new RegExp(r);
4462  
4463                  if (p.length > 1)
4464                      this.childRules[tn[y]].wrapTag = p[2];
4465              }
4466          }
4467      },
4468  
4469      parseRuleStr : function(s) {
4470          var ta, p, r, a, i, x, px, t, tn, y, av, or = tinyMCE.clearArray(new Array()), dv;
4471  
4472          if (s == null || s.length == 0)
4473              return or;
4474  
4475          ta = s.split(',');
4476          for (x=0; x<ta.length; x++) {
4477              s = ta[x];
4478              if (s.length == 0)
4479                  continue;
4480  
4481              // Split tag/attrs
4482              p = this.split(/\[|\]/, s);
4483              if (p == null || p.length < 1)
4484                  t = s.toUpperCase();
4485              else
4486                  t = p[0].toUpperCase();
4487  
4488              // Handle all tag names
4489              tn = this.split('/', t);
4490              for (y=0; y<tn.length; y++) {
4491                  r = {};
4492  
4493                  r.tag = tn[y];
4494                  r.forceAttribs = null;
4495                  r.defaultAttribs = null;
4496                  r.validAttribValues = null;
4497  
4498                  // Handle prefixes
4499                  px = r.tag.charAt(0);
4500                  r.forceOpen = px == '+';
4501                  r.removeEmpty = px == '-';
4502                  r.fill = px == '#';
4503                  r.tag = r.tag.replace(/\+|-|#/g, '');
4504                  r.oTagName = tn[0].replace(/\+|-|#/g, '').toLowerCase();
4505                  r.isWild = new RegExp('\\*|\\?|\\+', 'g').test(r.tag);
4506                  r.validRe = new RegExp(this._wildcardToRe('^' + r.tag + '$'));
4507  
4508                  // Setup valid attributes
4509                  if (p.length > 1) {
4510                      r.vAttribsRe = '^(';
4511                      a = this.split(/\|/, p[1]);
4512  
4513                      for (i=0; i<a.length; i++) {
4514                          t = a[i];
4515  
4516                          if (t.charAt(0) == '!') {
4517                              a[i] = t = t.substring(1);
4518  
4519                              if (!r.reqAttribsRe)
4520                                  r.reqAttribsRe = '\\s+(' + t;
4521                              else
4522                                  r.reqAttribsRe += '|' + t;
4523                          }
4524  
4525                          av = new RegExp('(=|:|<)(.*?)$').exec(t);
4526                          t = t.replace(new RegExp('(=|:|<).*?$'), '');
4527                          if (av && av.length > 0) {
4528                              if (av[0].charAt(0) == ':') {
4529                                  if (!r.forceAttribs)
4530                                      r.forceAttribs = tinyMCE.clearArray(new Array());
4531  
4532                                  r.forceAttribs[t.toLowerCase()] = av[0].substring(1);
4533                              } else if (av[0].charAt(0) == '=') {
4534                                  if (!r.defaultAttribs)
4535                                      r.defaultAttribs = tinyMCE.clearArray(new Array());
4536  
4537                                  dv = av[0].substring(1);
4538  
4539                                  r.defaultAttribs[t.toLowerCase()] = dv == "" ? "mce_empty" : dv;
4540                              } else if (av[0].charAt(0) == '<') {
4541                                  if (!r.validAttribValues)
4542                                      r.validAttribValues = tinyMCE.clearArray(new Array());
4543  
4544                                  r.validAttribValues[t.toLowerCase()] = this._arrayToRe(this.split('?', av[0].substring(1)), 'i');
4545                              }
4546                          }
4547  
4548                          r.vAttribsRe += '' + t.toLowerCase() + (i != a.length - 1 ? '|' : '');
4549  
4550                          a[i] = t.toLowerCase();
4551                      }
4552  
4553                      if (r.reqAttribsRe)
4554                          r.reqAttribsRe = new RegExp(r.reqAttribsRe + ')=\"', 'g');
4555  
4556                      r.vAttribsRe += ')$';
4557                      r.vAttribsRe = this._wildcardToRe(r.vAttribsRe);
4558                      r.vAttribsReIsWild = new RegExp('\\*|\\?|\\+', 'g').test(r.vAttribsRe);
4559                      r.vAttribsRe = new RegExp(r.vAttribsRe);
4560                      r.vAttribs = a.reverse();
4561  
4562                      //tinyMCE.debug(r.tag, r.oTagName, r.vAttribsRe, r.vAttribsReWC);
4563                  } else {
4564                      r.vAttribsRe = '';
4565                      r.vAttribs = tinyMCE.clearArray(new Array());
4566                      r.vAttribsReIsWild = false;
4567                  }
4568  
4569                  or[r.tag] = r;
4570              }
4571          }
4572  
4573          return or;
4574      },
4575  
4576      serializeNodeAsXML : function(n) {
4577          var s, b;
4578  
4579          if (!this.xmlDoc) {
4580              if (this.isIE) {
4581                  try {this.xmlDoc = new ActiveXObject('MSXML2.DOMDocument');} catch (e) {}
4582  
4583                  if (!this.xmlDoc)
4584                      try {this.xmlDoc = new ActiveXObject('Microsoft.XmlDom');} catch (e) {}
4585              } else
4586                  this.xmlDoc = document.implementation.createDocument('', '', null);
4587  
4588              if (!this.xmlDoc)
4589                  alert("Error XML Parser could not be found.");
4590          }
4591  
4592          if (this.xmlDoc.firstChild)
4593              this.xmlDoc.removeChild(this.xmlDoc.firstChild);
4594  
4595          b = this.xmlDoc.createElement("html");
4596          b = this.xmlDoc.appendChild(b);
4597  
4598          this._convertToXML(n, b);
4599  
4600          if (this.isIE)
4601              return this.xmlDoc.xml;
4602          else
4603              return new XMLSerializer().serializeToString(this.xmlDoc);
4604      },
4605  
4606      _convertToXML : function(n, xn) {
4607          var xd, el, i, l, cn, at, no, hc = false;
4608  
4609          if (this._isDuplicate(n))
4610              return;
4611  
4612          xd = this.xmlDoc;
4613  
4614          switch (n.nodeType) {
4615              case 1: // Element
4616                  hc = n.hasChildNodes();
4617  
4618                  el = xd.createElement(n.nodeName.toLowerCase());
4619  
4620                  at = n.attributes;
4621                  for (i=at.length-1; i>-1; i--) {
4622                      no = at[i];
4623  
4624                      if (no.specified && no.nodeValue)
4625                          el.setAttribute(no.nodeName.toLowerCase(), no.nodeValue);
4626                  }
4627  
4628                  if (!hc && !this.closeElementsRe.test(n.nodeName))
4629                      el.appendChild(xd.createTextNode(""));
4630  
4631                  xn = xn.appendChild(el);
4632                  break;
4633  
4634              case 3: // Text
4635                  xn.appendChild(xd.createTextNode(n.nodeValue));
4636                  return;
4637  
4638              case 8: // Comment
4639                  xn.appendChild(xd.createComment(n.nodeValue));
4640                  return;
4641          }
4642  
4643          if (hc) {
4644              cn = n.childNodes;
4645  
4646              for (i=0, l=cn.length; i<l; i++)
4647                  this._convertToXML(cn[i], xn);
4648          }
4649      },
4650  
4651      serializeNodeAsHTML : function(n, inn) {
4652          var en, no, h = '', i, l, t, st, r, cn, va = false, f = false, at, hc, cr;
4653  
4654          this._setupRules(); // Will initialize cleanup rules
4655  
4656          if (this._isDuplicate(n))
4657              return '';
4658  
4659          // Skip non valid child elements
4660          if (n.parentNode && this.childRules != null) {
4661              cr = this.childRules[n.parentNode.nodeName];
4662  
4663              if (typeof(cr) != "undefined" && !cr.test(n.nodeName)) {
4664                  st = true;
4665                  t = null;
4666              }
4667          }
4668  
4669          switch (n.nodeType) {
4670              case 1: // Element
4671                  hc = n.hasChildNodes();
4672  
4673                  if (st)
4674                      break;
4675  
4676                  // MSIE sometimes produces <//tag>
4677                  if ((tinyMCE.isRealIE) && n.nodeName.indexOf('/') != -1)
4678                      break;
4679  
4680                  if (this.vElementsRe.test(n.nodeName) && (!this.iveRe || !this.iveRe.test(n.nodeName)) && !inn) {
4681                      va = true;
4682  
4683                      r = this.rules[n.nodeName];
4684                      if (!r) {
4685                          at = this.rules;
4686                          for (no in at) {
4687                              if (at[no] && at[no].validRe.test(n.nodeName)) {
4688                                  r = at[no];
4689                                  break;
4690                              }
4691                          }
4692                      }
4693  
4694                      en = r.isWild ? n.nodeName.toLowerCase() : r.oTagName;
4695                      f = r.fill;
4696  
4697                      if (r.removeEmpty && !hc)
4698                          return "";
4699  
4700                      t = '<' + en;
4701  
4702                      if (r.vAttribsReIsWild) {
4703                          // Serialize wildcard attributes
4704                          at = n.attributes;
4705                          for (i=at.length-1; i>-1; i--) {
4706                              no = at[i];
4707                              if (no.specified && r.vAttribsRe.test(no.nodeName))
4708                                  t += this._serializeAttribute(n, r, no.nodeName);
4709                          }
4710                      } else {
4711                          // Serialize specific attributes
4712                          for (i=r.vAttribs.length-1; i>-1; i--)
4713                              t += this._serializeAttribute(n, r, r.vAttribs[i]);
4714                      }
4715  
4716                      // Serialize mce_ atts
4717                      if (!this.settings.on_save) {
4718                          at = this.mceAttribs;
4719  
4720                          for (no in at) {
4721                              if (at[no])
4722                                  t += this._serializeAttribute(n, r, at[no]);
4723                          }
4724                      }
4725  
4726                      // Check for required attribs
4727                      if (r.reqAttribsRe && !t.match(r.reqAttribsRe))
4728                          t = null;
4729  
4730                      // Close these
4731                      if (t != null && this.closeElementsRe.test(n.nodeName))
4732                          return t + ' />';
4733  
4734                      if (t != null)
4735                          h += t + '>';
4736  
4737                      if (this.isIE && this.codeElementsRe.test(n.nodeName))
4738                          h += n.innerHTML;
4739                  }
4740              break;
4741  
4742              case 3: // Text
4743                  if (st)
4744                      break;
4745  
4746                  if (n.parentNode && this.codeElementsRe.test(n.parentNode.nodeName))
4747                      return this.isIE ? '' : n.nodeValue;
4748  
4749                  return this.xmlEncode(n.nodeValue);
4750  
4751              case 8: // Comment
4752                  if (st)
4753                      break;
4754  
4755                  return "<!--" + this._trimComment(n.nodeValue) + "-->";
4756          }
4757  
4758          if (hc) {
4759              cn = n.childNodes;
4760  
4761              for (i=0, l=cn.length; i<l; i++)
4762                  h += this.serializeNodeAsHTML(cn[i]);
4763          }
4764  
4765          // Fill empty nodes
4766          if (f && !hc)
4767              h += this.fillStr;
4768  
4769          // End element
4770          if (t != null && va)
4771              h += '</' + en + '>';
4772  
4773          return h;
4774      },
4775  
4776      _serializeAttribute : function(n, r, an) {
4777          var av = '', t, os = this.settings.on_save;
4778  
4779          if (os && (an.indexOf('mce_') == 0 || an.indexOf('_moz') == 0))
4780              return '';
4781  
4782          if (os && this.mceAttribs[an])
4783              av = this._getAttrib(n, this.mceAttribs[an]);
4784  
4785          if (av.length == 0)
4786              av = this._getAttrib(n, an);
4787  
4788          if (av.length == 0 && r.defaultAttribs && (t = r.defaultAttribs[an])) {
4789              av = t;
4790  
4791              if (av == "mce_empty")
4792                  return " " + an + '=""';
4793          }
4794  
4795          if (r.forceAttribs && (t = r.forceAttribs[an]))
4796              av = t;
4797  
4798          if (os && av.length != 0 && this.settings.url_converter.length != 0 && /^(src|href|longdesc)$/.test(an))
4799              av = eval(this.settings.url_converter + '(this, n, av)');
4800  
4801          if (av.length != 0 && r.validAttribValues && r.validAttribValues[an] && !r.validAttribValues[an].test(av))
4802              return "";
4803  
4804          if (av.length != 0 && av == "{$uid}")
4805              av = "uid_" + (this.idCount++);
4806  
4807          if (av.length != 0) {
4808              if (an.indexOf('on') != 0)
4809                  av = this.xmlEncode(av);
4810  
4811              return " " + an + "=" + '"' + av + '"';
4812          }
4813  
4814          return "";
4815      },
4816  
4817      formatHTML : function(h) {
4818          var s = this.settings, p = '', i = 0, li = 0, o = '', l;
4819  
4820          // Replace BR in pre elements to \n
4821          h = h.replace(/<pre([^>]*)>(.*?)<\/pre>/gi, function (a, b, c) {
4822              c = c.replace(/<br\s*\/>/gi, '\n');
4823              return '<pre' + b + '>' + c + '</pre>';
4824          });
4825  
4826          h = h.replace(/\r/g, ''); // Windows sux, isn't carriage return a thing of the past :)
4827          h = '\n' + h;
4828          h = h.replace(new RegExp('\\n\\s+', 'gi'), '\n'); // Remove previous formatting
4829          h = h.replace(this.nlBeforeRe, '\n<$1$2>');
4830          h = h.replace(this.nlAfterRe, '<$1$2>\n');
4831          h = h.replace(this.nlBeforeAfterRe, '\n<$1$2$3>\n');
4832          h += '\n';
4833  
4834          //tinyMCE.debug(h);
4835  
4836          while ((i = h.indexOf('\n', i + 1)) != -1) {
4837              if ((l = h.substring(li + 1, i)).length != 0) {
4838                  if (this.ouRe.test(l) && p.length >= s.indent_levels)
4839                      p = p.substring(s.indent_levels);
4840  
4841                  o += p + l + '\n';
4842      
4843                  if (this.inRe.test(l))
4844                      p += this.inStr;
4845              }
4846  
4847              li = i;
4848          }
4849  
4850          //tinyMCE.debug(h);
4851  
4852          return o;
4853      },
4854  
4855      xmlEncode : function(s) {
4856          var cl = this;
4857  
4858          this._setupEntities(); // Will intialize lookup table
4859  
4860          switch (this.settings.entity_encoding) {
4861              case "raw":
4862                  return tinyMCE.xmlEncode(s);
4863  
4864              case "named":
4865                  return s.replace(new RegExp('[\u007F-\uFFFF<>&"\']', 'g'), function (c, b) {
4866                      b = cl.entities[c.charCodeAt(0)];
4867  
4868                      return b ? '&' + b + ';' : c;
4869                  });
4870  
4871              case "numeric":
4872                  return s.replace(new RegExp('[\u007F-\uFFFF<>&"\']', 'g'), function (c, b) {
4873                      return b ? '&#' + c.charCodeAt(0) + ';' : c;
4874                  });
4875          }
4876  
4877          return s;
4878      },
4879  
4880      split : function(re, s) {
4881          var c = s.split(re);
4882          var i, l, o = new Array();
4883  
4884          for (i=0, l=c.length; i<l; i++) {
4885              if (c[i] != '')
4886                  o[i] = c[i];
4887          }
4888  
4889          return o;
4890      },
4891  
4892      _trimComment : function(s) {
4893          // Remove mce_src, mce_href
4894          s = s.replace(new RegExp('\\smce_src=\"[^\"]*\"', 'gi'), "");
4895          s = s.replace(new RegExp('\\smce_href=\"[^\"]*\"', 'gi'), "");
4896  
4897          return s;
4898      },
4899  
4900      _getAttrib : function(e, n, d) {
4901          if (typeof(d) == "undefined")
4902              d = "";
4903  
4904          if (!e || e.nodeType != 1)
4905              return d;
4906  
4907          var v = e.getAttribute(n, 0);
4908  
4909          if (n == "class" && !v)
4910              v = e.className;
4911  
4912          if (this.isIE && n == "http-equiv")
4913              v = e.httpEquiv;
4914  
4915          if (this.isIE && e.nodeName == "FORM" && n == "enctype" && v == "application/x-www-form-urlencoded")
4916              v = "";
4917  
4918          if (this.isIE && e.nodeName == "INPUT" && n == "size" && v == "20")
4919              v = "";
4920  
4921          if (this.isIE && e.nodeName == "INPUT" && n == "maxlength" && v == "2147483647")
4922              v = "";
4923  
4924          if (n == "style" && !tinyMCE.isOpera)
4925              v = e.style.cssText;
4926  
4927          if (n == 'style')
4928              v = tinyMCE.serializeStyle(tinyMCE.parseStyle(v));
4929  
4930          if (this.settings.on_save && n.indexOf('on') != -1 && this.settings.on_save && v && v != "")
4931              v = tinyMCE.cleanupEventStr(v);
4932  
4933          return (v && v != "") ? '' + v : d;
4934      },
4935  
4936      _urlConverter : function(c, n, v) {
4937          if (!c.settings.on_save)
4938              return tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href, v);
4939          else if (tinyMCE.getParam('convert_urls'))
4940              return eval(tinyMCE.settings.urlconverter_callback + "(v, n, true);");
4941  
4942          return v;
4943      },
4944  
4945      _arrayToRe : function(a, op, be, af) {
4946          var i, r;
4947  
4948          op = typeof(op) == "undefined" ? "gi" : op;
4949          be = typeof(be) == "undefined" ? "^(" : be;
4950          af = typeof(af) == "undefined" ? ")$" : af;
4951  
4952          r = be;
4953  
4954          for (i=0; i<a.length; i++)
4955              r += this._wildcardToRe(a[i]) + (i != a.length-1 ? "|" : "");
4956  
4957          r += af;
4958  
4959          return new RegExp(r, op);
4960      },
4961  
4962      _wildcardToRe : function(s) {
4963          s = s.replace(/\?/g, '(\\S?)');
4964          s = s.replace(/\+/g, '(\\S+)');
4965          s = s.replace(/\*/g, '(\\S*)');
4966  
4967          return s;
4968      },
4969  
4970      _setupEntities : function() {
4971          var n, a, i, s = this.settings;
4972  
4973          // Setup entities
4974          if (!this.entitiesDone) {
4975              if (s.entity_encoding == "named") {
4976                  n = tinyMCE.clearArray(new Array());
4977                  a = this.split(',', s.entities);
4978                  for (i=0; i<a.length; i+=2)
4979                      n[a[i]] = a[i+1];
4980  
4981                  this.entities = n;
4982              }
4983  
4984              this.entitiesDone = true;
4985          }
4986      },
4987  
4988      _setupRules : function() {
4989          var s = this.settings;
4990  
4991          // Setup default rule
4992          if (!this.rulesDone) {
4993              this.addRuleStr(s.valid_elements);
4994              this.addRuleStr(s.extended_valid_elements);
4995              this.addChildRemoveRuleStr(s.valid_child_elements);
4996  
4997              this.rulesDone = true;
4998          }
4999      },
5000  
5001      _isDuplicate : function(n) {
5002          var i;
5003  
5004          if (!this.settings.fix_content_duplication)
5005              return false;
5006  
5007          if (tinyMCE.isRealIE && n.nodeType == 1) {
5008              // Mark elements
5009              if (n.mce_serialized == this.serializationId)
5010                  return true;
5011  
5012              n.setAttribute('mce_serialized', this.serializationId);
5013          } else {
5014              // Search lookup table for text nodes  and comments
5015              for (i=0; i<this.serializedNodes.length; i++) {
5016                  if (this.serializedNodes[i] == n)
5017                      return true;
5018              }
5019  
5020              this.serializedNodes[this.serializedNodes.length] = n;
5021          }
5022  
5023          return false;
5024      }
5025  
5026      };
5027  
5028  /* file:jscripts/tiny_mce/classes/TinyMCE_DOMUtils.class.js */
5029  
5030  TinyMCE_Engine.prototype.createTagHTML = function(tn, a, h) {
5031      var o = '', f = tinyMCE.xmlEncode;
5032  
5033      o = '<' + tn;
5034  
5035      if (a) {
5036          for (n in a) {
5037              if (typeof(a[n]) != 'function' && a[n] != null)
5038                  o += ' ' + f(n) + '="' + f('' + a[n]) + '"';
5039          }
5040      }
5041  
5042      o += !h ? ' />' : '>' + h + '</' + tn + '>';
5043  
5044      return o;
5045  };
5046  
5047  TinyMCE_Engine.prototype.createTag = function(d, tn, a, h) {
5048      var o = d.createElement(tn);
5049  
5050      if (a) {
5051          for (n in a) {
5052              if (typeof(a[n]) != 'function' && a[n] != null)
5053                  tinyMCE.setAttrib(o, n, a[n]);
5054          }
5055      }
5056  
5057      if (h)
5058          o.innerHTML = h;
5059  
5060      return o;
5061  };
5062  
5063  TinyMCE_Engine.prototype.getElementByAttributeValue = function(n, e, a, v) {
5064      return (n = this.getElementsByAttributeValue(n, e, a, v)).length == 0 ? null : n[0];
5065  };
5066  
5067  TinyMCE_Engine.prototype.getElementsByAttributeValue = function(n, e, a, v) {
5068      var i, nl = n.getElementsByTagName(e), o = new Array();
5069  
5070      for (i=0; i<nl.length; i++) {
5071          if (tinyMCE.getAttrib(nl[i], a).indexOf(v) != -1)
5072              o[o.length] = nl[i];
5073      }
5074  
5075      return o;
5076  };
5077  
5078  TinyMCE_Engine.prototype.isBlockElement = function(n) {
5079      return n != null && n.nodeType == 1 && this.blockRegExp.test(n.nodeName);
5080  };
5081  
5082  TinyMCE_Engine.prototype.getParentBlockElement = function(n, r) {
5083      return this.getParentNode(n, function(n) {
5084          return tinyMCE.isBlockElement(n);
5085      }, r);
5086  
5087      return null;
5088  };
5089  
5090  TinyMCE_Engine.prototype.insertAfter = function(n, r){
5091      if (r.nextSibling)
5092          r.parentNode.insertBefore(n, r.nextSibling);
5093      else
5094          r.parentNode.appendChild(n);
5095  };
5096  
5097  TinyMCE_Engine.prototype.setInnerHTML = function(e, h) {
5098      var i, nl, n;
5099  
5100      // Convert all strong/em to b/i in Gecko
5101      if (tinyMCE.isGecko) {
5102          h = h.replace(/<strong/gi, '<b');
5103          h = h.replace(/<em(\/?)/gi, '<i');
5104          h = h.replace(/<em /gi, '<i');
5105          h = h.replace(/<\/strong>/gi, '</b>');
5106          h = h.replace(/<\/em>/gi, '</i>');
5107      }
5108  
5109      if (tinyMCE.isRealIE) {
5110          // Since MSIE handles invalid HTML better that valid XHTML we
5111          // need to make some things invalid. <hr /> gets converted to <hr>.
5112          h = h.replace(/\s\/>/g, '>');
5113  
5114          // Since MSIE auto generated emtpy P tags some times we must tell it to keep the real ones
5115          h = h.replace(/<p([^>]*)>\u00A0?<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
5116          h = h.replace(/<p([^>]*)>\s*&nbsp;\s*<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
5117          h = h.replace(/<p([^>]*)>\s+<\/p>/gi, '<p$1 mce_keep="true">&nbsp;</p>'); // Keep empty paragraphs
5118  
5119          // Remove first comment
5120          e.innerHTML = tinyMCE.uniqueTag + h;
5121          e.firstChild.removeNode(true);
5122  
5123          // Remove weird auto generated empty paragraphs unless it's supposed to be there
5124          nl = e.getElementsByTagName("p");
5125          for (i=nl.length-1; i>=0; i--) {
5126              n = nl[i];
5127  
5128              if (n.nodeName == 'P' && !n.hasChildNodes() && !n.mce_keep)
5129                  n.parentNode.removeChild(n);
5130          }
5131      } else {
5132          h = this.fixGeckoBaseHREFBug(1, e, h);
5133          e.innerHTML = h;
5134          this.fixGeckoBaseHREFBug(2, e, h);
5135      }
5136  };
5137  
5138  TinyMCE_Engine.prototype.getOuterHTML = function(e) {
5139      if (tinyMCE.isIE)
5140          return e.outerHTML;
5141  
5142      var d = e.ownerDocument.createElement("body");
5143      d.appendChild(e.cloneNode(true));
5144      return d.innerHTML;
5145  };
5146  
5147  TinyMCE_Engine.prototype.setOuterHTML = function(e, h, d) {
5148      var d = typeof(d) == "undefined" ? e.ownerDocument : d, i, nl, t;
5149  
5150      if (tinyMCE.isIE && e.nodeType == 1)
5151          e.outerHTML = h;
5152      else {
5153          t = d.createElement("body");
5154          t.innerHTML = h;
5155  
5156          for (i=0, nl=t.childNodes; i<nl.length; i++)
5157              e.parentNode.insertBefore(nl[i].cloneNode(true), e);
5158  
5159          e.parentNode.removeChild(e);
5160      }
5161  };
5162  
5163  TinyMCE_Engine.prototype._getElementById = function(id, d) {
5164      var e, i, j, f;
5165  
5166      if (typeof(d) == "undefined")
5167          d = document;
5168  
5169      e = d.getElementById(id);
5170      if (!e) {
5171          f = d.forms;
5172  
5173          for (i=0; i<f.length; i++) {
5174              for (j=0; j<f[i].elements.length; j++) {
5175                  if (f[i].elements[j].name == id) {
5176                      e = f[i].elements[j];
5177                      break;
5178                  }
5179              }
5180          }
5181      }
5182  
5183      return e;
5184  };
5185  
5186  TinyMCE_Engine.prototype.getNodeTree = function(n, na, t, nn) {
5187      return this.selectNodes(n, function(n) {
5188          return (!t || n.nodeType == t) && (!nn || n.nodeName == nn);
5189      }, na ? na : new Array());
5190  };
5191  
5192  TinyMCE_Engine.prototype.getParentElement = function(n, na, f, r) {
5193      var re = na ? new RegExp('^(' + na.toUpperCase().replace(/,/g, '|') + ')$') : 0, v;
5194  
5195      // Compatiblity with old scripts where f param was a attribute string
5196      if (f && typeof(f) == 'string')
5197          return this.getParentElement(n, na, function(no) {return tinyMCE.getAttrib(no, f) != '';});
5198  
5199      return this.getParentNode(n, function(n) {
5200          return ((n.nodeType == 1 && !re) || (re && re.test(n.nodeName))) && (!f || f(n));
5201      }, r);
5202  };
5203  
5204  TinyMCE_Engine.prototype.getParentNode = function(n, f, r) {
5205      while (n) {
5206          if (n == r)
5207              return null;
5208  
5209          if (f(n))
5210              return n;
5211  
5212          n = n.parentNode;
5213      }
5214  
5215      return null;
5216  };
5217  
5218  TinyMCE_Engine.prototype.getAttrib = function(elm, name, dv) {
5219      var v;
5220  
5221      if (typeof(dv) == "undefined")
5222          dv = "";
5223  
5224      // Not a element
5225      if (!elm || elm.nodeType != 1)
5226          return dv;
5227  
5228      v = elm.getAttribute(name);
5229  
5230      // Try className for class attrib
5231      if (name == "class" && !v)
5232          v = elm.className;
5233  
5234      // Workaround for a issue with Firefox 1.5rc2+
5235      if (tinyMCE.isGecko && name == "src" && elm.src != null && elm.src != "")
5236          v = elm.src;
5237  
5238      // Workaround for a issue with Firefox 1.5rc2+
5239      if (tinyMCE.isGecko && name == "href" && elm.href != null && elm.href != "")
5240          v = elm.href;
5241  
5242      if (name == "http-equiv" && tinyMCE.isIE)
5243          v = elm.httpEquiv;
5244  
5245      if (name == "style" && !tinyMCE.isOpera)
5246          v = elm.style.cssText;
5247  
5248      return (v && v != "") ? v : dv;
5249  };
5250  
5251  TinyMCE_Engine.prototype.setAttrib = function(el, name, va, fix) {
5252      if (typeof(va) == "number" && va != null)
5253          va = "" + va;
5254  
5255      if (fix) {
5256          if (va == null)
5257              va = "";
5258  
5259          va = va.replace(/[^0-9%]/g, '');
5260      }
5261  
5262      if (name == "style")
5263          el.style.cssText = va;
5264  
5265      if (name == "class")
5266          el.className = va;
5267  
5268      if (va != null && va != "" && va != -1)
5269          el.setAttribute(name, va);
5270      else
5271          el.removeAttribute(name);
5272  };
5273  
5274  TinyMCE_Engine.prototype.setStyleAttrib = function(e, n, v) {
5275      e.style[n] = v;
5276  
5277      // Style attrib deleted in IE
5278      if (tinyMCE.isIE && v == null || v == '') {
5279          v = tinyMCE.serializeStyle(tinyMCE.parseStyle(e.style.cssText));
5280          e.style.cssText = v;
5281          e.setAttribute("style", v);
5282      }
5283  };
5284  
5285  TinyMCE_Engine.prototype.switchClass = function(ei, c) {
5286      var e;
5287  
5288      if (tinyMCE.switchClassCache[ei])
5289          e = tinyMCE.switchClassCache[ei];
5290      else
5291          e = tinyMCE.switchClassCache[ei] = document.getElementById(ei);
5292  
5293      if (e) {
5294          // Keep tile mode
5295          if (tinyMCE.settings.button_tile_map && e.className && e.className.indexOf('mceTiledButton') == 0)
5296              c = 'mceTiledButton ' + c;
5297  
5298          e.className = c;
5299      }
5300  };
5301  
5302  TinyMCE_Engine.prototype.getAbsPosition = function(n, cn) {
5303      var l = 0, t = 0;
5304  
5305      while (n && n != cn) {
5306          l += n.offsetLeft;
5307          t += n.offsetTop;
5308          n = n.offsetParent;
5309      }
5310  
5311      return {absLeft : l, absTop : t};
5312  };
5313  
5314  TinyMCE_Engine.prototype.prevNode = function(e, n) {
5315      var a = n.split(','), i;
5316  
5317      while ((e = e.previousSibling) != null) {
5318          for (i=0; i<a.length; i++) {
5319              if (e.nodeName == a[i])
5320                  return e;
5321          }
5322      }
5323  
5324      return null;
5325  };
5326  
5327  TinyMCE_Engine.prototype.nextNode = function(e, n) {
5328      var a = n.split(','), i;
5329  
5330      while ((e = e.nextSibling) != null) {
5331          for (i=0; i<a.length; i++) {
5332              if (e.nodeName == a[i])
5333                  return e;
5334          }
5335      }
5336  
5337      return null;
5338  };
5339  
5340  TinyMCE_Engine.prototype.selectElements = function(n, na, f) {
5341      var i, a = [], nl, x;
5342  
5343      for (x=0, na = na.split(','); x<na.length; x++)
5344          for (i=0, nl = n.getElementsByTagName(na[x]); i<nl.length; i++)
5345              (!f || f(nl[i])) && a.push(nl[i]);
5346  
5347      return a;
5348  };
5349  
5350  TinyMCE_Engine.prototype.selectNodes = function(n, f, a) {
5351      var i;
5352  
5353      if (!a)
5354          a = new Array();
5355  
5356      if (f(n))
5357          a[a.length] = n;
5358  
5359      if (n.hasChildNodes()) {
5360          for (i=0; i<n.childNodes.length; i++)
5361              tinyMCE.selectNodes(n.childNodes[i], f, a);
5362      }
5363  
5364      return a;
5365  };
5366  
5367  TinyMCE_Engine.prototype.addCSSClass = function(e, c, b) {
5368      var o = this.removeCSSClass(e, c);
5369      return e.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
5370  };
5371  
5372  TinyMCE_Engine.prototype.removeCSSClass = function(e, c) {
5373      c = e.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
5374      return e.className = c != ' ' ? c : '';
5375  };
5376  
5377  TinyMCE_Engine.prototype.hasCSSClass = function(n, c) {
5378      return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
5379  };
5380  
5381  TinyMCE_Engine.prototype.renameElement = function(e, n, d) {
5382      var ne, i, ar;
5383  
5384      d = typeof(d) == "undefined" ? tinyMCE.selectedInstance.getDoc() : d;
5385  
5386      if (e) {
5387          ne = d.createElement(n);
5388  
5389          ar = e.attributes;
5390          for (i=ar.length-1; i>-1; i--) {
5391              if (ar[i].specified && ar[i].nodeValue)
5392                  ne.setAttribute(ar[i].nodeName.toLowerCase(), ar[i].nodeValue);
5393          }
5394  
5395          ar = e.childNodes;
5396          for (i=0; i<ar.length; i++)
5397              ne.appendChild(ar[i].cloneNode(true));
5398  
5399          e.parentNode.replaceChild(ne, e);
5400      }
5401  };
5402  
5403  TinyMCE_Engine.prototype.getViewPort = function(w) {
5404      var d = w.document, m = d.compatMode == 'CSS1Compat', b = d.body, de = d.documentElement;
5405  
5406      return {
5407          left : w.pageXOffset || (m ? de.scrollLeft : b.scrollLeft),
5408          top : w.pageYOffset || (m ? de.scrollTop : b.scrollTop),
5409          width : w.innerWidth || (m ? de.clientWidth : b.clientWidth),
5410          height : w.innerHeight || (m ? de.clientHeight : b.clientHeight)
5411      };
5412  };
5413  
5414  /* file:jscripts/tiny_mce/classes/TinyMCE_URL.class.js */
5415  
5416  TinyMCE_Engine.prototype.parseURL = function(url_str) {
5417      var urlParts = new Array();
5418  
5419      if (url_str) {
5420          var pos, lastPos;
5421  
5422          // Parse protocol part
5423          pos = url_str.indexOf('://');
5424          if (pos != -1) {
5425              urlParts['protocol'] = url_str.substring(0, pos);
5426              lastPos = pos + 3;
5427          }
5428  
5429          // Find port or path start
5430          for (var i=lastPos; i<url_str.length; i++) {
5431              var chr = url_str.charAt(i);
5432  
5433              if (chr == ':')
5434                  break;
5435  
5436              if (chr == '/')
5437                  break;
5438          }
5439          pos = i;
5440  
5441          // Get host
5442          urlParts['host'] = url_str.substring(lastPos, pos);
5443  
5444          // Get port
5445          urlParts['port'] = "";
5446          lastPos = pos;
5447          if (url_str.charAt(pos) == ':') {
5448              pos = url_str.indexOf('/', lastPos);
5449              urlParts['port'] = url_str.substring(lastPos+1, pos);
5450          }
5451  
5452          // Get path
5453          lastPos = pos;
5454          pos = url_str.indexOf('?', lastPos);
5455  
5456          if (pos == -1)
5457              pos = url_str.indexOf('#', lastPos);
5458  
5459          if (pos == -1)
5460              pos = url_str.length;
5461  
5462          urlParts['path'] = url_str.substring(lastPos, pos);
5463  
5464          // Get query
5465          lastPos = pos;
5466          if (url_str.charAt(pos) == '?') {
5467              pos = url_str.indexOf('#');
5468              pos = (pos == -1) ? url_str.length : pos;
5469              urlParts['query'] = url_str.substring(lastPos+1, pos);
5470          }
5471  
5472          // Get anchor
5473          lastPos = pos;
5474          if (url_str.charAt(pos) == '#') {
5475              pos = url_str.length;
5476              urlParts['anchor'] = url_str.substring(lastPos+1, pos);
5477          }
5478      }
5479  
5480      return urlParts;
5481  };
5482  
5483  TinyMCE_Engine.prototype.serializeURL = function(up) {
5484      var o = "";
5485  
5486      if (up['protocol'])
5487          o += up['protocol'] + "://";
5488  
5489      if (up['host'])
5490          o += up['host'];
5491  
5492      if (up['port'])
5493          o += ":" + up['port'];
5494  
5495      if (up['path'])
5496          o += up['path'];
5497  
5498      if (up['query'])
5499          o += "?" + up['query'];
5500  
5501      if (up['anchor'])
5502          o += "#" + up['anchor'];
5503  
5504      return o;
5505  };
5506  
5507  TinyMCE_Engine.prototype.convertAbsoluteURLToRelativeURL = function(base_url, url_to_relative) {
5508      var baseURL = this.parseURL(base_url);
5509      var targetURL = this.parseURL(url_to_relative);
5510      var strTok1;
5511      var strTok2;
5512      var breakPoint = 0;
5513      var outPath = "";
5514      var forceSlash = false;
5515  
5516      if (targetURL.path == "")
5517          targetURL.path = "/";
5518      else
5519          forceSlash = true;
5520  
5521      // Crop away last path part
5522      base_url = baseURL.path.substring(0, baseURL.path.lastIndexOf('/'));
5523      strTok1 = base_url.split('/');
5524      strTok2 = targetURL.path.split('/');
5525  
5526      if (strTok1.length >= strTok2.length) {
5527          for (var i=0; i<strTok1.length; i++) {
5528              if (i >= strTok2.length || strTok1[i] != strTok2[i]) {
5529                  breakPoint = i + 1;
5530                  break;
5531              }
5532          }
5533      }
5534  
5535      if (strTok1.length < strTok2.length) {
5536          for (var i=0; i<strTok2.length; i++) {
5537              if (i >= strTok1.length || strTok1[i] != strTok2[i]) {
5538                  breakPoint = i + 1;
5539                  break;
5540              }
5541          }
5542      }
5543  
5544      if (breakPoint == 1)
5545          return targetURL.path;
5546  
5547      for (var i=0; i<(strTok1.length-(breakPoint-1)); i++)
5548          outPath += "../";
5549  
5550      for (var i=breakPoint-1; i<strTok2.length; i++) {
5551          if (i != (breakPoint-1))
5552              outPath += "/" + strTok2[i];
5553          else
5554              outPath += strTok2[i];
5555      }
5556  
5557      targetURL.protocol = null;
5558      targetURL.host = null;
5559      targetURL.port = null;
5560      targetURL.path = outPath == "" && forceSlash ? "/" : outPath;
5561  
5562      // Remove document prefix from local anchors
5563      var fileName = baseURL.path;
5564      var pos;
5565  
5566      if ((pos = fileName.lastIndexOf('/')) != -1)
5567          fileName = fileName.substring(pos + 1);
5568  
5569      // Is local anchor
5570      if (fileName == targetURL.path && targetURL.anchor != "")
5571          targetURL.path = "";
5572  
5573      // If empty and not local anchor force filename or slash
5574      if (targetURL.path == "" && !targetURL.anchor)
5575          targetURL.path = fileName != "" ? fileName : "/";
5576  
5577      return this.serializeURL(targetURL);
5578  };
5579  
5580  TinyMCE_Engine.prototype.convertRelativeToAbsoluteURL = function(base_url, relative_url) {
5581      var baseURL = this.parseURL(base_url), baseURLParts, relURLParts;
5582      var relURL = this.parseURL(relative_url);
5583  
5584      if (relative_url == "" || relative_url.indexOf('://') != -1 || /^(mailto:|javascript:|#|\/)/.test(relative_url))
5585          return relative_url;
5586  
5587      // Split parts
5588      baseURLParts = baseURL['path'].split('/');
5589      relURLParts = relURL['path'].split('/');
5590  
5591      // Remove empty chunks
5592      var newBaseURLParts = new Array();
5593      for (var i=baseURLParts.length-1; i>=0; i--) {
5594          if (baseURLParts[i].length == 0)
5595              continue;
5596  
5597          newBaseURLParts[newBaseURLParts.length] = baseURLParts[i];
5598      }
5599      baseURLParts = newBaseURLParts.reverse();
5600  
5601      // Merge relURLParts chunks
5602      var newRelURLParts = new Array();
5603      var numBack = 0;
5604      for (var i=relURLParts.length-1; i>=0; i--) {
5605          if (relURLParts[i].length == 0 || relURLParts[i] == ".")
5606              continue;
5607  
5608          if (relURLParts[i] == '..') {
5609              numBack++;
5610              continue;
5611          }
5612  
5613          if (numBack > 0) {
5614              numBack--;
5615              continue;
5616          }
5617  
5618          newRelURLParts[newRelURLParts.length] = relURLParts[i];
5619      }
5620  
5621      relURLParts = newRelURLParts.reverse();
5622  
5623      // Remove end from absolute path
5624      var len = baseURLParts.length-numBack;
5625      var absPath = (len <= 0 ? "" : "/") + baseURLParts.slice(0, len).join('/') + "/" + relURLParts.join('/');
5626      var start = "", end = "";
5627  
5628      // Build output URL
5629      relURL.protocol = baseURL.protocol;
5630      relURL.host = baseURL.host;
5631      relURL.port = baseURL.port;
5632  
5633      // Re-add trailing slash if it's removed
5634      if (relURL.path.charAt(relURL.path.length-1) == "/")
5635          absPath += "/";
5636  
5637      relURL.path = absPath;
5638  
5639      return this.serializeURL(relURL);
5640  };
5641  
5642  TinyMCE_Engine.prototype.convertURL = function(url, node, on_save) {
5643      var prot = document.location.protocol;
5644      var host = document.location.hostname;
5645      var port = document.location.port;
5646  
5647      // Pass through file protocol
5648      if (prot == "file:")
5649          return url;
5650  
5651      // Something is wrong, remove weirdness
5652      url = tinyMCE.regexpReplace(url, '(http|https):///', '/');
5653  
5654      // Mailto link or anchor (Pass through)
5655      if (url.indexOf('mailto:') != -1 || url.indexOf('javascript:') != -1 || tinyMCE.regexpReplace(url,'[ \t\r\n\+]|%20','').charAt(0) == "#")
5656          return url;
5657  
5658      // Fix relative/Mozilla
5659      if (!tinyMCE.isIE && !on_save && url.indexOf("://") == -1 && url.charAt(0) != '/')
5660          return tinyMCE.settings['base_href'] + url;
5661  
5662      // Handle relative URLs
5663      if (on_save && tinyMCE.getParam('relative_urls')) {
5664          var curl = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
5665          if (curl.charAt(0) == '/')
5666              curl = tinyMCE.settings['document_base_prefix'] + curl;
5667  
5668          var urlParts = tinyMCE.parseURL(curl);
5669          var tmpUrlParts = tinyMCE.parseURL(tinyMCE.settings['document_base_url']);
5670  
5671          // Force relative
5672          if (urlParts['host'] == tmpUrlParts['host'] && (urlParts['port'] == tmpUrlParts['port']))
5673              return tinyMCE.convertAbsoluteURLToRelativeURL(tinyMCE.settings['document_base_url'], curl);
5674      }
5675  
5676      // Handle absolute URLs
5677      if (!tinyMCE.getParam('relative_urls')) {
5678          var urlParts = tinyMCE.parseURL(url);
5679          var baseUrlParts = tinyMCE.parseURL(tinyMCE.settings['base_href']);
5680  
5681          // Force absolute URLs from relative URLs
5682          url = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], url);
5683  
5684          // If anchor and path is the same page
5685          if (urlParts['anchor'] && urlParts['path'] == baseUrlParts['path'])
5686              return "#" + urlParts['anchor'];
5687      }
5688  
5689      // Remove current domain
5690      if (tinyMCE.getParam('remove_script_host')) {
5691          var start = "", portPart = "";
5692  
5693          if (port != "")
5694              portPart = ":" + port;
5695  
5696          start = prot + "//" + host + portPart + "/";
5697  
5698          if (url.indexOf(start) == 0)
5699              url = url.substring(start.length-1);
5700      }
5701  
5702      return url;
5703  };
5704  
5705  TinyMCE_Engine.prototype.convertAllRelativeURLs = function(body) {
5706      var i, elms, src, href, mhref, msrc;
5707  
5708      // Convert all image URL:s to absolute URL
5709      elms = body.getElementsByTagName("img");
5710      for (i=0; i<elms.length; i++) {
5711          src = tinyMCE.getAttrib(elms[i], 'src');
5712  
5713          msrc = tinyMCE.getAttrib(elms[i], 'mce_src');
5714          if (msrc != "")
5715              src = msrc;
5716  
5717          if (src != "") {
5718              src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], src);
5719              elms[i].setAttribute("src", src);
5720          }
5721      }
5722  
5723      // Convert all link URL:s to absolute URL
5724      elms = body.getElementsByTagName("a");
5725      for (i=0; i<elms.length; i++) {
5726          href = tinyMCE.getAttrib(elms[i], 'href');
5727  
5728          mhref = tinyMCE.getAttrib(elms[i], 'mce_href');
5729          if (mhref != "")
5730              href = mhref;
5731  
5732          if (href && href != "") {
5733              href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings['base_href'], href);
5734              elms[i].setAttribute("href", href);
5735          }
5736      }
5737  };
5738  
5739  /* file:jscripts/tiny_mce/classes/TinyMCE_Array.class.js */
5740  
5741  TinyMCE_Engine.prototype.clearArray = function(a) {
5742      var n;
5743  
5744      for (n in a)
5745          a[n] = null;
5746  
5747      return a;
5748  };
5749  
5750  TinyMCE_Engine.prototype.explode = function(d, s) {
5751      var ar = s.split(d), oar = new Array(), i;
5752  
5753      for (i = 0; i<ar.length; i++) {
5754          if (ar[i] != "")
5755              oar[oar.length] = ar[i];
5756      }
5757  
5758      return oar;
5759  };
5760  
5761  /* file:jscripts/tiny_mce/classes/TinyMCE_Event.class.js */
5762  
5763  TinyMCE_Engine.prototype._setEventsEnabled = function(node, state) {
5764      var evs, x, y, elms, i, event;
5765      var events = ['onfocus','onblur','onclick','ondblclick',
5766                  'onmousedown','onmouseup','onmouseover','onmousemove',
5767                  'onmouseout','onkeypress','onkeydown','onkeydown','onkeyup'];
5768  
5769      evs = tinyMCE.settings['event_elements'].split(',');
5770      for (y=0; y<evs.length; y++){
5771          elms = node.getElementsByTagName(evs[y]);
5772          for (i=0; i<elms.length; i++) {
5773              event = "";
5774  
5775              for (x=0; x<events.length; x++) {
5776                  if ((event = tinyMCE.getAttrib(elms[i], events[x])) != '') {
5777                      event = tinyMCE.cleanupEventStr("" + event);
5778  
5779                      if (!state)
5780                          event = "return true;" + event;
5781                      else
5782                          event = event.replace(/^return true;/gi, '');
5783  
5784                      elms[i].removeAttribute(events[x]);
5785                      elms[i].setAttribute(events[x], event);
5786                  }
5787              }
5788          }
5789      }
5790  };
5791  
5792  TinyMCE_Engine.prototype._eventPatch = function(editor_id) {
5793      var n, inst, win, e;
5794  
5795      // Remove odd, error
5796      if (typeof(tinyMCE) == "undefined")
5797          return true;
5798  
5799      try {
5800          // Try selected instance first
5801          if (tinyMCE.selectedInstance) {
5802              win = tinyMCE.selectedInstance.getWin();
5803  
5804              if (win && win.event) {
5805                  e = win.event;
5806  
5807                  if (!e.target)
5808                      e.target = e.srcElement;
5809  
5810                  TinyMCE_Engine.prototype.handleEvent(e);
5811                  return;
5812              }
5813          }
5814  
5815          // Search for it
5816          for (n in tinyMCE.instances) {
5817              inst = tinyMCE.instances[n];
5818  
5819              if (!tinyMCE.isInstance(inst))
5820                  continue;
5821  
5822              inst.select();
5823              win = inst.getWin();
5824  
5825              if (win && win.event) {
5826                  e = win.event;
5827  
5828                  if (!e.target)
5829                      e.target = e.srcElement;
5830  
5831                  TinyMCE_Engine.prototype.handleEvent(e);
5832                  return;
5833              }
5834          }
5835      } catch (ex) {
5836          // Ignore error if iframe is pointing to external URL
5837      }
5838  };
5839  
5840  TinyMCE_Engine.prototype.findEvent = function(e) {
5841      var n, inst;
5842  
5843      if (e)
5844          return e;
5845  
5846      for (n in tinyMCE.instances) {
5847          inst = tinyMCE.instances[n];
5848  
5849          if (tinyMCE.isInstance(inst) && inst.getWin().event)
5850              return inst.getWin().event;
5851      }
5852  
5853      return null;
5854  };
5855  
5856  TinyMCE_Engine.prototype.unloadHandler = function() {
5857      tinyMCE.triggerSave(true, true);
5858  };
5859  
5860  TinyMCE_Engine.prototype.addEventHandlers = function(inst) {
5861      this.setEventHandlers(inst, 1);
5862  };
5863  
5864  TinyMCE_Engine.prototype.setEventHandlers = function(inst, s) {
5865      var doc = inst.getDoc(), ie, ot, i, f = s ? tinyMCE.addEvent : tinyMCE.removeEvent;
5866  
5867      ie = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'controlselect', 'dblclick'];
5868      ot = ['keypress', 'keyup', 'keydown', 'click', 'mouseup', 'mousedown', 'focus', 'blur', 'dragdrop'];
5869  
5870      inst.switchSettings();
5871  
5872      if (tinyMCE.isIE) {
5873          for (i=0; i<ie.length; i++)
5874              f(doc, ie[i], TinyMCE_Engine.prototype._eventPatch);
5875      } else {
5876          for (i=0; i<ot.length; i++)
5877              f(doc, ot[i], tinyMCE.handleEvent);
5878  
5879          eval('try { doc.designMode = "On"; } catch(e) {}'); // Force designmode
5880      }
5881  };
5882  
5883  TinyMCE_Engine.prototype.onMouseMove = function() {
5884      var inst, lh;
5885  
5886      // Fix for IE7 bug where it's not restoring hover on anchors correctly
5887      if (tinyMCE.lastHover) {
5888          lh = tinyMCE.lastHover;
5889  
5890          // Call out on menus and refresh class on normal buttons
5891          if (lh.className.indexOf('mceMenu') != -1)
5892              tinyMCE._menuButtonEvent('out', lh);
5893          else
5894              lh.className = lh.className;
5895  
5896          tinyMCE.lastHover = null;
5897      }
5898  
5899      if (!tinyMCE.hasMouseMoved) {
5900          inst = tinyMCE.selectedInstance;
5901  
5902          // Workaround for bug #1437457 (Odd MSIE bug)
5903          if (inst.isFocused) {
5904              inst.undoBookmark = inst.selection.getBookmark();
5905              tinyMCE.hasMouseMoved = true;
5906          }
5907      }
5908  
5909  //    tinyMCE.cancelEvent(inst.getWin().event);
5910  //    return false;
5911  };
5912  
5913  TinyMCE_Engine.prototype.cancelEvent = function(e) {
5914      if (!e)
5915          return false;
5916  
5917      if (tinyMCE.isIE) {
5918          e.returnValue = false;
5919          e.cancelBubble = true;
5920      } else {
5921          e.preventDefault();
5922          e.stopPropagation && e.stopPropagation();
5923      }
5924  
5925      return false;
5926  };
5927  
5928  TinyMCE_Engine.prototype.addEvent = function(o, n, h) {
5929      // Add cleanup for all non unload events
5930      if (n != 'unload') {
5931  		function clean() {
5932              var ex;
5933  
5934              try {
5935                  tinyMCE.removeEvent(o, n, h);
5936                  tinyMCE.removeEvent(window, 'unload', clean);
5937                  o = n = h = null;
5938              } catch (ex) {
5939                  // IE may produce access denied exception on unload
5940              }
5941          }
5942  
5943          // Add memory cleaner
5944          tinyMCE.addEvent(window, 'unload', clean);
5945      }
5946  
5947      if (o.attachEvent)
5948          o.attachEvent("on" + n, h);
5949      else
5950          o.addEventListener(n, h, false);
5951  };
5952  
5953  TinyMCE_Engine.prototype.removeEvent = function(o, n, h) {
5954      if (o.detachEvent)
5955          o.detachEvent("on" + n, h);
5956      else
5957          o.removeEventListener(n, h, false);
5958  };
5959  
5960  TinyMCE_Engine.prototype.addSelectAccessibility = function(e, s, w) {
5961      // Add event handlers 
5962      if (!s._isAccessible) {
5963          s.onkeydown = tinyMCE.accessibleEventHandler;
5964          s.onblur = tinyMCE.accessibleEventHandler;
5965          s._isAccessible = true;
5966          s._win = w;
5967      }
5968  
5969      return false;
5970  };
5971  
5972  TinyMCE_Engine.prototype.accessibleEventHandler = function(e) {
5973      var win = this._win;
5974      e = tinyMCE.isIE ? win.event : e;
5975      var elm = tinyMCE.isIE ? e.srcElement : e.target;
5976  
5977      // Unpiggyback onchange on blur
5978      if (e.type == "blur") {
5979          if (elm.oldonchange) {
5980              elm.onchange = elm.oldonchange;
5981              elm.oldonchange = null;
5982          }
5983  
5984          return true;
5985      }
5986  
5987      // Piggyback onchange
5988      if (elm.nodeName == "SELECT" && !elm.oldonchange) {
5989          elm.oldonchange = elm.onchange;
5990          elm.onchange = null;
5991      }
5992  
5993      // Execute onchange and remove piggyback
5994      if (e.keyCode == 13 || e.keyCode == 32) {
5995          elm.onchange = elm.oldonchange;
5996          elm.onchange();
5997          elm.oldonchange = null;
5998  
5999          tinyMCE.cancelEvent(e);
6000          return false;
6001      }
6002  
6003      return true;
6004  };
6005  
6006  TinyMCE_Engine.prototype._resetIframeHeight = function() {
6007      var ife;
6008  
6009      if (tinyMCE.isRealIE) {
6010          ife = tinyMCE.selectedInstance.iframeElement;
6011  
6012  /*        if (ife._oldWidth) {
6013              ife.style.width = ife._oldWidth;
6014              ife.width = ife._oldWidth;
6015          }*/
6016  
6017          if (ife._oldHeight) {
6018              ife.style.height = ife._oldHeight;
6019              ife.height = ife._oldHeight;
6020          }
6021      }
6022  };
6023  
6024  /* file:jscripts/tiny_mce/classes/TinyMCE_Selection.class.js */
6025  
6026  function TinyMCE_Selection(inst) {
6027      this.instance = inst;
6028  };
6029  
6030  TinyMCE_Selection.prototype = {
6031      getSelectedHTML : function() {
6032          var inst = this.instance;
6033          var e, r = this.getRng(), h;
6034  
6035          if (!r)
6036              return null;
6037  
6038          e = document.createElement("body");
6039  
6040          if (r.cloneContents)
6041              e.appendChild(r.cloneContents());
6042          else if (typeof(r.item) != 'undefined' || typeof(r.htmlText) != 'undefined')
6043              e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
6044          else
6045              e.innerHTML = r.toString(); // Failed, use text for now
6046  
6047          h = tinyMCE._cleanupHTML(inst, inst.contentDocument, inst.settings, e, e, false, true, false);
6048  
6049          // When editing always use fonts internaly
6050          if (tinyMCE.getParam("convert_fonts_to_spans"))
6051              tinyMCE.convertSpansToFonts(inst.getDoc());
6052  
6053          return h;
6054      },
6055  
6056      getSelectedText : function() {
6057          var inst = this.instance;
6058          var d, r, s, t;
6059  
6060          if (tinyMCE.isIE) {
6061              d = inst.getDoc();
6062  
6063              if (d.selection.type == "Text") {
6064                  r = d.selection.createRange();
6065                  t = r.text;
6066              } else
6067                  t = '';
6068          } else {
6069              s = this.getSel();
6070  
6071              if (s && s.toString)
6072                  t = s.toString();
6073              else
6074                  t = '';
6075          }
6076  
6077          return t;
6078      },
6079  
6080      getBookmark : function(simple) {
6081          var inst = this.instance;
6082          var rng = this.getRng();
6083          var doc = inst.getDoc(), b = inst.getBody();
6084          var sp, le, s, e, nl, i, si, ei, w;
6085          var trng, sx, sy, xx = -999999999, vp = inst.getViewPort();
6086  
6087          sx = vp.left;
6088          sy = vp.top;
6089  
6090          if (tinyMCE.isSafari || tinyMCE.isOpera || simple)
6091              return {rng : rng, scrollX : sx, scrollY : sy};
6092  
6093          if (tinyMCE.isIE) {
6094              if (rng.item) {
6095                  e = rng.item(0);
6096  
6097                  nl = b.getElementsByTagName(e.nodeName);
6098                  for (i=0; i<nl.length; i++) {
6099                      if (e == nl[i]) {
6100                          sp = i;
6101                          break;
6102                      }
6103                  }
6104  
6105                  return {
6106                      tag : e.nodeName,
6107                      index : sp,
6108                      scrollX : sx,
6109                      scrollY : sy
6110                  };
6111              } else {
6112                  trng = doc.body.createTextRange();
6113                  trng.moveToElementText(inst.getBody());
6114                  trng.collapse(true);
6115                  bp = Math.abs(trng.move('character', xx));
6116  
6117                  trng = rng.duplicate();
6118                  trng.collapse(true);
6119                  sp = Math.abs(trng.move('character', xx));
6120  
6121                  trng = rng.duplicate();
6122                  trng.collapse(false);
6123                  le = Math.abs(trng.move('character', xx)) - sp;
6124  
6125                  return {
6126                      start : sp - bp,
6127                      length : le,
6128                      scrollX : sx,
6129                      scrollY : sy
6130                  };
6131              }
6132          }
6133  
6134          if (tinyMCE.isGecko) {
6135              s = this.getSel();
6136              e = this.getFocusElement();
6137  
6138              if (!s)
6139                  return null;
6140  
6141              if (e && e.nodeName == 'IMG') {
6142                  /*nl = b.getElementsByTagName('IMG');
6143                  for (i=0; i<nl.length; i++) {
6144                      if (e == nl[i]) {
6145                          sp = i;
6146                          break;
6147                      }
6148                  }*/
6149  
6150                  return {
6151                      start : -1,
6152                      end : -1,
6153                      index : sp,
6154                      scrollX : sx,
6155                      scrollY : sy
6156                  };
6157              }
6158  
6159              // Caret or selection
6160              if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
6161                  e = this._getPosText(b, s.anchorNode, s.focusNode);
6162  
6163                  if (!e)
6164                      return {scrollX : sx, scrollY : sy};
6165  
6166                  return {
6167                      start : e.start + s.anchorOffset,
6168                      end : e.end + s.focusOffset,
6169                      scrollX : sx,
6170                      scrollY : sy
6171                  };
6172              } else {
6173                  e = this._getPosText(b, rng.startContainer, rng.endContainer);
6174  
6175                  if (!e)
6176                      return {scrollX : sx, scrollY : sy};
6177  
6178                  return {
6179                      start : e.start + rng.startOffset,
6180                      end : e.end + rng.endOffset,
6181                      scrollX : sx,
6182                      scrollY : sy
6183                  };
6184              }
6185          }
6186  
6187          return null;
6188      },
6189  
6190      moveToBookmark : function(bookmark) {
6191          var inst = this.instance;
6192          var rng, nl, i, ex, b = inst.getBody(), sd;
6193          var doc = inst.getDoc();
6194          var win = inst.getWin();
6195          var sel = this.getSel();
6196  
6197          if (!bookmark)
6198              return false;
6199  
6200          if (tinyMCE.isSafari) {
6201              sel.setBaseAndExtent(bookmark.rng.startContainer, bookmark.rng.startOffset, bookmark.rng.endContainer, bookmark.rng.endOffset);
6202              return true;
6203          }
6204  
6205          if (tinyMCE.isRealIE) {
6206              if (bookmark.rng) {
6207                  try {
6208                      bookmark.rng.select();
6209                  } catch (ex) {
6210                      // Ignore
6211                  }
6212  
6213                  return true;
6214              }
6215  
6216              win.focus();
6217  
6218              if (bookmark.tag) {
6219                  rng = b.createControlRange();
6220  
6221                  nl = b.getElementsByTagName(bookmark.tag);
6222  
6223                  if (nl.length > bookmark.index) {
6224                      try {
6225                          rng.addElement(nl[bookmark.index]);
6226                      } catch (ex) {
6227                          // Might be thrown if the node no longer exists
6228                      }
6229                  }
6230              } else {
6231                  // Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
6232                  try {
6233                      // Incorrect bookmark
6234                      if (bookmark.start < 0)
6235                          return true;
6236  
6237                      rng = inst.getSel().createRange();
6238                      rng.moveToElementText(inst.getBody());
6239                      rng.collapse(true);
6240                      rng.moveStart('character', bookmark.start);
6241                      rng.moveEnd('character', bookmark.length);
6242                  } catch (ex) {
6243                      return true;
6244                  }
6245              }
6246  
6247              rng.select();
6248  
6249              win.scrollTo(bookmark.scrollX, bookmark.scrollY);
6250              return true;
6251          }
6252  
6253          if (tinyMCE.isGecko || tinyMCE.isOpera) {
6254              if (bookmark.rng) {
6255                  sel.removeAllRanges();
6256                  sel.addRange(bookmark.rng);
6257              }
6258  
6259              if (bookmark.start != -1 && bookmark.end != -1) {
6260                  try {
6261                      sd = this._getTextPos(b, bookmark.start, bookmark.end);
6262                      rng = doc.createRange();
6263                      rng.setStart(sd.startNode, sd.startOffset);
6264                      rng.setEnd(sd.endNode, sd.endOffset);
6265                      sel.removeAllRanges();
6266                      sel.addRange(rng);
6267                      win.focus();
6268                  } catch (ex) {
6269                      // Ignore
6270                  }
6271              }
6272  
6273              /*
6274              if (typeof(bookmark.index) != 'undefined') {
6275                  tinyMCE.selectElements(b, 'IMG', function (n) {
6276                      if (bookmark.index-- == 0) {
6277                          // Select image in Gecko here
6278                      }
6279  
6280                      return false;
6281                  });
6282              }
6283              */
6284  
6285              win.scrollTo(bookmark.scrollX, bookmark.scrollY);
6286              return true;
6287          }
6288  
6289          return false;
6290      },
6291  
6292      _getPosText : function(r, sn, en) {
6293          var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
6294  
6295          while ((n = w.nextNode()) != null) {
6296              if (n == sn)
6297                  d.start = p;
6298  
6299              if (n == en) {
6300                  d.end = p;
6301                  return d;
6302              }
6303  
6304              p += n.nodeValue ? n.nodeValue.length : 0;
6305          }
6306  
6307          return null;
6308      },
6309  
6310      _getTextPos : function(r, sp, ep) {
6311          var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
6312  
6313          while ((n = w.nextNode()) != null) {
6314              p += n.nodeValue ? n.nodeValue.length : 0;
6315  
6316              if (p >= sp && !d.startNode) {
6317                  d.startNode = n;
6318                  d.startOffset = sp - (p - n.nodeValue.length);
6319              }
6320  
6321              if (p >= ep) {
6322                  d.endNode = n;
6323                  d.endOffset = ep - (p - n.nodeValue.length);
6324  
6325                  return d;
6326              }
6327          }
6328  
6329          return null;
6330      },
6331  
6332      selectNode : function(node, collapse, select_text_node, to_start) {
6333          var inst = this.instance, sel, rng, nodes;
6334  
6335          if (!node)
6336              return;
6337  
6338          if (typeof(collapse) == "undefined")
6339              collapse = true;
6340  
6341          if (typeof(select_text_node) == "undefined")
6342              select_text_node = false;
6343  
6344          if (typeof(to_start) == "undefined")
6345              to_start = true;
6346  
6347          if (inst.settings.auto_resize)
6348              inst.resizeToContent();
6349  
6350          if (tinyMCE.isRealIE) {
6351              rng = inst.getDoc().body.createTextRange();
6352  
6353              try {
6354                  rng.moveToElementText(node);
6355  
6356                  if (collapse)
6357                      rng.collapse(to_start);
6358  
6359                  rng.select();
6360              } catch (e) {
6361                  // Throws illigal agrument in MSIE some times
6362              }
6363          } else {
6364              sel = this.getSel();
6365  
6366              if (!sel)
6367                  return;
6368  
6369              if (tinyMCE.isSafari) {
6370                  sel.setBaseAndExtent(node, 0, node, node.innerText.length);
6371  
6372                  if (collapse) {
6373                      if (to_start)
6374                          sel.collapseToStart();
6375                      else
6376                          sel.collapseToEnd();
6377                  }
6378  
6379                  this.scrollToNode(node);
6380  
6381                  return;
6382              }
6383  
6384              rng = inst.getDoc().createRange();
6385  
6386              if (select_text_node) {
6387                  // Find first textnode in tree
6388                  nodes = tinyMCE.getNodeTree(node, new Array(), 3);
6389                  if (nodes.length > 0)
6390                      rng.selectNodeContents(nodes[0]);
6391                  else
6392                      rng.selectNodeContents(node);
6393              } else
6394                  rng.selectNode(node);
6395  
6396              if (collapse) {
6397                  // Special treatment of textnode collapse
6398                  if (!to_start && node.nodeType == 3) {
6399                      rng.setStart(node, node.nodeValue.length);
6400                      rng.setEnd(node, node.nodeValue.length);
6401                  } else
6402                      rng.collapse(to_start);
6403              }
6404  
6405              sel.removeAllRanges();
6406              sel.addRange(rng);
6407          }
6408  
6409          this.scrollToNode(node);
6410  
6411          // Set selected element
6412          tinyMCE.selectedElement = null;
6413          if (node.nodeType == 1)
6414              tinyMCE.selectedElement = node;
6415      },
6416  
6417      scrollToNode : function(node) {
6418          var inst = this.instance, w = inst.getWin(), vp = inst.getViewPort(), pos = tinyMCE.getAbsPosition(node), cvp, p, cwin;
6419  
6420          // Only scroll if out of visible area
6421          if (pos.absLeft < vp.left || pos.absLeft > vp.left + vp.width || pos.absTop < vp.top || pos.absTop > vp.top + (vp.height-25))
6422              w.scrollTo(pos.absLeft, pos.absTop - vp.height + 25);
6423  
6424          // Scroll container window
6425          if (inst.settings.auto_resize) {
6426              cwin = inst.getContainerWin();
6427              cvp = tinyMCE.getViewPort(cwin);
6428              p = this.getAbsPosition(node);
6429  
6430              if (p.absLeft < cvp.left || p.absLeft > cvp.left + cvp.width || p.absTop < cvp.top || p.absTop > cvp.top + cvp.height)
6431                  cwin.scrollTo(p.absLeft, p.absTop - cvp.height + 25);
6432          }
6433      },
6434  
6435      getAbsPosition : function(n) {
6436          var pos = tinyMCE.getAbsPosition(n), ipos = tinyMCE.getAbsPosition(this.instance.iframeElement);
6437  
6438          return {
6439              absLeft : ipos.absLeft + pos.absLeft,
6440              absTop : ipos.absTop + pos.absTop
6441          };
6442      },
6443  
6444      getSel : function() {
6445          var inst = this.instance;
6446  
6447          if (tinyMCE.isRealIE)
6448              return inst.getDoc().selection;
6449  
6450          return inst.contentWindow.getSelection();
6451      },
6452  
6453      getRng : function() {
6454          var s = this.getSel();
6455  
6456          if (s == null)
6457              return null;
6458  
6459          if (tinyMCE.isRealIE)
6460              return s.createRange();
6461  
6462          if (tinyMCE.isSafari && !s.getRangeAt)
6463              return '' + window.getSelection();
6464  
6465          return s.getRangeAt(0);
6466      },
6467  
6468      getFocusElement : function() {
6469          var inst = this.instance, doc, rng, sel, elm;
6470  
6471          if (tinyMCE.isRealIE) {
6472              doc = inst.getDoc();
6473              rng = doc.selection.createRange();
6474  
6475      //        if (rng.collapse)
6476      //            rng.collapse(true);
6477  
6478              elm = rng.item ? rng.item(0) : rng.parentElement();
6479          } else {
6480              if (!tinyMCE.isSafari && inst.isHidden())
6481                  return inst.getBody();
6482  
6483              sel = this.getSel();
6484              rng = this.getRng();
6485  
6486              if (!sel || !rng)
6487                  return null;
6488  
6489              elm = rng.commonAncestorContainer;
6490              //elm = (sel && sel.anchorNode) ? sel.anchorNode : null;
6491  
6492              // Handle selection a image or other control like element such as anchors
6493              if (!rng.collapsed) {
6494                  // Is selection small
6495                  if (rng.startContainer == rng.endContainer) {
6496                      if (rng.startOffset - rng.endOffset < 2) {
6497                          if (rng.startContainer.hasChildNodes())
6498                              elm = rng.startContainer.childNodes[rng.startOffset];
6499                      }
6500                  }
6501              }
6502  
6503              // Get the element parent of the node
6504              elm = tinyMCE.getParentElement(elm);
6505  
6506              //if (tinyMCE.selectedElement != null && tinyMCE.selectedElement.nodeName.toLowerCase() == "img")
6507              //    elm = tinyMCE.selectedElement;
6508          }
6509  
6510          return elm;
6511      }
6512  
6513      };
6514  
6515  /* file:jscripts/tiny_mce/classes/TinyMCE_UndoRedo.class.js */
6516  
6517  function TinyMCE_UndoRedo(inst) {
6518      this.instance = inst;
6519      this.undoLevels = new Array();
6520      this.undoIndex = 0;
6521      this.typingUndoIndex = -1;
6522      this.undoRedo = true;
6523  };
6524  
6525  TinyMCE_UndoRedo.prototype = {
6526      add : function(l) {
6527          var b, customUndoLevels, newHTML, inst = this.instance, i, ul, ur;
6528  
6529          if (l) {
6530              this.undoLevels[this.undoLevels.length] = l;
6531              return true;
6532          }
6533  
6534          if (this.typingUndoIndex != -1) {
6535              this.undoIndex = this.typingUndoIndex;
6536  
6537              if (tinyMCE.typingUndoIndex != -1)
6538                  tinyMCE.undoIndex = tinyMCE.typingUndoIndex;
6539          }
6540  
6541          newHTML = tinyMCE.trim(inst.getBody().innerHTML);
6542          if (this.undoLevels[this.undoIndex] && newHTML != this.undoLevels[this.undoIndex].content) {
6543              //tinyMCE.debug(newHTML, this.undoLevels[this.undoIndex].content);
6544  
6545              tinyMCE.dispatchCallback(inst, 'onchange_callback', 'onChange', inst);
6546  
6547              // Time to compress
6548              customUndoLevels = tinyMCE.settings['custom_undo_redo_levels'];
6549              if (customUndoLevels != -1 && this.undoLevels.length > customUndoLevels) {
6550                  for (i=0; i<this.undoLevels.length-1; i++)
6551                      this.undoLevels[i] = this.undoLevels[i+1];
6552  
6553                  this.undoLevels.length--;
6554                  this.undoIndex--;
6555  
6556                  // Todo: Implement global undo/redo logic here
6557              }
6558  
6559              b = inst.undoBookmark;
6560  
6561              if (!b)
6562                  b = inst.selection.getBookmark();
6563  
6564              this.undoIndex++;
6565              this.undoLevels[this.undoIndex] = {
6566                  content : newHTML,
6567                  bookmark : b
6568              };
6569  
6570              // Remove all above from global undo/redo
6571              ul = tinyMCE.undoLevels;
6572              for (i=tinyMCE.undoIndex + 1; i<ul.length; i++) {
6573                  ur = ul[i].undoRedo;
6574  
6575                  if (ur.undoIndex == ur.undoLevels.length -1)
6576                      ur.undoIndex--;
6577  
6578                  ur.undoLevels.length--;
6579              }
6580  
6581              // Add global undo level
6582              tinyMCE.undoLevels[tinyMCE.undoIndex++] = inst;
6583              tinyMCE.undoLevels.length = tinyMCE.undoIndex;
6584  
6585              this.undoLevels.length = this.undoIndex + 1;
6586  
6587              return true;
6588          }
6589  
6590          return false;
6591      },
6592  
6593      undo : function() {
6594          var inst = this.instance;
6595  
6596          // Do undo
6597          if (this.undoIndex > 0) {
6598              this.undoIndex--;
6599  
6600              tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
6601              inst.repaint();
6602  
6603              if (inst.settings.custom_undo_redo_restore_selection)
6604                  inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
6605          }
6606      },
6607  
6608      redo : function() {
6609          var inst = this.instance;
6610  
6611          tinyMCE.execCommand("mceEndTyping");
6612  
6613          if (this.undoIndex < (this.undoLevels.length-1)) {
6614              this.undoIndex++;
6615  
6616              tinyMCE.setInnerHTML(inst.getBody(), this.undoLevels[this.undoIndex].content);
6617              inst.repaint();
6618  
6619              if (inst.settings.custom_undo_redo_restore_selection)
6620                  inst.selection.moveToBookmark(this.undoLevels[this.undoIndex].bookmark);
6621          }
6622  
6623          tinyMCE.triggerNodeChange();
6624      }
6625  
6626      };
6627  
6628  /* file:jscripts/tiny_mce/classes/TinyMCE_ForceParagraphs.class.js */
6629  
6630  var TinyMCE_ForceParagraphs = {
6631      _insertPara : function(inst, e) {
6632          var doc = inst.getDoc(), sel = inst.getSel(), body = inst.getBody(), win = inst.contentWindow, rng = sel.getRangeAt(0);
6633          var rootElm = doc.documentElement, blockName = "P", startNode, endNode, startBlock, endBlock;
6634          var rngBefore, rngAfter, direct, startNode, startOffset, endNode, endOffset, b = tinyMCE.isOpera ? inst.selection.getBookmark() : null;
6635          var paraBefore, paraAfter, startChop, endChop, contents;
6636  
6637  		function isEmpty(para) {
6638  			function isEmptyHTML(html) {
6639                  return html.replace(new RegExp('[ \t\r\n]+', 'g'), '').toLowerCase() == "";
6640              }
6641  
6642              // Check for images
6643              if (para.getElementsByTagName("img").length > 0)
6644                  return false;
6645  
6646              // Check for tables
6647              if (para.getElementsByTagName("table").length > 0)
6648                  return false;
6649  
6650              // Check for HRs
6651              if (para.getElementsByTagName("hr").length > 0)
6652                  return false;
6653  
6654              // Check all textnodes
6655              var nodes = tinyMCE.getNodeTree(para, new Array(), 3);
6656              for (var i=0; i<nodes.length; i++) {
6657                  if (!isEmptyHTML(nodes[i].nodeValue))
6658                      return false;
6659              }
6660  
6661              // No images, no tables, no hrs, no text content then it's empty
6662              return true;
6663          }
6664  
6665      //    tinyMCE.debug(body.innerHTML);
6666  
6667      //    debug(e.target, sel.anchorNode.nodeName, sel.focusNode.nodeName, rng.startContainer, rng.endContainer, rng.commonAncestorContainer, sel.anchorOffset, sel.focusOffset, rng.toString());
6668  
6669          // Setup before range
6670          rngBefore = doc.createRange();
6671          rngBefore.setStart(sel.anchorNode, sel.anchorOffset);
6672          rngBefore.collapse(true);
6673  
6674          // Setup after range
6675          rngAfter = doc.createRange();
6676          rngAfter.setStart(sel.focusNode, sel.focusOffset);
6677          rngAfter.collapse(true);
6678  
6679          // Setup start/end points
6680          direct = rngBefore.compareBoundaryPoints(rngBefore.START_TO_END, rngAfter) < 0;
6681          startNode = direct ? sel.anchorNode : sel.focusNode;
6682          startOffset = direct ? sel.anchorOffset : sel.focusOffset;
6683          endNode = direct ? sel.focusNode : sel.anchorNode;
6684          endOffset = direct ? sel.focusOffset : sel.anchorOffset;
6685  
6686          startNode = startNode.nodeName == "BODY" ? startNode.firstChild : startNode;
6687          endNode = endNode.nodeName == "BODY" ? endNode.firstChild : endNode;
6688  
6689          // Get block elements
6690          startBlock = inst.getParentBlockElement(startNode);
6691          endBlock = inst.getParentBlockElement(endNode);
6692  
6693          // If absolute force paragraph generation within
6694          if (startBlock && new RegExp('absolute|relative|static', 'gi').test(startBlock.style.position))
6695              startBlock = null;
6696  
6697          if (endBlock && new RegExp('absolute|relative|static', 'gi').test(endBlock.style.position))
6698              endBlock = null;
6699  
6700          // Use current block name
6701          if (startBlock != null) {
6702              blockName = startBlock.nodeName;
6703  
6704              // Use P instead
6705              if (blockName == "TD" || blockName == "TABLE" || (blockName == "DIV" && new RegExp('left|right', 'gi').test(startBlock.style.cssFloat)))
6706                  blockName = "P";
6707          }
6708  
6709          // Within a list use normal behaviour
6710          if (tinyMCE.getParentElement(startBlock, "OL,UL", null, body) != null)
6711              return false;
6712  
6713          // Within a table create new paragraphs
6714          if ((startBlock != null && startBlock.nodeName == "TABLE") || (endBlock != null && endBlock.nodeName == "TABLE"))
6715              startBlock = endBlock = null;
6716  
6717          // Setup new paragraphs
6718          paraBefore = (startBlock != null && startBlock.nodeName == blockName) ? startBlock.cloneNode(false) : doc.createElement(blockName);
6719          paraAfter = (endBlock != null && endBlock.nodeName == blockName) ? endBlock.cloneNode(false) : doc.createElement(blockName);
6720  
6721          // Is header, then force paragraph under
6722          if (/^(H[1-6])$/.test(blockName))
6723              paraAfter = doc.createElement("p");
6724  
6725          // Setup chop nodes
6726          startChop = startNode;
6727          endChop = endNode;
6728  
6729          // Get startChop node
6730          node = startChop;
6731          do {
6732              if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
6733                  break;
6734  
6735              startChop = node;
6736          } while ((node = node.previousSibling ? node.previousSibling : node.parentNode));
6737  
6738          // Get endChop node
6739          node = endChop;
6740          do {
6741              if (node == body || node.nodeType == 9 || tinyMCE.isBlockElement(node))
6742                  break;
6743  
6744              endChop = node;
6745          } while ((node = node.nextSibling ? node.nextSibling : node.parentNode));
6746  
6747          // Fix when only a image is within the TD
6748          if (startChop.nodeName == "TD")
6749              startChop = startChop.firstChild;
6750  
6751          if (endChop.nodeName == "TD")
6752              endChop = endChop.lastChild;
6753  
6754          // If not in a block element
6755          if (startBlock == null) {
6756              // Delete selection
6757              rng.deleteContents();
6758  
6759              if (!tinyMCE.isSafari)
6760                  sel.removeAllRanges();
6761  
6762              if (startChop != rootElm && endChop != rootElm) {
6763                  // Insert paragraph before
6764                  rngBefore = rng.cloneRange();
6765  
6766                  if (startChop == body)
6767                      rngBefore.setStart(startChop, 0);
6768                  else
6769                      rngBefore.setStartBefore(startChop);
6770  
6771                  paraBefore.appendChild(rngBefore.cloneContents());
6772  
6773                  // Insert paragraph after
6774                  if (endChop.parentNode.nodeName == blockName)
6775                      endChop = endChop.parentNode;
6776  
6777                  // If not after image
6778                  //if (rng.startContainer.nodeName != "BODY" && rng.endContainer.nodeName != "BODY")
6779                      rng.setEndAfter(endChop);
6780  
6781                  if (endChop.nodeName != "#text" && endChop.nodeName != "BODY")
6782                      rngBefore.setEndAfter(endChop);
6783  
6784                  contents = rng.cloneContents();
6785                  if (contents.firstChild && (contents.firstChild.nodeName == blockName || contents.firstChild.nodeName == "BODY"))
6786                      paraAfter.innerHTML = contents.firstChild.innerHTML;
6787                  else
6788                      paraAfter.appendChild(contents);
6789  
6790                  // Check if it's a empty paragraph
6791                  if (isEmpty(paraBefore))
6792                      paraBefore.innerHTML = "&nbsp;";
6793  
6794                  // Check if it's a empty paragraph
6795                  if (isEmpty(paraAfter))
6796                      paraAfter.innerHTML = "&nbsp;";
6797  
6798                  // Delete old contents
6799                  rng.deleteContents();
6800                  rngAfter.deleteContents();
6801                  rngBefore.deleteContents();
6802  
6803                  // Insert new paragraphs
6804                  if (tinyMCE.isOpera) {
6805                      paraBefore.normalize();
6806                      rngBefore.insertNode(paraBefore);
6807                      paraAfter.normalize();
6808                      rngBefore.insertNode(paraAfter);
6809                  } else {
6810                      paraAfter.normalize();
6811                      rngBefore.insertNode(paraAfter);
6812                      paraBefore.normalize();
6813                      rngBefore.insertNode(paraBefore);
6814                  }
6815  
6816                  //tinyMCE.debug("1: ", paraBefore.innerHTML, paraAfter.innerHTML);
6817              } else {
6818                  body.innerHTML = "<" + blockName + ">&nbsp;</" + blockName + "><" + blockName + ">&nbsp;</" + blockName + ">";
6819                  paraAfter = body.childNodes[1];
6820              }
6821  
6822              inst.selection.moveToBookmark(b);
6823              inst.selection.selectNode(paraAfter, true, true);
6824  
6825              return true;
6826          }
6827  
6828          // Place first part within new paragraph
6829          if (startChop.nodeName == blockName)
6830              rngBefore.setStart(startChop, 0);
6831          else
6832              rngBefore.setStartBefore(startChop);
6833  
6834          rngBefore.setEnd(startNode, startOffset);
6835          paraBefore.appendChild(rngBefore.cloneContents());
6836  
6837          // Place secound part within new paragraph
6838          rngAfter.setEndAfter(endChop);
6839          rngAfter.setStart(endNode, endOffset);
6840          contents = rngAfter.cloneContents();
6841  
6842          if (contents.firstChild && contents.firstChild.nodeName == blockName) {
6843      /*        var nodes = contents.firstChild.childNodes;
6844              for (var i=0; i<nodes.length; i++) {
6845                  //tinyMCE.debug(nodes[i].nodeName);
6846                  if (nodes[i].nodeName != "BODY")
6847                      paraAfter.appendChild(nodes[i]);
6848              }
6849      */
6850              paraAfter.innerHTML = contents.firstChild.innerHTML;
6851          } else
6852              paraAfter.appendChild(contents);
6853  
6854          // Check if it's a empty paragraph
6855          if (isEmpty(paraBefore))
6856              paraBefore.innerHTML = "&nbsp;";
6857  
6858          // Check if it's a empty paragraph
6859          if (isEmpty(paraAfter))
6860              paraAfter.innerHTML = "&nbsp;";
6861  
6862          // Create a range around everything
6863          rng = doc.createRange();
6864  
6865          if (!startChop.previousSibling && startChop.parentNode.nodeName.toUpperCase() == blockName) {
6866              rng.setStartBefore(startChop.parentNode);
6867          } else {
6868              if (rngBefore.startContainer.nodeName.toUpperCase() == blockName && rngBefore.startOffset == 0)
6869                  rng.setStartBefore(rngBefore.startContainer);
6870              else
6871                  rng.setStart(rngBefore.startContainer, rngBefore.startOffset);
6872          }
6873  
6874          if (!endChop.nextSibling && endChop.parentNode.nodeName.toUpperCase() == blockName)
6875              rng.setEndAfter(endChop.parentNode);
6876          else
6877              rng.setEnd(rngAfter.endContainer, rngAfter.endOffset);
6878  
6879          // Delete all contents and insert new paragraphs
6880          rng.deleteContents();
6881  
6882          if (tinyMCE.isOpera) {
6883              rng.insertNode(paraBefore);
6884              rng.insertNode(paraAfter);
6885          } else {
6886              rng.insertNode(paraAfter);
6887              rng.insertNode(paraBefore);
6888          }
6889  
6890          //tinyMCE.debug("2", paraBefore.innerHTML, paraAfter.innerHTML);
6891  
6892          // Normalize
6893          paraAfter.normalize();
6894          paraBefore.normalize();
6895  
6896          inst.selection.moveToBookmark(b);
6897          inst.selection.selectNode(paraAfter, true, true);
6898  
6899          return true;
6900      },
6901  
6902      _handleBackSpace : function(inst) {
6903          var r = inst.getRng(), sn = r.startContainer, nv, s = false;
6904  
6905          // Added body check for bug #1527787
6906          if (sn && sn.nextSibling && sn.nextSibling.nodeName == "BR" && sn.parentNode.nodeName != "BODY") {
6907              nv = sn.nodeValue;
6908  
6909              // Handle if a backspace is pressed after a space character #bug 1466054 removed since fix for #1527787
6910              /*if (nv != null && nv.length >= r.startOffset && nv.charAt(r.startOffset - 1) == ' ')
6911                  s = true;*/
6912  
6913              // Only remove BRs if we are at the end of line #bug 1464152
6914              if (nv != null && r.startOffset == nv.length)
6915                  sn.nextSibling.parentNode.removeChild(sn.nextSibling);
6916          }
6917  
6918          if (inst.settings.auto_resize)
6919              inst.resizeToContent();
6920  
6921          return s;
6922      }
6923  
6924      };
6925  
6926  /* file:jscripts/tiny_mce/classes/TinyMCE_Layer.class.js */
6927  
6928  function TinyMCE_Layer(id, bm) {
6929      this.id = id;
6930      this.blockerElement = null;
6931      this.events = false;
6932      this.element = null;
6933      this.blockMode = typeof(bm) != 'undefined' ? bm : true;
6934      this.doc = document;
6935  };
6936  
6937  TinyMCE_Layer.prototype = {
6938      moveRelativeTo : function(re, p) {
6939          var rep = this.getAbsPosition(re);
6940          var w = parseInt(re.offsetWidth);
6941          var h = parseInt(re.offsetHeight);
6942          var e = this.getElement();
6943          var ew = parseInt(e.offsetWidth);
6944          var eh = parseInt(e.offsetHeight);
6945          var x, y;
6946  
6947          switch (p) {
6948              case "tl":
6949                  x = rep.absLeft;
6950                  y = rep.absTop;
6951                  break;
6952  
6953              case "tr":
6954                  x = rep.absLeft + w;
6955                  y = rep.absTop;
6956                  break;
6957  
6958              case "bl":
6959                  x = rep.absLeft;
6960                  y = rep.absTop + h;
6961                  break;
6962  
6963              case "br":
6964                  x = rep.absLeft + w;
6965                  y = rep.absTop + h;
6966                  break;
6967  
6968              case "cc":
6969                  x = rep.absLeft + (w / 2) - (ew / 2);
6970                  y = rep.absTop + (h / 2) - (eh / 2);
6971                  break;
6972          }
6973  
6974          this.moveTo(x, y);
6975      },
6976  
6977      moveBy : function(x, y) {
6978          var e = this.getElement();
6979          this.moveTo(parseInt(e.style.left) + x, parseInt(e.style.top) + y);
6980      },
6981  
6982      moveTo : function(x, y) {
6983          var e = this.getElement();
6984  
6985          e.style.left = x + "px";
6986          e.style.top = y + "px";
6987  
6988          this.updateBlocker();
6989      },
6990  
6991      resizeBy : function(w, h) {
6992          var e = this.getElement();
6993          this.resizeTo(parseInt(e.style.width) + w, parseInt(e.style.height) + h);
6994      },
6995  
6996      resizeTo : function(w, h) {
6997          var e = this.getElement();
6998  
6999          if (w != null)
7000              e.style.width = w + "px";
7001  
7002          if (h != null)
7003              e.style.height = h + "px";
7004  
7005          this.updateBlocker();
7006      },
7007  
7008      show : function() {
7009          this.getElement().style.display = 'block';
7010          this.updateBlocker();
7011      },
7012  
7013      hide : function() {
7014          this.getElement().style.display = 'none';
7015          this.updateBlocker();
7016      },
7017  
7018      isVisible : function() {
7019          return this.getElement().style.display == 'block';
7020      },
7021  
7022      getElement : function() {
7023          if (!this.element)
7024              this.element = this.doc.getElementById(this.id);
7025  
7026          return this.element;
7027      },
7028  
7029      setBlockMode : function(s) {
7030          this.blockMode = s;
7031      },
7032  
7033      updateBlocker : function() {
7034          var e, b, x, y, w, h;
7035  
7036          b = this.getBlocker();
7037          if (b) {
7038              if (this.blockMode) {
7039                  e = this.getElement();
7040                  x = this.parseInt(e.style.left);
7041                  y = this.parseInt(e.style.top);
7042                  w = this.parseInt(e.offsetWidth);
7043                  h = this.parseInt(e.offsetHeight);
7044  
7045                  b.style.left = x + 'px';
7046                  b.style.top = y + 'px';
7047                  b.style.width = w + 'px';
7048                  b.style.height = h + 'px';
7049                  b.style.display = e.style.display;
7050              } else
7051                  b.style.display = 'none';
7052          }
7053      },
7054  
7055      getBlocker : function() {
7056          var d, b;
7057  
7058          if (!this.blockerElement && this.blockMode) {
7059              d = this.doc;
7060              b = d.getElementById(this.id + "_blocker");
7061  
7062              if (!b) {
7063                  b = d.createElement("iframe");
7064  
7065                  b.setAttribute('id', this.id + "_blocker");
7066                  b.style.cssText = 'display: none; position: absolute; left: 0; top: 0';
7067                  b.src = 'javascript:false;';
7068                  b.frameBorder = '0';
7069                  b.scrolling = 'no';
7070      
7071                  d.body.appendChild(b);
7072              }
7073  
7074              this.blockerElement = b;
7075          }
7076  
7077          return this.blockerElement;
7078      },
7079  
7080      getAbsPosition : function(n) {
7081          var p = {absLeft : 0, absTop : 0};
7082  
7083          while (n) {
7084              p.absLeft += n.offsetLeft;
7085              p.absTop += n.offsetTop;
7086              n = n.offsetParent;
7087          }
7088  
7089          return p;
7090      },
7091  
7092      create : function(n, c, p, h) {
7093          var d = this.doc, e = d.createElement(n);
7094  
7095          e.setAttribute('id', this.id);
7096  
7097          if (c)
7098              e.className = c;
7099  
7100          if (!p)
7101              p = d.body;
7102  
7103          if (h)
7104              e.innerHTML = h;
7105  
7106          p.appendChild(e);
7107  
7108          return this.element = e;
7109      },
7110  
7111      exists : function() {
7112          return this.doc.getElementById(this.id) != null;
7113      },
7114  
7115      parseInt : function(s) {
7116          if (s == null || s == '')
7117              return 0;
7118  
7119          return parseInt(s);
7120      }
7121  
7122      };
7123  
7124  /* file:jscripts/tiny_mce/classes/TinyMCE_Menu.class.js */
7125  
7126  function TinyMCE_Menu() {
7127      var id;
7128  
7129      if (typeof(tinyMCE.menuCounter) == "undefined")
7130          tinyMCE.menuCounter = 0;
7131  
7132      id = "mc_menu_" + tinyMCE.menuCounter++;
7133  
7134      TinyMCE_Layer.call(this, id, true);
7135  
7136      this.id = id;
7137      this.items = new Array();
7138      this.needsUpdate = true;
7139  };
7140  
7141  TinyMCE_Menu.prototype = tinyMCE.extend(TinyMCE_Layer.prototype, {
7142      init : function(s) {
7143          var n;
7144  
7145          // Default params
7146          this.settings = {
7147              separator_class : 'mceMenuSeparator',
7148              title_class : 'mceMenuTitle',
7149              disabled_class : 'mceMenuDisabled',
7150              menu_class : 'mceMenu',
7151              drop_menu : true
7152          };
7153  
7154          for (n in s)
7155              this.settings[n] = s[n];
7156  
7157          this.create('div', this.settings.menu_class);
7158      },
7159  
7160      clear : function() {
7161          this.items = new Array();
7162      },
7163  
7164      addTitle : function(t) {
7165          this.add({type : 'title', text : t});
7166      },
7167  
7168      addDisabled : function(t) {
7169          this.add({type : 'disabled', text : t});
7170      },
7171  
7172      addSeparator : function() {
7173          this.add({type : 'separator'});
7174      },
7175  
7176      addItem : function(t, js) {
7177          this.add({text : t, js : js});
7178      },
7179  
7180      add : function(mi) {
7181          this.items[this.items.length] = mi;
7182          this.needsUpdate = true;
7183      },
7184  
7185      update : function() {
7186          var e = this.getElement(), h = '', i, t, m = this.items, s = this.settings;
7187  
7188          if (this.settings.drop_menu)
7189              h += '<span class="mceMenuLine"></span>';
7190  
7191          h += '<table border="0" cellpadding="0" cellspacing="0">';
7192  
7193          for (i=0; i<m.length; i++) {
7194              t = tinyMCE.xmlEncode(m[i].text);
7195              c = m[i].class_name ? ' class="' + m[i].class_name + '"' : '';
7196  
7197              switch (m[i].type) {
7198                  case 'separator':
7199                      h += '<tr class="' + s.separator_class + '"><td>';
7200                      break;
7201  
7202                  case 'title':
7203                      h += '<tr class="' + s.title_class + '"><td><span' + c +'>' + t + '</span>';
7204                      break;
7205  
7206                  case 'disabled':
7207                      h += '<tr class="' + s.disabled_class + '"><td><span' + c +'>' + t + '</span>';
7208                      break;
7209  
7210                  default:
7211                      h += '<tr><td><a href="#" onclick="return tinyMCE.cancelEvent(event);" onmousedown="return tinyMCE.cancelEvent(event);" onmouseup="' + tinyMCE.xmlEncode(m[i].js) + ';return tinyMCE.cancelEvent(event);"><span' + c +'>' + t + '</span></a>';
7212              }
7213  
7214              h += '</td></tr>';
7215          }
7216  
7217          h += '</table>';
7218  
7219          e.innerHTML = h;
7220  
7221          this.needsUpdate = false;
7222          this.updateBlocker();
7223      },
7224  
7225      show : function() {
7226          var nl, i;
7227  
7228          if (tinyMCE.lastMenu == this)
7229              return;
7230  
7231          if (this.needsUpdate)
7232              this.update();
7233  
7234          if (tinyMCE.lastMenu && tinyMCE.lastMenu != this)
7235              tinyMCE.lastMenu.hide();
7236  
7237          TinyMCE_Layer.prototype.show.call(this);
7238  
7239          if (!tinyMCE.isOpera) {
7240              // Accessibility stuff
7241  /*            nl = this.getElement().getElementsByTagName("a");
7242              if (nl.length > 0)
7243                  nl[0].focus();*/
7244          }
7245  
7246          tinyMCE.lastMenu = this;
7247      }
7248  
7249      });
7250  
7251  /* file:jscripts/tiny_mce/classes/TinyMCE_Compatibility.class.js */
7252  
7253  if (!Function.prototype.call) {
7254      Function.prototype.call = function() {
7255          var a = arguments, s = a[0], i, as = '', r, o;
7256  
7257          for (i=1; i<a.length; i++)
7258              as += (i > 1 ? ',' : '') + 'a[' + i + ']';
7259  
7260          o = s._fu;
7261          s._fu = this;
7262          r = eval('s._fu(' + as + ')');
7263          s._fu = o;
7264  
7265          return r;
7266      };
7267  };
7268  
7269  /* file:jscripts/tiny_mce/classes/TinyMCE_Debug.class.js */
7270  
7271  TinyMCE_Engine.prototype.debug = function() {
7272      var m = "", a, i, l = tinyMCE.log.length;
7273  
7274      for (i=0, a = this.debug.arguments; i<a.length; i++) {
7275          m += a[i];
7276  
7277          if (i<a.length-1)
7278              m += ', ';
7279      }
7280  
7281      if (l < 1000)
7282          tinyMCE.log[l] = "[debug] " + m;
7283  };
7284  


Généré le : Fri Mar 30 19:41:27 2007 par Balluche grâce à PHPXref 0.7