CodeMirror: add 'dir' and 'lang' attrs to .cm-editor and not .cm-content

Before we were adding these attributes to .cm-content, which didn't
encompass the gutter (line numbers). When you edited a LTR page in a RTL
interface language (or vice versa), the line gutter appeared on the
wrong side, which caused the cursor to be misaligned.

This commit fixes this by applying the direction and language to the
entire editor (.cm-editor), and not just .cm-content. However this means
the search panel could be in the page language when it should be the
interface language. This will be addressed in a follow-up patch.

Other attributes like 'class' that are copied from the textarea must
remain on .cm-content, because the parent .cm-scroller would otherwise
override them.

Bug: T359589
Change-Id: Id805944231fd75c1dc1c336e3cd4c7bc5c42c036
This commit is contained in:
MusikAnimal 2024-03-07 20:36:15 -05:00
parent aa3876a97e
commit 911b2d3d46
4 changed files with 27 additions and 13 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -73,9 +73,7 @@ export default class CodeMirror {
}
/**
* This specifies which attributes get added to the .cm-content element.
* If you need to add more, add another Extension on initialization for the contentAttributes
* Facet in the form of EditorView.contentAttributes.of( {Object} ).
* This specifies which attributes get added to the .cm-content and .cm-editor elements.
* Subclasses are safe to override this method, but attributes here are considered vital.
*
* @see https://codemirror.net/docs/ref/#view.EditorView^contentAttributes
@ -98,14 +96,22 @@ export default class CodeMirror {
classList.push( 'cm-mw-colorblind-colors' );
}
return EditorView.contentAttributes.of( {
return [
// .cm-content element (the contenteditable area)
EditorView.contentAttributes.of( {
// T259347: Use accesskey of the original textbox
accesskey: this.$textarea.attr( 'accesskey' ),
// use direction and language of the original textbox
dir: this.$textarea.attr( 'dir' ),
lang: this.$textarea.attr( 'lang' ),
// Classes need to be on .cm-content to have precedence over .cm-scroller
class: classList.join( ' ' )
} );
} ),
// .cm-editor element (contains the whole CodeMirror UI)
EditorView.editorAttributes.of( {
// Use direction and language of the original textbox.
// These should be attributes of .cm-editor, not the .cm-content (T359589)
dir: this.$textarea.attr( 'dir' ),
lang: this.$textarea.attr( 'lang' )
} )
];
}
/**

View file

@ -47,6 +47,14 @@ describe( 'initialize', () => {
cm.initialize();
expect( cm.view.dom.querySelector( '.cm-content' ).classList ).toContain( 'mw-editfont-monospace' );
} );
it( "should copy the 'dir' and 'lang' attributes of the textarea to .cm-editor", () => {
cm.$textarea.prop( 'dir', 'rtl' )
.prop( 'lang', 'ar' );
cm.initialize();
expect( cm.view.dom.getAttribute( 'dir' ) ).toStrictEqual( 'rtl' );
expect( cm.view.dom.getAttribute( 'lang' ) ).toStrictEqual( 'ar' );
} );
} );
describe( 'logUsage', () => {