tinymce-rails 4.0.19 → 4.0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -36
  3. data/app/assets/source/tinymce/tinymce.jquery.js +1344 -760
  4. data/app/assets/source/tinymce/tinymce.js +1284 -700
  5. data/lib/tinymce/rails/engine.rb +4 -1
  6. data/lib/tinymce/rails/version.rb +2 -2
  7. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/plugins/anchor/plugin.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  12. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/emoticons/plugin.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/example/dialog.html +8 -0
  16. data/vendor/assets/javascripts/tinymce/plugins/example/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/fullpage/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/importcss/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/layer/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/legacyoutput/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/plugins/noneditable/plugin.js +1 -1
  27. data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
  28. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/plugins/print/plugin.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  32. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/plugins/spellchecker/plugin.js +1 -1
  34. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/plugins/template/plugin.js +1 -1
  36. data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
  37. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.dev.svg +175 -0
  38. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  39. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.svg +55 -168
  40. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  41. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  42. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.dev.svg +153 -0
  43. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  44. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.svg +56 -146
  45. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  46. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  47. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  48. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
  49. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  50. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +10 -10
  51. data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
  52. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c73958992ac308c2e36adddb53bb830bead67c09
4
- data.tar.gz: 6d61070d761174a06d0ef391ddab7497e1281948
3
+ metadata.gz: 98010f91779772edeb4ccd7b425414a2715f5d21
4
+ data.tar.gz: cf3ffd85b9a52c9ec7a6bae0cc07cafe5b9de8de
5
5
  SHA512:
