tinymce-rails 4.0.2 → 4.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/app/assets/source/tinymce/tinymce.jquery.js +975 -599
  2. data/app/assets/source/tinymce/tinymce.js +975 -599
  3. data/lib/tinymce/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  5. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  6. data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
  7. data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/example/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -0
  12. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/template/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/css/visualblocks.css +14 -0
  23. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.eot +0 -0
  25. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.svg +150 -141
  26. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.ttf +0 -0
  27. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon-small.woff +0 -0
  28. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.eot +0 -0
  29. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.svg +132 -129
  30. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.ttf +0 -0
  31. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/icomoon.woff +0 -0
  32. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  33. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
  34. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +9 -9
  36. data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
  37. metadata +3 -7
  38. data/vendor/assets/javascripts/tinymce/plugins/compat3x/editable_selects.js +0 -70
  39. data/vendor/assets/javascripts/tinymce/plugins/compat3x/form_utils.js +0 -210
  40. data/vendor/assets/javascripts/tinymce/plugins/compat3x/mctabs.js +0 -162
  41. data/vendor/assets/javascripts/tinymce/plugins/compat3x/tiny_mce_popup.js +0 -435
  42. data/vendor/assets/javascripts/tinymce/plugins/compat3x/validate.js +0 -252
@@ -1,4 +1,4 @@
1
- // 4.0.2 (2013-07-18)
1
+ // 4.0.6 (2013-09-12)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -437,6 +437,7 @@ define("tinymce/dom/EventUtils", [], function() {
437
437
 
438
438
  var eventExpandoPrefix = "mce-data-";
439
439
  var mouseEventRe = /^(?:mouse|contextmenu)|click/;
440
+ var deprecated = {keyLocation: 1, layerX: 1, layerY: 1, returnValue: 1};
440
441
 
441
442
  /**
442
443
  * Binds a native event to a callback on the speified target.
@@ -479,7 +480,7 @@ define("tinymce/dom/EventUtils", [], function() {
479
480
  // Copy all properties from the original event
480
481
  for (name in originalEvent) {
481
482
  // layerX/layerY is deprecated in Chrome and produces a warning
482
- if (name !== "layerX" && name !== "layerY") {
483
+ if (!deprecated[name]) {
483
484
  event[name] = originalEvent[name];
484
485
  }
485
486
  }
@@ -814,6 +815,13 @@ define("tinymce/dom/EventUtils", [], function() {
814
815
  ci = callbackList.length;
815
816
  while (ci--) {
816
817
  if (callbackList[ci].func === callback) {
818
+ var nativeHandler = callbackList.nativeHandler;
819
+
820
+ // Clone callbackList since unbind inside a callback would otherwise break the handlers loop
821
+ callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
822
+ callbackList.nativeHandler = nativeHandler;
823
+
824
+ eventMap[name] = callbackList;
817
825
  callbackList.splice(ci, 1);
818
826
  }
819
827
  }
@@ -1692,7 +1700,11 @@ define("tinymce/dom/Range", [
1692
1700
  if (o) {
1693
1701
  startContainer.insertBefore(n, o);
1694
1702
  } else {
1695
- startContainer.appendChild(n);
1703
+ if (startContainer.nodeType == 3) {
1704
+ dom.insertAfter(n, startContainer);
1705
+ } else {
1706
+ startContainer.appendChild(n);
1707
+ }
1696
1708
  }
1697
1709
  }
1698
1710
  }
@@ -2612,12 +2624,14 @@ define("tinymce/html/Entities", [
2612
2624
  */
2613
2625
  define("tinymce/Env", [], function() {
2614
2626
  var nav = navigator, userAgent = nav.userAgent;
2615
- var opera, webkit, ie, gecko, mac, iDevice;
2627
+ var opera, webkit, ie, ie11, gecko, mac, iDevice;
2616
2628
 
2617
2629
  opera = window.opera && window.opera.buildNumber;
2618
2630
  webkit = /WebKit/.test(userAgent);
2619
2631
  ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
2620
2632
  ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
2633
+ ie11 = userAgent.indexOf('Trident') != -1 ? 11 : false;
2634
+ ie = ie || ie11;
2621
2635
  gecko = !webkit && /Gecko/.test(userAgent);
2622
2636
  mac = userAgent.indexOf('Mac') != -1;
2623
2637
  iDevice = /(iPad|iPhone)/.test(userAgent);
@@ -2784,6 +2798,7 @@ define("tinymce/dom/DOMUtils", [
2784
2798
  self.stdMode = !isIE || doc.documentMode >= 8;
2785
2799
  self.boxModel = !isIE || doc.compatMode == "CSS1Compat" || self.stdMode;
2786
2800
  self.hasOuterHTML = "outerHTML" in doc.createElement("a");
2801
+ this.boundEvents = [];
2787
2802
 
2788
2803
  self.settings = settings = extend({
2789
2804
  keep_values: false,
@@ -3415,7 +3430,7 @@ define("tinymce/dom/DOMUtils", [
3415
3430
  }
3416
3431
 
3417
3432
  // IE & Opera
3418
- if (name.currentStyle && computed) {
3433
+ if (elm.currentStyle && computed) {
3419
3434
  return elm.currentStyle[name];
3420
3435
  }
3421
3436
 
@@ -3712,8 +3727,8 @@ define("tinymce/dom/DOMUtils", [
3712
3727
  * Returns the absolute x, y position of a node. The position will be returned in an object with x, y fields.
3713
3728
  *
3714
3729
  * @method getPos
3715
- * @param {Element/String} n HTML element or element id to get x, y position from.
3716
- * @param {Element} ro Optional root element to stop calculations at.
3730
+ * @param {Element/String} elm HTML element or element id to get x, y position from.
3731
+ * @param {Element} rootElm Optional root element to stop calculations at.
3717
3732
  * @return {object} Absolute position of the specified element object with x, y fields.
3718
3733
  */
3719
3734
  getPos: function(elm, rootElm) {
@@ -4328,78 +4343,6 @@ define("tinymce/dom/DOMUtils", [
4328
4343
  return this.styles.toHex(Tools.trim(rgbVal));
4329
4344
  },
4330
4345
 
4331
- /**
4332
- * Returns an array of all single CSS classes in the document. A single CSS class is a simple
4333
- * rule like ".class" - complex ones like "div td.class" will not be added to output.
4334
- *
4335
- * @method getClasses
4336
- * @return {Array} Array with class objects - each object has a class field - might be other fields in the future.
4337
- */
4338
- getClasses: function() {
4339
- var self = this, classList = [], lookup = {}, filter = self.settings.class_filter, oldVal;
4340
-
4341
- if (self.classes) {
4342
- return self.classes;
4343
- }
4344
-
4345
- function addClasses(stylesheet) {
4346
- // IE style imports
4347
- each(stylesheet.imports, function(r) {
4348
- addClasses(r);
4349
- });
4350
-
4351
- each(stylesheet.cssRules || stylesheet.rules, function(rule) {
4352
- // Real type or fake it on IE
4353
- switch (rule.type || 1) {
4354
- // Rule
4355
- case 1:
4356
- if (rule.selectorText) {
4357
- each(rule.selectorText.split(','), function(value) {
4358
- value = value.replace(/^\s*|\s*$|^\s\./g, "");
4359
-
4360
- // Is internal or it doesn't contain a class
4361
- if (/\.mce/.test(value) || !/\.[\w\-]+$/.test(value)) {
4362
- return;
4363
- }
4364
-
4365
- // Remove everything but class name
4366
- oldVal = value;
4367
- value = value.replace(/.*\.([a-z0-9_\-]+).*/i, '$1');
4368
-
4369
- // Filter classes
4370
- if (filter && !(value = filter(value, oldVal))) {
4371
- return;
4372
- }
4373
-
4374
- if (!lookup[value]) {
4375
- classList.push({'class': value});
4376
- lookup[value] = 1;
4377
- }
4378
- });
4379
- }
4380
- break;
4381
-
4382
- // Import
4383
- case 3:
4384
- addClasses(rule.styleSheet);
4385
- break;
4386
- }
4387
- });
4388
- }
4389
-
4390
- try {
4391
- each(self.doc.styleSheets, addClasses);
4392
- } catch (ex) {
4393
- // Ignore
4394
- }
4395
-
4396
- if (classList.length > 0) {
4397
- self.classes = classList;
4398
- }
4399
-
4400
- return classList;
4401
- },
4402
-
4403
4346
  /**
4404
4347
  * Executes the specified function on the element by id or dom element node or array of elements/id.
4405
4348
  *
@@ -4696,28 +4639,70 @@ define("tinymce/dom/DOMUtils", [
4696
4639
  * Adds an event handler to the specified object.
4697
4640
  *
4698
4641
  * @method bind
4699
- * @param {Element/Document/Window/Array/String} o Object or element id string to add event
4642
+ * @param {Element/Document/Window/Array} target Target element to bind events to.
4700
4643
  * handler to or an array of elements/ids/documents.
4701
- * @param {String} n Name of event handler to add, for example: click.
4702
- * @param {function} f Function to execute when the event occurs.
4703
- * @param {Object} s Optional scope to execute the function in.
4644
+ * @param {String} name Name of event handler to add, for example: click.
4645
+ * @param {function} func Function to execute when the event occurs.
4646
+ * @param {Object} scope Optional scope to execute the function in.
4704
4647
  * @return {function} Function callback handler the same as the one passed in.
4705
4648
  */
4706
4649
  bind: function(target, name, func, scope) {
4707
- return this.events.bind(target, name, func, scope || this);
4650
+ var self = this;
4651
+
4652
+ if (Tools.isArray(target)) {
4653
+ var i = target.length;
4654
+
4655
+ while (i--) {
4656
+ target[i] = self.bind(target[i], name, func, scope);
4657
+ }
4658
+
4659
+ return target;
4660
+ }
4661
+
4662
+ // Collect all window/document events bound by editor instance
4663
+ if (self.settings.collect && (target === self.doc || target === self.win)) {
4664
+ self.boundEvents.push([target, name, func, scope]);
4665
+ }
4666
+
4667
+ return self.events.bind(target, name, func, scope || self);
4708
4668
  },
4709
4669
 
4710
4670
  /**
4711
4671
  * Removes the specified event handler by name and function from an element or collection of elements.
4712
4672
  *
4713
4673
  * @method unbind
4714
- * @param {String/Element/Array} o Element ID string or HTML element or an array of elements or ids to remove handler from.
4715
- * @param {String} n Event handler name, for example: "click"
4716
- * @param {function} f Function to remove.
4674
+ * @param {Element/Document/Window/Array} target Target element to unbind events on.
4675
+ * @param {String} name Event handler name, for example: "click"
4676
+ * @param {function} func Function to remove.
4717
4677
  * @return {bool/Array} Bool state of true if the handler was removed, or an array of states if multiple input elements
4718
4678
  * were passed in.
4719
4679
  */
4720
4680
  unbind: function(target, name, func) {
4681
+ var self = this, i;
4682
+
4683
+ if (Tools.isArray(target)) {
4684
+ i = target.length;
4685
+
4686
+ while (i--) {
4687
+ target[i] = self.unbind(target[i], name, func);
4688
+ }
4689
+
4690
+ return target;
4691
+ }
4692
+
4693
+ // Remove any bound events matching the input
4694
+ if (self.boundEvents && (target === self.doc || target === self.win)) {
4695
+ i = self.boundEvents.length;
4696
+
4697
+ while (i--) {
4698
+ var item = self.boundEvents[i];
4699
+
4700
+ if (target == item[0] && (!name || name == item[1]) && (!func || func == item[2])) {
4701
+ this.events.unbind(item[0], item[1], item[2]);
4702
+ }
4703
+ }
4704
+ }
4705
+
4721
4706
  return this.events.unbind(target, name, func);
4722
4707
  },
4723
4708
 
@@ -4761,6 +4746,18 @@ define("tinymce/dom/DOMUtils", [
4761
4746
  destroy: function() {
4762
4747
  var self = this;
4763
4748
 
4749
+ // Unbind all events bound to window/document by editor instance
4750
+ if (self.boundEvents) {
4751
+ var i = self.boundEvents.length;
4752
+
4753
+ while (i--) {
4754
+ var item = self.boundEvents[i];
4755
+ this.events.unbind(item[0], item[1], item[2]);
4756
+ }
4757
+
4758
+ self.boundEvents = null;
4759
+ }
4760
+
4764
4761
  self.win = self.doc = self.root = self.events = self.frag = null;
4765
4762
  },
4766
4763
 
@@ -5089,182 +5086,180 @@ define("tinymce/dom/ScriptLoader", [
5089
5086
  * @class tinymce.AddOnManager
5090
5087
  */
5091
5088
  define("tinymce/AddOnManager", [
5092
- "tinymce/dom/ScriptLoader",
5093
- "tinymce/util/Tools"
5089
+ "tinymce/dom/ScriptLoader",
5090
+ "tinymce/util/Tools"
5094
5091
  ], function(ScriptLoader, Tools) {
5095
- var each = Tools.each;
5096
-
5097
- function AddOnManager() {
5098
- var self = this;
5099
-
5100
- self.items = [];
5101
- self.urls = {};
5102
- self.lookup = {};
5103
- }
5104
-
5105
- AddOnManager.prototype = {
5106
- /**
5107
- * Returns the specified add on by the short name.
5108
- *
5109
- * @method get
5110
- * @param {String} name Add-on to look for.
5111
- * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
5112
- */
5113
- get: function(name) {
5114
- if (this.lookup[name]) {
5115
- return this.lookup[name].instance;
5116
- } else {
5117
- return undefined;
5118
- }
5119
- },
5120
-
5121
- dependencies: function(name) {
5122
- var result;
5123
-
5124
- if (this.lookup[name]) {
5125
- result = this.lookup[name].dependencies;
5126
- }
5127
-
5128
- return result || [];
5129
- },
5130
-
5131
- /**
5132
- * Loads a language pack for the specified add-on.
5133
- *
5134
- * @method requireLangPack
5135
- * @param {String} name Short name of the add-on.
5136
- */
5137
- requireLangPack: function(name) {
5138
- var settings = AddOnManager.settings;
5139
-
5140
- if (settings && settings.language && settings.language_load !== false) {
5141
- ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + settings.language + '.js');
5142
- }
5143
- },
5144
-
5145
- /**
5146
- * Adds a instance of the add-on by it's short name.
5147
- *
5148
- * @method add
5149
- * @param {String} id Short name/id for the add-on.
5150
- * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add.
5151
- * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
5152
- * @example
5153
- * // Create a simple plugin
5154
- * tinymce.create('tinymce.plugins.TestPlugin', {
5155
- * TestPlugin: function(ed, url) {
5156
- * ed.on('click', function(e) {
5157
- * ed.windowManager.alert('Hello World!');
5158
- * });
5159
- * }
5160
- * });
5161
- *
5162
- * // Register plugin using the add method
5163
- * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
5164
- *
5165
- * // Initialize TinyMCE
5166
- * tinymce.init({
5167
- * ...
5168
- * plugins: '-test' // Init the plugin but don't try to load it
5169
- * });
5170
- */
5171
- add: function(id, addOn, dependencies) {
5172
- this.items.push(addOn);
5173
- this.lookup[id] = {instance: addOn, dependencies: dependencies};
5174
-
5175
- return addOn;
5176
- },
5177
-
5178
- createUrl: function(baseUrl, dep) {
5179
- if (typeof dep === "object") {
5180
- return dep;
5181
- } else {
5182
- return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
5183
- }
5184
- },
5185
-
5186
- /**
5187
- * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
5188
- * This should be used in development mode. A new compressor/javascript munger process will ensure that the
5189
- * components are put together into the plugin.js file and compressed correctly.
5190
- *
5191
- * @method addComponents
5192
- * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins).
5193
- * @param {Array} scripts Array containing the names of the scripts to load.
5194
- */
5195
- addComponents: function(pluginName, scripts) {
5196
- var pluginUrl = this.urls[pluginName];
5197
-
5198
- each(scripts, function(script) {
5199
- ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script);
5200
- });
5201
- },
5202
-
5203
- /**
5204
- * Loads an add-on from a specific url.
5205
- *
5206
- * @method load
5207
- * @param {String} n Short name of the add-on that gets loaded.
5208
- * @param {String} u URL to the add-on that will get loaded.
5209
- * @param {function} cb Optional callback to execute ones the add-on is loaded.
5210
- * @param {Object} s Optional scope to execute the callback in.
5211
- * @example
5212
- * // Loads a plugin from an external URL
5213
- * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
5214
- *
5215
- * // Initialize TinyMCE
5216
- * tinymce.init({
5217
- * ...
5218
- * plugins: '-myplugin' // Don't try to load it again
5219
- * });
5220
- */
5221
- load: function(n, u, cb, s) {
5222
- var t = this, url = u;
5223
-
5224
- function loadDependencies() {
5225
- var dependencies = t.dependencies(n);
5226
-
5227
- each(dependencies, function(dep) {
5228
- var newUrl = t.createUrl(u, dep);
5229
-
5230
- t.load(newUrl.resource, newUrl, undefined, undefined);
5231
- });
5232
-
5233
- if (cb) {
5234
- if (s) {
5235
- cb.call(s);
5236
- } else {
5237
- cb.call(ScriptLoader);
5238
- }
5239
- }
5240
- }
5241
-
5242
- if (t.urls[n]) {
5243
- return;
5244
- }
5245
-
5246
- if (typeof u === "object") {
5247
- url = u.prefix + u.resource + u.suffix;
5248
- }
5249
-
5250
- if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) {
5251
- url = AddOnManager.baseURL + '/' + url;
5252
- }
5253
-
5254
- t.urls[n] = url.substring(0, url.lastIndexOf('/'));
5255
-
5256
- if (t.lookup[n]) {
5257
- loadDependencies();
5258
- } else {
5259
- ScriptLoader.ScriptLoader.add(url, loadDependencies, s);
5260
- }
5261
- }
5262
- };
5263
-
5264
- AddOnManager.PluginManager = new AddOnManager();
5265
- AddOnManager.ThemeManager = new AddOnManager();
5266
-
5267
- return AddOnManager;
5092
+ var each = Tools.each;
5093
+
5094
+ function AddOnManager() {
5095
+ var self = this;
5096
+
5097
+ self.items = [];
5098
+ self.urls = {};
5099
+ self.lookup = {};
5100
+ }
5101
+
5102
+ AddOnManager.prototype = {
5103
+ /**
5104
+ * Returns the specified add on by the short name.
5105
+ *
5106
+ * @method get
5107
+ * @param {String} name Add-on to look for.
5108
+ * @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
5109
+ */
5110
+ get: function(name) {
5111
+ if (this.lookup[name]) {
5112
+ return this.lookup[name].instance;
5113
+ } else {
5114
+ return undefined;
5115
+ }
5116
+ },
5117
+
5118
+ dependencies: function(name) {
5119
+ var result;
5120
+
5121
+ if (this.lookup[name]) {
5122
+ result = this.lookup[name].dependencies;
5123
+ }
5124
+
5125
+ return result || [];
5126
+ },
5127
+
5128
+ /**
5129
+ * Loads a language pack for the specified add-on.
5130
+ *
5131
+ * @method requireLangPack
5132
+ * @param {String} name Short name of the add-on.
5133
+ */
5134
+ requireLangPack: function(name) {
5135
+ if (AddOnManager.language && AddOnManager.languageLoad !== false) {
5136
+ ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
5137
+ }
5138
+ },
5139
+
5140
+ /**
5141
+ * Adds a instance of the add-on by it's short name.
5142
+ *
5143
+ * @method add
5144
+ * @param {String} id Short name/id for the add-on.
5145
+ * @param {tinymce.Theme/tinymce.Plugin} addOn Theme or plugin to add.
5146
+ * @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
5147
+ * @example
5148
+ * // Create a simple plugin
5149
+ * tinymce.create('tinymce.plugins.TestPlugin', {
5150
+ * TestPlugin: function(ed, url) {
5151
+ * ed.on('click', function(e) {
5152
+ * ed.windowManager.alert('Hello World!');
5153
+ * });
5154
+ * }
5155
+ * });
5156
+ *
5157
+ * // Register plugin using the add method
5158
+ * tinymce.PluginManager.add('test', tinymce.plugins.TestPlugin);
5159
+ *
5160
+ * // Initialize TinyMCE
5161
+ * tinymce.init({
5162
+ * ...
5163
+ * plugins: '-test' // Init the plugin but don't try to load it
5164
+ * });
5165
+ */
5166
+ add: function(id, addOn, dependencies) {
5167
+ this.items.push(addOn);
5168
+ this.lookup[id] = {instance: addOn, dependencies: dependencies};
5169
+
5170
+ return addOn;
5171
+ },
5172
+
5173
+ createUrl: function(baseUrl, dep) {
5174
+ if (typeof dep === "object") {
5175
+ return dep;
5176
+ } else {
5177
+ return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
5178
+ }
5179
+ },
5180
+
5181
+ /**
5182
+ * Add a set of components that will make up the add-on. Using the url of the add-on name as the base url.
5183
+ * This should be used in development mode. A new compressor/javascript munger process will ensure that the
5184
+ * components are put together into the plugin.js file and compressed correctly.
5185
+ *
5186
+ * @method addComponents
5187
+ * @param {String} pluginName name of the plugin to load scripts from (will be used to get the base url for the plugins).
5188
+ * @param {Array} scripts Array containing the names of the scripts to load.
5189
+ */
5190
+ addComponents: function(pluginName, scripts) {
5191
+ var pluginUrl = this.urls[pluginName];
5192
+
5193
+ each(scripts, function(script) {
5194
+ ScriptLoader.ScriptLoader.add(pluginUrl + "/" + script);
5195
+ });
5196
+ },
5197
+
5198
+ /**
5199
+ * Loads an add-on from a specific url.
5200
+ *
5201
+ * @method load
5202
+ * @param {String} n Short name of the add-on that gets loaded.
5203
+ * @param {String} u URL to the add-on that will get loaded.
5204
+ * @param {function} cb Optional callback to execute ones the add-on is loaded.
5205
+ * @param {Object} s Optional scope to execute the callback in.
5206
+ * @example
5207
+ * // Loads a plugin from an external URL
5208
+ * tinymce.PluginManager.load('myplugin', '/some/dir/someplugin/plugin.js');
5209
+ *
5210
+ * // Initialize TinyMCE
5211
+ * tinymce.init({
5212
+ * ...
5213
+ * plugins: '-myplugin' // Don't try to load it again
5214
+ * });
5215
+ */
5216
+ load: function(n, u, cb, s) {
5217
+ var t = this, url = u;
5218
+
5219
+ function loadDependencies() {
5220
+ var dependencies = t.dependencies(n);
5221
+
5222
+ each(dependencies, function(dep) {
5223
+ var newUrl = t.createUrl(u, dep);
5224
+
5225
+ t.load(newUrl.resource, newUrl, undefined, undefined);
5226
+ });
5227
+
5228
+ if (cb) {
5229
+ if (s) {
5230
+ cb.call(s);
5231
+ } else {
5232
+ cb.call(ScriptLoader);
5233
+ }
5234
+ }
5235
+ }
5236
+
5237
+ if (t.urls[n]) {
5238
+ return;
5239
+ }
5240
+
5241
+ if (typeof u === "object") {
5242
+ url = u.prefix + u.resource + u.suffix;
5243
+ }
5244
+
5245
+ if (url.indexOf('/') !== 0 && url.indexOf('://') == -1) {
5246
+ url = AddOnManager.baseURL + '/' + url;
5247
+ }
5248
+
5249
+ t.urls[n] = url.substring(0, url.lastIndexOf('/'));
5250
+
5251
+ if (t.lookup[n]) {
5252
+ loadDependencies();
5253
+ } else {
5254
+ ScriptLoader.ScriptLoader.add(url, loadDependencies, s);
5255
+ }
5256
+ }
5257
+ };
5258
+
5259
+ AddOnManager.PluginManager = new AddOnManager();
5260
+ AddOnManager.ThemeManager = new AddOnManager();
5261
+
5262
+ return AddOnManager;
5268
5263
  });
5269
5264
 
5270
5265
  /**
@@ -6402,7 +6397,13 @@ define("tinymce/html/Schema", [
6402
6397
 
6403
6398
  // Add elements clone if needed
6404
6399
  if (!elements[name]) {
6405
- elements[name] = elements[cloneName];
6400
+ var customRule = elements[cloneName];
6401
+
6402
+ customRule = extend({}, customRule);
6403
+ delete customRule.removeEmptyAttrs;
6404
+ delete customRule.removeEmpty;
6405
+
6406
+ elements[name] = customRule;
6406
6407
  }
6407
6408
 
6408
6409
  // Add custom elements at span/div positions
@@ -8289,7 +8290,7 @@ define("tinymce/dom/Serializer", [
8289
8290
  var DOM = DOMUtils.DOM;
8290
8291
 
8291
8292
  /**
8292
- * Constucts a new DOM serializer class.
8293
+ * Constructs a new DOM serializer class.
8293
8294
  *
8294
8295
  * @constructor
8295
8296
  * @method Serializer
@@ -8402,8 +8403,9 @@ define("tinymce/dom/Serializer", [
8402
8403
  value = node.firstChild ? node.firstChild.value : '';
8403
8404
 
8404
8405
  if (name === "script") {
8405
- // Remove mce- prefix from script elements
8406
- node.attr('type', (node.attr('type') || 'text/javascript').replace(/^mce\-/, ''));
8406
+ // Remove mce- prefix from script elements and remove default text/javascript mime type (HTML5)
8407
+ var type = (node.attr('type') || 'text/javascript').replace(/^mce\-/, '');
8408
+ node.attr('type', type === 'text/javascript' ? null : type);
8407
8409
 
8408
8410
  if (value.length > 0) {
8409
8411
  node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
@@ -9216,10 +9218,9 @@ define("tinymce/dom/ControlSelection", [
9216
9218
  ], function(VK, Tools, Env) {
9217
9219
  return function(selection, editor) {
9218
9220
  var dom = editor.dom, each = Tools.each;
9219
- var selectedElm, selectedElmGhost, resizeHandles, selectedHandle;
9221
+ var selectedElm, selectedElmGhost, resizeHandles, selectedHandle, lastMouseDownEvent;
9220
9222
  var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
9221
- var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie;
9222
- var lastMouseDownEvent;
9223
+ var width, height, editableDoc = editor.getDoc(), rootDocument = document, isIE = Env.ie && Env.ie < 11;
9223
9224
 
9224
9225
  // Details about each resize handle how to scale etc
9225
9226
  resizeHandles = {
@@ -9360,8 +9361,11 @@ define("tinymce/dom/ControlSelection", [
9360
9361
  function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
9361
9362
  var position, targetWidth, targetHeight, e, rect;
9362
9363
 
9364
+ // Fix when inline element is within a relaive container
9365
+ var offsetParent = editor.getBody().offsetParent || editor.getBody();
9366
+
9363
9367
  // Get position and size of target
9364
- position = dom.getPos(targetElm, editor.getBody());
9368
+ position = dom.getPos(targetElm, offsetParent);
9365
9369
  selectedElmX = position.x;
9366
9370
  selectedElmY = position.y;
9367
9371
  rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption
@@ -9623,6 +9627,16 @@ define("tinymce/dom/ControlSelection", [
9623
9627
  });
9624
9628
  } else {
9625
9629
  disableGeckoResize();
9630
+
9631
+ if (Env.ie >= 11) {
9632
+ // TODO: Drag/drop doesn't work
9633
+ editor.on('mouseup mousedown', function(e) {
9634
+ if (e.target.nodeName == 'IMG' || editor.selection.getNode().nodeName == 'IMG') {
9635
+ e.preventDefault();
9636
+ editor.selection.select(e.target);
9637
+ }
9638
+ });
9639
+ }
9626
9640
  }
9627
9641
 
9628
9642
  editor.on('nodechange mousedown ResizeEditor', updateResizeRect);
@@ -10333,10 +10347,15 @@ define("tinymce/dom/Selection", [
10333
10347
  * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
10334
10348
  */
10335
10349
  select: function(node, content) {
10336
- var t = this, dom = t.dom, rng = dom.createRng(), idx;
10350
+ var self = this, dom = self.dom, rng = dom.createRng(), idx, nonEmptyElementsMap;
10351
+
10352
+ // Clear stored range set by FocusManager
10353
+ self.lastFocusBookmark = null;
10354
+
10355
+ nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10337
10356
 
10338
10357
  function setPoint(node, start) {
10339
- var walker = new TreeWalker(node, node);
10358
+ var root = node, walker = new TreeWalker(node, root);
10340
10359
 
10341
10360
  do {
10342
10361
  // Text node
@@ -10350,21 +10369,34 @@ define("tinymce/dom/Selection", [
10350
10369
  return;
10351
10370
  }
10352
10371
 
10353
- // BR element
10354
- if (node.nodeName == 'BR') {
10372
+ // BR/IMG/INPUT elements
10373
+ if (nonEmptyElementsMap[node.nodeName]) {
10355
10374
  if (start) {
10356
10375
  rng.setStartBefore(node);
10357
10376
  } else {
10358
- rng.setEndBefore(node);
10377
+ if (node.nodeName == 'BR') {
10378
+ rng.setEndBefore(node);
10379
+ } else {
10380
+ rng.setEndAfter(node);
10381
+ }
10359
10382
  }
10360
10383
 
10361
10384
  return;
10362
10385
  }
10363
10386
  } while ((node = (start ? walker.next() : walker.prev())));
10387
+
10388
+ // Failed to find any text node or other suitable location then move to the root of body
10389
+ if (root.nodeName == 'BODY') {
10390
+ if (start) {
10391
+ rng.setStart(root, 0);
10392
+ } else {
10393
+ rng.setEnd(root, root.childNodes.length);
10394
+ }
10395
+ }
10364
10396
  }
10365
10397
 
10366
10398
  if (node) {
10367
- if (!content && t.controlSelection.controlSelect(node)) {
10399
+ if (!content && self.controlSelection.controlSelect(node)) {
10368
10400
  return;
10369
10401
  }
10370
10402
 
@@ -10378,7 +10410,7 @@ define("tinymce/dom/Selection", [
10378
10410
  setPoint(node);
10379
10411
  }
10380
10412
 
10381
- t.setRng(rng);
10413
+ self.setRng(rng);
10382
10414
  }
10383
10415
 
10384
10416
  return node;
@@ -10451,8 +10483,19 @@ define("tinymce/dom/Selection", [
10451
10483
 
10452
10484
  // Use last rng passed from FocusManager if it's available this enables
10453
10485
  // calls to editor.selection.getStart() to work when caret focus is lost on IE
10454
- if (!w3c && self.restoreRng) {
10455
- return self.restoreRng;
10486
+ if (!w3c && self.lastFocusBookmark) {
10487
+ var bookmark = self.lastFocusBookmark;
10488
+
10489
+ // Convert bookmark to range IE 11 fix
10490
+ if (bookmark.startContainer) {
10491
+ rng = doc.createRange();
10492
+ rng.setStart(bookmark.startContainer, bookmark.startOffset);
10493
+ rng.setEnd(bookmark.endContainer, bookmark.endOffset);
10494
+ } else {
10495
+ rng = bookmark;
10496
+ }
10497
+
10498
+ return rng;
10456
10499
  }
10457
10500
 
10458
10501
  // Found tridentSel object then we need to use that one
@@ -10546,12 +10589,11 @@ define("tinymce/dom/Selection", [
10546
10589
 
10547
10590
  try {
10548
10591
  sel.removeAllRanges();
10592
+ sel.addRange(rng);
10549
10593
  } catch (ex) {
10550
- // IE9 might throw errors here don't know why
10594
+ // IE might throw errors here if the editor is within a hidden container and selection is changed
10551
10595
  }
10552
10596
 
10553
- sel.addRange(rng);
10554
-
10555
10597
  // Forward is set to false and we have an extend function
10556
10598
  if (forward === false && sel.extend) {
10557
10599
  sel.collapse(rng.endContainer, rng.endOffset);
@@ -10955,13 +10997,57 @@ define("tinymce/dom/Selection", [
10955
10997
  return self;
10956
10998
  },
10957
10999
 
11000
+ getScrollContainer: function() {
11001
+ var scrollContainer, node = this.dom.getRoot();
11002
+
11003
+ while (node && node.nodeName != 'BODY') {
11004
+ if (node.scrollHeight > node.clientHeight) {
11005
+ scrollContainer = node;
11006
+ break;
11007
+ }
11008
+
11009
+ node = node.parentNode;
11010
+ }
11011
+
11012
+ return scrollContainer;
11013
+ },
11014
+
10958
11015
  scrollIntoView: function(elm) {
10959
- var y, viewPort, self = this, dom = self.dom;
11016
+ var y, viewPort, self = this, dom = self.dom, root = dom.getRoot(), viewPortY, viewPortH;
11017
+
11018
+ function getPos(elm) {
11019
+ var x = 0, y = 0;
11020
+
11021
+ var offsetParent = elm;
11022
+ while (offsetParent && offsetParent.nodeType) {
11023
+ x += offsetParent.offsetLeft || 0;
11024
+ y += offsetParent.offsetTop || 0;
11025
+ offsetParent = offsetParent.offsetParent;
11026
+ }
11027
+
11028
+ return {x: x, y: y};
11029
+ }
11030
+
11031
+ if (root.nodeName != 'BODY') {
11032
+ var scrollContainer = self.getScrollContainer();
11033
+ if (scrollContainer) {
11034
+ y = getPos(elm).y - getPos(scrollContainer).y;
11035
+ viewPortH = scrollContainer.clientHeight;
11036
+ viewPortY = scrollContainer.scrollTop;
11037
+ if (y < viewPortY || y + 25 > viewPortY + viewPortH) {
11038
+ scrollContainer.scrollTop = y < viewPortY ? y : y - viewPortH + 25;
11039
+ }
11040
+
11041
+ return;
11042
+ }
11043
+ }
10960
11044
 
10961
11045
  viewPort = dom.getViewPort(self.editor.getWin());
10962
11046
  y = dom.getPos(elm).y;
10963
- if (y < viewPort.y || y + 25 > viewPort.y + viewPort.h) {
10964
- self.editor.getWin().scrollTo(0, y < viewPort.y ? y : y - viewPort.h + 25);
11047
+ viewPortY = viewPort.y;
11048
+ viewPortH = viewPort.h;
11049
+ if (y < viewPort.y || y + 25 > viewPortY + viewPortH) {
11050
+ self.editor.getWin().scrollTo(0, y < viewPortY ? y : y - viewPortH + 25);
10965
11051
  }
10966
11052
  },
10967
11053
 
@@ -11268,7 +11354,7 @@ define("tinymce/dom/RangeUtils", [
11268
11354
  /**
11269
11355
  * Text formatter engine class. This class is used to apply formats like bold, italic, font size
11270
11356
  * etc to the current selection or specific nodes. This engine was build to replace the browsers
11271
- * default formatting logic for execCommand due to it's inconsistant and buggy behavior.
11357
+ * default formatting logic for execCommand due to it's inconsistent and buggy behavior.
11272
11358
  *
11273
11359
  * @class tinymce.Formatter
11274
11360
  * @example
@@ -11397,7 +11483,14 @@ define("tinymce/Formatter", [
11397
11483
  },
11398
11484
 
11399
11485
  removeformat: [
11400
- {selector: 'b,strong,em,i,font,u,strike', remove: 'all', split: true, expand: false, block_expand: true, deep: true},
11486
+ {
11487
+ selector: 'b,strong,em,i,font,u,strike,sub,sup',
11488
+ remove: 'all',
11489
+ split: true,
11490
+ expand: false,
11491
+ block_expand: true,
11492
+ deep: true
11493
+ },
11401
11494
  {selector: 'span', attributes: ['style', 'class'], remove: 'empty', split: true, expand: false, deep: true},
11402
11495
  {selector: '*', attributes: ['style', 'class'], split: false, expand: false, deep: true}
11403
11496
  ]
@@ -12264,9 +12357,11 @@ define("tinymce/Formatter", [
12264
12357
  var startNode;
12265
12358
 
12266
12359
  function matchParents(node) {
12360
+ var root = dom.getRoot();
12361
+
12267
12362
  // Find first node with similar format settings
12268
12363
  node = dom.getParent(node, function(node) {
12269
- return !!matchNode(node, name, vars, true);
12364
+ return node.parentNode === root || !!matchNode(node, name, vars, true);
12270
12365
  });
12271
12366
 
12272
12367
  // Do an exact check on the similar format element
@@ -12342,8 +12437,9 @@ define("tinymce/Formatter", [
12342
12437
  for (x = formatList.length - 1; x >= 0; x--) {
12343
12438
  selector = formatList[x].selector;
12344
12439
 
12345
- // Format is not selector based, then always return TRUE
12346
- if (!selector) {
12440
+ // Format is not selector based then always return TRUE
12441
+ // Is it has a defaultBlock then it's likely it can be applied for example align on a non block element line
12442
+ if (!selector || formatList[x].defaultBlock) {
12347
12443
  return TRUE;
12348
12444
  }
12349
12445
 
@@ -12773,7 +12869,7 @@ define("tinymce/Formatter", [
12773
12869
  }
12774
12870
 
12775
12871
  function findBlockEndPoint(container, sibling_name) {
12776
- var node;
12872
+ var node, root = dom.getRoot();
12777
12873
 
12778
12874
  // Expand to block of similar type
12779
12875
  if (!format[0].wrapper) {
@@ -12782,7 +12878,10 @@ define("tinymce/Formatter", [
12782
12878
 
12783
12879
  // Expand to first wrappable block element or any block element
12784
12880
  if (!node) {
12785
- node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isTextBlock);
12881
+ node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, function(node) {
12882
+ // Fixes #6183 where it would expand to editable parent element in inline mode
12883
+ return node != root && isTextBlock(node);
12884
+ });
12786
12885
  }
12787
12886
 
12788
12887
  // Exclude inner lists from wrapping
@@ -12833,14 +12932,14 @@ define("tinymce/Formatter", [
12833
12932
 
12834
12933
  if (format[0].inline) {
12835
12934
  if (rng.collapsed) {
12836
- // Expand left to closest word boundery
12935
+ // Expand left to closest word boundary
12837
12936
  endPoint = findWordEndPoint(startContainer, startOffset, true);
12838
12937
  if (endPoint) {
12839
12938
  startContainer = endPoint.container;
12840
12939
  startOffset = endPoint.offset;
12841
12940
  }
12842
12941
 
12843
- // Expand right to closest word boundery
12942
+ // Expand right to closest word boundary
12844
12943
  endPoint = findWordEndPoint(endContainer, endOffset);
12845
12944
  if (endPoint) {
12846
12945
  endContainer = endPoint.container;
@@ -13536,6 +13635,10 @@ define("tinymce/Formatter", [
13536
13635
 
13537
13636
  // Move selection to text node
13538
13637
  selection.setCursorLocation(node, 1);
13638
+ // If the formatNode is empty, we can remove it safely.
13639
+ if(dom.isEmpty(formatNode)) {
13640
+ dom.remove(formatNode);
13641
+ }
13539
13642
  }
13540
13643
  }
13541
13644
 
@@ -13676,7 +13779,7 @@ define("tinymce/UndoManager", [
13676
13779
  ].join('|'), 'gi');
13677
13780
 
13678
13781
  return function(editor) {
13679
- var self, index = 0, data = [], beforeBookmark, isFirstTypedCharacter;
13782
+ var self, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, lock;
13680
13783
 
13681
13784
  // Returns a trimmed version of the current editor contents
13682
13785
  function getContent() {
@@ -13740,6 +13843,11 @@ define("tinymce/UndoManager", [
13740
13843
  // Make the it dirty if the content was changed after typing the first character
13741
13844
  if (!editor.isDirty()) {
13742
13845
  editor.isNotDirty = !data[0] || getContent() == data[0].content;
13846
+
13847
+ // Fire initial change event
13848
+ if (!editor.isNotDirty) {
13849
+ editor.fire('change', {level: data[0], lastLevel: null});
13850
+ }
13743
13851
  }
13744
13852
 
13745
13853
  editor.fire('TypingUndo');
@@ -13804,7 +13912,9 @@ define("tinymce/UndoManager", [
13804
13912
  * @method beforeChange
13805
13913
  */
13806
13914
  beforeChange: function() {
13807
- beforeBookmark = editor.selection.getBookmark(2, true);
13915
+ if (!lock) {
13916
+ beforeBookmark = editor.selection.getBookmark(2, true);
13917
+ }
13808
13918
  },
13809
13919
 
13810
13920
  /**
@@ -13820,7 +13930,7 @@ define("tinymce/UndoManager", [
13820
13930
  level = level || {};
13821
13931
  level.content = getContent();
13822
13932
 
13823
- if (editor.fire('BeforeAddUndo', {level: level}).isDefaultPrevented()) {
13933
+ if (lock || editor.fire('BeforeAddUndo', {level: level}).isDefaultPrevented()) {
13824
13934
  return null;
13825
13935
  }
13826
13936
 
@@ -13887,6 +13997,11 @@ define("tinymce/UndoManager", [
13887
13997
  if (index > 0) {
13888
13998
  level = data[--index];
13889
13999
 
14000
+ // Undo to first index then set dirty state to false
14001
+ if (index === 0) {
14002
+ editor.isNotDirty = true;
14003
+ }
14004
+
13890
14005
  editor.setContent(level.content, {format: 'raw'});
13891
14006
  editor.selection.moveToBookmark(level.beforeBookmark);
13892
14007
 
@@ -13953,14 +14068,19 @@ define("tinymce/UndoManager", [
13953
14068
  /**
13954
14069
  * Executes the specified function in an undo transation. The selection
13955
14070
  * before the modification will be stored to the undo stack and if the DOM changes
13956
- * it will add a new undo level.
14071
+ * it will add a new undo level. Any methods within the transation that adds undo levels will
14072
+ * be ignored. So a transation can include calls to execCommand or editor.insertContent.
13957
14073
  *
13958
14074
  * @method transact
13959
14075
  * @param {function} callback Function to execute dom manipulation logic in.
13960
14076
  */
13961
14077
  transact: function(callback) {
13962
14078
  self.beforeChange();
14079
+
14080
+ lock = true;
13963
14081
  callback();
14082
+ lock = false;
14083
+
13964
14084
  self.add();
13965
14085
  }
13966
14086
  };
@@ -13988,7 +14108,7 @@ define("tinymce/EnterKey", [
13988
14108
  "tinymce/dom/TreeWalker",
13989
14109
  "tinymce/Env"
13990
14110
  ], function(TreeWalker, Env) {
13991
- var isIE = Env.ie;
14111
+ var isIE = Env.ie && Env.ie < 11;
13992
14112
 
13993
14113
  return function(editor) {
13994
14114
  var dom = editor.dom, selection = editor.selection, settings = editor.settings;
@@ -14556,6 +14676,7 @@ define("tinymce/EnterKey", [
14556
14676
  // Insert new block before
14557
14677
  newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
14558
14678
  renderBlockOnIE(newBlock);
14679
+ moveToCaretPosition(parentBlock);
14559
14680
  } else {
14560
14681
  // Extract after fragment and insert it after the current block
14561
14682
  tmpRng = rng.cloneRange();
@@ -14713,7 +14834,7 @@ define("tinymce/ForceBlocks", [], function() {
14713
14834
 
14714
14835
  // Force root blocks
14715
14836
  if (settings.forced_root_block) {
14716
- editor.on('KeyUp NodeChange', addRootBlocks);
14837
+ editor.on('NodeChange', addRootBlocks);
14717
14838
  }
14718
14839
  };
14719
14840
  });
@@ -15086,8 +15207,8 @@ define("tinymce/EditorCommands", [
15086
15207
  parentNode = selection.getNode();
15087
15208
 
15088
15209
  // Parse the fragment within the context of the parent node
15089
- args = {context: parentNode.nodeName.toLowerCase()};
15090
- fragment = parser.parse(value, args);
15210
+ var parserArgs = {context: parentNode.nodeName.toLowerCase()};
15211
+ fragment = parser.parse(value, parserArgs);
15091
15212
 
15092
15213
  // Move the caret to a more suitable location
15093
15214
  node = fragment.lastChild;
@@ -15103,7 +15224,7 @@ define("tinymce/EditorCommands", [
15103
15224
  }
15104
15225
 
15105
15226
  // If parser says valid we can insert the contents into that parent
15106
- if (!args.invalid) {
15227
+ if (!parserArgs.invalid) {
15107
15228
  value = serializer.serialize(fragment);
15108
15229
 
15109
15230
  // Check if parent is empty or only has one BR element then set the innerHTML of that parent
@@ -15426,7 +15547,7 @@ define("tinymce/util/URI", [
15426
15547
  var each = Tools.each, trim = Tools.trim;
15427
15548
 
15428
15549
  /**
15429
- * Constucts a new URI instance.
15550
+ * Constructs a new URI instance.
15430
15551
  *
15431
15552
  * @constructor
15432
15553
  * @method URI
@@ -15956,7 +16077,7 @@ define("tinymce/util/Class", [
15956
16077
  * element[attr^=value]
15957
16078
  * element[attr$=value]
15958
16079
  * element:<state>
15959
- * element:not(<expession>)
16080
+ * element:not(<expression>)
15960
16081
  * element:first
15961
16082
  * element:last
15962
16083
  * element:odd
@@ -16249,11 +16370,11 @@ define("tinymce/ui/Selector", [
16249
16370
 
16250
16371
  // All filters matched the item
16251
16372
  if (fi === fl) {
16252
- // Matched item is on the last expession like: panel toolbar [button]
16373
+ // Matched item is on the last expression like: panel toolbar [button]
16253
16374
  if (index == selector.length - 1) {
16254
16375
  matches.push(item);
16255
16376
  } else {
16256
- // Collect next expession type
16377
+ // Collect next expression type
16257
16378
  if (item.items) {
16258
16379
  collect(item.items(), selector, index + 1);
16259
16380
  }
@@ -16557,6 +16678,22 @@ define("tinymce/ui/Collection", [
16557
16678
  });
16558
16679
 
16559
16680
  return self;
16681
+ },
16682
+
16683
+ /**
16684
+ * Remove all items from collection and DOM.
16685
+ *
16686
+ * @method remove
16687
+ * @return {tinymce.ui.Collection} Current collection.
16688
+ */
16689
+ remove: function() {
16690
+ var i = this.length;
16691
+
16692
+ while (i--) {
16693
+ this[i].remove();
16694
+ }
16695
+
16696
+ return this;
16560
16697
  }
16561
16698
 
16562
16699
  /**
@@ -16787,6 +16924,11 @@ define("tinymce/ui/DomUtils", [
16787
16924
 
16788
16925
  fire: function(target, name, args) {
16789
16926
  return DOMUtils.DOM.fire(target, name, args);
16927
+ },
16928
+
16929
+ innerHtml: function(elm, html) {
16930
+ // Workaround for <div> in <p> bug on IE 8 #6178
16931
+ DOMUtils.DOM.setHTML(elm, html);
16790
16932
  }
16791
16933
  };
16792
16934
  });
@@ -17681,6 +17823,18 @@ define("tinymce/ui/Control", [
17681
17823
  return classes ? classes.join(' ') : '';
17682
17824
  },
17683
17825
 
17826
+ /**
17827
+ * Sets the inner HTML of the control element.
17828
+ *
17829
+ * @method innerHtml
17830
+ * @param {String} html Html string to set as inner html.
17831
+ * @return {tinymce.ui.Control} Current control object.
17832
+ */
17833
+ innerHtml: function(html) {
17834
+ DomUtils.innerHtml(this.getEl(), html);
17835
+ return this;
17836
+ },
17837
+
17684
17838
  /**
17685
17839
  * Returns the control DOM element or sub element.
17686
17840
  *
@@ -17866,11 +18020,11 @@ define("tinymce/ui/Control", [
17866
18020
  * @return {tinymce.ui.Control} Current control instance.
17867
18021
  */
17868
18022
  remove: function() {
17869
- var self = this, elm = self.getEl(), parent = self.parent(), newItems;
18023
+ var self = this, elm = self.getEl(), parent = self.parent(), newItems, i;
17870
18024
 
17871
18025
  if (self.items) {
17872
18026
  var controls = self.items().toArray();
17873
- var i = controls.length;
18027
+ i = controls.length;
17874
18028
  while (i--) {
17875
18029
  controls[i].remove();
17876
18030
  }
@@ -17894,8 +18048,16 @@ define("tinymce/ui/Control", [
17894
18048
  }
17895
18049
 
17896
18050
  delete Control.controlIdLookup[self._id];
18051
+ delete elementIdCache[self._id];
18052
+
18053
+ if (elm && elm.parentNode) {
18054
+ var nodes = elm.getElementsByTagName('*');
18055
+
18056
+ i = nodes.length;
18057
+ while (i--) {
18058
+ delete elementIdCache[nodes[i].id];
18059
+ }
17897
18060
 
17898
- if (elm.parentNode) {
17899
18061
  elm.parentNode.removeChild(elm);
17900
18062
  }
17901
18063
 
@@ -18273,7 +18435,7 @@ define("tinymce/ui/Control", [
18273
18435
  */
18274
18436
  // title: function(value) {} -- Generated
18275
18437
  });
18276
-
18438
+ window.elementIdCache = elementIdCache;
18277
18439
  return Control;
18278
18440
  });
18279
18441
 
@@ -19865,7 +20027,7 @@ define("tinymce/ui/KeyboardNavigation", [
19865
20027
  * @setting {tinymce.ui.Control} root the root control navigation focus movement is scoped to this root.
19866
20028
  * @setting {Array} items an array containing the items to move focus between. Every object in this array must have an
19867
20029
  * id attribute which maps to the actual DOM element and it must be able to have focus i.e. tabIndex=-1.
19868
- * @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates cancelling.
20030
+ * @setting {Function} onCancel the callback for when the user presses escape or otherwise indicates canceling.
19869
20031
  * @setting {Function} onAction (optional) the action handler to call when the user activates an item.
19870
20032
  * @setting {Boolean} enableLeftRight (optional, default) when true, the up/down arrows move through items.
19871
20033
  * @setting {Boolean} enableUpDown (optional) when true, the up/down arrows move through items.
@@ -20564,8 +20726,8 @@ define("tinymce/ui/Window", [
20564
20726
  remove: function() {
20565
20727
  var self = this;
20566
20728
 
20567
- self._super();
20568
20729
  self.dragHelper.destroy();
20730
+ self._super();
20569
20731
 
20570
20732
  if (self.statusbar) {
20571
20733
  this.statusbar.remove();
@@ -20821,6 +20983,12 @@ define("tinymce/WindowManager", [
20821
20983
  return function(editor) {
20822
20984
  var self = this, windows = [];
20823
20985
 
20986
+ function getTopMostWindow() {
20987
+ if (windows.length) {
20988
+ return windows[windows.length - 1];
20989
+ }
20990
+ }
20991
+
20824
20992
  self.windows = windows;
20825
20993
 
20826
20994
  /**
@@ -20840,6 +21008,10 @@ define("tinymce/WindowManager", [
20840
21008
  self.open = function(args, params) {
20841
21009
  var win;
20842
21010
 
21011
+ editor.editorManager.activeEditor = editor;
21012
+
21013
+ args.title = args.title || ' ';
21014
+
20843
21015
  // Handle URL
20844
21016
  args.url = args.url || args.file; // Legacy
20845
21017
  if (args.url) {
@@ -20897,7 +21069,8 @@ define("tinymce/WindowManager", [
20897
21069
  });
20898
21070
  }
20899
21071
 
20900
- // store parameters
21072
+ // store args and parameters
21073
+ win.features = args || {};
20901
21074
  win.params = params || {};
20902
21075
 
20903
21076
  // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
@@ -20953,8 +21126,8 @@ define("tinymce/WindowManager", [
20953
21126
  * @method close
20954
21127
  */
20955
21128
  self.close = function() {
20956
- if (windows.length) {
20957
- windows[windows.length - 1].close();
21129
+ if (getTopMostWindow()) {
21130
+ getTopMostWindow().close();
20958
21131
  }
20959
21132
  };
20960
21133
 
@@ -20969,12 +21142,8 @@ define("tinymce/WindowManager", [
20969
21142
  * @return {Object} Name/value object with parameters passed from windowManager.open call.
20970
21143
  */
20971
21144
  self.getParams = function() {
20972
- if (windows.length) {
20973
- return windows[windows.length - 1].params;
20974
- }
20975
-
20976
- return null;
20977
- };
21145
+ return getTopMostWindow() ? getTopMostWindow().params : null;
21146
+ };
20978
21147
 
20979
21148
  /**
20980
21149
  * Sets the params of the last opened window.
@@ -20983,8 +21152,8 @@ define("tinymce/WindowManager", [
20983
21152
  * @param {Object} params Params object to set for the last opened window.
20984
21153
  */
20985
21154
  self.setParams = function(params) {
20986
- if (windows.length) {
20987
- windows[windows.length - 1].params = params;
21155
+ if (getTopMostWindow()) {
21156
+ getTopMostWindow().params = params;
20988
21157
  }
20989
21158
  };
20990
21159
  };
@@ -21257,7 +21426,9 @@ define("tinymce/util/Quirks", [
21257
21426
  * browser just deletes the paragraph - the browser fails to merge the text node with a horizontal rule so it is
21258
21427
  * left there. TinyMCE sees a floating text node and wraps it in a paragraph on the key up event (ForceBlocks.js
21259
21428
  * addRootBlocks), meaning the action does nothing. With this code, FireFox/IE matche the behaviour of other
21260
- * browsers
21429
+ * browsers.
21430
+ *
21431
+ * It also fixes a bug on Firefox where it's impossible to delete HR elements.
21261
21432
  */
21262
21433
  function removeHrOnBackspace() {
21263
21434
  editor.on('keydown', function(e) {
@@ -21266,6 +21437,12 @@ define("tinymce/util/Quirks", [
21266
21437
  var node = selection.getNode();
21267
21438
  var previousSibling = node.previousSibling;
21268
21439
 
21440
+ if (node.nodeName == 'HR') {
21441
+ dom.remove(node);
21442
+ e.preventDefault();
21443
+ return;
21444
+ }
21445
+
21269
21446
  if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") {
21270
21447
  dom.remove(previousSibling);
21271
21448
  e.preventDefault();
@@ -21334,7 +21511,7 @@ define("tinymce/util/Quirks", [
21334
21511
  * Instead of:
21335
21512
  * <p style="color:red">bla|ed</p>
21336
21513
  */
21337
- function removeStylesWhenDeletingAccrossBlockElements() {
21514
+ function removeStylesWhenDeletingAcrossBlockElements() {
21338
21515
  function getAttributeApplyFunction() {
21339
21516
  var template = dom.getAttribs(selection.getStart().cloneNode(false));
21340
21517
 
@@ -21894,6 +22071,44 @@ define("tinymce/util/Quirks", [
21894
22071
  );
21895
22072
  }
21896
22073
 
22074
+ /**
22075
+ * iOS has a bug where it's impossible to type if the document has a touchstart event
22076
+ * bound and the user touches the document while having the on screen keyboard visible.
22077
+ *
22078
+ * The touch event moves the focus to the parent document while having the caret inside the iframe
22079
+ * this fix moves the focus back into the iframe document.
22080
+ */
22081
+ function restoreFocusOnKeyDown() {
22082
+ if (!editor.inline) {
22083
+ editor.on('keydown', function() {
22084
+ if (document.activeElement == document.body) {
22085
+ editor.getWin().focus();
22086
+ }
22087
+ });
22088
+ }
22089
+ }
22090
+
22091
+ /**
22092
+ * IE 11 has an annoying issue where you can't move focus into the editor
22093
+ * by clicking on the white area HTML element. We used to be able to to fix this with
22094
+ * the fixCaretSelectionOfDocumentElementOnIe fix. But since M$ removed the selection
22095
+ * object it's not possible anymore. So we need to hack in a ungly CSS to force the
22096
+ * body to be at least 150px. If the user clicks the HTML element out side this 150px region
22097
+ * we simply move the focus into the first paragraph. Not ideal since you loose the
22098
+ * positioning of the caret but goot enough for most cases.
22099
+ */
22100
+ function bodyHeight() {
22101
+ if (!editor.inline) {
22102
+ editor.contentStyles.push('body {min-height: 150px}');
22103
+ editor.on('click', function(e) {
22104
+ if (e.target.nodeName == 'HTML') {
22105
+ editor.execCommand('SelectAll');
22106
+ editor.selection.collapse(true);
22107
+ }
22108
+ });
22109
+ }
22110
+ }
22111
+
21897
22112
  // All browsers
21898
22113
  disableBackspaceIntoATable();
21899
22114
  removeBlockQuoteOnBackSpace();
@@ -21911,13 +22126,14 @@ define("tinymce/util/Quirks", [
21911
22126
  // iOS
21912
22127
  if (Env.iOS) {
21913
22128
  selectionChangeNodeChanged();
22129
+ restoreFocusOnKeyDown();
21914
22130
  } else {
21915
22131
  selectAll();
21916
22132
  }
21917
22133
  }
21918
22134
 
21919
22135
  // IE
21920
- if (isIE) {
22136
+ if (isIE && Env.ie < 11) {
21921
22137
  removeHrOnBackspace();
21922
22138
  ensureBodyHasRoleApplication();
21923
22139
  addNewLinesBeforeBrInPre();
@@ -21928,11 +22144,15 @@ define("tinymce/util/Quirks", [
21928
22144
  fixCaretSelectionOfDocumentElementOnIe();
21929
22145
  }
21930
22146
 
22147
+ if (Env.ie >= 11) {
22148
+ bodyHeight();
22149
+ }
22150
+
21931
22151
  // Gecko
21932
22152
  if (isGecko) {
21933
22153
  removeHrOnBackspace();
21934
22154
  focusBody();
21935
- removeStylesWhenDeletingAccrossBlockElements();
22155
+ removeStylesWhenDeletingAcrossBlockElements();
21936
22156
  setGeckoEditingOptions();
21937
22157
  addBrAfterLastLinks();
21938
22158
  removeGhostSelection();
@@ -22369,7 +22589,7 @@ define("tinymce/Editor", [
22369
22589
  var extend = Tools.extend, each = Tools.each, explode = Tools.explode;
22370
22590
  var inArray = Tools.inArray, trim = Tools.trim, resolve = Tools.resolve;
22371
22591
  var Event = EventUtils.Event;
22372
- var isGecko = Env.gecko, isIE = Env.ie, isOpera = Env.opera;
22592
+ var isGecko = Env.gecko, ie = Env.ie, isOpera = Env.opera;
22373
22593
 
22374
22594
  function getEventTarget(editor, eventName) {
22375
22595
  if (eventName == 'selectionchange' || eventName == 'drop') {
@@ -22456,8 +22676,9 @@ define("tinymce/Editor", [
22456
22676
  ie7_compat: true
22457
22677
  }, settings);
22458
22678
 
22459
- // TODO: Fix this
22460
- AddOnManager.settings = settings;
22679
+ AddOnManager.language = settings.language || 'en';
22680
+ AddOnManager.languageLoad = settings.language_load;
22681
+
22461
22682
  AddOnManager.baseURL = editorManager.baseURL;
22462
22683
 
22463
22684
  /**
@@ -22557,6 +22778,7 @@ define("tinymce/Editor", [
22557
22778
 
22558
22779
  // Call setup
22559
22780
  self.execCallback('setup', self);
22781
+ editorManager.fire('SetupEditor', self);
22560
22782
  }
22561
22783
 
22562
22784
  Editor.prototype = {
@@ -22568,16 +22790,17 @@ define("tinymce/Editor", [
22568
22790
  render: function() {
22569
22791
  var self = this, settings = self.settings, id = self.id, suffix = self.suffix;
22570
22792
 
22793
+ function readyHandler() {
22794
+ DOM.unbind(window, 'ready', readyHandler);
22795
+ self.render();
22796
+ }
22797
+
22571
22798
  // Page is not loaded yet, wait for it
22572
22799
  if (!Event.domLoaded) {
22573
- DOM.bind(window, 'ready', function() {
22574
- self.render();
22575
- });
22800
+ DOM.bind(window, 'ready', readyHandler);
22576
22801
  return;
22577
22802
  }
22578
22803
 
22579
- self.editorManager.settings = settings;
22580
-
22581
22804
  // Element not found, then skip initialization
22582
22805
  if (!self.getElement()) {
22583
22806
  return;
@@ -22662,7 +22885,6 @@ define("tinymce/Editor", [
22662
22885
  self.on('submit', function() {
22663
22886
  if (self.initialized) {
22664
22887
  self.save();
22665
- self.isNotDirty = true;
22666
22888
  }
22667
22889
  });
22668
22890
  }
@@ -22670,7 +22892,7 @@ define("tinymce/Editor", [
22670
22892
  if (settings.add_unload_trigger) {
22671
22893
  self._beforeUnload = function() {
22672
22894
  if (self.initialized && !self.destroyed && !self.isHidden()) {
22673
- self.save({format: 'raw', no_events: true});
22895
+ self.save({format: 'raw', no_events: true, set_dirty: false});
22674
22896
  }
22675
22897
  };
22676
22898
 
@@ -22691,7 +22913,15 @@ define("tinymce/Editor", [
22691
22913
 
22692
22914
  if (settings.theme && typeof settings.theme != "function" &&
22693
22915
  settings.theme.charAt(0) != '-' && !ThemeManager.urls[settings.theme]) {
22694
- ThemeManager.load(settings.theme, 'themes/' + settings.theme + '/theme' + suffix + '.js');
22916
+ var themeUrl = settings.theme_url;
22917
+
22918
+ if (themeUrl) {
22919
+ themeUrl = self.documentBaseURI.toAbsolute(themeUrl);
22920
+ } else {
22921
+ themeUrl = 'themes/' + settings.theme + '/theme' + suffix + '.js';
22922
+ }
22923
+
22924
+ ThemeManager.load(settings.theme, themeUrl);
22695
22925
  }
22696
22926
 
22697
22927
  if (Tools.isArray(settings.plugins)) {
@@ -22929,7 +23159,7 @@ define("tinymce/Editor", [
22929
23159
 
22930
23160
  // Domain relaxing enabled, then set document domain
22931
23161
  // TODO: Fix this old stuff
22932
- if (self.editorManager.relaxedDomain && (isIE || (isOpera && parseFloat(window.opera.version()) < 11))) {
23162
+ if (self.editorManager.relaxedDomain && (ie || (isOpera && parseFloat(window.opera.version()) < 11))) {
22933
23163
  // We need to write the contents here in IE since multiple writes messes up refresh button and back button
22934
23164
  url = 'javascript:(function(){document.open();document.domain="' + document.domain + '";' +
22935
23165
  'var ed = window.parent.tinymce.get("' + self.id + '");document.write(ed.iframeHTML);' +
@@ -22986,7 +23216,7 @@ define("tinymce/Editor", [
22986
23216
  }
22987
23217
 
22988
23218
  // Setup iframe body
22989
- if ((!isIE || !self.editorManager.relaxedDomain) && !settings.content_editable) {
23219
+ if ((!ie || !self.editorManager.relaxedDomain) && !settings.content_editable) {
22990
23220
  doc.open();
22991
23221
  doc.write(self.iframeHTML);
22992
23222
  doc.close();
@@ -23054,6 +23284,7 @@ define("tinymce/Editor", [
23054
23284
  class_filter: settings.class_filter,
23055
23285
  update_styles: true,
23056
23286
  root_element: settings.content_editable ? self.id : null,
23287
+ collect: settings.content_editable,
23057
23288
  schema: self.schema,
23058
23289
  onSetAttrib: function(e) {
23059
23290
  self.fire('SetAttrib', e);
@@ -23388,8 +23619,8 @@ define("tinymce/Editor", [
23388
23619
  return '';
23389
23620
  }
23390
23621
 
23391
- return i18n[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function(a, b) {
23392
- return i18n[lang + '.' + b] || '{#' + b + '}';
23622
+ return i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function(a, b) {
23623
+ return i18n.data[lang + '.' + b] || '{#' + b + '}';
23393
23624
  });
23394
23625
  },
23395
23626
 
@@ -23402,7 +23633,7 @@ define("tinymce/Editor", [
23402
23633
  */
23403
23634
  getLang: function(name, defaultVal) {
23404
23635
  return (
23405
- this.editorManager.i18n[(this.settings.language || 'en') + '.' + name] ||
23636
+ this.editorManager.i18n.data[(this.settings.language || 'en') + '.' + name] ||
23406
23637
  (defaultVal !== undefined ? defaultVal : '{#' + name + '}')
23407
23638
  );
23408
23639
  },
@@ -23462,7 +23693,7 @@ define("tinymce/Editor", [
23462
23693
  // Get start node
23463
23694
  root = self.getBody();
23464
23695
  node = selection.getStart() || root;
23465
- node = isIE && node.ownerDocument != self.getDoc() ? self.getBody() : node; // Fix for IE initial state
23696
+ node = ie && node.ownerDocument != self.getDoc() ? self.getBody() : node; // Fix for IE initial state
23466
23697
 
23467
23698
  // Edge case for <p>|<img></p>
23468
23699
  if (node.nodeName == 'IMG' && selection.isCollapsed()) {
@@ -23813,7 +24044,7 @@ define("tinymce/Editor", [
23813
24044
  var self = this, doc = self.getDoc();
23814
24045
 
23815
24046
  // Fixed bug where IE has a blinking cursor left from the editor
23816
- if (isIE && doc) {
24047
+ if (ie && doc) {
23817
24048
  doc.execCommand('SelectAll');
23818
24049
  }
23819
24050
 
@@ -23932,7 +24163,10 @@ define("tinymce/Editor", [
23932
24163
  }
23933
24164
 
23934
24165
  args.element = elm = null;
23935
- self.isNotDirty = true;
24166
+
24167
+ if (args.set_dirty !== false) {
24168
+ self.isNotDirty = true;
24169
+ }
23936
24170
 
23937
24171
  return html;
23938
24172
  },
@@ -23976,42 +24210,54 @@ define("tinymce/Editor", [
23976
24210
 
23977
24211
  // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
23978
24212
  // It will also be impossible to place the caret in the editor unless there is a BR element present
23979
- if (!isIE && (content.length === 0 || /^\s+$/.test(content))) {
24213
+ if (content.length === 0 || /^\s+$/.test(content)) {
23980
24214
  forcedRootBlockName = self.settings.forced_root_block;
23981
24215
 
23982
24216
  // Check if forcedRootBlock is configured and that the block is a valid child of the body
23983
24217
  if (forcedRootBlockName && self.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
23984
- content = '<' + forcedRootBlockName + '><br data-mce-bogus="1"></' + forcedRootBlockName + '>';
23985
- } else {
24218
+ if (ie && ie < 11) {
24219
+ // IE renders BR elements in blocks so lets just add an empty block
24220
+ content = '<' + forcedRootBlockName + '></' + forcedRootBlockName + '>';
24221
+ } else {
24222
+ content = '<' + forcedRootBlockName + '><br data-mce-bogus="1"></' + forcedRootBlockName + '>';
24223
+ }
24224
+ } else if (!ie) {
24225
+ // We need to add a BR when forced_root_block is disabled on non IE browsers to place the caret
23986
24226
  content = '<br data-mce-bogus="1">';
23987
24227
  }
23988
24228
 
23989
24229
  body.innerHTML = content;
23990
- self.selection.select(body, true);
23991
- self.selection.collapse(true);
24230
+
23992
24231
  self.fire('SetContent', args);
23993
- return;
23994
- }
24232
+ } else {
24233
+ // Parse and serialize the html
24234
+ if (args.format !== 'raw') {
24235
+ content = new Serializer({}, self.schema).serialize(
24236
+ self.parser.parse(content, {isRootContent: true})
24237
+ );
24238
+ }
23995
24239
 
23996
- // Parse and serialize the html
23997
- if (args.format !== 'raw') {
23998
- content = new Serializer({}, self.schema).serialize(
23999
- self.parser.parse(content, {isRootContent: true})
24000
- );
24001
- }
24240
+ // Set the new cleaned contents to the editor
24241
+ args.content = trim(content);
24242
+ self.dom.setHTML(body, args.content);
24002
24243
 
24003
- // Set the new cleaned contents to the editor
24004
- args.content = trim(content);
24005
- self.dom.setHTML(body, args.content);
24244
+ // Do post processing
24245
+ if (!args.no_events) {
24246
+ self.fire('SetContent', args);
24247
+ }
24006
24248
 
24007
- // Do post processing
24008
- if (!args.no_events) {
24009
- self.fire('SetContent', args);
24249
+ // Don't normalize selection if the focused element isn't the body in
24250
+ // content editable mode since it will steal focus otherwise
24251
+ /*if (!self.settings.content_editable || document.activeElement === self.getBody()) {
24252
+ self.selection.normalize();
24253
+ }*/
24010
24254
  }
24011
24255
 
24012
- // Don't normalize selection if the focused element isn't the body in content editable mode since it will steal focus otherwise
24013
- if (!self.settings.content_editable || document.activeElement === self.getBody()) {
24014
- self.selection.normalize();
24256
+ // Move selection to start of body if it's a after init setContent call
24257
+ // This prevents IE 7/8 from moving focus to empty editors
24258
+ if (!args.initial) {
24259
+ self.selection.select(body, true);
24260
+ self.selection.collapse(true);
24015
24261
  }
24016
24262
 
24017
24263
  return args.content;
@@ -24284,7 +24530,7 @@ define("tinymce/Editor", [
24284
24530
  self.removed = 1; // Cancels post remove event execution
24285
24531
 
24286
24532
  // Fixed bug where IE has a blinking cursor left from the editor
24287
- if (isIE && doc) {
24533
+ if (ie && doc) {
24288
24534
  doc.execCommand('SelectAll');
24289
24535
  }
24290
24536
 
@@ -24307,6 +24553,7 @@ define("tinymce/Editor", [
24307
24553
 
24308
24554
  self.editorManager.remove(self);
24309
24555
  DOM.remove(elm);
24556
+ self.destroy();
24310
24557
  }
24311
24558
  },
24312
24559
 
@@ -24352,7 +24599,7 @@ define("tinymce/Editor", [
24352
24599
 
24353
24600
  // We must unbind on Gecko since it would otherwise produce the pesky "attempt
24354
24601
  // to run compile-and-go script on a cleared scope" message
24355
- if (isGecko) {
24602
+ if (automatic && isGecko) {
24356
24603
  Event.unbind(self.getDoc());
24357
24604
  Event.unbind(self.getWin());
24358
24605
  Event.unbind(self.getBody());
@@ -24373,8 +24620,11 @@ define("tinymce/Editor", [
24373
24620
 
24374
24621
  form = self.formElement;
24375
24622
  if (form) {
24376
- form.submit = form._mceOldSubmit;
24377
- form._mceOldSubmit = null;
24623
+ if (form._mceOldSubmit) {
24624
+ form.submit = form._mceOldSubmit;
24625
+ form._mceOldSubmit = null;
24626
+ }
24627
+
24378
24628
  DOM.unbind(form, 'submit reset', self.formEventDelegate);
24379
24629
  }
24380
24630
 
@@ -24538,6 +24788,35 @@ define("tinymce/FocusManager", [
24538
24788
  }
24539
24789
  }
24540
24790
 
24791
+ // We can't store a real range on IE 11 since it gets mutated so we need to use a bookmark object
24792
+ // TODO: Move this to a separate range utils class since it's it's logic is present in Selection as well.
24793
+ function createBookmark(rng) {
24794
+ if (rng && rng.startContainer) {
24795
+ return {
24796
+ startContainer: rng.startContainer,
24797
+ startOffset: rng.startOffset,
24798
+ endContainer: rng.endContainer,
24799
+ endOffset: rng.endOffset
24800
+ };
24801
+ }
24802
+
24803
+ return rng;
24804
+ }
24805
+
24806
+ function bookmarkToRng(editor, bookmark) {
24807
+ var rng;
24808
+
24809
+ if (bookmark.startContainer) {
24810
+ rng = editor.getDoc().createRange();
24811
+ rng.setStart(bookmark.startContainer, bookmark.startOffset);
24812
+ rng.setEnd(bookmark.endContainer, bookmark.endOffset);
24813
+ } else {
24814
+ rng = bookmark;
24815
+ }
24816
+
24817
+ return rng;
24818
+ }
24819
+
24541
24820
  function registerEvents(e) {
24542
24821
  var editor = e.editor, lastRng, selectionChangeHandler;
24543
24822
 
@@ -24547,16 +24826,26 @@ define("tinymce/FocusManager", [
24547
24826
 
24548
24827
  editor.on('init', function() {
24549
24828
  // On IE take selection snapshot onbeforedeactivate
24550
- if ("onbeforedeactivate" in document) {
24829
+ if ("onbeforedeactivate" in document && Env.ie < 11) {
24551
24830
  editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
24552
24831
  var ieSelection = editor.getDoc().selection;
24553
- lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
24832
+
24833
+ try {
24834
+ lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
24835
+ } catch (ex) {
24836
+ // IE throws "Unexcpected call to method or property access" some times so lets ignore it
24837
+ }
24554
24838
  });
24555
- } else if (editor.inline) {
24839
+ } else if (editor.inline || Env.ie > 10) {
24556
24840
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
24557
- editor.on('nodechange', function() {
24841
+ editor.on('nodechange keyup', function() {
24558
24842
  var isInBody, node = document.activeElement;
24559
24843
 
24844
+ // IE 11 reports active element as iframe not body of iframe
24845
+ if (node && node.id == editor.id + '_ifr') {
24846
+ node = editor.getBody();
24847
+ }
24848
+
24560
24849
  // Check if selection is within editor body
24561
24850
  while (node) {
24562
24851
  if (node == editor.getBody()) {
@@ -24596,12 +24885,17 @@ define("tinymce/FocusManager", [
24596
24885
  }
24597
24886
  });
24598
24887
 
24888
+ // Remove last selection bookmark on mousedown see #6305
24889
+ editor.on('mousedown', function() {
24890
+ editor.selection.lastFocusBookmark = null;
24891
+ });
24892
+
24599
24893
  editor.on('focusin', function() {
24600
24894
  var focusedEditor = editorManager.focusedEditor;
24601
24895
 
24602
- if (editor.selection.restoreRng) {
24603
- editor.selection.setRng(editor.selection.restoreRng);
24604
- editor.selection.restoreRng = null;
24896
+ if (editor.selection.lastFocusBookmark) {
24897
+ editor.selection.setRng(bookmarkToRng(editor, editor.selection.lastFocusBookmark));
24898
+ editor.selection.lastFocusBookmark = null;
24605
24899
  }
24606
24900
 
24607
24901
  if (focusedEditor != editor) {
@@ -24609,6 +24903,7 @@ define("tinymce/FocusManager", [
24609
24903
  focusedEditor.fire('blur', {focusedEditor: editor});
24610
24904
  }
24611
24905
 
24906
+ editorManager.activeEditor = editor;
24612
24907
  editor.fire('focus', {blurredEditor: focusedEditor});
24613
24908
  editor.focus(false);
24614
24909
  editorManager.focusedEditor = editor;
@@ -24616,21 +24911,21 @@ define("tinymce/FocusManager", [
24616
24911
  });
24617
24912
 
24618
24913
  editor.on('focusout', function() {
24619
- editor.selection.restoreRng = lastRng;
24914
+ editor.selection.lastFocusBookmark = createBookmark(lastRng);
24620
24915
 
24621
24916
  window.setTimeout(function() {
24622
24917
  var focusedEditor = editorManager.focusedEditor;
24623
24918
 
24624
24919
  // Focus from editorA into editorB then don't restore selection
24625
24920
  if (focusedEditor != editor) {
24626
- editor.selection.restoreRng = null;
24921
+ editor.selection.lastFocusBookmark = null;
24627
24922
  }
24628
24923
 
24629
- // Still the same editor the the blur was outside any editor
24924
+ // Still the same editor the the blur was outside any editor UI
24630
24925
  if (!isUIElement(getActiveElement()) && focusedEditor == editor) {
24631
24926
  editor.fire('blur', {focusedEditor: null});
24632
24927
  editorManager.focusedEditor = null;
24633
- editor.selection.restoreRng = null;
24928
+ editor.selection.lastFocusBookmark = null;
24634
24929
  }
24635
24930
  }, 0);
24636
24931
  });
@@ -24666,7 +24961,7 @@ define("tinymce/FocusManager", [
24666
24961
  */
24667
24962
 
24668
24963
  /**
24669
- * This class used as a factory for manager for tinymce.Editor instaces.
24964
+ * This class used as a factory for manager for tinymce.Editor instances.
24670
24965
  *
24671
24966
  * @example
24672
24967
  * tinymce.EditorManager.init({});
@@ -24704,7 +24999,7 @@ define("tinymce/EditorManager", [
24704
24999
  * @property minorVersion
24705
25000
  * @type String
24706
25001
  */
24707
- minorVersion : '0',
25002
+ minorVersion : '0.6',
24708
25003
 
24709
25004
  /**
24710
25005
  * Release date of TinyMCE build.
@@ -24712,7 +25007,7 @@ define("tinymce/EditorManager", [
24712
25007
  * @property releaseDate
24713
25008
  * @type String
24714
25009
  */
24715
- releaseDate: '2013-07-18',
25010
+ releaseDate: '2013-09-12',
24716
25011
 
24717
25012
  /**
24718
25013
  * Collection of editor instances.
@@ -24863,11 +25158,11 @@ define("tinymce/EditorManager", [
24863
25158
  return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
24864
25159
  }
24865
25160
 
24866
- self.settings = settings;
24867
-
24868
- DOM.bind(window, 'ready', function() {
25161
+ function readyHandler() {
24869
25162
  var l, co;
24870
25163
 
25164
+ DOM.unbind(window, 'ready', readyHandler);
25165
+
24871
25166
  execCallback(settings, 'onpageload');
24872
25167
 
24873
25168
  if (settings.types) {
@@ -24964,7 +25259,11 @@ define("tinymce/EditorManager", [
24964
25259
  }
24965
25260
  });
24966
25261
  }
24967
- });
25262
+ }
25263
+
25264
+ self.settings = settings;
25265
+
25266
+ DOM.bind(window, 'ready', readyHandler);
24968
25267
  },
24969
25268
 
24970
25269
  /**
@@ -25060,7 +25359,7 @@ define("tinymce/EditorManager", [
25060
25359
  * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
25061
25360
  */
25062
25361
  remove: function(selector) {
25063
- var self = this, i, editors = self.editors, editor;
25362
+ var self = this, i, editors = self.editors, editor, removedFromList;
25064
25363
 
25065
25364
  // Remove all editors
25066
25365
  if (!selector) {
@@ -25095,6 +25394,7 @@ define("tinymce/EditorManager", [
25095
25394
  for (i = 0; i < editors.length; i++) {
25096
25395
  if (editors[i] == editor) {
25097
25396
  editors.splice(i, 1);
25397
+ removedFromList = true;
25098
25398
  break;
25099
25399
  }
25100
25400
  }
@@ -25104,26 +25404,22 @@ define("tinymce/EditorManager", [
25104
25404
  self.activeEditor = editors[0];
25105
25405
  }
25106
25406
 
25107
- // Don't remove missing editor or removed instances
25108
- if (!editor || editor.removed) {
25109
- return;
25110
- }
25111
-
25112
- editor.remove();
25113
- editor.destroy();
25114
-
25115
25407
  /**
25116
25408
  * Fires when an editor is removed from EditorManager collection.
25117
25409
  *
25118
25410
  * @event RemoveEditor
25119
25411
  * @param {Object} e Event arguments.
25120
25412
  */
25121
- self.fire('RemoveEditor', {editor: editor});
25413
+ if (removedFromList) {
25414
+ self.fire('RemoveEditor', {editor: editor});
25415
+ }
25122
25416
 
25123
25417
  if (!editors.length) {
25124
25418
  DOM.unbind(window, 'beforeunload', beforeUnloadDelegate);
25125
25419
  }
25126
25420
 
25421
+ editor.remove();
25422
+
25127
25423
  return editor;
25128
25424
  },
25129
25425
 
@@ -25244,10 +25540,10 @@ define("tinymce/LegacyInput", [
25244
25540
  var each = Tools.each, explode = Tools.explode;
25245
25541
 
25246
25542
  EditorManager.on('AddEditor', function(e) {
25247
- var ed = e.editor;
25543
+ var editor = e.editor;
25248
25544
 
25249
- ed.on('preInit', function() {
25250
- var filters, fontSizes, dom, settings = ed.settings;
25545
+ editor.on('preInit', function() {
25546
+ var filters, fontSizes, dom, settings = editor.settings;
25251
25547
 
25252
25548
  function replaceWithSpan(node, styles) {
25253
25549
  each(styles, function(value, name) {
@@ -25260,7 +25556,7 @@ define("tinymce/LegacyInput", [
25260
25556
  }
25261
25557
 
25262
25558
  function convert(e) {
25263
- dom = ed.dom;
25559
+ dom = editor.dom;
25264
25560
 
25265
25561
  if (settings.convert_fonts_to_spans) {
25266
25562
  each(dom.select('font,u,strike', e.node), function(node) {
@@ -25295,7 +25591,7 @@ define("tinymce/LegacyInput", [
25295
25591
  }
25296
25592
  };
25297
25593
 
25298
- ed.on('PreProcess SetContent', convert);
25594
+ editor.on('PreProcess SetContent', convert);
25299
25595
  }
25300
25596
  });
25301
25597
  });
@@ -25686,16 +25982,24 @@ define("tinymce/util/JSONP", [
25686
25982
  * var value = tinymce.util.LocalStorage.getItem('key');
25687
25983
  */
25688
25984
  define("tinymce/util/LocalStorage", [], function() {
25689
- var LocalStorage, storageElm, items, keys, userDataKey;
25985
+ var LocalStorage, storageElm, items, keys, userDataKey, hasOldIEDataSupport;
25690
25986
 
25691
25987
  // Check for native support
25692
- if (window.localStorage) {
25693
- return localStorage;
25988
+ try {
25989
+ if (window.localStorage) {
25990
+ return localStorage;
25991
+ }
25992
+ } catch (ex) {
25993
+ // Ignore
25694
25994
  }
25695
25995
 
25696
25996
  userDataKey = "tinymce";
25697
25997
  storageElm = document.documentElement;
25698
- storageElm.addBehavior('#default#userData');
25998
+ hasOldIEDataSupport = !!storageElm.addBehavior;
25999
+
26000
+ if (hasOldIEDataSupport) {
26001
+ storageElm.addBehavior('#default#userData');
26002
+ }
25699
26003
 
25700
26004
  /**
25701
26005
  * Gets the keys names and updates LocalStorage.length property. Since IE7 doesn't have any getters/setters.
@@ -25718,6 +26022,11 @@ define("tinymce/util/LocalStorage", [], function() {
25718
26022
 
25719
26023
  items = {};
25720
26024
 
26025
+ // localStorage can be disabled on WebKit/Gecko so make a dummy storage
26026
+ if (!hasOldIEDataSupport) {
26027
+ return;
26028
+ }
26029
+
25721
26030
  function next(end) {
25722
26031
  var value, nextPos;
25723
26032
 
@@ -25752,6 +26061,11 @@ define("tinymce/util/LocalStorage", [], function() {
25752
26061
  function save() {
25753
26062
  var value, data = '';
25754
26063
 
26064
+ // localStorage can be disabled on WebKit/Gecko so make a dummy storage
26065
+ if (!hasOldIEDataSupport) {
26066
+ return;
26067
+ }
26068
+
25755
26069
  for (var key in items) {
25756
26070
  value = items[key];
25757
26071
  data += (data ? ',' : '') + key.length.toString(32) + ',' + key + ',' + value.length.toString(32) + ',' + value;
@@ -26368,7 +26682,7 @@ define("tinymce/ui/Widget", [
26368
26682
  *
26369
26683
  * @example
26370
26684
  * // Create and render a button to the body element
26371
- * tinymce.ui.Factory({
26685
+ * tinymce.ui.Factory.create({
26372
26686
  * type: 'button',
26373
26687
  * text: 'My button'
26374
26688
  * }).renderTo(document.body);
@@ -26476,7 +26790,7 @@ define("tinymce/ui/Button", [
26476
26790
  *
26477
26791
  * @example
26478
26792
  * // Create and render a buttongroup with two buttons to the body element
26479
- * tinymce.ui.Factory({
26793
+ * tinymce.ui.Factory.create({
26480
26794
  * type: 'buttongroup',
26481
26795
  * items: [
26482
26796
  * {text: 'Button A'},
@@ -26540,7 +26854,7 @@ define("tinymce/ui/ButtonGroup", [
26540
26854
  *
26541
26855
  * @example
26542
26856
  * // Create and render a checkbox to the body element
26543
- * tinymce.ui.Factory({
26857
+ * tinymce.ui.Factory.create({
26544
26858
  * type: 'checkbox',
26545
26859
  * checked: true,
26546
26860
  * text: 'My checkbox'
@@ -27038,6 +27352,11 @@ define("tinymce/ui/ComboBox", [
27038
27352
  return self._super();
27039
27353
  },
27040
27354
 
27355
+ remove: function() {
27356
+ DomUtils.off(this.getEl('inp'));
27357
+ this._super();
27358
+ },
27359
+
27041
27360
  /**
27042
27361
  * Renders the control as a HTML string.
27043
27362
  *
@@ -27173,7 +27492,7 @@ define("tinymce/ui/Path", [
27173
27492
  * @private
27174
27493
  */
27175
27494
  update: function() {
27176
- this.getEl().innerHTML = this._getPathHtml();
27495
+ this.innerHtml(this._getPathHtml());
27177
27496
  },
27178
27497
 
27179
27498
  /**
@@ -28003,191 +28322,195 @@ define("tinymce/ui/FlowLayout", [
28003
28322
  * @class tinymce.ui.FormatControls
28004
28323
  */
28005
28324
  define("tinymce/ui/FormatControls", [
28006
- "tinymce/ui/Factory",
28007
28325
  "tinymce/ui/Control",
28008
28326
  "tinymce/ui/Widget",
28009
28327
  "tinymce/ui/FloatPanel",
28010
28328
  "tinymce/util/Tools",
28011
28329
  "tinymce/EditorManager",
28012
28330
  "tinymce/Env"
28013
- ], function(Factory, Control, Widget, FloatPanel, Tools, EditorManager, Env) {
28331
+ ], function(Control, Widget, FloatPanel, Tools, EditorManager, Env) {
28014
28332
  var each = Tools.each;
28015
28333
 
28334
+ EditorManager.on('AddEditor', function(e) {
28335
+ registerControls(e.editor);
28336
+ });
28337
+
28016
28338
  Control.translate = function(text) {
28017
28339
  return EditorManager.translate(text);
28018
28340
  };
28019
28341
 
28020
28342
  Widget.tooltips = !Env.iOS;
28021
28343
 
28022
- // Generates a preview for a format
28023
- function getPreviewCss(format) {
28024
- var editor = EditorManager.activeEditor, name, previewElm, dom = editor.dom;
28025
- var previewCss = '', parentFontSize, previewStyles;
28344
+ function registerControls(editor) {
28345
+ var formatMenu;
28026
28346
 
28027
- previewStyles = editor.settings.preview_styles;
28347
+ // Generates a preview for a format
28348
+ function getPreviewCss(format) {
28349
+ var name, previewElm, dom = editor.dom;
28350
+ var previewCss = '', parentFontSize, previewStyles;
28028
28351
 
28029
- // No preview forced
28030
- if (previewStyles === false) {
28031
- return '';
28032
- }
28352
+ previewStyles = editor.settings.preview_styles;
28033
28353
 
28034
- // Default preview
28035
- if (!previewStyles) {
28036
- previewStyles = 'font-family font-size font-weight text-decoration text-transform color background-color border border-radius';
28037
- }
28354
+ // No preview forced
28355
+ if (previewStyles === false) {
28356
+ return '';
28357
+ }
28038
28358
 
28039
- // Removes any variables since these can't be previewed
28040
- function removeVars(val) {
28041
- return val.replace(/%(\w+)/g, '');
28042
- }
28359
+ // Default preview
28360
+ if (!previewStyles) {
28361
+ previewStyles = 'font-family font-size font-weight text-decoration ' +
28362
+ 'text-transform color background-color border border-radius';
28363
+ }
28043
28364
 
28044
- // Create block/inline element to use for preview
28045
- format = editor.formatter.get(format);
28046
- if (!format) {
28047
- return;
28048
- }
28365
+ // Removes any variables since these can't be previewed
28366
+ function removeVars(val) {
28367
+ return val.replace(/%(\w+)/g, '');
28368
+ }
28049
28369
 
28050
- format = format[0];
28051
- name = format.block || format.inline || 'span';
28052
- previewElm = dom.create(name);
28370
+ // Create block/inline element to use for preview
28371
+ format = editor.formatter.get(format);
28372
+ if (!format) {
28373
+ return;
28374
+ }
28053
28375
 
28054
- // Add format styles to preview element
28055
- each(format.styles, function(value, name) {
28056
- value = removeVars(value);
28376
+ format = format[0];
28377
+ name = format.block || format.inline || 'span';
28378
+ previewElm = dom.create(name);
28057
28379
 
28058
- if (value) {
28059
- dom.setStyle(previewElm, name, value);
28060
- }
28061
- });
28380
+ // Add format styles to preview element
28381
+ each(format.styles, function(value, name) {
28382
+ value = removeVars(value);
28062
28383
 
28063
- // Add attributes to preview element
28064
- each(format.attributes, function(value, name) {
28065
- value = removeVars(value);
28384
+ if (value) {
28385
+ dom.setStyle(previewElm, name, value);
28386
+ }
28387
+ });
28066
28388
 
28067
- if (value) {
28068
- dom.setAttrib(previewElm, name, value);
28069
- }
28070
- });
28389
+ // Add attributes to preview element
28390
+ each(format.attributes, function(value, name) {
28391
+ value = removeVars(value);
28071
28392
 
28072
- // Add classes to preview element
28073
- each(format.classes, function(value) {
28074
- value = removeVars(value);
28393
+ if (value) {
28394
+ dom.setAttrib(previewElm, name, value);
28395
+ }
28396
+ });
28075
28397
 
28076
- if (!dom.hasClass(previewElm, value)) {
28077
- dom.addClass(previewElm, value);
28078
- }
28079
- });
28398
+ // Add classes to preview element
28399
+ each(format.classes, function(value) {
28400
+ value = removeVars(value);
28080
28401
 
28081
- editor.fire('PreviewFormats');
28402
+ if (!dom.hasClass(previewElm, value)) {
28403
+ dom.addClass(previewElm, value);
28404
+ }
28405
+ });
28082
28406
 
28083
- // Add the previewElm outside the visual area
28084
- dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
28085
- editor.getBody().appendChild(previewElm);
28407
+ editor.fire('PreviewFormats');
28086
28408
 
28087
- // Get parent container font size so we can compute px values out of em/% for older IE:s
28088
- parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
28089
- parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
28409
+ // Add the previewElm outside the visual area
28410
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
28411
+ editor.getBody().appendChild(previewElm);
28090
28412
 
28091
- each(previewStyles.split(' '), function(name) {
28092
- var value = dom.getStyle(previewElm, name, true);
28413
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
28414
+ parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
28415
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
28093
28416
 
28094
- // If background is transparent then check if the body has a background color we can use
28095
- if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
28096
- value = dom.getStyle(editor.getBody(), name, true);
28417
+ each(previewStyles.split(' '), function(name) {
28418
+ var value = dom.getStyle(previewElm, name, true);
28097
28419
 
28098
- // Ignore white since it's the default color, not the nicest fix
28099
- // TODO: Fix this by detecting runtime style
28100
- if (dom.toHex(value).toLowerCase() == '#ffffff') {
28101
- return;
28102
- }
28103
- }
28420
+ // If background is transparent then check if the body has a background color we can use
28421
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
28422
+ value = dom.getStyle(editor.getBody(), name, true);
28104
28423
 
28105
- if (name == 'color') {
28106
- // Ignore black since it's the default color, not the nicest fix
28107
- // TODO: Fix this by detecting runtime style
28108
- if (dom.toHex(value).toLowerCase() == '#000000') {
28109
- return;
28424
+ // Ignore white since it's the default color, not the nicest fix
28425
+ // TODO: Fix this by detecting runtime style
28426
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
28427
+ return;
28428
+ }
28110
28429
  }
28111
- }
28112
28430
 
28113
- // Old IE won't calculate the font size so we need to do that manually
28114
- if (name == 'font-size') {
28115
- if (/em|%$/.test(value)) {
28116
- if (parentFontSize === 0) {
28431
+ if (name == 'color') {
28432
+ // Ignore black since it's the default color, not the nicest fix
28433
+ // TODO: Fix this by detecting runtime style
28434
+ if (dom.toHex(value).toLowerCase() == '#000000') {
28117
28435
  return;
28118
28436
  }
28437
+ }
28119
28438
 
28120
- // Convert font size from em/% to px
28121
- value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
28122
- value = (value * parentFontSize) + 'px';
28439
+ // Old IE won't calculate the font size so we need to do that manually
28440
+ if (name == 'font-size') {
28441
+ if (/em|%$/.test(value)) {
28442
+ if (parentFontSize === 0) {
28443
+ return;
28444
+ }
28445
+
28446
+ // Convert font size from em/% to px
28447
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
28448
+ value = (value * parentFontSize) + 'px';
28449
+ }
28123
28450
  }
28124
- }
28125
28451
 
28126
- if (name == "border" && value) {
28127
- previewCss += 'padding:0 2px;';
28128
- }
28452
+ if (name == "border" && value) {
28453
+ previewCss += 'padding:0 2px;';
28454
+ }
28129
28455
 
28130
- previewCss += name + ':' + value + ';';
28131
- });
28456
+ previewCss += name + ':' + value + ';';
28457
+ });
28132
28458
 
28133
- editor.fire('AfterPreviewFormats');
28459
+ editor.fire('AfterPreviewFormats');
28134
28460
 
28135
- //previewCss += 'line-height:normal';
28461
+ //previewCss += 'line-height:normal';
28136
28462
 
28137
- dom.remove(previewElm);
28463
+ dom.remove(previewElm);
28138
28464
 
28139
- return previewCss;
28140
- }
28465
+ return previewCss;
28466
+ }
28141
28467
 
28142
- function createListBoxChangeHandler(items, formatName) {
28143
- return function() {
28144
- var self = this;
28468
+ function createListBoxChangeHandler(items, formatName) {
28469
+ return function() {
28470
+ var self = this;
28145
28471
 
28146
- EditorManager.activeEditor.on('nodeChange', function(e) {
28147
- var formatter = EditorManager.activeEditor.formatter;
28148
- var value = null;
28472
+ editor.on('nodeChange', function(e) {
28473
+ var formatter = editor.formatter;
28474
+ var value = null;
28149
28475
 
28150
- each(e.parents, function(node) {
28151
- each(items, function(item) {
28152
- if (formatName) {
28153
- if (formatter.matchNode(node, formatName, {value: item.value})) {
28154
- value = item.value;
28476
+ each(e.parents, function(node) {
28477
+ each(items, function(item) {
28478
+ if (formatName) {
28479
+ if (formatter.matchNode(node, formatName, {value: item.value})) {
28480
+ value = item.value;
28481
+ }
28482
+ } else {
28483
+ if (formatter.matchNode(node, item.value)) {
28484
+ value = item.value;
28485
+ }
28155
28486
  }
28156
- } else {
28157
- if (formatter.matchNode(node, item.value)) {
28158
- value = item.value;
28487
+
28488
+ if (value) {
28489
+ return false;
28159
28490
  }
28160
- }
28491
+ });
28161
28492
 
28162
28493
  if (value) {
28163
28494
  return false;
28164
28495
  }
28165
28496
  });
28166
28497
 
28167
- if (value) {
28168
- return false;
28169
- }
28498
+ self.value(value);
28170
28499
  });
28500
+ };
28501
+ }
28171
28502
 
28172
- self.value(value);
28173
- });
28174
- };
28175
- }
28503
+ function createFormats(formats) {
28504
+ formats = formats.split(';');
28176
28505
 
28177
- function createFormats(formats) {
28178
- formats = formats.split(';');
28506
+ var i = formats.length;
28507
+ while (i--) {
28508
+ formats[i] = formats[i].split('=');
28509
+ }
28179
28510
 
28180
- var i = formats.length;
28181
- while (i--) {
28182
- formats[i] = formats[i].split('=');
28511
+ return formats;
28183
28512
  }
28184
28513
 
28185
- return formats;
28186
- }
28187
-
28188
- EditorManager.on('AddEditor', function(e) {
28189
- var editor = e.editor, formatMenu;
28190
-
28191
28514
  function createFormatMenu() {
28192
28515
  var count = 0, newFormats = [];
28193
28516
 
@@ -28236,8 +28559,7 @@ define("tinymce/ui/FormatControls", [
28236
28559
  each(formats, function(format) {
28237
28560
  var menuItem = {
28238
28561
  text: format.title,
28239
- icon: format.icon,
28240
- preview: true
28562
+ icon: format.icon
28241
28563
  };
28242
28564
 
28243
28565
  if (format.items) {
@@ -28250,22 +28572,7 @@ define("tinymce/ui/FormatControls", [
28250
28572
  newFormats.push(format);
28251
28573
  }
28252
28574
 
28253
- menuItem.textStyle = function() {
28254
- return getPreviewCss(formatName);
28255
- };
28256
-
28257
- menuItem.onclick = function() {
28258
- toggleFormat(formatName);
28259
- };
28260
-
28261
- menuItem.onPostRender = function() {
28262
- var self = this;
28263
-
28264
- self.parent().on('show', function() {
28265
- self.disabled(!editor.formatter.canApply(formatName));
28266
- self.active(editor.formatter.match(formatName));
28267
- });
28268
- };
28575
+ menuItem.format = formatName;
28269
28576
  }
28270
28577
 
28271
28578
  menu.push(menuItem);
@@ -28282,6 +28589,40 @@ define("tinymce/ui/FormatControls", [
28282
28589
 
28283
28590
  var menu = createMenu(editor.settings.style_formats || defaultStyleFormats);
28284
28591
 
28592
+ menu = {
28593
+ type: 'menu',
28594
+ items: menu,
28595
+ onPostRender: function(e) {
28596
+ editor.fire('renderFormatsMenu', {control: e.control});
28597
+ },
28598
+ itemDefaults: {
28599
+ preview: true,
28600
+
28601
+ textStyle: function() {
28602
+ if (this.settings.format) {
28603
+ return getPreviewCss(this.settings.format);
28604
+ }
28605
+ },
28606
+
28607
+ onPostRender: function() {
28608
+ var self = this, formatName = this.settings.format;
28609
+
28610
+ if (formatName) {
28611
+ self.parent().on('show', function() {
28612
+ self.disabled(!editor.formatter.canApply(formatName));
28613
+ self.active(editor.formatter.match(formatName));
28614
+ });
28615
+ }
28616
+ },
28617
+
28618
+ onclick: function() {
28619
+ if (this.settings.format) {
28620
+ toggleFormat(this.settings.format);
28621
+ }
28622
+ }
28623
+ }
28624
+ };
28625
+
28285
28626
  return menu;
28286
28627
  }
28287
28628
 
@@ -28344,7 +28685,7 @@ define("tinymce/ui/FormatControls", [
28344
28685
  each({
28345
28686
  blockquote: ['Toggle blockquote', 'mceBlockQuote'],
28346
28687
  numlist: ['Numbered list', 'InsertOrderedList'],
28347
- bullist: ['Bulleted list', 'InsertUnorderedList'],
28688
+ bullist: ['Bullet list', 'InsertUnorderedList'],
28348
28689
  subscript: ['Subscript', 'Subscript'],
28349
28690
  superscript: ['Superscript', 'Superscript'],
28350
28691
  alignleft: ['Align left', 'JustifyLeft'],
@@ -28483,31 +28824,17 @@ define("tinymce/ui/FormatControls", [
28483
28824
  }
28484
28825
 
28485
28826
  if (fmt) {
28486
- EditorManager.activeEditor.execCommand('mceToggleFormat', false, fmt);
28827
+ editor.execCommand('mceToggleFormat', false, fmt);
28487
28828
  }
28488
28829
  }
28489
28830
 
28490
- Factory.add('styleselect', function(settings) {
28491
- var menu = [].concat(formatMenu);
28492
-
28493
- /*
28494
- menu.push({text: '-'});
28495
- menu.push({
28496
- text: 'Remove formatting',
28497
- icon: 'removeformat',
28498
- onclick: function() {
28499
- editor.execCommand('RemoveFormat');
28500
- }
28501
- });
28502
- */
28503
-
28504
- return Factory.create('menubutton', Tools.extend({
28505
- text: 'Formats',
28506
- menu: menu
28507
- }, settings));
28831
+ editor.addButton('styleselect', {
28832
+ type: 'menubutton',
28833
+ text: 'Formats',
28834
+ menu: formatMenu
28508
28835
  });
28509
28836
 
28510
- Factory.add('formatselect', function(settings) {
28837
+ editor.addButton('formatselect', function() {
28511
28838
  var items = [], blocks = createFormats(editor.settings.block_formats ||
28512
28839
  'Paragraph=p;' +
28513
28840
  'Address=address;' +
@@ -28522,7 +28849,7 @@ define("tinymce/ui/FormatControls", [
28522
28849
 
28523
28850
  each(blocks, function(block) {
28524
28851
  items.push({
28525
- text: {raw: block[0]},
28852
+ text: block[0],
28526
28853
  value: block[1],
28527
28854
  textStyle: function() {
28528
28855
  return getPreviewCss(block[1]);
@@ -28530,16 +28857,17 @@ define("tinymce/ui/FormatControls", [
28530
28857
  });
28531
28858
  });
28532
28859
 
28533
- return Factory.create('listbox', Tools.extend({
28860
+ return {
28861
+ type: 'listbox',
28534
28862
  text: {raw: blocks[0][0]},
28535
28863
  values: items,
28536
28864
  fixedWidth: true,
28537
28865
  onselect: toggleFormat,
28538
28866
  onPostRender: createListBoxChangeHandler(items)
28539
- }, settings));
28867
+ };
28540
28868
  });
28541
28869
 
28542
- Factory.add('fontselect', function(settings) {
28870
+ editor.addButton('fontselect', function() {
28543
28871
  var defaultFontsFormats =
28544
28872
  'Andale Mono=andale mono,times;' +
28545
28873
  'Arial=arial,helvetica,sans-serif;' +
@@ -28569,7 +28897,8 @@ define("tinymce/ui/FormatControls", [
28569
28897
  });
28570
28898
  });
28571
28899
 
28572
- return Factory.create('listbox', Tools.extend({
28900
+ return {
28901
+ type: 'listbox',
28573
28902
  text: 'Font Family',
28574
28903
  tooltip: 'Font Family',
28575
28904
  values: items,
@@ -28577,13 +28906,13 @@ define("tinymce/ui/FormatControls", [
28577
28906
  onPostRender: createListBoxChangeHandler(items, 'fontname'),
28578
28907
  onselect: function(e) {
28579
28908
  if (e.control.settings.value) {
28580
- EditorManager.activeEditor.execCommand('FontName', false, e.control.settings.value);
28909
+ editor.execCommand('FontName', false, e.control.settings.value);
28581
28910
  }
28582
28911
  }
28583
- }, settings));
28912
+ };
28584
28913
  });
28585
28914
 
28586
- Factory.add('fontsizeselect', function(settings) {
28915
+ editor.addButton('fontsizeselect', function() {
28587
28916
  var items = [], defaultFontsizeFormats = '8pt 10pt 12pt 14pt 18pt 24pt 36pt';
28588
28917
  var fontsize_formats = editor.settings.fontsize_formats || defaultFontsizeFormats;
28589
28918
 
@@ -28591,7 +28920,8 @@ define("tinymce/ui/FormatControls", [
28591
28920
  items.push({text: item, value: item});
28592
28921
  });
28593
28922
 
28594
- return Factory.create('listbox', Tools.extend({
28923
+ return {
28924
+ type: 'listbox',
28595
28925
  text: 'Font Sizes',
28596
28926
  tooltip: 'Font Sizes',
28597
28927
  values: items,
@@ -28599,17 +28929,17 @@ define("tinymce/ui/FormatControls", [
28599
28929
  onPostRender: createListBoxChangeHandler(items, 'fontsize'),
28600
28930
  onclick: function(e) {
28601
28931
  if (e.control.settings.value) {
28602
- EditorManager.activeEditor.execCommand('FontSize', false, e.control.settings.value);
28932
+ editor.execCommand('FontSize', false, e.control.settings.value);
28603
28933
  }
28604
28934
  }
28605
- }, settings));
28935
+ };
28606
28936
  });
28607
28937
 
28608
28938
  editor.addMenuItem('formats', {
28609
28939
  text: 'Formats',
28610
28940
  menu: formatMenu
28611
28941
  });
28612
- });
28942
+ }
28613
28943
  });
28614
28944
 
28615
28945
  // Included from: js/tinymce/classes/ui/GridLayout.js
@@ -28904,10 +29234,25 @@ define("tinymce/ui/Iframe", [
28904
29234
  *
28905
29235
  * @method html
28906
29236
  * @param {String} html HTML string to set as HTML inside the iframe.
29237
+ * @param {function} callback Optional callback to execute when the iframe body is filled with contents.
28907
29238
  * @return {tinymce.ui.Iframe} Current iframe control.
28908
29239
  */
28909
- html: function(html) {
28910
- this.getEl().contentWindow.document.body.innerHTML = html;
29240
+ html: function(html, callback) {
29241
+ var self = this, body = this.getEl().contentWindow.document.body;
29242
+
29243
+ // Wait for iframe to initialize IE 10 takes time
29244
+ if (!body) {
29245
+ setTimeout(function() {
29246
+ self.html(html);
29247
+ }, 0);
29248
+ } else {
29249
+ body.innerHTML = html;
29250
+
29251
+ if (callback) {
29252
+ callback();
29253
+ }
29254
+ }
29255
+
28911
29256
  return this;
28912
29257
  }
28913
29258
  });
@@ -29035,7 +29380,7 @@ define("tinymce/ui/Label", [
29035
29380
  var self = this;
29036
29381
 
29037
29382
  if (self._rendered && text) {
29038
- self.getEl().innerHTML = self.encode(text);
29383
+ this.innerHtml(self.encode(text));
29039
29384
  }
29040
29385
 
29041
29386
  return self._super(text);
@@ -29635,9 +29980,9 @@ define("tinymce/ui/MenuItem", [
29635
29980
  * @method showMenu
29636
29981
  */
29637
29982
  showMenu: function() {
29638
- var self = this, settings = self.settings, menu;
29983
+ var self = this, settings = self.settings, menu, parent = self.parent();
29639
29984
 
29640
- self.parent().items().each(function(ctrl) {
29985
+ parent.items().each(function(ctrl) {
29641
29986
  if (ctrl !== self) {
29642
29987
  ctrl.hideMenu();
29643
29988
  }
@@ -29659,6 +30004,10 @@ define("tinymce/ui/MenuItem", [
29659
30004
  menu.type = menu.type || 'menu';
29660
30005
  }
29661
30006
 
30007
+ if (parent.settings.itemDefaults) {
30008
+ menu.itemDefaults = parent.settings.itemDefaults;
30009
+ }
30010
+
29662
30011
  menu = self.menu = Factory.create(menu).parent(self).renderTo(self.getContainerElm());
29663
30012
  menu.reflow();
29664
30013
  menu.fire('show');
@@ -29675,7 +30024,7 @@ define("tinymce/ui/MenuItem", [
29675
30024
  menu.show();
29676
30025
  }
29677
30026
 
29678
- menu._parentMenu = self.parent();
30027
+ menu._parentMenu = parent;
29679
30028
 
29680
30029
  menu.addClass('menu-sub');
29681
30030
 
@@ -29722,17 +30071,22 @@ define("tinymce/ui/MenuItem", [
29722
30071
  */
29723
30072
  renderHtml: function() {
29724
30073
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
29725
- var icon = self.settings.icon;
30074
+ var icon = self.settings.icon, image = '';
29726
30075
 
29727
30076
  if (icon) {
29728
30077
  self.parent().addClass('menu-has-icons');
29729
30078
  }
29730
30079
 
30080
+ if (settings.image) {
30081
+ icon = 'none';
30082
+ image = ' style="background-image: url(\'' + settings.image + '\')"';
30083
+ }
30084
+
29731
30085
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
29732
30086
 
29733
30087
  return (
29734
30088
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
29735
- (text !== '-' ? '<i class="' + icon + '"></i>&nbsp;' : '') +
30089
+ (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
29736
30090
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
29737
30091
  (settings.shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
29738
30092
  settings.shortcut + '</div>' : '') +
@@ -29751,7 +30105,7 @@ define("tinymce/ui/MenuItem", [
29751
30105
 
29752
30106
  var textStyle = settings.textStyle;
29753
30107
  if (typeof(textStyle) == "function") {
29754
- textStyle = textStyle();
30108
+ textStyle = textStyle.call(this);
29755
30109
  }
29756
30110
 
29757
30111
  if (textStyle) {
@@ -29801,8 +30155,9 @@ define("tinymce/ui/MenuItem", [
29801
30155
  define("tinymce/ui/Menu", [
29802
30156
  "tinymce/ui/FloatPanel",
29803
30157
  "tinymce/ui/KeyboardNavigation",
29804
- "tinymce/ui/MenuItem"
29805
- ], function(FloatPanel, KeyboardNavigation, MenuItem) {
30158
+ "tinymce/ui/MenuItem",
30159
+ "tinymce/util/Tools"
30160
+ ], function(FloatPanel, KeyboardNavigation, MenuItem, Tools) {
29806
30161
  "use strict";
29807
30162
 
29808
30163
  var Menu = FloatPanel.extend({
@@ -29825,6 +30180,14 @@ define("tinymce/ui/Menu", [
29825
30180
  settings.autohide = true;
29826
30181
  settings.constrainToViewport = true;
29827
30182
 
30183
+ if (settings.itemDefaults) {
30184
+ var items = settings.items, i = items.length;
30185
+
30186
+ while (i--) {
30187
+ items[i] = Tools.extend({}, settings.itemDefaults, items[i]);
30188
+ }
30189
+ }
30190
+
29828
30191
  self._super(settings);
29829
30192
  self.addClass('menu');
29830
30193
 
@@ -30021,6 +30384,14 @@ define("tinymce/ui/ResizeHandle", [
30021
30384
  self.fire('ResizeEnd');
30022
30385
  }
30023
30386
  });
30387
+ },
30388
+
30389
+ remove: function() {
30390
+ if (this.resizeDragHelper) {
30391
+ this.resizeDragHelper.destroy();
30392
+ }
30393
+
30394
+ return this._super();
30024
30395
  }
30025
30396
  });
30026
30397
  });
@@ -30576,6 +30947,11 @@ define("tinymce/ui/TextBox", [
30576
30947
  });
30577
30948
 
30578
30949
  return self._super();
30950
+ },
30951
+
30952
+ remove: function() {
30953
+ DomUtils.off(this.getEl());
30954
+ this._super();
30579
30955
  }
30580
30956
  });
30581
30957
  });