mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 07:13:08 -05:00
Fix iOS auto-capitalisation on enter
This commit is contained in:
parent
dcd121a65a
commit
9218c9ba14
3 changed files with 339 additions and 299 deletions
|
@ -1426,161 +1426,184 @@ var afterDelete = function ( self, range ) {
|
|||
}
|
||||
};
|
||||
|
||||
var keyHandlers = {
|
||||
enter: function ( self, event, range ) {
|
||||
var root = self._root;
|
||||
var block, parent, node, offset, nodeAfterSplit;
|
||||
var handleEnter = function ( self, shiftKey, range ) {
|
||||
var root = self._root;
|
||||
var block, parent, node, offset, nodeAfterSplit;
|
||||
|
||||
// We handle this ourselves
|
||||
event.preventDefault();
|
||||
// Save undo checkpoint and add any links in the preceding section.
|
||||
// Remove any zws so we don't think there's content in an empty
|
||||
// block.
|
||||
self._recordUndoState( range );
|
||||
addLinks( range.startContainer, root, self );
|
||||
self._removeZWS();
|
||||
self._getRangeAndRemoveBookmark( range );
|
||||
|
||||
// Save undo checkpoint and add any links in the preceding section.
|
||||
// Remove any zws so we don't think there's content in an empty
|
||||
// block.
|
||||
self._recordUndoState( range );
|
||||
addLinks( range.startContainer, root, self );
|
||||
self._removeZWS();
|
||||
self._getRangeAndRemoveBookmark( range );
|
||||
// Selected text is overwritten, therefore delete the contents
|
||||
// to collapse selection.
|
||||
if ( !range.collapsed ) {
|
||||
deleteContentsOfRange( range, root );
|
||||
}
|
||||
|
||||
// Selected text is overwritten, therefore delete the contents
|
||||
// to collapse selection.
|
||||
if ( !range.collapsed ) {
|
||||
deleteContentsOfRange( range, root );
|
||||
block = getStartBlockOfRange( range, root );
|
||||
|
||||
// Inside a PRE, insert literal newline, unless on blank line.
|
||||
if ( block && ( parent = getNearest( block, root, 'PRE' ) ) ) {
|
||||
moveRangeBoundariesDownTree( range );
|
||||
node = range.startContainer;
|
||||
offset = range.startOffset;
|
||||
if ( node.nodeType !== TEXT_NODE ) {
|
||||
node = self._doc.createTextNode( '' );
|
||||
parent.insertBefore( node, parent.firstChild );
|
||||
}
|
||||
|
||||
block = getStartBlockOfRange( range, root );
|
||||
|
||||
// Inside a PRE, insert literal newline, unless on blank line.
|
||||
if ( block && ( parent = getNearest( block, root, 'PRE' ) ) ) {
|
||||
moveRangeBoundariesDownTree( range );
|
||||
node = range.startContainer;
|
||||
offset = range.startOffset;
|
||||
if ( node.nodeType !== TEXT_NODE ) {
|
||||
node = self._doc.createTextNode( '' );
|
||||
parent.insertBefore( node, parent.firstChild );
|
||||
// If blank line: split and insert default block
|
||||
if ( !shiftKey &&
|
||||
( node.data.charAt( offset - 1 ) === '\n' ||
|
||||
rangeDoesStartAtBlockBoundary( range, root ) ) &&
|
||||
( node.data.charAt( offset ) === '\n' ||
|
||||
rangeDoesEndAtBlockBoundary( range, root ) ) ) {
|
||||
node.deleteData( offset && offset - 1, offset ? 2 : 1 );
|
||||
nodeAfterSplit =
|
||||
split( node, offset && offset - 1, root, root );
|
||||
node = nodeAfterSplit.previousSibling;
|
||||
if ( !node.textContent ) {
|
||||
detach( node );
|
||||
}
|
||||
// If blank line: split and insert default block
|
||||
if ( !event.shiftKey &&
|
||||
( node.data.charAt( offset - 1 ) === '\n' ||
|
||||
rangeDoesStartAtBlockBoundary( range, root ) ) &&
|
||||
( node.data.charAt( offset ) === '\n' ||
|
||||
rangeDoesEndAtBlockBoundary( range, root ) ) ) {
|
||||
node.deleteData( offset && offset - 1, offset ? 2 : 1 );
|
||||
nodeAfterSplit =
|
||||
split( node, offset && offset - 1, root, root );
|
||||
node = nodeAfterSplit.previousSibling;
|
||||
if ( !node.textContent ) {
|
||||
detach( node );
|
||||
}
|
||||
node = self.createDefaultBlock();
|
||||
nodeAfterSplit.parentNode.insertBefore( node, nodeAfterSplit );
|
||||
if ( !nodeAfterSplit.textContent ) {
|
||||
detach( nodeAfterSplit );
|
||||
}
|
||||
range.setStart( node, 0 );
|
||||
node = self.createDefaultBlock();
|
||||
nodeAfterSplit.parentNode.insertBefore( node, nodeAfterSplit );
|
||||
if ( !nodeAfterSplit.textContent ) {
|
||||
detach( nodeAfterSplit );
|
||||
}
|
||||
range.setStart( node, 0 );
|
||||
} else {
|
||||
node.insertData( offset, '\n' );
|
||||
fixCursor( parent, root );
|
||||
// Firefox bug: if you set the selection in the text node after
|
||||
// the new line, it draws the cursor before the line break still
|
||||
// but if you set the selection to the equivalent position
|
||||
// in the parent, it works.
|
||||
if ( node.length === offset + 1 ) {
|
||||
range.setStartAfter( node );
|
||||
} else {
|
||||
node.insertData( offset, '\n' );
|
||||
fixCursor( parent, root );
|
||||
// Firefox bug: if you set the selection in the text node after
|
||||
// the new line, it draws the cursor before the line break still
|
||||
// but if you set the selection to the equivalent position
|
||||
// in the parent, it works.
|
||||
if ( node.length === offset + 1 ) {
|
||||
range.setStartAfter( node );
|
||||
} else {
|
||||
range.setStart( node, offset + 1 );
|
||||
}
|
||||
}
|
||||
range.collapse( true );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
self._docWasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || event.shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
// If inside an <a>, move focus out
|
||||
parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
||||
range.collapse( false );
|
||||
}
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
return;
|
||||
}
|
||||
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, root, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( isEmptyBlock( block ) ) {
|
||||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
return self.modifyBlocks( removeBlockQuote, range );
|
||||
range.setStart( node, offset + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
removeZWS( block );
|
||||
removeEmptyInlines( block );
|
||||
fixCursor( block, root );
|
||||
|
||||
// Focus cursor
|
||||
// If there's a <b>/<i> etc. at the beginning of the split
|
||||
// make sure we focus inside it.
|
||||
while ( nodeAfterSplit.nodeType === ELEMENT_NODE ) {
|
||||
var child = nodeAfterSplit.firstChild,
|
||||
next;
|
||||
|
||||
// Don't continue links over a block break; unlikely to be the
|
||||
// desired outcome.
|
||||
if ( nodeAfterSplit.nodeName === 'A' &&
|
||||
( !nodeAfterSplit.textContent ||
|
||||
nodeAfterSplit.textContent === ZWS ) ) {
|
||||
child = self._doc.createTextNode( '' );
|
||||
replaceWith( nodeAfterSplit, child );
|
||||
nodeAfterSplit = child;
|
||||
break;
|
||||
}
|
||||
|
||||
while ( child && child.nodeType === TEXT_NODE && !child.data ) {
|
||||
next = child.nextSibling;
|
||||
if ( !next || next.nodeName === 'BR' ) {
|
||||
break;
|
||||
}
|
||||
detach( child );
|
||||
child = next;
|
||||
}
|
||||
|
||||
// 'BR's essentially don't count; they're a browser hack.
|
||||
// If you try to select the contents of a 'BR', FF will not let
|
||||
// you type anything!
|
||||
if ( !child || child.nodeName === 'BR' ||
|
||||
( child.nodeType === TEXT_NODE && !isPresto ) ) {
|
||||
break;
|
||||
}
|
||||
nodeAfterSplit = child;
|
||||
}
|
||||
range = self.createRange( nodeAfterSplit, 0 );
|
||||
range.collapse( true );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
self._docWasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
// If inside an <a>, move focus out
|
||||
parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
||||
range.collapse( false );
|
||||
}
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
return;
|
||||
}
|
||||
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, root, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( isEmptyBlock( block ) ) {
|
||||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
return self.modifyBlocks( removeBlockQuote, range );
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
removeZWS( block );
|
||||
removeEmptyInlines( block );
|
||||
fixCursor( block, root );
|
||||
|
||||
// Focus cursor
|
||||
// If there's a <b>/<i> etc. at the beginning of the split
|
||||
// make sure we focus inside it.
|
||||
while ( nodeAfterSplit.nodeType === ELEMENT_NODE ) {
|
||||
var child = nodeAfterSplit.firstChild,
|
||||
next;
|
||||
|
||||
// Don't continue links over a block break; unlikely to be the
|
||||
// desired outcome.
|
||||
if ( nodeAfterSplit.nodeName === 'A' &&
|
||||
( !nodeAfterSplit.textContent ||
|
||||
nodeAfterSplit.textContent === ZWS ) ) {
|
||||
child = self._doc.createTextNode( '' );
|
||||
replaceWith( nodeAfterSplit, child );
|
||||
nodeAfterSplit = child;
|
||||
break;
|
||||
}
|
||||
|
||||
while ( child && child.nodeType === TEXT_NODE && !child.data ) {
|
||||
next = child.nextSibling;
|
||||
if ( !next || next.nodeName === 'BR' ) {
|
||||
break;
|
||||
}
|
||||
detach( child );
|
||||
child = next;
|
||||
}
|
||||
|
||||
// 'BR's essentially don't count; they're a browser hack.
|
||||
// If you try to select the contents of a 'BR', FF will not let
|
||||
// you type anything!
|
||||
if ( !child || child.nodeName === 'BR' ||
|
||||
( child.nodeType === TEXT_NODE && !isPresto ) ) {
|
||||
break;
|
||||
}
|
||||
nodeAfterSplit = child;
|
||||
}
|
||||
range = self.createRange( nodeAfterSplit, 0 );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
};
|
||||
|
||||
var keyHandlers = {
|
||||
// This song and dance is to force iOS to do enable the shift key
|
||||
// automatically on enter. When you do the DOM split manipulation yourself,
|
||||
// WebKit doesn't reset the IME state and so presents auto-complete options
|
||||
// as though you were continuing to type on the previous line, and doesn't
|
||||
// auto-enable the shift key. The old trick of blurring and focussing
|
||||
// again no longer works in iOS 13, and I tried various execCommand options
|
||||
// but they didn't seem to do anything. The only solution I've found is to
|
||||
// let iOS handle the enter key, then after it's done that reset the HTML
|
||||
// to what it was before and handle it properly in Squire; the IME state of
|
||||
// course doesn't reset so you end up in the correct state!
|
||||
enter: isIOS ? function ( self, event, range ) {
|
||||
self._saveRangeToBookmark( range );
|
||||
var html = self._getHTML();
|
||||
var restoreAndDoEnter = function () {
|
||||
self.removeEventListener( 'keyup', restoreAndDoEnter );
|
||||
self._setHTML( html );
|
||||
range = self._getRangeAndRemoveBookmark();
|
||||
// Ignore the shift key on iOS, as this is for auto-capitalisation.
|
||||
handleEnter( self, false, range );
|
||||
};
|
||||
self.addEventListener( 'keyup', restoreAndDoEnter );
|
||||
} : function ( self, event, range ) {
|
||||
event.preventDefault();
|
||||
handleEnter( self, event.shiftKey, range );
|
||||
},
|
||||
|
||||
'shift-enter': function ( self, event, range ) {
|
||||
|
@ -2254,9 +2277,7 @@ var onCut = function ( event ) {
|
|||
this.saveUndoState( range );
|
||||
|
||||
// Edge only seems to support setting plain text as of 2016-03-11.
|
||||
// Mobile Safari flat out doesn't work:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=143776
|
||||
if ( !isEdge && !isIOS && clipboardData ) {
|
||||
if ( !isEdge && clipboardData ) {
|
||||
// Clipboard content should include all parents within block, or all
|
||||
// parents up to root if selection across blocks
|
||||
startBlock = getStartBlockOfRange( range, root );
|
||||
|
@ -2301,9 +2322,7 @@ var onCopy = function ( event ) {
|
|||
var startBlock, endBlock, copyRoot, contents, parent, newContents, node;
|
||||
|
||||
// Edge only seems to support setting plain text as of 2016-03-11.
|
||||
// Mobile Safari flat out doesn't work:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=143776
|
||||
if ( !isEdge && !isIOS && clipboardData ) {
|
||||
if ( !isEdge && clipboardData ) {
|
||||
// Clipboard content should include all parents within block, or all
|
||||
// parents up to root if selection across blocks
|
||||
startBlock = getStartBlockOfRange( range, root );
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -145,163 +145,184 @@ var afterDelete = function ( self, range ) {
|
|||
}
|
||||
};
|
||||
|
||||
var keyHandlers = {
|
||||
enter: function ( self, event, range ) {
|
||||
var root = self._root;
|
||||
// Ignore the shift key on iOS, as this is for auto-capitalisation.
|
||||
var shiftKey = !isIOS && event.shiftKey;
|
||||
var block, parent, node, offset, nodeAfterSplit;
|
||||
var handleEnter = function ( self, shiftKey, range ) {
|
||||
var root = self._root;
|
||||
var block, parent, node, offset, nodeAfterSplit;
|
||||
|
||||
// We handle this ourselves
|
||||
event.preventDefault();
|
||||
// Save undo checkpoint and add any links in the preceding section.
|
||||
// Remove any zws so we don't think there's content in an empty
|
||||
// block.
|
||||
self._recordUndoState( range );
|
||||
addLinks( range.startContainer, root, self );
|
||||
self._removeZWS();
|
||||
self._getRangeAndRemoveBookmark( range );
|
||||
|
||||
// Save undo checkpoint and add any links in the preceding section.
|
||||
// Remove any zws so we don't think there's content in an empty
|
||||
// block.
|
||||
self._recordUndoState( range );
|
||||
addLinks( range.startContainer, root, self );
|
||||
self._removeZWS();
|
||||
self._getRangeAndRemoveBookmark( range );
|
||||
// Selected text is overwritten, therefore delete the contents
|
||||
// to collapse selection.
|
||||
if ( !range.collapsed ) {
|
||||
deleteContentsOfRange( range, root );
|
||||
}
|
||||
|
||||
// Selected text is overwritten, therefore delete the contents
|
||||
// to collapse selection.
|
||||
if ( !range.collapsed ) {
|
||||
deleteContentsOfRange( range, root );
|
||||
block = getStartBlockOfRange( range, root );
|
||||
|
||||
// Inside a PRE, insert literal newline, unless on blank line.
|
||||
if ( block && ( parent = getNearest( block, root, 'PRE' ) ) ) {
|
||||
moveRangeBoundariesDownTree( range );
|
||||
node = range.startContainer;
|
||||
offset = range.startOffset;
|
||||
if ( node.nodeType !== TEXT_NODE ) {
|
||||
node = self._doc.createTextNode( '' );
|
||||
parent.insertBefore( node, parent.firstChild );
|
||||
}
|
||||
|
||||
block = getStartBlockOfRange( range, root );
|
||||
|
||||
// Inside a PRE, insert literal newline, unless on blank line.
|
||||
if ( block && ( parent = getNearest( block, root, 'PRE' ) ) ) {
|
||||
moveRangeBoundariesDownTree( range );
|
||||
node = range.startContainer;
|
||||
offset = range.startOffset;
|
||||
if ( node.nodeType !== TEXT_NODE ) {
|
||||
node = self._doc.createTextNode( '' );
|
||||
parent.insertBefore( node, parent.firstChild );
|
||||
// If blank line: split and insert default block
|
||||
if ( !shiftKey &&
|
||||
( node.data.charAt( offset - 1 ) === '\n' ||
|
||||
rangeDoesStartAtBlockBoundary( range, root ) ) &&
|
||||
( node.data.charAt( offset ) === '\n' ||
|
||||
rangeDoesEndAtBlockBoundary( range, root ) ) ) {
|
||||
node.deleteData( offset && offset - 1, offset ? 2 : 1 );
|
||||
nodeAfterSplit =
|
||||
split( node, offset && offset - 1, root, root );
|
||||
node = nodeAfterSplit.previousSibling;
|
||||
if ( !node.textContent ) {
|
||||
detach( node );
|
||||
}
|
||||
// If blank line: split and insert default block
|
||||
if ( !shiftKey &&
|
||||
( node.data.charAt( offset - 1 ) === '\n' ||
|
||||
rangeDoesStartAtBlockBoundary( range, root ) ) &&
|
||||
( node.data.charAt( offset ) === '\n' ||
|
||||
rangeDoesEndAtBlockBoundary( range, root ) ) ) {
|
||||
node.deleteData( offset && offset - 1, offset ? 2 : 1 );
|
||||
nodeAfterSplit =
|
||||
split( node, offset && offset - 1, root, root );
|
||||
node = nodeAfterSplit.previousSibling;
|
||||
if ( !node.textContent ) {
|
||||
detach( node );
|
||||
}
|
||||
node = self.createDefaultBlock();
|
||||
nodeAfterSplit.parentNode.insertBefore( node, nodeAfterSplit );
|
||||
if ( !nodeAfterSplit.textContent ) {
|
||||
detach( nodeAfterSplit );
|
||||
}
|
||||
range.setStart( node, 0 );
|
||||
node = self.createDefaultBlock();
|
||||
nodeAfterSplit.parentNode.insertBefore( node, nodeAfterSplit );
|
||||
if ( !nodeAfterSplit.textContent ) {
|
||||
detach( nodeAfterSplit );
|
||||
}
|
||||
range.setStart( node, 0 );
|
||||
} else {
|
||||
node.insertData( offset, '\n' );
|
||||
fixCursor( parent, root );
|
||||
// Firefox bug: if you set the selection in the text node after
|
||||
// the new line, it draws the cursor before the line break still
|
||||
// but if you set the selection to the equivalent position
|
||||
// in the parent, it works.
|
||||
if ( node.length === offset + 1 ) {
|
||||
range.setStartAfter( node );
|
||||
} else {
|
||||
node.insertData( offset, '\n' );
|
||||
fixCursor( parent, root );
|
||||
// Firefox bug: if you set the selection in the text node after
|
||||
// the new line, it draws the cursor before the line break still
|
||||
// but if you set the selection to the equivalent position
|
||||
// in the parent, it works.
|
||||
if ( node.length === offset + 1 ) {
|
||||
range.setStartAfter( node );
|
||||
} else {
|
||||
range.setStart( node, offset + 1 );
|
||||
}
|
||||
}
|
||||
range.collapse( true );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
self._docWasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
// If inside an <a>, move focus out
|
||||
parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
||||
range.collapse( false );
|
||||
}
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
return;
|
||||
}
|
||||
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, root, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( isEmptyBlock( block ) ) {
|
||||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
return self.modifyBlocks( removeBlockQuote, range );
|
||||
range.setStart( node, offset + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
removeZWS( block );
|
||||
removeEmptyInlines( block );
|
||||
fixCursor( block, root );
|
||||
|
||||
// Focus cursor
|
||||
// If there's a <b>/<i> etc. at the beginning of the split
|
||||
// make sure we focus inside it.
|
||||
while ( nodeAfterSplit.nodeType === ELEMENT_NODE ) {
|
||||
var child = nodeAfterSplit.firstChild,
|
||||
next;
|
||||
|
||||
// Don't continue links over a block break; unlikely to be the
|
||||
// desired outcome.
|
||||
if ( nodeAfterSplit.nodeName === 'A' &&
|
||||
( !nodeAfterSplit.textContent ||
|
||||
nodeAfterSplit.textContent === ZWS ) ) {
|
||||
child = self._doc.createTextNode( '' );
|
||||
replaceWith( nodeAfterSplit, child );
|
||||
nodeAfterSplit = child;
|
||||
break;
|
||||
}
|
||||
|
||||
while ( child && child.nodeType === TEXT_NODE && !child.data ) {
|
||||
next = child.nextSibling;
|
||||
if ( !next || next.nodeName === 'BR' ) {
|
||||
break;
|
||||
}
|
||||
detach( child );
|
||||
child = next;
|
||||
}
|
||||
|
||||
// 'BR's essentially don't count; they're a browser hack.
|
||||
// If you try to select the contents of a 'BR', FF will not let
|
||||
// you type anything!
|
||||
if ( !child || child.nodeName === 'BR' ||
|
||||
( child.nodeType === TEXT_NODE && !isPresto ) ) {
|
||||
break;
|
||||
}
|
||||
nodeAfterSplit = child;
|
||||
}
|
||||
range = self.createRange( nodeAfterSplit, 0 );
|
||||
range.collapse( true );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
self._docWasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
// If this is a malformed bit of document or in a table;
|
||||
// just play it safe and insert a <br>.
|
||||
if ( !block || shiftKey || /^T[HD]$/.test( block.nodeName ) ) {
|
||||
// If inside an <a>, move focus out
|
||||
parent = getNearest( range.endContainer, root, 'A' );
|
||||
if ( parent ) {
|
||||
parent = parent.parentNode;
|
||||
moveRangeBoundariesUpTree( range, parent, parent, root );
|
||||
range.collapse( false );
|
||||
}
|
||||
insertNodeInRange( range, self.createElement( 'BR' ) );
|
||||
range.collapse( false );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
return;
|
||||
}
|
||||
|
||||
// If in a list, we'll split the LI instead.
|
||||
if ( parent = getNearest( block, root, 'LI' ) ) {
|
||||
block = parent;
|
||||
}
|
||||
|
||||
if ( isEmptyBlock( block ) ) {
|
||||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
return self.modifyBlocks( removeBlockQuote, range );
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, split at cursor point.
|
||||
nodeAfterSplit = splitBlock( self, block,
|
||||
range.startContainer, range.startOffset );
|
||||
|
||||
// Clean up any empty inlines if we hit enter at the beginning of the
|
||||
// block
|
||||
removeZWS( block );
|
||||
removeEmptyInlines( block );
|
||||
fixCursor( block, root );
|
||||
|
||||
// Focus cursor
|
||||
// If there's a <b>/<i> etc. at the beginning of the split
|
||||
// make sure we focus inside it.
|
||||
while ( nodeAfterSplit.nodeType === ELEMENT_NODE ) {
|
||||
var child = nodeAfterSplit.firstChild,
|
||||
next;
|
||||
|
||||
// Don't continue links over a block break; unlikely to be the
|
||||
// desired outcome.
|
||||
if ( nodeAfterSplit.nodeName === 'A' &&
|
||||
( !nodeAfterSplit.textContent ||
|
||||
nodeAfterSplit.textContent === ZWS ) ) {
|
||||
child = self._doc.createTextNode( '' );
|
||||
replaceWith( nodeAfterSplit, child );
|
||||
nodeAfterSplit = child;
|
||||
break;
|
||||
}
|
||||
|
||||
while ( child && child.nodeType === TEXT_NODE && !child.data ) {
|
||||
next = child.nextSibling;
|
||||
if ( !next || next.nodeName === 'BR' ) {
|
||||
break;
|
||||
}
|
||||
detach( child );
|
||||
child = next;
|
||||
}
|
||||
|
||||
// 'BR's essentially don't count; they're a browser hack.
|
||||
// If you try to select the contents of a 'BR', FF will not let
|
||||
// you type anything!
|
||||
if ( !child || child.nodeName === 'BR' ||
|
||||
( child.nodeType === TEXT_NODE && !isPresto ) ) {
|
||||
break;
|
||||
}
|
||||
nodeAfterSplit = child;
|
||||
}
|
||||
range = self.createRange( nodeAfterSplit, 0 );
|
||||
self.setSelection( range );
|
||||
self._updatePath( range, true );
|
||||
};
|
||||
|
||||
var keyHandlers = {
|
||||
// This song and dance is to force iOS to do enable the shift key
|
||||
// automatically on enter. When you do the DOM split manipulation yourself,
|
||||
// WebKit doesn't reset the IME state and so presents auto-complete options
|
||||
// as though you were continuing to type on the previous line, and doesn't
|
||||
// auto-enable the shift key. The old trick of blurring and focussing
|
||||
// again no longer works in iOS 13, and I tried various execCommand options
|
||||
// but they didn't seem to do anything. The only solution I've found is to
|
||||
// let iOS handle the enter key, then after it's done that reset the HTML
|
||||
// to what it was before and handle it properly in Squire; the IME state of
|
||||
// course doesn't reset so you end up in the correct state!
|
||||
enter: isIOS ? function ( self, event, range ) {
|
||||
self._saveRangeToBookmark( range );
|
||||
var html = self._getHTML();
|
||||
var restoreAndDoEnter = function () {
|
||||
self.removeEventListener( 'keyup', restoreAndDoEnter );
|
||||
self._setHTML( html );
|
||||
range = self._getRangeAndRemoveBookmark();
|
||||
// Ignore the shift key on iOS, as this is for auto-capitalisation.
|
||||
handleEnter( self, false, range );
|
||||
};
|
||||
self.addEventListener( 'keyup', restoreAndDoEnter );
|
||||
} : function ( self, event, range ) {
|
||||
event.preventDefault();
|
||||
handleEnter( self, event.shiftKey, range );
|
||||
},
|
||||
|
||||
'shift-enter': function ( self, event, range ) {
|
||||
|
|
Loading…
Reference in a new issue