tinymce-rails 4.0.11 → 4.0.12

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.
@@ -1,4 +1,4 @@
1
- // 4.0.11 (2013-11-20)
1
+ // 4.0.12 (2013-12-18)
2
2
 
3
3
  /**
4
4
  * Compiled inline version. (Library mode)
@@ -8858,7 +8858,7 @@ define("tinymce/html/Schema", [
8858
8858
  'meta param embed source wbr track');
8859
8859
  boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' +
8860
8860
  'noshade nowrap readonly selected autoplay loop controls');
8861
- nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
8861
+ nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap);
8862
8862
  textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
8863
8863
  'blockquote center dir fieldset header footer article section hgroup aside nav figure');
8864
8864
  blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
@@ -13439,6 +13439,7 @@ define("tinymce/dom/Selection", [
13439
13439
 
13440
13440
  function normalizeEndPoint(start) {
13441
13441
  var container, offset, walker, dom = self.dom, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
13442
+ var directionLeft;
13442
13443
 
13443
13444
  function hasBrBeforeAfter(node, left) {
13444
13445
  var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
@@ -13491,6 +13492,11 @@ define("tinymce/dom/Selection", [
13491
13492
  container = rng[(start ? 'start' : 'end') + 'Container'];
13492
13493
  offset = rng[(start ? 'start' : 'end') + 'Offset'];
13493
13494
  nonEmptyElementsMap = dom.schema.getNonEmptyElements();
13495
+ directionLeft = start;
13496
+
13497
+ if (container.nodeType == 1 && offset > container.childNodes.length - 1) {
13498
+ directionLeft = false;
13499
+ }
13494
13500
 
13495
13501
  // If the container is a document move it to the body element
13496
13502
  if (container.nodeType === 9) {
@@ -13501,7 +13507,7 @@ define("tinymce/dom/Selection", [
13501
13507
  // If the container is body try move it into the closest text node or position
13502
13508
  if (container === body) {
13503
13509
  // If start is before/after a image, table etc
13504
- if (start) {
13510
+ if (directionLeft) {
13505
13511
  node = container.childNodes[offset > 0 ? offset - 1 : 0];
13506
13512
  if (node) {
13507
13513
  nodeName = node.nodeName.toLowerCase();
@@ -13513,7 +13519,7 @@ define("tinymce/dom/Selection", [
13513
13519
 
13514
13520
  // Resolve the index
13515
13521
  if (container.hasChildNodes()) {
13516
- offset = Math.min(!start && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
13522
+ offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
13517
13523
  container = container.childNodes[offset];
13518
13524
  offset = 0;
13519
13525
 
@@ -13526,7 +13532,7 @@ define("tinymce/dom/Selection", [
13526
13532
  do {
13527
13533
  // Found a text node use that position
13528
13534
  if (node.nodeType === 3 && node.nodeValue.length > 0) {
13529
- offset = start ? 0 : node.nodeValue.length;
13535
+ offset = directionLeft ? 0 : node.nodeValue.length;
13530
13536
  container = node;
13531
13537
  normalized = true;
13532
13538
  break;
@@ -13538,14 +13544,14 @@ define("tinymce/dom/Selection", [
13538
13544
  container = node.parentNode;
13539
13545
 
13540
13546
  // Put caret after image when moving the end point
13541
- if (node.nodeName == "IMG" && !start) {
13547
+ if (node.nodeName == "IMG" && !directionLeft) {
13542
13548
  offset++;
13543
13549
  }
13544
13550
 
13545
13551
  normalized = true;
13546
13552
  break;
13547
13553
  }
13548
- } while ((node = (start ? walker.next() : walker.prev())));
13554
+ } while ((node = (directionLeft ? walker.next() : walker.prev())));
13549
13555
  }
13550
13556
  }
13551
13557
  }
@@ -13576,7 +13582,7 @@ define("tinymce/dom/Selection", [
13576
13582
  // Lean the start of the selection right if possible
13577
13583
  // So this: x[<b>x]</b>
13578
13584
  // Becomes: x<b>[x]</b>
13579
- if (start && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
13585
+ if (directionLeft && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
13580
13586
  findTextNodeRelative(false);
13581
13587
  }
13582
13588
 
@@ -15095,6 +15101,10 @@ define("tinymce/Formatter", [
15095
15101
  function matchParents(node) {
15096
15102
  var root = dom.getRoot();
15097
15103
 
15104
+ if (node === root) {
15105
+ return false;
15106
+ }
15107
+
15098
15108
  // Find first node with similar format settings
15099
15109
  node = dom.getParent(node, function(node) {
15100
15110
  return node.parentNode === root || !!matchNode(node, name, vars, true);
@@ -15609,7 +15619,7 @@ define("tinymce/Formatter", [
15609
15619
 
15610
15620
  // Expand to block of similar type
15611
15621
  if (!format[0].wrapper) {
15612
- node = dom.getParent(container, format[0].block);
15622
+ node = dom.getParent(container, format[0].block, root);
15613
15623
  }
15614
15624
 
15615
15625
  // Expand to first wrappable block element or any block element
@@ -17817,7 +17827,7 @@ define("tinymce/EditorCommands", [
17817
17827
  },
17818
17828
 
17819
17829
  // Override unlink command
17820
- unlink: function(command) {
17830
+ unlink: function() {
17821
17831
  if (selection.isCollapsed()) {
17822
17832
  var elm = selection.getNode();
17823
17833
  if (elm.tagName == 'A') {
@@ -17827,8 +17837,7 @@ define("tinymce/EditorCommands", [
17827
17837
  return;
17828
17838
  }
17829
17839
 
17830
- execNativeCommand(command);
17831
- selection.collapse(FALSE);
17840
+ formatter.remove("link");
17832
17841
  },
17833
17842
 
17834
17843
  // Override justify commands to use the text formatter engine
@@ -24136,92 +24145,166 @@ define("tinymce/util/Quirks", [
24136
24145
  * <h1>a</h1><p>|b</p>
24137
24146
  *
24138
24147
  * Will produce this on backspace:
24139
- * <h1>a<span class="Apple-style-span" style="<all runtime styles>">b</span></p>
24148
+ * <h1>a<span style="<all runtime styles>">b</span></p>
24140
24149
  *
24141
24150
  * This fixes the backspace to produce:
24142
24151
  * <h1>a|b</p>
24143
24152
  *
24144
24153
  * See bug: https://bugs.webkit.org/show_bug.cgi?id=45784
24145
24154
  *
24146
- * This code is a bit of a hack and hopefully it will be fixed soon in WebKit.
24155
+ * This fixes the following delete scenarios:
24156
+ * 1. Delete by pressing backspace key.
24157
+ * 2. Delete by pressing delete key.
24158
+ * 3. Delete by pressing backspace key with ctrl/cmd (Word delete).
24159
+ * 4. Delete by pressing delete key with ctrl/cmd (Word delete).
24160
+ * 5. Delete by drag/dropping contents inside the editor.
24161
+ * 6. Delete by using Cut Ctrl+X/Cmd+X.
24162
+ * 7. Delete by selecting contents and writing a character.'
24163
+ *
24164
+ * This code is a ugly hack since writing full custom delete logic for just this bug
24165
+ * fix seemed like a huge task. I hope we can remove this before the year 2030.
24147
24166
  */
24148
24167
  function cleanupStylesWhenDeleting() {
24149
- function removeMergedFormatSpans(isDelete) {
24150
- var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
24168
+ var doc = editor.getDoc();
24151
24169
 
24152
- function isAtStartOrEndOfElm() {
24153
- if (container.nodeType == 3) {
24154
- if (isDelete && offset == container.length) {
24155
- return true;
24156
- }
24170
+ if (!window.MutationObserver) {
24171
+ return;
24172
+ }
24157
24173
 
24158
- if (!isDelete && offset === 0) {
24159
- return true;
24160
- }
24174
+ function customDelete(isForward) {
24175
+ var mutationObserver = new MutationObserver(function() {});
24176
+
24177
+ Tools.each(editor.getBody().getElementsByTagName('*'), function(elm) {
24178
+ // Mark existing spans
24179
+ if (elm.tagName == 'SPAN') {
24180
+ elm.setAttribute('mce-data-marked', 1);
24161
24181
  }
24162
- }
24163
24182
 
24164
- rng = selection.getRng();
24165
- var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
24183
+ // Make sure all elements has a data-mce-style attribute
24184
+ if (!elm.hasAttribute('data-mce-style') && elm.hasAttribute('style')) {
24185
+ editor.dom.setAttrib(elm, 'style', elm.getAttribute('style'));
24186
+ }
24187
+ });
24166
24188
 
24167
- if (!rng.collapsed) {
24168
- isDelete = true;
24169
- }
24189
+ // Observe added nodes and style attribute changes
24190
+ mutationObserver.observe(editor.getDoc(), {
24191
+ childList: true,
24192
+ attributes: true,
24193
+ subtree: true,
24194
+ attributeFilter: ['style']
24195
+ });
24170
24196
 
24171
- container = rng[(isDelete ? 'start' : 'end') + 'Container'];
24172
- offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
24197
+ editor.getDoc().execCommand(isForward ? 'ForwardDelete' : 'Delete', false, null);
24173
24198
 
24174
- if (container.nodeType == 3) {
24175
- blockElm = dom.getParent(rng.startContainer, dom.isBlock);
24199
+ var rng = editor.selection.getRng();
24200
+ var caretElement = rng.startContainer.parentNode;
24176
24201
 
24177
- // On delete clone the root span of the next block element
24178
- if (isDelete) {
24179
- blockElm = dom.getNext(blockElm, dom.isBlock);
24180
- }
24202
+ Tools.each(mutationObserver.takeRecords(), function(record) {
24203
+ // Restore style attribute to previous value
24204
+ if (record.attributeName == "style") {
24205
+ var oldValue = record.target.getAttribute('data-mce-style');
24181
24206
 
24182
- if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
24183
- // Wrap children of block in a EM and let WebKit stick is
24184
- // runtime styles junk into that EM
24185
- wrapperElm = dom.create('em', {'id': '__mceDel'});
24207
+ if (oldValue) {
24208
+ record.target.setAttribute("style", oldValue);
24209
+ } else {
24210
+ record.target.removeAttribute("style");
24211
+ }
24212
+ }
24186
24213
 
24187
- each(Tools.grep(blockElm.childNodes), function(node) {
24188
- wrapperElm.appendChild(node);
24189
- });
24214
+ // Remove all spans that isn't maked and retain selection
24215
+ Tools.each(record.addedNodes, function(node) {
24216
+ if (node.nodeName == "SPAN" && !node.getAttribute('mce-data-marked')) {
24217
+ var offset, container;
24190
24218
 
24191
- blockElm.appendChild(wrapperElm);
24192
- }
24193
- }
24219
+ if (node == caretElement) {
24220
+ offset = rng.startOffset;
24221
+ container = node.firstChild;
24222
+ }
24194
24223
 
24195
- // Do the backspace/delete action
24196
- rng = dom.createRng();
24197
- rng.setStart(tmpRng[0], tmpRng[1]);
24198
- rng.setEnd(tmpRng[2], tmpRng[3]);
24199
- selection.setRng(rng);
24200
- editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
24224
+ dom.remove(node, true);
24201
24225
 
24202
- // Remove temp wrapper element
24203
- if (wrapperElm) {
24204
- bookmark = selection.getBookmark();
24226
+ if (container) {
24227
+ rng.setStart(container, offset);
24228
+ rng.setEnd(container, offset);
24229
+ editor.selection.setRng(rng);
24230
+ }
24231
+ }
24232
+ });
24233
+ });
24205
24234
 
24206
- while ((elm = dom.get('__mceDel'))) {
24207
- dom.remove(elm, true);
24208
- }
24235
+ mutationObserver.disconnect();
24209
24236
 
24210
- selection.moveToBookmark(bookmark);
24211
- }
24237
+ // Remove any left over marks
24238
+ Tools.each(editor.dom.select('span[mce-data-marked]'), function(span) {
24239
+ span.removeAttribute('mce-data-marked');
24240
+ });
24212
24241
  }
24213
24242
 
24214
24243
  editor.on('keydown', function(e) {
24215
- var isDelete;
24244
+ var isForward = e.keyCode == DELETE, isMeta = VK.metaKeyPressed(e);
24245
+
24246
+ if (!isDefaultPrevented(e) && (isForward || e.keyCode == BACKSPACE)) {
24247
+ var rng = editor.selection.getRng(), container = rng.startContainer, offset = rng.startOffset;
24248
+
24249
+ // Ignore non meta delete in the where there is text before/after the caret
24250
+ if (!isMeta && rng.collapsed && container.nodeType == 3) {
24251
+ if (isForward ? offset < container.data.length : offset > 0) {
24252
+ return;
24253
+ }
24254
+ }
24216
24255
 
24217
- isDelete = e.keyCode == DELETE;
24218
- if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
24219
24256
  e.preventDefault();
24220
- removeMergedFormatSpans(isDelete);
24257
+
24258
+ if (isMeta) {
24259
+ editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", "word");
24260
+ }
24261
+
24262
+ customDelete(isForward);
24263
+ }
24264
+ });
24265
+
24266
+ editor.on('keypress', function(e) {
24267
+ if (!isDefaultPrevented(e) && !selection.isCollapsed() && e.charCode) {
24268
+ e.preventDefault();
24269
+ customDelete(true);
24270
+ editor.selection.setContent(String.fromCharCode(e.charCode));
24271
+ }
24272
+ });
24273
+
24274
+ editor.addCommand('Delete', function() {
24275
+ customDelete();
24276
+ });
24277
+
24278
+ editor.addCommand('ForwardDelete', function() {
24279
+ customDelete(true);
24280
+ });
24281
+
24282
+ editor.on('dragstart', function(e) {
24283
+ e.dataTransfer.setData('mce-internal', editor.selection.getContent());
24284
+ });
24285
+
24286
+ editor.on('drop', function(e) {
24287
+ if (!isDefaultPrevented(e)) {
24288
+ var internalContent = e.dataTransfer.getData('mce-internal');
24289
+
24290
+ if (internalContent && doc.caretRangeFromPoint) {
24291
+ e.preventDefault();
24292
+ customDelete();
24293
+ editor.selection.setRng(doc.caretRangeFromPoint(e.x, e.y));
24294
+ editor.insertContent(internalContent);
24295
+ }
24221
24296
  }
24222
24297
  });
24223
24298
 
24224
- editor.addCommand('Delete', function() {removeMergedFormatSpans();});
24299
+ editor.on('cut', function(e) {
24300
+ if (!isDefaultPrevented(e) && e.clipboardData) {
24301
+ e.preventDefault();
24302
+ e.clipboardData.clearData();
24303
+ e.clipboardData.setData('text/html', editor.selection.getContent());
24304
+ e.clipboardData.setData('text/plain', editor.selection.getContent({format: 'text'}));
24305
+ customDelete(true);
24306
+ }
24307
+ });
24225
24308
  }
24226
24309
 
24227
24310
  /**
@@ -24605,68 +24688,6 @@ define("tinymce/util/Quirks", [
24605
24688
  });
24606
24689
  }
24607
24690
 
24608
- /**
24609
- * Backspace or delete on WebKit will combine all visual styles in a span if the last character is deleted.
24610
- *
24611
- * For example backspace on:
24612
- * <p><b>x|</b></p>
24613
- *
24614
- * Will produce:
24615
- * <p><span style="font-weight: bold">|<br></span></p>
24616
- *
24617
- * When it should produce:
24618
- * <p><b>|<br></b></p>
24619
- *
24620
- * See: https://bugs.webkit.org/show_bug.cgi?id=81656
24621
- */
24622
- function keepInlineElementOnDeleteBackspace() {
24623
- editor.on('keydown', function(e) {
24624
- var isDelete, rng, container, offset, brElm, sibling, collapsed, nonEmptyElements;
24625
-
24626
- isDelete = e.keyCode == DELETE;
24627
- if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
24628
- rng = selection.getRng();
24629
- container = rng.startContainer;
24630
- offset = rng.startOffset;
24631
- collapsed = rng.collapsed;
24632
-
24633
- // Override delete if the start container is a text node and is at the beginning of text or
24634
- // just before/after the last character to be deleted in collapsed mode
24635
- if (container.nodeType == 3 && container.nodeValue.length > 0 && ((offset === 0 && !collapsed) ||
24636
- (collapsed && offset === (isDelete ? 0 : 1)))) {
24637
- // Edge case when deleting <p><b><img> |x</b></p>
24638
- sibling = container.previousSibling;
24639
- if (sibling && sibling.nodeName == "IMG") {
24640
- return;
24641
- }
24642
-
24643
- nonEmptyElements = editor.schema.getNonEmptyElements();
24644
-
24645
- // Prevent default logic since it's broken
24646
- e.preventDefault();
24647
-
24648
- // Insert a BR before the text node this will prevent the containing element from being deleted/converted
24649
- brElm = dom.create('br', {id: '__tmp'});
24650
- container.parentNode.insertBefore(brElm, container);
24651
-
24652
- // Do the browser delete
24653
- editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
24654
-
24655
- // Check if the previous sibling is empty after deleting for example: <p><b></b>|</p>
24656
- container = selection.getRng().startContainer;
24657
- sibling = container.previousSibling;
24658
- if (sibling && sibling.nodeType == 1 && !dom.isBlock(sibling) && dom.isEmpty(sibling) &&
24659
- !nonEmptyElements[sibling.nodeName.toLowerCase()]) {
24660
- dom.remove(sibling);
24661
- }
24662
-
24663
- // Remove the temp element we inserted
24664
- dom.remove('__tmp');
24665
- }
24666
- }
24667
- });
24668
- }
24669
-
24670
24691
  /**
24671
24692
  * Removes a blockquote when backspace is pressed at the beginning of it.
24672
24693
  *
@@ -25051,7 +25072,6 @@ define("tinymce/util/Quirks", [
25051
25072
 
25052
25073
  // WebKit
25053
25074
  if (isWebKit) {
25054
- keepInlineElementOnDeleteBackspace();
25055
25075
  cleanupStylesWhenDeleting();
25056
25076
  inputMethodFocus();
25057
25077
  selectControlElements();
@@ -25124,7 +25144,7 @@ define("tinymce/util/Observable", [
25124
25144
  var bindingsName = "__bindings";
25125
25145
  var nativeEvents = Tools.makeMap(
25126
25146
  "focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange" +
25127
- " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragend dragover draggesture dragdrop drop drag", ' '
25147
+ " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragstart dragend dragover draggesture dragdrop drop drag", ' '
25128
25148
  );
25129
25149
 
25130
25150
  function returnFalse() {
@@ -27788,36 +27808,36 @@ define("tinymce/FocusManager", [
27788
27808
  return rng;
27789
27809
  }
27790
27810
 
27791
- function registerEvents(e) {
27792
- var editor = e.editor, lastRng, selectionChangeHandler;
27793
-
27794
- function isUIElement(elm) {
27795
- return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
27796
- }
27797
-
27798
- function isNodeInBody(node) {
27799
- var body = editor.getBody();
27811
+ function isUIElement(elm) {
27812
+ return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
27813
+ }
27800
27814
 
27801
- while (node) {
27802
- if (node == body) {
27803
- return true;
27804
- }
27815
+ function isNodeInBodyOfEditor(node, editor) {
27816
+ var body = editor.getBody();
27805
27817
 
27806
- node = node.parentNode;
27818
+ while (node) {
27819
+ if (node == body) {
27820
+ return true;
27807
27821
  }
27822
+
27823
+ node = node.parentNode;
27808
27824
  }
27825
+ }
27826
+
27827
+ function registerEvents(e) {
27828
+ var editor = e.editor, selectionChangeHandler;
27809
27829
 
27810
27830
  editor.on('init', function() {
27811
27831
  // On IE take selection snapshot onbeforedeactivate
27812
27832
  if ("onbeforedeactivate" in document && Env.ie < 11) {
27813
27833
  editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
27814
- var ieSelection = editor.getDoc().selection;
27815
-
27816
27834
  try {
27817
- lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
27835
+ editor.lastRng = editor.selection.getRng();
27818
27836
  } catch (ex) {
27819
27837
  // IE throws "Unexcpected call to method or property access" some times so lets ignore it
27820
27838
  }
27839
+
27840
+ editor.selection.lastFocusBookmark = createBookmark(editor.lastRng);
27821
27841
  });
27822
27842
  } else if (editor.inline || Env.ie > 10) {
27823
27843
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
@@ -27829,8 +27849,8 @@ define("tinymce/FocusManager", [
27829
27849
  node = editor.getBody();
27830
27850
  }
27831
27851
 
27832
- if (isNodeInBody(node)) {
27833
- lastRng = editor.selection.getRng();
27852
+ if (isNodeInBodyOfEditor(node, editor)) {
27853
+ editor.lastRng = editor.selection.getRng();
27834
27854
  }
27835
27855
  });
27836
27856
 
@@ -27844,7 +27864,7 @@ define("tinymce/FocusManager", [
27844
27864
 
27845
27865
  // Store when it's non collapsed
27846
27866
  if (!rng.collapsed) {
27847
- lastRng = rng;
27867
+ editor.lastRng = rng;
27848
27868
  }
27849
27869
  };
27850
27870
 
@@ -27859,7 +27879,7 @@ define("tinymce/FocusManager", [
27859
27879
  });
27860
27880
 
27861
27881
  editor.on('setcontent', function() {
27862
- lastRng = null;
27882
+ editor.lastRng = null;
27863
27883
  });
27864
27884
 
27865
27885
  // Remove last selection bookmark on mousedown see #6305
@@ -27881,32 +27901,18 @@ define("tinymce/FocusManager", [
27881
27901
  }
27882
27902
 
27883
27903
  editorManager.activeEditor = editor;
27904
+ editorManager.focusedEditor = editor;
27884
27905
  editor.fire('focus', {blurredEditor: focusedEditor});
27885
27906
  editor.focus(false);
27886
- editorManager.focusedEditor = editor;
27887
27907
  }
27888
27908
 
27889
- lastRng = null;
27909
+ editor.lastRng = null;
27890
27910
  });
27891
27911
 
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
-
27900
- editor.selection.lastFocusBookmark = createBookmark(lastRng);
27901
-
27912
+ editor.on('focusout', function() {
27902
27913
  window.setTimeout(function() {
27903
27914
  var focusedEditor = editorManager.focusedEditor;
27904
27915
 
27905
- // Focus from editorA into editorB then don't restore selection
27906
- if (focusedEditor != editor) {
27907
- editor.selection.lastFocusBookmark = null;
27908
- }
27909
-
27910
27916
  // Still the same editor the the blur was outside any editor UI
27911
27917
  if (!isUIElement(getActiveElement()) && focusedEditor == editor) {
27912
27918
  editor.fire('blur', {focusedEditor: null});
@@ -27917,6 +27923,22 @@ define("tinymce/FocusManager", [
27917
27923
  });
27918
27924
  }
27919
27925
 
27926
+ // Check if focus is moved to an element outside the active editor by checking if the target node
27927
+ // isn't within the body of the activeEditor nor a UI element such as a dialog child control
27928
+ DOMUtils.DOM.bind(document, 'focusin', function(e) {
27929
+ var activeEditor = editorManager.activeEditor;
27930
+
27931
+ if (activeEditor && e.target.ownerDocument == document) {
27932
+ activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.lastRng);
27933
+
27934
+ // Fire a blur event if the element isn't a UI element
27935
+ if (!isUIElement(e.target) && editorManager.focusedEditor == activeEditor) {
27936
+ activeEditor.fire('blur', {focusedEditor: null});
27937
+ editorManager.focusedEditor = null;
27938
+ }
27939
+ }
27940
+ });
27941
+
27920
27942
  editorManager.on('AddEditor', registerEvents);
27921
27943
  }
27922
27944
 
@@ -27985,7 +28007,7 @@ define("tinymce/EditorManager", [
27985
28007
  * @property minorVersion
27986
28008
  * @type String
27987
28009
  */
