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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46a016e645519f46d5570169dbfe0cf098effad1
4
- data.tar.gz: 737677e3678de8224ff679722bf395c59e88e30c
3
+ metadata.gz: 4d2fae378258790499baa18b3c24339a9bd7cdbb
4
+ data.tar.gz: 5584c277b163e6a331a685640c9dc55085817c1c
5
5
  SHA512:
6
- metadata.gz: d5bfe833865438c7fd0d904fc882ca067e85e4ee76e69a0be7bd378d157d2d4da7e714c5f15b739fcffa57aa8e03333e4c37cbf7e4035b441ae81f140d42a8c3
7
- data.tar.gz: c6aa5face3a046f4534bfb9a5babff3a1e8100481cd361d693908ce6d3709f92d7e955e319f21b4cca5bdd21d33c5bbace06f536b9144cb72fb982c377398789
6
+ metadata.gz: 7330d8ab350d64af447cbbe84f951350d23e3798e8c77d9edb66939b7dd82587757cc49602a853a97580ce29a6649ae680b7a6ea5f93a6a06e20e3f7144b1f4e
7
+ data.tar.gz: 5dcf9451e066fdf91c84fe036c8e26aa0105b51e0d014375ee53c4539b5ca3a6cff86e9d2aa525c0ccc18fba63911d9fc5473c52c1066624a70709d887584e24
data/README.md CHANGED
@@ -9,6 +9,7 @@ This is the branch for TinyMCE 4. For TinyMCE 3.5.x, please see the [tinymce-3 b
9
9
 
10
10
  [![Build Status](https://travis-ci.org/spohlenz/tinymce-rails.png?branch=master)](https://travis-ci.org/spohlenz/tinymce-rails)
11
11
 
12
+ **New in 3.5.11, 4.1.10 and 4.2.1:** Alternative asset installation methods (copy vs compile/symlink). See the [Asset Compilation](#asset-compilation) section below for details.
12
13
 
13
14
  Instructions
14
15
  ------------
@@ -135,9 +136,25 @@ Using the `tinymce` helper and global configuration file is entirely optional. T
135
136
  Asset Compilation
136
137
  -----------------
137
138
 
138
- If you are including TinyMCE via `application.js` or using the `tinymce_assets` helper, the TinyMCE assets will be automatically precompiled when you run `rake assets:precompile`.
139
+ Since TinyMCE loads most of its files dynamically, some workarounds are required to ensure that the TinyMCE asset files are accessible using non-digested filenames.
139
140
 
140
- However if you wish to include `tinymce-jquery.js` independently, you will need to add it to the precompile list in `config/environments/production.rb`:
141
+ As of tinymce-rails 3.5.11, 4.1.10 and 4.2.1, two alternative asset installation methods are available, which can be changed by setting `config.tinymce.install` within your `config/application.rb` file. Both methods are called when you run `rake asset:precompile` (via `Rake::Task#enhance`) after the regular application assets are compiled.
142
+
143
+ The default method, `copy`, copies the TinyMCE assets directly into `public/assets` and appends the file information into the asset manifest.
144
+
145
+ ```ruby
146
+ config.tinymce.install = :copy
147
+ ```
148
+
149
+ The new method, `compile`, adds the TinyMCE paths to the Sprockets precompilation paths and then creates symlinks from the non-digested filenames to their digested versions.
150
+
151
+ ```ruby
152
+ config.tinymce.install = :compile
153
+ ```
154
+
155
+ Due to compilation times, this method is only recommended using Rails 4 and up. This method is intended to eventually become the default, so please try it if it suits your environment and report any issues.
156
+
157
+ If you are including TinyMCE via `application.js` or using the `tinymce_assets` helper, you do not need to manually alter the precompile paths. However if you wish to include `tinymce-jquery.js` independently (i.e. using `javascript_include_tag`), you will need to add it to the precompile list in `config/environments/production.rb`:
141
158
 
142
159
  ```ruby
143
160
  config.assets.precompile << "tinymce-jquery.js"
@@ -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
@@ -674,6 +674,159 @@ define("tinymce/dom/Sizzle", [], function() {
674
674
  return jQuery.find;
675
675
  });
676
676
 
677
+ // Included from: js/tinymce/classes/Env.js
678
+
679
+ /**
680
+ * Env.js
681
+ *
682
+ * Copyright, Moxiecode Systems AB
683
+ * Released under LGPL License.
684
+ *
685
+ * License: http://www.tinymce.com/license
686
+ * Contributing: http://www.tinymce.com/contributing
687
+ */
688
+
689
+ /**
690
+ * This class contains various environment constants like browser versions etc.
691
+ * Normally you don't want to sniff specific browser versions but sometimes you have
692
+ * to when it's impossible to feature detect. So use this with care.
693
+ *
694
+ * @class tinymce.Env
695
+ * @static
696
+ */
697
+ define("tinymce/Env", [], function() {
698
+ var nav = navigator, userAgent = nav.userAgent;
699
+ var opera, webkit, ie, ie11, ie12, gecko, mac, iDevice, android;
700
+
701
+ opera = window.opera && window.opera.buildNumber;
702
+ android = /Android/.test(userAgent);
703
+ webkit = /WebKit/.test(userAgent);
704
+ ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
705
+ ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
706
+ ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false;
707
+ ie12 = (document.msElementsFromPoint && !ie && !ie11) ? 12 : false;
708
+ ie = ie || ie11 || ie12;
709
+ gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
710
+ mac = userAgent.indexOf('Mac') != -1;
711
+ iDevice = /(iPad|iPhone)/.test(userAgent);
712
+
713
+ if (ie12) {
714
+ webkit = false;
715
+ }
716
+
717
+ // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
718
+ // says it has contentEditable support but there is no visible caret.
719
+ var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534;
720
+
721
+ return {
722
+ /**
723
+ * Constant that is true if the browser is Opera.
724
+ *
725
+ * @property opera
726
+ * @type Boolean
727
+ * @final
728
+ */
729
+ opera: opera,
730
+
731
+ /**
732
+ * Constant that is true if the browser is WebKit (Safari/Chrome).
733
+ *
734
+ * @property webKit
735
+ * @type Boolean
736
+ * @final
737
+ */
738
+ webkit: webkit,
739
+
740
+ /**
741
+ * Constant that is more than zero if the browser is IE.
742
+ *
743
+ * @property ie
744
+ * @type Boolean
745
+ * @final
746
+ */
747
+ ie: ie,
748
+
749
+ /**
750
+ * Constant that is true if the browser is Gecko.
751
+ *
752
+ * @property gecko
753
+ * @type Boolean
754
+ * @final
755
+ */
756
+ gecko: gecko,
757
+
758
+ /**
759
+ * Constant that is true if the os is Mac OS.
760
+ *
761
+ * @property mac
762
+ * @type Boolean
763
+ * @final
764
+ */
765
+ mac: mac,
766
+
767
+ /**
768
+ * Constant that is true if the os is iOS.
769
+ *
770
+ * @property iOS
771
+ * @type Boolean
772
+ * @final
773
+ */
774
+ iOS: iDevice,
775
+
776
+ /**
777
+ * Constant that is true if the os is android.
778
+ *
779
+ * @property android
780
+ * @type Boolean
781
+ * @final
782
+ */
783
+ android: android,
784
+
785
+ /**
786
+ * Constant that is true if the browser supports editing.
787
+ *
788
+ * @property contentEditable
789
+ * @type Boolean
790
+ * @final
791
+ */
792
+ contentEditable: contentEditable,
793
+
794
+ /**
795
+ * Transparent image data url.
796
+ *
797
+ * @property transparentSrc
798
+ * @type Boolean
799
+ * @final
800
+ */
801
+ transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
802
+
803
+ /**
804
+ * Returns true/false if the browser can or can't place the caret after a inline block like an image.
805
+ *
806
+ * @property noCaretAfter
807
+ * @type Boolean
808
+ * @final
809
+ */
810
+ caretAfter: ie != 8,
811
+
812
+ /**
813
+ * Constant that is true if the browser supports native DOM Ranges. IE 9+.
814
+ *
815
+ * @property range
816
+ * @type Boolean
817
+ */
818
+ range: window.getSelection && "Range" in window,
819
+
820
+ /**
821
+ * Returns the IE document mode for non IE browsers this will fake IE 10.
822
+ *
823
+ * @property documentMode
824
+ * @type Number
825
+ */
826
+ documentMode: ie && !ie12 ? (document.documentMode || 7) : 10
827
+ };
828
+ });
829
+
677
830
  // Included from: js/tinymce/classes/util/Tools.js
678
831
 
679
832
  /**
@@ -692,7 +845,9 @@ define("tinymce/dom/Sizzle", [], function() {
692
845
  *
693
846
  * @class tinymce.util.Tools
694
847
  */
695
- define("tinymce/util/Tools", [], function() {
848
+ define("tinymce/util/Tools", [
849
+ "tinymce/Env"
850
+ ], function(Env) {
696
851
  /**
697
852
  * Removes whitespace from the beginning and end of a string.
698
853
  *
@@ -721,20 +876,20 @@ define("tinymce/util/Tools", [], function() {
721
876
  * Checks if a object is of a specific type for example an array.
722
877
  *
723
878
  * @method is
724
- * @param {Object} o Object to check type of.
725
- * @param {string} t Optional type to check for.
879
+ * @param {Object} obj Object to check type of.
880
+ * @param {string} type Optional type to check for.
726
881
  * @return {Boolean} true/false if the object is of the specified type.
727
882
  */
728
- function is(o, t) {
729
- if (!t) {
730
- return o !== undefined;
883
+ function is(obj, type) {
884
+ if (!type) {
885
+ return obj !== undefined;
731
886
  }
732
887
 
733
- if (t == 'array' && isArray(o)) {
888
+ if (type == 'array' && isArray(obj)) {
734
889
  return true;
735
890
  }
736
891
 
737
- return typeof(o) == t;
892
+ return typeof obj == type;
738
893
  }
739
894
 
740
895
  /**
@@ -772,7 +927,7 @@ define("tinymce/util/Tools", [], function() {
772
927
  items = items || [];
773
928
  delim = delim || ',';
774
929
 
775
- if (typeof(items) == "string") {
930
+ if (typeof items == "string") {
776
931
  items = items.split(delim);
777
932
  }
778
933
 
@@ -841,18 +996,18 @@ define("tinymce/util/Tools", [], function() {
841
996
  * one array list into another.
842
997
  *
843
998
  * @method map
844
- * @param {Array} a Array of items to iterate.
845
- * @param {function} f Function to call for each item. It's return value will be the new value.
999
+ * @param {Array} array Array of items to iterate.
1000
+ * @param {function} callback Function to call for each item. It's return value will be the new value.
846
1001
  * @return {Array} Array with new values based on function return values.
847
1002
  */
848
- function map(a, f) {
849
- var o = [];
1003
+ function map(array, callback) {
1004
+ var out = [];
850
1005
 
851
- each(a, function(v) {
852
- o.push(f(v));
1006
+ each(array, function(item) {
1007
+ out.push(callback(item));
853
1008
  });
854
1009
 
855
- return o;
1010
+ return out;
856
1011
  }
857
1012
 
858
1013
  /**
@@ -1005,6 +1160,7 @@ define("tinymce/util/Tools", [], function() {
1005
1160
 
1006
1161
  // Add static methods
1007
1162
  /*jshint sub:true*/
1163
+ /*eslint dot-notation:0*/
1008
1164
  self.each(p['static'], function(f, n) {
1009
1165
  ns[cn][n] = f;
1010
1166
  });
@@ -1164,6 +1320,16 @@ define("tinymce/util/Tools", [], function() {
1164
1320
  return map(s.split(d || ','), trim);
1165
1321
  }
1166
1322
 
1323
+ function _addCacheSuffix(url) {
1324
+ var cacheSuffix = Env.cacheSuffix;
1325
+
1326
+ if (cacheSuffix) {
1327
+ url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
1328
+ }
1329
+
1330
+ return url;
1331
+ }
1332
+
1167
1333
  return {
1168
1334
  trim: trim,
1169
1335
  isArray: isArray,
@@ -1179,145 +1345,8 @@ define("tinymce/util/Tools", [], function() {
1179
1345
  walk: walk,
1180
1346
  createNS: createNS,
1181
1347
  resolve: resolve,
1182
- explode: explode
1183
- };
1184
- });
1185
-
1186
- // Included from: js/tinymce/classes/Env.js
1187
-
1188
- /**
1189
- * Env.js
1190
- *
1191
- * Copyright, Moxiecode Systems AB
1192
- * Released under LGPL License.
1193
- *
1194
- * License: http://www.tinymce.com/license
1195
- * Contributing: http://www.tinymce.com/contributing
1196
- */
1197
-
1198
- /**
1199
- * This class contains various environment constants like browser versions etc.
1200
- * Normally you don't want to sniff specific browser versions but sometimes you have
1201
- * to when it's impossible to feature detect. So use this with care.
1202
- *
1203
- * @class tinymce.Env
1204
- * @static
1205
- */
1206
- define("tinymce/Env", [], function() {
1207
- var nav = navigator, userAgent = nav.userAgent;
1208
- var opera, webkit, ie, ie11, gecko, mac, iDevice;
1209
-
1210
- opera = window.opera && window.opera.buildNumber;
1211
- webkit = /WebKit/.test(userAgent);
1212
- ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
1213
- ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
1214
- ie11 = userAgent.indexOf('Trident/') != -1 && (userAgent.indexOf('rv:') != -1 || nav.appName.indexOf('Netscape') != -1) ? 11 : false;
1215
- ie = ie || ie11;
1216
- gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
1217
- mac = userAgent.indexOf('Mac') != -1;
1218
- iDevice = /(iPad|iPhone)/.test(userAgent);
1219
-
1220
- // Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
1221
- // says it has contentEditable support but there is no visible caret.
1222
- var contentEditable = !iDevice || userAgent.match(/AppleWebKit\/(\d*)/)[1] >= 534;
1223
-
1224
- return {
1225
- /**
1226
- * Constant that is true if the browser is Opera.
1227
- *
1228
- * @property opera
1229
- * @type Boolean
1230
- * @final
1231
- */
1232
- opera: opera,
1233
-
1234
- /**
1235
- * Constant that is true if the browser is WebKit (Safari/Chrome).
1236
- *
1237
- * @property webKit
1238
- * @type Boolean
1239
- * @final
1240
- */
1241
- webkit: webkit,
1242
-
1243
- /**
1244
- * Constant that is more than zero if the browser is IE.
1245
- *
1246
- * @property ie
1247
- * @type Boolean
1248
- * @final
1249
- */
1250
- ie: ie,
1251
-
1252
- /**
1253
- * Constant that is true if the browser is Gecko.
1254
- *
1255
- * @property gecko
1256
- * @type Boolean
1257
- * @final
1258
- */
1259
- gecko: gecko,
1260
-
1261
- /**
1262
- * Constant that is true if the os is Mac OS.
1263
- *
1264
- * @property mac
1265
- * @type Boolean
1266
- * @final
1267
- */
1268
- mac: mac,
1269
-
1270
- /**
1271
- * Constant that is true if the os is iOS.
1272
- *
1273
- * @property iOS
1274
- * @type Boolean
1275
- * @final
1276
- */
1277
- iOS: iDevice,
1278
-
1279
- /**
1280
- * Constant that is true if the browser supports editing.
1281
- *
1282
- * @property contentEditable
1283
- * @type Boolean
1284
- * @final
1285
- */
1286
- contentEditable: contentEditable,
1287
-
1288
- /**
1289
- * Transparent image data url.
1290
- *
1291
- * @property transparentSrc
1292
- * @type Boolean
1293
- * @final
1294
- */
1295
- transparentSrc: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
1296
-
1297
- /**
1298
- * Returns true/false if the browser can or can't place the caret after a inline block like an image.
1299
- *
1300
- * @property noCaretAfter
1301
- * @type Boolean
1302
- * @final
1303
- */
1304
- caretAfter: ie != 8,
1305
-
1306
- /**
1307
- * Constant that is true if the browser supports native DOM Ranges. IE 9+.
1308
- *
1309
- * @property range
1310
- * @type Boolean
1311
- */
1312
- range: window.getSelection && "Range" in window,
1313
-
1314
- /**
1315
- * Returns the IE document mode for non IE browsers this will fake IE 10.
1316
- *
1317
- * @property documentMode
1318
- * @type Number
1319
- */
1320
- documentMode: ie ? (document.documentMode || 7) : 10
1348
+ explode: explode,
1349
+ _addCacheSuffix: _addCacheSuffix
1321
1350
  };
1322
1351
  });
1323
1352
 
@@ -1372,6 +1401,10 @@ define("tinymce/dom/DomQuery", [
1372
1401
  return typeof obj === 'string';
1373
1402
  }
1374
1403
 
1404
+ function isWindow(obj) {
1405
+ return obj && obj == obj.window;
1406
+ }
1407
+
1375
1408
  function createFragment(html, fragDoc) {
1376
1409
  var frag, node, container;
1377
1410
 
@@ -1662,10 +1695,6 @@ define("tinymce/dom/DomQuery", [
1662
1695
  return self.add(DomQuery(items));
1663
1696
  }
1664
1697
 
1665
- if (items.nodeType) {
1666
- return self.add([items]);
1667
- }
1668
-
1669
1698
  if (sort !== false) {
1670
1699
  nodes = DomQuery.unique(self.toArray().concat(DomQuery.makeArray(items)));
1671
1700
  self.length = nodes.length;
@@ -1813,7 +1842,7 @@ define("tinymce/dom/DomQuery", [
1813
1842
  name = camel(name);
1814
1843
 
1815
1844
  // Default px suffix on these
1816
- if (typeof(value) === 'number' && !numericCssMap[name]) {
1845
+ if (typeof value === 'number' && !numericCssMap[name]) {
1817
1846
  value += 'px';
1818
1847
  }
1819
1848
 
@@ -2446,7 +2475,13 @@ define("tinymce/dom/DomQuery", [
2446
2475
  * @param {Object} object Object to convert to array.
2447
2476
  * @return {Arrau} Array produced from object.
2448
2477
  */
2449
- makeArray: Tools.toArray,
2478
+ makeArray: function(array) {
2479
+ if (isWindow(array) || array.nodeType) {
2480
+ return [array];
2481
+ }
2482
+
2483
+ return Tools.toArray(array);
2484
+ },
2450
2485
 
2451
2486
  /**
2452
2487
  * Returns the index of the specified item inside the array.
@@ -4159,7 +4194,7 @@ define("tinymce/html/Entities", [
4159
4194
  attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
4160
4195
  textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
4161
4196
  rawCharsRegExp = /[<>&\"\']/g,
4162
- entityRegExp = /&(#x|#)?([\w]+);/g,
4197
+ entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi,
4163
4198
  asciiMap = {
4164
4199
  128: "\u20AC", 130: "\u201A", 131: "\u0192", 132: "\u201E", 133: "\u2026", 134: "\u2020",
4165
4200
  135: "\u2021", 136: "\u02C6", 137: "\u2030", 138: "\u0160", 139: "\u2039", 140: "\u0152",
@@ -4373,17 +4408,21 @@ define("tinymce/html/Entities", [
4373
4408
  * @return {String} Entity decoded string.
4374
4409
  */
4375
4410
  decode: function(text) {
4376
- return text.replace(entityRegExp, function(all, numeric, value) {
4411
+ return text.replace(entityRegExp, function(all, numeric) {
4377
4412
  if (numeric) {
4378
- value = parseInt(value, numeric.length === 2 ? 16 : 10);
4413
+ if (numeric.charAt(0).toLowerCase() === 'x') {
4414
+ numeric = parseInt(numeric.substr(1), 16);
4415
+ } else {
4416
+ numeric = parseInt(numeric, 10);
4417
+ }
4379
4418
 
4380
4419
  // Support upper UTF
4381
- if (value > 0xFFFF) {
4382
- value -= 0x10000;
4420
+ if (numeric > 0xFFFF) {
4421
+ numeric -= 0x10000;
4383
4422
 
4384
- return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF));
4423
+ return String.fromCharCode(0xD800 + (numeric >> 10), 0xDC00 + (numeric & 0x3FF));
4385
4424
  } else {
4386
- return asciiMap[value] || String.fromCharCode(value);
4425
+ return asciiMap[numeric] || String.fromCharCode(numeric);
4387
4426
  }
4388
4427
  }
4389
4428
 
@@ -4413,7 +4452,9 @@ define("tinymce/html/Entities", [
4413
4452
  * @class tinymce.dom.StyleSheetLoader
4414
4453
  * @private
4415
4454
  */
4416
- define("tinymce/dom/StyleSheetLoader", [], function() {
4455
+ define("tinymce/dom/StyleSheetLoader", [
4456
+ "tinymce/util/Tools"
4457
+ ], function(Tools) {
4417
4458
  "use strict";
4418
4459
 
4419
4460
  return function(document, settings) {
@@ -4510,6 +4551,8 @@ define("tinymce/dom/StyleSheetLoader", [], function() {
4510
4551
  }, waitForGeckoLinkLoaded);
4511
4552
  }
4512
4553
 
4554
+ url = Tools._addCacheSuffix(url);
4555
+
4513
4556
  if (!loadedStates[url]) {
4514
4557
  state = {
4515
4558
  passed: [],
@@ -4956,7 +4999,7 @@ define("tinymce/dom/DOMUtils", [
4956
4999
  get: function(elm) {
4957
5000
  var name;
4958
5001
 
4959
- if (elm && this.doc && typeof(elm) == 'string') {
5002
+ if (elm && this.doc && typeof elm == 'string') {
4960
5003
  name = elm;
4961
5004
  elm = this.doc.getElementById(elm);
4962
5005
 
@@ -5139,7 +5182,7 @@ define("tinymce/dom/DOMUtils", [
5139
5182
  }
5140
5183
 
5141
5184
  // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime
5142
- if (typeof(html) != "undefined") {
5185
+ if (typeof html != "undefined") {
5143
5186
  return outHtml + '>' + html + '</' + name + '>';
5144
5187
  }
5145
5188
 
@@ -5546,6 +5589,8 @@ define("tinymce/dom/DOMUtils", [
5546
5589
  each(url.split(','), function(url) {
5547
5590
  var link;
5548
5591
 
5592
+ url = Tools._addCacheSuffix(url);
5593
+
5549
5594
  if (self.files[url]) {
5550
5595
  return;
5551
5596
  }
@@ -5738,7 +5783,9 @@ define("tinymce/dom/DOMUtils", [
5738
5783
  */
5739
5784
  getOuterHTML: function(elm) {
5740
5785
  elm = this.get(elm);
5741
- return elm.nodeType == 1 ? elm.outerHTML : $('<div>').append($(elm).clone()).html();
5786
+
5787
+ // Older FF doesn't have outerHTML 3.6 is still used by some orgaizations
5788
+ return elm.nodeType == 1 && "outerHTML" in elm ? elm.outerHTML : $('<div>').append($(elm).clone()).html();
5742
5789
  },
5743
5790
 
5744
5791
  /**
@@ -5760,11 +5807,17 @@ define("tinymce/dom/DOMUtils", [
5760
5807
 
5761
5808
  self.$$(elm).each(function() {
5762
5809
  try {
5763
- this.outerHTML = html;
5810
+ // Older FF doesn't have outerHTML 3.6 is still used by some orgaizations
5811
+ if ("outerHTML" in this) {
5812
+ this.outerHTML = html;
5813
+ return;
5814
+ }
5764
5815
  } catch (ex) {
5765
- // OuterHTML for IE it sometimes produces an "unknown runtime error"
5766
- self.remove($(this).html(html), true);
5816
+ // Ignore
5767
5817
  }
5818
+
5819
+ // OuterHTML for IE it sometimes produces an "unknown runtime error"
5820
+ self.remove($(this).html(html), true);
5768
5821
  });
5769
5822
  },
5770
5823
 
@@ -5922,7 +5975,7 @@ define("tinymce/dom/DOMUtils", [
5922
5975
  run: function(elm, func, scope) {
5923
5976
  var self = this, result;
5924
5977
 
5925
- if (typeof(elm) === 'string') {
5978
+ if (typeof elm === 'string') {
5926
5979
  elm = self.get(elm);
5927
5980
  }
5928
5981
 
@@ -5936,7 +5989,7 @@ define("tinymce/dom/DOMUtils", [
5936
5989
 
5937
5990
  each(elm, function(elm, i) {
5938
5991
  if (elm) {
5939
- if (typeof(elm) == 'string') {
5992
+ if (typeof elm == 'string') {
5940
5993
  elm = self.get(elm);
5941
5994
  }
5942
5995
 
@@ -6378,7 +6431,7 @@ define("tinymce/dom/DOMUtils", [
6378
6431
 
6379
6432
  if (node) {
6380
6433
  // If expression make a function of it using is
6381
- if (typeof(func) == 'string') {
6434
+ if (typeof func == 'string') {
6382
6435
  func = function(node) {
6383
6436
  return self.is(node, selector);
6384
6437
  };
@@ -6494,7 +6547,7 @@ define("tinymce/dom/ScriptLoader", [
6494
6547
  /*eslint no-console:0 */
6495
6548
 
6496
6549
  // Report the error so it's easier for people to spot loading errors
6497
- if (typeof(console) !== "undefined" && console.log) {
6550
+ if (typeof console !== "undefined" && console.log) {
6498
6551
  console.log("Failed to load: " + url);
6499
6552
  }
6500
6553
 
@@ -6510,7 +6563,7 @@ define("tinymce/dom/ScriptLoader", [
6510
6563
  elm = document.createElement('script');
6511
6564
  elm.id = id;
6512
6565
  elm.type = 'text/javascript';
6513
- elm.src = url;
6566
+ elm.src = Tools._addCacheSuffix(url);
6514
6567
 
6515
6568
  // Seems that onreadystatechange works better on IE 10 onload seems to fire incorrectly
6516
6569
  if ("onreadystatechange" in elm) {
@@ -6953,7 +7006,6 @@ define("tinymce/AddOnManager", [
6953
7006
  * This class contains a few utility methods for ranges.
6954
7007
  *
6955
7008
  * @class tinymce.dom.RangeUtils
6956
- * @private
6957
7009
  */
6958
7010
  define("tinymce/dom/RangeUtils", [
6959
7011
  "tinymce/util/Tools",
@@ -7328,7 +7380,7 @@ define("tinymce/dom/RangeUtils", [
7328
7380
  container = node.parentNode;
7329
7381
 
7330
7382
  // Put caret after image when moving the end point
7331
- if (node.nodeName == "IMG" && !directionLeft) {
7383
+ if (node.nodeName == "IMG" && !directionLeft) {
7332
7384
  offset++;
7333
7385
  }
7334
7386
 
@@ -7431,6 +7483,53 @@ define("tinymce/dom/RangeUtils", [
7431
7483
  return false;
7432
7484
  };
7433
7485
 
7486
+ /**
7487
+ * Gets the caret range for the given x/y location.
7488
+ *
7489
+ * @static
7490
+ * @method getCaretRangeFromPoint
7491
+ * @param {Number} x X coordinate for range
7492
+ * @param {Number} y Y coordinate for range
7493
+ * @param {Document} doc Document that x/y are relative to
7494
+ * @returns {Range} caret range
7495
+ */
7496
+ RangeUtils.getCaretRangeFromPoint = function(x, y, doc) {
7497
+ var rng, point;
7498
+
7499
+ if (doc.caretPositionFromPoint) {
7500
+ point = doc.caretPositionFromPoint(x, y);
7501
+ rng = doc.createRange();
7502
+ rng.setStart(point.offsetNode, point.offset);
7503
+ rng.collapse(true);
7504
+ } else if (doc.caretRangeFromPoint) {
7505
+ rng = doc.caretRangeFromPoint(x, y);
7506
+ } else if (doc.body.createTextRange) {
7507
+ rng = doc.body.createTextRange();
7508
+
7509
+ try {
7510
+ rng.moveToPoint(x, y);
7511
+ rng.collapse(true);
7512
+ } catch (ex) {
7513
+ // Append to top or bottom depending on drop location
7514
+ rng.collapse(y < doc.body.clientHeight);
7515
+ }
7516
+ }
7517
+
7518
+ return rng;
7519
+ };
7520
+
7521
+ RangeUtils.getNode = function(container, offset) {
7522
+ if (container.nodeType == 1 && container.hasChildNodes()) {
7523
+ if (offset >= container.childNodes.length) {
7524
+ offset = container.childNodes.length - 1;
7525
+ }
7526
+
7527
+ container = container.childNodes[offset];
7528
+ }
7529
+
7530
+ return container;
7531
+ };
7532
+
7434
7533
  return RangeUtils;
7435
7534
  });
7436
7535
 
@@ -7453,8 +7552,9 @@ define("tinymce/dom/RangeUtils", [
7453
7552
  * @private
7454
7553
  */
7455
7554
  define("tinymce/NodeChange", [
7456
- "tinymce/dom/RangeUtils"
7457
- ], function(RangeUtils) {
7555
+ "tinymce/dom/RangeUtils",
7556
+ "tinymce/Env"
7557
+ ], function(RangeUtils, Env) {
7458
7558
  return function(editor) {
7459
7559
  var lastRng, lastPath = [];
7460
7560
 
@@ -7517,11 +7617,17 @@ define("tinymce/NodeChange", [
7517
7617
  editor.fire('SelectionChange');
7518
7618
  });
7519
7619
 
7620
+ // Selection change is delayed ~200ms on IE when you click inside the current range
7520
7621
  editor.on('SelectionChange', function() {
7521
7622
  var startElm = editor.selection.getStart(true);
7522
7623
 
7523
- // Fire a nodechange only when the selection isn't collapsed since focusout will collapse and remove the selection
7524
- if (!editor.selection.isCollapsed() && !isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
7624
+ // IE 8 will fire a selectionchange event with an incorrect selection
7625
+ // when focusing out of table cells. Click inside cell -> toolbar = Invalid SelectionChange event
7626
+ if (!Env.range && editor.selection.isCollapsed()) {
7627
+ return;
7628
+ }
7629
+
7630
+ if (!isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
7525
7631
  editor.nodeChanged({selectionChange: true});
7526
7632
  }
7527
7633
  });
@@ -7531,9 +7637,13 @@ define("tinymce/NodeChange", [
7531
7637
  if (!e.isDefaultPrevented()) {
7532
7638
  // Delay nodeChanged call for WebKit edge case issue where the range
7533
7639
  // isn't updated until after you click outside a selected image
7534
- setTimeout(function() {
7640
+ if (editor.selection.getNode().nodeName == 'IMG') {
7641
+ setTimeout(function() {
7642
+ editor.nodeChanged();
7643
+ }, 0);
7644
+ } else {
7535
7645
  editor.nodeChanged();
7536
- }, 0);
7646
+ }
7537
7647
  }
7538
7648
  });
7539
7649
 
@@ -8141,13 +8251,13 @@ define("tinymce/html/Schema", [
8141
8251
  children = children || [];
8142
8252
  attributes = attributes || "";
8143
8253
 
8144
- if (typeof(children) === "string") {
8254
+ if (typeof children === "string") {
8145
8255
  children = split(children);
8146
8256
  }
8147
8257
 
8148
8258
  // Split string children
8149
8259
  for (i = 3; i < args.length; i++) {
8150
- if (typeof(args[i]) === "string") {
8260
+ if (typeof args[i] === "string") {
8151
8261
  args[i] = split(args[i]);
8152
8262
  }
8153
8263
 
@@ -8267,7 +8377,7 @@ define("tinymce/html/Schema", [
8267
8377
  add("a", "href target rel media hreflang type", phrasingContent);
8268
8378
  add("q", "cite", phrasingContent);
8269
8379
  add("ins del", "cite datetime", flowContent);
8270
- add("img", "src alt usemap ismap width height");
8380
+ add("img", "src sizes srcset alt usemap ismap width height");
8271
8381
  add("iframe", "src name width height", flowContent);
8272
8382
  add("embed", "src type width height");
8273
8383
  add("object", "data type typemustmatch name usemap form width height", flowContent, "param");
@@ -8306,7 +8416,8 @@ define("tinymce/html/Schema", [
8306
8416
  add("video", "src crossorigin poster preload autoplay mediagroup loop " +
8307
8417
  "muted controls width height buffered", flowContent, "track source");
8308
8418
  add("audio", "src crossorigin preload autoplay mediagroup loop muted controls buffered volume", flowContent, "track source");
8309
- add("source", "src type media");
8419
+ add("picture", "", "img source");
8420
+ add("source", "src srcset type media sizes");
8310
8421
  add("track", "kind src srclang label default");
8311
8422
  add("datalist", "", phrasingContent, "option");
8312
8423
  add("article section nav aside header footer", "", flowContent);
@@ -8410,7 +8521,7 @@ define("tinymce/html/Schema", [
8410
8521
 
8411
8522
  // Convert styles into a rule list
8412
8523
  each(value, function(value, key) {
8413
- styles[key] = mode == 'map' ? makeMap(value, /[, ]/) : explode(value, /[, ]/);
8524
+ styles[key] = styles[key.toUpperCase()] = mode == 'map' ? makeMap(value, /[, ]/) : explode(value, /[, ]/);
8414
8525
  });
8415
8526
  }
8416
8527
 
@@ -8427,7 +8538,7 @@ define("tinymce/html/Schema", [
8427
8538
  return function(settings) {
8428
8539
  var self = this, elements = {}, children = {}, patternElements = [], validStyles, invalidStyles, schemaItems;
8429
8540
  var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, validClasses;
8430
- var blockElementsMap, nonEmptyElementsMap, textBlockElementsMap, textInlineElementsMap;
8541
+ var blockElementsMap, nonEmptyElementsMap, moveCaretBeforeOnEnterElementsMap, textBlockElementsMap, textInlineElementsMap;
8431
8542
  var customElementsMap = {}, specialElements = {};
8432
8543
 
8433
8544
  // Creates an lookup table map object for the specified option or the default value
@@ -8472,6 +8583,7 @@ define("tinymce/html/Schema", [
8472
8583
  boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' +
8473
8584
  'noshade nowrap readonly selected autoplay loop controls');
8474
8585
  nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap);
8586
+ moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', 'table', nonEmptyElementsMap);
8475
8587
  textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
8476
8588
  'blockquote center dir fieldset header footer article section hgroup aside nav figure');
8477
8589
  blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
@@ -8933,6 +9045,17 @@ define("tinymce/html/Schema", [
8933
9045
  return nonEmptyElementsMap;
8934
9046
  };
8935
9047
 
9048
+ /**
9049
+ * Returns a map with elements that the caret should be moved in front of after enter is
9050
+ * pressed
9051
+ *
9052
+ * @method getMoveCaretBeforeOnEnterElements
9053
+ * @return {Object} Name/value lookup map for elements to place the caret in front of.
9054
+ */
9055
+ self.getMoveCaretBeforeOnEnterElements = function() {
9056
+ return moveCaretBeforeOnEnterElementsMap;
9057
+ };
9058
+
8936
9059
  /**
8937
9060
  * Returns a map with elements where white space is to be preserved like PRE or SCRIPT.
8938
9061
  *
@@ -10330,7 +10453,7 @@ define("tinymce/html/DomParser", [
10330
10453
  }
10331
10454
 
10332
10455
  validClassesMap = validClasses[node.name];
10333
- if (!valid && validClassesMap && !validClassesMap[className]) {
10456
+ if (!valid && validClassesMap && validClassesMap[className]) {
10334
10457
  valid = true;
10335
10458
  }
10336
10459
 
@@ -10514,7 +10637,7 @@ define("tinymce/html/Writer", [
10514
10637
  */
10515
10638
  pi: function(name, text) {
10516
10639
  if (text) {
10517
- html.push('<?', name, ' ', text, '?>');
10640
+ html.push('<?', name, ' ', encode(text), '?>');
10518
10641
  } else {
10519
10642
  html.push('<?', name, '?>');
10520
10643
  }
@@ -11659,7 +11782,7 @@ define("tinymce/util/VK", [
11659
11782
  UP: 38,
11660
11783
 
11661
11784
  modifierPressed: function(e) {
11662
- return e.shiftKey || e.ctrlKey || e.altKey;
11785
+ return e.shiftKey || e.ctrlKey || e.altKey || this.metaKeyPressed(e);
11663
11786
  },
11664
11787
 
11665
11788
  metaKeyPressed: function(e) {
@@ -11703,14 +11826,14 @@ define("tinymce/dom/ControlSelection", [
11703
11826
  // Details about each resize handle how to scale etc
11704
11827
  resizeHandles = {
11705
11828
  // Name: x multiplier, y multiplier, delta size x, delta size y
11706
- n: [0.5, 0, 0, -1],
11707
- e: [1, 0.5, 1, 0],
11708
- s: [0.5, 1, 0, 1],
11709
- w: [0, 0.5, -1, 0],
11710
- nw: [0, 0, -1, -1],
11711
- ne: [1, 0, 1, -1],
11712
- se: [1, 1, 1, 1],
11713
- sw: [0, 1, -1, 1]
11829
+ n: [0.5, 0, 0, -1],
11830
+ e: [1, 0.5, 1, 0],
11831
+ s: [0.5, 1, 0, 1],
11832
+ w: [0, 0.5, -1, 0],
11833
+ nw: [0, 0, -1, -1],
11834
+ ne: [1, 0, 1, -1],
11835
+ se: [1, 1, 1, 1],
11836
+ sw: [0, 1, -1, 1]
11714
11837
  };
11715
11838
 
11716
11839
  // Add CSS for resize handles, cloned element and selected
@@ -13443,7 +13566,7 @@ define("tinymce/dom/Selection", [
13443
13566
  normalize: function() {
13444
13567
  var self = this, rng = self.getRng();
13445
13568
 
13446
- if (!isIE && new RangeUtils(self.dom).normalize(rng)) {
13569
+ if (Env.range && new RangeUtils(self.dom).normalize(rng)) {
13447
13570
  self.setRng(rng, self.isForward());
13448
13571
  }
13449
13572
 
@@ -13451,7 +13574,8 @@ define("tinymce/dom/Selection", [
13451
13574
  },
13452
13575
 
13453
13576
  /**
13454
- * Executes callback of the current selection matches the specified selector or not and passes the state and args to the callback.
13577
+ * Executes callback when the current selection starts/stops matching the specified selector. The current
13578
+ * state will be passed to the callback as it's first argument.
13455
13579
  *
13456
13580
  * @method selectorChanged
13457
13581
  * @param {String} selector CSS selector to check for.
@@ -13818,7 +13942,7 @@ define("tinymce/fmt/Preview", [
13818
13942
  }
13819
13943
 
13820
13944
  // Create block/inline element to use for preview
13821
- if (typeof(format) == "string") {
13945
+ if (typeof format == "string") {
13822
13946
  format = editor.formatter.get(format);
13823
13947
  if (!format) {
13824
13948
  return;
@@ -13996,6 +14120,10 @@ define("tinymce/Formatter", [
13996
14120
  return !!ed.schema.getTextBlockElements()[name.toLowerCase()];
13997
14121
  }
13998
14122
 
14123
+ function isTableCell(node) {
14124
+ return /^(TH|TD)$/.test(node.nodeName);
14125
+ }
14126
+
13999
14127
  function getParents(node, selector) {
14000
14128
  return dom.getParents(node, selector, dom.getRoot());
14001
14129
  }
@@ -14084,7 +14212,7 @@ define("tinymce/Formatter", [
14084
14212
 
14085
14213
  removeformat: [
14086
14214
  {
14087
- selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q',
14215
+ selector: 'b,strong,em,i,font,u,strike,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins',
14088
14216
  remove: 'all',
14089
14217
  split: true,
14090
14218
  expand: false,
@@ -14107,18 +14235,18 @@ define("tinymce/Formatter", [
14107
14235
 
14108
14236
  function addKeyboardShortcuts() {
14109
14237
  // Add some inline shortcuts
14110
- ed.addShortcut('ctrl+b', 'bold_desc', 'Bold');
14111
- ed.addShortcut('ctrl+i', 'italic_desc', 'Italic');
14112
- ed.addShortcut('ctrl+u', 'underline_desc', 'Underline');
14238
+ ed.addShortcut('meta+b', 'bold_desc', 'Bold');
14239
+ ed.addShortcut('meta+i', 'italic_desc', 'Italic');
14240
+ ed.addShortcut('meta+u', 'underline_desc', 'Underline');
14113
14241
 
14114
14242
  // BlockFormat shortcuts keys
14115
14243
  for (var i = 1; i <= 6; i++) {
14116
- ed.addShortcut('ctrl+' + i, '', ['FormatBlock', false, 'h' + i]);
14244
+ ed.addShortcut('access+' + i, '', ['FormatBlock', false, 'h' + i]);
14117
14245
  }
14118
14246
 
14119
- ed.addShortcut('ctrl+7', '', ['FormatBlock', false, 'p']);
14120
- ed.addShortcut('ctrl+8', '', ['FormatBlock', false, 'div']);
14121
- ed.addShortcut('ctrl+9', '', ['FormatBlock', false, 'address']);
14247
+ ed.addShortcut('access+7', '', ['FormatBlock', false, 'p']);
14248
+ ed.addShortcut('access+8', '', ['FormatBlock', false, 'div']);
14249
+ ed.addShortcut('access+9', '', ['FormatBlock', false, 'address']);
14122
14250
  }
14123
14251
 
14124
14252
  // Public functions
@@ -14144,7 +14272,7 @@ define("tinymce/Formatter", [
14144
14272
  */
14145
14273
  function register(name, format) {
14146
14274
  if (name) {
14147
- if (typeof(name) !== 'string') {
14275
+ if (typeof name !== 'string') {
14148
14276
  each(name, function(format, name) {
14149
14277
  register(name, format);
14150
14278
  });
@@ -14176,7 +14304,7 @@ define("tinymce/Formatter", [
14176
14304
  }
14177
14305
 
14178
14306
  // Split classes if needed
14179
- if (typeof(format.classes) === 'string') {
14307
+ if (typeof format.classes === 'string') {
14180
14308
  format.classes = format.classes.split(/\s+/);
14181
14309
  }
14182
14310
  });
@@ -14217,7 +14345,7 @@ define("tinymce/Formatter", [
14217
14345
  textDecoration = getTextDecoration(node.parentNode);
14218
14346
  if (ed.dom.getStyle(node, 'color') && textDecoration) {
14219
14347
  ed.dom.setStyle(node, 'text-decoration', textDecoration);
14220
- } else if (ed.dom.getStyle(node, 'textdecoration') === textDecoration) {
14348
+ } else if (ed.dom.getStyle(node, 'text-decoration') === textDecoration) {
14221
14349
  ed.dom.setStyle(node, 'text-decoration', null);
14222
14350
  }
14223
14351
  }
@@ -14693,6 +14821,11 @@ define("tinymce/Formatter", [
14693
14821
  out = out[start ? 'firstChild' : 'lastChild'];
14694
14822
  }
14695
14823
 
14824
+ // Since dom.remove removes empty text nodes then we need to try to find a better node
14825
+ if (out.nodeType == 3 && out.data.length === 0) {
14826
+ out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
14827
+ }
14828
+
14696
14829
  dom.remove(node, true);
14697
14830
 
14698
14831
  return out;
@@ -14723,29 +14856,36 @@ define("tinymce/Formatter", [
14723
14856
  // Try to adjust endContainer as well if cells on the same row were selected - bug #6410
14724
14857
  if (commonAncestorContainer &&
14725
14858
  /^T(HEAD|BODY|FOOT|R)$/.test(commonAncestorContainer.nodeName) &&
14726
- /^(TH|TD)$/.test(endContainer.nodeName) && endContainer.firstChild) {
14859
+ isTableCell(endContainer) && endContainer.firstChild) {
14727
14860
  endContainer = endContainer.firstChild || endContainer;
14728
14861
  }
14729
14862
 
14730
- // Wrap start/end nodes in span element since these might be cloned/moved
14731
- startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
14732
- endContainer = wrap(endContainer, 'span', {id: '_end', 'data-mce-type': 'bookmark'});
14863
+ if (dom.isChildOf(startContainer, endContainer) && !isTableCell(startContainer) && !isTableCell(endContainer)) {
14864
+ startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
14865
+ splitToFormatRoot(startContainer);
14866
+ startContainer = unwrap(TRUE);
14867
+ return;
14868
+ } else {
14869
+ // Wrap start/end nodes in span element since these might be cloned/moved
14870
+ startContainer = wrap(startContainer, 'span', {id: '_start', 'data-mce-type': 'bookmark'});
14871
+ endContainer = wrap(endContainer, 'span', {id: '_end', 'data-mce-type': 'bookmark'});
14733
14872
 
14734
- // Split start/end
14735
- splitToFormatRoot(startContainer);
14736
- splitToFormatRoot(endContainer);
14873
+ // Split start/end
14874
+ splitToFormatRoot(startContainer);
14875
+ splitToFormatRoot(endContainer);
14737
14876
 
14738
- // Unwrap start/end to get real elements again
14739
- startContainer = unwrap(TRUE);
14740
- endContainer = unwrap();
14877
+ // Unwrap start/end to get real elements again
14878
+ startContainer = unwrap(TRUE);
14879
+ endContainer = unwrap();
14880
+ }
14741
14881
  } else {
14742
14882
  startContainer = endContainer = splitToFormatRoot(startContainer);
14743
14883
  }
14744
14884
 
14745
14885
  // Update range positions since they might have changed after the split operations
14746
- rng.startContainer = startContainer.parentNode;
14886
+ rng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
14747
14887
  rng.startOffset = nodeIndex(startContainer);
14748
- rng.endContainer = endContainer.parentNode;
14888
+ rng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
14749
14889
  rng.endOffset = nodeIndex(endContainer) + 1;
14750
14890
  }
14751
14891
 
@@ -15218,7 +15358,7 @@ define("tinymce/Formatter", [
15218
15358
  * @return {String} New value with replaced variables.
15219
15359
  */
15220
15360
  function replaceVars(value, vars) {
15221
- if (typeof(value) != "string") {
15361
+ if (typeof value != "string") {
15222
15362
  value = value(vars);
15223
15363
  } else if (vars) {
15224
15364
  value = value.replace(/%(\w+)/g, function(str, name) {
@@ -15362,7 +15502,7 @@ define("tinymce/Formatter", [
15362
15502
  function findSpace(node, offset) {
15363
15503
  var pos, pos2, str = node.nodeValue;
15364
15504
 
15365
- if (typeof(offset) == "undefined") {
15505
+ if (typeof offset == "undefined") {
15366
15506
  offset = start ? str.length : 0;
15367
15507
  }
15368
15508
 
@@ -15633,7 +15773,7 @@ define("tinymce/Formatter", [
15633
15773
  value = normalizeStyleValue(replaceVars(value, vars), name);
15634
15774
 
15635
15775
  // Indexed array
15636
- if (typeof(name) === 'number') {
15776
+ if (typeof name === 'number') {
15637
15777
  name = value;
15638
15778
  compare_node = 0;
15639
15779
  }
@@ -15658,7 +15798,7 @@ define("tinymce/Formatter", [
15658
15798
  value = replaceVars(value, vars);
15659
15799
 
15660
15800
  // Indexed array
15661
- if (typeof(name) === 'number') {
15801
+ if (typeof name === 'number') {
15662
15802
  name = value;
15663
15803
  compare_node = 0;
15664
15804
  }
@@ -15671,7 +15811,7 @@ define("tinymce/Formatter", [
15671
15811
  // Build new class value where everything is removed except the internal prefixed classes
15672
15812
  valueOut = '';
15673
15813
  each(value.split(/\s+/), function(cls) {
15674
- if (/mce\w+/.test(cls)) {
15814
+ if (/mce\-\w+/.test(cls)) {
15675
15815
  valueOut += (valueOut ? ' ' : '') + cls;
15676
15816
  }
15677
15817
  });
@@ -16168,7 +16308,8 @@ define("tinymce/Formatter", [
16168
16308
  removeCaretContainer();
16169
16309
 
16170
16310
  // Remove caret container on keydown and it's a backspace, enter or left/right arrow keys
16171
- if (keyCode == 8 || keyCode == 37 || keyCode == 39) {
16311
+ // Backspace key needs to check if the range is collapsed due to bug #6780
16312
+ if ((keyCode == 8 && selection.isCollapsed()) || keyCode == 37 || keyCode == 39) {
16172
16313
  removeCaretContainer(getParentCaretContainer(selection.getStart()));
16173
16314
  }
16174
16315
 
@@ -16257,10 +16398,11 @@ define("tinymce/Formatter", [
16257
16398
  * @class tinymce.UndoManager
16258
16399
  */
16259
16400
  define("tinymce/UndoManager", [
16401
+ "tinymce/util/VK",
16260
16402
  "tinymce/Env",
16261
16403
  "tinymce/util/Tools",
16262
16404
  "tinymce/html/SaxParser"
16263
- ], function(Env, Tools, SaxParser) {
16405
+ ], function(VK, Env, Tools, SaxParser) {
16264
16406
  var trim = Tools.trim, trimContentRegExp;
16265
16407
 
16266
16408
  trimContentRegExp = new RegExp([
@@ -16307,6 +16449,10 @@ define("tinymce/UndoManager", [
16307
16449
  return trim(content);
16308
16450
  }
16309
16451
 
16452
+ function setDirty(state) {
16453
+ editor.isNotDirty = !state;
16454
+ }
16455
+
16310
16456
  function addNonTypingUndoLevel(e) {
16311
16457
  self.typing = false;
16312
16458
  self.add({}, e);
@@ -16356,9 +16502,9 @@ define("tinymce/UndoManager", [
16356
16502
 
16357
16503
  // Fire a TypingUndo event on the first character entered
16358
16504
  if (isFirstTypedCharacter && self.typing) {
16359
- // Make the it dirty if the content was changed after typing the first character
16505
+ // Make it dirty if the content was changed after typing the first character
16360
16506
  if (!editor.isDirty()) {
16361
- editor.isNotDirty = !data[0] || getContent() == data[0].content;
16507
+ setDirty(data[0] && getContent() != data[0].content);
16362
16508
 
16363
16509
  // Fire initial change event
16364
16510
  if (!editor.isNotDirty) {
@@ -16384,8 +16530,9 @@ define("tinymce/UndoManager", [
16384
16530
  return;
16385
16531
  }
16386
16532
 
16387
- // If key isn't shift,ctrl,alt,capslock,metakey
16388
- if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing) {
16533
+ // If key isn't Ctrl+Alt/AltGr
16534
+ var modKey = (e.ctrlKey && !e.altKey) || e.metaKey;
16535
+ if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing && !modKey) {
16389
16536
  self.beforeChange();
16390
16537
  self.typing = true;
16391
16538
  self.add({}, e);
@@ -16400,8 +16547,8 @@ define("tinymce/UndoManager", [
16400
16547
  });
16401
16548
 
16402
16549
  // Add keyboard shortcuts for undo/redo keys
16403
- editor.addShortcut('ctrl+z', '', 'Undo');
16404
- editor.addShortcut('ctrl+y,ctrl+shift+z', '', 'Redo');
16550
+ editor.addShortcut('meta+z', '', 'Undo');
16551
+ editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
16405
16552
 
16406
16553
  editor.on('AddUndo Undo Redo ClearUndos', function(e) {
16407
16554
  if (!e.isDefaultPrevented()) {
@@ -16409,6 +16556,7 @@ define("tinymce/UndoManager", [
16409
16556
  }
16410
16557
  });
16411
16558
 
16559
+ /*eslint consistent-this:0 */
16412
16560
  self = {
16413
16561
  // Explose for debugging reasons
16414
16562
  data: data,
@@ -16494,7 +16642,7 @@ define("tinymce/UndoManager", [
16494
16642
  editor.fire('AddUndo', args);
16495
16643
 
16496
16644
  if (index > 0) {
16497
- editor.isNotDirty = false;
16645
+ setDirty(true);
16498
16646
  editor.fire('change', args);
16499
16647
  }
16500
16648
 
@@ -16520,7 +16668,7 @@ define("tinymce/UndoManager", [
16520
16668
 
16521
16669
  // Undo to first index then set dirty state to false
16522
16670
  if (index === 0) {
16523
- editor.isNotDirty = true;
16671
+ setDirty(false);
16524
16672
  }
16525
16673
 
16526
16674
  editor.setContent(level.content, {format: 'raw'});
@@ -16546,6 +16694,7 @@ define("tinymce/UndoManager", [
16546
16694
 
16547
16695
  editor.setContent(level.content, {format: 'raw'});
16548
16696
  editor.selection.moveToBookmark(level.bookmark);
16697
+ setDirty(true);
16549
16698
 
16550
16699
  editor.fire('redo', {level: level});
16551
16700
  }
@@ -16637,7 +16786,8 @@ define("tinymce/EnterKey", [
16637
16786
 
16638
16787
  return function(editor) {
16639
16788
  var dom = editor.dom, selection = editor.selection, settings = editor.settings;
16640
- var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
16789
+ var undoManager = editor.undoManager, schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements(),
16790
+ moveCaretBeforeOnEnterElementsMap = schema.getMoveCaretBeforeOnEnterElements();
16641
16791
 
16642
16792
  function handleEnterKey(evt) {
16643
16793
  var rng, tmpRng, editableRoot, container, offset, parentBlock, documentMode, shiftKey,
@@ -16702,7 +16852,6 @@ define("tinymce/EnterKey", [
16702
16852
  // pure whitespace text node or before an image
16703
16853
  function moveToCaretPosition(root) {
16704
16854
  var walker, node, rng, lastNode = root, tempElm;
16705
-
16706
16855
  function firstNonWhiteSpaceNodeSibling(node) {
16707
16856
  while (node) {
16708
16857
  if (node.nodeType == 1 || (node.nodeType == 3 && node.data && /[\r\n\s]/.test(node.data))) {
@@ -16753,7 +16902,7 @@ define("tinymce/EnterKey", [
16753
16902
  break;
16754
16903
  }
16755
16904
 
16756
- if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
16905
+ if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
16757
16906
  rng.setStartBefore(node);
16758
16907
  rng.setEndBefore(node);
16759
16908
  break;
@@ -17422,13 +17571,18 @@ define("tinymce/EditorCommands", [
17422
17571
  var TRUE = true, FALSE = false;
17423
17572
 
17424
17573
  return function(editor) {
17425
- var dom = editor.dom,
17426
- selection = editor.selection,
17574
+ var dom, selection, formatter,
17427
17575
  commands = {state: {}, exec: {}, value: {}},
17428
17576
  settings = editor.settings,
17429
- formatter = editor.formatter,
17430
17577
  bookmark;
17431
17578
 
17579
+ editor.on('PreInit', function() {
17580
+ dom = editor.dom;
17581
+ selection = editor.selection;
17582
+ settings = editor.settings;
17583
+ formatter = editor.formatter;
17584
+ });
17585
+
17432
17586
  /**
17433
17587
  * Executes the specified command.
17434
17588
  *
@@ -17438,16 +17592,58 @@ define("tinymce/EditorCommands", [
17438
17592
  * @param {Object} value Optional value for command.
17439
17593
  * @return {Boolean} true/false if the command was found or not.
17440
17594
  */
17441
- function execCommand(command, ui, value) {
17442
- var func;
17595
+ function execCommand(command, ui, value, args) {
17596
+ var func, customCommand, state = 0;
17443
17597
 
17444
- command = command.toLowerCase();
17445
- if ((func = commands.exec[command])) {
17446
- func(command, ui, value);
17447
- return TRUE;
17598
+ if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(command) && (!args || !args.skip_focus)) {
17599
+ editor.focus();
17448
17600
  }
17449
17601
 
17450
- return FALSE;
17602
+ args = extend({}, args);
17603
+ args = editor.fire('BeforeExecCommand', {command: command, ui: ui, value: value});
17604
+ if (args.isDefaultPrevented()) {
17605
+ return false;
17606
+ }
17607
+
17608
+ customCommand = command.toLowerCase();
17609
+ if ((func = commands.exec[customCommand])) {
17610
+ func(customCommand, ui, value);
17611
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
17612
+ return true;
17613
+ }
17614
+
17615
+ // Plugin commands
17616
+ each(editor.plugins, function(p) {
17617
+ if (p.execCommand && p.execCommand(command, ui, value)) {
17618
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
17619
+ state = true;
17620
+ return false;
17621
+ }
17622
+ });
17623
+
17624
+ if (state) {
17625
+ return state;
17626
+ }
17627
+
17628
+ // Theme commands
17629
+ if (editor.theme && editor.theme.execCommand && editor.theme.execCommand(command, ui, value)) {
17630
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
17631
+ return true;
17632
+ }
17633
+
17634
+ // Browser commands
17635
+ try {
17636
+ state = editor.getDoc().execCommand(command, ui, value);
17637
+ } catch (ex) {
17638
+ // Ignore old IE errors
17639
+ }
17640
+
17641
+ if (state) {
17642
+ editor.fire('ExecCommand', {command: command, ui: ui, value: value});
17643
+ return true;
17644
+ }
17645
+
17646
+ return false;
17451
17647
  }
17452
17648
 
17453
17649
  /**
@@ -17460,12 +17656,24 @@ define("tinymce/EditorCommands", [
17460
17656
  function queryCommandState(command) {
17461
17657
  var func;
17462
17658
 
17659
+ // Is hidden then return undefined
17660
+ if (editor._isHidden()) {
17661
+ return;
17662
+ }
17663
+
17463
17664
  command = command.toLowerCase();
17464
17665
  if ((func = commands.state[command])) {
17465
17666
  return func(command);
17466
17667
  }
17467
17668
 
17468
- return -1;
17669
+ // Browser commands
17670
+ try {
17671
+ return editor.getDoc().queryCommandState(command);
17672
+ } catch (ex) {
17673
+ // Fails sometimes see bug: 1896577
17674
+ }
17675
+
17676
+ return false;
17469
17677
  }
17470
17678
 
17471
17679
  /**
@@ -17478,12 +17686,22 @@ define("tinymce/EditorCommands", [
17478
17686
  function queryCommandValue(command) {
17479
17687
  var func;
17480
17688
 
17689
+ // Is hidden then return undefined
17690
+ if (editor._isHidden()) {
17691
+ return;
17692
+ }
17693
+
17481
17694
  command = command.toLowerCase();
17482
17695
  if ((func = commands.value[command])) {
17483
17696
  return func(command);
17484
17697
  }
17485
17698
 
17486
- return FALSE;
17699
+ // Browser commands
17700
+ try {
17701
+ return editor.getDoc().queryCommandValue(command);
17702
+ } catch (ex) {
17703
+ // Fails sometimes see bug: 1896577
17704
+ }
17487
17705
  }
17488
17706
 
17489
17707
  /**
@@ -17503,12 +17721,67 @@ define("tinymce/EditorCommands", [
17503
17721
  });
17504
17722
  }
17505
17723
 
17724
+ function addCommand(command, callback, scope) {
17725
+ command = command.toLowerCase();
17726
+ commands.exec[command] = function(command, ui, value, args) {
17727
+ return callback.call(scope || editor, ui, value, args);
17728
+ };
17729
+ }
17730
+
17731
+ /**
17732
+ * Returns true/false if the command is supported or not.
17733
+ *
17734
+ * @method queryCommandSupported
17735
+ * @param {String} cmd Command that we check support for.
17736
+ * @return {Boolean} true/false if the command is supported or not.
17737
+ */
17738
+ function queryCommandSupported(command) {
17739
+ command = command.toLowerCase();
17740
+
17741
+ if (commands.exec[command]) {
17742
+ return true;
17743
+ }
17744
+
17745
+ // Browser commands
17746
+ try {
17747
+ return editor.getDoc().queryCommandSupported(command);
17748
+ } catch (ex) {
17749
+ // Fails sometimes see bug: 1896577
17750
+ }
17751
+
17752
+ return false;
17753
+ }
17754
+
17755
+ function addQueryStateHandler(command, callback, scope) {
17756
+ command = command.toLowerCase();
17757
+ commands.state[command] = function() {
17758
+ return callback.call(scope || editor);
17759
+ };
17760
+ }
17761
+
17762
+ function addQueryValueHandler(command, callback, scope) {
17763
+ command = command.toLowerCase();
17764
+ commands.value[command] = function() {
17765
+ return callback.call(scope || editor);
17766
+ };
17767
+ }
17768
+
17769
+ function hasCustomCommand(command) {
17770
+ command = command.toLowerCase();
17771
+ return !!commands.exec[command];
17772
+ }
17773
+
17506
17774
  // Expose public methods
17507
17775
  extend(this, {
17508
17776
  execCommand: execCommand,
17509
17777
  queryCommandState: queryCommandState,
17510
17778
  queryCommandValue: queryCommandValue,
17511
- addCommands: addCommands
17779
+ queryCommandSupported: queryCommandSupported,
17780
+ addCommands: addCommands,
17781
+ addCommand: addCommand,
17782
+ addQueryStateHandler: addQueryStateHandler,
17783
+ addQueryValueHandler: addQueryValueHandler,
17784
+ hasCustomCommand: hasCustomCommand
17512
17785
  });
17513
17786
 
17514
17787
  // Private methods
@@ -17740,6 +18013,31 @@ define("tinymce/EditorCommands", [
17740
18013
  return html;
17741
18014
  }
17742
18015
 
18016
+ // Removes &nbsp; from a [b] c -> a &nbsp;c -> a c
18017
+ function trimNbspAfterDeleteAndPaddValue() {
18018
+ var rng, container, offset;
18019
+
18020
+ rng = selection.getRng(true);
18021
+ container = rng.startContainer;
18022
+ offset = rng.startOffset;
18023
+
18024
+ if (container.nodeType == 3 && rng.collapsed) {
18025
+ if (container.data[offset] === '\u00a0') {
18026
+ container.deleteData(offset, 1);
18027
+
18028
+ if (!/[\u00a0| ]$/.test(value)) {
18029
+ value += ' ';
18030
+ }
18031
+ } else if (container.data[offset - 1] === '\u00a0') {
18032
+ container.deleteData(offset - 1, 1);
18033
+
18034
+ if (!/[\u00a0| ]$/.test(value)) {
18035
+ value = ' ' + value;
18036
+ }
18037
+ }
18038
+ }
18039
+ }
18040
+
17743
18041
  function markInlineFormatElements(fragment) {
17744
18042
  if (merge) {
17745
18043
  for (node = fragment.firstChild; node; node = node.walk(true)) {
@@ -17766,7 +18064,7 @@ define("tinymce/EditorCommands", [
17766
18064
  }
17767
18065
  }
17768
18066
 
17769
- if (typeof(value) != 'string') {
18067
+ if (typeof value != 'string') {
17770
18068
  merge = value.merge;
17771
18069
  value = value.content;
17772
18070
  }
@@ -17810,6 +18108,7 @@ define("tinymce/EditorCommands", [
17810
18108
  // Insert node maker where we will insert the new HTML and get it's parent
17811
18109
  if (!selection.isCollapsed()) {
17812
18110
  editor.getDoc().execCommand('Delete', false, null);
18111
+ trimNbspAfterDeleteAndPaddValue();
17813
18112
  }
17814
18113
 
17815
18114
  parentNode = selection.getNode();
@@ -18008,7 +18307,7 @@ define("tinymce/EditorCommands", [
18008
18307
  mceInsertLink: function(command, ui, value) {
18009
18308
  var anchor;
18010
18309
 
18011
- if (typeof(value) == 'string') {
18310
+ if (typeof value == 'string') {
18012
18311
  value = {href: value};
18013
18312
  }
18014
18313
 
@@ -18908,11 +19207,11 @@ define("tinymce/util/EventDispatcher", [
18908
19207
  handlers = bindings[name];
18909
19208
  if (handlers) {
18910
19209
  for (i = 0, l = handlers.length; i < l; i++) {
18911
- handlers[i] = callback = handlers[i];
19210
+ callback = handlers[i];
18912
19211
 
18913
19212
  // Unbind handlers marked with "once"
18914
19213
  if (callback.once) {
18915
- off(name, callback);
19214
+ off(name, callback.func);
18916
19215
  }
18917
19216
 
18918
19217
  // Stop immediate propagation if needed
@@ -18922,7 +19221,7 @@ define("tinymce/util/EventDispatcher", [
18922
19221
  }
18923
19222
 
18924
19223
  // If callback returns false then prevent default and stop all propagation
18925
- if (callback.call(scope, args) === false) {
19224
+ if (callback.func.call(scope, args) === false) {
18926
19225
  args.preventDefault();
18927
19226
  return args;
18928
19227
  }
@@ -18945,7 +19244,7 @@ define("tinymce/util/EventDispatcher", [
18945
19244
  * // Callback logic
18946
19245
  * });
18947
19246
  */
18948
- function on(name, callback, prepend) {
19247
+ function on(name, callback, prepend, extra) {
18949
19248
  var handlers, names, i;
18950
19249
 
18951
19250
  if (callback === false) {
@@ -18953,6 +19252,14 @@ define("tinymce/util/EventDispatcher", [
18953
19252
  }
18954
19253
 
18955
19254
  if (callback) {
19255
+ callback = {
19256
+ func: callback
19257
+ };
19258
+
19259
+ if (extra) {
19260
+ Tools.extend(callback, extra);
19261
+ }
19262
+
18956
19263
  names = name.toLowerCase().split(' ');
18957
19264
  i = names.length;
18958
19265
  while (i--) {
@@ -19019,7 +19326,7 @@ define("tinymce/util/EventDispatcher", [
19019
19326
  // Unbind specific ones
19020
19327
  hi = handlers.length;
19021
19328
  while (hi--) {
19022
- if (handlers[hi] === callback) {
19329
+ if (handlers[hi].func === callback) {
19023
19330
  handlers = handlers.slice(0, hi).concat(handlers.slice(hi + 1));
19024
19331
  bindings[name] = handlers;
19025
19332
  }
@@ -19058,8 +19365,7 @@ define("tinymce/util/EventDispatcher", [
19058
19365
  * });
19059
19366
  */
19060
19367
  function once(name, callback, prepend) {
19061
- callback.once = true;
19062
- return on(name, callback, prepend);
19368
+ return on(name, callback, prepend, {once: true});
19063
19369
  }
19064
19370
 
19065
19371
  /**
@@ -19578,7 +19884,7 @@ define("tinymce/ui/Collection", [
19578
19884
  var self = this, i, l, matches = [], item, match;
19579
19885
 
19580
19886
  // Compile string into selector expression
19581
- if (typeof(selector) === "string") {
19887
+ if (typeof selector === "string") {
19582
19888
  selector = new Selector(selector);
19583
19889
 
19584
19890
  match = function(item) {
@@ -19963,15 +20269,15 @@ define("tinymce/ui/DomUtils", [
19963
20269
  return document.getElementById(id);
19964
20270
  },
19965
20271
 
19966
- addClass : function(elm, cls) {
20272
+ addClass: function(elm, cls) {
19967
20273
  return DOMUtils.DOM.addClass(elm, cls);
19968
20274
  },
19969
20275
 
19970
- removeClass : function(elm, cls) {
20276
+ removeClass: function(elm, cls) {
19971
20277
  return DOMUtils.DOM.removeClass(elm, cls);
19972
20278
  },
19973
20279
 
19974
- hasClass : function(elm, cls) {
20280
+ hasClass: function(elm, cls) {
19975
20281
  return DOMUtils.DOM.hasClass(elm, cls);
19976
20282
  },
19977
20283
 
@@ -20215,7 +20521,7 @@ define("tinymce/ui/Control", [
20215
20521
  return;
20216
20522
  }
20217
20523
 
20218
- if (typeof(value) === "number") {
20524
+ if (typeof value === "number") {
20219
20525
  value = value || 0;
20220
20526
 
20221
20527
  return {
@@ -20315,7 +20621,7 @@ define("tinymce/ui/Control", [
20315
20621
  width = settings.width;
20316
20622
  height = settings.height;
20317
20623
  autoResize = settings.autoResize;
20318
- autoResize = typeof(autoResize) != "undefined" ? autoResize : !width && !height;
20624
+ autoResize = typeof autoResize != "undefined" ? autoResize : !width && !height;
20319
20625
 
20320
20626
  width = width || minWidth;
20321
20627
  height = height || minHeight;
@@ -20540,7 +20846,7 @@ define("tinymce/ui/Control", [
20540
20846
  function resolveCallbackName(name) {
20541
20847
  var callback, scope;
20542
20848
 
20543
- if (typeof(name) != 'string') {
20849
+ if (typeof name != 'string') {
20544
20850
  return name;
20545
20851
  }
20546
20852
 
@@ -20870,7 +21176,7 @@ define("tinymce/ui/Control", [
20870
21176
  visible: function(state) {
20871
21177
  var self = this, parentCtrl;
20872
21178
 
20873
- if (typeof(state) !== "undefined") {
21179
+ if (typeof state !== "undefined") {
20874
21180
  if (self._visible !== state) {
20875
21181
  if (self._rendered) {
20876
21182
  self.getEl().style.display = state ? '' : 'none';
@@ -20952,7 +21258,7 @@ define("tinymce/ui/Control", [
20952
21258
  aria: function(name, value) {
20953
21259
  var self = this, elm = self.getEl(self.ariaTarget);
20954
21260
 
20955
- if (typeof(value) === "undefined") {
21261
+ if (typeof value === "undefined") {
20956
21262
  return self._aria[name];
20957
21263
  } else {
20958
21264
  self._aria[name] = value;
@@ -21276,7 +21582,7 @@ define("tinymce/ui/Control", [
21276
21582
  for (i = lastParents.length - 1; i >= idx; i--) {
21277
21583
  lastCtrl = lastParents[i];
21278
21584
  lastCtrl.fire("mouseleave", {
21279
- target : lastCtrl.getEl()
21585
+ target: lastCtrl.getEl()
21280
21586
  });
21281
21587
  }
21282
21588
  }
@@ -21284,7 +21590,7 @@ define("tinymce/ui/Control", [
21284
21590
  for (i = idx; i < parents.length; i++) {
21285
21591
  ctrl = parents[i];
21286
21592
  ctrl.fire("mouseenter", {
21287
- target : ctrl.getEl()
21593
+ target: ctrl.getEl()
21288
21594
  });
21289
21595
  }
21290
21596
  }
@@ -21568,7 +21874,7 @@ define("tinymce/ui/Factory", [], function() {
21568
21874
  }
21569
21875
 
21570
21876
  // If string is specified then use it as the type
21571
- if (typeof(type) == 'string') {
21877
+ if (typeof type == 'string') {
21572
21878
  settings = settings || {};
21573
21879
  settings.type = type;
21574
21880
  } else {
@@ -22215,7 +22521,7 @@ define("tinymce/ui/Container", [
22215
22521
  // Construct item if needed
22216
22522
  if (!(item instanceof Control)) {
22217
22523
  // Name only then convert it to an object
22218
- if (typeof(item) == "string") {
22524
+ if (typeof item == "string") {
22219
22525
  item = {type: item};
22220
22526
  }
22221
22527
 
@@ -22353,7 +22659,7 @@ define("tinymce/ui/Container", [
22353
22659
  self.find('*').each(function(ctrl) {
22354
22660
  var name = ctrl.name(), value = ctrl.value();
22355
22661
 
22356
- if (name && typeof(value) != "undefined") {
22662
+ if (name && typeof value != "undefined") {
22357
22663
  data[name] = value;
22358
22664
  }
22359
22665
  });
@@ -22831,14 +23137,14 @@ define("tinymce/ui/Panel", [
22831
23137
  self.preRender();
22832
23138
  layout.preRender(self);
22833
23139
 
22834
- if (typeof(innerHtml) == "undefined") {
23140
+ if (typeof innerHtml == "undefined") {
22835
23141
  innerHtml = (
22836
23142
  '<div id="' + self._id + '-body" class="' + self.classes('body') + '">' +
22837
23143
  layout.renderHtml(self) +
22838
23144
  '</div>'
22839
23145
  );
22840
23146
  } else {
22841
- if (typeof(innerHtml) == 'function') {
23147
+ if (typeof innerHtml == 'function') {
22842
23148
  innerHtml = innerHtml.call(self);
22843
23149
  }
22844
23150
 
@@ -22987,7 +23293,7 @@ define("tinymce/ui/Movable", [
22987
23293
  * @return {tinymce.ui.Control} Current control instance.
22988
23294
  */
22989
23295
  moveRel: function(elm, rel) {
22990
- if (typeof(rel) != 'string') {
23296
+ if (typeof rel != 'string') {
22991
23297
  rel = this.testMoveRel(elm, rel);
22992
23298
  }
22993
23299
 
@@ -23744,7 +24050,7 @@ define("tinymce/ui/Window", [
23744
24050
  html = '<iframe src="' + settings.url + '" tabindex="-1"></iframe>';
23745
24051
  }
23746
24052
 
23747
- if (typeof(html) == "undefined") {
24053
+ if (typeof html == "undefined") {
23748
24054
  html = layout.renderHtml(self);
23749
24055
  }
23750
24056
 
@@ -24093,7 +24399,7 @@ define("tinymce/ui/MessageBox", [
24093
24399
  * @param {function} [callback] Callback to execute when the user makes a choice.
24094
24400
  */
24095
24401
  alert: function(settings, callback) {
24096
- if (typeof(settings) == "string") {
24402
+ if (typeof settings == "string") {
24097
24403
  settings = {text: settings};
24098
24404
  }
24099
24405
 
@@ -24109,7 +24415,7 @@ define("tinymce/ui/MessageBox", [
24109
24415
  * @param {function} [callback] Callback to execute when the user makes a choice.
24110
24416
  */
24111
24417
  confirm: function(settings, callback) {
24112
- if (typeof(settings) == "string") {
24418
+ if (typeof settings == "string") {
24113
24419
  settings = {text: settings};
24114
24420
  }
24115
24421
 
@@ -24194,9 +24500,7 @@ define("tinymce/WindowManager", [
24194
24500
  * @option {String} file URL of the file to open in the window.
24195
24501
  * @option {Number} width Width in pixels.
24196
24502
  * @option {Number} height Height in pixels.
24197
- * @option {Boolean} resizable Specifies whether the popup window is resizable or not.
24198
- * @option {Boolean} maximizable Specifies whether the popup window has a "maximize" button and can get maximized or not.
24199
- * @option {String/Boolean} scrollbars Specifies whether the popup window can have scrollbars if required (i.e. content
24503
+ * @option {Boolean} autoScroll Specifies whether the popup window can have scrollbars if required (i.e. content
24200
24504
  * larger than the popup size specified).
24201
24505
  */
24202
24506
  self.open = function(args, params) {
@@ -24392,16 +24696,19 @@ define("tinymce/WindowManager", [
24392
24696
  define("tinymce/util/Quirks", [
24393
24697
  "tinymce/util/VK",
24394
24698
  "tinymce/dom/RangeUtils",
24699
+ "tinymce/dom/TreeWalker",
24395
24700
  "tinymce/html/Node",
24396
24701
  "tinymce/html/Entities",
24397
24702
  "tinymce/Env",
24398
24703
  "tinymce/util/Tools"
24399
- ], function(VK, RangeUtils, Node, Entities, Env, Tools) {
24704
+ ], function(VK, RangeUtils, TreeWalker, Node, Entities, Env, Tools) {
24400
24705
  return function(editor) {
24401
- var each = Tools.each;
24706
+ var each = Tools.each, $ = editor.$;
24402
24707
  var BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection,
24403
24708
  settings = editor.settings, parser = editor.parser, serializer = editor.serializer;
24404
24709
  var isGecko = Env.gecko, isIE = Env.ie, isWebKit = Env.webkit;
24710
+ var mceInternalUrlPrefix = 'data:text/mce-internal,';
24711
+ var mceInternalDataType = isIE ? 'Text' : 'URL';
24405
24712
 
24406
24713
  /**
24407
24714
  * Executes a command with a specific state this can be to enable/disable browser editing features.
@@ -24434,6 +24741,69 @@ define("tinymce/util/Quirks", [
24434
24741
  return e.isDefaultPrevented();
24435
24742
  }
24436
24743
 
24744
+ /**
24745
+ * Sets Text/URL data on the event's dataTransfer object to a special data:text/mce-internal url.
24746
+ * This is to workaround the inability to set custom contentType on IE and Safari.
24747
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
24748
+ *
24749
+ * @private
24750
+ * @param {DragEvent} e Event object
24751
+ */
24752
+ function setMceInteralContent(e) {
24753
+ var selectionHtml;
24754
+
24755
+ if (e.dataTransfer) {
24756
+ if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
24757
+ selection.select(e.target);
24758
+ }
24759
+
24760
+ selectionHtml = editor.selection.getContent();
24761
+
24762
+ // Safari/IE doesn't support custom dataTransfer items so we can only use URL and Text
24763
+ if (selectionHtml.length > 0) {
24764
+ e.dataTransfer.setData(mceInternalDataType, mceInternalUrlPrefix + escape(selectionHtml));
24765
+ }
24766
+ }
24767
+ }
24768
+
24769
+ /**
24770
+ * Gets content of special data:text/mce-internal url on the event's dataTransfer object.
24771
+ * This is to workaround the inability to set custom contentType on IE and Safari.
24772
+ * The editor's selected content is encoded into this url so drag and drop between editors will work.
24773
+ *
24774
+ * @private
24775
+ * @param {DragEvent} e Event object
24776
+ * @returns {String} mce-internal content
24777
+ */
24778
+ function getMceInternalContent(e) {
24779
+ var internalContent, content;
24780
+
24781
+ if (e.dataTransfer) {
24782
+ internalContent = e.dataTransfer.getData(mceInternalDataType);
24783
+
24784
+ if (internalContent && internalContent.indexOf(mceInternalUrlPrefix) >= 0) {
24785
+ content = unescape(internalContent.substr(mceInternalUrlPrefix.length));
24786
+ }
24787
+ }
24788
+
24789
+ return content;
24790
+ }
24791
+
24792
+ /**
24793
+ * Inserts contents using the paste clipboard command if it's available if it isn't it will fallback
24794
+ * to the core command.
24795
+ *
24796
+ * @private
24797
+ * @param {String} content Content to insert at selection.
24798
+ */
24799
+ function insertClipboardContents(content) {
24800
+ if (editor.queryCommandSupported('mceInsertClipboardContent')) {
24801
+ editor.execCommand('mceInsertClipboardContent', false, {content: content});
24802
+ } else {
24803
+ editor.execCommand('mceInsertContent', false, content);
24804
+ }
24805
+ }
24806
+
24437
24807
  /**
24438
24808
  * Fixes a WebKit bug when deleting contents using backspace or delete key.
24439
24809
  * WebKit will produce a span element if you delete across two block elements.
@@ -24456,13 +24826,13 @@ define("tinymce/util/Quirks", [
24456
24826
  * 4. Delete by pressing delete key with ctrl/cmd (Word delete).
24457
24827
  * 5. Delete by drag/dropping contents inside the editor.
24458
24828
  * 6. Delete by using Cut Ctrl+X/Cmd+X.
24459
- * 7. Delete by selecting contents and writing a character.'
24829
+ * 7. Delete by selecting contents and writing a character.
24460
24830
  *
24461
24831
  * This code is a ugly hack since writing full custom delete logic for just this bug
24462
24832
  * fix seemed like a huge task. I hope we can remove this before the year 2030.
24463
24833
  */
24464
24834
  function cleanupStylesWhenDeleting() {
24465
- var doc = editor.getDoc(), urlPrefix = 'data:text/mce-internal,';
24835
+ var doc = editor.getDoc(), dom = editor.dom, selection = editor.selection;
24466
24836
  var MutationObserver = window.MutationObserver, olderWebKit, dragStartRng;
24467
24837
 
24468
24838
  // Add mini polyfill for older WebKits
@@ -24504,8 +24874,212 @@ define("tinymce/util/Quirks", [
24504
24874
  };
24505
24875
  }
24506
24876
 
24877
+ function isTrailingBr(node) {
24878
+ var blockElements = dom.schema.getBlockElements(), rootNode = editor.getBody();
24879
+
24880
+ if (node.nodeName != 'BR') {
24881
+ return false;
24882
+ }
24883
+
24884
+ for (node = node; node != rootNode && !blockElements[node.nodeName]; node = node.parentNode) {
24885
+ if (node.nextSibling) {
24886
+ return false;
24887
+ }
24888
+ }
24889
+
24890
+ return true;
24891
+ }
24892
+
24893
+ function isSiblingsIgnoreWhiteSpace(node1, node2) {
24894
+ var node;
24895
+
24896
+ for (node = node1.nextSibling; node && node != node2; node = node.nextSibling) {
24897
+ if (node.nodeType == 3 && $.trim(node.data).length === 0) {
24898
+ continue;
24899
+ }
24900
+
24901
+ if (node !== node2) {
24902
+ return false;
24903
+ }
24904
+ }
24905
+
24906
+ return node === node2;
24907
+ }
24908
+
24909
+ function findCaretNode(node, forward, startNode) {
24910
+ var walker, current, nonEmptyElements;
24911
+
24912
+ nonEmptyElements = dom.schema.getNonEmptyElements();
24913
+
24914
+ walker = new TreeWalker(startNode || node, node);
24915
+
24916
+ while ((current = walker[forward ? 'next' : 'prev']())) {
24917
+ if (nonEmptyElements[current.nodeName] && !isTrailingBr(current)) {
24918
+ return current;
24919
+ }
24920
+
24921
+ if (current.nodeType == 3 && current.data.length > 0) {
24922
+ return current;
24923
+ }
24924
+ }
24925
+ }
24926
+
24927
+ function deleteRangeBetweenTextBlocks(rng) {
24928
+ var startBlock, endBlock, caretNodeBefore, caretNodeAfter, textBlockElements;
24929
+
24930
+ if (rng.collapsed) {
24931
+ return;
24932
+ }
24933
+
24934
+ startBlock = dom.getParent(RangeUtils.getNode(rng.startContainer, rng.startOffset), dom.isBlock);
24935
+ endBlock = dom.getParent(RangeUtils.getNode(rng.endContainer, rng.endOffset), dom.isBlock);
24936
+ textBlockElements = editor.schema.getTextBlockElements();
24937
+
24938
+ if (startBlock == endBlock) {
24939
+ return;
24940
+ }
24941
+
24942
+ if (!textBlockElements[startBlock.nodeName] || !textBlockElements[endBlock.nodeName]) {
24943
+ return;
24944
+ }
24945
+
24946
+ if (dom.getContentEditable(startBlock) === "false" || dom.getContentEditable(endBlock) === "false") {
24947
+ return;
24948
+ }
24949
+
24950
+ rng.deleteContents();
24951
+
24952
+ caretNodeBefore = findCaretNode(startBlock, false);
24953
+ caretNodeAfter = findCaretNode(endBlock, true);
24954
+
24955
+ if (!dom.isEmpty(endBlock)) {
24956
+ $(startBlock).append(endBlock.childNodes);
24957
+ }
24958
+
24959
+ $(endBlock).remove();
24960
+
24961
+ if (caretNodeBefore) {
24962
+ if (caretNodeBefore.nodeType == 1) {
24963
+ if (caretNodeBefore.nodeName == "BR") {
24964
+ rng.setStartBefore(caretNodeBefore);
24965
+ rng.setEndBefore(caretNodeBefore);
24966
+ } else {
24967
+ rng.setStartAfter(caretNodeBefore);
24968
+ rng.setEndAfter(caretNodeBefore);
24969
+ }
24970
+ } else {
24971
+ rng.setStart(caretNodeBefore, caretNodeBefore.data.length);
24972
+ rng.setEnd(caretNodeBefore, caretNodeBefore.data.length);
24973
+ }
24974
+ } else if (caretNodeAfter) {
24975
+ if (caretNodeAfter.nodeType == 1) {
24976
+ rng.setStartBefore(caretNodeAfter);
24977
+ rng.setEndBefore(caretNodeAfter);
24978
+ } else {
24979
+ rng.setStart(caretNodeAfter, 0);
24980
+ rng.setEnd(caretNodeAfter, 0);
24981
+ }
24982
+ }
24983
+
24984
+ selection.setRng(rng);
24985
+
24986
+ return true;
24987
+ }
24988
+
24989
+ function expandBetweenBlocks(rng, isForward) {
24990
+ var caretNode, targetCaretNode, textBlock, targetTextBlock, container, offset;
24991
+
24992
+ if (!rng.collapsed) {
24993
+ return rng;
24994
+ }
24995
+
24996
+ container = rng.startContainer;
24997
+ offset = rng.startOffset;
24998
+
24999
+ if (container.nodeType == 3) {
25000
+ if (isForward) {
25001
+ if (offset < container.data.length) {
25002
+ return rng;
25003
+ }
25004
+ } else {
25005
+ if (offset > 0) {
25006
+ return rng;
25007
+ }
25008
+ }
25009
+ }
25010
+
25011
+ caretNode = RangeUtils.getNode(rng.startContainer, rng.startOffset);
25012
+ textBlock = dom.getParent(caretNode, dom.isBlock);
25013
+ targetCaretNode = findCaretNode(editor.getBody(), isForward, caretNode);
25014
+ targetTextBlock = dom.getParent(targetCaretNode, dom.isBlock);
25015
+
25016
+ if (!caretNode || !targetCaretNode) {
25017
+ return rng;
25018
+ }
25019
+
25020
+ if (targetTextBlock && textBlock != targetTextBlock) {
25021
+ if (!isForward) {
25022
+ if (!isSiblingsIgnoreWhiteSpace(targetTextBlock, textBlock)) {
25023
+ return rng;
25024
+ }
25025
+
25026
+ if (targetCaretNode.nodeType == 1) {
25027
+ if (targetCaretNode.nodeName == "BR") {
25028
+ rng.setStartBefore(targetCaretNode);
25029
+ } else {
25030
+ rng.setStartAfter(targetCaretNode);
25031
+ }
25032
+ } else {
25033
+ rng.setStart(targetCaretNode, targetCaretNode.data.length);
25034
+ }
25035
+
25036
+ if (caretNode.nodeType == 1) {
25037
+ rng.setEnd(caretNode, 0);
25038
+ } else {
25039
+ rng.setEndBefore(caretNode);
25040
+ }
25041
+ } else {
25042
+ if (!isSiblingsIgnoreWhiteSpace(textBlock, targetTextBlock)) {
25043
+ return rng;
25044
+ }
25045
+
25046
+ if (caretNode.nodeType == 1) {
25047
+ if (caretNode.nodeName == "BR") {
25048
+ rng.setStartBefore(caretNode);
25049
+ } else {
25050
+ rng.setStartAfter(caretNode);
25051
+ }
25052
+ } else {
25053
+ rng.setStart(caretNode, caretNode.data.length);
25054
+ }
25055
+
25056
+ if (targetCaretNode.nodeType == 1) {
25057
+ rng.setEnd(targetCaretNode, 0);
25058
+ } else {
25059
+ rng.setEndBefore(targetCaretNode);
25060
+ }
25061
+ }
25062
+ }
25063
+
25064
+ return rng;
25065
+ }
25066
+
25067
+ function handleTextBlockMergeDelete(isForward) {
25068
+ var rng = selection.getRng();
25069
+
25070
+ rng = expandBetweenBlocks(rng, isForward);
25071
+
25072
+ if (deleteRangeBetweenTextBlocks(rng)) {
25073
+ return true;
25074
+ }
25075
+ }
25076
+
24507
25077
  function customDelete(isForward) {
24508
- var mutationObserver = new MutationObserver(function() {});
25078
+ var mutationObserver, rng, caretElement;
25079
+
25080
+ if (handleTextBlockMergeDelete(isForward)) {
25081
+ return;
25082
+ }
24509
25083
 
24510
25084
  Tools.each(editor.getBody().getElementsByTagName('*'), function(elm) {
24511
25085
  // Mark existing spans
@@ -24520,6 +25094,7 @@ define("tinymce/util/Quirks", [
24520
25094
  });
24521
25095
 
24522
25096
  // Observe added nodes and style attribute changes
25097
+ mutationObserver = new MutationObserver(function() {});
24523
25098
  mutationObserver.observe(editor.getDoc(), {
24524
25099
  childList: true,
24525
25100
  attributes: true,
@@ -24529,8 +25104,8 @@ define("tinymce/util/Quirks", [
24529
25104
 
24530
25105
  editor.getDoc().execCommand(isForward ? 'ForwardDelete' : 'Delete', false, null);
24531
25106
 
24532
- var rng = editor.selection.getRng();
24533
- var caretElement = rng.startContainer.parentNode;
25107
+ rng = editor.selection.getRng();
25108
+ caretElement = rng.startContainer.parentNode;
24534
25109
 
24535
25110
  Tools.each(mutationObserver.takeRecords(), function(record) {
24536
25111
  if (!dom.isChildOf(record.target, editor.getBody())) {
@@ -24578,13 +25153,13 @@ define("tinymce/util/Quirks", [
24578
25153
  }
24579
25154
 
24580
25155
  editor.on('keydown', function(e) {
24581
- var isForward = e.keyCode == DELETE, isMeta = VK.metaKeyPressed(e);
25156
+ var isForward = e.keyCode == DELETE, isMetaOrCtrl = e.ctrlKey || e.metaKey;
24582
25157
 
24583
25158
  if (!isDefaultPrevented(e) && (isForward || e.keyCode == BACKSPACE)) {
24584
25159
  var rng = editor.selection.getRng(), container = rng.startContainer, offset = rng.startOffset;
24585
25160
 
24586
25161
  // Ignore non meta delete in the where there is text before/after the caret
24587
- if (!isMeta && rng.collapsed && container.nodeType == 3) {
25162
+ if (!isMetaOrCtrl && rng.collapsed && container.nodeType == 3) {
24588
25163
  if (isForward ? offset < container.data.length : offset > 0) {
24589
25164
  return;
24590
25165
  }
@@ -24592,19 +25167,69 @@ define("tinymce/util/Quirks", [
24592
25167
 
24593
25168
  e.preventDefault();
24594
25169
 
24595
- if (isMeta) {
24596
- editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", "word");
25170
+ if (isMetaOrCtrl) {
25171
+ editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", e.metaKey ? "lineboundary" : "word");
24597
25172
  }
24598
25173
 
24599
25174
  customDelete(isForward);
24600
25175
  }
24601
25176
  });
24602
25177
 
25178
+ // Handle case where text is deleted by typing over
24603
25179
  editor.on('keypress', function(e) {
24604
25180
  if (!isDefaultPrevented(e) && !selection.isCollapsed() && e.charCode && !VK.metaKeyPressed(e)) {
25181
+ var rng, currentFormatNodes, fragmentNode, blockParent, caretNode, charText;
25182
+
25183
+ rng = editor.selection.getRng();
25184
+ charText = String.fromCharCode(e.charCode);
24605
25185
  e.preventDefault();
25186
+
25187
+ // Keep track of current format nodes
25188
+ currentFormatNodes = $(rng.startContainer).parents().filter(function(idx, node) {
25189
+ return !!editor.schema.getTextInlineElements()[node.nodeName];
25190
+ });
25191
+
24606
25192
  customDelete(true);
24607
- editor.selection.setContent(String.fromCharCode(e.charCode));
25193
+
25194
+ // Check if the browser removed them
25195
+ currentFormatNodes = currentFormatNodes.filter(function(idx, node) {
25196
+ return !$.contains(editor.getBody(), node);
25197
+ });
25198
+
25199
+ // Then re-add them
25200
+ if (currentFormatNodes.length) {
25201
+ fragmentNode = dom.createFragment();
25202
+
25203
+ currentFormatNodes.each(function(idx, formatNode) {
25204
+ formatNode = formatNode.cloneNode(false);
25205
+
25206
+ if (fragmentNode.hasChildNodes()) {
25207
+ formatNode.appendChild(fragmentNode.firstChild);
25208
+ fragmentNode.appendChild(formatNode);
25209
+ } else {
25210
+ caretNode = formatNode;
25211
+ fragmentNode.appendChild(formatNode);
25212
+ }
25213
+
25214
+ fragmentNode.appendChild(formatNode);
25215
+ });
25216
+
25217
+ caretNode.appendChild(editor.getDoc().createTextNode(charText));
25218
+
25219
+ // Prevent edge case where older WebKit would add an extra BR element
25220
+ blockParent = dom.getParent(rng.startContainer, dom.isBlock);
25221
+ if (dom.isEmpty(blockParent)) {
25222
+ $(blockParent).empty().append(fragmentNode);
25223
+ } else {
25224
+ rng.insertNode(fragmentNode);
25225
+ }
25226
+
25227
+ rng.setStart(caretNode.firstChild, 1);
25228
+ rng.setEnd(caretNode.firstChild, 1);
25229
+ editor.selection.setRng(rng);
25230
+ } else {
25231
+ editor.selection.setContent(charText);
25232
+ }
24608
25233
  }
24609
25234
  });
24610
25235
 
@@ -24622,31 +25247,14 @@ define("tinymce/util/Quirks", [
24622
25247
  }
24623
25248
 
24624
25249
  editor.on('dragstart', function(e) {
24625
- var selectionHtml;
24626
-
24627
- if (editor.selection.isCollapsed() && e.target.tagName == 'IMG') {
24628
- selection.select(e.target);
24629
- }
24630
-
24631
25250
  dragStartRng = selection.getRng();
24632
- selectionHtml = editor.selection.getContent();
24633
-
24634
- // Safari doesn't support custom dataTransfer items so we can only use URL and Text
24635
- if (selectionHtml.length > 0) {
24636
- e.dataTransfer.setData('URL', 'data:text/mce-internal,' + escape(selectionHtml));
24637
- }
25251
+ setMceInteralContent(e);
24638
25252
  });
24639
25253
 
24640
25254
  editor.on('drop', function(e) {
24641
25255
  if (!isDefaultPrevented(e)) {
24642
- var internalContent = e.dataTransfer.getData('URL');
24643
-
24644
- if (!internalContent || internalContent.indexOf(urlPrefix) == -1 || !doc.caretRangeFromPoint) {
24645
- return;
24646
- }
24647
-
24648
- internalContent = unescape(internalContent.substr(urlPrefix.length));
24649
- if (doc.caretRangeFromPoint) {
25256
+ var internalContent = getMceInternalContent(e);
25257
+ if (internalContent) {
24650
25258
  e.preventDefault();
24651
25259
 
24652
25260
  // Safari has a weird issue where drag/dropping images sometimes
@@ -24654,7 +25262,7 @@ define("tinymce/util/Quirks", [
24654
25262
  // will return "null" even though the x, y coordinate is correct.
24655
25263
  // But if we detach the insert from the drop event we will get a proper range
24656
25264
  window.setTimeout(function() {
24657
- var pointRng = doc.caretRangeFromPoint(e.x, e.y);
25265
+ var pointRng = RangeUtils.getCaretRangeFromPoint(e.x, e.y, doc);
24658
25266
 
24659
25267
  if (dragStartRng) {
24660
25268
  selection.setRng(dragStartRng);
@@ -24662,12 +25270,10 @@ define("tinymce/util/Quirks", [
24662
25270
  }
24663
25271
 
24664
25272
  customDelete();
24665
-
24666
25273
  selection.setRng(pointRng);
24667
- editor.insertContent(internalContent);
25274
+ insertClipboardContents(internalContent);
24668
25275
  }, 0);
24669
25276
  }
24670
-
24671
25277
  }
24672
25278
  });
24673
25279
 
@@ -24761,7 +25367,7 @@ define("tinymce/util/Quirks", [
24761
25367
  * This selects the whole body so that backspace/delete logic will delete everything
24762
25368
  */
24763
25369
  function selectAll() {
24764
- editor.shortcuts.add('ctrl+a', null, 'SelectAll');
25370
+ editor.shortcuts.add('meta+a', null, 'SelectAll');
24765
25371
  }
24766
25372
 
24767
25373
  /**
@@ -25399,7 +26005,12 @@ define("tinymce/util/Quirks", [
25399
26005
  editor.contentStyles.push('body {min-height: 150px}');
25400
26006
  editor.on('click', function(e) {
25401
26007
  if (e.target.nodeName == 'HTML') {
26008
+ var rng;
26009
+
26010
+ // Need to store away non collapsed ranges since the focus call will mess that up see #7382
26011
+ rng = editor.selection.getRng();
25402
26012
  editor.getBody().focus();
26013
+ editor.selection.setRng(rng);
25403
26014
  editor.selection.normalize();
25404
26015
  editor.nodeChanged();
25405
26016
  }
@@ -25416,7 +26027,7 @@ define("tinymce/util/Quirks", [
25416
26027
  editor.on('keydown', function(e) {
25417
26028
  if (VK.metaKeyPressed(e) && (e.keyCode == 37 || e.keyCode == 39)) {
25418
26029
  e.preventDefault();
25419
- editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'word');
26030
+ editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'lineboundary');
25420
26031
  }
25421
26032
  });
25422
26033
  }
@@ -25555,6 +26166,29 @@ define("tinymce/util/Quirks", [
25555
26166
  });
25556
26167
  }
25557
26168
 
26169
+ /**
26170
+ * IE cannot set custom contentType's on drag events, and also does not properly drag/drop between
26171
+ * editors. This uses a special data:text/mce-internal URL to pass data when drag/drop between editors.
26172
+ */
26173
+ function ieInternalDragAndDrop() {
26174
+ editor.on('dragstart', function(e) {
26175
+ setMceInteralContent(e);
26176
+ });
26177
+
26178
+ editor.on('drop', function(e) {
26179
+ if (!isDefaultPrevented(e)) {
26180
+ var internalContent = getMceInternalContent(e);
26181
+ if (internalContent) {
26182
+ e.preventDefault();
26183
+
26184
+ var rng = RangeUtils.getCaretRangeFromPoint(e.x, e.y, editor.getDoc());
26185
+ selection.setRng(rng);
26186
+ insertClipboardContents(internalContent);
26187
+ }
26188
+ }
26189
+ });
26190
+ }
26191
+
25558
26192
  // All browsers
25559
26193
  removeBlockQuoteOnBackSpace();
25560
26194
  emptyEditorWhenDeleting();
@@ -25602,6 +26236,7 @@ define("tinymce/util/Quirks", [
25602
26236
  if (Env.ie) {
25603
26237
  selectAll();
25604
26238
  disableAutoUrlDetect();
26239
+ ieInternalDragAndDrop();
25605
26240
  }
25606
26241
 
25607
26242
  // Gecko
@@ -25972,6 +26607,12 @@ define("tinymce/EditorObservable", [
25972
26607
 
25973
26608
  /**
25974
26609
  * Contains all logic for handling of keyboard shortcuts.
26610
+ *
26611
+ * @example
26612
+ * editor.shortcuts.add('ctrl+a', function() {});
26613
+ * editor.shortcuts.add('meta+a', function() {}); // "meta" maps to Command on Mac and Ctrl on PC
26614
+ * editor.shortcuts.add('ctrl+alt+a', function() {});
26615
+ * editor.shortcuts.add('access+a', function() {}); // "access" maps to ctrl+alt on Mac and shift+alt on PC
25975
26616
  */
25976
26617
  define("tinymce/Shortcuts", [
25977
26618
  "tinymce/util/Tools",
@@ -25985,15 +26626,78 @@ define("tinymce/Shortcuts", [
25985
26626
  "f11": 122
25986
26627
  };
25987
26628
 
26629
+ var modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
26630
+
25988
26631
  return function(editor) {
25989
26632
  var self = this, shortcuts = {};
25990
26633
 
26634
+ function createShortcut(pattern, desc, cmdFunc, scope) {
26635
+ var id, key, shortcut;
26636
+
26637
+ shortcut = {
26638
+ func: cmdFunc,
26639
+ scope: scope || editor,
26640
+ desc: editor.translate(desc)
26641
+ };
26642
+
26643
+ // Parse modifiers and keys ctrl+alt+b for example
26644
+ each(explode(pattern, '+'), function(value) {
26645
+ if (value in modifierNames) {
26646
+ shortcut[value] = true;
26647
+ } else {
26648
+ // Allow numeric keycodes like ctrl+219 for ctrl+[
26649
+ if (/^[0-9]{2,}$/.test(value)) {
26650
+ shortcut.keyCode = parseInt(value, 10);
26651
+ } else {
26652
+ shortcut.charCode = value.charCodeAt(0);
26653
+ shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
26654
+ }
26655
+ }
26656
+ });
26657
+
26658
+ // Generate unique id for modifier combination and set default state for unused modifiers
26659
+ id = [shortcut.keyCode];
26660
+ for (key in modifierNames) {
26661
+ if (shortcut[key]) {
26662
+ id.push(key);
26663
+ } else {
26664
+ shortcut[key] = false;
26665
+ }
26666
+ }
26667
+ shortcut.id = id.join(',');
26668
+
26669
+ // Handle special access modifier differently depending on Mac/Win
26670
+ if (shortcut.access) {
26671
+ shortcut.alt = true;
26672
+
26673
+ if (Env.mac) {
26674
+ shortcut.ctrl = true;
26675
+ } else {
26676
+ shortcut.shift = true;
26677
+ }
26678
+ }
26679
+
26680
+ // Handle special meta modifier differently depending on Mac/Win
26681
+ if (shortcut.meta) {
26682
+ if (Env.mac) {
26683
+ shortcut.meta = true;
26684
+ } else {
26685
+ shortcut.ctrl = true;
26686
+ shortcut.meta = false;
26687
+ }
26688
+ }
26689
+
26690
+ return shortcut;
26691
+ }
26692
+
25991
26693
  editor.on('keyup keypress keydown', function(e) {
25992
26694
  if ((e.altKey || e.ctrlKey || e.metaKey) && !e.isDefaultPrevented()) {
25993
26695
  each(shortcuts, function(shortcut) {
25994
- var ctrlKey = Env.mac ? e.metaKey : e.ctrlKey;
26696
+ if (shortcut.ctrl != e.ctrlKey || shortcut.meta != e.metaKey) {
26697
+ return;
26698
+ }
25995
26699
 
25996
- if (shortcut.ctrl != ctrlKey || shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
26700
+ if (shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
25997
26701
  return;
25998
26702
  }
25999
26703
 
@@ -26025,7 +26729,7 @@ define("tinymce/Shortcuts", [
26025
26729
 
26026
26730
  cmd = cmdFunc;
26027
26731
 
26028
- if (typeof(cmdFunc) === 'string') {
26732
+ if (typeof cmdFunc === 'string') {
26029
26733
  cmdFunc = function() {
26030
26734
  editor.execCommand(cmd, false, null);
26031
26735
  };
@@ -26036,43 +26740,29 @@ define("tinymce/Shortcuts", [
26036
26740
  }
26037
26741
 
26038
26742
  each(explode(pattern.toLowerCase()), function(pattern) {
26039
- var shortcut = {
26040
- func: cmdFunc,
26041
- scope: scope || editor,
26042
- desc: editor.translate(desc),
26043
- alt: false,
26044
- ctrl: false,
26045
- shift: false
26046
- };
26743
+ var shortcut = createShortcut(pattern, desc, cmdFunc, scope);
26744
+ shortcuts[shortcut.id] = shortcut;
26745
+ });
26047
26746
 
26048
- each(explode(pattern, '+'), function(value) {
26049
- switch (value) {
26050
- case 'alt':
26051
- case 'ctrl':
26052
- case 'shift':
26053
- shortcut[value] = true;
26054
- break;
26747
+ return true;
26748
+ };
26055
26749
 
26056
- default:
26057
- // Allow numeric keycodes like ctrl+219 for ctrl+[
26058
- if (/^[0-9]{2,}$/.test(value)) {
26059
- shortcut.keyCode = parseInt(value, 10);
26060
- } else {
26061
- shortcut.charCode = value.charCodeAt(0);
26062
- shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
26063
- }
26064
- }
26065
- });
26750
+ /**
26751
+ * Remove a keyboard shortcut by pattern.
26752
+ *
26753
+ * @method remove
26754
+ * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
26755
+ * @return {Boolean} true/false state if the shortcut was removed or not.
26756
+ */
26757
+ self.remove = function(pattern) {
26758
+ var shortcut = createShortcut(pattern);
26066
26759
 
26067
- shortcuts[
26068
- (shortcut.ctrl ? 'ctrl' : '') + ',' +
26069
- (shortcut.alt ? 'alt' : '') + ',' +
26070
- (shortcut.shift ? 'shift' : '') + ',' +
26071
- shortcut.keyCode
26072
- ] = shortcut;
26073
- });
26760
+ if (shortcuts[shortcut.id]) {
26761
+ delete shortcuts[shortcut.id];
26762
+ return true;
26763
+ }
26074
26764
 
26075
- return true;
26765
+ return false;
26076
26766
  };
26077
26767
  };
26078
26768
  });
@@ -26219,9 +26909,9 @@ define("tinymce/Editor", [
26219
26909
  inline_styles: true,
26220
26910
  convert_fonts_to_spans: true,
26221
26911
  indent: 'simple',
26222
- 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,' +
26912
+ 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,' +
26223
26913
  'tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
26224
- 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,' +
26914
+ 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,' +
26225
26915
  'tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
26226
26916
  validate: true,
26227
26917
  entity_encoding: 'named',
@@ -26319,12 +27009,8 @@ define("tinymce/Editor", [
26319
27009
 
26320
27010
  // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
26321
27011
  self.shortcuts = new Shortcuts(self);
26322
-
26323
- // Internal command handler objects
26324
- self.execCommands = {};
26325
- self.queryStateCommands = {};
26326
- self.queryValueCommands = {};
26327
27012
  self.loadedCSS = {};
27013
+ self.editorCommands = new EditorCommands(self);
26328
27014
 
26329
27015
  if (settings.target) {
26330
27016
  self.targetElm = settings.target;
@@ -26334,6 +27020,10 @@ define("tinymce/Editor", [
26334
27020
  self.editorManager = editorManager;
26335
27021
  self.inline = settings.inline;
26336
27022
 
27023
+ if (settings.cache_suffix) {
27024
+ Env.cacheSuffix = settings.cache_suffix.replace(/^[\?\&]+/, '');
27025
+ }
27026
+
26337
27027
  // Call setup
26338
27028
  editorManager.fire('SetupEditor', self);
26339
27029
  self.execCallback('setup', self);
@@ -26558,6 +27248,7 @@ define("tinymce/Editor", [
26558
27248
  var self = this, settings = self.settings, elm = self.getElement();
26559
27249
  var w, h, minHeight, n, o, Theme, url, bodyId, bodyClass, re, i, initializedPlugins = [];
26560
27250
 
27251
+ this.editorManager.i18n.setCode(settings.language);
26561
27252
  self.rtl = this.editorManager.i18n.rtl;
26562
27253
  self.editorManager.add(self);
26563
27254
 
@@ -26639,7 +27330,7 @@ define("tinymce/Editor", [
26639
27330
 
26640
27331
  // Resize editor
26641
27332
  if (!settings.content_editable) {
26642
- h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');
27333
+ h = (o.iframeHeight || h) + (typeof h == 'number' ? (o.deltaHeight || 0) : '');
26643
27334
  if (h < minHeight) {
26644
27335
  h = minHeight;
26645
27336
  }
@@ -26700,7 +27391,11 @@ define("tinymce/Editor", [
26700
27391
  // Load the CSS by injecting them into the HTML this will reduce "flicker"
26701
27392
  for (i = 0; i < self.contentCSS.length; i++) {
26702
27393
  var cssUrl = self.contentCSS[i];
26703
- self.iframeHTML += '<link type="text/css" rel="stylesheet" href="' + cssUrl + '" />';
27394
+ self.iframeHTML += (
27395
+ '<link type="text/css" ' +
27396
+ 'rel="stylesheet" ' +
27397
+ 'href="' + Tools._addCacheSuffix(cssUrl) + '" />'
27398
+ );
26704
27399
  self.loadedCSS[cssUrl] = true;
26705
27400
  }
26706
27401
 
@@ -26999,7 +27694,6 @@ define("tinymce/Editor", [
26999
27694
 
27000
27695
  self.forceBlocks = new ForceBlocks(self);
27001
27696
  self.enterKey = new EnterKey(self);
27002
- self.editorCommands = new EditorCommands(self);
27003
27697
  self._nodeChangeDispatcher = new NodeChange(self);
27004
27698
 
27005
27699
  self.fire('PreInit');
@@ -27093,7 +27787,9 @@ define("tinymce/Editor", [
27093
27787
  editor = self.editorManager.get(settings.auto_focus);
27094
27788
  }
27095
27789
 
27096
- editor.focus();
27790
+ if (!editor.destroyed) {
27791
+ editor.focus();
27792
+ }
27097
27793
  }, 100);
27098
27794
  }
27099
27795
 
@@ -27187,7 +27883,7 @@ define("tinymce/Editor", [
27187
27883
  scope = scope.scope;
27188
27884
  }
27189
27885
 
27190
- if (typeof(callback) === 'string') {
27886
+ if (typeof callback === 'string') {
27191
27887
  scope = callback.replace(/\.\w+$/, '');
27192
27888
  scope = scope ? resolve(scope) : 0;
27193
27889
  callback = resolve(callback);
@@ -27253,7 +27949,7 @@ define("tinymce/Editor", [
27253
27949
  if (type === 'hash') {
27254
27950
  output = {};
27255
27951
 
27256
- if (typeof(value) === 'string') {
27952
+ if (typeof value === 'string') {
27257
27953
  each(value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','), function(value) {
27258
27954
  value = value.split('=');
27259
27955
 
@@ -27394,7 +28090,7 @@ define("tinymce/Editor", [
27394
28090
  * @param {Object} value Optional value for command.
27395
28091
  * @return {Boolean} True/false state if the command was handled or not.
27396
28092
  */
27397
- this.execCommands[name] = {func: callback, scope: scope || this};
28093
+ this.editorCommands.addCommand(name, callback, scope);
27398
28094
  },
27399
28095
 
27400
28096
  /**
@@ -27413,7 +28109,7 @@ define("tinymce/Editor", [
27413
28109
  * @callback addQueryStateHandlerCallback
27414
28110
  * @return {Boolean} True/false state if the command is enabled or not like is it bold.
27415
28111
  */
27416
- this.queryStateCommands[name] = {func: callback, scope: scope || this};
28112
+ this.editorCommands.addQueryStateHandler(name, callback, scope);
27417
28113
  },
27418
28114
 
27419
28115
  /**
@@ -27432,7 +28128,7 @@ define("tinymce/Editor", [
27432
28128
  * @callback addQueryValueHandlerCallback
27433
28129
  * @return {Object} Value of the command or undefined.
27434
28130
  */
27435
- this.queryValueCommands[name] = {func: callback, scope: scope || this};
28131
+ this.editorCommands.addQueryValueHandler(name, callback, scope);
27436
28132
  },
27437
28133
 
27438
28134
  /**
@@ -27459,68 +28155,10 @@ define("tinymce/Editor", [
27459
28155
  * @param {String} cmd Command name to execute, for example mceLink or Bold.
27460
28156
  * @param {Boolean} ui True/false state if a UI (dialog) should be presented or not.
27461
28157
  * @param {mixed} value Optional command value, this can be anything.
27462
- * @param {Object} a Optional arguments object.
28158
+ * @param {Object} args Optional arguments object.
27463
28159
  */
27464
28160
  execCommand: function(cmd, ui, value, args) {
27465
- var self = this, state = 0, cmdItem;
27466
-
27467
- if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint)$/.test(cmd) && (!args || !args.skip_focus)) {
27468
- self.focus();
27469
- }
27470
-
27471
- args = extend({}, args);
27472
- args = self.fire('BeforeExecCommand', {command: cmd, ui: ui, value: value});
27473
- if (args.isDefaultPrevented()) {
27474
- return false;
27475
- }
27476
-
27477
- // Registred commands
27478
- if ((cmdItem = self.execCommands[cmd])) {
27479
- // Fall through on true
27480
- if (cmdItem.func.call(cmdItem.scope, ui, value) !== true) {
27481
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
27482
- return true;
27483
- }
27484
- }
27485
-
27486
- // Plugin commands
27487
- each(self.plugins, function(p) {
27488
- if (p.execCommand && p.execCommand(cmd, ui, value)) {
27489
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
27490
- state = true;
27491
- return false;
27492
- }
27493
- });
27494
-
27495
- if (state) {
27496
- return state;
27497
- }
27498
-
27499
- // Theme commands
27500
- if (self.theme && self.theme.execCommand && self.theme.execCommand(cmd, ui, value)) {
27501
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
27502
- return true;
27503
- }
27504
-
27505
- // Editor commands
27506
- if (self.editorCommands.execCommand(cmd, ui, value)) {
27507
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
27508
- return true;
27509
- }
27510
-
27511
- // Browser commands
27512
- try {
27513
- state = self.getDoc().execCommand(cmd, ui, value);
27514
- } catch (ex) {
27515
- // Ignore old IE errors
27516
- }
27517
-
27518
- if (state) {
27519
- self.fire('ExecCommand', {command: cmd, ui: ui, value: value});
27520
- return true;
27521
- }
27522
-
27523
- return false;
28161
+ return this.editorCommands.execCommand(cmd, ui, value, args);
27524
28162
  },
27525
28163
 
27526
28164
  /**
@@ -27531,35 +28169,7 @@ define("tinymce/Editor", [
27531
28169
  * @return {Boolean} Command specific state, for example if bold is enabled or not.
27532
28170
  */
27533
28171
  queryCommandState: function(cmd) {
27534
- var self = this, queryItem, returnVal;
27535
-
27536
- // Is hidden then return undefined
27537
- if (self._isHidden()) {
27538
- return;
27539
- }
27540
-
27541
- // Registred commands
27542
- if ((queryItem = self.queryStateCommands[cmd])) {
27543
- returnVal = queryItem.func.call(queryItem.scope);
27544
-
27545
- // Fall though on non boolean returns
27546
- if (returnVal === true || returnVal === false) {
27547
- return returnVal;
27548
- }
27549
- }
27550
-
27551
- // Editor commands
27552
- returnVal = self.editorCommands.queryCommandState(cmd);
27553
- if (returnVal !== -1) {
27554
- return returnVal;
27555
- }
27556
-
27557
- // Browser commands
27558
- try {
27559
- return self.getDoc().queryCommandState(cmd);
27560
- } catch (ex) {
27561
- // Fails sometimes see bug: 1896577
27562
- }
28172
+ return this.editorCommands.queryCommandState(cmd);
27563
28173
  },
27564
28174
 
27565
28175
  /**
@@ -27570,35 +28180,18 @@ define("tinymce/Editor", [
27570
28180
  * @return {Object} Command specific value, for example the current font size.
27571
28181
  */
27572
28182
  queryCommandValue: function(cmd) {
27573
- var self = this, queryItem, returnVal;
27574
-
27575
- // Is hidden then return undefined
27576
- if (self._isHidden()) {
27577
- return;
27578
- }
27579
-
27580
- // Registred commands
27581
- if ((queryItem = self.queryValueCommands[cmd])) {
27582
- returnVal = queryItem.func.call(queryItem.scope);
27583
-
27584
- // Fall though on true
27585
- if (returnVal !== true) {
27586
- return returnVal;
27587
- }
27588
- }
27589
-
27590
- // Editor commands
27591
- returnVal = self.editorCommands.queryCommandValue(cmd);
27592
- if (returnVal !== undefined) {
27593
- return returnVal;
27594
- }
28183
+ return this.editorCommands.queryCommandValue(cmd);
28184
+ },
27595
28185
 
27596
- // Browser commands
27597
- try {
27598
- return self.getDoc().queryCommandValue(cmd);
27599
- } catch (ex) {
27600
- // Fails sometimes see bug: 1896577
27601
- }
28186
+ /**
28187
+ * Returns true/false if the command is supported or not.
28188
+ *
28189
+ * @method queryCommandSupported
28190
+ * @param {String} cmd Command that we check support for.
28191
+ * @return {Boolean} true/false if the command is supported or not.
28192
+ */
28193
+ queryCommandSupported: function(cmd) {
28194
+ return this.editorCommands.queryCommandSupported(cmd);
27602
28195
  },
27603
28196
 
27604
28197
  /**
@@ -28023,10 +28616,11 @@ define("tinymce/Editor", [
28023
28616
  },
28024
28617
 
28025
28618
  /**
28026
- * Returns the iframes body element.
28619
+ * Returns the root element of the editable area.
28620
+ * For a non-inline iframe-based editor, returns the iframe's body element.
28027
28621
  *
28028
28622
  * @method getBody
28029
- * @return {Element} Iframe body element.
28623
+ * @return {Element} The root element of the editable area.
28030
28624
  */
28031
28625
  getBody: function() {
28032
28626
  return this.bodyElement || this.getDoc().body;
@@ -28267,9 +28861,31 @@ define("tinymce/Editor", [
28267
28861
  define("tinymce/util/I18n", [], function() {
28268
28862
  "use strict";
28269
28863
 
28270
- var data = {};
28864
+ var data = {}, code = "en";
28271
28865
 
28272
28866
  return {
28867
+ /**
28868
+ * Sets the current language code.
28869
+ *
28870
+ * @method setCode
28871
+ * @param {String} newCode Current language code.
28872
+ */
28873
+ setCode: function(newCode) {
28874
+ if (newCode) {
28875
+ code = newCode;
28876
+ this.rtl = this.data[newCode] ? this.data[newCode]._dir === 'rtl' : false;
28877
+ }
28878
+ },
28879
+
28880
+ /**
28881
+ * Returns the current language code.
28882
+ *
28883
+ * @return {String} Current language code.
28884
+ */
28885
+ getCode: function() {
28886
+ return code;
28887
+ },
28888
+
28273
28889
  /**
28274
28890
  * Property gets set to true if a RTL language pack was loaded.
28275
28891
  *
@@ -28286,11 +28902,17 @@ define("tinymce/util/I18n", [], function() {
28286
28902
  * @param {Array} items Name/value array with English en_US to sv_SE.
28287
28903
  */
28288
28904
  add: function(code, items) {
28905
+ var langData = data[code];
28906
+
28907
+ if (!langData) {
28908
+ data[code] = langData = {};
28909
+ }
28910
+
28289
28911
  for (var name in items) {
28290
- data[name] = items[name];
28912
+ langData[name] = items[name];
28291
28913
  }
28292
28914
 
28293
- this.rtl = this.rtl || data._dir === 'rtl';
28915
+ this.setCode(code);
28294
28916
  },
28295
28917
 
28296
28918
  /**
@@ -28306,23 +28928,30 @@ define("tinymce/util/I18n", [], function() {
28306
28928
  * @return {String} String that got translated.
28307
28929
  */
28308
28930
  translate: function(text) {
28309
- if (typeof(text) == "undefined") {
28931
+ var langData;
28932
+
28933
+ langData = data[code];
28934
+ if (!langData) {
28935
+ langData = {};
28936
+ }
28937
+
28938
+ if (typeof text == "undefined") {
28310
28939
  return text;
28311
28940
  }
28312
28941
 
28313
- if (typeof(text) != "string" && text.raw) {
28942
+ if (typeof text != "string" && text.raw) {
28314
28943
  return text.raw;
28315
28944
  }
28316
28945
 
28317
28946
  if (text.push) {
28318
28947
  var values = text.slice(1);
28319
28948
 
28320
- text = (data[text[0]] || text[0]).replace(/\{([^\}]+)\}/g, function(match1, match2) {
28949
+ text = (langData[text[0]] || text[0]).replace(/\{([0-9]+)\}/g, function(match1, match2) {
28321
28950
  return values[match2];
28322
28951
  });
28323
28952
  }
28324
28953
 
28325
- return data[text] || text;
28954
+ return (langData[text] || text).replace(/{context:\w+}$/, '');
28326
28955
  },
28327
28956
 
28328
28957
  data: data
@@ -28694,7 +29323,7 @@ define("tinymce/EditorManager", [
28694
29323
  * @property minorVersion
28695
29324
  * @type String
28696
29325
  */
28697
- minorVersion: '1.6',
29326
+ minorVersion: '1.10',
28698
29327
 
28699
29328
  /**
28700
29329
  * Release date of TinyMCE build.
@@ -28702,7 +29331,7 @@ define("tinymce/EditorManager", [
28702
29331
  * @property releaseDate
28703
29332
  * @type String
28704
29333
  */
28705
- releaseDate: '2014-10-08',
29334
+ releaseDate: '2015-05-05',
28706
29335
 
28707
29336
  /**
28708
29337
  * Collection of editor instances.
@@ -29094,7 +29723,7 @@ define("tinymce/EditorManager", [
29094
29723
  }
29095
29724
 
29096
29725
  // Remove editors by selector
29097
- if (typeof(selector) == "string") {
29726
+ if (typeof selector == "string") {
29098
29727
  selector = selector.selector || selector;
29099
29728
 
29100
29729
  each(DOM.select(selector), function(elm) {
@@ -29311,9 +29940,12 @@ define("tinymce/LegacyInput", [
29311
29940
  },
29312
29941
 
29313
29942
  u: function(dom, node) {
29314
- replaceWithSpan(node, {
29315
- textDecoration: 'underline'
29316
- });
29943
+ // HTML5 allows U element
29944
+ if (editor.settings.schema === "html4") {
29945
+ replaceWithSpan(node, {
29946
+ textDecoration: 'underline'
29947
+ });
29948
+ }
29317
29949
  },
29318
29950
 
29319
29951
  strike: function(dom, node) {
@@ -29624,9 +30256,9 @@ define("tinymce/util/JSONRequest", [
29624
30256
  args.success = function(c, x) {
29625
30257
  c = JSON.parse(c);
29626
30258
 
29627
- if (typeof(c) == 'undefined') {
30259
+ if (typeof c == 'undefined') {
29628
30260
  c = {
29629
- error : 'JSON Parse error.'
30261
+ error: 'JSON Parse error.'
29630
30262
  };
29631
30263
  }
29632
30264
 
@@ -30227,7 +30859,7 @@ define("tinymce/ui/Tooltip", [
30227
30859
  text: function(value) {
30228
30860
  var self = this;
30229
30861
 
30230
- if (typeof(value) != "undefined") {
30862
+ if (typeof value != "undefined") {
30231
30863
  self._value = value;
30232
30864
 
30233
30865
  if (self._rendered) {
@@ -30510,7 +31142,7 @@ define("tinymce/ui/Button", [
30510
31142
  icon: function(icon) {
30511
31143
  var self = this, prefix = self.classPrefix;
30512
31144
 
30513
- if (typeof(icon) == 'undefined') {
31145
+ if (typeof icon == 'undefined') {
30514
31146
  return self.settings.icon;
30515
31147
  }
30516
31148
 
@@ -30966,7 +31598,7 @@ define("tinymce/ui/ComboBox", [
30966
31598
  value: function(value) {
30967
31599
  var self = this;
30968
31600
 
30969
- if (typeof(value) != "undefined") {
31601
+ if (typeof value != "undefined") {
30970
31602
  self._value = value;
30971
31603
  self.removeClass('placeholder');
30972
31604
 
@@ -31000,7 +31632,7 @@ define("tinymce/ui/ComboBox", [
31000
31632
  disabled: function(state) {
31001
31633
  var self = this;
31002
31634
 
31003
- if (self._rendered && typeof(state) != 'undefined') {
31635
+ if (self._rendered && typeof state != 'undefined') {
31004
31636
  self.getEl('inp').disabled = state;
31005
31637
  }
31006
31638
 
@@ -31380,6 +32012,18 @@ define("tinymce/ui/ColorButton", [
31380
32012
  return this._color;
31381
32013
  },
31382
32014
 
32015
+ /**
32016
+ * Resets the current color.
32017
+ *
32018
+ * @method resetColor
32019
+ * @return {tinymce.ui.ColorButton} Current instance.
32020
+ */
32021
+ resetColor: function() {
32022
+ this._color = null;
32023
+ this.getEl('preview').style.backgroundColor = null;
32024
+ return this;
32025
+ },
32026
+
31383
32027
  /**
31384
32028
  * Renders the control as a HTML string.
31385
32029
  *
@@ -31953,7 +32597,7 @@ define("tinymce/ui/Path", [
31953
32597
  data: function(data) {
31954
32598
  var self = this;
31955
32599
 
31956
- if (typeof(data) !== "undefined") {
32600
+ if (typeof data !== "undefined") {
31957
32601
  self._data = data;
31958
32602
  self.update();
31959
32603
 
@@ -32067,34 +32711,36 @@ define("tinymce/ui/ElementPath", [
32067
32711
  return false;
32068
32712
  }
32069
32713
 
32070
- self.on('select', function(e) {
32071
- editor.focus();
32072
- editor.selection.select(this.data()[e.index].element);
32073
- editor.nodeChanged();
32074
- });
32714
+ if (editor.settings.elementpath !== false) {
32715
+ self.on('select', function(e) {
32716
+ editor.focus();
32717
+ editor.selection.select(this.data()[e.index].element);
32718
+ editor.nodeChanged();
32719
+ });
32075
32720
 
32076
- editor.on('nodeChange', function(e) {
32077
- var outParents = [], parents = e.parents, i = parents.length;
32721
+ editor.on('nodeChange', function(e) {
32722
+ var outParents = [], parents = e.parents, i = parents.length;
32078
32723
 
32079
- while (i--) {
32080
- if (parents[i].nodeType == 1 && !isHidden(parents[i])) {
32081
- var args = editor.fire('ResolveName', {
32082
- name: parents[i].nodeName.toLowerCase(),
32083
- target: parents[i]
32084
- });
32724
+ while (i--) {
32725
+ if (parents[i].nodeType == 1 && !isHidden(parents[i])) {
32726
+ var args = editor.fire('ResolveName', {
32727
+ name: parents[i].nodeName.toLowerCase(),
32728
+ target: parents[i]
32729
+ });
32085
32730
 
32086
- if (!args.isDefaultPrevented()) {
32087
- outParents.push({name: args.name, element: parents[i]});
32088
- }
32731
+ if (!args.isDefaultPrevented()) {
32732
+ outParents.push({name: args.name, element: parents[i]});
32733
+ }
32089
32734
 
32090
- if (args.isPropagationStopped()) {
32091
- break;
32735
+ if (args.isPropagationStopped()) {
32736
+ break;
32737
+ }
32092
32738
  }
32093
32739
  }
32094
- }
32095
32740
 
32096
- self.data(outParents);
32097
- });
32741
+ self.data(outParents);
32742
+ });
32743
+ }
32098
32744
 
32099
32745
  return self._super();
32100
32746
  }
@@ -32248,7 +32894,7 @@ define("tinymce/ui/Form", [
32248
32894
  formItem.type = 'formitem';
32249
32895
  ctrl.aria('labelledby', ctrl._id + '-l');
32250
32896
 
32251
- if (typeof(ctrl.settings.flex) == "undefined") {
32897
+ if (typeof ctrl.settings.flex == "undefined") {
32252
32898
  ctrl.settings.flex = 1;
32253
32899
  }
32254
32900
 
@@ -32760,7 +33406,7 @@ define("tinymce/ui/FlexLayout", [
32760
33406
  );
32761
33407
  rect[alignAxisName] = contPaddingBox[alignBeforeName];
32762
33408
  } else if (align === "end") {
32763
- rect[alignAxisName] = contLayoutRect[alignInnerSizeName] - ctrlLayoutRect[alignSizeName] - contPaddingBox.top;
33409
+ rect[alignAxisName] = contLayoutRect[alignInnerSizeName] - ctrlLayoutRect[alignSizeName] - contPaddingBox.top;
32764
33410
  }
32765
33411
 
32766
33412
  // Calculate new size based on flex
@@ -32810,7 +33456,7 @@ define("tinymce/ui/FlowLayout", [
32810
33456
  Defaults: {
32811
33457
  containerClass: 'flow-layout',
32812
33458
  controlClass: 'flow-layout-item',
32813
- endClass : 'break'
33459
+ endClass: 'break'
32814
33460
  },
32815
33461
 
32816
33462
  /**
@@ -33189,7 +33835,6 @@ define("tinymce/ui/FormatControls", [
33189
33835
 
33190
33836
  editor.addMenuItem('newdocument', {
33191
33837
  text: 'New document',
33192
- shortcut: 'Ctrl+N',
33193
33838
  icon: 'newdocument',
33194
33839
  cmd: 'mceNewDocument'
33195
33840
  });
@@ -33197,7 +33842,7 @@ define("tinymce/ui/FormatControls", [
33197
33842
  editor.addMenuItem('undo', {
33198
33843
  text: 'Undo',
33199
33844
  icon: 'undo',
33200
- shortcut: 'Ctrl+Z',
33845
+ shortcut: 'Meta+Z',
33201
33846
  onPostRender: toggleUndoRedoState('undo'),
33202
33847
  cmd: 'undo'
33203
33848
  });
@@ -33205,7 +33850,7 @@ define("tinymce/ui/FormatControls", [
33205
33850
  editor.addMenuItem('redo', {
33206
33851
  text: 'Redo',
33207
33852
  icon: 'redo',
33208
- shortcut: 'Ctrl+Y',
33853
+ shortcut: 'Meta+Y',
33209
33854
  onPostRender: toggleUndoRedoState('redo'),
33210
33855
  cmd: 'redo'
33211
33856
  });
@@ -33218,12 +33863,12 @@ define("tinymce/ui/FormatControls", [
33218
33863
  });
33219
33864
 
33220
33865
  each({
33221
- cut: ['Cut', 'Cut', 'Ctrl+X'],
33222
- copy: ['Copy', 'Copy', 'Ctrl+C'],
33223
- paste: ['Paste', 'Paste', 'Ctrl+V'],
33224
- selectall: ['Select all', 'SelectAll', 'Ctrl+A'],
33225
- bold: ['Bold', 'Bold', 'Ctrl+B'],
33226
- italic: ['Italic', 'Italic', 'Ctrl+I'],
33866
+ cut: ['Cut', 'Cut', 'Meta+X'],
33867
+ copy: ['Copy', 'Copy', 'Meta+C'],
33868
+ paste: ['Paste', 'Paste', 'Meta+V'],
33869
+ selectall: ['Select all', 'SelectAll', 'Meta+A'],
33870
+ bold: ['Bold', 'Bold', 'Meta+B'],
33871
+ italic: ['Italic', 'Italic', 'Meta+I'],
33227
33872
  underline: ['Underline', 'Underline'],
33228
33873
  strikethrough: ['Strikethrough', 'Strikethrough'],
33229
33874
  subscript: ['Subscript', 'Subscript'],
@@ -33261,14 +33906,13 @@ define("tinymce/ui/FormatControls", [
33261
33906
  editor.addButton('formatselect', function() {
33262
33907
  var items = [], blocks = createFormats(editor.settings.block_formats ||
33263
33908
  'Paragraph=p;' +
33264
- 'Address=address;' +
33265
- 'Pre=pre;' +
33266
33909
  'Heading 1=h1;' +
33267
33910
  'Heading 2=h2;' +
33268
33911
  'Heading 3=h3;' +
33269
33912
  'Heading 4=h4;' +
33270
33913
  'Heading 5=h5;' +
33271
- 'Heading 6=h6'
33914
+ 'Heading 6=h6;' +
33915
+ 'Preformatted=pre'
33272
33916
  );
33273
33917
 
33274
33918
  each(blocks, function(block) {
@@ -33293,21 +33937,21 @@ define("tinymce/ui/FormatControls", [
33293
33937
 
33294
33938
  editor.addButton('fontselect', function() {
33295
33939
  var defaultFontsFormats =
33296
- 'Andale Mono=andale mono,times;' +
33940
+ 'Andale Mono=andale mono,monospace;' +
33297
33941
  'Arial=arial,helvetica,sans-serif;' +
33298
- 'Arial Black=arial black,avant garde;' +
33299
- 'Book Antiqua=book antiqua,palatino;' +
33942
+ 'Arial Black=arial black,sans-serif;' +
33943
+ 'Book Antiqua=book antiqua,palatino,serif;' +
33300
33944
  'Comic Sans MS=comic sans ms,sans-serif;' +
33301
- 'Courier New=courier new,courier;' +
33302
- 'Georgia=georgia,palatino;' +
33303
- 'Helvetica=helvetica;' +
33304
- 'Impact=impact,chicago;' +
33945
+ 'Courier New=courier new,courier,monospace;' +
33946
+ 'Georgia=georgia,palatino,serif;' +
33947
+ 'Helvetica=helvetica,arial,sans-serif;' +
33948
+ 'Impact=impact,sans-serif;' +
33305
33949
  'Symbol=symbol;' +
33306
33950
  'Tahoma=tahoma,arial,helvetica,sans-serif;' +
33307
- 'Terminal=terminal,monaco;' +
33308
- 'Times New Roman=times new roman,times;' +
33309
- 'Trebuchet MS=trebuchet ms,geneva;' +
33310
- 'Verdana=verdana,geneva;' +
33951
+ 'Terminal=terminal,monaco,monospace;' +
33952
+ 'Times New Roman=times new roman,times,serif;' +
33953
+ 'Trebuchet MS=trebuchet ms,geneva,sans-serif;' +
33954
+ 'Verdana=verdana,geneva,sans-serif;' +
33311
33955
  'Webdings=webdings;' +
33312
33956
  'Wingdings=wingdings,zapf dingbats';
33313
33957
 
@@ -33429,11 +34073,11 @@ define("tinymce/ui/GridLayout", [
33429
34073
  contPaddingBox = container._paddingBox;
33430
34074
  reverseRows = 'reverseRows' in settings ? settings.reverseRows : container.isRtl();
33431
34075
 
33432
- if (alignH && typeof(alignH) == "string") {
34076
+ if (alignH && typeof alignH == "string") {
33433
34077
  alignH = [alignH];
33434
34078
  }
33435
34079
 
33436
- if (alignV && typeof(alignV) == "string") {
34080
+ if (alignV && typeof alignV == "string") {
33437
34081
  alignV = [alignV];
33438
34082
  }
33439
34083
 
@@ -34235,9 +34879,7 @@ define("tinymce/ui/ListBox", [
34235
34879
 
34236
34880
  self._values = values = settings.values;
34237
34881
  if (values) {
34238
- if (typeof settings.value != "undefined") {
34239
- setSelected(values);
34240
- }
34882
+ setSelected(values);
34241
34883
 
34242
34884
  // Default with first item
34243
34885
  if (!selected && values.length > 0) {
@@ -34312,7 +34954,7 @@ define("tinymce/ui/ListBox", [
34312
34954
  }
34313
34955
  }
34314
34956
 
34315
- if (typeof(value) != "undefined") {
34957
+ if (typeof value != "undefined") {
34316
34958
  if (self.menu) {
34317
34959
  activateByValue(self.menu, value);
34318
34960
  } else {
@@ -34535,6 +35177,36 @@ define("tinymce/ui/MenuItem", [
34535
35177
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
34536
35178
  var icon = self.settings.icon, image = '', shortcut = settings.shortcut;
34537
35179
 
35180
+ // Converts shortcut format to Mac/PC variants
35181
+ function convertShortcut(shortcut) {
35182
+ var i, value, replace = {};
35183
+
35184
+ if (Env.mac) {
35185
+ replace = {
35186
+ alt: '&#x2325;',
35187
+ ctrl: '&#x2318;',
35188
+ shift: '&#x21E7;',
35189
+ meta: '&#x2318;'
35190
+ };
35191
+ } else {
35192
+ replace = {
35193
+ meta: 'Ctrl'
35194
+ };
35195
+ }
35196
+
35197
+ shortcut = shortcut.split('+');
35198
+
35199
+ for (i = 0; i < shortcut.length; i++) {
35200
+ value = replace[shortcut[i].toLowerCase()];
35201
+
35202
+ if (value) {
35203
+ shortcut[i] = value;
35204
+ }
35205
+ }
35206
+
35207
+ return shortcut.join('+');
35208
+ }
35209
+
34538
35210
  if (icon) {
34539
35211
  self.parent().addClass('menu-has-icons');
34540
35212
  }
@@ -34544,12 +35216,8 @@ define("tinymce/ui/MenuItem", [
34544
35216
  image = ' style="background-image: url(\'' + settings.image + '\')"';
34545
35217
  }
34546
35218
 
34547
- if (shortcut && Env.mac) {
34548
- // format shortcut for Mac
34549
- shortcut = shortcut.replace(/ctrl\+alt\+/i, '&#x2325;&#x2318;'); // ctrl+cmd
34550
- shortcut = shortcut.replace(/ctrl\+/i, '&#x2318;'); // ctrl symbol
34551
- shortcut = shortcut.replace(/alt\+/i, '&#x2325;'); // cmd symbol
34552
- shortcut = shortcut.replace(/shift\+/i, '&#x21E7;'); // shift symbol
35219
+ if (shortcut) {
35220
+ shortcut = convertShortcut(shortcut);
34553
35221
  }
34554
35222
 
34555
35223
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
@@ -34573,7 +35241,7 @@ define("tinymce/ui/MenuItem", [
34573
35241
  var self = this, settings = self.settings;
34574
35242
 
34575
35243
  var textStyle = settings.textStyle;
34576
- if (typeof(textStyle) == "function") {
35244
+ if (typeof textStyle == "function") {
34577
35245
  textStyle = textStyle.call(this);
34578
35246
  }
34579
35247
 
@@ -34605,7 +35273,7 @@ define("tinymce/ui/MenuItem", [
34605
35273
  },
34606
35274
 
34607
35275
  active: function(state) {
34608
- if (typeof(state) != "undefined") {
35276
+ if (typeof state != "undefined") {
34609
35277
  this.aria('checked', state);
34610
35278
  }
34611
35279
 
@@ -35099,7 +35767,7 @@ define("tinymce/ui/StackLayout", [
35099
35767
  Defaults: {
35100
35768
  containerClass: 'stack-layout',
35101
35769
  controlClass: 'stack-layout-item',
35102
- endClass : 'break'
35770
+ endClass: 'break'
35103
35771
  }
35104
35772
  });
35105
35773
  });
@@ -35356,7 +36024,7 @@ define("tinymce/ui/TextBox", [
35356
36024
  disabled: function(state) {
35357
36025
  var self = this;
35358
36026
 
35359
- if (self._rendered && typeof(state) != 'undefined') {
36027
+ if (self._rendered && typeof state != 'undefined') {
35360
36028
  self.getEl().disabled = state;
35361
36029
  }
35362
36030
 
@@ -35373,7 +36041,7 @@ define("tinymce/ui/TextBox", [
35373
36041
  value: function(value) {
35374
36042
  var self = this;
35375
36043
 
35376
- if (typeof(value) != "undefined") {
36044
+ if (typeof value != "undefined") {
35377
36045
  self._value = value;
35378
36046
 
35379
36047
  if (self._rendered) {
@@ -35578,5 +36246,5 @@ define("tinymce/ui/Throbber", [
35578
36246
  };
35579
36247
  });
35580
36248
 
35581
- 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"]);
36249
+ 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"]);
35582
36250
  })(this);