tinymce-rails 4.0.2 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/app/assets/source/tinymce/tinymce.jquery.js +975 -599
  2. data/app/assets/source/tinymce/tinymce.js +975 -599
  3. data/lib/tinymce/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  5. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  6. data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
  7. data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/example/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -0
  12. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/template/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/css/visualblocks.css +14 -0
  23. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.eot +0 -0
  25. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.svg +150 -141
  26. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.ttf +0 -0
  27. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.woff +0 -0
  28. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.eot +0 -0
  29. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.svg +132 -129
  30. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.ttf +0 -0
  31. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.woff +0 -0
  32. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  33. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
  34. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +9 -9
  36. data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
  37. metadata +3 -7
  38. data/vendor/assets/javascripts/tinymce/plugins/compat3x/editable_selects.js +0 -70
  39. data/vendor/assets/javascripts/tinymce/plugins/compat3x/form_utils.js +0 -210
  40. data/vendor/assets/javascripts/tinymce/plugins/compat3x/mctabs.js +0 -162
  41. data/vendor/assets/javascripts/tinymce/plugins/compat3x/tiny_mce_popup.js +0 -435
  42. data/vendor/assets/javascripts/tinymce/plugins/compat3x/validate.js +0 -252
@@ -1,4 +1,4 @@
1
- // 4.0.2 (2013-07-18)
1
+ // 4.0.6 (2013-09-12)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -101,6 +101,7 @@ define("tinymce/dom/EventUtils", [], function() {
101
101
 
102
102
  var eventExpandoPrefix = "mce-data-";
103
103
  var mouseEventRe = /^(?:mouse|contextmenu)|click/;
104
+ var deprecated = {keyLocation: 1, layerX: 1, layerY: 1, returnValue: 1};
104
105
 
105
106
  /**
106
107
  * Binds a native event to a callback on the speified target.
@@ -143,7 +144,7 @@ define("tinymce/dom/EventUtils", [], function() {
143
144
  // Copy all properties from the original event
144
145
  for (name in originalEvent) {
145
146
  // layerX/layerY is deprecated in Chrome and produces a warning
146
- if (name !== "layerX" && name !== "layerY") {
147
+ if (!deprecated[name]) {
147
148
  event[name] = originalEvent[name];
148
149
  }
149
150
  }
@@ -478,6 +479,13 @@ define("tinymce/dom/EventUtils", [], function() {
478
479
  ci = callbackList.length;
479
480
  while (ci--) {
480
481
  if (callbackList[ci].func === callback) {
482
+ var nativeHandler = callbackList.nativeHandler;
483
+
484
+ // Clone callbackList since unbind inside a callback would otherwise break the handlers loop
485
+ callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
486
+ callbackList.nativeHandler = nativeHandler;
487
+
488
+ eventMap[name] = callbackList;
481
489
  callbackList.splice(ci, 1);
482
490
  }
483
491
  }
@@ -1236,7 +1244,7 @@ setDocument = Sizzle.setDocument = function( node ) {
1236
1244
  rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1237
1245
 
1238
1246
  // Element contains another
1239
- // Purposefully does not implement inclusive descendent
1247
+ // Purposefully does not implement inclusive descendant
1240
1248
  // As in, an element does not contain itself
1241
1249
  contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
1242
1250
  function( a, b ) {
@@ -4311,7 +4319,11 @@ define("tinymce/dom/Range", [
4311
4319
  if (o) {
4312
4320
  startContainer.insertBefore(n, o);
4313
4321
  } else {
4314
- startContainer.appendChild(n);
4322
+ if (startContainer.nodeType == 3) {
4323
+ dom.insertAfter(n, startContainer);
4324
+ } else {
4325
+ startContainer.appendChild(n);
4326
+ }
4315
4327
  }
4316
4328
  }
4317
4329
  }
@@ -5231,12 +5243,14 @@ define("tinymce/html/Entities", [
5231
5243
  */
