mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 07:13:08 -05:00
Allowing arbitrary nesting for bullets
This allows any level of indentation for bullets. It does this by introducing invalid HTML. In particular, you can make bullets like: <ul> <ul> <li>foo</li> </ul> </ul>
This commit is contained in:
parent
4f83b0a8bc
commit
6a9582c7e7
5 changed files with 139 additions and 48 deletions
|
@ -1636,12 +1636,9 @@ var keyHandlers = {
|
|||
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' ) {
|
||||
// AND the LI is not the first in the list
|
||||
if ( node.previousSibling ) {
|
||||
// Then increase the list level
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( increaseListLevel, range );
|
||||
}
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
|
@ -3764,19 +3761,19 @@ var makeOrderedList = function ( frag ) {
|
|||
|
||||
var removeList = function ( frag ) {
|
||||
var lists = frag.querySelectorAll( 'UL, OL' ),
|
||||
i, l, ll, list, listFrag, children, child;
|
||||
items = frag.querySelectorAll( 'LI' ),
|
||||
i, l, list, listFrag, item;
|
||||
for ( i = 0, l = lists.length; i < l; i += 1 ) {
|
||||
list = lists[i];
|
||||
listFrag = empty( list );
|
||||
children = listFrag.childNodes;
|
||||
ll = children.length;
|
||||
while ( ll-- ) {
|
||||
child = children[ll];
|
||||
replaceWith( child, empty( child ) );
|
||||
}
|
||||
fixContainer( listFrag, this._root );
|
||||
replaceWith( list, listFrag );
|
||||
}
|
||||
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
replaceWith( item, empty( item ) );
|
||||
}
|
||||
return frag;
|
||||
};
|
||||
|
||||
|
@ -3785,7 +3782,6 @@ var increaseListLevel = function ( frag ) {
|
|||
i, l, item,
|
||||
type, newParent,
|
||||
tagAttributes = this._config.tagAttributes,
|
||||
listItemAttrs = tagAttributes.li,
|
||||
listAttrs;
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
|
@ -3796,11 +3792,11 @@ var increaseListLevel = function ( frag ) {
|
|||
if ( !newParent || !( newParent = newParent.lastChild ) ||
|
||||
newParent.nodeName !== type ) {
|
||||
listAttrs = tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
|
||||
replaceWith(
|
||||
item,
|
||||
this.createElement( 'LI', listItemAttrs, [
|
||||
newParent = this.createElement( type, listAttrs )
|
||||
])
|
||||
newParent
|
||||
);
|
||||
}
|
||||
newParent.appendChild( item );
|
||||
|
@ -3823,6 +3819,15 @@ var decreaseListLevel = function ( frag ) {
|
|||
if ( item.previousSibling ) {
|
||||
parent = split( parent, item, newParent, root );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
} else {
|
||||
while ( node ) {
|
||||
next = node.nextSibling;
|
||||
if ( isContainer( node ) ) {
|
||||
|
@ -3831,6 +3836,7 @@ var decreaseListLevel = function ( frag ) {
|
|||
newParent.insertBefore( node, parent );
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
if ( newParent.nodeName === 'LI' && first.previousSibling ) {
|
||||
split( newParent, first, newParent.parentNode, root );
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1406,19 +1406,19 @@ var makeOrderedList = function ( frag ) {
|
|||
|
||||
var removeList = function ( frag ) {
|
||||
var lists = frag.querySelectorAll( 'UL, OL' ),
|
||||
i, l, ll, list, listFrag, children, child;
|
||||
items = frag.querySelectorAll( 'LI' ),
|
||||
i, l, list, listFrag, item;
|
||||
for ( i = 0, l = lists.length; i < l; i += 1 ) {
|
||||
list = lists[i];
|
||||
listFrag = empty( list );
|
||||
children = listFrag.childNodes;
|
||||
ll = children.length;
|
||||
while ( ll-- ) {
|
||||
child = children[ll];
|
||||
replaceWith( child, empty( child ) );
|
||||
}
|
||||
fixContainer( listFrag, this._root );
|
||||
replaceWith( list, listFrag );
|
||||
}
|
||||
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
replaceWith( item, empty( item ) );
|
||||
}
|
||||
return frag;
|
||||
};
|
||||
|
||||
|
@ -1427,7 +1427,6 @@ var increaseListLevel = function ( frag ) {
|
|||
i, l, item,
|
||||
type, newParent,
|
||||
tagAttributes = this._config.tagAttributes,
|
||||
listItemAttrs = tagAttributes.li,
|
||||
listAttrs;
|
||||
for ( i = 0, l = items.length; i < l; i += 1 ) {
|
||||
item = items[i];
|
||||
|
@ -1438,11 +1437,11 @@ var increaseListLevel = function ( frag ) {
|
|||
if ( !newParent || !( newParent = newParent.lastChild ) ||
|
||||
newParent.nodeName !== type ) {
|
||||
listAttrs = tagAttributes[ type.toLowerCase() ];
|
||||
newParent = this.createElement( type, listAttrs );
|
||||
|
||||
replaceWith(
|
||||
item,
|
||||
this.createElement( 'LI', listItemAttrs, [
|
||||
newParent = this.createElement( type, listAttrs )
|
||||
])
|
||||
newParent
|
||||
);
|
||||
}
|
||||
newParent.appendChild( item );
|
||||
|
@ -1465,6 +1464,15 @@ var decreaseListLevel = function ( frag ) {
|
|||
if ( item.previousSibling ) {
|
||||
parent = split( parent, item, newParent, root );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
} else {
|
||||
while ( node ) {
|
||||
next = node.nextSibling;
|
||||
if ( isContainer( node ) ) {
|
||||
|
@ -1473,6 +1481,7 @@ var decreaseListLevel = function ( frag ) {
|
|||
newParent.insertBefore( node, parent );
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
if ( newParent.nodeName === 'LI' && first.previousSibling ) {
|
||||
split( newParent, first, newParent.parentNode, root );
|
||||
}
|
||||
|
|
|
@ -390,12 +390,9 @@ var keyHandlers = {
|
|||
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' ) {
|
||||
// AND the LI is not the first in the list
|
||||
if ( node.previousSibling ) {
|
||||
// Then increase the list level
|
||||
event.preventDefault();
|
||||
self.modifyBlocks( increaseListLevel, range );
|
||||
}
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
|
|
|
@ -272,6 +272,85 @@ describe('Squire RTE', function () {
|
|||
});
|
||||
});
|
||||
|
||||
describe('multi-level lists', function () {
|
||||
it('increases list indentation', function() {
|
||||
var startHTML = '<ul><li><div>a</div></li><li><div>b</div></li><li><div>c</div></li></ul>';
|
||||
editor.setHTML(startHTML);
|
||||
expect(editor, 'to contain HTML', startHTML);
|
||||
|
||||
var range = doc.createRange();
|
||||
var textNode = doc.getElementsByTagName('li').item(1).childNodes[0].childNodes[0]
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 0);
|
||||
editor.setSelection(range);
|
||||
|
||||
editor.increaseListLevel()
|
||||
expect(editor, 'to contain HTML', '<ul><li><div>a</div></li><ul><li><div>b</div></li></ul><li><div>c</div></li></ul>');
|
||||
});
|
||||
|
||||
it('increases list indentation 2', function() {
|
||||
var startHTML = '<ul><li><div>a</div></li><li><div>b</div></li><li><div>c</div></li></ul>';
|
||||
editor.setHTML(startHTML);
|
||||
expect(editor, 'to contain HTML', startHTML);
|
||||
|
||||
var range = doc.createRange();
|
||||
var textNode = doc.getElementsByTagName('li').item(1).childNodes[0].childNodes[0]
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 0);
|
||||
editor.setSelection(range);
|
||||
|
||||
editor.increaseListLevel()
|
||||
editor.increaseListLevel()
|
||||
expect(editor, 'to contain HTML', '<ul><li><div>a</div></li><ul><ul><li><div>b</div></li></ul></ul><li><div>c</div></li></ul>');
|
||||
});
|
||||
|
||||
it('decreases list indentation', function() {
|
||||
var startHTML = '<ul><li><div>a</div></li><ul><li><div>b</div></li></ul><li><div>c</div></li></ul>';
|
||||
editor.setHTML(startHTML);
|
||||
expect(editor, 'to contain HTML', startHTML);
|
||||
|
||||
var range = doc.createRange();
|
||||
var textNode = doc.getElementsByTagName('li').item(1).childNodes[0].childNodes[0]
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 0);
|
||||
editor.setSelection(range);
|
||||
|
||||
editor.decreaseListLevel()
|
||||
expect(editor, 'to contain HTML', '<ul><li><div>a</div></li><li><div>b</div></li><li><div>c</div></li></ul>');
|
||||
});
|
||||
|
||||
it('decreases list indentation 2', function() {
|
||||
var startHTML = '<ul><li><div>a</div></li><ul><ul><li><div>b</div></li></ul></ul><li><div>c</div></li></ul>';
|
||||
editor.setHTML(startHTML);
|
||||
expect(editor, 'to contain HTML', startHTML);
|
||||
|
||||
var range = doc.createRange();
|
||||
var textNode = doc.getElementsByTagName('li').item(1).childNodes[0].childNodes[0]
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 0);
|
||||
editor.setSelection(range);
|
||||
|
||||
editor.decreaseListLevel()
|
||||
editor.decreaseListLevel()
|
||||
expect(editor, 'to contain HTML', '<ul><li><div>a</div></li><li><div>b</div></li><li><div>c</div></li></ul>');
|
||||
});
|
||||
|
||||
it('removes lists', function() {
|
||||
var startHTML = '<ul><li><div>foo</div></li><ul><li><div>bar</div></li></ul></ul>';
|
||||
editor.setHTML(startHTML);
|
||||
expect(editor, 'to contain HTML', startHTML);
|
||||
|
||||
var range = doc.createRange();
|
||||
var textNode = doc.getElementsByTagName('li').item(1).childNodes[0].childNodes[0]
|
||||
range.setStart(textNode, 0);
|
||||
range.setEnd(textNode, 0);
|
||||
editor.setSelection(range);
|
||||
|
||||
editor.removeList()
|
||||
expect(editor, 'to contain HTML', '<ul><li><div>foo</div></li></ul><div>bar</div>');
|
||||
})
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
editor = null;
|
||||
var iframe = document.getElementById('testFrame');
|
||||
|
|
Loading…
Reference in a new issue