From 58fb6502e3550e59afa8799d36dfce61a18f8b1b Mon Sep 17 00:00:00 2001 From: alecpl <alec@alec.pl> Date: Tue, 15 Dec 2009 03:48:45 -0500 Subject: [PATCH] - Updated TinyMCE to 3.2.7 --- program/js/tiny_mce/tiny_mce_src.js | 920 +++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 627 insertions(+), 293 deletions(-) diff --git a/program/js/tiny_mce/tiny_mce_src.js b/program/js/tiny_mce/tiny_mce_src.js index 4838499..6f86af4 100644 --- a/program/js/tiny_mce/tiny_mce_src.js +++ b/program/js/tiny_mce/tiny_mce_src.js @@ -1,18 +1,23 @@ var tinymce = { majorVersion : '3', - minorVersion : '2.3', - releaseDate : '2009-04-23', + minorVersion : '2.7', + releaseDate : '2009-09-22', _init : function() { var t = this, d = document, w = window, na = navigator, ua = na.userAgent, i, nl, n, base, p, v; - // Browser checks t.isOpera = w.opera && opera.buildNumber; + t.isWebKit = /WebKit/.test(ua); + t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName); + t.isIE6 = t.isIE && /MSIE [56]/.test(ua); + t.isGecko = !t.isWebKit && /Gecko/.test(ua); + t.isMac = ua.indexOf('Mac') != -1; + t.isAir = /adobeair/i.test(ua); // TinyMCE .NET webcontrol might be setting the values for TinyMCE @@ -39,7 +44,7 @@ } function getBase(n) { - if (n.src && /tiny_mce(|_dev|_src|_gzip|_jquery|_prototype).js/.test(n.src)) { + if (n.src && /tiny_mce(|_gzip|_jquery|_prototype)(_dev|_src)?.js/.test(n.src)) { if (/_(src|dev)\.js/g.test(n.src)) t.suffix = '_src'; @@ -49,7 +54,9 @@ t.baseURL = n.src.substring(0, n.src.lastIndexOf('/')); // If path to script is relative and a base href was found add that one infront - if (base && t.baseURL.indexOf('://') == -1) + // the src property will always be an absolute one on non IE browsers and IE 8 + // so this logic will basically only be executed on older IE versions + if (base && t.baseURL.indexOf('://') == -1 && t.baseURL.indexOf('/') !== 0) t.baseURL = base + t.baseURL; return t.baseURL; @@ -90,7 +97,6 @@ return n == t; }, - each : function(o, cb, s) { var n, l; @@ -117,6 +123,7 @@ return 1; }, + map : function(a, f) { var o = []; @@ -167,10 +174,10 @@ return o; }, + trim : function(s) { return (s ? '' + s : '').replace(/^\s*|\s*$/g, ''); }, - create : function(s, p) { var t = this, sp, ns, cn, scn, c, de = 0; @@ -296,7 +303,7 @@ o = o || window; n = n.split('.'); - for (i=0, l = n.length; i<l; i++) { + for (i = 0, l = n.length; i < l; i++) { o = o[n[i]]; if (!o) @@ -483,11 +490,14 @@ URI : function(u, s) { var t = this, o, a, b; + // Trim whitespace + u = tinymce.trim(u); + // Default settings s = t.settings = s || {}; // Strange app protocol or local anchor - if (/^(mailto|tel|news|javascript|about):/i.test(u) || /^\s*#/.test(u)) { + if (/^(mailto|tel|news|javascript|about|data):/i.test(u) || /^\s*#/.test(u)) { t.source = u; return; } @@ -496,8 +506,8 @@ if (u.indexOf('/') === 0 && u.indexOf('//') !== 0) u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u; - // Relative path - if (u.indexOf(':/') === -1 && u.indexOf('//') !== 0) + // Relative path http:// or protocol relative //path + if (!/^\w*:?\/\//.test(u)) u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u); // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri) @@ -575,7 +585,7 @@ toAbsolute : function(u, nh) { var u = new tinymce.util.URI(u, {base_uri : this}); - return u.getURI(this.host == u.host ? nh : 0); + return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0); }, toRelPath : function(base, path) { @@ -621,7 +631,7 @@ }, toAbsPath : function(base, path) { - var i, nb = 0, o = [], tr; + var i, nb = 0, o = [], tr, outPath; // Split paths tr = /\/$/.test(path) ? '/' : ''; @@ -661,9 +671,19 @@ // If /a/b/c or / if (i <= 0) - return '/' + o.reverse().join('/') + tr; + outPath = o.reverse().join('/'); + else + outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/'); - return '/' + base.slice(0, i).join('/') + '/' + o.reverse().join('/') + tr; + // Add front / if it's needed + if (outPath.indexOf('/') !== 0) + outPath = '/' + outPath; + + // Add traling / if it's needed + if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) + outPath += tr; + + return outPath; }, getURI : function(nh) { @@ -701,8 +721,7 @@ return t.source; } - - }); + }); })(); (function() { var each = tinymce.each; @@ -772,8 +791,7 @@ this.set(n, '', d, p, d); } - - }); + }); })(); tinymce.create('static tinymce.util.JSON', { serialize : function(o) { @@ -860,6 +878,8 @@ if (o.content_type) x.setRequestHeader('Content-Type', o.content_type); + x.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); + x.send(o.data); function ready() { @@ -881,8 +901,7 @@ // Wait for response, onReadyStateChange can not be used since it leaks memory in IE t = w.setTimeout(ready, 10); } - - } + } }); (function() { var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR; @@ -935,8 +954,7 @@ return new tinymce.util.JSONRequest().send(o); } } - - }); + }); }());(function(tinymce) { // Shorten names var each = tinymce.each, is = tinymce.is; @@ -973,7 +991,7 @@ t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat"; t.stdMode = d.documentMode === 8; - this.settings = s = tinymce.extend({ + t.settings = s = tinymce.extend({ keep_values : false, hex_colors : 1, process_html : 1 @@ -1049,10 +1067,6 @@ }; }, - is : function(n, patt) { - return tinymce.dom.Sizzle.matches(patt, n.nodeType ? [n] : n).length > 0; - }, - getParent : function(n, f, r) { return this.getParents(n, f, r, false); }, @@ -1111,11 +1125,23 @@ return e; }, + getNext : function(node, selector) { + return this._findSib(node, selector, 'nextSibling'); + }, + + getPrev : function(node, selector) { + return this._findSib(node, selector, 'previousSibling'); + }, + select : function(pa, s) { var t = this; return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []); + }, + + is : function(n, patt) { + return tinymce.dom.Sizzle.matches(patt, n.nodeType ? [n] : n).length > 0; }, @@ -1193,7 +1219,6 @@ return p.removeChild(n); }); }, - setStyle : function(n, na, v) { var t = this; @@ -1364,7 +1389,6 @@ }); }, - getAttrib : function(e, n, dv) { var v, t = this; @@ -1391,6 +1415,18 @@ if (!v) v = e.getAttribute(n, 2); + + // Check boolean attribs + if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) { + if (e[t.props[n]] === true && v === '') + return n; + + return v ? n : ''; + } + + // Inner input elements will override attributes on form elements + if (e.nodeName === "FORM" && e.getAttributeNode(n)) + return e.getAttributeNode(n).nodeValue; if (n === 'style') { v = v || e.style.cssText; @@ -1467,7 +1503,7 @@ default: // IE has odd anonymous function for event attributes if (n.indexOf('on') === 0 && v) - v = ('' + v).replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/, '$1'); + v = ('' + v).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1'); } } @@ -1632,20 +1668,35 @@ }, loadCSS : function(u) { - var t = this, d = t.doc; + var t = this, d = t.doc, head; if (!u) u = ''; + head = t.select('head')[0]; + each(u.split(','), function(u) { + var link; + if (t.files[u]) return; t.files[u] = true; - t.add(t.select('head')[0], 'link', {rel : 'stylesheet', href : tinymce._addVer(u)}); + link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)}); + + // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug + // This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading + // It's ugly but it seems to work fine. + if (isIE && d.documentMode) { + link.onload = function() { + d.recalc(); + link.onload = null; + }; + } + + head.appendChild(link); }); }, - addClass : function(e, c) { return this.run(e, function(e) { @@ -1704,7 +1755,6 @@ return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none'; }, - uniqueId : function(p) { return (!p ? 'mce_' : p) + (this.counter++); @@ -1775,7 +1825,7 @@ if (x) { // So if we replace the p elements with divs and mark them and then replace them back to paragraphs // after we use innerHTML we can fix the DOM tree - h = h.replace(/<p ([^>]+)>|<p>/g, '<div $1 mce_tmp="1">'); + h = h.replace(/<p ([^>]+)>|<p>/ig, '<div $1 mce_tmp="1">'); h = h.replace(/<\/p>/g, '</div>'); // Set the new HTML with DIVs @@ -1826,7 +1876,7 @@ }, processHTML : function(h) { - var t = this, s = t.settings; + var t = this, s = t.settings, codeBlocks = []; if (!s.process_html) return h; @@ -1846,7 +1896,7 @@ // Store away src and href in mce_src and mce_href since browsers mess them up if (s.keep_values) { // Wrap scripts and styles in comments for serialization purposes - if (/<script|style/.test(h)) { + if (/<script|noscript|style/i.test(h)) { function trim(s) { // Remove prefix and suffix code for element s = s.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n'); @@ -1857,31 +1907,65 @@ return s; }; - // Preserve script elements - h = h.replace(/<script([^>]+|)>([\s\S]*?)<\/script>/g, function(v, a, b) { - // Remove prefix and suffix code for script element - b = trim(b); - + // Wrap the script contents in CDATA and keep them from executing + h = h.replace(/<script([^>]+|)>([\s\S]*?)<\/script>/gi, function(v, attribs, text) { // Force type attribute - if (!a) - a = ' type="text/javascript"'; + if (!attribs) + attribs = ' type="text/javascript"'; - // Wrap contents in a comment - if (b) - b = '<!--\n' + b + '\n// -->'; + // Convert the src attribute of the scripts + attribs = attribs.replace(/src=\"([^\"]+)\"?/i, function(a, url) { + if (s.url_converter) + url = t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(url), 'src', 'script')); - // Output fake element - return '<mce:script' + a + '>' + b + '</mce:script>'; + return 'mce_src="' + url + '"'; + }); + + // Wrap text contents + if (tinymce.trim(text)) { + codeBlocks.push(trim(text)); + text = '<!--\nMCE_SCRIPT:' + (codeBlocks.length - 1) + '\n// -->'; + } + + return '<mce:script' + attribs + '>' + text + '</mce:script>'; }); - // Preserve style elements - h = h.replace(/<style([^>]+|)>([\s\S]*?)<\/style>/g, function(v, a, b) { - b = trim(b); - return '<mce:style' + a + '><!--\n' + b + '\n--></mce:style><style' + a + ' mce_bogus="1">' + b + '</style>'; + // Wrap style elements + h = h.replace(/<style([^>]+|)>([\s\S]*?)<\/style>/gi, function(v, attribs, text) { + // Wrap text contents + if (text) { + codeBlocks.push(trim(text)); + text = '<!--\nMCE_SCRIPT:' + (codeBlocks.length - 1) + '\n-->'; + } + + return '<mce:style' + attribs + '>' + text + '</mce:style><style ' + attribs + ' mce_bogus="1">' + text + '</style>'; + }); + + // Wrap noscript elements + h = h.replace(/<noscript([^>]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) { + return '<mce:noscript' + attribs + '><!--' + t.encode(text).replace(/--/g, '--') + '--></mce:noscript>'; }); } h = h.replace(/<!\[CDATA\[([\s\S]+)\]\]>/g, '<!--[CDATA[$1]]-->'); + + // Remove false bool attributes and force attributes into xhtml style attr="attr" + h = h.replace(/<([\w:]+) [^>]*(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)[^>]*>/gi, function(val) { + function handle(val, name, value) { + // Remove false/0 attribs + if (value === 'false' || value === '0') + return ''; + + return ' ' + name + '="' + name + '"'; + }; + + val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=[\"]([^\"]+)[\"]/gi, handle); // W3C + val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=[\']([^\']+)[\']/gi, handle); // W3C + val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)=([^\s\"\'>]+)/gi, handle); // IE + val = val.replace(/ (checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)([\s>])/gi, ' $1="$1"$2'); // Force attr="attr" + + return val; + }); // Process all tags with src, href or style h = h.replace(/<([\w:]+) [^>]*(src|href|style|shape|coords)[^>]*>/gi, function(a, n) { @@ -1897,17 +1981,8 @@ if (t._isRes(c)) return m; - if (s.hex_colors) { - u = u.replace(/rgb\([^\)]+\)/g, function(v) { - return t.toHex(v); - }); - } - - if (s.url_converter) { - u = u.replace(/url\([\'\"]?([^\)\'\"]+)\)/g, function(x, c) { - return 'url(' + t.encode(s.url_converter.call(s.url_converter_scope || t, t.decode(c), b, n)) + ')'; - }); - } + // Parse and serialize the style to convert for example uppercase styles like "BORDER: 1px" + u = t.encode(t.serializeStyle(t.parseStyle(u))); } 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)); @@ -1920,6 +1995,11 @@ a = a.replace(/ (src|href|style|coords|shape)=[\']([^\']+)[\']/gi, handle); // W3C return a.replace(/ (src|href|style|coords|shape)=([^\s\"\'>]+)/gi, handle); // IE + }); + + // Restore script blocks + h = h.replace(/MCE_SCRIPT:([0-9]+)/g, function(val, idx) { + return codeBlocks[idx]; }); } @@ -1946,25 +2026,41 @@ setOuterHTML : function(e, h, d) { var t = this; - return this.run(e, function(e) { + function setHTML(e, h, d) { var n, tp; + + tp = d.createElement("body"); + tp.innerHTML = h; + n = tp.lastChild; + while (n) { + t.insertAfter(n.cloneNode(true), e); + n = n.previousSibling; + } + + t.remove(e); + }; + + return this.run(e, function(e) { e = t.get(e); - d = d || e.ownerDocument || t.doc; - if (isIE && e.nodeType == 1) - e.outerHTML = h; - else { - tp = d.createElement("body"); - tp.innerHTML = h; + // Only set HTML on elements + if (e.nodeType == 1) { + d = d || e.ownerDocument || t.doc; - n = tp.lastChild; - while (n) { - t.insertAfter(n.cloneNode(true), e); - n = n.previousSibling; - } - - t.remove(e); + if (isIE) { + try { + // Try outerHTML for IE it sometimes produces an unknown runtime error + if (isIE && e.nodeType == 1) + e.outerHTML = h; + else + setHTML(e, h, d); + } catch (ex) { + // Fix for unknown runtime error + setHTML(e, h, d); + } + } else + setHTML(e, h, d); } }); }, @@ -2012,7 +2108,6 @@ }) : s; }, - insertAfter : function(n, r) { var t = this; @@ -2033,16 +2128,14 @@ }); }, - isBlock : function(n) { if (n.nodeType && n.nodeType !== 1) return false; n = n.nodeName || n; - return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TR|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n); + return /^(H[1-6]|HR|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TH|TBODY|TR|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP)$/.test(n); }, - replace : function(n, o, k) { var t = this; @@ -2068,7 +2161,6 @@ return o.parentNode.replaceChild(n, o); }); }, - findCommonAncestor : function(a, b) { var ps = a, pe; @@ -2213,9 +2305,13 @@ if (n.nodeName == 'OBJECT') return n.attributes; + // IE doesn't keep the selected attribute if you clone option elements + if (n.nodeName === 'OPTION' && this.getAttrib(n, 'selected')) + o.push({specified : 1, nodeName : 'selected'}); + // It's crazy that this is faster in IE but it's because it returns all attributes all the time - n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi, function(a, b) { - o.push({specified : 1, nodeName : b}); + n.cloneNode(false).outerHTML.replace(/<\/?[\w:]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=\w+|>/gi, '').replace(/[\w:]+/gi, function(a) { + o.push({specified : 1, nodeName : a}); }); return o; @@ -2227,7 +2323,10 @@ destroy : function(s) { var t = this; - t.win = t.doc = t.root = null; + if (t.events) + t.events.destroy(); + + t.win = t.doc = t.root = t.events = null; // Manual destroy then remove unload handler if (!s) @@ -2266,16 +2365,29 @@ return n.replace(/[ \t\r\n]+| | /g, '') == ''; }; + // Added until Gecko can create real HTML documents using implementation.createHTMLDocument + // this is to future proof it if Gecko decides to implement the error checking for range methods. + function nodeIndex(n) { + var i = 0; + + while (n.previousSibling) { + i++; + n = n.previousSibling; + } + + return i; + }; + if (pe && e) { // Get before chunk - r.setStartBefore(pe); - r.setEndBefore(e); + r.setStart(pe.parentNode, nodeIndex(pe)); + r.setEnd(e.parentNode, nodeIndex(e)); bef = r.extractContents(); // Get after chunk r = t.createRng(); - r.setStartAfter(e); - r.setEndAfter(pe); + r.setStart(e.parentNode, nodeIndex(e) + 1); + r.setEnd(pe.parentNode, nodeIndex(pe) + 1); aft = r.extractContents(); // Insert chunks and remove parent @@ -2304,6 +2416,45 @@ } }, + bind : function(target, name, func, scope) { + var t = this; + + if (!t.events) + t.events = new tinymce.dom.EventUtils(); + + return t.events.add(target, name, func, scope || this); + }, + + unbind : function(target, name, func) { + var t = this; + + if (!t.events) + t.events = new tinymce.dom.EventUtils(); + + return t.events.remove(target, name, func); + }, + + + _findSib : function(node, selector, name) { + var t = this, f = selector; + + if (node) { + // If expression make a function of it using is + if (is(f, 'string')) { + f = function(node) { + return t.is(node, selector); + }; + } + + // Loop all siblings + for (node = node[name]; node; node = node[name]) { + if (f(node)) + return node; + } + } + + return null; + }, _isRes : function(c) { // Is live resizble element @@ -2339,10 +2490,8 @@ return s; } */ + }); - }); - - // Setup page DOM tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0}); })(tinymce); (function(ns) { @@ -3251,6 +3400,7 @@ if (sc == ec && sc.nodeType == 3) { startPos = getCharPos(sc, so); + ieRng = body.createTextRange(); ieRng.move('character', startPos); ieRng.moveEnd('character', eo - so); ieRng.select(); @@ -4284,13 +4434,24 @@ // Shorten names var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event; - tinymce.create('static tinymce.dom.Event', { - inits : [], - events : [], - + tinymce.create('tinymce.dom.EventUtils', { + EventUtils : function() { + this.inits = []; + this.events = []; + }, add : function(o, n, f, s) { var cb, t = this, el = t.events, r; + + if (n instanceof Array) { + r = []; + + each(n, function(n) { + r.push(t.add(o, n, f, s)); + }); + + return r; + } // Handle array if (o && o.hasOwnProperty && o instanceof Array) { @@ -4311,11 +4472,20 @@ // Setup event callback cb = function(e) { + // Is all events disabled + if (t.disabled) + return; + e = e || window.event; - // Patch in target in IE it's W3C valid - if (e && !e.target && isIE) - e.target = e.srcElement; + // Patch in target, preventDefault and stopPropagation in IE it's W3C valid + if (e && isIE) { + if (!e.target) + e.target = e.srcElement; + + // Patch in preventDefault, stopPropagation methods for W3C compatibility + tinymce.extend(e, t._stoppers); + } if (!s) return f(e); @@ -4398,12 +4568,12 @@ } }, - cancel : function(e) { if (!e) return false; this.stop(e); + return this.prevent(e); }, @@ -4425,8 +4595,8 @@ return false; }, - _unload : function() { - var t = Event; + destroy : function() { + var t = this; each(t.events, function(e, i) { t._remove(e.obj, e.name, e.cfunc); @@ -4461,70 +4631,87 @@ } }, - _pageInit : function() { - var e = Event; + _pageInit : function(win) { + var t = this; // Keep it from running more than once - if (e.domLoaded) + if (t.domLoaded) return; - e._remove(window, 'DOMContentLoaded', e._pageInit); - e.domLoaded = true; + t.domLoaded = true; - each(e.inits, function(c) { + each(t.inits, function(c) { c(); }); - e.inits = []; + t.inits = []; }, - _wait : function() { + _wait : function(win) { + var t = this, doc = win.document; + // No need since the document is already loaded - if (window.tinyMCE_GZ && tinyMCE_GZ.loaded) { - Event.domLoaded = 1; + if (win.tinyMCE_GZ && tinyMCE_GZ.loaded) { + t.domLoaded = 1; return; } // Use IE method - if (document.attachEvent) { - document.attachEvent("onreadystatechange", function() { - if (document.readyState === "complete") { - document.detachEvent("onreadystatechange", arguments.callee); - Event._pageInit(); + if (doc.attachEvent) { + doc.attachEvent("onreadystatechange", function() { + if (doc.readyState === "complete") { + doc.detachEvent("onreadystatechange", arguments.callee); + t._pageInit(win); } }); - if (document.documentElement.doScroll && window == window.top) { + if (doc.documentElement.doScroll && win == win.top) { (function() { - if (Event.domLoaded) + if (t.domLoaded) return; try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); + doc.documentElement.doScroll("left"); } catch (ex) { setTimeout(arguments.callee, 0); return; } - Event._pageInit(); + t._pageInit(win); })(); } - } else if (document.addEventListener) - Event._add(window, 'DOMContentLoaded', Event._pageInit, Event); + } else if (doc.addEventListener) { + t._add(win, 'DOMContentLoaded', function() { + t._pageInit(win); + }); + } - Event._add(window, 'load', Event._pageInit, Event); + t._add(win, 'load', function() { + t._pageInit(win); + }); + }, + + _stoppers : { + preventDefault : function() { + this.returnValue = false; + }, + + stopPropagation : function() { + this.cancelBubble = true; + } } + }); - }); - - // Shorten name - Event = tinymce.dom.Event; + Event = tinymce.dom.Event = new tinymce.dom.EventUtils(); // Dispatch DOM content loaded event for IE and Safari - Event._wait(); - tinymce.addUnload(Event._unload); + Event._wait(window); + + tinymce.addUnload(function() { + Event.destroy(); + }); })(tinymce); (function(tinymce) { var each = tinymce.each; @@ -4650,8 +4837,7 @@ dom.setStyle(b, 'zIndex', parseInt(t.getStyle('zIndex', 1) || 0) - 1); } } - - }); + }); })(tinymce); (function(tinymce) { function trimNl(s) { @@ -4829,7 +5015,7 @@ sy = vp.y; // Simple bookmark fast but not as persistent - if (si == 'simple') + if (si) return {rng : r, scrollX : sx, scrollY : sy}; // Handle IE @@ -4991,6 +5177,8 @@ // Handle explorer if (isIE) { + t.tridentSel.destroy(); + // Handle simple if (r = b.rng) { try { @@ -5289,8 +5477,7 @@ if (!s) tinymce.removeUnload(t.destroy); } - - }); + }); })(tinymce); (function(tinymce) { tinymce.create('tinymce.dom.XMLWriter', { @@ -5358,7 +5545,7 @@ }, writeCDATA : function(v) { - this.node.appendChild(this.doc.createCDATA(v)); + this.node.appendChild(this.doc.createCDATASection(v)); }, writeComment : function(v) { @@ -5381,8 +5568,7 @@ return h; } - - }); + }); })(tinymce); (function(tinymce) { tinymce.create('tinymce.dom.StringWriter', { @@ -5395,7 +5581,7 @@ StringWriter : function(s) { this.settings = tinymce.extend({ indent_char : ' ', - indentation : 1 + indentation : 0 }, s); this.reset(); @@ -5508,8 +5694,7 @@ return true; } - - }); + }); })(tinymce); (function(tinymce) { // Shorten names @@ -5540,11 +5725,10 @@ valid_nodes : 0, node_filter : 0, attr_filter : 0, - invalid_attrs : /^(mce_|_moz_)/, + invalid_attrs : /^(mce_|_moz_|sizset|sizcache)/, closed : /^(br|hr|input|meta|img|link|param|area)$/, entity_encoding : 'named', entities : '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro', - bool_attrs : /(checked|disabled|readonly|selected|nowrap)/, valid_elements : '*[*]', extended_valid_elements : 0, valid_child_elements : 0, @@ -5628,9 +5812,21 @@ if (s.fix_table_elements) { t.onPreProcess.add(function(se, o) { - each(t.dom.select('p table', o.node), function(n) { - t.dom.split(t.dom.getParent(n, 'p'), n); - }); + // Since Opera will crash if you attach the node to a dynamic document we need to brrowser sniff a specific build + // so Opera users with an older version will have to live with less compaible output not much we can do here + if (!tinymce.isOpera || opera.buildNumber() >= 1767) { + each(t.dom.select('p table', o.node).reverse(), function(n) { + var parent = t.dom.getParent(n.parentNode, 'table,p'); + + if (parent.nodeName != 'TABLE') { + try { + t.dom.split(parent, n); + } catch (ex) { + // IE can sometimes fire an unknown runtime error so we just ignore it + } + } + }); + } }); } }, @@ -5946,13 +6142,58 @@ }, serialize : function(n, o) { - var h, t = this; + var h, t = this, doc, oldDoc, impl, selected; t._setup(); o = o || {}; o.format = o.format || 'html'; t.processObj = o; + + // IE looses the selected attribute on option elements so we need to store it + // See: http://support.microsoft.com/kb/829907 + if (isIE) { + selected = []; + each(n.getElementsByTagName('option'), function(n) { + var v = t.dom.getAttrib(n, 'selected'); + + selected.push(v ? v : null); + }); + } + n = n.cloneNode(true); + + // IE looses the selected attribute on option elements so we need to restore it + if (isIE) { + each(n.getElementsByTagName('option'), function(n, i) { + t.dom.setAttrib(n, 'selected', selected[i]); + }); + } + + // Nodes needs to be attached to something in WebKit/Opera + // Older builds of Opera crashes if you attach the node to an document created dynamically + // and since we can't feature detect a crash we need to sniff the acutal build number + // This fix will make DOM ranges and make Sizzle happy! + impl = n.ownerDocument.implementation; + if (impl.createHTMLDocument && (tinymce.isOpera && opera.buildNumber() >= 1767)) { + // Create an empty HTML document + doc = impl.createHTMLDocument(""); + + // Add the element or it's children if it's a body element to the new document + each(n.nodeName == 'BODY' ? n.childNodes : [n], function(node) { + doc.body.appendChild(doc.importNode(node, true)); + }); + + // Grab first child or body element for serialization + if (n.nodeName != 'BODY') + n = doc.body.firstChild; + else + n = doc.body; + + // set the new document in DOMUtils so createElement etc works + oldDoc = t.dom.doc; + t.dom.doc = doc; + } + t.key = '' + (parseInt(t.key) + 1); // Pre process @@ -5967,6 +6208,10 @@ // Post process o.content = t.writer.getContent(); + + // Restore the old document if it was changed + if (oldDoc) + t.dom.doc = oldDoc; if (!o.no_events) t.onPostProcess.dispatch(t, o); @@ -5988,6 +6233,7 @@ content : h, patterns : [ {pattern : /(<script[^>]*>)(.*?)(<\/script>)/g}, + {pattern : /(<noscript[^>]*>)(.*?)(<\/noscript>)/g}, {pattern : /(<style[^>]*>)(.*?)(<\/style>)/g}, {pattern : /(<pre[^>]*>)(.*?)(<\/pre>)/g, encode : 1}, {pattern : /(<!--\[CDATA\[)(.*?)(\]\]-->)/g} @@ -6040,13 +6286,18 @@ // Restore the \u00a0 character if raw mode is enabled if (s.entity_encoding == 'raw') h = h.replace(/<p> <\/p>|<p([^>]+)> <\/p>/g, '<p$1>\u00a0</p>'); + + // Restore noscript elements + h = h.replace(/<noscript([^>]+|)>([\s\S]*?)<\/noscript>/g, function(v, attribs, text) { + return '<noscript' + attribs + '>' + t.dom.decode(text.replace(/<!--|-->/g, '')) + '</noscript>'; + }); } o.content = h; }, _serializeNode : function(n, inn) { - var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv; + var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv, closed; if (!s.node_filter || s.node_filter(n)) { switch (n.nodeType) { @@ -6069,7 +6320,7 @@ nn = nn.substring(4); // Check if valid - if (!t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) { + if (!t.validElementsRE || !t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) { iv = true; break; } @@ -6106,6 +6357,7 @@ ru = t.findRule(nn); nn = ru.name || nn; + closed = s.closed.test(nn); // Skip empty nodes or empty node name in IE if ((!hc && ru.noEmpty) || (isIE && !nn)) { @@ -6163,6 +6415,14 @@ } } + // Write text from script + if (nn === 'script' && tinymce.trim(n.innerHTML)) { + w.writeText('// '); // Padd it with a comment so it will parse on older browsers + w.writeCDATA(n.innerHTML.replace(/<!--|-->|<\[CDATA\[|\]\]>/g, '')); // Remove comments and cdata stuctures + hc = false; + break; + } + // Padd empty nodes with a if (ru.padd) { // If it has only one bogus child, padd it anyway workaround for <td><br /></td> bug @@ -6193,7 +6453,7 @@ } else if (n.nodeType == 1) hc = n.hasChildNodes(); - if (hc) { + if (hc && !closed) { cn = n.firstChild; while (cn) { @@ -6205,7 +6465,7 @@ // Write element end if (!iv) { - if (hc || !s.closed.test(nn)) + if (!closed) w.writeFullEndElement(); else w.writeEndElement(); @@ -6326,16 +6586,6 @@ v = this.dom.getAttrib(n, na); - // Bool attr - if (this.settings.bool_attrs.test(na) && v) { - v = ('' + v).toLowerCase(); - - if (v === 'false' || v === '0') - return null; - - v = na; - } - switch (na) { case 'rowspan': case 'colspan': @@ -6378,8 +6628,7 @@ return v; } - - }); + }); })(tinymce); (function(tinymce) { var each = tinymce.each, Event = tinymce.dom.Event; @@ -6651,8 +6900,7 @@ } } } - - }); + }); // Global script loader tinymce.ScriptLoader = new tinymce.dom.ScriptLoader(); @@ -6756,12 +7004,13 @@ destroy : function() { tinymce.dom.Event.clear(this.id); } - - }); + }); })(tinymce);tinymce.create('tinymce.ui.Container:tinymce.ui.Control', { Container : function(id, s) { this.parent(id, s); + this.controls = []; + this.lookup = {}; }, @@ -6775,8 +7024,7 @@ get : function(n) { return this.lookup[n]; } - - }); +}); tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', { Separator : function(id, s) { @@ -6787,8 +7035,7 @@ renderHTML : function() { return tinymce.DOM.createHTML('span', {'class' : this.classPrefix}); } - - }); +}); (function(tinymce) { var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk; @@ -6816,8 +7063,7 @@ if (is(t.selected)) t.setSelected(t.selected); } - - }); + }); })(tinymce); (function(tinymce) { var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk; @@ -6915,8 +7161,7 @@ return m; } - - }); + }); })(tinymce);(function(tinymce) { var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element; @@ -7243,8 +7488,7 @@ DOM.addClass(ro, 'mceLast'); } - - }); + }); })(tinymce);(function(tinymce) { var DOM = tinymce.DOM; @@ -7276,8 +7520,7 @@ return s.onclick.call(s.scope, e); }); } - - }); + }); })(tinymce); (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher; @@ -7287,11 +7530,17 @@ var t = this; t.parent(id, s); + t.items = []; + t.onChange = new Dispatcher(t); + t.onPostRender = new Dispatcher(t); + t.onAdd = new Dispatcher(t); + t.onRenderMenu = new tinymce.util.Dispatcher(this); + t.classPrefix = 'mceListBox'; }, @@ -7527,9 +7776,9 @@ this.parent(); Event.clear(this.id + '_text'); + Event.clear(this.id + '_open'); } - - }); + }); })(tinymce);(function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher; @@ -7657,15 +7906,16 @@ t.onPostRender.dispatch(t, DOM.get(t.id)); } - - }); + }); })(tinymce);(function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each; tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', { MenuButton : function(id, s) { this.parent(id, s); + this.onRenderMenu = new tinymce.util.Dispatcher(this); + s.menu_container = s.menu_container || DOM.doc.body; }, @@ -7744,8 +7994,7 @@ } }); } - - }); + }); })(tinymce); (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each; @@ -7810,8 +8059,7 @@ Event.clear(this.id + '_action'); Event.clear(this.id + '_open'); } - - }); + }); })(tinymce); (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each; @@ -7829,6 +8077,7 @@ }, t.settings); t.onShowMenu = new tinymce.util.Dispatcher(t); + t.onHideMenu = new tinymce.util.Dispatcher(t); t.value = s.default_color; @@ -7860,6 +8109,7 @@ e = 0; Event.add(DOM.doc, 'mousedown', t.hideMenu, t); + t.onShowMenu.dispatch(t); if (t._focused) { t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) { @@ -7869,8 +8119,6 @@ DOM.select('a', t.id + '_menu')[0].focus(); // Select first link } - - t.onShowMenu.dispatch(t); t.isMenuVisible = 1; }, @@ -7977,8 +8225,7 @@ Event.clear(this.id + '_more'); DOM.remove(this.id + '_menu'); } - - }); + }); })(tinymce); tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', { renderHTML : function() { @@ -8041,8 +8288,7 @@ return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || ''}, '<tbody><tr>' + h + '</tr></tbody>'); } - - }); +}); (function(tinymce) { var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each; @@ -8050,6 +8296,7 @@ items : [], urls : {}, lookup : {}, + onAdd : new Dispatcher(this), get : function(n) { @@ -8089,19 +8336,22 @@ t.urls[n] = u.substring(0, u.lastIndexOf('/')); tinymce.ScriptLoader.add(u, cb, s); } - - }); + }); // Create plugin and theme managers tinymce.PluginManager = new tinymce.AddOnManager(); tinymce.ThemeManager = new tinymce.AddOnManager(); -}(tinymce));(function(tinymce) { +}(tinymce)); + +(function(tinymce) { // Shorten names var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode; tinymce.create('static tinymce.EditorManager', { editors : {}, + i18n : {}, + activeEditor : null, preInit : function() { @@ -8114,10 +8364,6 @@ tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL); tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL); - - // User specified a document.domain value - if (document.domain && lo.hostname != document.domain) - tinymce.relaxedDomain = document.domain; // Add before unload listener // This was required since IE was leaking memory if you added and removed beforeunload listeners @@ -8169,10 +8415,6 @@ // Load plugins if (s.plugins) { pl = explode(s.plugins); - - // Load compat2x first - if (tinymce.inArray(pl, 'compat2x') != -1) - PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js'); // Load rest if plugins each(pl, function(v) { @@ -8342,6 +8584,8 @@ // Select another editor since the active one was removed if (t.activeEditor == e) { + t._setActive(null); + each(t.editors, function(e) { t._setActive(e); return false; // Break @@ -8466,13 +8710,11 @@ _setActive : function(e) { this.selectedInstance = this.activeEditor = e; } - - }); + }); tinymce.EditorManager.preInit(); })(tinymce); -// Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call var tinyMCE = window.tinyMCE = tinymce.EditorManager; (function(tinymce) { var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, Dispatcher = tinymce.util.Dispatcher; @@ -8485,53 +8727,90 @@ var t = this; t.id = t.editorId = id; + t.execCommands = {}; t.queryStateCommands = {}; t.queryValueCommands = {}; + + t.isNotDirty = false; + t.plugins = {}; // Add events to the editor each([ 'onPreInit', + 'onBeforeRenderUI', + 'onPostRender', + 'onInit', + 'onRemove', + 'onActivate', + 'onDeactivate', + 'onClick', + 'onEvent', + 'onMouseUp', + 'onMouseDown', + 'onDblClick', + 'onKeyDown', + 'onKeyUp', + 'onKeyPress', + 'onContextMenu', + 'onSubmit', + 'onReset', + 'onPaste', + 'onPreProcess', + 'onPostProcess', + 'onBeforeSetContent', + 'onBeforeGetContent', + 'onSetContent', + 'onGetContent', + 'onLoadContent', + 'onSaveContent', + 'onNodeChange', + 'onChange', + 'onBeforeExecCommand', + 'onExecCommand', + 'onUndo', + 'onRedo', + 'onVisualAid', + 'onSetProgressState' ], function(e) { t[e] = new Dispatcher(t); }); - // Default editor config t.settings = s = extend({ id : id, language : 'en', @@ -8566,7 +8845,7 @@ apply_source_formatting : 1, directionality : 'ltr', forced_root_block : 'p', - valid_elements : '@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong/b,em/i,strike,u,#p[align],-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border=0|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big', + valid_elements : '@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong/b,em/i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote[cite],-table[border|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[name|value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value|tabindex|accesskey],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big', hidden_input : 1, padd_empty_editor : 1, render_ui : 1, @@ -8578,10 +8857,10 @@ removeformat_selector : 'span,b,strong,em,i,font,u,strike' }, s); - // Setup URIs t.documentBaseURI = new tinymce.util.URI(s.document_base_url || tinymce.documentBaseURL, { base_uri : tinyMCE.baseURI }); + t.baseURI = EditorManager.baseURI; // Call setup @@ -8699,12 +8978,7 @@ }); }; - // Load compat2x first - if (s.plugins.indexOf('compat2x') != -1) { - PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js'); - sl.loadQueue(loadScripts); - } else - loadScripts(); + loadScripts(); }, init : function() { @@ -8712,7 +8986,6 @@ EditorManager.add(t); - // Create theme if (s.theme) { s.theme = s.theme.replace(/-/, ''); o = ThemeManager.get(s.theme); @@ -8747,8 +9020,8 @@ if (s.popup_css_add) s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add); - // Setup control factory t.controlManager = new tinymce.ControlManager(t); + t.undoManager = new tinymce.UndoManager(t); // Pass through @@ -8819,6 +9092,10 @@ } + // User specified a document.domain value + if (document.domain && location.hostname != document.domain) + tinymce.relaxedDomain = document.domain; + // Resize editor DOM.setStyles(o.sizeContainer || o.editorContainer, { width : w, @@ -8829,7 +9106,13 @@ if (h < 100) h = 100; - t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml"><base href="' + t.documentBaseURI.getURI() + '" />'; + t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml">'; + + // We only need to override paths if we have to + // IE has a bug where it remove site absolute urls to relative ones if this is specified + if (s.document_base_url != tinymce.documentBaseURL) + t.iframeHTML += '<base href="' + t.documentBaseURI.getURI() + '" />'; + t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />'; if (tinymce.relaxedDomain) @@ -8912,8 +9195,7 @@ DOM.show(b); } - // Setup objects - t.dom = new tinymce.DOM.DOMUtils(t.getDoc(), { + t.dom = new tinymce.dom.DOMUtils(t.getDoc(), { keep_values : true, url_converter : t.convertURL, url_converter_scope : t, @@ -8923,26 +9205,13 @@ fix_ie_paragraphs : 1 }); - t.serializer = new tinymce.dom.Serializer({ - entity_encoding : s.entity_encoding, - entities : s.entities, + t.serializer = new tinymce.dom.Serializer(extend(s, { valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements, - extended_valid_elements : s.extended_valid_elements, - valid_child_elements : s.valid_child_elements, - invalid_elements : s.invalid_elements, - fix_table_elements : s.fix_table_elements, - fix_list_elements : s.fix_list_elements, - fix_content_duplication : s.fix_content_duplication, - convert_fonts_to_spans : s.convert_fonts_to_spans, - font_size_classes : s.font_size_classes, - font_size_style_values : s.font_size_style_values, - apply_source_formatting : s.apply_source_formatting, - remove_linebreaks : s.remove_linebreaks, - element_format : s.element_format, dom : t.dom - }); + })); t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer); + t.forceBlocks = new tinymce.ForceBlocks(t, { forced_root_block : s.forced_root_block }); @@ -8974,9 +9243,6 @@ if (s.nowrap) t.getBody().style.whiteSpace = "nowrap"; - if (s.auto_resize) - t.onNodeChange.add(t.resizeToContent, t); - if (s.custom_elements) { function handleCustom(ed, o) { each(explode(s.custom_elements), function(v) { @@ -8996,7 +9262,7 @@ t.onBeforeSetContent.add(handleCustom); t.onPostProcess.add(function(ed, o) { if (o.set) - handleCustom(ed, o) + handleCustom(ed, o); }); } @@ -9520,12 +9786,6 @@ return b; }, - resizeToContent : function() { - var t = this; - - DOM.setStyle(t.id + "_ifr", 'height', t.getBody().scrollHeight); - }, - load : function(o) { var t = this, e = t.getElement(), h; @@ -9860,33 +10120,33 @@ case 'contextmenu': if (tinymce.isOpera) { // Fake contextmenu on Opera - Event.add(t.getBody(), 'mousedown', function(e) { + t.dom.bind(t.getBody(), 'mousedown', function(e) { if (e.ctrlKey) { e.fakeType = 'contextmenu'; eventHandler(e); } }); } else - Event.add(t.getBody(), k, eventHandler); + t.dom.bind(t.getBody(), k, eventHandler); break; case 'paste': - Event.add(t.getBody(), k, function(e) { + t.dom.bind(t.getBody(), k, function(e) { eventHandler(e); }); break; case 'submit': case 'reset': - Event.add(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler); + t.dom.bind(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler); break; default: - Event.add(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler); + t.dom.bind(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler); } }); - Event.add(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) { + t.dom.bind(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) { t.focus(true); }); @@ -9904,7 +10164,7 @@ }) });*/ - Event.add(t.getDoc(), 'DOMNodeInserted', function(e) { + t.dom.bind(t.getDoc(), 'DOMNodeInserted', function(e) { var v; e = e.target; @@ -10041,7 +10301,7 @@ if (tinymce.isIE) { // Fix so resize will only update the width and height attributes not the styles of an image // It will also block mceItemNoResize items - Event.add(t.getDoc(), 'controlselect', function(e) { + t.dom.bind(t.getDoc(), 'controlselect', function(e) { var re = t.resizeInfo, cb; e = e.target; @@ -10051,11 +10311,11 @@ return; if (re) - Event.remove(re.node, re.ev, re.cb); + t.dom.unbind(re.node, re.ev, re.cb); if (!t.dom.hasClass(e, 'mceItemNoResize')) { ev = 'resizeend'; - cb = Event.add(e, ev, function(e) { + cb = t.dom.bind(e, ev, function(e) { var v; e = e.target; @@ -10072,7 +10332,7 @@ }); } else { ev = 'resizestart'; - cb = Event.add(e, 'resizestart', Event.cancel, Event); + cb = t.dom.bind(e, 'resizestart', Event.cancel, Event); } re = t.resizeInfo = { @@ -10119,7 +10379,7 @@ // Add undo level on editor blur if (tinymce.isIE) { - Event.add(t.getWin(), 'blur', function(e) { + t.dom.bind(t.getWin(), 'blur', function(e) { var n; // Check added for fullscreen bug @@ -10132,7 +10392,7 @@ } }); } else { - Event.add(t.getDoc(), 'blur', function() { + t.dom.bind(t.getDoc(), 'blur', function() { if (t.selection && !t.removed) addUndo(); }); @@ -10355,8 +10615,7 @@ return s; } - - }); + }); })(tinymce); (function(tinymce) { var each = tinymce.each, isIE = tinymce.isIE, isGecko = tinymce.isGecko, isOpera = tinymce.isOpera, isWebKit = tinymce.isWebKit; @@ -11410,8 +11669,7 @@ hasRedo : function() { return this.index < this.data.length - 1; } - - }); + }); })(tinymce); (function(tinymce) { // Shorten names @@ -11424,10 +11682,21 @@ each = tinymce.each; extend = tinymce.extend; + // Checks if the selection/caret is at the end of the specified block element + function isAtEnd(rng, par) { + var rng2 = par.ownerDocument.createRange(); + + rng2.setStart(rng.endContainer, rng.endOffset); + rng2.setEndAfter(par); + + // Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element + return rng2.cloneContents().textContent.length == 0; + }; + function isEmpty(n) { n = n.innerHTML; - n = n.replace(/<\w+ .*?mce_\w+\"?=.*?>/gi, '-'); // Keep tags with mce_ attribs - n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars + + n = n.replace(/<(img|hr|table|input|select|textarea)[ \>]/gi, '-'); // Keep these convert them to - chars n = n.replace(/<[^>]+>/g, ''); // Remove all tags return n.replace(/[ \t\r\n]+/g, '') == ''; @@ -11547,17 +11816,23 @@ return ne; }; + // Padd empty inline elements within block elements + // For example: <p><strong><em></em></strong></p> becomes <p><strong><em> </em></strong></p> + ed.onPreProcess.add(function(ed, o) { + each(ed.dom.select('p,h1,h2,h3,h4,h5,h6,div', o.node), function(p) { + if (isEmpty(p)) { + each(ed.dom.select('span,em,strong,b,i', o.node), function(n) { + if (!n.hasChildNodes()) { + n.appendChild(ed.getDoc().createTextNode('\u00a0')); + return false; // Break the loop one padding is enough + } + }); + } + }); + }); + // IE specific fixes if (isIE) { - // Remove empty inline elements within block elements - // For example: <p><strong><em></em></strong></p> - ed.onPreProcess.add(function(ed, o) { - each(ed.dom.select('p,h1,h2,h3,h4,h5,h6,div', o.node), function(p) { - if (isEmpty(p)) - p.innerHTML = ''; - }); - }); - // Replaces IE:s auto generated paragraphs with the specified element name if (s.element != 'P') { ed.onKeyPress.add(function(ed, e) { @@ -11616,7 +11891,7 @@ nx = nl[i]; // Is text or non block element - if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) { + if (nx.nodeType === 3 || (!t.dom.isBlock(nx) && nx.nodeType !== 8 && !/^(script|mce:script|style|mce:style)$/i.test(nx.nodeName))) { if (!bl) { // Create new block but ignore whitespace if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) { @@ -11656,9 +11931,11 @@ } } + // Uses replaceChild instead of cloneNode since it removes selected attribute from option elements on IE + // See: http://support.microsoft.com/kb/829907 bl = ed.dom.create(ed.settings.forced_root_block); - bl.appendChild(nx.cloneNode(1)); nx.parentNode.replaceChild(bl, nx); + bl.appendChild(nx); } } else { if (bl.hasChildNodes()) @@ -11757,11 +12034,19 @@ // If selection is in empty table cell if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) { - dom.remove(sn.firstChild); // Remove BR + if (sn.firstChild.nodeName == 'BR') + dom.remove(sn.firstChild); // Remove BR // Create two new block elements - ed.dom.add(sn, se.element, null, '<br />'); - aft = ed.dom.add(sn, se.element, null, '<br />'); + if (sn.childNodes.length == 0) { + ed.dom.add(sn, se.element, null, '<br />'); + aft = ed.dom.add(sn, se.element, null, '<br />'); + } else { + n = sn.innerHTML; + sn.innerHTML = ''; + ed.dom.add(sn, se.element, null, n); + aft = ed.dom.add(sn, se.element, null, '<br />'); + } // Move caret into the last one r = d.createRange(); @@ -11823,7 +12108,7 @@ aft.removeAttribute('id'); // Is header and cursor is at the end, then force paragraph under - if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length) + if (/^(H[1-6])$/.test(bn) && isAtEnd(r, sb)) aft = ed.dom.create(se.element); // Find start chop node @@ -11968,7 +12253,46 @@ }, backspaceDelete : function(e, bs) { - var t = this, ed = t.editor, b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn; + var t = this, ed = t.editor, b = ed.getBody(), dom = ed.dom, n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn; + + /* + var par, rng, nextBlock; + + // Delete key will not merge paragraphs on Gecko so we need to do this manually + // Hitting the delete key at the following caret position doesn't merge the elements <p>A|</p><p>B</p> + // This logic will merge them into this: <p>A|B</p> + if (e.keyCode == 46) { + if (r.collapsed) { + par = dom.getParent(sc, 'p,h1,h2,h3,h4,h5,h6,div'); + + if (par) { + rng = dom.createRng(); + + rng.setStart(sc, r.startOffset); + rng.setEndAfter(par); + + // Get number of characters to the right of the cursor if it's zero then we are at the end and need to merge the next block element + if (dom.getOuterHTML(rng.cloneContents()).replace(/<[^>]+>/g, '').length == 0) { + nextBlock = dom.getNext(par, 'p,h1,h2,h3,h4,h5,h6,div'); + + // Copy all children from next sibling block and remove it + if (nextBlock) { + each(nextBlock.childNodes, function(node) { + par.appendChild(node.cloneNode(true)); + }); + + dom.remove(nextBlock); + } + + // Block the default even since the Gecko team might eventually fix this + // We will remove this logic once they do we can't feature detect this one + e.preventDefault(); + return; + } + } + } + } + */ // The caret sometimes gets stuck in Gecko if you delete empty paragraphs // This workaround removes the element by hand and moves the caret to the previous element @@ -12202,7 +12526,7 @@ c.onPostRender.add(function(c, n) { // Store bookmark on mousedown Event.add(n, 'mousedown', function() { - ed.bookmark = ed.selection.getBookmark('simple'); + ed.bookmark = ed.selection.getBookmark(1); }); // Restore on focus, since it might be lost @@ -12313,7 +12637,7 @@ s.onclick = function(v) { if (tinymce.isIE) bm = ed.selection.getBookmark(1); - + ed.execCommand(s.cmd, s.ui || false, v || s.value); }; } @@ -12344,6 +12668,12 @@ // Fix for bug #1897785, #1898007 if (tinymce.isIE) { + c.onShowMenu.add(function() { + // IE 8 needs focus in order to store away a range with the current collapsed caret location + ed.focus(); + bm = ed.selection.getBookmark(1); + }); + c.onHideMenu.add(function() { if (bm) { ed.selection.moveToBookmark(bm); @@ -12377,7 +12707,7 @@ setControlType : function(n, c) { return this._cls[n.toLowerCase()] = c; }, - + destroy : function() { each(this.controls, function(c) { c.destroy(); @@ -12385,8 +12715,7 @@ this.controls = null; } - - }); + }); })(tinymce); (function(tinymce) { var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera; @@ -12497,8 +12826,7 @@ _decode : function(s) { return tinymce.DOM.decode(s).replace(/\\n/g, '\n'); } - - }); + }); }(tinymce));(function(tinymce) { tinymce.CommandManager = function() { var execCommands = {}, queryStateCommands = {}, queryValueCommands = {}; @@ -12848,10 +13176,16 @@ doc.execCommand(cmd, false, null); // On WebKit the command will just be ignored if it's not enabled - if (!doc.queryCommandSupported(cmd)) + if (!doc.queryCommandEnabled(cmd)) throw 'Error'; } catch (ex) { - ed.windowManager.alert(ed.getLang('clipboard_no_support')); + if (tinymce.isGecko) { + ed.windowManager.confirm(ed.getLang('clipboard_msg'), function(s) { + if (s) + open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', '_blank'); + }); + } else + ed.windowManager.alert(ed.getLang('clipboard_no_support')); } }); }); -- Gitblit v1.9.1