jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/347901 )
Change subject: Introduce single-line mode for surfaces ...................................................................... Introduce single-line mode for surfaces Or rather multi-line, defaulted to true. For now this blocks the creation of newlines using <enter> or via paste. There are other ways to trigger complex creation that will need to be addressed later, possibly at the transaction level: * Pasting objects (e.g. HTML files) * Sequences (e.g. '* ') * Commands (no real-world examples) Bug: T162808 Change-Id: I31fce3cc9ac6f7c12ec916b364b91cead2b4e6c9 --- M src/ce/keydownhandlers/ve.ce.LinearEnterKeyDownHandler.js M src/ce/keydownhandlers/ve.ce.TableArrowKeyDownHandler.js M src/ce/ve.ce.Surface.js M src/dm/lineardata/ve.dm.ElementLinearData.js M src/ui/ve.ui.Surface.js M src/ui/widgets/ve.ui.TargetWidget.js M tests/ce/ve.ce.Surface.test.js M tests/dm/lineardata/ve.dm.ElementLinearData.test.js M tests/ve.test.utils.js 9 files changed, 67 insertions(+), 3 deletions(-) Approvals: jenkins-bot: Verified Jforrester: Looks good to me, approved diff --git a/src/ce/keydownhandlers/ve.ce.LinearEnterKeyDownHandler.js b/src/ce/keydownhandlers/ve.ce.LinearEnterKeyDownHandler.js index fa8a64d..7d05f16 100644 --- a/src/ce/keydownhandlers/ve.ce.LinearEnterKeyDownHandler.js +++ b/src/ce/keydownhandlers/ve.ce.LinearEnterKeyDownHandler.js @@ -49,6 +49,10 @@ e.preventDefault(); + if ( !surface.getSurface().isMultiline() ) { + return true; + } + if ( ( e.ctrlKey || e.metaKey ) && surface.getSurface().getInDialog() ) { // We're inside a dialog. OOUI behavior is to close+submit a dialog if // ctrl/cmd+enter is pressed. If this dialog is going to close, we diff --git a/src/ce/keydownhandlers/ve.ce.TableArrowKeyDownHandler.js b/src/ce/keydownhandlers/ve.ce.TableArrowKeyDownHandler.js index 84cbcd2..e82a26a 100644 --- a/src/ce/keydownhandlers/ve.ce.TableArrowKeyDownHandler.js +++ b/src/ce/keydownhandlers/ve.ce.TableArrowKeyDownHandler.js @@ -89,6 +89,7 @@ e.preventDefault(); this.moveTableSelection( surface, rowOffset, colOffset, checkDir, expand, wrap ); + return true; }; /** diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js index 8d04250..5620fae 100644 --- a/src/ce/ve.ce.Surface.js +++ b/src/ce/ve.ce.Surface.js @@ -1100,7 +1100,10 @@ } else { // External drop - this.handleDataTransfer( dataTransfer, false, targetFragment ); + // TODO: Support sanitized drop on single line surfaces + if ( this.getSurface().isMultiline() ) { + this.handleDataTransfer( dataTransfer, false, targetFragment ); + } } this.endRelocation(); }; diff --git a/src/dm/lineardata/ve.dm.ElementLinearData.js b/src/dm/lineardata/ve.dm.ElementLinearData.js index cc96094..eb8a05d 100644 --- a/src/dm/lineardata/ve.dm.ElementLinearData.js +++ b/src/dm/lineardata/ve.dm.ElementLinearData.js @@ -1100,10 +1100,11 @@ * @param {boolean} [rules.preserveHtmlWhitespace] Preserve non-semantic HTML whitespace * @param {boolean} [rules.nodeSanitization] Apply per-type node sanitizations via ve.dm.Node#sanitize * @param {boolean} [rules.keepEmptyContentBranches] Preserve empty content branch nodes + * @param {boolean} [rules.singleLine] Don't allow more that one ContentBranchNode */ ve.dm.ElementLinearData.prototype.sanitize = function ( rules ) { var i, len, annotations, emptySet, setToRemove, type, oldHash, newHash, - canContainContent, contentElement, isOpen, nodeClass, ann, + canContainContent, contentElement, isOpen, nodeClass, ann, start, elementStack = [], store = this.getStore(), allAnnotations = this.getAnnotationsFromRange( new ve.Range( 0, this.getLength() ), true ); @@ -1228,6 +1229,16 @@ } } + if ( canContainContent && !isOpen && rules.singleLine ) { + i++; + start = i; + while ( i < len && !( this.isOpenElementData( i ) && this.getType( i ) === 'internalList' ) ) { + i++; + } + this.splice( start, i - start ); + break; + } + // Store the current contentElement for splitting if ( canContainContent ) { contentElement = isOpen ? this.getData( i ) : null; diff --git a/src/ui/ve.ui.Surface.js b/src/ui/ve.ui.Surface.js index e25a74b..4c89bee 100644 --- a/src/ui/ve.ui.Surface.js +++ b/src/ui/ve.ui.Surface.js @@ -22,6 +22,7 @@ * @cfg {string[]|null} [includeCommands] List of commands to include, null for all registered commands * @cfg {string[]} [excludeCommands] List of commands to exclude * @cfg {Object} [importRules] Import rules + * @cfg {boolean} [multiline=true] Multi-line surface * @cfg {string} [placeholder] Placeholder text to display when the surface is empty * @cfg {string} [inDialog] The name of the dialog this surface is in */ @@ -69,6 +70,7 @@ this.view = this.createView( this.model ); this.dialogs = this.createDialogWindowManager(); this.importRules = config.importRules || {}; + this.multiline = config.multiline !== false; this.context = this.createContext(); this.progresses = []; this.showProgressDebounced = ve.debounce( this.showProgress.bind( this ) ); @@ -750,7 +752,20 @@ * @return {Object} Import rules */ ve.ui.Surface.prototype.getImportRules = function () { - return this.importRules; + var singleLine = { singleLine: !this.multiline }; + return { + all: ve.extendObject( {}, this.importRules.all, singleLine ), + external: ve.extendObject( {}, this.importRules.external, singleLine ) + }; +}; + +/** + * Check if the surface is multi-line + * + * @return {boolean} Surface is multi-line + */ +ve.ui.Surface.prototype.isMultiline = function () { + return this.multiline; }; /** diff --git a/src/ui/widgets/ve.ui.TargetWidget.js b/src/ui/widgets/ve.ui.TargetWidget.js index 34b6e89..e3436ac 100644 --- a/src/ui/widgets/ve.ui.TargetWidget.js +++ b/src/ui/widgets/ve.ui.TargetWidget.js @@ -21,6 +21,7 @@ * @cfg {string[]|null} [includeCommands] List of commands to include, null for all registered commands * @cfg {string[]} [excludeCommands] List of commands to exclude * @cfg {Object} [importRules] Import rules + * @cfg {boolean} [multiline] Multi-line surface * @cfg {string} [inDialog] The name of the dialog this surface widget is in */ ve.ui.TargetWidget = function VeUiTargetWidget( config ) { @@ -38,6 +39,7 @@ this.tools = config.tools; this.includeCommands = config.includeCommands; this.excludeCommands = config.excludeCommands; + this.multiline = config.multiline !== false; this.importRules = config.importRules; this.inDialog = config.inDialog; // TODO: Support source widgets @@ -94,6 +96,7 @@ includeCommands: this.includeCommands, excludeCommands: this.excludeCommands, importRules: this.importRules, + multiline: this.multiline, inDialog: this.inDialog } ); diff --git a/tests/ce/ve.ce.Surface.test.js b/tests/ce/ve.ce.Surface.test.js index 53aa686..8a9238c 100644 --- a/tests/ce/ve.ce.Surface.test.js +++ b/tests/ce/ve.ce.Surface.test.js @@ -895,6 +895,18 @@ }, { rangeOrSelection: new ve.Range( 57 ), + keys: [ 'ENTER' ], + htmlOrDoc: ( function () { + var view = ve.test.utils.createSurfaceViewFromDocument( ve.dm.example.createExampleDocument() ); + view.surface.isMultiline = function () { return false; }; + return view; + }() ), + expectedData: function () {}, + expectedRangeOrSelection: new ve.Range( 57 ), + msg: 'Enter does nothing in single line mode' + }, + { + rangeOrSelection: new ve.Range( 57 ), keys: [ 'SHIFT+ENTER' ], expectedData: function ( data ) { data.splice( diff --git a/tests/dm/lineardata/ve.dm.ElementLinearData.test.js b/tests/dm/lineardata/ve.dm.ElementLinearData.test.js index 3a3c10f..e7ddb21 100644 --- a/tests/dm/lineardata/ve.dm.ElementLinearData.test.js +++ b/tests/dm/lineardata/ve.dm.ElementLinearData.test.js @@ -1597,6 +1597,18 @@ msg: 'Headings converted to paragraph in plainText mode' }, { + html: '<p>Bar</p><p>Baz</p><p>Quux</p>', + data: [ + { type: 'paragraph' }, + 'B', 'a', 'r', + { type: '/paragraph' }, + { type: 'internalList' }, + { type: '/internalList' } + ], + rules: { singleLine: true }, + msg: 'Extra lines truncated in singleline mode' + }, + { html: '<h1>Bar</h1>', data: [ // TODO: non-relevant attributes should be discarded, T130377 diff --git a/tests/ve.test.utils.js b/tests/ve.test.utils.js index 4fbc6c5..11db900 100644 --- a/tests/ve.test.utils.js +++ b/tests/ve.test.utils.js @@ -319,6 +319,9 @@ isMobile: function () { return false; }, + isMultiline: function () { + return true; + }, getBoundingClientRect: function () { return {}; }, -- To view, visit https://gerrit.wikimedia.org/r/347901 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I31fce3cc9ac6f7c12ec916b364b91cead2b4e6c9 Gerrit-PatchSet: 4 Gerrit-Project: VisualEditor/VisualEditor Gerrit-Branch: master Gerrit-Owner: Esanders <esand...@wikimedia.org> Gerrit-Reviewer: Esanders <esand...@wikimedia.org> Gerrit-Reviewer: Jforrester <jforres...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits