tinymce-rails 4.0.10 → 4.0.11

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 (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)
@@ -190,38 +190,42 @@ define("tinymce/html/Styles", [], function() {
190
190
  var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter;
191
191
  var urlConverterScope = settings.url_converter_scope || this;
192
192
 
193
- function compress(prefix, suffix) {
193
+ function compress(prefix, suffix, noJoin) {
194
194
  var top, right, bottom, left;
195
195
 
196
- // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
197
- // So lets asume it shouldn't be there
198
- if (styles['border-image'] === 'none') {
199
- delete styles['border-image'];
200
- }
201
-
202
- // Get values and check it it needs compressing
203
196
  top = styles[prefix + '-top' + suffix];
204
197
  if (!top) {
205
198
  return;
206
199
  }
207
200
 
208
201
  right = styles[prefix + '-right' + suffix];
209
- if (top != right) {
202
+ if (!right) {
210
203
  return;
211
204
  }
212
205
 
213
206
  bottom = styles[prefix + '-bottom' + suffix];
214
- if (right != bottom) {
207
+ if (!bottom) {
215
208
  return;
216
209
  }
217
210
 
218
211
  left = styles[prefix + '-left' + suffix];
219
- if (bottom != left) {
212
+ if (!left) {
220
213
  return;
221
214
  }
222
215
 
223
- // Compress
224
- styles[prefix + suffix] = left;
216
+ var box = [top, right, bottom, left];
217
+ i = box.length - 1;
218
+ while (i--) {
219
+ if (box[i] !== box[i + 1]) {
220
+ break;
221
+ }
222
+ }
223
+
224
+ if (i > -1 && noJoin) {
225
+ return;
226
+ }
227
+
228
+ styles[prefix + suffix] = i == -1 ? box[0] : box.join(' ');
225
229
  delete styles[prefix + '-top' + suffix];
226
230
  delete styles[prefix + '-right' + suffix];
227
231
  delete styles[prefix + '-bottom' + suffix];
@@ -234,7 +238,7 @@ define("tinymce/html/Styles", [], function() {
234
238
  function canCompress(key) {
235
239
  var value = styles[key], i;
236
240
 
237
- if (!value || value.indexOf(' ') < 0) {
241
+ if (!value) {
238
242
  return;
239
243
  }
240
244
 
@@ -357,9 +361,8 @@ define("tinymce/html/Styles", [], function() {
357
361
 
358
362
  styleRegExp.lastIndex = matches.index + matches[0].length;
359
363
  }
360
-
361
364
  // Compress the styles to reduce it's size for example IE will expand styles
362
- compress("border", "");
365
+ compress("border", "", true);
363
366
  compress("border", "-width");
364
367
  compress("border", "-color");
365
368
  compress("border", "-style");
@@ -371,6 +374,12 @@ define("tinymce/html/Styles", [], function() {
371
374
  if (styles.border === 'medium none') {
372
375
  delete styles.border;
373
376
  }
377
+
378
+ // IE 11 will produce a border-image: none when getting the style attribute from <p style="border: 1px solid red"></p>
379
+ // So lets asume it shouldn't be there
380
+ if (styles['border-image'] === 'none') {
381
+ delete styles['border-image'];
382
+ }
374
383
  }
375
384
 
376
385
  return styles;
@@ -2625,7 +2634,7 @@ define("tinymce/html/Entities", [
2625
2634
  */
2626
2635
 
2627
2636
  /**
2628
- * This class contains various environment constrants like browser versions etc.
2637
+ * This class contains various environment constants like browser versions etc.
2629
2638
  * Normally you don't want to sniff specific browser versions but sometimes you have
2630
2639
  * to when it's impossible to feature detect. So use this with care.
2631
2640
  *
@@ -5146,9 +5155,14 @@ define("tinymce/AddOnManager", [
5146
5155
  *
5147
5156
  * @method requireLangPack
5148
5157
  * @param {String} name Short name of the add-on.
5158
+ * @param {String} languages Optional comma or space separated list of languages to check if it matches the name.
5149
5159
  */
5150
- requireLangPack: function(name) {
5160
+ requireLangPack: function(name, languages) {
5151
5161
  if (AddOnManager.language && AddOnManager.languageLoad !== false) {
5162
+ if (languages && new RegExp('([, ]|\\b)' + AddOnManager.language + '([, ]|\\b)').test(languages) === false) {
5163
+ return;
5164
+ }
5165
+
5152
5166
  ScriptLoader.ScriptLoader.add(this.urls[name] + '/langs/' + AddOnManager.language + '.js');
5153
5167
  }
5154
5168
  },
@@ -6868,7 +6882,8 @@ define("tinymce/html/SaxParser", [
6868
6882
  var validate, elementRule, isValidElement, attr, attribsValue, validAttributesMap, validAttributePatterns;
6869
6883
  var attributesRequired, attributesDefault, attributesForced;
6870
6884
  var anyAttributesRequired, selfClosing, tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0;
6871
- var decode = Entities.decode, fixSelfClosing, filteredAttrs = Tools.makeMap('src,href');
6885
+ var decode = Entities.decode, fixSelfClosing, filteredUrlAttrs = Tools.makeMap('src,href');
6886
+ var scriptUriRegExp = /(java|vb)script:/i;
6872
6887
 
6873
6888
  function processEndTag(name) {
6874
6889
  var pos, i;
@@ -6934,9 +6949,22 @@ define("tinymce/html/SaxParser", [
6934
6949
  }
6935
6950
  }
6936
6951
 
6937
- if (filteredAttrs[name] && !settings.allow_script_urls) {
6938
- if (/(java|vb)script:/i.test(decodeURIComponent(value.replace(trimRegExp, '')))) {
6939
- return;
6952
+ // Block any javascript: urls
6953
+ if (filteredUrlAttrs[name] && !settings.allow_script_urls) {
6954
+ var uri = value.replace(trimRegExp, '');
6955
+
6956
+ try {
6957
+ // Might throw malformed URI sequence
6958
+ uri = decodeURIComponent(uri);
6959
+ if (scriptUriRegExp.test(uri)) {
6960
+ return;
6961
+ }
6962
+ } catch (ex) {
6963
+ // Fallback to non UTF-8 decoder
6964
+ uri = unescape(uri);
6965
+ if (scriptUriRegExp.test(uri)) {
6966
+ return;
6967
+ }
6940
6968
  }
6941
6969
  }
6942
6970
 
@@ -9227,7 +9255,7 @@ define("tinymce/util/VK", [
9227
9255
 
9228
9256
  metaKeyPressed: function(e) {
9229
9257
  // Check if ctrl or meta key is pressed also check if alt is false for Polish users
9230
- return (Env.mac ? e.ctrlKey || e.metaKey : e.ctrlKey) && !e.altKey;
9258
+ return (Env.mac ? e.metaKey : e.ctrlKey) && !e.altKey;
9231
9259
  }
9232
9260
  };
9233
9261
  });
@@ -9772,17 +9800,24 @@ define("tinymce/dom/Selection", [
9772
9800
  Selection.prototype = {
9773
9801
  /**
9774
9802
  * Move the selection cursor range to the specified node and offset.
9803
+ * If there is no node specified it will move it to the first suitable location within the body.
9775
9804
  *
9776
9805
  * @method setCursorLocation
9777
- * @param {Node} node Node to put the cursor in.
9778
- * @param {Number} offset Offset from the start of the node to put the cursor at.
9806
+ * @param {Node} node Optional node to put the cursor in.
9807
+ * @param {Number} offset Optional offset from the start of the node to put the cursor at.
9779
9808
  */
9780
9809
  setCursorLocation: function(node, offset) {
9781
9810
  var self = this, rng = self.dom.createRng();
9782
- rng.setStart(node, offset);
9783
- rng.setEnd(node, offset);
9784
- self.setRng(rng);
9785
- self.collapse(false);
9811
+
9812
+ if (!node) {
9813
+ self._moveEndPoint(rng, self.editor.getBody(), true);
9814
+ self.setRng(rng);
9815
+ } else {
9816
+ rng.setStart(node, offset);
9817
+ rng.setEnd(node, offset);
9818
+ self.setRng(rng);
9819
+ self.collapse(false);
9820
+ }
9786
9821
  },
9787
9822
 
9788
9823
  /**
@@ -10392,54 +10427,11 @@ define("tinymce/dom/Selection", [
10392
10427
  * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
10393
10428
  */
10394
10429
  select: function(node, content) {
10395
- var self = this, dom = self.dom, rng = dom.createRng(), idx, nonEmptyElementsMap;
10430
+ var self = this, dom = self.dom, rng = dom.createRng(), idx;
10396
10431
 
10397
10432
  // Clear stored range set by FocusManager
10398
10433
  self.lastFocusBookmark = null;
10399
10434
 
10400
- nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10401
-
10402
- function setPoint(node, start) {
10403
- var root = node, walker = new TreeWalker(node, root);
10404
-
10405
- do {
10406
- // Text node
10407
- if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
10408
- if (start) {
10409
- rng.setStart(node, 0);
10410
- } else {
10411
- rng.setEnd(node, node.nodeValue.length);
10412
- }
10413
-
10414
- return;
10415
- }
10416
-
10417
- // BR/IMG/INPUT elements
10418
- if (nonEmptyElementsMap[node.nodeName]) {
10419
- if (start) {
10420
- rng.setStartBefore(node);
10421
- } else {
10422
- if (node.nodeName == 'BR') {
10423
- rng.setEndBefore(node);
10424
- } else {
10425
- rng.setEndAfter(node);
10426
- }
10427
- }
10428
-
10429
- return;
10430
- }
10431
- } while ((node = (start ? walker.next() : walker.prev())));
10432
-
10433
- // Failed to find any text node or other suitable location then move to the root of body
10434
- if (root.nodeName == 'BODY') {
10435
- if (start) {
10436
- rng.setStart(root, 0);
10437
- } else {
10438
- rng.setEnd(root, root.childNodes.length);
10439
- }
10440
- }
10441
- }
10442
-
10443
10435
  if (node) {
10444
10436
  if (!content && self.controlSelection.controlSelect(node)) {
10445
10437
  return;
@@ -10451,8 +10443,8 @@ define("tinymce/dom/Selection", [
10451
10443
 
10452
10444
  // Find first/last text node or BR element
10453
10445
  if (content) {
10454
- setPoint(node, 1);
10455
- setPoint(node);
10446
+ self._moveEndPoint(rng, node, true);
10447
+ self._moveEndPoint(rng, node);
10456
10448
  }
10457
10449
 
10458
10450
  self.setRng(rng);
@@ -11103,6 +11095,59 @@ define("tinymce/dom/Selection", [
11103
11095
  }
11104
11096
  },
11105
11097
 
11098
+ _moveEndPoint: function(rng, node, start) {
11099
+ var root = node, walker = new TreeWalker(node, root);
11100
+ var nonEmptyElementsMap = this.dom.schema.getNonEmptyElements();
11101
+
11102
+ do {
11103
+ // Text node
11104
+ if (node.nodeType == 3 && trim(node.nodeValue).length !== 0) {
11105
+ if (start) {
11106
+ rng.setStart(node, 0);
11107
+ } else {
11108
+ rng.setEnd(node, node.nodeValue.length);
11109
+ }
11110
+
11111
+ return;
11112
+ }
11113
+
11114
+ // BR/IMG/INPUT elements
11115
+ if (nonEmptyElementsMap[node.nodeName]) {
11116
+ if (start) {
11117
+ rng.setStartBefore(node);
11118
+ } else {
11119
+ if (node.nodeName == 'BR') {
11120
+ rng.setEndBefore(node);
11121
+ } else {
11122
+ rng.setEndAfter(node);
11123
+ }
11124
+ }
11125
+
11126
+ return;
11127
+ }
11128
+
11129
+ // Found empty text block old IE can place the selection inside those
11130
+ if (Env.ie && Env.ie < 11 && this.dom.isBlock(node) && this.dom.isEmpty(node)) {
11131
+ if (start) {
11132
+ rng.setStart(node, 0);
11133
+ } else {
11134
+ rng.setEnd(node, 0);
11135
+ }
11136
+
11137
+ return;
11138
+ }
11139
+ } while ((node = (start ? walker.next() : walker.prev())));
11140
+
11141
+ // Failed to find any text node or other suitable location then move to the root of body
11142
+ if (root.nodeName == 'BODY') {
11143
+ if (start) {
11144
+ rng.setStart(root, 0);
11145
+ } else {
11146
+ rng.setEnd(root, root.childNodes.length);
11147
+ }
11148
+ }
11149
+ },
11150
+
11106
11151
  destroy: function() {
11107
11152
  this.win = null;
11108
11153
  this.controlSelection.destroy();
@@ -14246,6 +14291,15 @@ define("tinymce/EnterKey", [
14246
14291
  }
14247
14292
  }
14248
14293
 
14294
+ // Old IE versions doesn't properly render blocks with br elements in them
14295
+ // For example <p><br></p> wont be rendered correctly in a contentEditable area
14296
+ // until you remove the br producing <p></p>
14297
+ if (Env.ie && Env.ie < 9 && parentBlock && parentBlock.firstChild) {
14298
+ if (parentBlock.firstChild == parentBlock.lastChild && parentBlock.firstChild.tagName == 'BR') {
14299
+ dom.remove(parentBlock.firstChild);
14300
+ }
14301
+ }
14302
+
14249
14303
  if (root.nodeName == 'LI') {
14250
14304
  var firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
14251
14305
 
@@ -15118,17 +15172,28 @@ define("tinymce/EditorCommands", [
15118
15172
 
15119
15173
  // Present alert message about clipboard access not being available
15120
15174
  if (failed || !doc.queryCommandSupported(command)) {
15121
- editor.windowManager.alert(
15175
+ var msg = editor.translate(
15122
15176
  "Your browser doesn't support direct access to the clipboard. " +
15123
15177
  "Please use the Ctrl+X/C/V keyboard shortcuts instead."
15124
15178
  );
15179
+
15180
+ if (Env.mac) {
15181
+ msg = msg.replace(/Ctrl\+/g, '\u2318+');
15182
+ }
15183
+
15184
+ editor.windowManager.alert(msg);
15125
15185
  }
15126
15186
  },
15127
15187
 
15128
15188
  // Override unlink command
15129
15189
  unlink: function(command) {
15130
15190
  if (selection.isCollapsed()) {
15131
- selection.select(selection.getNode());
15191
+ var elm = selection.getNode();
15192
+ if (elm.tagName == 'A') {
15193
+ editor.dom.remove(elm, true);
15194
+ }
15195
+
15196
+ return;
15132
15197
  }
15133
15198
 
15134
15199
  execNativeCommand(command);
@@ -15290,7 +15355,7 @@ define("tinymce/EditorCommands", [
15290
15355
  // Setup parser and serializer
15291
15356
  parser = editor.parser;
15292
15357
  serializer = new Serializer({}, editor.schema);
15293
- bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
15358
+ bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;&#200B;</span>';
15294
15359
 
15295
15360
  // Run beforeSetContent handlers on the HTML to be inserted
15296
15361
  args = {content: value, format: 'html', selection: true};
@@ -15306,11 +15371,16 @@ define("tinymce/EditorCommands", [
15306
15371
  value = value.replace(/\{\$caret\}/, bookmarkHtml);
15307
15372
 
15308
15373
  // If selection is at <body>|<p></p> then move it into <body><p>|</p>
15374
+ rng = selection.getRng();
15375
+ var caretElement = rng.startContainer || (rng.parentElement ? rng.parentElement() : null);
15309
15376
  var body = editor.getBody();
15310
- if (dom.isBlock(body.firstChild) && dom.isEmpty(body.firstChild)) {
15311
- body.firstChild.appendChild(dom.doc.createTextNode('\u00a0'));
15312
- selection.select(body.firstChild, true);
15313
- dom.remove(body.firstChild.lastChild);
15377
+ if (caretElement === body && selection.isCollapsed()) {
15378
+ if (dom.isBlock(body.firstChild) && dom.isEmpty(body.firstChild)) {
15379
+ rng = dom.createRng();
15380
+ rng.setStart(body.firstChild, 0);
15381
+ rng.setEnd(body.firstChild, 0);
15382
+ selection.setRng(rng);
15383
+ }
15314
15384
  }
15315
15385
 
15316
15386
  // Insert node maker where we will insert the new HTML and get it's parent
@@ -15529,16 +15599,42 @@ define("tinymce/EditorCommands", [
15529
15599
  },
15530
15600
 
15531
15601
  selectAll: function() {
15532
- var root = dom.getRoot(), rng = dom.createRng();
15602
+ var root = dom.getRoot(), rng;
15533
15603
 
15534
- // Old IE does a better job with selectall than new versions
15535
15604
  if (selection.getRng().setStart) {
15605
+ rng = dom.createRng();
15536
15606
  rng.setStart(root, 0);
15537
15607
  rng.setEnd(root, root.childNodes.length);
15538
-
15539
15608
  selection.setRng(rng);
15540
15609
  } else {
15541
- execNativeCommand('SelectAll');
15610
+ // IE will render it's own root level block elements and sometimes
15611
+ // even put font elements in them when the user starts typing. So we need to
15612
+ // move the selection to a more suitable element from this:
15613
+ // <body>|<p></p></body> to this: <body><p>|</p></body>
15614
+ rng = selection.getRng();
15615
+ if (!rng.item) {
15616
+ rng.moveToElementText(root);
15617
+ rng.select();
15618
+ }
15619
+ }
15620
+ },
15621
+
15622
+ "delete": function() {
15623
+ execNativeCommand("Delete");
15624
+
15625
+ // Check if body is empty after the delete call if so then set the contents
15626
+ // to an empty string and move the caret to any block produced by that operation
15627
+ // this fixes the issue with root blocks not being properly produced after a delete call on IE
15628
+ var body = editor.getBody();
15629
+
15630
+ if (dom.isEmpty(body)) {
15631
+ editor.setContent('');
15632
+
15633
+ if (body.firstChild && dom.isBlock(body.firstChild)) {
15634
+ editor.selection.setCursorLocation(body.firstChild, 0);
15635
+ } else {
15636
+ editor.selection.setCursorLocation(body, 0);
15637
+ }
15542
15638
  }
15543
15639
  },
15544
15640
 
@@ -15673,15 +15769,21 @@ define("tinymce/util/URI", [
15673
15769
  return;
15674
15770
  }
15675
15771
 
15772
+ var isProtocolRelative = url.indexOf('//') === 0;
15773
+
15676
15774
  // Absolute path with no host, fake host and protocol
15677
- if (url.indexOf('/') === 0 && url.indexOf('//') !== 0) {
15775
+ if (url.indexOf('/') === 0 && !isProtocolRelative) {
15678
15776
  url = (settings.base_uri ? settings.base_uri.protocol || 'http' : 'http') + '://mce_host' + url;
15679
15777
  }
15680
15778
 
15681
15779
  // Relative path http:// or protocol relative //path
15682
15780
  if (!/^[\w\-]*:?\/\//.test(url)) {
15683
15781
  base_url = settings.base_uri ? settings.base_uri.path : new URI(location.href).directory;
15684
- url = ((settings.base_uri && settings.base_uri.protocol) || 'http') + '://mce_host' + self.toAbsPath(base_url, url);
15782
+ if (settings.base_uri.protocol === "") {
15783
+ url = '//mce_host' + self.toAbsPath(base_url, url);
15784
+ } else {
15785
+ url = ((settings.base_uri && settings.base_uri.protocol) || 'http') + '://mce_host' + self.toAbsPath(base_url, url);
15786
+ }
15685
15787
  }
15686
15788
 
15687
15789
  // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
@@ -15722,6 +15824,10 @@ define("tinymce/util/URI", [
15722
15824
  self.source = '';
15723
15825
  }
15724
15826
 
15827
+ if (isProtocolRelative) {
15828
+ self.protocol = '';
15829
+ }
15830
+
15725
15831
  //t.path = t.path || '/';
15726
15832
  }
15727
15833
 
@@ -15767,14 +15873,15 @@ define("tinymce/util/URI", [
15767
15873
  uri = new URI(uri, {base_uri: self});
15768
15874
 
15769
15875
  // Not on same domain/port or protocol
15770
- if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port || self.protocol != uri.protocol) {
15876
+ if ((uri.host != 'mce_host' && self.host != uri.host && uri.host) || self.port != uri.port ||
15877
+ (self.protocol != uri.protocol && uri.protocol !== "")) {
15771
15878
  return uri.getURI();
15772
15879
  }
15773
15880
 
15774
15881
  var tu = self.getURI(), uu = uri.getURI();
15775
15882
 
15776
15883
  // Allow usage of the base_uri when relative_urls = true
15777
- if(tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
15884
+ if (tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu)) {
15778
15885
  return tu;
15779
15886
  }
15780
15887
 
@@ -15946,6 +16053,8 @@ define("tinymce/util/URI", [
15946
16053
  if (!noProtoHost) {
15947
16054
  if (self.protocol) {
15948
16055
  s += self.protocol + '://';
16056
+ } else {
16057
+ s += '//';
15949
16058
  }
15950
16059
 
15951
16060
  if (self.userInfo) {
@@ -17493,7 +17602,12 @@ define("tinymce/ui/Control", [
17493
17602
  * @method repaint
17494
17603
  */
17495
17604
  repaint: function() {
17496
- var self = this, style, bodyStyle, rect, borderBox, borderW = 0, borderH = 0, lastRepaintRect;
17605
+ var self = this, style, bodyStyle, rect, borderBox, borderW = 0, borderH = 0, lastRepaintRect, round;
17606
+
17607
+ // Use Math.round on all values on IE < 9
17608
+ round = !document.createRange ? Math.round : function(value) {
17609
+ return value;
17610
+ };
17497
17611
 
17498
17612
  style = self.getEl().style;
17499
17613
  rect = self._layoutRect;
@@ -17504,35 +17618,35 @@ define("tinymce/ui/Control", [
17504
17618
  borderH = borderBox.top + borderBox.bottom;
17505
17619
 
17506
17620
  if (rect.x !== lastRepaintRect.x) {
17507
- style.left = rect.x + 'px';
17621
+ style.left = round(rect.x) + 'px';
17508
17622
  lastRepaintRect.x = rect.x;
17509
17623
  }
17510
17624
 
17511
17625
  if (rect.y !== lastRepaintRect.y) {
17512
- style.top = rect.y + 'px';
17626
+ style.top = round(rect.y) + 'px';
17513
17627
  lastRepaintRect.y = rect.y;
17514
17628
  }
17515
17629
 
17516
17630
  if (rect.w !== lastRepaintRect.w) {
17517
- style.width = (rect.w - borderW) + 'px';
17631
+ style.width = round(rect.w - borderW) + 'px';
17518
17632
  lastRepaintRect.w = rect.w;
17519
17633
  }
17520
17634
 
17521
17635
  if (rect.h !== lastRepaintRect.h) {
17522
- style.height = (rect.h - borderH) + 'px';
17636
+ style.height = round(rect.h - borderH) + 'px';
17523
17637
  lastRepaintRect.h = rect.h;
17524
17638
  }
17525
17639
 
17526
17640
  // Update body if needed
17527
17641
  if (self._hasBody && rect.innerW !== lastRepaintRect.innerW) {
17528
17642
  bodyStyle = self.getEl('body').style;
17529
- bodyStyle.width = (rect.innerW) + 'px';
17643
+ bodyStyle.width = round(rect.innerW) + 'px';
17530
17644
  lastRepaintRect.innerW = rect.innerW;
17531
17645
  }
17532
17646
 
17533
17647
  if (self._hasBody && rect.innerH !== lastRepaintRect.innerH) {
17534
17648
  bodyStyle = bodyStyle || self.getEl('body').style;
17535
- bodyStyle.height = (rect.innerH) + 'px';
17649
+ bodyStyle.height = round(rect.innerH) + 'px';
17536
17650
  lastRepaintRect.innerH = rect.innerH;
17537
17651
  }
17538
17652
 
@@ -20876,7 +20990,7 @@ define("tinymce/ui/Window", [
20876
20990
  * @return {tinymce.ui.Control} Current control instance.
20877
20991
  */
20878
20992
  remove: function() {
20879
- var self = this;
20993
+ var self = this, prefix = self.classPrefix;
20880
20994
 
20881
20995
  self.dragHelper.destroy();
20882
20996
  self._super();
@@ -20884,6 +20998,11 @@ define("tinymce/ui/Window", [
20884
20998
  if (self.statusbar) {
20885
20999
  this.statusbar.remove();
20886
21000
  }
21001
+
21002
+ if (self._fullscreen) {
21003
+ DomUtils.removeClass(document.documentElement, prefix + 'fullscreen');
21004
+ DomUtils.removeClass(document.body, prefix + 'fullscreen');
21005
+ }
20887
21006
  }
20888
21007
  });
20889
21008
 
@@ -21495,6 +21614,16 @@ define("tinymce/util/Quirks", [
21495
21614
  }
21496
21615
 
21497
21616
  function allContentsSelected(rng) {
21617
+ if (!rng.setStart) {
21618
+ if (rng.item) {
21619
+ return false;
21620
+ }
21621
+
21622
+ var bodyRng = rng.duplicate();
21623
+ bodyRng.moveToElementText(editor.getBody());
21624
+ return RangeUtils.compareRanges(rng, bodyRng);
21625
+ }
21626
+
21498
21627
  var selection = serializeRng(rng);
21499
21628
 
21500
21629
  var allRng = dom.createRng();
@@ -21505,19 +21634,15 @@ define("tinymce/util/Quirks", [
21505
21634
  }
21506
21635
 
21507
21636
  editor.on('keydown', function(e) {
21508
- var keyCode = e.keyCode, isCollapsed;
21637
+ var keyCode = e.keyCode, isCollapsed, body;
21509
21638
 
21510
21639
  // Empty the editor if it's needed for example backspace at <p><b>|</b></p>
21511
21640
  if (!isDefaultPrevented(e) && (keyCode == DELETE || keyCode == BACKSPACE)) {
21512
21641
  isCollapsed = editor.selection.isCollapsed();
21642
+ body = editor.getBody();
21513
21643
 
21514
21644
  // Selection is collapsed but the editor isn't empty
21515
- if (isCollapsed && !dom.isEmpty(editor.getBody())) {
21516
- return;
21517
- }
21518
-
21519
- // IE deletes all contents correctly when everything is selected
21520
- if (isIE && !isCollapsed) {
21645
+ if (isCollapsed && !dom.isEmpty(body)) {
21521
21646
  return;
21522
21647
  }
21523
21648
 
@@ -21529,7 +21654,13 @@ define("tinymce/util/Quirks", [
21529
21654
  // Manually empty the editor
21530
21655
  e.preventDefault();
21531
21656
  editor.setContent('');
21532
- editor.selection.setCursorLocation(editor.getBody(), 0);
21657
+
21658
+ if (body.firstChild && dom.isBlock(body.firstChild)) {
21659
+ editor.selection.setCursorLocation(body.firstChild, 0);
21660
+ } else {
21661
+ editor.selection.setCursorLocation(body, 0);
21662
+ }
21663
+
21533
21664
  editor.nodeChanged();
21534
21665
  }
21535
21666
  });
@@ -21537,6 +21668,7 @@ define("tinymce/util/Quirks", [
21537
21668
 
21538
21669
  /**
21539
21670
  * WebKit doesn't select all the nodes in the body when you press Ctrl+A.
21671
+ * IE selects more than the contents <body>[<p>a</p>]</body> instead of <body><p>[a]</p]</body> see bug #6438
21540
21672
  * This selects the whole body so that backspace/delete logic will delete everything
21541
21673
  */
21542
21674
  function selectAll() {
@@ -22265,6 +22397,21 @@ define("tinymce/util/Quirks", [
22265
22397
  }
22266
22398
  }
22267
22399
 
22400
+ /**
22401
+ * Firefox on Mac OS will move the browser back to the previous page if you press CMD+Left arrow.
22402
+ * You might then loose all your work so we need to block that behavior and replace it with our own.
22403
+ */
22404
+ function blockCmdArrowNavigation() {
22405
+ if (Env.mac) {
22406
+ editor.on('keydown', function(e) {
22407
+ if (VK.metaKeyPressed(e) && (e.keyCode == 37 || e.keyCode == 39)) {
22408
+ e.preventDefault();
22409
+ editor.selection.getSel().modify('move', e.keyCode == 37 ? 'backward' : 'forward', 'word');
22410
+ }
22411
+ });
22412
+ }
22413
+ }
22414
+
22268
22415
  // All browsers
22269
22416
  disableBackspaceIntoATable();
22270
22417
  removeBlockQuoteOnBackSpace();
@@ -22283,6 +22430,7 @@ define("tinymce/util/Quirks", [
22283
22430
  if (Env.iOS) {
22284
22431
  selectionChangeNodeChanged();
22285
22432
  restoreFocusOnKeyDown();
22433
+ bodyHeight();
22286
22434
  } else {
22287
22435
  selectAll();
22288
22436
  }
@@ -22304,6 +22452,10 @@ define("tinymce/util/Quirks", [
22304
22452
  bodyHeight();
22305
22453
  }
22306
22454
 
22455
+ if (Env.ie) {
22456
+ selectAll();
22457
+ }
22458
+
22307
22459
  // Gecko
22308
22460
  if (isGecko) {
22309
22461
  removeHrOnBackspace();
@@ -22313,6 +22465,7 @@ define("tinymce/util/Quirks", [
22313
22465
  addBrAfterLastLinks();
22314
22466
  removeGhostSelection();
22315
22467
  showBrokenImageIcon();
22468
+ blockCmdArrowNavigation();
22316
22469
  }
22317
22470
  };
22318
22471
  });
@@ -22594,7 +22747,7 @@ define("tinymce/Shortcuts", [
22594
22747
  editor.on('keyup keypress keydown', function(e) {
22595
22748
  if (e.altKey || e.ctrlKey || e.metaKey) {
22596
22749
  each(shortcuts, function(shortcut) {
22597
- var ctrlKey = Env.mac ? (e.ctrlKey || e.metaKey) : e.ctrlKey;
22750
+ var ctrlKey = Env.mac ? e.metaKey : e.ctrlKey;
22598
22751
 
22599
22752
  if (shortcut.ctrl != ctrlKey || shortcut.alt != e.altKey || shortcut.shift != e.shiftKey) {
22600
22753
  return;
@@ -23200,9 +23353,6 @@ define("tinymce/Editor", [
23200
23353
  // Create all plugins
23201
23354
  each(settings.plugins.replace(/\-/g, '').split(/[ ,]/), initPlugin);
23202
23355
 
23203
- // Enables users to override the control factory
23204
- self.fire('BeforeRenderUI');
23205
-
23206
23356
  // Measure box
23207
23357
  if (settings.render_ui && self.theme) {
23208
23358
  self.orgDisplay = elm.style.display;
@@ -24216,7 +24366,7 @@ define("tinymce/Editor", [
24216
24366
  var self = this, doc = self.getDoc();
24217
24367
 
24218
24368
  // Fixed bug where IE has a blinking cursor left from the editor
24219
- if (ie && doc) {
24369
+ if (ie && doc && !self.inline) {
24220
24370
  doc.execCommand('SelectAll');
24221
24371
  }
24222
24372
 
@@ -24387,6 +24537,7 @@ define("tinymce/Editor", [
24387
24537
 
24388
24538
  // Check if forcedRootBlock is configured and that the block is a valid child of the body
24389
24539
  if (forcedRootBlockName && self.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
24540
+ // Padd with bogus BR elements on modern browsers and IE 7 and 8 since they don't render empty P tags properly
24390
24541
  content = ie && ie < 11 ? '' : '<br data-mce-bogus="1">';
24391
24542
  content = self.dom.createHTML(forcedRootBlockName, self.settings.forced_root_block_attrs, content);
24392
24543
  } else if (!ie || ie < 11) {
@@ -24697,7 +24848,7 @@ define("tinymce/Editor", [
24697
24848
 
24698
24849
  // Fixed bug where IE has a blinking cursor left from the editor
24699
24850
  var doc = self.getDoc();
24700
- if (ie && doc) {
24851
+ if (ie && doc && !self.inline) {
24701
24852
  doc.execCommand('SelectAll');
24702
24853
  }
24703
24854
 
@@ -25013,6 +25164,18 @@ define("tinymce/FocusManager", [
25013
25164
  return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
25014
25165
  }
25015
25166
 
25167
+ function isNodeInBody(node) {
25168
+ var body = editor.getBody();
25169
+
25170
+ while (node) {
25171
+ if (node == body) {
25172
+ return true;
25173
+ }
25174
+
25175
+ node = node.parentNode;
25176
+ }
25177
+ }
25178
+
25016
25179
  editor.on('init', function() {
25017
25180
  // On IE take selection snapshot onbeforedeactivate
25018
25181
  if ("onbeforedeactivate" in document && Env.ie < 11) {
@@ -25028,24 +25191,14 @@ define("tinymce/FocusManager", [
25028
25191
  } else if (editor.inline || Env.ie > 10) {
25029
25192
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
25030
25193
  editor.on('nodechange keyup', function() {
25031
- var isInBody, node = document.activeElement;
25194
+ var node = document.activeElement;
25032
25195
 
25033
25196
  // IE 11 reports active element as iframe not body of iframe
25034
25197
  if (node && node.id == editor.id + '_ifr') {
25035
25198
  node = editor.getBody();
25036
25199
  }
25037
25200
 
25038
- // Check if selection is within editor body
25039
- while (node) {
25040
- if (node == editor.getBody()) {
25041
- isInBody = true;
25042
- break;
25043
- }
25044
-
25045
- node = node.parentNode;
25046
- }
25047
-
25048
- if (isInBody) {
25201
+ if (isNodeInBody(node)) {
25049
25202
  lastRng = editor.selection.getRng();
25050
25203
  }
25051
25204
  });
@@ -25105,7 +25258,14 @@ define("tinymce/FocusManager", [
25105
25258
  lastRng = null;
25106
25259
  });
25107
25260
 
25108
- editor.on('focusout', function() {
25261
+ editor.on('focusout', function(e) {
25262
+ // Moving focus to elements within the body that have a control seleciton on IE
25263
+ // will fire an focusout event so we need to check if the event is fired on the body
25264
+ // or on a sub element see #6456
25265
+ if (e.target !== editor.getBody() && isNodeInBody(e.target)) {
25266
+ return;
25267
+ }
25268
+
25109
25269
  editor.selection.lastFocusBookmark = createBookmark(lastRng);
25110
25270
 
25111
25271
  window.setTimeout(function() {
@@ -25194,7 +25354,7 @@ define("tinymce/EditorManager", [
25194
25354
  * @property minorVersion
25195
25355
  * @type String
25196
25356
  */
25197
- minorVersion : '0.10',
25357
+ minorVersion : '0.11',
25198
25358
 
25199
25359
  /**
25200
25360
  * Release date of TinyMCE build.
@@ -25202,7 +25362,7 @@ define("tinymce/EditorManager", [
25202
25362
  * @property releaseDate
25203
25363
  * @type String
25204
25364
  */
25205
- releaseDate: '2013-10-28',
25365
+ releaseDate: '2013-11-20',
25206
25366
 
25207
25367
  /**
25208
25368
  * Collection of editor instances.
@@ -25254,7 +25414,11 @@ define("tinymce/EditorManager", [
25254
25414
  for (var i = 0; i < scripts.length; i++) {
25255
25415
  var src = scripts[i].src;
25256
25416
 
25257
- if (/tinymce(\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
25417
+ // Script types supported:
25418
+ // tinymce.js tinymce.min.js tinymce.dev.js
25419
+ // tinymce.jquery.js tinymce.jquery.min.js tinymce.jquery.dev.js
25420
+ // tinymce.full.js tinymce.full.min.js tinymce.full.dev.js
25421
+ if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
25258
25422
  if (src.indexOf('.min') != -1) {
25259
25423
  suffix = '.min';
25260
25424
  }
@@ -26944,6 +27108,43 @@ define("tinymce/ui/Button", [
26944
27108
  }
26945
27109
  },
26946
27110
 
27111
+ /**
27112
+ * Sets/gets the current button icon.
27113
+ *
27114
+ * @method icon
27115
+ * @param {String} [icon] New icon identifier.
27116
+ * @return {String|tinymce.ui.MenuButton} Current icon or current MenuButton instance.
27117
+ */
27118
+ icon: function(icon) {
27119
+ var self = this, prefix = self.classPrefix;
27120
+
27121
+ if (typeof(icon) == 'undefined') {
27122
+ return self.settings.icon;
27123
+ }
27124
+
27125
+ self.settings.icon = icon;
27126
+ icon = icon ? prefix + 'ico ' + prefix + 'i-' + self.settings.icon : '';
27127
+
27128
+ if (self._rendered) {
27129
+ var btnElm = self.getEl().firstChild, iconElm = btnElm.getElementsByTagName('i')[0];
27130
+
27131
+ if (icon) {
27132
+ if (!iconElm || iconElm != btnElm.firstChild) {
27133
+ iconElm = document.createElement('i');
27134
+ btnElm.insertBefore(iconElm, btnElm.firstChild);
27135
+ }
27136
+
27137
+ iconElm.className = icon;
27138
+ } else if (iconElm) {
27139
+ btnElm.removeChild(iconElm);
27140
+ }
27141
+
27142
+ self.text(self._text); // Set text again to fix whitespace between icon + text
27143
+ }
27144
+
27145
+ return self;
27146
+ },
27147
+
26947
27148
  /**
26948
27149
  * Repaints the button for example after it's been resizes by a layout engine.
26949
27150
  *
@@ -28415,7 +28616,7 @@ define("tinymce/ui/FlexLayout", [
28415
28616
  ctrl = maxSizeItems[i];
28416
28617
  ctrlLayoutRect = ctrl.layoutRect();
28417
28618
  maxSize = ctrlLayoutRect[maxSizeName];
28418
- size = ctrlLayoutRect[minSizeName] + Math.ceil(ctrlLayoutRect.flex * ratio);
28619
+ size = ctrlLayoutRect[minSizeName] + ctrlLayoutRect.flex * ratio;
28419
28620
 
28420
28621
  if (size > maxSize) {
28421
28622
  availableSpace -= (ctrlLayoutRect[maxSizeName] - ctrlLayoutRect[minSizeName]);
@@ -28474,7 +28675,7 @@ define("tinymce/ui/FlexLayout", [
28474
28675
 
28475
28676
  // Calculate new size based on flex
28476
28677
  if (ctrlLayoutRect.flex > 0) {
28477
- size += Math.ceil(ctrlLayoutRect.flex * ratio);
28678
+ size += ctrlLayoutRect.flex * ratio;
28478
28679
  }
28479
28680
 
28480
28681
  rect[sizeName] = size;
@@ -28597,7 +28798,7 @@ define("tinymce/ui/FormatControls", [
28597
28798
 
28598
28799
  // Default preview
28599
28800
  if (!previewStyles) {
28600
- previewStyles = 'font-family font-size font-weight text-decoration ' +
28801
+ previewStyles = 'font-family font-size font-weight font-style text-decoration ' +
28601
28802
  'text-transform color background-color border border-radius';
28602
28803
  }
28603
28804
 
@@ -29351,7 +29552,7 @@ define("tinymce/ui/GridLayout", [
29351
29552
  // Calculate new column widths based on flex values
29352
29553
  var ratio = availableWidth / totalFlex;
29353
29554
  for (x = 0; x < cols; x++) {
29354
- colWidths[x] += flexWidths ? Math.ceil(flexWidths[x] * ratio) : ratio;
29555
+ colWidths[x] += flexWidths ? flexWidths[x] * ratio : ratio;
29355
29556
  }
29356
29557
 
29357
29558
  // Move/resize controls
@@ -29940,7 +30141,7 @@ define("tinymce/ui/MenuButton", [
29940
30141
  if (self._rendered) {
29941
30142
  children = self.getEl('open').getElementsByTagName('span');
29942
30143
  for (i = 0; i < children.length; i++) {
29943
- children[i].innerHTML = self.encode(text);
30144
+ children[i].innerHTML = (self.settings.icon && text ? '\u00a0' : '') + self.encode(text);
29944
30145
  }
29945
30146
  }
29946
30147
 
@@ -30106,8 +30307,9 @@ define("tinymce/ui/ListBox", [
30106
30307
  */
30107
30308
  define("tinymce/ui/MenuItem", [
30108
30309
  "tinymce/ui/Widget",
30109
- "tinymce/ui/Factory"
30110
- ], function(Widget, Factory) {
30310
+ "tinymce/ui/Factory",
30311
+ "tinymce/Env"
30312
+ ], function(Widget, Factory, Env) {
30111
30313
  "use strict";
30112
30314
 
30113
30315
  return Widget.extend({
@@ -30301,7 +30503,7 @@ define("tinymce/ui/MenuItem", [
30301
30503
  */
30302
30504
  renderHtml: function() {
30303
30505
  var self = this, id = self._id, settings = self.settings, prefix = self.classPrefix, text = self.encode(self._text);
30304
- var icon = self.settings.icon, image = '';
30506
+ var icon = self.settings.icon, image = '', shortcut = settings.shortcut;
30305
30507
 
30306
30508
  if (icon) {
30307
30509
  self.parent().addClass('menu-has-icons');
@@ -30312,14 +30514,22 @@ define("tinymce/ui/MenuItem", [
30312
30514
  image = ' style="background-image: url(\'' + settings.image + '\')"';
30313
30515
  }
30314
30516
 
30517
+ if (shortcut && Env.mac) {
30518
+ // format shortcut for Mac
30519
+ shortcut = shortcut.replace(/ctrl\+alt\+/i, '&#x2325;&#x2318;'); // ctrl+cmd
30520
+ shortcut = shortcut.replace(/ctrl\+/i, '&#x2318;'); // ctrl symbol
30521
+ shortcut = shortcut.replace(/alt\+/i, '&#x2325;'); // cmd symbol
30522
+ shortcut = shortcut.replace(/shift\+/i, '&#x21E7;'); // shift symbol
30523
+ }
30524
+
30315
30525
  icon = prefix + 'ico ' + prefix + 'i-' + (self.settings.icon || 'none');
30316
30526
 
30317
30527
  return (
30318
30528
  '<div id="' + id + '" class="' + self.classes() + '" tabindex="-1">' +
30319
30529
  (text !== '-' ? '<i class="' + icon + '"' + image + '></i>&nbsp;' : '') +
30320
30530
  (text !== '-' ? '<span id="' + id + '-text" class="' + prefix + 'text">' + text + '</span>' : '') +
30321
- (settings.shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
30322
- settings.shortcut + '</div>' : '') +
30531
+ (shortcut ? '<div id="' + id + '-shortcut" class="' + prefix + 'menu-shortcut">' +
30532
+ shortcut + '</div>' : '') +
30323
30533
  (settings.menu ? '<div class="' + prefix + 'caret"></div>' : '') +
30324
30534
  '</div>'
30325
30535
  );