tinymce-rails 4.0.10 → 4.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/app/assets/source/tinymce/tinymce.jquery.js +349 -139
  2. data/app/assets/source/tinymce/tinymce.js +349 -139
  3. data/lib/tinymce/rails/version.rb +2 -2
  4. data/vendor/assets/javascripts/tinymce/jquery.tinymce.js +1 -1
  5. data/vendor/assets/javascripts/tinymce/plugins/advlist/plugin.js +1 -1
  6. data/vendor/assets/javascripts/tinymce/plugins/autolink/plugin.js +1 -1
  7. data/vendor/assets/javascripts/tinymce/plugins/autoresize/plugin.js +1 -1
  8. data/vendor/assets/javascripts/tinymce/plugins/autosave/plugin.js +1 -1
  9. data/vendor/assets/javascripts/tinymce/plugins/charmap/plugin.js +1 -1
  10. data/vendor/assets/javascripts/tinymce/plugins/code/plugin.js +1 -1
  11. data/vendor/assets/javascripts/tinymce/plugins/contextmenu/plugin.js +1 -1
  12. data/vendor/assets/javascripts/tinymce/plugins/directionality/plugin.js +1 -1
  13. data/vendor/assets/javascripts/tinymce/plugins/example/plugin.js +1 -1
  14. data/vendor/assets/javascripts/tinymce/plugins/fullpage/plugin.js +1 -1
  15. data/vendor/assets/javascripts/tinymce/plugins/fullscreen/plugin.js +1 -1
  16. data/vendor/assets/javascripts/tinymce/plugins/hr/plugin.js +1 -1
  17. data/vendor/assets/javascripts/tinymce/plugins/image/plugin.js +1 -1
  18. data/vendor/assets/javascripts/tinymce/plugins/insertdatetime/plugin.js +1 -1
  19. data/vendor/assets/javascripts/tinymce/plugins/layer/plugin.js +1 -1
  20. data/vendor/assets/javascripts/tinymce/plugins/legacyoutput/plugin.js +1 -1
  21. data/vendor/assets/javascripts/tinymce/plugins/nonbreaking/plugin.js +1 -1
  22. data/vendor/assets/javascripts/tinymce/plugins/noneditable/plugin.js +1 -1
  23. data/vendor/assets/javascripts/tinymce/plugins/pagebreak/plugin.js +1 -1
  24. data/vendor/assets/javascripts/tinymce/plugins/paste/plugin.js +1 -1
  25. data/vendor/assets/javascripts/tinymce/plugins/preview/plugin.js +1 -1
  26. data/vendor/assets/javascripts/tinymce/plugins/print/plugin.js +1 -1
  27. data/vendor/assets/javascripts/tinymce/plugins/save/plugin.js +1 -1
  28. data/vendor/assets/javascripts/tinymce/plugins/searchreplace/plugin.js +1 -1
  29. data/vendor/assets/javascripts/tinymce/plugins/spellchecker/plugin.js +1 -1
  30. data/vendor/assets/javascripts/tinymce/plugins/tabfocus/plugin.js +1 -1
  31. data/vendor/assets/javascripts/tinymce/plugins/table/plugin.js +1 -1
  32. data/vendor/assets/javascripts/tinymce/plugins/template/plugin.js +1 -1
  33. data/vendor/assets/javascripts/tinymce/plugins/visualblocks/plugin.js +1 -1
  34. data/vendor/assets/javascripts/tinymce/plugins/visualchars/plugin.js +1 -1
  35. data/vendor/assets/javascripts/tinymce/skins/lightgray/content.inline.min.css +1 -1
  36. data/vendor/assets/javascripts/tinymce/skins/lightgray/content.min.css +1 -1
  37. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.ie7.min.css +1 -1
  38. data/vendor/assets/javascripts/tinymce/skins/lightgray/skin.min.css +1 -1
  39. data/vendor/assets/javascripts/tinymce/themes/modern/theme.js +1 -1
  40. data/vendor/assets/javascripts/tinymce/tinymce.jquery.js +9 -9
  41. data/vendor/assets/javascripts/tinymce/tinymce.js +10 -10
  42. metadata +3 -3
@@ -1,4 +1,4 @@
1
- // 4.0.10 (2013-10-28)
1
+ // 4.0.11 (2013-11-20)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -3375,38 +3375,42 @@ define("tinymce/html/Styles", [], function() {
3375
3375
  var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter;
3376
3376
  var urlConverterScope = settings.url_converter_scope || this;
3377
3377
 
