tinymce-rails 4.1.6 → 4.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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);