6
- metadata.gz: 000443eccfbe9cb6afdc44936f10e2e8c6d603a5577363913ea0d45d858219721f8a0a049d29d817dcba4a95d72d852dc25e2d76d2df438f42abeef29a93d882
7
- data.tar.gz: 58a671d81776ee23a9987db2f7d84c16897952ed4a5595ac36e63a1d0a9a66726365f9bfcf484ffa56e12b132bb1f7e0cac4f67046599e140774746ef5e958ec
6
+ metadata.gz: 46b1d81eda6b817413d6620ec69693c45c080f44eeb8be4e629cfd7ef05fbd6810e19e343c5a778ed5b5189f4addf28246bc308d87c9d3cddd8ec5f001be5144
7
+ data.tar.gz: c4fce036672158aa0a41f7c664030e011e6a6bf7bf300141a1fdf7a0c0133c29c829b570eca9ea154b4d0efb7000244fa29eb4be48b552d246b85c2c8b86892d
data/README.md CHANGED
@@ -5,9 +5,9 @@ The `tinymce-rails` gem integrates the [TinyMCE](http://www.tinymce.com/) editor
5
5
 
6
6
  This gem is compatible with Rails 3.1.1 and higher (including Rails 4).
7
7
 
8
- This is the branch for TinyMCE 4. TinyMCE 3.5.x is currently available in the [master branch](https://github.com/spohlenz/tinymce-rails). For the time being, parallel versions of TinyMCE (3.5.x and 4.x) will be maintained. However TinyMCE 4 will eventually be promoted to the master branch.
8
+ This is the branch for TinyMCE 4. For TinyMCE 3.5.x, please see the [tinymce-3 branch](https://github.com/spohlenz/tinymce-rails/tree/tinymce-3).
9
9
 
10
- [![Build Status](https://travis-ci.org/spohlenz/tinymce-rails.png?branch=tinymce-4)](https://travis-ci.org/spohlenz/tinymce-rails)
10
+ [![Build Status](https://travis-ci.org/spohlenz/tinymce-rails.png?branch=master)](https://travis-ci.org/spohlenz/tinymce-rails)
11
11
 
12
12
 
13
13
  Instructions
@@ -15,33 +15,39 @@ Instructions
15
15
 
16
16
  **1. Add `tinymce-rails` to your Gemfile**
17
17
 
18
- gem 'tinymce-rails'
18
+ ```ruby
19
+ gem 'tinymce-rails'
20
+ ```
19
21
 
20
22
  Be sure to add to the global group, not the `assets` group. Then run `bundle install`.
21
23
 
22
24
 
23
25
  **2. Create a `config/tinymce.yml` file with your global configuration options:**
24
26
 
25
- toolbar1: styleselect | bold italic | link image | undo redo
26
- toolbar2: table | fullscreen
27
- plugins:
28
- - table
29
- - fullscreen
30
-
27
+ ```yml
28
+ toolbar1: styleselect | bold italic | link image | undo redo
29
+ toolbar2: table | fullscreen
30
+ plugins:
31
+ - table
32
+ - fullscreen
33
+ ```
34
+
31
35
  The Rails server no longer needs to be restarted when this file is updated in development mode.
32
36
 
33
37
  To define multiple configuration sets, follow this syntax (a default configuration must be specified):
34
38
 
35
- default:
36
- plugins:
37
- - image
38
- - link
39
-
40
- alternate:
41
- selector: textarea.table-editor
42
- toolbar: styleselect | bold italic | link image | undo redo | table
43
- plugins:
44
- - table
39
+ ```yml
40
+ default:
41
+ plugins:
42
+ - image
43
+ - link
44
+
45
+ alternate:
46
+ selector: textarea.table-editor
47
+ toolbar: styleselect | bold italic | link image | undo redo | table
48
+ plugins:
49
+ - table
50
+ ```
45
51
 
46
52
  See the [TinyMCE 4 Documentation](http://www.tinymce.com/wiki.php/Configuration) for a full list of configuration options.
47
53
 
@@ -52,39 +58,55 @@ Use *one* of the following options to include TinyMCE assets.
52
58
 
53
59
  (1) Add to your application.js:
54
60
 
55
- //= require tinymce
61
+ ```js
62
+ //= require tinymce
63
+ ```
56
64
 
57
65
  or (2) with jQuery integration:
58
66
 
59
- //= require tinymce-jquery
67
+ ```js
68
+ //= require tinymce-jquery
69
+ ```
60
70
 
61
71
  (3) The TinyMCE assets can be included on a per-page basis using the `tinymce_assets` helper:
62
72
 
63
- <%= tinymce_assets %>
64
- #=> <script type="text/javascript" src="/assets/tinymce.js">
73
+ ```erb
74
+ <%= tinymce_assets %>
75
+ #=> <script type="text/javascript" src="/assets/tinymce.js">
76
+ ```
65
77
 
66
78
 
67
79
  **4. Initialize TinyMCE**
68
80
 
69
81
  For each textarea that you want to use with TinyMCE, add the "tinymce" class and ensure it has a unique ID:
70
82
 
71
- <%= text_area_tag :content, "", :class => "tinymce", :rows => 40, :cols => 120 %>
72
-
83
+ ```erb
84
+ <%= text_area_tag :content, "", :class => "tinymce", :rows => 40, :cols => 120 %>
85
+ ```
86
+
73
87
  or if you are using Rails' form builders:
74
88
 
75
- <%= f.text_area :content, :class => "tinymce", :rows => 40, :cols => 120 %>
89
+ ```erb
90
+ <%= f.text_area :content, :class => "tinymce", :rows => 40, :cols => 120 %>
91
+ ```
76
92
 
77
93
  Then invoke the `tinymce` helper to initialize TinyMCE:
78
94
 
79
- <%= tinymce %>
95
+ ```erb
96
+ <%= tinymce %>
97
+ ```
80
98
 
81
99
  Custom options can be passed to `tinymce` to override the global options specified in `config/tinymce.yml`:
82
100
 
83
- <%= tinymce :theme => "simple", :language => "de", :plugins => ["wordcount", "paste"] %>
101
+ ```erb
102
+ <%= tinymce :theme => "simple", :language => "de", :plugins => ["wordcount", "paste"] %>
103
+ ```
84
104
 
85
105
  Alternate configurations defined in 'config/tinymce.yml' can be used with:
86
106
 
87
- <%= tinymce :alternate %>
107
+ ```erb
108
+ <%= tinymce :alternate %>
109
+ ```
88
110
 
89
111
 
90
112
  Language Packs
@@ -98,13 +120,15 @@ Manual Initialization
98
120
 
99
121
  Using the `tinymce` helper and global configuration file is entirely optional. The `tinyMCE.init` function can be invoked manually if desired.
100
122
 
101
- <%= text_area_tag :editor, "", :rows => 40, :cols => 120 %>
123
+ ```erb
124
+ <%= text_area_tag :editor, "", :rows => 40, :cols => 120 %>
102
125
 
103
- <script type="text/javascript">
104
- tinyMCE.init({
105
- selector: 'textarea.editor'
106
- });
107
- </script>
126
+ <script type="text/javascript">
127
+ tinyMCE.init({
128
+ selector: 'textarea.editor'
129
+ });
130
+ </script>
131
+ ```
108
132
 
109
133
 
110
134
  Asset Compilation
@@ -114,7 +138,9 @@ If you are including TinyMCE via `application.js` or using the `tinymce_assets`
114
138
 
115
139
  However if you wish to include `tinymce-jquery.js` independently, you will need to add it to the precompile list in `config/environments/production.rb`:
116
140
 
117
- config.assets.precompile << "tinymce-jquery.js"
141
+ ```ruby
142
+ config.assets.precompile << "tinymce-jquery.js"
143
+ ```
118
144
 
119
145
 
120
146
  Custom Plugins & Skins
@@ -1,4 +1,4 @@
1
- // 4.0.19 (2014-03-11)
1
+ // 4.0.26 (2014-05-06)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -314,8 +314,16 @@ define("tinymce/html/Styles", [], function() {
314
314
 
315
315
  url = decode(url || url2 || url3);
316
316
 
317
- if (!settings.allow_script_urls && /(java|vb)script:/i.test(url.replace(/[\s\r\n]+/, ''))) {
318
- return "";
317
+ if (!settings.allow_script_urls) {
318
+ var scriptUrl = url.replace(/[\s\r\n]+/, '');
319
+
320
+ if (/(java|vb)script:/i.test(scriptUrl)) {
321
+ return "";
322
+ }
323
+
324
+ if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
325
+ return "";
326
+ }
319
327
  }
320
328
 
321
329
  // Convert the URL to relative/absolute depending on config
@@ -340,8 +348,16 @@ define("tinymce/html/Styles", [], function() {
340
348
  name = matches[1].replace(trimRightRegExp, '').toLowerCase();
341
349
  value = matches[2].replace(trimRightRegExp, '');
342
350
 
351
+ // Decode escaped sequences like \65 -> e
352
+ /*jshint loopfunc:true*/
353
+ /*eslint no-loop-func:0 */
354
+ value = value.replace(/\\[0-9a-f]+/g, function(e) {
355
+ return String.fromCharCode(parseInt(e.substr(1), 16));
356
+ });
357
+
343
358
  if (name && value.length > 0) {
344
- if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(/.test(value))) {
359
+ // Don't allow behavior name or expression/comments within the values
360
+ if (!settings.allow_script_urls && (name == "behavior" || /expression\s*\(|\/\*|\*\//.test(value))) {
345
361
  continue;
346
362
  }
347
363
 
@@ -840,10 +856,13 @@ define("tinymce/dom/EventUtils", [], function() {
840
856
  while (ci--) {
841
857
  if (callbackList[ci].func === callback) {
842
858
  var nativeHandler = callbackList.nativeHandler;
859
+ var fakeName = callbackList.fakeName, capture = callbackList.capture;
843
860
 
844
861
  // Clone callbackList since unbind inside a callback would otherwise break the handlers loop
845
862
  callbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
846
863
  callbackList.nativeHandler = nativeHandler;
864
+ callbackList.fakeName = fakeName;
865
+ callbackList.capture = capture;
847
866
 
848
867
  eventMap[name] = callbackList;
849
868
  }
@@ -2388,7 +2407,7 @@ define("tinymce/html/Entities", [
2388
2407
  var makeMap = Tools.makeMap;
2389
2408
 
2390
2409
  var namedEntities, baseEntities, reverseEntities,
2391
- attrsCharsRegExp = /[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
2410
+ attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
2392
2411
  textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
2393
2412
  rawCharsRegExp = /[<>&\"\']/g,
2394
2413
  entityRegExp = /&(#x|#)?([\w]+);/g,
@@ -2406,7 +2425,8 @@ define("tinymce/html/Entities", [
2406
2425
  "'": '&#39;',
2407
2426
  '<': '&lt;',
2408
2427
  '>': '&gt;',
2409
- '&': '&amp;'
2428
+ '&': '&amp;',
2429
+ '\u0060': '&#96;'
2410
2430
  };
2411
2431
 
2412
2432
  // Reverse lookup table for raw entities
@@ -3390,7 +3410,8 @@ define("tinymce/dom/DOMUtils", [
3390
3410
  return false;
3391
3411
  }
3392
3412
 
3393
- return Sizzle.matches(selector, elm.nodeType ? [elm] : elm).length > 0;
3413
+ var elms = elm.nodeType ? [elm] : elm;
3414
+ return Sizzle(selector, elms[0].ownerDocument || elms[0], null, elms).length > 0;
3394
3415
  },
3395
3416
 
3396
3417
  // #endif
@@ -4678,9 +4699,9 @@ define("tinymce/dom/DOMUtils", [
4678
4699
 
4679
4700
  // Keep elements with data-bookmark attributes or name attribute like <a name="1"></a>
4680
4701
  attributes = self.getAttribs(node);
4681
- i = node.attributes.length;
4702
+ i = attributes.length;
4682
4703
  while (i--) {
4683
- name = node.attributes[i].nodeName;
4704
+ name = attributes[i].nodeName;
4684
4705
  if (name === "name" || name === 'data-mce-bookmark') {
4685
4706
  return false;
4686
4707
  }
@@ -4938,7 +4959,7 @@ define("tinymce/dom/DOMUtils", [
4938
4959
  var contentEditable;
4939
4960
 
4940
4961
  // Check type
4941
- if (node.nodeType != 1) {
4962
+ if (!node || node.nodeType != 1) {
4942
4963
  return null;
4943
4964
  }
4944
4965
 
@@ -4952,6 +4973,20 @@ define("tinymce/dom/DOMUtils", [
4952
4973
  return node.contentEditable !== "inherit" ? node.contentEditable : null;
4953
4974
  },
4954
4975
 
4976
+ getContentEditableParent: function(node) {
4977
+ var root = this.getRoot(), state = null;
4978
+
4979
+ for (; node && node !== root; node = node.parentNode) {
4980
+ state = this.getContentEditable(node);
4981
+
4982
+ if (state !== null) {
4983
+ break;
4984
+ }
4985
+ }
4986
+
4987
+ return state;
4988
+ },
4989
+
4955
4990
  /**
4956
4991
  * Destroys all internal references to the DOM to solve IE leak issues.
4957
4992
  *
@@ -4981,6 +5016,18 @@ define("tinymce/dom/DOMUtils", [
4981
5016
  self.win = self.doc = self.root = self.events = self.frag = null;
4982
5017
  },
4983
5018
 
5019
+ isChildOf: function(node, parent) {
5020
+ while (node) {
5021
+ if (parent === node) {
5022
+ return true;
5023
+ }
5024
+
5025
+ node = node.parentNode;
5026
+ }
5027
+
5028
+ return false;
5029
+ },
5030
+
4984
5031
  // #ifdef debug
4985
5032
 
4986
5033
  dumpRng: function(r) {
@@ -5355,12 +5402,21 @@ define("tinymce/AddOnManager", [
5355
5402
  * @param {String} languages Optional comma or space separated list of languages to check if it matches the name.
5356
5403
  */
5357
5404
  requireLangPack: function(name, languages) {
5358
- if (AddOnManager.language && AddOnManager.languageLoad !== false) {
5359
- if (languages && new RegExp('([, ]|\\b)' + AddOnManager.language + '([, ]|\\b)').test(languages) === false) {
5360
- return;
5405
+ var language = AddOnManager.language;
5406
+
5407
+ if (language && AddOnManager.languageLoad !== false) {
5408
+ if (languages) {
5409
+ languages = ',' + languages + ',';
5410
+
5411
+ // Load short form sv.js or long form sv_SE.js
5412
+ if (languages.indexOf(',' + language.substr(0, 2) + ',') != -1) {
5413
+ language = language.substr(0, 2);
5414
+ } else if (languages.indexOf(',' + language + ',') == -1) {
5415
+ return;
5416
+ }
5361
5417
  }
5362
5418
 
5363
- ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
5419
+ ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + language + '.js');
5364
5420
  }
5365
5421
  },
5366
5422
 
@@ -6274,8 +6330,8 @@ define("tinymce/html/Schema", [
6274
6330
  add("mark rt rp summary bdi", "", phrasingContent);
6275
6331
  add("canvas", "width height", flowContent);
6276
6332
  add("video", "src crossorigin poster preload autoplay mediagroup loop " +
6277
- "muted controls width height", flowContent, "track source");
6278
- add("audio", "src crossorigin preload autoplay mediagroup loop muted controls", flowContent, "track source");
6333
+ "muted controls width height buffered", flowContent, "track source");
6334
+ add("audio", "src crossorigin preload autoplay mediagroup loop muted controls buffered volume", flowContent, "track source");
6279
6335
  add("source", "src type media");
6280
6336
  add("track", "kind src srclang label default");
6281
6337
  add("datalist", "", phrasingContent, "option");
@@ -6334,7 +6390,7 @@ define("tinymce/html/Schema", [
6334
6390
  addAttrs("input textarea", "placeholder");
6335
6391
  addAttrs("a", "download");
6336
6392
  addAttrs("link script img", "crossorigin");
6337
- addAttrs("iframe", "srcdoc sandbox seamless allowfullscreen");
6393
+ addAttrs("iframe", "sandbox seamless allowfullscreen"); // Excluded: srcdoc
6338
6394
  }
6339
6395
 
6340
6396
  // Special: iframe, ruby, video, audio, label
@@ -6393,7 +6449,7 @@ define("tinymce/html/Schema", [
6393
6449
  }
6394
6450
  } else {
6395
6451
  // Create custom map
6396
- value = makeMap(value, ',', makeMap(value.toUpperCase(), ' '));
6452
+ value = makeMap(value, /[, ]/, makeMap(value.toUpperCase(), /[, ]/));
6397
6453
  }
6398
6454
 
6399
6455
  return value;
@@ -6607,6 +6663,9 @@ define("tinymce/html/Schema", [
6607
6663
  var customElementRegExp = /^(~)?(.+)$/;
6608
6664
 
6609
6665
  if (custom_elements) {
6666
+ // Flush cached items since we are altering the default maps
6667
+ mapCache.text_block_elements = mapCache.block_elements = null;
6668
+
6610
6669
  each(split(custom_elements, ','), function(rule) {
6611
6670
  var matches = customElementRegExp.exec(rule),
6612
6671
  inline = matches[1] === '~',
@@ -6634,8 +6693,9 @@ define("tinymce/html/Schema", [
6634
6693
  }
6635
6694
 
6636
6695
  // Add custom elements at span/div positions
6637
- each(children, function(element) {
6696
+ each(children, function(element, elmName) {
6638
6697
  if (element[cloneName]) {
6698
+ children[elmName] = element = extend({}, children[elmName]);
6639
6699
  element[name] = element[cloneName];
6640
6700
  }
6641
6701
  });
@@ -6665,6 +6725,10 @@ define("tinymce/html/Schema", [
6665
6725
 
6666
6726
  each(split(matches[3], '|'), function(child) {
6667
6727
  if (prefix === '-') {
6728
+ // Clone the element before we delete
6729
+ // things in it to not mess up default schemas
6730
+ children[matches[2]] = parent = extend({}, children[matches[2]]);
6731
+
6668
6732
  delete parent[child];
6669
6733
  } else {
6670
6734
  parent[child] = {};
@@ -7083,8 +7147,8 @@ define("tinymce/html/SaxParser", [
7083
7147
  var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
7084
7148
  var attributesRequired, attributesDefault, attributesForced;
7085
7149
  var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
7086
- var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href');
7087
- var scriptUriRegExp = /(java|vb)script:/i;
7150
+ var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href,data,background,formaction,poster');
7151
+ var scriptUriRegExp = /((java|vb)script|mhtml):/i, dataUriRegExp = /^data:/i;
7088
7152
 
7089
7153
  function processEndTag(name) {
7090
7154
  var pos, i;
@@ -7150,22 +7214,24 @@ define("tinymce/html/SaxParser", [
7150
7214
  }
7151
7215
  }
7152
7216
 
7153
- // Block any javascript: urls
7217
+ // Block any javascript: urls or non image data uris
7154
7218
  if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
7155
7219
  var uri = value.replace(trimRegExp, '');
7156
7220
 
7157
7221
  try {
7158
7222
  // Might throw malformed URI sequence
7159
7223
  uri = decodeURIComponent(uri);
7160
- if (scriptUriRegExp.test(uri)) {
7161
- return;
7162
- }
7163
7224
  } catch (ex) {
7164
7225
  // Fallback to non UTF-8 decoder
7165
7226
  uri = unescape(uri);
7166
- if (scriptUriRegExp.test(uri)) {
7167
- return;
7168
- }
7227
+ }
7228
+
7229
+ if (scriptUriRegExp.test(uri)) {
7230
+ return;
7231
+ }
7232
+
7233
+ if (!settings.allow_html_data_urls && dataUriRegExp.test(uri) && !/^data:image\//i.test(uri)) {
7234
+ return;
7169
7235
  }
7170
7236
  }
7171
7237
 
@@ -8582,6 +8648,17 @@ define("tinymce/dom/Serializer", [
8582
8648
 
8583
8649
  htmlParser = new DomParser(settings, schema);
8584
8650
 
8651
+ // Convert tabindex back to elements when serializing contents
8652
+ htmlParser.addAttributeFilter('data-mce-tabindex', function(nodes, name) {
8653
+ var i = nodes.length, node;
8654
+
8655
+ while (i--) {
8656
+ node = nodes[i];
8657
+ node.attr('tabindex', node.attributes.map['data-mce-tabindex']);
8658
+ node.attr(name, null);
8659
+ }
8660
+ });
8661
+
8585
8662
  // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
8586
8663
  htmlParser.addAttributeFilter('src,href,style', function(nodes, name) {
8587
8664
  var i = nodes.length, node, value, internalName = 'data-mce-' + name;
@@ -9633,6 +9710,8 @@ define("tinymce/dom/ControlSelection", [
9633
9710
  function showResizeRect(targetElm, mouseDownHandleName, mouseDownEvent) {
9634
9711
  var position, targetWidth, targetHeight, e, rect, offsetParent = editor.getBody();
9635
9712
 
9713
+ unbindResizeHandleEvents();
9714
+
9636
9715
  // Get position and size of target
9637
9716
  position = dom.getPos(targetElm, offsetParent);
9638
9717
  selectedElmX = position.x;
@@ -9712,14 +9791,18 @@ define("tinymce/dom/ControlSelection", [
9712
9791
  if (Env.ie) {
9713
9792
  handleElm.contentEditable = false;
9714
9793
  }
9794
+ } else {
9795
+ dom.show(handleElm);
9796
+ }
9715
9797
 
9798
+ if (!handle.elm) {
9716
9799
  dom.bind(handleElm, 'mousedown', function(e) {
9717
9800
  e.stopImmediatePropagation();
9718
9801
  e.preventDefault();
9719
9802
  startDrag(e);
9720
9803
  });
9721
- } else {
9722
- dom.show(handleElm);
9804
+
9805
+ handle.elm = handleElm;
9723
9806
  }
9724
9807
 
9725
9808
  /*
@@ -9749,6 +9832,8 @@ define("tinymce/dom/ControlSelection", [
9749
9832
  function hideResizeRect() {
9750
9833
  var name, handleElm;
9751
9834
 
9835
+ unbindResizeHandleEvents();
9836
+
9752
9837
  if (selectedElm) {
9753
9838
  selectedElm.removeAttribute('data-mce-selected');
9754
9839
  }
@@ -9858,6 +9943,17 @@ define("tinymce/dom/ControlSelection", [
9858
9943
  detachEvent(selectedElm, 'resizestart', resizeNativeStart);
9859
9944
  }
9860
9945
 
9946
+ function unbindResizeHandleEvents() {
9947
+ for (var name in resizeHandles) {
9948
+ var handle = resizeHandles[name];
9949
+
9950
+ if (handle.elm) {
9951
+ dom.unbind(handle.elm);
9952
+ delete handle.elm;
9953
+ }
9954
+ }
9955
+ }
9956
+
9861
9957
  function disableGeckoResize() {
9862
9958
  try {
9863
9959
  // Disable object resizing on Gecko
@@ -9939,10 +10035,14 @@ define("tinymce/dom/ControlSelection", [
9939
10035
  }
9940
10036
  });
9941
10037
 
10038
+ editor.on('hide', hideResizeRect);
10039
+
9942
10040
  // Hide rect on focusout since it would float on top of windows otherwise
9943
10041
  //editor.on('focusout', hideResizeRect);
9944
10042
  });
9945
10043
 
10044
+ editor.on('remove', unbindResizeHandleEvents);
10045
+
9946
10046
  function destroy() {
9947
10047
  selectedElm = selectedElmGhost = null;
9948
10048
 
@@ -10219,7 +10319,7 @@ define("tinymce/dom/RangeUtils", [
10219
10319
  var normalized, collapsed;
10220
10320
 
10221
10321
  function normalizeEndPoint(start) {
10222
- var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
10322
+ var container, offset, walker, body = dom.getRoot(), node, nonEmptyElementsMap;
10223
10323
  var directionLeft, isAfterNode;
10224
10324
 
10225
10325
  function hasBrBeforeAfter(node, left) {
@@ -10256,6 +10356,11 @@ define("tinymce/dom/RangeUtils", [
10256
10356
  // Walk left until we hit a text node we can move to or a block/br/img
10257
10357
  walker = new TreeWalker(startNode, parentBlockContainer);
10258
10358
  while ((node = walker[left ? 'prev' : 'next']())) {
10359
+ // Break if we hit a non content editable node
10360
+ if (dom.getContentEditableParent(node) === "false") {
10361
+ return;
10362
+ }
10363
+
10259
10364
  // Found text node that has a length
10260
10365
  if (node.nodeType === 3 && node.nodeValue.length > 0) {
10261
10366
  container = node;
@@ -10302,7 +10407,6 @@ define("tinymce/dom/RangeUtils", [
10302
10407
  if (directionLeft) {
10303
10408
  node = container.childNodes[offset > 0 ? offset - 1 : 0];
10304
10409
  if (node) {
10305
- nodeName = node.nodeName.toLowerCase();
10306
10410
  if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
10307
10411
  return;
10308
10412
  }
@@ -11704,6 +11808,160 @@ define("tinymce/dom/Selection", [
11704
11808
  return Selection;
11705
11809
  });
11706
11810
 
11811
+ // Included from: js/tinymce/classes/fmt/Preview.js
11812
+
11813
+ /**
11814
+ * Preview.js
11815
+ *
11816
+ * Copyright, Moxiecode Systems AB
11817
+ * Released under LGPL License.
11818
+ *
11819
+ * License: http://www.tinymce.com/license
11820
+ * Contributing: http://www.tinymce.com/contributing
11821
+ */
11822
+
11823
+ /**
11824
+ * Internal class for generating previews styles for formats.
11825
+ *
11826
+ * Example:
11827
+ * Preview.getCssText(editor, 'bold');
11828
+ *
11829
+ * @class tinymce.fmt.Preview
11830
+ * @private
11831
+ */
11832
+ define("tinymce/fmt/Preview", [
11833
+ "tinymce/util/Tools"
11834
+ ], function(Tools) {
11835
+ var each = Tools.each;
11836
+
11837
+ function getCssText(editor, format) {
11838
+ var name, previewElm, dom = editor.dom;
11839
+ var previewCss = '', parentFontSize, previewStyles;
11840
+
11841
+ previewStyles = editor.settings.preview_styles;
11842
+
11843
+ // No preview forced
11844
+ if (previewStyles === false) {
11845
+ return '';
11846
+ }
11847
+
11848
+ // Default preview
11849
+ if (!previewStyles) {
11850
+ previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
11851
+ 'text-transform color background-color border border-radius outline text-shadow';
11852
+ }
11853
+
11854
+ // Removes any variables since these can't be previewed
11855
+ function removeVars(val) {
11856
+ return val.replace(/%(\w+)/g, '');
11857
+ }
11858
+
11859
+ // Create block/inline element to use for preview
11860
+ if (typeof(format) == "string") {
11861
+ format = editor.formatter.get(format);
11862
+ if (!format) {
11863
+ return;
11864
+ }
11865
+
11866
+ format = format[0];
11867
+ }
11868
+
11869
+ name = format.block || format.inline || 'span';
11870
+ previewElm = dom.create(name);
11871
+
11872
+ // Add format styles to preview element
11873
+ each(format.styles, function(value, name) {
11874
+ value = removeVars(value);
11875
+
11876
+ if (value) {
11877
+ dom.setStyle(previewElm, name, value);
11878
+ }
11879
+ });
11880
+
11881
+ // Add attributes to preview element
11882
+ each(format.attributes, function(value, name) {
11883
+ value = removeVars(value);
11884
+
11885
+ if (value) {
11886
+ dom.setAttrib(previewElm, name, value);
11887
+ }
11888
+ });
11889
+
11890
+ // Add classes to preview element
11891
+ each(format.classes, function(value) {
11892
+ value = removeVars(value);
11893
+
11894
+ if (!dom.hasClass(previewElm, value)) {
11895
+ dom.addClass(previewElm, value);
11896
+ }
11897
+ });
11898
+
11899
+ editor.fire('PreviewFormats');
11900
+
11901
+ // Add the previewElm outside the visual area
11902
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
11903
+ editor.getBody().appendChild(previewElm);
11904
+
11905
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
11906
+ parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
11907
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
11908
+
11909
+ each(previewStyles.split(' '), function(name) {
11910
+ var value = dom.getStyle(previewElm, name, true);
11911
+
11912
+ // If background is transparent then check if the body has a background color we can use
11913
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
11914
+ value = dom.getStyle(editor.getBody(), name, true);
11915
+
11916
+ // Ignore white since it's the default color, not the nicest fix
11917
+ // TODO: Fix this by detecting runtime style
11918
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
11919
+ return;
11920
+ }
11921
+ }
11922
+
11923
+ if (name == 'color') {
11924
+ // Ignore black since it's the default color, not the nicest fix
11925
+ // TODO: Fix this by detecting runtime style
11926
+ if (dom.toHex(value).toLowerCase() == '#000000') {
11927
+ return;
11928
+ }
11929
+ }
11930
+
11931
+ // Old IE won't calculate the font size so we need to do that manually
11932
+ if (name == 'font-size') {
11933
+ if (/em|%$/.test(value)) {
11934
+ if (parentFontSize === 0) {
11935
+ return;
11936
+ }
11937
+
11938
+ // Convert font size from em/% to px
11939
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
11940
+ value = (value * parentFontSize) + 'px';
11941
+ }
11942
+ }
11943
+
11944
+ if (name == "border" && value) {
11945
+ previewCss += 'padding:0 2px;';
11946
+ }
11947
+
11948
+ previewCss += name + ':' + value + ';';
11949
+ });
11950
+
11951
+ editor.fire('AfterPreviewFormats');
11952
+
11953
+ //previewCss += 'line-height:normal';
11954
+
11955
+ dom.remove(previewElm);
11956
+
11957
+ return previewCss;
11958
+ }
11959
+
11960
+ return {
11961
+ getCssText: getCssText
11962
+ };
11963
+ });
11964
+
11707
11965
  // Included from: js/tinymce/classes/Formatter.js
11708
11966
 
11709
11967
  /**
@@ -11733,8 +11991,9 @@ define("tinymce/dom/Selection", [
11733
11991
  define("tinymce/Formatter", [
11734
11992
  "tinymce/dom/TreeWalker",
11735
11993
  "tinymce/dom/RangeUtils",
11736
- "tinymce/util/Tools"
11737
- ], function(TreeWalker, RangeUtils, Tools) {
11994
+ "tinymce/util/Tools",
11995
+ "tinymce/fmt/Preview"
11996
+ ], function(TreeWalker, RangeUtils, Tools, Preview) {
11738
11997
  /**
11739
11998
  * Constructs a new formatter instance.
11740
11999
  *
@@ -11783,6 +12042,19 @@ define("tinymce/Formatter", [
11783
12042
 
11784
12043
  function defaultFormats() {
11785
12044
  register({
12045
+
12046
+ valigntop: [
12047
+ {selector: 'td,th', styles: {'verticalAlign': 'top'}}
12048
+ ],
12049
+
12050
+ valignmiddle: [
12051
+ {selector: 'td,th', styles: {'verticalAlign': 'middle'}}
12052
+ ],
12053
+
12054
+ valignbottom: [
12055
+ {selector: 'td,th', styles: {'verticalAlign': 'bottom'}}
12056
+ ],
12057
+
11786
12058
  alignleft: [
11787
12059
  {selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li', styles: {textAlign: 'left'}, defaultBlock: 'div'},
11788
12060
  {selector: 'img,table', collapsed: false, styles: {'float': 'left'}}
@@ -11997,6 +12269,16 @@ define("tinymce/Formatter", [
11997
12269
  dom.setStyle(elm, name, replaceVars(value, vars));
11998
12270
  });
11999
12271
 
12272
+ // Needed for the WebKit span spam bug
12273
+ // TODO: Remove this once WebKit/Blink fixes this
12274
+ if (fmt.styles) {
12275
+ var styleVal = dom.getAttrib(elm, 'style');
12276
+
12277
+ if (styleVal) {
12278
+ elm.setAttribute('data-mce-style', styleVal);
12279
+ }
12280
+ }
12281
+
12000
12282
  each(fmt.attributes, function(value, name) {
12001
12283
  dom.setAttrib(elm, name, replaceVars(value, vars));
12002
12284
  });
@@ -12899,6 +13181,20 @@ define("tinymce/Formatter", [
12899
13181
  return this;
12900
13182
  }
12901
13183
 
13184
+ /**
13185
+ * Returns a preview css text for the specified format.
13186
+ *
13187
+ * @method getCssText
13188
+ * @param {String/Object} format Format to generate preview css text for.
13189
+ * @return {String} Css text for the specified format.
13190
+ * @example
13191
+ * var cssText1 = editor.formatter.getCssText('bold');
13192
+ * var cssText2 = editor.formatter.getCssText({inline: 'b'});
13193
+ */
13194
+ function getCssText(format) {
13195
+ return Preview.getCssText(ed, format);
13196
+ }
13197
+
12902
13198
  // Expose to public
12903
13199
  extend(this, {
12904
13200
  get: get,
@@ -12910,7 +13206,8 @@ define("tinymce/Formatter", [
12910
13206
  matchAll: matchAll,
12911
13207
  matchNode: matchNode,
12912
13208
  canApply: canApply,
12913
- formatChanged: formatChanged
13209
+ formatChanged: formatChanged,
13210
+ getCssText: getCssText
12914
13211
  });
12915
13212
 
12916
13213
  // Initialize
@@ -14163,7 +14460,7 @@ define("tinymce/UndoManager", [
14163
14460
  ].join('|'), 'gi');
14164
14461
 
14165
14462
  return function(editor) {
14166
- var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, lock;
14463
+ var self = this, index = 0, data = [], beforeBookmark, isFirstTypedCharacter, locks = 0;
14167
14464
 
14168
14465
  // Returns a trimmed version of the current editor contents
14169
14466
  function getContent() {
@@ -14203,7 +14500,7 @@ define("tinymce/UndoManager", [
14203
14500
  });
14204
14501
 
14205
14502
  editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
14206
- editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
14503
+ editor.on('DragEnd', addNonTypingUndoLevel);
14207
14504
 
14208
14505
  editor.on('KeyUp', function(e) {
14209
14506
  var keyCode = e.keyCode;
@@ -14291,7 +14588,7 @@ define("tinymce/UndoManager", [
14291
14588
  * @method beforeChange
14292
14589
  */
14293
14590
  beforeChange: function() {
14294
- if (!lock) {
14591
+ if (!locks) {
14295
14592
  beforeBookmark = editor.selection.getBookmark(2, true);
14296
14593
  }
14297
14594
  },
@@ -14310,16 +14607,16 @@ define("tinymce/UndoManager", [
14310
14607
  level = level || {};
14311
14608
  level.content = getContent();
14312
14609
 
14313
- if (lock || editor.removed) {
14610
+ if (locks || editor.removed) {
14314
14611
  return null;
14315
14612
  }
14316
14613
 
14317
- if (editor.fire('BeforeAddUndo', {level: level, originalEvent: event}).isDefaultPrevented()) {
14614
+ lastLevel = data[index];
14615
+ if (editor.fire('BeforeAddUndo', {level: level, lastLevel: lastLevel, originalEvent: event}).isDefaultPrevented()) {
14318
14616
  return null;
14319
14617
  }
14320
14618
 
14321
14619
  // Add undo level if needed
14322
- lastLevel = data[index];
14323
14620
  if (lastLevel && lastLevel.content == level.content) {
14324
14621
  return null;
14325
14622
  }
@@ -14461,9 +14758,12 @@ define("tinymce/UndoManager", [
14461
14758
  transact: function(callback) {
14462
14759
  self.beforeChange();
14463
14760
 
14464
- lock = true;
14465
- callback();
14466
- lock = false;
14761
+ try {
14762
+ locks++;
14763
+ callback();
14764
+ } finally {
14765
+ locks--;
14766
+ }
14467
14767
 
14468
14768
  self.add();
14469
14769
  }
@@ -16024,7 +16324,13 @@ define("tinymce/EditorCommands", [
16024
16324
  define("tinymce/util/URI", [
16025
16325
  "tinymce/util/Tools"
16026
16326
  ], function(Tools) {
16027
- var each = Tools.each, trim = Tools.trim;
16327
+ var each = Tools.each, trim = Tools.trim,
16328
+ DEFAULT_PORTS = {
16329
+ 'ftp': 21,
16330
+ 'http': 80,
16331
+ 'https': 443,
16332
+ 'mailto': 25
16333
+ };
16028
16334
 
16029
16335
  /**
16030
16336
  * Constructs a new URI instance.
@@ -16196,7 +16502,31 @@ define("tinymce/util/URI", [
16196
16502
  toAbsolute: function(uri, noHost) {
16197
16503
  uri = new URI(uri, {base_uri: this});
16198
16504
 
16199
- return uri.getURI(this.host == uri.host && this.protocol == uri.protocol ? noHost : 0);
16505
+ return uri.getURI(noHost && this.isSameOrigin(uri));
16506
+ },
16507
+
16508
+ /**
16509
+ * Determine whether the given URI has the same origin as this URI. Based on RFC-6454.
16510
+ * Supports default ports for protocols listed in DEFAULT_PORTS. Unsupported protocols will fail safe: they
16511
+ * won't match, if the port specifications differ.
16512
+ *
16513
+ * @method isSameOrigin
16514
+ * @param {tinymce.util.URI} uri Uri instance to compare.
16515
+ * @returns {Boolean} True if the origins are the same.
16516
+ */
16517
+ isSameOrigin: function(uri) {
16518
+ if (this.host == uri.host && this.protocol == uri.protocol){
16519
+ if (this.port == uri.port) {
16520
+ return true;
16521
+ }
16522
+
16523
+ var defaultPort = DEFAULT_PORTS[this.protocol];
16524
+ if (defaultPort && ((this.port || defaultPort) == (uri.port || defaultPort))) {
16525
+ return true;
16526
+ }
16527
+ }
16528
+
16529
+ return false;
16200
16530
  },
16201
16531
 
16202
16532
  /**
@@ -16454,6 +16784,8 @@ define("tinymce/util/Class", [
16454
16784
  // Instantiate a base class (but only create the instance,
16455
16785
  // don't run the init constructor)
16456
16786
  initializing = true;
16787
+
16788
+ /*eslint new-cap:0 */
16457
16789
  prototype = new self();
16458
16790
  initializing = false;
16459
16791
 
@@ -16540,10 +16872,10 @@ define("tinymce/util/Class", [
16540
16872
  return Class;
16541
16873
  });
16542
16874
 
16543
- // Included from: js/tinymce/classes/ui/Selector.js
16875
+ // Included from: js/tinymce/classes/util/EventDispatcher.js
16544
16876
 
16545
16877
  /**
16546
- * Selector.js
16878
+ * EventDispatcher.js
16547
16879
  *
16548
16880
  * Copyright, Moxiecode Systems AB
16549
16881
  * Released under LGPL License.
@@ -16552,75 +16884,338 @@ define("tinymce/util/Class", [
16552
16884
  * Contributing: http://www.tinymce.com/contributing
16553
16885
  */
16554
16886
 
16555
- /*eslint no-nested-ternary:0 */
16556
-
16557
16887
  /**
16558
- * Selector engine, enables you to select controls by using CSS like expressions.
16559
- * We currently only support basic CSS expressions to reduce the size of the core
16560
- * and the ones we support should be enough for most cases.
16888
+ * This class lets you add/remove and fire events by name on the specified scope. This makes
16889
+ * it easy to add event listener logic to any class.
16561
16890
  *
16891
+ * @class tinymce.util.EventDispatcher
16562
16892
  * @example
16563
- * Supported expressions:
16564
- * element
16565
- * element#name
16566
- * element.class
16567
- * element[attr]
16568
- * element[attr*=value]
16569
- * element[attr~=value]
16570
- * element[attr!=value]
16571
- * element[attr^=value]
16572
- * element[attr$=value]
16573
- * element:<state>
16574
- * element:not(<expression>)
16575
- * element:first
16576
- * element:last
16577
- * element:odd
16578
- * element:even
16579
- * element element
16580
- * element > element
16893
+ * var eventDispatcher = new EventDispatcher();
16581
16894
  *
16582
- * @class tinymce.ui.Selector
16895
+ * eventDispatcher.on('click', function() {console.log('data');});
16896
+ * eventDispatcher.fire('click', {data: 123});
16583
16897
  */
16584
- define("tinymce/ui/Selector", [
16585
- "tinymce/util/Class"
16586
- ], function(Class) {
16587
- "use strict";
16588
-
16589
- /**
16590
- * Produces an array with a unique set of objects. It will not compare the values
16591
- * but the references of the objects.
16592
- *
16593
- * @private
16594
- * @method unqiue
16595
- * @param {Array} array Array to make into an array with unique items.
16596
- * @return {Array} Array with unique items.
16597
- */
16598
- function unique(array) {
16599
- var uniqueItems = [], i = array.length, item;
16898
+ define("tinymce/util/EventDispatcher", [
16899
+ "tinymce/util/Tools"
16900
+ ], function(Tools) {
16901
+ var nativeEvents = Tools.makeMap(
16902
+ "focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange " +
16903
+ "mouseout mouseenter mouseleave wheel keydown keypress keyup input contextmenu dragstart dragend dragover " +
16904
+ "draggesture dragdrop drop drag submit",
16905
+ ' '
16906
+ );
16600
16907
 
16601
- while (i--) {
16602
- item = array[i];
16908
+ function Dispatcher(settings) {
16909
+ var self = this, scope, bindings = {}, toggleEvent;
16603
16910
 
16604
- if (!item.__checked) {
16605
- uniqueItems.push(item);
16606
- item.__checked = 1;
16607
- }
16911
+ function returnFalse() {
16912
+ return false;
16608
16913
  }
16609
16914
 
16610
- i = uniqueItems.length;
16611
- while (i--) {
16612
- delete uniqueItems[i].__checked;
16915
+ function returnTrue() {
16916
+ return true;
16613
16917
  }
16614
16918
 
16615
- return uniqueItems;
16616
- }
16617
-
16618
- var expression = /^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i;
16919
+ settings = settings || {};
16920
+ scope = settings.scope || self;
16921
+ toggleEvent = settings.toggleEvent || returnFalse;
16619
16922
 
16620
- /*jshint maxlen:255 */
16621
- /*eslint max-len:0 */
16622
- var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
16623
- whiteSpace = /^\s*|\s*$/g,
16923
+ /**
16924
+ * Fires the specified event by name.
16925
+ *
16926
+ * @method fire
16927
+ * @param {String} name Name of the event to fire.
16928
+ * @param {Object?} args Event arguments.
16929
+ * @return {Object} Event args instance passed in.
16930
+ * @example
16931
+ * instance.fire('event', {...});
16932
+ */
16933
+ function fire(name, args) {
16934
+ var handlers, i, l, callback;
16935
+
16936
+ name = name.toLowerCase();
16937
+ args = args || {};
16938
+ args.type = name;
16939
+
16940
+ // Setup target is there isn't one
16941
+ if (!args.target) {
16942
+ args.target = scope;
16943
+ }
16944
+
16945
+ // Add event delegation methods if they are missing
16946
+ if (!args.preventDefault) {
16947
+ // Add preventDefault method
16948
+ args.preventDefault = function() {
16949
+ args.isDefaultPrevented = returnTrue;
16950
+ };
16951
+
16952
+ // Add stopPropagation
16953
+ args.stopPropagation = function() {
16954
+ args.isPropagationStopped = returnTrue;
16955
+ };
16956
+
16957
+ // Add stopImmediatePropagation
16958
+ args.stopImmediatePropagation = function() {
16959
+ args.isImmediatePropagationStopped = returnTrue;
16960
+ };
16961
+
16962
+ // Add event delegation states
16963
+ args.isDefaultPrevented = returnFalse;
16964
+ args.isPropagationStopped = returnFalse;
16965
+ args.isImmediatePropagationStopped = returnFalse;
16966
+ }
16967
+
16968
+ if (settings.beforeFire) {
16969
+ settings.beforeFire(args);
16970
+ }
16971
+
16972
+ handlers = bindings[name];
16973
+ if (handlers) {
16974
+ for (i = 0, l = handlers.length; i < l; i++) {
16975
+ handlers[i] = callback = handlers[i];
16976
+
16977
+ // Stop immediate propagation if needed
16978
+ if (args.isImmediatePropagationStopped()) {
16979
+ args.stopPropagation();
16980
+ return args;
16981
+ }
16982
+
16983
+ // If callback returns false then prevent default and stop all propagation
16984
+ if (callback.call(scope, args) === false) {
16985
+ args.preventDefault();
16986
+ return args;
16987
+ }
16988
+ }
16989
+ }
16990
+
16991
+ return args;
16992
+ }
16993
+
16994
+ /**
16995
+ * Binds an event listener to a specific event by name.
16996
+ *
16997
+ * @method on
16998
+ * @param {String} name Event name or space separated list of events to bind.
16999
+ * @param {callback} callback Callback to be executed when the event occurs.
17000
+ * @param {Boolean} first Optional flag if the event should be prepended. Use this with care.
17001
+ * @return {Object} Current class instance.
17002
+ * @example
17003
+ * instance.on('event', function(e) {
17004
+ * // Callback logic
17005
+ * });
17006
+ */
17007
+ function on(name, callback, prepend) {
17008
+ var handlers, names, i;
17009
+
17010
+ if (callback === false) {
17011
+ callback = returnFalse;
17012
+ }
17013
+
17014
+ if (callback) {
17015
+ names = name.toLowerCase().split(' ');
17016
+ i = names.length;
17017
+ while (i--) {
17018
+ name = names[i];
17019
+ handlers = bindings[name];
17020
+ if (!handlers) {
17021
+ handlers = bindings[name] = [];
17022
+ toggleEvent(name, true);
17023
+ }
17024
+
17025
+ if (prepend) {
17026
+ handlers.unshift(callback);
17027
+ } else {
17028
+ handlers.push(callback);
17029
+ }
17030
+ }
17031
+ }
17032
+
17033
+ return self;
17034
+ }
17035
+
17036
+ /**
17037
+ * Unbinds an event listener to a specific event by name.
17038
+ *
17039
+ * @method off
17040
+ * @param {String?} name Name of the event to unbind.
17041
+ * @param {callback?} callback Callback to unbind.
17042
+ * @return {Object} Current class instance.
17043
+ * @example
17044
+ * // Unbind specific callback
17045
+ * instance.off('event', handler);
17046
+ *
17047
+ * // Unbind all listeners by name
17048
+ * instance.off('event');
17049
+ *
17050
+ * // Unbind all events
17051
+ * instance.off();
17052
+ */
17053
+ function off(name, callback) {
17054
+ var i, handlers, bindingName, names, hi;
17055
+
17056
+ if (name) {
17057
+ names = name.toLowerCase().split(' ');
17058
+ i = names.length;
17059
+ while (i--) {
17060
+ name = names[i];
17061
+ handlers = bindings[name];
17062
+
17063
+ // Unbind all handlers
17064
+ if (!name) {
17065
+ for (bindingName in bindings) {
17066
+ toggleEvent(bindingName, false);
17067
+ delete bindings[bindingName];
17068
+ }
17069
+
17070
+ return self;
17071
+ }
17072
+
17073
+ if (handlers) {
17074
+ // Unbind all by name
17075
+ if (!callback) {
17076
+ handlers.length = 0;
17077
+ } else {
17078
+ // Unbind specific ones
17079
+ hi = handlers.length;
17080
+ while (hi--) {
17081
+ if (handlers[hi] === callback) {
17082
+ handlers.splice(hi, 1);
17083
+ }
17084
+ }
17085
+ }
17086
+
17087
+ if (!handlers.length) {
17088
+ toggleEvent(name, false);
17089
+ delete bindings[name];
17090
+ }
17091
+ }
17092
+ }
17093
+ } else {
17094
+ for (name in bindings) {
17095
+ toggleEvent(name, false);
17096
+ }
17097
+
17098
+ bindings = {};
17099
+ }
17100
+
17101
+ return self;
17102
+ }
17103
+
17104
+ /**
17105
+ * Returns true/false if the dispatcher has a event of the specified name.
17106
+ *
17107
+ * @method has
17108
+ * @param {String} name Name of the event to check for.
17109
+ * @return {Boolean} true/false if the event exists or not.
17110
+ */
17111
+ function has(name) {
17112
+ name = name.toLowerCase();
17113
+ return !(!bindings[name] || bindings[name].length === 0);
17114
+ }
17115
+
17116
+ // Expose
17117
+ self.fire = fire;
17118
+ self.on = on;
17119
+ self.off = off;
17120
+ self.has = has;
17121
+ }
17122
+
17123
+ /**
17124
+ * Returns true/false if the specified event name is a native browser event or not.
17125
+ *
17126
+ * @method isNative
17127
+ * @param {String} name Name to check if it's native.
17128
+ * @return {Boolean} true/false if the event is native or not.
17129
+ * @static
17130
+ */
17131
+ Dispatcher.isNative = function(name) {
17132
+ return !!nativeEvents[name.toLowerCase()];
17133
+ };
17134
+
17135
+ return Dispatcher;
17136
+ });
17137
+
17138
+ // Included from: js/tinymce/classes/ui/Selector.js
17139
+
17140
+ /**
17141
+ * Selector.js
17142
+ *
17143
+ * Copyright, Moxiecode Systems AB
17144
+ * Released under LGPL License.
17145
+ *
17146
+ * License: http://www.tinymce.com/license
17147
+ * Contributing: http://www.tinymce.com/contributing
17148
+ */
17149
+
17150
+ /*eslint no-nested-ternary:0 */
17151
+
17152
+ /**
17153
+ * Selector engine, enables you to select controls by using CSS like expressions.
17154
+ * We currently only support basic CSS expressions to reduce the size of the core
17155
+ * and the ones we support should be enough for most cases.
17156
+ *
17157
+ * @example
17158
+ * Supported expressions:
17159
+ * element
17160
+ * element#name
17161
+ * element.class
17162
+ * element[attr]
17163
+ * element[attr*=value]
17164
+ * element[attr~=value]
17165
+ * element[attr!=value]
17166
+ * element[attr^=value]
17167
+ * element[attr$=value]
17168
+ * element:<state>
17169
+ * element:not(<expression>)
17170
+ * element:first
17171
+ * element:last
17172
+ * element:odd
17173
+ * element:even
17174
+ * element element
17175
+ * element > element
17176
+ *
17177
+ * @class tinymce.ui.Selector
17178
+ */
17179
+ define("tinymce/ui/Selector", [
17180
+ "tinymce/util/Class"
17181
+ ], function(Class) {
17182
+ "use strict";
17183
+
17184
+ /**
17185
+ * Produces an array with a unique set of objects. It will not compare the values
17186
+ * but the references of the objects.
17187
+ *
17188
+ * @private
17189
+ * @method unqiue
17190
+ * @param {Array} array Array to make into an array with unique items.
17191
+ * @return {Array} Array with unique items.
17192
+ */
17193
+ function unique(array) {
17194
+ var uniqueItems = [], i = array.length, item;
17195
+
17196
+ while (i--) {
17197
+ item = array[i];
17198
+
17199
+ if (!item.__checked) {
17200
+ uniqueItems.push(item);
17201
+ item.__checked = 1;
17202
+ }
17203
+ }
17204
+
17205
+ i = uniqueItems.length;
17206
+ while (i--) {
17207
+ delete uniqueItems[i].__checked;
17208
+ }
17209
+
17210
+ return uniqueItems;
17211
+ }
17212
+
17213
+ var expression = /^([\w\\*]+)?(?:#([\w\\]+))?(?:\.([\w\\\.]+))?(?:\[\@?([\w\\]+)([\^\$\*!~]?=)([\w\\]+)\])?(?:\:(.+))?/i;
17214
+
17215
+ /*jshint maxlen:255 */
17216
+ /*eslint max-len:0 */
17217
+ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
17218
+ whiteSpace = /^\s*|\s*$/g,
16624
17219
  Collection;
16625
17220
 
16626
17221
  var Selector = Class.extend({
@@ -17466,21 +18061,44 @@ define("tinymce/ui/DomUtils", [
17466
18061
  define("tinymce/ui/Control", [
17467
18062
  "tinymce/util/Class",
17468
18063
  "tinymce/util/Tools",
18064
+ "tinymce/util/EventDispatcher",
17469
18065
  "tinymce/ui/Collection",
17470
18066
  "tinymce/ui/DomUtils"
17471
- ], function(Class, Tools, Collection, DomUtils) {
18067
+ ], function(Class, Tools, EventDispatcher, Collection, DomUtils) {
17472
18068
  "use strict";
17473
18069
 
17474
- var nativeEvents = Tools.makeMap("focusin focusout scroll click dblclick mousedown mouseup mousemove mouseover" +
17475
- " mouseout mouseenter mouseleave wheel keydown keypress keyup contextmenu", " ");
17476
-
17477
18070
  var elementIdCache = {};
17478
18071
  var hasMouseWheelEventSupport = "onmousewheel" in document;
17479
18072
  var hasWheelEventSupport = false;
18073
+ var classPrefix = "mce-";
18074
+
18075
+ function getEventDispatcher(obj) {
18076
+ if (!obj._eventDispatcher) {
18077
+ obj._eventDispatcher = new EventDispatcher({
18078
+ scope: obj,
18079
+ toggleEvent: function(name, state) {
18080
+ if (state && EventDispatcher.isNative(name)) {
18081
+ if (!obj._nativeEvents) {
18082
+ obj._nativeEvents = {};
18083
+ }
18084
+
18085
+ obj._nativeEvents[name] = true;
18086
+
18087
+ if (obj._rendered) {
18088
+ obj.bindPendingEvents();
18089
+ }
18090
+ }
18091
+ }
18092
+ });
18093
+ }
18094
+
18095
+ return obj._eventDispatcher;
18096
+ }
17480
18097
 
17481
18098
  var Control = Class.extend({
17482
18099
  Statics: {
17483
- elementIdCache: elementIdCache
18100
+ elementIdCache: elementIdCache,
18101
+ classPrefix: classPrefix
17484
18102
  },
17485
18103
 
17486
18104
  isRtl: function() {
@@ -17493,7 +18111,7 @@ define("tinymce/ui/Control", [
17493
18111
  * @final
17494
18112
  * @field {String} classPrefix
17495
18113
  */
17496
- classPrefix: "mce-",
18114
+ classPrefix: classPrefix,
17497
18115
 
17498
18116
  /**
17499
18117
  * Constructs a new control instance with the specified settings.
@@ -17950,14 +18568,18 @@ define("tinymce/ui/Control", [
17950
18568
  * @return {tinymce.ui.Control} Current control object.
17951
18569
  */
17952
18570
  on: function(name, callback) {
17953
- var self = this, bindings, handlers, names, i;
18571
+ var self = this;
17954
18572
 
17955
18573
  function resolveCallbackName(name) {
17956
18574
  var callback, scope;
17957
18575
 
18576
+ if (typeof(name) != 'string') {
18577
+ return name;
18578
+ }
18579
+
17958
18580
  return function(e) {
17959
18581
  if (!callback) {
17960
- self.parents().each(function(ctrl) {
18582
+ self.parentsAndSelf().each(function(ctrl) {
17961
18583
  var callbacks = ctrl.settings.callbacks;
17962
18584
 
17963
18585
  if (callbacks && (callback = callbacks[name])) {
@@ -17971,41 +18593,7 @@ define("tinymce/ui/Control", [
17971
18593
  };
17972
18594
  }
17973
18595
 
17974
- if (callback) {
17975
- if (typeof(callback) == 'string') {
17976
- callback = resolveCallbackName(callback);
17977
- }
17978
-
17979
- names = name.toLowerCase().split(' ');
17980
- i = names.length;
17981
- while (i--) {
17982
- name = names[i];
17983
-
17984
- bindings = self._bindings;
17985
- if (!bindings) {
17986
- bindings = self._bindings = {};
17987
- }
17988
-
17989
- handlers = bindings[name];
17990
- if (!handlers) {
17991
- handlers = bindings[name] = [];
17992
- }
17993
-
17994
- handlers.push(callback);
17995
-
17996
- if (nativeEvents[name]) {
17997
- if (!self._nativeEvents) {
17998
- self._nativeEvents = {name: true};
17999
- } else {
18000
- self._nativeEvents[name] = true;
18001
- }
18002
-
18003
- if (self._rendered) {
18004
- self.bindPendingEvents();
18005
- }
18006
- }
18007
- }
18008
- }
18596
+ getEventDispatcher(self).on(name, resolveCallbackName(callback));
18009
18597
 
18010
18598
  return self;
18011
18599
  },
@@ -18021,46 +18609,8 @@ define("tinymce/ui/Control", [
18021
18609
  * @return {mxex.ui.Control} Current control object.
18022
18610
  */
18023
18611
  off: function(name, callback) {
18024
- var self = this, i, bindings = self._bindings, handlers, bindingName, names, hi;
18025
-
18026
- if (bindings) {
18027
- if (name) {
18028
- names = name.toLowerCase().split(' ');
18029
- i = names.length;
18030
- while (i--) {
18031
- name = names[i];
18032
- handlers = bindings[name];
18033
-
18034
- // Unbind all handlers
18035
- if (!name) {
18036
- for (bindingName in bindings) {
18037
- bindings[bindingName].length = 0;
18038
- }
18039
-
18040
- return self;
18041
- }
18042
-
18043
- if (handlers) {
18044
- // Unbind all by name
18045
- if (!callback) {
18046
- handlers.length = 0;
18047
- } else {
18048
- // Unbind specific ones
18049
- hi = handlers.length;
18050
- while (hi--) {
18051
- if (handlers[hi] === callback) {
18052
- handlers.splice(hi, 1);
18053
- }
18054
- }
18055
- }
18056
- }
18057
- }
18058
- } else {
18059
- self._bindings = [];
18060
- }
18061
- }
18062
-
18063
- return self;
18612
+ getEventDispatcher(this).off(name, callback);
18613
+ return this;
18064
18614
  },
18065
18615
 
18066
18616
  /**
@@ -18074,75 +18624,22 @@ define("tinymce/ui/Control", [
18074
18624
  * @return {Object} Current arguments object.
18075
18625
  */
18076
18626
  fire: function(name, args, bubble) {
18077
- var self = this, i, l, handlers, parentCtrl;
18078
-
18079
- name = name.toLowerCase();
18080
-
18081
- // Dummy function that gets replaced on the delegation state functions
18082
- function returnFalse() {
18083
- return false;
18084
- }
18085
-
18086
- // Dummy function that gets replaced on the delegation state functions
18087
- function returnTrue() {
18088
- return true;
18089
- }
18627
+ var self = this;
18090
18628
 
18091
- // Setup empty object if args is omited
18092
18629
  args = args || {};
18093
18630
 
18094
- // Stick type into event object
18095
- if (!args.type) {
18096
- args.type = name;
18097
- }
18098
-
18099
- // Stick control into event
18100
18631
  if (!args.control) {
18101
18632
  args.control = self;
18102
18633
  }
18103
18634
 
18104
- // Add event delegation methods if they are missing
18105
- if (!args.preventDefault) {
18106
- // Add preventDefault method
18107
- args.preventDefault = function() {
18108
- args.isDefaultPrevented = returnTrue;
18109
- };
18110
-
18111
- // Add stopPropagation
18112
- args.stopPropagation = function() {
18113
- args.isPropagationStopped = returnTrue;
18114
- };
18115
-
18116
- // Add stopImmediatePropagation
18117
- args.stopImmediatePropagation = function() {
18118
- args.isImmediatePropagationStopped = returnTrue;
18119
- };
18120
-
18121
- // Add event delegation states
18122
- args.isDefaultPrevented = returnFalse;
18123
- args.isPropagationStopped = returnFalse;
18124
- args.isImmediatePropagationStopped = returnFalse;
18125
- }
18126
-
18127
- if (self._bindings) {
18128
- handlers = self._bindings[name];
18129
-
18130
- if (handlers) {
18131
- for (i = 0, l = handlers.length; i < l; i++) {
18132
- // Execute callback and break if the callback returns a false
18133
- if (!args.isImmediatePropagationStopped() && handlers[i].call(self, args) === false) {
18134
- break;
18135
- }
18136
- }
18137
- }
18138
- }
18635
+ args = getEventDispatcher(self).fire(name, args);
18139
18636
 
18140
- // Bubble event up to parent controls
18141
- if (bubble !== false) {
18142
- parentCtrl = self.parent();
18143
- while (parentCtrl && !args.isPropagationStopped()) {
18144
- parentCtrl.fire(name, args, false);
18145
- parentCtrl = parentCtrl.parent();
18637
+ // Bubble event up to parents
18638
+ if (bubble !== false && self.parent) {
18639
+ var parent = self.parent();
18640
+ while (parent && !args.isPropagationStopped()) {
18641
+ parent.fire(name, args, false);
18642
+ parent = parent.parent();
18146
18643
  }
18147
18644
  }
18148
18645
 
@@ -18157,7 +18654,7 @@ define("tinymce/ui/Control", [
18157
18654
  * @return {Boolean} True/false state if the event has listeners.
18158
18655
  */
18159
18656
  hasEventListeners: function(name) {
18160
- return name in this._bindings;
18657
+ return getEventDispatcher(this).has(name);
18161
18658
  },
18162
18659
 
18163
18660
  /**
@@ -18183,6 +18680,17 @@ define("tinymce/ui/Control", [
18183
18680
  return parents;
18184
18681
  },
18185
18682
 
18683
+ /**
18684
+ * Returns the current control and it's parents.
18685
+ *
18686
+ * @method parentsAndSelf
18687
+ * @param {String} selector Optional selector expression to find parents.
18688
+ * @return {tinymce.ui.Collection} Collection with all parent controls.
18689
+ */
18690
+ parentsAndSelf: function(selector) {
18691
+ return new Collection(this).add(this.parents(selector));
18692
+ },
18693
+
18186
18694
  /**
18187
18695
  * Returns the control next to the current control.
18188
18696
  *
@@ -18499,8 +19007,8 @@ define("tinymce/ui/Control", [
18499
19007
  * @return {String} Encoded and possible traslated string.
18500
19008
  */
18501
19009
  encode: function(text, translate) {
18502
- if (translate !== false && Control.translate) {
18503
- text = Control.translate(text);
19010
+ if (translate !== false) {
19011
+ text = this.translate(text);
18504
19012
  }
18505
19013
 
18506
19014
  return (text || '').replace(/[&<>"]/g, function(match) {
@@ -18508,6 +19016,17 @@ define("tinymce/ui/Control", [
18508
19016
  });
18509
19017
  },
18510
19018
 
19019
+ /**
19020
+ * Returns the translated string.
19021
+ *
19022
+ * @method translate
19023
+ * @param {String} text Text to translate.
19024
+ * @return {String} Translated string or the same as the input.
19025
+ */
19026
+ translate: function(text) {
19027
+ return Control.translate ? Control.translate(text) : text;
19028
+ },
19029
+
18511
19030
  /**
18512
19031
  * Adds items before the current control.
18513
19032
  *
@@ -18851,6 +19370,11 @@ define("tinymce/ui/Control", [
18851
19370
  parents[i]._eventsRoot = eventRootCtrl;
18852
19371
  }
18853
19372
 
19373
+ var eventRootDelegates = eventRootCtrl._delegates;
19374
+ if (!eventRootDelegates) {
19375
+ eventRootDelegates = eventRootCtrl._delegates = {};
19376
+ }
19377
+
18854
19378
  // Bind native event delegates
18855
19379
  for (name in nativeEvents) {
18856
19380
  if (!nativeEvents) {
@@ -18875,9 +19399,9 @@ define("tinymce/ui/Control", [
18875
19399
  DomUtils.on(eventRootCtrl.getEl(), "mouseover", mouseEnterHandler);
18876
19400
  eventRootCtrl._hasMouseEnter = 1;
18877
19401
  }
18878
- } else if (!eventRootCtrl[name]) {
19402
+ } else if (!eventRootDelegates[name]) {
18879
19403
  DomUtils.on(eventRootCtrl.getEl(), name, delegate);
18880
- eventRootCtrl[name] = true;
19404
+ eventRootDelegates[name] = true;
18881
19405
  }
18882
19406
 
18883
19407
  // Remove the event once it's bound
@@ -19201,9 +19725,11 @@ define("tinymce/ui/KeyboardNavigation", [
19201
19725
  * @return {Boolean} True/false if the element is a text element or not.
19202
19726
  */
19203
19727
  function isTextInputElement(elm) {
19728
+ var tagName = elm.tagName.toUpperCase();
19729
+
19204
19730
  // Notice: since type can be "email" etc we don't check the type
19205
19731
  // So all input elements gets treated as text input elements
19206
- return elm.tagName == "INPUT" || elm.tagName == "TEXTAREA";
19732
+ return tagName == "INPUT" || tagName == "TEXTAREA";
19207
19733
  }
19208
19734
 
19209
19735
  /**
@@ -19445,7 +19971,7 @@ define("tinymce/ui/KeyboardNavigation", [
19445
19971
  }
19446
19972
 
19447
19973
  root.on('keydown', function(e) {
19448
- function handleNonTabEvent(e, handler) {
19974
+ function handleNonTabOrEscEvent(e, handler) {
19449
19975
  // Ignore non tab keys for text elements
19450
19976
  if (isTextInputElement(focusedElement)) {
19451
19977
  return;
@@ -19462,29 +19988,29 @@ define("tinymce/ui/KeyboardNavigation", [
19462
19988
 
19463
19989
  switch (e.keyCode) {
19464
19990
  case 37: // DOM_VK_LEFT
19465
- handleNonTabEvent(e, left);
19991
+ handleNonTabOrEscEvent(e, left);
19466
19992
  break;
19467
19993
 
19468
19994
  case 39: // DOM_VK_RIGHT
19469
- handleNonTabEvent(e, right);
19995
+ handleNonTabOrEscEvent(e, right);
19470
19996
  break;
19471
19997
 
19472
19998
  case 38: // DOM_VK_UP
19473
- handleNonTabEvent(e, up);
19999
+ handleNonTabOrEscEvent(e, up);
19474
20000
  break;
19475
20001
 
19476
20002
  case 40: // DOM_VK_DOWN
19477
- handleNonTabEvent(e, down);
20003
+ handleNonTabOrEscEvent(e, down);
19478
20004
  break;
19479
20005
 
19480
20006
  case 27: // DOM_VK_ESCAPE
19481
- handleNonTabEvent(e, cancel);
20007
+ cancel();
19482
20008
  break;
19483
20009
 
19484
20010
  case 14: // DOM_VK_ENTER
19485
20011
  case 13: // DOM_VK_RETURN
19486
20012
  case 32: // DOM_VK_SPACE
19487
- handleNonTabEvent(e, enter);
20013
+ handleNonTabOrEscEvent(e, enter);
19488
20014
  break;
19489
20015
 
19490
20016
  case 9: // DOM_VK_TAB
@@ -20356,7 +20882,7 @@ define("tinymce/ui/Panel", [
20356
20882
  }
20357
20883
 
20358
20884
  return (
20359
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1" role="group">' +
20885
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1" role="group">' +
20360
20886
  (self._preBodyHtml || '') +
20361
20887
  innerHtml +
20362
20888
  '</div>'
@@ -21210,7 +21736,7 @@ define("tinymce/ui/Window", [
21210
21736
  headerHtml = (
21211
21737
  '<div id="' + id + '-head" class="' + prefix + 'window-head">' +
21212
21738
  '<div id="' + id + '-title" class="' + prefix + 'title">' + self.encode(settings.title) + '</div>' +
21213
- '<button type="button" class="' + prefix + 'close" aria-hidden="true">&times;</button>' +
21739
+ '<button type="button" class="' + prefix + 'close" aria-hidden="true">\u00d7</button>' +
21214
21740
  '<div id="' + id + '-dragh" class="' + prefix + 'dragh"></div>' +
21215
21741
  '</div>'
21216
21742
  );
@@ -21229,7 +21755,7 @@ define("tinymce/ui/Window", [
21229
21755
  }
21230
21756
 
21231
21757
  return (
21232
- '<div id="' + id + '" class="' + self.classes() + '" hideFocus="1">' +
21758
+ '<div id="' + id + '" class="' + self.classes() + '" hidefocus="1">' +
21233
21759
  '<div class="' + self.classPrefix + 'reset" role="application">' +
21234
21760
  headerHtml +
21235
21761
  '<div id="' + id + '-body" class="' + self.classes('body') + '">' +
@@ -21378,6 +21904,17 @@ define("tinymce/ui/Window", [
21378
21904
  DomUtils.removeClass(document.documentElement, prefix + 'fullscreen');
21379
21905
  DomUtils.removeClass(document.body, prefix + 'fullscreen');
21380
21906
  }
21907
+ },
21908
+
21909
+ /**
21910
+ * Returns the contentWindow object of the iframe if it exists.
21911
+ *
21912
+ * @method getContentWindow
21913
+ * @return {Window} window object or null.
21914
+ */
21915
+ getContentWindow: function() {
21916
+ var ifr = this.getEl().getElementsByTagName('iframe')[0];
21917
+ return ifr ? ifr.contentWindow : null;
21381
21918
  }
21382
21919
  });
21383
21920
 
@@ -21686,7 +22223,6 @@ define("tinymce/WindowManager", [
21686
22223
  args.buttons = [
21687
22224
  {text: 'Ok', subtype: 'primary', onclick: function() {
21688
22225
  win.find('form')[0].submit();
21689
- win.close();
21690
22226
  }},
21691
22227
 
21692
22228
  {text: 'Cancel', onclick: function() {
@@ -21730,7 +22266,7 @@ define("tinymce/WindowManager", [
21730
22266
  // Takes a snapshot in the FocusManager of the selection before focus is lost to dialog
21731
22267
  editor.nodeChanged();
21732
22268
 
21733
- return win.renderTo(document.body).reflow();
22269
+ return win.renderTo().reflow();
21734
22270
  };
21735
22271
 
21736
22272
  /**
@@ -21814,6 +22350,16 @@ define("tinymce/WindowManager", [
21814
22350
  getTopMostWindow().params = params;
21815
22351
  }
21816
22352
  };
22353
+
22354
+ /**
22355
+ * Returns the currently opened window objects.
22356
+ *
22357
+ * @method getWindows
22358
+ * @return {Array} Array of the currently opened windows.
22359
+ */
22360
+ self.getWindows = function() {
22361
+ return windows;
22362
+ };
21817
22363
  };
21818
22364
  });
21819
22365
 
@@ -21910,9 +22456,45 @@ define("tinymce/util/Quirks", [
21910
22456
  */
21911
22457
  function cleanupStylesWhenDeleting() {
21912
22458
  var doc = editor.getDoc(), urlPrefix = 'data:text/mce-internal,';
22459
+ var MutationObserver = window.MutationObserver, olderWebKit, dragStartRng;
21913
22460
 
21914
- if (!window.MutationObserver) {
21915
- return;
22461
+ // Add mini polyfill for older WebKits
22462
+ // TODO: Remove this when old Safari versions gets updated
22463
+ if (!MutationObserver) {
22464
+ olderWebKit = true;
22465
+
22466
+ MutationObserver = function() {
22467
+ var records = [], target;
22468
+
22469
+ function nodeInsert(e) {
22470
+ var target = e.relatedNode || e.target;
22471
+ records.push({target: target, addedNodes: [target]});
22472
+ }
22473
+
22474
+ function attrModified(e) {
22475
+ var target = e.relatedNode || e.target;
22476
+ records.push({target: target, attributeName: e.attrName});
22477
+ }
22478
+
22479
+ this.observe = function(node) {
22480
+ target = node;
22481
+ target.addEventListener('DOMSubtreeModified', nodeInsert, false);
22482
+ target.addEventListener('DOMNodeInsertedIntoDocument', nodeInsert, false);
22483
+ target.addEventListener('DOMNodeInserted', nodeInsert, false);
22484
+ target.addEventListener('DOMAttrModified', attrModified, false);
22485
+ };
22486
+
22487
+ this.disconnect = function() {
22488
+ target.removeEventListener('DOMSubtreeModified', nodeInsert, false);
22489
+ target.removeEventListener('DOMNodeInsertedIntoDocument', nodeInsert, false);
22490
+ target.removeEventListener('DOMNodeInserted', nodeInsert, false);
22491
+ target.removeEventListener('DOMAttrModified', attrModified, false);
22492
+ };
22493
+
22494
+ this.takeRecords = function() {
22495
+ return records;
22496
+ };
22497
+ };
21916
22498
  }
21917
22499
 
21918
22500
  function customDelete(isForward) {
@@ -21944,6 +22526,10 @@ define("tinymce/util/Quirks", [
21944
22526
  var caretElement = rng.startContainer.parentNode;
21945
22527
 
21946
22528
  Tools.each(mutationObserver.takeRecords(), function(record) {
22529
+ if (!dom.isChildOf(record.target, editor.getBody())) {
22530
+ return;
22531
+ }
22532
+
21947
22533
  // Restore style attribute to previous value
21948
22534
  if (record.attributeName == "style") {
21949
22535
  var oldValue = record.target.getAttribute('data-mce-style');
@@ -22023,9 +22609,25 @@ define("tinymce/util/Quirks", [
22023
22609
  customDelete(true);
22024
22610
  });
22025
22611
 
22612
+ // Older WebKits doesn't properly handle the clipboard so we can't add the rest
22613
+ if (olderWebKit) {
22614
+ return;
22615
+ }
22616
+
22026
22617
  editor.on('dragstart', function(e) {
22618
+ var selectionHtml;
22619
+
22620
+ if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
22621
+ selection.select(e.target);
22622
+ }
22623
+
22624
+ dragStartRng = selection.getRng();
22625
+ selectionHtml = editor.selection.getContent();
22626
+
22027
22627
  // Safari doesn't support custom dataTransfer items so we can only use URL and Text
22028
- e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(editor.selection.getContent()));
22628
+ if (selectionHtml.length > 0) {
22629
+ e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(selectionHtml));
22630
+ }
22029
22631
  });
22030
22632
 
22031
22633
  editor.on('drop', function(e) {
@@ -22039,10 +22641,26 @@ define("tinymce/util/Quirks", [
22039
22641
  internalContent = unescape(internalContent.substr(urlPrefix.length));
22040
22642
  if (doc.caretRangeFromPoint) {
22041
22643
  e.preventDefault();
22042
- customDelete();
22043
- editor.selection.setRng(doc.caretRangeFromPoint(e.x, e.y));
22044
- editor.insertContent(internalContent);
22644
+
22645
+ // Safari has a weird issue where drag/dropping images sometimes
22646
+ // produces a green plus icon. When this happens the caretRangeFromPoint
22647
+ // will return "null" even though the x, y coordinate is correct.
22648
+ // But if we detach the insert from the drop event we will get a proper range
22649
+ window.setTimeout(function() {
22650
+ var pointRng = doc.caretRangeFromPoint(e.x, e.y);
22651
+
22652
+ if (dragStartRng) {
22653
+ selection.setRng(dragStartRng);
22654
+ dragStartRng = null;
22655
+ }
22656
+
22657
+ customDelete();
22658
+
22659
+ selection.setRng(pointRng);
22660
+ editor.insertContent(internalContent);
22661
+ }, 0);
22045
22662
  }
22663
+
22046
22664
  }
22047
22665
  });
22048
22666
 
@@ -22323,6 +22941,10 @@ define("tinymce/util/Quirks", [
22323
22941
  }
22324
22942
 
22325
22943
  selectionTimer = window.setTimeout(function() {
22944
+ if (editor.removed) {
22945
+ return;
22946
+ }
22947
+
22326
22948
  var rng = selection.getRng();
22327
22949
 
22328
22950
  // Compare the ranges to see if it was a real change or not
@@ -22735,16 +23357,16 @@ define("tinymce/util/Quirks", [
22735
23357
  }
22736
23358
 
22737
23359
  /**
22738
- * Fixes selection issues on Gecko where the caret can be placed between two inline elements like <b>a</b>|<b>b</b>
23360
+ * Fixes selection issues where the caret can be placed between two inline elements like <b>a</b>|<b>b</b>
22739
23361
  * this fix will lean the caret right into the closest inline element.
22740
23362
  */
22741
23363
  function normalizeSelection() {
22742
23364
  // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i> except for Ctrl+A since it selects everything
22743
- editor.on('keyup focusin', function(e) {
23365
+ editor.on('keyup focusin mouseup', function(e) {
22744
23366
  if (e.keyCode != 65 || !VK.metaKeyPressed(e)) {
22745
23367
  selection.normalize();
22746
23368
  }
22747
- });
23369
+ }, true);
22748
23370
  }
22749
23371
 
22750
23372
  /**
@@ -22832,7 +23454,7 @@ define("tinymce/util/Quirks", [
22832
23454
  */
22833
23455
  function doubleTrailingBrElements() {
22834
23456
  if (!editor.inline) {
22835
- editor.on('focus blur', function() {
23457
+ editor.on('focus blur beforegetcontent', function() {
22836
23458
  var br = editor.dom.create('br');
22837
23459
  editor.getBody().appendChild(br);
22838
23460
  br.parentNode.removeChild(br);
@@ -22840,6 +23462,38 @@ define("tinymce/util/Quirks", [
22840
23462
  }
22841
23463
  }
22842
23464
 
23465
+ /**
23466
+ * iOS 7.1 introduced two new bugs:
23467
+ * 1) It's possible to open links within a contentEditable area by clicking on them.
23468
+ * 2) If you hold down the finger it will display the link/image touch callout menu.
23469
+ */
23470
+ function tapLinksAndImages() {
23471
+ editor.on('click', function(e) {
23472
+ var elm = e.target;
23473
+
23474
+ do {
23475
+ if (elm.tagName === 'A') {
23476
+ e.preventDefault();
23477
+ return;
23478
+ }
23479
+ } while ((elm = elm.parentNode));
23480
+ });
23481
+
23482
+ editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
23483
+ }
23484
+
23485
+ /**
23486
+ * WebKit has a bug where it will allow forms to be submitted if they are inside a contentEditable element.
23487
+ * For example this: <form><button></form>
23488
+ */
23489
+ function blockFormSubmitInsideEditor() {
23490
+ editor.on('init', function() {
23491
+ editor.dom.bind(editor.getBody(), 'submit', function(e) {
23492
+ e.preventDefault();
23493
+ });
23494
+ });
23495
+ }
23496
+
22843
23497
  // All browsers
22844
23498
  disableBackspaceIntoATable();
22845
23499
  removeBlockQuoteOnBackSpace();
@@ -22852,12 +23506,14 @@ define("tinymce/util/Quirks", [
22852
23506
  inputMethodFocus();
22853
23507
  selectControlElements();
22854
23508
  setDefaultBlockType();
23509
+ blockFormSubmitInsideEditor();
22855
23510
 
22856
23511
  // iOS
22857
23512
  if (Env.iOS) {
22858
23513
  selectionChangeNodeChanged();
22859
23514
  restoreFocusOnKeyDown();
22860
23515
  bodyHeight();
23516
+ tapLinksAndImages();
22861
23517
  } else {
22862
23518
  selectAll();
22863
23519
  }
@@ -22917,20 +23573,21 @@ define("tinymce/util/Quirks", [
22917
23573
  * @mixin tinymce.util.Observable
22918
23574
  */
22919
23575
  define("tinymce/util/Observable", [
22920
- "tinymce/util/Tools"
22921
- ], function(Tools) {
22922
- var bindingsName = "__bindings";
22923
- var nativeEvents = Tools.makeMap(
22924
- "focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange" +
22925
- " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragstart dragend dragover draggesture dragdrop drop drag", ' '
22926
- );
22927
-
22928
- function returnFalse() {
22929
- return false;
22930
- }
23576
+ "tinymce/util/EventDispatcher"
23577
+ ], function(EventDispatcher) {
23578
+ function getEventDispatcher(obj) {
23579
+ if (!obj._eventDispatcher) {
23580
+ obj._eventDispatcher = new EventDispatcher({
23581
+ scope: obj,
23582
+ toggleEvent: function(name, state) {
23583
+ if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
23584
+ obj.toggleNativeEvent(name, state);
23585
+ }
23586
+ }
23587
+ });
23588
+ }
22931
23589
 
22932
- function returnTrue() {
22933
- return true;
23590
+ return obj._eventDispatcher;
22934
23591
  }
22935
23592
 
22936
23593
  return {
@@ -22939,77 +23596,25 @@ define("tinymce/util/Observable", [
22939
23596
  *
22940
23597
  * @method fire
22941
23598
  * @param {String} name Name of the event to fire.
22942
- * @param {tinymce.Event/Object?} args Event arguments.
23599
+ * @param {Object?} args Event arguments.
22943
23600
  * @param {Boolean?} bubble True/false if the event is to be bubbled.
22944
- * @return {tinymce.Event} Event instance passed in converted into tinymce.Event instance.
23601
+ * @return {Object} Event args instance passed in.
22945
23602
  * @example
22946
23603
  * instance.fire('event', {...});
22947
23604
  */
22948
23605
  fire: function(name, args, bubble) {
22949
- var self = this, handlers, i, l, callback, parent;
22950
-
22951
- if (self.removed) {
22952
- return;
22953
- }
22954
-
22955
- name = name.toLowerCase();
22956
- args = args || {};
22957
- args.type = name;
22958
-
22959
- // Setup target is there isn't one
22960
- if (!args.target) {
22961
- args.target = self;
22962
- }
22963
-
22964
- // Add event delegation methods if they are missing
22965
- if (!args.preventDefault) {
22966
- // Add preventDefault method
22967
- args.preventDefault = function() {
22968
- args.isDefaultPrevented = returnTrue;
22969
- };
22970
-
22971
- // Add stopPropagation
22972
- args.stopPropagation = function() {
22973
- args.isPropagationStopped = returnTrue;
22974
- };
22975
-
22976
- // Add stopImmediatePropagation
22977
- args.stopImmediatePropagation = function() {
22978
- args.isImmediatePropagationStopped = returnTrue;
22979
- };
23606
+ var self = this;
22980
23607
 
22981
- // Add event delegation states
22982
- args.isDefaultPrevented = returnFalse;
22983
- args.isPropagationStopped = returnFalse;
22984
- args.isImmediatePropagationStopped = returnFalse;
23608
+ // Prevent all events except the remove event after the instance has been removed
23609
+ if (self.removed && name !== "remove") {
23610
+ return args;
22985
23611
  }
22986
23612
 
22987
- //console.log(name, args);
22988
-
22989
- if (self[bindingsName]) {
22990
- handlers = self[bindingsName][name];
22991
-
22992
- if (handlers) {
22993
- for (i = 0, l = handlers.length; i < l; i++) {
22994
- handlers[i] = callback = handlers[i];
22995
-
22996
- // Stop immediate propagation if needed
22997
- if (args.isImmediatePropagationStopped()) {
22998
- break;
22999
- }
23000
-
23001
- // If callback returns false then prevent default and stop all propagation
23002
- if (callback.call(self, args) === false) {
23003
- args.preventDefault();
23004
- return args;
23005
- }
23006
- }
23007
- }
23008
- }
23613
+ args = getEventDispatcher(self).fire(name, args, bubble);
23009
23614
 
23010
23615
  // Bubble event up to parents
23011
23616
  if (bubble !== false && self.parent) {
23012
- parent = self.parent();
23617
+ var parent = self.parent();
23013
23618
  while (parent && !args.isPropagationStopped()) {
23014
23619
  parent.fire(name, args, false);
23015
23620
  parent = parent.parent();
@@ -23033,42 +23638,7 @@ define("tinymce/util/Observable", [
23033
23638
  * });
23034
23639
  */
23035
23640
  on: function(name, callback, prepend) {
23036
- var self = this, bindings, handlers, names, i;
23037
-
23038
- if (callback === false) {
23039
- callback = function() {
23040
- return false;
23041
- };
23042
- }
23043
-
23044
- if (callback) {
23045
- names = name.toLowerCase().split(' ');
23046
- i = names.length;
23047
- while (i--) {
23048
- name = names[i];
23049
-
23050
- bindings = self[bindingsName];
23051
- if (!bindings) {
23052
- bindings = self[bindingsName] = {};
23053
- }
23054
-
23055
- handlers = bindings[name];
23056
- if (!handlers) {
23057
- handlers = bindings[name] = [];
23058
- if (self.bindNative && nativeEvents[name]) {
23059
- self.bindNative(name);
23060
- }
23061
- }
23062
-
23063
- if (prepend) {
23064
- handlers.unshift(callback);
23065
- } else {
23066
- handlers.push(callback);
23067
- }
23068
- }
23069
- }
23070
-
23071
- return self;
23641
+ return getEventDispatcher(this).on(name, callback, prepend);
23072
23642
  },
23073
23643
 
23074
23644
  /**
@@ -23089,67 +23659,150 @@ define("tinymce/util/Observable", [
23089
23659
  * instance.off();
23090
23660
  */
23091
23661
  off: function(name, callback) {
23092
- var self = this, i, bindings = self[bindingsName], handlers, bindingName, names, hi;
23662
+ return getEventDispatcher(this).off(name, callback);
23663
+ },
23093
23664
 
23094
- if (bindings) {
23095
- if (name) {
23096
- names = name.toLowerCase().split(' ');
23097
- i = names.length;
23098
- while (i--) {
23099
- name = names[i];
23100
- handlers = bindings[name];
23665
+ /**
23666
+ * Returns true/false if the object has a event of the specified name.
23667
+ *
23668
+ * @method hasEventListeners
23669
+ * @param {String} name Name of the event to check for.
23670
+ * @return {Boolean} true/false if the event exists or not.
23671
+ */
23672
+ hasEventListeners: function(name) {
23673
+ return getEventDispatcher(this).has(name);
23674
+ }
23675
+ };
23676
+ });
23677
+
23678
+ // Included from: js/tinymce/classes/EditorObservable.js
23679
+
23680
+ /**
23681
+ * EditorObservable.js
23682
+ *
23683
+ * Copyright, Moxiecode Systems AB
23684
+ * Released under LGPL License.
23685
+ *
23686
+ * License: http://www.tinymce.com/license
23687
+ * Contributing: http://www.tinymce.com/contributing
23688
+ */
23689
+
23690
+ /**
23691
+ * This mixin contains the event logic for the tinymce.Editor class.
23692
+ *
23693
+ * @mixin tinymce.EditorObservable
23694
+ * @extends tinymce.util.Observable
23695
+ */
23696
+ define("tinymce/EditorObservable", [
23697
+ "tinymce/util/Observable",
23698
+ "tinymce/dom/DOMUtils",
23699
+ "tinymce/util/Tools"
23700
+ ], function(Observable, DOMUtils, Tools) {
23701
+ var DOM = DOMUtils.DOM;
23702
+
23703
+ function getEventTarget(editor, eventName) {
23704
+ if (eventName == 'selectionchange') {
23705
+ return editor.getDoc();
23706
+ }
23707
+
23708
+ // Need to bind mousedown/mouseup etc to document not body in iframe mode
23709
+ // Since the user might click on the HTML element not the BODY
23710
+ if (!editor.inline && /^mouse|click|contextmenu|drop/.test(eventName)) {
23711
+ return editor.getDoc();
23712
+ }
23713
+
23714
+ return editor.getBody();
23715
+ }
23716
+
23717
+ function bindEventDelegate(editor, name) {
23718
+ var eventRootSelector = editor.settings.event_root, editorManager = editor.editorManager;
23719
+ var eventRootElm = editorManager.eventRootElm || getEventTarget(editor, name);
23720
+
23721
+ if (eventRootSelector) {
23722
+ if (!editorManager.rootEvents) {
23723
+ editorManager.rootEvents = {};
23724
+
23725
+ editorManager.on('RemoveEditor', function() {
23726
+ if (!editorManager.activeEditor) {
23727
+ DOM.unbind(eventRootElm);
23728
+ delete editorManager.rootEvents;
23729
+ }
23730
+ });
23731
+ }
23732
+
23733
+ if (editorManager.rootEvents[name]) {
23734
+ return;
23735
+ }
23101
23736
 
23102
- // Unbind all handlers
23103
- if (!name) {
23104
- for (bindingName in bindings) {
23105
- bindings[name].length = 0;
23106
- }
23737
+ if (eventRootElm == editor.getBody()) {
23738
+ eventRootElm = DOM.select(eventRootSelector)[0];
23739
+ editorManager.eventRootElm = eventRootElm;
23740
+ }
23107
23741
 
23108
- return self;
23109
- }
23742
+ editorManager.rootEvents[name] = true;
23110
23743
 
23111
- if (handlers) {
23112
- // Unbind all by name
23113
- if (!callback) {
23114
- handlers.length = 0;
23115
- } else {
23116
- // Unbind specific ones
23117
- hi = handlers.length;
23118
- while (hi--) {
23119
- if (handlers[hi] === callback) {
23120
- handlers.splice(hi, 1);
23121
- }
23122
- }
23123
- }
23744
+ DOM.bind(eventRootElm, name, function(e) {
23745
+ var target = e.target, editors = editorManager.editors, i = editors.length;
23124
23746
 
23125
- if (!handlers.length && self.unbindNative && nativeEvents[name]) {
23126
- self.unbindNative(name);
23127
- delete bindings[name];
23128
- }
23129
- }
23130
- }
23131
- } else {
23132
- if (self.unbindNative) {
23133
- for (name in bindings) {
23134
- self.unbindNative(name);
23747
+ while (i--) {
23748
+ var body = editors[i].getBody();
23749
+
23750
+ if (body === target || DOM.isChildOf(target, body)) {
23751
+ if (!editors[i].hidden) {
23752
+ editors[i].fire(name, e);
23135
23753
  }
23136
23754
  }
23137
-
23138
- self[bindingsName] = [];
23139
23755
  }
23140
- }
23756
+ });
23757
+ } else {
23758
+ editor.dom.bind(eventRootElm, name, function(e) {
23759
+ if (!editor.hidden) {
23760
+ editor.fire(name, e);
23761
+ }
23762
+ });
23763
+ }
23764
+ }
23141
23765
 
23142
- return self;
23766
+ var EditorObservable = {
23767
+ bindPendingEventDelegates: function() {
23768
+ var self = this;
23769
+
23770
+ Tools.each(self._pendingNativeEvents, function(name) {
23771
+ bindEventDelegate(self, name);
23772
+ });
23143
23773
  },
23144
23774
 
23145
- hasEventListeners: function(name) {
23146
- var bindings = this[bindingsName];
23775
+ toggleNativeEvent: function(name, state) {
23776
+ var self = this;
23147
23777
 
23148
- name = name.toLowerCase();
23778
+ if (self.settings.readonly) {
23779
+ return;
23780
+ }
23781
+
23782
+ // Never bind focus/blur since the FocusManager fakes those
23783
+ if (name == "focus" || name == "blur") {
23784
+ return;
23785
+ }
23149
23786
 
23150
- return !(!bindings || !bindings[name] || bindings[name].length === 0);
23787
+ if (state) {
23788
+ if (self.initialized) {
23789
+ bindEventDelegate(self, name);
23790
+ } else {
23791
+ if (!self._pendingNativeEvents) {
23792
+ self._pendingNativeEvents = [name];
23793
+ } else {
23794
+ self._pendingNativeEvents.push(name);
23795
+ }
23796
+ }
23797
+ } else if (self.initialized) {
23798
+ self.dom.unbind(getEventTarget(self, name), name);
23799
+ }
23151
23800
  }
23152
23801
  };
23802
+
23803
+ EditorObservable = Tools.extend({}, Observable, EditorObservable);
23804
+
23805
+ return EditorObservable;
23153
23806
  });
23154
23807
 
23155
23808
  // Included from: js/tinymce/classes/Shortcuts.js
@@ -23331,13 +23984,13 @@ define("tinymce/Editor", [
23331
23984
  "tinymce/util/Quirks",
23332
23985
  "tinymce/Env",
23333
23986
  "tinymce/util/Tools",
23334
- "tinymce/util/Observable",
23987
+ "tinymce/EditorObservable",
23335
23988
  "tinymce/Shortcuts"
23336
23989
  ], function(
23337
23990
  DOMUtils, AddOnManager, Node, DomSerializer, Serializer,
23338
23991
  Selection, Formatter, UndoManager, EnterKey, ForceBlocks, EditorCommands,
23339
23992
  URI, ScriptLoader, EventUtils, WindowManager,
23340
- Schema, DomParser, Quirks, Env, Tools, Observable, Shortcuts
23993
+ Schema, DomParser, Quirks, Env, Tools, EditorObservable, Shortcuts
23341
23994
  ) {
23342
23995
  // Shorten these names
23343
23996
  var DOM = DOMUtils.DOM, ThemeManager = AddOnManager.ThemeManager, PluginManager = AddOnManager.PluginManager;
@@ -23346,20 +23999,6 @@ define("tinymce/Editor", [
23346
23999
  var Event = EventUtils.Event;
23347
24000
  var isGecko = Env.gecko, ie = Env.ie;
23348
24001
 
23349
- function getEventTarget(editor, eventName) {
23350
- if (eventName == 'selectionchange') {
23351
- return editor.getDoc();
23352
- }
23353
-
23354
- // Need to bind mousedown/mouseup etc to document not body in iframe mode
23355
- // Since the user might click on the HTML element not the BODY
23356
- if (!editor.inline && /^mouse|click|contextmenu|drop/.test(eventName)) {
23357
- return editor.getDoc();
23358
- }
23359
-
23360
- return editor.getBody();
23361
- }
23362
-
23363
24002
  /**
23364
24003
  * Include documentation for all the events.
23365
24004
  *
@@ -23989,12 +24628,10 @@ define("tinymce/Editor", [
23989
24628
 
23990
24629
  DOM.removeClass(bodyEl, 'mce-content-body');
23991
24630
  DOM.removeClass(bodyEl, 'mce-edit-focus');
23992
- DOM.setAttrib(bodyEl, 'tabIndex', null);
23993
24631
  DOM.setAttrib(bodyEl, 'contentEditable', null);
23994
24632
  });
23995
24633
 
23996
24634
  DOM.addClass(targetElm, 'mce-content-body');
23997
- targetElm.tabIndex = -1;
23998
24635
  self.contentDocument = doc = settings.content_document || document;
23999
24636
  self.contentWindow = settings.content_window || window;
24000
24637
  self.bodyElement = targetElm;
@@ -24061,7 +24698,7 @@ define("tinymce/Editor", [
24061
24698
  self.parser = new DomParser(settings, self.schema);
24062
24699
 
24063
24700
  // Convert src and href into data-mce-src, data-mce-href and data-mce-style
24064
- self.parser.addAttributeFilter('src,href,style', function(nodes, name) {
24701
+ self.parser.addAttributeFilter('src,href,style,tabindex', function(nodes, name) {
24065
24702
  var i = nodes.length, node, dom = self.dom, value, internalName;
24066
24703
 
24067
24704
  while (i--) {
@@ -24073,6 +24710,9 @@ define("tinymce/Editor", [
24073
24710
  if (!node.attributes.map[internalName]) {
24074
24711
  if (name === "style") {
24075
24712
  node.attr(internalName, dom.serializeStyle(dom.parseStyle(value), node.name));
24713
+ } else if (name === "tabindex") {
24714
+ node.attr(internalName, value);
24715
+ node.attr(name, null);
24076
24716
  } else {
24077
24717
  node.attr(internalName, self.convertURL(value, name, node.name));
24078
24718
  }
@@ -24218,12 +24858,7 @@ define("tinymce/Editor", [
24218
24858
  * }
24219
24859
  */
24220
24860
  self.initialized = true;
24221
-
24222
- each(self._pendingNativeEvents, function(name) {
24223
- self.dom.bind(getEventTarget(self, name), name, function(e) {
24224
- self.fire(e.type, e);
24225
- });
24226
- });
24861
+ self.bindPendingEventDelegates();
24227
24862
 
24228
24863
  self.fire('init');
24229
24864
  self.focus(true);
@@ -24301,8 +24936,13 @@ define("tinymce/Editor", [
24301
24936
  body = self.getBody();
24302
24937
 
24303
24938
  // Check for setActive since it doesn't scroll to the element
24304
- if (body.setActive && Env.ie < 11) {
24305
- body.setActive();
24939
+ if (body.setActive) {
24940
+ // IE 11 sometimes throws "Invalid function" then fallback to focus
24941
+ try {
24942
+ body.setActive();
24943
+ } catch (ex) {
24944
+ body.focus();
24945
+ }
24306
24946
  } else {
24307
24947
  body.focus();
24308
24948
  }
@@ -24476,9 +25116,7 @@ define("tinymce/Editor", [
24476
25116
  },
24477
25117
 
24478
25118
  /**
24479
- * Adds a button that later gets created by the ControlManager. This is a shorter and easier method
24480
- * of adding buttons without the need to deal with the ControlManager directly. But it's also less
24481
- * powerfull if you need more control use the ControlManagers factory methods instead.
25119
+ * Adds a button that later gets created by the theme in the editors toolbars.
24482
25120
  *
24483
25121
  * @method addButton
24484
25122
  * @param {String} name Button name to add.
@@ -24520,7 +25158,9 @@ define("tinymce/Editor", [
24520
25158
  },
24521
25159
 
24522
25160
  /**
24523
- * Adds a menu item to be used in the menus of the modern theme.
25161
+ * Adds a menu item to be used in the menus of the theme. There might be multiple instances
25162
+ * of this menu item for example it might be used in the main menus of the theme but also in
25163
+ * the context menu so make sure that it's self contained and supports multiple instances.
24524
25164
  *
24525
25165
  * @method addMenuItem
24526
25166
  * @param {String} name Menu item name to add.
@@ -24790,10 +25430,19 @@ define("tinymce/Editor", [
24790
25430
  show: function() {
24791
25431
  var self = this;
24792
25432
 
24793
- DOM.show(self.getContainer());
24794
- DOM.hide(self.id);
24795
- self.load();
24796
- self.fire('show');
25433
+ if (self.hidden) {
25434
+ self.hidden = false;
25435
+
25436
+ if (self.inline) {
25437
+ self.getBody().contentEditable = true;
25438
+ } else {
25439
+ DOM.show(self.getContainer());
25440
+ DOM.hide(self.id);
25441
+ }
25442
+
25443
+ self.load();
25444
+ self.fire('show');
25445
+ }
24797
25446
  },
24798
25447
 
24799
25448
  /**
@@ -24804,18 +25453,31 @@ define("tinymce/Editor", [
24804
25453
  hide: function() {
24805
25454
  var self = this, doc = self.getDoc();
24806
25455
 
24807
- // Fixed bug where IE has a blinking cursor left from the editor
24808
- if (ie && doc && !self.inline) {
24809
- doc.execCommand('SelectAll');
24810
- }
25456
+ if (!self.hidden) {
25457
+ self.hidden = true;
25458
+
25459
+ // Fixed bug where IE has a blinking cursor left from the editor
25460
+ if (ie && doc && !self.inline) {
25461
+ doc.execCommand('SelectAll');
25462
+ }
25463
+
25464
+ // We must save before we hide so Safari doesn't crash
25465
+ self.save();
24811
25466
 
24812
- // We must save before we hide so Safari doesn't crash
24813
- self.save();
25467
+ if (self.inline) {
25468
+ self.getBody().contentEditable = false;
25469
+
25470
+ // Make sure the editor gets blurred
25471
+ if (self == self.editorManager.focusedEditor) {
25472
+ self.editorManager.focusedEditor = null;
25473
+ }
25474
+ } else {
25475
+ DOM.hide(self.getContainer());
25476
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
25477
+ }
24814
25478
 
24815
- // defer the call to hide to prevent an IE9 crash #4921
24816
- DOM.hide(self.getContainer());
24817
- DOM.setStyle(self.id, 'display', self.orgDisplay);
24818
- self.fire('hide');
25479
+ self.fire('hide');
25480
+ }
24819
25481
  },
24820
25482
 
24821
25483
  /**
@@ -24825,7 +25487,7 @@ define("tinymce/Editor", [
24825
25487
  * @return {Boolean} True/false if the editor is hidden or not.
24826
25488
  */
24827
25489
  isHidden: function() {
24828
- return !DOM.isHidden(this.id);
25490
+ return !!this.hidden;
24829
25491
  },
24830
25492
 
24831
25493
  /**
@@ -25281,23 +25943,26 @@ define("tinymce/Editor", [
25281
25943
  var self = this;
25282
25944
 
25283
25945
  if (!self.removed) {
25284
- self.fire('remove');
25285
- self.off();
25286
- self.removed = 1; // Cancels post remove event execution
25946
+ self.removed = 1;
25947
+ self.save();
25287
25948
 
25288
25949
  // Remove any hidden input
25289
25950
  if (self.hasHiddenInput) {
25290
25951
  DOM.remove(self.getElement().nextSibling);
25291
25952
  }
25292
25953
 
25293
- // We must save before we hide so Safari doesn't crash
25294
- self.save();
25954
+ if (!self.inline) {
25955
+ // IE 9 has a bug where the selection stops working if you place the
25956
+ // caret inside the editor then remove the iframe
25957
+ if (ie && ie < 10) {
25958
+ self.getDoc().execCommand('SelectAll', false, null);
25959
+ }
25295
25960
 
25296
- DOM.setStyle(self.id, 'display', self.orgDisplay);
25961
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
25962
+ self.getBody().onload = null; // Prevent #6816
25297
25963
 
25298
- // Don't clear the window or document if content editable
25299
- // is enabled since other instances might still be present
25300
- if (!self.settings.content_editable) {
25964
+ // Don't clear the window or document if content editable
25965
+ // is enabled since other instances might still be present
25301
25966
  Event.unbind(self.getWin());
25302
25967
  Event.unbind(self.getDoc());
25303
25968
  }
@@ -25306,40 +25971,14 @@ define("tinymce/Editor", [
25306
25971
  Event.unbind(self.getBody());
25307
25972
  Event.unbind(elm);
25308
25973
 
25974
+ self.fire('remove');
25975
+
25309
25976
  self.editorManager.remove(self);
25310
25977
  DOM.remove(elm);
25311
25978
  self.destroy();
25312
25979
  }
25313
25980
  },
25314
25981
 
25315
- bindNative: function(name) {
25316
- var self = this;
25317
-
25318
- if (self.settings.readonly) {
25319
- return;
25320
- }
25321
-
25322
- if (self.initialized) {
25323
- self.dom.bind(getEventTarget(self, name), name, function(e) {
25324
- self.fire(name, e);
25325
- });
25326
- } else {
25327
- if (!self._pendingNativeEvents) {
25328
- self._pendingNativeEvents = [name];
25329
- } else {
25330
- self._pendingNativeEvents.push(name);
25331
- }
25332
- }
25333
- },
25334
-
25335
- unbindNative: function(name) {
25336
- var self = this;
25337
-
25338
- if (self.initialized) {
25339
- self.dom.unbind(name);
25340
- }
25341
- },
25342
-
25343
25982
  /**
25344
25983
  * Destroys the editor instance by removing all events, element references or other resources
25345
25984
  * that could leak memory. This method will be called automatically when the page is unloaded
@@ -25434,7 +26073,7 @@ define("tinymce/Editor", [
25434
26073
  }
25435
26074
  };
25436
26075
 
25437
- extend(Editor.prototype, Observable);
26076
+ extend(Editor.prototype, EditorObservable);
25438
26077
 
25439
26078
  return Editor;
25440
26079
  });
@@ -25547,7 +26186,7 @@ define("tinymce/FocusManager", [
25547
26186
  "tinymce/dom/DOMUtils",
25548
26187
  "tinymce/Env"
25549
26188
  ], function(DOMUtils, Env) {
25550
- var selectionChangeHandler, documentFocusInHandler, DOM = DOMUtils.DOM;
26189
+ var selectionChangeHandler, documentFocusInHandler, documentMouseUpHandler, DOM = DOMUtils.DOM;
25551
26190
 
25552
26191
  /**
25553
26192
  * Constructs a new focus manager instance.
@@ -25568,8 +26207,13 @@ define("tinymce/FocusManager", [
25568
26207
 
25569
26208
  // We can't store a real range on IE 11 since it gets mutated so we need to use a bookmark object
25570
26209
  // TODO: Move this to a separate range utils class since it's it's logic is present in Selection as well.
25571
- function createBookmark(rng) {
26210
+ function createBookmark(dom, rng) {
25572
26211
  if (rng && rng.startContainer) {
26212
+ // Verify that the range is within the root of the editor
26213
+ if (!dom.isChildOf(rng.startContainer, dom.getRoot()) || !dom.isChildOf(rng.endContainer, dom.getRoot())) {
26214
+ return;
26215
+ }
26216
+
25573
26217
  return {
25574
26218
  startContainer: rng.startContainer,
25575
26219
  startOffset: rng.startOffset,
@@ -25599,44 +26243,12 @@ define("tinymce/FocusManager", [
25599
26243
  return !!DOM.getParent(elm, FocusManager.isEditorUIElement);
25600
26244
  }
25601
26245
 
25602
- function isNodeInBodyOfEditor(node, editor) {
25603
- var body = editor.getBody();
25604
-
25605
- while (node) {
25606
- if (node == body) {
25607
- return true;
25608
- }
25609
-
25610
- node = node.parentNode;
25611
- }
25612
- }
25613
-
25614
26246
  function registerEvents(e) {
25615
26247
  var editor = e.editor;
25616
26248
 
25617
26249
  editor.on('init', function() {
25618
- // On IE take selection snapshot onbeforedeactivate
25619
- if ("onbeforedeactivate" in document && Env.ie < 11) {
25620
- // Gets fired when the editor is about to be blurred but also when the selection
25621
- // is moved into a table cell so we need to add the range as a pending range then
25622
- // use that pending range on the blur event of the editor body
25623
- editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
25624
- try {
25625
- editor.pendingRng = editor.selection.getRng();
25626
- } catch (ex) {
25627
- // IE throws "Unexcpected call to method or property access" some times so lets ignore it
25628
- }
25629
- });
25630
-
25631
- // Set the pending range as the current last range if the blur event occurs
25632
- editor.dom.bind(editor.getBody(), 'blur', function() {
25633
- if (editor.pendingRng) {
25634
- editor.lastRng = editor.pendingRng;
25635
- editor.selection.lastFocusBookmark = createBookmark(editor.lastRng);
25636
- editor.pendingRng = null;
25637
- }
25638
- });
25639
- } else if (editor.inline || Env.ie > 10) {
26250
+ // Gecko/WebKit has ghost selections in iframes and IE only has one selection per browser tab
26251
+ if (editor.inline || Env.ie) {
25640
26252
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
25641
26253
  editor.on('nodechange keyup', function() {
25642
26254
  var node = document.activeElement;
@@ -25646,7 +26258,7 @@ define("tinymce/FocusManager", [
25646
26258
  node = editor.getBody();
25647
26259
  }
25648
26260
 
25649
- if (isNodeInBodyOfEditor(node, editor)) {
26261
+ if (editor.dom.isChildOf(node, editor.getBody())) {
25650
26262
  editor.lastRng = editor.selection.getRng();
25651
26263
  }
25652
26264
  });
@@ -25720,6 +26332,8 @@ define("tinymce/FocusManager", [
25720
26332
  }, 0);
25721
26333
  });
25722
26334
 
26335
+ // Check if focus is moved to an element outside the active editor by checking if the target node
26336
+ // isn't within the body of the activeEditor nor a UI element such as a dialog child control
25723
26337
  if (!documentFocusInHandler) {
25724
26338
  documentFocusInHandler = function(e) {
25725
26339
  var activeEditor = editorManager.activeEditor;
@@ -25727,7 +26341,7 @@ define("tinymce/FocusManager", [
25727
26341
  if (activeEditor && e.target.ownerDocument == document) {
25728
26342
  // Check to make sure we have a valid selection
25729
26343
  if (activeEditor.selection) {
25730
- activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.lastRng);
26344
+ activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.dom, activeEditor.lastRng);
25731
26345
  }
25732
26346
 
25733
26347
  // Fire a blur event if the element isn't a UI element
@@ -25738,17 +26352,39 @@ define("tinymce/FocusManager", [
25738
26352
  }
25739
26353
  };
25740
26354
 
25741
- // Check if focus is moved to an element outside the active editor by checking if the target node
25742
- // isn't within the body of the activeEditor nor a UI element such as a dialog child control
25743
26355
  DOM.bind(document, 'focusin', documentFocusInHandler);
25744
26356
  }
26357
+
26358
+ // Handle edge case when user starts the selection inside the editor and releases
26359
+ // the mouse outside the editor producing a new selection. This weird workaround is needed since
26360
+ // Gecko doesn't have the "selectionchange" event we need to do this. Fixes: #6843
26361
+ if (editor.inline && !documentMouseUpHandler) {
26362
+ documentMouseUpHandler = function(e) {
26363
+ var activeEditor = editorManager.activeEditor;
26364
+
26365
+ if (activeEditor.inline && !activeEditor.dom.isChildOf(e.target, activeEditor.getBody())) {
26366
+ var rng = activeEditor.selection.getRng();
26367
+
26368
+ if (!rng.collapsed) {
26369
+ activeEditor.lastRng = rng;
26370
+ }
26371
+ }
26372
+ };
26373
+
26374
+ DOM.bind(document, 'mouseup', documentMouseUpHandler);
26375
+ }
25745
26376
  }
25746
26377
 
25747
- function unregisterDocumentEvents() {
26378
+ function unregisterDocumentEvents(e) {
26379
+ if (editorManager.focusedEditor == e.editor) {
26380
+ editorManager.focusedEditor = null;
26381
+ }
26382
+
25748
26383
  if (!editorManager.activeEditor) {
25749
26384
  DOM.unbind(document, 'selectionchange', selectionChangeHandler);
25750
26385
  DOM.unbind(document, 'focusin', documentFocusInHandler);
25751
- selectionChangeHandler = documentFocusInHandler = null;
26386
+ DOM.unbind(document, 'mouseup', documentMouseUpHandler);
26387
+ selectionChangeHandler = documentFocusInHandler = documentMouseUpHandler = null;
25752
26388
  }
25753
26389
  }
25754
26390
 
@@ -25764,7 +26400,8 @@ define("tinymce/FocusManager", [
25764
26400
  * @return {Boolean} True/false state if the element is part of the UI or not.
25765
26401
  */
25766
26402
  FocusManager.isEditorUIElement = function(elm) {
25767
- return elm.className.indexOf('mce-') !== -1;
26403
+ // Needs to be converted to string since svg can have focus: #6776
26404
+ return elm.className.toString().indexOf('mce-') !== -1;
25768
26405
  };
25769
26406
 
25770
26407
  return FocusManager;
@@ -25804,9 +26441,46 @@ define("tinymce/EditorManager", [
25804
26441
  ], function(Editor, DOMUtils, URI, Env, Tools, Observable, I18n, FocusManager) {
25805
26442
  var DOM = DOMUtils.DOM;
25806
26443
  var explode = Tools.explode, each = Tools.each, extend = Tools.extend;
25807
- var instanceCounter = 0, beforeUnloadDelegate;
26444
+ var instanceCounter = 0, beforeUnloadDelegate, EditorManager;
26445
+
26446
+ function removeEditorFromList(editor) {
26447
+ var editors = EditorManager.editors, removedFromList;
26448
+
26449
+ delete editors[editor.id];
26450
+
26451
+ for (var i = 0; i < editors.length; i++) {
26452
+ if (editors[i] == editor) {
26453
+ editors.splice(i, 1);
26454
+ removedFromList = true;
26455
+ break;
26456
+ }
26457
+ }
26458
+
26459
+ // Select another editor since the active one was removed
26460
+ if (EditorManager.activeEditor == editor) {
26461
+ EditorManager.activeEditor = editors[0];
26462
+ }
26463
+
26464
+ // Clear focusedEditor if necessary, so that we don't try to blur the destroyed editor
26465
+ if (EditorManager.focusedEditor == editor) {
26466
+ EditorManager.focusedEditor = null;
26467
+ }
26468
+
26469
+ return removedFromList;
26470
+ }
26471
+
26472
+ function purgeDestroyedEditor(editor) {
26473
+ // User has manually destroyed the editor lets clean up the mess
26474
+ if (editor && !(editor.getContainer() || editor.getBody()).parentNode) {
26475
+ removeEditorFromList(editor);
26476
+ editor.destroy(true);
26477
+ editor = null;
26478
+ }
26479
+
26480
+ return editor;
26481
+ }
25808
26482
 
25809
- var EditorManager = {
26483
+ EditorManager = {
25810
26484
  /**
25811
26485
  * Major version of TinyMCE build.
25812
26486
  *
@@ -25821,7 +26495,7 @@ define("tinymce/EditorManager", [
25821
26495
  * @property minorVersion
25822
26496
  * @type String
25823
26497
  */
25824
- minorVersion : '0.19',
26498
+ minorVersion : '0.26',
25825
26499
 
25826
26500
  /**
25827
26501
  * Release date of TinyMCE build.
@@ -25829,7 +26503,7 @@ define("tinymce/EditorManager", [
25829
26503
  * @property releaseDate
25830
26504
  * @type String
25831
26505
  */
25832
- releaseDate: '2014-03-11',
26506
+ releaseDate: '2014-05-06',
25833
26507
 
25834
26508
  /**
25835
26509
  * Collection of editor instances.
@@ -25862,7 +26536,7 @@ define("tinymce/EditorManager", [
25862
26536
  activeEditor: null,
25863
26537
 
25864
26538
  setup: function() {
25865
- var self = this, baseURL, documentBaseURL, suffix = "", preInit;
26539
+ var self = this, baseURL, documentBaseURL, suffix = "", preInit, src;
25866
26540
 
25867
26541
  // Get base URL for the current document
25868
26542
  documentBaseURL = document.location.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
@@ -25879,7 +26553,7 @@ define("tinymce/EditorManager", [
25879
26553
  // Get base where the tinymce script is located
25880
26554
  var scripts = document.getElementsByTagName('script');
25881
26555
  for (var i = 0; i < scripts.length; i++) {
25882
- var src = scripts[i].src;
26556
+ src = scripts[i].src;
25883
26557
 
25884
26558
  // Script types supported:
25885
26559
  // tinymce.js tinymce.min.js tinymce.dev.js
@@ -25894,6 +26568,18 @@ define("tinymce/EditorManager", [
25894
26568
  break;
25895
26569
  }
25896
26570
  }
26571
+
26572
+ // We didn't find any baseURL by looking at the script elements
26573
+ // Try to use the document.currentScript as a fallback
26574
+ if (!baseURL && document.currentScript) {
26575
+ src = document.currentScript.src;
26576
+
26577
+ if (src.indexOf('.min') != -1) {
26578
+ suffix = '.min';
26579
+ }
26580
+
26581
+ baseURL = src.substring(0, src.lastIndexOf('/'));
26582
+ }
25897
26583
  }
25898
26584
 
25899
26585
  /**
@@ -25970,6 +26656,14 @@ define("tinymce/EditorManager", [
25970
26656
  return id;
25971
26657
  }
25972
26658
 
26659
+ function createEditor(id, settings) {
26660
+ if (!purgeDestroyedEditor(self.get(id))) {
26661
+ var editor = new Editor(id, settings, self);
26662
+ editors.push(editor);
26663
+ editor.render();
26664
+ }
26665
+ }
26666
+
25973
26667
  function execCallback(se, n, s) {
25974
26668
  var f = se[n];
25975
26669
 
@@ -25995,9 +26689,7 @@ define("tinymce/EditorManager", [
25995
26689
  // Process type specific selector
25996
26690
  each(settings.types, function(type) {
25997
26691
  each(DOM.select(type.selector), function(elm) {
25998
- var editor = new Editor(createId(elm), extend({}, settings, type), self);
25999
- editors.push(editor);
26000
- editor.render(1);
26692
+ createEditor(createId(elm), extend({}, settings, type));
26001
26693
  });
26002
26694
  });
26003
26695
 
@@ -26005,9 +26697,7 @@ define("tinymce/EditorManager", [
26005
26697
  } else if (settings.selector) {
26006
26698
  // Process global selector
26007
26699
  each(DOM.select(settings.selector), function(elm) {
26008
- var editor = new Editor(createId(elm), settings, self);
26009
- editors.push(editor);
26010
- editor.render(1);
26700
+ createEditor(createId(elm), settings);
26011
26701
  });
26012
26702
 
26013
26703
  return;
@@ -26018,22 +26708,19 @@ define("tinymce/EditorManager", [
26018
26708
  case "exact":
26019
26709
  l = settings.elements || '';
26020
26710
 
26021
- if(l.length > 0) {
26711
+ if (l.length > 0) {
26022
26712
  each(explode(l), function(v) {
26023
26713
  if (DOM.get(v)) {
26024
26714
  editor = new Editor(v, settings, self);
26025
26715
  editors.push(editor);
26026
- editor.render(true);
26716
+ editor.render();
26027
26717
  } else {
26028
26718
  each(document.forms, function(f) {
26029
26719
  each(f.elements, function(e) {
26030
26720
  if (e.name === v) {
26031
26721
  v = 'mce_editor_' + instanceCounter++;
26032
26722
  DOM.setAttrib(e, 'id', v);
26033
-
26034
- editor = new Editor(v, settings, self);
26035
- editors.push(editor);
26036
- editor.render(1);
26723
+ createEditor(v, settings);
26037
26724
  }
26038
26725
  });
26039
26726
  });
@@ -26050,9 +26737,7 @@ define("tinymce/EditorManager", [
26050
26737
  }
26051
26738
 
26052
26739
  if (!settings.editor_selector || hasClass(elm, settings.editor_selector)) {
26053
- editor = new Editor(createId(elm), settings, self);
26054
- editors.push(editor);
26055
- editor.render(true);
26740
+ createEditor(createId(elm), settings);
26056
26741
  }
26057
26742
  });
26058
26743
  break;
@@ -26110,11 +26795,11 @@ define("tinymce/EditorManager", [
26110
26795
  * });
26111
26796
  */
26112
26797
  get: function(id) {
26113
- if (id === undefined) {
26798
+ if (!arguments.length) {
26114
26799
  return this.editors;
26115
26800
  }
26116
26801
 
26117
- return this.editors[id];
26802
+ return id in this.editors ? this.editors[id] : null;
26118
26803
  },
26119
26804
 
26120
26805
  /**
@@ -26185,7 +26870,7 @@ define("tinymce/EditorManager", [
26185
26870
  * @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
26186
26871
  */
26187
26872
  remove: function(selector) {
26188
- var self = this, i, editors = self.editors, editor, removedFromList;
26873
+ var self = this, i, editors = self.editors, editor;
26189
26874
 
26190
26875
  // Remove all editors
26191
26876
  if (!selector) {
@@ -26215,28 +26900,13 @@ define("tinymce/EditorManager", [
26215
26900
  return null;
26216
26901
  }
26217
26902
 
26218
- delete editors[editor.id];
26219
-
26220
- for (i = 0; i < editors.length; i++) {
26221
- if (editors[i] == editor) {
26222
- editors.splice(i, 1);
26223
- removedFromList = true;
26224
- break;
26225
- }
26226
- }
26227
-
26228
- // Select another editor since the active one was removed
26229
- if (self.activeEditor == editor) {
26230
- self.activeEditor = editors[0];
26231
- }
26232
-
26233
26903
  /**
26234
26904
  * Fires when an editor is removed from EditorManager collection.
26235
26905
  *
26236
26906
  * @event RemoveEditor
26237
26907
  * @param {Object} e Event arguments.
26238
26908
  */
26239
- if (removedFromList) {
26909
+ if (removeEditorFromList(editor)) {
26240
26910
  self.fire('RemoveEditor', {editor: editor});
26241
26911
  }
26242
26912
 
@@ -27391,6 +28061,7 @@ define("tinymce/ui/Widget", [
27391
28061
  var self = this;
27392
28062
 
27393
28063
  self._super(settings);
28064
+ settings = self.settings;
27394
28065
  self.canFocus = true;
27395
28066
 
27396
28067
  if (settings.tooltip && Widget.tooltips !== false) {
@@ -27625,6 +28296,26 @@ define("tinymce/ui/Button", [
27625
28296
  this._super();
27626
28297
  },
27627
28298
 
28299
+ /**
28300
+ * Sets/gets the current button text.
28301
+ *
28302
+ * @method text
28303
+ * @param {String} [text] New button text.
28304
+ * @return {String|tinymce.ui.Button} Current text or current Button instance.
28305
+ */
28306
+ text: function(text) {
28307
+ var self = this;
28308
+
28309
+ if (self._rendered) {
28310
+ var textNode = self.getEl().lastChild.lastChild;
28311
+ if (textNode) {
28312
+ textNode.data = self.translate(text);
28313
+ }
28314
+ }
28315
+
28316
+ return self._super(text);
28317
+ },
28318
+
27628
28319
  /**
27629
28320
  * Renders the control as a HTML string.
27630
28321
  *
@@ -27633,11 +28324,20 @@ define("tinymce/ui/Button", [
27633
28324
  */
27634
28325
  renderHtml: function() {
27635
28326
  var self = this, id = self._id, prefix = self.classPrefix;
27636
- var icon = self.settings.icon, image = '';
28327
+ var icon = self.settings.icon, image;
27637
28328
 
27638
- if (self.settings.image) {
28329
+ image = self.settings.image;
28330
+ if (image) {
27639
28331
  icon = 'none';
27640
- image = ' style="background-image: url(\'' + self.settings.image + '\')"';
28332
+
28333
+ // Support for [high dpi, low dpi] image sources
28334
+ if (typeof image != "string") {
28335
+ image = window.getSelection ? image[0] : image[1];
28336
+ }
28337
+
28338
+ image = ' style="background-image: url(\'' + image + '\')"';
28339
+ } else {
28340
+ image = '';
27641
28341
  }
27642
28342
 
27643
28343
  icon = self.settings.icon ? prefix + 'ico ' + prefix + 'i-' + icon : '';
@@ -28020,12 +28720,12 @@ define("tinymce/ui/ColorButton", [
28020
28720
 
28021
28721
  return (
28022
28722
  '<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1" aria-haspopup="true">' +
28023
- '<button role="presentation" hidefocus type="button" tabindex="-1">' +
28723
+ '<button role="presentation" hidefocus="1" type="button" tabindex="-1">' +
28024
28724
  (icon ? '<i class="' + icon + '"' + image + '></i>' : '') +
28025
28725
  '<span id="' + id + '-preview" class="' + prefix + 'preview"></span>' +
28026
28726
  (self._text ? (icon ? ' ' : '') + (self._text) : '') +
28027
28727
  '</button>' +
28028
- '<button type="button" class="' + prefix + 'open" hidefocus tabindex="-1">' +
28728
+ '<button type="button" class="' + prefix + 'open" hidefocus="1" tabindex="-1">' +
28029
28729
  ' <i class="' + prefix + 'caret"></i>' +
28030
28730
  '</button>' +
28031
28731
  '</div>'
@@ -28207,7 +28907,7 @@ define("tinymce/ui/ComboBox", [
28207
28907
  });
28208
28908
 
28209
28909
  self.on('focusin', function(e) {
28210
- if (e.target.tagName == 'INPUT') {
28910
+ if (e.target.tagName.toUpperCase() == 'INPUT') {
28211
28911
  self.menu.hide();
28212
28912
  }
28213
28913
  });
@@ -28373,7 +29073,7 @@ define("tinymce/ui/ComboBox", [
28373
29073
  if (icon || text) {
28374
29074
  openBtnHtml = (
28375
29075
  '<div id="' + id + '-open" class="' + prefix + 'btn ' + prefix + 'open" tabIndex="-1" role="button">' +
28376
- '<button id="' + id + '-action" type="button" hidefocus tabindex="-1">' +
29076
+ '<button id="' + id + '-action" type="button" hidefocus="1" tabindex="-1">' +
28377
29077
  (icon != 'caret' ? '<i class="' + icon + '"></i>' : '<i class="' + prefix + 'caret"></i>') +
28378
29078
  (text ? (icon ? ' ' : '') + text : '') +
28379
29079
  '</button>' +
@@ -28386,7 +29086,7 @@ define("tinymce/ui/ComboBox", [
28386
29086
  return (
28387
29087
  '<div id="' + id + '" class="' + self.classes() + '">' +
28388
29088
  '<input id="' + id + '-inp" class="' + prefix + 'textbox ' + prefix + 'placeholder" value="' +
28389
- value + '" hidefocus="true"' + extraAttrs + '>' +
29089
+ value + '" hidefocus="1"' + extraAttrs + ' />' +
28390
29090
  openBtnHtml +
28391
29091
  '</div>'
28392
29092
  );
@@ -28529,7 +29229,7 @@ define("tinymce/ui/Path", [
28529
29229
  }
28530
29230
 
28531
29231
  if (!html) {
28532
- html = '<div class="' + prefix + 'path-item">&nbsp;</div>';
29232
+ html = '<div class="' + prefix + 'path-item">\u00a0</div>';
28533
29233
  }
28534
29234
 
28535
29235
  return html;
@@ -28670,7 +29370,7 @@ define("tinymce/ui/FormItem", [
28670
29370
  layout.preRender(self);
28671
29371
 
28672
29372
  return (
28673
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
29373
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
28674
29374
  (self.settings.title ? ('<div id="' + self._id + '-title" class="' + prefix + 'title">' +
28675
29375
  self.settings.title + '</div>') : '') +
28676
29376
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
@@ -28889,7 +29589,7 @@ define("tinymce/ui/FieldSet", [
28889
29589
  layout.preRender(self);
28890
29590
 
28891
29591
  return (
28892
- '<fieldset id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
29592
+ '<fieldset id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
28893
29593
  (self.settings.title ? ('<legend id="' + self._id + '-title" class="' + prefix + 'fieldset-title">' +
28894
29594
  self.settings.title + '</legend>') : '') +
28895
29595
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
@@ -29347,127 +30047,6 @@ define("tinymce/ui/FormatControls", [
29347
30047
  function registerControls(editor) {
29348
30048
  var formatMenu;
29349
30049
 
29350
- // Generates a preview for a format
29351
- function getPreviewCss(format) {
29352
- var name, previewElm, dom = editor.dom;
29353
- var previewCss = '', parentFontSize, previewStyles;
29354
-
29355
- previewStyles = editor.settings.preview_styles;
29356
-
29357
- // No preview forced
29358
- if (previewStyles === false) {
29359
- return '';
29360
- }
29361
-
29362
- // Default preview
29363
- if (!previewStyles) {
29364
- previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
29365
- 'text-transform color background-color border border-radius outline text-shadow';
29366
- }
29367
-
29368
- // Removes any variables since these can't be previewed
29369
- function removeVars(val) {
29370
- return val.replace(/%(\w+)/g, '');
29371
- }
29372
-
29373
- // Create block/inline element to use for preview
29374
- format = editor.formatter.get(format);
29375
- if (!format) {
29376
- return;
29377
- }
29378
-
29379
- format = format[0];
29380
- name = format.block || format.inline || 'span';
29381
- previewElm = dom.create(name);
29382
-
29383
- // Add format styles to preview element
29384
- each(format.styles, function(value, name) {
29385
- value = removeVars(value);
29386
-
29387
- if (value) {
29388
- dom.setStyle(previewElm, name, value);
29389
- }
29390
- });
29391
-
29392
- // Add attributes to preview element
29393
- each(format.attributes, function(value, name) {
29394
- value = removeVars(value);
29395
-
29396
- if (value) {
29397
- dom.setAttrib(previewElm, name, value);
29398
- }
29399
- });
29400
-
29401
- // Add classes to preview element
29402
- each(format.classes, function(value) {
29403
- value = removeVars(value);
29404
-
29405
- if (!dom.hasClass(previewElm, value)) {
29406
- dom.addClass(previewElm, value);
29407
- }
29408
- });
29409
-
29410
- editor.fire('PreviewFormats');
29411
-
29412
- // Add the previewElm outside the visual area
29413
- dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
29414
- editor.getBody().appendChild(previewElm);
29415
-
29416
- // Get parent container font size so we can compute px values out of em/% for older IE:s
29417
- parentFontSize = dom.getStyle(editor.getBody(), 'fontSize', true);
29418
- parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
29419
-
29420
- each(previewStyles.split(' '), function(name) {
29421
- var value = dom.getStyle(previewElm, name, true);
29422
-
29423
- // If background is transparent then check if the body has a background color we can use
29424
- if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
29425
- value = dom.getStyle(editor.getBody(), name, true);
29426
-
29427
- // Ignore white since it's the default color, not the nicest fix
29428
- // TODO: Fix this by detecting runtime style
29429
- if (dom.toHex(value).toLowerCase() == '#ffffff') {
29430
- return;
29431
- }
29432
- }
29433
-
29434
- if (name == 'color') {
29435
- // Ignore black since it's the default color, not the nicest fix
29436
- // TODO: Fix this by detecting runtime style
29437
- if (dom.toHex(value).toLowerCase() == '#000000') {
29438
- return;
29439
- }
29440
- }
29441
-
29442
- // Old IE won't calculate the font size so we need to do that manually
29443
- if (name == 'font-size') {
29444
- if (/em|%$/.test(value)) {
29445
- if (parentFontSize === 0) {
29446
- return;
29447
- }
29448
-
29449
- // Convert font size from em/% to px
29450
- value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
29451
- value = (value * parentFontSize) + 'px';
29452
- }
29453
- }
29454
-
29455
- if (name == "border" && value) {
29456
- previewCss += 'padding:0 2px;';
29457
- }
29458
-
29459
- previewCss += name + ':' + value + ';';
29460
- });
29461
-
29462
- editor.fire('AfterPreviewFormats');
29463
-
29464
- //previewCss += 'line-height:normal';
29465
-
29466
- dom.remove(previewElm);
29467
-
29468
- return previewCss;
29469
- }
29470
-
29471
30050
  function createListBoxChangeHandler(items, formatName) {
29472
30051
  return function() {
29473
30052
  var self = this;
@@ -29504,7 +30083,7 @@ define("tinymce/ui/FormatControls", [
29504
30083
  }
29505
30084
 
29506
30085
  function createFormats(formats) {
29507
- formats = formats.split(';');
30086
+ formats = formats.replace(/;$/, '').split(';');
29508
30087
 
29509
30088
  var i = formats.length;
29510
30089
  while (i--) {
@@ -29518,13 +30097,13 @@ define("tinymce/ui/FormatControls", [
29518
30097
  var count = 0, newFormats = [];
29519
30098
 
29520
30099
  var defaultStyleFormats = [
29521
- {title: 'Headers', items: [
29522
- {title: 'Header 1', format: 'h1'},
29523
- {title: 'Header 2', format: 'h2'},
29524
- {title: 'Header 3', format: 'h3'},
29525
- {title: 'Header 4', format: 'h4'},
29526
- {title: 'Header 5', format: 'h5'},
29527
- {title: 'Header 6', format: 'h6'}
30100
+ {title: 'Headings', items: [
30101
+ {title: 'Heading 1', format: 'h1'},
30102
+ {title: 'Heading 2', format: 'h2'},
30103
+ {title: 'Heading 3', format: 'h3'},
30104
+ {title: 'Heading 4', format: 'h4'},
30105
+ {title: 'Heading 5', format: 'h5'},
30106
+ {title: 'Heading 6', format: 'h6'}
29528
30107
  ]},
29529
30108
 
29530
30109
  {title: 'Inline', items: [
@@ -29617,7 +30196,7 @@ define("tinymce/ui/FormatControls", [
29617
30196
 
29618
30197
  textStyle: function() {
29619
30198
  if (this.settings.format) {
29620
- return getPreviewCss(this.settings.format);
30199
+ return editor.formatter.getCssText(this.settings.format);
29621
30200
  }
29622
30201
  },
29623
30202
 
@@ -29854,12 +30433,12 @@ define("tinymce/ui/FormatControls", [
29854
30433
  'Paragraph=p;' +
29855
30434
  'Address=address;' +
29856
30435
  'Pre=pre;' +
29857
- 'Header 1=h1;' +
29858
- 'Header 2=h2;' +
29859
- 'Header 3=h3;' +
29860
- 'Header 4=h4;' +
29861
- 'Header 5=h5;' +
29862
- 'Header 6=h6'
30436
+ 'Heading 1=h1;' +
30437
+ 'Heading 2=h2;' +
30438
+ 'Heading 3=h3;' +
30439
+ 'Heading 4=h4;' +
30440
+ 'Heading 5=h5;' +
30441
+ 'Heading 6=h6'
29863
30442
  );
29864
30443
 
29865
30444
  each(blocks, function(block) {
@@ -29867,7 +30446,7 @@ define("tinymce/ui/FormatControls", [
29867
30446
  text: block[0],
29868
30447
  value: block[1],
29869
30448
  textStyle: function() {
29870
- return getPreviewCss(block[1]);
30449
+ return editor.formatter.getCssText(block[1]);
29871
30450
  }
29872
30451
  });
29873
30452
  });
@@ -30227,6 +30806,7 @@ define("tinymce/ui/Iframe", [
30227
30806
  self.addClass('iframe');
30228
30807
  self.canFocus = false;
30229
30808
 
30809
+ /*eslint no-script-url:0 */
30230
30810
  return (
30231
30811
  '<iframe id="' + self._id + '" class="' + self.classes() + '" tabindex="-1" src="' +
30232
30812
  (self.settings.url || "javascript:\'\'") + '" frameborder="0"></iframe>'
@@ -30948,7 +31528,7 @@ define("tinymce/ui/MenuItem", [
30948
31528
  e.preventDefault();
30949
31529
  });
30950
31530
 
30951
- if (settings.menu) {
31531
+ if (settings.menu && !settings.ariaHideMenu) {
30952
31532
  self.aria('haspopup', true);
30953
31533
  }
30954
31534
  },
@@ -31092,7 +31672,7 @@ define("tinymce/ui/MenuItem", [
31092
31672
 
31093
31673
  return (
31094
31674
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
31095
- (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
31675
+ (text !== '-' ? '<i class="' + icon + '"' + image + '></i>\u00a0' : '') +
31096
31676
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
31097
31677
  (shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' + shortcut + '</div>' : '') +
31098
31678
  (settings.menu ? '<div class="' + prefix + 'caret"></div>' : '') +
@@ -31546,11 +32126,11 @@ define("tinymce/ui/SplitButton", [
31546
32126
 
31547
32127
  return (
31548
32128
  '<div id="' + id + '" class="' + self.classes() + '" role="button" tabindex="-1">' +
31549
- '<button type="button" hidefocus tabindex="-1">' +
32129
+ '<button type="button" hidefocus="1" tabindex="-1">' +
31550
32130
  (icon ? '<i class="' + icon + '"></i>' : '') +
31551
32131
  (self._text ? (icon ? ' ' : '') + self._text : '') +
31552
32132
  '</button>' +
31553
- '<button type="button" class="' + prefix + 'open" hidefocus tabindex="-1">' +
32133
+ '<button type="button" class="' + prefix + 'open" hidefocus="1" tabindex="-1">' +
31554
32134
  //(icon ? '<i class="' + icon + '"></i>' : '') +
31555
32135
  (self._menuBtnText ? (icon ? '\u00a0' : '') + self._menuBtnText : '') +
31556
32136
  ' <i class="' + prefix + 'caret"></i>' +
@@ -31718,7 +32298,7 @@ define("tinymce/ui/TabPanel", [
31718
32298
  });
31719
32299
 
31720
32300
  return (
31721
- '<div id="' + self._id + '" class="' + self.classes() + '" hideFocus="1" tabIndex="-1">' +
32301
+ '<div id="' + self._id + '" class="' + self.classes() + '" hidefocus="1" tabindex="-1">' +
31722
32302
  '<div id="' + self._id + '-head" class="' + prefix + 'tabs" role="tablist">' +
31723
32303
  tabsHtml +
31724
32304
  '</div>' +
@@ -31994,12 +32574,12 @@ define("tinymce/ui/TextBox", [
31994
32574
  return (
31995
32575
  '<textarea id="' + id + '" class="' + self.classes() + '" ' +
31996
32576
  (settings.rows ? ' rows="' + settings.rows + '"' : '') +
31997
- ' hidefocus="true"' + extraAttrs + '>' + value +
32577
+ ' hidefocus="1"' + extraAttrs + '>' + value +
31998
32578
  '</textarea>'
31999
32579
  );
32000
32580
  }
32001
32581
 
32002
- return '<input id="' + id + '" class="' + self.classes() + '" value="' + value + '" hidefocus="true"' + extraAttrs + '>';
32582
+ return '<input id="' + id + '" class="' + self.classes() + '" value="' + value + '" hidefocus="1"' + extraAttrs + ' />';
32003
32583
  },
32004
32584
 
32005
32585
  /**
@@ -32043,8 +32623,9 @@ define("tinymce/ui/TextBox", [
32043
32623
  * @class tinymce.ui.Throbber
32044
32624
  */
32045
32625
  define("tinymce/ui/Throbber", [
32046
- "tinymce/ui/DomUtils"
32047
- ], function(DomUtils) {
32626
+ "tinymce/ui/DomUtils",
32627
+ "tinymce/ui/Control"
32628
+ ], function(DomUtils, Control) {
32048
32629
  "use strict";
32049
32630
 
32050
32631
  /**
@@ -32052,9 +32633,10 @@ define("tinymce/ui/Throbber", [
32052
32633
  *
32053
32634
  * @constructor
32054
32635
  * @param {Element} elm DOM Html element to display throbber in.
32636
+ * @param {Boolean} inline Optional true/false state if the throbber should be appended to end of element for infinite scroll.
32055
32637
  */
32056
- return function(elm) {
32057
- var self = this, state;
32638
+ return function(elm, inline) {
32639
+ var self = this, state, classPrefix = Control.classPrefix;
32058
32640
 
32059
32641
  /**
32060
32642
  * Shows the throbber.
@@ -32070,7 +32652,9 @@ define("tinymce/ui/Throbber", [
32070
32652
 
32071
32653
  window.setTimeout(function() {
32072
32654
  if (state) {
32073
- elm.appendChild(DomUtils.createFragment('<div class="mce-throbber"></div>'));
32655
+ elm.appendChild(DomUtils.createFragment(
32656
+ '<div class="' + classPrefix + 'throbber' + (inline ? ' ' + classPrefix + 'throbber-inline' : '') + '"></div>'
32657
+ ));
32074
32658
  }
32075
32659
  }, time || 0);
32076
32660
 
@@ -32097,5 +32681,5 @@ define("tinymce/ui/Throbber", [
32097
32681
  };
32098
32682
  });
32099
32683
 
32100
- expose(["tinymce/dom/Sizzle","tinymce/html/Styles","tinymce/dom/EventUtils","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/RangeUtils","tinymce/dom/Selection","tinymce/Formatter","tinymce/UndoManager","tinymce/EnterKey","tinymce/ForceBlocks","tinymce/EditorCommands","tinymce/util/URI","tinymce/util/Class","tinymce/ui/Selector","tinymce/ui/Collection","tinymce/ui/DomUtils","tinymce/ui/Control","tinymce/ui/Factory","tinymce/ui/KeyboardNavigation","tinymce/ui/Container","tinymce/ui/DragHelper","tinymce/ui/Scrollable","tinymce/ui/Panel","tinymce/ui/Movable","tinymce/ui/Resizable","tinymce/ui/FloatPanel","tinymce/ui/Window","tinymce/ui/MessageBox","tinymce/WindowManager","tinymce/util/Quirks","tinymce/util/Observable","tinymce/Shortcuts","tinymce/Editor","tinymce/util/I18n","tinymce/FocusManager","tinymce/EditorManager","tinymce/LegacyInput","tinymce/util/XHR","tinymce/util/JSON","tinymce/util/JSONRequest","tinymce/util/JSONP","tinymce/util/LocalStorage","tinymce/Compat","tinymce/ui/Layout","tinymce/ui/AbsoluteLayout","tinymce/ui/Tooltip","tinymce/ui/Widget","tinymce/ui/Button","tinymce/ui/ButtonGroup","tinymce/ui/Checkbox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/ui/ComboBox","tinymce/ui/Path","tinymce/ui/ElementPath","tinymce/ui/FormItem","tinymce/ui/Form","tinymce/ui/FieldSet","tinymce/ui/FilePicker","tinymce/ui/FitLayout","tinymce/ui/FlexLayout","tinymce/ui/FlowLayout","tinymce/ui/FormatControls","tinymce/ui/GridLayout","tinymce/ui/Iframe","tinymce/ui/Label","tinymce/ui/Toolbar","tinymce/ui/MenuBar","tinymce/ui/MenuButton","tinymce/ui/ListBox","tinymce/ui/MenuItem","tinymce/ui/Menu","tinymce/ui/Radio","tinymce/ui/ResizeHandle","tinymce/ui/Spacer","tinymce/ui/SplitButton","tinymce/ui/StackLayout","tinymce/ui/TabPanel","tinymce/ui/TextBox","tinymce/ui/Throbber"]);
32684
+ expose(["tinymce/dom/Sizzle","tinymce/html/Styles","tinymce/dom/EventUtils","tinymce/dom/TreeWalker","tinymce/util/Tools","tinymce/dom/Range","tinymce/html/Entities","tinymce/Env","tinymce/dom/StyleSheetLoader","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/html/Node","tinymce/html/Schema","tinymce/html/SaxParser","tinymce/html/DomParser","tinymce/html/Writer","tinymce/html/Serializer","tinymce/dom/Serializer","tinymce/dom/TridentSelection","tinymce/util/VK","tinymce/dom/ControlSelection","tinymce/dom/RangeUtils","tinymce/dom/Selection","tinymce/fmt/Preview","tinymce/Formatter","tinymce/UndoManager","tinymce/EnterKey","tinymce/ForceBlocks","tinymce/EditorCommands","tinymce/util/URI","tinymce/util/Class","tinymce/util/EventDispatcher","tinymce/ui/Selector","tinymce/ui/Collection","tinymce/ui/DomUtils","tinymce/ui/Control","tinymce/ui/Factory","tinymce/ui/KeyboardNavigation","tinymce/ui/Container","tinymce/ui/DragHelper","tinymce/ui/Scrollable","tinymce/ui/Panel","tinymce/ui/Movable","tinymce/ui/Resizable","tinymce/ui/FloatPanel","tinymce/ui/Window","tinymce/ui/MessageBox","tinymce/WindowManager","tinymce/util/Quirks","tinymce/util/Observable","tinymce/EditorObservable","tinymce/Shortcuts","tinymce/Editor","tinymce/util/I18n","tinymce/FocusManager","tinymce/EditorManager","tinymce/LegacyInput","tinymce/util/XHR","tinymce/util/JSON","tinymce/util/JSONRequest","tinymce/util/JSONP","tinymce/util/LocalStorage","tinymce/Compat","tinymce/ui/Layout","tinymce/ui/AbsoluteLayout","tinymce/ui/Tooltip","tinymce/ui/Widget","tinymce/ui/Button","tinymce/ui/ButtonGroup","tinymce/ui/Checkbox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/ui/ComboBox","tinymce/ui/Path","tinymce/ui/ElementPath","tinymce/ui/FormItem","tinymce/ui/Form","tinymce/ui/FieldSet","tinymce/ui/FilePicker","tinymce/ui/FitLayout","tinymce/ui/FlexLayout","tinymce/ui/FlowLayout","tinymce/ui/FormatControls","tinymce/ui/GridLayout","tinymce/ui/Iframe","tinymce/ui/Label","tinymce/ui/Toolbar","tinymce/ui/MenuBar","tinymce/ui/MenuButton","tinymce/ui/ListBox","tinymce/ui/MenuItem","tinymce/ui/Menu","tinymce/ui/Radio","tinymce/ui/ResizeHandle","tinymce/ui/Spacer","tinymce/ui/SplitButton","tinymce/ui/StackLayout","tinymce/ui/TabPanel","tinymce/ui/TextBox","tinymce/ui/Throbber"]);
32101
32685
  })(this);