3378
- function compress(prefix, suffix) {
3378
+ function compress(prefix, suffix, noJoin) {
3379
3379
  var top, right, bottom, left;
3380
3380
 
3381
- // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
3382
- // So lets asume it shouldn't be there
3383
- if (styles['border-image'] === 'none') {
3384
- delete styles['border-image'];
3385
- }
3386
-
3387
- // Get values and check it it needs compressing
3388
3381
  top = styles[prefix + '-top' + suffix];
3389
3382
  if (!top) {
3390
3383
  return;
3391
3384
  }
3392
3385
 
3393
3386
  right = styles[prefix + '-right' + suffix];
3394
- if (top != right) {
3387
+ if (!right) {
3395
3388
  return;
3396
3389
  }
3397
3390
 
3398
3391
  bottom = styles[prefix + '-bottom' + suffix];
3399
- if (right != bottom) {
3392
+ if (!bottom) {
3400
3393
  return;
3401
3394
  }
3402
3395
 
3403
3396
  left = styles[prefix + '-left' + suffix];
3404
- if (bottom != left) {
3397
+ if (!left) {
3405
3398
  return;
3406
3399
  }
3407
3400
 
3408
- // Compress
3409
- styles[prefix + suffix] = left;
3401
+ var box = [top, right, bottom, left];
3402
+ i = box.length - 1;
3403
+ while (i--) {
3404
+ if (box[i] !== box[i + 1]) {
3405
+ break;
3406
+ }
3407
+ }
3408
+
3409
+ if (i > -1 && noJoin) {
3410
+ return;
3411
+ }
3412
+
3413
+ styles[prefix + suffix] = i == -1 ? box[0] : box.join(' ');
3410
3414
  delete styles[prefix + '-top' + suffix];
3411
3415
  delete styles[prefix + '-right' + suffix];
3412
3416
  delete styles[prefix + '-bottom' + suffix];
@@ -3419,7 +3423,7 @@ define("tinymce/html/Styles", [], function() {
3419
3423
  function canCompress(key) {
3420
3424
  var value = styles[key], i;
3421
3425
 
3422
- if (!value || value.indexOf(' ') < 0) {
3426
+ if (!value) {
3423
3427
  return;
3424
3428
  }
3425
3429
 
@@ -3542,9 +3546,8 @@ define("tinymce/html/Styles", [], function() {
3542
3546
 
3543
3547
  styleRegExp.lastIndex = matches.index + matches[0].length;
3544
3548
  }
3545
-
3546
3549
  // Compress the styles to reduce it's size for example IE will expand styles
3547
- compress("border", "");
3550
+ compress("border", "", true);
3548
3551
  compress("border", "-width");
3549
3552
  compress("border", "-color");
3550
3553
  compress("border", "-style");
@@ -3556,6 +3559,12 @@ define("tinymce/html/Styles", [], function() {
3556
3559
  if (styles.border === 'medium none') {
3557
3560
  delete styles.border;
3558
3561
  }
3562
+
3563
+ // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
3564
+ // So lets asume it shouldn't be there
3565
+ if (styles['border-image'] === 'none') {
3566
+ delete styles['border-image'];
3567
+ }
3559
3568
  }
3560
3569
 
3561
3570
  return styles;
@@ -5256,7 +5265,7 @@ define("tinymce/html/Entities", [
5256
5265
  */
5257
5266
 
5258
5267
  /**
5259
- * This class contains various environment constrants like browser versions etc.
5268
+ * This class contains various environment constants like browser versions etc.
5260
5269
  * Normally you don't want to sniff specific browser versions but sometimes you have
5261
5270
  * to when it's impossible to feature detect. So use this with care.
5262
5271
  *
@@ -7777,9 +7786,14 @@ define("tinymce/AddOnManager", [
7777
7786
  *
7778
7787
  * @method requireLangPack
7779
7788
  * @param {String} name Short name of the add-on.
7789
+ * @param {String} languages Optional comma or space separated list of languages to check if it matches the name.
7780
7790
  */
7781
- requireLangPack: function(name) {
7791
+ requireLangPack: function(name, languages) {
7782
7792
  if (AddOnManager.language && AddOnManager.languageLoad !== false) {
7793
+ if (languages && new RegExp('([, ]|\\b)' + AddOnManager.language + '([, ]|\\b)').test(languages) === false) {
7794
+ return;
7795
+ }
7796
+
7783
7797
  ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
7784
7798
  }
7785
7799
  },
@@ -9499,7 +9513,8 @@ define("tinymce/html/SaxParser", [
9499
9513
  var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
9500
9514
  var attributesRequired, attributesDefault, attributesForced;
9501
9515
  var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
9502
- var decode = Entities.decode, fixSelfClosing, filteredAttrs = Tools.makeMap('src,href');
9516
+ var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href');
9517
+ var scriptUriRegExp = /(java|vb)script:/i;
9503
9518
 
9504
9519
  function processEndTag(name) {
9505
9520
  var pos, i;
@@ -9565,9 +9580,22 @@ define("tinymce/html/SaxParser", [
9565
9580
  }
9566
9581
  }
9567
9582
 
9568
- if (filteredAttrs[name] && !settings.allow_script_urls) {
9569
- if (/(java|vb)script:/i.test(decodeURIComponent(value.replace(trimRegExp, '')))) {
9570
- return;
9583
+ // Block any javascript: urls
9584
+ if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
9585
+ var uri = value.replace(trimRegExp, '');
9586
+
9587
+ try {
9588
+ // Might throw malformed URI sequence
9589
+ uri = decodeURIComponent(uri);
9590
+ if (scriptUriRegExp.test(uri)) {
9591
+ return;
9592
+ }
9593
+ } catch (ex) {
9594
+ // Fallback to non UTF-8 decoder
9595
+ uri = unescape(uri);
9596
+ if (scriptUriRegExp.test(uri)) {
9597
+ return;
9598
+ }
9571
9599
  }
9572
9600
  }
9573
9601
 
@@ -11858,7 +11886,7 @@ define("tinymce/util/VK", [
11858
11886
 
11859
11887
  metaKeyPressed: function(e) {
11860
11888
  // Check if ctrl or meta key is pressed also check if alt is false for Polish users
11861
- return (Env.mac ? e.ctrlKey || e.metaKey : e.ctrlKey) && !e.altKey;
11889
+ return (Env.mac ? e.metaKey : e.ctrlKey) && !e.altKey;
11862
11890
  }
11863
11891
  };
11864
11892
  });
@@ -12403,17 +12431,24 @@ define("tinymce/dom/Selection", [
12403
12431
  Selection.prototype = {
12404
12432
  /**
12405
12433
  * Move the selection cursor range to the specified node and offset.
12434
+ * If there is no node specified it will move it to the first suitable location within the body.
12406
12435
  *
12407
12436
  * @method setCursorLocation
12408
- * @param {Node} node Node to put the cursor in.
12409
- * @param {Number} offset Offset from the start of the node to put the cursor at.
12437
+ * @param {Node} node Optional node to put the cursor in.
12438
+ * @param {Number} offset Optional offset from the start of the node to put the cursor at.
12410
12439
  */
12411
12440
  setCursorLocation: function(node, offset) {
12412
12441
  var self = this, rng = self.dom.createRng();
12413
- rng.setStart(node, offset);
12414
- rng.setEnd(node, offset);
12415
- self.setRng(rng);
12416
- self.collapse(false);
12442
+
12443
+ if (!node) {
12444
+ self._moveEndPoint(rng, self.editor.getBody(), true);
12445
+ self.setRng(rng);
12446
+ } else {
12447
+ rng.setStart(node, offset);
12448
+ rng.setEnd(node, offset);
12449
+ self.setRng(rng);
12450
+ self.collapse(false);
12451
+ }
12417
12452
  },
12418
12453
 
12419
12454
  /**
@@ -13023,54 +13058,11 @@ define("tinymce/dom/Selection", [
13023
13058
  * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
13024
13059
  */
13025
13060
  select: function(node, content) {
13026
- var self = this, dom = self.dom, rng = dom.createRng(), idx, nonEmptyElementsMap;
13061
+ var self = this, dom = self.dom, rng = dom.createRng(), idx;
13027
13062
 
13028
13063
  // Clear stored range set by FocusManager
13029
13064
  self.lastFocusBookmark = null;
13030
13065
 
13031
- nonEmptyElementsMap = dom.schema.getNonEmptyElements();
13032
-
13033
- function setPoint(node, start) {
13034
- var root = node, walker = new TreeWalker(node, root);
13035
-
13036
- do {
13037
- // Text node
13038
- if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
13039
- if (start) {
13040
- rng.setStart(node, 0);
13041
- } else {
13042
- rng.setEnd(node, node.nodeValue.length);
13043
- }
13044
-
13045
- return;
13046
- }
13047
-
13048
- // BR/IMG/INPUT elements
13049
- if (nonEmptyElementsMap[node.nodeName]) {
13050
- if (start) {
13051
- rng.setStartBefore(node);
13052
- } else {
13053
- if (node.nodeName == 'BR') {
13054
- rng.setEndBefore(node);
13055
- } else {
13056
- rng.setEndAfter(node);
13057
- }
13058
- }
13059
-
13060
- return;
13061
- }
13062
- } while ((node = (start ? walker.next() : walker.prev())));
13063
-
13064
- // Failed to find any text node or other suitable location then move to the root of body
13065
- if (root.nodeName == 'BODY') {
13066
- if (start) {
13067
- rng.setStart(root, 0);
13068
- } else {
13069
- rng.setEnd(root, root.childNodes.length);
13070
- }
13071
- }
13072
- }
13073
-
13074
13066
  if (node) {
13075
13067
  if (!content && self.controlSelection.controlSelect(node)) {
13076
13068
  return;
@@ -13082,8 +13074,8 @@ define("tinymce/dom/Selection", [
13082
13074
 
13083
13075
  // Find first/last text node or BR element
13084
13076
  if (content) {
13085
- setPoint(node, 1);
13086
- setPoint(node);
13077
+ self._moveEndPoint(rng, node, true);
13078
+ self._moveEndPoint(rng, node);
13087
13079
  }
13088
13080
 
13089
13081
  self.setRng(rng);
@@ -13734,6 +13726,59 @@ define("tinymce/dom/Selection", [
13734
13726
  }
13735
13727
  },
13736
13728
 
13729
+ _moveEndPoint: function(rng, node, start) {
13730
+ var root = node, walker = new TreeWalker(node, root);
13731
+ var nonEmptyElementsMap = this.dom.schema.getNonEmptyElements();
13732
+
13733
+ do {
13734
+ // Text node
13735
+ if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
13736
+ if (start) {
13737
+ rng.setStart(node, 0);
13738
+ } else {
13739
+ rng.setEnd(node, node.nodeValue.length);
13740
+ }
13741
+
13742
+ return;
13743
+ }
13744
+
13745
+ // BR/IMG/INPUT elements
13746
+ if (nonEmptyElementsMap[node.nodeName]) {
13747
+ if (start) {
13748
+ rng.setStartBefore(node);
13749
+ } else {
13750
+ if (node.nodeName == 'BR') {
13751
+ rng.setEndBefore(node);
13752
+ } else {
13753
+ rng.setEndAfter(node);
13754
+ }
13755
+ }
13756
+
13757
+ return;
13758
+ }
13759
+
13760
+ // Found empty text block old IE can place the selection inside those
13761
+ if (Env.ie && Env.ie < 11 && this.dom.isBlock(node) && this.dom.isEmpty(node)) {
13762
+ if (start) {
13763
+ rng.setStart(node, 0);
13764
+ } else {
13765
+ rng.setEnd(node, 0);
13766
+ }
13767
+
13768
+ return;
13769
+ }
13770
+ } while ((node = (start ? walker.next() : walker.prev())));
13771
+
13772
+ // Failed to find any text node or other suitable location then move to the root of body
13773
+ if (root.nodeName == 'BODY') {
13774
+ if (start) {
13775
+ rng.setStart(root, 0);
13776
+ } else {
13777
+ rng.setEnd(root, root.childNodes.length);
13778
+ }
13779
+ }
13780
+ },
13781
+
13737
13782
  destroy: function() {
13738
13783
  this.win = null;
13739
13784
  this.controlSelection.destroy();
@@ -16877,6 +16922,15 @@ define("tinymce/EnterKey", [
16877
16922
  }
16878
16923
  }
16879
16924
 
16925
+ // Old IE versions doesn't properly render blocks with br elements in them
16926
+ // For example <p><br></p> wont be rendered correctly in a contentEditable area
16927
+ // until you remove the br producing <p></p>
16928
+ if (Env.ie && Env.ie < 9 && parentBlock && parentBlock.firstChild) {
16929
+ if (parentBlock.firstChild == parentBlock.lastChild && parentBlock.firstChild.tagName == 'BR') {
16930
+ dom.remove(parentBlock.firstChild);
16931
+ }
16932
+ }
16933
+
16880
16934
  if (root.nodeName == 'LI') {
16881
16935
  var firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
16882
16936
 
@@ -17749,17 +17803,28 @@ define("tinymce/EditorCommands", [
17749
17803
 
17750
17804
  // Present alert message about clipboard access not being available
17751
17805
  if (failed || !doc.queryCommandSupported(command)) {
17752
- editor.windowManager.alert(
17806
+ var msg = editor.translate(
17753
17807
  "Your browser doesn't support direct access to the clipboard. " +
17754
17808
  "Please use the Ctrl+X/C/V keyboard shortcuts instead."
17755
17809
  );
17810
+
17811
+ if (Env.mac) {
17812
+ msg = msg.replace(/Ctrl\+/g, '\u2318+');
17813
+ }
17814
+
17815
+ editor.windowManager.alert(msg);
17756
17816
  }
17757
17817
  },
17758
17818
 
17759
17819
  // Override unlink command
17760
17820
  unlink: function(command) {
17761
17821
  if (selection.isCollapsed()) {
17762
- selection.select(selection.getNode());
17822
+ var elm = selection.getNode();
17823
+ if (elm.tagName == 'A') {
17824
+ editor.dom.remove(elm, true);
17825
+ }
17826
+
17827
+ return;
17763
17828
  }
17764
17829
 
17765
17830
  execNativeCommand(command);
@@ -17921,7 +17986,7 @@ define("tinymce/EditorCommands", [
17921
17986
  // Setup parser and serializer
17922
17987
  parser = editor.parser;
17923
17988
  serializer = new Serializer({}, editor.schema);
17924
- bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
17989
+ bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#200B;</span>';
17925
17990
 
17926
17991
  // Run beforeSetContent handlers on the HTML to be inserted
17927
17992
  args = {content: value, format: 'html', selection: true};
@@ -17937,11 +18002,16 @@ define("tinymce/EditorCommands", [
17937
18002
  value = value.replace(/\{\$caret\}/, bookmarkHtml);
17938
18003
 
17939
18004
  // If selection is at <body>|<p></p> then move it into <body><p>|</p>
18005
+ rng = selection.getRng();
18006
+ var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
17940
18007
  var body = editor.getBody();
17941
- if (dom.isBlock(body.firstChild) && dom.isEmpty(body.firstChild)) {
17942
- body.firstChild.appendChild(dom.doc.createTextNode('\u00a0'));
17943
- selection.select(body.firstChild, true);
17944
- dom.remove(body.firstChild.lastChild);
18008
+ if (caretElement === body && selection.isCollapsed()) {
18009
+ if (dom.isBlock(body.firstChild) && dom.isEmpty(body.firstChild)) {
18010
+ rng = dom.createRng();
18011
+ rng.setStart(body.firstChild, 0);
18012
+ rng.setEnd(body.firstChild, 0);
18013
+ selection.setRng(rng);
18014
+ }
17945
18015
  }
17946
18016
 
17947
18017
  // Insert node maker where we will insert the new HTML and get it's parent
@@ -18160,16 +18230,42 @@ define("tinymce/EditorCommands", [
18160
18230
  },
18161
18231
 
18162
18232
  selectAll: function() {
18163
- var root = dom.getRoot(), rng = dom.createRng();
18233
+ var root = dom.getRoot(), rng;
18164
18234
 
18165
- // Old IE does a better job with selectall than new versions
18166
18235
  if (selection.getRng().setStart) {
18236
+ rng = dom.createRng();
18167
18237
  rng.setStart(root, 0);
18168
18238
  rng.setEnd(root, root.childNodes.length);
18169
-
18170
18239
  selection.setRng(rng);
18171
18240
  } else {
18172
- execNativeCommand('SelectAll');
18241
+ // IE will render it's own root level block elements and sometimes
18242
+ // even put font elements in them when the user starts typing. So we need to
18243
+ // move the selection to a more suitable element from this:
18244
+ // <body>|<p></p></body> to this: <body><p>|</p></body>
18245
+ rng = selection.getRng();
18246
+ if (!rng.item) {
18247
+ rng.moveToElementText(root);
18248
+ rng.select();
18249
+ }
18250
+ }
18251
+ },
18252
+
18253
+ "delete": function() {
18254
+ execNativeCommand("Delete");
18255
+
18256
+ // Check if body is empty after the delete call if so then set the contents
18257
+ // to an empty string and move the caret to any block produced by that operation
18258
+ // this fixes the issue with root blocks not being properly produced after a delete call on IE
18259
+ var body = editor.getBody();
18260
+
18261
+ if (dom.isEmpty(body)) {
18262
+ editor.setContent('');
18263
+
18264
+ if (body.firstChild && dom.isBlock(body.firstChild)) {
18265
+ editor.selection.setCursorLocation(body.firstChild, 0);
18266
+ } else {
18267
+ editor.selection.setCursorLocation(body, 0);
18268
+ }
18173
18269
  }
18174
18270
  },
18175
18271
 
@@ -18304,15 +18400,21 @@ define("tinymce/util/URI", [
18304
18400
  return;
18305
18401
  }
18306
18402
 
18403
+ var isProtocolRelative = url.indexOf('//') === 0;
18404
+
18307
18405
  // Absolute path with no host, fake host and protocol
18308
- if (url.indexOf('/') === 0 && url.indexOf('//') !== 0) {
18406
+ if (url.indexOf('/') === 0 && !isProtocolRelative) {
18309
18407
  url = (settings.base_uri ? settings.base_uri.protocol || 'http' : 'http') + '://mce_host' + url;
18310
18408
  }
18311
18409
 
18312
18410
  // Relative path http:// or protocol relative //path
18313
18411
  if (!/^[\w\-]*:?\/\//.test(url)) {
18314
18412
  base_url = settings.base_uri ? settings.base_uri.path : new URI(location.href).directory;
18315
- url = ((settings.base_uri && settings.base_uri.protocol) || 'http') + '://mce_host' + self.toAbsPath(base_url, url);
18413
+ if (settings.base_uri.protocol === "") {
18414
+ url = '//mce_host' + self.toAbsPath(base_url, url);
18415
+ } else {
18416
+ url = ((settings.base_uri && settings.base_uri.protocol) || 'http') + '://mce_host' + self.toAbsPath(base_url, url);
18417
+ }
18316
18418
  }
18317
18419
 
18318
18420
  // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
@@ -18353,6 +18455,10 @@ define("tinymce/util/URI", [
18353
18455
  self.source = '';
18354
18456
  }
18355
18457
 
18458
+ if (isProtocolRelative) {
18459
+ self.protocol = '';
18460
+ }
18461
+
18356
18462
  //t.path = t.path || '/';
18357
18463
  }
18358
18464
 
@@ -18398,14 +18504,15 @@ define("tinymce/util/URI", [
18398
18504
  uri = new URI(uri, {base_uri: self});
18399
18505
 
18400
18506
  // Not on same domain/port or protocol
18401
- if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port || self.protocol != uri.protocol) {
18507
+ if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port ||
18508
+ (self.protocol != uri.protocol && uri.protocol !== "")) {
18402
18509
  return uri.getURI();
18403
18510
  }
18404
18511
 
18405
18512
  var tu = self.getURI(), uu = uri.getURI();
18406
18513
 
18407
18514
  // Allow usage of the base_uri when relative_urls = true
18408
- if(tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
18515
+ if (tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
18409
18516
  return tu;
18410
18517
  }
18411
18518
 
@@ -18577,6 +18684,8 @@ define("tinymce/util/URI", [
18577
18684
  if (!noProtoHost) {
18578
18685
  if (self.protocol) {
18579
18686
  s += self.protocol + '://';
18687
+ } else {
18688
+ s += '//';
18580
18689
  }
18581
18690
 
18582
18691
  if (self.userInfo) {
@@ -20124,7 +20233,12 @@ define("tinymce/ui/Control", [
20124
20233
  * @method repaint
20125
20234
  */
20126
20235
  repaint: function() {
20127
- var self = this, style, bodyStyle, rect, borderBox, borderW = 0, borderH = 0, lastRepaintRect;
20236
+ var self = this, style, bodyStyle, rect, borderBox, borderW = 0, borderH = 0, lastRepaintRect, round;
20237
+
20238
+ // Use Math.round on all values on IE < 9
20239
+ round = !document.createRange ? Math.round : function(value) {
20240
+ return value;
20241
+ };
20128
20242
 
20129
20243
  style = self.getEl().style;
20130
20244
  rect = self._layoutRect;
@@ -20135,35 +20249,35 @@ define("tinymce/ui/Control", [
20135
20249
  borderH = borderBox.top + borderBox.bottom;
20136
20250
 
20137
20251
  if (rect.x !== lastRepaintRect.x) {
20138
- style.left = rect.x + 'px';
20252
+ style.left = round(rect.x) + 'px';
20139
20253
  lastRepaintRect.x = rect.x;
20140
20254
  }
20141
20255
 
20142
20256
  if (rect.y !== lastRepaintRect.y) {
20143
- style.top = rect.y + 'px';
20257
+ style.top = round(rect.y) + 'px';
20144
20258
  lastRepaintRect.y = rect.y;
20145
20259
  }
20146
20260
 
20147
20261
  if (rect.w !== lastRepaintRect.w) {
20148
- style.width = (rect.w - borderW) + 'px';
20262
+ style.width = round(rect.w - borderW) + 'px';
20149
20263
  lastRepaintRect.w = rect.w;
20150
20264
  }
20151
20265
 
20152
20266
  if (rect.h !== lastRepaintRect.h) {
20153
- style.height = (rect.h - borderH) + 'px';
20267
+ style.height = round(rect.h - borderH) + 'px';
20154
20268
  lastRepaintRect.h = rect.h;
20155
20269
  }
20156
20270
 
20157
20271
  // Update body if needed
20158
20272
  if (self._hasBody && rect.innerW !== lastRepaintRect.innerW) {
20159
20273
  bodyStyle = self.getEl('body').style;
20160
- bodyStyle.width = (rect.innerW) + 'px';
20274
+ bodyStyle.width = round(rect.innerW) + 'px';
20161
20275
  lastRepaintRect.innerW = rect.innerW;
20162
20276
  }
20163
20277
 
20164
20278
  if (self._hasBody && rect.innerH !== lastRepaintRect.innerH) {
20165
20279
  bodyStyle = bodyStyle || self.getEl('body').style;
20166
- bodyStyle.height = (rect.innerH) + 'px';
20280
+ bodyStyle.height = round(rect.innerH) + 'px';
20167
20281
  lastRepaintRect.innerH = rect.innerH;
20168
20282
  }
20169
20283
 
@@ -23507,7 +23621,7 @@ define("tinymce/ui/Window", [
23507
23621
  * @return {tinymce.ui.Control} Current control instance.
23508
23622
  */
23509
23623
  remove: function() {
23510
- var self = this;
23624
+ var self = this, prefix = self.classPrefix;
23511
23625
 
23512
23626
  self.dragHelper.destroy();
23513
23627
  self._super();
@@ -23515,6 +23629,11 @@ define("tinymce/ui/Window", [
23515
23629
  if (self.statusbar) {
23516
23630
  this.statusbar.remove();
23517
23631
  }
23632
+
23633
+ if (self._fullscreen) {
23634
+ DomUtils.removeClass(document.documentElement, prefix + 'fullscreen');
23635
+ DomUtils.removeClass(document.body, prefix + 'fullscreen');
23636
+ }
23518
23637
  }
23519
23638
  });
23520
23639
 
@@ -24126,6 +24245,16 @@ define("tinymce/util/Quirks", [
24126
24245
  }
24127
24246
 
24128
24247
  function allContentsSelected(rng) {
24248
+ if (!rng.setStart) {
24249
+ if (rng.item) {
24250
+ return false;
24251
+ }
24252
+
24253
+ var bodyRng = rng.duplicate();
24254
+ bodyRng.moveToElementText(editor.getBody());
24255
+ return RangeUtils.compareRanges(rng, bodyRng);
24256
+ }
24257
+
24129
24258
  var selection = serializeRng(rng);
24130
24259
 
24131
24260
  var allRng = dom.createRng();
@@ -24136,19 +24265,15 @@ define("tinymce/util/Quirks", [
24136
24265
  }
24137
24266
 
24138
24267
  editor.on('keydown', function(e) {
24139
- var keyCode = e.keyCode, isCollapsed;
24268
+ var keyCode = e.keyCode, isCollapsed, body;
24140
24269
 
24141
24270
  // Empty the editor if it's needed for example backspace at <p><b>|</b></p>
24142
24271
  if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
24143
24272
  isCollapsed = editor.selection.isCollapsed();
24273
+ body = editor.getBody();
24144
24274
 
24145
24275
  // Selection is collapsed but the editor isn't empty
24146
- if (isCollapsed && !dom.isEmpty(editor.getBody())) {
24147
- return;
24148
- }
24149
-
24150
- // IE deletes all contents correctly when everything is selected
24151
- if (isIE && !isCollapsed) {
24276
+ if (isCollapsed && !dom.isEmpty(body)) {
24152
24277
  return;
24153
24278
  }
24154
24279
 
@@ -24160,7 +24285,13 @@ define("tinymce/util/Quirks", [
24160
24285
  // Manually empty the editor
24161
24286
  e.preventDefault();
24162
24287
  editor.setContent('');
24163
- editor.selection.setCursorLocation(editor.getBody(), 0);
24288
+
24289
+ if (body.firstChild && dom.isBlock(body.firstChild)) {
24290
+ editor.selection.setCursorLocation(body.firstChild, 0);
24291
+ } else {
24292
+ editor.selection.setCursorLocation(body, 0);
24293
+ }
24294
+
24164
24295
  editor.nodeChanged();
24165
24296
  }
24166
24297
  });
@@ -24168,6 +24299,7 @@ define("tinymce/util/Quirks", [
24168
24299
 
24169
24300
  /**
24170
24301
  * WebKit doesn't select all the nodes in the body when you press Ctrl+A.
24302
+ * IE selects more than the contents <body>[<p>a</p>]</body> instead of <body><p>[a]</p]</body> see bug #6438
24171
24303
  * This selects the whole body so that backspace/delete logic will delete everything
24172
24304
  */
24173
24305
  function selectAll() {
@@ -24896,6 +25028,21 @@ define("tinymce/util/Quirks", [
24896
25028
  }
24897
25029
  }
24898
25030
 
25031
+ /**
25032
+ * Firefox on Mac OS will move the browser back to the previous page if you press CMD+Left arrow.
25033
+ * You might then loose all your work so we need to block that behavior and replace it with our own.
25034
+ */
25035
+ function blockCmdArrowNavigation() {
25036
+ if (Env.mac) {
25037
+ editor.on('keydown', function(e) {
25038
+ if (VK.metaKeyPressed(e) && (e.keyCode == 37 || e.keyCode == 39)) {
25039
+ e.preventDefault();
25040
+ editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'word');
25041
+ }
25042
+ });
25043
+ }
25044
+ }
25045
+
24899
25046
  // All browsers
24900
25047
  disableBackspaceIntoATable();
24901
25048
  removeBlockQuoteOnBackSpace();
@@ -24914,6 +25061,7 @@ define("tinymce/util/Quirks", [
24914
25061
  if (Env.iOS) {
24915
25062
  selectionChangeNodeChanged();
24916
25063
  restoreFocusOnKeyDown();
25064
+ bodyHeight();
24917
25065
  } else {
24918
25066
  selectAll();
24919
25067
  }
@@ -24935,6 +25083,10 @@ define("tinymce/util/Quirks", [
24935
25083
  bodyHeight();
24936
25084
  }
24937
25085
 
25086
+ if (Env.ie) {
25087
+ selectAll();
25088
+ }
25089
+
24938
25090
  // Gecko
24939
25091
  if (isGecko) {
24940
25092
  removeHrOnBackspace();
@@ -24944,6 +25096,7 @@ define("tinymce/util/Quirks", [
24944
25096
  addBrAfterLastLinks();
24945
25097
  removeGhostSelection();
24946
25098
  showBrokenImageIcon();
25099
+ blockCmdArrowNavigation();
24947
25100
  }
24948
25101
  };
24949
25102
  });
@@ -25225,7 +25378,7 @@ define("tinymce/Shortcuts", [
25225
25378
  editor.on('keyup keypress keydown', function(e) {
25226
25379
  if (e.altKey || e.ctrlKey || e.metaKey) {
25227
25380
  each(shortcuts, function(shortcut) {
25228
- var ctrlKey = Env.mac ? (e.ctrlKey || e.metaKey) : e.ctrlKey;
25381
+ var ctrlKey = Env.mac ? e.metaKey : e.ctrlKey;
25229
25382
 
25230
25383
  if (shortcut.ctrl != ctrlKey || shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
25231
25384
  return;
@@ -25831,9 +25984,6 @@ define("tinymce/Editor", [
25831
25984
  // Create all plugins
25832
25985
  each(settings.plugins.replace(/\-/g, '').split(/[ ,]/), initPlugin);
25833
25986
 
25834
- // Enables users to override the control factory
25835
- self.fire('BeforeRenderUI');
25836
-
25837
25987
  // Measure box
25838
25988
  if (settings.render_ui && self.theme) {
25839
25989
  self.orgDisplay = elm.style.display;
@@ -26847,7 +26997,7 @@ define("tinymce/Editor", [
26847
26997
  var self = this, doc = self.getDoc();
26848
26998
 
26849
26999
  // Fixed bug where IE has a blinking cursor left from the editor
26850
- if (ie && doc) {
27000
+ if (ie && doc && !self.inline) {
26851
27001
  doc.execCommand('SelectAll');
26852
27002
  }
26853
27003
 
@@ -27018,6 +27168,7 @@ define("tinymce/Editor", [
27018
27168
 
27019
27169
  // Check if forcedRootBlock is configured and that the block is a valid child of the body
27020
27170
  if (forcedRootBlockName && self.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
27171
+ // Padd with bogus BR elements on modern browsers and IE 7 and 8 since they don't render empty P tags properly
27021
27172
  content = ie && ie < 11 ? '' : '<br data-mce-bogus="1">';
27022
27173
  content = self.dom.createHTML(forcedRootBlockName, self.settings.forced_root_block_attrs, content);
27023
27174
  } else if (!ie || ie < 11) {
@@ -27328,7 +27479,7 @@ define("tinymce/Editor", [
27328
27479
 
27329
27480
  // Fixed bug where IE has a blinking cursor left from the editor
27330
27481
  var doc = self.getDoc();
27331
- if (ie && doc) {
27482
+ if (ie && doc && !self.inline) {
27332
27483
  doc.execCommand('SelectAll');
27333
27484
  }
27334
27485
 
@@ -27644,6 +27795,18 @@ define("tinymce/FocusManager", [
27644
27795
  return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
27645
27796
  }
27646
27797
 
27798
+ function isNodeInBody(node) {
27799
+ var body = editor.getBody();
27800
+
27801
+ while (node) {
27802
+ if (node == body) {
27803
+ return true;
27804
+ }
27805
+
27806
+ node = node.parentNode;
27807
+ }
27808
+ }
27809
+
27647
27810
  editor.on('init', function() {
27648
27811
  // On IE take selection snapshot onbeforedeactivate
27649
27812
  if ("onbeforedeactivate" in document && Env.ie < 11) {
@@ -27659,24 +27822,14 @@ define("tinymce/FocusManager", [
27659
27822
  } else if (editor.inline || Env.ie > 10) {
27660
27823
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
27661
27824
  editor.on('nodechange keyup', function() {
27662
- var isInBody, node = document.activeElement;
27825
+ var node = document.activeElement;
27663
27826
 
27664
27827
  // IE 11 reports active element as iframe not body of iframe
27665
27828
  if (node && node.id == editor.id + '_ifr') {
27666
27829
  node = editor.getBody();
27667
27830
  }
27668
27831
 
27669
- // Check if selection is within editor body
27670
- while (node) {
27671
- if (node == editor.getBody()) {
27672
- isInBody = true;
27673
- break;
27674
- }
27675
-
27676
- node = node.parentNode;
27677
- }
27678
-
27679
- if (isInBody) {
27832
+ if (isNodeInBody(node)) {
27680
27833
  lastRng = editor.selection.getRng();
27681
27834
  }
27682
27835
  });
@@ -27736,7 +27889,14 @@ define("tinymce/FocusManager", [
27736
27889
  lastRng = null;
27737
27890
  });
27738
27891
 
27739
- editor.on('focusout', function() {
27892
+ editor.on('focusout', function(e) {
27893
+ // Moving focus to elements within the body that have a control seleciton on IE
27894
+ // will fire an focusout event so we need to check if the event is fired on the body
27895
+ // or on a sub element see #6456
27896
+ if (e.target !== editor.getBody() && isNodeInBody(e.target)) {
27897
+ return;
27898
+ }
27899
+
27740
27900
  editor.selection.lastFocusBookmark = createBookmark(lastRng);
27741
27901
 
27742
27902
  window.setTimeout(function() {
@@ -27825,7 +27985,7 @@ define("tinymce/EditorManager", [
27825
27985
  * @property minorVersion
27826
27986
  * @type String
27827
27987
  */
27828
- minorVersion : '0.10',
27988
+ minorVersion : '0.11',
27829
27989
 
27830
27990
  /**
27831
27991
  * Release date of TinyMCE build.
@@ -27833,7 +27993,7 @@ define("tinymce/EditorManager", [
27833
27993
  * @property releaseDate
27834
27994
  * @type String
27835
27995
  */
27836
- releaseDate: '2013-10-28',
27996
+ releaseDate: '2013-11-20',
27837
27997
 
27838
27998
  /**
27839
27999
  * Collection of editor instances.
@@ -27885,7 +28045,11 @@ define("tinymce/EditorManager", [
27885
28045
  for (var i = 0; i < scripts.length; i++) {
27886
28046
  var src = scripts[i].src;
27887
28047
 
27888
- if (/tinymce(\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
28048
+ // Script types supported:
28049
+ // tinymce.js tinymce.min.js tinymce.dev.js
28050
+ // tinymce.jquery.js tinymce.jquery.min.js tinymce.jquery.dev.js
28051
+ // tinymce.full.js tinymce.full.min.js tinymce.full.dev.js
28052
+ if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
27889
28053
  if (src.indexOf('.min') != -1) {
27890
28054
  suffix = '.min';
27891
28055
  }
@@ -29575,6 +29739,43 @@ define("tinymce/ui/Button", [
29575
29739
  }
29576
29740
  },
29577
29741
 
29742
+ /**
29743
+ * Sets/gets the current button icon.
29744
+ *
29745
+ * @method icon
29746
+ * @param {String} [icon] New icon identifier.
29747
+ * @return {String|tinymce.ui.MenuButton} Current icon or current MenuButton instance.
29748
+ */
29749
+ icon: function(icon) {
29750
+ var self = this, prefix = self.classPrefix;
29751
+
29752
+ if (typeof(icon) == 'undefined') {
29753
+ return self.settings.icon;
29754
+ }
29755
+
29756
+ self.settings.icon = icon;
29757
+ icon = icon ? prefix + 'ico ' + prefix + 'i-' + self.settings.icon : '';
29758
+
29759
+ if (self._rendered) {
29760
+ var btnElm = self.getEl().firstChild, iconElm = btnElm.getElementsByTagName('i')[0];
29761
+
29762
+ if (icon) {
29763
+ if (!iconElm || iconElm != btnElm.firstChild) {
29764
+ iconElm = document.createElement('i');
29765
+ btnElm.insertBefore(iconElm, btnElm.firstChild);
29766
+ }
29767
+
29768
+ iconElm.className = icon;
29769
+ } else if (iconElm) {
29770
+ btnElm.removeChild(iconElm);
29771
+ }
29772
+
29773
+ self.text(self._text); // Set text again to fix whitespace between icon + text
29774
+ }
29775
+
29776
+ return self;
29777
+ },
29778
+
29578
29779
  /**
29579
29780
  * Repaints the button for example after it's been resizes by a layout engine.
29580
29781
  *
@@ -31046,7 +31247,7 @@ define("tinymce/ui/FlexLayout", [
31046
31247
  ctrl = maxSizeItems[i];
31047
31248
  ctrlLayoutRect = ctrl.layoutRect();
31048
31249
  maxSize = ctrlLayoutRect[maxSizeName];
31049
- size = ctrlLayoutRect[minSizeName] + Math.ceil(ctrlLayoutRect.flex * ratio);
31250
+ size = ctrlLayoutRect[minSizeName] + ctrlLayoutRect.flex * ratio;
31050
31251
 
31051
31252
  if (size > maxSize) {
31052
31253
  availableSpace -= (ctrlLayoutRect[maxSizeName] - ctrlLayoutRect[minSizeName]);
@@ -31105,7 +31306,7 @@ define("tinymce/ui/FlexLayout", [
31105
31306
 
31106
31307
  // Calculate new size based on flex
31107
31308
  if (ctrlLayoutRect.flex > 0) {
31108
- size += Math.ceil(ctrlLayoutRect.flex * ratio);
31309
+ size += ctrlLayoutRect.flex * ratio;
31109
31310
  }
31110
31311
 
31111
31312
  rect[sizeName] = size;
@@ -31228,7 +31429,7 @@ define("tinymce/ui/FormatControls", [
31228
31429
 
31229
31430
  // Default preview
31230
31431
  if (!previewStyles) {
31231
- previewStyles = 'font-family font-size font-weight text-decoration ' +
31432
+ previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
31232
31433
  'text-transform color background-color border border-radius';
31233
31434
  }
31234
31435
 
@@ -31982,7 +32183,7 @@ define("tinymce/ui/GridLayout", [
31982
32183
  // Calculate new column widths based on flex values
31983
32184
  var ratio = availableWidth / totalFlex;
31984
32185
  for (x = 0; x < cols; x++) {
31985
- colWidths[x] += flexWidths ? Math.ceil(flexWidths[x] * ratio) : ratio;
32186
+ colWidths[x] += flexWidths ? flexWidths[x] * ratio : ratio;
31986
32187
  }
31987
32188
 
31988
32189
  // Move/resize controls
@@ -32571,7 +32772,7 @@ define("tinymce/ui/MenuButton", [
32571
32772
  if (self._rendered) {
32572
32773
  children = self.getEl('open').getElementsByTagName('span');
32573
32774
  for (i = 0; i < children.length; i++) {
32574
- children[i].innerHTML = self.encode(text);
32775
+ children[i].innerHTML = (self.settings.icon && text ? '\u00a0' : '') + self.encode(text);
32575
32776
  }
32576
32777
  }
32577
32778
 
@@ -32737,8 +32938,9 @@ define("tinymce/ui/ListBox", [
32737
32938
  */
32738
32939
  define("tinymce/ui/MenuItem", [
32739
32940
  "tinymce/ui/Widget",
32740
- "tinymce/ui/Factory"
32741
- ], function(Widget, Factory) {
32941
+ "tinymce/ui/Factory",
32942
+ "tinymce/Env"
32943
+ ], function(Widget, Factory, Env) {
32742
32944
  "use strict";
32743
32945
 
32744
32946
  return Widget.extend({
@@ -32932,7 +33134,7 @@ define("tinymce/ui/MenuItem", [
32932
33134
  */
32933
33135
  renderHtml: function() {
32934
33136
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
32935
- var icon = self.settings.icon, image = '';
33137
+ var icon = self.settings.icon, image = '', shortcut = settings.shortcut;
32936
33138
 
32937
33139
  if (icon) {
32938
33140
  self.parent().addClass('menu-has-icons');
@@ -32943,14 +33145,22 @@ define("tinymce/ui/MenuItem", [
32943
33145
  image = ' style="background-image: url(\'' + settings.image + '\')"';
32944
33146
  }
32945
33147
 
33148
+ if (shortcut && Env.mac) {
33149
+ // format shortcut for Mac
33150
+ shortcut = shortcut.replace(/ctrl\+alt\+/i, '&#x2325;&#x2318;'); // ctrl+cmd
33151
+ shortcut = shortcut.replace(/ctrl\+/i, '&#x2318;'); // ctrl symbol
33152
+ shortcut = shortcut.replace(/alt\+/i, '&#x2325;'); // cmd symbol
33153
+ shortcut = shortcut.replace(/shift\+/i, '&#x21E7;'); // shift symbol
33154
+ }
33155
+
32946
33156
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
32947
33157
 
32948
33158
  return (
32949
33159
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
32950
33160
  (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
32951
33161
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
32952
- (settings.shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
32953
- settings.shortcut + '</div>' : '') +
33162
+ (shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
33163
+ shortcut + '</div>' : '') +
32954
33164
  (settings.menu ? '<div class="' + prefix + 'caret"></div>' : '') +
32955
33165
  '</div>'
32956
33166
  );