Index: openacs-4/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/tiny_mce_src.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/tiny_mce_src.js,v diff -u -r1.1 -r1.2 --- openacs-4/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/tiny_mce_src.js 25 Jan 2008 21:43:52 -0000 1.1 +++ openacs-4/packages/acs-templating/www/resources/tinymce/jscripts/tiny_mce/tiny_mce_src.js 8 May 2009 17:34:11 -0000 1.2 @@ -1,7607 +1,12797 @@ +var tinymce = { + majorVersion : '3', + minorVersion : '2.2.3', + releaseDate : '2009-03-26', -/* file:jscripts/tiny_mce/classes/TinyMCE_Engine.class.js */ + _init : function() { + var t = this, d = document, w = window, na = navigator, ua = na.userAgent, i, nl, n, base, p, v; -function TinyMCE_Engine() { - var ua; + // Browser checks + t.isOpera = w.opera && opera.buildNumber; + t.isWebKit = /WebKit/.test(ua); + t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName); + t.isIE6 = t.isIE && /MSIE [56]/.test(ua); + t.isGecko = !t.isWebKit && /Gecko/.test(ua); + t.isMac = ua.indexOf('Mac') != -1; + t.isAir = /adobeair/i.test(ua); - this.majorVersion = "2"; - this.minorVersion = "1.3"; - this.releaseDate = "2007-11-27"; + // TinyMCE .NET webcontrol might be setting the values for TinyMCE + if (w.tinyMCEPreInit) { + t.suffix = tinyMCEPreInit.suffix; + t.baseURL = tinyMCEPreInit.base; + t.query = tinyMCEPreInit.query; + return; + } - this.instances = []; - this.switchClassCache = []; - this.windowArgs = []; - this.loadedFiles = []; - this.pendingFiles = []; - this.loadingIndex = 0; - this.configs = []; - this.currentConfig = 0; - this.eventHandlers = []; - this.log = []; - this.undoLevels = []; - this.undoIndex = 0; - this.typingUndoIndex = -1; - this.settings = []; + // Get suffix and base + t.suffix = ''; - // Browser check - ua = navigator.userAgent; - this.isMSIE = (navigator.appName == "Microsoft Internet Explorer"); - this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1); - this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1); - this.isMSIE7 = this.isMSIE && (ua.indexOf('MSIE 7') != -1); - this.isGecko = ua.indexOf('Gecko') != -1; // Will also be true on Safari - this.isSafari = ua.indexOf('Safari') != -1; - this.isOpera = window['opera'] && opera.buildNumber ? true : false; - this.isMac = ua.indexOf('Mac') != -1; - this.isNS7 = ua.indexOf('Netscape/7') != -1; - this.isNS71 = ua.indexOf('Netscape/7.1') != -1; - this.dialogCounter = 0; - this.plugins = []; - this.themes = []; - this.menus = []; - this.loadedPlugins = []; - this.buttonMap = []; - this.isLoaded = false; + // If base element found, add that infront of baseURL + nl = d.getElementsByTagName('base'); + for (i=0; i'); - this._def("font_size_classes", ''); - this._def("font_size_style_values", 'xx-small,x-small,small,medium,large,x-large,xx-large', true); - this._def("event_elements", 'a,img', true); - this._def("convert_urls", true); - this._def("table_inline_editing", false); - this._def("object_resizing", true); - this._def("custom_shortcuts", true); - this._def("convert_on_click", false); - this._def("content_css", ''); - this._def("fix_list_elements", true); - this._def("fix_table_elements", false); - this._def("strict_loading_mode", document.contentType == 'application/xhtml+xml'); - this._def("hidden_tab_class", ''); - this._def("display_tab_class", ''); - this._def("gecko_spellcheck", false); - this._def("hide_selects_on_submit", true); - this._def("forced_root_block", false); - this._def("remove_trailing_nbsp", false); - this._def("save_on_tinymce_forms", false); + tinymce.each(a, function(v) { + o.push(f(v)); + }); - // Force strict loading mode to false on non Gecko browsers - if (this.isMSIE && !this.isOpera) - this.settings.strict_loading_mode = false; + return o; + }, - // Browser check IE - if (this.isMSIE && this.settings.browsers.indexOf('msie') == -1) - return; + grep : function(a, f) { + var o = []; - // Browser check Gecko - if (this.isGecko && this.settings.browsers.indexOf('gecko') == -1) - return; + tinymce.each(a, function(v) { + if (!f || f(v)) + o.push(v); + }); - // Browser check Safari - if (this.isSafari && this.settings.browsers.indexOf('safari') == -1) - return; + return o; + }, - // Browser check Opera - if (this.isOpera && this.settings.browsers.indexOf('opera') == -1) - return; + inArray : function(a, v) { + var i, l; - // If not super absolute make it so - baseHREF = tinyMCE.settings.document_base_url; - h = document.location.href; - p = h.indexOf('://'); - if (p > 0 && document.location.protocol != "file:") { - p = h.indexOf('/', p + 3); - h = h.substring(0, p); + if (a) { + for (i = 0, l = a.length; i < l; i++) { + if (a[i] === v) + return i; + } + } - if (baseHREF.indexOf('://') == -1) - baseHREF = h + baseHREF; + return -1; + }, - tinyMCE.settings.document_base_url = baseHREF; - tinyMCE.settings.document_base_prefix = h; + extend : function(o, e) { + var i, a = arguments; + + for (i=1; i : + s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); + cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name - if (tinyMCE.getParam("popups_css", false)) { - cssPath = tinyMCE.getParam("popups_css", ""); + // Create namespace for new class + ns = t.createNS(s[3].replace(/\.\w+$/, '')); - // Is relative - if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/') - this.settings.popups_css = this.documentBasePath + "/" + cssPath; - else - this.settings.popups_css = cssPath; - } else - this.settings.popups_css = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_popup.css"; + // Class already exists + if (ns[cn]) + return; - if (tinyMCE.getParam("editor_css", false)) { - cssPath = tinyMCE.getParam("editor_css", ""); + // Make pure static class + if (s[2] == 'static') { + ns[cn] = p; - // Is relative - if (cssPath.indexOf('://') == -1 && cssPath.charAt(0) != '/') - this.settings.editor_css = this.documentBasePath + "/" + cssPath; - else - this.settings.editor_css = cssPath; - } else { - if (this.settings.editor_css !== '') - this.settings.editor_css = tinyMCE.baseURL + "/themes/" + theme + "/css/editor_ui.css"; + if (this.onCreate) + this.onCreate(s[2], s[3], ns[cn]); + + return; } - // Only do this once - if (this.configs.length == 0) { - if (typeof(TinyMCECompressed) == "undefined") { - tinyMCE.addEvent(window, "DOMContentLoaded", TinyMCE_Engine.prototype.onLoad); + // Create default constructor + if (!p[cn]) { + p[cn] = function() {}; + de = 1; + } - if (tinyMCE.isRealIE) { - if (document.body) - tinyMCE.addEvent(document.body, "readystatechange", TinyMCE_Engine.prototype.onLoad); - else - tinyMCE.addEvent(document, "readystatechange", TinyMCE_Engine.prototype.onLoad); - } + // Add constructor and methods + ns[cn] = p[cn]; + t.extend(ns[cn].prototype, p); - tinyMCE.addEvent(window, "load", TinyMCE_Engine.prototype.onLoad); - tinyMCE._addUnloadEvents(); + // Extend + if (s[5]) { + sp = t.resolve(s[5]).prototype; + scn = s[5].match(/\.(\w+)$/i)[1]; // Class name + + // Extend constructor + c = ns[cn]; + if (de) { + // Add passthrough constructor + ns[cn] = function() { + return sp[scn].apply(this, arguments); + }; + } else { + // Add inherit constructor + ns[cn] = function() { + this.parent = sp[scn]; + return c.apply(this, arguments); + }; } - } + ns[cn].prototype[cn] = ns[cn]; - this.loadScript(tinyMCE.baseURL + '/themes/' + this.settings.theme + '/editor_template' + tinyMCE.srcMode + '.js'); - this.loadScript(tinyMCE.baseURL + '/langs/' + this.settings.language + '.js'); - this.loadCSS(this.settings.editor_css); + // Add super methods + t.each(sp, function(f, n) { + ns[cn].prototype[n] = sp[n]; + }); - // Add plugins - p = tinyMCE.getParam('plugins', '', true, ','); - if (p.length > 0) { - for (i=0; i&"]', 'g'); + return o; }, - _addUnloadEvents : function() { - var st = tinyMCE.settings.add_unload_trigger; + resolve : function(n, o) { + var i, l; - if (tinyMCE.isIE) { - if (st) { - tinyMCE.addEvent(window, "unload", TinyMCE_Engine.prototype.unloadHandler); - tinyMCE.addEvent(window.document, "beforeunload", TinyMCE_Engine.prototype.unloadHandler); - } - } else { - if (st) - tinyMCE.addEvent(window, "unload", function () {tinyMCE.triggerSave(true, true);}); + o = o || window; + + n = n.split('.'); + for (i=0, l = n.length; i'); + return s; + } - this.loadedFiles[this.loadedFiles.length] = url; - }, + }); +(function() { + var each = tinymce.each; - loadNextScript : function() { - var d = document, se; + tinymce.create('tinymce.util.URI', { + URI : function(u, s) { + var t = this, o, a, b; - if (!tinyMCE.settings.strict_loading_mode) - return; + // Default settings + s = t.settings = s || {}; - if (this.loadingIndex < this.pendingFiles.length) { - se = d.createElementNS('http://www.w3.org/1999/xhtml', 'script'); - se.setAttribute('language', 'javascript'); - se.setAttribute('type', 'text/javascript'); - se.setAttribute('src', this.pendingFiles[this.loadingIndex++]); + // Strange app protocol or local anchor + if (/^(mailto|tel|news|javascript|about):/i.test(u) || /^\s*#/.test(u)) { + t.source = u; + return; + } - d.getElementsByTagName("head")[0].appendChild(se); - } else - this.loadingIndex = -1; // Done with loading - }, + // Absolute path with no host, fake host and protocol + if (u.indexOf('/') === 0 && u.indexOf('//') !== 0) + u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u; - loadCSS : function(url) { - var ar = url.replace(/\s+/, '').split(','); - var lflen = 0, csslen = 0, skip = false; - var x = 0, i = 0, nl, le; + // Relative path + if (u.indexOf(':/') === -1 && u.indexOf('//') !== 0) + u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u); - for (x = 0,csslen = ar.length; x 0) { - /* Make sure it doesn't exist. */ - for (i=0, lflen=this.loadedFiles.length; i= items.length) { + for (i = 0, l = base.length; i < l; i++) { + if (i >= items.length || base[i] != items[i]) { + bp = i + 1; break; } } + } - if (!skip) { - if (tinyMCE.settings.strict_loading_mode) { - nl = document.getElementsByTagName("head"); + if (base.length < items.length) { + for (i = 0, l = items.length; i < l; i++) { + if (i >= base.length || base[i] != items[i]) { + bp = i + 1; + break; + } + } + } - le = document.createElement('link'); - le.setAttribute('href', ar[x]); - le.setAttribute('rel', 'stylesheet'); - le.setAttribute('type', 'text/css'); + if (bp == 1) + return path; - nl[0].appendChild(le); - } else - document.write(''); + for (i = 0, l = base.length - (bp - 1); i < l; i++) + out += "../"; - this.loadedFiles[this.loadedFiles.length] = ar[x]; - } + for (i = bp - 1, l = items.length; i < l; i++) { + if (i != bp - 1) + out += "/" + items[i]; + else + out += items[i]; } - } - }, - importCSS : function(doc, css) { - var css_ary = css.replace(/\s+/, '').split(','); - var csslen, elm, headArr, x, css_file; + return out; + }, - for (x = 0, csslen = css_ary.length; x 0) { - // Is relative, make absolute - if (css_file.indexOf('://') == -1 && css_file.charAt(0) != '/') - css_file = this.documentBasePath + "/" + css_file; + // Split paths + tr = /\/$/.test(path) ? '/' : ''; + base = base.split('/'); + path = path.split('/'); - if (typeof(doc.createStyleSheet) == "undefined") { - elm = doc.createElement("link"); + // Remove empty chunks + each(base, function(k) { + if (k) + o.push(k); + }); - elm.rel = "stylesheet"; - elm.href = css_file; + base = o; - if ((headArr = doc.getElementsByTagName("head")) != null && headArr.length > 0) - headArr[0].appendChild(elm); - } else - doc.createStyleSheet(css_file); + // Merge relURLParts chunks + for (i = path.length - 1, o = []; i >= 0; i--) { + // Ignore empty or . + if (path[i].length == 0 || path[i] == ".") + continue; + + // Is parent + if (path[i] == '..') { + nb++; + continue; + } + + // Move up + if (nb > 0) { + nb--; + continue; + } + + o.push(path[i]); } - } - }, - confirmAdd : function(e, settings) { - var elm = tinyMCE.isIE ? event.srcElement : e.target; - var elementId = elm.name ? elm.name : elm.id; + i = base.length - nb; - tinyMCE.settings = settings; + // If /a/b/c or / + if (i <= 0) + return '/' + o.reverse().join('/') + tr; - if (tinyMCE.settings.convert_on_click || (!elm.getAttribute('mce_noask') && confirm(tinyMCELang.lang_edit_confirm))) - tinyMCE.addMCEControl(elm, elementId); + return '/' + base.slice(0, i).join('/') + '/' + o.reverse().join('/') + tr; + }, - elm.setAttribute('mce_noask', 'true'); - }, + getURI : function(nh) { + var s, t = this; - updateContent : function(form_element_name) { - var formElement, n, inst, doc; + // Rebuild source + if (!t.source || nh) { + s = ''; - // Find MCE instance linked to given form element and copy it's value - formElement = document.getElementById(form_element_name); - for (n in tinyMCE.instances) { - inst = tinyMCE.instances[n]; + if (!nh) { + if (t.protocol) + s += t.protocol + '://'; - if (!tinyMCE.isInstance(inst)) - continue; + if (t.userInfo) + s += t.userInfo + '@'; - inst.switchSettings(); + if (t.host) + s += t.host; - if (inst.formElement == formElement) { - doc = inst.getDoc(); + if (t.port) + s += ':' + t.port; + } - tinyMCE._setHTML(doc, inst.formElement.value); + if (t.path) + s += t.path; - if (!tinyMCE.isIE) - doc.body.innerHTML = tinyMCE._cleanupHTML(inst, doc, this.settings, doc.body, inst.visualAid); + if (t.query) + s += '?' + t.query; + + if (t.anchor) + s += '#' + t.anchor; + + t.source = s; } + + return t.source; } - }, - addMCEControl : function(replace_element, form_element_name, target_document) { - var id = "mce_editor_" + tinyMCE.idCounter++; - var inst = new TinyMCE_Control(tinyMCE.settings); + }); +})(); +(function() { + var each = tinymce.each; - inst.editorId = id; - this.instances[id] = inst; + tinymce.create('static tinymce.util.Cookie', { + getHash : function(n) { + var v = this.get(n), h; - inst._onAdd(replace_element, form_element_name, target_document); - }, + if (v) { + each(v.split('&'), function(v) { + v = v.split('='); + h = h || {}; + h[unescape(v[0])] = unescape(v[1]); + }); + } - removeInstance : function(ti) { - var t = [], n, i; + return h; + }, - // Remove from instances - for (n in tinyMCE.instances) { - i = tinyMCE.instances[n]; + setHash : function(n, v, e, p, d, s) { + var o = ''; - if (tinyMCE.isInstance(i) && ti != i) - t[n] = i; - } + each(v, function(v, k) { + o += (!o ? '' : '&') + escape(k) + '=' + escape(v); + }); - tinyMCE.instances = t; + this.set(n, o, e, p, d, s); + }, - // Remove from global undo/redo - n = []; - t = tinyMCE.undoLevels; + get : function(n) { + var c = document.cookie, e, p = n + "=", b; - for (i=0; i 0 ? ',' : '') + s(o[i]); + + return v + ']'; + } + + v = '{'; + + for (i in o) + v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : ''; + + return v + '}'; } + + return '' + o; }, - resetForm : function(form_index) { - var i, inst, n, formObj = document.forms[form_index]; + parse : function(s) { + try { + return eval('(' + s + ')'); + } catch (ex) { + // Ignore + } + } - for (n in tinyMCE.instances) { - inst = tinyMCE.instances[n]; + }); +tinymce.create('static tinymce.util.XHR', { + send : function(o) { + var x, t, w = window, c = 0; - if (!tinyMCE.isInstance(inst)) - continue; + // Default settings + o.scope = o.scope || this; + o.success_scope = o.success_scope || o.scope; + o.error_scope = o.error_scope || o.scope; + o.async = o.async === false ? false : true; + o.data = o.data || ''; - inst.switchSettings(); + function get(s) { + x = 0; - for (i=0; i 10000) { + if (o.success && c < 10000 && x.status == 200) + o.success.call(o.success_scope, '' + x.responseText, x, o); + else if (o.error) + o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o); + + x = null; + } else + w.setTimeout(ready, 10); + }; + + // Syncronous request + if (!o.async) + return ready(); + + // Wait for response, onReadyStateChange can not be used since it leaks memory in IE + t = w.setTimeout(ready, 10); } - }, - execInstanceCommand : function(editor_id, command, user_interface, value, focus) { - var inst = tinyMCE.getInstanceById(editor_id), r; + } +}); +(function() { + var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR; - if (inst) { - r = inst.selection.getRng(); + tinymce.create('tinymce.util.JSONRequest', { + JSONRequest : function(s) { + this.settings = extend({ + }, s); + this.count = 0; + }, - if (typeof(focus) == "undefined") - focus = true; + send : function(o) { + var ecb = o.error, scb = o.success; - // IE bug lost focus on images in absolute divs Bug #1534575 - if (focus && (!r || !r.item)) - inst.contentWindow.focus(); + o = extend(this.settings, o); - // Reset design mode if lost - inst.autoResetDesignMode(); + o.success = function(c, x) { + c = JSON.parse(c); - this.selectedElement = inst.getFocusElement(); - inst.select(); - tinyMCE.execCommand(command, user_interface, value); + if (typeof(c) == 'undefined') { + c = { + error : 'JSON Parse error.' + }; + } - // Cancel event so it doesn't call onbeforeonunlaod - if (tinyMCE.isIE && window.event != null) - tinyMCE.cancelEvent(window.event); + if (c.error) + ecb.call(o.error_scope || o.scope, c.error, x); + else + scb.call(o.success_scope || o.scope, c.result); + }; + + o.error = function(ty, x) { + ecb.call(o.error_scope || o.scope, ty, x); + }; + + o.data = JSON.serialize({ + id : o.id || 'c' + (this.count++), + method : o.method, + params : o.params + }); + + // JSON content type for Ruby on rails. Bug: #1883287 + o.content_type = 'application/json'; + + XHR.send(o); + }, + + 'static' : { + sendRPC : function(o) { + return new tinymce.util.JSONRequest().send(o); + } } - }, - execCommand : function(command, user_interface, value) { - var inst = tinyMCE.selectedInstance, n, pe, te; + }); +}());(function(tinymce) { + // Shorten names + var each = tinymce.each, is = tinymce.is; + var isWebKit = tinymce.isWebKit, isIE = tinymce.isIE; - // Default input - user_interface = user_interface ? user_interface : false; - value = value ? value : null; + tinymce.create('tinymce.dom.DOMUtils', { + doc : null, + root : null, + files : null, + pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/, + props : { + "for" : "htmlFor", + "class" : "className", + className : "className", + checked : "checked", + disabled : "disabled", + maxlength : "maxLength", + readonly : "readOnly", + selected : "selected", + value : "value", + id : "id", + name : "name", + type : "type" + }, - if (inst) - inst.switchSettings(); + DOMUtils : function(d, s) { + var t = this; - switch (command) { - case "Undo": - if (this.getParam('custom_undo_redo_global')) { - if (this.undoIndex > 0) { - tinyMCE.nextUndoRedoAction = 'Undo'; - inst = this.undoLevels[--this.undoIndex]; - inst.select(); + t.doc = d; + t.win = window; + t.files = {}; + t.cssFlicker = false; + t.counter = 0; + t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat"; + t.stdMode = d.documentMode === 8; - if (!tinyMCE.nextUndoRedoInstanceId) - inst.execCommand('Undo'); - } - } else - inst.execCommand('Undo'); - return true; + this.settings = s = tinymce.extend({ + keep_values : false, + hex_colors : 1, + process_html : 1 + }, s); - case "Redo": - if (this.getParam('custom_undo_redo_global')) { - if (this.undoIndex <= this.undoLevels.length - 1) { - tinyMCE.nextUndoRedoAction = 'Redo'; - inst = this.undoLevels[this.undoIndex++]; - inst.select(); + // Fix IE6SP2 flicker and check it failed for pre SP2 + if (tinymce.isIE6) { + try { + d.execCommand('BackgroundImageCache', false, true); + } catch (e) { + t.cssFlicker = true; + } + } - if (!tinyMCE.nextUndoRedoInstanceId) - inst.execCommand('Redo'); - } - } else - inst.execCommand('Redo'); + tinymce.addUnload(t.destroy, t); + }, - return true; + getRoot : function() { + var t = this, s = t.settings; - case 'mceFocus': - inst = tinyMCE.getInstanceById(value); + return (s && t.get(s.root_element)) || t.doc.body; + }, - if (inst) - inst.getWin().focus(); - return; + getViewPort : function(w) { + var d, b; - case "mceAddControl": - case "mceAddEditor": - tinyMCE.addMCEControl(tinyMCE._getElementById(value), value); - return; + w = !w ? this.win : w; + d = w.document; + b = this.boxModel ? d.documentElement : d.body; - case "mceAddFrameControl": - tinyMCE.addMCEControl(tinyMCE._getElementById(value.element, value.document), value.element, value.document); - return; + // Returns viewport size excluding scrollbars + return { + x : w.pageXOffset || b.scrollLeft, + y : w.pageYOffset || b.scrollTop, + w : w.innerWidth || b.clientWidth, + h : w.innerHeight || b.clientHeight + }; + }, - case "mceRemoveControl": - case "mceRemoveEditor": - tinyMCE.removeMCEControl(value); - return; + getRect : function(e) { + var p, t = this, sr; - case "mceToggleEditor": - inst = tinyMCE.getInstanceById(value); + e = t.get(e); + p = t.getPos(e); + sr = t.getSize(e); - if (inst) { - pe = document.getElementById(inst.editorId + '_parent'); - te = inst.oldTargetElement; + return { + x : p.x, + y : p.y, + w : sr.w, + h : sr.h + }; + }, - if (typeof(inst.enabled) == 'undefined') - inst.enabled = true; + getSize : function(e) { + var t = this, w, h; - inst.enabled = !inst.enabled; + e = t.get(e); + w = t.getStyle(e, 'width'); + h = t.getStyle(e, 'height'); - if (!inst.enabled) { - pe.style.display = 'none'; + // Non pixel value, then force offset/clientWidth + if (w.indexOf('px') === -1) + w = 0; - if (te.nodeName == 'TEXTAREA' || te.nodeName == 'INPUT') - te.value = inst.getHTML(); - else - te.innerHTML = inst.getHTML(); + // Non pixel value, then force offset/clientWidth + if (h.indexOf('px') === -1) + h = 0; - te.style.display = inst.oldTargetDisplay; - tinyMCE.dispatchCallback(inst, 'hide_instance_callback', 'hideInstance', inst); - } else { - pe.style.display = 'block'; - te.style.display = 'none'; + return { + w : parseInt(w) || e.offsetWidth || e.clientWidth, + h : parseInt(h) || e.offsetHeight || e.clientHeight + }; + }, - if (te.nodeName == 'TEXTAREA' || te.nodeName == 'INPUT') - inst.setHTML(te.value); - else - inst.setHTML(te.innerHTML); + is : function(n, patt) { + return tinymce.dom.Sizzle.matches(patt, n.nodeType ? [n] : n).length > 0; + }, - inst.useCSS = false; - tinyMCE.dispatchCallback(inst, 'show_instance_callback', 'showInstance', inst); - } - } else - tinyMCE.addMCEControl(tinyMCE._getElementById(value), value); + getParent : function(n, f, r) { + return this.getParents(n, f, r, false); + }, - return; + getParents : function(n, f, r, c) { + var t = this, na, se = t.settings, o = []; - case "mceResetDesignMode": - // Resets the designmode state of the editors in Gecko - if (tinyMCE.isGecko) { - for (n in tinyMCE.instances) { - if (!tinyMCE.isInstance(tinyMCE.instances[n])) - continue; + n = t.get(n); + c = c === undefined; - try { - tinyMCE.instances[n].getDoc().designMode = "off"; - tinyMCE.instances[n].getDoc().designMode = "on"; - tinyMCE.instances[n].useCSS = false; - } catch (e) { - // Ignore any errors - } - } - } + if (se.strict_root) + r = r || t.getRoot(); - return; - } + // Wrap node name as func + if (is(f, 'string')) { + na = f; - if (inst) { - inst.execCommand(command, user_interface, value); - } else if (tinyMCE.settings.focus_alert) - alert(tinyMCELang.lang_focus_alert); - }, + if (f === '*') { + f = function(n) {return n.nodeType == 1;}; + } else { + f = function(n) { + return t.is(n, na); + }; + } + } - _createIFrame : function(replace_element, doc, win) { - var iframe, id = replace_element.getAttribute("id"); - var aw, ah; + while (n) { + if (n == r) + break; - if (typeof(doc) == "undefined") - doc = document; + if (!f || f(n)) { + if (c) + o.push(n); + else + return n; + } - if (typeof(win) == "undefined") - win = window; + n = n.parentNode; + } - iframe = doc.createElement("iframe"); + return c ? o : null; + }, - aw = "" + tinyMCE.settings.area_width; - ah = "" + tinyMCE.settings.area_height; + get : function(e) { + var n; - if (aw.indexOf('%') == -1) { - aw = parseInt(aw); - aw = (isNaN(aw) || aw < 0) ? 300 : aw; - aw = aw + "px"; - } + if (e && this.doc && typeof(e) == 'string') { + n = e; + e = this.doc.getElementById(e); - if (ah.indexOf('%') == -1) { - ah = parseInt(ah); - ah = (isNaN(ah) || ah < 0) ? 240 : ah; - ah = ah + "px"; - } + // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick + if (e && e.id !== n) + return this.doc.getElementsByName(n)[1]; + } - iframe.setAttribute("id", id); - iframe.setAttribute("name", id); - iframe.setAttribute("class", "mceEditorIframe"); - iframe.setAttribute("border", "0"); - iframe.setAttribute("frameBorder", "0"); - iframe.setAttribute("marginWidth", "0"); - iframe.setAttribute("marginHeight", "0"); - iframe.setAttribute("leftMargin", "0"); - iframe.setAttribute("topMargin", "0"); - iframe.setAttribute("width", aw); - iframe.setAttribute("height", ah); - iframe.setAttribute("allowtransparency", "true"); - iframe.className = 'mceEditorIframe'; + return e; + }, - if (tinyMCE.settings.auto_resize) - iframe.setAttribute("scrolling", "no"); - // Must have a src element in MSIE HTTPs breaks aswell as absoute URLs - if (tinyMCE.isRealIE) - iframe.setAttribute("src", this.settings.default_document); + select : function(pa, s) { + var t = this; - iframe.style.width = aw; - iframe.style.height = ah; + return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []); + }, - // Ugly hack for Gecko problem in strict mode - if (tinyMCE.settings.strict_loading_mode) - iframe.style.marginBottom = '-5px'; - // MSIE 5.0 issue - if (tinyMCE.isRealIE) - replace_element.outerHTML = iframe.outerHTML; - else - replace_element.parentNode.replaceChild(iframe, replace_element); + add : function(p, n, a, h, c) { + var t = this; - if (tinyMCE.isRealIE) - return win.frames[id]; - else - return iframe; - }, + return this.run(p, function(p) { + var e, k; - setupContent : function(editor_id) { - var inst = tinyMCE.instances[editor_id], i, doc = inst.getDoc(), head = doc.getElementsByTagName('head').item(0); - var content = inst.startContent, contentElement, body; + e = is(n, 'string') ? t.doc.createElement(n) : n; + t.setAttribs(e, a); - // HTML values get XML encoded in strict mode - if (tinyMCE.settings.strict_loading_mode) { - content = content.replace(/</g, '<'); - content = content.replace(/>/g, '>'); - content = content.replace(/"/g, '"'); - content = content.replace(/&/g, '&'); - } + if (h) { + if (h.nodeType) + e.appendChild(h); + else + t.setHTML(e, h); + } - tinyMCE.selectedInstance = inst; - inst.switchSettings(); + return !c ? p.appendChild(e) : e; + }); + }, - // Not loaded correctly hit it again, Mozilla bug #997860 - if (!tinyMCE.isIE && tinyMCE.getParam("setupcontent_reload", false) && doc.title != "blank_page") { - // This part will remove the designMode status - // Failes first time in Firefox 1.5b2 on Mac - try {doc.location.href = tinyMCE.baseURL + "/blank.htm";} catch (ex) {} - window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 1000); - return; - } + create : function(n, a, h) { + return this.add(this.doc.createElement(n), n, a, h, 1); + }, - // Wait for it to load - if (!head || !doc.body) { - window.setTimeout("tinyMCE.setupContent('" + editor_id + "');", 10); - return; - } + createHTML : function(n, a, h) { + var o = '', t = this, k; - // Import theme specific content CSS the user specific - tinyMCE.importCSS(inst.getDoc(), tinyMCE.baseURL + "/themes/" + inst.settings.theme + "/css/editor_content.css"); - tinyMCE.importCSS(inst.getDoc(), inst.settings.content_css); - tinyMCE.dispatchCallback(inst, 'init_instance_callback', 'initInstance', inst); + o += '<' + n; - // Setup keyboard shortcuts - if (tinyMCE.getParam('custom_undo_redo_keyboard_shortcuts')) { - inst.addShortcut('ctrl', 'z', 'lang_undo_desc', 'Undo'); - inst.addShortcut('ctrl', 'y', 'lang_redo_desc', 'Redo'); - } + for (k in a) { + if (a.hasOwnProperty(k)) + o += ' ' + k + '="' + t.encode(a[k]) + '"'; + } - // BlockFormat shortcuts keys - for (i=1; i<=6; i++) - inst.addShortcut('ctrl', '' + i, '', 'FormatBlock', false, ''); + if (tinymce.is(h)) + return o + '>' + h + ''; - inst.addShortcut('ctrl', '7', '', 'FormatBlock', false, '

'); - inst.addShortcut('ctrl', '8', '', 'FormatBlock', false, '

'); - inst.addShortcut('ctrl', '9', '', 'FormatBlock', false, '
'); + return o + ' />'; + }, - // Add default shortcuts for gecko - if (tinyMCE.isGecko) { - inst.addShortcut('ctrl', 'b', 'lang_bold_desc', 'Bold'); - inst.addShortcut('ctrl', 'i', 'lang_italic_desc', 'Italic'); - inst.addShortcut('ctrl', 'u', 'lang_underline_desc', 'Underline'); - } + remove : function(n, k) { + var t = this; - // Setup span styles - if (tinyMCE.getParam("convert_fonts_to_spans")) - inst.getBody().setAttribute('id', 'mceSpanFonts'); + return this.run(n, function(n) { + var p, g, i; - if (tinyMCE.settings.nowrap) - doc.body.style.whiteSpace = "nowrap"; + p = n.parentNode; - doc.body.dir = this.settings.directionality; - doc.editorId = editor_id; + if (!p) + return null; - // Add on document element in Mozilla - if (!tinyMCE.isIE) - doc.documentElement.editorId = editor_id; + if (k) { + for (i = n.childNodes.length - 1; i >= 0; i--) + t.insertAfter(n.childNodes[i], n); - inst.setBaseHREF(tinyMCE.settings.base_href); + //each(n.childNodes, function(c) { + // p.insertBefore(c.cloneNode(true), n); + //}); + } - // Replace new line characters to BRs - if (tinyMCE.settings.convert_newlines_to_brs) { - content = tinyMCE.regexpReplace(content, "\r\n", "
", "gi"); - content = tinyMCE.regexpReplace(content, "\r", "
", "gi"); - content = tinyMCE.regexpReplace(content, "\n", "
", "gi"); - } + // Fix IE psuedo leak + if (t.fixPsuedoLeaks) { + p = n.cloneNode(true); + k = 'IELeakGarbageBin'; + g = t.get(k) || t.add(t.doc.body, 'div', {id : k, style : 'display:none'}); + g.appendChild(n); + g.innerHTML = ''; - // Open closed anchors - // content = content.replace(new RegExp('', 'gi'), ''); + return p; + } - // Call custom cleanup code - content = tinyMCE.storeAwayURLs(content); - content = tinyMCE._customCleanup(inst, "insert_to_editor", content); + return p.removeChild(n); + }); + }, - if (tinyMCE.isIE) { - // Ugly!!! - window.setInterval('try{tinyMCE.getCSSClasses(tinyMCE.instances["' + editor_id + '"].getDoc(), "' + editor_id + '");}catch(e){}', 500); - if (tinyMCE.settings.force_br_newlines) - doc.styleSheets[0].addRule("p", "margin: 0;"); + setStyle : function(n, na, v) { + var t = this; - body = inst.getBody(); - body.editorId = editor_id; - } + return t.run(n, function(e) { + var s, i; - content = tinyMCE.cleanupHTMLCode(content); + s = e.style; - // Fix for bug #958637 - if (!tinyMCE.isIE) { - contentElement = inst.getDoc().createElement("body"); - doc = inst.getDoc(); + // Camelcase it, if needed + na = na.replace(/-(\D)/g, function(a, b){ + return b.toUpperCase(); + }); - contentElement.innerHTML = content; + // Default px suffix on these + if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v))) + v += 'px'; - if (tinyMCE.settings.cleanup_on_startup) - tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, doc, this.settings, contentElement)); - else - tinyMCE.setInnerHTML(inst.getBody(), content); + switch (na) { + case 'opacity': + // IE specific opacity + if (isIE) { + s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")"; - tinyMCE.convertAllRelativeURLs(inst.getBody()); - } else { - if (tinyMCE.settings.cleanup_on_startup) { - tinyMCE._setHTML(inst.getDoc(), content); + if (!n.currentStyle || !n.currentStyle.hasLayout) + s.display = 'inline-block'; + } - // Produces permission denied error in MSIE 5.5 - try { - tinyMCE.setInnerHTML(inst.getBody(), tinyMCE._cleanupHTML(inst, inst.contentDocument, this.settings, inst.getBody())); - } catch(e) { - // Ignore + // Fix for older browsers + s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || ''; + break; + + case 'float': + isIE ? s.styleFloat = v : s.cssFloat = v; + break; + + default: + s[na] = v || ''; } - } else - tinyMCE._setHTML(inst.getDoc(), content); - } - // Fix for bug #957681 - //inst.getDoc().designMode = inst.getDoc().designMode; + // Force update of the style data + if (t.settings.update_styles) + t.setAttrib(e, 'mce_style'); + }); + }, - tinyMCE.handleVisualAid(inst.getBody(), true, tinyMCE.settings.visual, inst); - tinyMCE.dispatchCallback(inst, 'setupcontent_callback', 'setupContent', editor_id, inst.getBody(), inst.getDoc()); + getStyle : function(n, na, c) { + n = this.get(n); - // Re-add design mode on mozilla - if (!tinyMCE.isIE) - tinyMCE.addEventHandlers(inst); + if (!n) + return false; - // Add blur handler - if (tinyMCE.isIE) { - tinyMCE.addEvent(inst.getBody(), "blur", TinyMCE_Engine.prototype._eventPatch); - tinyMCE.addEvent(inst.getBody(), "beforedeactivate", TinyMCE_Engine.prototype._eventPatch); // Bug #1439953 + // Gecko + if (this.doc.defaultView && c) { + // Remove camelcase + na = na.replace(/[A-Z]/g, function(a){ + return '-' + a; + }); - // Workaround for drag drop/copy paste base href bug - if (!tinyMCE.isOpera) { - tinyMCE.addEvent(doc.body, "mousemove", TinyMCE_Engine.prototype.onMouseMove); - tinyMCE.addEvent(doc.body, "beforepaste", TinyMCE_Engine.prototype._eventPatch); - tinyMCE.addEvent(doc.body, "drop", TinyMCE_Engine.prototype._eventPatch); + try { + return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na); + } catch (ex) { + // Old safari might fail + return null; + } } - } - // Trigger node change, this call locks buttons for tables and so forth - inst.select(); - tinyMCE.selectedElement = inst.contentWindow.document.body; + // Camelcase it, if needed + na = na.replace(/-(\D)/g, function(a, b){ + return b.toUpperCase(); + }); - // Call custom DOM cleanup - tinyMCE._customCleanup(inst, "insert_to_editor_dom", inst.getBody()); - tinyMCE._customCleanup(inst, "setup_content_dom", inst.getBody()); - tinyMCE._setEventsEnabled(inst.getBody(), false); - tinyMCE.cleanupAnchors(inst.getDoc()); + if (na == 'float') + na = isIE ? 'styleFloat' : 'cssFloat'; - if (tinyMCE.getParam("convert_fonts_to_spans")) - tinyMCE.convertSpansToFonts(inst.getDoc()); + // IE & Opera + if (n.currentStyle && c) + return n.currentStyle[na]; - inst.startContent = tinyMCE.trim(inst.getBody().innerHTML); - inst.undoRedo.add({ content : inst.startContent }); + return n.style[na]; + }, - // Cleanup any mess left from storyAwayURLs - if (tinyMCE.isGecko) { - // Remove mce_src from textnodes and comments - tinyMCE.selectNodes(inst.getBody(), function(n) { - if (n.nodeType == 3 || n.nodeType == 8) - n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), ""); + setStyles : function(e, o) { + var t = this, s = t.settings, ol; - return false; + ol = s.update_styles; + s.update_styles = 0; + + each(o, function(v, n) { + t.setStyle(e, n, v); }); - } - // Remove Gecko spellchecking - if (tinyMCE.isGecko) - inst.getBody().spellcheck = tinyMCE.getParam("gecko_spellcheck"); + // Update style info + s.update_styles = ol; + if (s.update_styles) + t.setAttrib(e, s.cssText); + }, - // Cleanup any mess left from storyAwayURLs - tinyMCE._removeInternal(inst.getBody()); + setAttrib : function(e, n, v) { + var t = this; - inst.select(); - tinyMCE.triggerNodeChange(false, true); - }, + // Whats the point + if (!e || !n) + return; - storeAwayURLs : function(s) { - // Remove all mce_src, mce_href and replace them with new ones - // s = s.replace(new RegExp('mce_src\\s*=\\s*\"[^ >\"]*\"', 'gi'), ''); - // s = s.replace(new RegExp('mce_href\\s*=\\s*\"[^ >\"]*\"', 'gi'), ''); + // Strict XML mode + if (t.settings.strict) + n = n.toLowerCase(); - if (!s.match(/(mce_src|mce_href)/gi, s)) { - s = s.replace(new RegExp('src\\s*=\\s*[\"\']([^ >\"]*)[\"\']', 'gi'), 'src="$1" mce_src="$1"'); - s = s.replace(new RegExp('href\\s*=\\s*[\"\']([^ >\"]*)[\"\']', 'gi'), 'href="$1" mce_href="$1"'); - } + return this.run(e, function(e) { + var s = t.settings; - return s; - }, + switch (n) { + case "style": + if (!is(v, 'string')) { + each(v, function(v, n) { + t.setStyle(e, n, v); + }); - _removeInternal : function(n) { - if (tinyMCE.isGecko) { - // Remove mce_src from textnodes and comments - tinyMCE.selectNodes(n, function(n) { - if (n.nodeType == 3 || n.nodeType == 8) - n.nodeValue = n.nodeValue.replace(new RegExp('\\s(mce_src|mce_href)=\"[^\"]*\"', 'gi'), ""); + return; + } - return false; - }); - } - }, + // No mce_style for elements with these since they might get resized by the user + if (s.keep_values) { + if (v && !t._isRes(v)) + e.setAttribute('mce_style', v, 2); + else + e.removeAttribute('mce_style', 2); + } - removeTinyMCEFormElements : function(form_obj) { - var i, elementId; + e.style.cssText = v; + break; - // Skip form element removal - if (!tinyMCE.getParam('hide_selects_on_submit')) - return; + case "class": + e.className = v || ''; // Fix IE null bug + break; - // Check if form is valid - if (typeof(form_obj) == "undefined" || form_obj == null) - return; + case "src": + case "href": + if (s.keep_values) { + if (s.url_converter) + v = s.url_converter.call(s.url_converter_scope || t, v, n, e); - // If not a form, find the form - if (form_obj.nodeName != "FORM") { - if (form_obj.form) - form_obj = form_obj.form; - else - form_obj = tinyMCE.getParentElement(form_obj, "form"); - } + t.setAttrib(e, 'mce_' + n, v, 2); + } - // Still nothing - if (form_obj == null) - return; + break; + + case "shape": + e.setAttribute('mce_style', v); + break; + } - // Disable all UI form elements that TinyMCE created - for (i=0; i"); - rng.collapse(false); - rng.select(); + each(o, function(v, k) { + if (k && v) { + if (tinymce.isGecko && k.indexOf('-moz-') === 0) + return; - tinyMCE.execCommand("mceAddUndoLevel"); - tinyMCE.triggerNodeChange(false); - return false; + switch (k) { + case 'color': + case 'background-color': + v = v.toLowerCase(); + break; } + + s += (s ? ' ' : '') + k + ': ' + v + ';'; } + }); - // Backspace or delete - if (e.keyCode == 8 || e.keyCode == 46) { - tinyMCE.selectedElement = e.target; - tinyMCE.linkElement = tinyMCE.getParentElement(e.target, "a"); - tinyMCE.imgElement = tinyMCE.getParentElement(e.target, "img"); - tinyMCE.triggerNodeChange(false); + return s; + }, + + loadCSS : function(u) { + var t = this, d = t.doc; + + if (!u) + u = ''; + + each(u.split(','), function(u) { + if (t.files[u]) + return; + + t.files[u] = true; + t.add(t.select('head')[0], 'link', {rel : 'stylesheet', href : tinymce._addVer(u)}); + }); + }, + + + addClass : function(e, c) { + return this.run(e, function(e) { + var o; + + if (!c) + return 0; + + if (this.hasClass(e, c)) + return e.className; + + o = this.removeClass(e, c); + + return e.className = (o != '' ? (o + ' ') : '') + c; + }); + }, + + removeClass : function(e, c) { + var t = this, re; + + return t.run(e, function(e) { + var v; + + if (t.hasClass(e, c)) { + if (!re) + re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g"); + + v = e.className.replace(re, ' '); + + return e.className = tinymce.trim(v != ' ' ? v : ''); } + return e.className; + }); + }, + + hasClass : function(n, c) { + n = this.get(n); + + if (!n || !c) return false; - case "keyup": - case "keydown": - tinyMCE.hideMenus(); - tinyMCE.hasMouseMoved = false; + return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1; + }, - if (inst && inst.handleShortcut(e)) - return false; + show : function(e) { + return this.setStyle(e, 'display', 'block'); + }, - inst._fixRootBlocks(); + hide : function(e) { + return this.setStyle(e, 'display', 'none'); + }, - if (inst.settings.remove_trailing_nbsp) - inst._fixTrailingNbsp(); + isHidden : function(e) { + e = this.get(e); - if (e.target.editorId) - tinyMCE.instances[e.target.editorId].select(); + return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none'; + }, - if (tinyMCE.selectedInstance) - tinyMCE.selectedInstance.switchSettings(); - inst = tinyMCE.selectedInstance; + uniqueId : function(p) { + return (!p ? 'mce_' : p) + (this.counter++); + }, - // Handle backspace - if (tinyMCE.isGecko && tinyMCE.settings.force_p_newlines && (e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) { - // Insert P element instead of BR - if (TinyMCE_ForceParagraphs._handleBackSpace(tinyMCE.selectedInstance, e.type)) { - // Cancel event - tinyMCE.execCommand("mceAddUndoLevel"); - e.preventDefault(); - return false; - } - } + setHTML : function(e, h) { + var t = this; - tinyMCE.selectedElement = null; - tinyMCE.selectedNode = null; - elm = tinyMCE.selectedInstance.getFocusElement(); - tinyMCE.linkElement = tinyMCE.getParentElement(elm, "a"); - tinyMCE.imgElement = tinyMCE.getParentElement(elm, "img"); - tinyMCE.selectedElement = elm; + return this.run(e, function(e) { + var x, i, nl, n, p, x; - // Update visualaids on tabs - if (tinyMCE.isGecko && e.type == "keyup" && e.keyCode == 9) - tinyMCE.handleVisualAid(tinyMCE.selectedInstance.getBody(), true, tinyMCE.settings.visual, tinyMCE.selectedInstance); + h = t.processHTML(h); - // Fix empty elements on return/enter, check where enter occured - if (tinyMCE.isIE && e.type == "keydown" && e.keyCode == 13) - tinyMCE.enterKeyElement = tinyMCE.selectedInstance.getFocusElement(); + if (isIE) { + function set() { + try { + // IE will remove comments from the beginning + // unless you padd the contents with something + e.innerHTML = '
' + h; + e.removeChild(e.firstChild); + } catch (ex) { + // IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p + // This seems to fix this problem - // Fix empty elements on return/enter - if (tinyMCE.isIE && e.type == "keyup" && e.keyCode == 13) { - elm = tinyMCE.enterKeyElement; - if (elm) { - var re = new RegExp('^HR|IMG|BR$','g'); // Skip these - var dre = new RegExp('^H[1-6]$','g'); // Add double on these + // Remove all child nodes + while (e.firstChild) + e.firstChild.removeNode(); - if (!elm.hasChildNodes() && !re.test(elm.nodeName)) { - if (dre.test(elm.nodeName)) - elm.innerHTML = "  "; - else - elm.innerHTML = " "; + // Create new div with HTML contents and a BR infront to keep comments + x = t.create('div'); + x.innerHTML = '
' + h; + + // Add all children from div to target + each (x.childNodes, function(n, i) { + // Skip br element + if (i) + e.appendChild(n); + }); } - } - } + }; - // Check if it's a position key - keys = tinyMCE.posKeyCodes; - var posKey = false; - for (i=0; i
  • Item 1

is inserted + // It seems to be that IE doesn't like a root block element placed inside another root block element + if (t.settings.fix_ie_paragraphs) + h = h.replace(/

<\/p>|]+)><\/p>|/gi, ' 

