bgneal@183: (function(win) {
bgneal@183: var whiteSpaceRe = /^\s*|\s*$/g,
bgneal@183: undefined;
bgneal@183:
bgneal@183: var tinymce = {
bgneal@183: majorVersion : '3',
bgneal@183:
bgneal@183: minorVersion : '3.2',
bgneal@183:
bgneal@183: releaseDate : '2010-03-25',
bgneal@183:
bgneal@183: _init : function() {
bgneal@183: var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
bgneal@183:
bgneal@183: t.isOpera = win.opera && opera.buildNumber;
bgneal@183:
bgneal@183: t.isWebKit = /WebKit/.test(ua);
bgneal@183:
bgneal@183: t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
bgneal@183:
bgneal@183: t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
bgneal@183:
bgneal@183: t.isGecko = !t.isWebKit && /Gecko/.test(ua);
bgneal@183:
bgneal@183: t.isMac = ua.indexOf('Mac') != -1;
bgneal@183:
bgneal@183: t.isAir = /adobeair/i.test(ua);
bgneal@183:
bgneal@183: // TinyMCE .NET webcontrol might be setting the values for TinyMCE
bgneal@183: if (win.tinyMCEPreInit) {
bgneal@183: t.suffix = tinyMCEPreInit.suffix;
bgneal@183: t.baseURL = tinyMCEPreInit.base;
bgneal@183: t.query = tinyMCEPreInit.query;
bgneal@45: return;
bgneal@183: }
bgneal@183:
bgneal@183: // Get suffix and base
bgneal@183: t.suffix = '';
bgneal@183:
bgneal@183: // If base element found, add that infront of baseURL
bgneal@183: nl = d.getElementsByTagName('base');
bgneal@183: for (i=0; i :
bgneal@183: s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
bgneal@183: cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
bgneal@183:
bgneal@183: // Create namespace for new class
bgneal@183: ns = t.createNS(s[3].replace(/\.\w+$/, ''));
bgneal@183:
bgneal@183: // Class already exists
bgneal@183: if (ns[cn])
bgneal@183: return;
bgneal@183:
bgneal@183: // Make pure static class
bgneal@183: if (s[2] == 'static') {
bgneal@183: ns[cn] = p;
bgneal@183:
bgneal@183: if (this.onCreate)
bgneal@183: this.onCreate(s[2], s[3], ns[cn]);
bgneal@183:
bgneal@183: return;
bgneal@183: }
bgneal@183:
bgneal@183: // Create default constructor
bgneal@183: if (!p[cn]) {
bgneal@183: p[cn] = function() {};
bgneal@183: de = 1;
bgneal@183: }
bgneal@183:
bgneal@183: // Add constructor and methods
bgneal@183: ns[cn] = p[cn];
bgneal@183: t.extend(ns[cn].prototype, p);
bgneal@183:
bgneal@183: // Extend
bgneal@183: if (s[5]) {
bgneal@183: sp = t.resolve(s[5]).prototype;
bgneal@183: scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
bgneal@183:
bgneal@183: // Extend constructor
bgneal@183: c = ns[cn];
bgneal@183: if (de) {
bgneal@183: // Add passthrough constructor
bgneal@183: ns[cn] = function() {
bgneal@183: return sp[scn].apply(this, arguments);
bgneal@45: };
bgneal@45: } else {
bgneal@183: // Add inherit constructor
bgneal@183: ns[cn] = function() {
bgneal@183: this.parent = sp[scn];
bgneal@183: return c.apply(this, arguments);
bgneal@183: };
bgneal@183: }
bgneal@183: ns[cn].prototype[cn] = ns[cn];
bgneal@183:
bgneal@183: // Add super methods
bgneal@183: t.each(sp, function(f, n) {
bgneal@183: ns[cn].prototype[n] = sp[n];
bgneal@183: });
bgneal@183:
bgneal@183: // Add overridden methods
bgneal@183: t.each(p, function(f, n) {
bgneal@183: // Extend methods if needed
bgneal@183: if (sp[n]) {
bgneal@183: ns[cn].prototype[n] = function() {
bgneal@183: this.parent = sp[n];
bgneal@183: return f.apply(this, arguments);
bgneal@183: };
bgneal@183: } else {
bgneal@183: if (n != cn)
bgneal@183: ns[cn].prototype[n] = f;
bgneal@183: }
bgneal@183: });
bgneal@183: }
bgneal@183:
bgneal@183: // Add static methods
bgneal@183: t.each(p['static'], function(f, n) {
bgneal@183: ns[cn][n] = f;
bgneal@183: });
bgneal@183:
bgneal@183: if (this.onCreate)
bgneal@183: this.onCreate(s[2], s[3], ns[cn].prototype);
bgneal@183: },
bgneal@183:
bgneal@183: walk : function(o, f, n, s) {
bgneal@183: s = s || this;
bgneal@183:
bgneal@183: if (o) {
bgneal@183: if (n)
bgneal@183: o = o[n];
bgneal@183:
bgneal@183: tinymce.each(o, function(o, i) {
bgneal@183: if (f.call(s, o, i, n) === false)
bgneal@183: return false;
bgneal@183:
bgneal@183: tinymce.walk(o, f, n, s);
bgneal@183: });
bgneal@183: }
bgneal@183: },
bgneal@183:
bgneal@183: createNS : function(n, o) {
bgneal@183: var i, v;
bgneal@183:
bgneal@183: o = o || win;
bgneal@183:
bgneal@183: n = n.split('.');
bgneal@183: for (i=0; i= items.length) {
bgneal@45: for (i = 0, l = base.length; i < l; i++) {
bgneal@45: if (i >= items.length || base[i] != items[i]) {
bgneal@45: bp = i + 1;
bgneal@45: break;
bgneal@45: }
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: if (base.length < items.length) {
bgneal@45: for (i = 0, l = items.length; i < l; i++) {
bgneal@45: if (i >= base.length || base[i] != items[i]) {
bgneal@45: bp = i + 1;
bgneal@45: break;
bgneal@45: }
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: if (bp == 1)
bgneal@45: return path;
bgneal@45:
bgneal@45: for (i = 0, l = base.length - (bp - 1); i < l; i++)
bgneal@45: out += "../";
bgneal@45:
bgneal@45: for (i = bp - 1, l = items.length; i < l; i++) {
bgneal@45: if (i != bp - 1)
bgneal@45: out += "/" + items[i];
bgneal@45: else
bgneal@45: out += items[i];
bgneal@45: }
bgneal@45:
bgneal@45: return out;
bgneal@45: },
bgneal@45:
bgneal@45: toAbsPath : function(base, path) {
bgneal@183: var i, nb = 0, o = [], tr, outPath;
bgneal@45:
bgneal@45: // Split paths
bgneal@45: tr = /\/$/.test(path) ? '/' : '';
bgneal@45: base = base.split('/');
bgneal@45: path = path.split('/');
bgneal@45:
bgneal@45: // Remove empty chunks
bgneal@45: each(base, function(k) {
bgneal@45: if (k)
bgneal@45: o.push(k);
bgneal@45: });
bgneal@45:
bgneal@45: base = o;
bgneal@45:
bgneal@45: // Merge relURLParts chunks
bgneal@45: for (i = path.length - 1, o = []; i >= 0; i--) {
bgneal@45: // Ignore empty or .
bgneal@45: if (path[i].length == 0 || path[i] == ".")
bgneal@45: continue;
bgneal@45:
bgneal@45: // Is parent
bgneal@45: if (path[i] == '..') {
bgneal@45: nb++;
bgneal@45: continue;
bgneal@45: }
bgneal@45:
bgneal@45: // Move up
bgneal@45: if (nb > 0) {
bgneal@45: nb--;
bgneal@45: continue;
bgneal@45: }
bgneal@45:
bgneal@45: o.push(path[i]);
bgneal@45: }
bgneal@45:
bgneal@45: i = base.length - nb;
bgneal@45:
bgneal@45: // If /a/b/c or /
bgneal@45: if (i <= 0)
bgneal@183: outPath = o.reverse().join('/');
bgneal@183: else
bgneal@183: outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
bgneal@183:
bgneal@183: // Add front / if it's needed
bgneal@183: if (outPath.indexOf('/') !== 0)
bgneal@183: outPath = '/' + outPath;
bgneal@183:
bgneal@183: // Add traling / if it's needed
bgneal@183: if (tr && outPath.lastIndexOf('/') !== outPath.length - 1)
bgneal@183: outPath += tr;
bgneal@183:
bgneal@183: return outPath;
bgneal@45: },
bgneal@45:
bgneal@45: getURI : function(nh) {
bgneal@45: var s, t = this;
bgneal@45:
bgneal@45: // Rebuild source
bgneal@45: if (!t.source || nh) {
bgneal@45: s = '';
bgneal@45:
bgneal@45: if (!nh) {
bgneal@45: if (t.protocol)
bgneal@45: s += t.protocol + '://';
bgneal@45:
bgneal@45: if (t.userInfo)
bgneal@45: s += t.userInfo + '@';
bgneal@45:
bgneal@45: if (t.host)
bgneal@45: s += t.host;
bgneal@45:
bgneal@45: if (t.port)
bgneal@45: s += ':' + t.port;
bgneal@45: }
bgneal@45:
bgneal@45: if (t.path)
bgneal@45: s += t.path;
bgneal@45:
bgneal@45: if (t.query)
bgneal@45: s += '?' + t.query;
bgneal@45:
bgneal@45: if (t.anchor)
bgneal@45: s += '#' + t.anchor;
bgneal@45:
bgneal@45: t.source = s;
bgneal@45: }
bgneal@45:
bgneal@45: return t.source;
bgneal@45: }
bgneal@183: });
bgneal@45: })();
bgneal@183:
bgneal@45: (function() {
bgneal@45: var each = tinymce.each;
bgneal@45:
bgneal@45: tinymce.create('static tinymce.util.Cookie', {
bgneal@45: getHash : function(n) {
bgneal@45: var v = this.get(n), h;
bgneal@45:
bgneal@45: if (v) {
bgneal@45: each(v.split('&'), function(v) {
bgneal@45: v = v.split('=');
bgneal@45: h = h || {};
bgneal@45: h[unescape(v[0])] = unescape(v[1]);
bgneal@45: });
bgneal@45: }
bgneal@45:
bgneal@45: return h;
bgneal@45: },
bgneal@45:
bgneal@45: setHash : function(n, v, e, p, d, s) {
bgneal@45: var o = '';
bgneal@45:
bgneal@45: each(v, function(v, k) {
bgneal@45: o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
bgneal@45: });
bgneal@45:
bgneal@45: this.set(n, o, e, p, d, s);
bgneal@45: },
bgneal@45:
bgneal@45: get : function(n) {
bgneal@45: var c = document.cookie, e, p = n + "=", b;
bgneal@45:
bgneal@45: // Strict mode
bgneal@45: if (!c)
bgneal@45: return;
bgneal@45:
bgneal@45: b = c.indexOf("; " + p);
bgneal@45:
bgneal@45: if (b == -1) {
bgneal@45: b = c.indexOf(p);
bgneal@45:
bgneal@45: if (b != 0)
bgneal@45: return null;
bgneal@45: } else
bgneal@45: b += 2;
bgneal@45:
bgneal@45: e = c.indexOf(";", b);
bgneal@45:
bgneal@45: if (e == -1)
bgneal@45: e = c.length;
bgneal@45:
bgneal@45: return unescape(c.substring(b + p.length, e));
bgneal@45: },
bgneal@45:
bgneal@45: set : function(n, v, e, p, d, s) {
bgneal@45: document.cookie = n + "=" + escape(v) +
bgneal@45: ((e) ? "; expires=" + e.toGMTString() : "") +
bgneal@45: ((p) ? "; path=" + escape(p) : "") +
bgneal@45: ((d) ? "; domain=" + d : "") +
bgneal@45: ((s) ? "; secure" : "");
bgneal@45: },
bgneal@45:
bgneal@45: remove : function(n, p) {
bgneal@45: var d = new Date();
bgneal@45:
bgneal@45: d.setTime(d.getTime() - 1000);
bgneal@45:
bgneal@45: this.set(n, '', d, p, d);
bgneal@45: }
bgneal@183: });
bgneal@45: })();
bgneal@183:
bgneal@45: tinymce.create('static tinymce.util.JSON', {
bgneal@45: serialize : function(o) {
bgneal@45: var i, v, s = tinymce.util.JSON.serialize, t;
bgneal@45:
bgneal@45: if (o == null)
bgneal@45: return 'null';
bgneal@45:
bgneal@45: t = typeof o;
bgneal@45:
bgneal@45: if (t == 'string') {
bgneal@45: v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
bgneal@45:
bgneal@45: return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) {
bgneal@45: i = v.indexOf(b);
bgneal@45:
bgneal@45: if (i + 1)
bgneal@45: return '\\' + v.charAt(i + 1);
bgneal@45:
bgneal@45: a = b.charCodeAt().toString(16);
bgneal@45:
bgneal@45: return '\\u' + '0000'.substring(a.length) + a;
bgneal@45: }) + '"';
bgneal@45: }
bgneal@45:
bgneal@45: if (t == 'object') {
bgneal@45: if (o.hasOwnProperty && o instanceof Array) {
bgneal@45: for (i=0, v = '['; i 0 ? ',' : '') + s(o[i]);
bgneal@45:
bgneal@45: return v + ']';
bgneal@45: }
bgneal@45:
bgneal@45: v = '{';
bgneal@45:
bgneal@45: for (i in o)
bgneal@45: v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';
bgneal@45:
bgneal@45: return v + '}';
bgneal@45: }
bgneal@45:
bgneal@45: return '' + o;
bgneal@45: },
bgneal@45:
bgneal@45: parse : function(s) {
bgneal@45: try {
bgneal@45: return eval('(' + s + ')');
bgneal@45: } catch (ex) {
bgneal@45: // Ignore
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: });
bgneal@183:
bgneal@45: tinymce.create('static tinymce.util.XHR', {
bgneal@45: send : function(o) {
bgneal@45: var x, t, w = window, c = 0;
bgneal@45:
bgneal@45: // Default settings
bgneal@45: o.scope = o.scope || this;
bgneal@45: o.success_scope = o.success_scope || o.scope;
bgneal@45: o.error_scope = o.error_scope || o.scope;
bgneal@45: o.async = o.async === false ? false : true;
bgneal@45: o.data = o.data || '';
bgneal@45:
bgneal@45: function get(s) {
bgneal@45: x = 0;
bgneal@45:
bgneal@45: try {
bgneal@45: x = new ActiveXObject(s);
bgneal@45: } catch (ex) {
bgneal@45: }
bgneal@45:
bgneal@45: return x;
bgneal@45: };
bgneal@45:
bgneal@45: x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
bgneal@45:
bgneal@45: if (x) {
bgneal@45: if (x.overrideMimeType)
bgneal@45: x.overrideMimeType(o.content_type);
bgneal@45:
bgneal@45: x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
bgneal@45:
bgneal@45: if (o.content_type)
bgneal@45: x.setRequestHeader('Content-Type', o.content_type);
bgneal@45:
bgneal@183: x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
bgneal@183:
bgneal@45: x.send(o.data);
bgneal@45:
bgneal@45: function ready() {
bgneal@45: if (!o.async || x.readyState == 4 || c++ > 10000) {
bgneal@45: if (o.success && c < 10000 && x.status == 200)
bgneal@45: o.success.call(o.success_scope, '' + x.responseText, x, o);
bgneal@45: else if (o.error)
bgneal@45: o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
bgneal@45:
bgneal@45: x = null;
bgneal@45: } else
bgneal@45: w.setTimeout(ready, 10);
bgneal@45: };
bgneal@45:
bgneal@45: // Syncronous request
bgneal@45: if (!o.async)
bgneal@45: return ready();
bgneal@45:
bgneal@45: // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
bgneal@45: t = w.setTimeout(ready, 10);
bgneal@45: }
bgneal@183: }
bgneal@45: });
bgneal@183:
bgneal@45: (function() {
bgneal@45: var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
bgneal@45:
bgneal@45: tinymce.create('tinymce.util.JSONRequest', {
bgneal@45: JSONRequest : function(s) {
bgneal@45: this.settings = extend({
bgneal@45: }, s);
bgneal@45: this.count = 0;
bgneal@45: },
bgneal@45:
bgneal@45: send : function(o) {
bgneal@45: var ecb = o.error, scb = o.success;
bgneal@45:
bgneal@45: o = extend(this.settings, o);
bgneal@45:
bgneal@45: o.success = function(c, x) {
bgneal@45: c = JSON.parse(c);
bgneal@45:
bgneal@45: if (typeof(c) == 'undefined') {
bgneal@45: c = {
bgneal@45: error : 'JSON Parse error.'
bgneal@45: };
bgneal@45: }
bgneal@45:
bgneal@45: if (c.error)
bgneal@45: ecb.call(o.error_scope || o.scope, c.error, x);
bgneal@45: else
bgneal@45: scb.call(o.success_scope || o.scope, c.result);
bgneal@45: };
bgneal@45:
bgneal@45: o.error = function(ty, x) {
bgneal@45: ecb.call(o.error_scope || o.scope, ty, x);
bgneal@45: };
bgneal@45:
bgneal@45: o.data = JSON.serialize({
bgneal@45: id : o.id || 'c' + (this.count++),
bgneal@45: method : o.method,
bgneal@45: params : o.params
bgneal@45: });
bgneal@45:
bgneal@45: // JSON content type for Ruby on rails. Bug: #1883287
bgneal@45: o.content_type = 'application/json';
bgneal@45:
bgneal@45: XHR.send(o);
bgneal@45: },
bgneal@45:
bgneal@45: 'static' : {
bgneal@45: sendRPC : function(o) {
bgneal@45: return new tinymce.util.JSONRequest().send(o);
bgneal@45: }
bgneal@45: }
bgneal@183: });
bgneal@183: }());
bgneal@183: (function(tinymce) {
bgneal@45: // Shorten names
bgneal@183: var each = tinymce.each,
bgneal@183: is = tinymce.is,
bgneal@183: isWebKit = tinymce.isWebKit,
bgneal@183: isIE = tinymce.isIE,
bgneal@183: blockRe = /^(H[1-6R]|P|DIV|ADDRESS|PRE|FORM|T(ABLE|BODY|HEAD|FOOT|H|R|D)|LI|OL|UL|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|NOSCRIPT|MENU|ISINDEX|SAMP)$/,
bgneal@183: boolAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'),
bgneal@183: mceAttribs = makeMap('src,href,style,coords,shape'),
bgneal@183: encodedChars = {'&' : '&', '"' : '"', '<' : '<', '>' : '>'},
bgneal@183: encodeCharsRe = /[<>&\"]/g,
bgneal@183: simpleSelectorRe = /^([a-z0-9],?)+$/i,
bgneal@183: tagRegExp = /<(\w+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)(\s*\/?)>/g,
bgneal@183: attrRegExp = /(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
bgneal@183:
bgneal@183: function makeMap(str) {
bgneal@183: var map = {}, i;
bgneal@183:
bgneal@183: str = str.split(',');
bgneal@183: for (i = str.length; i >= 0; i--)
bgneal@183: map[str[i]] = 1;
bgneal@183:
bgneal@183: return map;
bgneal@183: };
bgneal@45:
bgneal@45: tinymce.create('tinymce.dom.DOMUtils', {
bgneal@45: doc : null,
bgneal@45: root : null,
bgneal@45: files : null,
bgneal@45: pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,
bgneal@45: props : {
bgneal@45: "for" : "htmlFor",
bgneal@45: "class" : "className",
bgneal@45: className : "className",
bgneal@45: checked : "checked",
bgneal@45: disabled : "disabled",
bgneal@45: maxlength : "maxLength",
bgneal@45: readonly : "readOnly",
bgneal@45: selected : "selected",
bgneal@45: value : "value",
bgneal@45: id : "id",
bgneal@45: name : "name",
bgneal@45: type : "type"
bgneal@45: },
bgneal@45:
bgneal@45: DOMUtils : function(d, s) {
bgneal@183: var t = this, globalStyle;
bgneal@45:
bgneal@45: t.doc = d;
bgneal@45: t.win = window;
bgneal@45: t.files = {};
bgneal@45: t.cssFlicker = false;
bgneal@45: t.counter = 0;
bgneal@45: t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat";
bgneal@45: t.stdMode = d.documentMode === 8;
bgneal@45:
bgneal@183: t.settings = s = tinymce.extend({
bgneal@45: keep_values : false,
bgneal@45: hex_colors : 1,
bgneal@45: process_html : 1
bgneal@45: }, s);
bgneal@45:
bgneal@45: // Fix IE6SP2 flicker and check it failed for pre SP2
bgneal@45: if (tinymce.isIE6) {
bgneal@45: try {
bgneal@45: d.execCommand('BackgroundImageCache', false, true);
bgneal@45: } catch (e) {
bgneal@45: t.cssFlicker = true;
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@183: // Build styles list
bgneal@183: if (s.valid_styles) {
bgneal@183: t._styles = {};
bgneal@183:
bgneal@183: // Convert styles into a rule list
bgneal@183: each(s.valid_styles, function(value, key) {
bgneal@183: t._styles[key] = tinymce.explode(value);
bgneal@183: });
bgneal@183: }
bgneal@183:
bgneal@45: tinymce.addUnload(t.destroy, t);
bgneal@45: },
bgneal@45:
bgneal@45: getRoot : function() {
bgneal@45: var t = this, s = t.settings;
bgneal@45:
bgneal@45: return (s && t.get(s.root_element)) || t.doc.body;
bgneal@45: },
bgneal@45:
bgneal@45: getViewPort : function(w) {
bgneal@45: var d, b;
bgneal@45:
bgneal@45: w = !w ? this.win : w;
bgneal@45: d = w.document;
bgneal@45: b = this.boxModel ? d.documentElement : d.body;
bgneal@45:
bgneal@45: // Returns viewport size excluding scrollbars
bgneal@45: return {
bgneal@45: x : w.pageXOffset || b.scrollLeft,
bgneal@45: y : w.pageYOffset || b.scrollTop,
bgneal@45: w : w.innerWidth || b.clientWidth,
bgneal@45: h : w.innerHeight || b.clientHeight
bgneal@45: };
bgneal@45: },
bgneal@45:
bgneal@45: getRect : function(e) {
bgneal@45: var p, t = this, sr;
bgneal@45:
bgneal@45: e = t.get(e);
bgneal@45: p = t.getPos(e);
bgneal@45: sr = t.getSize(e);
bgneal@45:
bgneal@45: return {
bgneal@45: x : p.x,
bgneal@45: y : p.y,
bgneal@45: w : sr.w,
bgneal@45: h : sr.h
bgneal@45: };
bgneal@45: },
bgneal@45:
bgneal@45: getSize : function(e) {
bgneal@45: var t = this, w, h;
bgneal@45:
bgneal@45: e = t.get(e);
bgneal@45: w = t.getStyle(e, 'width');
bgneal@45: h = t.getStyle(e, 'height');
bgneal@45:
bgneal@45: // Non pixel value, then force offset/clientWidth
bgneal@45: if (w.indexOf('px') === -1)
bgneal@45: w = 0;
bgneal@45:
bgneal@45: // Non pixel value, then force offset/clientWidth
bgneal@45: if (h.indexOf('px') === -1)
bgneal@45: h = 0;
bgneal@45:
bgneal@45: return {
bgneal@45: w : parseInt(w) || e.offsetWidth || e.clientWidth,
bgneal@45: h : parseInt(h) || e.offsetHeight || e.clientHeight
bgneal@45: };
bgneal@45: },
bgneal@45:
bgneal@45: getParent : function(n, f, r) {
bgneal@45: return this.getParents(n, f, r, false);
bgneal@45: },
bgneal@45:
bgneal@45: getParents : function(n, f, r, c) {
bgneal@45: var t = this, na, se = t.settings, o = [];
bgneal@45:
bgneal@45: n = t.get(n);
bgneal@45: c = c === undefined;
bgneal@45:
bgneal@45: if (se.strict_root)
bgneal@45: r = r || t.getRoot();
bgneal@45:
bgneal@45: // Wrap node name as func
bgneal@45: if (is(f, 'string')) {
bgneal@45: na = f;
bgneal@45:
bgneal@45: if (f === '*') {
bgneal@45: f = function(n) {return n.nodeType == 1;};
bgneal@45: } else {
bgneal@45: f = function(n) {
bgneal@45: return t.is(n, na);
bgneal@45: };
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: while (n) {
bgneal@183: if (n == r || !n.nodeType || n.nodeType === 9)
bgneal@45: break;
bgneal@45:
bgneal@45: if (!f || f(n)) {
bgneal@45: if (c)
bgneal@45: o.push(n);
bgneal@45: else
bgneal@45: return n;
bgneal@45: }
bgneal@45:
bgneal@45: n = n.parentNode;
bgneal@45: }
bgneal@45:
bgneal@45: return c ? o : null;
bgneal@45: },
bgneal@45:
bgneal@45: get : function(e) {
bgneal@45: var n;
bgneal@45:
bgneal@45: if (e && this.doc && typeof(e) == 'string') {
bgneal@45: n = e;
bgneal@45: e = this.doc.getElementById(e);
bgneal@45:
bgneal@45: // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
bgneal@45: if (e && e.id !== n)
bgneal@45: return this.doc.getElementsByName(n)[1];
bgneal@45: }
bgneal@45:
bgneal@45: return e;
bgneal@45: },
bgneal@45:
bgneal@183: getNext : function(node, selector) {
bgneal@183: return this._findSib(node, selector, 'nextSibling');
bgneal@183: },
bgneal@183:
bgneal@183: getPrev : function(node, selector) {
bgneal@183: return this._findSib(node, selector, 'previousSibling');
bgneal@183: },
bgneal@183:
bgneal@45:
bgneal@45: select : function(pa, s) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []);
bgneal@45: },
bgneal@45:
bgneal@183: is : function(n, selector) {
bgneal@183: var i;
bgneal@183:
bgneal@183: // If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance
bgneal@183: if (n.length === undefined) {
bgneal@183: // Simple all selector
bgneal@183: if (selector === '*')
bgneal@183: return n.nodeType == 1;
bgneal@183:
bgneal@183: // Simple selector just elements
bgneal@183: if (simpleSelectorRe.test(selector)) {
bgneal@183: selector = selector.toLowerCase().split(/,/);
bgneal@183: n = n.nodeName.toLowerCase();
bgneal@183:
bgneal@183: for (i = selector.length - 1; i >= 0; i--) {
bgneal@183: if (selector[i] == n)
bgneal@183: return true;
bgneal@183: }
bgneal@183:
bgneal@183: return false;
bgneal@183: }
bgneal@183: }
bgneal@183:
bgneal@183: return tinymce.dom.Sizzle.matches(selector, n.nodeType ? [n] : n).length > 0;
bgneal@183: },
bgneal@183:
bgneal@45:
bgneal@45: add : function(p, n, a, h, c) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: return this.run(p, function(p) {
bgneal@45: var e, k;
bgneal@45:
bgneal@45: e = is(n, 'string') ? t.doc.createElement(n) : n;
bgneal@45: t.setAttribs(e, a);
bgneal@45:
bgneal@45: if (h) {
bgneal@45: if (h.nodeType)
bgneal@45: e.appendChild(h);
bgneal@45: else
bgneal@45: t.setHTML(e, h);
bgneal@45: }
bgneal@45:
bgneal@45: return !c ? p.appendChild(e) : e;
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: create : function(n, a, h) {
bgneal@45: return this.add(this.doc.createElement(n), n, a, h, 1);
bgneal@45: },
bgneal@45:
bgneal@45: createHTML : function(n, a, h) {
bgneal@45: var o = '', t = this, k;
bgneal@45:
bgneal@45: o += '<' + n;
bgneal@45:
bgneal@45: for (k in a) {
bgneal@45: if (a.hasOwnProperty(k))
bgneal@45: o += ' ' + k + '="' + t.encode(a[k]) + '"';
bgneal@45: }
bgneal@45:
bgneal@45: if (tinymce.is(h))
bgneal@45: return o + '>' + h + '' + n + '>';
bgneal@45:
bgneal@45: return o + ' />';
bgneal@45: },
bgneal@45:
bgneal@183: remove : function(node, keep_children) {
bgneal@183: return this.run(node, function(node) {
bgneal@183: var parent, child;
bgneal@183:
bgneal@183: parent = node.parentNode;
bgneal@183:
bgneal@183: if (!parent)
bgneal@45: return null;
bgneal@45:
bgneal@183: if (keep_children) {
bgneal@183: while (child = node.firstChild) {
bgneal@183: // IE 8 will crash if you don't remove completely empty text nodes
bgneal@183: if (child.nodeType !== 3 || child.nodeValue)
bgneal@183: parent.insertBefore(child, node);
bgneal@183: else
bgneal@183: node.removeChild(child);
bgneal@183: }
bgneal@183: }
bgneal@183:
bgneal@183: return parent.removeChild(node);
bgneal@183: });
bgneal@183: },
bgneal@45:
bgneal@45: setStyle : function(n, na, v) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: return t.run(n, function(e) {
bgneal@45: var s, i;
bgneal@45:
bgneal@45: s = e.style;
bgneal@45:
bgneal@45: // Camelcase it, if needed
bgneal@45: na = na.replace(/-(\D)/g, function(a, b){
bgneal@45: return b.toUpperCase();
bgneal@45: });
bgneal@45:
bgneal@45: // Default px suffix on these
bgneal@45: if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))
bgneal@45: v += 'px';
bgneal@45:
bgneal@45: switch (na) {
bgneal@45: case 'opacity':
bgneal@45: // IE specific opacity
bgneal@45: if (isIE) {
bgneal@45: s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
bgneal@45:
bgneal@45: if (!n.currentStyle || !n.currentStyle.hasLayout)
bgneal@45: s.display = 'inline-block';
bgneal@45: }
bgneal@45:
bgneal@45: // Fix for older browsers
bgneal@45: s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';
bgneal@45: break;
bgneal@45:
bgneal@45: case 'float':
bgneal@45: isIE ? s.styleFloat = v : s.cssFloat = v;
bgneal@45: break;
bgneal@45:
bgneal@45: default:
bgneal@45: s[na] = v || '';
bgneal@45: }
bgneal@45:
bgneal@45: // Force update of the style data
bgneal@45: if (t.settings.update_styles)
bgneal@183: t.setAttrib(e, '_mce_style');
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: getStyle : function(n, na, c) {
bgneal@45: n = this.get(n);
bgneal@45:
bgneal@45: if (!n)
bgneal@45: return false;
bgneal@45:
bgneal@45: // Gecko
bgneal@45: if (this.doc.defaultView && c) {
bgneal@45: // Remove camelcase
bgneal@45: na = na.replace(/[A-Z]/g, function(a){
bgneal@45: return '-' + a;
bgneal@45: });
bgneal@45:
bgneal@45: try {
bgneal@45: return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);
bgneal@45: } catch (ex) {
bgneal@45: // Old safari might fail
bgneal@45: return null;
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: // Camelcase it, if needed
bgneal@45: na = na.replace(/-(\D)/g, function(a, b){
bgneal@45: return b.toUpperCase();
bgneal@45: });
bgneal@45:
bgneal@45: if (na == 'float')
bgneal@45: na = isIE ? 'styleFloat' : 'cssFloat';
bgneal@45:
bgneal@45: // IE & Opera
bgneal@45: if (n.currentStyle && c)
bgneal@45: return n.currentStyle[na];
bgneal@45:
bgneal@45: return n.style[na];
bgneal@45: },
bgneal@45:
bgneal@45: setStyles : function(e, o) {
bgneal@45: var t = this, s = t.settings, ol;
bgneal@45:
bgneal@45: ol = s.update_styles;
bgneal@45: s.update_styles = 0;
bgneal@45:
bgneal@45: each(o, function(v, n) {
bgneal@45: t.setStyle(e, n, v);
bgneal@45: });
bgneal@45:
bgneal@45: // Update style info
bgneal@45: s.update_styles = ol;
bgneal@45: if (s.update_styles)
bgneal@45: t.setAttrib(e, s.cssText);
bgneal@45: },
bgneal@45:
bgneal@45: setAttrib : function(e, n, v) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: // Whats the point
bgneal@45: if (!e || !n)
bgneal@45: return;
bgneal@45:
bgneal@45: // Strict XML mode
bgneal@45: if (t.settings.strict)
bgneal@45: n = n.toLowerCase();
bgneal@45:
bgneal@45: return this.run(e, function(e) {
bgneal@45: var s = t.settings;
bgneal@45:
bgneal@45: switch (n) {
bgneal@45: case "style":
bgneal@45: if (!is(v, 'string')) {
bgneal@45: each(v, function(v, n) {
bgneal@45: t.setStyle(e, n, v);
bgneal@45: });
bgneal@45:
bgneal@45: return;
bgneal@45: }
bgneal@45:
bgneal@45: // No mce_style for elements with these since they might get resized by the user
bgneal@45: if (s.keep_values) {
bgneal@45: if (v && !t._isRes(v))
bgneal@183: e.setAttribute('_mce_style', v, 2);
bgneal@45: else
bgneal@183: e.removeAttribute('_mce_style', 2);
bgneal@45: }
bgneal@45:
bgneal@45: e.style.cssText = v;
bgneal@45: break;
bgneal@45:
bgneal@45: case "class":
bgneal@45: e.className = v || ''; // Fix IE null bug
bgneal@45: break;
bgneal@45:
bgneal@45: case "src":
bgneal@45: case "href":
bgneal@45: if (s.keep_values) {
bgneal@45: if (s.url_converter)
bgneal@45: v = s.url_converter.call(s.url_converter_scope || t, v, n, e);
bgneal@45:
bgneal@183: t.setAttrib(e, '_mce_' + n, v, 2);
bgneal@45: }
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case "shape":
bgneal@183: e.setAttribute('_mce_style', v);
bgneal@45: break;
bgneal@45: }
bgneal@45:
bgneal@45: if (is(v) && v !== null && v.length !== 0)
bgneal@45: e.setAttribute(n, '' + v, 2);
bgneal@45: else
bgneal@45: e.removeAttribute(n, 2);
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: setAttribs : function(e, o) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: return this.run(e, function(e) {
bgneal@45: each(o, function(v, n) {
bgneal@45: t.setAttrib(e, n, v);
bgneal@45: });
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: getAttrib : function(e, n, dv) {
bgneal@45: var v, t = this;
bgneal@45:
bgneal@45: e = t.get(e);
bgneal@45:
bgneal@45: if (!e || e.nodeType !== 1)
bgneal@45: return false;
bgneal@45:
bgneal@45: if (!is(dv))
bgneal@45: dv = '';
bgneal@45:
bgneal@45: // Try the mce variant for these
bgneal@45: if (/^(src|href|style|coords|shape)$/.test(n)) {
bgneal@183: v = e.getAttribute("_mce_" + n);
bgneal@45:
bgneal@45: if (v)
bgneal@45: return v;
bgneal@45: }
bgneal@45:
bgneal@45: if (isIE && t.props[n]) {
bgneal@45: v = e[t.props[n]];
bgneal@45: v = v && v.nodeValue ? v.nodeValue : v;
bgneal@45: }
bgneal@45:
bgneal@45: if (!v)
bgneal@45: v = e.getAttribute(n, 2);
bgneal@45:
bgneal@183: // Check boolean attribs
bgneal@183: if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) {
bgneal@183: if (e[t.props[n]] === true && v === '')
bgneal@183: return n;
bgneal@183:
bgneal@183: return v ? n : '';
bgneal@183: }
bgneal@183:
bgneal@183: // Inner input elements will override attributes on form elements
bgneal@183: if (e.nodeName === "FORM" && e.getAttributeNode(n))
bgneal@183: return e.getAttributeNode(n).nodeValue;
bgneal@183:
bgneal@45: if (n === 'style') {
bgneal@45: v = v || e.style.cssText;
bgneal@45:
bgneal@45: if (v) {
bgneal@183: v = t.serializeStyle(t.parseStyle(v), e.nodeName);
bgneal@45:
bgneal@45: if (t.settings.keep_values && !t._isRes(v))
bgneal@183: e.setAttribute('_mce_style', v);
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: // Remove Apple and WebKit stuff
bgneal@45: if (isWebKit && n === "class" && v)
bgneal@45: v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');
bgneal@45:
bgneal@45: // Handle IE issues
bgneal@45: if (isIE) {
bgneal@45: switch (n) {
bgneal@45: case 'rowspan':
bgneal@45: case 'colspan':
bgneal@45: // IE returns 1 as default value
bgneal@45: if (v === 1)
bgneal@45: v = '';
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case 'size':
bgneal@45: // IE returns +0 as default value for size
bgneal@45: if (v === '+0' || v === 20 || v === 0)
bgneal@45: v = '';
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case 'width':
bgneal@45: case 'height':
bgneal@45: case 'vspace':
bgneal@45: case 'checked':
bgneal@45: case 'disabled':
bgneal@45: case 'readonly':
bgneal@45: if (v === 0)
bgneal@45: v = '';
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case 'hspace':
bgneal@45: // IE returns -1 as default value
bgneal@45: if (v === -1)
bgneal@45: v = '';
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case 'maxlength':
bgneal@45: case 'tabindex':
bgneal@45: // IE returns default value
bgneal@45: if (v === 32768 || v === 2147483647 || v === '32768')
bgneal@45: v = '';
bgneal@45:
bgneal@45: break;
bgneal@45:
bgneal@45: case 'multiple':
bgneal@45: case 'compact':
bgneal@45: case 'noshade':
bgneal@45: case 'nowrap':
bgneal@45: if (v === 65535)
bgneal@45: return n;
bgneal@45:
bgneal@45: return dv;
bgneal@45:
bgneal@45: case 'shape':
bgneal@45: v = v.toLowerCase();
bgneal@45: break;
bgneal@45:
bgneal@45: default:
bgneal@45: // IE has odd anonymous function for event attributes
bgneal@45: if (n.indexOf('on') === 0 && v)
bgneal@183: v = ('' + v).replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1');
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: return (v !== undefined && v !== null && v !== '') ? '' + v : dv;
bgneal@45: },
bgneal@45:
bgneal@183: getPos : function(n, ro) {
bgneal@45: var t = this, x = 0, y = 0, e, d = t.doc, r;
bgneal@45:
bgneal@45: n = t.get(n);
bgneal@183: ro = ro || d.body;
bgneal@183:
bgneal@183: if (n) {
bgneal@183: // Use getBoundingClientRect on IE, Opera has it but it's not perfect
bgneal@183: if (isIE && !t.stdMode) {
bgneal@183: n = n.getBoundingClientRect();
bgneal@183: e = t.boxModel ? d.documentElement : d.body;
bgneal@183: x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
bgneal@183: x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
bgneal@183: n.top += t.win.self != t.win.top ? 2 : 0; // IE adds some strange extra cord if used in a frameset
bgneal@183:
bgneal@183: return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
bgneal@183: }
bgneal@183:
bgneal@183: r = n;
bgneal@183: while (r && r != ro && r.nodeType) {
bgneal@183: x += r.offsetLeft || 0;
bgneal@183: y += r.offsetTop || 0;
bgneal@183: r = r.offsetParent;
bgneal@183: }
bgneal@183:
bgneal@183: r = n.parentNode;
bgneal@183: while (r && r != ro && r.nodeType) {
bgneal@45: x -= r.scrollLeft || 0;
bgneal@45: y -= r.scrollTop || 0;
bgneal@183: r = r.parentNode;
bgneal@183: }
bgneal@45: }
bgneal@45:
bgneal@45: return {x : x, y : y};
bgneal@45: },
bgneal@45:
bgneal@45: parseStyle : function(st) {
bgneal@45: var t = this, s = t.settings, o = {};
bgneal@45:
bgneal@45: if (!st)
bgneal@45: return o;
bgneal@45:
bgneal@45: function compress(p, s, ot) {
bgneal@45: var t, r, b, l;
bgneal@45:
bgneal@45: // Get values and check it it needs compressing
bgneal@45: t = o[p + '-top' + s];
bgneal@45: if (!t)
bgneal@45: return;
bgneal@45:
bgneal@45: r = o[p + '-right' + s];
bgneal@45: if (t != r)
bgneal@45: return;
bgneal@45:
bgneal@45: b = o[p + '-bottom' + s];
bgneal@45: if (r != b)
bgneal@45: return;
bgneal@45:
bgneal@45: l = o[p + '-left' + s];
bgneal@45: if (b != l)
bgneal@45: return;
bgneal@45:
bgneal@45: // Compress
bgneal@45: o[ot] = l;
bgneal@45: delete o[p + '-top' + s];
bgneal@45: delete o[p + '-right' + s];
bgneal@45: delete o[p + '-bottom' + s];
bgneal@45: delete o[p + '-left' + s];
bgneal@45: };
bgneal@45:
bgneal@45: function compress2(ta, a, b, c) {
bgneal@45: var t;
bgneal@45:
bgneal@45: t = o[a];
bgneal@45: if (!t)
bgneal@45: return;
bgneal@45:
bgneal@45: t = o[b];
bgneal@45: if (!t)
bgneal@45: return;
bgneal@45:
bgneal@45: t = o[c];
bgneal@45: if (!t)
bgneal@45: return;
bgneal@45:
bgneal@45: // Compress
bgneal@45: o[ta] = o[a] + ' ' + o[b] + ' ' + o[c];
bgneal@45: delete o[a];
bgneal@45: delete o[b];
bgneal@45: delete o[c];
bgneal@45: };
bgneal@45:
bgneal@45: st = st.replace(/&(#?[a-z0-9]+);/g, '&$1_MCE_SEMI_'); // Protect entities
bgneal@45:
bgneal@45: each(st.split(';'), function(v) {
bgneal@45: var sv, ur = [];
bgneal@45:
bgneal@45: if (v) {
bgneal@45: v = v.replace(/_MCE_SEMI_/g, ';'); // Restore entities
bgneal@45: v = v.replace(/url\([^\)]+\)/g, function(v) {ur.push(v);return 'url(' + ur.length + ')';});
bgneal@45: v = v.split(':');
bgneal@45: sv = tinymce.trim(v[1]);
bgneal@45: sv = sv.replace(/url\(([^\)]+)\)/g, function(a, b) {return ur[parseInt(b) - 1];});
bgneal@45:
bgneal@45: sv = sv.replace(/rgb\([^\)]+\)/g, function(v) {
bgneal@45: return t.toHex(v);
bgneal@45: });
bgneal@45:
bgneal@45: if (s.url_converter) {
bgneal@45: sv = sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g, function(x, c) {
bgneal@45: return 'url(' + s.url_converter.call(s.url_converter_scope || t, t.decode(c), 'style', null) + ')';
bgneal@45: });
bgneal@45: }
bgneal@45:
bgneal@45: o[tinymce.trim(v[0]).toLowerCase()] = sv;
bgneal@45: }
bgneal@45: });
bgneal@45:
bgneal@45: compress("border", "", "border");
bgneal@45: compress("border", "-width", "border-width");
bgneal@45: compress("border", "-color", "border-color");
bgneal@45: compress("border", "-style", "border-style");
bgneal@45: compress("padding", "", "padding");
bgneal@45: compress("margin", "", "margin");
bgneal@45: compress2('border', 'border-width', 'border-style', 'border-color');
bgneal@45:
bgneal@45: if (isIE) {
bgneal@45: // Remove pointless border
bgneal@45: if (o.border == 'medium none')
bgneal@45: o.border = '';
bgneal@45: }
bgneal@45:
bgneal@45: return o;
bgneal@45: },
bgneal@45:
bgneal@183: serializeStyle : function(o, name) {
bgneal@183: var t = this, s = '';
bgneal@183:
bgneal@183: function add(v, k) {
bgneal@45: if (k && v) {
bgneal@183: // Remove browser specific styles like -moz- or -webkit-
bgneal@183: if (k.indexOf('-') === 0)
bgneal@45: return;
bgneal@45:
bgneal@45: switch (k) {
bgneal@183: case 'font-weight':
bgneal@183: // Opera will output bold as 700
bgneal@183: if (v == 700)
bgneal@183: v = 'bold';
bgneal@183:
bgneal@183: break;
bgneal@183:
bgneal@45: case 'color':
bgneal@45: case 'background-color':
bgneal@45: v = v.toLowerCase();
bgneal@45: break;
bgneal@45: }
bgneal@45:
bgneal@45: s += (s ? ' ' : '') + k + ': ' + v + ';';
bgneal@45: }
bgneal@183: };
bgneal@183:
bgneal@183: // Validate style output
bgneal@183: if (name && t._styles) {
bgneal@183: each(t._styles['*'], function(name) {
bgneal@183: add(o[name], name);
bgneal@183: });
bgneal@183:
bgneal@183: each(t._styles[name.toLowerCase()], function(name) {
bgneal@183: add(o[name], name);
bgneal@183: });
bgneal@183: } else
bgneal@183: each(o, add);
bgneal@45:
bgneal@45: return s;
bgneal@45: },
bgneal@45:
bgneal@45: loadCSS : function(u) {
bgneal@183: var t = this, d = t.doc, head;
bgneal@45:
bgneal@45: if (!u)
bgneal@45: u = '';
bgneal@45:
bgneal@183: head = t.select('head')[0];
bgneal@183:
bgneal@45: each(u.split(','), function(u) {
bgneal@183: var link;
bgneal@183:
bgneal@45: if (t.files[u])
bgneal@45: return;
bgneal@45:
bgneal@45: t.files[u] = true;
bgneal@183: link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)});
bgneal@183:
bgneal@183: // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
bgneal@183: // This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading
bgneal@183: // It's ugly but it seems to work fine.
bgneal@183: if (isIE && d.documentMode) {
bgneal@183: link.onload = function() {
bgneal@183: d.recalc();
bgneal@183: link.onload = null;
bgneal@183: };
bgneal@183: }
bgneal@183:
bgneal@183: head.appendChild(link);
bgneal@183: });
bgneal@183: },
bgneal@45:
bgneal@45: addClass : function(e, c) {
bgneal@45: return this.run(e, function(e) {
bgneal@45: var o;
bgneal@45:
bgneal@45: if (!c)
bgneal@45: return 0;
bgneal@45:
bgneal@45: if (this.hasClass(e, c))
bgneal@45: return e.className;
bgneal@45:
bgneal@45: o = this.removeClass(e, c);
bgneal@45:
bgneal@45: return e.className = (o != '' ? (o + ' ') : '') + c;
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: removeClass : function(e, c) {
bgneal@45: var t = this, re;
bgneal@45:
bgneal@45: return t.run(e, function(e) {
bgneal@45: var v;
bgneal@45:
bgneal@45: if (t.hasClass(e, c)) {
bgneal@45: if (!re)
bgneal@45: re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
bgneal@45:
bgneal@45: v = e.className.replace(re, ' ');
bgneal@183: v = tinymce.trim(v != ' ' ? v : '');
bgneal@183:
bgneal@183: e.className = v;
bgneal@183:
bgneal@183: // Empty class attr
bgneal@183: if (!v) {
bgneal@183: e.removeAttribute('class');
bgneal@183: e.removeAttribute('className');
bgneal@183: }
bgneal@183:
bgneal@183: return v;
bgneal@45: }
bgneal@45:
bgneal@45: return e.className;
bgneal@45: });
bgneal@45: },
bgneal@45:
bgneal@45: hasClass : function(n, c) {
bgneal@45: n = this.get(n);
bgneal@45:
bgneal@45: if (!n || !c)
bgneal@45: return false;
bgneal@45:
bgneal@45: return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;
bgneal@45: },
bgneal@45:
bgneal@45: show : function(e) {
bgneal@45: return this.setStyle(e, 'display', 'block');
bgneal@45: },
bgneal@45:
bgneal@45: hide : function(e) {
bgneal@45: return this.setStyle(e, 'display', 'none');
bgneal@45: },
bgneal@45:
bgneal@45: isHidden : function(e) {
bgneal@45: e = this.get(e);
bgneal@45:
bgneal@45: return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none';
bgneal@45: },
bgneal@45:
bgneal@45: uniqueId : function(p) {
bgneal@45: return (!p ? 'mce_' : p) + (this.counter++);
bgneal@45: },
bgneal@45:
bgneal@45: setHTML : function(e, h) {
bgneal@45: var t = this;
bgneal@45:
bgneal@45: return this.run(e, function(e) {
bgneal@45: var x, i, nl, n, p, x;
bgneal@45:
bgneal@45: h = t.processHTML(h);
bgneal@45:
bgneal@45: if (isIE) {
bgneal@45: function set() {
bgneal@183: // Remove all child nodes
bgneal@183: while (e.firstChild)
bgneal@183: e.firstChild.removeNode();
bgneal@183:
bgneal@45: try {
bgneal@45: // IE will remove comments from the beginning
bgneal@45: // unless you padd the contents with something
bgneal@45: e.innerHTML = '
' + h;
bgneal@45: e.removeChild(e.firstChild);
bgneal@45: } catch (ex) {
bgneal@45: // 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
bgneal@45: // This seems to fix this problem
bgneal@45:
bgneal@45: // Create new div with HTML contents and a BR infront to keep comments
bgneal@45: x = t.create('div');
bgneal@45: x.innerHTML = '
' + h;
bgneal@45:
bgneal@45: // Add all children from div to target
bgneal@45: each (x.childNodes, function(n, i) {
bgneal@45: // Skip br element
bgneal@45: if (i)
bgneal@45: e.appendChild(n);
bgneal@45: });
bgneal@45: }
bgneal@45: };
bgneal@45:
bgneal@45: // IE has a serious bug when it comes to paragraphs it can produce an invalid
bgneal@45: // DOM tree if contents like this
is inserted
bgneal@45: // It seems to be that IE doesn't like a root block element placed inside another root block element
bgneal@45: if (t.settings.fix_ie_paragraphs)
bgneal@183: h = h.replace(/<\/p>|
]+)><\/p>|
/gi, '
');
bgneal@45:
bgneal@45: set();
bgneal@45:
bgneal@45: if (t.settings.fix_ie_paragraphs) {
bgneal@45: // Check for odd paragraphs this is a sign of a broken DOM
bgneal@45: nl = e.getElementsByTagName("p");
bgneal@45: for (i = nl.length - 1, x = 0; i >= 0; i--) {
bgneal@45: n = nl[i];
bgneal@45:
bgneal@45: if (!n.hasChildNodes()) {
bgneal@183: if (!n._mce_keep) {
bgneal@45: x = 1; // Is broken
bgneal@45: break;
bgneal@45: }
bgneal@45:
bgneal@183: n.removeAttribute('_mce_keep');
bgneal@45: }
bgneal@45: }
bgneal@45: }
bgneal@45:
bgneal@45: // Time to fix the madness IE left us
bgneal@45: if (x) {
bgneal@45: // So if we replace the p elements with divs and mark them and then replace them back to paragraphs
bgneal@45: // after we use innerHTML we can fix the DOM tree
bgneal@183: h = h.replace(/]+)>|
/ig, '
');
bgneal@45: h = h.replace(/<\/p>/g, '
');
bgneal@45:
bgneal@45: // Set the new HTML with DIVs
bgneal@45: set();
bgneal@45:
bgneal@183: // Replace all DIV elements with the _mce_tmp attibute back to paragraphs
bgneal@45: // This is needed since IE has a annoying bug see above for details
bgneal@45: // This is a slow process but it has to be done. :(
bgneal@45: if (t.settings.fix_ie_paragraphs) {
bgneal@45: nl = e.getElementsByTagName("DIV");
bgneal@45: for (i = nl.length - 1; i >= 0; i--) {
bgneal@45: n = nl[i];
bgneal@45:
bgneal@45: // Is it a temp div
bgneal@183: if (n._mce_tmp) {
bgneal@45: // Create new paragraph
bgneal@45: p = t.doc.createElement('p');
bgneal@45:
bgneal@45: // Copy all attributes
bgneal@45: n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi, function(a, b) {
bgneal@45: var v;
bgneal@45:
bgneal@183: if (b !== '_mce_tmp') {
bgneal@45: v = n.getAttribute(b);
bgneal@45:
bgneal@45: if (!v && b === 'class')
bgneal@45: v = n.className;
bgneal@45:
bgneal@45: p.setAttribute(b, v);
bgneal@45: }
bgneal@45: });
bgneal@45:
bgneal@45: // Append all children to new paragraph
bgneal@45: for (x = 0; x]+)\/>|/gi, ''); // Force open
bgneal@45:
bgneal@183: // Store away src and href in _mce_src and mce_href since browsers mess them up
bgneal@45: if (s.keep_values) {
bgneal@45: // Wrap scripts and styles in comments for serialization purposes
bgneal@183: if (/';
bgneal@45:
bgneal@45: bi = s.body_id || 'tinymce';
bgneal@45: if (bi.indexOf('=') != -1) {
bgneal@45: bi = t.getParam('body_id', '', 'hash');
bgneal@45: bi = bi[t.id] || bi;
bgneal@45: }
bgneal@45:
bgneal@45: bc = s.body_class || '';
bgneal@45: if (bc.indexOf('=') != -1) {
bgneal@45: bc = t.getParam('body_class', '', 'hash');
bgneal@45: bc = bc[t.id] || '';
bgneal@45: }
bgneal@45:
bgneal@45: t.iframeHTML += '