tinymce-rails 4.0.2 → 4.0.6

Sign up to get free protection for your applications and to get access to all the features.
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
  });