tinymce-rails 4.0.11 → 4.0.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)
@@ -6227,7 +6227,7 @@ define("tinymce/html/Schema", [
6227
6227
  'meta param embed source wbr track');
6228
6228
  boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' +
6229
6229
  'noshade nowrap readonly selected autoplay loop controls');
6230
- nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
6230
+ nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object script', shortEndedElementsMap);
6231
6231
  textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' +
6232
6232
  'blockquote center dir fieldset header footer article section hgroup aside nav figure');
6233
6233
  blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' +
@@ -10808,6 +10808,7 @@ define("tinymce/dom/Selection", [
10808
10808
 
10809
10809
  function normalizeEndPoint(start) {
10810
10810
  var container, offset, walker, dom = self.dom, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
10811
+ var directionLeft;
10811
10812
 
10812
10813
  function hasBrBeforeAfter(node, left) {
10813
10814
  var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
@@ -10860,6 +10861,11 @@ define("tinymce/dom/Selection", [
10860
10861
  container = rng[(start ? 'start' : 'end') + 'Container'];
10861
10862
  offset = rng[(start ? 'start' : 'end') + 'Offset'];
10862
10863
  nonEmptyElementsMap = dom.schema.getNonEmptyElements();
10864
+ directionLeft = start;
10865
+
10866
+ if (container.nodeType == 1 && offset > container.childNodes.length - 1) {
10867
+ directionLeft = false;
10868
+ }
10863
10869
 
10864
10870
  // If the container is a document move it to the body element
10865
10871
  if (container.nodeType === 9) {
@@ -10870,7 +10876,7 @@ define("tinymce/dom/Selection", [
10870
10876
  // If the container is body try move it into the closest text node or position
10871
10877
  if (container === body) {
10872
10878
  // If start is before/after a image, table etc
10873
- if (start) {
10879
+ if (directionLeft) {
10874
10880
  node = container.childNodes[offset > 0 ? offset - 1 : 0];
10875
10881
  if (node) {
10876
10882
  nodeName = node.nodeName.toLowerCase();
@@ -10882,7 +10888,7 @@ define("tinymce/dom/Selection", [
10882
10888
 
10883
10889
  // Resolve the index
10884
10890
  if (container.hasChildNodes()) {
10885
- offset = Math.min(!start && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
10891
+ offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
10886
10892
  container = container.childNodes[offset];
10887
10893
  offset = 0;
10888
10894
 
@@ -10895,7 +10901,7 @@ define("tinymce/dom/Selection", [
10895
10901
  do {
10896
10902
  // Found a text node use that position
10897
10903
  if (node.nodeType === 3 && node.nodeValue.length > 0) {
10898
- offset = start ? 0 : node.nodeValue.length;
10904
+ offset = directionLeft ? 0 : node.nodeValue.length;
10899
10905
  container = node;
10900
10906
  normalized = true;
10901
10907
  break;
@@ -10907,14 +10913,14 @@ define("tinymce/dom/Selection", [
10907
10913
  container = node.parentNode;
10908
10914
 
10909
10915
  // Put caret after image when moving the end point
10910
- if (node.nodeName == "IMG" && !start) {
10916
+ if (node.nodeName == "IMG" && !directionLeft) {
10911
10917
  offset++;
10912
10918
  }
10913
10919
 
10914
10920
  normalized = true;
10915
10921
  break;
10916
10922
  }
10917
- } while ((node = (start ? walker.next() : walker.prev())));
10923
+ } while ((node = (directionLeft ? walker.next() : walker.prev())));
10918
10924
  }
10919
10925
  }
10920
10926
  }
@@ -10945,7 +10951,7 @@ define("tinymce/dom/Selection", [
10945
10951
  // Lean the start of the selection right if possible
10946
10952
  // So this: x[<b>x]</b>
10947
10953
  // Becomes: x<b>[x]</b>
10948
- if (start && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
10954
+ if (directionLeft && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
10949
10955
  findTextNodeRelative(false);
10950
10956
  }
10951
10957
 
@@ -12464,6 +12470,10 @@ define("tinymce/Formatter", [
12464
12470
  function matchParents(node) {
12465
12471
  var root = dom.getRoot();
12466
12472
 
12473
+ if (node === root) {
12474
+ return false;
12475
+ }
12476
+
12467
12477
  // Find first node with similar format settings
12468
12478
  node = dom.getParent(node, function(node) {
12469
12479
  return node.parentNode === root || !!matchNode(node, name, vars, true);
@@ -12978,7 +12988,7 @@ define("tinymce/Formatter", [
12978
12988
 
12979
12989
  // Expand to block of similar type
12980
12990
  if (!format[0].wrapper) {
12981
- node = dom.getParent(container, format[0].block);
12991
+ node = dom.getParent(container, format[0].block, root);
12982
12992
  }
12983
12993
 
12984
12994
  // Expand to first wrappable block element or any block element
@@ -15186,7 +15196,7 @@ define("tinymce/EditorCommands", [
15186
15196
  },
15187
15197
 
15188
15198
  // Override unlink command
15189
- unlink: function(command) {
15199
+ unlink: function() {
15190
15200
  if (selection.isCollapsed()) {
15191
15201
  var elm = selection.getNode();
15192
15202
  if (elm.tagName == 'A') {
@@ -15196,8 +15206,7 @@ define("tinymce/EditorCommands", [
15196
15206
  return;
15197
15207
  }
15198
15208
 
15199
- execNativeCommand(command);
15200
- selection.collapse(FALSE);
15209
+ formatter.remove("link");
15201
15210
  },
15202
15211
 
15203
15212
  // Override justify commands to use the text formatter engine
@@ -21505,92 +21514,166 @@ define("tinymce/util/Quirks", [
21505
21514
  * <h1>a</h1><p>|b</p>
21506
21515
  *
21507
21516
  * Will produce this on backspace:
21508
- * <h1>a<span class="Apple-style-span" style="<all runtime styles>">b</span></p>
21517
+ * <h1>a<span style="<all runtime styles>">b</span></p>
21509
21518
  *
21510
21519
  * This fixes the backspace to produce:
21511
21520
  * <h1>a|b</p>
21512
21521
  *
21513
21522
  * See bug: https://bugs.webkit.org/show_bug.cgi?id=45784
21514
21523
  *
21515
- * This code is a bit of a hack and hopefully it will be fixed soon in WebKit.
21524
+ * This fixes the following delete scenarios:
21525
+ * 1. Delete by pressing backspace key.
21526
+ * 2. Delete by pressing delete key.
21527
+ * 3. Delete by pressing backspace key with ctrl/cmd (Word delete).
21528
+ * 4. Delete by pressing delete key with ctrl/cmd (Word delete).
21529
+ * 5. Delete by drag/dropping contents inside the editor.
21530
+ * 6. Delete by using Cut Ctrl+X/Cmd+X.
21531
+ * 7. Delete by selecting contents and writing a character.'
21532
+ *
21533
+ * This code is a ugly hack since writing full custom delete logic for just this bug
21534
+ * fix seemed like a huge task. I hope we can remove this before the year 2030.
21516
21535
  */
21517
21536
  function cleanupStylesWhenDeleting() {
21518
- function removeMergedFormatSpans(isDelete) {
21519
- var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
21537
+ var doc = editor.getDoc();
21520
21538
 
21521
- function isAtStartOrEndOfElm() {
21522
- if (container.nodeType == 3) {
21523
- if (isDelete && offset == container.length) {
21524
- return true;
21525
- }
21539
+ if (!window.MutationObserver) {
21540
+ return;
21541
+ }
21526
21542
 
21527
- if (!isDelete && offset === 0) {
21528
- return true;
21529
- }
21543
+ function customDelete(isForward) {
21544
+ var mutationObserver = new MutationObserver(function() {});
21545
+
21546
+ Tools.each(editor.getBody().getElementsByTagName('*'), function(elm) {
21547
+ // Mark existing spans
21548
+ if (elm.tagName == 'SPAN') {
21549
+ elm.setAttribute('mce-data-marked', 1);
21530
21550
  }
21531
- }
21532
21551
 
21533
- rng = selection.getRng();
21534
- var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
21552
+ // Make sure all elements has a data-mce-style attribute
21553
+ if (!elm.hasAttribute('data-mce-style') && elm.hasAttribute('style')) {
21554
+ editor.dom.setAttrib(elm, 'style', elm.getAttribute('style'));
21555
+ }
21556
+ });
21535
21557
 
21536
- if (!rng.collapsed) {
21537
- isDelete = true;
21538
- }
21558
+ // Observe added nodes and style attribute changes
21559
+ mutationObserver.observe(editor.getDoc(), {
21560
+ childList: true,
21561
+ attributes: true,
21562
+ subtree: true,
21563
+ attributeFilter: ['style']
21564
+ });
21539
21565
 
21540
- container = rng[(isDelete ? 'start' : 'end') + 'Container'];
21541
- offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
21566
+ editor.getDoc().execCommand(isForward ? 'ForwardDelete' : 'Delete', false, null);
21542
21567
 
21543
- if (container.nodeType == 3) {
21544
- blockElm = dom.getParent(rng.startContainer, dom.isBlock);
21568
+ var rng = editor.selection.getRng();
21569
+ var caretElement = rng.startContainer.parentNode;
21545
21570
 
21546
- // On delete clone the root span of the next block element
21547
- if (isDelete) {
21548
- blockElm = dom.getNext(blockElm, dom.isBlock);
21549
- }
21571
+ Tools.each(mutationObserver.takeRecords(), function(record) {
21572
+ // Restore style attribute to previous value
21573
+ if (record.attributeName == "style") {
21574
+ var oldValue = record.target.getAttribute('data-mce-style');
21550
21575
 
21551
- if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
21552
- // Wrap children of block in a EM and let WebKit stick is
21553
- // runtime styles junk into that EM
21554
- wrapperElm = dom.create('em', {'id': '__mceDel'});
21576
+ if (oldValue) {
21577
+ record.target.setAttribute("style", oldValue);
21578
+ } else {
21579
+ record.target.removeAttribute("style");
21580
+ }
21581
+ }
21555
21582
 
21556
- each(Tools.grep(blockElm.childNodes), function(node) {
21557
- wrapperElm.appendChild(node);
21558
- });
21583
+ // Remove all spans that isn't maked and retain selection
21584
+ Tools.each(record.addedNodes, function(node) {
21585
+ if (node.nodeName == "SPAN" && !node.getAttribute('mce-data-marked')) {
21586
+ var offset, container;
21559
21587
 
21560
- blockElm.appendChild(wrapperElm);
21561
- }
21562
- }
21588
+ if (node == caretElement) {
21589
+ offset = rng.startOffset;
21590
+ container = node.firstChild;
21591
+ }
21563
21592
 
21564
- // Do the backspace/delete action
21565
- rng = dom.createRng();
21566
- rng.setStart(tmpRng[0], tmpRng[1]);
21567
- rng.setEnd(tmpRng[2], tmpRng[3]);
21568
- selection.setRng(rng);
21569
- editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
21593
+ dom.remove(node, true);
21570
21594
 
21571
- // Remove temp wrapper element
21572
- if (wrapperElm) {
21573
- bookmark = selection.getBookmark();
21595
+ if (container) {
21596
+ rng.setStart(container, offset);
21597
+ rng.setEnd(container, offset);
21598
+ editor.selection.setRng(rng);
21599
+ }
21600
+ }
21601
+ });
21602
+ });
21574
21603
 
21575
- while ((elm = dom.get('__mceDel'))) {
21576
- dom.remove(elm, true);
21577
- }
21604
+ mutationObserver.disconnect();
21578
21605
 
21579
- selection.moveToBookmark(bookmark);
21580
- }
21606
+ // Remove any left over marks
21607
+ Tools.each(editor.dom.select('span[mce-data-marked]'), function(span) {
21608
+ span.removeAttribute('mce-data-marked');
21609
+ });
21581
21610
  }
21582
21611
 
21583
21612
  editor.on('keydown', function(e) {
21584
- var isDelete;
21613
+ var isForward = e.keyCode == DELETE, isMeta = VK.metaKeyPressed(e);
21614
+
21615
+ if (!isDefaultPrevented(e) && (isForward || e.keyCode == BACKSPACE)) {
21616
+ var rng = editor.selection.getRng(), container = rng.startContainer, offset = rng.startOffset;
21617
+
21618
+ // Ignore non meta delete in the where there is text before/after the caret
21619
+ if (!isMeta && rng.collapsed && container.nodeType == 3) {
21620
+ if (isForward ? offset < container.data.length : offset > 0) {
21621
+ return;
21622
+ }
21623
+ }
21585
21624
 
21586
- isDelete = e.keyCode == DELETE;
21587
- if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
21588
21625
  e.preventDefault();
21589
- removeMergedFormatSpans(isDelete);
21626
+
21627
+ if (isMeta) {
21628
+ editor.selection.getSel().modify("extend", isForward ? "forward" : "backward", "word");
21629
+ }
21630
+
21631
+ customDelete(isForward);
21632
+ }
21633
+ });
21634
+
21635
+ editor.on('keypress', function(e) {
21636
+ if (!isDefaultPrevented(e) && !selection.isCollapsed() && e.charCode) {
21637
+ e.preventDefault();
21638
+ customDelete(true);
21639
+ editor.selection.setContent(String.fromCharCode(e.charCode));
21640
+ }
21641
+ });
21642
+
21643
+ editor.addCommand('Delete', function() {
21644
+ customDelete();
21645
+ });
21646
+
21647
+ editor.addCommand('ForwardDelete', function() {
21648
+ customDelete(true);
21649
+ });
21650
+
21651
+ editor.on('dragstart', function(e) {
21652
+ e.dataTransfer.setData('mce-internal', editor.selection.getContent());
21653
+ });
21654
+
21655
+ editor.on('drop', function(e) {
21656
+ if (!isDefaultPrevented(e)) {
21657
+ var internalContent = e.dataTransfer.getData('mce-internal');
21658
+
21659
+ if (internalContent && doc.caretRangeFromPoint) {
21660
+ e.preventDefault();
21661
+ customDelete();
21662
+ editor.selection.setRng(doc.caretRangeFromPoint(e.x, e.y));
21663
+ editor.insertContent(internalContent);
21664
+ }
21590
21665
  }
21591
21666
  });
21592
21667
 
21593
- editor.addCommand('Delete', function() {removeMergedFormatSpans();});
21668
+ editor.on('cut', function(e) {
21669
+ if (!isDefaultPrevented(e) && e.clipboardData) {
21670
+ e.preventDefault();
21671
+ e.clipboardData.clearData();
21672
+ e.clipboardData.setData('text/html', editor.selection.getContent());
21673
+ e.clipboardData.setData('text/plain', editor.selection.getContent({format: 'text'}));
21674
+ customDelete(true);
21675
+ }
21676
+ });
21594
21677
  }
21595
21678
 
21596
21679
  /**
@@ -21974,68 +22057,6 @@ define("tinymce/util/Quirks", [
21974
22057
  });
21975
22058
  }
21976
22059
 
21977
- /**
21978
- * Backspace or delete on WebKit will combine all visual styles in a span if the last character is deleted.
21979
- *
21980
- * For example backspace on:
21981
- * <p><b>x|</b></p>
21982
- *
21983
- * Will produce:
21984
- * <p><span style="font-weight: bold">|<br></span></p>
21985
- *
21986
- * When it should produce:
21987
- * <p><b>|<br></b></p>
21988
- *
21989
- * See: https://bugs.webkit.org/show_bug.cgi?id=81656
21990
- */
21991
- function keepInlineElementOnDeleteBackspace() {
21992
- editor.on('keydown', function(e) {
21993
- var isDelete, rng, container, offset, brElm, sibling, collapsed, nonEmptyElements;
21994
-
21995
- isDelete = e.keyCode == DELETE;
21996
- if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
21997
- rng = selection.getRng();
21998
- container = rng.startContainer;
21999
- offset = rng.startOffset;
22000
- collapsed = rng.collapsed;
22001
-
22002
- // Override delete if the start container is a text node and is at the beginning of text or
22003
- // just before/after the last character to be deleted in collapsed mode
22004
- if (container.nodeType == 3 && container.nodeValue.length > 0 && ((offset === 0 && !collapsed) ||
22005
- (collapsed && offset === (isDelete ? 0 : 1)))) {
22006
- // Edge case when deleting <p><b><img> |x</b></p>
22007
- sibling = container.previousSibling;
22008
- if (sibling && sibling.nodeName == "IMG") {
22009
- return;
22010
- }
22011
-
22012
- nonEmptyElements = editor.schema.getNonEmptyElements();
22013
-
22014
- // Prevent default logic since it's broken
22015
- e.preventDefault();
22016
-
22017
- // Insert a BR before the text node this will prevent the containing element from being deleted/converted
22018
- brElm = dom.create('br', {id: '__tmp'});
22019
- container.parentNode.insertBefore(brElm, container);
22020
-
22021
- // Do the browser delete
22022
- editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
22023
-
22024
- // Check if the previous sibling is empty after deleting for example: <p><b></b>|</p>
22025
- container = selection.getRng().startContainer;
22026
- sibling = container.previousSibling;
22027
- if (sibling && sibling.nodeType == 1 && !dom.isBlock(sibling) && dom.isEmpty(sibling) &&
22028
- !nonEmptyElements[sibling.nodeName.toLowerCase()]) {
22029
- dom.remove(sibling);
22030
- }
22031
-
22032
- // Remove the temp element we inserted
22033
- dom.remove('__tmp');
22034
- }
22035
- }
22036
- });
22037
- }
22038
-
22039
22060
  /**
22040
22061
  * Removes a blockquote when backspace is pressed at the beginning of it.
22041
22062
  *
@@ -22420,7 +22441,6 @@ define("tinymce/util/Quirks", [
22420
22441
 
22421
22442
  // WebKit
22422
22443
  if (isWebKit) {
22423
- keepInlineElementOnDeleteBackspace();
22424
22444
  cleanupStylesWhenDeleting();
22425
22445
  inputMethodFocus();
22426
22446
  selectControlElements();
@@ -22493,7 +22513,7 @@ define("tinymce/util/Observable", [
22493
22513
  var bindingsName = "__bindings";
22494
22514
  var nativeEvents = Tools.makeMap(
22495
22515
  "focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange" +
22496
- " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragend dragover draggesture dragdrop drop drag", ' '
22516
+ " mouseout mouseenter mouseleave keydown keypress keyup contextmenu dragstart dragend dragover draggesture dragdrop drop drag", ' '
22497
22517
  );
22498
22518
 
22499
22519
  function returnFalse() {
@@ -25157,36 +25177,36 @@ define("tinymce/FocusManager", [
25157
25177
  return rng;
25158
25178
  }
25159
25179
 
25160
- function registerEvents(e) {
25161
- var editor = e.editor, lastRng, selectionChangeHandler;
25162
-
25163
- function isUIElement(elm) {
25164
- return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
25165
- }
25166
-
25167
- function isNodeInBody(node) {
25168
- var body = editor.getBody();
25180
+ function isUIElement(elm) {
25181
+ return !!DOMUtils.DOM.getParent(elm, FocusManager.isEditorUIElement);
25182
+ }
25169
25183
 
25170
- while (node) {
25171
- if (node == body) {
25172
- return true;
25173
- }
25184
+ function isNodeInBodyOfEditor(node, editor) {
25185
+ var body = editor.getBody();
25174
25186
 
25175
- node = node.parentNode;
25187
+ while (node) {
25188
+ if (node == body) {
25189
+ return true;
25176
25190
  }
25191
+
25192
+ node = node.parentNode;
25177
25193
  }
25194
+ }
25195
+
25196
+ function registerEvents(e) {
25197
+ var editor = e.editor, selectionChangeHandler;
25178
25198
 
25179
25199
  editor.on('init', function() {
25180
25200
  // On IE take selection snapshot onbeforedeactivate
25181
25201
  if ("onbeforedeactivate" in document && Env.ie < 11) {
25182
25202
  editor.dom.bind(editor.getBody(), 'beforedeactivate', function() {
25183
- var ieSelection = editor.getDoc().selection;
25184
-
25185
25203
  try {
25186
- lastRng = ieSelection && ieSelection.createRange ? ieSelection.createRange() : editor.selection.getRng();
25204
+ editor.lastRng = editor.selection.getRng();
25187
25205
  } catch (ex) {
25188
25206
  // IE throws "Unexcpected call to method or property access" some times so lets ignore it
25189
25207
  }
25208
+
25209
+ editor.selection.lastFocusBookmark = createBookmark(editor.lastRng);
25190
25210
  });
25191
25211
  } else if (editor.inline || Env.ie > 10) {
25192
25212
  // On other browsers take snapshot on nodechange in inline mode since they have Ghost selections for iframes
@@ -25198,8 +25218,8 @@ define("tinymce/FocusManager", [
25198
25218
  node = editor.getBody();
25199
25219
  }
25200
25220
 
25201
- if (isNodeInBody(node)) {
25202
- lastRng = editor.selection.getRng();
25221
+ if (isNodeInBodyOfEditor(node, editor)) {
25222
+ editor.lastRng = editor.selection.getRng();
25203
25223
  }
25204
25224
  });
25205
25225
 
@@ -25213,7 +25233,7 @@ define("tinymce/FocusManager", [
25213
25233
 
25214
25234
  // Store when it's non collapsed
25215
25235
  if (!rng.collapsed) {
25216
- lastRng = rng;
25236
+ editor.lastRng = rng;
25217
25237
  }
25218
25238
  };
25219
25239
 
@@ -25228,7 +25248,7 @@ define("tinymce/FocusManager", [
25228
25248
  });
25229
25249
 
25230
25250
  editor.on('setcontent', function() {
25231
- lastRng = null;
25251
+ editor.lastRng = null;
25232
25252
  });
25233
25253
 
25234
25254
  // Remove last selection bookmark on mousedown see #6305
@@ -25250,32 +25270,18 @@ define("tinymce/FocusManager", [
25250
25270
  }
25251
25271
 
25252
25272
  editorManager.activeEditor = editor;
25273
+ editorManager.focusedEditor = editor;
25253
25274
  editor.fire('focus', {blurredEditor: focusedEditor});
25254
25275
  editor.focus(false);
25255
- editorManager.focusedEditor = editor;
25256
25276
  }
25257
25277
 
25258
- lastRng = null;
25278
+ editor.lastRng = null;
25259
25279
  });
25260
25280
 
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
-
25269
- editor.selection.lastFocusBookmark = createBookmark(lastRng);
25270
-
25281
+ editor.on('focusout', function() {
25271
25282
  window.setTimeout(function() {
25272
25283
  var focusedEditor = editorManager.focusedEditor;
25273
25284
 
25274
- // Focus from editorA into editorB then don't restore selection
25275
- if (focusedEditor != editor) {
25276
- editor.selection.lastFocusBookmark = null;
25277
- }
25278
-
25279
25285
  // Still the same editor the the blur was outside any editor UI
25280
25286
  if (!isUIElement(getActiveElement()) && focusedEditor == editor) {
25281
25287
  editor.fire('blur', {focusedEditor: null});
@@ -25286,6 +25292,22 @@ define("tinymce/FocusManager", [
25286
25292
  });
25287
25293
  }
25288
25294
 
25295
+ // Check if focus is moved to an element outside the active editor by checking if the target node
25296
+ // isn't within the body of the activeEditor nor a UI element such as a dialog child control
25297
+ DOMUtils.DOM.bind(document, 'focusin', function(e) {
25298
+ var activeEditor = editorManager.activeEditor;
25299
+
25300
+ if (activeEditor && e.target.ownerDocument == document) {
25301
+ activeEditor.selection.lastFocusBookmark = createBookmark(activeEditor.lastRng);
25302
+
25303
+ // Fire a blur event if the element isn't a UI element
25304
+ if (!isUIElement(e.target) && editorManager.focusedEditor == activeEditor) {
25305
+ activeEditor.fire('blur', {focusedEditor: null});
25306
+ editorManager.focusedEditor = null;
25307
+ }
25308
+ }
25309
+ });
25310
+
25289
25311
  editorManager.on('AddEditor', registerEvents);
25290
25312
  }
25291
25313
 
@@ -25354,7 +25376,7 @@ define("tinymce/EditorManager", [
25354
25376
  * @property minorVersion
25355
25377
  * @type String
25356
25378
  */
25357
- minorVersion : '0.11',
25379
+ minorVersion : '0.12',
25358
25380
 
25359
25381
  /**
25360
25382
  * Release date of TinyMCE build.
@@ -25362,7 +25384,7 @@ define("tinymce/EditorManager", [
25362
25384
  * @property releaseDate
25363
25385
  * @type String
25364
25386
  */
25365
- releaseDate: '2013-11-20',
25387
+ releaseDate: '2013-12-18',
25366
25388
 
25367
25389
  /**
25368
25390
  * Collection of editor instances.
@@ -26927,10 +26949,10 @@ define("tinymce/ui/Widget", [
26927
26949
  self.canFocus = true;
26928
26950
 
26929
26951
  if (settings.tooltip && Widget.tooltips !== false) {
26930
- self.on('mouseenter mouseleave', function(e) {
26952
+ self.on('mouseenter', function(e) {
26931
26953
  var tooltip = self.tooltip().moveTo(-0xFFFF);
26932
26954
 
26933
- if (e.control == self && e.type == 'mouseenter') {
26955
+ if (e.control == self) {
26934
26956
  var rel = tooltip.text(settings.tooltip).show().testMoveRel(self.getEl(), ['bc-tc', 'bc-tl', 'bc-tr']);
26935
26957
 
26936
26958
  tooltip.toggleClass('tooltip-n', rel == 'bc-tc');
@@ -26942,6 +26964,11 @@ define("tinymce/ui/Widget", [
26942
26964
  tooltip.hide();
26943
26965
  }
26944
26966
  });
26967
+
26968
+ self.on('mouseleave mousedown click', function() {
26969
+ self.tooltip().hide();
26970
+ });
26971
+
26945
26972
  }
26946
26973
 
26947
26974
  self.aria('label', settings.tooltip);
@@ -29299,7 +29326,7 @@ define("tinymce/ui/FormatControls", [
29299
29326
 
29300
29327
  return {
29301
29328
  type: 'listbox',
29302
- text: {raw: blocks[0][0]},
29329
+ text: blocks[0][0],
29303
29330
  values: items,
29304
29331
  fixedWidth: true,
29305
29332
  onselect: toggleFormat,