Synchronise VE availability checks in frontend and backend

Adds better support for NWE loading on action=edit.

Change-Id: I35208cce0696607377378a1b58d426e914a3ba7d
This commit is contained in:
Ed Sanders 2017-04-27 16:23:26 +01:00
parent fefb76eebc
commit cd8b059e7d
2 changed files with 96 additions and 50 deletions

View file

@ -11,6 +11,20 @@
use MediaWiki\MediaWikiServices;
class VisualEditorHooks {
// Known parameters that VE does not handle
// TODO: Other params too?
// Known-good parameters: edit, veaction, section
private static $unsupportedEditParams = [
'lintid',
'preload',
'preloadparams',
'preloadtitle',
'undo',
'undoafter',
'veswitched'
];
/**
* Initialise the 'VisualEditorAvailableNamespaces' setting, and add content
* namespaces to it. This will run after LocalSettings.php is processed.
@ -56,6 +70,7 @@ class VisualEditorHooks {
$toolbarScrollOffset = $skinsToolbarScrollOffset[$skinName];
}
$output->addJsConfigVars( 'wgVisualEditorToolbarScrollOffset', $toolbarScrollOffset );
$output->addJsConfigVars( 'wgVisualEditorUnsupportedEditParams', self::$unsupportedEditParams );
$output->addJsConfigVars(
'wgEditSubmitButtonLabelPublish',
@ -108,6 +123,43 @@ class VisualEditorHooks {
return false;
}
private static function isSupportedEditPage( Title $title, User $user, WebRequest $req ) {
if ( $req->getVal( 'action' ) !== 'edit' || !$title->quickUserCan( 'edit' ) ) {
return false;
}
foreach ( self::$unsupportedEditParams as $param ) {
if ( $req->getVal( $param ) !== null ) {
return false;
}
}
if ( $req->getVal( 'wteswitched' ) ) {
return self::isVisualAvailable( $title );
}
switch ( self::getPreferredEditor( $user, $req ) ) {
case 'visualeditor':
return self::isVisualAvailable( $title ) || self::isWikitextAvailable( $title, $user );
case 'wikitext':
return self::isWikitextAvailable( $title, $user );
}
return false;
}
private static function isVisualAvailable( $title ) {
$veConfig = ConfigFactory::getDefaultInstance()->makeConfig( 'visualeditor' );
return ApiVisualEditor::isAllowedNamespace( $veConfig, $title->getNamespace() ) &&
ApiVisualEditor::isAllowedContentType( $veConfig, $title->getContentModel() );
}
private static function isWikitextAvailable( $title, $user ) {
$veConfig = ConfigFactory::getDefaultInstance()->makeConfig( 'visualeditor' );
return $veConfig->get( 'VisualEditorEnableWikitext' ) &&
$user->getOption( 'visualeditor-newwikitext' ) &&
$title->getContentModel() === 'wikitext';
}
/**
* Decide whether to bother showing the wikitext editor at all.
* If not, we expect the VE initialisation JS to activate.
@ -123,8 +175,6 @@ class VisualEditorHooks {
!$user->getOption( 'visualeditor-enable' ) ||
$user->getOption( 'visualeditor-betatempdisable' ) ||
$user->getOption( 'visualeditor-autodisable' ) ||
$user->getOption( 'visualeditor-tabs' ) === 'prefer-wt' ||
$user->getOption( 'visualeditor-tabs' ) === 'multi-tab' ||
( $veConfig->get( 'VisualEditorDisableForAnons' ) && $user->isAnon() ) ||
self::isUABlacklisted( $req, $veConfig )
) {
@ -132,9 +182,8 @@ class VisualEditorHooks {
}
$title = $article->getTitle();
$params = $req->getValues();
if ( isset( $params['venoscript'] ) ) {
if ( $req->getVal( 'venoscript' ) ) {
$req->response()->setCookie( 'VEE', 'wikitext', 0, [ 'prefix' => '' ] );
$user->setOption( 'visualeditor-editor', 'wikitext' );
if ( !wfReadOnly() && !$user->isAnon() ) {
@ -145,36 +194,23 @@ class VisualEditorHooks {
return true;
}
$ret = $req->getVal( 'action' ) !== 'edit' ||
!$veConfig->get( 'VisualEditorUseSingleEditTab' ) ||
self::getUserEditor( $user, $req ) === 'wikitext' ||
!$title->quickUserCan( 'edit' ) ||
!ApiVisualEditor::isAllowedNamespace( $veConfig, $title->getNamespace() ) ||
!ApiVisualEditor::isAllowedContentType( $veConfig, $title->getContentModel() ) ||
// Known parameters that VE does not handle
// TODO: Other params too? Expose this in JS for ve.init.mw.DesktopArticleTarget.init.js
isset( $params['undo'] ) ||
isset( $params['undoafter'] ) ||
isset( $params['preload'] ) ||
isset( $params['preloadtitle'] ) ||
isset( $params['preloadparams'] ) ||
isset( $params['lintid'] ) ||
isset( $params['veswitched'] );
// Known-good parameters: edit, veaction, section
$params['venoscript'] = '1';
$url = wfScript() . '?' . wfArrayToCgi( $params );
$out = $article->getContext()->getOutput();
if ( !$ret ) {
if ( self::isSupportedEditPage( $title, $user, $req ) ) {
$params = $req->getValues();
$params['venoscript'] = '1';
$url = wfScript() . '?' . wfArrayToCgi( $params );
$escapedUrl = htmlspecialchars( $url );
$out = $article->getContext()->getOutput();
$titleMsg = $title->exists() ? 'editing' : 'creating';
$out->setPageTitle( wfMessage( $titleMsg, $title->getPrefixedText() ) );
$out->addWikiMsg( 'visualeditor-toload', wfExpandUrl( $url ) );
// Redirect if the user has no JS (<noscript>)
$out->addHeadItem(
've-noscript-fallback',
"<noscript><meta http-equiv=\"refresh\" content=\"0; url=$escapedUrl\"></noscript>"
);
$titleMsg = $title->exists() ? 'editing' : 'creating';
$out->setPageTitle( wfMessage( $titleMsg, $title->getPrefixedText() ) );
$out->addWikiMsg( 'visualeditor-toload', wfExpandUrl( $url ) );
// Redirect if the user has no ResourceLoader
$out->addScript( Html::inlineScript(
"(window.NORLQ=window.NORLQ||[]).push(" .
"function(){" .
@ -182,11 +218,29 @@ class VisualEditorHooks {
"}" .
");"
) );
return false;
}
return $ret;
return true;
}
private static function getUserEditor( User $user, WebRequest $req ) {
private static function getPreferredEditor( User $user, WebRequest $req ) {
switch ( $user->getOption( 'visualeditor-tabs' ) ) {
case 'prefer-ve':
return 'visualeditor';
case 'prefer-wt':
return 'wikitext';
case 'remember-last':
return self::getLastEditor( $user, $req );
case 'multi-tab':
// May have got here by switching from VE
// TODO: Make such an action explicitly request wikitext
// so we can use getLastEditor here instead.
return 'wikitext';
}
return null;
}
private static function getLastEditor( User $user, WebRequest $req ) {
// This logic matches getLastEditor in:
// modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
$editor = $req->getCookie( 'VEE', '' );
@ -318,7 +372,7 @@ class VisualEditorHooks {
$editTab['text'] = $skin->msg( $editTabMessage )->text();
}
$editor = self::getUserEditor( $user, $skin->getRequest() );
$editor = self::getLastEditor( $user, $skin->getRequest() );
if (
$isAvailable &&
$config->get( 'VisualEditorUseSingleEditTab' ) &&
@ -446,7 +500,7 @@ class VisualEditorHooks {
return true;
}
$editor = self::getUserEditor( $user, RequestContext::getMain()->getRequest() );
$editor = self::getLastEditor( $user, RequestContext::getMain()->getRequest() );
if (
!$config->get( 'VisualEditorUseSingleEditTab' ) ||
$user->getOption( 'visualeditor-tabs' ) === 'multi-tab' ||

View file

@ -313,7 +313,7 @@
}
function getLastEditor() {
// This logic matches VisualEditorHooks::getUserEditor
// This logic matches VisualEditorHooks::getLastEditor
var editor = $.cookie( 'VEE' );
// Set editor to user's preference or site's default if …
if (
@ -337,10 +337,12 @@
return 'visualeditor';
case 'prefer-wt':
return 'wikitext';
default:
// Two tabs, no preference
return null;
case 'multi-tab':
// 'multi-tab'
// TODO: See VisualEditor.hooks.php
return 'wikitext';
}
return null;
}
conf = mw.config.get( 'wgVisualEditorConfig' );
@ -785,6 +787,7 @@
mw.config.get( 'wgNamespaceNumber' ) !== -1
);
// Duplicated in VisualEditor.hooks.php#isVisualAvailable()
init.isVisualAvailable = (
init.isAvailable &&
@ -795,6 +798,7 @@
conf.contentModels.hasOwnProperty( mw.config.get( 'wgPageContentModel' ) )
);
// Duplicated in VisualEditor.hooks.php#isWikitextAvailable()
init.isWikitextAvailable = (
init.isAvailable &&
@ -863,19 +867,7 @@
}
function isSupportedEditPage() {
// Known-good parameters: edit, veaction, section
// TODO: Expose this from VisualEditor.hooks.php
var unsupportedParams = [
'lintid',
'preload',
'preloadparams',
'preloadtitle',
'undo',
'undoafter',
'veswitched'
];
return unsupportedParams.every( function ( param ) {
return mw.config.get( 'wgVisualEditorUnsupportedEditParams' ).every( function ( param ) {
return uri.query[ param ] === undefined;
} );
}