5232
5244
  define("tinymce/Env", [], function() {
5233
5245
  var nav = navigator, userAgent = nav.userAgent;
5234
- var opera, webkit, ie, gecko, mac, iDevice;
5246
+ var opera, webkit, ie, ie11, gecko, mac, iDevice;
5235
5247
 
5236
5248
  opera = window.opera && window.opera.buildNumber;
5237
5249
  webkit = /WebKit/.test(userAgent);
5238
5250
  ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
5239
5251
  ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
5252
+ ie11 = userAgent.indexOf('Trident') != -1 ? 11 : false;
5253
+ ie = ie || ie11;
5240
5254
  gecko = !webkit && /Gecko/.test(userAgent);
5241
5255
  mac = userAgent.indexOf('Mac') != -1;
5242
5256
  iDevice = /(iPad|iPhone)/.test(userAgent);
@@ -5403,6 +5417,7 @@ define("tinymce/dom/DOMUtils", [
5403
5417
  self.stdMode = !isIE || doc.documentMode >= 8;
5404
5418
  self.boxModel = !isIE || doc.compatMode == "CSS1Compat" || self.stdMode;
5405
5419
  self.hasOuterHTML = "outerHTML" in doc.createElement("a");
5420
+ this.boundEvents = [];
5406
5421
 
5407
5422
  self.settings = settings = extend({
5408
5423
  keep_values: false,
@@ -6034,7 +6049,7 @@ define("tinymce/dom/DOMUtils", [
6034
6049
  }
6035
6050
 
6036
6051
  // IE & Opera
6037
- if (name.currentStyle && computed) {
6052
+ if (elm.currentStyle && computed) {
6038
6053
  return elm.currentStyle[name];
6039
6054
  }
6040
6055
 
@@ -6331,8 +6346,8 @@ define("tinymce/dom/DOMUtils", [
6331
6346
  * Returns the absolute x, y position of a node. The position will be returned in an object with x, y fields.
6332
6347
  *
6333
6348
  * @method getPos
6334
- * @param {Element/String} n HTML element or element id to get x, y position from.
6335
- * @param {Element} ro Optional root element to stop calculations at.
6349
+ * @param {Element/String} elm HTML element or element id to get x, y position from.
6350
+ * @param {Element} rootElm Optional root element to stop calculations at.
6336
6351
  * @return {object} Absolute position of the specified element object with x, y fields.
6337
6352
  */
6338
6353
  getPos: function(elm, rootElm) {
@@ -6947,78 +6962,6 @@ define("tinymce/dom/DOMUtils", [
6947
6962
  return this.styles.toHex(Tools.trim(rgbVal));
6948
6963
  },
6949
6964
 
6950
- /**
6951
- * Returns an array of all single CSS classes in the document. A single CSS class is a simple
6952
- * rule like ".class" - complex ones like "div td.class" will not be added to output.
6953
- *
6954
- * @method getClasses
6955
- * @return {Array} Array with class objects - each object has a class field - might be other fields in the future.
6956
- */
6957
- getClasses: function() {
6958
- var self = this, classList = [], lookup = {}, filter = self.settings.class_filter, oldVal;
6959
-
6960
- if (self.classes) {
6961
- return self.classes;
6962
- }
6963
-
6964
- function addClasses(stylesheet) {
6965
- // IE style imports
6966
- each(stylesheet.imports, function(r) {
6967
- addClasses(r);
6968
- });
6969
-
6970
- each(stylesheet.cssRules || stylesheet.rules, function(rule) {
6971
- // Real type or fake it on IE
6972
- switch (rule.type || 1) {
6973
- // Rule
6974
- case 1:
6975
- if (rule.selectorText) {
6976
- each(rule.selectorText.split(','), function(value) {
6977
- value = value.replace(/^\s*|\s*$|^\s\./g, "");
6978
-
6979
- // Is internal or it doesn't contain a class
6980
- if (/\.mce/.test(value) || !/\.[\w\-]+$/.test(value)) {
6981
- return;
6982
- }
6983
-
6984
- // Remove everything but class name
6985
- oldVal = value;
6986
- value = value.replace(/.*\.([a-z0-9_\-]+).*/i, '$1');
6987
-
6988
- // Filter classes
6989
- if (filter && !(value = filter(value, oldVal))) {
6990
- return;
6991
- }
6992
-
6993
- if (!lookup[value]) {
6994
- classList.push({'class': value});
6995
- lookup[value] = 1;
6996
- }
6997
- });
6998
- }
6999
- break;
7000
-
7001
- // Import
7002
- case 3:
7003
- addClasses(rule.styleSheet);
7004
- break;
7005
- }
7006
- });
7007
- }
7008
-
7009
- try {
7010
- each(self.doc.styleSheets, addClasses);
7011
- } catch (ex) {
7012
- // Ignore
7013
- }
7014
-
7015
- if (classList.length > 0) {
7016
- self.classes = classList;
7017
- }
7018
-
7019
- return classList;
7020
- },
7021
-
7022
6965
  /**
7023
6966
  * Executes the specified function on the element by id or dom element node or array of elements/id.
7024
6967
  *
@@ -7315,28 +7258,70 @@ define("tinymce/dom/DOMUtils", [
7315
7258
  * Adds an event handler to the specified object.
7316
7259
  *
7317
7260
  * @method bind
7318
- * @param {Element/Document/Window/Array/String} o Object or element id string to add event
7261
+ * @param {Element/Document/Window/Array} target Target element to bind events to.
7319
7262
  * handler to or an array of elements/ids/documents.
7320
- * @param {String} n Name of event handler to add, for example: click.
7321
- * @param {function} f Function to execute when the event occurs.
7322
- * @param {Object} s Optional scope to execute the function in.
7263
+ * @param {String} name Name of event handler to add, for example: click.
7264
+ * @param {function} func Function to execute when the event occurs.
7265
+ * @param {Object} scope Optional scope to execute the function in.
7323
7266
  * @return {function} Function callback handler the same as the one passed in.
7324
7267
  */
7325
7268
  bind: function(target, name, func, scope) {
7326
- return this.events.bind(target, name, func, scope || this);
7269
+ var self = this;
7270
+
7271
+ if (Tools.isArray(target)) {
7272
+ var i = target.length;
7273
+
7274
+ while (i--) {
7275
+ target[i] = self.bind(target[i], name, func, scope);
7276
+ }
7277
+
7278
+ return target;
7279
+ }
7280
+
7281
+ // Collect all window/document events bound by editor instance
7282
+ if (self.settings.collect && (target === self.doc || target === self.win)) {
7283
+ self.boundEvents.push([target, name, func, scope]);
7284
+ }
7285
+
7286
+ return self.events.bind(target, name, func, scope || self);
7327
7287
  },
7328
7288
 
7329
7289
  /**
7330
7290
  * Removes the specified event handler by name and function from an element or collection of elements.
7331
7291
  *
7332
7292
  * @method unbind
7333
- * @param {String/Element/Array} o Element ID string or HTML element or an array of elements or ids to remove handler from.
7334
- * @param {String} n Event handler name, for example: "click"
7335
- * @param {function} f Function to remove.
7293
+ * @param {Element/Document/Window/Array} target Target element to unbind events on.
7294
+ * @param {String} name Event handler name, for example: "click"
7295
+ * @param {function} func Function to remove.
7336
7296
  * @return {bool/Array} Bool state of true if the handler was removed, or an array of states if multiple input elements
7337
7297
  * were passed in.
7338
7298
  */
7339
7299
  unbind: function(target, name, func) {
7300
+ var self = this, i;
7301
+
7302
+ if (Tools.isArray(target)) {
7303
+ i = target.length;
7304
+
7305
+ while (i--) {
7306
+ target[i] = self.unbind(target[i], name, func);
7307
+ }
7308
+
7309
+ return target;
7310
+ }
7311
+
7312
+ // Remove any bound events matching the input
7313
+ if (self.boundEvents && (target === self.doc || target === self.win)) {
7314
+ i = self.boundEvents.length;
7315
+
7316
+ while (i--) {
7317
+ var item = self.boundEvents[i];
7318
+
7319
+ if (target == item[0] && (!name || name == item[1]) && (!func || func == item[2])) {
7320
+ this.events.unbind(item[0], item[1], item[2]);
7321
+ }
7322
+ }
7323
+ }
7324
+
7340
7325
  return this.events.unbind(target, name, func);
7341
7326
  },
7342
7327
 
@@ -7380,6 +7365,18 @@ define("tinymce/dom/DOMUtils", [
7380
7365
  destroy: function() {
7381
7366
  var self = this;
7382
7367
 
7368
+ // Unbind all events bound to window/document by editor instance
7369
+ if (self.boundEvents) {
7370
+ var i = self.boundEvents.length;
7371
+
7372
+ while (i--) {
7373
+ var item = self.boundEvents[i];
7374
+ this.events.unbind(item[0], item[1], item[2]);
7375
+ }
7376
+
7377
+ self.boundEvents = null;
7378
+ }
7379
+
7383
7380
  self.win = self.doc = self.root = self.events = self.frag = null;
7384
7381
  },
7385
7382
 
@@ -7708,182 +7705,180 @@ define("tinymce/dom/ScriptLoader", [
7708
7705
  * @class tinymce.AddOnManager
7709
7706
  */
7710
7707
  define("tinymce/AddOnManager", [
7711
- "tinymce/dom/ScriptLoader",
7712
- "tinymce/util/Tools"
7708
+ "tinymce/dom/ScriptLoader",
7709
+ "tinymce/util/Tools"
7713
7710
  ], function(ScriptLoader, Tools) {
7714
- var each = Tools.each;
7715
-
7716
- function AddOnManager() {
7717
- var self = this;
7718
-
7719
- self.items = [];
7720
- self.urls = {};
7721
- self.lookup = {};
7722
- }
7723
-
7724
- AddOnManager.prototype = {
7725
- /**
7726
- * Returns the specified add on by the short name.
7727
- *
7728
- * @method get
7729
- * @param {String} name Add-on to look for.
7730
- * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
7731
- */
7732
- get: function(name) {
7733
- if (this.lookup[name]) {
7734
- return this.lookup[name].instance;
7735
- } else {
7736
- return undefined;
7737
- }
7738
- },
7739
-
7740
- dependencies: function(name) {
7741
- var result;
7742
-
7743
- if (this.lookup[name]) {
7744
- result = this.lookup[name].dependencies;
7745
- }
7746
-
7747
- return result || [];
7748
- },
7749
-
7750
- /**
7751
- * Loads a language pack for the specified add-on.
7752
- *
7753
- * @method requireLangPack
7754
- * @param {String} name Short name of the add-on.
7755
- */
7756
- requireLangPack: function(name) {
7757
- var settings = AddOnManager.settings;
7758
-
7759
- if (settings && settings.language && settings.language_load !== false) {
7760
- ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + settings.language + '.js');
7761
- }
7762
- },
7763
-
7764
- /**
7765
- * Adds a instance of the add-on by it's short name.
7766
- *
7767
- * @method add
7768
- * @param {String} id Short name/id for the add-on.
7769
- * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add.
7770
- * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
7771
- * @example
7772
- * // Create a simple plugin
7773
- * tinymce.create('tinymce.plugins.TestPlugin', {
7774
- * TestPlugin: function(ed, url) {
7775
- * ed.on('click', function(e) {
7776
- * ed.windowManager.alert('Hello World!');
7777
- * });
7778
- * }
7779
- * });
7780
- *
7781
- * // Register plugin using the add method
7782
- * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
7783
- *
7784
- * // Initialize TinyMCE
7785
- * tinymce.init({
7786
- * ...
7787
- * plugins: '-test' // Init the plugin but don't try to load it
7788
- * });
7789
- */
7790
- add: function(id, addOn, dependencies) {
7791
- this.items.push(addOn);
7792
- this.lookup[id] = {instance: addOn, dependencies: dependencies};
7793
-
7794
- return addOn;
7795
- },
7796
-
7797
- createUrl: function(baseUrl, dep) {
7798
- if (typeof dep === "object") {
7799
- return dep;
7800
- } else {
7801
- return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
7802
- }
7803
- },
7804
-
7805
- /**
7806
- * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
7807
- * This should be used in development mode. A new compressor/javascript munger process will ensure that the
7808
- * components are put together into the plugin.js file and compressed correctly.
7809
- *
7810
- * @method addComponents
7811
- * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins).
7812
- * @param {Array} scripts Array containing the names of the scripts to load.
7813
- */
7814
- addComponents: function(pluginName, scripts) {
7815
- var pluginUrl = this.urls[pluginName];
7816
-
7817
- each(scripts, function(script) {
7818
- ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script);
7819
- });
7820
- },
7821
-
7822
- /**
7823
- * Loads an add-on from a specific url.
7824
- *
7825
- * @method load
7826
- * @param {String} n Short name of the add-on that gets loaded.
7827
- * @param {String} u URL to the add-on that will get loaded.
7828
- * @param {function} cb Optional callback to execute ones the add-on is loaded.
7829
- * @param {Object} s Optional scope to execute the callback in.
7830
- * @example
7831
- * // Loads a plugin from an external URL
7832
- * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
7833
- *
7834
- * // Initialize TinyMCE
7835
- * tinymce.init({
7836
- * ...
7837
- * plugins: '-myplugin' // Don't try to load it again
7838
- * });
7839
- */
7840
- load: function(n, u, cb, s) {
7841
- var t = this, url = u;
7842
-
7843
- function loadDependencies() {
7844
- var dependencies = t.dependencies(n);
7845
-
7846
- each(dependencies, function(dep) {
7847
- var newUrl = t.createUrl(u, dep);
7848
-
7849
- t.load(newUrl.resource, newUrl, undefined, undefined);
7850
- });
7851
-
7852
- if (cb) {
7853
- if (s) {
7854
- cb.call(s);
7855
- } else {
7856
- cb.call(ScriptLoader);
7857
- }
7858
- }
7859
- }
7860
-
7861
- if (t.urls[n]) {
7862
- return;
7863
- }
7864
-
7865
- if (typeof u === "object") {
7866
- url = u.prefix + u.resource + u.suffix;
7867
- }
7868
-
7869
- if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) {
7870
- url = AddOnManager.baseURL + '/' + url;
7871
- }
7872
-
7873
- t.urls[n] = url.substring(0, url.lastIndexOf('/'));
7874
-
7875
- if (t.lookup[n]) {
7876
- loadDependencies();
7877
- } else {
7878
- ScriptLoader.ScriptLoader.add(url, loadDependencies, s);
7879
- }
7880
- }
7881
- };
7882
-
7883
- AddOnManager.PluginManager = new AddOnManager();
7884
- AddOnManager.ThemeManager = new AddOnManager();
7885
-
7886
- return AddOnManager;
7711
+ var each = Tools.each;
7712
+
7713
+ function AddOnManager() {
7714
+ var self = this;
7715
+
7716
+ self.items = [];
7717
+ self.urls = {};
7718
+ self.lookup = {};
7719
+ }
7720
+
7721
+ AddOnManager.prototype = {
7722
+ /**
7723
+ * Returns the specified add on by the short name.
7724
+ *
7725
+ * @method get
7726
+ * @param {String} name Add-on to look for.
7727
+ * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
7728
+ */
7729
+ get: function(name) {
7730
+ if (this.lookup[name]) {
7731
+ return this.lookup[name].instance;
7732
+ } else {
7733
+ return undefined;
7734
+ }
7735
+ },
7736
+
7737
+ dependencies: function(name) {
7738
+ var result;
7739
+
7740
+ if (this.lookup[name]) {
7741
+ result = this.lookup[name].dependencies;
7742
+ }
7743
+
7744
+ return result || [];
7745
+ },
7746
+
7747
+ /**
7748
+ * Loads a language pack for the specified add-on.
7749
+ *
7750
+ * @method requireLangPack
7751
+ * @param {String} name Short name of the add-on.
7752
+ */
7753
+ requireLangPack: function(name) {
7754
+ if (AddOnManager.language && AddOnManager.languageLoad !== false) {
7755
+ ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
7756
+ }
7757
+ },
7758
+
7759
+ /**
7760
+ * Adds a instance of the add-on by it's short name.
7761
+ *
7762
+ * @method add
7763
+ * @param {String} id Short name/id for the add-on.
7764
+ * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add.
7765
+ * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
7766
+ * @example
7767
+ * // Create a simple plugin
7768
+ * tinymce.create('tinymce.plugins.TestPlugin', {
7769
+ * TestPlugin: function(ed, url) {
7770
+ * ed.on('click', function(e) {
7771
+ * ed.windowManager.alert('Hello World!');
7772
+ * });
7773
+ * }
7774
+ * });
7775
+ *
7776
+ * // Register plugin using the add method
7777
+ * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
7778
+ *
7779
+ * // Initialize TinyMCE
7780
+ * tinymce.init({
7781
+ * ...
7782
+ * plugins: '-test' // Init the plugin but don't try to load it
7783
+ * });
7784
+ */
7785
+ add: function(id, addOn, dependencies) {
7786
+ this.items.push(addOn);
7787
+ this.lookup[id] = {instance: addOn, dependencies: dependencies};
7788
+
7789
+ return addOn;
7790
+ },
7791
+
7792
+ createUrl: function(baseUrl, dep) {
7793
+ if (typeof dep === "object") {
7794
+ return dep;
7795
+ } else {
7796
+ return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
7797
+ }
7798
+ },
7799
+
7800
+ /**
7801
+ * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
7802
+ * This should be used in development mode. A new compressor/javascript munger process will ensure that the
7803
+ * components are put together into the plugin.js file and compressed correctly.
7804
+ *
7805
+ * @method addComponents
7806
+ * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins).
7807
+ * @param {Array} scripts Array containing the names of the scripts to load.
7808
+ */
7809
+ addComponents: function(pluginName, scripts) {
7810
+ var pluginUrl = this.urls[pluginName];
7811
+
7812
+ each(scripts, function(script) {
7813
+ ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script);
7814
+ });
7815
+ },
7816
+
7817
+ /**
7818
+ * Loads an add-on from a specific url.
7819
+ *
7820
+ * @method load
7821
+ * @param {String} n Short name of the add-on that gets loaded.
7822
+ * @param {String} u URL to the add-on that will get loaded.
7823
+ * @param {function} cb Optional callback to execute ones the add-on is loaded.
7824
+ * @param {Object} s Optional scope to execute the callback in.
7825
+ * @example
7826
+ * // Loads a plugin from an external URL
7827
+ * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
7828
+ *
7829
+ * // Initialize TinyMCE
7830
+ * tinymce.init({
7831
+ * ...
7832
+ * plugins: '-myplugin' // Don't try to load it again
7833
+ * });
7834
+ */
7835
+ load: function(n, u, cb, s) {
7836
+ var t = this, url = u;
7837
+
7838
+ function loadDependencies() {
7839
+ var dependencies = t.dependencies(n);
7840
+
7841
+ each(dependencies, function(dep) {
7842
+ var newUrl = t.createUrl(u, dep);
7843
+
7844
+ t.load(newUrl.resource, newUrl, undefined, undefined);
7845
+ });
7846
+
7847
+ if (cb) {
7848
+ if (s) {
7849
+ cb.call(s);
7850
+ } else {
7851
+ cb.call(ScriptLoader);
7852
+ }
7853
+ }
7854
+ }
7855
+
7856
+ if (t.urls[n]) {
7857
+ return;
7858
+ }
7859
+
7860
+ if (typeof u === "object") {
7861
+ url = u.prefix + u.resource + u.suffix;
7862
+ }
7863
+
7864
+ if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) {
7865
+ url = AddOnManager.baseURL + '/' + url;
7866
+ }
7867
+
7868
+ t.urls[n] = url.substring(0, url.lastIndexOf('/'));
7869
+
7870
+ if (t.lookup[n]) {
7871
+ loadDependencies();
7872
+ } else {
7873
+ ScriptLoader.ScriptLoader.add(url, loadDependencies, s);
7874
+ }
7875
+ }
7876
+ };
7877
+
7878
+ AddOnManager.PluginManager = new AddOnManager();
7879
+ AddOnManager.ThemeManager = new AddOnManager();
7880
+
7881
+ return AddOnManager;
7887
7882
  });
7888
7883
 
7889
7884
  /**
@@ -9021,7 +9016,13 @@ define("tinymce/html/Schema", [
9021
9016
 
9022
9017
  // Add elements clone if needed
9023
9018
  if (!elements[name]) {
9024
- elements[name] = elements[cloneName];
9019
+ var customRule = elements[cloneName];
9020
+
9021
+ customRule = extend({}, customRule);
9022
+ delete customRule.removeEmptyAttrs;
9023
+ delete customRule.removeEmpty;
9024
+
9025
+ elements[name] = customRule;
9025
9026
  }
9026
9027
 
9027
9028
  // Add custom elements at span/div positions
@@ -10908,7 +10909,7 @@ define("tinymce/dom/Serializer", [
10908
10909
  var DOM = DOMUtils.DOM;
10909
10910
 
10910
10911
  /**
10911
- * Constucts a new DOM serializer class.
10912
+ * Constructs a new DOM serializer class.
10912
10913
  *
10913
10914
  * @constructor
10914
10915
  * @method Serializer
@@ -11021,8 +11022,9 @@ define("tinymce/dom/Serializer", [
11021
11022
  value = node.firstChild ? node.firstChild.value : '';
11022
11023
 
11023
11024
  if (name === "script") {
11024
- // Remove mce- prefix from script elements
11025
- node.attr('type', (node.attr('type') || 'text/javascript').replace(/^mce\-/, ''));
11025
+ // Remove mce- prefix from script elements and remove default text/javascript mime type (HTML5)
11026
+ var type = (node.attr('type') || 'text/javascript').replace(/^mce\-/, '');
11027
+ node.attr('type', type === 'text/javascript' ? null : type);
11026
11028
 
11027
11029
  if (value.length > 0) {
11028
11030
  node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
@@ -11835,10 +11837,9 @@ define("tinymce/dom/ControlSelection", [
11835
11837
  ], function(VK, Tools, Env) {
11836
11838
  return function(selection, editor) {
11837
11839
  var dom = editor.dom, each = Tools.each;
11838
- var selectedElm, selectedElmGhost, resizeHandles, selectedHandle;
11840
+ var selectedElm, selectedElmGhost, resizeHandles, selectedHandle, lastMouseDownEvent;
11839
11841
  var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
11840
- var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie;
11841
- var lastMouseDownEvent;
11842
+ var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie && Env.ie < 11;
11842
11843
 
11843
11844
  // Details about each resize handle how to scale etc
11844
11845
  resizeHandles = {
@@ -11979,8 +11980,11 @@ define("tinymce/dom/ControlSelection", [
11979
11980
  function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
11980
11981
  var position, targetWidth, targetHeight, e, rect;
11981
11982
 
11983
+ // Fix when inline element is within a relaive container
11984
+ var offsetParent = editor.getBody().offsetParent || editor.getBody();
11985
+
11982
11986
  // Get position and size of target
11983
- position = dom.getPos(targetElm, editor.getBody());
11987
+ position = dom.getPos(targetElm, offsetParent);
11984
11988
  selectedElmX = position.x;
11985
11989
  selectedElmY = position.y;
11986
11990
  rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption
@@ -12242,6 +12246,16 @@ define("tinymce/dom/ControlSelection", [
12242
12246
  });
12243
12247
  } else {
12244
12248
  disableGeckoResize();
12249
+
12250
+ if (Env.ie >= 11) {
12251
+ // TODO: Drag/drop doesn't work
12252
+ editor.on('mouseup mousedown', function(e) {
12253
+ if (e.target.nodeName == 'IMG' || editor.selection.getNode().nodeName == 'IMG') {
12254
+ e.preventDefault();
12255
+ editor.selection.select(e.target);
12256
+ }
12257
+ });
12258
+ }
12245
12259
  }
12246
12260
 
12247
12261
  editor.on('nodechange mousedown ResizeEditor', updateResizeRect);
@@ -12952,10 +12966,15 @@ define("tinymce/dom/Selection", [
12952
12966
  * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
12953
12967
  */
12954
12968
  select: function(node, content) {
12955
- var t = this, dom = t.dom, rng = dom.createRng(), idx;
12969
+ var self = this, dom = self.dom, rng = dom.createRng(), idx, nonEmptyElementsMap;
12970
+
12971
+ // Clear stored range set by FocusManager
12972
+ self.lastFocusBookmark = null;
12973
+
12974
+ nonEmptyElementsMap = dom.schema.getNonEmptyElements();
12956
12975
 
12957
12976
  function setPoint(node, start) {
12958
- var walker = new TreeWalker(node, node);
12977
+ var root = node, walker = new TreeWalker(node, root);
12959
12978
 
12960
12979
  do {
12961
12980
  // Text node
@@ -12969,21 +12988,34 @@ define("tinymce/dom/Selection", [
12969
12988
  return;
12970
12989
  }
12971
12990
 
12972
- // BR element
12973
- if (node.nodeName == 'BR') {
12991
+ // BR/IMG/INPUT elements
12992
+ if (nonEmptyElementsMap[node.nodeName]) {
12974
12993
  if (start) {
12975
12994
  rng.setStartBefore(node);
12976
12995
  } else {
12977
- rng.setEndBefore(node);
12996
+ if (node.nodeName == 'BR') {
12997
+ rng.setEndBefore(node);
12998
+ } else {
12999
+ rng.setEndAfter(node);
13000
+ }
12978
13001
  }
12979
13002
 
12980
13003
  return;
12981
13004
  }
12982
13005
  } while ((node = (start ? walker.next() : walker.prev())));
13006
+
13007
+ // Failed to find any text node or other suitable location then move to the root of body
13008
+ if (root.nodeName == 'BODY') {
13009
+ if (start) {
13010
+ rng.setStart(root, 0);
13011
+ } else {
13012
+ rng.setEnd(root, root.childNodes.length);
13013
+ }
13014
+ }
12983
13015
  }
12984
13016
 
12985
13017
  if (node) {
12986
- if (!content && t.controlSelection.controlSelect(node)) {
13018
+ if (!content && self.controlSelection.controlSelect(node)) {
12987
13019
  return;
12988
13020
  }
12989
13021
 
@@ -12997,7 +13029,7 @@ define("tinymce/dom/Selection", [
12997
13029
  setPoint(node);
12998
13030
  }
12999
13031
 
13000
- t.setRng(rng);
13032
+ self.setRng(rng);
13001
13033
  }
13002
13034
 
13003
13035
  return node;
@@ -13070,8 +13102,19 @@ define("tinymce/dom/Selection", [
13070
13102
 
13071
13103
  // Use last rng passed from FocusManager if it's available this enables
13072
13104
  // calls to editor.selection.getStart() to work when caret focus is lost on IE
13073
- if (!w3c && self.restoreRng) {
13074
- return self.restoreRng;
13105
+ if (!w3c && self.lastFocusBookmark) {
13106
+ var bookmark = self.lastFocusBookmark;
13107
+
13108
+ // Convert bookmark to range IE 11 fix
13109
+ if (bookmark.startContainer) {
13110
+ rng = doc.createRange();
13111
+ rng.setStart(bookmark.startContainer, bookmark.startOffset);
13112
+ rng.setEnd(bookmark.endContainer, bookmark.endOffset);
13113
+ } else {
13114
+ rng = bookmark;
13115
+ }
13116
+
13117
+ return rng;
13075
13118
  }
13076
13119
 
13077
13120
  // Found tridentSel object then we need to use that one
@@ -13165,12 +13208,11 @@ define("tinymce/dom/Selection", [
13165
13208
 
13166
13209
  try {
13167
13210
  sel.removeAllRanges();
13211
+ sel.addRange(rng);
13168
13212
  } catch (ex) {
13169
- // IE9 might throw errors here don't know why
13213
+ // IE might throw errors here if the editor is within a hidden container and selection is changed
13170
13214
  }
13171
13215
 
13172
- sel.addRange(rng);
13173
-
13174
13216
  // Forward is set to false and we have an extend function
13175
13217
  if (forward === false && sel.extend) {
13176
13218
  sel.collapse(rng.endContainer, rng.endOffset);
@@ -13574,13 +13616,57 @@ define("tinymce/dom/Selection", [
13574
13616
  return self;
13575
13617
  },
13576
13618
 
13619
+ getScrollContainer: function() {
13620
+ var scrollContainer, node = this.dom.getRoot();
13621
+
13622
+ while (node && node.nodeName != 'BODY') {
13623
+ if (node.scrollHeight > node.clientHeight) {
13624
+ scrollContainer = node;
13625
+ break;
13626
+ }
13627
+
13628
+ node = node.parentNode;
13629
+ }
13630
+
13631
+ return scrollContainer;
13632
+ },
13633
+
13577
13634
  scrollIntoView: function(elm) {
13578
- var y, viewPort, self = this, dom = self.dom;
13635
+ var y, viewPort, self = this, dom = self.dom, root = dom.getRoot(), viewPortY, viewPortH;
13636
+
13637
+ function getPos(elm) {
13638
+ var x = 0, y = 0;
13639
+
13640
+ var offsetParent = elm;
13641
+ while (offsetParent && offsetParent.nodeType) {
13642
+ x += offsetParent.offsetLeft || 0;
13643
+ y += offsetParent.offsetTop || 0;
13644
+ offsetParent = offsetParent.offsetParent;
13645
+ }
13646
+
13647
+ return {x: x, y: y};
13648
+ }
13649
+
13650
+ if (root.nodeName != 'BODY') {
13651
+ var scrollContainer = self.getScrollContainer();
13652
+ if (scrollContainer) {
13653
+ y = getPos(elm).y - getPos(scrollContainer).y;
13654
+ viewPortH = scrollContainer.clientHeight;
13655
+ viewPortY = scrollContainer.scrollTop;
13656
+ if (y < viewPortY || y + 25 > viewPortY + viewPortH) {
13657
+ scrollContainer.scrollTop = y < viewPortY ? y : y - viewPortH + 25;
13658
+ }
13659
+
13660
+ return;
13661
+ }
13662
+ }
13579
13663
 
13580
13664
  viewPort = dom.getViewPort(self.editor.getWin());
13581
13665
  y = dom.getPos(elm).y;
13582
- if (y < viewPort.y || y + 25 > viewPort.y + viewPort.h) {
13583
- self.editor.getWin().scrollTo(0, y < viewPort.y ? y : y - viewPort.h + 25);
13666
+ viewPortY = viewPort.y;
13667
+ viewPortH = viewPort.h;
13668
+ if (y < viewPort.y || y + 25 > viewPortY + viewPortH) {
13669
+ self.editor.getWin().scrollTo(0, y < viewPortY ? y : y - viewPortH + 25);
13584
13670
  }
13585
13671
  },
13586
13672
 
@@ -13887,7 +13973,7 @@ define("tinymce/dom/RangeUtils", [
13887
13973
  /**
13888
13974
  * Text formatter engine class. This class is used to apply formats like bold, italic, font size
13889
13975
  * etc to the current selection or specific nodes. This engine was build to replace the browsers
13890
- * default formatting logic for execCommand due to it's inconsistant and buggy behavior.
13976
+ * default formatting logic for execCommand due to it's inconsistent and buggy behavior.
13891
13977
  *
13892
13978
  * @class tinymce.Formatter
13893
13979
  * @example
@@ -14016,7 +14102,14 @@ define("tinymce/Formatter", [
14016
14102
  },
14017
14103
 
14018
14104
  removeformat: [
14019
- {selector: 'b,strong,em,i,font,u,strike', remove: 'all', split: true, expand: false, block_expand: true, deep: true},
14105
+ {
14106
+ selector: 'b,strong,em,i,font,u,strike,sub,sup',
14107
+ remove: 'all',
14108
+ split: true,
14109
+ expand: false,
14110
+ block_expand: true,
14111
+ deep: true
14112
+ },
14020
14113
  {selector: 'span', attributes: ['style', 'class'], remove: 'empty', split: true, expand: false, deep: true},
14021
14114
  {selector: '*', attributes: ['style', 'class'], split: false, expand: false, deep: true}
14022
14115
  ]
@@ -14883,9 +14976,11 @@ define("tinymce/Formatter", [
14883
14976
  var startNode;
14884
14977
 
14885
14978
  function matchParents(node) {
14979
+ var root = dom.getRoot();
14980
+
14886
14981
  // Find first node with similar format settings
14887
14982
  node = dom.getParent(node, function(node) {
14888
- return !!matchNode(node, name, vars, true);
14983
+ return node.parentNode === root || !!matchNode(node, name, vars, true);
14889
14984
  });
14890
14985
 
14891
14986
  // Do an exact check on the similar format element
@@ -14961,8 +15056,9 @@ define("tinymce/Formatter", [
14961
15056
  for (x = formatList.length - 1; x >= 0; x--) {
14962
15057
  selector = formatList[x].selector;
14963
15058
 
14964
- // Format is not selector based, then always return TRUE
14965
- if (!selector) {
15059
+ // Format is not selector based then always return TRUE
15060
+ // Is it has a defaultBlock then it's likely it can be applied for example align on a non block element line
15061
+ if (!selector || formatList[x].defaultBlock) {
14966
15062
  return TRUE;
14967
15063
  }
14968
15064
 
@@ -15392,7 +15488,7 @@ define("tinymce/Formatter", [
15392
15488
  }
15393
15489
 
15394
15490
  function findBlockEndPoint(container, sibling_name) {
15395
- var node;
15491
+ var node, root = dom.getRoot();
15396
15492
 
15397
15493
  // Expand to block of similar type
15398
15494
  if (!format[0].wrapper) {
@@ -15401,7 +15497,10 @@ define("tinymce/Formatter", [
15401
15497
 
15402
15498
  // Expand to first wrappable block element or any block element
15403
15499
  if (!node) {
15404
- node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isTextBlock);
15500
+ node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, function(node) {
15501
+ // Fixes #6183 where it would expand to editable parent element in inline mode
15502
+ return node != root && isTextBlock(node);
15503
+ });
15405
15504
  }
15406
15505
 
15407
15506
  // Exclude inner lists from wrapping
@@ -15452,14 +15551,14 @@ define("tinymce/Formatter", [
15452
15551
 
15453
15552
  if (format[0].inline) {
15454
15553
  if (rng.collapsed) {
15455
- // Expand left to closest word boundery
15554
+ // Expand left to closest word boundary
15456
15555
  endPoint = findWordEndPoint(startContainer, startOffset, true);
15457
15556
  if (endPoint) {
15458
15557
  startContainer = endPoint.container;
15459
15558
  startOffset = endPoint.offset;
15460
15559
  }
15461
15560
 
15462
- // Expand right to closest word boundery
15561
+ // Expand right to closest word boundary
15463
15562
  endPoint = findWordEndPoint(endContainer, endOffset);
15464
15563
  if (endPoint) {
15465
15564
  endContainer = endPoint.container;
@@ -16155,6 +16254,10 @@ define("tinymce/Formatter", [
16155
16254
 
16156
16255
  // Move selection to text node
16157
16256
  selection.setCursorLocation(node, 1);
16257
+ // If the formatNode is empty, we can remove it safely.
16258
+ if(dom.isEmpty(formatNode)) {
16259
+ dom.remove(formatNode);
16260
+ }
16158
16261
  }
16159
16262
  }
16160
16263
 
@@ -16295,7 +16398,7 @@ define("tinymce/UndoManager", [
16295
16398
  ].join('|'), 'gi');
16296
16399
 
16297
16400
  return function(editor) {
16298
- var self, index = 0, data = [], beforeBookmark, isFirstTypedCharacter;
16401
+ var self, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, lock;
16299
16402
 
16300
16403
  // Returns a trimmed version of the current editor contents
16301
16404
  function getContent() {
@@ -16359,6 +16462,11 @@ define("tinymce/UndoManager", [
16359
16462
  // Make the it dirty if the content was changed after typing the first character
16360
16463
  if (!editor.isDirty()) {
16361
16464
  editor.isNotDirty = !data[0] || getContent() == data[0].content;
16465
+
16466
+ // Fire initial change event
16467
+ if (!editor.isNotDirty) {
16468
+ editor.fire('change', {level: data[0], lastLevel: null});
16469
+ }
16362
16470
  }
16363
16471
 
16364
16472
  editor.fire('TypingUndo');
@@ -16423,7 +16531,9 @@ define("tinymce/UndoManager", [
16423
16531
  * @method beforeChange
16424
16532
  */
16425
16533
  beforeChange: function() {
16426
- beforeBookmark = editor.selection.getBookmark(2, true);
16534
+ if (!lock) {
16535
+ beforeBookmark = editor.selection.getBookmark(2, true);
16536
+ }
16427
16537
  },
16428
16538
 
16429
16539
  /**
@@ -16439,7 +16549,7 @@ define("tinymce/UndoManager", [
16439
16549
  level = level || {};
16440
16550
  level.content = getContent();
16441
16551
 
16442
- if (editor.fire('BeforeAddUndo', {level: level}).isDefaultPrevented()) {
16552
+ if (lock || editor.fire('BeforeAddUndo', {level: level}).isDefaultPrevented()) {
16443
16553
  return null;
16444
16554
  }
16445
16555
 
@@ -16506,6 +16616,11 @@ define("tinymce/UndoManager", [
16506
16616
  if (index > 0) {
16507
16617
  level = data[--index];
16508
16618
 
16619
+ // Undo to first index then set dirty state to false
16620
+ if (index === 0) {
16621
+ editor.isNotDirty = true;
16622
+ }
16623
+
16509
16624
  editor.setContent(level.content, {format: 'raw'});
16510
16625
  editor.selection.moveToBookmark(level.beforeBookmark);
16511
16626
 
@@ -16572,14 +16687,19 @@ define("tinymce/UndoManager", [
16572
16687
  /**
16573
16688
  * Executes the specified function in an undo transation. The selection
16574
16689
  * before the modification will be stored to the undo stack and if the DOM changes
16575
- * it will add a new undo level.
16690
+ * it will add a new undo level. Any methods within the transation that adds undo levels will
16691
+ * be ignored. So a transation can include calls to execCommand or editor.insertContent.
16576
16692
  *
16577
16693
  * @method transact
16578
16694
  * @param {function} callback Function to execute dom manipulation logic in.
16579
16695
  */
16580
16696
  transact: function(callback) {
16581
16697
  self.beforeChange();
16698
+
16699
+ lock = true;
16582
16700
  callback();
16701
+ lock = false;
16702
+
16583
16703
  self.add();
16584
16704
  }
16585
16705
  };
@@ -16607,7 +16727,7 @@ define("tinymce/EnterKey", [
16607
16727
  "tinymce/dom/TreeWalker",
16608
16728
  "tinymce/Env"
16609
16729
  ], function(TreeWalker, Env) {
16610
- var isIE = Env.ie;
16730
+ var isIE = Env.ie && Env.ie < 11;
16611
16731
 
16612
16732
  return function(editor) {
16613
16733
  var dom = editor.dom, selection = editor.selection, settings = editor.settings;
@@ -17175,6 +17295,7 @@ define("tinymce/EnterKey", [
17175
17295
  // Insert new block before
17176
17296
  newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
17177
17297
  renderBlockOnIE(newBlock);
17298
+ moveToCaretPosition(parentBlock);
17178
17299
  } else {
17179
17300
  // Extract after fragment and insert it after the current block
17180
17301
  tmpRng = rng.cloneRange();
@@ -17332,7 +17453,7 @@ define("tinymce/ForceBlocks", [], function() {
17332
17453
 
17333
17454
  // Force root blocks
17334
17455
  if (settings.forced_root_block) {
17335
- editor.on('KeyUp NodeChange', addRootBlocks);
17456
+ editor.on('NodeChange', addRootBlocks);
17336
17457
  }
17337
17458
  };
17338
17459
  });
@@ -17705,8 +17826,8 @@ define("tinymce/EditorCommands", [
17705
17826
  parentNode = selection.getNode();
17706
17827
 
17707
17828
  // Parse the fragment within the context of the parent node
17708
- args = {context: parentNode.nodeName.toLowerCase()};
17709
- fragment = parser.parse(value, args);
17829
+ var parserArgs = {context: parentNode.nodeName.toLowerCase()};
17830
+ fragment = parser.parse(value, parserArgs);
17710
17831
 
17711
17832
  // Move the caret to a more suitable location
17712
17833
  node = fragment.lastChild;
@@ -17722,7 +17843,7 @@ define("tinymce/EditorCommands", [
17722
17843
  }
17723
17844
 
17724
17845
  // If parser says valid we can insert the contents into that parent
17725
- if (!args.invalid) {
17846
+ if (!parserArgs.invalid) {
17726
17847
  value = serializer.serialize(fragment);
17727
17848
 
17728
17849
  // Check if parent is empty or only has one BR element then set the innerHTML of that parent
@@ -18045,7 +18166,7 @@ define("tinymce/util/URI", [
18045
18166
  var each = Tools.each, trim = Tools.trim;
18046
18167
 
18047
18168
  /**
18048
- * Constucts a new URI instance.
18169
+ * Constructs a new URI instance.
18049
18170
  *
18050
18171
  * @constructor
18051
18172
  * @method URI
@@ -18575,7 +18696,7 @@ define("tinymce/util/Class", [
18575
18696
  * element[attr^=value]
18576
18697
  * element[attr$=value]
18577
18698
  * element:<state>
18578
- * element:not(<expession>)
18699
+ * element:not(<expression>)
18579
18700
  * element:first
18580
18701
  * element:last
18581
18702
  * element:odd
@@ -18868,11 +18989,11 @@ define("tinymce/ui/Selector", [
18868
18989
 
18869
18990
  // All filters matched the item
18870
18991
  if (fi === fl) {
18871
- // Matched item is on the last expession like: panel toolbar [button]
18992
+ // Matched item is on the last expression like: panel toolbar [button]
18872
18993
  if (index == selector.length - 1) {
18873
18994
  matches.push(item);
18874
18995
  } else {
18875
- // Collect next expession type
18996
+ // Collect next expression type
18876
18997
  if (item.items) {
18877
18998
  collect(item.items(), selector, index + 1);
18878
18999
  }
@@ -19176,6 +19297,22 @@ define("tinymce/ui/Collection", [
19176
19297
  });
19177
19298
 
19178
19299
  return self;
19300
+ },
19301
+
19302
+ /**
19303
+ * Remove all items from collection and DOM.
19304
+ *
19305
+ * @method remove
19306
+ * @return {tinymce.ui.Collection} Current collection.
19307
+ */
19308
+ remove: function() {
19309
+ var i = this.length;
19310
+
19311
+ while (i--) {
19312
+ this[i].remove();
19313
+ }
19314
+
19315
+ return this;
19179
19316
  }
19180
19317
 
19181
19318
  /**
@@ -19406,6 +19543,11 @@ define("tinymce/ui/DomUtils", [
19406
19543
 
19407
19544
  fire: function(target, name, args) {
19408
19545
  return DOMUtils.DOM.fire(target, name, args);
19546
+ },
19547
+
19548
+ innerHtml: function(elm, html) {
19549
+ // Workaround for <div> in <p> bug on IE 8 #6178
19550
+ DOMUtils.DOM.setHTML(elm, html);
19409
19551
  }
19410
19552
  };
19411
19553
  });
@@ -20300,6 +20442,18 @@ define("tinymce/ui/Control", [
20300
20442
  return classes ? classes.join(' ') : '';
20301
20443
  },
20302
20444
 
20445
+ /**
20446
+ * Sets the inner HTML of the control element.
20447
+ *
20448
+ * @method innerHtml
20449
+ * @param {String} html Html string to set as inner html.
20450
+ * @return {tinymce.ui.Control} Current control object.
20451
+ */
20452
+ innerHtml: function(html) {
20453
+ DomUtils.innerHtml(this.getEl(), html);
20454
+ return this;
20455
+ },
20456
+
20303
20457
  /**
20304
20458
  * Returns the control DOM element or sub element.
20305
20459
  *
@@ -20485,11 +20639,11 @@ define("tinymce/ui/Control", [
20485
20639
  * @return {tinymce.ui.Control} Current control instance.
20486
20640
  */
20487
20641
  remove: function() {
20488
- var self = this, elm = self.getEl(), parent = self.parent(), newItems;
20642
+ var self = this, elm = self.getEl(), parent = self.parent(), newItems, i;
20489
20643
 
20490
20644
  if (self.items) {
20491
20645
  var controls = self.items().toArray();
20492
- var i = controls.length;
20646
+ i = controls.length;
20493
20647
  while (i--) {
20494
20648
  controls[i].remove();
20495
20649
  }
@@ -20513,8 +20667,16 @@ define("tinymce/ui/Control", [
20513
20667
  }
20514
20668
 
20515
20669
  delete Control.controlIdLookup[self._id];
20670
+ delete elementIdCache[self._id];
20671
+
20672
+ if (elm && elm.parentNode) {
20673
+ var nodes = elm.getElementsByTagName('*');
20674
+
20675
+ i = nodes.length;
20676
+ while (i--) {
20677
+ delete elementIdCache[nodes[i].id];
20678
+ }
20516
20679
 
20517
- if (elm.parentNode) {
20518
20680
  elm.parentNode.removeChild(elm);
20519
20681
  }
20520
20682
 
@@ -20892,7 +21054,7 @@ define("tinymce/ui/Control", [
20892
21054
  */
20893
21055
  // title: function(value) {} -- Generated
20894
21056
  });
20895
-
21057
+ window.elementIdCache = elementIdCache;
20896
21058
  return Control;
20897
21059
  });
20898
21060
 
@@ -22484,7 +22646,7 @@ define("tinymce/ui/KeyboardNavigation", [
22484
22646
  * @setting {tinymce.ui.Control} root the root control navigation focus movement is scoped to this root.
22485
22647
  * @setting {Array} items an array containing the items to move focus between. Every object in this array must have an
22486
22648
  * id attribute which maps to the actual DOM element and it must be able to have focus i.e. tabIndex=-1.
22487
- * @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates cancelling.
22649
+ * @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates canceling.
22488
22650
  * @setting {Function} onAction (optional) the action handler to call when the user activates an item.
22489
22651
  * @setting {Boolean} enableLeftRight (optional, default) when true, the up/down arrows move through items.
22490
22652
  * @setting {Boolean} enableUpDown (optional) when true, the up/down arrows move through items.
@@ -23183,8 +23345,8 @@ define("tinymce/ui/Window", [
23183
23345
  remove: function() {
23184
23346
  var self = this;
23185
23347
 
23186
- self._super();
23187
23348
  self.dragHelper.destroy();
23349
+ self._super();
23188
23350
 
23189
23351
  if (self.statusbar) {
23190
23352
  this.statusbar.remove();
@@ -23440,6 +23602,12 @@ define("tinymce/WindowManager", [
23440
23602
  return function(editor) {
23441
23603
  var self = this, windows = [];
23442
23604
 
23605
+ function getTopMostWindow() {
23606
+ if (windows.length) {
23607
+ return windows[windows.length - 1];
23608
+ }
23609
+ }
23610
+
23443
23611
  self.windows = windows;
23444
23612
 
23445
23613
  /**
@@ -23459,6 +23627,10 @@ define("tinymce/WindowManager", [
23459
23627
  self.open = function(args, params) {
23460
23628
  var win;
23461
23629
 
23630
+ editor.editorManager.activeEditor = editor;
23631
+
23632
+ args.title = args.title || ' ';
23633
+
23462
23634
  // Handle URL
23463
23635
  args.url = args.url || args.file; // Legacy
23464
23636
  if (args.url) {
@@ -23516,7 +23688,8 @@ define("tinymce/WindowManager", [
23516
23688
  });
23517
23689
  }
23518
23690
 
23519
- // store parameters
23691
+ // store args and parameters
23692
+ win.features = args || {};
23520
23693
  win.params = params || {};
23521
23694
 
23522
23695
  // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
@@ -23572,8 +23745,8 @@ define("tinymce/WindowManager", [
23572
23745
  * @method close
23573
23746
  */
23574
23747
  self.close = function() {
23575
- if (windows.length) {
23576
- windows[windows.length - 1].close();
23748
+ if (getTopMostWindow()) {
23749
+ getTopMostWindow().close();
23577
23750
  }
23578
23751
  };
23579
23752
 
@@ -23588,11 +23761,7 @@ define("tinymce/WindowManager", [
23588
23761
  * @return {Object} Name/value object with parameters passed from windowManager.open call.
23589
23762
  */
23590
23763
  self.getParams = function() {
23591
- if (windows.length) {
23592
- return windows[windows.length - 1].params;
23593
- }
23594
-
23595
- return null;
23764
+ return getTopMostWindow() ? getTopMostWindow().params : null;
23596
23765
  };
23597
23766
 
23598
23767
  /**
@@ -23602,8 +23771,8 @@ define("tinymce/WindowManager", [
23602
23771
  * @param {Object} params Params object to set for the last opened window.
23603
23772
  */
23604
23773
  self.setParams = function(params) {
23605
- if (windows.length) {
23606
- windows[windows.length - 1].params = params;
23774
+ if (getTopMostWindow()) {
23775
+ getTopMostWindow().params = params;
23607
23776
  }
23608
23777
  };
23609
23778
  };
@@ -23876,7 +24045,9 @@ define("tinymce/util/Quirks", [
23876
24045
  * browser just deletes the paragraph - the browser fails to merge the text node with a horizontal rule so it is
23877
24046
  * left there. TinyMCE sees a floating text node and wraps it in a paragraph on the key up event (ForceBlocks.js
23878
24047
  * addRootBlocks), meaning the action does nothing. With this code, FireFox/IE matche the behaviour of other
23879
- * browsers
24048
+ * browsers.
24049
+ *
24050
+ * It also fixes a bug on Firefox where it's impossible to delete HR elements.
23880
24051
  */
23881
24052
  function removeHrOnBackspace() {
23882
24053
  editor.on('keydown', function(e) {
@@ -23885,6 +24056,12 @@ define("tinymce/util/Quirks", [
23885
24056
  var node = selection.getNode();
23886
24057
  var previousSibling = node.previousSibling;
23887
24058
 
24059
+ if (node.nodeName == 'HR') {
24060
+ dom.remove(node);
24061
+ e.preventDefault();
24062
+ return;
24063
+ }
24064
+
23888
24065
  if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") {
23889
24066
  dom.remove(previousSibling);
23890
24067
  e.preventDefault();
@@ -23953,7 +24130,7 @@ define("tinymce/util/Quirks", [
23953
24130
  * Instead of:
23954
24131
  * <p style="color:red">bla|ed</p>
23955
24132
  */
23956
- function removeStylesWhenDeletingAccrossBlockElements() {
24133
+ function removeStylesWhenDeletingAcrossBlockElements() {
23957
24134
  function getAttributeApplyFunction() {
23958
24135
  var template = dom.getAttribs(selection.getStart().cloneNode(false));
23959
24136
 
@@ -24513,6 +24690,44 @@ define("tinymce/util/Quirks", [
24513
24690
  );
24514
24691
  }
24515
24692
 
24693
+ /**
24694
+ * iOS has a bug where it's impossible to type if the document has a touchstart event
24695
+ * bound and the user touches the document while having the on screen keyboard visible.
24696
+ *
24697
+ * The touch event moves the focus to the parent document while having the caret inside the iframe
24698
+ * this fix moves the focus back into the iframe document.
24699
+ */
24700
+ function restoreFocusOnKeyDown() {
24701
+ if (!editor.inline) {
24702
+ editor.on('keydown', function() {
24703
+ if (document.activeElement == document.body) {
24704
+ editor.getWin().focus();
24705
+ }
24706
+ });
24707
+ }
24708
+ }
24709
+
24710
+ /**
24711
+ * IE 11 has an annoying issue where you can't move focus into the editor
24712
+ * by clicking on the white area HTML element. We used to be able to to fix this with
24713
+ * the fixCaretSelectionOfDocumentElementOnIe fix. But since M$ removed the selection
24714
+ * object it's not possible anymore. So we need to hack in a ungly CSS to force the
24715
+ * body to be at least 150px. If the user clicks the HTML element out side this 150px region
24716
+ * we simply move the focus into the first paragraph. Not ideal since you loose the
24717
+ * positioning of the caret but goot enough for most cases.
24718
+ */
24719
+ function bodyHeight() {
24720
+ if (!editor.inline) {
24721
+ editor.contentStyles.push('body {min-height: 150px}');
24722
+ editor.on('click', function(e) {
24723
+ if (e.target.nodeName == 'HTML') {
24724
+ editor.execCommand('SelectAll');
24725
+ editor.selection.collapse(true);
24726
+ }
24727
+ });
24728
+ }
24729
+ }
24730
+
24516
24731
  // All browsers
24517
24732
  disableBackspaceIntoATable();
24518
24733
  removeBlockQuoteOnBackSpace();
@@ -24530,13 +24745,14 @@ define("tinymce/util/Quirks", [
24530
24745
  // iOS
24531
24746
  if (Env.iOS) {
24532
24747
  selectionChangeNodeChanged();
24748
+ restoreFocusOnKeyDown();
24533
24749
  } else {
24534
24750
  selectAll();
24535
24751
  }
24536
24752
  }
24537
24753
 
24538
24754
  // IE
24539
- if (isIE) {
24755
+ if (isIE && Env.ie < 11) {
24540
24756
  removeHrOnBackspace();
24541
24757
  ensureBodyHasRoleApplication();
24542
24758
  addNewLinesBeforeBrInPre();
@@ -24547,11 +24763,15 @@ define("tinymce/util/Quirks", [
24547
24763
  fixCaretSelectionOfDocumentElementOnIe();
24548
24764
  }
24549
24765
 
24766
+ if (Env.ie >= 11) {
24767
+ bodyHeight();
24768
+ }
24769
+
24550
24770
  // Gecko
24551
24771
  if (isGecko) {
24552
24772
  removeHrOnBackspace();
24553
24773
  focusBody();
24554
- removeStylesWhenDeletingAccrossBlockElements();
24774
+ removeStylesWhenDeletingAcrossBlockElements();
24555
24775
  setGeckoEditingOptions();
24556
24776
  addBrAfterLastLinks();
24557
24777
  removeGhostSelection();
@@ -24988,7 +25208,7 @@ define("tinymce/Editor", [
24988
25208
  var extend = Tools.extend, each = Tools.each, explode = Tools.explode;
24989
25209
  var inArray = Tools.inArray, trim = Tools.trim, resolve = Tools.resolve;
24990
25210
  var Event = EventUtils.Event;
24991
- var isGecko = Env.gecko, isIE = Env.ie, isOpera = Env.opera;
25211
+ var isGecko = Env.gecko, ie = Env.ie, isOpera = Env.opera;
24992
25212
 
24993
25213
  function getEventTarget(editor, eventName) {
24994
25214
  if (eventName == 'selectionchange' || eventName == 'drop') {
@@ -25075,8 +25295,9 @@ define("tinymce/Editor", [
25075
25295
  ie7_compat: true
25076
25296
  }, settings);
25077
25297
 
25078
- // TODO: Fix this
25079
- AddOnManager.settings = settings;
25298
+ AddOnManager.language = settings.language || 'en';
25299
+ AddOnManager.languageLoad = settings.language_load;
25300
+
25080
25301
  AddOnManager.baseURL = editorManager.baseURL;
25081
25302
 
25082
25303
  /**
@@ -25176,6 +25397,7 @@ define("tinymce/Editor", [
25176
25397
 
25177
25398
  // Call setup
25178
25399
  self.execCallback('setup', self);
25400
+ editorManager.fire('SetupEditor', self);
25179
25401
  }
25180
25402
 
25181
25403
  Editor.prototype = {
@@ -25187,16 +25409,17 @@ define("tinymce/Editor", [
25187
25409
  render: function() {
25188
25410
  var self = this, settings = self.settings, id = self.id, suffix = self.suffix;
25189
25411
 
25412
+ function readyHandler() {
25413
+ DOM.unbind(window, 'ready', readyHandler);
25414
+ self.render();
25415
+ }
25416
+
25190
25417
  // Page is not loaded yet, wait for it
25191
25418
  if (!Event.domLoaded) {
25192
- DOM.bind(window, 'ready', function() {
25193
- self.render();
25194
- });
25419
+ DOM.bind(window, 'ready', readyHandler);
25195
25420
  return;
25196
25421
  }
25197
25422
 
25198
- self.editorManager.settings = settings;
25199
-
25200
25423
  // Element not found, then skip initialization
25201
25424
  if (!self.getElement()) {
25202
25425
  return;
@@ -25281,7 +25504,6 @@ define("tinymce/Editor", [
25281
25504
  self.on('submit', function() {
25282
25505
  if (self.initialized) {
25283
25506
  self.save();
25284
- self.isNotDirty = true;
25285
25507
  }
25286
25508
  });
25287
25509
  }
@@ -25289,7 +25511,7 @@ define("tinymce/Editor", [
25289
25511
  if (settings.add_unload_trigger) {
25290
25512
  self._beforeUnload = function() {
25291
25513
  if (self.initialized && !self.destroyed && !self.isHidden()) {
25292
- self.save({format: 'raw', no_events: true});
25514
+ self.save({format: 'raw', no_events: true, set_dirty: false});
25293
25515
  }
25294
25516
  };
25295
25517
 
@@ -25310,7 +25532,15 @@ define("tinymce/Editor", [
25310
25532
 
25311
25533
  if (settings.theme && typeof settings.theme != "function" &&
25312
25534
  settings.theme.charAt(0) != '-' && !ThemeManager.urls[settings.theme]) {
25313
- ThemeManager.load(settings.theme, 'themes/' + settings.theme + '/theme' + suffix + '.js');
25535
+ var themeUrl = settings.theme_url;
25536
+
25537
+ if (themeUrl) {
25538
+ themeUrl = self.documentBaseURI.toAbsolute(themeUrl);
25539
+ } else {
25540
+ themeUrl = 'themes/' + settings.theme + '/theme' + suffix + '.js';
25541
+ }
25542
+
25543
+ ThemeManager.load(settings.theme, themeUrl);
25314
25544
  }
25315
25545
 
25316
25546
  if (Tools.isArray(settings.plugins)) {
@@ -25548,7 +25778,7 @@ define("tinymce/Editor", [
25548
25778
 
25549
25779
  // Domain relaxing enabled, then set document domain
25550
25780
  // TODO: Fix this old stuff
25551
- if (self.editorManager.relaxedDomain && (isIE || (isOpera && parseFloat(window.opera.version()) < 11))) {
25781
+ if (self.editorManager.relaxedDomain && (ie || (isOpera && parseFloat(window.opera.version()) < 11))) {
25552
25782
  // We need to write the contents here in IE since multiple writes messes up refresh button and back button
25553
25783
  url = 'javascript:(function(){document.open();document.domain="' + document.domain + '";' +
25554
25784
  'var ed = window.parent.tinymce.get("' + self.id + '");document.write(ed.iframeHTML);' +
@@ -25605,7 +25835,7 @@ define("tinymce/Editor", [
25605
25835
  }
25606
25836
 
25607
25837
  // Setup iframe body
25608
- if ((!isIE || !self.editorManager.relaxedDomain) && !settings.content_editable) {
25838
+ if ((!ie || !self.editorManager.relaxedDomain) && !settings.content_editable) {
25609
25839
  doc.open();
25610
25840
  doc.write(self.iframeHTML);
25611
25841
  doc.close();
@@ -25673,6 +25903,7 @@ define("tinymce/Editor", [
25673
25903
  class_filter: settings.class_filter,
25674
25904
  update_styles: true,
25675
25905
  root_element: settings.content_editable ? self.id : null,
25906
+ collect: settings.content_editable,
25676
25907
  schema: self.schema,
25677
25908
  onSetAttrib: function(e) {
25678
25909
  self.fire('SetAttrib', e);
@@ -26007,8 +26238,8 @@ define("tinymce/Editor", [
26007
26238
  return '';
26008
26239
  }
26009
26240
 
26010
- return i18n[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function(a, b) {
26011
- return i18n[lang + '.' + b] || '{#' + b + '}';
26241
+ return i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function(a, b) {
26242
+ return i18n.data[lang + '.' + b] || '{#' + b + '}';
26012
26243
  });
26013
26244
  },
26014
26245
 
@@ -26021,7 +26252,7 @@ define("tinymce/Editor", [
26021
26252
  */
26022
26253
  getLang: function(name, defaultVal) {
26023
26254
  return (
26024
- this.editorManager.i18n[(this.settings.language || 'en') + '.' + name] ||
26255
+ this.editorManager.i18n.data[(this.settings.language || 'en') + '.' + name] ||
26025
26256
  (defaultVal !== undefined ? defaultVal : '{#' + name + '}')
26026
26257
  );
26027
26258
  },
@@ -26081,7 +26312,7 @@ define("tinymce/Editor", [
26081
26312
  // Get start node
26082
26313
  root = self.getBody();
26083
26314
  node = selection.getStart() || root;
26084
- node = isIE && node.ownerDocument != self.getDoc() ? self.getBody() : node; // Fix for IE initial state
26315
+ node = ie && node.ownerDocument != self.getDoc() ? self.getBody() : node; // Fix for IE initial state
26085
26316
 
26086
26317
  // Edge case for <p>|<img></p>
26087
26318
  if (node.nodeName == 'IMG' && selection.isCollapsed()) {
@@ -26432,7 +26663,7 @@ define("tinymce/Editor", [
26432
26663
  var self = this, doc = self.getDoc();
26433
26664
 
26434
26665
  // Fixed bug where IE has a blinking cursor left from the editor
26435
- if (isIE && doc) {
26666
+ if (ie && doc) {
26436
26667
  doc.execCommand('SelectAll');
26437
26668
  }
26438
26669
 
@@ -26551,7 +26782,10 @@ define("tinymce/Editor", [
26551
26782
  }
26552
26783
 
26553
26784
  args.element = elm = null;
26554
- self.isNotDirty = true;
26785
+
26786
+ if (args.set_dirty !== false) {
26787
+ self.isNotDirty = true;
26788
+ }
26555
26789
 
26556
26790
  return html;
26557
26791
  },
@@ -26595,42 +26829,54 @@ define("tinymce/Editor", [
26595
26829
 
26596
26830
  // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
26597
26831
  // It will also be impossible to place the caret in the editor unless there is a BR element present
26598
- if (!isIE && (content.length === 0 || /^\s+$/.test(content))) {
26832
+ if (content.length === 0 || /^\s+$/.test(content)) {
26599
26833
  forcedRootBlockName = self.settings.forced_root_block;
26600
26834
 
26601
26835
  // Check if forcedRootBlock is configured and that the block is a valid child of the body
26602
26836
  if (forcedRootBlockName && self.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
26603
- content = '<' + forcedRootBlockName + '><br data-mce-bogus="1"></' + forcedRootBlockName + '>';
26604
- } else {
26837
+ if (ie && ie < 11) {
26838
+ // IE renders BR elements in blocks so lets just add an empty block
26839
+ content = '<' + forcedRootBlockName + '></' + forcedRootBlockName + '>';
26840
+ } else {
26841
+ content = '<' + forcedRootBlockName + '><br data-mce-bogus="1"></' + forcedRootBlockName + '>';
26842
+ }
26843
+ } else if (!ie) {
26844
+ // We need to add a BR when forced_root_block is disabled on non IE browsers to place the caret
26605
26845
  content = '<br data-mce-bogus="1">';
26606
26846
  }
26607
26847
 
26608
26848
  body.innerHTML = content;
26609
- self.selection.select(body, true);
26610
- self.selection.collapse(true);
26849
+
26611
26850
  self.fire('SetContent', args);
26612
- return;
26613
- }
26851
+ } else {
26852
+ // Parse and serialize the html
26853
+ if (args.format !== 'raw') {
26854
+ content = new Serializer({}, self.schema).serialize(
26855
+ self.parser.parse(content, {isRootContent: true})
26856
+ );
26857
+ }
26614
26858
 
26615
- // Parse and serialize the html
26616
- if (args.format !== 'raw') {
26617
- content = new Serializer({}, self.schema).serialize(
26618
- self.parser.parse(content, {isRootContent: true})
26619
- );
26620
- }
26859
+ // Set the new cleaned contents to the editor
26860
+ args.content = trim(content);
26861
+ self.dom.setHTML(body, args.content);
26621
26862
 
26622
- // Set the new cleaned contents to the editor
26623
- args.content = trim(content);
26624
- self.dom.setHTML(body, args.content);
26863
+ // Do post processing
26864
+ if (!args.no_events) {
26865
+ self.fire('SetContent', args);
26866
+ }
26625
26867
 
26626
- // Do post processing
26627
- if (!args.no_events) {
26628
- self.fire('SetContent', args);
26868
+ // Don't normalize selection if the focused element isn't the body in
26869
+ // content editable mode since it will steal focus otherwise
26870
+ /*if (!self.settings.content_editable || document.activeElement === self.getBody()) {
26871
+ self.selection.normalize();
26872
+ }*/
26629
26873
  }
26630
26874
 
26631
- // Don't normalize selection if the focused element isn't the body in content editable mode since it will steal focus otherwise
26632
- if (!self.settings.content_editable || document.activeElement === self.getBody()) {
26633
- self.selection.normalize();
26875
+ // Move selection to start of body if it's a after init setContent call
26876
+ // This prevents IE 7/8 from moving focus to empty editors
26877
+ if (!args.initial) {
26878
+ self.selection.select(body, true);
26879
+ self.selection.collapse(true);
26634
26880
  }
26635
26881
 
26636
26882
  return args.content;
@@ -26903,7 +27149,7 @@ define("tinymce/Editor", [
26903
27149
  self.removed = 1; // Cancels post remove event execution
26904
27150
 
26905
27151
  // Fixed bug where IE has a blinking cursor left from the editor
26906
- if (isIE && doc) {
27152
+ if (ie && doc) {
26907
27153
  doc.execCommand('SelectAll');
26908
27154
  }
26909
27155
 
@@ -26926,6 +27172,7 @@ define("tinymce/Editor", [
26926
27172
 
26927
27173
  self.editorManager.remove(self);
26928
27174
  DOM.remove(elm);
27175
+ self.destroy();
26929
27176
  }
26930
27177
  },
26931
27178
 
@@ -26971,7 +27218,7 @@ define("tinymce/Editor", [
26971
27218
 
26972
27219
  // We must unbind on Gecko since it would otherwise produce the pesky "attempt
26973
27220
  // to run compile-and-go script on a cleared scope" message
26974
- if (isGecko) {
27221
+ if (automatic && isGecko) {
26975
27222
  Event.unbind(self.getDoc());
26976
27223
  Event.unbind(self.getWin());
26977
27224
  Event.unbind(self.getBody());
@@ -26992,8 +27239,11 @@ define("tinymce/Editor", [
26992
27239
 
26993
27240
  form = self.formElement;
26994
27241
  if (form) {
26995
- form.submit = form._mceOldSubmit;
26996
- form._mceOldSubmit = null;
27242
+ if (form._mceOldSubmit) {
27243
+ form.submit = form._mceOldSubmit;
27244
+ form._mceOldSubmit = null;
27245
+ }
27246
+
26997
27247
  DOM.unbind(form, 'submit reset', self.formEventDelegate);
26998
27248
  }
26999
27249
 
@@ -27157,6 +27407,35 @@ define("tinymce/FocusManager", [
27157
27407
  }
27158
27408
  }
27159
27409
 
27410
+ // We can't store a real range on IE 11 since it gets mutated so we need to use a bookmark object
27411
+ // TODO: Move this to a separate range utils class since it's it's logic is present in Selection as well.
27412
+ function createBookmark(rng) {
27413
+ if (rng && rng.startContainer) {
27414
+ return {
27415
+ startContainer: rng.startContainer,
27416
+ startOffset: rng.startOffset,
27417
+ endContainer: rng.endContainer,
27418
+ endOffset: rng.endOffset
27419
+ };
27420
+ }
27421
+
27422
+ return rng;
27423
+ }
27424
+
27425
+ function bookmarkToRng(editor, bookmark) {
27426
+ var rng;
27427
+
27428
+ if (bookmark.startContainer) {
27429
+ rng = editor.getDoc().createRange();
27430
+ rng.setStart(bookmark.startContainer, bookmark.startOffset);
27431
+ rng.setEnd(bookmark.endContainer, bookmark.endOffset);
27432
+ } else {
27433
+ rng = bookmark;
27434
+ }
27435
+
27436
+ return rng;
27437
+ }
27438
+
27160
27439
  function registerEvents(e) {
27161
27440
  var editor = e.editor, lastRng, selectionChangeHandler;
27162
27441
 
@@ -27166,16 +27445,26 @@ define("tinymce/FocusManager", [
27166
27445
 
27167
27446
  editor.on('init', function() {
27168
27447
  // On IE take selection snapshot onbeforedeactivate
27169
- if ("onbeforedeactivate" in document) {
27448
+ if ("onbeforedeactivate" in document && Env.ie < 11) {
27170
27449
  editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
27171
27450
  var ieSelection = editor.getDoc().selection;
27172
- lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
27451
+
27452
+ try {
27453
+ lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
27454
+ } catch (ex) {
27455
+ // IE throws "Unexcpected call to method or property access" some times so lets ignore it
27456
+ }
27173
27457
  });
27174
- } else if (editor.inline) {
27458
+ } else if (editor.inline || Env.ie > 10) {
27175
27459
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
27176
- editor.on('nodechange', function() {
27460
+ editor.on('nodechange keyup', function() {
27177
27461
  var isInBody, node = document.activeElement;
27178
27462
 
27463
+ // IE 11 reports active element as iframe not body of iframe
27464
+ if (node && node.id == editor.id + '_ifr') {
27465
+ node = editor.getBody();
27466
+ }
27467
+
27179
27468
  // Check if selection is within editor body
27180
27469
  while (node) {
27181
27470
  if (node == editor.getBody()) {
@@ -27215,12 +27504,17 @@ define("tinymce/FocusManager", [
27215
27504
  }
27216
27505
  });
27217
27506
 
27507
+ // Remove last selection bookmark on mousedown see #6305
27508
+ editor.on('mousedown', function() {
27509
+ editor.selection.lastFocusBookmark = null;
27510
+ });
27511
+
27218
27512
  editor.on('focusin', function() {
27219
27513
  var focusedEditor = editorManager.focusedEditor;
27220
27514
 
27221
- if (editor.selection.restoreRng) {
27222
- editor.selection.setRng(editor.selection.restoreRng);
27223
- editor.selection.restoreRng = null;
27515
+ if (editor.selection.lastFocusBookmark) {
27516
+ editor.selection.setRng(bookmarkToRng(editor, editor.selection.lastFocusBookmark));
27517
+ editor.selection.lastFocusBookmark = null;
27224
27518
  }
27225
27519
 
27226
27520
  if (focusedEditor != editor) {
@@ -27228,6 +27522,7 @@ define("tinymce/FocusManager", [
27228
27522
  focusedEditor.fire('blur', {focusedEditor: editor});
27229
27523
  }
27230
27524
 
27525
+ editorManager.activeEditor = editor;
27231
27526
  editor.fire('focus', {blurredEditor: focusedEditor});
27232
27527
  editor.focus(false);
27233
27528
  editorManager.focusedEditor = editor;
@@ -27235,21 +27530,21 @@ define("tinymce/FocusManager", [
27235
27530
  });
27236
27531
 
27237
27532
  editor.on('focusout', function() {
27238
- editor.selection.restoreRng = lastRng;
27533
+ editor.selection.lastFocusBookmark = createBookmark(lastRng);
27239
27534
 
27240
27535
  window.setTimeout(function() {
27241
27536
  var focusedEditor = editorManager.focusedEditor;
27242
27537
 
27243
27538
  // Focus from editorA into editorB then don't restore selection
27244
27539
  if (focusedEditor != editor) {
27245
- editor.selection.restoreRng = null;
27540
+ editor.selection.lastFocusBookmark = null;
27246
27541
  }
27247
27542
 
27248
- // Still the same editor the the blur was outside any editor
27543
+ // Still the same editor the the blur was outside any editor UI
27249
27544
  if (!isUIElement(getActiveElement()) && focusedEditor == editor) {
27250
27545
  editor.fire('blur', {focusedEditor: null});
27251
27546
  editorManager.focusedEditor = null;
27252
- editor.selection.restoreRng = null;
27547
+ editor.selection.lastFocusBookmark = null;
27253
27548
  }
27254
27549
  }, 0);
27255
27550
  });
@@ -27285,7 +27580,7 @@ define("tinymce/FocusManager", [
27285
27580
  */
27286
27581
 
27287
27582
  /**
27288
- * This class used as a factory for manager for tinymce.Editor instaces.
27583
+ * This class used as a factory for manager for tinymce.Editor instances.
27289
27584
  *
27290
27585
  * @example
27291
27586
  * tinymce.EditorManager.init({});
@@ -27323,7 +27618,7 @@ define("tinymce/EditorManager", [
27323
27618
  * @property minorVersion
27324
27619
  * @type String
27325
27620
  */
27326
- minorVersion : '0',
27621
+ minorVersion : '0.6',
27327
27622
 
27328
27623
  /**
27329
27624
  * Release date of TinyMCE build.
@@ -27331,7 +27626,7 @@ define("tinymce/EditorManager", [
27331
27626
  * @property releaseDate
27332
27627
  * @type String
27333
27628
  */
27334
- releaseDate: '2013-07-18',
27629
+ releaseDate: '2013-09-12',
27335
27630
 
27336
27631
  /**
27337
27632
  * Collection of editor instances.
@@ -27482,11 +27777,11 @@ define("tinymce/EditorManager", [
27482
27777
  return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
27483
27778
  }
27484
27779
 
27485
- self.settings = settings;
27486
-
27487
- DOM.bind(window, 'ready', function() {
27780
+ function readyHandler() {
27488
27781
  var l, co;
27489
27782
 
27783
+ DOM.unbind(window, 'ready', readyHandler);
27784
+
27490
27785
  execCallback(settings, 'onpageload');
27491
27786
 
27492
27787
  if (settings.types) {
@@ -27583,7 +27878,11 @@ define("tinymce/EditorManager", [
27583
27878
  }
27584
27879
  });
27585
27880
  }
27586
- });
27881
+ }
27882
+
27883
+ self.settings = settings;
27884
+
27885
+ DOM.bind(window, 'ready', readyHandler);
27587
27886
  },
27588
27887
 
27589
27888
  /**
@@ -27679,7 +27978,7 @@ define("tinymce/EditorManager", [
27679
27978
  * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
27680
27979
  */
27681
27980
  remove: function(selector) {
27682
- var self = this, i, editors = self.editors, editor;
27981
+ var self = this, i, editors = self.editors, editor, removedFromList;
27683
27982
 
27684
27983
  // Remove all editors
27685
27984
  if (!selector) {
@@ -27714,6 +28013,7 @@ define("tinymce/EditorManager", [
27714
28013
  for (i = 0; i < editors.length; i++) {
27715
28014
  if (editors[i] == editor) {
27716
28015
  editors.splice(i, 1);
28016
+ removedFromList = true;
27717
28017
  break;
27718
28018
  }
27719
28019
  }
@@ -27723,26 +28023,22 @@ define("tinymce/EditorManager", [
27723
28023
  self.activeEditor = editors[0];
27724
28024
  }
27725
28025
 
27726
- // Don't remove missing editor or removed instances
27727
- if (!editor || editor.removed) {
27728
- return;
27729
- }
27730
-
27731
- editor.remove();
27732
- editor.destroy();
27733
-
27734
28026
  /**
27735
28027
  * Fires when an editor is removed from EditorManager collection.
27736
28028
  *
27737
28029
  * @event RemoveEditor
27738
28030
  * @param {Object} e Event arguments.
27739
28031
  */
27740
- self.fire('RemoveEditor', {editor: editor});
28032
+ if (removedFromList) {
28033
+ self.fire('RemoveEditor', {editor: editor});
28034
+ }
27741
28035
 
27742
28036
  if (!editors.length) {
27743
28037
  DOM.unbind(window, 'beforeunload', beforeUnloadDelegate);
27744
28038
  }
27745
28039
 
28040
+ editor.remove();
28041
+
27746
28042
  return editor;
27747
28043
  },
27748
28044
 
@@ -27863,10 +28159,10 @@ define("tinymce/LegacyInput", [
27863
28159
  var each = Tools.each, explode = Tools.explode;
27864
28160
 
27865
28161
  EditorManager.on('AddEditor', function(e) {
27866
- var ed = e.editor;
28162
+ var editor = e.editor;
27867
28163
 
27868
- ed.on('preInit', function() {
27869
- var filters, fontSizes, dom, settings = ed.settings;
28164
+ editor.on('preInit', function() {
28165
+ var filters, fontSizes, dom, settings = editor.settings;
27870
28166
 
27871
28167
  function replaceWithSpan(node, styles) {
27872
28168
  each(styles, function(value, name) {
@@ -27879,7 +28175,7 @@ define("tinymce/LegacyInput", [
27879
28175
  }
27880
28176
 
27881
28177
  function convert(e) {
27882
- dom = ed.dom;
28178
+ dom = editor.dom;
27883
28179
 
27884
28180
  if (settings.convert_fonts_to_spans) {
27885
28181
  each(dom.select('font,u,strike', e.node), function(node) {
@@ -27914,7 +28210,7 @@ define("tinymce/LegacyInput", [
27914
28210
  }
27915
28211
  };
27916
28212
 
27917
- ed.on('PreProcess SetContent', convert);
28213
+ editor.on('PreProcess SetContent', convert);
27918
28214
  }
27919
28215
  });
27920
28216
  });
@@ -28305,16 +28601,24 @@ define("tinymce/util/JSONP", [
28305
28601
  * var value = tinymce.util.LocalStorage.getItem('key');
28306
28602
  */
28307
28603
  define("tinymce/util/LocalStorage", [], function() {
28308
- var LocalStorage, storageElm, items, keys, userDataKey;
28604
+ var LocalStorage, storageElm, items, keys, userDataKey, hasOldIEDataSupport;
28309
28605
 
28310
28606
  // Check for native support
28311
- if (window.localStorage) {
28312
- return localStorage;
28607
+ try {
28608
+ if (window.localStorage) {
28609
+ return localStorage;
28610
+ }
28611
+ } catch (ex) {
28612
+ // Ignore
28313
28613
  }
28314
28614
 
28315
28615
  userDataKey = "tinymce";
28316
28616
  storageElm = document.documentElement;
28317
- storageElm.addBehavior('#default#userData');
28617
+ hasOldIEDataSupport = !!storageElm.addBehavior;
28618
+
28619
+ if (hasOldIEDataSupport) {
28620
+ storageElm.addBehavior('#default#userData');
28621
+ }
28318
28622
 
28319
28623
  /**
28320
28624
  * Gets the keys names and updates LocalStorage.length property. Since IE7 doesn't have any getters/setters.
@@ -28337,6 +28641,11 @@ define("tinymce/util/LocalStorage", [], function() {
28337
28641
 
28338
28642
  items = {};
28339
28643
 
28644
+ // localStorage can be disabled on WebKit/Gecko so make a dummy storage
28645
+ if (!hasOldIEDataSupport) {
28646
+ return;
28647
+ }
28648
+
28340
28649
  function next(end) {
28341
28650
  var value, nextPos;
28342
28651
 
@@ -28371,6 +28680,11 @@ define("tinymce/util/LocalStorage", [], function() {
28371
28680
  function save() {
28372
28681
  var value, data = '';
28373
28682
 
28683
+ // localStorage can be disabled on WebKit/Gecko so make a dummy storage
28684
+ if (!hasOldIEDataSupport) {
28685
+ return;
28686
+ }
28687
+
28374
28688
  for (var key in items) {
28375
28689
  value = items[key];
28376
28690
  data += (data ? ',' : '') + key.length.toString(32) + ',' + key + ',' + value.length.toString(32) + ',' + value;
@@ -28987,7 +29301,7 @@ define("tinymce/ui/Widget", [
28987
29301
  *
28988
29302
  * @example
28989
29303
  * // Create and render a button to the body element
28990
- * tinymce.ui.Factory({
29304
+ * tinymce.ui.Factory.create({
28991
29305
  * type: 'button',
28992
29306
  * text: 'My button'
28993
29307
  * }).renderTo(document.body);
@@ -29095,7 +29409,7 @@ define("tinymce/ui/Button", [
29095
29409
  *
29096
29410
  * @example
29097
29411
  * // Create and render a buttongroup with two buttons to the body element
29098
- * tinymce.ui.Factory({
29412
+ * tinymce.ui.Factory.create({
29099
29413
  * type: 'buttongroup',
29100
29414
  * items: [
29101
29415
  * {text: 'Button A'},
@@ -29159,7 +29473,7 @@ define("tinymce/ui/ButtonGroup", [
29159
29473
  *
29160
29474
  * @example
29161
29475
  * // Create and render a checkbox to the body element
29162
- * tinymce.ui.Factory({
29476
+ * tinymce.ui.Factory.create({
29163
29477
  * type: 'checkbox',
29164
29478
  * checked: true,
29165
29479
  * text: 'My checkbox'
@@ -29657,6 +29971,11 @@ define("tinymce/ui/ComboBox", [
29657
29971
  return self._super();
29658
29972
  },
29659
29973
 
29974
+ remove: function() {
29975
+ DomUtils.off(this.getEl('inp'));
29976
+ this._super();
29977
+ },
29978
+
29660
29979
  /**
29661
29980
  * Renders the control as a HTML string.
29662
29981
  *
@@ -29792,7 +30111,7 @@ define("tinymce/ui/Path", [
29792
30111
  * @private
29793
30112
  */
29794
30113
  update: function() {
29795
- this.getEl().innerHTML = this._getPathHtml();
30114
+ this.innerHtml(this._getPathHtml());
29796
30115
  },
29797
30116
 
29798
30117
  /**
@@ -30622,191 +30941,195 @@ define("tinymce/ui/FlowLayout", [
30622
30941
  * @class tinymce.ui.FormatControls
30623
30942
  */
30624
30943
  define("tinymce/ui/FormatControls", [
30625
- "tinymce/ui/Factory",
30626
30944
  "tinymce/ui/Control",
30627
30945
  "tinymce/ui/Widget",
30628
30946
  "tinymce/ui/FloatPanel",
30629
30947
  "tinymce/util/Tools",
30630
30948
  "tinymce/EditorManager",
30631
30949
  "tinymce/Env"
30632
- ], function(Factory, Control, Widget, FloatPanel, Tools, EditorManager, Env) {
30950
+ ], function(Control, Widget, FloatPanel, Tools, EditorManager, Env) {
30633
30951
  var each = Tools.each;
30634
30952
 
30953
+ EditorManager.on('AddEditor', function(e) {
30954
+ registerControls(e.editor);
30955
+ });
30956
+
30635
30957
  Control.translate = function(text) {
30636
30958
  return EditorManager.translate(text);
30637
30959
  };
30638
30960
 
30639
30961
  Widget.tooltips = !Env.iOS;
30640
30962
 
30641
- // Generates a preview for a format
30642
- function getPreviewCss(format) {
30643
- var editor = EditorManager.activeEditor, name, previewElm, dom = editor.dom;
30644
- var previewCss = '', parentFontSize, previewStyles;
30963
+ function registerControls(editor) {
30964
+ var formatMenu;
30645
30965
 
30646
- previewStyles = editor.settings.preview_styles;
30966
+ // Generates a preview for a format
30967
+ function getPreviewCss(format) {
30968
+ var name, previewElm, dom = editor.dom;
30969
+ var previewCss = '', parentFontSize, previewStyles;
30647
30970
 
30648
- // No preview forced
30649
- if (previewStyles === false) {
30650
- return '';
30651
- }
30971
+ previewStyles = editor.settings.preview_styles;
30652
30972
 
30653
- // Default preview
30654
- if (!previewStyles) {
30655
- previewStyles = 'font-family font-size font-weight text-decoration text-transform color background-color border border-radius';
30656
- }
30973
+ // No preview forced
30974
+ if (previewStyles === false) {
30975
+ return '';
30976
+ }
30657
30977
 
30658
- // Removes any variables since these can't be previewed
30659
- function removeVars(val) {
30660
- return val.replace(/%(\w+)/g, '');
30661
- }
30978
+ // Default preview
30979
+ if (!previewStyles) {
30980
+ previewStyles = 'font-family font-size font-weight text-decoration ' +
30981
+ 'text-transform color background-color border border-radius';
30982
+ }
30662
30983
 
30663
- // Create block/inline element to use for preview
30664
- format = editor.formatter.get(format);
30665
- if (!format) {
30666
- return;
30667
- }
30984
+ // Removes any variables since these can't be previewed
30985
+ function removeVars(val) {
30986
+ return val.replace(/%(\w+)/g, '');
30987
+ }
30668
30988
 
30669
- format = format[0];
30670
- name = format.block || format.inline || 'span';
30671
- previewElm = dom.create(name);
30989
+ // Create block/inline element to use for preview
30990
+ format = editor.formatter.get(format);
30991
+ if (!format) {
30992
+ return;
30993
+ }
30672
30994
 
30673
- // Add format styles to preview element
30674
- each(format.styles, function(value, name) {
30675
- value = removeVars(value);
30995
+ format = format[0];
30996
+ name = format.block || format.inline || 'span';
30997
+ previewElm = dom.create(name);
30676
30998
 
30677
- if (value) {
30678
- dom.setStyle(previewElm, name, value);
30679
- }
30680
- });
30999
+ // Add format styles to preview element
31000
+ each(format.styles, function(value, name) {
31001
+ value = removeVars(value);
30681
31002
 
30682
- // Add attributes to preview element
30683
- each(format.attributes, function(value, name) {
30684
- value = removeVars(value);
31003
+ if (value) {
31004
+ dom.setStyle(previewElm, name, value);
31005
+ }
31006
+ });
30685
31007
 
30686
- if (value) {
30687
- dom.setAttrib(previewElm, name, value);
30688
- }
30689
- });
31008
+ // Add attributes to preview element
31009
+ each(format.attributes, function(value, name) {
31010
+ value = removeVars(value);
30690
31011
 
30691
- // Add classes to preview element
30692
- each(format.classes, function(value) {
30693
- value = removeVars(value);
31012
+ if (value) {
31013
+ dom.setAttrib(previewElm, name, value);
31014
+ }
31015
+ });
30694
31016
 
30695
- if (!dom.hasClass(previewElm, value)) {
30696
- dom.addClass(previewElm, value);
30697
- }
30698
- });
31017
+ // Add classes to preview element
31018
+ each(format.classes, function(value) {
31019
+ value = removeVars(value);
30699
31020
 
30700
- editor.fire('PreviewFormats');
31021
+ if (!dom.hasClass(previewElm, value)) {
31022
+ dom.addClass(previewElm, value);
31023
+ }
31024
+ });
30701
31025
 
30702
- // Add the previewElm outside the visual area
30703
- dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
30704
- editor.getBody().appendChild(previewElm);
31026
+ editor.fire('PreviewFormats');
30705
31027
 
30706
- // Get parent container font size so we can compute px values out of em/% for older IE:s
30707
- parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
30708
- parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
31028
+ // Add the previewElm outside the visual area
31029
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
31030
+ editor.getBody().appendChild(previewElm);
30709
31031
 
30710
- each(previewStyles.split(' '), function(name) {
30711
- var value = dom.getStyle(previewElm, name, true);
31032
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
31033
+ parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
31034
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
30712
31035
 
30713
- // If background is transparent then check if the body has a background color we can use
30714
- if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
30715
- value = dom.getStyle(editor.getBody(), name, true);
31036
+ each(previewStyles.split(' '), function(name) {
31037
+ var value = dom.getStyle(previewElm, name, true);
30716
31038
 
30717
- // Ignore white since it's the default color, not the nicest fix
30718
- // TODO: Fix this by detecting runtime style
30719
- if (dom.toHex(value).toLowerCase() == '#ffffff') {
30720
- return;
30721
- }
30722
- }
31039
+ // If background is transparent then check if the body has a background color we can use
31040
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
31041
+ value = dom.getStyle(editor.getBody(), name, true);
30723
31042
 
30724
- if (name == 'color') {
30725
- // Ignore black since it's the default color, not the nicest fix
30726
- // TODO: Fix this by detecting runtime style
30727
- if (dom.toHex(value).toLowerCase() == '#000000') {
30728
- return;
31043
+ // Ignore white since it's the default color, not the nicest fix
31044
+ // TODO: Fix this by detecting runtime style
31045
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
31046
+ return;
31047
+ }
30729
31048
  }
30730
- }
30731
31049
 
30732
- // Old IE won't calculate the font size so we need to do that manually
30733
- if (name == 'font-size') {
30734
- if (/em|%$/.test(value)) {
30735
- if (parentFontSize === 0) {
31050
+ if (name == 'color') {
31051
+ // Ignore black since it's the default color, not the nicest fix
31052
+ // TODO: Fix this by detecting runtime style
31053
+ if (dom.toHex(value).toLowerCase() == '#000000') {
30736
31054
  return;
30737
31055
  }
31056
+ }
31057
+
31058
+ // Old IE won't calculate the font size so we need to do that manually
31059
+ if (name == 'font-size') {
31060
+ if (/em|%$/.test(value)) {
31061
+ if (parentFontSize === 0) {
31062
+ return;
31063
+ }
30738
31064
 
30739
- // Convert font size from em/% to px
30740
- value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
30741
- value = (value * parentFontSize) + 'px';
31065
+ // Convert font size from em/% to px
31066
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
31067
+ value = (value * parentFontSize) + 'px';
31068
+ }
30742
31069
  }
30743
- }
30744
31070
 
30745
- if (name == "border" && value) {
30746
- previewCss += 'padding:0 2px;';
30747
- }
31071
+ if (name == "border" && value) {
31072
+ previewCss += 'padding:0 2px;';
31073
+ }
30748
31074
 
30749
- previewCss += name + ':' + value + ';';
30750
- });
31075
+ previewCss += name + ':' + value + ';';
31076
+ });
30751
31077
 
30752
- editor.fire('AfterPreviewFormats');
31078
+ editor.fire('AfterPreviewFormats');
30753
31079
 
30754
- //previewCss += 'line-height:normal';
31080
+ //previewCss += 'line-height:normal';
30755
31081
 
30756
- dom.remove(previewElm);
31082
+ dom.remove(previewElm);
30757
31083
 
30758
- return previewCss;
30759
- }
31084
+ return previewCss;
31085
+ }
30760
31086
 
30761
- function createListBoxChangeHandler(items, formatName) {
30762
- return function() {
30763
- var self = this;
31087
+ function createListBoxChangeHandler(items, formatName) {
31088
+ return function() {
31089
+ var self = this;
30764
31090
 
30765
- EditorManager.activeEditor.on('nodeChange', function(e) {
30766
- var formatter = EditorManager.activeEditor.formatter;
30767
- var value = null;
31091
+ editor.on('nodeChange', function(e) {
31092
+ var formatter = editor.formatter;
31093
+ var value = null;
30768
31094
 
30769
- each(e.parents, function(node) {
30770
- each(items, function(item) {
30771
- if (formatName) {
30772
- if (formatter.matchNode(node, formatName, {value: item.value})) {
30773
- value = item.value;
31095
+ each(e.parents, function(node) {
31096
+ each(items, function(item) {
31097
+ if (formatName) {
31098
+ if (formatter.matchNode(node, formatName, {value: item.value})) {
31099
+ value = item.value;
31100
+ }
31101
+ } else {
31102
+ if (formatter.matchNode(node, item.value)) {
31103
+ value = item.value;
31104
+ }
30774
31105
  }
30775
- } else {
30776
- if (formatter.matchNode(node, item.value)) {
30777
- value = item.value;
31106
+
31107
+ if (value) {
31108
+ return false;
30778
31109
  }
30779
- }
31110
+ });
30780
31111
 
30781
31112
  if (value) {
30782
31113
  return false;
30783
31114
  }
30784
31115
  });
30785
31116
 
30786
- if (value) {
30787
- return false;
30788
- }
31117
+ self.value(value);
30789
31118
  });
31119
+ };
31120
+ }
30790
31121
 
30791
- self.value(value);
30792
- });
30793
- };
30794
- }
31122
+ function createFormats(formats) {
31123
+ formats = formats.split(';');
30795
31124
 
30796
- function createFormats(formats) {
30797
- formats = formats.split(';');
31125
+ var i = formats.length;
31126
+ while (i--) {
31127
+ formats[i] = formats[i].split('=');
31128
+ }
30798
31129
 
30799
- var i = formats.length;
30800
- while (i--) {
30801
- formats[i] = formats[i].split('=');
31130
+ return formats;
30802
31131
  }
30803
31132
 
30804
- return formats;
30805
- }
30806
-
30807
- EditorManager.on('AddEditor', function(e) {
30808
- var editor = e.editor, formatMenu;
30809
-
30810
31133
  function createFormatMenu() {
30811
31134
  var count = 0, newFormats = [];
30812
31135
 
@@ -30855,8 +31178,7 @@ define("tinymce/ui/FormatControls", [
30855
31178
  each(formats, function(format) {
30856
31179
  var menuItem = {
30857
31180
  text: format.title,
30858
- icon: format.icon,
30859
- preview: true
31181
+ icon: format.icon
30860
31182
  };
30861
31183
 
30862
31184
  if (format.items) {
@@ -30869,22 +31191,7 @@ define("tinymce/ui/FormatControls", [
30869
31191
  newFormats.push(format);
30870
31192
  }
30871
31193
 
30872
- menuItem.textStyle = function() {
30873
- return getPreviewCss(formatName);
30874
- };
30875
-
30876
- menuItem.onclick = function() {
30877
- toggleFormat(formatName);
30878
- };
30879
-
30880
- menuItem.onPostRender = function() {
30881
- var self = this;
30882
-
30883
- self.parent().on('show', function() {
30884
- self.disabled(!editor.formatter.canApply(formatName));
30885
- self.active(editor.formatter.match(formatName));
30886
- });
30887
- };
31194
+ menuItem.format = formatName;
30888
31195
  }
30889
31196
 
30890
31197
  menu.push(menuItem);
@@ -30901,6 +31208,40 @@ define("tinymce/ui/FormatControls", [
30901
31208
 
30902
31209
  var menu = createMenu(editor.settings.style_formats || defaultStyleFormats);
30903
31210
 
31211
+ menu = {
31212
+ type: 'menu',
31213
+ items: menu,
31214
+ onPostRender: function(e) {
31215
+ editor.fire('renderFormatsMenu', {control: e.control});
31216
+ },
31217
+ itemDefaults: {
31218
+ preview: true,
31219
+
31220
+ textStyle: function() {
31221
+ if (this.settings.format) {
31222
+ return getPreviewCss(this.settings.format);
31223
+ }
31224
+ },
31225
+
31226
+ onPostRender: function() {
31227
+ var self = this, formatName = this.settings.format;
31228
+
31229
+ if (formatName) {
31230
+ self.parent().on('show', function() {
31231
+ self.disabled(!editor.formatter.canApply(formatName));
31232
+ self.active(editor.formatter.match(formatName));
31233
+ });
31234
+ }
31235
+ },
31236
+
31237
+ onclick: function() {
31238
+ if (this.settings.format) {
31239
+ toggleFormat(this.settings.format);
31240
+ }
31241
+ }
31242
+ }
31243
+ };
31244
+
30904
31245
  return menu;
30905
31246
  }
30906
31247
 
@@ -30963,7 +31304,7 @@ define("tinymce/ui/FormatControls", [
30963
31304
  each({
30964
31305
  blockquote: ['Toggle blockquote', 'mceBlockQuote'],
30965
31306
  numlist: ['Numbered list', 'InsertOrderedList'],
30966
- bullist: ['Bulleted list', 'InsertUnorderedList'],
31307
+ bullist: ['Bullet list', 'InsertUnorderedList'],
30967
31308
  subscript: ['Subscript', 'Subscript'],
30968
31309
  superscript: ['Superscript', 'Superscript'],
30969
31310
  alignleft: ['Align left', 'JustifyLeft'],
@@ -31102,31 +31443,17 @@ define("tinymce/ui/FormatControls", [
31102
31443
  }
31103
31444
 
31104
31445
  if (fmt) {
31105
- EditorManager.activeEditor.execCommand('mceToggleFormat', false, fmt);
31446
+ editor.execCommand('mceToggleFormat', false, fmt);
31106
31447
  }
31107
31448
  }
31108
31449
 
31109
- Factory.add('styleselect', function(settings) {
31110
- var menu = [].concat(formatMenu);
31111
-
31112
- /*
31113
- menu.push({text: '-'});
31114
- menu.push({
31115
- text: 'Remove formatting',
31116
- icon: 'removeformat',
31117
- onclick: function() {
31118
- editor.execCommand('RemoveFormat');
31119
- }
31120
- });
31121
- */
31122
-
31123
- return Factory.create('menubutton', Tools.extend({
31124
- text: 'Formats',
31125
- menu: menu
31126
- }, settings));
31450
+ editor.addButton('styleselect', {
31451
+ type: 'menubutton',
31452
+ text: 'Formats',
31453
+ menu: formatMenu
31127
31454
  });
31128
31455
 
31129
- Factory.add('formatselect', function(settings) {
31456
+ editor.addButton('formatselect', function() {
31130
31457
  var items = [], blocks = createFormats(editor.settings.block_formats ||
31131
31458
  'Paragraph=p;' +
31132
31459
  'Address=address;' +
@@ -31141,7 +31468,7 @@ define("tinymce/ui/FormatControls", [
31141
31468
 
31142
31469
  each(blocks, function(block) {
31143
31470
  items.push({
31144
- text: {raw: block[0]},
31471
+ text: block[0],
31145
31472
  value: block[1],
31146
31473
  textStyle: function() {
31147
31474
  return getPreviewCss(block[1]);
@@ -31149,16 +31476,17 @@ define("tinymce/ui/FormatControls", [
31149
31476
  });
31150
31477
  });
31151
31478
 
31152
- return Factory.create('listbox', Tools.extend({
31479
+ return {
31480
+ type: 'listbox',
31153
31481
  text: {raw: blocks[0][0]},
31154
31482
  values: items,
31155
31483
  fixedWidth: true,
31156
31484
  onselect: toggleFormat,
31157
31485
  onPostRender: createListBoxChangeHandler(items)
31158
- }, settings));
31486
+ };
31159
31487
  });
31160
31488
 
31161
- Factory.add('fontselect', function(settings) {
31489
+ editor.addButton('fontselect', function() {
31162
31490
  var defaultFontsFormats =
31163
31491
  'Andale Mono=andale mono,times;' +
31164
31492
  'Arial=arial,helvetica,sans-serif;' +
@@ -31188,7 +31516,8 @@ define("tinymce/ui/FormatControls", [
31188
31516
  });
31189
31517
  });
31190
31518
 
31191
- return Factory.create('listbox', Tools.extend({
31519
+ return {
31520
+ type: 'listbox',
31192
31521
  text: 'Font Family',
31193
31522
  tooltip: 'Font Family',
31194
31523
  values: items,
@@ -31196,13 +31525,13 @@ define("tinymce/ui/FormatControls", [
31196
31525
  onPostRender: createListBoxChangeHandler(items, 'fontname'),
31197
31526
  onselect: function(e) {
31198
31527
  if (e.control.settings.value) {
31199
- EditorManager.activeEditor.execCommand('FontName', false, e.control.settings.value);
31528
+ editor.execCommand('FontName', false, e.control.settings.value);
31200
31529
  }
31201
31530
  }
31202
- }, settings));
31531
+ };
31203
31532
  });
31204
31533
 
31205
- Factory.add('fontsizeselect', function(settings) {
31534
+ editor.addButton('fontsizeselect', function() {
31206
31535
  var items = [], defaultFontsizeFormats = '8pt 10pt 12pt 14pt 18pt 24pt 36pt';
31207
31536
  var fontsize_formats = editor.settings.fontsize_formats || defaultFontsizeFormats;
31208
31537
 
@@ -31210,7 +31539,8 @@ define("tinymce/ui/FormatControls", [
31210
31539
  items.push({text: item, value: item});
31211
31540
  });
31212
31541
 
31213
- return Factory.create('listbox', Tools.extend({
31542
+ return {
31543
+ type: 'listbox',
31214
31544
  text: 'Font Sizes',
31215
31545
  tooltip: 'Font Sizes',
31216
31546
  values: items,
@@ -31218,17 +31548,17 @@ define("tinymce/ui/FormatControls", [
31218
31548
  onPostRender: createListBoxChangeHandler(items, 'fontsize'),
31219
31549
  onclick: function(e) {
31220
31550
  if (e.control.settings.value) {
31221
- EditorManager.activeEditor.execCommand('FontSize', false, e.control.settings.value);
31551
+ editor.execCommand('FontSize', false, e.control.settings.value);
31222
31552
  }
31223
31553
  }
31224
- }, settings));
31554
+ };
31225
31555
  });
31226
31556
 
31227
31557
  editor.addMenuItem('formats', {
31228
31558
  text: 'Formats',
31229
31559
  menu: formatMenu
31230
31560
  });
31231
- });
31561
+ }
31232
31562
  });
31233
31563
 
31234
31564
  // Included from: js/tinymce/classes/ui/GridLayout.js
@@ -31523,10 +31853,25 @@ define("tinymce/ui/Iframe", [
31523
31853
  *
31524
31854
  * @method html
31525
31855
  * @param {String} html HTML string to set as HTML inside the iframe.
31856
+ * @param {function} callback Optional callback to execute when the iframe body is filled with contents.
31526
31857
  * @return {tinymce.ui.Iframe} Current iframe control.
31527
31858
  */
31528
- html: function(html) {
31529
- this.getEl().contentWindow.document.body.innerHTML = html;
31859
+ html: function(html, callback) {
31860
+ var self = this, body = this.getEl().contentWindow.document.body;
31861
+
31862
+ // Wait for iframe to initialize IE 10 takes time
31863
+ if (!body) {
31864
+ setTimeout(function() {
31865
+ self.html(html);
31866
+ }, 0);
31867
+ } else {
31868
+ body.innerHTML = html;
31869
+
31870
+ if (callback) {
31871
+ callback();
31872
+ }
31873
+ }
31874
+
31530
31875
  return this;
31531
31876
  }
31532
31877
  });
@@ -31654,7 +31999,7 @@ define("tinymce/ui/Label", [
31654
31999
  var self = this;
31655
32000
 
31656
32001
  if (self._rendered && text) {
31657
- self.getEl().innerHTML = self.encode(text);
32002
+ this.innerHtml(self.encode(text));
31658
32003
  }
31659
32004
 
31660
32005
  return self._super(text);
@@ -32254,9 +32599,9 @@ define("tinymce/ui/MenuItem", [
32254
32599
  * @method showMenu
32255
32600
  */
32256
32601
  showMenu: function() {
32257
- var self = this, settings = self.settings, menu;
32602
+ var self = this, settings = self.settings, menu, parent = self.parent();
32258
32603
 
32259
- self.parent().items().each(function(ctrl) {
32604
+ parent.items().each(function(ctrl) {
32260
32605
  if (ctrl !== self) {
32261
32606
  ctrl.hideMenu();
32262
32607
  }
@@ -32278,6 +32623,10 @@ define("tinymce/ui/MenuItem", [
32278
32623
  menu.type = menu.type || 'menu';
32279
32624
  }
32280
32625
 
32626
+ if (parent.settings.itemDefaults) {
32627
+ menu.itemDefaults = parent.settings.itemDefaults;
32628
+ }
32629
+
32281
32630
  menu = self.menu = Factory.create(menu).parent(self).renderTo(self.getContainerElm());
32282
32631
  menu.reflow();
32283
32632
  menu.fire('show');
@@ -32294,7 +32643,7 @@ define("tinymce/ui/MenuItem", [
32294
32643
  menu.show();
32295
32644
  }
32296
32645
 
32297
- menu._parentMenu = self.parent();
32646
+ menu._parentMenu = parent;
32298
32647
 
32299
32648
  menu.addClass('menu-sub');
32300
32649
 
@@ -32341,17 +32690,22 @@ define("tinymce/ui/MenuItem", [
32341
32690
  */
32342
32691
  renderHtml: function() {
32343
32692
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
32344
- var icon = self.settings.icon;
32693
+ var icon = self.settings.icon, image = '';
32345
32694
 
32346
32695
  if (icon) {
32347
32696
  self.parent().addClass('menu-has-icons');
32348
32697
  }
32349
32698
 
32699
+ if (settings.image) {
32700
+ icon = 'none';
32701
+ image = ' style="background-image: url(\'' + settings.image + '\')"';
32702
+ }
32703
+
32350
32704
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
32351
32705
 
32352
32706
  return (
32353
32707
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
32354
- (text !== '-' ? '<i class="' + icon + '"></i>&nbsp;' : '') +
32708
+ (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
32355
32709
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
32356
32710
  (settings.shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
32357
32711
  settings.shortcut + '</div>' : '') +
@@ -32370,7 +32724,7 @@ define("tinymce/ui/MenuItem", [
32370
32724
 
32371
32725
  var textStyle = settings.textStyle;
32372
32726
  if (typeof(textStyle) == "function") {
32373
- textStyle = textStyle();
32727
+ textStyle = textStyle.call(this);
32374
32728
  }
32375
32729
 
32376
32730
  if (textStyle) {
@@ -32420,8 +32774,9 @@ define("tinymce/ui/MenuItem", [
32420
32774
  define("tinymce/ui/Menu", [
32421
32775
  "tinymce/ui/FloatPanel",
32422
32776
  "tinymce/ui/KeyboardNavigation",
32423
- "tinymce/ui/MenuItem"
32424
- ], function(FloatPanel, KeyboardNavigation, MenuItem) {
32777
+ "tinymce/ui/MenuItem",
32778
+ "tinymce/util/Tools"
32779
+ ], function(FloatPanel, KeyboardNavigation, MenuItem, Tools) {
32425
32780
  "use strict";
32426
32781
 
32427
32782
  var Menu = FloatPanel.extend({
@@ -32444,6 +32799,14 @@ define("tinymce/ui/Menu", [
32444
32799
  settings.autohide = true;
32445
32800
  settings.constrainToViewport = true;
32446
32801
 
32802
+ if (settings.itemDefaults) {
32803
+ var items = settings.items, i = items.length;
32804
+
32805
+ while (i--) {
32806
+ items[i] = Tools.extend({}, settings.itemDefaults, items[i]);
32807
+ }
32808
+ }
32809
+
32447
32810
  self._super(settings);
32448
32811
  self.addClass('menu');
32449
32812
 
@@ -32640,6 +33003,14 @@ define("tinymce/ui/ResizeHandle", [
32640
33003
  self.fire('ResizeEnd');
32641
33004
  }
32642
33005
  });
33006
+ },
33007
+
33008
+ remove: function() {
33009
+ if (this.resizeDragHelper) {
33010
+ this.resizeDragHelper.destroy();
33011
+ }
33012
+
33013
+ return this._super();
32643
33014
  }
32644
33015
  });
32645
33016
  });
@@ -33195,6 +33566,11 @@ define("tinymce/ui/TextBox", [
33195
33566
  });
33196
33567
 
33197
33568
  return self._super();
33569
+ },
33570
+
33571
+ remove: function() {
33572
+ DomUtils.off(this.getEl());
33573
+ this._super();
33198
33574
  }
33199
33575
  });
33200
33576
  });