From 0ab3b65c03723b052f7b580225ce16325be5c0bb Mon Sep 17 00:00:00 2001 From: Christian Williams Date: Wed, 20 Jun 2012 21:10:48 -0700 Subject: [PATCH] Pressing enter in the last listItem, if empty, will exit the list Change-Id: I084fabac09654adf50db97b554e937d2772f9a37 --- modules/ve/ce/ve.ce.Surface.js | 49 +++++++++++++++++++++++++----- modules/ve/dm/ve.dm.Transaction.js | 2 +- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/modules/ve/ce/ve.ce.Surface.js b/modules/ve/ce/ve.ce.Surface.js index cb635b9525..bcba4b3fc7 100644 --- a/modules/ve/ce/ve.ce.Surface.js +++ b/modules/ve/ce/ve.ce.Surface.js @@ -525,7 +525,9 @@ ve.ce.Surface.prototype.onChange = function( transaction, selection ) { ve.ce.Surface.prototype.handleEnter = function() { var selection = this.model.getSelection(), documentModel = this.model.getDocument(), - tx; + emptyParagraph = [{ 'type': 'paragraph' }, { 'type': '/paragraph' }], + tx, + advanceCursor = true; // Stop polling while we work this.stopPolling(); // Handle removal first @@ -551,7 +553,6 @@ ve.ce.Surface.prototype.handleEnter = function() { ) { // If we're at the start/end of something that's not a paragraph, insert a paragraph // before/after - var emptyParagraph = [{ 'type': 'paragraph' }, { 'type': '/paragraph' }]; if ( cursor === contentBranchModelRange.from ) { tx = ve.dm.Transaction.newFromInsertion( documentModel, contentBranchModel.getOuterRange().from, emptyParagraph @@ -563,7 +564,9 @@ ve.ce.Surface.prototype.handleEnter = function() { } } else { // Split - stack = []; + var stack = [], + outermostNode = null; + ve.Node.traverseUpstream( node, function( node ) { if ( !node.canBeSplit() ) { return false; @@ -574,16 +577,46 @@ ve.ce.Surface.prototype.handleEnter = function() { { 'type': '/' + node.type }, node.model.getClonedElement() ); + outermostNode = node; return true; } ); - // We must process the transaction first because getRelativeContentOffset can't help us yet - tx = ve.dm.Transaction.newFromInsertion( documentModel, selection.from, stack ); + + var outerParent = outermostNode.getModel().getParent(), + outerChildrenCount = outerParent.getChildren().length + + if ( + outermostNode.type == 'listItem' && // this is a list item + outerParent.getChildren()[outerChildrenCount - 1] == outermostNode.getModel() && // this is the last list item + outermostNode.children.length == 1 && // there is one child + node.model.length == 0 // the child is empty + ) { + // Enter was pressed in an empty list item. + var list = outermostNode.getModel().getParent(); + // Remove the list item + tx = ve.dm.Transaction.newFromRemoval( documentModel, outermostNode.getModel().getOuterRange() ); + selection = tx.translateRange( selection ); + this.model.change( tx, selection ); + // Insert a paragraph + tx = ve.dm.Transaction.newFromInsertion( documentModel, list.getOuterRange().to, emptyParagraph ); + + advanceCursor = false; + } else { + // We must process the transaction first because getRelativeContentOffset can't help us yet + tx = ve.dm.Transaction.newFromInsertion( documentModel, selection.from, stack ); + } } this.model.change( tx ); + // Now we can move the cursor forward - this.model.change( - null, new ve.Range( documentModel.getRelativeContentOffset( selection.from, 1 ) ) - ); + if ( advanceCursor ) { + this.model.change( + null, new ve.Range( documentModel.getRelativeContentOffset( selection.from, 1 ) ) + ); + } else { + this.model.change( + null, new ve.Range( documentModel.getNearestContentOffset( selection.from ) ) + ); + } // Reset and resume polling this.clearPollData(); this.startPolling(); diff --git a/modules/ve/dm/ve.dm.Transaction.js b/modules/ve/dm/ve.dm.Transaction.js index 30b8302166..fe45a5bdd2 100644 --- a/modules/ve/dm/ve.dm.Transaction.js +++ b/modules/ve/dm/ve.dm.Transaction.js @@ -477,7 +477,7 @@ ve.dm.Transaction.prototype.translateOffset = function( offset ) { return offset + adjustment; } else if ( offset > cursor && offset < cursor + op.remove.length ) { // The offset points inside of the removal - return null; + return offset; } cursor += op.remove.length; } else if ( op.type === 'retain' ) {