PageRenderTime 56ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/BlogEngine/BlogEngine.NET/editors/tiny_mce_3_4_3_1/tiny_mce_src.js

#
JavaScript | 2488 lines | 2193 code | 222 blank | 73 comment | 196 complexity | 2c6c96b9d0b46ee7053301c941d3da97 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. (function(win) {
  2. var whiteSpaceRe = /^\s*|\s*$/g,
  3. undefined, isRegExpBroken = 'B'.replace(/A(.)|B/, '$1') === '$1';
  4. var tinymce = {
  5. majorVersion : '3',
  6. minorVersion : '4.3.1',
  7. releaseDate : '2011-06-16',
  8. _init : function() {
  9. var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
  10. t.isOpera = win.opera && opera.buildNumber;
  11. t.isWebKit = /WebKit/.test(ua);
  12. t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
  13. t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
  14. t.isGecko = !t.isWebKit && /Gecko/.test(ua);
  15. t.isMac = ua.indexOf('Mac') != -1;
  16. t.isAir = /adobeair/i.test(ua);
  17. t.isIDevice = /(iPad|iPhone)/.test(ua);
  18. t.isIOS5 = t.isIDevice && ua.match(/AppleWebKit\/(\d*)/)[1]>=534;
  19. // TinyMCE .NET webcontrol might be setting the values for TinyMCE
  20. if (win.tinyMCEPreInit) {
  21. t.suffix = tinyMCEPreInit.suffix;
  22. t.baseURL = tinyMCEPreInit.base;
  23. t.query = tinyMCEPreInit.query;
  24. return;
  25. }
  26. // Get suffix and base
  27. t.suffix = '';
  28. // If base element found, add that infront of baseURL
  29. nl = d.getElementsByTagName('base');
  30. for (i=0; i<nl.length; i++) {
  31. if (v = nl[i].href) {
  32. // Host only value like http://site.com or http://site.com:8008
  33. if (/^https?:\/\/[^\/]+$/.test(v))
  34. v += '/';
  35. base = v ? v.match(/.*\//)[0] : ''; // Get only directory
  36. }
  37. }
  38. function getBase(n) {
  39. if (n.src && /tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(n.src)) {
  40. if (/_(src|dev)\.js/g.test(n.src))
  41. t.suffix = '_src';
  42. if ((p = n.src.indexOf('?')) != -1)
  43. t.query = n.src.substring(p + 1);
  44. t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
  45. // If path to script is relative and a base href was found add that one infront
  46. // the src property will always be an absolute one on non IE browsers and IE 8
  47. // so this logic will basically only be executed on older IE versions
  48. if (base && t.baseURL.indexOf('://') == -1 && t.baseURL.indexOf('/') !== 0)
  49. t.baseURL = base + t.baseURL;
  50. return t.baseURL;
  51. }
  52. return null;
  53. };
  54. // Check document
  55. nl = d.getElementsByTagName('script');
  56. for (i=0; i<nl.length; i++) {
  57. if (getBase(nl[i]))
  58. return;
  59. }
  60. // Check head
  61. n = d.getElementsByTagName('head')[0];
  62. if (n) {
  63. nl = n.getElementsByTagName('script');
  64. for (i=0; i<nl.length; i++) {
  65. if (getBase(nl[i]))
  66. return;
  67. }
  68. }
  69. return;
  70. },
  71. is : function(o, t) {
  72. if (!t)
  73. return o !== undefined;
  74. if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
  75. return true;
  76. return typeof(o) == t;
  77. },
  78. makeMap : function(items, delim, map) {
  79. var i;
  80. items = items || [];
  81. delim = delim || ',';
  82. if (typeof(items) == "string")
  83. items = items.split(delim);
  84. map = map || {};
  85. i = items.length;
  86. while (i--)
  87. map[items[i]] = {};
  88. return map;
  89. },
  90. each : function(o, cb, s) {
  91. var n, l;
  92. if (!o)
  93. return 0;
  94. s = s || o;
  95. if (o.length !== undefined) {
  96. // Indexed arrays, needed for Safari
  97. for (n=0, l = o.length; n < l; n++) {
  98. if (cb.call(s, o[n], n, o) === false)
  99. return 0;
  100. }
  101. } else {
  102. // Hashtables
  103. for (n in o) {
  104. if (o.hasOwnProperty(n)) {
  105. if (cb.call(s, o[n], n, o) === false)
  106. return 0;
  107. }
  108. }
  109. }
  110. return 1;
  111. },
  112. map : function(a, f) {
  113. var o = [];
  114. tinymce.each(a, function(v) {
  115. o.push(f(v));
  116. });
  117. return o;
  118. },
  119. grep : function(a, f) {
  120. var o = [];
  121. tinymce.each(a, function(v) {
  122. if (!f || f(v))
  123. o.push(v);
  124. });
  125. return o;
  126. },
  127. inArray : function(a, v) {
  128. var i, l;
  129. if (a) {
  130. for (i = 0, l = a.length; i < l; i++) {
  131. if (a[i] === v)
  132. return i;
  133. }
  134. }
  135. return -1;
  136. },
  137. extend : function(o, e) {
  138. var i, l, a = arguments;
  139. for (i = 1, l = a.length; i < l; i++) {
  140. e = a[i];
  141. tinymce.each(e, function(v, n) {
  142. if (v !== undefined)
  143. o[n] = v;
  144. });
  145. }
  146. return o;
  147. },
  148. trim : function(s) {
  149. return (s ? '' + s : '').replace(whiteSpaceRe, '');
  150. },
  151. create : function(s, p, root) {
  152. var t = this, sp, ns, cn, scn, c, de = 0;
  153. // Parse : <prefix> <class>:<super class>
  154. s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
  155. cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
  156. // Create namespace for new class
  157. ns = t.createNS(s[3].replace(/\.\w+$/, ''), root);
  158. // Class already exists
  159. if (ns[cn])
  160. return;
  161. // Make pure static class
  162. if (s[2] == 'static') {
  163. ns[cn] = p;
  164. if (this.onCreate)
  165. this.onCreate(s[2], s[3], ns[cn]);
  166. return;
  167. }
  168. // Create default constructor
  169. if (!p[cn]) {
  170. p[cn] = function() {};
  171. de = 1;
  172. }
  173. // Add constructor and methods
  174. ns[cn] = p[cn];
  175. t.extend(ns[cn].prototype, p);
  176. // Extend
  177. if (s[5]) {
  178. sp = t.resolve(s[5]).prototype;
  179. scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
  180. // Extend constructor
  181. c = ns[cn];
  182. if (de) {
  183. // Add passthrough constructor
  184. ns[cn] = function() {
  185. return sp[scn].apply(this, arguments);
  186. };
  187. } else {
  188. // Add inherit constructor
  189. ns[cn] = function() {
  190. this.parent = sp[scn];
  191. return c.apply(this, arguments);
  192. };
  193. }
  194. ns[cn].prototype[cn] = ns[cn];
  195. // Add super methods
  196. t.each(sp, function(f, n) {
  197. ns[cn].prototype[n] = sp[n];
  198. });
  199. // Add overridden methods
  200. t.each(p, function(f, n) {
  201. // Extend methods if needed
  202. if (sp[n]) {
  203. ns[cn].prototype[n] = function() {
  204. this.parent = sp[n];
  205. return f.apply(this, arguments);
  206. };
  207. } else {
  208. if (n != cn)
  209. ns[cn].prototype[n] = f;
  210. }
  211. });
  212. }
  213. // Add static methods
  214. t.each(p['static'], function(f, n) {
  215. ns[cn][n] = f;
  216. });
  217. if (this.onCreate)
  218. this.onCreate(s[2], s[3], ns[cn].prototype);
  219. },
  220. walk : function(o, f, n, s) {
  221. s = s || this;
  222. if (o) {
  223. if (n)
  224. o = o[n];
  225. tinymce.each(o, function(o, i) {
  226. if (f.call(s, o, i, n) === false)
  227. return false;
  228. tinymce.walk(o, f, n, s);
  229. });
  230. }
  231. },
  232. createNS : function(n, o) {
  233. var i, v;
  234. o = o || win;
  235. n = n.split('.');
  236. for (i=0; i<n.length; i++) {
  237. v = n[i];
  238. if (!o[v])
  239. o[v] = {};
  240. o = o[v];
  241. }
  242. return o;
  243. },
  244. resolve : function(n, o) {
  245. var i, l;
  246. o = o || win;
  247. n = n.split('.');
  248. for (i = 0, l = n.length; i < l; i++) {
  249. o = o[n[i]];
  250. if (!o)
  251. break;
  252. }
  253. return o;
  254. },
  255. addUnload : function(f, s) {
  256. var t = this;
  257. f = {func : f, scope : s || this};
  258. if (!t.unloads) {
  259. function unload() {
  260. var li = t.unloads, o, n;
  261. if (li) {
  262. // Call unload handlers
  263. for (n in li) {
  264. o = li[n];
  265. if (o && o.func)
  266. o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
  267. }
  268. // Detach unload function
  269. if (win.detachEvent) {
  270. win.detachEvent('onbeforeunload', fakeUnload);
  271. win.detachEvent('onunload', unload);
  272. } else if (win.removeEventListener)
  273. win.removeEventListener('unload', unload, false);
  274. // Destroy references
  275. t.unloads = o = li = w = unload = 0;
  276. // Run garbarge collector on IE
  277. if (win.CollectGarbage)
  278. CollectGarbage();
  279. }
  280. };
  281. function fakeUnload() {
  282. var d = document;
  283. // Is there things still loading, then do some magic
  284. if (d.readyState == 'interactive') {
  285. function stop() {
  286. // Prevent memory leak
  287. d.detachEvent('onstop', stop);
  288. // Call unload handler
  289. if (unload)
  290. unload();
  291. d = 0;
  292. };
  293. // Fire unload when the currently loading page is stopped
  294. if (d)
  295. d.attachEvent('onstop', stop);
  296. // Remove onstop listener after a while to prevent the unload function
  297. // to execute if the user presses cancel in an onbeforeunload
  298. // confirm dialog and then presses the browser stop button
  299. win.setTimeout(function() {
  300. if (d)
  301. d.detachEvent('onstop', stop);
  302. }, 0);
  303. }
  304. };
  305. // Attach unload handler
  306. if (win.attachEvent) {
  307. win.attachEvent('onunload', unload);
  308. win.attachEvent('onbeforeunload', fakeUnload);
  309. } else if (win.addEventListener)
  310. win.addEventListener('unload', unload, false);
  311. // Setup initial unload handler array
  312. t.unloads = [f];
  313. } else
  314. t.unloads.push(f);
  315. return f;
  316. },
  317. removeUnload : function(f) {
  318. var u = this.unloads, r = null;
  319. tinymce.each(u, function(o, i) {
  320. if (o && o.func == f) {
  321. u.splice(i, 1);
  322. r = f;
  323. return false;
  324. }
  325. });
  326. return r;
  327. },
  328. explode : function(s, d) {
  329. return s ? tinymce.map(s.split(d || ','), tinymce.trim) : s;
  330. },
  331. _addVer : function(u) {
  332. var v;
  333. if (!this.query)
  334. return u;
  335. v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;
  336. if (u.indexOf('#') == -1)
  337. return u + v;
  338. return u.replace('#', v + '#');
  339. },
  340. // Fix function for IE 9 where regexps isn't working correctly
  341. // Todo: remove me once MS fixes the bug
  342. _replace : function(find, replace, str) {
  343. // On IE9 we have to fake $x replacement
  344. if (isRegExpBroken) {
  345. return str.replace(find, function() {
  346. var val = replace, args = arguments, i;
  347. for (i = 0; i < args.length - 2; i++) {
  348. if (args[i] === undefined) {
  349. val = val.replace(new RegExp('\\$' + i, 'g'), '');
  350. } else {
  351. val = val.replace(new RegExp('\\$' + i, 'g'), args[i]);
  352. }
  353. }
  354. return val;
  355. });
  356. }
  357. return str.replace(find, replace);
  358. }
  359. };
  360. // Initialize the API
  361. tinymce._init();
  362. // Expose tinymce namespace to the global namespace (window)
  363. win.tinymce = win.tinyMCE = tinymce;
  364. // Describe the different namespaces
  365. })(window);
  366. tinymce.create('tinymce.util.Dispatcher', {
  367. scope : null,
  368. listeners : null,
  369. Dispatcher : function(s) {
  370. this.scope = s || this;
  371. this.listeners = [];
  372. },
  373. add : function(cb, s) {
  374. this.listeners.push({cb : cb, scope : s || this.scope});
  375. return cb;
  376. },
  377. addToTop : function(cb, s) {
  378. this.listeners.unshift({cb : cb, scope : s || this.scope});
  379. return cb;
  380. },
  381. remove : function(cb) {
  382. var l = this.listeners, o = null;
  383. tinymce.each(l, function(c, i) {
  384. if (cb == c.cb) {
  385. o = cb;
  386. l.splice(i, 1);
  387. return false;
  388. }
  389. });
  390. return o;
  391. },
  392. dispatch : function() {
  393. var s, a = arguments, i, li = this.listeners, c;
  394. // Needs to be a real loop since the listener count might change while looping
  395. // And this is also more efficient
  396. for (i = 0; i<li.length; i++) {
  397. c = li[i];
  398. s = c.cb.apply(c.scope, a);
  399. if (s === false)
  400. break;
  401. }
  402. return s;
  403. }
  404. });
  405. (function() {
  406. var each = tinymce.each;
  407. tinymce.create('tinymce.util.URI', {
  408. URI : function(u, s) {
  409. var t = this, o, a, b, base_url;
  410. // Trim whitespace
  411. u = tinymce.trim(u);
  412. // Default settings
  413. s = t.settings = s || {};
  414. // Strange app protocol or local anchor
  415. if (/^(mailto|tel|news|javascript|about|data):/i.test(u) || /^\s*#/.test(u)) {
  416. t.source = u;
  417. return;
  418. }
  419. // Absolute path with no host, fake host and protocol
  420. if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
  421. u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
  422. // Relative path http:// or protocol relative //path
  423. if (!/^[\w-]*:?\/\//.test(u)) {
  424. base_url = s.base_uri ? s.base_uri.path : new tinymce.util.URI(location.href).directory;
  425. u = ((s.base_uri && s.base_uri.protocol) || 'http') + '://mce_host' + t.toAbsPath(base_url, u);
  426. }
  427. // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
  428. u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
  429. u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
  430. each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
  431. var s = u[i];
  432. // Zope 3 workaround, they use @@something
  433. if (s)
  434. s = s.replace(/\(mce_at\)/g, '@@');
  435. t[v] = s;
  436. });
  437. if (b = s.base_uri) {
  438. if (!t.protocol)
  439. t.protocol = b.protocol;
  440. if (!t.userInfo)
  441. t.userInfo = b.userInfo;
  442. if (!t.port && t.host == 'mce_host')
  443. t.port = b.port;
  444. if (!t.host || t.host == 'mce_host')
  445. t.host = b.host;
  446. t.source = '';
  447. }
  448. //t.path = t.path || '/';
  449. },
  450. setPath : function(p) {
  451. var t = this;
  452. p = /^(.*?)\/?(\w+)?$/.exec(p);
  453. // Update path parts
  454. t.path = p[0];
  455. t.directory = p[1];
  456. t.file = p[2];
  457. // Rebuild source
  458. t.source = '';
  459. t.getURI();
  460. },
  461. toRelative : function(u) {
  462. var t = this, o;
  463. if (u === "./")
  464. return u;
  465. u = new tinymce.util.URI(u, {base_uri : t});
  466. // Not on same domain/port or protocol
  467. if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
  468. return u.getURI();
  469. o = t.toRelPath(t.path, u.path);
  470. // Add query
  471. if (u.query)
  472. o += '?' + u.query;
  473. // Add anchor
  474. if (u.anchor)
  475. o += '#' + u.anchor;
  476. return o;
  477. },
  478. toAbsolute : function(u, nh) {
  479. var u = new tinymce.util.URI(u, {base_uri : this});
  480. return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0);
  481. },
  482. toRelPath : function(base, path) {
  483. var items, bp = 0, out = '', i, l;
  484. // Split the paths
  485. base = base.substring(0, base.lastIndexOf('/'));
  486. base = base.split('/');
  487. items = path.split('/');
  488. if (base.length >= items.length) {
  489. for (i = 0, l = base.length; i < l; i++) {
  490. if (i >= items.length || base[i] != items[i]) {
  491. bp = i + 1;
  492. break;
  493. }
  494. }
  495. }
  496. if (base.length < items.length) {
  497. for (i = 0, l = items.length; i < l; i++) {
  498. if (i >= base.length || base[i] != items[i]) {
  499. bp = i + 1;
  500. break;
  501. }
  502. }
  503. }
  504. if (bp == 1)
  505. return path;
  506. for (i = 0, l = base.length - (bp - 1); i < l; i++)
  507. out += "../";
  508. for (i = bp - 1, l = items.length; i < l; i++) {
  509. if (i != bp - 1)
  510. out += "/" + items[i];
  511. else
  512. out += items[i];
  513. }
  514. return out;
  515. },
  516. toAbsPath : function(base, path) {
  517. var i, nb = 0, o = [], tr, outPath;
  518. // Split paths
  519. tr = /\/$/.test(path) ? '/' : '';
  520. base = base.split('/');
  521. path = path.split('/');
  522. // Remove empty chunks
  523. each(base, function(k) {
  524. if (k)
  525. o.push(k);
  526. });
  527. base = o;
  528. // Merge relURLParts chunks
  529. for (i = path.length - 1, o = []; i >= 0; i--) {
  530. // Ignore empty or .
  531. if (path[i].length == 0 || path[i] == ".")
  532. continue;
  533. // Is parent
  534. if (path[i] == '..') {
  535. nb++;
  536. continue;
  537. }
  538. // Move up
  539. if (nb > 0) {
  540. nb--;
  541. continue;
  542. }
  543. o.push(path[i]);
  544. }
  545. i = base.length - nb;
  546. // If /a/b/c or /
  547. if (i <= 0)
  548. outPath = o.reverse().join('/');
  549. else
  550. outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
  551. // Add front / if it's needed
  552. if (outPath.indexOf('/') !== 0)
  553. outPath = '/' + outPath;
  554. // Add traling / if it's needed
  555. if (tr && outPath.lastIndexOf('/') !== outPath.length - 1)
  556. outPath += tr;
  557. return outPath;
  558. },
  559. getURI : function(nh) {
  560. var s, t = this;
  561. // Rebuild source
  562. if (!t.source || nh) {
  563. s = '';
  564. if (!nh) {
  565. if (t.protocol)
  566. s += t.protocol + '://';
  567. if (t.userInfo)
  568. s += t.userInfo + '@';
  569. if (t.host)
  570. s += t.host;
  571. if (t.port)
  572. s += ':' + t.port;
  573. }
  574. if (t.path)
  575. s += t.path;
  576. if (t.query)
  577. s += '?' + t.query;
  578. if (t.anchor)
  579. s += '#' + t.anchor;
  580. t.source = s;
  581. }
  582. return t.source;
  583. }
  584. });
  585. })();
  586. (function() {
  587. var each = tinymce.each;
  588. tinymce.create('static tinymce.util.Cookie', {
  589. getHash : function(n) {
  590. var v = this.get(n), h;
  591. if (v) {
  592. each(v.split('&'), function(v) {
  593. v = v.split('=');
  594. h = h || {};
  595. h[unescape(v[0])] = unescape(v[1]);
  596. });
  597. }
  598. return h;
  599. },
  600. setHash : function(n, v, e, p, d, s) {
  601. var o = '';
  602. each(v, function(v, k) {
  603. o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
  604. });
  605. this.set(n, o, e, p, d, s);
  606. },
  607. get : function(n) {
  608. var c = document.cookie, e, p = n + "=", b;
  609. // Strict mode
  610. if (!c)
  611. return;
  612. b = c.indexOf("; " + p);
  613. if (b == -1) {
  614. b = c.indexOf(p);
  615. if (b != 0)
  616. return null;
  617. } else
  618. b += 2;
  619. e = c.indexOf(";", b);
  620. if (e == -1)
  621. e = c.length;
  622. return unescape(c.substring(b + p.length, e));
  623. },
  624. set : function(n, v, e, p, d, s) {
  625. document.cookie = n + "=" + escape(v) +
  626. ((e) ? "; expires=" + e.toGMTString() : "") +
  627. ((p) ? "; path=" + escape(p) : "") +
  628. ((d) ? "; domain=" + d : "") +
  629. ((s) ? "; secure" : "");
  630. },
  631. remove : function(n, p) {
  632. var d = new Date();
  633. d.setTime(d.getTime() - 1000);
  634. this.set(n, '', d, p, d);
  635. }
  636. });
  637. })();
  638. (function() {
  639. function serialize(o, quote) {
  640. var i, v, t;
  641. quote = quote || '"';
  642. if (o == null)
  643. return 'null';
  644. t = typeof o;
  645. if (t == 'string') {
  646. v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
  647. return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function(a, b) {
  648. // Make sure single quotes never get encoded inside double quotes for JSON compatibility
  649. if (quote === '"' && a === "'")
  650. return a;
  651. i = v.indexOf(b);
  652. if (i + 1)
  653. return '\\' + v.charAt(i + 1);
  654. a = b.charCodeAt().toString(16);
  655. return '\\u' + '0000'.substring(a.length) + a;
  656. }) + quote;
  657. }
  658. if (t == 'object') {
  659. if (o.hasOwnProperty && o instanceof Array) {
  660. for (i=0, v = '['; i<o.length; i++)
  661. v += (i > 0 ? ',' : '') + serialize(o[i], quote);
  662. return v + ']';
  663. }
  664. v = '{';
  665. for (i in o)
  666. v += typeof o[i] != 'function' ? (v.length > 1 ? ',' + quote : quote) + i + quote +':' + serialize(o[i], quote) : '';
  667. return v + '}';
  668. }
  669. return '' + o;
  670. };
  671. tinymce.util.JSON = {
  672. serialize: serialize,
  673. parse: function(s) {
  674. try {
  675. return eval('(' + s + ')');
  676. } catch (ex) {
  677. // Ignore
  678. }
  679. }
  680. };
  681. })();
  682. tinymce.create('static tinymce.util.XHR', {
  683. send : function(o) {
  684. var x, t, w = window, c = 0;
  685. // Default settings
  686. o.scope = o.scope || this;
  687. o.success_scope = o.success_scope || o.scope;
  688. o.error_scope = o.error_scope || o.scope;
  689. o.async = o.async === false ? false : true;
  690. o.data = o.data || '';
  691. function get(s) {
  692. x = 0;
  693. try {
  694. x = new ActiveXObject(s);
  695. } catch (ex) {
  696. }
  697. return x;
  698. };
  699. x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
  700. if (x) {
  701. if (x.overrideMimeType)
  702. x.overrideMimeType(o.content_type);
  703. x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
  704. if (o.content_type)
  705. x.setRequestHeader('Content-Type', o.content_type);
  706. x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  707. x.send(o.data);
  708. function ready() {
  709. if (!o.async || x.readyState == 4 || c++ > 10000) {
  710. if (o.success && c < 10000 && x.status == 200)
  711. o.success.call(o.success_scope, '' + x.responseText, x, o);
  712. else if (o.error)
  713. o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
  714. x = null;
  715. } else
  716. w.setTimeout(ready, 10);
  717. };
  718. // Syncronous request
  719. if (!o.async)
  720. return ready();
  721. // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
  722. t = w.setTimeout(ready, 10);
  723. }
  724. }
  725. });
  726. (function() {
  727. var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
  728. tinymce.create('tinymce.util.JSONRequest', {
  729. JSONRequest : function(s) {
  730. this.settings = extend({
  731. }, s);
  732. this.count = 0;
  733. },
  734. send : function(o) {
  735. var ecb = o.error, scb = o.success;
  736. o = extend(this.settings, o);
  737. o.success = function(c, x) {
  738. c = JSON.parse(c);
  739. if (typeof(c) == 'undefined') {
  740. c = {
  741. error : 'JSON Parse error.'
  742. };
  743. }
  744. if (c.error)
  745. ecb.call(o.error_scope || o.scope, c.error, x);
  746. else
  747. scb.call(o.success_scope || o.scope, c.result);
  748. };
  749. o.error = function(ty, x) {
  750. if (ecb)
  751. ecb.call(o.error_scope || o.scope, ty, x);
  752. };
  753. o.data = JSON.serialize({
  754. id : o.id || 'c' + (this.count++),
  755. method : o.method,
  756. params : o.params
  757. });
  758. // JSON content type for Ruby on rails. Bug: #1883287
  759. o.content_type = 'application/json';
  760. XHR.send(o);
  761. },
  762. 'static' : {
  763. sendRPC : function(o) {
  764. return new tinymce.util.JSONRequest().send(o);
  765. }
  766. }
  767. });
  768. }());
  769. (function(tinymce) {
  770. var namedEntities, baseEntities, reverseEntities,
  771. attrsCharsRegExp = /[&<>\"\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
  772. textCharsRegExp = /[<>&\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
  773. rawCharsRegExp = /[<>&\"\']/g,
  774. entityRegExp = /&(#x|#)?([\w]+);/g,
  775. asciiMap = {
  776. 128 : "\u20AC", 130 : "\u201A", 131 : "\u0192", 132 : "\u201E", 133 : "\u2026", 134 : "\u2020",
  777. 135 : "\u2021", 136 : "\u02C6", 137 : "\u2030", 138 : "\u0160", 139 : "\u2039", 140 : "\u0152",
  778. 142 : "\u017D", 145 : "\u2018", 146 : "\u2019", 147 : "\u201C", 148 : "\u201D", 149 : "\u2022",
  779. 150 : "\u2013", 151 : "\u2014", 152 : "\u02DC", 153 : "\u2122", 154 : "\u0161", 155 : "\u203A",
  780. 156 : "\u0153", 158 : "\u017E", 159 : "\u0178"
  781. };
  782. // Raw entities
  783. baseEntities = {
  784. '"' : '&quot;',
  785. "'" : '&#39;',
  786. '<' : '&lt;',
  787. '>' : '&gt;',
  788. '&' : '&amp;'
  789. };
  790. // Reverse lookup table for raw entities
  791. reverseEntities = {
  792. '&lt;' : '<',
  793. '&gt;' : '>',
  794. '&amp;' : '&',
  795. '&quot;' : '"',
  796. '&apos;' : "'"
  797. };
  798. // Decodes text by using the browser
  799. function nativeDecode(text) {
  800. var elm;
  801. elm = document.createElement("div");
  802. elm.innerHTML = text;
  803. return elm.textContent || elm.innerText || text;
  804. };
  805. // Build a two way lookup table for the entities
  806. function buildEntitiesLookup(items, radix) {
  807. var i, chr, entity, lookup = {};
  808. if (items) {
  809. items = items.split(',');
  810. radix = radix || 10;
  811. // Build entities lookup table
  812. for (i = 0; i < items.length; i += 2) {
  813. chr = String.fromCharCode(parseInt(items[i], radix));
  814. // Only add non base entities
  815. if (!baseEntities[chr]) {
  816. entity = '&' + items[i + 1] + ';';
  817. lookup[chr] = entity;
  818. lookup[entity] = chr;
  819. }
  820. }
  821. return lookup;
  822. }
  823. };
  824. // Unpack entities lookup where the numbers are in radix 32 to reduce the size
  825. namedEntities = buildEntitiesLookup(
  826. '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' +
  827. '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' +
  828. '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' +
  829. '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' +
  830. '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' +
  831. '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' +
  832. '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' +
  833. '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' +
  834. '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' +
  835. '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' +
  836. 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' +
  837. 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' +
  838. 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' +
  839. 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' +
  840. 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' +
  841. '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' +
  842. '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' +
  843. '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' +
  844. '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' +
  845. '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' +
  846. 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' +
  847. 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' +
  848. 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' +
  849. '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' +
  850. '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro'
  851. , 32);
  852. tinymce.html = tinymce.html || {};
  853. tinymce.html.Entities = {
  854. encodeRaw : function(text, attr) {
  855. return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
  856. return baseEntities[chr] || chr;
  857. });
  858. },
  859. encodeAllRaw : function(text) {
  860. return ('' + text).replace(rawCharsRegExp, function(chr) {
  861. return baseEntities[chr] || chr;
  862. });
  863. },
  864. encodeNumeric : function(text, attr) {
  865. return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
  866. // Multi byte sequence convert it to a single entity
  867. if (chr.length > 1)
  868. return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
  869. return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
  870. });
  871. },
  872. encodeNamed : function(text, attr, entities) {
  873. entities = entities || namedEntities;
  874. return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
  875. return baseEntities[chr] || entities[chr] || chr;
  876. });
  877. },
  878. getEncodeFunc : function(name, entities) {
  879. var Entities = tinymce.html.Entities;
  880. entities = buildEntitiesLookup(entities) || namedEntities;
  881. function encodeNamedAndNumeric(text, attr) {
  882. return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
  883. return baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
  884. });
  885. };
  886. function encodeCustomNamed(text, attr) {
  887. return Entities.encodeNamed(text, attr, entities);
  888. };
  889. // Replace + with , to be compatible with previous TinyMCE versions
  890. name = tinymce.makeMap(name.replace(/\+/g, ','));
  891. // Named and numeric encoder
  892. if (name.named && name.numeric)
  893. return encodeNamedAndNumeric;
  894. // Named encoder
  895. if (name.named) {
  896. // Custom names
  897. if (entities)
  898. return encodeCustomNamed;
  899. return Entities.encodeNamed;
  900. }
  901. // Numeric
  902. if (name.numeric)
  903. return Entities.encodeNumeric;
  904. // Raw encoder
  905. return Entities.encodeRaw;
  906. },
  907. decode : function(text) {
  908. return text.replace(entityRegExp, function(all, numeric, value) {
  909. if (numeric) {
  910. value = parseInt(value, numeric.length === 2 ? 16 : 10);
  911. // Support upper UTF
  912. if (value > 0xFFFF) {
  913. value -= 0x10000;
  914. return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF));
  915. } else
  916. return asciiMap[value] || String.fromCharCode(value);
  917. }
  918. return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
  919. });
  920. }
  921. };
  922. })(tinymce);
  923. tinymce.html.Styles = function(settings, schema) {
  924. var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,
  925. urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,
  926. styleRegExp = /\s*([^:]+):\s*([^;]+);?/g,
  927. trimRightRegExp = /\s+$/,
  928. urlColorRegExp = /rgb/,
  929. undef, i, encodingLookup = {}, encodingItems;
  930. settings = settings || {};
  931. encodingItems = '\\" \\\' \\; \\: ; : \uFEFF'.split(' ');
  932. for (i = 0; i < encodingItems.length; i++) {
  933. encodingLookup[encodingItems[i]] = '\uFEFF' + i;
  934. encodingLookup['\uFEFF' + i] = encodingItems[i];
  935. }
  936. function toHex(match, r, g, b) {
  937. function hex(val) {
  938. val = parseInt(val).toString(16);
  939. return val.length > 1 ? val : '0' + val; // 0 -> 00
  940. };
  941. return '#' + hex(r) + hex(g) + hex(b);
  942. };
  943. return {
  944. toHex : function(color) {
  945. return color.replace(rgbRegExp, toHex);
  946. },
  947. parse : function(css) {
  948. var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope || this;
  949. function compress(prefix, suffix) {
  950. var top, right, bottom, left;
  951. // Get values and check it it needs compressing
  952. top = styles[prefix + '-top' + suffix];
  953. if (!top)
  954. return;
  955. right = styles[prefix + '-right' + suffix];
  956. if (top != right)
  957. return;
  958. bottom = styles[prefix + '-bottom' + suffix];
  959. if (right != bottom)
  960. return;
  961. left = styles[prefix + '-left' + suffix];
  962. if (bottom != left)
  963. return;
  964. // Compress
  965. styles[prefix + suffix] = left;
  966. delete styles[prefix + '-top' + suffix];
  967. delete styles[prefix + '-right' + suffix];
  968. delete styles[prefix + '-bottom' + suffix];
  969. delete styles[prefix + '-left' + suffix];
  970. };
  971. function canCompress(key) {
  972. var value = styles[key], i;
  973. if (!value || value.indexOf(' ') < 0)
  974. return;
  975. value = value.split(' ');
  976. i = value.length;
  977. while (i--) {
  978. if (value[i] !== value[0])
  979. return false;
  980. }
  981. styles[key] = value[0];
  982. return true;
  983. };
  984. function compress2(target, a, b, c) {
  985. if (!canCompress(a))
  986. return;
  987. if (!canCompress(b))
  988. return;
  989. if (!canCompress(c))
  990. return;
  991. // Compress
  992. styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
  993. delete styles[a];
  994. delete styles[b];
  995. delete styles[c];
  996. };
  997. // Encodes the specified string by replacing all \" \' ; : with _<num>
  998. function encode(str) {
  999. isEncoded = true;
  1000. return encodingLookup[str];
  1001. };
  1002. // Decodes the specified string by replacing all _<num> with it's original value \" \' etc
  1003. // It will also decode the \" \' if keep_slashes is set to fale or omitted
  1004. function decode(str, keep_slashes) {
  1005. if (isEncoded) {
  1006. str = str.replace(/\uFEFF[0-9]/g, function(str) {
  1007. return encodingLookup[str];
  1008. });
  1009. }
  1010. if (!keep_slashes)
  1011. str = str.replace(/\\([\'\";:])/g, "$1");
  1012. return str;
  1013. }
  1014. if (css) {
  1015. // Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
  1016. css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) {
  1017. return str.replace(/[;:]/g, encode);
  1018. });
  1019. // Parse styles
  1020. while (matches = styleRegExp.exec(css)) {
  1021. name = matches[1].replace(trimRightRegExp, '').toLowerCase();
  1022. value = matches[2].replace(trimRightRegExp, '');
  1023. if (name && value.length > 0) {
  1024. // Opera will produce 700 instead of bold in their style values
  1025. if (name === 'font-weight' && value === '700')
  1026. value = 'bold';
  1027. else if (name === 'color' || name === 'background-color') // Lowercase colors like RED
  1028. value = value.toLowerCase();
  1029. // Convert RGB colors to HEX
  1030. value = value.replace(rgbRegExp, toHex);
  1031. // Convert URLs and force them into url('value') format
  1032. value = value.replace(urlOrStrRegExp, function(match, url, url2, url3, str, str2) {
  1033. str = str || str2;
  1034. if (str) {
  1035. str = decode(str);
  1036. // Force strings into single quote format
  1037. return "'" + str.replace(/\'/g, "\\'") + "'";
  1038. }
  1039. url = decode(url || url2 || url3);
  1040. // Convert the URL to relative/absolute depending on config
  1041. if (urlConverter)
  1042. url = urlConverter.call(urlConverterScope, url, 'style');
  1043. // Output new URL format
  1044. return "url('" + url.replace(/\'/g, "\\'") + "')";
  1045. });
  1046. styles[name] = isEncoded ? decode(value, true) : value;
  1047. }
  1048. styleRegExp.lastIndex = matches.index + matches[0].length;
  1049. }
  1050. // Compress the styles to reduce it's size for example IE will expand styles
  1051. compress("border", "");
  1052. compress("border", "-width");
  1053. compress("border", "-color");
  1054. compress("border", "-style");
  1055. compress("padding", "");
  1056. compress("margin", "");
  1057. compress2('border', 'border-width', 'border-style', 'border-color');
  1058. // Remove pointless border, IE produces these
  1059. if (styles.border === 'medium none')
  1060. delete styles.border;
  1061. }
  1062. return styles;
  1063. },
  1064. serialize : function(styles, element_name) {
  1065. var css = '', name, value;
  1066. function serializeStyles(name) {
  1067. var styleList, i, l, value;
  1068. styleList = schema.styles[name];
  1069. if (styleList) {
  1070. for (i = 0, l = styleList.length; i < l; i++) {
  1071. name = styleList[i];
  1072. value = styles[name];
  1073. if (value !== undef && value.length > 0)
  1074. css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
  1075. }
  1076. }
  1077. };
  1078. // Serialize styles according to schema
  1079. if (element_name && schema && schema.styles) {
  1080. // Serialize global styles and element specific styles
  1081. serializeStyles('*');
  1082. serializeStyles(element_name);
  1083. } else {
  1084. // Output the styles in the order they are inside the object
  1085. for (name in styles) {
  1086. value = styles[name];
  1087. if (value !== undef && value.length > 0)
  1088. css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
  1089. }
  1090. }
  1091. return css;
  1092. }
  1093. };
  1094. };
  1095. (function(tinymce) {
  1096. var transitional = {}, boolAttrMap, blockElementsMap, shortEndedElementsMap, nonEmptyElementsMap, customElementsMap = {},
  1097. whiteSpaceElementsMap, selfClosingElementsMap, makeMap = tinymce.makeMap, each = tinymce.each;
  1098. function split(str, delim) {
  1099. return str.split(delim || ',');
  1100. };
  1101. function unpack(lookup, data) {
  1102. var key, elements = {};
  1103. function replace(value) {
  1104. return value.replace(/[A-Z]+/g, function(key) {
  1105. return replace(lookup[key]);
  1106. });
  1107. };
  1108. // Unpack lookup
  1109. for (key in lookup) {
  1110. if (lookup.hasOwnProperty(key))
  1111. lookup[key] = replace(lookup[key]);
  1112. }
  1113. // Unpack and parse data into object map
  1114. replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g, function(str, name, attributes, children) {
  1115. attributes = split(attributes, '|');
  1116. elements[name] = {
  1117. attributes : makeMap(attributes),
  1118. attributesOrder : attributes,
  1119. children : makeMap(children, '|', {'#comment' : {}})
  1120. }
  1121. });
  1122. return elements;
  1123. };
  1124. // Build a lookup table for block elements both lowercase and uppercase
  1125. blockElementsMap = 'h1,h2,h3,h4,h5,h6,hr,p,div,address,pre,form,table,tbody,thead,tfoot,' +
  1126. 'th,tr,td,li,ol,ul,caption,blockquote,center,dl,dt,dd,dir,fieldset,' +
  1127. 'noscript,menu,isindex,samp,header,footer,article,section,hgroup';
  1128. blockElementsMap = makeMap(blockElementsMap, ',', makeMap(blockElementsMap.toUpperCase()));
  1129. // This is the XHTML 1.0 transitional elements with it's attributes and children packed to reduce it's size
  1130. transitional = unpack({
  1131. Z : 'H|K|N|O|P',
  1132. Y : 'X|form|R|Q',
  1133. ZG : 'E|span|width|align|char|charoff|valign',
  1134. X : 'p|T|div|U|W|isindex|fieldset|table',
  1135. ZF : 'E|align|char|charoff|valign',
  1136. W : 'pre|hr|blockquote|address|center|noframes',
  1137. ZE : 'abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height',
  1138. ZD : '[E][S]',
  1139. U : 'ul|ol|dl|menu|dir',
  1140. ZC : 'p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q',
  1141. T : 'h1|h2|h3|h4|h5|h6',
  1142. ZB : 'X|S|Q',
  1143. S : 'R|P',
  1144. ZA : 'a|G|J|M|O|P',
  1145. R : 'a|H|K|N|O',
  1146. Q : 'noscript|P',
  1147. P : 'ins|del|script',
  1148. O : 'input|select|textarea|label|button',
  1149. N : 'M|L',
  1150. M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym',
  1151. L : 'sub|sup',
  1152. K : 'J|I',
  1153. J : 'tt|i|b|u|s|strike',
  1154. I : 'big|small|font|basefont',
  1155. H : 'G|F',
  1156. G : 'br|span|bdo',
  1157. F : 'object|applet|img|map|iframe',
  1158. E : 'A|B|C',
  1159. D : 'accesskey|tabindex|onfocus|onblur',
  1160. C : 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
  1161. B : 'lang|xml:lang|dir',
  1162. A : 'id|class|style|title'
  1163. }, 'script[id|charset|type|language|src|defer|xml:space][]' +
  1164. 'style[B|id|type|media|title|xml:space][]' +
  1165. 'object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]' +
  1166. 'param[id|name|value|valuetype|type][]' +
  1167. 'p[E|align][#|S]' +
  1168. 'a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]' +
  1169. 'br[A|clear][]' +
  1170. 'span[E][#|S]' +
  1171. 'bdo[A|C|B][#|S]' +
  1172. 'applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]' +
  1173. 'h1[E|align][#|S]' +
  1174. 'img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]' +
  1175. 'map[B|C|A|name][X|form|Q|area]' +
  1176. 'h2[E|align][#|S]' +
  1177. 'iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]' +
  1178. 'h3[E|align][#|S]' +
  1179. 'tt[E][#|S]' +
  1180. 'i[E][#|S]' +
  1181. 'b[E][#|S]' +
  1182. 'u[E][#|S]' +
  1183. 's[E][#|S]' +
  1184. 'strike[E][#|S]' +
  1185. 'big[E][#|S]' +
  1186. 'small[E][#|S]' +
  1187. 'font[A|B|size|color|face][#|S]' +
  1188. 'basefont[id|size|color|face][]' +
  1189. 'em[E][#|S]' +
  1190. 'strong[E][#|S]' +
  1191. 'dfn[E][#|S]' +
  1192. 'code[E][#|S]' +
  1193. 'q[E|cite][#|S]' +
  1194. 'samp[E][#|S]' +
  1195. 'kbd[E][#|S]' +
  1196. 'var[E][#|S]' +
  1197. 'cite[E][#|S]' +
  1198. 'abbr[E][#|S]' +
  1199. 'acronym[E][#|S]' +
  1200. 'sub[E][#|S]' +
  1201. 'sup[E][#|S]' +
  1202. 'input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]' +
  1203. 'select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]' +
  1204. 'optgroup[E|disabled|label][option]' +
  1205. 'option[E|selected|disabled|label|value][]' +
  1206. 'textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]' +
  1207. 'label[E|for|accesskey|onfocus|onblur][#|S]' +
  1208. 'button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' +
  1209. 'h4[E|align][#|S]' +
  1210. 'ins[E|cite|datetime][#|Y]' +
  1211. 'h5[E|align][#|S]' +
  1212. 'del[E|cite|datetime][#|Y]' +
  1213. 'h6[E|align][#|S]' +
  1214. 'div[E|align][#|Y]' +
  1215. 'ul[E|type|compact][li]' +
  1216. 'li[E|type|value][#|Y]' +
  1217. 'ol[E|type|compact|start][li]' +
  1218. 'dl[E|compact][dt|dd]' +
  1219. 'dt[E][#|S]' +
  1220. 'dd[E][#|Y]' +
  1221. 'menu[E|compact][li]' +
  1222. 'dir[E|compact][li]' +
  1223. 'pre[E|width|xml:space][#|ZA]' +
  1224. 'hr[E|align|noshade|size|width][]' +
  1225. 'blockquote[E|cite][#|Y]' +
  1226. 'address[E][#|S|p]' +
  1227. 'center[E][#|Y]' +
  1228. 'noframes[E][#|Y]' +
  1229. 'isindex[A|B|prompt][]' +
  1230. 'fieldset[E][#|legend|Y]' +
  1231. 'legend[E|accesskey|align][#|S]' +
  1232. 'table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]' +
  1233. 'caption[E|align][#|S]' +
  1234. 'col[ZG][]' +
  1235. 'colgroup[ZG][col]' +
  1236. 'thead[ZF][tr]' +
  1237. 'tr[ZF|bgcolor][th|td]' +
  1238. 'th[E|ZE][#|Y]' +
  1239. 'form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]' +
  1240. 'noscript[E][#|Y]' +
  1241. 'td[E|ZE][#|Y]' +
  1242. 'tfoot[ZF][tr]' +
  1243. 'tbody[ZF][tr]' +
  1244. 'area[E|D|shape|coords|href|nohref|alt|target][]' +
  1245. 'base[id|href|target][]' +
  1246. 'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
  1247. );
  1248. boolAttrMap = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected,preload,autoplay,loop,controls');
  1249. shortEndedElementsMap = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,source');
  1250. nonEmptyElementsMap = tinymce.extend(makeMap('td,th,iframe,video,object'), shortEndedElementsMap);
  1251. whiteSpaceElementsMap = makeMap('pre,script,style');
  1252. selfClosingElementsMap = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
  1253. tinymce.html.Schema = function(settings) {
  1254. var self = this, elements = {}, children = {}, patternElements = [], validStyles;
  1255. settings = settings || {};
  1256. // Allow all elements and attributes if verify_html is set to false
  1257. if (settings.verify_html === false)
  1258. settings.valid_elements = '*[*]';
  1259. // Build styles list
  1260. if (settings.valid_styles) {
  1261. validStyles = {};
  1262. // Convert styles into a rule list
  1263. each(settings.valid_styles, function(value, key) {
  1264. validStyles[key] = tinymce.explode(value);
  1265. });
  1266. }
  1267. // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
  1268. function patternToRegExp(str) {
  1269. return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
  1270. };
  1271. // Parses the specified valid_elements string and adds to the current rules
  1272. // This function is a bit hard to read since it's heavily optimized for speed
  1273. function addValidElements(valid_elements) {
  1274. var ei, el, ai, al, yl, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
  1275. prefix, outputName, globalAttributes, globalAttributesOrder, transElement, key, childKey, value,
  1276. elementRuleRegExp = /^([#+-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,
  1277. attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
  1278. hasPatternsRegExp = /[*?+]/;
  1279. if (valid_elements) {
  1280. // Split valid elements into an array with rules
  1281. valid_elements = split(valid_elements);
  1282. if (elements['@']) {
  1283. globalAttributes = elements['@'].attributes;
  1284. globalAttributesOrder = elements['@'].attributesOrder;
  1285. }
  1286. // Loop all rules
  1287. for (ei = 0, el = valid_elements.length; ei < el; ei++) {
  1288. // Parse element rule
  1289. matches = elementRuleRegExp.exec(valid_elements[ei]);
  1290. if (matches) {
  1291. // Setup local names for matches
  1292. prefix = matches[1];
  1293. elementName = matches[2];
  1294. outputName = matches[3];
  1295. attrData = matches[4];
  1296. // Create new attributes and attributesOrder
  1297. attributes = {};
  1298. attributesOrder = [];
  1299. // Create the new element
  1300. element = {
  1301. attributes : attributes,
  1302. attributesOrder : attributesOrder
  1303. };
  1304. // Padd empty elements prefix
  1305. if (prefix === '#')
  1306. element.paddEmpty = true;
  1307. // Remove empty elements prefix
  1308. if (prefix === '-')
  1309. element.removeEmpty = true;
  1310. // Copy attributes from global rule into current rule
  1311. if (globalAttributes) {
  1312. for (key in globalAttributes)
  1313. attributes[key] = globalAttributes[key];
  1314. attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
  1315. }
  1316. // Attributes defined
  1317. if (attrData) {
  1318. attrData = split(attrData, '|');
  1319. for (ai = 0, al = attrData.length; ai < al; ai++) {
  1320. matches = attrRuleRegExp.exec(attrData[ai]);
  1321. if (matches) {
  1322. attr = {};
  1323. attrType = matches[1];
  1324. attrName = matches[2].replace(/::/g, ':');
  1325. prefix = matches[3];
  1326. value = matches[4];
  1327. // Required
  1328. if (attrType === '!') {
  1329. element.attributesRequired = element.attributesRequired || [];
  1330. element.attributesRequired.push(attrName);
  1331. attr.required = true;
  1332. }
  1333. // Denied from global
  1334. if (attrType === '-') {
  1335. delete attributes[attrName];
  1336. attributesOrder.splice(tinymce.inArray(attributesOrder, attrName), 1);
  1337. continue;
  1338. }
  1339. // Default value
  1340. if (prefix) {
  1341. // Default value
  1342. if (prefix === '=') {
  1343. element.attributesDefault = element.attributesDefault || [];
  1344. element.attributesDefault.push({name: attrName, value: value});
  1345. attr.defaultValue = value;
  1346. }
  1347. // Forced value
  1348. if (prefix === ':') {
  1349. element.attributesForced = element.attributesForced || [];
  1350. element.attributesForced.push({name: attrName, value: value});
  1351. attr.forcedValue = value;
  1352. }
  1353. // Required values
  1354. if (prefix === '<')
  1355. attr.validValues = makeMap(value, '?');
  1356. }
  1357. // Check for attribute patterns
  1358. if (hasPatternsRegExp.test(attrName)) {
  1359. element.attributePatterns = element.attributePatterns || [];
  1360. attr.pattern = patternToRegExp(attrName);
  1361. element.attributePatterns.push(attr);
  1362. } else {
  1363. // Add attribute to order list if it doesn't already exist
  1364. if (!attributes[attrName])
  1365. attributesOrder.push(attrName);
  1366. attributes[attrName] = attr;
  1367. }
  1368. }
  1369. }
  1370. }
  1371. // Global rule, store away these for later usage
  1372. if (!globalAttributes && elementName == '@') {
  1373. globalAttributes = attributes;
  1374. globalAttributesOrder = attributesOrder;
  1375. }
  1376. // Handle substitute elements such as b/strong
  1377. if (outputName) {
  1378. element.outputName = elementName;
  1379. elements[outputName] = element;
  1380. }
  1381. // Add pattern or exact element
  1382. if (hasPatternsRegExp.test(elementName)) {
  1383. element.pattern = patternToRegExp(elementName);
  1384. patternElements.push(element);
  1385. } else
  1386. elements[elementName] = element;
  1387. }
  1388. }
  1389. }
  1390. };
  1391. function setValidElements(valid_elements) {
  1392. elements = {};
  1393. patternElements = [];
  1394. addValidElements(valid_elements);
  1395. each(transitional, function(element, name) {
  1396. children[name] = element.children;
  1397. });
  1398. };
  1399. // Adds custom non HTML elements to the schema
  1400. function addCustomElements(custom_elements) {
  1401. var customElementRegExp = /^(~)?(.+)$/;
  1402. if (custom_elements) {
  1403. each(split(custom_elements), function(rule) {
  1404. var matches = customElementRegExp.exec(rule),
  1405. inline = matches[1] === '~',
  1406. cloneName = inline ? 'span' : 'div',
  1407. name = matches[2];
  1408. children[name] = children[cloneName];
  1409. customElementsMap[name] = cloneName;
  1410. // If it's not marked as inline then add it to valid block elements
  1411. if (!inline)
  1412. blockElementsMap[name] = {};
  1413. // Add custom elements at span/div positions
  1414. each(children, function(element, child) {
  1415. if (element[cloneName])
  1416. element[name] = element[cloneName];
  1417. });
  1418. });
  1419. }
  1420. };
  1421. // Adds valid children to the schema object
  1422. function addValidChildren(valid_children) {
  1423. var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
  1424. if (valid_children) {
  1425. each(split(valid_children), function(rule) {
  1426. var matches = childRuleRegExp.exec(rule), parent, prefix;
  1427. if (matches) {
  1428. prefix = matches[1];
  1429. // Add/remove items from default
  1430. if (prefix)
  1431. parent = children[matches[2]];
  1432. else
  1433. parent = children[matches[2]] = {'#comment' : {}};
  1434. parent = children[matches[2]];
  1435. each(split(matches[3], '|'), function(child) {
  1436. if (prefix === '-')
  1437. delete parent[child];
  1438. else
  1439. parent[child] = {};
  1440. });
  1441. }
  1442. });
  1443. }
  1444. }
  1445. if (!settings.valid_elements) {
  1446. // No valid elements defined then clone the elements from the transitional spec
  1447. each(transitional, function(element, name) {
  1448. elements[name] = {
  1449. attributes : element.attributes,
  1450. attributesOrder : element.attributesOrder
  1451. };
  1452. children[name] = element.children;
  1453. });
  1454. // Switch these
  1455. each(split('strong/b,em/i'), function(item) {
  1456. item = split(item, '/');
  1457. elements[item[1]].outputName = item[0];
  1458. });
  1459. // Add default alt attribute for images
  1460. elements.img.attributesDefault = [{name: 'alt', value: ''}];
  1461. // Remove these if they are empty by default
  1462. each(split('ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr'), function(name) {
  1463. elements[name].removeEmpty = true;
  1464. });
  1465. // Padd these by default
  1466. each(split('p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption'), function(name) {
  1467. elements[name].paddEmpty = true;
  1468. });
  1469. } else
  1470. setValidElements(settings.valid_elements);
  1471. addCustomElements(settings.custom_elements);

Large files files are truncated, but you can click here to view the full file