mirror of
https://github.com/fastmail/Squire.git
synced 2025-01-03 05:00:13 -05:00
parent
6842cb94eb
commit
833d7dfdbd
4 changed files with 298 additions and 148 deletions
|
@ -1451,7 +1451,7 @@ var keyHandlers = {
|
|||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.modifyBlocks( decreaseListLevel, range );
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
|
@ -1558,7 +1558,7 @@ var keyHandlers = {
|
|||
// Break list
|
||||
if ( getNearest( current, root, 'UL' ) ||
|
||||
getNearest( current, root, 'OL' ) ) {
|
||||
return self.modifyBlocks( decreaseListLevel, range );
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( current, root, 'BLOCKQUOTE' ) ) {
|
||||
|
@ -1653,12 +1653,12 @@ var keyHandlers = {
|
|||
if ( range.collapsed && rangeDoesStartAtBlockBoundary( range, root ) ) {
|
||||
node = getStartBlockOfRange( range, root );
|
||||
// Iterate through the block's parents
|
||||
while ( parent = node.parentNode ) {
|
||||
while ( ( parent = node.parentNode ) ) {
|
||||
// If we find a UL or OL (so are in a list, node must be an LI)
|
||||
if ( parent.nodeName === 'UL' || parent.nodeName === 'OL' ) {
|
||||
// Then increase the list level
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( increaseListLevel, range );
|
||||
self.increaseListLevel( range );
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
|
@ -1676,7 +1676,7 @@ var keyHandlers = {
|
|||
if ( getNearest( node, root, 'UL' ) ||
|
||||
getNearest( node, root, 'OL' ) ) {
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( decreaseListLevel, range );
|
||||
self.decreaseListLevel( range );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -3888,77 +3888,155 @@ var removeList = function ( frag ) {
|
|||
return frag;
|
||||
};
|
||||
|
||||
var increaseListLevel = function ( frag ) {
|
||||
var items = frag.querySelectorAll( 'LI' ),
|
||||
i, l, item,
|
||||
type, newParent,
|
||||
tagAttributes = this._config.tagAttributes,
|
||||
listAttrs;
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
if ( !isContainer( item.firstChild ) ) {
|
||||
// type => 'UL' or 'OL'
|
||||
type = item.parentNode.nodeName;
|
||||
newParent = item.previousSibling;
|
||||
if ( !newParent || !( newParent = newParent.lastChild ) ||
|
||||
newParent.nodeName !== type ) {
|
||||
listAttrs = tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
|
||||
replaceWith(
|
||||
item,
|
||||
newParent
|
||||
);
|
||||
var getListSelection = function ( range, root ) {
|
||||
// Get start+end li in single common ancestor
|
||||
var list = range.commonAncestorContainer;
|
||||
var startLi = range.startContainer;
|
||||
var endLi = range.endContainer;
|
||||
while ( list && list !== root && !/^[OU]L$/.test( list.nodeName ) ) {
|
||||
list = list.parentNode;
|
||||
}
|
||||
newParent.appendChild( item );
|
||||
if ( !list || list === root ) {
|
||||
return null;
|
||||
}
|
||||
if ( startLi === list ) {
|
||||
startLi = startLi.childNodes[ range.startOffset ];
|
||||
}
|
||||
return frag;
|
||||
if ( endLi === list ) {
|
||||
endLi = endLi.childNodes[ range.endOffset ];
|
||||
}
|
||||
while ( startLi && startLi.parentNode !== list ) {
|
||||
startLi = startLi.parentNode;
|
||||
}
|
||||
while ( endLi && endLi.parentNode !== list ) {
|
||||
endLi = endLi.parentNode;
|
||||
}
|
||||
return [ list, startLi, endLi ];
|
||||
};
|
||||
|
||||
var decreaseListLevel = function ( frag ) {
|
||||
var root = this._root;
|
||||
var items = frag.querySelectorAll( 'LI' );
|
||||
Array.prototype.filter.call( items, function ( el ) {
|
||||
return !isContainer( el.firstChild );
|
||||
}).forEach( function ( item ) {
|
||||
var parent = item.parentNode,
|
||||
newParent = parent.parentNode,
|
||||
first = item.firstChild,
|
||||
node = first,
|
||||
next;
|
||||
if ( item.previousSibling ) {
|
||||
parent = split( parent, item, newParent, root );
|
||||
proto.increaseListLevel = function ( range ) {
|
||||
if ( !range && !( range = this.getSelection() ) ) {
|
||||
return this.focus();
|
||||
}
|
||||
|
||||
// if the new parent is another list then we simply move the node
|
||||
// e.g. `ul > ul > li` becomes `ul > li`
|
||||
if ( /^[OU]L$/.test( newParent.nodeName ) ) {
|
||||
newParent.insertBefore( item, parent );
|
||||
if ( !parent.firstChild ) {
|
||||
newParent.removeChild( parent );
|
||||
var listSelection = getListSelection( range, root );
|
||||
if ( !listSelection ) {
|
||||
return this.focus();
|
||||
}
|
||||
} else {
|
||||
while ( node ) {
|
||||
next = node.nextSibling;
|
||||
if ( isContainer( node ) ) {
|
||||
break;
|
||||
|
||||
var list = listSelection[0];
|
||||
var startLi = listSelection[1];
|
||||
var endLi = listSelection[2];
|
||||
if ( !startLi || startLi === list.firstChild ) {
|
||||
return this.focus();
|
||||
}
|
||||
newParent.insertBefore( node, parent );
|
||||
node = next;
|
||||
|
||||
// Save undo checkpoint and bookmark selection
|
||||
this._recordUndoState( range, this._isInUndoState );
|
||||
|
||||
// Increase list depth
|
||||
var type = list.nodeName;
|
||||
var newParent = startLi.previousSibling;
|
||||
var listAttrs, next;
|
||||
if ( newParent.nodeName !== type ) {
|
||||
listAttrs = this._config.tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
list.insertBefore( newParent, startLi );
|
||||
}
|
||||
do {
|
||||
next = startLi === endLi ? null : startLi.nextSibling;
|
||||
newParent.appendChild( startLi );
|
||||
} while ( ( startLi = next ) );
|
||||
next = newParent.nextSibling;
|
||||
if ( next ) {
|
||||
mergeContainers( next, this._root );
|
||||
}
|
||||
if ( newParent.nodeName === 'LI' && first.previousSibling ) {
|
||||
split( newParent, first, newParent.parentNode, root );
|
||||
|
||||
// Restore selection
|
||||
this._getRangeAndRemoveBookmark( range );
|
||||
this.setSelection( range );
|
||||
this._updatePath( range, true );
|
||||
|
||||
// We're not still in an undo state
|
||||
if ( !canObserveMutations ) {
|
||||
this._docWasChanged();
|
||||
}
|
||||
while ( item !== frag && !item.childNodes.length ) {
|
||||
parent = item.parentNode;
|
||||
parent.removeChild( item );
|
||||
item = parent;
|
||||
|
||||
return this.focus();
|
||||
};
|
||||
|
||||
proto.decreaseListLevel = function ( range ) {
|
||||
if ( !range && !( range = this.getSelection() ) ) {
|
||||
return this.focus();
|
||||
}
|
||||
}, this );
|
||||
fixContainer( frag, root );
|
||||
return frag;
|
||||
|
||||
var root = this._root;
|
||||
var listSelection = getListSelection( range, root );
|
||||
if ( !listSelection ) {
|
||||
return this.focus();
|
||||
}
|
||||
|
||||
var list = listSelection[0];
|
||||
var startLi = listSelection[1];
|
||||
var endLi = listSelection[2];
|
||||
if ( !startLi ) {
|
||||
startLi = list.firstChild;
|
||||
}
|
||||
if ( !endLi ) {
|
||||
endLi = list.lastChild;
|
||||
}
|
||||
|
||||
// Save undo checkpoint and bookmark selection
|
||||
this._recordUndoState( range, this._isInUndoState );
|
||||
|
||||
// Find the new parent list node
|
||||
var newParent = list.parentNode;
|
||||
var next;
|
||||
|
||||
// Split list if necesary
|
||||
var insertBefore = !endLi.nextSibling ?
|
||||
list.nextSibling :
|
||||
split( list, endLi.nextSibling, newParent, root );
|
||||
|
||||
if ( newParent !== root && newParent.nodeName === 'LI' ) {
|
||||
newParent = newParent.parentNode;
|
||||
while ( insertBefore ) {
|
||||
next = insertBefore.nextSibling;
|
||||
endLi.appendChild( insertBefore );
|
||||
insertBefore = next;
|
||||
}
|
||||
insertBefore = list.parentNode.nextSibling;
|
||||
}
|
||||
|
||||
var makeNotList = !/^[OU]L$/.test( newParent.nodeName );
|
||||
do {
|
||||
next = startLi === endLi ? null : startLi.nextSibling;
|
||||
list.removeChild( startLi );
|
||||
if ( makeNotList && startLi.nodeName === 'LI' ) {
|
||||
startLi = this.createDefaultBlock([ empty( startLi ) ]);
|
||||
}
|
||||
newParent.insertBefore( startLi, insertBefore );
|
||||
} while ( ( startLi = next ) );
|
||||
|
||||
if ( !list.firstChild ) {
|
||||
detach( list );
|
||||
}
|
||||
|
||||
if ( insertBefore ) {
|
||||
mergeContainers( insertBefore, root );
|
||||
}
|
||||
|
||||
// Restore selection
|
||||
this._getRangeAndRemoveBookmark( range );
|
||||
this.setSelection( range );
|
||||
this._updatePath( range, true );
|
||||
|
||||
// We're not still in an undo state
|
||||
if ( !canObserveMutations ) {
|
||||
this._docWasChanged();
|
||||
}
|
||||
|
||||
return this.focus();
|
||||
};
|
||||
|
||||
proto._ensureBottomLine = function () {
|
||||
|
@ -4554,9 +4632,6 @@ proto.makeUnorderedList = command( 'modifyBlocks', makeUnorderedList );
|
|||
proto.makeOrderedList = command( 'modifyBlocks', makeOrderedList );
|
||||
proto.removeList = command( 'modifyBlocks', removeList );
|
||||
|
||||
proto.increaseListLevel = command( 'modifyBlocks', increaseListLevel );
|
||||
proto.decreaseListLevel = command( 'modifyBlocks', decreaseListLevel );
|
||||
|
||||
// Node.js exports
|
||||
Squire.isInline = isInline;
|
||||
Squire.isBlock = isBlock;
|
||||
|
|
File diff suppressed because one or more lines are too long
197
source/Editor.js
197
source/Editor.js
|
@ -1454,77 +1454,155 @@ var removeList = function ( frag ) {
|
|||
return frag;
|
||||
};
|
||||
|
||||
var increaseListLevel = function ( frag ) {
|
||||
var items = frag.querySelectorAll( 'LI' ),
|
||||
i, l, item,
|
||||
type, newParent,
|
||||
tagAttributes = this._config.tagAttributes,
|
||||
listAttrs;
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
if ( !isContainer( item.firstChild ) ) {
|
||||
// type => 'UL' or 'OL'
|
||||
type = item.parentNode.nodeName;
|
||||
newParent = item.previousSibling;
|
||||
if ( !newParent || !( newParent = newParent.lastChild ) ||
|
||||
newParent.nodeName !== type ) {
|
||||
listAttrs = tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
|
||||
replaceWith(
|
||||
item,
|
||||
newParent
|
||||
);
|
||||
var getListSelection = function ( range, root ) {
|
||||
// Get start+end li in single common ancestor
|
||||
var list = range.commonAncestorContainer;
|
||||
var startLi = range.startContainer;
|
||||
var endLi = range.endContainer;
|
||||
while ( list && list !== root && !/^[OU]L$/.test( list.nodeName ) ) {
|
||||
list = list.parentNode;
|
||||
}
|
||||
newParent.appendChild( item );
|
||||
if ( !list || list === root ) {
|
||||
return null;
|
||||
}
|
||||
if ( startLi === list ) {
|
||||
startLi = startLi.childNodes[ range.startOffset ];
|
||||
}
|
||||
return frag;
|
||||
if ( endLi === list ) {
|
||||
endLi = endLi.childNodes[ range.endOffset ];
|
||||
}
|
||||
while ( startLi && startLi.parentNode !== list ) {
|
||||
startLi = startLi.parentNode;
|
||||
}
|
||||
while ( endLi && endLi.parentNode !== list ) {
|
||||
endLi = endLi.parentNode;
|
||||
}
|
||||
return [ list, startLi, endLi ];
|
||||
};
|
||||
|
||||
var decreaseListLevel = function ( frag ) {
|
||||
var root = this._root;
|
||||
var items = frag.querySelectorAll( 'LI' );
|
||||
Array.prototype.filter.call( items, function ( el ) {
|
||||
return !isContainer( el.firstChild );
|
||||
}).forEach( function ( item ) {
|
||||
var parent = item.parentNode,
|
||||
newParent = parent.parentNode,
|
||||
first = item.firstChild,
|
||||
node = first,
|
||||
next;
|
||||
if ( item.previousSibling ) {
|
||||
parent = split( parent, item, newParent, root );
|
||||
proto.increaseListLevel = function ( range ) {
|
||||
if ( !range && !( range = this.getSelection() ) ) {
|
||||
return this.focus();
|
||||
}
|
||||
|
||||
// if the new parent is another list then we simply move the node
|
||||
// e.g. `ul > ul > li` becomes `ul > li`
|
||||
if ( /^[OU]L$/.test( newParent.nodeName ) ) {
|
||||
newParent.insertBefore( item, parent );
|
||||
if ( !parent.firstChild ) {
|
||||
newParent.removeChild( parent );
|
||||
var listSelection = getListSelection( range, root );
|
||||
if ( !listSelection ) {
|
||||
return this.focus();
|
||||
}
|
||||
} else {
|
||||
while ( node ) {
|
||||
next = node.nextSibling;
|
||||
if ( isContainer( node ) ) {
|
||||
break;
|
||||
|
||||
var list = listSelection[0];
|
||||
var startLi = listSelection[1];
|
||||
var endLi = listSelection[2];
|
||||
if ( !startLi || startLi === list.firstChild ) {
|
||||
return this.focus();
|
||||
}
|
||||
newParent.insertBefore( node, parent );
|
||||
node = next;
|
||||
|
||||
// Save undo checkpoint and bookmark selection
|
||||
this._recordUndoState( range, this._isInUndoState );
|
||||
|
||||
// Increase list depth
|
||||
var type = list.nodeName;
|
||||
var newParent = startLi.previousSibling;
|
||||
var listAttrs, next;
|
||||
if ( newParent.nodeName !== type ) {
|
||||
listAttrs = this._config.tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
list.insertBefore( newParent, startLi );
|
||||
}
|
||||
do {
|
||||
next = startLi === endLi ? null : startLi.nextSibling;
|
||||
newParent.appendChild( startLi );
|
||||
} while ( ( startLi = next ) );
|
||||
next = newParent.nextSibling;
|
||||
if ( next ) {
|
||||
mergeContainers( next, this._root );
|
||||
}
|
||||
if ( newParent.nodeName === 'LI' && first.previousSibling ) {
|
||||
split( newParent, first, newParent.parentNode, root );
|
||||
|
||||
// Restore selection
|
||||
this._getRangeAndRemoveBookmark( range );
|
||||
this.setSelection( range );
|
||||
this._updatePath( range, true );
|
||||
|
||||
// We're not still in an undo state
|
||||
if ( !canObserveMutations ) {
|
||||
this._docWasChanged();
|
||||
}
|
||||
while ( item !== frag && !item.childNodes.length ) {
|
||||
parent = item.parentNode;
|
||||
parent.removeChild( item );
|
||||
item = parent;
|
||||
|
||||
return this.focus();
|
||||
};
|
||||
|
||||
proto.decreaseListLevel = function ( range ) {
|
||||
if ( !range && !( range = this.getSelection() ) ) {
|
||||
return this.focus();
|
||||
}
|
||||
}, this );
|
||||
fixContainer( frag, root );
|
||||
return frag;
|
||||
|
||||
var root = this._root;
|
||||
var listSelection = getListSelection( range, root );
|
||||
if ( !listSelection ) {
|
||||
return this.focus();
|
||||
}
|
||||
|
||||
var list = listSelection[0];
|
||||
var startLi = listSelection[1];
|
||||
var endLi = listSelection[2];
|
||||
if ( !startLi ) {
|
||||
startLi = list.firstChild;
|
||||
}
|
||||
if ( !endLi ) {
|
||||
endLi = list.lastChild;
|
||||
}
|
||||
|
||||
// Save undo checkpoint and bookmark selection
|
||||
this._recordUndoState( range, this._isInUndoState );
|
||||
|
||||
// Find the new parent list node
|
||||
var newParent = list.parentNode;
|
||||
var next;
|
||||
|
||||
// Split list if necesary
|
||||
var insertBefore = !endLi.nextSibling ?
|
||||
list.nextSibling :
|
||||
split( list, endLi.nextSibling, newParent, root );
|
||||
|
||||
if ( newParent !== root && newParent.nodeName === 'LI' ) {
|
||||
newParent = newParent.parentNode;
|
||||
while ( insertBefore ) {
|
||||
next = insertBefore.nextSibling;
|
||||
endLi.appendChild( insertBefore );
|
||||
insertBefore = next;
|
||||
}
|
||||
insertBefore = list.parentNode.nextSibling;
|
||||
}
|
||||
|
||||
var makeNotList = !/^[OU]L$/.test( newParent.nodeName );
|
||||
do {
|
||||
next = startLi === endLi ? null : startLi.nextSibling;
|
||||
list.removeChild( startLi );
|
||||
if ( makeNotList && startLi.nodeName === 'LI' ) {
|
||||
startLi = this.createDefaultBlock([ empty( startLi ) ]);
|
||||
}
|
||||
newParent.insertBefore( startLi, insertBefore );
|
||||
} while ( ( startLi = next ) );
|
||||
|
||||
if ( !list.firstChild ) {
|
||||
detach( list );
|
||||
}
|
||||
|
||||
if ( insertBefore ) {
|
||||
mergeContainers( insertBefore, root );
|
||||
}
|
||||
|
||||
// Restore selection
|
||||
this._getRangeAndRemoveBookmark( range );
|
||||
this.setSelection( range );
|
||||
this._updatePath( range, true );
|
||||
|
||||
// We're not still in an undo state
|
||||
if ( !canObserveMutations ) {
|
||||
this._docWasChanged();
|
||||
}
|
||||
|
||||
return this.focus();
|
||||
};
|
||||
|
||||
proto._ensureBottomLine = function () {
|
||||
|
@ -2119,6 +2197,3 @@ proto.decreaseQuoteLevel = command( 'modifyBlocks', decreaseBlockQuoteLevel );
|
|||
proto.makeUnorderedList = command( 'modifyBlocks', makeUnorderedList );
|
||||
proto.makeOrderedList = command( 'modifyBlocks', makeOrderedList );
|
||||
proto.removeList = command( 'modifyBlocks', removeList );
|
||||
|
||||
proto.increaseListLevel = command( 'modifyBlocks', increaseListLevel );
|
||||
proto.decreaseListLevel = command( 'modifyBlocks', decreaseListLevel );
|
||||
|
|
|
@ -192,7 +192,7 @@ var keyHandlers = {
|
|||
// Break list
|
||||
if ( getNearest( block, root, 'UL' ) ||
|
||||
getNearest( block, root, 'OL' ) ) {
|
||||
return self.modifyBlocks( decreaseListLevel, range );
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( block, root, 'BLOCKQUOTE' ) ) {
|
||||
|
@ -299,7 +299,7 @@ var keyHandlers = {
|
|||
// Break list
|
||||
if ( getNearest( current, root, 'UL' ) ||
|
||||
getNearest( current, root, 'OL' ) ) {
|
||||
return self.modifyBlocks( decreaseListLevel, range );
|
||||
return self.decreaseListLevel( range );
|
||||
}
|
||||
// Break blockquote
|
||||
else if ( getNearest( current, root, 'BLOCKQUOTE' ) ) {
|
||||
|
@ -394,12 +394,12 @@ var keyHandlers = {
|
|||
if ( range.collapsed && rangeDoesStartAtBlockBoundary( range, root ) ) {
|
||||
node = getStartBlockOfRange( range, root );
|
||||
// Iterate through the block's parents
|
||||
while ( parent = node.parentNode ) {
|
||||
while ( ( parent = node.parentNode ) ) {
|
||||
// If we find a UL or OL (so are in a list, node must be an LI)
|
||||
if ( parent.nodeName === 'UL' || parent.nodeName === 'OL' ) {
|
||||
// Then increase the list level
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( increaseListLevel, range );
|
||||
self.increaseListLevel( range );
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
|
@ -417,7 +417,7 @@ var keyHandlers = {
|
|||
if ( getNearest( node, root, 'UL' ) ||
|
||||
getNearest( node, root, 'OL' ) ) {
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( decreaseListLevel, range );
|
||||
self.decreaseListLevel( range );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue