tinymce-rails 4.1.6 → 4.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -2
  3. data/app/assets/source/tinymce/tinymce.jquery.js +1259 -591
  4. data/app/assets/source/tinymce/tinymce.js +1260 -592
  5. data/lib/tasks/tinymce-assets.rake +6 -3
  6. data/lib/tinymce/rails.rb +1 -1
  7. data/lib/tinymce/rails/asset_installer.rb +34 -36
  8. data/lib/tinymce/rails/asset_installer/compile.rb +44 -0
  9. data/lib/tinymce/rails/asset_installer/copy.rb +52 -0
  10. data/lib/tinymce/rails/asset_manifest.rb +108 -89
  11. data/lib/tinymce/rails/configuration.rb +14 -4
  12. data/lib/tinymce/rails/engine.rb +13 -0
  13. data/lib/tinymce/rails/version.rb +2 -2
  14. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/legacyoutput/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/link/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/lists/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/plugins/media/plugin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/plugins/noneditable/plugin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  27. data/vendor/assets/javascripts/tinymce/plugins/print/plugin.js +1 -1
  28. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/plugins/textcolor/plugin.js +1 -1
  32. data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/skins/lightgray/content.inline.min.css +1 -1
  34. data/vendor/assets/javascripts/tinymce/skins/lightgray/content.min.css +1 -1
  35. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  36. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.svg +56 -56
  37. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  38. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  39. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  40. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.svg +57 -57
  41. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  42. data/vendor/assets/javascripts/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  43. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  44. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  45. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +16 -10
  46. data/vendor/assets/javascripts/tinymce/tinymce.js +13 -11
  47. metadata +6 -3
@@ -1,4 +1,4 @@
1
- // 4.1.6 (2014-10-08)
1
+ // 4.1.10 (2015-05-05)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -169,8 +169,8 @@ define("tinymce/dom/EventUtils", [], function() {
169
169
  event.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
170
170
  (doc && doc.clientLeft || body && body.clientLeft || 0);
171
171
 
172
- event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) -
173
- (doc && doc.clientTop || body && body.clientTop || 0);
172
+ event.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) -
173
+ (doc && doc.clientTop || body && body.clientTop || 0);
174
174
  }
175
175
 
176
176
  // Add preventDefault method
