diff -r 51386f1852b8 -r f26a69c40431 includes/clientside/tinymce/tiny_mce_src.js --- a/includes/clientside/tinymce/tiny_mce_src.js Thu Mar 06 20:45:46 2008 -0500 +++ b/includes/clientside/tinymce/tiny_mce_src.js Thu Mar 06 20:47:11 2008 -0500 @@ -3,8 +3,8 @@ var tinymce = { majorVersion : '3', - minorVersion : '0.1', - releaseDate : '2008-02-21', + minorVersion : '0.3', + releaseDate : '2008-03-03', _init : function() { var t = this, ua = navigator.userAgent, i, nl, n, base; @@ -1031,8 +1031,16 @@ }, get : function(e) { - if (typeof(e) == 'string') - return this.doc.getElementById(e); + var n; + + if (typeof(e) == 'string') { + n = e; + e = this.doc.getElementById(e); + + // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick + if (e && e.id !== n) + return this.doc.getElementsByName(n)[1]; + } return e; }, @@ -1558,11 +1566,11 @@ r = n; while (r) { - // Opera 9.25 bug fix, fixed in 9.50 - if (!tinymce.isOpera || r.nodeName != 'TR') { + // Opera 9.25 bug fix, fixed in 9.50 seems to be fixed in Opera 9.26 too + /* if (!tinymce.isOpera || r.nodeName != 'TR') { x -= r.scrollLeft || 0; y -= r.scrollTop || 0; - } + }*/ r = r.parentNode; @@ -1789,14 +1797,21 @@ e.innerHTML = '
' + h; e.removeChild(e.firstChild); } catch (ex) { - // IE sometimes produces an unknown runtime error on innerHTML - // This seems to fix this issue, don't know why. + // IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p + // This seems to fix this problem + + // Remove all child nodes + while (e.firstChild) + e.firstChild.removeNode(); + + // Create new div with HTML contents and a BR infront to keep comments x = t.create('div'); x.innerHTML = '
' + h; + // Add all children from div to target each (x.childNodes, function(n, i) { - // Skip the BR - if (i > 1) + // Skip br element + if (i) e.appendChild(n); }); } @@ -1985,11 +2000,18 @@ }, decode : function(s) { - var e = document.createElement("div"); - - e.innerHTML = s; - - return !e.firstChild ? s : e.firstChild.nodeValue; + var e; + + // Look for entities to decode + if (/&[^;]+;/.test(s)) { + // Decode the entities using a div element not super efficient but less code + e = this.doc.createElement("div"); + e.innerHTML = s; + + return !e.firstChild ? s : e.firstChild.nodeValue; + } + + return s; }, encode : function(s) { @@ -2781,7 +2803,7 @@ return d; } - p += n.nodeValue ? n.nodeValue.length : 0; + p += n.nodeValue ? tinymce.trim(n.nodeValue).length : 0; } return null; @@ -2798,7 +2820,8 @@ start : e.start + s.anchorOffset, end : e.end + s.focusOffset, scrollX : sx, - scrollY : sy + scrollY : sy, + beg : s.anchorOffset == 0 }; } else { e = getPos(ro, r.startContainer, r.endContainer); @@ -2810,7 +2833,8 @@ start : e.start + r.startOffset, end : e.end + r.endOffset, scrollX : sx, - scrollY : sy + scrollY : sy, + beg : r.startOffset == 0 }; } }, @@ -2819,20 +2843,25 @@ var t = this, r = t.getRng(), s = t.getSel(), ro = t.dom.getRoot(), sd; function getPos(r, sp, ep) { - var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}; + var w = document.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}, o, v; while ((n = w.nextNode()) != null) { - p += n.nodeValue ? n.nodeValue.length : 0; + p += n.nodeValue ? tinymce.trim(n.nodeValue).length : 0; if (p >= sp && !d.startNode) { + o = sp - (p - n.nodeValue.length); + + // Fix for odd quirk in FF + if (b.beg && o >= n.nodeValue.length) + continue; + d.startNode = n; - d.startOffset = sp - (p - n.nodeValue.length); + d.startOffset = o; } if (p >= ep) { d.endNode = n; d.endOffset = ep - (p - n.nodeValue.length); - return d; } } @@ -2906,6 +2935,7 @@ if (is(b.start) && is(b.end)) { try { sd = getPos(ro, b.start, b.end); + if (sd) { r = t.dom.doc.createRange(); r.setStart(sd.startNode, sd.startOffset); @@ -3339,7 +3369,18 @@ t.key = 0; t.onPreProcess = new Dispatcher(t); t.onPostProcess = new Dispatcher(t); - t.writer = tinymce.relaxedDomain && tinymce.isGecko ? new tinymce.dom.StringWriter() : new tinymce.dom.XMLWriter(); + + if (tinymce.relaxedDomain && tinymce.isGecko) { + // Gecko has a bug where we can't create a new XML document if domain relaxing is used + t.writer = new tinymce.dom.StringWriter(); + } else { + try { + t.writer = new tinymce.dom.XMLWriter(); + } catch (ex) { + // IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter + t.writer = new tinymce.dom.StringWriter(); + } + } // Default settings t.settings = s = extend({ @@ -3848,17 +3889,17 @@ if (s.remove_linebreaks) { h = h.replace(/(<[^>]+>)\s+/g, '$1 '); h = h.replace(/\s+(<\/[^>]+>)/g, ' $1'); - h = h.replace(/<(p|h[1-6]|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g, '<$1 $2>'); // Trim block start - h = h.replace(/<(p|h[1-6]|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g, '<$1>'); // Trim block start - h = h.replace(/\s+<\/(p|h[1-6]|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g, ''); // Trim block end + h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g, '<$1 $2>'); // Trim block start + h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g, '<$1>'); // Trim block start + h = h.replace(/\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g, ''); // Trim block end } // Simple indentation if (s.apply_source_formatting && s.indent_mode == 'simple') { // Add line breaks before and after block elements h = h.replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n'); - h = h.replace(/\s*<(p|h[1-6]|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>'); - h = h.replace(/<\/(p|h[1-6]|div|title|style|pre|script|td|li)>\s*/g, '\n'); + h = h.replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>'); + h = h.replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '\n'); h = h.replace(/\n\n/g, '\n'); } } @@ -4030,18 +4071,22 @@ o.items = o.items || []; function enc(s) { - return s.replace(/[\r\n]/g, function(c) { + return s.replace(/[\r\n\\]/g, function(c) { if (c === '\n') return '\\n'; + else if (c === '\\') + return '\\\\'; return '\\r'; }); }; function dec(s) { - return s.replace(/\\[rn]/g, function(c) { + return s.replace(/\\[\\rn]/g, function(c) { if (c === '\\n') return '\n'; + else if (c === '\\\\') + return '\\'; return '\r'; }); @@ -4133,7 +4178,7 @@ } else { // Remove internal mceItemXX classes when content is extracted from editor if (na == 'class' && this.processObj.get) - v = v.replace(/\bmceItem\w+\b/g, ''); + v = v.replace(/\s?mceItem\w+\s?/g, ''); } if (v === '') @@ -4158,6 +4203,10 @@ this.lookup = {}; }, + isDone : function(u) { + return this.lookup[u] ? this.lookup[u].state == 2 : 0; + }, + markDone : function(u) { this.lookup[u] = {state : 2, url : u}; }, @@ -4648,12 +4697,15 @@ s.vp_offset_y = s.vp_offset_y || 0; if (is(s.icons) && !s.icons) - s['class'] += ' noIcons'; + s['class'] += ' mceNoIcons'; this.parent(id, s); this.onShowMenu = new tinymce.util.Dispatcher(this); this.onHideMenu = new tinymce.util.Dispatcher(this); this.classPrefix = 'mceMenu'; + + // Fix for odd IE bug: #1903622 + this.fixIE = tinymce.isIE && window.top != window; }, createMenu : function(s) { @@ -4743,7 +4795,7 @@ t.element.update(); t.isMenuVisible = 1; - t.mouseClickFunc = Event.add(co, 'click', function(e) { + t.mouseClickFunc = Event.add(co, t.fixIE ? 'mousedown' : 'click', function(e) { var m; e = e.target; @@ -4805,7 +4857,7 @@ return; Event.remove(co, 'mouseover', t.mouseOverFunc); - Event.remove(co, 'click', t.mouseClickFunc); + Event.remove(co, t.fixIE ? 'mousedown' : 'click', t.mouseClickFunc); DOM.hide(co); t.isMenuVisible = 0; @@ -4888,7 +4940,7 @@ DOM.add(ro, 'td', {'class' : 'mceMenuItemSeparator'}); if (n = ro.previousSibling) - DOM.addClass(n, 'last'); + DOM.addClass(n, 'mceLast'); return; } @@ -4899,25 +4951,25 @@ DOM.addClass(it, s['class']); // n = DOM.add(n, 'span', {'class' : 'item'}); - DOM.add(n, 'span', {'class' : 'icon' + (s.icon ? ' ' + s.icon : '')}); - n = DOM.add(n, s.element || 'span', {'class' : 'text', title : o.settings.title}, o.settings.title); + DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')}); + n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title); if (o.settings.style) DOM.setAttrib(n, 'style', o.settings.style); if (tb.childNodes.length == 1) - DOM.addClass(ro, 'first'); + DOM.addClass(ro, 'mceFirst'); if ((n = ro.previousSibling) && DOM.hasClass(n, 'mceMenuItemSeparator')) - DOM.addClass(ro, 'first'); + DOM.addClass(ro, 'mceFirst'); if (o.collapse) DOM.addClass(ro, 'mceMenuItemSub'); if (n = ro.previousSibling) - DOM.removeClass(n, 'last'); - - DOM.addClass(ro, 'last'); + DOM.removeClass(n, 'mceLast'); + + DOM.addClass(ro, 'mceLast'); } }); @@ -4937,9 +4989,9 @@ var s = this.settings, h = ''; if (s.image) - h += ''; + h += ''; else - h += ''; + h += ''; return h; }, @@ -4994,11 +5046,11 @@ // If no item was found then present title if (!fv) { DOM.setHTML(e, DOM.encode(t.settings.title)); - DOM.addClass(e, 'title'); + DOM.addClass(e, 'mceTitle'); e = 0; return; } else - DOM.removeClass(e, 'title'); + DOM.removeClass(e, 'mceTitle'); } e = 0; @@ -5025,8 +5077,8 @@ var h = '', t = this, s = t.settings; h = ''; - h += ''; - h += ''; + h += ''; + h += ''; h += '
' + DOM.createHTML('a', {id : t.id + '_text', href : 'javascript:;', 'class' : 'text', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'open', onclick : "return false;", onmousedown : 'return false;'}, '') + '' + DOM.createHTML('a', {id : t.id + '_text', href : 'javascript:;', 'class' : 'mceText', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '') + '
'; return h; @@ -5084,7 +5136,7 @@ m = t.settings.control_manager.createDropMenu(t.id + '_menu', { menu_line : 1, - 'class' : 'mceListBoxMenu noIcons', + 'class' : 'mceListBoxMenu mceNoIcons', max_width : 150, max_height : 150 }); @@ -5337,14 +5389,14 @@ h = ''; if (s.image) - h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'action ' + s['class']}); + h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'mceAction ' + s['class']}); else - h1 = DOM.createHTML('span', {'class' : 'action ' + s['class']}); - - h += '' + DOM.createHTML('a', {id : t.id + '_action', href : 'javascript:;', 'class' : 'action ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + ''; + h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}); + + h += '' + DOM.createHTML('a', {id : t.id + '_action', href : 'javascript:;', 'class' : 'mceAction ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + ''; - h1 = DOM.createHTML('span', {'class' : 'open ' + s['class']}); - h += '' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'open ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + ''; + h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']}); + h += '' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'mceOpen ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + ''; h += ''; @@ -5471,8 +5523,8 @@ if (s.more_colors_func) { n = DOM.add(tb, 'tr'); - n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'morecolors'}); - n = DOM.add(n, 'a', {href : 'javascript:;', onclick : 'return false;', 'class' : 'morecolors'}, s.more_colors_title); + n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'}); + n = DOM.add(n, 'a', {href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title); Event.add(n, 'click', function(e) { s.more_colors_func.call(s.more_colors_scope || this); @@ -5699,23 +5751,26 @@ switch (s.mode) { case "exact": l = s.elements || ''; - each(l.split(','), function(v) { - if (DOM.get(v)) - new tinymce.Editor(v, s).render(1); - else { - c = 0; - - each(document.forms, function(f) { - each(f.elements, function(e) { - if (e.name === v) { - v = 'mce_editor_' + c; - DOM.setAttrib(e, 'id', v); - new tinymce.Editor(v, s).render(1); - } + + if(l.length > 0) { + each(l.split(','), function(v) { + if (DOM.get(v)) + new tinymce.Editor(v, s).render(1); + else { + c = 0; + + each(document.forms, function(f) { + each(f.elements, function(e) { + if (e.name === v) { + v = 'mce_editor_' + c; + DOM.setAttrib(e, 'id', v); + new tinymce.Editor(v, s).render(1); + } + }); }); - }); - } - }); + } + }); + } break; case "textareas": @@ -5894,8 +5949,8 @@ tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL); tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL); - if (tinymce.EditorManager.baseURI.host != document.domain) - document.domain = tinymce.relaxedDomain = document.domain.replace(/.*\.(.+\..+)$/, '$1'); + if (tinymce.EditorManager.baseURI.host != window.location.hostname) + document.domain = tinymce.relaxedDomain = window.location.hostname.replace(/.*\.(.+\..+)$/, '$1'); })(); // Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call @@ -6000,6 +6055,7 @@ padd_empty_editor : 1, render_ui : 1, init_theme : 1, + force_p_newlines : 1, indentation : '30px' }, s); @@ -6016,6 +6072,14 @@ render : function(nst) { var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader; + // Page is not loaded yet, wait for it + if (!Event.domLoaded) { + Event.add(document, 'init', function() { + t.render(); + }); + return; + } + // Force strict loading mode if render us called by user and not internally if (!nst) { s.strict_loading_mode = 1; @@ -6138,7 +6202,7 @@ }, init : function() { - var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u; + var n, t = this, s = t.settings, w, h, e = t.getElement(), o, ti, u, bi, bc, re; EditorManager.add(t); @@ -6202,8 +6266,9 @@ // Remove ghost selections on images and tables in Gecko if (isGecko) { - function repaint() { - t.execCommand('mceRepaint'); + function repaint(a, o) { + if (!o || !o.initial) + t.execCommand('mceRepaint'); }; t.onUndo.add(repaint); @@ -6219,11 +6284,12 @@ w = s.width || e.style.width || e.clientWidth; h = s.height || e.style.height || e.clientHeight; t.orgDisplay = e.style.display; - - if (('' + w).indexOf('%') == -1) + re = new RegExp('%|px|auto', 'gi'); + + if (!re.test('' + w)) w = Math.max(parseInt(w) + (o.deltaWidth || 0), 100); - if (('' + h).indexOf('%') == -1) + if (!re.test('' + h)) h = Math.max(parseInt(h) + (o.deltaHeight || 0), 100); // Render UI @@ -6255,20 +6321,32 @@ if (tinymce.relaxedDomain) t.iframeHTML += ''; - t.iframeHTML += ''; + bi = s.body_id || 'tinymce'; + if (bi.indexOf('=') != -1) { + bi = t.getParam('body_id', '', 'hash'); + bi = bi[t.id] || bi; + } + + bc = s.body_class || ''; + if (bc.indexOf('=') != -1) { + bc = t.getParam('body_class', '', 'hash'); + bc = bc[t.id] || ''; + } + + t.iframeHTML += ''; // 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) - u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + s.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()'; + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()'; else if (tinymce.isOpera) u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()'; } // Create iframe n = DOM.add(o.iframeContainer, 'iframe', { - id : s.id + "_ifr", + id : t.id + "_ifr", src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7 frameBorder : '0', style : { @@ -6279,7 +6357,7 @@ t.contentAreaContainer = o.iframeContainer; DOM.get(o.editorContainer).style.display = t.orgDisplay; - DOM.get(s.id).style.display = 'none'; + DOM.get(t.id).style.display = 'none'; // Safari 2.x requires us to wait for the load event and load a real HTML doc if (tinymce.isOldWebKit) { @@ -6294,7 +6372,7 @@ }, setupIframe : function() { - var t = this, s = t.settings, e = DOM.get(s.id), d = t.getDoc(), h; + var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h; // Setup iframe body if (!isIE || !tinymce.relaxedDomain) { @@ -6638,8 +6716,28 @@ return EditorManager.i18n[this.settings.language + '.' + n] || (is(dv) ? dv : '{#' + n + '}'); }, - getParam : function(n, dv) { - return is(this.settings[n]) ? this.settings[n] : dv; + getParam : function(n, dv, ty) { + var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o; + + if (ty === 'hash') { + o = {}; + + if (is(v, 'string')) { + each(v.split(/[;,]/), function(v) { + v = v.split('='); + + if (v.length > 1) + o[tr(v[0])] = tr(v[1]); + else + o[tr(v[0])] = tr(v); + }); + } else + o = v; + + return o; + } + + return v; }, nodeChanged : function(o) { @@ -6800,7 +6898,11 @@ return o; // Browser commands - return this.getDoc().queryCommandState(c); + try { + return this.getDoc().queryCommandState(c); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } }, queryCommandValue : function(c) { @@ -6820,7 +6922,11 @@ return o; // Browser commands - return this.getDoc().queryCommandValue(c); + try { + return this.getDoc().queryCommandValue(c); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } }, show : function() { @@ -6832,15 +6938,16 @@ }, hide : function() { - var t = this, s = t.settings, d = t.getDoc(); + var t = this, d = t.getDoc(); // Fixed bug where IE has a blinking cursor left from the editor if (isIE && d) d.execCommand('SelectAll'); + // We must save before we hide so Safari doesn't crash + t.save(); DOM.hide(t.getContainer()); - DOM.setStyle(s.id, 'display', t.orgDisplay); - t.save(); + DOM.setStyle(t.id, 'display', t.orgDisplay); }, isHidden : function() { @@ -6863,6 +6970,9 @@ t.execCallback('remove_instance_callback', t); t.onRemove.dispatch(t); + // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command + t.onExecCommand.listeners = []; + EditorManager.remove(t); }, @@ -7040,8 +7150,8 @@ if (s.urlconverter_callback) return t.execCallback('urlconverter_callback', u, e, true, n); - // Don't convert link href since thats the CSS files that gets loaded into the editor - if (!s.convert_urls || (e && e.nodeName == 'LINK')) + // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs + if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0) return u; // Convert to relative @@ -7532,7 +7642,7 @@ }, _convertInlineElements : function() { - var t = this, s = t.settings, dom = t.dom, v; + var t = this, s = t.settings, dom = t.dom, v, e, na, st, sp; function convert(ed, o) { if (!s.inline_styles) @@ -7549,11 +7659,11 @@ break; case 'U': - dom.replace(dom.create('span', {style : 'text-decoration: underline;'}), n, 1); - break; - case 'STRIKE': - dom.replace(dom.create('span', {style : 'text-decoration: line-through;'}), n, 1); + sp = dom.create('span', {style : dom.getAttrib(n, 'style')}); + sp.style.textDecoration = n.nodeName == 'U' ? 'underline' : 'line-through'; + dom.setAttrib(sp, 'mce_style', ''); + dom.replace(sp, n, 1); break; } }); @@ -7565,9 +7675,22 @@ } else { // Convert spans to elements if (n.style.textDecoration == 'underline') - dom.replace(dom.create('u'), n, 1); + na = 'u'; else if (n.style.textDecoration == 'line-through') - dom.replace(dom.create('strike'), n, 1); + na = 'strike'; + else + na = ''; + + if (na) { + n.style.textDecoration = ''; + dom.setAttrib(n, 'mce_style', ''); + + e = dom.create(na, { + style : dom.getAttrib(n, 'style') + }); + + dom.replace(e, n, 1); + } } }); } @@ -7583,7 +7706,7 @@ }, _convertFonts : function() { - var t = this, s = t.settings, dom = t.dom, sl, cl, fz, fzn, v, i, st; + var t = this, s = t.settings, dom = t.dom, sl, cl, fz, fzn, v, i, st, x, nl, sp, f, n; // No need if (!s.inline_styles) @@ -7604,8 +7727,11 @@ if (tinymce.isWebKit || !s.inline_styles) return; - each(t.dom.select('span', no), function(n) { - var f = dom.create('font', { + nl = t.dom.select('span', no); + for (x = nl.length - 1; x >= 0; x--) { + n = nl[x]; + + f = dom.create('font', { color : dom.toHex(dom.getStyle(n, 'color')), face : dom.getStyle(n, 'fontFamily'), style : dom.getAttrib(n, 'style') @@ -7639,13 +7765,12 @@ dom.setAttrib(f, 'mce_style', ''); dom.replace(f, n, 1); } - }); + } }; // Run on setup t.onSetContent.add(function(ed, o) { - if (o.initial) - convertToFonts(ed.getBody()); + convertToFonts(ed.getBody()); }); // Run on cleanup @@ -7655,8 +7780,11 @@ return; if (o.get) { - each(t.dom.select('font', o.node), function(n) { - var sp = dom.create('span', { + nl = t.dom.select('font', o.node); + for (x = nl.length - 1; x >= 0; x--) { + n = nl[x]; + + sp = dom.create('span', { style : dom.getAttrib(n, 'style') }); @@ -7675,9 +7803,8 @@ dom.setAttrib(sp, 'mce_style', ''); dom.replace(sp, n, 1); - }); - } else if (o.set) - convertToFonts(o.node); + } + } }); }, @@ -8467,6 +8594,133 @@ }, mceBlockQuote : function() { + var t = this, ed = t.editor, s = ed.selection, dom = ed.dom, sb, eb, n, bm, bq, r, bq2, i, nl; + + function getBQ(e) { + return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';}); + }; + + // Get start/end block + sb = dom.getParent(s.getStart(), dom.isBlock); + eb = dom.getParent(s.getEnd(), dom.isBlock); + + // Remove blockquote(s) + if (bq = getBQ(sb)) { + if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR')) + bm = s.getBookmark(); + + // Move all elements after the end block into new bq + if (getBQ(eb)) { + bq2 = bq.cloneNode(false); + + while (n = eb.nextSibling) + bq2.appendChild(n.parentNode.removeChild(n)); + } + + // Add new bq after + if (bq2) + dom.insertAfter(bq2, bq); + + // Move all selected blocks after the current bq + nl = t._getSelectedBlocks(sb, eb); + for (i = nl.length - 1; i >= 0; i--) { + dom.insertAfter(nl[i], bq); + } + + // Empty bq, then remove it + if (/^\s*$/.test(bq.innerHTML)) + dom.remove(bq, 1); // Keep children so boomark restoration works correctly + + // Empty bq, then remote it + if (bq2 && /^\s*$/.test(bq2.innerHTML)) + dom.remove(bq2, 1); // Keep children so boomark restoration works correctly + + if (!bm) { + // Move caret inside empty block element + if (!isIE) { + r = ed.getDoc().createRange(); + r.setStart(sb, 0); + r.setEnd(sb, 0); + s.setRng(r); + } else { + s.select(sb); + s.collapse(0); + + // IE misses the empty block some times element so we must move back the caret + if (dom.getParent(s.getStart(), dom.isBlock) != sb) { + r = s.getRng(); + r.move('character', -1); + r.select(); + } + } + } else + t.editor.selection.moveToBookmark(bm); + + return; + } + + // Since IE can start with a totally empty document we need to add the first bq and paragraph + if (isIE && !sb && !eb) { + t.editor.getDoc().execCommand('Indent'); + n = getBQ(s.getNode()); + n.style.margin = n.dir = ''; // IE adds margin and dir to bq + return; + } + + if (!sb || !eb) + return; + + // If empty paragraph node then do not use bookmark + if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR')) + bm = s.getBookmark(); + + // Move selected block elements into a bq + each(t._getSelectedBlocks(getBQ(s.getStart()), getBQ(s.getEnd())), function(e) { + // Found existing BQ add to this one + if (e.nodeName == 'BLOCKQUOTE' && !bq) { + bq = e; + return; + } + + // No BQ found, create one + if (!bq) { + bq = dom.create('blockquote'); + e.parentNode.insertBefore(bq, e); + } + + // Add children from existing BQ + if (e.nodeName == 'BLOCKQUOTE' && bq) { + n = e.firstChild; + + while (n) { + bq.appendChild(n.cloneNode(true)); + n = n.nextSibling; + } + + dom.remove(e); + return; + } + + // Add non BQ element to BQ + bq.appendChild(dom.remove(e)); + }); + + if (!bm) { + // Move caret inside empty block element + if (!isIE) { + r = ed.getDoc().createRange(); + r.setStart(sb, 0); + r.setEnd(sb, 0); + s.setRng(r); + } else { + s.select(sb); + s.collapse(1); + } + } else + s.moveToBookmark(bm); + }, +/* + _mceBlockQuote : function() { var t = this, s = t.editor.selection, b = s.getBookmark(), bq, dom = t.editor.dom; function findBQ(e) { @@ -8520,7 +8774,7 @@ t.editor.selection.moveToBookmark(b); }, - +*/ _getSelectedBlocks : function(st, en) { var ed = this.editor, dom = ed.dom, s = ed.selection, sb, eb, n, bl = []; @@ -8588,7 +8842,7 @@ } } - if (s.custom_undo_redo_restore_selection) + if (s.custom_undo_redo_restore_selection && !l.initial) l.bookmark = b = l.bookmark || ed.selection.getBookmark(); if (t.index < t.data.length && t.data[t.index].initial) @@ -8690,17 +8944,10 @@ tinymce.create('tinymce.ForceBlocks', { ForceBlocks : function(ed) { - var t = this, s, elm; + var t = this, s = ed.settings, elm; t.editor = ed; t.dom = ed.dom; - - // Default settings - t.settings = s = extend({ - forced_root_block : 'p', - force_p_newlines : true - }, ed.settings); - elm = (s.forced_root_block || 'p').toLowerCase(); s.element = elm.toUpperCase(); @@ -8738,7 +8985,7 @@ }, setup : function() { - var t = this, ed = t.editor, s = t.settings; + var t = this, ed = t.editor, s = ed.settings; // Force root blocks when typing and when getting output if (s.forced_root_block) { @@ -8897,7 +9144,7 @@ } } - bl = ed.dom.create(t.settings.forced_root_block); + bl = ed.dom.create(ed.settings.forced_root_block); bl.appendChild(nx.cloneNode(1)); nx.parentNode.replaceChild(bl, nx); } @@ -8914,7 +9161,7 @@ // Restore selection if (si != -2) { if (!isIE) { - bl = d.getElementsByTagName(t.settings.element)[0]; + bl = d.getElementsByTagName(ed.settings.element)[0]; r = d.createRange(); // Select last location or generated block @@ -8955,7 +9202,7 @@ }, insertPara : function(e) { - var t = this, ed = t.editor, d = ed.getDoc(), se = t.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body; + var t = this, ed = t.editor, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body; var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n; function isEmpty(n) { @@ -9153,9 +9400,9 @@ if (sc && ed.dom.isBlock(sc) && bs) { if (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR') { n = sc.previousSibling; - if (n) { + if (n) { ed.dom.remove(sc); - se.select(n, 1); + se.select(n.firstChild); se.collapse(0); return Event.cancel(e); } @@ -9266,13 +9513,15 @@ }, createDropMenu : function(id, s) { - var t = this, ed = t.editor, c, bm; + var t = this, ed = t.editor, c, bm, v; s = extend({ 'class' : 'mceDropDown' }, s); s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin'; + if (v = ed.getParam('skin_variant')) + s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1); id = t.prefix + id; c = t.controls[id] = new tinymce.ui.DropMenu(id, s); @@ -9329,7 +9578,7 @@ s = extend({ title : s.title, - 'class' : id, + 'class' : 'mce_' + id, scope : s.scope, control_manager : t }, s); @@ -9382,7 +9631,7 @@ s = extend({ title : s.title, - 'class' : id, + 'class' : 'mce_' + id, unavailable_prefix : ed.getLang('unavailable', ''), scope : s.scope, control_manager : t @@ -9429,7 +9678,7 @@ s = extend({ title : s.title, - 'class' : id, + 'class' : 'mce_' + id, scope : s.scope, control_manager : t }, s); @@ -9464,7 +9713,7 @@ s = extend({ title : s.title, - 'class' : id, + 'class' : 'mce_' + id, 'menu_class' : ed.getParam('skin') + 'Skin', scope : s.scope, more_colors_title : ed.getLang('more_colors')