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)
@@ -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,