mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 23:40:35 -05:00
Workaround WebKit/IE can't focus empty text nodes.
This commit is contained in:
parent
6480739143
commit
543abca022
2 changed files with 69 additions and 5 deletions
|
@ -19,11 +19,15 @@
|
||||||
var win = doc.defaultView,
|
var win = doc.defaultView,
|
||||||
body = doc.body;
|
body = doc.body;
|
||||||
|
|
||||||
|
// Browser sniffing. Unfortunately necessary.
|
||||||
var isOpera = !!win.opera;
|
var isOpera = !!win.opera;
|
||||||
var isIE = !!win.ie;
|
var isIE = !!win.ie;
|
||||||
var isGecko = /Gecko\//.test( navigator.userAgent );
|
var isGecko = /Gecko\//.test( navigator.userAgent );
|
||||||
|
var isWebKit = /WebKit/.test( navigator.userAgent );
|
||||||
var isIOS = /iP(?:ad|hone|od)/.test( navigator.userAgent );
|
var isIOS = /iP(?:ad|hone|od)/.test( navigator.userAgent );
|
||||||
|
|
||||||
var useTextFixer = isIE || isOpera;
|
var useTextFixer = isIE || isOpera;
|
||||||
|
var cantFocusEmptyTextNodes = isIE || isWebKit;
|
||||||
|
|
||||||
// --- DOM Sugar ---
|
// --- DOM Sugar ---
|
||||||
|
|
||||||
|
@ -150,7 +154,42 @@
|
||||||
var lastFocusNode;
|
var lastFocusNode;
|
||||||
var path = '';
|
var path = '';
|
||||||
|
|
||||||
|
// --- Workaround for browsers that can't focus empty text nodes ---
|
||||||
|
|
||||||
|
// WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=15256
|
||||||
|
|
||||||
|
var placeholderTextNode = null;
|
||||||
|
var setPlaceholderTextNode = function ( node ) {
|
||||||
|
if ( placeholderTextNode ) {
|
||||||
|
removePlaceholderTextNode( getSelection(), true );
|
||||||
|
}
|
||||||
|
placeholderTextNode = node;
|
||||||
|
};
|
||||||
|
var removePlaceholderTextNode = function ( range, force ) {
|
||||||
|
var node = placeholderTextNode,
|
||||||
|
index;
|
||||||
|
if ( !force && node.data === '\u200B' &&
|
||||||
|
( range.startContainer === node || range.endContainer === node ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
placeholderTextNode = null;
|
||||||
|
if ( node.parentNode ) {
|
||||||
|
while ( ( index = node.data.indexOf( '\u200B' ) ) > -1 ) {
|
||||||
|
node.deleteData( index, 1 );
|
||||||
|
}
|
||||||
|
if ( !node.data && !node.nextSibling && !node.previousSibling &&
|
||||||
|
node.parentNode.isInline() ) {
|
||||||
|
node.parentNode.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Path change events ---
|
||||||
|
|
||||||
var updatePath = function ( range, force ) {
|
var updatePath = function ( range, force ) {
|
||||||
|
if ( placeholderTextNode ) {
|
||||||
|
removePlaceholderTextNode( range );
|
||||||
|
}
|
||||||
var anchor = range.startContainer,
|
var anchor = range.startContainer,
|
||||||
focus = range.endContainer,
|
focus = range.endContainer,
|
||||||
newPath;
|
newPath;
|
||||||
|
@ -457,7 +496,8 @@
|
||||||
if ( range.collapsed ) {
|
if ( range.collapsed ) {
|
||||||
var el = createElement( tag, attributes ).fixCursor();
|
var el = createElement( tag, attributes ).fixCursor();
|
||||||
range._insertNode( el );
|
range._insertNode( el );
|
||||||
range.selectNodeContents( el );
|
range.setStart( el.firstChild, el.firstChild.length );
|
||||||
|
range.collapse( true );
|
||||||
}
|
}
|
||||||
// Otherwise we find all the textnodes in the range (splitting
|
// Otherwise we find all the textnodes in the range (splitting
|
||||||
// partially selected nodes) and if they're not already formatted
|
// partially selected nodes) and if they're not already formatted
|
||||||
|
@ -526,8 +566,17 @@
|
||||||
|
|
||||||
// We need a node in the selection to break the surrounding
|
// We need a node in the selection to break the surrounding
|
||||||
// formatted text.
|
// formatted text.
|
||||||
|
var fixer;
|
||||||
if ( range.collapsed ) {
|
if ( range.collapsed ) {
|
||||||
range._insertNode( doc.createTextNode( '' ) );
|
if ( cantFocusEmptyTextNodes ) {
|
||||||
|
fixer = doc.createTextNode( '\u200B' );
|
||||||
|
setTimeout( function () {
|
||||||
|
setPlaceholderTextNode( fixer );
|
||||||
|
}, 0 );
|
||||||
|
} else {
|
||||||
|
fixer = doc.createTextNode( '' );
|
||||||
|
}
|
||||||
|
range._insertNode( fixer );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find block-level ancestor of selection
|
// Find block-level ancestor of selection
|
||||||
|
@ -609,6 +658,9 @@
|
||||||
|
|
||||||
// Merge adjacent inlines:
|
// Merge adjacent inlines:
|
||||||
range = getRangeAndRemoveBookmark();
|
range = getRangeAndRemoveBookmark();
|
||||||
|
if ( fixer ) {
|
||||||
|
range.collapse( false );
|
||||||
|
}
|
||||||
var _range = {
|
var _range = {
|
||||||
startContainer: range.startContainer,
|
startContainer: range.startContainer,
|
||||||
startOffset: range.startOffset,
|
startOffset: range.startOffset,
|
||||||
|
@ -1485,6 +1537,8 @@
|
||||||
|
|
||||||
win.editor = {
|
win.editor = {
|
||||||
|
|
||||||
|
_setPlaceholderTextNode: setPlaceholderTextNode,
|
||||||
|
|
||||||
addEventListener: chain( addEventListener ),
|
addEventListener: chain( addEventListener ),
|
||||||
removeEventListener: chain( removeEventListener ),
|
removeEventListener: chain( removeEventListener ),
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
( function () {
|
( function () {
|
||||||
|
|
||||||
/*global Node, Text, Element, HTMLDocument, window, document */
|
/*global Node, Text, Element, HTMLDocument, window, document, navigator,
|
||||||
|
setTimeout, editor */
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
@ -56,6 +57,8 @@ var isBlock = function ( el ) {
|
||||||
return el.isBlock() ? FILTER_ACCEPT : FILTER_SKIP;
|
return el.isBlock() ? FILTER_ACCEPT : FILTER_SKIP;
|
||||||
};
|
};
|
||||||
var useTextFixer = !!( window.opera || window.ie );
|
var useTextFixer = !!( window.opera || window.ie );
|
||||||
|
var cantFocusEmptyTextNodes =
|
||||||
|
/WebKit/.test( navigator.userAgent ) || !!window.ie;
|
||||||
|
|
||||||
implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], {
|
implement( window.Node ? [ Node ] : [ Text, Element, HTMLDocument ], {
|
||||||
isInline: $False,
|
isInline: $False,
|
||||||
|
@ -376,7 +379,14 @@ implement([ Element ], {
|
||||||
|
|
||||||
if ( el.isInline() ) {
|
if ( el.isInline() ) {
|
||||||
if ( !el.firstChild ) {
|
if ( !el.firstChild ) {
|
||||||
fixer = doc.createTextNode( /* isWebkit ? '\u200B' :*/ '' );
|
if ( cantFocusEmptyTextNodes ) {
|
||||||
|
fixer = doc.createTextNode( '\u200B' );
|
||||||
|
setTimeout( function () {
|
||||||
|
editor._setPlaceholderTextNode( fixer );
|
||||||
|
}, 0 );
|
||||||
|
} else {
|
||||||
|
fixer = doc.createTextNode( '' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( useTextFixer ) {
|
if ( useTextFixer ) {
|
||||||
|
@ -415,7 +425,7 @@ implement([ Element ], {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fix IE9's buggy implementation of Text#splitText.
|
// Fix IE8/9's buggy implementation of Text#splitText.
|
||||||
// If the split is at the end of the node, it doesn't insert the newly split
|
// If the split is at the end of the node, it doesn't insert the newly split
|
||||||
// node into the document, and sets its value to undefined rather than ''.
|
// node into the document, and sets its value to undefined rather than ''.
|
||||||
// And even if the split is not at the end, the original node is removed from
|
// And even if the split is not at the end, the original node is removed from
|
||||||
|
|
Loading…
Reference in a new issue