'); - // MSIE custom key handling - if (tinyMCE.isIE && tinyMCE.settings.custom_undo_redo) { - keys = [8, 46]; // Backspace,Delete + set(); - for (i=0; i= 0; i--) { + n = nl[i]; + + if (!n.hasChildNodes()) { + if (!n.mce_keep) { + x = 1; // Is broken + break; + } + + n.removeAttribute('mce_keep'); + } } } - } - // If Ctrl key - if (e.keyCode == 17) - return true; + // Time to fix the madness IE left us + if (x) { + // So if we replace the p elements with divs and mark them and then replace them back to paragraphs + // after we use innerHTML we can fix the DOM tree + h = h.replace(/

]+)>|

/g, '

'); + h = h.replace(/<\/p>/g, '
'); - // Handle Undo/Redo when typing content + // Set the new HTML with DIVs + set(); - if (tinyMCE.isGecko) { - // Start typing (not a position key or ctrl key, but ctrl+x and ctrl+p is ok) - if (!posKey && e.type == "keyup" && !e.ctrlKey || (e.ctrlKey && (e.keyCode == 86 || e.keyCode == 88))) - tinyMCE.execCommand("mceStartTyping"); - } else { - // IE seems to be working better with this setting - if (!posKey && e.type == "keyup") - tinyMCE.execCommand("mceStartTyping"); - } + // Replace all DIV elements with he mce_tmp attibute back to paragraphs + // This is needed since IE has a annoying bug see above for details + // This is a slow process but it has to be done. :( + if (t.settings.fix_ie_paragraphs) { + nl = e.getElementsByTagName("DIV"); + for (i = nl.length - 1; i >= 0; i--) { + n = nl[i]; - // Store undo bookmark - if (e.type == "keydown" && (posKey || e.ctrlKey) && inst) - inst.undoBookmark = inst.selection.getBookmark(); + // Is it a temp div + if (n.mce_tmp) { + // Create new paragraph + p = t.doc.createElement('p'); - // End typing (position key) or some Ctrl event - if (e.type == "keyup" && (posKey || e.ctrlKey)) - tinyMCE.execCommand("mceEndTyping"); + // Copy all attributes + n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) { + var v; - if (posKey && e.type == "keyup") - tinyMCE.triggerNodeChange(false); + if (b !== 'mce_tmp') { + v = n.getAttribute(b); - if (tinyMCE.isIE && e.ctrlKey) - window.setTimeout('tinyMCE.triggerNodeChange(false);', 1); - break; + if (!v && b === 'class') + v = n.className; - case "mousedown": - case "mouseup": - case "click": - case "dblclick": - case "focus": - tinyMCE.hideMenus(); + p.setAttribute(b, v); + } + }); - if (tinyMCE.selectedInstance) { - tinyMCE.selectedInstance.switchSettings(); - tinyMCE.selectedInstance.isFocused = true; - } + // Append all children to new paragraph + for (x = 0; x|]+)>/gi, '<$1b$2>'); + h = h.replace(/<(\/?)em>|]+)>/gi, '<$1i$2>'); + } else if (isIE) { + h = h.replace(/'/g, '''); // IE can't handle apos + h = h.replace(/\s+(disabled|checked|readonly|selected)\s*=\s*[\"\']?(false|0)[\"\']?/gi, ''); // IE doesn't handle default values correct + } - // Reset selected node - if (e.type != "focus") - tinyMCE.selectedNode = null; + // Fix some issues + h = h.replace(/]+)\/>|/gi, ''); // Force open - tinyMCE.triggerNodeChange(false); - tinyMCE.execCommand("mceEndTyping"); + // Store away src and href in mce_src and mce_href since browsers mess them up + if (s.keep_values) { + // Wrap scripts and styles in comments for serialization purposes + if (/)/g, '\n'); + s = s.replace(/^[\r\n]*|[\r\n]*$/g, ''); + s = s.replace(/^\s*(\/\/\s*|\]\]>|-->|\]\]-->)\s*$/g, ''); - if (e.type == "mouseup") - tinyMCE.execCommand("mceAddUndoLevel"); + return s; + }; - // Just in case - if (!tinyMCE.selectedInstance && e.target.editorId) - tinyMCE.instances[e.target.editorId].select(); + // Preserve script elements + h = h.replace(/]+|)>([\s\S]*?)<\/script>/g, function(v, a, b) { + // Remove prefix and suffix code for script element + b = trim(b); - return false; - } - }, + // Force type attribute + if (!a) + a = ' type="text/javascript"'; - getButtonHTML : function(id, lang, img, cmd, ui, val) { - var h = '', m, x, io = ''; + // Wrap contents in a comment + if (b) + b = ''; - cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\''; + // Output fake element + return '' + b + ''; + }); - if (typeof(ui) != "undefined" && ui != null) - cmd += ',' + ui; + // Preserve style elements + h = h.replace(/]+|)>([\s\S]*?)<\/style>/g, function(v, a, b) { + b = trim(b); + return '' + b + ''; + }); + } - if (typeof(val) != "undefined" && val != null) - cmd += ",'" + val + "'"; + h = h.replace(//g, ''); - cmd += ');'; + // Process all tags with src, href or style + h = h.replace(/<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi, function(a, n) { + function handle(m, b, c) { + var u = c; - // Patch for IE7 bug with hover out not restoring correctly - if (tinyMCE.isRealIE) - io = 'onmouseover="tinyMCE.lastHover = this;"'; + // Tag already got a mce_ version + if (a.indexOf('mce_' + b) != -1) + return m; - // Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled - if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = this.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) { - // Tiled button - x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20); - h += ''; - h += '{$'+lang+'}'; - h += ''; - } else { - // Normal button - h += ''; - h += '{$'+lang+'}'; - h += ''; - } + if (b == 'style') { + // Why did I need this one? + //if (isIE) + // u = t.serializeStyle(t.parseStyle(u)); - return h; - }, + // No mce_style for elements with these since they might get resized by the user + if (t._isRes(c)) + return m; - getMenuButtonHTML : function(id, lang, img, mcmd, cmd, ui, val) { - var h = '', m, x; + if (s.hex_colors) { + u = u.replace(/rgb\([^\)]+\)/g, function(v) { + return t.toHex(v); + }); + } - mcmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + mcmd + '\');'; - cmd = 'tinyMCE.execInstanceCommand(\'{$editor_id}\',\'' + cmd + '\''; + if (s.url_converter) { + u = u.replace(/url\([\'\"]?([^\)\'\"]+)\)/g, function(x, c) { + return 'url(' + t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n)) + ')'; + }); + } + } else if (b != 'coords' && b != 'shape') { + if (s.url_converter) + u = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n)); + } - if (typeof(ui) != "undefined" && ui != null) - cmd += ',' + ui; + return ' ' + b + '="' + c + '" mce_' + b + '="' + u + '"'; + }; - if (typeof(val) != "undefined" && val != null) - cmd += ",'" + val + "'"; + a = a.replace(/ (src|href|style|coords|shape)=[\"]([^\"]+)[\"]/gi, handle); // W3C + a = a.replace(/ (src|href|style|coords|shape)=[\']([^\']+)[\']/gi, handle); // W3C - cmd += ');'; + return a.replace(/ (src|href|style|coords|shape)=([^\s\"\'>]+)/gi, handle); // IE + }); + } - // Use tilemaps when enabled and found and never in MSIE since it loads the tile each time from cache if cahce is disabled - if (tinyMCE.getParam('button_tile_map') && (!tinyMCE.isIE || tinyMCE.isOpera) && (m = tinyMCE.buttonMap[id]) != null && (tinyMCE.getParam("language") == "en" || img.indexOf('$lang') == -1)) { - x = 0 - (m * 20) == 0 ? '0' : 0 - (m * 20); + return h; + }, - if (tinyMCE.isRealIE) - h += ''; - else - h += ''; + getOuterHTML : function(e) { + var d; - h += ''; - h += ''; - h += ''; - h += ''; - } else { - if (tinyMCE.isRealIE) - h += ''; - else - h += ''; + e = this.get(e); - h += ''; - h += ''; - h += ''; - h += ''; - } + if (!e) + return null; - return h; - }, + if (e.outerHTML !== undefined) + return e.outerHTML; - _menuButtonEvent : function(e, o) { - if (o.className == 'mceMenuButtonFocus') - return; + d = (e.ownerDocument || this.doc).createElement("body"); + d.appendChild(e.cloneNode(true)); - if (e == 'over') - o.className = o.className + ' mceMenuHover'; - else - o.className = o.className.replace(/\s.*$/, ''); - }, + return d.innerHTML; + }, - addButtonMap : function(m) { - var i, a = m.replace(/\s+/, '').split(','); + setOuterHTML : function(e, h, d) { + var t = this; - for (i=0; i&\"]/g, function (c, b) { + switch (c) { + case '&': + return '&'; - submitPatch : function() { - tinyMCE.formSubmit(this, true); - }, + case '"': + return '"'; - onLoad : function() { - var r, i, c, mode, trigger, elements, element, settings, elementId, elm; - var selector, deselector, elementRefAr, form; + case '<': + return '<'; - // Wait for everything to be loaded first - if (tinyMCE.settings.strict_loading_mode && this.loadingIndex != -1) { - window.setTimeout('tinyMCE.onLoad();', 1); - return; - } + case '>': + return '>'; + } - if (tinyMCE.isRealIE && window.event.type == "readystatechange" && document.readyState != "complete") - return true; + return c; + }) : s; + }, - if (tinyMCE.isLoaded) - return true; - tinyMCE.isLoaded = true; + insertAfter : function(n, r) { + var t = this; - // IE produces JS error if TinyMCE is placed in a frame - // It seems to have something to do with the selection not beeing - // correctly initialized in IE so this hack solves the problem - if (tinyMCE.isRealIE && document.body && window.location.href != window.top.location.href) { - r = document.body.createTextRange(); - r.collapse(true); - r.select(); - } + r = t.get(r); - tinyMCE.dispatchCallback(null, 'onpageload', 'onPageLoad'); + return this.run(n, function(n) { + var p, ns; - for (c=0; c 1 ? s : '0' + s; // 0 -> 00 + }; - if (element) - tinyMCE.addMCEControl(element, elements[i]); - } - break; + if (c) { + s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]); - case "specific_textareas": - case "textareas": - elements = document.getElementsByTagName("textarea"); + return s; + } - for (i=0; i 0) + t.classes = cl; - if (tinyMCE.settings.ask || tinyMCE.settings.convert_on_click) { - // Focus breaks in Mozilla - if (tinyMCE.isGecko) { - settings = tinyMCE.settings; + return cl; + }, - tinyMCE.addEvent(element, "focus", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);}); + run : function(e, f, s) { + var t = this, o; - if (element.nodeName != "TEXTAREA" && element.nodeName != "INPUT") - tinyMCE.addEvent(element, "click", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);}); - // tinyMCE.addEvent(element, "mouseover", function (e) {window.setTimeout(function() {TinyMCE_Engine.prototype.confirmAdd(e, settings);}, 10);}); - } else { - settings = tinyMCE.settings; + if (t.doc && typeof(e) === 'string') + e = t.get(e); - tinyMCE.addEvent(element, "focus", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); }); - tinyMCE.addEvent(element, "click", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); }); - // tinyMCE.addEvent(element, "mouseenter", function () { TinyMCE_Engine.prototype.confirmAdd(null, settings); }); + if (!e) + return false; + + s = s || this; + if (!e.nodeType && (e.length || e.length === 0)) { + o = []; + + each(e, function(e, i) { + if (e) { + if (typeof(e) == 'string') + e = t.doc.getElementById(e); + + o.push(f.call(s, e, i)); } - } else - tinyMCE.addMCEControl(element, elementId); - } + }); - // Handle auto focus - if (tinyMCE.settings.auto_focus) { - window.setTimeout(function () { - var inst = tinyMCE.getInstanceById(tinyMCE.settings.auto_focus); - inst.selection.selectNode(inst.getBody(), true, true); - inst.contentWindow.focus(); - }, 100); + return o; } - tinyMCE.dispatchCallback(null, 'oninit', 'onInit'); - } - }, + return f.call(s, e); + }, - isInstance : function(o) { - return o != null && typeof(o) == "object" && o.isTinyMCE_Control; - }, + getAttribs : function(n) { + var o; - getParam : function(name, default_value, strip_whitespace, split_chr) { - var i, outArray, value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name]; + n = this.get(n); - // Fix bool values - if (value == "true" || value == "false") - return (value == "true"); + if (!n) + return []; - if (strip_whitespace) - value = tinyMCE.regexpReplace(value, "[ \t\r\n]", ""); + if (isIE) { + o = []; - if (typeof(split_chr) != "undefined" && split_chr != null) { - value = value.split(split_chr); - outArray = []; + // Object will throw exception in IE + if (n.nodeName == 'OBJECT') + return n.attributes; - for (i=0; itext 1CHOPtext 2

+ // would produce: + //

text 1

CHOP

text 2

+ // this function will then trim of empty edges and produce: + //

text 1

CHOP

text 2

+ function trimEdge(n, na) { + n = n[na]; - return !e.firstChild ? s : e.firstChild.nodeValue; - }, + if (n && n[na] && n[na].nodeType == 1 && isEmpty(n[na])) + t.remove(n[na]); + }; - addToLang : function(prefix, ar) { - var k; + function isEmpty(n) { + n = t.getOuterHTML(n); + n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars + n = n.replace(/<[^>]+>/g, ''); // Remove all tags - for (k in ar) { - if (typeof(ar[k]) == 'function') - continue; + return n.replace(/[ \t\r\n]+| | /g, '') == ''; + }; - tinyMCELang[(k.indexOf('lang_') == -1 ? 'lang_' : '') + (prefix !== '' ? (prefix + "_") : '') + k] = ar[k]; - } + if (pe && e) { + // Get before chunk + r.setStartBefore(pe); + r.setEndBefore(e); + bef = r.extractContents(); - this.loadNextScript(); - }, + // Get after chunk + r = t.createRng(); + r.setStartAfter(e); + r.setEndAfter(pe); + aft = r.extractContents(); - triggerNodeChange : function(focus, setup_content) { - var elm, inst, editorId, undoIndex = -1, undoLevels = -1, doc, anySelection, st; + // Insert chunks and remove parent + pa = pe.parentNode; - if (tinyMCE.selectedInstance) { - inst = tinyMCE.selectedInstance; - elm = (typeof(setup_content) != "undefined" && setup_content) ? tinyMCE.selectedElement : inst.getFocusElement(); + // Remove right side edge of the before contents + trimEdge(bef, 'lastChild'); -/* if (elm == inst.lastTriggerEl) - return; + if (!isEmpty(bef)) + pa.insertBefore(bef, pe); - inst.lastTriggerEl = elm;*/ + if (re) + pa.replaceChild(re, e); + else + pa.insertBefore(e, pe); - editorId = inst.editorId; - st = inst.selection.getSelectedText(); + // Remove left site edge of the after contents + trimEdge(aft, 'firstChild'); - if (tinyMCE.settings.auto_resize) - inst.resizeToContent(); + if (!isEmpty(aft)) + pa.insertBefore(aft, pe); - if (setup_content && tinyMCE.isGecko && inst.isHidden()) - elm = inst.getBody(); + t.remove(pe); - inst.switchSettings(); - anySelection = !inst.selection.isCollapsed(); - - if (tinyMCE.settings.custom_undo_redo) { - undoIndex = inst.undoRedo.undoIndex; - undoLevels = inst.undoRedo.undoLevels.length; + return re || e; } + }, - tinyMCE.dispatchCallback(inst, 'handle_node_change_callback', 'handleNodeChange', editorId, elm, undoIndex, undoLevels, inst.visualAid, anySelection, setup_content); + _isRes : function(c) { + // Is live resizble element + return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c); } - if (this.selectedInstance && (typeof(focus) == "undefined" || focus)) - this.selectedInstance.contentWindow.focus(); - }, + /* + walk : function(n, f, s) { + var d = this.doc, w; - _customCleanup : function(inst, type, content) { - var pl, po, i, customCleanup; + if (d.createTreeWalker) { + w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); - // Call custom cleanup - customCleanup = tinyMCE.settings.cleanup_callback; - if (customCleanup != '') - content = tinyMCE.resolveDots(tinyMCE.settings.cleanup_callback, window)(type, content, inst); + while ((n = w.nextNode()) != null) + f.call(s || this, n); + } else + tinymce.walk(n, f, 'childNodes', s); + } + */ - // Trigger theme cleanup - po = tinyMCE.themes[tinyMCE.settings.theme]; - if (po && po.cleanup) - content = po.cleanup(type, content, inst); + /* + toRGB : function(s) { + var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s); - // Trigger plugin cleanups - pl = inst.plugins; - for (i=0; i #FFFFFF + if (!is(c[3])) + c[3] = c[2] = c[1]; - if (po && po.cleanup) - content = po.cleanup(type, content, inst); + return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")"; + } + + return s; } + */ - return content; - }, + }); - setContent : function(h) { - if (tinyMCE.selectedInstance) { - tinyMCE.selectedInstance.execCommand('mceSetContent', false, h); - tinyMCE.selectedInstance.repaint(); + // Setup page DOM + tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0}); +})(tinymce); +(function(ns) { + // Traverse constants + var EXTRACT = 0, CLONE = 1, DELETE = 2, extend = tinymce.extend; + + function indexOf(child, parent) { + var i, node; + + if (child.parentNode != parent) + return -1; + + for (node = parent.firstChild, i = 0; node != child; node = node.nextSibling) + i++; + + return i; + }; + + function nodeIndex(n) { + var i = 0; + + while (n.previousSibling) { + i++; + n = n.previousSibling; } - }, - importThemeLanguagePack : function(name) { - if (typeof(name) == "undefined") - name = tinyMCE.settings.theme; + return i; + }; - tinyMCE.loadScript(tinyMCE.baseURL + '/themes/' + name + '/langs/' + tinyMCE.settings.language + '.js'); - }, + function getSelectedNode(container, offset) { + var child; - importPluginLanguagePack : function(name) { - var b = tinyMCE.baseURL + '/plugins/' + name; + if (container.nodeType == 3 /* TEXT_NODE */) + return container; - if (this.plugins[name]) - b = this.plugins[name].baseURL; + if (offset < 0) + return container; - tinyMCE.loadScript(b + '/langs/' + tinyMCE.settings.language + '.js'); - }, + child = container.firstChild; + while (child != null && offset > 0) { + --offset; + child = child.nextSibling; + } - applyTemplate : function(h, ag) { - return h.replace(new RegExp('\\{\\$([a-z0-9_]+)\\}', 'gi'), function(m, s) { - if (s.indexOf('lang_') == 0 && tinyMCELang[s]) - return tinyMCELang[s]; + if (child != null) + return child; - if (ag && ag[s]) - return ag[s]; + return container; + }; - if (tinyMCE.settings[s]) - return tinyMCE.settings[s]; + // Range constructor + function Range(dom) { + var d = dom.doc; - if (m == 'themeurl') - return tinyMCE.themeURL; + extend(this, { + dom : dom, - return m; + // Inital states + startContainer : d, + startOffset : 0, + endContainer : d, + endOffset : 0, + collapsed : true, + commonAncestorContainer : d, + + // Range constants + START_TO_START : 0, + START_TO_END : 1, + END_TO_END : 2, + END_TO_START : 3 }); - }, + }; - replaceVar : function(h, r, v) { - return h.replace(new RegExp('{\\\$' + r + '}', 'g'), v); - }, + // Add range methods + extend(Range.prototype, { + setStart : function(n, o) { + this._setEndPoint(true, n, o); + }, - openWindow : function(template, args) { - var html, width, height, x, y, resizable, scrollbars, url, name, win, modal, features; + setEnd : function(n, o) { + this._setEndPoint(false, n, o); + }, - args = !args ? {} : args; + setStartBefore : function(n) { + this.setStart(n.parentNode, nodeIndex(n)); + }, - args.mce_template_file = template.file; - args.mce_width = template.width; - args.mce_height = template.height; - tinyMCE.windowArgs = args; + setStartAfter : function(n) { + this.setStart(n.parentNode, nodeIndex(n) + 1); + }, - html = template.html; - if (!(width = parseInt(template.width))) - width = 320; + setEndBefore : function(n) { + this.setEnd(n.parentNode, nodeIndex(n)); + }, - if (!(height = parseInt(template.height))) - height = 200; + setEndAfter : function(n) { + this.setEnd(n.parentNode, nodeIndex(n) + 1); + }, - // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!! - if (tinyMCE.isIE) - height += 40; - else - height += 20; + collapse : function(ts) { + var t = this; - x = parseInt(screen.width / 2.0) - (width / 2.0); - y = parseInt(screen.height / 2.0) - (height / 2.0); + if (ts) { + t.endContainer = t.startContainer; + t.endOffset = t.startOffset; + } else { + t.startContainer = t.endContainer; + t.startOffset = t.endOffset; + } - resizable = (args && args.resizable) ? args.resizable : "no"; - scrollbars = (args && args.scrollbars) ? args.scrollbars : "no"; + t.collapsed = true; + }, - if (template.file.charAt(0) != '/' && template.file.indexOf('://') == -1) - url = tinyMCE.baseURL + "/themes/" + tinyMCE.getParam("theme") + "/" + template.file; - else - url = template.file; + selectNode : function(n) { + this.setStartBefore(n); + this.setEndAfter(n); + }, - // Replace all args as variables in URL - for (name in args) { - if (typeof(args[name]) == 'function') - continue; + selectNodeContents : function(n) { + this.setStart(n, 0); + this.setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length); + }, - url = tinyMCE.replaceVar(url, name, escape(args[name])); - } + compareBoundaryPoints : function(h, r) { + var t = this, sc = t.startContainer, so = t.startOffset, ec = t.endContainer, eo = t.endOffset; - if (html) { - html = tinyMCE.replaceVar(html, "css", this.settings.popups_css); - html = tinyMCE.applyTemplate(html, args); + // Check START_TO_START + if (h === 0) + return t._compareBoundaryPoints(sc, so, sc, so); - 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); - if (win == null) { - alert(tinyMCELang.lang_popup_blocked); - return; - } + // Check START_TO_END + if (h === 1) + return t._compareBoundaryPoints(sc, so, ec, eo); - win.document.write(html); - win.document.close(); - win.resizeTo(width, height); - win.focus(); - } else { - if ((tinyMCE.isRealIE) && resizable != 'yes' && tinyMCE.settings.dialog_type == "modal") { - height += 10; + // Check END_TO_END + if (h === 2) + return t._compareBoundaryPoints(ec, eo, ec, eo); - features = "resizable:" + resizable + ";scroll:" + scrollbars + ";status:yes;center:yes;help:no;dialogWidth:" + width + "px;dialogHeight:" + height + "px;"; + // Check END_TO_START + if (h === 3) + return t._compareBoundaryPoints(ec, eo, sc, so); + }, - window.showModalDialog(url, window, features); + deleteContents : function() { + this._traverse(DELETE); + }, + + extractContents : function() { + return this._traverse(EXTRACT); + }, + + cloneContents : function() { + return this._traverse(CLONE); + }, + + insertNode : function(n) { + var t = this, nn, o; + + // Node is TEXT_NODE or CDATA + if (n.nodeType === 3 || n.nodeType === 4) { + nn = t.startContainer.splitText(t.startOffset); + t.startContainer.parentNode.insertBefore(n, nn); } else { - modal = (resizable == "yes") ? "no" : "yes"; + // Insert element node + if (t.startContainer.childNodes.length > 0) + o = t.startContainer.childNodes[t.startOffset]; - if (tinyMCE.isGecko && tinyMCE.isMac) - modal = "no"; + t.startContainer.insertBefore(n, o); + } + }, - if (template.close_previous != "no") - try {tinyMCE.lastWindow.close();} catch (ex) {} + surroundContents : function(n) { + var t = this, f = t.extractContents(); - 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); - if (win == null) { - alert(tinyMCELang.lang_popup_blocked); - return; + t.insertNode(n); + n.appendChild(f); + t.selectNode(n); + }, + + cloneRange : function() { + var t = this; + + return extend(new Range(t.dom), { + startContainer : t.startContainer, + startOffset : t.startOffset, + endContainer : t.endContainer, + endOffset : t.endOffset, + collapsed : t.collapsed, + commonAncestorContainer : t.commonAncestorContainer + }); + }, + +/* + toString : function() { + // Not implemented + }, + + detach : function() { + // Not implemented + }, +*/ + // Internal methods + + _isCollapsed : function() { + return (this.startContainer == this.endContainer && this.startOffset == this.endOffset); + }, + + _compareBoundaryPoints : function (containerA, offsetA, containerB, offsetB) { + var c, offsetC, n, cmnRoot, childA, childB; + + // In the first case the boundary-points have the same container. A is before B + // if its offset is less than the offset of B, A is equal to B if its offset is + // equal to the offset of B, and A is after B if its offset is greater than the + // offset of B. + if (containerA == containerB) { + if (offsetA == offsetB) { + return 0; // equal + } else if (offsetA < offsetB) { + return -1; // before + } else { + return 1; // after } + } - if (template.close_previous != "no") - tinyMCE.lastWindow = win; + // In the second case a child node C of the container of A is an ancestor + // container of B. In this case, A is before B if the offset of A is less than or + // equal to the index of the child node C and A is after B otherwise. + c = containerB; + while (c && c.parentNode != containerA) { + c = c.parentNode; + } + if (c) { + offsetC = 0; + n = containerA.firstChild; - try { - win.resizeTo(width, height); - } catch(e) { - // Ignore + while (n != c && offsetC < offsetA) { + offsetC++; + n = n.nextSibling; } - // Make it bigger if statusbar is forced - if (tinyMCE.isGecko && win.document) { - if (win.document.defaultView.statusbar.visible) - win.resizeBy(0, tinyMCE.isMac ? 10 : 24); + if (offsetA <= offsetC) { + return -1; // before + } else { + return 1; // after } + } - win.focus(); + // In the third case a child node C of the container of B is an ancestor container + // of A. In this case, A is before B if the index of the child node C is less than + // the offset of B and A is after B otherwise. + c = containerA; + while (c && c.parentNode != containerB) { + c = c.parentNode; } - } - }, - closeWindow : function(win) { - win.close(); - }, + if (c) { + offsetC = 0; + n = containerB.firstChild; - getVisualAidClass : function(class_name, state) { - var i, classNames, ar, className, aidClass = tinyMCE.settings.visual_table_class; + while (n != c && offsetC < offsetB) { + offsetC++; + n = n.nextSibling; + } - if (typeof(state) == "undefined") - state = tinyMCE.settings.visual; + if (offsetC < offsetB) { + return -1; // before + } else { + return 1; // after + } + } - // Split - classNames = []; - ar = class_name.split(' '); - for (i=0; i 0) - className += " "; + childB = containerB; + while (childB && childB.parentNode != cmnRoot) { + childB = childB.parentNode; + } - className += classNames[i]; - } + if (!childB) { + childB = cmnRoot; + } - return className; - }, + if (childA == childB) { + return 0; // equal + } - handleVisualAid : function(el, deep, state, inst, skip_dispatch) { - var i, x, y, tableElement, anchorName, oldW, oldH, bo, cn; + n = cmnRoot.firstChild; + while (n) { + if (n == childA) { + return -1; // before + } - if (!el) - return; + if (n == childB) { + return 1; // after + } - if (!skip_dispatch) - tinyMCE.dispatchCallback(inst, 'handle_visual_aid_callback', 'handleVisualAid', el, deep, state, inst); + n = n.nextSibling; + } + }, - tableElement = null; + _setEndPoint : function(st, n, o) { + var t = this, ec, sc; - switch (el.nodeName) { - case "TABLE": - oldW = el.style.width; - oldH = el.style.height; - bo = tinyMCE.getAttrib(el, "border"); + if (st) { + t.startContainer = n; + t.startOffset = o; + } else { + t.endContainer = n; + t.endOffset = o; + } - bo = bo == '' || bo == "0" ? true : false; + // If one boundary-point of a Range is set to have a root container + // other than the current one for the Range, the Range is collapsed to + // the new position. This enforces the restriction that both boundary- + // points of a Range must have the same root container. + ec = t.endContainer; + while (ec.parentNode) + ec = ec.parentNode; - tinyMCE.setAttrib(el, "class", tinyMCE.getVisualAidClass(tinyMCE.getAttrib(el, "class"), state && bo)); + sc = t.startContainer; + while (sc.parentNode) + sc = sc.parentNode; - el.style.width = oldW; - el.style.height = oldH; + if (sc != ec) { + t.collapse(st); + } else { + // The start position of a Range is guaranteed to never be after the + // end position. To enforce this restriction, if the start is set to + // be at a position after the end, the Range is collapsed to that + // position. + if (t._compareBoundaryPoints(t.startContainer, t.startOffset, t.endContainer, t.endOffset) > 0) + t.collapse(st); + } - for (y=0; y 0) { + startNode = startNode.parentNode; + depthDiff--; + } - if (xsrc !== '') { - try { - n.src = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href, xsrc); - } catch (e) { - // Ignore, Firefox cast exception if local file wasn't found - } + endNode = t.endContainer; + while (depthDiff < 0) { + endNode = endNode.parentNode; + depthDiff++; + } - n.removeAttribute("mce_tsrc"); - } + // ascend the ancestor hierarchy until we have a common parent. + for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) { + startNode = sp; + endNode = ep; + } - if (xhref !== '') { - try { - n.href = tinyMCE.convertRelativeToAbsoluteURL(tinyMCE.settings.base_href, xhref); - } catch (e) { - // Ignore, Firefox cast exception if local file wasn't found - } + return t._traverseCommonAncestors(startNode, endNode, how); + }, - n.removeAttribute("mce_thref"); - } + _traverseSameContainer : function(how) { + var t = this, frag, s, sub, n, cnt, sibling, xferNode; - return false; - }); + if (how != DELETE) + frag = t.dom.doc.createDocumentFragment(); - // Restore text/comment nodes - tinyMCE.selectNodes(e, function(n) { - if (n.nodeType == 3 || n.nodeType == 8) { - n.nodeValue = n.nodeValue.replace(/\smce_tsrc=/gi, " src="); - n.nodeValue = n.nodeValue.replace(/\smce_thref=/gi, " href="); - } + // If selection is empty, just return the fragment + if (t.startOffset == t.endOffset) + return frag; - return false; - }); + // Text node needs special case handling + if (t.startContainer.nodeType == 3 /* TEXT_NODE */) { + // get the substring + s = t.startContainer.nodeValue; + sub = s.substring(t.startOffset, t.endOffset); + + // set the original text node to its new value + if (how != CLONE) { + t.startContainer.deleteData(t.startOffset, t.endOffset - t.startOffset); + + // Nothing is partially selected, so collapse to start point + t.collapse(true); + } + + if (how == DELETE) + return null; + + frag.appendChild(t.dom.doc.createTextNode(sub)); + return frag; } - } - return h; - }, + // Copy nodes between the start/end offsets. + n = getSelectedNode(t.startContainer, t.startOffset); + cnt = t.endOffset - t.startOffset; - _setHTML : function(doc, html_content) { - var i, html, paras, node; + while (cnt > 0) { + sibling = n.nextSibling; + xferNode = t._traverseFullySelected(n, how); - // Force closed anchors open - //html_content = html_content.replace(new RegExp('', 'gi'), ''); + if (frag) + frag.appendChild( xferNode ); - html_content = tinyMCE.cleanupHTMLCode(html_content); + --cnt; + n = sibling; + } - // Try innerHTML if it fails use pasteHTML in MSIE - try { - tinyMCE.setInnerHTML(doc.body, html_content); - } catch (e) { - if (this.isMSIE) - doc.body.createTextRange().pasteHTML(html_content); - } + // Nothing is partially selected, so collapse to start point + if (how != CLONE) + t.collapse(true); - // Content duplication bug fix - if (tinyMCE.isIE && tinyMCE.settings.fix_content_duplication) { - // Remove P elements in P elements - paras = doc.getElementsByTagName("P"); - for (i=0; i 0) { + sibling = n.previousSibling; + xferNode = t._traverseFullySelected(n, how); - // Always set the htmlText output - tinyMCE.setInnerHTML(doc.body, html); - } + if (frag) + frag.insertBefore(xferNode, frag.firstChild); - tinyMCE.cleanupAnchors(doc); + --cnt; + n = sibling; + } - if (tinyMCE.getParam("convert_fonts_to_spans")) - tinyMCE.convertSpansToFonts(doc); - }, + // Collapse to just before the endAncestor, which + // is partially selected. + if (how != CLONE) { + t.setEndBefore(endAncestor); + t.collapse(false); + } - getEditorId : function(form_element) { - var inst = this.getInstanceById(form_element); + return frag; + }, - if (!inst) - return null; + _traverseCommonEndContainer : function(startAncestor, how) { + var t = this, frag, startIdx, n, cnt, sibling, xferNode; - return inst.editorId; - }, + if (how != DELETE) + frag = t.dom.doc.createDocumentFragment(); - getInstanceById : function(editor_id) { - var inst = this.instances[editor_id], n; + n = t._traverseLeftBoundary(startAncestor, how); + if (frag) + frag.appendChild(n); - if (!inst) { - for (n in tinyMCE.instances) { - inst = tinyMCE.instances[n]; + startIdx = indexOf(startAncestor, t.endContainer); + ++startIdx; // Because we already traversed it.... - if (!tinyMCE.isInstance(inst)) - continue; + cnt = t.endOffset - startIdx; + n = startAncestor.nextSibling; + while (cnt > 0) { + sibling = n.nextSibling; + xferNode = t._traverseFullySelected(n, how); - if (inst.formTargetElementId == editor_id) - return inst; + if (frag) + frag.appendChild(xferNode); + + --cnt; + n = sibling; } - } else - return inst; - return null; - }, + if (how != CLONE) { + t.setStartAfter(startAncestor); + t.collapse(true); + } - queryInstanceCommandValue : function(editor_id, command) { - var inst = tinyMCE.getInstanceById(editor_id); + return frag; + }, - if (inst) - return inst.queryCommandValue(command); + _traverseCommonAncestors : function(startAncestor, endAncestor, how) { + var t = this, n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling; - return false; - }, + if (how != DELETE) + frag = t.dom.doc.createDocumentFragment(); - queryInstanceCommandState : function(editor_id, command) { - var inst = tinyMCE.getInstanceById(editor_id); + n = t._traverseLeftBoundary(startAncestor, how); + if (frag) + frag.appendChild(n); - if (inst) - return inst.queryCommandState(command); + commonParent = startAncestor.parentNode; + startOffset = indexOf(startAncestor, commonParent); + endOffset = indexOf(endAncestor, commonParent); + ++startOffset; - return null; - }, + cnt = endOffset - startOffset; + sibling = startAncestor.nextSibling; - setWindowArg : function(n, v) { - this.windowArgs[n] = v; - }, + while (cnt > 0) { + nextSibling = sibling.nextSibling; + n = t._traverseFullySelected(sibling, how); - getWindowArg : function(n, d) { - return (typeof(this.windowArgs[n]) == "undefined") ? d : this.windowArgs[n]; - }, + if (frag) + frag.appendChild(n); - getCSSClasses : function(editor_id, doc) { - var i, c, x, rule, styles, rules, csses, selectorText, inst = tinyMCE.getInstanceById(editor_id); - var cssClass, addClass, p; + sibling = nextSibling; + --cnt; + } - if (!inst) - inst = tinyMCE.selectedInstance; + n = t._traverseRightBoundary(endAncestor, how); - if (!inst) - return []; + if (frag) + frag.appendChild(n); - if (!doc) - doc = inst.getDoc(); + if (how != CLONE) { + t.setStartAfter(startAncestor); + t.collapse(true); + } - // Is cached, use that - if (inst && inst.cssClasses.length > 0) - return inst.cssClasses; + return frag; + }, - if (!doc) - return; + _traverseRightBoundary : function(root, how) { + var t = this, next = getSelectedNode(t.endContainer, t.endOffset - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent; + var isFullySelected = next != t.endContainer; - styles = doc.styleSheets; + if (next == root) + return t._traverseNode(next, isFullySelected, false, how); - if (styles && styles.length > 0) { - for (x=0; x' + tinyMCE.replaceVar(v, "pluginurl", o.baseURL) + '
'; + if (how == DELETE) + return null; - return tinyMCE.replaceVar(v, "pluginurl", o.baseURL); + newNode = n.cloneNode(false); + newNode.nodeValue = newNodeValue; + + return newNode; } - } - o = tinyMCE.themes[tinyMCE.settings.theme]; - if (o.getControlHTML && (v = o.getControlHTML(c)) !== '') { - if (rtl) - return '' + v + ''; + if (how == DELETE) + return null; - return v; + return n.cloneNode(false); + }, + + _traverseFullySelected : function(n, how) { + var t = this; + + if (how != DELETE) + return how == CLONE ? n.cloneNode(true) : n; + + n.parentNode.removeChild(n); + return null; } + }); - return ''; - }, + ns.Range = Range; +})(tinymce.dom); +(function() { + function Selection(selection) { + var t = this; - evalFunc : function(f, idx, a, o) { - o = !o ? window : o; - f = typeof(f) == 'function' ? f : o[f]; + function getRange() { + var dom = selection.dom, ieRange = selection.getRng(), domRange = dom.createRng(), startPos = {}, endPos = {}; - return f.apply(o, Array.prototype.slice.call(a, idx)); - }, + // Handle control selection + if (ieRange.item) { + domRange.setStartBefore(ieRange.item(0)); + domRange.setEndAfter(ieRange.item(0)); - dispatchCallback : function(i, p, n) { - return this.callFunc(i, p, n, 0, this.dispatchCallback.arguments); - }, + return domRange; + } - executeCallback : function(i, p, n) { - return this.callFunc(i, p, n, 1, this.executeCallback.arguments); - }, + function findEndPoint(ie_rng, start, pos) { + var rng, rng2, startElement; - execCommandCallback : function(i, p, n) { - return this.callFunc(i, p, n, 2, this.execCommandCallback.arguments); - }, + rng = ie_rng.duplicate(); + rng.collapse(start); + element = rng.parentElement(); - callFunc : function(ins, p, n, m, a) { - var l, i, on, o, s, v; + // If element is block then we need to move one character + // since the selection has a extra invisible character + if (element.currentStyle.display == 'block') { + rng = ie_rng.duplicate(); + rng2 = ie_rng.duplicate(); - s = m == 2; + // Move one character at beginning/end of selection + if (start) + rng.moveStart('character', 1); + else + rng.moveEnd('character', -1); - l = tinyMCE.getParam(p, ''); + // The range shouldn't have been changed so lets restore it + if (rng.text != rng2.text) + rng = rng2; - if (l !== '' && (v = tinyMCE.evalFunc(l, 3, a)) == s && m > 0) - return true; + rng.collapse(start); + element = rng.parentElement(); + } - if (ins != null) { - for (i=0, l = ins.plugins; i 0) - return true; - } - } + function findIndexAndOffset(pos) { + var rng = pos.range, i, nl, marker, sibling, idx = 0; - l = tinyMCE.themes; - for (on in l) { - o = l[on]; + // Set parent and offset + pos.offset = 0; + pos.parent = rng.parentElement(); - if (o[n] && (v = tinyMCE.evalFunc(n, 3, a, o)) == s && m > 0) - return true; - } + // Insert marker + rng.pasteHTML(''); + marker = dom.get('_mce'); - return false; - }, + // Find the makers node index excluding text node fragmentation + nl = pos.parent.childNodes; + for (i = 0; i < nl.length; i++) { + if (nl[i] == marker) { + pos.index = idx; + break; + } - resolveDots : function(s, o) { - var i; + if (i > 0 && (nl[i].nodeType != 3 || nl[i - 1].nodeType != 3)) + idx++; + } - if (typeof(s) == 'string') { - for (i=0, s=s.split('.'); i': - return '>'; + // Normalize the elements to avoid fragmented dom + startPos.parent.normalize(); + endPos.parent.normalize(); + + // Set start and end points of the domRange + domRange.setStart(startPos.parent.childNodes[startPos.index], startPos.offset); + domRange.setEnd(endPos.parent.childNodes[endPos.index], endPos.offset); + + // Restore selection to new range + t.addRange(domRange); + + return domRange; + }; + + this.addRange = function(rng) { + var ieRng, startPos, endPos, body = selection.dom.doc.body; + + // Element selection, then make a control range + if (rng.startContainer.nodeType == 1) { + ieRng = body.createControlRange(); + ieRng.addElement(rng.startContainer.childNodes[rng.startOffset]); + return; } - return c; - }) : s; - }, + function findPos(start) { + var container, offset, rng2, pos; - add : function(c, m) { - var n; + // Get container and offset + container = start ? rng.startContainer : rng.endContainer; + offset = start ? rng.startOffset : rng.endOffset; - for (n in m) { - if (m.hasOwnProperty(n)) - c.prototype[n] = m[n]; - } - }, + // Insert marker character + container.nodeValue = container.nodeValue.substring(0, offset) + '\uFEFF' + container.nodeValue.substring(offset); - extend : function(p, np) { - var o = {}, n; + // Create range for whole parent element + rng2 = body.createTextRange(); + rng2.moveToElementText(container.parentNode); + pos = rng2.text.indexOf('\uFEFF'); + container.nodeValue = container.nodeValue.replace(/\uFEFF/, ''); - o.parent = p; + if (start) + startPos = pos; + else + endPos = pos; + }; - for (n in p) { - if (p.hasOwnProperty(n)) - o[n] = p[n]; + function setPos(start) { + var rng2, container = start ? rng.startContainer : rng.endContainer; + + rng2 = body.createTextRange(); + rng2.moveToElementText(container.parentNode); + rng2.collapse(true); + rng2.move('character', start ? startPos : endPos); + + if (start) + ieRng.setEndPoint('StartToStart', rng2); + else + ieRng.setEndPoint('EndToStart', rng2); + }; + + // Create IE specific range + ieRng = body.createTextRange(); + + // Find start/end pos + findPos(true); + findPos(false); + + // Set start/end pos + setPos(true); + setPos(false); + + ieRng.select(); + }; + + this.getRangeAt = function() { + // todo: Implement range caching here later + return getRange(); + }; + }; + + // Expose the selection object + tinymce.dom.TridentSelection = Selection; +})(); + +/* + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g, + done = 0, + toString = Object.prototype.toString, + arraySplice = Array.prototype.splice, + arrayPush = Array.prototype.push, + arraySort = Array.prototype.sort; + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context); + + // Reset the position of the chunker regexp (start from head) + chunker.lastIndex = 0; + + while ( (m = chunker.exec(selector)) !== null ) { + parts.push( m[1] ); + + if ( m[2] ) { + extra = RegExp.rightContext; + break; } + } - for (n in np) { - if (np.hasOwnProperty(n)) - o[n] = np[n]; + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } - return o; - }, + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - hideMenus : function() { - var e = tinyMCE.lastSelectedMenuBtn; + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } - if (tinyMCE.lastMenu) { - tinyMCE.lastMenu.hide(); - tinyMCE.lastMenu = null; + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; } + } - if (e) { - tinyMCE.switchClass(e, tinyMCE.lastMenuBtnClass); - tinyMCE.lastSelectedMenuBtn = null; + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + arrayPush.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + arrayPush.call( results, set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + arrayPush.call( results, set[i] ); + } + } } + } else { + makeArray( checkSet, results ); } - }; + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } -// Global instances -var TinyMCE = TinyMCE_Engine; // Compatiblity with gzip compressors -var tinyMCE = new TinyMCE_Engine(); -var tinyMCELang = {}; + return results; +}; -/* file:jscripts/tiny_mce/classes/TinyMCE_Control.class.js */ +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = false; + arraySort.call(results, sortOrder); -function TinyMCE_Control(settings) { - var t, i, tos, fu, p, x, fn, fu, pn, s = settings; + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + arraySplice.call(results, i--, 1); + } + } + } + } +}; - this.undoRedoLevel = true; - this.isTinyMCE_Control = true; +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; - // Default settings - this.enabled = true; - this.settings = s; - this.settings.theme = tinyMCE.getParam("theme", "default"); - this.settings.width = tinyMCE.getParam("width", -1); - this.settings.height = tinyMCE.getParam("height", -1); - this.selection = new TinyMCE_Selection(this); - this.undoRedo = new TinyMCE_UndoRedo(this); - this.cleanup = new TinyMCE_Cleanup(); - this.shortcuts = []; - this.hasMouseMoved = false; - this.foreColor = this.backColor = "#999999"; - this.data = {}; - this.cssClasses = []; +Sizzle.find = function(expr, context, isXML){ + var set, match; - this.cleanup.init({ - valid_elements : s.valid_elements, - extended_valid_elements : s.extended_valid_elements, - valid_child_elements : s.valid_child_elements, - entities : s.entities, - entity_encoding : s.entity_encoding, - debug : s.cleanup_debug, - indent : s.apply_source_formatting, - invalid_elements : s.invalid_elements, - verify_html : s.verify_html, - fix_content_duplication : s.fix_content_duplication, - convert_fonts_to_spans : s.convert_fonts_to_spans - }); + if ( !expr ) { + return []; + } - // Wrap old theme - t = this.settings.theme; - if (!tinyMCE.hasTheme(t)) { - fn = tinyMCE.callbacks; - tos = {}; + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.match[ type ].exec( expr )) ) { + var left = RegExp.leftContext; - for (i=0; i 0) { - for (i=0; i": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; - return o; - }, + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); - hasPlugin : function(n) { - var i; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } - for (i=0; i= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } - try { - s = this.selection; - b = s.getBookmark(true); - this.getBody().style.display = 'none'; - this.getDoc().execCommand('selectall', false, null); - this.getSel().collapseToStart(); - this.getBody().style.display = 'block'; - s.moveToBookmark(b); - } catch (ex) { - // Ignore + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; } }, - - switchSettings : function() { - if (tinyMCE.configs.length > 1 && tinyMCE.currentConfig != this.settings.index) { - tinyMCE.settings = this.settings; - tinyMCE.currentConfig = this.settings.index; + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); } }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; - select : function() { - var oldInst = tinyMCE.selectedInstance; + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; - if (oldInst != this) { - if (oldInst) - oldInst.execCommand('mceEndTyping'); + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } - tinyMCE.dispatchCallback(this, 'select_instance_callback', 'selectInstance', this, oldInst); - tinyMCE.selectedInstance = this; + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while (node = node.previousSibling) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while (node = node.nextSibling) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } } - }, + } +}; - getBody : function() { - return this.contentBody ? this.contentBody : this.getDoc().body; - }, +var origPOS = Expr.match.POS; - getDoc : function() { -// return this.contentDocument ? this.contentDocument : this.contentWindow.document; // Removed due to IE 5.5 ? - return this.contentWindow.document; - }, +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); +} - getWin : function() { - return this.contentWindow; - }, +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array ); - getContainerWin : function() { - return this.containerWindow ? this.containerWindow : window; - }, + if ( results ) { + arrayPush.apply( results, array ); + return results; + } + + return array; +}; - getViewPort : function() { - return tinyMCE.getViewPort(this.getWin()); - }, +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +try { + Array.prototype.slice.call( document.documentElement.childNodes ); - getParentNode : function(n, f) { - return tinyMCE.getParentNode(n, f, this.getBody()); - }, +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; - getParentElement : function(n, na, f) { - return tinyMCE.getParentElement(n, na, f, this.getBody()); - }, + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } - getParentBlockElement : function(n) { - return tinyMCE.getParentBlockElement(n, this.getBody()); - }, + return ret; + }; +} - resizeToContent : function() { - var d = this.getDoc(), b = d.body, de = d.documentElement; +var sortOrder; - this.iframeElement.style.height = (tinyMCE.isRealIE) ? b.scrollHeight : de.offsetHeight + 'px'; - }, +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.selectNode(a); + aRange.collapse(true); + bRange.selectNode(b); + bRange.collapse(true); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} - addShortcut : function(m, k, d, cmd, ui, va) { - var n = typeof(k) == "number", ie = tinyMCE.isIE, c, sc, i, scl = this.shortcuts; +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("form"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; - if (!tinyMCE.getParam('custom_shortcuts')) - return false; + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); - m = m.toLowerCase(); - k = ie && !n ? k.toUpperCase() : k; - c = n ? null : k.charCodeAt(0); - d = d && d.indexOf('lang_') == 0 ? tinyMCE.getLang(d) : d; + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; - sc = { - alt : m.indexOf('alt') != -1, - ctrl : m.indexOf('ctrl') != -1, - shift : m.indexOf('shift') != -1, - charCode : c, - keyCode : n ? k : (ie ? c : null), - desc : d, - cmd : cmd, - ui : ui, - val : va + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; }; + } - for (i=0; i 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} } + + return oldSizzle(query, context, extra, seed); + }; - scl[scl.length] = sc; + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } +})(); - return true; - }, +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
"; - handleShortcut : function(e) { - var i, s, o; + // Opera can't find a second classname (in 9.6) + if ( div.getElementsByClassName("e").length === 0 ) + return; - // Normal key press, then ignore it - if (!e.altKey && !e.ctrlKey) - return false; + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; - s = this.shortcuts; + if ( div.getElementsByClassName("e").length === 1 ) + return; - for (i=0; i 0 ) { + match = elem; + break; + } + } - s = this.getSel(); + elem = elem[dir]; + } - // Weird, wheres that cursor selection? - return (!s || !s.rangeCount || s.rangeCount == 0); - }, + checkSet[i] = match; + } + } +} - isDirty : function() { - // Is content modified and not in a submit procedure - return tinyMCE.trim(this.startContent) != tinyMCE.trim(this.getBody().innerHTML) && !this.isNotDirty; - }, +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; - _mergeElements : function(scmd, pa, ch, override) { - var st, stc, className, n; +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; - if (scmd == "removeformat") { - pa.className = ""; - pa.style.cssText = ""; - ch.className = ""; - ch.style.cssText = ""; - return; - } +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; - st = tinyMCE.parseStyle(tinyMCE.getAttrib(pa, "style")); - stc = tinyMCE.parseStyle(tinyMCE.getAttrib(ch, "style")); - className = tinyMCE.getAttrib(pa, "class"); + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } - // Removed class adding due to bug #1478272 - className = tinyMCE.getAttrib(ch, "class"); + selector = Expr.relative[selector] ? selector + "*" : selector; - if (override) { - for (n in st) { - if (typeof(st[n]) == 'function') - continue; + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } - stc[n] = st[n]; + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +window.tinymce.dom.Sizzle = Sizzle; + +})(); +(function(tinymce) { + // Shorten names + var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event; + + tinymce.create('static tinymce.dom.Event', { + inits : [], + events : [], + + + add : function(o, n, f, s) { + var cb, t = this, el = t.events, r; + + // Handle array + if (o && o.hasOwnProperty && o instanceof Array) { + r = []; + + each(o, function(o) { + o = DOM.get(o); + r.push(t.add(o, n, f, s)); + }); + + return r; } - } else { - for (n in stc) { - if (typeof(stc[n]) == 'function') - continue; - st[n] = stc[n]; + o = DOM.get(o); + + if (!o) + return; + + // Setup event callback + cb = function(e) { + e = e || window.event; + + // Patch in target in IE it's W3C valid + if (e && !e.target && isIE) + e.target = e.srcElement; + + if (!s) + return f(e); + + return f.call(s, e); + }; + + if (n == 'unload') { + tinymce.unloads.unshift({func : cb}); + return cb; } - } - tinyMCE.setAttrib(pa, "style", tinyMCE.serializeStyle(st)); - tinyMCE.setAttrib(pa, "class", tinyMCE.trim(className)); - ch.className = ""; - ch.style.cssText = ""; - ch.removeAttribute("class"); - ch.removeAttribute("style"); - }, + if (n == 'init') { + if (t.domLoaded) + cb(); + else + t.inits.push(cb); - _fixRootBlocks : function() { - var rb, b, ne, be, nx, bm; + return cb; + } - rb = tinyMCE.getParam('forced_root_block'); - if (!rb) - return; + // Store away listener reference + el.push({ + obj : o, + name : n, + func : f, + cfunc : cb, + scope : s + }); - b = this.getBody(); - ne = b.firstChild; + t._add(o, n, cb); - while (ne) { - nx = ne.nextSibling; + return f; + }, - // If text node or inline element wrap it in a block element - if ((ne.nodeType == 3 && ne.nodeValue.replace(/\s+/g, '') != '') || (ne.nodeType == 1 && !tinyMCE.blockRegExp.test(ne.nodeName))) { - if (!bm) - bm = this.selection.getBookmark(); + remove : function(o, n, f) { + var t = this, a = t.events, s = false, r; - if (!be) { - be = this.getDoc().createElement(rb); - be.appendChild(ne.cloneNode(true)); - b.replaceChild(be, ne); - } else { - be.appendChild(ne.cloneNode(true)); - b.removeChild(ne); + // Handle array + if (o && o.hasOwnProperty && o instanceof Array) { + r = []; + + each(o, function(o) { + o = DOM.get(o); + r.push(t.remove(o, n, f)); + }); + + return r; + } + + o = DOM.get(o); + + each(a, function(e, i) { + if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) { + a.splice(i, 1); + t._remove(o, n, e.cfunc); + s = true; + return false; } - } else - be = null; + }); - ne = nx; - } + return s; + }, - if (bm) - this.selection.moveToBookmark(bm); - }, + clear : function(o) { + var t = this, a = t.events, i, e; - _fixTrailingNbsp : function() { - var s = this.selection, e = s.getFocusElement(), bm, v; + if (o) { + o = DOM.get(o); - if (e && tinyMCE.blockRegExp.test(e.nodeName) && e.firstChild) { - v = e.firstChild.nodeValue; + for (i = a.length - 1; i >= 0; i--) { + e = a[i]; - if (v && v.length > 1 && /(^\u00a0|\u00a0$)/.test(v)) { - e.firstChild.nodeValue = v.replace(/(^\u00a0|\u00a0$)/, ''); - s.selectNode(e.firstChild, true, false, false); // Select and collapse + if (e.obj === o) { + t._remove(e.obj, e.name, e.cfunc); + e.obj = e.cfunc = null; + a.splice(i, 1); + } + } } - } - }, + }, - _setUseCSS : function(b) { - var d = this.getDoc(); - try {d.execCommand("useCSS", false, !b);} catch (ex) {} - try {d.execCommand("styleWithCSS", false, b);} catch (ex) {} + cancel : function(e) { + if (!e) + return false; - if (!tinyMCE.getParam("table_inline_editing")) - try {d.execCommand('enableInlineTableEditing', false, "false");} catch (ex) {} + this.stop(e); + return this.prevent(e); + }, - if (!tinyMCE.getParam("object_resizing")) - try {d.execCommand('enableObjectResizing', false, "false");} catch (ex) {} - }, + stop : function(e) { + if (e.stopPropagation) + e.stopPropagation(); + else + e.cancelBubble = true; - execCommand : function(command, user_interface, value) { - var i, x, z, align, img, div, doc = this.getDoc(), win = this.getWin(), focusElm = this.getFocusElement(); + return false; + }, - // Is not a undo specific command - if (!new RegExp('mceStartTyping|mceEndTyping|mceBeginUndoLevel|mceEndUndoLevel|mceAddUndoLevel', 'gi').test(command)) - this.undoBookmark = null; + prevent : function(e) { + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; - // Mozilla issue - if (!tinyMCE.isIE && !this.useCSS) { - this._setUseCSS(false); - this.useCSS = true; - } + return false; + }, - //debug("command: " + command + ", user_interface: " + user_interface + ", value: " + value); - this.contentDocument = doc; // <-- Strange, unless this is applied Mozilla 1.3 breaks + _unload : function() { + var t = Event; - // Don't dispatch key commands - if (!/mceStartTyping|mceEndTyping/.test(command)) { - if (tinyMCE.execCommandCallback(this, 'execcommand_callback', 'execCommand', this.editorId, this.getBody(), command, user_interface, value)) - return; - } + each(t.events, function(e, i) { + t._remove(e.obj, e.name, e.cfunc); + e.obj = e.cfunc = null; + }); - // Fix align on images - if (focusElm && focusElm.nodeName == "IMG") { - align = focusElm.getAttribute('align'); - img = command == "JustifyCenter" ? focusElm.cloneNode(false) : focusElm; + t.events = []; + t = null; + }, - switch (command) { - case "JustifyLeft": - if (align == 'left') { - img.setAttribute('align', ''); // Needed for IE - img.removeAttribute('align'); - } else - img.setAttribute('align', 'left'); + _add : function(o, n, f) { + if (o.attachEvent) + o.attachEvent('on' + n, f); + else if (o.addEventListener) + o.addEventListener(n, f, false); + else + o['on' + n] = f; + }, - // Remove the div - div = focusElm.parentNode; - if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode) - div.parentNode.replaceChild(img, div); + _remove : function(o, n, f) { + if (o) { + try { + if (o.detachEvent) + o.detachEvent('on' + n, f); + else if (o.removeEventListener) + o.removeEventListener(n, f, false); + else + o['on' + n] = null; + } catch (ex) { + // Might fail with permission denined on IE so we just ignore that + } + } + }, - this.selection.selectNode(img); - this.repaint(); - tinyMCE.triggerNodeChange(); - return; + _pageInit : function() { + var e = Event; - case "JustifyCenter": - img.setAttribute('align', ''); // Needed for IE - img.removeAttribute('align'); + // Safari on Mac fires this twice + if (e.domLoaded) + return; - // Is centered - div = tinyMCE.getParentElement(focusElm, "div"); - if (div && div.style.textAlign == "center") { - // Remove div - if (div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode) - div.parentNode.replaceChild(img, div); - } else { - // Add div - div = this.getDoc().createElement("div"); - div.style.textAlign = 'center'; - div.appendChild(img); - focusElm.parentNode.replaceChild(div, focusElm); - } + e._remove(window, 'DOMContentLoaded', e._pageInit); + e.domLoaded = true; - this.selection.selectNode(img); - this.repaint(); - tinyMCE.triggerNodeChange(); - return; + each(e.inits, function(c) { + c(); + }); - case "JustifyRight": - if (align == 'right') { - img.setAttribute('align', ''); // Needed for IE - img.removeAttribute('align'); - } else - img.setAttribute('align', 'right'); + e.inits = []; + }, - // Remove the div - div = focusElm.parentNode; - if (div && div.nodeName == "DIV" && div.childNodes.length == 1 && div.parentNode) - div.parentNode.replaceChild(img, div); + _wait : function() { + var t; - this.selection.selectNode(img); - this.repaint(); - tinyMCE.triggerNodeChange(); - return; + // No need since the document is already loaded + if (window.tinyMCE_GZ && tinyMCE_GZ.loaded) { + Event.domLoaded = 1; + return; } + + if (isIE && document.location.protocol != 'https:') { + // Fake DOMContentLoaded on IE + document.write(''; + + bi = s.body_id || 'tinymce'; + if (bi.indexOf('=') != -1) { + bi = t.getParam('body_id', '', 'hash'); + bi = bi[t.id] || bi; } - sn.push(n); - } + bc = s.body_class || ''; + if (bc.indexOf('=') != -1) { + bc = t.getParam('body_class', '', 'hash'); + bc = bc[t.id] || ''; + } - return false; - } + t.iframeHTML += ''; - }; + // Domain relaxing enabled, then set document domain + if (tinymce.relaxedDomain) { + // We need to write the contents here in IE since multiple writes messes up refresh button and back button + if (isIE || (tinymce.isOpera && parseFloat(opera.version()) >= 9.5)) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()'; + else if (tinymce.isOpera) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()'; + } -/* file:jscripts/tiny_mce/classes/TinyMCE_DOMUtils.class.js */ + // Create iframe + n = DOM.add(o.iframeContainer, 'iframe', { + id : t.id + "_ifr", + src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7 + frameBorder : '0', + style : { + width : '100%', + height : h + } + }); -tinyMCE.add(TinyMCE_Engine, { - createTagHTML : function(tn, a, h) { - var o = '', f = tinyMCE.xmlEncode, n; + t.contentAreaContainer = o.iframeContainer; + DOM.get(o.editorContainer).style.display = t.orgDisplay; + DOM.get(t.id).style.display = 'none'; - o = '<' + tn; + if (!isIE || !tinymce.relaxedDomain) + t.setupIframe(); - if (a) { - for (n in a) { - if (typeof(a[n]) != 'function' && a[n] != null) - o += ' ' + f(n) + '="' + f('' + a[n]) + '"'; + e = n = o = null; // Cleanup + }, + + setupIframe : function() { + var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b; + + // Setup iframe body + if (!isIE || !tinymce.relaxedDomain) { + d.open(); + d.write(t.iframeHTML); + d.close(); } - } - o += !h ? ' />' : '>' + h + ''; + // Design mode needs to be added here Ctrl+A will fail otherwise + if (!isIE) { + try { + if (!s.readonly) + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } - return o; - }, + // IE needs to use contentEditable or it will display non secure items for HTTPS + if (isIE) { + // It will not steal focus if we hide it while setting contentEditable + b = t.getBody(); + DOM.hide(b); - createTag : function(d, tn, a, h) { - var o = d.createElement(tn), n; + if (!s.readonly) + b.contentEditable = true; - if (a) { - for (n in a) { - if (typeof(a[n]) != 'function' && a[n] != null) - tinyMCE.setAttrib(o, n, a[n]); + DOM.show(b); } - } - if (h) - o.innerHTML = h; + // Setup objects + t.dom = new tinymce.DOM.DOMUtils(t.getDoc(), { + keep_values : true, + url_converter : t.convertURL, + url_converter_scope : t, + hex_colors : s.force_hex_style_colors, + class_filter : s.class_filter, + update_styles : 1, + fix_ie_paragraphs : 1 + }); - return o; - }, + t.serializer = new tinymce.dom.Serializer({ + entity_encoding : s.entity_encoding, + entities : s.entities, + valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements, + extended_valid_elements : s.extended_valid_elements, + valid_child_elements : s.valid_child_elements, + invalid_elements : s.invalid_elements, + fix_table_elements : s.fix_table_elements, + fix_list_elements : s.fix_list_elements, + fix_content_duplication : s.fix_content_duplication, + convert_fonts_to_spans : s.convert_fonts_to_spans, + font_size_classes : s.font_size_classes, + font_size_style_values : s.font_size_style_values, + apply_source_formatting : s.apply_source_formatting, + remove_linebreaks : s.remove_linebreaks, + element_format : s.element_format, + dom : t.dom + }); - getElementByAttributeValue : function(n, e, a, v) { - return (n = this.getElementsByAttributeValue(n, e, a, v)).length == 0 ? null : n[0]; - }, + t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer); + t.forceBlocks = new tinymce.ForceBlocks(t, { + forced_root_block : s.forced_root_block + }); + t.editorCommands = new tinymce.EditorCommands(t); - getElementsByAttributeValue : function(n, e, a, v) { - var i, nl = n.getElementsByTagName(e), o = []; + // Pass through + t.serializer.onPreProcess.add(function(se, o) { + return t.onPreProcess.dispatch(t, o, se); + }); - for (i=0; i]*)>/gi, ''); - h = h.replace(/]*)>/gi, ''); - h = h.replace(/]*)>/gi, ''); - h = h.replace(/]*)>/gi, ''); - h = h.replace(/<\/strong>/gi, ''); - h = h.replace(/<\/em>/gi, ''); - } + if (s.auto_resize) + t.onNodeChange.add(t.resizeToContent, t); - if (tinyMCE.isRealIE) { - // Since MSIE handles invalid HTML better that valid XHTML we - // need to make some things invalid.
gets converted to
. - h = h.replace(/\s\/>/g, '>'); + if (s.custom_elements) { + function handleCustom(ed, o) { + each(explode(s.custom_elements), function(v) { + var n; - // Since MSIE auto generated emtpy P tags some times we must tell it to keep the real ones - h = h.replace(/]*)>\u00A0?<\/p>/gi, ' 

'); // Keep empty paragraphs - h = h.replace(/]*)>\s* \s*<\/p>/gi, ' 

'); // Keep empty paragraphs - h = h.replace(/]*)>\s+<\/p>/gi, ' 

'); // Keep empty paragraphs + if (v.indexOf('~') === 0) { + v = v.substring(1); + n = 'span'; + } else + n = 'div'; - // Remove first comment - e.innerHTML = tinyMCE.uniqueTag + h; - e.firstChild.removeNode(true); + o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' mce_name="$1"$2>'); + o.content = o.content.replace(new RegExp('', 'g'), ''); + }); + }; - // Remove weird auto generated empty paragraphs unless it's supposed to be there - nl = e.getElementsByTagName("p"); - for (i=nl.length-1; i>=0; i--) { - n = nl[i]; + t.onBeforeSetContent.add(handleCustom); + t.onPostProcess.add(function(ed, o) { + if (o.set) + handleCustom(ed, o) + }); + } - if (n.nodeName == 'P' && !n.hasChildNodes() && !n.mce_keep) - n.parentNode.removeChild(n); + if (s.handle_node_change_callback) { + t.onNodeChange.add(function(ed, cm, n) { + t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed()); + }); } - } else { - h = this.fixGeckoBaseHREFBug(1, e, h); - e.innerHTML = h; - this.fixGeckoBaseHREFBug(2, e, h); - } - }, - getOuterHTML : function(e) { - var d; + if (s.save_callback) { + t.onSaveContent.add(function(ed, o) { + var h = t.execCallback('save_callback', t.id, o.content, t.getBody()); - if (tinyMCE.isIE) - return e.outerHTML; + if (h) + o.content = h; + }); + } - d = e.ownerDocument.createElement("body"); - d.appendChild(e.cloneNode(true)); + if (s.onchange_callback) { + t.onChange.add(function(ed, l) { + t.execCallback('onchange_callback', t, l); + }); + } - return d.innerHTML; - }, + if (s.convert_newlines_to_brs) { + t.onBeforeSetContent.add(function(ed, o) { + if (o.initial) + o.content = o.content.replace(/\r?\n/g, '
'); + }); + } - setOuterHTML : function(e, h, d) { - var d = typeof(d) == "undefined" ? e.ownerDocument : d, i, nl, t; + if (s.fix_nesting && isIE) { + t.onBeforeSetContent.add(function(ed, o) { + o.content = t._fixNesting(o.content); + }); + } - if (tinyMCE.isIE && e.nodeType == 1) - e.outerHTML = h; - else { - t = d.createElement("body"); - t.innerHTML = h; + if (s.preformatted) { + t.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/^\s*/, ''); + o.content = o.content.replace(/<\/pre>\s*$/, ''); - for (i=0, nl=t.childNodes; i'; + }); + } - e.parentNode.removeChild(e); - } - }, + if (s.verify_css_classes) { + t.serializer.attribValueFilter = function(n, v) { + var s, cl; - _getElementById : function(id, d) { - var e, i, j, f; + if (n == 'class') { + // Build regexp for classes + if (!t.classesRE) { + cl = t.dom.getClasses(); - if (typeof(d) == "undefined") - d = document; + if (cl.length > 0) { + s = ''; - e = d.getElementById(id); - if (!e) { - f = d.forms; + each (cl, function(o) { + s += (s ? '|' : '') + o['class']; + }); - for (i=0; i]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
[\r\n]*)$/, ''); + }); + } - // Not a element - if (!elm || elm.nodeType != 1) - return dv; + // Fix gecko link bug, when a link is placed at the end of block elements there is + // no way to move the caret behind the link. This fix adds a bogus br element after the link + if (isGecko) { + function fixLinks(ed, o) { + each(ed.dom.select('a'), function(n) { + var pn = n.parentNode; - try { - v = elm.getAttribute(name, 0); - } catch (ex) { - // IE 7 may cast exception on invalid attributes - v = elm.getAttribute(name, 2); - } + if (ed.dom.isBlock(pn) && pn.lastChild === n) + ed.dom.add(pn, 'br', {'mce_bogus' : 1}); + }); + }; - // Try className for class attrib - if (name == "class" && !v) - v = elm.className; + t.onExecCommand.add(function(ed, cmd) { + if (cmd === 'CreateLink') + fixLinks(ed); + }); - // Workaround for a issue with Firefox 1.5rc2+ - if (tinyMCE.isGecko) { - if (name == "src" && elm.src != null && elm.src !== '') - v = elm.src; + t.onSetContent.add(t.selection.onSetContent.add(fixLinks)); + } - // Workaround for a issue with Firefox 1.5rc2+ - if (name == "href" && elm.href != null && elm.href !== '') - v = elm.href; - } else if (tinyMCE.isIE) { - switch (name) { - case "http-equiv": - v = elm.httpEquiv; - break; + if (isGecko && !s.readonly) { + try { + // Design mode must be set here once again to fix a bug where + // Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again + d.designMode = 'Off'; + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } - case "width": - case "height": - v = elm.getAttribute(name, 2); - break; + // A small timeout was needed since firefox will remove. Bug: #1838304 + setTimeout(function () { + if (t.removed) + return; + + t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')}); + t.startContent = t.getContent({format : 'raw'}); + t.undoManager.add({initial : true}); + t.initialized = true; + + t.onInit.dispatch(t); + t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc()); + t.execCallback('init_instance_callback', t); + t.focus(true); + t.nodeChanged({initial : 1}); + + // Load specified content CSS last + if (s.content_css) { + tinymce.each(explode(s.content_css), function(u) { + t.dom.loadCSS(t.documentBaseURI.toAbsolute(u)); + }); + } + + // Handle auto focus + if (s.auto_focus) { + setTimeout(function () { + var ed = EditorManager.get(s.auto_focus); + + ed.selection.select(ed.getBody(), 1); + ed.selection.collapse(1); + ed.getWin().focus(); + }, 100); + } + }, 1); + + e = null; + }, + + + focus : function(sf) { + var oed, t = this, ce = t.settings.content_editable; + + if (!sf) { + // Is not content editable or the selection is outside the area in IE + // the IE statement is needed to avoid bluring if element selections inside layers since + // the layer is like it's own document in IE + if (!ce && (!isIE || t.selection.getNode().ownerDocument != t.getDoc())) + t.getWin().focus(); + } - } - if (name == "style" && !tinyMCE.isOpera) - v = elm.style.cssText; + if (EditorManager.activeEditor != t) { + if ((oed = EditorManager.activeEditor) != null) + oed.onDeactivate.dispatch(oed, t); - return (v && v !== '') ? v : dv; - }, + t.onActivate.dispatch(t, oed); + } - setAttrib : function(el, name, va, fix) { - if (typeof(va) == "number" && va != null) - va = "" + va; + EditorManager._setActive(t); + }, - if (fix) { - if (va == null) - va = ""; + execCallback : function(n) { + var t = this, f = t.settings[n], s; - va = va.replace(/[^0-9%]/g, ''); - } + if (!f) + return; - if (name == "style") - el.style.cssText = va; + // Look through lookup + if (t.callbackLookup && (s = t.callbackLookup[n])) { + f = s.func; + s = s.scope; + } - if (name == "class") - el.className = va; + if (is(f, 'string')) { + s = f.replace(/\.\w+$/, ''); + s = s ? tinymce.resolve(s) : 0; + f = tinymce.resolve(f); + t.callbackLookup = t.callbackLookup || {}; + t.callbackLookup[n] = {func : f, scope : s}; + } - if (va != null && va !== '' && va != -1) - el.setAttribute(name, va); - else - el.removeAttribute(name); - }, + return f.apply(s || t, Array.prototype.slice.call(arguments, 1)); + }, - setStyleAttrib : function(e, n, v) { - e.style[n] = v; + translate : function(s) { + var c = this.settings.language || 'en', i18n = EditorManager.i18n; - // Style attrib deleted in IE - if (tinyMCE.isIE && v == null || v == '') { - v = tinyMCE.serializeStyle(tinyMCE.parseStyle(e.style.cssText)); - e.style.cssText = v; - e.setAttribute("style", v); - } - }, + if (!s) + return ''; - switchClass : function(ei, c) { - var e; + return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) { + return i18n[c + '.' + b] || '{#' + b + '}'; + }); + }, - if (tinyMCE.switchClassCache[ei]) - e = tinyMCE.switchClassCache[ei]; - else - e = tinyMCE.switchClassCache[ei] = document.getElementById(ei); + getLang : function(n, dv) { + return EditorManager.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}'); + }, - if (e) { - // Keep tile mode - if (tinyMCE.settings.button_tile_map && e.className && e.className.indexOf('mceTiledButton') == 0) - c = 'mceTiledButton ' + c; + getParam : function(n, dv, ty) { + var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o; - e.className = c; - } - }, + if (ty === 'hash') { + o = {}; - getAbsPosition : function(n, cn) { - var l = 0, t = 0; + if (is(v, 'string')) { + each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) { + v = v.split('='); - while (n && n != cn) { - l += n.offsetLeft; - t += n.offsetTop; - n = n.offsetParent; - } + if (v.length > 1) + o[tr(v[0])] = tr(v[1]); + else + o[tr(v[0])] = tr(v); + }); + } else + o = v; - return {absLeft : l, absTop : t}; - }, + return o; + } - prevNode : function(e, n) { - var a = n.split(','), i; + return v; + }, - while ((e = e.previousSibling) != null) { - for (i=0; i-1; i--) { - if (ar[i].specified && ar[i].nodeValue) - ne.setAttribute(ar[i].nodeName.toLowerCase(), ar[i].nodeValue); + // Theme commands + if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; } - ar = e.childNodes; - for (i=0; i