UNPKG

processmaker-builder

Version:

The gulp task runner for ProcessMaker building

1,976 lines (1,545 loc) 524 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.7', releaseDate : '2012-09-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://site.com or http://site.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; }, map : function(a, f) { var o = []; tinymce.each(a, function(v) { o.push(f(v)); }); return o; }, grep : function(a, f) { var o = []; tinymce.each(a, function(v) { if (!f || f(v)) o.push(v); }); return o; }, inArray : function(a, v) { var i, l; if (a) { for (i = 0, l = a.length; i < l; i++) { if (a[i] === v) return i; } } return -1; }, extend : function(obj, ext) { var i, l, name, args = arguments, value; for (i = 1, l = args.length; i < l; i++) { ext = args[i]; for (name in ext) { if (ext.hasOwnProperty(name)) { value = ext[name]; if (value !== undef) { obj[name] = value; } } } } return obj; }, 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); 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; 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); } } // 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); tinymce.each(dom.select('span.Apple-style-span,font.Apple-style-span', blockElm), function(span) { var bm = selection.getBookmark(); if (clonedSpan) { dom.replace(clonedSpan.cloneNode(false), span, true); } else { dom.remove(span, true); } // 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); tinymce.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) { tinymce.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 = ''; tinymce.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; } tinymce.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.hide('mceResizeHandle' + name); } } // Add CSS for resize handles, cloned element and selected editor.contentStyles.push( '.mceResizeHandle {' + 'position: absolute;' + 'border: 1px solid black;' + 'background: #FFF;' + 'width: 5px;' + 'height: 5px;' + 'z-index: 10000' + '}' + '.mceResizeHandle:hover {' + 'background: #000' + '}' + 'img[data-mce-selected] {' + 'outline: 1px solid black' + '}' + 'img.mceClonedResizable, table.mceClonedResizable {' + 'position: absolute;' + 'outline: 1px dashed black;' + 'opacity: .5;' + 'z-index: 10000' + '}' ); function updateResizeRect() { var controlElm = dom.getParent(selection.getNode(), 'table,img'); // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v tinymce.each(dom.select('img[data-mce-selected]'), function(img) { img.removeAttribute('data-mce-selected'); }); if (controlElm) { showResizeRect(controlElm); } else { hideResizeRect(); } } // Show/hide resize rect when image is selected editor.onNodeChange.add(updateResizeRect); // Fixes WebKit quirk where it returns IMG on getNode if caret is after last image in container dom.bind(editableDoc, 'selectionchange', updateResizeRect); // Remove the internal attribute when serializing the DOM editor.serializer.addAttributeFilter('data-mce-selected', function(nodes, name) { var i = nodes.length; while (i--) { nodes[i].attr(name, null); } }); } function keepNoScriptContents() { if (getDocumentMode() < 9) { parser.addNodeFilter('noscript', function(nodes) { var i = nodes.length, node, textNode; while (i--) { node = nodes[i]; textNode = node.firstChild; if (textNode) { node.attr('data-mce-innertext', textNode.value); } } }); serializer.addNodeFilter('noscript', function(nodes) { var i = nodes.length, node, textNode, value; while (i--) { node = nodes[i]; textNode = nodes[i].firstChild; if (textNode) { textNode.value = tinymce.html.Entities.decode(textNode.value); } else { // Old IE can't retain noscript value so an attribute is used to store it value = node.attributes.map['data-mce-innertext']; if (value) { node.attr('data-mce-innertext', null); textNode = new tinymce.html.Node('#text', 3); textNode.value = value; textNode.raw = true; node.append(textNode); } } } }); } } // All browsers disableBackspaceIntoATable(); removeBlockQuoteOnBackSpace(); emptyEditorWhenDeleting(); // WebKit if (tinymce.isWebKit) { keepInlineElementOnDeleteBackspace(); cleanupStylesWhenDeleting(); inputMethodFocus(); selectControlElements(); setDefaultBlockType(); // iOS if (tinymce.isIDevice) { selectionChangeNodeChanged(); } else { fakeImageResize(); selectAll(); } } // IE if (tinymce.isIE) { removeHrOnBackspace(); ensureBodyHasRoleApplication(); addNewLinesBeforeBrInPre(); removePreSerializedStylesWhenSelectingControls(); deleteControlItemOnBackSpace(); renderEmptyBlocksFix(); keepNoScriptContents(); } // Gecko if (tinymce.isGecko) { removeHrOnBackspace(); focusBody(); removeStylesWhenDeletingAccrossBlockElements(); setGeckoEditingOptions(); addBrAfterLastLinks(); removeGhostSelection(); } // Opera if (tinymce.isOpera) { fakeImageResize(); } }; (function(tinymce) { var namedEntities, baseEntities, reverseEntities, attrsCharsRegExp = /[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, rawCharsRegExp = /[<>&\"\']/g, entityRegExp = /&(#x|#)?([\w]+);/g, asciiMap = { 128 : "\u20AC", 130 : "\u201A", 131 : "\u0192", 132 : "\u201E", 133 : "\u2026", 134 : "\u2020", 135 : "\u2021", 136 : "\u02C6", 137 : "\u2030", 138 : "\u0160", 139 : "\u2039", 140 : "\u0152", 142 : "\u017D", 145 : "\u2018", 146 : "\u2019", 147 : "\u201C", 148 : "\u201D", 149 : "\u2022", 150 : "\u2013", 151 : "\u2014", 152 : "\u02DC", 153 : "\u2122", 154 : "\u0161", 155 : "\u203A", 156 : "\u0153", 158 : "\u017E", 159