mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-29 00:30:44 +00:00
Merge "(bug 41929) Unlist button overzealously unlists the whole list"
This commit is contained in:
commit
be0f6f7bd7
|
@ -44,20 +44,31 @@ ve.IndentationAction.static.methods = ['increase', 'decrease'];
|
|||
*/
|
||||
ve.IndentationAction.prototype.increase = function () {
|
||||
var i, group,
|
||||
fragments = [],
|
||||
increased = false,
|
||||
surfaceModel = this.surface.getModel(),
|
||||
documentModel = surfaceModel.getDocument(),
|
||||
selection = surfaceModel.getSelection(),
|
||||
groups = documentModel.getCoveredSiblingGroups( selection );
|
||||
selected = surfaceModel.getFragment(),
|
||||
groups = documentModel.getCoveredSiblingGroups( selected.getRange() );
|
||||
|
||||
// Build fragments from groups (we need their ranges since the nodes will be rebuilt on change)
|
||||
for ( i = 0; i < groups.length; i++ ) {
|
||||
group = groups[i];
|
||||
if ( group.grandparent && group.grandparent.getType() === 'list' ) {
|
||||
// FIXME this doesn't work when trying to work with multiple list items
|
||||
this.indentListItem( group.parent );
|
||||
fragments.push( surfaceModel.getFragment( group.parent.getOuterRange(), true ) );
|
||||
increased = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Process each fragment (their ranges are automatically adjusted on change)
|
||||
for ( i = 0; i < fragments.length; i++ ) {
|
||||
this.indentListItem(
|
||||
documentModel.getNodeFromOffset( fragments[i].getRange().start + 1 )
|
||||
);
|
||||
}
|
||||
|
||||
selected.select();
|
||||
|
||||
return increased;
|
||||
};
|
||||
|
||||
|
@ -71,20 +82,31 @@ ve.IndentationAction.prototype.increase = function () {
|
|||
*/
|
||||
ve.IndentationAction.prototype.decrease = function () {
|
||||
var i, group,
|
||||
fragments = [],
|
||||
decreased = false,
|
||||
surfaceModel = this.surface.getModel(),
|
||||
documentModel = surfaceModel.getDocument(),
|
||||
selection = surfaceModel.getSelection(),
|
||||
groups = documentModel.getCoveredSiblingGroups( selection );
|
||||
selected = surfaceModel.getFragment(),
|
||||
groups = documentModel.getCoveredSiblingGroups( selected.getRange() );
|
||||
|
||||
// Build fragments from groups (we need their ranges since the nodes will be rebuilt on change)
|
||||
for ( i = 0; i < groups.length; i++ ) {
|
||||
group = groups[i];
|
||||
if ( group.grandparent && group.grandparent.getType() === 'list' ) {
|
||||
// FIXME this doesn't work when trying to work with multiple list items
|
||||
this.outdentListItem( group.parent );
|
||||
fragments.push( surfaceModel.getFragment( group.parent.getOuterRange(), true ) );
|
||||
decreased = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Process each fragment (their ranges are automatically adjusted on change)
|
||||
for ( i = 0; i < fragments.length; i++ ) {
|
||||
this.outdentListItem(
|
||||
documentModel.getNodeFromOffset( fragments[i].getRange().start + 1 )
|
||||
);
|
||||
}
|
||||
|
||||
selected.select();
|
||||
|
||||
return decreased;
|
||||
};
|
||||
|
||||
|
@ -176,7 +198,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
var tx,
|
||||
surfaceModel = this.surface.getModel(),
|
||||
documentModel = surfaceModel.getDocument(),
|
||||
selection = surfaceModel.getSelection(),
|
||||
list = listItem.getParent(),
|
||||
listElement = list.getClonedElement(),
|
||||
grandParentType = list.getParent().getType(),
|
||||
|
@ -195,7 +216,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[ { 'type': '/list' }, listElement ]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
// tx.translateRange( listItemRange ) doesn't do what we want
|
||||
listItemRange = ve.Range.newFromTranslatedRange( listItemRange, 2 );
|
||||
}
|
||||
|
@ -205,7 +225,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[ { 'type': '/list' }, listElement ]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
// listItemRange is not affected by this transaction
|
||||
}
|
||||
splitListRange = new ve.Range( listItemRange.start - 1, listItemRange.end + 1 );
|
||||
|
@ -222,7 +241,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
} else {
|
||||
// (3) Split the list away from parentListItem into its own listItem
|
||||
// TODO factor common split logic somehow?
|
||||
|
@ -232,7 +250,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[ { 'type': '/listItem' }, { 'type': 'listItem' } ]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
// tx.translateRange( splitListRange ) doesn't do what we want
|
||||
splitListRange = ve.Range.newFromTranslatedRange( splitListRange, 2 );
|
||||
}
|
||||
|
@ -242,7 +259,6 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[ { 'type': '/listItem' }, { 'type': 'listItem' } ]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
// splitListRange is not affected by this transaction
|
||||
}
|
||||
|
||||
|
@ -255,10 +271,7 @@ ve.IndentationAction.prototype.outdentListItem = function ( listItem ) {
|
|||
[]
|
||||
);
|
||||
surfaceModel.change( tx );
|
||||
selection = tx.translateRange( selection );
|
||||
}
|
||||
|
||||
surfaceModel.change( null, selection );
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
|
|
@ -100,95 +100,21 @@ ve.ListAction.prototype.wrap = function ( style ) {
|
|||
* @method
|
||||
*/
|
||||
ve.ListAction.prototype.unwrap = function () {
|
||||
var tx, i, j,
|
||||
var node,
|
||||
surfaceModel = this.surface.getModel(),
|
||||
documentModel = surfaceModel.getDocument(),
|
||||
selection = surfaceModel.getSelection(),
|
||||
unlistRangesObj = this.getUnlistRanges( selection ),
|
||||
unlistRangesArr = [];
|
||||
documentModel = surfaceModel.getDocument();
|
||||
|
||||
surfaceModel.breakpoint();
|
||||
for ( i in unlistRangesObj ) {
|
||||
unlistRangesArr.push( unlistRangesObj[i] );
|
||||
|
||||
node = documentModel.getNodeFromOffset( surfaceModel.getSelection().start );
|
||||
while ( node.hasMatchingAncestor( 'list' ) ) {
|
||||
this.surface.execute( 'indentation', 'decrease' );
|
||||
node = documentModel.getNodeFromOffset( surfaceModel.getSelection().start );
|
||||
}
|
||||
for ( i = 0; i < unlistRangesArr.length; i++ ) {
|
||||
// Unwrap the range given by unlistRanges[i]
|
||||
tx = ve.dm.Transaction.newFromWrap(
|
||||
documentModel,
|
||||
unlistRangesArr[i],
|
||||
[ { 'type': 'list' } ],
|
||||
[],
|
||||
[ { 'type': 'listItem' } ],
|
||||
[]
|
||||
);
|
||||
selection = tx.translateRange( selection );
|
||||
surfaceModel.change( tx );
|
||||
// Translate all the remaining ranges for this transaction
|
||||
// TODO ideally we'd have a way to merge all these transactions into one and execute that instead
|
||||
for ( j = i + 1; j < unlistRangesArr.length; j++ ) {
|
||||
unlistRangesArr[j] = tx.translateRange( unlistRangesArr[j] );
|
||||
}
|
||||
}
|
||||
// Update the selection
|
||||
surfaceModel.change( null, selection );
|
||||
|
||||
surfaceModel.breakpoint();
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively prepare to unwrap all lists in a given range.
|
||||
*
|
||||
* This function will find all lists covered wholly or partially by the given range, as well
|
||||
* as all lists inside these lists, and return their inner ranges. This means that all sublists
|
||||
* will be found even if range doesn't cover them.
|
||||
*
|
||||
* To actually unwrap the list, feed the returned ranges to ve.dm.Transaction.newFromWrap(),
|
||||
* in order.
|
||||
*
|
||||
* TODO: Refactor functionality into {ve.dm.SurfaceFragment}.
|
||||
*
|
||||
* @param {ve.dm.Document} documentModel
|
||||
* @param {ve.Range} range
|
||||
* @returns {ve.Range[]} Array of inner ranges of lists
|
||||
*/
|
||||
ve.ListAction.prototype.getUnlistRanges = function( range ) {
|
||||
var i, j, k, group, previousList, list, listItem, subList,
|
||||
unlistRanges = {},
|
||||
endOffset = 0,
|
||||
documentModel = this.surface.getModel().getDocument(),
|
||||
groups = documentModel.getCoveredSiblingGroups( range );
|
||||
|
||||
for ( i = 0; i < groups.length; i++ ) {
|
||||
group = groups[i];
|
||||
list = group.grandparent;
|
||||
if ( list && list.getType() === 'list' && list !== previousList ) {
|
||||
// Unwrap the parent list
|
||||
range = list.getRange();
|
||||
if ( range.end > endOffset ) {
|
||||
unlistRanges[range.start + '-' + range.end] = range;
|
||||
endOffset = range.end;
|
||||
}
|
||||
// Skip this list next time
|
||||
previousList = list;
|
||||
// Recursively unwrap any sublists of the list
|
||||
for ( j = 0; j < list.children.length; j++ ) {
|
||||
listItem = list.children[j];
|
||||
if ( listItem.getType() === 'listItem' ) {
|
||||
for ( k = 0; k < listItem.children.length; k++ ) {
|
||||
subList = listItem.children[k];
|
||||
if ( subList.getType() === 'list' ) {
|
||||
// Recurse
|
||||
unlistRanges = ve.extendObject( unlistRanges, this.getUnlistRanges(
|
||||
subList.getRange()
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return unlistRanges;
|
||||
};
|
||||
|
||||
/* Registration */
|
||||
|
||||
ve.actionFactory.register( 'list', ve.ListAction );
|
||||
|
|
Loading…
Reference in a new issue