mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/CodeMirror
synced 2024-11-23 13:56:44 +00:00
CodeMirror: highlight special characters and non-breaking spaces
The highlightSpecialChars() should act mostly identical to CM5. An example is the soft hyphen (U+00AD). These are highlighted as a red dot because they are non-printable characters. The i18n may seem like overkill, but CM6 would otherwise actually print the same message in plain English and without a way to localize it. Per request at T181677, we also highlight non-breaking space and the narrow non-breaking space. These are shown as a faint gray dot, to match CM6's highlightWhiteSpace() extension. That extension isn't used here because it would also highlight normal spaces, which we don't want. Bug: T181677 Change-Id: Iac1a8cf78e4cd0a27abc917f4b70bdfbaf86252a
This commit is contained in:
parent
5a07eb35db
commit
75f5c9b2be
|
@ -202,7 +202,31 @@
|
|||
"codemirror-by-word",
|
||||
"codemirror-replace",
|
||||
"codemirror-replace-placeholder",
|
||||
"codemirror-replace-all"
|
||||
"codemirror-replace-all",
|
||||
"codemirror-control-character",
|
||||
"codemirror-special-char-null",
|
||||
"codemirror-special-char-bell",
|
||||
"codemirror-special-char-backspace",
|
||||
"codemirror-special-char-newline",
|
||||
"codemirror-special-char-vertical-tab",
|
||||
"codemirror-special-char-carriage-return",
|
||||
"codemirror-special-char-escape",
|
||||
"codemirror-special-char-nbsp",
|
||||
"codemirror-special-char-zero-width-space",
|
||||
"codemirror-special-char-zero-width-non-joiner",
|
||||
"codemirror-special-char-zero-width-joiner",
|
||||
"codemirror-special-char-left-to-right-mark",
|
||||
"codemirror-special-char-right-to-left-mark",
|
||||
"codemirror-special-char-line-separator",
|
||||
"codemirror-special-char-left-to-right-override",
|
||||
"codemirror-special-char-right-to-left-override",
|
||||
"codemirror-special-char-narrow-nbsp",
|
||||
"codemirror-special-char-left-to-right-isolate",
|
||||
"codemirror-special-char-right-to-left-isolate",
|
||||
"codemirror-special-char-pop-directional-isolate",
|
||||
"codemirror-special-char-paragraph-separator",
|
||||
"codemirror-special-char-zero-width-no-break-space",
|
||||
"codemirror-special-char-object-replacement"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"codemirror-replace": "ersetzen",
|
||||
"codemirror-replace-placeholder": "Ersetzen",
|
||||
"codemirror-replace-all": "alle ersetzen",
|
||||
"codemirror-control-character": "Steuerzeichen $1",
|
||||
"prefs-accessibility": "Barrierefreiheit"
|
||||
}
|
||||
|
|
27
i18n/en.json
27
i18n/en.json
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"@metadata": {
|
||||
"authors": [
|
||||
"pastakhov"
|
||||
"pastakhov",
|
||||
"MusikAnimal"
|
||||
]
|
||||
},
|
||||
"codemirror-desc": "Provides syntax highlighting in wikitext editor",
|
||||
|
@ -18,5 +19,29 @@
|
|||
"codemirror-replace": "replace",
|
||||
"codemirror-replace-placeholder": "Replace",
|
||||
"codemirror-replace-all": "replace all",
|
||||
"codemirror-control-character": "Control character $1",
|
||||
"codemirror-special-char-null": "Null character",
|
||||
"codemirror-special-char-bell": "Bell character",
|
||||
"codemirror-special-char-backspace": "Backspace",
|
||||
"codemirror-special-char-newline": "Newline",
|
||||
"codemirror-special-char-vertical-tab": "Vertical tab",
|
||||
"codemirror-special-char-carriage-return": "Carriage return",
|
||||
"codemirror-special-char-escape": "Escape character",
|
||||
"codemirror-special-char-nbsp": "Non-breaking space",
|
||||
"codemirror-special-char-zero-width-space": "Zero-width space",
|
||||
"codemirror-special-char-zero-width-non-joiner": "Zero-width non-joiner",
|
||||
"codemirror-special-char-zero-width-joiner": "Zero-width joiner",
|
||||
"codemirror-special-char-left-to-right-mark": "Left-to-right mark",
|
||||
"codemirror-special-char-right-to-left-mark": "Right-to-left mark",
|
||||
"codemirror-special-char-line-separator": "Line separator",
|
||||
"codemirror-special-char-left-to-right-override": "Left-to-right override",
|
||||
"codemirror-special-char-right-to-left-override": "Right-to-left override",
|
||||
"codemirror-special-char-narrow-nbsp": "Narrow non-breaking space",
|
||||
"codemirror-special-char-left-to-right-isolate": "Left-to-right isolate",
|
||||
"codemirror-special-char-right-to-left-isolate": "Right-to-left isolate",
|
||||
"codemirror-special-char-pop-directional-isolate": "Pop directional isolate",
|
||||
"codemirror-special-char-paragraph-separator": "Paragraph separator",
|
||||
"codemirror-special-char-zero-width-no-break-space": "Word joiner",
|
||||
"codemirror-special-char-object-replacement": "Object replacement character",
|
||||
"prefs-accessibility": "Accessibility"
|
||||
}
|
||||
|
|
|
@ -22,5 +22,29 @@
|
|||
"codemirror-replace": "Label for the 'replace' button in the CodeMirror search dialog.",
|
||||
"codemirror-replace-placeholder": "Placeholder text for the 'Replace' input in the CodeMirror search dialog.",
|
||||
"codemirror-replace-all": "Label for the 'replace all' button in the CodeMirror search dialog.",
|
||||
"prefs-accessibility": "Section heading in the user prefences for accessibility topics."
|
||||
"codemirror-control-character": "Tooltip text shown when hovering over special characters. $1 is the Unicode value of the special character.",
|
||||
"codemirror-special-char-null": "Tooltip text shown when hovering over a null character. See [[wikidata:Q617945]] for possible translations.",
|
||||
"codemirror-special-char-bell": "Tooltip text shown when hovering over a bell character. See [[wikidata:Q815674]] for possible translations.",
|
||||
"codemirror-special-char-backspace": "Tooltip text shown when hovering over a backspace character. See [[wikidata:Q110028699]] for possible translations.",
|
||||
"codemirror-special-char-newline": "Tooltip text shown when hovering over a newline character. See [[wikidata:Q184914]] for possible translations.",
|
||||
"codemirror-special-char-vertical-tab": "Tooltip text shown when hovering over a vertical tab character. See [[wikidata:Q87529625]] for possible translations.",
|
||||
"codemirror-special-char-carriage-return": "Tooltip text shown when hovering over a carriage return character. See [[wikidata:Q283976]] for possible translations.",
|
||||
"codemirror-special-char-escape": "Tooltip text shown when hovering over an escape character. See [[wikidata:Q998991]] for possible translations.",
|
||||
"codemirror-special-char-nbsp": "Tooltip text shown when hovering over an non-breaking space character. See [[wikidata:Q1053612]] for possible translations.",
|
||||
"codemirror-special-char-zero-width-space": "Tooltip text shown when hovering over a zero-width space character. See [[wikidata:Q2604861]] for possible translations.",
|
||||
"codemirror-special-char-zero-width-non-joiner": "Tooltip text shown when hovering over a zero-width non-joiner character. See [[wikidata:Q863569]] for possible translations.",
|
||||
"codemirror-special-char-zero-width-joiner": "Tooltip text shown when hovering over a zero-width joiner character. See [[wikidata:Q614232]] for possible translations.",
|
||||
"codemirror-special-char-left-to-right-mark": "Tooltip text shown when hovering over a left-to-right mark character. See [[wikidata:Q1022245]] for possible translations.",
|
||||
"codemirror-special-char-right-to-left-mark": "Tooltip text shown when hovering over a right-to-left character. See [[wikidata:Q1017375]] for possible translations.",
|
||||
"codemirror-special-char-line-separator": "Tooltip text shown when hovering over a line separator character. See [[wikidata:Q87523336]] for possible translations.",
|
||||
"codemirror-special-char-left-to-right-override": "Tooltip text shown when hovering over a left-to-right override character. See [[wikidata:Q87523350]] for possible translations.",
|
||||
"codemirror-special-char-right-to-left-override": "Tooltip text shown when hovering over a right-to-left override character. See [[wikidata:Q87523352]] for possible translations.",
|
||||
"codemirror-special-char-narrow-nbsp": "Tooltip text shown when hovering over a narrow non-breaking space character. See [[wikidata:Q3058198]] for possible translations.",
|
||||
"codemirror-special-char-left-to-right-isolate": "Tooltip text shown when hovering over a left-to-right isolate character. See [[wikidata:Q87523498]] for possible translations.",
|
||||
"codemirror-special-char-right-to-left-isolate": "Tooltip text shown when hovering over a right-to-left isolate character. See [[wikidata:Q87523500]] for possible translations.",
|
||||
"codemirror-special-char-pop-directional-isolate": "Tooltip text shown when hovering over a pop directional character. See [[wikidata:Q87523504]] for possible translations.",
|
||||
"codemirror-special-char-paragraph-separator": "Tooltip text shown when hovering over a paragraph separator character. See [[wikidata:Q87523339]] for possible translations.",
|
||||
"codemirror-special-char-zero-width-no-break-space": "Tooltip text shown when hovering over a zero-width word joiner character. See [[wikidata:Q8069466]] for possible translations.",
|
||||
"codemirror-special-char-object-replacement": "Tooltip text shown when hovering over a object replacement character. See [[wikidata:Q9398047]] for possible translations.",
|
||||
"prefs-accessibility": "Section heading in the user preferences for accessibility topics."
|
||||
}
|
||||
|
|
2
resources/dist/main.js
vendored
2
resources/dist/main.js
vendored
File diff suppressed because one or more lines are too long
2
resources/dist/main.js.map.json
vendored
2
resources/dist/main.js.map.json
vendored
File diff suppressed because one or more lines are too long
|
@ -1,5 +1,7 @@
|
|||
@import 'mediawiki.mixins';
|
||||
|
||||
/* TODO: Remove styles below following CM6 upgrade, or move them to ext.CodeMirror.v6.WikiEditor.less */
|
||||
|
||||
.mw-editfont-monospace,
|
||||
.mw-editfont-sans-serif,
|
||||
.mw-editfont-serif {
|
||||
|
|
|
@ -8,3 +8,7 @@
|
|||
box-shadow: inset 0 0 1px 1px #999;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cm-special-char-nbsp {
|
||||
color: #888;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { EditorState, Extension } from '@codemirror/state';
|
||||
import { EditorView, lineNumbers } from '@codemirror/view';
|
||||
import { EditorView, lineNumbers, highlightSpecialChars } from '@codemirror/view';
|
||||
|
||||
/**
|
||||
* @class CodeMirror
|
||||
|
@ -29,7 +29,8 @@ export default class CodeMirror {
|
|||
get defaultExtensions() {
|
||||
const extensions = [
|
||||
this.contentAttributesExtension,
|
||||
this.phrasesExtension
|
||||
this.phrasesExtension,
|
||||
this.specialCharsExtension
|
||||
];
|
||||
const namespaces = mw.config.get( 'wgCodeMirrorLineNumberingNamespaces' );
|
||||
|
||||
|
@ -78,7 +79,67 @@ export default class CodeMirror {
|
|||
'by word': mw.msg( 'codemirror-by-word' ),
|
||||
replace: mw.msg( 'codemirror-replace' ),
|
||||
Replace: mw.msg( 'codemirror-replace-placeholder' ),
|
||||
'replace all': mw.msg( 'codemirror-replace-all' )
|
||||
'replace all': mw.msg( 'codemirror-replace-all' ),
|
||||
'Control character': mw.msg( 'codemirror-control-character' )
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* We give a small subset of special characters a tooltip explaining what they are.
|
||||
* The messages and for what characters are defined here.
|
||||
* Any character that does not have a message will instead use CM6 defaults,
|
||||
* which is the localization of 'codemirror-control-character' followed by the Unicode number.
|
||||
*
|
||||
* @see https://codemirror.net/docs/ref/#view.highlightSpecialChars
|
||||
* @return {Extension}
|
||||
*/
|
||||
get specialCharsExtension() {
|
||||
// Keys are the decimal unicode number, values are the messages.
|
||||
const messages = {
|
||||
0: mw.msg( 'codemirror-special-char-null' ),
|
||||
7: mw.msg( 'codemirror-special-char-bell' ),
|
||||
8: mw.msg( 'codemirror-special-char-backspace' ),
|
||||
10: mw.msg( 'codemirror-special-char-newline' ),
|
||||
11: mw.msg( 'codemirror-special-char-vertical-tab' ),
|
||||
13: mw.msg( 'codemirror-special-char-carriage-return' ),
|
||||
27: mw.msg( 'codemirror-special-char-escape' ),
|
||||
160: mw.msg( 'codemirror-special-char-nbsp' ),
|
||||
8203: mw.msg( 'codemirror-special-char-zero-width-space' ),
|
||||
8204: mw.msg( 'codemirror-special-char-zero-width-non-joiner' ),
|
||||
8205: mw.msg( 'codemirror-special-char-zero-width-joiner' ),
|
||||
8206: mw.msg( 'codemirror-special-char-left-to-right-mark' ),
|
||||
8207: mw.msg( 'codemirror-special-char-right-to-left-mark' ),
|
||||
8232: mw.msg( 'codemirror-special-char-line-separator' ),
|
||||
8237: mw.msg( 'codemirror-special-char-left-to-right-override' ),
|
||||
8238: mw.msg( 'codemirror-special-char-right-to-left-override' ),
|
||||
8239: mw.msg( 'codemirror-special-char-narrow-nbsp' ),
|
||||
8294: mw.msg( 'codemirror-special-char-left-to-right-isolate' ),
|
||||
8295: mw.msg( 'codemirror-special-char-right-to-left-isolate' ),
|
||||
8297: mw.msg( 'codemirror-special-char-pop-directional-isolate' ),
|
||||
8233: mw.msg( 'codemirror-special-char-paragraph-separator' ),
|
||||
65279: mw.msg( 'codemirror-special-char-zero-width-no-break-space' ),
|
||||
65532: mw.msg( 'codemirror-special-char-object-replacement' )
|
||||
};
|
||||
|
||||
return highlightSpecialChars( {
|
||||
render: ( code, description, placeholder ) => {
|
||||
description = messages[ code ] || mw.msg( 'codemirror-control-character', code );
|
||||
const span = document.createElement( 'span' );
|
||||
span.className = 'cm-specialChar';
|
||||
|
||||
// Special case non-breaking spaces (T181677).
|
||||
if ( code === 160 || code === 8239 ) {
|
||||
placeholder = '·';
|
||||
span.className = 'cm-special-char-nbsp';
|
||||
}
|
||||
|
||||
span.textContent = placeholder;
|
||||
span.title = description;
|
||||
span.setAttribute( 'aria-label', description );
|
||||
return span;
|
||||
},
|
||||
// Highlight non-breaking spaces (T181677)
|
||||
addSpecialChars: /\u00a0|\u202f/g
|
||||
} );
|
||||
}
|
||||
|
||||
|
|
|
@ -142,6 +142,12 @@ const testCases = [
|
|||
title: 'Extension tag with no TagMode',
|
||||
input: '<myextension>foo\nbar\nbaz</myextension>',
|
||||
output: '<div class="cm-line"><span class="cm-mw-exttag-bracket cm-mw-ext-myextension"><</span><span class="cm-mw-exttag-name cm-mw-ext-myextension">myextension</span><span class="cm-mw-exttag-bracket cm-mw-ext-myextension">></span><span class="cm-mw-exttag">foo</span></div><div class="cm-line"><span class="cm-mw-exttag">bar</span></div><div class="cm-line"><span class="cm-mw-exttag">baz</span><span class="cm-mw-exttag-bracket cm-mw-ext-myextension"></</span><span class="cm-mw-exttag-name cm-mw-ext-myextension">myextension</span><span class="cm-mw-exttag-bracket cm-mw-ext-myextension">></span></div>'
|
||||
},
|
||||
{
|
||||
title: 'Special characters',
|
||||
input: 'Softhyphen\nzero-widthspace\nnon-breaking space\nnarrow nbsp',
|
||||
// i18n messages are the keys because we don't stub mw.msg() in this test.
|
||||
output: '<div class="cm-line">Soft<img class="cm-widgetBuffer" aria-hidden="true"><span class="cm-specialChar" title="codemirror-control-character" aria-label="codemirror-control-character">•</span><img class="cm-widgetBuffer" aria-hidden="true">hyphen</div><div class="cm-line">zero-width<img class="cm-widgetBuffer" aria-hidden="true"><span class="cm-specialChar" title="codemirror-special-char-zero-width-space" aria-label="codemirror-special-char-zero-width-space">•</span><img class="cm-widgetBuffer" aria-hidden="true">space</div><div class="cm-line">non-breaking<img class="cm-widgetBuffer" aria-hidden="true"><span class="cm-special-char-nbsp" title="codemirror-special-char-nbsp" aria-label="codemirror-special-char-nbsp">·</span><img class="cm-widgetBuffer" aria-hidden="true">space</div><div class="cm-line">narrow<img class="cm-widgetBuffer" aria-hidden="true"><span class="cm-special-char-nbsp" title="codemirror-special-char-narrow-nbsp" aria-label="codemirror-special-char-narrow-nbsp">·</span><img class="cm-widgetBuffer" aria-hidden="true">nbsp</div>'
|
||||
}
|
||||
];
|
||||
|
||||
|
|
Loading…
Reference in a new issue