27988
- minorVersion : '0.11',
28010
+ minorVersion : '0.12',
27989
28011
 
27990
28012
  /**
27991
28013
  * Release date of TinyMCE build.
@@ -27993,7 +28015,7 @@ define("tinymce/EditorManager", [
27993
28015
  * @property releaseDate
27994
28016
  * @type String
27995
28017
  */
27996
- releaseDate: '2013-11-20',
28018
+ releaseDate: '2013-12-18',
27997
28019
 
27998
28020
  /**
27999
28021
  * Collection of editor instances.
@@ -29558,10 +29580,10 @@ define("tinymce/ui/Widget", [
29558
29580
  self.canFocus = true;
29559
29581
 
29560
29582
  if (settings.tooltip && Widget.tooltips !== false) {
29561
- self.on('mouseenter mouseleave', function(e) {
29583
+ self.on('mouseenter', function(e) {
29562
29584
  var tooltip = self.tooltip().moveTo(-0xFFFF);
29563
29585
 
29564
- if (e.control == self && e.type == 'mouseenter') {
29586
+ if (e.control == self) {
29565
29587
  var rel = tooltip.text(settings.tooltip).show().testMoveRel(self.getEl(), ['bc-tc', 'bc-tl', 'bc-tr']);
29566
29588
 
29567
29589
  tooltip.toggleClass('tooltip-n', rel == 'bc-tc');
@@ -29573,6 +29595,11 @@ define("tinymce/ui/Widget", [
29573
29595
  tooltip.hide();
29574
29596
  }
29575
29597
  });
29598
+
29599
+ self.on('mouseleave mousedown click', function() {
29600
+ self.tooltip().hide();
29601
+ });
29602
+
29576
29603
  }
29577
29604
 
29578
29605
  self.aria('label', settings.tooltip);
@@ -31930,7 +31957,7 @@ define("tinymce/ui/FormatControls", [
31930
31957
 
31931
31958
  return {
31932
31959
  type: 'listbox',
31933
- text: {raw: blocks[0][0]},
31960
+ text: blocks[0][0],
31934
31961
  values: items,
31935
31962
  fixedWidth: true,
31936
31963
  onselect: toggleFormat,