CM6: put template folding behind feature flag and rework config settings

Template folding is likely going to be a big 'hit' of a feature, but not
everyone will want it. Until CodeMirror prefs are introduced (T359498),
we need a way to control the rollout of template folding. This commit
adds $wgCodeMirrorTemplateFoldingNamespaces which acts similar to the
existing $wgCodeMirrorLineNumberingNamespaces.

We also move template folding to be part of CodeMirrorModeMediaWiki,
since the feature is unique to MediaWiki wikitext.

Move configuration settings to be part of the DataScript, thus removing
the need for the ResourceLoaderGetConfigVarsHook (which unnecessarily
makes the config settings available on every page load).

Other minor changes like adding missing JSDoc blocks.

Bug: T30684
Change-Id: I67518c0968f64c79e290f57b4884d30a161212d3
This commit is contained in:
MusikAnimal 2024-03-11 14:10:08 -04:00
parent 3a6c805135
commit 7e9d90bb52
10 changed files with 55 additions and 50 deletions

View file

@ -16,11 +16,6 @@
"MediaWiki": ">= 1.42.0"
},
"config": {
"CodeMirrorLineNumberingNamespaces": {
"value": null,
"description": "List of namespace IDs where line numbering should be enabled, or `null` to enable for all namespaces. Set to [] to disable everywhere. Defaults to `null` for all namespaces.",
"public": true
},
"CodeMirrorV6": {
"value": false,
"description": "Temporary feature flag for the CodeMirror 6 upgrade."
@ -31,6 +26,16 @@
],
"description": "An array of gadget names that, if enabled, will prevent CodeMirror from loading on action=edit and action=submit.",
"public": true
},
"CodeMirrorTemplateFoldingNamespaces": {
"value": null,
"description": "List of namespace IDs where template folding should be enabled, or `null` to enable for all namespaces. Set to [] to disable everywhere.",
"public": true
},
"CodeMirrorLineNumberingNamespaces": {
"value": null,
"description": "List of namespace IDs where line numbering should be enabled, or `null` to enable for all namespaces. Set to [] to disable everywhere.",
"public": true
}
},
"MessagesDirs": {
@ -252,8 +257,7 @@
"Hooks": {
"EditPage::showEditForm:initial": "main",
"EditPage::showReadOnlyForm:initial": "main",
"GetPreferences": "main",
"ResourceLoaderGetConfigVars": "main"
"GetPreferences": "main"
},
"HookHandlers": {
"main": {

View file

@ -51,12 +51,15 @@ class DataScript {
$lang = MediaWikiServices::getInstance()->getContentLanguage();
$registry = ExtensionRegistry::getInstance();
$parser = MediaWikiServices::getInstance()->getParser();
$mwConfig = MediaWikiServices::getInstance()->getMainConfig();
$tagModes = $registry->getAttribute( 'CodeMirrorTagModes' );
$tagNames = array_merge( $parser->getTags(), array_keys( $tagModes ) );
// initialize configuration
$config = [
'lineNumberingNamespaces' => $mwConfig->get( 'CodeMirrorLineNumberingNamespaces' ),
'templateFoldingNamespaces' => $mwConfig->get( 'CodeMirrorTemplateFoldingNamespaces' ),
'pluginModules' => $registry->getAttribute( 'CodeMirrorPluginModules' ),
'tagModes' => $tagModes,
'tags' => array_fill_keys( $tagNames, true ),

View file

@ -11,7 +11,6 @@ use MediaWiki\Hook\EditPage__showEditForm_initialHook;
use MediaWiki\Hook\EditPage__showReadOnlyForm_initialHook;
use MediaWiki\Output\OutputPage;
use MediaWiki\Preferences\Hook\GetPreferencesHook;
use MediaWiki\ResourceLoader\Hook\ResourceLoaderGetConfigVarsHook;
use MediaWiki\User\Options\UserOptionsLookup;
use MediaWiki\User\User;
@ -21,7 +20,6 @@ use MediaWiki\User\User;
class Hooks implements
EditPage__showEditForm_initialHook,
EditPage__showReadOnlyForm_initialHook,
ResourceLoaderGetConfigVarsHook,
GetPreferencesHook
{
@ -143,20 +141,6 @@ class Hooks implements
return $this->useV6 || $out->getRequest()->getRawVal( 'cm6enable' );
}
/**
* Hook handler for enabling bracket matching.
*
* TODO: restrict to pages where codemirror might be enabled.
*
* @param array &$vars Array of variables to be added into the output of the startup module
* @param string $skin
* @param Config $config
* @return void This hook must not abort, it must return no value
*/
public function onResourceLoaderGetConfigVars( array &$vars, $skin, Config $config ): void {
$vars['wgCodeMirrorLineNumberingNamespaces'] = $config->get( 'CodeMirrorLineNumberingNamespaces' );
}
/**
* GetPreferences hook handler
*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,6 +3,11 @@ import { EditorView, lineNumbers, highlightSpecialChars } from '@codemirror/view
import CodemirrorTextSelection from './codemirror.textSelection';
import bidiIsolationExtension from './codemirror.bidiIsolation';
// Necessary so that `require` doesn't get mangled into `__webpack_require__`,
// which ResourceLoader won't recognize and thus be unable to load the virtual file.
// See https://webpack-v3.jsx.app/api/module-variables/#__non_webpack_require__-webpack-specific-
__non_webpack_require__( '../ext.CodeMirror.data.js' );
/**
* @class CodeMirror
* @property {jQuery} $textarea
@ -47,10 +52,11 @@ export default class CodeMirror {
}
// Set to [] to disable everywhere, or null to enable everywhere
const namespaces = mw.config.get( 'wgCodeMirrorLineNumberingNamespaces' );
const namespaces = mw.config.get( 'extCodeMirrorConfig' ).lineNumberingNamespaces;
if ( !namespaces || namespaces.includes( mw.config.get( 'wgNamespaceNumber' ) ) ) {
extensions.push( lineNumbers() );
}
return extensions;
}

View file

@ -8,6 +8,7 @@ import {
} from '@codemirror/language';
import { mwModeConfig as modeConfig } from './codemirror.mode.mediawiki.config';
import { Tag } from '@lezer/highlight';
import { templateFoldingExtension } from './codemirror.templateFolding';
/**
* Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov
@ -1202,7 +1203,7 @@ class CodeMirrorModeMediaWiki {
/**
* Extra tokens to use in this parser.
*
* @see CodeMirrorModeMediaWikiConfig.tokenTable
* @see CodeMirrorModeMediaWikiConfig.defaultTokenTable
* @return {Object<Tag>}
*/
tokenTable: this.tokenTable
@ -1223,15 +1224,22 @@ class CodeMirrorModeMediaWiki {
* @return {LanguageSupport}
*/
export const mediaWikiLang = ( config = null ) => {
const mode = new CodeMirrorModeMediaWiki(
config || mw.config.get( 'extCodeMirrorConfig' )
);
config = config || mw.config.get( 'extCodeMirrorConfig' );
const mode = new CodeMirrorModeMediaWiki( config );
const parser = mode.mediawiki;
const lang = StreamLanguage.define( parser );
const highlighter = syntaxHighlighting(
const langExtension = [ syntaxHighlighting(
HighlightStyle.define(
modeConfig.getTagStyles( parser )
)
);
return new LanguageSupport( lang, highlighter );
) ];
// Add template folding if in supported namespace.
const templateFoldingNs = config.templateFoldingNamespaces;
// Set to [] to disable everywhere, or null to enable everywhere.
if ( !templateFoldingNs || templateFoldingNs.includes( mw.config.get( 'wgNamespaceNumber' ) ) ) {
langExtension.push( templateFoldingExtension );
}
return new LanguageSupport( lang, langExtension );
};

View file

@ -3,20 +3,23 @@ import { EditorState, EditorSelection } from '@codemirror/state';
import { EditorView, drawSelection, keymap } from '@codemirror/view';
import { defaultKeymap, history, historyKeymap } from '@codemirror/commands';
import { searchKeymap } from '@codemirror/search';
import { bracketMatching } from '@codemirror/language';
// Necessary so that `require` doesn't get mangled into `__webpack_require__`,
// which ResourceLoader won't recognize and thus be unable to load the virtual file.
// See https://webpack-v3.jsx.app/api/module-variables/#__non_webpack_require__-webpack-specific-
__non_webpack_require__( '../ext.CodeMirror.data.js' );
import { bracketMatching, LanguageSupport } from '@codemirror/language';
/**
* @class CodeMirrorWikiEditor
* @property {LanguageSupport|Extension} langExtension
* @property {Function|null} editRecoveryHandler
* @property {boolean} useCodeMirror
*/
export default class CodeMirrorWikiEditor extends CodeMirror {
constructor( $textarea, langExtensions ) {
/**
* @constructor
* @param {jQuery} $textarea
* @param {LanguageSupport|Extension} langExtension
*/
constructor( $textarea, langExtension ) {
super( $textarea );
this.langExtensions = langExtensions;
this.langExtension = langExtension;
this.editRecoveryHandler = null;
this.useCodeMirror = mw.user.options.get( 'usecodemirror' ) > 0;
}
@ -25,7 +28,8 @@ export default class CodeMirrorWikiEditor extends CodeMirror {
* @inheritDoc
*/
setCodeMirrorPreference( prefValue ) {
this.useCodeMirror = prefValue; // Save state for function updateToolbarButton()
// Save state for function updateToolbarButton()
this.useCodeMirror = prefValue;
super.setCodeMirrorPreference( prefValue );
}
@ -49,7 +53,7 @@ export default class CodeMirrorWikiEditor extends CodeMirror {
*/
const extensions = [
...this.defaultExtensions,
...this.langExtensions,
this.langExtension,
bracketMatching(),
history(),
// See also the default attributes at contentAttributesExtension() in the parent class.

View file

@ -1,13 +1,9 @@
import CodeMirrorWikiEditor from './codemirror.wikieditor';
import { mediaWikiLang } from './codemirror.mode.mediawiki';
import { templateFoldingExtension } from './codemirror.templateFolding';
if ( mw.loader.getState( 'ext.wikiEditor' ) ) {
mw.hook( 'wikiEditor.toolbarReady' ).add( ( $textarea ) => {
const cmWE = new CodeMirrorWikiEditor( $textarea, [
mediaWikiLang(),
templateFoldingExtension
] );
const cmWE = new CodeMirrorWikiEditor( $textarea, mediaWikiLang() );
cmWE.addCodeMirrorToWikiEditor();
} );
}

View file

@ -89,8 +89,8 @@ module.exports = ( env, argv ) => ( {
// Minified uncompressed size limits for chunks / assets and entrypoints. Keep these numbers
// up-to-date and rounded to the nearest 10th of a kibibyte so that code sizing costs are
// well understood. Related to bundlesize minified, gzipped compressed file size tests.
maxAssetSize: 351.0 * 1024,
maxEntrypointSize: 351.0 * 1024,
maxAssetSize: 352.0 * 1024,
maxEntrypointSize: 352.0 * 1024,
// The default filter excludes map files, but we rename ours.
assetFilter: ( filename ) => !filename.endsWith( srcMapExt )