UNPKG

cody

Version:
2,078 lines (1,613 loc) 473 kB
// FILE IS GENERATED BY COMBINING THE SOURCES IN THE "classes" DIRECTORY SO DON'T MODIFY THIS FILE DIRECTLY (function(win) { var whiteSpaceRe = /^\s*|\s*$/g, undef, isRegExpBroken = 'B'.replace(/A(.)|B/, '$1') === '$1'; var tinymce = { majorVersion : '3', minorVersion : '5.8', releaseDate : '2012-11-20', _init : function() { var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v; t.isOpera = win.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.isIE7 = t.isIE && /MSIE [7]/.test(ua); t.isIE8 = t.isIE && /MSIE [8]/.test(ua); t.isIE9 = t.isIE && /MSIE [9]/.test(ua); t.isGecko = !t.isWebKit && /Gecko/.test(ua); t.isMac = ua.indexOf('Mac') != -1; t.isAir = /adobeair/i.test(ua); t.isIDevice = /(iPad|iPhone)/.test(ua); t.isIOS5 = t.isIDevice && ua.match(/AppleWebKit\/(\d*)/)[1]>=534; // TinyMCE .NET webcontrol might be setting the values for TinyMCE if (win.tinyMCEPreInit) { t.suffix = tinyMCEPreInit.suffix; t.baseURL = tinyMCEPreInit.base; t.query = tinyMCEPreInit.query; return; } // Get suffix and base t.suffix = ''; // If base element found, add that infront of baseURL nl = d.getElementsByTagName('base'); for (i=0; i<nl.length; i++) { v = nl[i].href; if (v) { // Host only value like http://essen.com or http://essen.com:8008 if (/^https?:\/\/[^\/]+$/.test(v)) v += '/'; base = v ? v.match(/.*\//)[0] : ''; // Get only directory } } function getBase(n) { if (n.src && /tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(n.src)) { if (/_(src|dev)\.js/g.test(n.src)) t.suffix = '_src'; if ((p = n.src.indexOf('?')) != -1) t.query = n.src.substring(p + 1); t.baseURL = n.src.substring(0, n.src.lastIndexOf('/')); // If path to script is relative and a base href was found add that one infront // 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; } return null; }; // Check document nl = d.getElementsByTagName('script'); for (i=0; i<nl.length; i++) { if (getBase(nl[i])) return; } // Check head n = d.getElementsByTagName('head')[0]; if (n) { nl = n.getElementsByTagName('script'); for (i=0; i<nl.length; i++) { if (getBase(nl[i])) return; } } return; }, is : function(o, t) { if (!t) return o !== undef; if (t == 'array' && tinymce.isArray(o)) return true; return typeof(o) == t; }, isArray: Array.isArray || function(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; }, makeMap : function(items, delim, map) { var i; items = items || []; delim = delim || ','; if (typeof(items) == "string") items = items.split(delim); map = map || {}; i = items.length; while (i--) map[items[i]] = {}; return map; }, each : function(o, cb, s) { var n, l; if (!o) return 0; s = s || o; if (o.length !== undef) { // Indexed arrays, needed for Safari for (n=0, l = o.length; n < l; n++) { if (cb.call(s, o[n], n, o) === false) return 0; } } else { // Hashtables for (n in o) { if (o.hasOwnProperty(n)) { if (cb.call(s, o[n], n, o) === false) return 0; } } } return 1; }, trim : function(s) { return (s ? '' + s : '').replace(whiteSpaceRe, ''); }, create : function(s, p, root) { var t = this, sp, ns, cn, scn, c, de = 0; // Parse : <prefix> <class>:<super class> s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s); cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name // Create namespace for new class ns = t.createNS(s[3].replace(/\.\w+$/, ''), root); // Class already exists if (ns[cn]) return; // Make pure static class if (s[2] == 'static') { ns[cn] = p; if (this.onCreate) this.onCreate(s[2], s[3], ns[cn]); return; } // Create default constructor if (!p[cn]) { p[cn] = function() {}; de = 1; } // Add constructor and methods ns[cn] = p[cn]; t.extend(ns[cn].prototype, p); // Extend if (s[5]) { sp = t.resolve(s[5]).prototype; scn = s[5].match(/\.(\w+)$/i)[1]; // Class name // Extend constructor c = ns[cn]; if (de) { // Add passthrough constructor ns[cn] = function() { return sp[scn].apply(this, arguments); }; } else { // Add inherit constructor ns[cn] = function() { this.parent = sp[scn]; return c.apply(this, arguments); }; } ns[cn].prototype[cn] = ns[cn]; // Add super methods t.each(sp, function(f, n) { ns[cn].prototype[n] = sp[n]; }); // Add overridden methods t.each(p, function(f, n) { // Extend methods if needed if (sp[n]) { ns[cn].prototype[n] = function() { this.parent = sp[n]; return f.apply(this, arguments); }; } else { if (n != cn) ns[cn].prototype[n] = f; } }); } // Add static methods t.each(p['static'], function(f, n) { ns[cn][n] = f; }); if (this.onCreate) this.onCreate(s[2], s[3], ns[cn].prototype); }, walk : function(o, f, n, s) { s = s || this; if (o) { if (n) o = o[n]; tinymce.each(o, function(o, i) { if (f.call(s, o, i, n) === false) return false; tinymce.walk(o, f, n, s); }); } }, createNS : function(n, o) { var i, v; o = o || win; n = n.split('.'); for (i=0; i<n.length; i++) { v = n[i]; if (!o[v]) o[v] = {}; o = o[v]; } return o; }, resolve : function(n, o) { var i, l; o = o || win; n = n.split('.'); for (i = 0, l = n.length; i < l; i++) { o = o[n[i]]; if (!o) break; } return o; }, addUnload : function(f, s) { var t = this, unload; unload = function() { var li = t.unloads, o, n; if (li) { // Call unload handlers for (n in li) { o = li[n]; if (o && o.func) o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy } // Detach unload function if (win.detachEvent) { win.detachEvent('onbeforeunload', fakeUnload); win.detachEvent('onunload', unload); } else if (win.removeEventListener) win.removeEventListener('unload', unload, false); // Destroy references t.unloads = o = li = w = unload = 0; // Run garbarge collector on IE if (win.CollectGarbage) CollectGarbage(); } }; function fakeUnload() { var d = document; function stop() { // Prevent memory leak d.detachEvent('onstop', stop); // Call unload handler if (unload) unload(); d = 0; }; // Is there things still loading, then do some magic if (d.readyState == 'interactive') { // Fire unload when the currently loading page is stopped if (d) d.attachEvent('onstop', stop); // Remove onstop listener after a while to prevent the unload function // to execute if the user presses cancel in an onbeforeunload // confirm dialog and then presses the browser stop button win.setTimeout(function() { if (d) d.detachEvent('onstop', stop); }, 0); } }; f = {func : f, scope : s || this}; if (!t.unloads) { // Attach unload handler if (win.attachEvent) { win.attachEvent('onunload', unload); win.attachEvent('onbeforeunload', fakeUnload); } else if (win.addEventListener) win.addEventListener('unload', unload, false); // Setup initial unload handler array t.unloads = [f]; } else t.unloads.push(f); return f; }, removeUnload : function(f) { var u = this.unloads, r = null; tinymce.each(u, function(o, i) { if (o && o.func == f) { u.splice(i, 1); r = f; return false; } }); return r; }, explode : function(s, d) { if (!s || tinymce.is(s, 'array')) { return s; } return tinymce.map(s.split(d || ','), tinymce.trim); }, _addVer : function(u) { var v; if (!this.query) return u; v = (u.indexOf('?') == -1 ? '?' : '&') + this.query; if (u.indexOf('#') == -1) return u + v; return u.replace('#', v + '#'); }, // Fix function for IE 9 where regexps isn't working correctly // Todo: remove me once MS fixes the bug _replace : function(find, replace, str) { // On IE9 we have to fake $x replacement if (isRegExpBroken) { return str.replace(find, function() { var val = replace, args = arguments, i; for (i = 0; i < args.length - 2; i++) { if (args[i] === undef) { val = val.replace(new RegExp('\\$' + i, 'g'), ''); } else { val = val.replace(new RegExp('\\$' + i, 'g'), args[i]); } } return val; }); } return str.replace(find, replace); } }; // Initialize the API tinymce._init(); // Expose tinymce namespace to the global namespace (window) win.tinymce = win.tinyMCE = tinymce; // Describe the different namespaces })(window); (function($, tinymce) { var is = tinymce.is, attrRegExp = /^(href|src|style)$/i, undef; // jQuery is undefined if (!$ && window.console) { return console.log("Load jQuery first!"); } // Stick jQuery into the tinymce namespace tinymce.$ = $; // Setup adapter tinymce.adapter = { patchEditor : function(editor) { var fn = $.fn; // Adapt the css function to make sure that the data-mce-style // attribute gets updated with the new style information function css(name, value) { var self = this; // Remove data-mce-style when set operation occurs if (value) self.removeAttr('data-mce-style'); return fn.css.apply(self, arguments); }; // Apapt the attr function to make sure that it uses the data-mce- prefixed variants function attr(name, value) { var self = this; // Update/retrive data-mce- attribute variants if (attrRegExp.test(name)) { if (value !== undef) { // Use TinyMCE behavior when setting the specifc attributes self.each(function(i, node) { editor.dom.setAttrib(node, name, value); }); return self; } else return self.attr('data-mce-' + name); } // Default behavior return fn.attr.apply(self, arguments); }; // Patch various jQuery functions to handle tinymce specific attribute and content behavior // we don't patch the jQuery.fn directly since it will most likely break compatibility // with other jQuery logic on the page. Only instances created by TinyMCE should be patched. function patch(jq) { // Patch some functions, only patch the object once if (jq.css !== css) { // Patch css/attr to use the data-mce- prefixed attribute variants jq.css = css; jq.attr = attr; jq.tinymce = editor; // Each pushed jQuery instance needs to be patched // as well for example when traversing the DOM jq.pushStack = function() { return patch(fn.pushStack.apply(this, arguments)); }; } return jq; }; // Add a $ function on each editor instance this one is scoped for the editor document object // this way you can do chaining like this tinymce.get(0).$('p').append('text').css('color', 'red'); editor.$ = function(selector, scope) { var doc = editor.getDoc(); return patch($(selector || doc, doc || scope)); }; } }; // Patch in core NS functions tinymce.extend = $.extend; tinymce.extend(tinymce, { map : $.map, grep : function(a, f) {return $.grep(a, f || function(){return 1;});}, inArray : function(a, v) {return $.inArray(v, a || []);} /* Didn't iterate stylesheets each : function(o, cb, s) { if (!o) return 0; var r = 1; $.each(o, function(nr, el){ if (cb.call(s, el, nr, o) === false) { r = 0; return false; } }); return r; }*/ }); // Patch in functions in various clases // Add a "#ifndefjquery" statement around each core API function you add below var patches = { 'tinymce.dom.DOMUtils' : { /* addClass : function(e, c) { if (is(e, 'array') && is(e[0], 'string')) e = e.join(',#'); return (e && $(is(e, 'string') ? '#' + e : e) .addClass(c) .attr('class')) || false; }, hasClass : function(n, c) { return $(is(n, 'string') ? '#' + n : n).hasClass(c); }, removeClass : function(e, c) { if (!e) return false; var r = []; $(is(e, 'string') ? '#' + e : e) .removeClass(c) .each(function(){ r.push(this.className); }); return r.length == 1 ? r[0] : r; }, */ select : function(pattern, scope) { var t = this; return $.find(pattern, t.get(scope) || t.get(t.settings.root_element) || t.doc, []); }, is : function(n, patt) { return $(this.get(n)).is(patt); } /* show : function(e) { if (is(e, 'array') && is(e[0], 'string')) e = e.join(',#'); $(is(e, 'string') ? '#' + e : e).css('display', 'block'); }, hide : function(e) { if (is(e, 'array') && is(e[0], 'string')) e = e.join(',#'); $(is(e, 'string') ? '#' + e : e).css('display', 'none'); }, isHidden : function(e) { return $(is(e, 'string') ? '#' + e : e).is(':hidden'); }, insertAfter : function(n, e) { return $(is(e, 'string') ? '#' + e : e).after(n); }, replace : function(o, n, k) { n = $(is(n, 'string') ? '#' + n : n); if (k) n.children().appendTo(o); n.replaceWith(o); }, setStyle : function(n, na, v) { if (is(n, 'array') && is(n[0], 'string')) n = n.join(',#'); $(is(n, 'string') ? '#' + n : n).css(na, v); }, getStyle : function(n, na, c) { return $(is(n, 'string') ? '#' + n : n).css(na); }, setStyles : function(e, o) { if (is(e, 'array') && is(e[0], 'string')) e = e.join(',#'); $(is(e, 'string') ? '#' + e : e).css(o); }, setAttrib : function(e, n, v) { var t = this, s = t.settings; if (is(e, 'array') && is(e[0], 'string')) e = e.join(',#'); e = $(is(e, 'string') ? '#' + e : e); switch (n) { case "style": e.each(function(i, v){ if (s.keep_values) $(v).attr('data-mce-style', v); v.style.cssText = v; }); break; case "class": e.each(function(){ this.className = v; }); break; case "src": case "href": e.each(function(i, v){ if (s.keep_values) { if (s.url_converter) v = s.url_converter.call(s.url_converter_scope || t, v, n, v); t.setAttrib(v, 'data-mce-' + n, v); } }); break; } if (v !== null && v.length !== 0) e.attr(n, '' + v); else e.removeAttr(n); }, setAttribs : function(e, o) { var t = this; $.each(o, function(n, v){ t.setAttrib(e,n,v); }); } */ } /* 'tinymce.dom.Event' : { add : function (o, n, f, s) { var lo, cb; cb = function(e) { e.target = e.target || this; f.call(s || this, e); }; if (is(o, 'array') && is(o[0], 'string')) o = o.join(',#'); o = $(is(o, 'string') ? '#' + o : o); if (n == 'init') { o.ready(cb, s); } else { if (s) { o.bind(n, s, cb); } else { o.bind(n, cb); } } lo = this._jqLookup || (this._jqLookup = []); lo.push({func : f, cfunc : cb}); return cb; }, remove : function(o, n, f) { // Find cfunc $(this._jqLookup).each(function() { if (this.func === f) f = this.cfunc; }); if (is(o, 'array') && is(o[0], 'string')) o = o.join(',#'); $(is(o, 'string') ? '#' + o : o).unbind(n,f); return true; } } */ }; // Patch functions after a class is created tinymce.onCreate = function(ty, c, p) { tinymce.extend(p, patches[c]); }; })(window.jQuery, tinymce); tinymce.create('tinymce.util.Dispatcher', { scope : null, listeners : null, inDispatch: false, Dispatcher : function(scope) { this.scope = scope || this; this.listeners = []; }, add : function(callback, scope) { this.listeners.push({cb : callback, scope : scope || this.scope}); return callback; }, addToTop : function(callback, scope) { var self = this, listener = {cb : callback, scope : scope || self.scope}; // Create new listeners if addToTop is executed in a dispatch loop if (self.inDispatch) { self.listeners = [listener].concat(self.listeners); } else { self.listeners.unshift(listener); } return callback; }, remove : function(callback) { var listeners = this.listeners, output = null; tinymce.each(listeners, function(listener, i) { if (callback == listener.cb) { output = listener; listeners.splice(i, 1); return false; } }); return output; }, dispatch : function() { var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener; self.inDispatch = true; // Needs to be a real loop since the listener count might change while looping // And this is also more efficient for (i = 0; i < listeners.length; i++) { listener = listeners[i]; returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]); if (returnValue === false) break; } self.inDispatch = false; return returnValue; } }); (function() { var each = tinymce.each; tinymce.create('tinymce.util.URI', { URI : function(u, s) { var t = this, o, a, b, base_url; // Trim whitespace u = tinymce.trim(u); // Default settings s = t.settings = s || {}; // Strange app protocol that isn't http/https or local anchor // For example: mailto,skype,tel etc. if (/^([\w\-]+):([^\/]{2})/i.test(u) || /^\s*#/.test(u)) { t.source = u; return; } // Absolute path with no host, fake host and protocol if (u.indexOf('/') === 0 && u.indexOf('//') !== 0) u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u; // Relative path http:// or protocol relative //path if (!/^[\w\-]*:?\/\//.test(u)) { base_url = s.base_uri ? s.base_uri.path : new tinymce.util.URI(location.href).directory; u = ((s.base_uri && s.base_uri.protocol) || 'http') + '://mce_host' + t.toAbsPath(base_url, u); } // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri) u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u); each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) { var s = u[i]; // Zope 3 workaround, they use @@something if (s) s = s.replace(/\(mce_at\)/g, '@@'); t[v] = s; }); b = s.base_uri; if (b) { if (!t.protocol) t.protocol = b.protocol; if (!t.userInfo) t.userInfo = b.userInfo; if (!t.port && t.host === 'mce_host') t.port = b.port; if (!t.host || t.host === 'mce_host') t.host = b.host; t.source = ''; } //t.path = t.path || '/'; }, setPath : function(p) { var t = this; p = /^(.*?)\/?(\w+)?$/.exec(p); // Update path parts t.path = p[0]; t.directory = p[1]; t.file = p[2]; // Rebuild source t.source = ''; t.getURI(); }, toRelative : function(u) { var t = this, o; if (u === "./") return u; u = new tinymce.util.URI(u, {base_uri : t}); // Not on same domain/port or protocol if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol) return u.getURI(); var tu = t.getURI(), uu = u.getURI(); // Allow usage of the base_uri when relative_urls = true if(tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) return tu; o = t.toRelPath(t.path, u.path); // Add query if (u.query) o += '?' + u.query; // Add anchor if (u.anchor) o += '#' + u.anchor; return o; }, toAbsolute : function(u, nh) { u = new tinymce.util.URI(u, {base_uri : this}); return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0); }, toRelPath : function(base, path) { var items, bp = 0, out = '', i, l; // Split the paths base = base.substring(0, base.lastIndexOf('/')); base = base.split('/'); items = path.split('/'); if (base.length >= items.length) { for (i = 0, l = base.length; i < l; i++) { if (i >= items.length || base[i] != items[i]) { bp = i + 1; break; } } } if (base.length < items.length) { for (i = 0, l = items.length; i < l; i++) { if (i >= base.length || base[i] != items[i]) { bp = i + 1; break; } } } if (bp === 1) return path; for (i = 0, l = base.length - (bp - 1); i < l; i++) out += "../"; for (i = bp - 1, l = items.length; i < l; i++) { if (i != bp - 1) out += "/" + items[i]; else out += items[i]; } return out; }, toAbsPath : function(base, path) { var i, nb = 0, o = [], tr, outPath; // Split paths tr = /\/$/.test(path) ? '/' : ''; base = base.split('/'); path = path.split('/'); // Remove empty chunks each(base, function(k) { if (k) o.push(k); }); base = o; // Merge relURLParts chunks for (i = path.length - 1, o = []; i >= 0; i--) { // Ignore empty or . if (path[i].length === 0 || path[i] === ".") continue; // Is parent if (path[i] === '..') { nb++; continue; } // Move up if (nb > 0) { nb--; continue; } o.push(path[i]); } i = base.length - nb; // If /a/b/c or / if (i <= 0) outPath = o.reverse().join('/'); else outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/'); // 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) { var s, t = this; // Rebuild source if (!t.source || nh) { s = ''; if (!nh) { if (t.protocol) s += t.protocol + '://'; if (t.userInfo) s += t.userInfo + '@'; if (t.host) s += t.host; if (t.port) s += ':' + t.port; } if (t.path) s += t.path; if (t.query) s += '?' + t.query; if (t.anchor) s += '#' + t.anchor; t.source = s; } return t.source; } }); })(); (function() { var each = tinymce.each; tinymce.create('static tinymce.util.Cookie', { getHash : function(n) { var v = this.get(n), h; if (v) { each(v.split('&'), function(v) { v = v.split('='); h = h || {}; h[unescape(v[0])] = unescape(v[1]); }); } return h; }, setHash : function(n, v, e, p, d, s) { var o = ''; each(v, function(v, k) { o += (!o ? '' : '&') + escape(k) + '=' + escape(v); }); this.set(n, o, e, p, d, s); }, get : function(n) { var c = document.cookie, e, p = n + "=", b; // Strict mode if (!c) return; b = c.indexOf("; " + p); if (b == -1) { b = c.indexOf(p); if (b !== 0) return null; } else b += 2; e = c.indexOf(";", b); if (e == -1) e = c.length; return unescape(c.substring(b + p.length, e)); }, set : function(n, v, e, p, d, s) { document.cookie = n + "=" + escape(v) + ((e) ? "; expires=" + e.toGMTString() : "") + ((p) ? "; path=" + escape(p) : "") + ((d) ? "; domain=" + d : "") + ((s) ? "; secure" : ""); }, remove : function(name, path, domain) { var date = new Date(); date.setTime(date.getTime() - 1000); this.set(name, '', date, path, domain); } }); })(); (function() { function serialize(o, quote) { var i, v, t, name; quote = quote || '"'; if (o == null) return 'null'; t = typeof o; if (t == 'string') { v = '\bb\tt\nn\ff\rr\""\'\'\\\\'; return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function(a, b) { // Make sure single quotes never get encoded inside double quotes for JSON compatibility if (quote === '"' && a === "'") return a; i = v.indexOf(b); if (i + 1) return '\\' + v.charAt(i + 1); a = b.charCodeAt().toString(16); return '\\u' + '0000'.substring(a.length) + a; }) + quote; } if (t == 'object') { if (o.hasOwnProperty && Object.prototype.toString.call(o) === '[object Array]') { for (i=0, v = '['; i<o.length; i++) v += (i > 0 ? ',' : '') + serialize(o[i], quote); return v + ']'; } v = '{'; for (name in o) { if (o.hasOwnProperty(name)) { v += typeof o[name] != 'function' ? (v.length > 1 ? ',' + quote : quote) + name + quote +':' + serialize(o[name], quote) : ''; } } return v + '}'; } return '' + o; }; tinymce.util.JSON = { serialize: serialize, parse: function(s) { try { return eval('(' + s + ')'); } catch (ex) { // Ignore } } }; })(); tinymce.create('static tinymce.util.XHR', { send : function(o) { var x, t, w = window, c = 0; function ready() { if (!o.async || x.readyState == 4 || c++ > 10000) { if (o.success && c < 10000 && x.status == 200) o.success.call(o.success_scope, '' + x.responseText, x, o); else if (o.error) o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o); x = null; } else w.setTimeout(ready, 10); }; // Default settings o.scope = o.scope || this; o.success_scope = o.success_scope || o.scope; o.error_scope = o.error_scope || o.scope; o.async = o.async === false ? false : true; o.data = o.data || ''; function get(s) { x = 0; try { x = new ActiveXObject(s); } catch (ex) { } return x; }; x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP'); if (x) { if (x.overrideMimeType) x.overrideMimeType(o.content_type); x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async); if (o.content_type) x.setRequestHeader('Content-Type', o.content_type); x.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); x.send(o.data); // Syncronous request if (!o.async) return ready(); // Wait for response, onReadyStateChange can not be used since it leaks memory in IE t = w.setTimeout(ready, 10); } } }); (function() { var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR; tinymce.create('tinymce.util.JSONRequest', { JSONRequest : function(s) { this.settings = extend({ }, s); this.count = 0; }, send : function(o) { var ecb = o.error, scb = o.success; o = extend(this.settings, o); o.success = function(c, x) { c = JSON.parse(c); if (typeof(c) == 'undefined') { c = { error : 'JSON Parse error.' }; } if (c.error) ecb.call(o.error_scope || o.scope, c.error, x); else scb.call(o.success_scope || o.scope, c.result); }; o.error = function(ty, x) { if (ecb) ecb.call(o.error_scope || o.scope, ty, x); }; o.data = JSON.serialize({ id : o.id || 'c' + (this.count++), method : o.method, params : o.params }); // JSON content type for Ruby on rails. Bug: #1883287 o.content_type = 'application/json'; XHR.send(o); }, 'static' : { sendRPC : function(o) { return new tinymce.util.JSONRequest().send(o); } } }); }()); (function(tinymce){ tinymce.VK = { BACKSPACE: 8, DELETE: 46, DOWN: 40, ENTER: 13, LEFT: 37, RIGHT: 39, SPACEBAR: 32, TAB: 9, UP: 38, modifierPressed: function (e) { return e.shiftKey || e.ctrlKey || e.altKey; }, metaKeyPressed: function(e) { // Check if ctrl or meta key is pressed also check if alt is false for Polish users return tinymce.isMac ? e.metaKey : e.ctrlKey && !e.altKey; } }; })(tinymce); tinymce.util.Quirks = function(editor) { var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, settings = editor.settings, parser = editor.parser, serializer = editor.serializer, each = tinymce.each; function setEditorCommandState(cmd, state) { try { editor.getDoc().execCommand(cmd, false, state); } catch (ex) { // Ignore } } function getDocumentMode() { var documentMode = editor.getDoc().documentMode; return documentMode ? documentMode : 6; }; function isDefaultPrevented(e) { return e.isDefaultPrevented(); }; function cleanupStylesWhenDeleting() { function removeMergedFormatSpans(isDelete) { var rng, blockElm, node, clonedSpan; rng = selection.getRng(); // Find root block blockElm = dom.getParent(rng.startContainer, dom.isBlock); // On delete clone the root span of the next block element if (isDelete) { blockElm = dom.getNext(blockElm, dom.isBlock); } // Locate root span element and clone it since it would otherwise get merged by the "apple-style-span" on delete/backspace if (blockElm) { node = blockElm.firstChild; // Ignore empty text nodes while (node && node.nodeType == 3 && node.nodeValue.length === 0) { node = node.nextSibling; } if (node && node.nodeName === 'SPAN') { clonedSpan = node.cloneNode(false); } } each(dom.select('span', blockElm), function(span) { span.setAttribute('data-mce-mark', '1'); }); // Do the backspace/delete action editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null); // Find all odd apple-style-spans blockElm = dom.getParent(rng.startContainer, dom.isBlock); each(dom.select('span', blockElm), function(span) { var bm = selection.getBookmark(); if (clonedSpan) { dom.replace(clonedSpan.cloneNode(false), span, true); } else if (!span.getAttribute('data-mce-mark')) { dom.remove(span, true); } else { span.removeAttribute('data-mce-mark'); } // Restore the selection selection.moveToBookmark(bm); }); } editor.onKeyDown.add(function(editor, e) { var isDelete; isDelete = e.keyCode == DELETE; if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) { e.preventDefault(); removeMergedFormatSpans(isDelete); } }); editor.addCommand('Delete', function() {removeMergedFormatSpans();}); }; function emptyEditorWhenDeleting() { function serializeRng(rng) { var body = dom.create("body"); var contents = rng.cloneContents(); body.appendChild(contents); return selection.serializer.serialize(body, {format: 'html'}); } function allContentsSelected(rng) { var selection = serializeRng(rng); var allRng = dom.createRng(); allRng.selectNode(editor.getBody()); var allSelection = serializeRng(allRng); return selection === allSelection; } editor.onKeyDown.add(function(editor, e) { var keyCode = e.keyCode, isCollapsed; // Empty the editor if it's needed for example backspace at <p><b>|</b></p> if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) { isCollapsed = editor.selection.isCollapsed(); // Selection is collapsed but the editor isn't empty if (isCollapsed && !dom.isEmpty(editor.getBody())) { return; } // IE deletes all contents correctly when everything is selected if (tinymce.isIE && !isCollapsed) { return; } // Selection isn't collapsed but not all the contents is selected if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) { return; } // Manually empty the editor editor.setContent(''); editor.selection.setCursorLocation(editor.getBody(), 0); editor.nodeChanged(); } }); }; function selectAll() { editor.onKeyDown.add(function(editor, e) { if (!isDefaultPrevented(e) && e.keyCode == 65 && VK.metaKeyPressed(e)) { e.preventDefault(); editor.execCommand('SelectAll'); } }); }; function inputMethodFocus() { if (!editor.settings.content_editable) { // Case 1 IME doesn't initialize if you focus the document dom.bind(editor.getDoc(), 'focusin', function(e) { selection.setRng(selection.getRng()); }); // Case 2 IME doesn't initialize if you click the documentElement it also doesn't properly fire the focusin event dom.bind(editor.getDoc(), 'mousedown', function(e) { if (e.target == editor.getDoc().documentElement) { editor.getWin().focus(); selection.setRng(selection.getRng()); } }); } }; function removeHrOnBackspace() { editor.onKeyDown.add(function(editor, e) { if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) { if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) { var node = selection.getNode(); var previousSibling = node.previousSibling; if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") { dom.remove(previousSibling); tinymce.dom.Event.cancel(e); } } } }) } function focusBody() { // Fix for a focus bug in FF 3.x where the body element // wouldn't get proper focus if the user clicked on the HTML element if (!Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4 editor.onMouseDown.add(function(editor, e) { if (!isDefaultPrevented(e) && e.target.nodeName === "HTML") { var body = editor.getBody(); // Blur the body it's focused but not correctly focused body.blur(); // Refocus the body after a little while setTimeout(function() { body.focus(); }, 0); } }); } }; function selectControlElements() { editor.onClick.add(function(editor, e) { e = e.target; // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250 // WebKit can't even do simple things like selecting an image // Needs tobe the setBaseAndExtend or it will fail to select floated images if (/^(IMG|HR)$/.test(e.nodeName)) { selection.getSel().setBaseAndExtent(e, 0, e, 1); } if (e.nodeName == 'A' && dom.hasClass(e, 'mceItemAnchor')) { selection.select(e); } editor.nodeChanged(); }); }; function removeStylesWhenDeletingAccrossBlockElements() { function getAttributeApplyFunction() { var template = dom.getAttribs(selection.getStart().cloneNode(false)); return function() { var target = selection.getStart(); if (target !== editor.getBody()) { dom.setAttrib(target, "style", null); each(template, function(attr) { target.setAttributeNode(attr.cloneNode(true)); }); } }; } function isSelectionAcrossElements() { return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) != dom.getParent(selection.getEnd(), dom.isBlock); } function blockEvent(editor, e) { e.preventDefault(); return false; } editor.onKeyPress.add(function(editor, e) { var applyAttributes; if (!isDefaultPrevented(e) && (e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) { applyAttributes = getAttributeApplyFunction(); editor.getDoc().execCommand('delete', false, null); applyAttributes(); e.preventDefault(); return false; } }); dom.bind(editor.getDoc(), 'cut', function(e) { var applyAttributes; if (!isDefaultPrevented(e) && isSelectionAcrossElements()) { applyAttributes = getAttributeApplyFunction(); editor.onKeyUp.addToTop(blockEvent); setTimeout(function() { applyAttributes(); editor.onKeyUp.remove(blockEvent); }, 0); } }); } function selectionChangeNodeChanged() { var lastRng, selectionTimer; dom.bind(editor.getDoc(), 'selectionchange', function() { if (selectionTimer) { clearTimeout(selectionTimer); selectionTimer = 0; } selectionTimer = window.setTimeout(function() { var rng = selection.getRng(); // Compare the ranges to see if it was a real change or not if (!lastRng || !tinymce.dom.RangeUtils.compareRanges(rng, lastRng)) { editor.nodeChanged(); lastRng = rng; } }, 50); }); } function ensureBodyHasRoleApplication() { document.body.setAttribute("role", "application"); } function disableBackspaceIntoATable() { editor.onKeyDown.add(function(editor, e) { if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) { if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) { var previousSibling = selection.getNode().previousSibling; if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") { return tinymce.dom.Event.cancel(e); } } } }) } function addNewLinesBeforeBrInPre() { // IE8+ rendering mode does the right thing with BR in PRE if (getDocumentMode() > 7) { return; } // Enable display: none in area and add a specific class that hides all BR elements in PRE to // avoid the caret from getting stuck at the BR elements while pressing the right arrow key setEditorCommandState('RespectVisibilityInDesign', true); editor.contentStyles.push('.mceHideBrInPre pre br {display: none}'); dom.addClass(editor.getBody(), 'mceHideBrInPre'); // Adds a \n before all BR elements in PRE to get them visual parser.addNodeFilter('pre', function(nodes, name) { var i = nodes.length, brNodes, j, brElm, sibling; while (i--) { brNodes = nodes[i].getAll('br'); j = brNodes.length; while (j--) { brElm = brNodes[j]; // Add \n before BR in PRE elements on older IE:s so the new lines get rendered sibling = brElm.prev; if (sibling && sibling.type === 3 && sibling.value.charAt(sibling.value - 1) != '\n') { sibling.value += '\n'; } else { brElm.parent.insert(new tinymce.html.Node('#text', 3), brElm, true).value = '\n'; } } } }); // Removes any \n before BR elements in PRE since other browsers and in contentEditable=false mode they will be visible serializer.addNodeFilter('pre', function(nodes, name) { var i = nodes.length, brNodes, j, brElm, sibling; while (i--) { brNodes = nodes[i].getAll('br'); j = brNodes.length; while (j--) { brElm = brNodes[j]; sibling = brElm.prev; if (sibling && sibling.type == 3) { sibling.value = sibling.value.replace(/\r?\n$/, ''); } } } }); } function removePreSerializedStylesWhenSelectingControls() { dom.bind(editor.getBody(), 'mouseup', function(e) { var value, node = selection.getNode(); // Moved styles to attributes on IMG eements if (node.nodeName == 'IMG') { // Convert style width to width attribute if (value = dom.getStyle(node, 'width')) { dom.setAttrib(node, 'width', value.replace(/[^0-9%]+/g, '')); dom.setStyle(node, 'width', ''); } // Convert style height to height attribute if (value = dom.getStyle(node, 'height')) { dom.setAttrib(node, 'height', value.replace(/[^0-9%]+/g, '')); dom.setStyle(node, 'height', ''); } } }); } function keepInlineElementOnDeleteBackspace() { editor.onKeyDown.add(function(editor, e) { var isDelete, rng, container, offset, brElm, sibling, collapsed; isDelete = e.keyCode == DELETE; if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) { rng = selection.getRng(); container = rng.startContainer; offset = rng.startOffset; collapsed = rng.collapsed; // Override delete if the start container is a text node and is at the beginning of text or // just before/after the last character to be deleted in collapsed mode if (container.nodeType == 3 && container.nodeValue.length > 0 && ((offset === 0 && !collapsed) || (collapsed && offset === (isDelete ? 0 : 1)))) { nonEmptyElements = editor.schema.getNonEmptyElements(); // Prevent default logic since it's broken e.preventDefault(); // Insert a BR before the text node this will prevent the containing element from being deleted/converted brElm = dom.create('br', {id: '__tmp'}); container.parentNode.insertBefore(brElm, container); // Do the browser delete editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null); // Check if the previous sibling is empty after deleting for example: <p><b></b>|</p> container = selection.getRng().startContainer; sibling = container.previousSibling; if (sibling && sibling.nodeType == 1 && !dom.isBlock(sibling) && dom.isEmpty(sibling) && !nonEmptyElements[sibling.nodeName.toLowerCase()]) { dom.remove(sibling); } // Remove the temp element we inserted dom.remove('__tmp'); } } }); } function removeBlockQuoteOnBackSpace() { // Add block quote deletion handler editor.onKeyDown.add(function(editor, e) { var rng, container, offset, root, parent; if (isDefaultPrevented(e) || e.keyCode != VK.BACKSPACE) { return; } rng = selection.getRng(); container = rng.startContainer; offset = rng.startOffset; root = dom.getRoot(); parent = container; if (!rng.collapsed || offset !== 0) { return; } while (parent && parent.parentNode && parent.parentNode.firstChild == parent && parent.parentNode != root) { parent = parent.parentNode; } // Is the cursor at the beginning of a blockquote? if (parent.tagName === 'BLOCKQUOTE') { // Remove the blockquote editor.formatter.toggle('blockquote', null, parent); // Move the caret to the beginning of container rng = dom.createRng(); rng.setStart(container, 0); rng.setEnd(container, 0); selection.setRng(rng); } }); }; function setGeckoEditingOptions() { function setOpts() { editor._refreshContentEditable(); setEditorCommandState("StyleWithCSS", false); setEditorCommandState("enableInlineTableEditing", false); if (!settings.object_resizing) { setEditorCommandState("enableObjectResizing", false); } }; if (!settings.readonly) { editor.onBeforeExecCommand.add(setOpts); editor.onMouseDown.add(setOpts); } }; function addBrAfterLastLinks() { function fixLinks(editor, o) { each(dom.select('a'), function(node) { var parentNode = node.parentNode, root = dom.getRoot(); if (parentNode.lastChild === node) { while (parentNode && !dom.isBlock(parentNode)) { if (parentNode.parentNode.lastChild !== parentNode || parentNode === root) { return; } parentNode = parentNode.parentNode; } dom.add(parentNode, 'br', {'data-mce-bogus' : 1}); } }); }; editor.onExecCommand.add(function(editor, cmd) { if (cmd === 'CreateLink') { fixLinks(editor); } }); editor.onSetContent.add(selection.onSetContent.add(fixLinks)); }; function setDefaultBlockType() { if (settings.forced_root_block) { editor.onInit.add(function() { setEditorCommandState('DefaultParagraphSeparator', settings.forced_root_block); }); } } function removeGhostSelection() { function repaint(sender, args) { if (!sender || !args.initial) { editor.execCommand('mceRepaint'); } }; editor.onUndo.add(repaint); editor.onRedo.add(repaint); editor.onSetContent.add(repaint); }; function deleteControlItemOnBackSpace() { editor.onKeyDown.add(function(editor, e) { var rng; if (!isDefaultPrevented(e) && e.keyCode == BACKSPACE) { rng = editor.getDoc().selection.createRange(); if (rng && rng.item) { e.preventDefault(); editor.undoManager.beforeChange(); dom.remove(rng.item(0)); editor.undoManager.add(); } } }); }; function renderEmptyBlocksFix() { var emptyBlocksCSS; // IE10+ if (getDocumentMode() >= 10) { emptyBlocksCSS = ''; each('p div h1 h2 h3 h4 h5 h6'.split(' '), function(name, i) { emptyBlocksCSS += (i > 0 ? ',' : '') + name + ':empty'; }); editor.contentStyles.push(emptyBlocksCSS + '{padding-right: 1px !important}'); } }; function fakeImageResize() { var selectedElmX, selectedElmY, selectedElm, selectedElmGhost, selectedHandle, startX, startY, startW, startH, ratio, resizeHandles, width, height, rootDocument = document, editableDoc = editor.getDoc(); if (!settings.object_resizing || settings.webkit_fake_resize === false) { return; } // Try disabling object resizing if WebKit implements resizing in the future setEditorCommandState("enableObjectResizing", false); // Details about each resize handle how to scale etc resizeHandles = { // Name: x multiplier, y multiplier, delta size x, delta size y n: [.5, 0, 0, -1], e: [1, .5, 1, 0], s: [.5, 1, 0, 1], w: [0, .5, -1, 0], nw: [0, 0, -1, -1], ne: [1, 0, 1, -1], se: [1, 1, 1, 1], sw : [0, 1, -1, 1] }; function resizeElement(e) { var deltaX, deltaY; // Calc new width/height deltaX = e.screenX - startX; deltaY = e.screenY - startY; // Calc new size width = deltaX * selectedHandle[2] + startW; height = deltaY * selectedHandle[3] + startH; // Never scale down lower than 5 pixels width = width < 5 ? 5 : width; height = height < 5 ? 5 : height; // Constrain proportions when modifier key is pressed or if the nw, ne, sw, se corners are moved on an image if (VK.modifierPressed(e) || (selectedElm.nodeName == "IMG" && selectedHandle[2] * selectedHandle[3] !== 0)) { width = Math.round(height / ratio); height = Math.round(width * ratio); } // Update ghost size dom.setStyles(selectedElmGhost, { width: width, height: height }); // Update ghost X position if needed if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) { dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width)); } // Update ghost Y position if needed if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) { dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height)); } } function endResize() { function setSizeProp(name, value) { if (value) { // Resize by using style or attribute if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) { dom.setStyle(selectedElm, name, value); } else { dom.setAttrib(selectedElm, name, value); } } } // Set width/height properties setSizeProp('width', width); setSizeProp('height', height); dom.unbind(editableDoc, 'mousemove', resizeElement); dom.unbind(editableDoc, 'mouseup', endResize); if (rootDocument != editableDoc) { dom.unbind(rootDocument, 'mousemove', resizeElement); dom.unbind(rootDocument, 'mouseup', endResize); } // Remove ghost and update resize handle positions dom.remove(selectedElmGhost); showResizeRect(selectedElm); } function showResizeRect(targetElm) { var position, targetWidth, targetHeight; hideResizeRect(); // Get position and size of target position = dom.getPos(targetElm); selectedElmX = position.x; selectedElmY = position.y; targetWidth = targetElm.offsetWidth; targetHeight = targetElm.offsetHeight; // Reset width/height if user selects a new image/table if (selectedElm != targetElm) { selectedElm = targetElm; width = height = 0; } each(resizeHandles, function(handle, name) { var handleElm; // Get existing or render resize handle handleElm = dom.get('mceResizeHandle' + name); if (!handleElm) { handleElm = dom.add(editableDoc.documentElement, 'div', { id: 'mceResizeHandle' + name, 'class': 'mceResizeHandle', style: 'cursor:' + name + '-resize; margin:0; padding:0' }); dom.bind(handleElm, 'mousedown', function(e) { e.preventDefault(); endResize(); startX = e.screenX; startY = e.screenY; startW = selectedElm.clientWidth; startH = selectedElm.clientHeight; ratio = startH / startW; selectedHandle = handle; selectedElmGhost = selectedElm.cloneNode(true); dom.addClass(selectedElmGhost, 'mceClonedResizable'); dom.setStyles(selectedElmGhost, { left: selectedElmX, top: selectedElmY, margin: 0 }); editableDoc.documentElement.appendChild(selectedElmGhost); dom.bind(editableDoc, 'mousemove', resizeElement); dom.bind(editableDoc, 'mouseup', endResize); if (rootDocument != editableDoc) { dom.bind(rootDocument, 'mousemove', resizeElement); dom.bind(rootDocument, 'mouseup', endResize); } }); } else { dom.show(handleElm); } // Position element dom.setStyles(handleElm, { left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2), top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2) }); }); // Only add resize rectangle on WebKit and only on images if (!tinymce.isOpera && selectedElm.nodeName == "IMG") { selectedElm.setAttribute('data-mce-selected', '1'); } } function hideResizeRect() { if (selectedElm) { selectedElm.removeAttribute('data-mce-selected'); } for (var name in resizeHandles) { dom