@@ -664,7 +664,7 @@ define("tinymce/dom/EventUtils", [], function() {
664
664
 
665
665
  /*jshint bitwise:false, expr:true, noempty:false, sub:true, eqnull:true, latedef:false, maxlen:255 */
666
666
  /*eslint dot-notation:0, no-empty:0, no-cond-assign:0, no-unused-expressions:0, new-cap:0 */
667
- /*eslint no-nested-ternary:0, func-style:0, no-bitwise:0, max-len:0, brace-style:0, no-return-assign:0 */
667
+ /*eslint no-nested-ternary:0, func-style:0, no-bitwise:0, max-len:0, brace-style:0, no-return-assign:0, no-multi-spaces:0 */
668
668
 
669
669
  /**
670
670
  * Sizzle CSS Selector Engine v@VERSION
@@ -2689,6 +2689,159 @@ if ( !assert(function( div ) {
2689
2689
  return Sizzle;
2690
2690
  });
2691
2691
 
2692
+ // Included from: js/tinymce/classes/Env.js
2693
+
2694
+ /**
2695
+ * Env.js
2696
+ *
2697
+ * Copyright, Moxiecode Systems AB
2698
+ * Released under LGPL License.
2699
+ *
2700
+ * License: http://www.tinymce.com/license
2701
+ * Contributing: http://www.tinymce.com/contributing
2702
+ */
2703
+
2704
+ /**
2705
+ * This class contains various environment constants like browser versions etc.
2706
+ * Normally you don't want to sniff specific browser versions but sometimes you have
2707
+ * to when it's impossible to feature detect. So use this with care.
2708
+ *
2709
+ * @class tinymce.Env
2710
+ * @static
2711
+ */
2712
+ define("tinymce/Env", [], function() {
2713
+ var nav = navigator, userAgent = nav.userAgent;
2714
+ var opera, webkit, ie, ie11, ie12, gecko, mac, iDevice, android;
2715
+
2716
+ opera = window.opera && window.opera.buildNumber;
2717
+ android = /Android/.test(userAgent);
2718
+ webkit = /WebKit/.test(userAgent);
2719
+ ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
2720
+ ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
2721
+ ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false;
2722
+ ie12 = (document.msElementsFromPoint && !ie && !ie11) ? 12 : false;
2723
+ ie = ie || ie11 || ie12;
2724
+ gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
2725
+ mac = userAgent.indexOf('Mac') != -1;
2726
+ iDevice = /(iPad|iPhone)/.test(userAgent);
2727
+
2728
+ if (ie12) {
2729
+ webkit = false;
2730
+ }
2731
+
2732
+ // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
2733
+ // says it has contentEditable support but there is no visible caret.
2734
+ var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534;
2735
+
2736
+ return {
2737
+ /**
2738
+ * Constant that is true if the browser is Opera.
2739
+ *
2740
+ * @property opera
2741
+ * @type Boolean
2742
+ * @final
2743
+ */
2744
+ opera: opera,
2745
+
2746
+ /**
2747
+ * Constant that is true if the browser is WebKit (Safari/Chrome).
2748
+ *
2749
+ * @property webKit
2750
+ * @type Boolean
2751
+ * @final
2752
+ */
2753
+ webkit: webkit,
2754
+
2755
+ /**
2756
+ * Constant that is more than zero if the browser is IE.
2757
+ *
2758
+ * @property ie
2759
+ * @type Boolean
2760
+ * @final
2761
+ */
2762
+ ie: ie,
2763
+
2764
+ /**
2765
+ * Constant that is true if the browser is Gecko.
2766
+ *
2767
+ * @property gecko
2768
+ * @type Boolean
2769
+ * @final
2770
+ */
2771
+ gecko: gecko,
2772
+
2773
+ /**
2774
+ * Constant that is true if the os is Mac OS.
2775
+ *
2776
+ * @property mac
2777
+ * @type Boolean
2778
+ * @final
2779
+ */
2780
+ mac: mac,
2781
+
2782
+ /**
2783
+ * Constant that is true if the os is iOS.
2784
+ *
2785
+ * @property iOS
2786
+ * @type Boolean
2787
+ * @final
2788
+ */
2789
+ iOS: iDevice,
2790
+
2791
+ /**
2792
+ * Constant that is true if the os is android.
2793
+ *
2794
+ * @property android
2795
+ * @type Boolean
2796
+ * @final
2797
+ */
2798
+ android: android,
2799
+
2800
+ /**
2801
+ * Constant that is true if the browser supports editing.
2802
+ *
2803
+ * @property contentEditable
2804
+ * @type Boolean
2805
+ * @final
2806
+ */
2807
+ contentEditable: contentEditable,
2808
+
2809
+ /**
2810
+ * Transparent image data url.
2811
+ *
2812
+ * @property transparentSrc
2813
+ * @type Boolean
2814
+ * @final
2815
+ */
2816
+ transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
2817
+
2818
+ /**
2819
+ * Returns true/false if the browser can or can't place the caret after a inline block like an image.
2820
+ *
2821
+ * @property noCaretAfter
2822
+ * @type Boolean
2823
+ * @final
2824
+ */
2825
+ caretAfter: ie != 8,
2826
+
2827
+ /**
2828
+ * Constant that is true if the browser supports native DOM Ranges. IE 9+.
2829
+ *
2830
+ * @property range
2831
+ * @type Boolean
2832
+ */
2833
+ range: window.getSelection && "Range" in window,
2834
+
2835
+ /**
2836
+ * Returns the IE document mode for non IE browsers this will fake IE 10.
2837
+ *
2838
+ * @property documentMode
2839
+ * @type Number
2840
+ */
2841
+ documentMode: ie && !ie12 ? (document.documentMode || 7) : 10
2842
+ };
2843
+ });
2844
+
2692
2845
  // Included from: js/tinymce/classes/util/Tools.js
2693
2846
 
2694
2847
  /**
@@ -2707,7 +2860,9 @@ return Sizzle;
2707
2860
  *
2708
2861
  * @class tinymce.util.Tools
2709
2862
  */
2710
- define("tinymce/util/Tools", [], function() {
2863
+ define("tinymce/util/Tools", [
2864
+ "tinymce/Env"
2865
+ ], function(Env) {
2711
2866
  /**
2712
2867
  * Removes whitespace from the beginning and end of a string.
2713
2868
  *
@@ -2736,20 +2891,20 @@ define("tinymce/util/Tools", [], function() {
2736
2891
  * Checks if a object is of a specific type for example an array.
2737
2892
  *
2738
2893
  * @method is
2739
- * @param {Object} o Object to check type of.
2740
- * @param {string} t Optional type to check for.
2894
+ * @param {Object} obj Object to check type of.
2895
+ * @param {string} type Optional type to check for.
2741
2896
  * @return {Boolean} true/false if the object is of the specified type.
2742
2897
  */
2743
- function is(o, t) {
2744
- if (!t) {
2745
- return o !== undefined;
2898
+ function is(obj, type) {
2899
+ if (!type) {
2900
+ return obj !== undefined;
2746
2901
  }
2747
2902
 
2748
- if (t == 'array' && isArray(o)) {
2903
+ if (type == 'array' && isArray(obj)) {
2749
2904
  return true;
2750
2905
  }
2751
2906
 
2752
- return typeof(o) == t;
2907
+ return typeof obj == type;
2753
2908
  }
2754
2909
 
2755
2910
  /**
@@ -2787,7 +2942,7 @@ define("tinymce/util/Tools", [], function() {
2787
2942
  items = items || [];
2788
2943
  delim = delim || ',';
2789
2944
 
2790
- if (typeof(items) == "string") {
2945
+ if (typeof items == "string") {
2791
2946
  items = items.split(delim);
2792
2947
  }
2793
2948
 
@@ -2856,18 +3011,18 @@ define("tinymce/util/Tools", [], function() {
2856
3011
  * one array list into another.
2857
3012
  *
2858
3013
  * @method map
2859
- * @param {Array} a Array of items to iterate.
2860
- * @param {function} f Function to call for each item. It's return value will be the new value.
3014
+ * @param {Array} array Array of items to iterate.
3015
+ * @param {function} callback Function to call for each item. It's return value will be the new value.
2861
3016
  * @return {Array} Array with new values based on function return values.
2862
3017
  */
2863
- function map(a, f) {
2864
- var o = [];
3018
+ function map(array, callback) {
3019
+ var out = [];
2865
3020
 
2866
- each(a, function(v) {
2867
- o.push(f(v));
3021
+ each(array, function(item) {
3022
+ out.push(callback(item));
2868
3023
  });
2869
3024
 
2870
- return o;
3025
+ return out;
2871
3026
  }
2872
3027
 
2873
3028
  /**
@@ -3020,6 +3175,7 @@ define("tinymce/util/Tools", [], function() {
3020
3175
 
3021
3176
  // Add static methods
3022
3177
  /*jshint sub:true*/
3178
+ /*eslint dot-notation:0*/
3023
3179
  self.each(p['static'], function(f, n) {
3024
3180
  ns[cn][n] = f;
3025
3181
  });
@@ -3179,6 +3335,16 @@ define("tinymce/util/Tools", [], function() {
3179
3335
  return map(s.split(d || ','), trim);
3180
3336
  }
3181
3337
 
3338
+ function _addCacheSuffix(url) {
3339
+ var cacheSuffix = Env.cacheSuffix;
3340
+
3341
+ if (cacheSuffix) {
3342
+ url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
3343
+ }
3344
+
3345
+ return url;
3346
+ }
3347
+
3182
3348
  return {
3183
3349
  trim: trim,
3184
3350
  isArray: isArray,
@@ -3194,145 +3360,8 @@ define("tinymce/util/Tools", [], function() {
3194
3360
  walk: walk,
3195
3361
  createNS: createNS,
3196
3362
  resolve: resolve,
3197
- explode: explode
3198
- };
3199
- });
3200
-
3201
- // Included from: js/tinymce/classes/Env.js
3202
-
3203
- /**
3204
- * Env.js
3205
- *
3206
- * Copyright, Moxiecode Systems AB
3207
- * Released under LGPL License.
3208
- *
3209
- * License: http://www.tinymce.com/license
3210
- * Contributing: http://www.tinymce.com/contributing
3211
- */
3212
-
3213
- /**
3214
- * This class contains various environment constants like browser versions etc.
3215
- * Normally you don't want to sniff specific browser versions but sometimes you have
3216
- * to when it's impossible to feature detect. So use this with care.
3217
- *
3218
- * @class tinymce.Env
3219
- * @static
3220
- */
3221
- define("tinymce/Env", [], function() {
3222
- var nav = navigator, userAgent = nav.userAgent;
3223
- var opera, webkit, ie, ie11, gecko, mac, iDevice;
3224
-
3225
- opera = window.opera && window.opera.buildNumber;
3226
- webkit = /WebKit/.test(userAgent);
3227
- ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
3228
- ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
3229
- ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false;
3230
- ie = ie || ie11;
3231
- gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
3232
- mac = userAgent.indexOf('Mac') != -1;
3233
- iDevice = /(iPad|iPhone)/.test(userAgent);
3234
-
3235
- // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
3236
- // says it has contentEditable support but there is no visible caret.
3237
- var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534;
3238
-
3239
- return {
3240
- /**
3241
- * Constant that is true if the browser is Opera.
3242
- *
3243
- * @property opera
3244
- * @type Boolean
3245
- * @final
3246
- */
3247
- opera: opera,
3248
-
3249
- /**
3250
- * Constant that is true if the browser is WebKit (Safari/Chrome).
3251
- *
3252
- * @property webKit
3253
- * @type Boolean
3254
- * @final
3255
- */
3256
- webkit: webkit,
3257
-
3258
- /**
3259
- * Constant that is more than zero if the browser is IE.
3260
- *
3261
- * @property ie
3262
- * @type Boolean
3263
- * @final
3264
- */
3265
- ie: ie,
3266
-
3267
- /**
3268
- * Constant that is true if the browser is Gecko.
3269
- *
3270
- * @property gecko
3271
- * @type Boolean
3272
- * @final
3273
- */
3274
- gecko: gecko,
3275
-
3276
- /**
3277
- * Constant that is true if the os is Mac OS.
3278
- *
3279
- * @property mac
3280
- * @type Boolean
3281
- * @final
3282
- */
3283
- mac: mac,
3284
-
3285
- /**
3286
- * Constant that is true if the os is iOS.
3287
- *
3288
- * @property iOS
3289
- * @type Boolean
3290
- * @final
3291
- */
3292
- iOS: iDevice,
3293
-
3294
- /**
3295
- * Constant that is true if the browser supports editing.
3296
- *
3297
- * @property contentEditable
3298
- * @type Boolean
3299
- * @final
3300
- */
3301
- contentEditable: contentEditable,
3302
-
3303
- /**
3304
- * Transparent image data url.
3305
- *
3306
- * @property transparentSrc
3307
- * @type Boolean
3308
- * @final
3309
- */
3310
- transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
3311
-
3312
- /**
3313
- * Returns true/false if the browser can or can't place the caret after a inline block like an image.
3314
- *
3315
- * @property noCaretAfter
3316
- * @type Boolean
3317
- * @final
3318
- */
3319
- caretAfter: ie != 8,
3320
-
3321
- /**
3322
- * Constant that is true if the browser supports native DOM Ranges. IE 9+.
3323
- *
3324
- * @property range
3325
- * @type Boolean
3326
- */
3327
- range: window.getSelection && "Range" in window,
3328
-
3329
- /**
3330
- * Returns the IE document mode for non IE browsers this will fake IE 10.
3331
- *
3332
- * @property documentMode
3333
- * @type Number
3334
- */
3335
- documentMode: ie ? (document.documentMode || 7) : 10
3363
+ explode: explode,
3364
+ _addCacheSuffix: _addCacheSuffix
3336
3365
  };
3337
3366
  });
3338
3367
 
@@ -3387,6 +3416,10 @@ define("tinymce/dom/DomQuery", [
3387
3416
  return typeof obj === 'string';
3388
3417
  }
3389
3418
 
3419
+ function isWindow(obj) {
3420
+ return obj && obj == obj.window;
3421
+ }
3422
+
3390
3423
  function createFragment(html, fragDoc) {
3391
3424
  var frag, node, container;
3392
3425
 
@@ -3677,10 +3710,6 @@ define("tinymce/dom/DomQuery", [
3677
3710
  return self.add(DomQuery(items));
3678
3711
  }
3679
3712
 
3680
- if (items.nodeType) {
3681
- return self.add([items]);
3682
- }
3683
-
3684
3713
  if (sort !== false) {
3685
3714
  nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items)));
3686
3715
  self.length = nodes.length;
@@ -3828,7 +3857,7 @@ define("tinymce/dom/DomQuery", [
3828
3857
  name = camel(name);
3829
3858
 
3830
3859
  // Default px suffix on these
3831
- if (typeof(value) === 'number' && !numericCssMap[name]) {
3860
+ if (typeof value === 'number' && !numericCssMap[name]) {
3832
3861
  value += 'px';
3833
3862
  }
3834
3863
 
@@ -4461,7 +4490,13 @@ define("tinymce/dom/DomQuery", [
4461
4490
  * @param {Object} object Object to convert to array.
4462
4491
  * @return {Arrau} Array produced from object.
4463
4492
  */
4464
- makeArray: Tools.toArray,
4493
+ makeArray: function(array) {
4494
+ if (isWindow(array) || array.nodeType) {
4495
+ return [array];
4496
+ }
4497
+
4498
+ return Tools.toArray(array);
4499
+ },
4465
4500
 
4466
4501
  /**
4467
4502
  * Returns the index of the specified item inside the array.
@@ -6174,7 +6209,7 @@ define("tinymce/html/Entities", [
6174
6209
  attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
6175
6210
  textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
6176
6211
  rawCharsRegExp = /[<>&\"\']/g,
6177
- entityRegExp = /&(#x|#)?([\w]+);/g,
6212
+ entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
6178
6213
  asciiMap = {
6179
6214
  128: "\u20AC", 130: "\u201A", 131: "\u0192", 132: "\u201E", 133: "\u2026", 134: "\u2020",
6180
6215
  135: "\u2021", 136: "\u02C6", 137: "\u2030", 138: "\u0160", 139: "\u2039", 140: "\u0152",
@@ -6388,17 +6423,21 @@ define("tinymce/html/Entities", [
6388
6423
  * @return {String} Entity decoded string.
6389
6424
  */
6390
6425
  decode: function(text) {
6391
- return text.replace(entityRegExp, function(all, numeric, value) {
6426
+ return text.replace(entityRegExp, function(all, numeric) {
6392
6427
  if (numeric) {
6393
- value = parseInt(value, numeric.length === 2 ? 16 : 10);
6428
+ if (numeric.charAt(0).toLowerCase() === 'x') {
6429
+ numeric = parseInt(numeric.substr(1), 16);
6430
+ } else {
6431
+ numeric = parseInt(numeric, 10);
6432
+ }
6394
6433
 
6395
6434
  // Support upper UTF
6396
- if (value > 0xFFFF) {
6397
- value -= 0x10000;
6435
+ if (numeric > 0xFFFF) {
6436
+ numeric -= 0x10000;
6398
6437
 
6399
- return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF));
6438
+ return String.fromCharCode(0xD800 + (numeric >> 10), 0xDC00 + (numeric & 0x3FF));
6400
6439
  } else {
6401
- return asciiMap[value] || String.fromCharCode(value);
6440
+ return asciiMap[numeric] || String.fromCharCode(numeric);
6402
6441
  }
6403
6442
  }
6404
6443
 
@@ -6428,7 +6467,9 @@ define("tinymce/html/Entities", [
6428
6467
  * @class tinymce.dom.StyleSheetLoader
6429
6468
  * @private
6430
6469
  */
6431
- define("tinymce/dom/StyleSheetLoader", [], function() {
6470
+ define("tinymce/dom/StyleSheetLoader", [
6471
+ "tinymce/util/Tools"
6472
+ ], function(Tools) {
6432
6473
  "use strict";
6433
6474
 
6434
6475
  return function(document, settings) {
@@ -6525,6 +6566,8 @@ define("tinymce/dom/StyleSheetLoader", [], function() {
6525
6566
  }, waitForGeckoLinkLoaded);
6526
6567
  }
6527
6568
 
6569
+ url = Tools._addCacheSuffix(url);
6570
+
6528
6571
  if (!loadedStates[url]) {
6529
6572
  state = {
6530
6573
  passed: [],
@@ -6971,7 +7014,7 @@ define("tinymce/dom/DOMUtils", [
6971
7014
  get: function(elm) {
6972
7015
  var name;
6973
7016
 
6974
- if (elm && this.doc && typeof(elm) == 'string') {
7017
+ if (elm && this.doc && typeof elm == 'string') {
6975
7018
  name = elm;
6976
7019
  elm = this.doc.getElementById(elm);
6977
7020
 
@@ -7154,7 +7197,7 @@ define("tinymce/dom/DOMUtils", [
7154
7197
  }
7155
7198
 
7156
7199
  // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime
7157
- if (typeof(html) != "undefined") {
7200
+ if (typeof html != "undefined") {
7158
7201
  return outHtml + '>' + html + '</' + name + '>';
7159
7202
  }
7160
7203
 
@@ -7561,6 +7604,8 @@ define("tinymce/dom/DOMUtils", [
7561
7604
  each(url.split(','), function(url) {
7562
7605
  var link;
7563
7606
 
7607
+ url = Tools._addCacheSuffix(url);
7608
+
7564
7609
  if (self.files[url]) {
7565
7610
  return;
7566
7611
  }
@@ -7753,7 +7798,9 @@ define("tinymce/dom/DOMUtils", [
7753
7798
  */
7754
7799
  getOuterHTML: function(elm) {
7755
7800
  elm = this.get(elm);
7756
- return elm.nodeType == 1 ? elm.outerHTML : $('<div>').append($(elm).clone()).html();
7801
+
7802
+ // Older FF doesn't have outerHTML 3.6 is still used by some orgaizations
7803
+ return elm.nodeType == 1 && "outerHTML" in elm ? elm.outerHTML : $('<div>').append($(elm).clone()).html();
7757
7804
  },
7758
7805
 
7759
7806
  /**
@@ -7775,11 +7822,17 @@ define("tinymce/dom/DOMUtils", [
7775
7822
 
7776
7823
  self.$$(elm).each(function() {
7777
7824
  try {
7778
- this.outerHTML = html;
7825
+ // Older FF doesn't have outerHTML 3.6 is still used by some orgaizations
7826
+ if ("outerHTML" in this) {
7827
+ this.outerHTML = html;
7828
+ return;
7829
+ }
7779
7830
  } catch (ex) {
7780
- // OuterHTML for IE it sometimes produces an "unknown runtime error"
7781
- self.remove($(this).html(html), true);
7831
+ // Ignore
7782
7832
  }
7833
+
7834
+ // OuterHTML for IE it sometimes produces an "unknown runtime error"
7835
+ self.remove($(this).html(html), true);
7783
7836
  });
7784
7837
  },
7785
7838
 
@@ -7937,7 +7990,7 @@ define("tinymce/dom/DOMUtils", [
7937
7990
  run: function(elm, func, scope) {
7938
7991
  var self = this, result;
7939
7992
 
7940
- if (typeof(elm) === 'string') {
7993
+ if (typeof elm === 'string') {
7941
7994
  elm = self.get(elm);
7942
7995
  }
7943
7996
 
@@ -7951,7 +8004,7 @@ define("tinymce/dom/DOMUtils", [
7951
8004
 
7952
8005
  each(elm, function(elm, i) {
7953
8006
  if (elm) {
7954
- if (typeof(elm) == 'string') {
8007
+ if (typeof elm == 'string') {
7955
8008
  elm = self.get(elm);
7956
8009
  }
7957
8010
 
@@ -8393,7 +8446,7 @@ define("tinymce/dom/DOMUtils", [
8393
8446
 
8394
8447
  if (node) {
8395
8448
  // If expression make a function of it using is
8396
- if (typeof(func) == 'string') {
8449
+ if (typeof func == 'string') {
8397
8450
  func = function(node) {
8398
8451
  return self.is(node, selector);
8399
8452
  };
@@ -8509,7 +8562,7 @@ define("tinymce/dom/ScriptLoader", [
8509
8562
  /*eslint no-console:0 */
8510
8563
 
8511
8564
  // Report the error so it's easier for people to spot loading errors
8512
- if (typeof(console) !== "undefined" && console.log) {
8565
+ if (typeof console !== "undefined" && console.log) {
8513
8566
  console.log("Failed to load: " + url);
8514
8567
  }
8515
8568
 
@@ -8525,7 +8578,7 @@ define("tinymce/dom/ScriptLoader", [
8525
8578
  elm = document.createElement('script');
8526
8579
  elm.id = id;
8527
8580
  elm.type = 'text/javascript';
8528
- elm.src = url;
8581
+ elm.src = Tools._addCacheSuffix(url);
8529
8582
 
8530
8583
  // Seems that onreadystatechange works better on IE 10 onload seems to fire incorrectly
8531
8584
  if ("onreadystatechange" in elm) {
@@ -8968,7 +9021,6 @@ define("tinymce/AddOnManager", [
8968
9021
  * This class contains a few utility methods for ranges.
8969
9022
  *
8970
9023
  * @class tinymce.dom.RangeUtils
8971
- * @private
8972
9024
  */
8973
9025
  define("tinymce/dom/RangeUtils", [
8974
9026
  "tinymce/util/Tools",
@@ -9343,7 +9395,7 @@ define("tinymce/dom/RangeUtils", [
9343
9395
  container = node.parentNode;
9344
9396
 
9345
9397
  // Put caret after image when moving the end point
9346
- if (node.nodeName == "IMG" && !directionLeft) {
9398
+ if (node.nodeName == "IMG" && !directionLeft) {
9347
9399
  offset++;
9348
9400
  }
9349
9401
 
@@ -9446,6 +9498,53 @@ define("tinymce/dom/RangeUtils", [
9446
9498
  return false;
9447
9499
  };
9448
9500
 
9501
+ /**
9502
+ * Gets the caret range for the given x/y location.
9503
+ *
9504
+ * @static
9505
+ * @method getCaretRangeFromPoint
9506
+ * @param {Number} x X coordinate for range
9507
+ * @param {Number} y Y coordinate for range
9508
+ * @param {Document} doc Document that x/y are relative to
9509
+ * @returns {Range} caret range
9510
+ */
9511
+ RangeUtils.getCaretRangeFromPoint = function(x, y, doc) {
9512
+ var rng, point;
9513
+
9514
+ if (doc.caretPositionFromPoint) {
9515
+ point = doc.caretPositionFromPoint(x, y);
9516
+ rng = doc.createRange();
9517
+ rng.setStart(point.offsetNode, point.offset);
9518
+ rng.collapse(true);
9519
+ } else if (doc.caretRangeFromPoint) {
9520
+ rng = doc.caretRangeFromPoint(x, y);
9521
+ } else if (doc.body.createTextRange) {
9522
+ rng = doc.body.createTextRange();
9523
+
9524
+ try {
9525
+ rng.moveToPoint(x, y);
9526
+ rng.collapse(true);
9527
+ } catch (ex) {
9528
+ // Append to top or bottom depending on drop location
9529
+ rng.collapse(y < doc.body.clientHeight);
9530
+ }
9531
+ }
9532
+
9533
+ return rng;
9534
+ };
9535
+
9536
+ RangeUtils.getNode = function(container, offset) {
9537
+ if (container.nodeType == 1 && container.hasChildNodes()) {
9538
+ if (offset >= container.childNodes.length) {
9539
+ offset = container.childNodes.length - 1;
9540
+ }
9541
+
9542
+ container = container.childNodes[offset];
9543
+ }
9544
+
9545
+ return container;
9546
+ };
9547
+
9449
9548
  return RangeUtils;
9450
9549
  });
9451
9550
 
@@ -9468,8 +9567,9 @@ define("tinymce/dom/RangeUtils", [
9468
9567
  * @private
9469
9568
  */
9470
9569
  define("tinymce/NodeChange", [
9471
- "tinymce/dom/RangeUtils"
9472
- ], function(RangeUtils) {
9570
+ "tinymce/dom/RangeUtils",
9571
+ "tinymce/Env"
9572
+ ], function(RangeUtils, Env) {
9473
9573
  return function(editor) {
9474
9574
  var lastRng, lastPath = [];
9475
9575
 
@@ -9532,11 +9632,17 @@ define("tinymce/NodeChange", [
9532
9632
  editor.fire('SelectionChange');
9533
9633
  });
9534
9634
 
9635
+ // Selection change is delayed ~200ms on IE when you click inside the current range
9535
9636
  editor.on('SelectionChange', function() {
9536
9637
  var startElm = editor.selection.getStart(true);
9537
9638
 
9538
- // Fire a nodechange only when the selection isn't collapsed since focusout will collapse and remove the selection
9539
- if (!editor.selection.isCollapsed() && !isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
9639
+ // IE 8 will fire a selectionchange event with an incorrect selection
9640
+ // when focusing out of table cells. Click inside cell -> toolbar = Invalid SelectionChange event
9641
+ if (!Env.range && editor.selection.isCollapsed()) {
9642
+ return;
9643
+ }
9644
+
9645
+ if (!isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
9540
9646
  editor.nodeChanged({selectionChange: true});
9541
9647
  }
9542
9648
  });
@@ -9546,9 +9652,13 @@ define("tinymce/NodeChange", [
9546
9652
  if (!e.isDefaultPrevented()) {
9547
9653
  // Delay nodeChanged call for WebKit edge case issue where the range
9548
9654
  // isn't updated until after you click outside a selected image
9549
- setTimeout(function() {
9655
+ if (editor.selection.getNode().nodeName == 'IMG') {
9656
+ setTimeout(function() {
9657
+ editor.nodeChanged();
9658
+ }, 0);
9659
+ } else {
9550
9660
  editor.nodeChanged();
9551
- }, 0);
9661
+ }
9552
9662
  }
9553
9663
  });
9554
9664
 
@@ -10156,13 +10266,13 @@ define("tinymce/html/Schema", [
10156
10266
  children = children || [];
10157
10267
  attributes = attributes || "";
10158
10268
 
10159
- if (typeof(children) === "string") {
10269
+ if (typeof children === "string") {
10160
10270
  children = split(children);
10161
10271
  }
10162
10272
 
10163
10273
  // Split string children
10164
10274
  for (i = 3; i < args.length; i++) {
10165
- if (typeof(args[i]) === "string") {
10275
+ if (typeof args[i] === "string") {
10166
10276
  args[i] = split(args[i]);
10167
10277
  }
10168
10278
 
@@ -10282,7 +10392,7 @@ define("tinymce/html/Schema", [
10282
10392
  add("a", "href target rel media hreflang type", phrasingContent);
10283
10393
  add("q", "cite", phrasingContent);
10284
10394
  add("ins del", "cite datetime", flowContent);
10285
- add("img", "src alt usemap ismap width height");
10395
+ add("img", "src sizes srcset alt usemap ismap width height");
10286
10396
  add("iframe", "src name width height", flowContent);
10287
10397
  add("embed", "src type width height");
10288
10398
  add("object", "data type typemustmatch name usemap form width height", flowContent, "param");
@@ -10321,7 +10431,8 @@ define("tinymce/html/Schema", [
10321
10431
  add("video", "src crossorigin poster preload autoplay mediagroup loop " +
10322
10432
  "muted controls width height buffered", flowContent, "track source");
10323
10433
  add("audio", "src crossorigin preload autoplay mediagroup loop muted controls buffered volume", flowContent, "track source");
10324
- add("source", "src type media");
10434
+ add("picture", "", "img source");
10435
+ add("source", "src srcset type media sizes");
10325
10436
  add("track", "kind src srclang label default");
10326
10437
  add("datalist", "", phrasingContent, "option");
10327
10438
  add("article section nav aside header footer", "", flowContent);
@@ -10425,7 +10536,7 @@ define("tinymce/html/Schema", [
10425
10536
 
10426
10537
  // Convert styles into a rule list
10427
10538
  each(value, function(value, key) {
10428
- styles[key] = mode == 'map' ? makeMap(value, /[, ]/) : explode(value, /[, ]/);
10539
+ styles[key] = styles[key.toUpperCase()] = mode == 'map' ? makeMap(value, /[, ]/) : explode(value, /[, ]/);
10429
10540
  });
10430
10541
  }
10431
10542
 
@@ -10442,7 +10553,7 @@ define("tinymce/html/Schema", [
10442
10553
  return function(settings) {
10443
10554
  var self = this, elements = {}, children = {}, patternElements = [], validStyles, invalidStyles, schemaItems;
10444
10555
  var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, validClasses;
10445
- var blockElementsMap, nonEmptyElementsMap, textBlockElementsMap, textInlineElementsMap;
10556
+ var blockElementsMap, nonEmptyElementsMap, moveCaretBeforeOnEnterElementsMap, textBlockElementsMap, textInlineElementsMap;
10446
10557
  var customElementsMap = {}, specialElements = {};
10447
10558
 
10448
10559
  // Creates an lookup table map object for the specified option or the default value
@@ -10487,6 +10598,7 @@ define("tinymce/html/Schema", [
10487
10598
  boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' +
10488
10599
  'noshade nowrap readonly selected autoplay loop controls');
10489
10600
  nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap);
10601
+ moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', 'table', nonEmptyElementsMap);
10490
10602
  textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
10491
10603
  'blockquote center dir fieldset header footer article section hgroup aside nav figure');
10492
10604
  blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
@@ -10948,6 +11060,17 @@ define("tinymce/html/Schema", [
10948
11060
  return nonEmptyElementsMap;
10949
11061
  };
10950
11062
 
11063
+ /**
11064
+ * Returns a map with elements that the caret should be moved in front of after enter is
11065
+ * pressed
11066
+ *
11067
+ * @method getMoveCaretBeforeOnEnterElements
11068
+ * @return {Object} Name/value lookup map for elements to place the caret in front of.
11069
+ */
11070
+ self.getMoveCaretBeforeOnEnterElements = function() {
11071
+ return moveCaretBeforeOnEnterElementsMap;
11072
+ };
11073
+
10951
11074
  /**
10952
11075
  * Returns a map with elements where white space is to be preserved like PRE or SCRIPT.
10953
11076
  *
@@ -12345,7 +12468,7 @@ define("tinymce/html/DomParser", [
12345
12468
  }
12346
12469
 
12347
12470
  validClassesMap = validClasses[node.name];
12348
- if (!valid && validClassesMap && !validClassesMap[className]) {
12471
+ if (!valid && validClassesMap && validClassesMap[className]) {
12349
12472
  valid = true;
12350
12473
  }
12351
12474
 
@@ -12529,7 +12652,7 @@ define("tinymce/html/Writer", [
12529
12652
  */
12530
12653
  pi: function(name, text) {
12531
12654
  if (text) {
12532
- html.push('<?', name, ' ', text, '?>');
12655
+ html.push('<?', name, ' ', encode(text), '?>');
12533
12656
  } else {
12534
12657
  html.push('<?', name, '?>');
12535
12658
  }
@@ -13674,7 +13797,7 @@ define("tinymce/util/VK", [
13674
13797
  UP: 38,
13675
13798
 
13676
13799
  modifierPressed: function(e) {
13677
- return e.shiftKey || e.ctrlKey || e.altKey;
13800
+ return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e);
13678
13801
  },
13679
13802
 
13680
13803
  metaKeyPressed: function(e) {
@@ -13718,14 +13841,14 @@ define("tinymce/dom/ControlSelection", [
13718
13841
  // Details about each resize handle how to scale etc
13719
13842
  resizeHandles = {
13720
13843
  // Name: x multiplier, y multiplier, delta size x, delta size y
13721
- n: [0.5, 0, 0, -1],
13722
- e: [1, 0.5, 1, 0],
13723
- s: [0.5, 1, 0, 1],
13724
- w: [0, 0.5, -1, 0],
13725
- nw: [0, 0, -1, -1],
13726
- ne: [1, 0, 1, -1],
13727
- se: [1, 1, 1, 1],
13728
- sw: [0, 1, -1, 1]
13844
+ n: [0.5, 0, 0, -1],
13845
+ e: [1, 0.5, 1, 0],
13846
+ s: [0.5, 1, 0, 1],
13847
+ w: [0, 0.5, -1, 0],
13848
+ nw: [0, 0, -1, -1],
13849
+ ne: [1, 0, 1, -1],
13850
+ se: [1, 1, 1, 1],
13851
+ sw: [0, 1, -1, 1]
13729
13852
  };
13730
13853
 
13731
13854
  // Add CSS for resize handles, cloned element and selected
@@ -15458,7 +15581,7 @@ define("tinymce/dom/Selection", [
15458
15581
  normalize: function() {
15459
15582
  var self = this, rng = self.getRng();
15460
15583
 
15461
- if (!isIE && new RangeUtils(self.dom).normalize(rng)) {
15584
+ if (Env.range && new RangeUtils(self.dom).normalize(rng)) {
15462
15585
  self.setRng(rng, self.isForward());
15463
15586
  }
15464
15587
 
@@ -15466,7 +15589,8 @@ define("tinymce/dom/Selection", [
15466
15589
  },
15467
15590
 
15468
15591
  /**
15469
- * Executes callback of the current selection matches the specified selector or not and passes the state and args to the callback.
15592
+ * Executes callback when the current selection starts/stops matching the specified selector. The current
15593
+ * state will be passed to the callback as it's first argument.
15470
15594
  *
15471
15595
  * @method selectorChanged
15472
15596
  * @param {String} selector CSS selector to check for.
@@ -15833,7 +15957,7 @@ define("tinymce/fmt/Preview", [
15833
15957
  }
15834
15958
 
15835
15959
  // Create block/inline element to use for preview
15836
- if (typeof(format) == "string") {
15960
+ if (typeof format == "string") {
15837
15961
  format = editor.formatter.get(format);
15838
15962
  if (!format) {
15839
15963
  return;
@@ -16011,6 +16135,10 @@ define("tinymce/Formatter", [
16011
16135
  return !!ed.schema.getTextBlockElements()[name.toLowerCase()];
16012
16136
  }
16013
16137
 
16138
+ function isTableCell(node) {
16139
+ return /^(TH|TD)$/.test(node.nodeName);
16140
+ }
16141
+
16014
16142
  function getParents(node, selector) {
16015
16143
  return dom.getParents(node, selector, dom.getRoot());
16016
16144
  }
@@ -16099,7 +16227,7 @@ define("tinymce/Formatter", [
16099
16227
 
16100
16228
  removeformat: [
16101
16229
  {
16102
- selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q',
16230
+ selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
16103
16231
  remove: 'all',
16104
16232
  split: true,
16105
16233
  expand: false,
@@ -16122,18 +16250,18 @@ define("tinymce/Formatter", [
16122
16250
 
16123
16251
  function addKeyboardShortcuts() {
16124
16252
  // Add some inline shortcuts
16125
- ed.addShortcut('ctrl+b', 'bold_desc', 'Bold');
16126
- ed.addShortcut('ctrl+i', 'italic_desc', 'Italic');
16127
- ed.addShortcut('ctrl+u', 'underline_desc', 'Underline');
16253
+ ed.addShortcut('meta+b', 'bold_desc', 'Bold');
16254
+ ed.addShortcut('meta+i', 'italic_desc', 'Italic');
16255
+ ed.addShortcut('meta+u', 'underline_desc', 'Underline');
16128
16256
 
16129
16257
  // BlockFormat shortcuts keys
16130
16258
  for (var i = 1; i <= 6; i++) {
16131
- ed.addShortcut('ctrl+' + i, '', ['FormatBlock', false, 'h' + i]);
16259
+ ed.addShortcut('access+' + i, '', ['FormatBlock', false, 'h' + i]);
16132
16260
  }
16133
16261
 
16134
- ed.addShortcut('ctrl+7', '', ['FormatBlock', false, 'p']);
16135
- ed.addShortcut('ctrl+8', '', ['FormatBlock', false, 'div']);
16136
- ed.addShortcut('ctrl+9', '', ['FormatBlock', false, 'address']);
16262
+ ed.addShortcut('access+7', '', ['FormatBlock', false, 'p']);
16263
+ ed.addShortcut('access+8', '', ['FormatBlock', false, 'div']);
16264
+ ed.addShortcut('access+9', '', ['FormatBlock', false, 'address']);
16137
16265
  }
16138
16266
 
16139
16267
  // Public functions
@@ -16159,7 +16287,7 @@ define("tinymce/Formatter", [
16159
16287
  */
16160
16288
  function register(name, format) {
16161
16289
  if (name) {
16162
- if (typeof(name) !== 'string') {
16290
+ if (typeof name !== 'string') {
16163
16291
  each(name, function(format, name) {
16164
16292
  register(name, format);
16165
16293
  });
@@ -16191,7 +16319,7 @@ define("tinymce/Formatter", [
16191
16319
  }
16192
16320
 
16193
16321
  // Split classes if needed
16194
- if (typeof(format.classes) === 'string') {
16322
+ if (typeof format.classes === 'string') {
16195
16323
  format.classes = format.classes.split(/\s+/);
16196
16324
  }
16197
16325
  });
@@ -16232,7 +16360,7 @@ define("tinymce/Formatter", [
16232
16360
  textDecoration = getTextDecoration(node.parentNode);
16233
16361
  if (ed.dom.getStyle(node, 'color') && textDecoration) {
16234
16362
  ed.dom.setStyle(node, 'text-decoration', textDecoration);
16235
- } else if (ed.dom.getStyle(node, 'textdecoration') === textDecoration) {
16363
+ } else if (ed.dom.getStyle(node, 'text-decoration') === textDecoration) {
16236
16364
  ed.dom.setStyle(node, 'text-decoration', null);
16237
16365
  }
16238
16366
  }
@@ -16708,6 +16836,11 @@ define("tinymce/Formatter", [
16708
16836
  out = out[start ? 'firstChild' : 'lastChild'];
16709
16837
  }
16710
16838
 
16839
+ // Since dom.remove removes empty text nodes then we need to try to find a better node
16840
+ if (out.nodeType == 3 && out.data.length === 0) {
16841
+ out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
16842
+ }
16843
+
16711
16844
  dom.remove(node, true);
16712
16845
 
16713
16846
  return out;
@@ -16738,29 +16871,36 @@ define("tinymce/Formatter", [
16738
16871
  // Try to adjust endContainer as well if cells on the same row were selected - bug #6410
16739
16872
  if (commonAncestorContainer &&
16740
16873
  /^T(HEAD|BODY|FOOT|R)$/.test(commonAncestorContainer.nodeName) &&
16741
- /^(TH|TD)$/.test(endContainer.nodeName) && endContainer.firstChild) {
16874
+ isTableCell(endContainer) && endContainer.firstChild) {
16742
16875
  endContainer = endContainer.firstChild || endContainer;
16743
16876
  }
16744
16877
 
16745
- // Wrap start/end nodes in span element since these might be cloned/moved
16746
- startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
16747
- endContainer = wrap(endContainer, 'span', {id: '_end', 'data-mce-type': 'bookmark'});
16878
+ if (dom.isChildOf(startContainer, endContainer) && !isTableCell(startContainer) && !isTableCell(endContainer)) {
16879
+ startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
16880
+ splitToFormatRoot(startContainer);
16881
+ startContainer = unwrap(TRUE);
16882
+ return;
16883
+ } else {
16884
+ // Wrap start/end nodes in span element since these might be cloned/moved
16885
+ startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
16886
+ endContainer = wrap(endContainer, 'span', {id: '_end', 'data-mce-type': 'bookmark'});
16748
16887
 
16749
- // Split start/end
16750
- splitToFormatRoot(startContainer);
16751
- splitToFormatRoot(endContainer);
16888
+ // Split start/end
16889
+ splitToFormatRoot(startContainer);
16890
+ splitToFormatRoot(endContainer);
16752
16891
 
16753
- // Unwrap start/end to get real elements again
16754
- startContainer = unwrap(TRUE);
16755
- endContainer = unwrap();
16892
+ // Unwrap start/end to get real elements again
16893
+ startContainer = unwrap(TRUE);
16894
+ endContainer = unwrap();
16895
+ }
16756
16896
  } else {
16757
16897
  startContainer = endContainer = splitToFormatRoot(startContainer);
16758
16898
  }
16759
16899
 
16760
16900
  // Update range positions since they might have changed after the split operations
16761
- rng.startContainer = startContainer.parentNode;
16901
+ rng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
16762
16902
  rng.startOffset = nodeIndex(startContainer);
16763
- rng.endContainer = endContainer.parentNode;
16903
+ rng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
16764
16904
  rng.endOffset = nodeIndex(endContainer) + 1;
16765
16905
  }
16766
16906
 
@@ -17233,7 +17373,7 @@ define("tinymce/Formatter", [
17233
17373
  * @return {String} New value with replaced variables.
17234
17374
  */
17235
17375
  function replaceVars(value, vars) {
17236
- if (typeof(value) != "string") {
17376
+ if (typeof value != "string") {
17237
17377
  value = value(vars);
17238
17378
  } else if (vars) {
17239
17379
  value = value.replace(/%(\w+)/g, function(str, name) {
@@ -17377,7 +17517,7 @@ define("tinymce/Formatter", [
17377
17517
  function findSpace(node, offset) {
17378
17518
  var pos, pos2, str = node.nodeValue;
17379
17519
 
17380
- if (typeof(offset) == "undefined") {
17520
+ if (typeof offset == "undefined") {
17381
17521
  offset = start ? str.length : 0;
17382
17522
  }
17383
17523
 
@@ -17648,7 +17788,7 @@ define("tinymce/Formatter", [
17648
17788
  value = normalizeStyleValue(replaceVars(value, vars), name);
17649
17789
 
17650
17790
  // Indexed array
17651
- if (typeof(name) === 'number') {
17791
+ if (typeof name === 'number') {
17652
17792
  name = value;
17653
17793
  compare_node = 0;
17654
17794
  }
@@ -17673,7 +17813,7 @@ define("tinymce/Formatter", [
17673
17813
  value = replaceVars(value, vars);
17674
17814
 
17675
17815
  // Indexed array
17676
- if (typeof(name) === 'number') {
17816
+ if (typeof name === 'number') {
17677
17817
  name = value;
17678
17818
  compare_node = 0;
17679
17819
  }
@@ -17686,7 +17826,7 @@ define("tinymce/Formatter", [
17686
17826
  // Build new class value where everything is removed except the internal prefixed classes
17687
17827
  valueOut = '';
17688
17828
  each(value.split(/\s+/), function(cls) {
17689
- if (/mce\w+/.test(cls)) {
17829
+ if (/mce\-\w+/.test(cls)) {
17690
17830
  valueOut += (valueOut ? ' ' : '') + cls;
17691
17831
  }
17692
17832
  });
@@ -18183,7 +18323,8 @@ define("tinymce/Formatter", [
18183
18323
  removeCaretContainer();
18184
18324
 
18185
18325
  // Remove caret container on keydown and it's a backspace, enter or left/right arrow keys
18186
- if (keyCode == 8 || keyCode == 37 || keyCode == 39) {
18326
+ // Backspace key needs to check if the range is collapsed due to bug #6780
18327
+ if ((keyCode == 8 && selection.isCollapsed()) || keyCode == 37 || keyCode == 39) {
18187
18328
  removeCaretContainer(getParentCaretContainer(selection.getStart()));
18188
18329
  }
18189
18330
 
@@ -18272,10 +18413,11 @@ define("tinymce/Formatter", [
18272
18413
  * @class tinymce.UndoManager
18273
18414
  */
18274
18415
  define("tinymce/UndoManager", [
18416
+ "tinymce/util/VK",
18275
18417
  "tinymce/Env",
18276
18418
  "tinymce/util/Tools",
18277
18419
  "tinymce/html/SaxParser"
18278
- ], function(Env, Tools, SaxParser) {
18420
+ ], function(VK, Env, Tools, SaxParser) {
18279
18421
  var trim = Tools.trim, trimContentRegExp;
18280
18422
 
18281
18423
  trimContentRegExp = new RegExp([
@@ -18322,6 +18464,10 @@ define("tinymce/UndoManager", [
18322
18464
  return trim(content);
18323
18465
  }
18324
18466
 
18467
+ function setDirty(state) {
18468
+ editor.isNotDirty = !state;
18469
+ }
18470
+
18325
18471
  function addNonTypingUndoLevel(e) {
18326
18472
  self.typing = false;
18327
18473
  self.add({}, e);
@@ -18371,9 +18517,9 @@ define("tinymce/UndoManager", [
18371
18517
 
18372
18518
  // Fire a TypingUndo event on the first character entered
18373
18519
  if (isFirstTypedCharacter && self.typing) {
18374
- // Make the it dirty if the content was changed after typing the first character
18520
+ // Make it dirty if the content was changed after typing the first character
18375
18521
  if (!editor.isDirty()) {
18376
- editor.isNotDirty = !data[0] || getContent() == data[0].content;
18522
+ setDirty(data[0] && getContent() != data[0].content);
18377
18523
 
18378
18524
  // Fire initial change event
18379
18525
  if (!editor.isNotDirty) {
@@ -18399,8 +18545,9 @@ define("tinymce/UndoManager", [
18399
18545
  return;
18400
18546
  }
18401
18547
 
18402
- // If key isn't shift,ctrl,alt,capslock,metakey
18403
- if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing) {
18548
+ // If key isn't Ctrl+Alt/AltGr
18549
+ var modKey = (e.ctrlKey && !e.altKey) || e.metaKey;
18550
+ if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing && !modKey) {
18404
18551
  self.beforeChange();
18405
18552
  self.typing = true;
18406
18553
  self.add({}, e);
@@ -18415,8 +18562,8 @@ define("tinymce/UndoManager", [
18415
18562
  });
18416
18563
 
18417
18564
  // Add keyboard shortcuts for undo/redo keys
18418
- editor.addShortcut('ctrl+z', '', 'Undo');
18419
- editor.addShortcut('ctrl+y,ctrl+shift+z', '', 'Redo');
18565
+ editor.addShortcut('meta+z', '', 'Undo');
18566
+ editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
18420
18567
 
18421
18568
  editor.on('AddUndo Undo Redo ClearUndos', function(e) {
18422
18569
  if (!e.isDefaultPrevented()) {
@@ -18424,6 +18571,7 @@ define("tinymce/UndoManager", [
18424
18571
  }
18425
18572
  });
18426
18573
 
18574
+ /*eslint consistent-this:0 */
18427
18575
  self = {
18428
18576
  // Explose for debugging reasons
18429
18577
  data: data,
@@ -18509,7 +18657,7 @@ define("tinymce/UndoManager", [
18509
18657
  editor.fire('AddUndo', args);
18510
18658
 
18511
18659
  if (index > 0) {
18512
- editor.isNotDirty = false;
18660
+ setDirty(true);
18513
18661
  editor.fire('change', args);
18514
18662
  }
18515
18663
 
@@ -18535,7 +18683,7 @@ define("tinymce/UndoManager", [
18535
18683
 
18536
18684
  // Undo to first index then set dirty state to false
18537
18685
  if (index === 0) {
18538
- editor.isNotDirty = true;
18686
+ setDirty(false);
18539
18687
  }
18540
18688
 
18541
18689
  editor.setContent(level.content, {format: 'raw'});
@@ -18561,6 +18709,7 @@ define("tinymce/UndoManager", [
18561
18709
 
18562
18710
  editor.setContent(level.content, {format: 'raw'});
18563
18711
  editor.selection.moveToBookmark(level.bookmark);
18712
+ setDirty(true);
18564
18713
 
18565
18714
  editor.fire('redo', {level: level});
18566
18715
  }
@@ -18652,7 +18801,8 @@ define("tinymce/EnterKey", [
18652
18801
 
18653
18802
  return function(editor) {
18654
18803
  var dom = editor.dom, selection = editor.selection, settings = editor.settings;
18655
- var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
18804
+ var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements(),
18805
+ moveCaretBeforeOnEnterElementsMap = schema.getMoveCaretBeforeOnEnterElements();
18656
18806
 
18657
18807
  function handleEnterKey(evt) {
18658
18808
  var rng, tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
@@ -18717,7 +18867,6 @@ define("tinymce/EnterKey", [
18717
18867
  // pure whitespace text node or before an image
18718
18868
  function moveToCaretPosition(root) {
18719
18869
  var walker, node, rng, lastNode = root, tempElm;
18720
-
18721
18870
  function firstNonWhiteSpaceNodeSibling(node) {
18722
18871
  while (node) {
18723
18872
  if (node.nodeType == 1 || (node.nodeType == 3 && node.data && /[\r\n\s]/.test(node.data))) {
@@ -18768,7 +18917,7 @@ define("tinymce/EnterKey", [
18768
18917
  break;
18769
18918
  }
18770
18919
 
18771
- if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
18920
+ if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
18772
18921
  rng.setStartBefore(node);
18773
18922
  rng.setEndBefore(node);
18774
18923
  break;
@@ -19437,13 +19586,18 @@ define("tinymce/EditorCommands", [
19437
19586
  var TRUE = true, FALSE = false;
19438
19587
 
19439
19588
  return function(editor) {
19440
- var dom = editor.dom,
19441
- selection = editor.selection,
19589
+ var dom, selection, formatter,
19442
19590
  commands = {state: {}, exec: {}, value: {}},
19443
19591
  settings = editor.settings,
19444
- formatter = editor.formatter,
19445
19592
  bookmark;
19446
19593
 
19594
+ editor.on('PreInit', function() {
19595
+ dom = editor.dom;
19596
+ selection = editor.selection;
19597
+ settings = editor.settings;
19598
+ formatter = editor.formatter;
19599
+ });
19600
+
19447
19601
  /**
19448
19602
  * Executes the specified command.
19449
19603
  *
@@ -19453,16 +19607,58 @@ define("tinymce/EditorCommands", [
19453
19607
  * @param {Object} value Optional value for command.
19454
19608
  * @return {Boolean} true/false if the command was found or not.
19455
19609
  */
19456
- function execCommand(command, ui, value) {
19457
- var func;
19610
+ function execCommand(command, ui, value, args) {
19611
+ var func, customCommand, state = 0;
19458
19612
 
19459
- command = command.toLowerCase();
19460
- if ((func = commands.exec[command])) {
19461
- func(command, ui, value);
19462
- return TRUE;
19613
+ if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
19614
+ editor.focus();
19463
19615
  }
19464
19616
 
19465
- return FALSE;
19617
+ args = extend({}, args);
19618
+ args = editor.fire('BeforeExecCommand', {command: command, ui: ui, value: value});
19619
+ if (args.isDefaultPrevented()) {
19620
+ return false;
19621
+ }
19622
+
19623
+ customCommand = command.toLowerCase();
19624
+ if ((func = commands.exec[customCommand])) {
19625
+ func(customCommand, ui, value);
19626
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
19627
+ return true;
19628
+ }
19629
+
19630
+ // Plugin commands
19631
+ each(editor.plugins, function(p) {
19632
+ if (p.execCommand && p.execCommand(command, ui, value)) {
19633
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
19634
+ state = true;
19635
+ return false;
19636
+ }
19637
+ });
19638
+
19639
+ if (state) {
19640
+ return state;
19641
+ }
19642
+
19643
+ // Theme commands
19644
+ if (editor.theme && editor.theme.execCommand && editor.theme.execCommand(command, ui, value)) {
19645
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
19646
+ return true;
19647
+ }
19648
+
19649
+ // Browser commands
19650
+ try {
19651
+ state = editor.getDoc().execCommand(command, ui, value);
19652
+ } catch (ex) {
19653
+ // Ignore old IE errors
19654
+ }
19655
+
19656
+ if (state) {
19657
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
19658
+ return true;
19659
+ }
19660
+
19661
+ return false;
19466
19662
  }
19467
19663
 
19468
19664
  /**
@@ -19475,12 +19671,24 @@ define("tinymce/EditorCommands", [
19475
19671
  function queryCommandState(command) {
19476
19672
  var func;
19477
19673
 
19674
+ // Is hidden then return undefined
19675
+ if (editor._isHidden()) {
19676
+ return;
19677
+ }
19678
+
19478
19679
  command = command.toLowerCase();
19479
19680
  if ((func = commands.state[command])) {
19480
19681
  return func(command);
19481
19682
  }
19482
19683
 
19483
- return -1;
19684
+ // Browser commands
19685
+ try {
19686
+ return editor.getDoc().queryCommandState(command);
19687
+ } catch (ex) {
19688
+ // Fails sometimes see bug: 1896577
19689
+ }
19690
+
19691
+ return false;
19484
19692
  }
19485
19693
 
19486
19694
  /**
@@ -19493,12 +19701,22 @@ define("tinymce/EditorCommands", [
19493
19701
  function queryCommandValue(command) {
19494
19702
  var func;
19495
19703
 
19704
+ // Is hidden then return undefined
19705
+ if (editor._isHidden()) {
19706
+ return;
19707
+ }
19708
+
19496
19709
  command = command.toLowerCase();
19497
19710
  if ((func = commands.value[command])) {
19498
19711
  return func(command);
19499
19712
  }
19500
19713
 
19501
- return FALSE;
19714
+ // Browser commands
19715
+ try {
19716
+ return editor.getDoc().queryCommandValue(command);
19717
+ } catch (ex) {
19718
+ // Fails sometimes see bug: 1896577
19719
+ }
19502
19720
  }
19503
19721
 
19504
19722
  /**
@@ -19518,12 +19736,67 @@ define("tinymce/EditorCommands", [
19518
19736
  });
19519
19737
  }
19520
19738
 
19739
+ function addCommand(command, callback, scope) {
19740
+ command = command.toLowerCase();
19741
+ commands.exec[command] = function(command, ui, value, args) {
19742
+ return callback.call(scope || editor, ui, value, args);
19743
+ };
19744
+ }
19745
+
19746
+ /**
19747
+ * Returns true/false if the command is supported or not.
19748
+ *
19749
+ * @method queryCommandSupported
19750
+ * @param {String} cmd Command that we check support for.
19751
+ * @return {Boolean} true/false if the command is supported or not.
19752
+ */
19753
+ function queryCommandSupported(command) {
19754
+ command = command.toLowerCase();
19755
+
19756
+ if (commands.exec[command]) {
19757
+ return true;
19758
+ }
19759
+
19760
+ // Browser commands
19761
+ try {
19762
+ return editor.getDoc().queryCommandSupported(command);
19763
+ } catch (ex) {
19764
+ // Fails sometimes see bug: 1896577
19765
+ }
19766
+
19767
+ return false;
19768
+ }
19769
+
19770
+ function addQueryStateHandler(command, callback, scope) {
19771
+ command = command.toLowerCase();
19772
+ commands.state[command] = function() {
19773
+ return callback.call(scope || editor);
19774
+ };
19775
+ }
19776
+
19777
+ function addQueryValueHandler(command, callback, scope) {
19778
+ command = command.toLowerCase();
19779
+ commands.value[command] = function() {
19780
+ return callback.call(scope || editor);
19781
+ };
19782
+ }
19783
+
19784
+ function hasCustomCommand(command) {
19785
+ command = command.toLowerCase();
19786
+ return !!commands.exec[command];
19787
+ }
19788
+
19521
19789
  // Expose public methods
19522
19790
  extend(this, {
19523
19791
  execCommand: execCommand,
19524
19792
  queryCommandState: queryCommandState,
19525
19793
  queryCommandValue: queryCommandValue,
19526
- addCommands: addCommands
19794
+ queryCommandSupported: queryCommandSupported,
19795
+ addCommands: addCommands,
19796
+ addCommand: addCommand,
19797
+ addQueryStateHandler: addQueryStateHandler,
19798
+ addQueryValueHandler: addQueryValueHandler,
19799
+ hasCustomCommand: hasCustomCommand
19527
19800
  });
19528
19801
 
19529
19802
  // Private methods
@@ -19755,6 +20028,31 @@ define("tinymce/EditorCommands", [
19755
20028
  return html;
19756
20029
  }
19757
20030
 
20031
+ // Removes &nbsp; from a [b] c -> a &nbsp;c -> a c
20032
+ function trimNbspAfterDeleteAndPaddValue() {
20033
+ var rng, container, offset;
20034
+
20035
+ rng = selection.getRng(true);
20036
+ container = rng.startContainer;
20037
+ offset = rng.startOffset;
20038
+
20039
+ if (container.nodeType == 3 && rng.collapsed) {
20040
+ if (container.data[offset] === '\u00a0') {
20041
+ container.deleteData(offset, 1);
20042
+
20043
+ if (!/[\u00a0| ]$/.test(value)) {
20044
+ value += ' ';
20045
+ }
20046
+ } else if (container.data[offset - 1] === '\u00a0') {
20047
+ container.deleteData(offset - 1, 1);
20048
+
20049
+ if (!/[\u00a0| ]$/.test(value)) {
20050
+ value = ' ' + value;
20051
+ }
20052
+ }
20053
+ }
20054
+ }
20055
+
19758
20056
  function markInlineFormatElements(fragment) {
19759
20057
  if (merge) {
19760
20058
  for (node = fragment.firstChild; node; node = node.walk(true)) {
@@ -19781,7 +20079,7 @@ define("tinymce/EditorCommands", [
19781
20079
  }
19782
20080
  }
19783
20081
 
19784
- if (typeof(value) != 'string') {
20082
+ if (typeof value != 'string') {
19785
20083
  merge = value.merge;
19786
20084
  value = value.content;
19787
20085
  }
@@ -19825,6 +20123,7 @@ define("tinymce/EditorCommands", [
19825
20123
  // Insert node maker where we will insert the new HTML and get it's parent
19826
20124
  if (!selection.isCollapsed()) {
19827
20125
  editor.getDoc().execCommand('Delete', false, null);
20126
+ trimNbspAfterDeleteAndPaddValue();
19828
20127
  }
19829
20128
 
19830
20129
  parentNode = selection.getNode();
@@ -20023,7 +20322,7 @@ define("tinymce/EditorCommands", [
20023
20322
  mceInsertLink: function(command, ui, value) {
20024
20323
  var anchor;
20025
20324
 
20026
- if (typeof(value) == 'string') {
20325
+ if (typeof value == 'string') {
20027
20326
  value = {href: value};
20028
20327
  }
20029
20328
 
@@ -20923,11 +21222,11 @@ define("tinymce/util/EventDispatcher", [
20923
21222
  handlers = bindings[name];
20924
21223
  if (handlers) {
20925
21224
  for (i = 0, l = handlers.length; i < l; i++) {
20926
- handlers[i] = callback = handlers[i];
21225
+ callback = handlers[i];
20927
21226
 
20928
21227
  // Unbind handlers marked with "once"
20929
21228
  if (callback.once) {
20930
- off(name, callback);
21229
+ off(name, callback.func);
20931
21230
  }
20932
21231
 
20933
21232
  // Stop immediate propagation if needed
@@ -20937,7 +21236,7 @@ define("tinymce/util/EventDispatcher", [
20937
21236
  }
20938
21237
 
20939
21238
  // If callback returns false then prevent default and stop all propagation
20940
- if (callback.call(scope, args) === false) {
21239
+ if (callback.func.call(scope, args) === false) {
20941
21240
  args.preventDefault();
20942
21241
  return args;
20943
21242
  }
@@ -20960,7 +21259,7 @@ define("tinymce/util/EventDispatcher", [
20960
21259
  * // Callback logic
20961
21260
  * });
20962
21261
  */
20963
- function on(name, callback, prepend) {
21262
+ function on(name, callback, prepend, extra) {
20964
21263
  var handlers, names, i;
20965
21264
 
20966
21265
  if (callback === false) {
@@ -20968,6 +21267,14 @@ define("tinymce/util/EventDispatcher", [
20968
21267
  }
20969
21268
 
20970
21269
  if (callback) {
21270
+ callback = {
21271
+ func: callback
21272
+ };
21273
+
21274
+ if (extra) {
21275
+ Tools.extend(callback, extra);
21276
+ }
21277
+
20971
21278
  names = name.toLowerCase().split(' ');
20972
21279
  i = names.length;
20973
21280
  while (i--) {
@@ -21034,7 +21341,7 @@ define("tinymce/util/EventDispatcher", [
21034
21341
  // Unbind specific ones
21035
21342
  hi = handlers.length;
21036
21343
  while (hi--) {
21037
- if (handlers[hi] === callback) {
21344
+ if (handlers[hi].func === callback) {
21038
21345
  handlers = handlers.slice(0, hi).concat(handlers.slice(hi + 1));
21039
21346
  bindings[name] = handlers;
21040
21347
  }
@@ -21073,8 +21380,7 @@ define("tinymce/util/EventDispatcher", [
21073
21380
  * });
21074
21381
  */
21075
21382
  function once(name, callback, prepend) {
21076
- callback.once = true;
21077
- return on(name, callback, prepend);
21383
+ return on(name, callback, prepend, {once: true});
21078
21384
  }
21079
21385
 
21080
21386
  /**
@@ -21593,7 +21899,7 @@ define("tinymce/ui/Collection", [
21593
21899
  var self = this, i, l, matches = [], item, match;
21594
21900
 
21595
21901
  // Compile string into selector expression
21596
- if (typeof(selector) === "string") {
21902
+ if (typeof selector === "string") {
21597
21903
  selector = new Selector(selector);
21598
21904
 
21599
21905
  match = function(item) {
@@ -21978,15 +22284,15 @@ define("tinymce/ui/DomUtils", [
21978
22284
  return document.getElementById(id);
21979
22285
  },
21980
22286
 
21981
- addClass : function(elm, cls) {
22287
+ addClass: function(elm, cls) {
21982
22288
  return DOMUtils.DOM.addClass(elm, cls);
21983
22289
  },
21984
22290
 
21985
- removeClass : function(elm, cls) {
22291
+ removeClass: function(elm, cls) {
21986
22292
  return DOMUtils.DOM.removeClass(elm, cls);
21987
22293
  },
21988
22294
 
21989
- hasClass : function(elm, cls) {
22295
+ hasClass: function(elm, cls) {
21990
22296
  return DOMUtils.DOM.hasClass(elm, cls);
21991
22297
  },
21992
22298
 
@@ -22230,7 +22536,7 @@ define("tinymce/ui/Control", [
22230
22536
  return;
22231
22537
  }
22232
22538
 
22233
- if (typeof(value) === "number") {
22539
+ if (typeof value === "number") {
22234
22540
  value = value || 0;
22235
22541
 
22236
22542
  return {
@@ -22330,7 +22636,7 @@ define("tinymce/ui/Control", [
22330
22636
  width = settings.width;
22331
22637
  height = settings.height;
22332
22638
  autoResize = settings.autoResize;
22333
- autoResize = typeof(autoResize) != "undefined" ? autoResize : !width && !height;
22639
+ autoResize = typeof autoResize != "undefined" ? autoResize : !width && !height;
22334
22640
 
22335
22641
  width = width || minWidth;
22336
22642
  height = height || minHeight;
@@ -22555,7 +22861,7 @@ define("tinymce/ui/Control", [
22555
22861
  function resolveCallbackName(name) {
22556
22862
  var callback, scope;
22557
22863
 
22558
- if (typeof(name) != 'string') {
22864
+ if (typeof name != 'string') {
22559
22865
  return name;
22560
22866
  }
22561
22867
 
@@ -22885,7 +23191,7 @@ define("tinymce/ui/Control", [
22885
23191
  visible: function(state) {
22886
23192
  var self = this, parentCtrl;
22887
23193
 
22888
- if (typeof(state) !== "undefined") {
23194
+ if (typeof state !== "undefined") {
22889
23195
  if (self._visible !== state) {
22890
23196
  if (self._rendered) {
22891
23197
  self.getEl().style.display = state ? '' : 'none';
@@ -22967,7 +23273,7 @@ define("tinymce/ui/Control", [
22967
23273
  aria: function(name, value) {
22968
23274
  var self = this, elm = self.getEl(self.ariaTarget);
22969
23275
 
22970
- if (typeof(value) === "undefined") {
23276
+ if (typeof value === "undefined") {
22971
23277
  return self._aria[name];
22972
23278
  } else {
22973
23279
  self._aria[name] = value;
@@ -23291,7 +23597,7 @@ define("tinymce/ui/Control", [
23291
23597
  for (i = lastParents.length - 1; i >= idx; i--) {
23292
23598
  lastCtrl = lastParents[i];
23293
23599
  lastCtrl.fire("mouseleave", {
23294
- target : lastCtrl.getEl()
23600
+ target: lastCtrl.getEl()
23295
23601
  });
23296
23602
  }
23297
23603
  }
@@ -23299,7 +23605,7 @@ define("tinymce/ui/Control", [
23299
23605
  for (i = idx; i < parents.length; i++) {
23300
23606
  ctrl = parents[i];
23301
23607
  ctrl.fire("mouseenter", {
23302
- target : ctrl.getEl()
23608
+ target: ctrl.getEl()
23303
23609
  });
23304
23610
  }
23305
23611
  }
@@ -23583,7 +23889,7 @@ define("tinymce/ui/Factory", [], function() {
23583
23889
  }
23584
23890
 
23585
23891
  // If string is specified then use it as the type
23586
- if (typeof(type) == 'string') {
23892
+ if (typeof type == 'string') {
23587
23893
  settings = settings || {};
23588
23894
  settings.type = type;
23589
23895
  } else {
@@ -24230,7 +24536,7 @@ define("tinymce/ui/Container", [
24230
24536
  // Construct item if needed
24231
24537
  if (!(item instanceof Control)) {
24232
24538
  // Name only then convert it to an object
24233
- if (typeof(item) == "string") {
24539
+ if (typeof item == "string") {
24234
24540
  item = {type: item};
24235
24541
  }
24236
24542
 
@@ -24368,7 +24674,7 @@ define("tinymce/ui/Container", [
24368
24674
  self.find('*').each(function(ctrl) {
24369
24675
  var name = ctrl.name(), value = ctrl.value();
24370
24676
 
24371
- if (name && typeof(value) != "undefined") {
24677
+ if (name && typeof value != "undefined") {
24372
24678
  data[name] = value;
24373
24679
  }
24374
24680
  });
@@ -24846,14 +25152,14 @@ define("tinymce/ui/Panel", [
24846
25152
  self.preRender();
24847
25153
  layout.preRender(self);
24848
25154
 
24849
- if (typeof(innerHtml) == "undefined") {
25155
+ if (typeof innerHtml == "undefined") {
24850
25156
  innerHtml = (
24851
25157
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
24852
25158
  layout.renderHtml(self) +
24853
25159
  '</div>'
24854
25160
  );
24855
25161
  } else {
24856
- if (typeof(innerHtml) == 'function') {
25162
+ if (typeof innerHtml == 'function') {
24857
25163
  innerHtml = innerHtml.call(self);
24858
25164
  }
24859
25165
 
@@ -25002,7 +25308,7 @@ define("tinymce/ui/Movable", [
25002
25308
  * @return {tinymce.ui.Control} Current control instance.
25003
25309
  */
25004
25310
  moveRel: function(elm, rel) {
25005
- if (typeof(rel) != 'string') {
25311
+ if (typeof rel != 'string') {
25006
25312
  rel = this.testMoveRel(elm, rel);
25007
25313
  }
25008
25314
 
@@ -25759,7 +26065,7 @@ define("tinymce/ui/Window", [
25759
26065
  html = '<iframe src="' + settings.url + '" tabindex="-1"></iframe>';
25760
26066
  }
25761
26067
 
25762
- if (typeof(html) == "undefined") {
26068
+ if (typeof html == "undefined") {
25763
26069
  html = layout.renderHtml(self);
25764
26070
  }
25765
26071
 
@@ -26108,7 +26414,7 @@ define("tinymce/ui/MessageBox", [
26108
26414
  * @param {function} [callback] Callback to execute when the user makes a choice.
26109
26415
  */
26110
26416
  alert: function(settings, callback) {
26111
- if (typeof(settings) == "string") {
26417
+ if (typeof settings == "string") {
26112
26418
  settings = {text: settings};
26113
26419
  }
26114
26420
 
@@ -26124,7 +26430,7 @@ define("tinymce/ui/MessageBox", [
26124
26430
  * @param {function} [callback] Callback to execute when the user makes a choice.
26125
26431
  */
26126
26432
  confirm: function(settings, callback) {
26127
- if (typeof(settings) == "string") {
26433
+ if (typeof settings == "string") {
26128
26434
  settings = {text: settings};
26129
26435
  }
26130
26436
 
@@ -26209,9 +26515,7 @@ define("tinymce/WindowManager", [
26209
26515
  * @option {String} file URL of the file to open in the window.
26210
26516
  * @option {Number} width Width in pixels.
26211
26517
  * @option {Number} height Height in pixels.
26212
- * @option {Boolean} resizable Specifies whether the popup window is resizable or not.
26213
- * @option {Boolean} maximizable Specifies whether the popup window has a "maximize" button and can get maximized or not.
26214
- * @option {String/Boolean} scrollbars Specifies whether the popup window can have scrollbars if required (i.e. content
26518
+ * @option {Boolean} autoScroll Specifies whether the popup window can have scrollbars if required (i.e. content
26215
26519
  * larger than the popup size specified).
26216
26520
  */
26217
26521
  self.open = function(args, params) {
@@ -26407,16 +26711,19 @@ define("tinymce/WindowManager", [
26407
26711
  define("tinymce/util/Quirks", [
26408
26712
  "tinymce/util/VK",
26409
26713
  "tinymce/dom/RangeUtils",
26714
+ "tinymce/dom/TreeWalker",
26410
26715
  "tinymce/html/Node",
26411
26716
  "tinymce/html/Entities",
26412
26717
  "tinymce/Env",
26413
26718
  "tinymce/util/Tools"
26414
- ], function(VK, RangeUtils, Node, Entities, Env, Tools) {
26719
+ ], function(VK, RangeUtils, TreeWalker, Node, Entities, Env, Tools) {
26415
26720
  return function(editor) {
26416
- var each = Tools.each;
26721
+ var each = Tools.each, $ = editor.$;
26417
26722
  var BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection,
26418
26723
  settings = editor.settings, parser = editor.parser, serializer = editor.serializer;
26419
26724
  var isGecko = Env.gecko, isIE = Env.ie, isWebKit = Env.webkit;
26725
+ var mceInternalUrlPrefix = 'data:text/mce-internal,';
26726
+ var mceInternalDataType = isIE ? 'Text' : 'URL';
26420
26727
 
26421
26728
  /**
26422
26729
  * Executes a command with a specific state this can be to enable/disable browser editing features.
@@ -26449,6 +26756,69 @@ define("tinymce/util/Quirks", [
26449
26756
  return e.isDefaultPrevented();
26450
26757
  }
26451
26758
 
26759
+ /**
26760
+ * Sets Text/URL data on the event's dataTransfer object to a special data:text/mce-internal url.
26761
+ * This is to workaround the inability to set custom contentType on IE and Safari.
26762
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
26763
+ *
26764
+ * @private
26765
+ * @param {DragEvent} e Event object
26766
+ */
26767
+ function setMceInteralContent(e) {
26768
+ var selectionHtml;
26769
+
26770
+ if (e.dataTransfer) {
26771
+ if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
26772
+ selection.select(e.target);
26773
+ }
26774
+
26775
+ selectionHtml = editor.selection.getContent();
26776
+
26777
+ // Safari/IE doesn't support custom dataTransfer items so we can only use URL and Text
26778
+ if (selectionHtml.length > 0) {
26779
+ e.dataTransfer.setData(mceInternalDataType, mceInternalUrlPrefix + escape(selectionHtml));
26780
+ }
26781
+ }
26782
+ }
26783
+
26784
+ /**
26785
+ * Gets content of special data:text/mce-internal url on the event's dataTransfer object.
26786
+ * This is to workaround the inability to set custom contentType on IE and Safari.
26787
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
26788
+ *
26789
+ * @private
26790
+ * @param {DragEvent} e Event object
26791
+ * @returns {String} mce-internal content
26792
+ */
26793
+ function getMceInternalContent(e) {
26794
+ var internalContent, content;
26795
+
26796
+ if (e.dataTransfer) {
26797
+ internalContent = e.dataTransfer.getData(mceInternalDataType);
26798
+
26799
+ if (internalContent && internalContent.indexOf(mceInternalUrlPrefix) >= 0) {
26800
+ content = unescape(internalContent.substr(mceInternalUrlPrefix.length));
26801
+ }
26802
+ }
26803
+
26804
+ return content;
26805
+ }
26806
+
26807
+ /**
26808
+ * Inserts contents using the paste clipboard command if it's available if it isn't it will fallback
26809
+ * to the core command.
26810
+ *
26811
+ * @private
26812
+ * @param {String} content Content to insert at selection.
26813
+ */
26814
+ function insertClipboardContents(content) {
26815
+ if (editor.queryCommandSupported('mceInsertClipboardContent')) {
26816
+ editor.execCommand('mceInsertClipboardContent', false, {content: content});
26817
+ } else {
26818
+ editor.execCommand('mceInsertContent', false, content);
26819
+ }
26820
+ }
26821
+
26452
26822
  /**
26453
26823
  * Fixes a WebKit bug when deleting contents using backspace or delete key.
26454
26824
  * WebKit will produce a span element if you delete across two block elements.
@@ -26471,13 +26841,13 @@ define("tinymce/util/Quirks", [
26471
26841
  * 4. Delete by pressing delete key with ctrl/cmd (Word delete).
26472
26842
  * 5. Delete by drag/dropping contents inside the editor.
26473
26843
  * 6. Delete by using Cut Ctrl+X/Cmd+X.
26474
- * 7. Delete by selecting contents and writing a character.'
26844
+ * 7. Delete by selecting contents and writing a character.
26475
26845
  *
26476
26846
  * This code is a ugly hack since writing full custom delete logic for just this bug
26477
26847
  * fix seemed like a huge task. I hope we can remove this before the year 2030.
26478
26848
  */
26479
26849
  function cleanupStylesWhenDeleting() {
26480
- var doc = editor.getDoc(), urlPrefix = 'data:text/mce-internal,';
26850
+ var doc = editor.getDoc(), dom = editor.dom, selection = editor.selection;
26481
26851
  var MutationObserver = window.MutationObserver, olderWebKit, dragStartRng;
26482
26852
 
26483
26853
  // Add mini polyfill for older WebKits
@@ -26519,8 +26889,212 @@ define("tinymce/util/Quirks", [
26519
26889
  };
26520
26890
  }
26521
26891
 
26892
+ function isTrailingBr(node) {
26893
+ var blockElements = dom.schema.getBlockElements(), rootNode = editor.getBody();
26894
+
26895
+ if (node.nodeName != 'BR') {
26896
+ return false;
26897
+ }
26898
+
26899
+ for (node = node; node != rootNode && !blockElements[node.nodeName]; node = node.parentNode) {
26900
+ if (node.nextSibling) {
26901
+ return false;
26902
+ }
26903
+ }
26904
+
26905
+ return true;
26906
+ }
26907
+
26908
+ function isSiblingsIgnoreWhiteSpace(node1, node2) {
26909
+ var node;
26910
+
26911
+ for (node = node1.nextSibling; node && node != node2; node = node.nextSibling) {
26912
+ if (node.nodeType == 3 && $.trim(node.data).length === 0) {
26913
+ continue;
26914
+ }
26915
+
26916
+ if (node !== node2) {
26917
+ return false;
26918
+ }
26919
+ }
26920
+
26921
+ return node === node2;
26922
+ }
26923
+
26924
+ function findCaretNode(node, forward, startNode) {
26925
+ var walker, current, nonEmptyElements;
26926
+
26927
+ nonEmptyElements = dom.schema.getNonEmptyElements();
26928
+
26929
+ walker = new TreeWalker(startNode || node, node);
26930
+
26931
+ while ((current = walker[forward ? 'next' : 'prev']())) {
26932
+ if (nonEmptyElements[current.nodeName] && !isTrailingBr(current)) {
26933
+ return current;
26934
+ }
26935
+
26936
+ if (current.nodeType == 3 && current.data.length > 0) {
26937
+ return current;
26938
+ }
26939
+ }
26940
+ }
26941
+
26942
+ function deleteRangeBetweenTextBlocks(rng) {
26943
+ var startBlock, endBlock, caretNodeBefore, caretNodeAfter, textBlockElements;
26944
+
26945
+ if (rng.collapsed) {
26946
+ return;
26947
+ }
26948
+
26949
+ startBlock = dom.getParent(RangeUtils.getNode(rng.startContainer, rng.startOffset), dom.isBlock);
26950
+ endBlock = dom.getParent(RangeUtils.getNode(rng.endContainer, rng.endOffset), dom.isBlock);
26951
+ textBlockElements = editor.schema.getTextBlockElements();
26952
+
26953
+ if (startBlock == endBlock) {
26954
+ return;
26955
+ }
26956
+
26957
+ if (!textBlockElements[startBlock.nodeName] || !textBlockElements[endBlock.nodeName]) {
26958
+ return;
26959
+ }
26960
+
26961
+ if (dom.getContentEditable(startBlock) === "false" || dom.getContentEditable(endBlock) === "false") {
26962
+ return;
26963
+ }
26964
+
26965
+ rng.deleteContents();
26966
+
26967
+ caretNodeBefore = findCaretNode(startBlock, false);
26968
+ caretNodeAfter = findCaretNode(endBlock, true);
26969
+
26970
+ if (!dom.isEmpty(endBlock)) {
26971
+ $(startBlock).append(endBlock.childNodes);
26972
+ }
26973
+
26974
+ $(endBlock).remove();
26975
+
26976
+ if (caretNodeBefore) {
26977
+ if (caretNodeBefore.nodeType == 1) {
26978
+ if (caretNodeBefore.nodeName == "BR") {
26979
+ rng.setStartBefore(caretNodeBefore);
26980
+ rng.setEndBefore(caretNodeBefore);
26981
+ } else {
26982
+ rng.setStartAfter(caretNodeBefore);
26983
+ rng.setEndAfter(caretNodeBefore);
26984
+ }
26985
+ } else {
26986
+ rng.setStart(caretNodeBefore, caretNodeBefore.data.length);
26987
+ rng.setEnd(caretNodeBefore, caretNodeBefore.data.length);
26988
+ }
26989
+ } else if (caretNodeAfter) {
26990
+ if (caretNodeAfter.nodeType == 1) {
26991
+ rng.setStartBefore(caretNodeAfter);
26992
+ rng.setEndBefore(caretNodeAfter);
26993
+ } else {
26994
+ rng.setStart(caretNodeAfter, 0);
26995
+ rng.setEnd(caretNodeAfter, 0);
26996
+ }
26997
+ }
26998
+
26999
+ selection.setRng(rng);
27000
+
27001
+ return true;
27002
+ }
27003
+
27004
+ function expandBetweenBlocks(rng, isForward) {
27005
+ var caretNode, targetCaretNode, textBlock, targetTextBlock, container, offset;
27006
+
27007
+ if (!rng.collapsed) {
27008
+ return rng;
27009
+ }
27010
+
27011
+ container = rng.startContainer;
27012
+ offset = rng.startOffset;
27013
+
27014
+ if (container.nodeType == 3) {
27015
+ if (isForward) {
27016
+ if (offset < container.data.length) {
27017
+ return rng;
27018
+ }
27019
+ } else {
27020
+ if (offset > 0) {
27021
+ return rng;
27022
+ }
27023
+ }
27024
+ }
27025
+
27026
+ caretNode = RangeUtils.getNode(rng.startContainer, rng.startOffset);
27027
+ textBlock = dom.getParent(caretNode, dom.isBlock);
27028
+ targetCaretNode = findCaretNode(editor.getBody(), isForward, caretNode);
27029
+ targetTextBlock = dom.getParent(targetCaretNode, dom.isBlock);
27030
+
27031
+ if (!caretNode || !targetCaretNode) {
27032
+ return rng;
27033
+ }
27034
+
27035
+ if (targetTextBlock && textBlock != targetTextBlock) {
27036
+ if (!isForward) {
27037
+ if (!isSiblingsIgnoreWhiteSpace(targetTextBlock, textBlock)) {
27038
+ return rng;
27039
+ }
27040
+
27041
+ if (targetCaretNode.nodeType == 1) {
27042
+ if (targetCaretNode.nodeName == "BR") {
27043
+ rng.setStartBefore(targetCaretNode);
27044
+ } else {
27045
+ rng.setStartAfter(targetCaretNode);
27046
+ }
27047
+ } else {
27048
+ rng.setStart(targetCaretNode, targetCaretNode.data.length);
27049
+ }
27050
+
27051
+ if (caretNode.nodeType == 1) {
27052
+ rng.setEnd(caretNode, 0);
27053
+ } else {
27054
+ rng.setEndBefore(caretNode);
27055
+ }
27056
+ } else {
27057
+ if (!isSiblingsIgnoreWhiteSpace(textBlock, targetTextBlock)) {
27058
+ return rng;
27059
+ }
27060
+
27061
+ if (caretNode.nodeType == 1) {
27062
+ if (caretNode.nodeName == "BR") {
27063
+ rng.setStartBefore(caretNode);
27064
+ } else {
27065
+ rng.setStartAfter(caretNode);
27066
+ }
27067
+ } else {
27068
+ rng.setStart(caretNode, caretNode.data.length);
27069
+ }
27070
+
27071
+ if (targetCaretNode.nodeType == 1) {
27072
+ rng.setEnd(targetCaretNode, 0);
27073
+ } else {
27074
+ rng.setEndBefore(targetCaretNode);
27075
+ }
27076
+ }
27077
+ }
27078
+
27079
+ return rng;
27080
+ }
27081
+
27082
+ function handleTextBlockMergeDelete(isForward) {
27083
+ var rng = selection.getRng();
27084
+
27085
+ rng = expandBetweenBlocks(rng, isForward);
27086
+
27087
+ if (deleteRangeBetweenTextBlocks(rng)) {
27088
+ return true;
27089
+ }
27090
+ }
27091
+
26522
27092
  function customDelete(isForward) {
26523
- var mutationObserver = new MutationObserver(function() {});
27093
+ var mutationObserver, rng, caretElement;
27094
+
27095
+ if (handleTextBlockMergeDelete(isForward)) {
27096
+ return;
27097
+ }
26524
27098
 
26525
27099
  Tools.each(editor.getBody().getElementsByTagName('*'), function(elm) {
26526
27100
  // Mark existing spans
@@ -26535,6 +27109,7 @@ define("tinymce/util/Quirks", [
26535
27109
  });
26536
27110
 
26537
27111
  // Observe added nodes and style attribute changes
27112
+ mutationObserver = new MutationObserver(function() {});
26538
27113
  mutationObserver.observe(editor.getDoc(), {
26539
27114
  childList: true,
26540
27115
  attributes: true,
@@ -26544,8 +27119,8 @@ define("tinymce/util/Quirks", [
26544
27119
 
26545
27120
  editor.getDoc().execCommand(isForward ? 'ForwardDelete' : 'Delete', false, null);
26546
27121
 
26547
- var rng = editor.selection.getRng();
26548
- var caretElement = rng.startContainer.parentNode;
27122
+ rng = editor.selection.getRng();
27123
+ caretElement = rng.startContainer.parentNode;
26549
27124
 
26550
27125
  Tools.each(mutationObserver.takeRecords(), function(record) {
26551
27126
  if (!dom.isChildOf(record.target, editor.getBody())) {
@@ -26593,13 +27168,13 @@ define("tinymce/util/Quirks", [
26593
27168
  }
26594
27169
 
26595
27170
  editor.on('keydown', function(e) {
26596
- var isForward = e.keyCode == DELETE, isMeta = VK.metaKeyPressed(e);
27171
+ var isForward = e.keyCode == DELETE, isMetaOrCtrl = e.ctrlKey || e.metaKey;
26597
27172
 
26598
27173
  if (!isDefaultPrevented(e) && (isForward || e.keyCode == BACKSPACE)) {
26599
27174
  var rng = editor.selection.getRng(), container = rng.startContainer, offset = rng.startOffset;
26600
27175
 
26601
27176
  // Ignore non meta delete in the where there is text before/after the caret
26602
- if (!isMeta && rng.collapsed && container.nodeType == 3) {
27177
+ if (!isMetaOrCtrl && rng.collapsed && container.nodeType == 3) {
26603
27178
  if (isForward ? offset < container.data.length : offset > 0) {
26604
27179
  return;
26605
27180
  }
@@ -26607,19 +27182,69 @@ define("tinymce/util/Quirks", [
26607
27182
 
26608
27183
  e.preventDefault();
26609
27184
 
26610
- if (isMeta) {
26611
- editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", "word");
27185
+ if (isMetaOrCtrl) {
27186
+ editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", e.metaKey ? "lineboundary" : "word");
26612
27187
  }
26613
27188
 
26614
27189
  customDelete(isForward);
26615
27190
  }
26616
27191
  });
26617
27192
 
27193
+ // Handle case where text is deleted by typing over
26618
27194
  editor.on('keypress', function(e) {
26619
27195
  if (!isDefaultPrevented(e) && !selection.isCollapsed() && e.charCode && !VK.metaKeyPressed(e)) {
27196
+ var rng, currentFormatNodes, fragmentNode, blockParent, caretNode, charText;
27197
+
27198
+ rng = editor.selection.getRng();
27199
+ charText = String.fromCharCode(e.charCode);
26620
27200
  e.preventDefault();
27201
+
27202
+ // Keep track of current format nodes
27203
+ currentFormatNodes = $(rng.startContainer).parents().filter(function(idx, node) {
27204
+ return !!editor.schema.getTextInlineElements()[node.nodeName];
27205
+ });
27206
+
26621
27207
  customDelete(true);
26622
- editor.selection.setContent(String.fromCharCode(e.charCode));
27208
+
27209
+ // Check if the browser removed them
27210
+ currentFormatNodes = currentFormatNodes.filter(function(idx, node) {
27211
+ return !$.contains(editor.getBody(), node);
27212
+ });
27213
+
27214
+ // Then re-add them
27215
+ if (currentFormatNodes.length) {
27216
+ fragmentNode = dom.createFragment();
27217
+
27218
+ currentFormatNodes.each(function(idx, formatNode) {
27219
+ formatNode = formatNode.cloneNode(false);
27220
+
27221
+ if (fragmentNode.hasChildNodes()) {
27222
+ formatNode.appendChild(fragmentNode.firstChild);
27223
+ fragmentNode.appendChild(formatNode);
27224
+ } else {
27225
+ caretNode = formatNode;
27226
+ fragmentNode.appendChild(formatNode);
27227
+ }
27228
+
27229
+ fragmentNode.appendChild(formatNode);
27230
+ });
27231
+
27232
+ caretNode.appendChild(editor.getDoc().createTextNode(charText));
27233
+
27234
+ // Prevent edge case where older WebKit would add an extra BR element
27235
+ blockParent = dom.getParent(rng.startContainer, dom.isBlock);
27236
+ if (dom.isEmpty(blockParent)) {
27237
+ $(blockParent).empty().append(fragmentNode);
27238
+ } else {
27239
+ rng.insertNode(fragmentNode);
27240
+ }
27241
+
27242
+ rng.setStart(caretNode.firstChild, 1);
27243
+ rng.setEnd(caretNode.firstChild, 1);
27244
+ editor.selection.setRng(rng);
27245
+ } else {
27246
+ editor.selection.setContent(charText);
27247
+ }
26623
27248
  }
26624
27249
  });
26625
27250
 
@@ -26637,31 +27262,14 @@ define("tinymce/util/Quirks", [
26637
27262
  }
26638
27263
 
26639
27264
  editor.on('dragstart', function(e) {
26640
- var selectionHtml;
26641
-
26642
- if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
26643
- selection.select(e.target);
26644
- }
26645
-
26646
27265
  dragStartRng = selection.getRng();
26647
- selectionHtml = editor.selection.getContent();
26648
-
26649
- // Safari doesn't support custom dataTransfer items so we can only use URL and Text
26650
- if (selectionHtml.length > 0) {
26651
- e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(selectionHtml));
26652
- }
27266
+ setMceInteralContent(e);
26653
27267
  });
26654
27268
 
26655
27269
  editor.on('drop', function(e) {
26656
27270
  if (!isDefaultPrevented(e)) {
26657
- var internalContent = e.dataTransfer.getData('URL');
26658
-
26659
- if (!internalContent || internalContent.indexOf(urlPrefix) == -1 || !doc.caretRangeFromPoint) {
26660
- return;
26661
- }
26662
-
26663
- internalContent = unescape(internalContent.substr(urlPrefix.length));
26664
- if (doc.caretRangeFromPoint) {
27271
+ var internalContent = getMceInternalContent(e);
27272
+ if (internalContent) {
26665
27273
  e.preventDefault();
26666
27274
 
26667
27275
  // Safari has a weird issue where drag/dropping images sometimes
@@ -26669,7 +27277,7 @@ define("tinymce/util/Quirks", [
26669
27277
  // will return "null" even though the x, y coordinate is correct.
26670
27278
  // But if we detach the insert from the drop event we will get a proper range
26671
27279
  window.setTimeout(function() {
26672
- var pointRng = doc.caretRangeFromPoint(e.x, e.y);
27280
+ var pointRng = RangeUtils.getCaretRangeFromPoint(e.x, e.y, doc);
26673
27281
 
26674
27282
  if (dragStartRng) {
26675
27283
  selection.setRng(dragStartRng);
@@ -26677,12 +27285,10 @@ define("tinymce/util/Quirks", [
26677
27285
  }
26678
27286
 
26679
27287
  customDelete();
26680
-
26681
27288
  selection.setRng(pointRng);
26682
- editor.insertContent(internalContent);
27289
+ insertClipboardContents(internalContent);
26683
27290
  }, 0);
26684
27291
  }
26685
-
26686
27292
  }
26687
27293
  });
26688
27294
 
@@ -26776,7 +27382,7 @@ define("tinymce/util/Quirks", [
26776
27382
  * This selects the whole body so that backspace/delete logic will delete everything
26777
27383
  */
26778
27384
  function selectAll() {
26779
- editor.shortcuts.add('ctrl+a', null, 'SelectAll');
27385
+ editor.shortcuts.add('meta+a', null, 'SelectAll');
26780
27386
  }
26781
27387
 
26782
27388
  /**
@@ -27414,7 +28020,12 @@ define("tinymce/util/Quirks", [
27414
28020
  editor.contentStyles.push('body {min-height: 150px}');
27415
28021
  editor.on('click', function(e) {
27416
28022
  if (e.target.nodeName == 'HTML') {
28023
+ var rng;
28024
+
28025
+ // Need to store away non collapsed ranges since the focus call will mess that up see #7382
28026
+ rng = editor.selection.getRng();
27417
28027
  editor.getBody().focus();
28028
+ editor.selection.setRng(rng);
27418
28029
  editor.selection.normalize();
27419
28030
  editor.nodeChanged();
27420
28031
  }
@@ -27431,7 +28042,7 @@ define("tinymce/util/Quirks", [
27431
28042
  editor.on('keydown', function(e) {
27432
28043
  if (VK.metaKeyPressed(e) && (e.keyCode == 37 || e.keyCode == 39)) {
27433
28044
  e.preventDefault();
27434
- editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'word');
28045
+ editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'lineboundary');
27435
28046
  }
27436
28047
  });
27437
28048
  }
@@ -27570,6 +28181,29 @@ define("tinymce/util/Quirks", [
27570
28181
  });
27571
28182
  }
27572
28183
 
28184
+ /**
28185
+ * IE cannot set custom contentType's on drag events, and also does not properly drag/drop between
28186
+ * editors. This uses a special data:text/mce-internal URL to pass data when drag/drop between editors.
28187
+ */
28188
+ function ieInternalDragAndDrop() {
28189
+ editor.on('dragstart', function(e) {
28190
+ setMceInteralContent(e);
28191
+ });
28192
+
28193
+ editor.on('drop', function(e) {
28194
+ if (!isDefaultPrevented(e)) {
28195
+ var internalContent = getMceInternalContent(e);
28196
+ if (internalContent) {
28197
+ e.preventDefault();
28198
+
28199
+ var rng = RangeUtils.getCaretRangeFromPoint(e.x, e.y, editor.getDoc());
28200
+ selection.setRng(rng);
28201
+ insertClipboardContents(internalContent);
28202
+ }
28203
+ }
28204
+ });
28205
+ }
28206
+
27573
28207
  // All browsers
27574
28208
  removeBlockQuoteOnBackSpace();
27575
28209
  emptyEditorWhenDeleting();
@@ -27617,6 +28251,7 @@ define("tinymce/util/Quirks", [
27617
28251
  if (Env.ie) {
27618
28252
  selectAll();
27619
28253
  disableAutoUrlDetect();
28254
+ ieInternalDragAndDrop();
27620
28255
  }
27621
28256
 
27622
28257
  // Gecko
@@ -27987,6 +28622,12 @@ define("tinymce/EditorObservable", [
27987
28622
 
27988
28623
  /**
27989
28624
  * Contains all logic for handling of keyboard shortcuts.
28625
+ *
28626
+ * @example
28627
+ * editor.shortcuts.add('ctrl+a', function() {});
28628
+ * editor.shortcuts.add('meta+a', function() {}); // "meta" maps to Command on Mac and Ctrl on PC
28629
+ * editor.shortcuts.add('ctrl+alt+a', function() {});
28630
+ * editor.shortcuts.add('access+a', function() {}); // "access" maps to ctrl+alt on Mac and shift+alt on PC
27990
28631
  */
27991
28632
  define("tinymce/Shortcuts", [
27992
28633
  "tinymce/util/Tools",
@@ -28000,15 +28641,78 @@ define("tinymce/Shortcuts", [
28000
28641
  "f11": 122
28001
28642
  };
28002
28643
 
28644
+ var modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
28645
+
28003
28646
  return function(editor) {
28004
28647
  var self = this, shortcuts = {};
28005
28648
 
28649
+ function createShortcut(pattern, desc, cmdFunc, scope) {
28650
+ var id, key, shortcut;
28651
+
28652
+ shortcut = {
28653
+ func: cmdFunc,
28654
+ scope: scope || editor,
28655
+ desc: editor.translate(desc)
28656
+ };
28657
+
28658
+ // Parse modifiers and keys ctrl+alt+b for example
28659
+ each(explode(pattern, '+'), function(value) {
28660
+ if (value in modifierNames) {
28661
+ shortcut[value] = true;
28662
+ } else {
28663
+ // Allow numeric keycodes like ctrl+219 for ctrl+[
28664
+ if (/^[0-9]{2,}$/.test(value)) {
28665
+ shortcut.keyCode = parseInt(value, 10);
28666
+ } else {
28667
+ shortcut.charCode = value.charCodeAt(0);
28668
+ shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
28669
+ }
28670
+ }
28671
+ });
28672
+
28673
+ // Generate unique id for modifier combination and set default state for unused modifiers
28674
+ id = [shortcut.keyCode];
28675
+ for (key in modifierNames) {
28676
+ if (shortcut[key]) {
28677
+ id.push(key);
28678
+ } else {
28679
+ shortcut[key] = false;
28680
+ }
28681
+ }
28682
+ shortcut.id = id.join(',');
28683
+
28684
+ // Handle special access modifier differently depending on Mac/Win
28685
+ if (shortcut.access) {
28686
+ shortcut.alt = true;
28687
+
28688
+ if (Env.mac) {
28689
+ shortcut.ctrl = true;
28690
+ } else {
28691
+ shortcut.shift = true;
28692
+ }
28693
+ }
28694
+
28695
+ // Handle special meta modifier differently depending on Mac/Win
28696
+ if (shortcut.meta) {
28697
+ if (Env.mac) {
28698
+ shortcut.meta = true;
28699
+ } else {
28700
+ shortcut.ctrl = true;
28701
+ shortcut.meta = false;
28702
+ }
28703
+ }
28704
+
28705
+ return shortcut;
28706
+ }
28707
+
28006
28708
  editor.on('keyup keypress keydown', function(e) {
28007
28709
  if ((e.altKey || e.ctrlKey || e.metaKey) && !e.isDefaultPrevented()) {
28008
28710
  each(shortcuts, function(shortcut) {
28009
- var ctrlKey = Env.mac ? e.metaKey : e.ctrlKey;
28711
+ if (shortcut.ctrl != e.ctrlKey || shortcut.meta != e.metaKey) {
28712
+ return;
28713
+ }
28010
28714
 
28011
- if (shortcut.ctrl != ctrlKey || shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
28715
+ if (shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
28012
28716
  return;
28013
28717
  }
28014
28718
 
@@ -28040,7 +28744,7 @@ define("tinymce/Shortcuts", [
28040
28744
 
28041
28745
  cmd = cmdFunc;
28042
28746
 
28043
- if (typeof(cmdFunc) === 'string') {
28747
+ if (typeof cmdFunc === 'string') {
28044
28748
  cmdFunc = function() {
28045
28749
  editor.execCommand(cmd, false, null);
28046
28750
  };
@@ -28051,43 +28755,29 @@ define("tinymce/Shortcuts", [
28051
28755
  }
28052
28756
 
28053
28757
  each(explode(pattern.toLowerCase()), function(pattern) {
28054
- var shortcut = {
28055
- func: cmdFunc,
28056
- scope: scope || editor,
28057
- desc: editor.translate(desc),
28058
- alt: false,
28059
- ctrl: false,
28060
- shift: false
28061
- };
28758
+ var shortcut = createShortcut(pattern, desc, cmdFunc, scope);
28759
+ shortcuts[shortcut.id] = shortcut;
28760
+ });
28062
28761
 
28063
- each(explode(pattern, '+'), function(value) {
28064
- switch (value) {
28065
- case 'alt':
28066
- case 'ctrl':
28067
- case 'shift':
28068
- shortcut[value] = true;
28069
- break;
28762
+ return true;
28763
+ };
28070
28764
 
28071
- default:
28072
- // Allow numeric keycodes like ctrl+219 for ctrl+[
28073
- if (/^[0-9]{2,}$/.test(value)) {
28074
- shortcut.keyCode = parseInt(value, 10);
28075
- } else {
28076
- shortcut.charCode = value.charCodeAt(0);
28077
- shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
28078
- }
28079
- }
28080
- });
28765
+ /**
28766
+ * Remove a keyboard shortcut by pattern.
28767
+ *
28768
+ * @method remove
28769
+ * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
28770
+ * @return {Boolean} true/false state if the shortcut was removed or not.
28771
+ */
28772
+ self.remove = function(pattern) {
28773
+ var shortcut = createShortcut(pattern);
28081
28774
 
28082
- shortcuts[
28083
- (shortcut.ctrl ? 'ctrl' : '') + ',' +
28084
- (shortcut.alt ? 'alt' : '') + ',' +
28085
- (shortcut.shift ? 'shift' : '') + ',' +
28086
- shortcut.keyCode
28087
- ] = shortcut;
28088
- });
28775
+ if (shortcuts[shortcut.id]) {
28776
+ delete shortcuts[shortcut.id];
28777
+ return true;
28778
+ }
28089
28779
 
28090
- return true;
28780
+ return false;
28091
28781
  };
28092
28782
  };
28093
28783
  });
@@ -28234,9 +28924,9 @@ define("tinymce/Editor", [
28234
28924
  inline_styles: true,
28235
28925
  convert_fonts_to_spans: true,
28236
28926
  indent: 'simple',
28237
- indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,ol,li,dl,dt,dd,area,table,thead,' +
28927
+ indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
28238
28928
  'tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
28239
- indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,ol,li,dl,dt,dd,area,table,thead,' +
28929
+ indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
28240
28930
  'tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
28241
28931
  validate: true,
28242
28932
  entity_encoding: 'named',
@@ -28334,12 +29024,8 @@ define("tinymce/Editor", [
28334
29024
 
28335
29025
  // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
28336
29026
  self.shortcuts = new Shortcuts(self);
28337
-
28338
- // Internal command handler objects
28339
- self.execCommands = {};
28340
- self.queryStateCommands = {};
28341
- self.queryValueCommands = {};
28342
29027
  self.loadedCSS = {};
29028
+ self.editorCommands = new EditorCommands(self);
28343
29029
 
28344
29030
  if (settings.target) {
28345
29031
  self.targetElm = settings.target;
@@ -28349,6 +29035,10 @@ define("tinymce/Editor", [
28349
29035
  self.editorManager = editorManager;
28350
29036
  self.inline = settings.inline;
28351
29037
 
29038
+ if (settings.cache_suffix) {
29039
+ Env.cacheSuffix = settings.cache_suffix.replace(/^[\?\&]+/, '');
29040
+ }
29041
+
28352
29042
  // Call setup
28353
29043
  editorManager.fire('SetupEditor', self);
28354
29044
  self.execCallback('setup', self);
@@ -28573,6 +29263,7 @@ define("tinymce/Editor", [
28573
29263
  var self = this, settings = self.settings, elm = self.getElement();
28574
29264
  var w, h, minHeight, n, o, Theme, url, bodyId, bodyClass, re, i, initializedPlugins = [];
28575
29265
 
29266
+ this.editorManager.i18n.setCode(settings.language);
28576
29267
  self.rtl = this.editorManager.i18n.rtl;
28577
29268
  self.editorManager.add(self);
28578
29269
 
@@ -28654,7 +29345,7 @@ define("tinymce/Editor", [
28654
29345
 
28655
29346
  // Resize editor
28656
29347
  if (!settings.content_editable) {
28657
- h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');
29348
+ h = (o.iframeHeight || h) + (typeof h == 'number' ? (o.deltaHeight || 0) : '');
28658
29349
  if (h < minHeight) {
28659
29350
  h = minHeight;
28660
29351
  }
@@ -28715,7 +29406,11 @@ define("tinymce/Editor", [
28715
29406
  // Load the CSS by injecting them into the HTML this will reduce "flicker"
28716
29407
  for (i = 0; i < self.contentCSS.length; i++) {
28717
29408
  var cssUrl = self.contentCSS[i];
28718
- self.iframeHTML += '<link type="text/css" rel="stylesheet" href="' + cssUrl + '" />';
29409
+ self.iframeHTML += (
29410
+ '<link type="text/css" ' +
29411
+ 'rel="stylesheet" ' +
29412
+ 'href="' + Tools._addCacheSuffix(cssUrl) + '" />'
29413
+ );
28719
29414
  self.loadedCSS[cssUrl] = true;
28720
29415
  }
28721
29416
 
@@ -29014,7 +29709,6 @@ define("tinymce/Editor", [
29014
29709
 
29015
29710
  self.forceBlocks = new ForceBlocks(self);
29016
29711
  self.enterKey = new EnterKey(self);
29017
- self.editorCommands = new EditorCommands(self);
29018
29712
  self._nodeChangeDispatcher = new NodeChange(self);
29019
29713
 
29020
29714
  self.fire('PreInit');
@@ -29108,7 +29802,9 @@ define("tinymce/Editor", [
29108
29802
  editor = self.editorManager.get(settings.auto_focus);
29109
29803
  }
29110
29804
 
29111
- editor.focus();
29805
+ if (!editor.destroyed) {
29806
+ editor.focus();
29807
+ }
29112
29808
  }, 100);
29113
29809
  }
29114
29810
 
@@ -29202,7 +29898,7 @@ define("tinymce/Editor", [
29202
29898
  scope = scope.scope;
29203
29899
  }
29204
29900
 
29205
- if (typeof(callback) === 'string') {
29901
+ if (typeof callback === 'string') {
29206
29902
  scope = callback.replace(/\.\w+$/, '');
29207
29903
  scope = scope ? resolve(scope) : 0;
29208
29904
  callback = resolve(callback);
@@ -29268,7 +29964,7 @@ define("tinymce/Editor", [
29268
29964
  if (type === 'hash') {
29269
29965
  output = {};
29270
29966
 
29271
- if (typeof(value) === 'string') {
29967
+ if (typeof value === 'string') {
29272
29968
  each(value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','), function(value) {
29273
29969
  value = value.split('=');
29274
29970
 
@@ -29409,7 +30105,7 @@ define("tinymce/Editor", [
29409
30105
  * @param {Object} value Optional value for command.
29410
30106
  * @return {Boolean} True/false state if the command was handled or not.
29411
30107
  */
29412
- this.execCommands[name] = {func: callback, scope: scope || this};
30108
+ this.editorCommands.addCommand(name, callback, scope);
29413
30109
  },
29414
30110
 
29415
30111
  /**
@@ -29428,7 +30124,7 @@ define("tinymce/Editor", [
29428
30124
  * @callback addQueryStateHandlerCallback
29429
30125
  * @return {Boolean} True/false state if the command is enabled or not like is it bold.
29430
30126
  */
29431
- this.queryStateCommands[name] = {func: callback, scope: scope || this};
30127
+ this.editorCommands.addQueryStateHandler(name, callback, scope);
29432
30128
  },
29433
30129
 
29434
30130
  /**
@@ -29447,7 +30143,7 @@ define("tinymce/Editor", [
29447
30143
  * @callback addQueryValueHandlerCallback
29448
30144
  * @return {Object} Value of the command or undefined.
29449
30145
  */
29450
- this.queryValueCommands[name] = {func: callback, scope: scope || this};
30146
+ this.editorCommands.addQueryValueHandler(name, callback, scope);
29451
30147
  },
29452
30148
 
29453
30149
  /**
@@ -29474,68 +30170,10 @@ define("tinymce/Editor", [
29474
30170
  * @param {String} cmd Command name to execute, for example mceLink or Bold.
29475
30171
  * @param {Boolean} ui True/false state if a UI (dialog) should be presented or not.
29476
30172
  * @param {mixed} value Optional command value, this can be anything.
29477
- * @param {Object} a Optional arguments object.
30173
+ * @param {Object} args Optional arguments object.
29478
30174
  */
29479
30175
  execCommand: function(cmd, ui, value, args) {
29480
- var self = this, state = 0, cmdItem;
29481
-
29482
- if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(cmd) && (!args || !args.skip_focus)) {
29483
- self.focus();
29484
- }
29485
-
29486
- args = extend({}, args);
29487
- args = self.fire('BeforeExecCommand', {command: cmd, ui: ui, value: value});
29488
- if (args.isDefaultPrevented()) {
29489
- return false;
29490
- }
29491
-
29492
- // Registred commands
29493
- if ((cmdItem = self.execCommands[cmd])) {
29494
- // Fall through on true
29495
- if (cmdItem.func.call(cmdItem.scope, ui, value) !== true) {
29496
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
29497
- return true;
29498
- }
29499
- }
29500
-
29501
- // Plugin commands
29502
- each(self.plugins, function(p) {
29503
- if (p.execCommand && p.execCommand(cmd, ui, value)) {
29504
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
29505
- state = true;
29506
- return false;
29507
- }
29508
- });
29509
-
29510
- if (state) {
29511
- return state;
29512
- }
29513
-
29514
- // Theme commands
29515
- if (self.theme && self.theme.execCommand && self.theme.execCommand(cmd, ui, value)) {
29516
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
29517
- return true;
29518
- }
29519
-
29520
- // Editor commands
29521
- if (self.editorCommands.execCommand(cmd, ui, value)) {
29522
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
29523
- return true;
29524
- }
29525
-
29526
- // Browser commands
29527
- try {
29528
- state = self.getDoc().execCommand(cmd, ui, value);
29529
- } catch (ex) {
29530
- // Ignore old IE errors
29531
- }
29532
-
29533
- if (state) {
29534
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
29535
- return true;
29536
- }
29537
-
29538
- return false;
30176
+ return this.editorCommands.execCommand(cmd, ui, value, args);
29539
30177
  },
29540
30178
 
29541
30179
  /**
@@ -29546,35 +30184,7 @@ define("tinymce/Editor", [
29546
30184
  * @return {Boolean} Command specific state, for example if bold is enabled or not.
29547
30185
  */
29548
30186
  queryCommandState: function(cmd) {
29549
- var self = this, queryItem, returnVal;
29550
-
29551
- // Is hidden then return undefined
29552
- if (self._isHidden()) {
29553
- return;
29554
- }
29555
-
29556
- // Registred commands
29557
- if ((queryItem = self.queryStateCommands[cmd])) {
29558
- returnVal = queryItem.func.call(queryItem.scope);
29559
-
29560
- // Fall though on non boolean returns
29561
- if (returnVal === true || returnVal === false) {
29562
- return returnVal;
29563
- }
29564
- }
29565
-
29566
- // Editor commands
29567
- returnVal = self.editorCommands.queryCommandState(cmd);
29568
- if (returnVal !== -1) {
29569
- return returnVal;
29570
- }
29571
-
29572
- // Browser commands
29573
- try {
29574
- return self.getDoc().queryCommandState(cmd);
29575
- } catch (ex) {
29576
- // Fails sometimes see bug: 1896577
29577
- }
30187
+ return this.editorCommands.queryCommandState(cmd);
29578
30188
  },
29579
30189
 
29580
30190
  /**
@@ -29585,35 +30195,18 @@ define("tinymce/Editor", [
29585
30195
  * @return {Object} Command specific value, for example the current font size.
29586
30196
  */
29587
30197
  queryCommandValue: function(cmd) {
29588
- var self = this, queryItem, returnVal;
29589
-
29590
- // Is hidden then return undefined
29591
- if (self._isHidden()) {
29592
- return;
29593
- }
29594
-
29595
- // Registred commands
29596
- if ((queryItem = self.queryValueCommands[cmd])) {
29597
- returnVal = queryItem.func.call(queryItem.scope);
29598
-
29599
- // Fall though on true
29600
- if (returnVal !== true) {
29601
- return returnVal;
29602
- }
29603
- }
29604
-
29605
- // Editor commands
29606
- returnVal = self.editorCommands.queryCommandValue(cmd);
29607
- if (returnVal !== undefined) {
29608
- return returnVal;
29609
- }
30198
+ return this.editorCommands.queryCommandValue(cmd);
30199
+ },
29610
30200
 
29611
- // Browser commands
29612
- try {
29613
- return self.getDoc().queryCommandValue(cmd);
29614
- } catch (ex) {
29615
- // Fails sometimes see bug: 1896577
29616
- }
30201
+ /**
30202
+ * Returns true/false if the command is supported or not.
30203
+ *
30204
+ * @method queryCommandSupported
30205
+ * @param {String} cmd Command that we check support for.
30206
+ * @return {Boolean} true/false if the command is supported or not.
30207
+ */
30208
+ queryCommandSupported: function(cmd) {
30209
+ return this.editorCommands.queryCommandSupported(cmd);
29617
30210
  },
29618
30211
 
29619
30212
  /**
@@ -30038,10 +30631,11 @@ define("tinymce/Editor", [
30038
30631
  },
30039
30632
 
30040
30633
  /**
30041
- * Returns the iframes body element.
30634
+ * Returns the root element of the editable area.
30635
+ * For a non-inline iframe-based editor, returns the iframe's body element.
30042
30636
  *
30043
30637
  * @method getBody
30044
- * @return {Element} Iframe body element.
30638
+ * @return {Element} The root element of the editable area.
30045
30639
  */
30046
30640
  getBody: function() {
30047
30641
  return this.bodyElement || this.getDoc().body;
@@ -30282,9 +30876,31 @@ define("tinymce/Editor", [
30282
30876
  define("tinymce/util/I18n", [], function() {
30283
30877
  "use strict";
30284
30878
 
30285
- var data = {};
30879
+ var data = {}, code = "en";
30286
30880
 
30287
30881
  return {
30882
+ /**
30883
+ * Sets the current language code.
30884
+ *
30885
+ * @method setCode
30886
+ * @param {String} newCode Current language code.
30887
+ */
30888
+ setCode: function(newCode) {
30889
+ if (newCode) {
30890
+ code = newCode;
30891
+ this.rtl = this.data[newCode] ? this.data[newCode]._dir === 'rtl' : false;
30892
+ }
30893
+ },
30894
+
30895
+ /**
30896
+ * Returns the current language code.
30897
+ *
30898
+ * @return {String} Current language code.
30899
+ */
30900
+ getCode: function() {
30901
+ return code;
30902
+ },
30903
+
30288
30904
  /**
30289
30905
  * Property gets set to true if a RTL language pack was loaded.
30290
30906
  *
@@ -30301,11 +30917,17 @@ define("tinymce/util/I18n", [], function() {
30301
30917
  * @param {Array} items Name/value array with English en_US to sv_SE.
30302
30918
  */
30303
30919
  add: function(code, items) {
30920
+ var langData = data[code];
30921
+
30922
+ if (!langData) {
30923
+ data[code] = langData = {};
30924
+ }
30925
+
30304
30926
  for (var name in items) {
30305
- data[name] = items[name];
30927
+ langData[name] = items[name];
30306
30928
  }
30307
30929
 
30308
- this.rtl = this.rtl || data._dir === 'rtl';
30930
+ this.setCode(code);
30309
30931
  },
30310
30932
 
30311
30933
  /**
@@ -30321,23 +30943,30 @@ define("tinymce/util/I18n", [], function() {
30321
30943
  * @return {String} String that got translated.
30322
30944
  */
30323
30945
  translate: function(text) {
30324
- if (typeof(text) == "undefined") {
30946
+ var langData;
30947
+
30948
+ langData = data[code];
30949
+ if (!langData) {
30950
+ langData = {};
30951
+ }
30952
+
30953
+ if (typeof text == "undefined") {
30325
30954
  return text;
30326
30955
  }
30327
30956
 
30328
- if (typeof(text) != "string" && text.raw) {
30957
+ if (typeof text != "string" && text.raw) {
30329
30958
  return text.raw;
30330
30959
  }
30331
30960
 
30332
30961
  if (text.push) {
30333
30962
  var values = text.slice(1);
30334
30963
 
30335
- text = (data[text[0]] || text[0]).replace(/\{([^\}]+)\}/g, function(match1, match2) {
30964
+ text = (langData[text[0]] || text[0]).replace(/\{([0-9]+)\}/g, function(match1, match2) {
30336
30965
  return values[match2];
30337
30966
  });
30338
30967
  }
30339
30968
 
30340
- return data[text] || text;
30969
+ return (langData[text] || text).replace(/{context:\w+}$/, '');
30341
30970
  },
30342
30971
 
30343
30972
  data: data
@@ -30709,7 +31338,7 @@ define("tinymce/EditorManager", [
30709
31338
  * @property minorVersion
30710
31339
  * @type String
30711
31340
  */
30712
- minorVersion: '1.6',
31341
+ minorVersion: '1.10',
30713
31342
 
30714
31343
  /**
30715
31344
  * Release date of TinyMCE build.
@@ -30717,7 +31346,7 @@ define("tinymce/EditorManager", [
30717
31346
  * @property releaseDate
30718
31347
  * @type String
30719
31348
  */
30720
- releaseDate: '2014-10-08',
31349
+ releaseDate: '2015-05-05',
30721
31350
 
30722
31351
  /**
30723
31352
  * Collection of editor instances.
@@ -31109,7 +31738,7 @@ define("tinymce/EditorManager", [
31109
31738
  }
31110
31739
 
31111
31740
  // Remove editors by selector
31112
- if (typeof(selector) == "string") {
31741
+ if (typeof selector == "string") {
31113
31742
  selector = selector.selector || selector;
31114
31743
 
31115
31744
  each(DOM.select(selector), function(elm) {
@@ -31326,9 +31955,12 @@ define("tinymce/LegacyInput", [
31326
31955
  },
31327
31956
 
31328
31957
  u: function(dom, node) {
31329
- replaceWithSpan(node, {
31330
- textDecoration: 'underline'
31331
- });
31958
+ // HTML5 allows U element
31959
+ if (editor.settings.schema === "html4") {
31960
+ replaceWithSpan(node, {
31961
+ textDecoration: 'underline'
31962
+ });
31963
+ }
31332
31964
  },
31333
31965
 
31334
31966
  strike: function(dom, node) {
@@ -31639,9 +32271,9 @@ define("tinymce/util/JSONRequest", [
31639
32271
  args.success = function(c, x) {
31640
32272
  c = JSON.parse(c);
31641
32273
 
31642
- if (typeof(c) == 'undefined') {
32274
+ if (typeof c == 'undefined') {
31643
32275
  c = {
31644
- error : 'JSON Parse error.'
32276
+ error: 'JSON Parse error.'
31645
32277
  };
31646
32278
  }
31647
32279
 
@@ -32242,7 +32874,7 @@ define("tinymce/ui/Tooltip", [
32242
32874
  text: function(value) {
32243
32875
  var self = this;
32244
32876
 
32245
- if (typeof(value) != "undefined") {
32877
+ if (typeof value != "undefined") {
32246
32878
  self._value = value;
32247
32879
 
32248
32880
  if (self._rendered) {
@@ -32525,7 +33157,7 @@ define("tinymce/ui/Button", [
32525
33157
  icon: function(icon) {
32526
33158
  var self = this, prefix = self.classPrefix;
32527
33159
 
32528
- if (typeof(icon) == 'undefined') {
33160
+ if (typeof icon == 'undefined') {
32529
33161
  return self.settings.icon;
32530
33162
  }
32531
33163
 
@@ -32981,7 +33613,7 @@ define("tinymce/ui/ComboBox", [
32981
33613
  value: function(value) {
32982
33614
  var self = this;
32983
33615
 
32984
- if (typeof(value) != "undefined") {
33616
+ if (typeof value != "undefined") {
32985
33617
  self._value = value;
32986
33618
  self.removeClass('placeholder');
32987
33619
 
@@ -33015,7 +33647,7 @@ define("tinymce/ui/ComboBox", [
33015
33647
  disabled: function(state) {
33016
33648
  var self = this;
33017
33649
 
33018
- if (self._rendered && typeof(state) != 'undefined') {
33650
+ if (self._rendered && typeof state != 'undefined') {
33019
33651
  self.getEl('inp').disabled = state;
33020
33652
  }
33021
33653
 
@@ -33395,6 +34027,18 @@ define("tinymce/ui/ColorButton", [
33395
34027
  return this._color;
33396
34028
  },
33397
34029
 
34030
+ /**
34031
+ * Resets the current color.
34032
+ *
34033
+ * @method resetColor
34034
+ * @return {tinymce.ui.ColorButton} Current instance.
34035
+ */
34036
+ resetColor: function() {
34037
+ this._color = null;
34038
+ this.getEl('preview').style.backgroundColor = null;
34039
+ return this;
34040
+ },
34041
+
33398
34042
  /**
33399
34043
  * Renders the control as a HTML string.
33400
34044
  *
@@ -33968,7 +34612,7 @@ define("tinymce/ui/Path", [
33968
34612
  data: function(data) {
33969
34613
  var self = this;
33970
34614
 
33971
- if (typeof(data) !== "undefined") {
34615
+ if (typeof data !== "undefined") {
33972
34616
  self._data = data;
33973
34617
  self.update();
33974
34618
 
@@ -34082,34 +34726,36 @@ define("tinymce/ui/ElementPath", [
34082
34726
  return false;
34083
34727
  }
34084
34728
 
34085
- self.on('select', function(e) {
34086
- editor.focus();
34087
- editor.selection.select(this.data()[e.index].element);
34088
- editor.nodeChanged();
34089
- });
34729
+ if (editor.settings.elementpath !== false) {
34730
+ self.on('select', function(e) {
34731
+ editor.focus();
34732
+ editor.selection.select(this.data()[e.index].element);
34733
+ editor.nodeChanged();
34734
+ });
34090
34735
 
34091
- editor.on('nodeChange', function(e) {
34092
- var outParents = [], parents = e.parents, i = parents.length;
34736
+ editor.on('nodeChange', function(e) {
34737
+ var outParents = [], parents = e.parents, i = parents.length;
34093
34738
 
34094
- while (i--) {
34095
- if (parents[i].nodeType == 1 && !isHidden(parents[i])) {
34096
- var args = editor.fire('ResolveName', {
34097
- name: parents[i].nodeName.toLowerCase(),
34098
- target: parents[i]
34099
- });
34739
+ while (i--) {
34740
+ if (parents[i].nodeType == 1 && !isHidden(parents[i])) {
34741
+ var args = editor.fire('ResolveName', {
34742
+ name: parents[i].nodeName.toLowerCase(),
34743
+ target: parents[i]
34744
+ });
34100
34745
 
34101
- if (!args.isDefaultPrevented()) {
34102
- outParents.push({name: args.name, element: parents[i]});
34103
- }
34746
+ if (!args.isDefaultPrevented()) {
34747
+ outParents.push({name: args.name, element: parents[i]});
34748
+ }
34104
34749
 
34105
- if (args.isPropagationStopped()) {
34106
- break;
34750
+ if (args.isPropagationStopped()) {
34751
+ break;
34752
+ }
34107
34753
  }
34108
34754
  }
34109
- }
34110
34755
 
34111
- self.data(outParents);
34112
- });
34756
+ self.data(outParents);
34757
+ });
34758
+ }
34113
34759
 
34114
34760
  return self._super();
34115
34761
  }
@@ -34263,7 +34909,7 @@ define("tinymce/ui/Form", [
34263
34909
  formItem.type = 'formitem';
34264
34910
  ctrl.aria('labelledby', ctrl._id + '-l');
34265
34911
 
34266
- if (typeof(ctrl.settings.flex) == "undefined") {
34912
+ if (typeof ctrl.settings.flex == "undefined") {
34267
34913
  ctrl.settings.flex = 1;
34268
34914
  }
34269
34915
 
@@ -34775,7 +35421,7 @@ define("tinymce/ui/FlexLayout", [
34775
35421
  );
34776
35422
  rect[alignAxisName] = contPaddingBox[alignBeforeName];
34777
35423
  } else if (align === "end") {
34778
- rect[alignAxisName] = contLayoutRect[alignInnerSizeName] - ctrlLayoutRect[alignSizeName] - contPaddingBox.top;
35424
+ rect[alignAxisName] = contLayoutRect[alignInnerSizeName] - ctrlLayoutRect[alignSizeName] - contPaddingBox.top;
34779
35425
  }
34780
35426
 
34781
35427
  // Calculate new size based on flex
@@ -34825,7 +35471,7 @@ define("tinymce/ui/FlowLayout", [
34825
35471
  Defaults: {
34826
35472
  containerClass: 'flow-layout',
34827
35473
  controlClass: 'flow-layout-item',
34828
- endClass : 'break'
35474
+ endClass: 'break'
34829
35475
  },
34830
35476
 
34831
35477
  /**
@@ -35204,7 +35850,6 @@ define("tinymce/ui/FormatControls", [
35204
35850
 
35205
35851
  editor.addMenuItem('newdocument', {
35206
35852
  text: 'New document',
35207
- shortcut: 'Ctrl+N',
35208
35853
  icon: 'newdocument',
35209
35854
  cmd: 'mceNewDocument'
35210
35855
  });
@@ -35212,7 +35857,7 @@ define("tinymce/ui/FormatControls", [
35212
35857
  editor.addMenuItem('undo', {
35213
35858
  text: 'Undo',
35214
35859
  icon: 'undo',
35215
- shortcut: 'Ctrl+Z',
35860
+ shortcut: 'Meta+Z',
35216
35861
  onPostRender: toggleUndoRedoState('undo'),
35217
35862
  cmd: 'undo'
35218
35863
  });
@@ -35220,7 +35865,7 @@ define("tinymce/ui/FormatControls", [
35220
35865
  editor.addMenuItem('redo', {
35221
35866
  text: 'Redo',
35222
35867
  icon: 'redo',
35223
- shortcut: 'Ctrl+Y',
35868
+ shortcut: 'Meta+Y',
35224
35869
  onPostRender: toggleUndoRedoState('redo'),
35225
35870
  cmd: 'redo'
35226
35871
  });
@@ -35233,12 +35878,12 @@ define("tinymce/ui/FormatControls", [
35233
35878
  });
35234
35879
 
35235
35880
  each({
35236
- cut: ['Cut', 'Cut', 'Ctrl+X'],
35237
- copy: ['Copy', 'Copy', 'Ctrl+C'],
35238
- paste: ['Paste', 'Paste', 'Ctrl+V'],
35239
- selectall: ['Select all', 'SelectAll', 'Ctrl+A'],
35240
- bold: ['Bold', 'Bold', 'Ctrl+B'],
35241
- italic: ['Italic', 'Italic', 'Ctrl+I'],
35881
+ cut: ['Cut', 'Cut', 'Meta+X'],
35882
+ copy: ['Copy', 'Copy', 'Meta+C'],
35883
+ paste: ['Paste', 'Paste', 'Meta+V'],
35884
+ selectall: ['Select all', 'SelectAll', 'Meta+A'],
35885
+ bold: ['Bold', 'Bold', 'Meta+B'],
35886
+ italic: ['Italic', 'Italic', 'Meta+I'],
35242
35887
  underline: ['Underline', 'Underline'],
35243
35888
  strikethrough: ['Strikethrough', 'Strikethrough'],
35244
35889
  subscript: ['Subscript', 'Subscript'],
@@ -35276,14 +35921,13 @@ define("tinymce/ui/FormatControls", [
35276
35921
  editor.addButton('formatselect', function() {
35277
35922
  var items = [], blocks = createFormats(editor.settings.block_formats ||
35278
35923
  'Paragraph=p;' +
35279
- 'Address=address;' +
35280
- 'Pre=pre;' +
35281
35924
  'Heading 1=h1;' +
35282
35925
  'Heading 2=h2;' +
35283
35926
  'Heading 3=h3;' +
35284
35927
  'Heading 4=h4;' +
35285
35928
  'Heading 5=h5;' +
35286
- 'Heading 6=h6'
35929
+ 'Heading 6=h6;' +
35930
+ 'Preformatted=pre'
35287
35931
  );
35288
35932
 
35289
35933
  each(blocks, function(block) {
@@ -35308,21 +35952,21 @@ define("tinymce/ui/FormatControls", [
35308
35952
 
35309
35953
  editor.addButton('fontselect', function() {
35310
35954
  var defaultFontsFormats =
35311
- 'Andale Mono=andale mono,times;' +
35955
+ 'Andale Mono=andale mono,monospace;' +
35312
35956
  'Arial=arial,helvetica,sans-serif;' +
35313
- 'Arial Black=arial black,avant garde;' +
35314
- 'Book Antiqua=book antiqua,palatino;' +
35957
+ 'Arial Black=arial black,sans-serif;' +
35958
+ 'Book Antiqua=book antiqua,palatino,serif;' +
35315
35959
  'Comic Sans MS=comic sans ms,sans-serif;' +
35316
- 'Courier New=courier new,courier;' +
35317
- 'Georgia=georgia,palatino;' +
35318
- 'Helvetica=helvetica;' +
35319
- 'Impact=impact,chicago;' +
35960
+ 'Courier New=courier new,courier,monospace;' +
35961
+ 'Georgia=georgia,palatino,serif;' +
35962
+ 'Helvetica=helvetica,arial,sans-serif;' +
35963
+ 'Impact=impact,sans-serif;' +
35320
35964
  'Symbol=symbol;' +
35321
35965
  'Tahoma=tahoma,arial,helvetica,sans-serif;' +
35322
- 'Terminal=terminal,monaco;' +
35323
- 'Times New Roman=times new roman,times;' +
35324
- 'Trebuchet MS=trebuchet ms,geneva;' +
35325
- 'Verdana=verdana,geneva;' +
35966
+ 'Terminal=terminal,monaco,monospace;' +
35967
+ 'Times New Roman=times new roman,times,serif;' +
35968
+ 'Trebuchet MS=trebuchet ms,geneva,sans-serif;' +
35969
+ 'Verdana=verdana,geneva,sans-serif;' +
35326
35970
  'Webdings=webdings;' +
35327
35971
  'Wingdings=wingdings,zapf dingbats';
35328
35972
 
@@ -35444,11 +36088,11 @@ define("tinymce/ui/GridLayout", [
35444
36088
  contPaddingBox = container._paddingBox;
35445
36089
  reverseRows = 'reverseRows' in settings ? settings.reverseRows : container.isRtl();
35446
36090
 
35447
- if (alignH && typeof(alignH) == "string") {
36091
+ if (alignH && typeof alignH == "string") {
35448
36092
  alignH = [alignH];
35449
36093
  }
35450
36094
 
35451
- if (alignV && typeof(alignV) == "string") {
36095
+ if (alignV && typeof alignV == "string") {
35452
36096
  alignV = [alignV];
35453
36097
  }
35454
36098
 
@@ -36250,9 +36894,7 @@ define("tinymce/ui/ListBox", [
36250
36894
 
36251
36895
  self._values = values = settings.values;
36252
36896
  if (values) {
36253
- if (typeof settings.value != "undefined") {
36254
- setSelected(values);
36255
- }
36897
+ setSelected(values);
36256
36898
 
36257
36899
  // Default with first item
36258
36900
  if (!selected && values.length > 0) {
@@ -36327,7 +36969,7 @@ define("tinymce/ui/ListBox", [
36327
36969
  }
36328
36970
  }
36329
36971
 
36330
- if (typeof(value) != "undefined") {
36972
+ if (typeof value != "undefined") {
36331
36973
  if (self.menu) {
36332
36974
  activateByValue(self.menu, value);
36333
36975
  } else {
@@ -36550,6 +37192,36 @@ define("tinymce/ui/MenuItem", [
36550
37192
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
36551
37193
  var icon = self.settings.icon, image = '', shortcut = settings.shortcut;
36552
37194
 
37195
+ // Converts shortcut format to Mac/PC variants
37196
+ function convertShortcut(shortcut) {
37197
+ var i, value, replace = {};
37198
+
37199
+ if (Env.mac) {
37200
+ replace = {
37201
+ alt: '&#x2325;',
37202
+ ctrl: '&#x2318;',
37203
+ shift: '&#x21E7;',
37204
+ meta: '&#x2318;'
37205
+ };
37206
+ } else {
37207
+ replace = {
37208
+ meta: 'Ctrl'
37209
+ };
37210
+ }
37211
+
37212
+ shortcut = shortcut.split('+');
37213
+
37214
+ for (i = 0; i < shortcut.length; i++) {
37215
+ value = replace[shortcut[i].toLowerCase()];
37216
+
37217
+ if (value) {
37218
+ shortcut[i] = value;
37219
+ }
37220
+ }
37221
+
37222
+ return shortcut.join('+');
37223
+ }
37224
+
36553
37225
  if (icon) {
36554
37226
  self.parent().addClass('menu-has-icons');
36555
37227
  }
@@ -36559,12 +37231,8 @@ define("tinymce/ui/MenuItem", [
36559
37231
  image = ' style="background-image: url(\'' + settings.image + '\')"';
36560
37232
  }
36561
37233
 
36562
- if (shortcut && Env.mac) {
36563
- // format shortcut for Mac
36564
- shortcut = shortcut.replace(/ctrl\+alt\+/i, '&#x2325;&#x2318;'); // ctrl+cmd
36565
- shortcut = shortcut.replace(/ctrl\+/i, '&#x2318;'); // ctrl symbol
36566
- shortcut = shortcut.replace(/alt\+/i, '&#x2325;'); // cmd symbol
36567
- shortcut = shortcut.replace(/shift\+/i, '&#x21E7;'); // shift symbol
37234
+ if (shortcut) {
37235
+ shortcut = convertShortcut(shortcut);
36568
37236
  }
36569
37237
 
36570
37238
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
@@ -36588,7 +37256,7 @@ define("tinymce/ui/MenuItem", [
36588
37256
  var self = this, settings = self.settings;
36589
37257
 
36590
37258
  var textStyle = settings.textStyle;
36591
- if (typeof(textStyle) == "function") {
37259
+ if (typeof textStyle == "function") {
36592
37260
  textStyle = textStyle.call(this);
36593
37261
  }
36594
37262
 
@@ -36620,7 +37288,7 @@ define("tinymce/ui/MenuItem", [
36620
37288
  },
36621
37289
 
36622
37290
  active: function(state) {
36623
- if (typeof(state) != "undefined") {
37291
+ if (typeof state != "undefined") {
36624
37292
  this.aria('checked', state);
36625
37293
  }
36626
37294
 
@@ -37114,7 +37782,7 @@ define("tinymce/ui/StackLayout", [
37114
37782
  Defaults: {
37115
37783
  containerClass: 'stack-layout',
37116
37784
  controlClass: 'stack-layout-item',
37117
- endClass : 'break'
37785
+ endClass: 'break'
37118
37786
  }
37119
37787
  });
37120
37788
  });
@@ -37371,7 +38039,7 @@ define("tinymce/ui/TextBox", [
37371
38039
  disabled: function(state) {
37372
38040
  var self = this;
37373
38041
 
37374
- if (self._rendered && typeof(state) != 'undefined') {
38042
+ if (self._rendered && typeof state != 'undefined') {
37375
38043
  self.getEl().disabled = state;
37376
38044
  }
37377
38045
 
@@ -37388,7 +38056,7 @@ define("tinymce/ui/TextBox", [
37388
38056
  value: function(value) {
37389
38057
  var self = this;
37390
38058
 
37391
- if (typeof(value) != "undefined") {
38059
+ if (typeof value != "undefined") {
37392
38060
  self._value = value;
37393
38061
 
37394
38062
  if (self._rendered) {
@@ -37593,5 +38261,5 @@ define("tinymce/ui/Throbber", [
37593
38261
  };
37594
38262
  });
37595
38263
 
37596
- expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/util/Tools","tinymce/Env","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/dom/Range","tinymce/html/Entities","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/BookmarkManager","tinymce/dom/Selection","tinymce/dom/ElementUtils","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/ComboBox","tinymce/ui/ColorBox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/util/Color","tinymce/ui/ColorPicker","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"]);
38264
+ expose(["tinymce/dom/EventUtils","tinymce/dom/Sizzle","tinymce/Env","tinymce/util/Tools","tinymce/dom/DomQuery","tinymce/html/Styles","tinymce/dom/TreeWalker","tinymce/dom/Range","tinymce/html/Entities","tinymce/dom/DOMUtils","tinymce/dom/ScriptLoader","tinymce/AddOnManager","tinymce/dom/RangeUtils","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/BookmarkManager","tinymce/dom/Selection","tinymce/dom/ElementUtils","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/ComboBox","tinymce/ui/ColorBox","tinymce/ui/PanelButton","tinymce/ui/ColorButton","tinymce/util/Color","tinymce/ui/ColorPicker","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"]);
37597
38265
  })(this);