2012-05-25 19:50:48 +00:00
|
|
|
|
<?php
|
2012-07-19 00:11:26 +00:00
|
|
|
|
/**
|
|
|
|
|
* VisualEditor extension hooks
|
2012-07-19 21:25:16 +00:00
|
|
|
|
*
|
2012-07-19 00:11:26 +00:00
|
|
|
|
* @file
|
|
|
|
|
* @ingroup Extensions
|
2020-01-08 17:13:04 +00:00
|
|
|
|
* @copyright 2011-2020 VisualEditor Team and others; see AUTHORS.txt
|
2018-03-28 19:47:04 +00:00
|
|
|
|
* @license MIT
|
2012-07-19 00:11:26 +00:00
|
|
|
|
*/
|
2012-05-25 19:50:48 +00:00
|
|
|
|
|
2017-04-19 15:15:06 +00:00
|
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
|
2012-05-25 19:50:48 +00:00
|
|
|
|
class VisualEditorHooks {
|
2017-04-27 15:23:26 +00:00
|
|
|
|
|
|
|
|
|
// Known parameters that VE does not handle
|
|
|
|
|
// TODO: Other params too?
|
2017-09-20 15:16:32 +00:00
|
|
|
|
// Known-good parameters: edit, veaction, section, oldid, lintid, preload, preloadparams, editintro
|
|
|
|
|
// Partially-good: preloadtitle (source-mode only)
|
2017-04-27 15:23:26 +00:00
|
|
|
|
private static $unsupportedEditParams = [
|
|
|
|
|
'undo',
|
|
|
|
|
'undoafter',
|
2019-05-18 16:15:51 +00:00
|
|
|
|
// Only for WTE. This parameter is not supported right now, and NWE has a very different design
|
|
|
|
|
// for previews, so we might not want to support this at all.
|
|
|
|
|
'preview',
|
2017-04-27 15:23:26 +00:00
|
|
|
|
'veswitched'
|
|
|
|
|
];
|
|
|
|
|
|
2020-02-06 21:10:24 +00:00
|
|
|
|
private static $tags = [
|
|
|
|
|
'visualeditor',
|
|
|
|
|
'visualeditor-wikitext',
|
|
|
|
|
// No longer in active use:
|
|
|
|
|
'visualeditor-needcheck',
|
|
|
|
|
'visualeditor-switched'
|
|
|
|
|
];
|
|
|
|
|
|
2015-01-27 05:47:31 +00:00
|
|
|
|
/**
|
2015-08-02 21:30:43 +00:00
|
|
|
|
* Initialise the 'VisualEditorAvailableNamespaces' setting, and add content
|
|
|
|
|
* namespaces to it. This will run after LocalSettings.php is processed.
|
2020-07-07 20:16:06 +00:00
|
|
|
|
* Also ensure Parsoid extension is loaded when necessary.
|
2015-01-27 05:47:31 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onRegistration() {
|
2020-07-07 20:16:06 +00:00
|
|
|
|
global $wgVisualEditorAvailableNamespaces, $wgContentNamespaces,
|
|
|
|
|
$wgVisualEditorParsoidAutoConfig, $wgVirtualRestConfig, $wgRestAPIAdditionalRouteFiles;
|
|
|
|
|
// phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix
|
|
|
|
|
global $IP;
|
2015-01-27 05:47:31 +00:00
|
|
|
|
|
2015-08-02 21:30:43 +00:00
|
|
|
|
foreach ( $wgContentNamespaces as $contentNamespace ) {
|
|
|
|
|
if ( !isset( $wgVisualEditorAvailableNamespaces[$contentNamespace] ) ) {
|
|
|
|
|
$wgVisualEditorAvailableNamespaces[$contentNamespace] = true;
|
|
|
|
|
}
|
2015-07-06 18:57:13 +00:00
|
|
|
|
}
|
2020-07-07 20:16:06 +00:00
|
|
|
|
|
|
|
|
|
// For the 1.35 LTS, Parsoid is loaded from includes/VEParsoid to provide a
|
|
|
|
|
// "zero configuration" VisualEditor experience. In Wikimedia production, we
|
|
|
|
|
// have $wgVisualEditorParsoidAutoConfig off (and $wgVirtualRestConfig set to
|
|
|
|
|
// point to a separate cluster which has the Parsoid extension installed), so
|
|
|
|
|
// this code won't be executed.
|
|
|
|
|
if (
|
|
|
|
|
$wgVisualEditorParsoidAutoConfig
|
|
|
|
|
&& !ExtensionRegistry::getInstance()->isLoaded( 'Parsoid' )
|
|
|
|
|
// Generally manually configuring VRS means that you're running
|
|
|
|
|
// Parsoid on a different host. If you need to manually configure
|
|
|
|
|
// VRS, load the Parsoid extension explicitly.
|
|
|
|
|
&& !isset( $wgVirtualRestConfig['modules']['parsoid'] )
|
|
|
|
|
&& !isset( $wgVirtualRestConfig['modules']['restbase'] )
|
|
|
|
|
) {
|
|
|
|
|
// Only install these route files if we're auto-configuring and
|
|
|
|
|
// the parsoid extension isn't loaded, otherwise we'll conflict.
|
|
|
|
|
$wgRestAPIAdditionalRouteFiles[] = wfRelativePath(
|
|
|
|
|
__DIR__ . '/VEParsoid/parsoidRoutes.json', $IP
|
|
|
|
|
);
|
|
|
|
|
}
|
2015-01-27 05:47:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-25 19:50:48 +00:00
|
|
|
|
/**
|
2013-08-01 19:14:41 +00:00
|
|
|
|
* Adds VisualEditor JS to the output.
|
2012-06-11 06:54:41 +00:00
|
|
|
|
*
|
|
|
|
|
* This is attached to the MediaWiki 'BeforePageDisplay' hook.
|
2012-05-25 19:50:48 +00:00
|
|
|
|
*
|
2019-05-04 21:02:29 +00:00
|
|
|
|
* @param OutputPage $output The page view.
|
|
|
|
|
* @param Skin $skin The skin that's going to build the UI.
|
2012-05-25 19:50:48 +00:00
|
|
|
|
*/
|
2019-05-04 21:02:29 +00:00
|
|
|
|
public static function onBeforePageDisplay( OutputPage $output, Skin $skin ) {
|
2019-11-01 22:05:59 +00:00
|
|
|
|
if ( !(
|
|
|
|
|
ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) &&
|
|
|
|
|
MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' )
|
|
|
|
|
->shouldDisplayMobileView()
|
|
|
|
|
) ) {
|
|
|
|
|
$output->addModules( [
|
|
|
|
|
'ext.visualEditor.desktopArticleTarget.init',
|
|
|
|
|
'ext.visualEditor.targetLoader'
|
|
|
|
|
] );
|
|
|
|
|
$output->addModuleStyles( [ 'ext.visualEditor.desktopArticleTarget.noscript' ] );
|
|
|
|
|
}
|
2015-04-09 09:18:22 +00:00
|
|
|
|
// add scroll offset js variable to output
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2015-04-09 09:18:22 +00:00
|
|
|
|
$skinsToolbarScrollOffset = $veConfig->get( 'VisualEditorSkinToolbarScrollOffset' );
|
|
|
|
|
$toolbarScrollOffset = 0;
|
|
|
|
|
$skinName = $skin->getSkinName();
|
|
|
|
|
if ( isset( $skinsToolbarScrollOffset[$skinName] ) ) {
|
|
|
|
|
$toolbarScrollOffset = $skinsToolbarScrollOffset[$skinName];
|
|
|
|
|
}
|
2019-04-05 18:40:36 +00:00
|
|
|
|
// T220158: Don't add this unless it's non-default
|
|
|
|
|
// TODO: Move this to packageFiles as it's not relevant to the HTML request.
|
|
|
|
|
if ( $toolbarScrollOffset !== 0 ) {
|
|
|
|
|
$output->addJsConfigVars( 'wgVisualEditorToolbarScrollOffset', $toolbarScrollOffset );
|
|
|
|
|
}
|
2016-06-30 14:04:51 +00:00
|
|
|
|
|
2018-02-07 19:48:49 +00:00
|
|
|
|
$output->addJsConfigVars(
|
|
|
|
|
'wgEditSubmitButtonLabelPublish',
|
|
|
|
|
$veConfig->get( 'EditSubmitButtonLabelPublish' )
|
|
|
|
|
);
|
2013-08-01 19:14:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 19:48:25 +00:00
|
|
|
|
/**
|
|
|
|
|
* @internal For internal use in extension.json only.
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
|
|
|
|
public static function getDataForDesktopArticleTargetInitModule() {
|
|
|
|
|
return [
|
|
|
|
|
'unsupportedEditParams' => self::$unsupportedEditParams,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 19:47:04 +00:00
|
|
|
|
/**
|
2020-06-24 00:43:27 +00:00
|
|
|
|
* Handler for the DifferenceEngineViewHeader hook, to add visual diffs code as configured
|
2018-03-28 19:47:04 +00:00
|
|
|
|
*
|
|
|
|
|
* @param DifferenceEngine $diff The difference engine
|
2018-12-09 15:26:30 +00:00
|
|
|
|
* @return void
|
2018-03-28 19:47:04 +00:00
|
|
|
|
*/
|
2020-06-24 00:43:27 +00:00
|
|
|
|
public static function onDifferenceEngineViewHeader( DifferenceEngine $diff ) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2017-06-09 13:45:59 +00:00
|
|
|
|
$output = RequestContext::getMain()->getOutput();
|
2018-01-25 21:36:05 +00:00
|
|
|
|
$user = RequestContext::getMain()->getUser();
|
|
|
|
|
|
|
|
|
|
if ( !(
|
|
|
|
|
// Enabled globally on wiki
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig->get( 'VisualEditorEnableDiffPage' ) ||
|
2018-01-25 21:36:05 +00:00
|
|
|
|
// Enabled as user beta feature
|
|
|
|
|
$user->getOption( 'visualeditor-visualdiffpage' ) ||
|
|
|
|
|
// Enabled by query param
|
|
|
|
|
$output->getRequest()->getVal( 'visualdiff' ) !== null
|
|
|
|
|
) ) {
|
2017-06-09 13:45:59 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 22:09:04 +00:00
|
|
|
|
if ( !ApiVisualEditor::isAllowedContentType( $veConfig, $diff->getTitle()->getContentModel() ) ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-09 13:45:59 +00:00
|
|
|
|
$output->addModuleStyles( [
|
|
|
|
|
'ext.visualEditor.diffPage.init.styles',
|
2019-09-30 20:55:47 +00:00
|
|
|
|
'oojs-ui.styles.icons-accessibility',
|
2017-06-09 13:45:59 +00:00
|
|
|
|
'oojs-ui.styles.icons-editing-advanced'
|
|
|
|
|
] );
|
|
|
|
|
$output->addModules( 'ext.visualEditor.diffPage.init' );
|
|
|
|
|
$output->enableOOUI();
|
|
|
|
|
$output->addHtml(
|
|
|
|
|
'<div class="ve-init-mw-diffPage-diffMode">' .
|
|
|
|
|
// Will be replaced by a ButtonSelectWidget in JS
|
|
|
|
|
new OOUI\ButtonGroupWidget( [
|
|
|
|
|
'items' => [
|
|
|
|
|
new \OOUI\ButtonWidget( [
|
|
|
|
|
'data' => 'visual',
|
|
|
|
|
'icon' => 'eye',
|
|
|
|
|
'disabled' => true,
|
|
|
|
|
'label' => $output->msg( 'visualeditor-savedialog-review-visual' )->plain()
|
|
|
|
|
] ),
|
|
|
|
|
new \OOUI\ButtonWidget( [
|
|
|
|
|
'data' => 'source',
|
|
|
|
|
'icon' => 'wikiText',
|
|
|
|
|
'active' => true,
|
|
|
|
|
'label' => $output->msg( 'visualeditor-savedialog-review-wikitext' )->plain()
|
|
|
|
|
] )
|
|
|
|
|
]
|
|
|
|
|
] ) .
|
|
|
|
|
'</div>'
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 22:39:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* Detect incompatibile browsers which we can't expect to load VE
|
|
|
|
|
*
|
|
|
|
|
* @param WebRequest $req The web request to check the details of
|
|
|
|
|
* @param Config $config VE config object
|
2020-06-10 11:03:51 +00:00
|
|
|
|
* @return bool The User Agent is unsupported
|
2015-12-16 22:39:19 +00:00
|
|
|
|
*/
|
2020-06-10 11:03:51 +00:00
|
|
|
|
private static function isUAUnsupported( WebRequest $req, $config ) {
|
|
|
|
|
if ( $req->getVal( 'vesupported' ) ) {
|
2015-12-16 22:39:19 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-06-10 11:03:51 +00:00
|
|
|
|
$unsupportedList = $config->get( 'VisualEditorBrowserUnsupportedList' );
|
2015-12-16 22:39:19 +00:00
|
|
|
|
$ua = strtolower( $req->getHeader( 'User-Agent' ) );
|
2020-06-10 11:03:51 +00:00
|
|
|
|
foreach ( $unsupportedList as $uaSubstr => $rules ) {
|
2016-01-22 02:22:34 +00:00
|
|
|
|
if ( !strpos( $ua, $uaSubstr . '/' ) ) {
|
2015-12-16 22:39:19 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if ( !is_array( $rules ) ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$matches = [];
|
2016-01-22 02:22:34 +00:00
|
|
|
|
$ret = preg_match( '/' . $uaSubstr . '\/([0-9\.]*) ?/i', $ua, $matches );
|
|
|
|
|
if ( $ret !== 1 ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
$version = $matches[1];
|
2015-12-16 22:39:19 +00:00
|
|
|
|
foreach ( $rules as $rule ) {
|
|
|
|
|
list( $op, $matchVersion ) = $rule;
|
|
|
|
|
if (
|
|
|
|
|
( $op === '<' && $version < $matchVersion ) ||
|
|
|
|
|
( $op === '>' && $version > $matchVersion ) ||
|
|
|
|
|
( $op === '<=' && $version <= $matchVersion ) ||
|
|
|
|
|
( $op === '>=' && $version >= $matchVersion )
|
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 23:00:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @param WebRequest $req
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2017-04-27 15:23:26 +00:00
|
|
|
|
private static function isSupportedEditPage( Title $title, User $user, WebRequest $req ) {
|
2020-02-12 23:39:55 +00:00
|
|
|
|
if (
|
|
|
|
|
$req->getVal( 'action' ) !== 'edit' ||
|
|
|
|
|
!MediaWikiServices::getInstance()->getPermissionManager()->quickUserCan( 'edit', $user, $title )
|
|
|
|
|
) {
|
2017-04-27 15:23:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ( self::$unsupportedEditParams as $param ) {
|
|
|
|
|
if ( $req->getVal( $param ) !== null ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $req->getVal( 'wteswitched' ) ) {
|
2020-01-26 18:53:57 +00:00
|
|
|
|
return self::isVisualAvailable( $title, $req, $user );
|
2017-04-27 15:23:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-07 13:30:52 +00:00
|
|
|
|
switch ( self::getEditPageEditor( $user, $req ) ) {
|
2017-04-27 15:23:26 +00:00
|
|
|
|
case 'visualeditor':
|
2020-01-26 18:53:57 +00:00
|
|
|
|
return self::isVisualAvailable( $title, $req, $user ) ||
|
|
|
|
|
self::isWikitextAvailable( $title, $user );
|
2017-04-27 15:23:26 +00:00
|
|
|
|
case 'wikitext':
|
2020-05-07 13:30:52 +00:00
|
|
|
|
default:
|
2017-04-27 15:23:26 +00:00
|
|
|
|
return self::isWikitextAvailable( $title, $user );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-26 18:53:57 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
|
|
|
|
private static function enabledForUser( $user ) {
|
|
|
|
|
return $user->getOption( 'visualeditor-enable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-betatempdisable' ) &&
|
2020-06-05 16:35:29 +00:00
|
|
|
|
!$user->getOption( 'visualeditor-autodisable' );
|
2020-01-26 18:53:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 23:00:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param WebRequest $req
|
2020-01-26 18:53:57 +00:00
|
|
|
|
* @param User $user
|
2020-01-10 23:00:20 +00:00
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2020-01-26 18:53:57 +00:00
|
|
|
|
private static function isVisualAvailable( $title, $req, $user ) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2020-01-26 18:53:57 +00:00
|
|
|
|
|
2019-05-09 20:37:28 +00:00
|
|
|
|
return (
|
2020-01-26 18:53:57 +00:00
|
|
|
|
// If forced by the URL parameter, skip the namespace check (T221892) and preference check
|
|
|
|
|
$req->getVal( 'veaction' ) === 'edit' || (
|
2019-05-09 20:37:28 +00:00
|
|
|
|
// Only in enabled namespaces
|
2020-01-26 18:53:57 +00:00
|
|
|
|
ApiVisualEditor::isAllowedNamespace( $veConfig, $title->getNamespace() ) &&
|
|
|
|
|
|
|
|
|
|
// Enabled per user preferences
|
|
|
|
|
self::enabledForUser( $user )
|
2019-05-09 20:37:28 +00:00
|
|
|
|
) &&
|
|
|
|
|
// Only for pages with a supported content model
|
2020-01-26 18:53:57 +00:00
|
|
|
|
ApiVisualEditor::isAllowedContentType( $veConfig, $title->getContentModel() )
|
|
|
|
|
);
|
2017-04-27 15:23:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 23:00:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param Title $title
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @return bool
|
|
|
|
|
*/
|
2017-04-27 15:23:26 +00:00
|
|
|
|
private static function isWikitextAvailable( $title, $user ) {
|
2018-02-23 01:17:00 +00:00
|
|
|
|
return $user->getOption( 'visualeditor-newwikitext' ) &&
|
2017-04-27 15:23:26 +00:00
|
|
|
|
$title->getContentModel() === 'wikitext';
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-23 16:29:56 +00:00
|
|
|
|
/**
|
|
|
|
|
* Decide whether to bother showing the wikitext editor at all.
|
|
|
|
|
* If not, we expect the VE initialisation JS to activate.
|
2017-05-04 22:59:27 +00:00
|
|
|
|
*
|
|
|
|
|
* @param Article $article The article being viewed.
|
|
|
|
|
* @param User $user The user-specific settings.
|
2017-07-25 14:49:56 +00:00
|
|
|
|
* @return bool Whether to show the wikitext editor or not.
|
2015-10-23 16:29:56 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onCustomEditor( Article $article, User $user ) {
|
2015-12-17 18:18:32 +00:00
|
|
|
|
$req = $article->getContext()->getRequest();
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2015-10-23 16:29:56 +00:00
|
|
|
|
|
|
|
|
|
if (
|
2020-01-26 18:53:57 +00:00
|
|
|
|
!self::enabledForUser( $user ) ||
|
2020-06-10 11:03:51 +00:00
|
|
|
|
self::isUAUnsupported( $req, $veConfig )
|
2015-10-23 16:29:56 +00:00
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$title = $article->getTitle();
|
|
|
|
|
|
2017-04-27 15:23:26 +00:00
|
|
|
|
if ( $req->getVal( 'venoscript' ) ) {
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$req->response()->setCookie( 'VEE', 'wikitext', 0, [ 'prefix' => '' ] );
|
2015-12-17 18:18:32 +00:00
|
|
|
|
$user->setOption( 'visualeditor-editor', 'wikitext' );
|
2016-04-21 14:33:24 +00:00
|
|
|
|
if ( !wfReadOnly() && !$user->isAnon() ) {
|
|
|
|
|
DeferredUpdates::addCallableUpdate( function () use ( $user ) {
|
|
|
|
|
$user->saveSettings();
|
|
|
|
|
} );
|
|
|
|
|
}
|
2015-12-17 18:18:32 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-27 15:23:26 +00:00
|
|
|
|
if ( self::isSupportedEditPage( $title, $user, $req ) ) {
|
|
|
|
|
$params = $req->getValues();
|
|
|
|
|
$params['venoscript'] = '1';
|
|
|
|
|
$url = wfScript() . '?' . wfArrayToCgi( $params );
|
2016-01-23 00:14:32 +00:00
|
|
|
|
$escapedUrl = htmlspecialchars( $url );
|
2016-02-05 02:26:14 +00:00
|
|
|
|
|
2017-04-27 15:23:26 +00:00
|
|
|
|
$out = $article->getContext()->getOutput();
|
2016-02-05 02:26:14 +00:00
|
|
|
|
$titleMsg = $title->exists() ? 'editing' : 'creating';
|
|
|
|
|
$out->setPageTitle( wfMessage( $titleMsg, $title->getPrefixedText() ) );
|
2016-02-27 01:47:15 +00:00
|
|
|
|
$out->addWikiMsg( 'visualeditor-toload', wfExpandUrl( $url ) );
|
2017-04-27 15:23:26 +00:00
|
|
|
|
|
|
|
|
|
// Redirect if the user has no JS (<noscript>)
|
|
|
|
|
$out->addHeadItem(
|
|
|
|
|
've-noscript-fallback',
|
|
|
|
|
"<noscript><meta http-equiv=\"refresh\" content=\"0; url=$escapedUrl\"></noscript>"
|
|
|
|
|
);
|
|
|
|
|
// Redirect if the user has no ResourceLoader
|
2017-04-18 17:47:04 +00:00
|
|
|
|
$out->addScript( Html::inlineScript(
|
|
|
|
|
"(window.NORLQ=window.NORLQ||[]).push(" .
|
|
|
|
|
"function(){" .
|
|
|
|
|
"location.href=\"$url\";" .
|
|
|
|
|
"}" .
|
|
|
|
|
");"
|
|
|
|
|
) );
|
2017-11-08 14:41:40 +00:00
|
|
|
|
$out->setRevisionId( $req->getInt( 'oldid', $article->getRevIdFetched() ) );
|
2017-04-27 15:23:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 23:00:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @param WebRequest $req
|
2020-05-07 13:30:52 +00:00
|
|
|
|
* @return string 'wikitext' or 'visual'
|
2020-01-10 23:00:20 +00:00
|
|
|
|
*/
|
2020-05-07 13:30:52 +00:00
|
|
|
|
private static function getEditPageEditor( User $user, WebRequest $req ) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$config = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2019-05-19 12:54:32 +00:00
|
|
|
|
$isRedLink = $req->getBool( 'redlink' );
|
|
|
|
|
// On dual-edit-tab wikis, the edit page must mean the user wants wikitext,
|
|
|
|
|
// unless following a redlink
|
|
|
|
|
if ( !$config->get( 'VisualEditorUseSingleEditTab' ) && !$isRedLink ) {
|
2017-05-15 11:33:40 +00:00
|
|
|
|
return 'wikitext';
|
|
|
|
|
}
|
2020-05-07 13:30:52 +00:00
|
|
|
|
return self::getPreferredEditor( $user, $req, !$isRedLink );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @param WebRequest $req
|
|
|
|
|
* @param bool $useWikitextInMultiTab
|
|
|
|
|
* @return string 'wikitext' or 'visual'
|
|
|
|
|
*/
|
|
|
|
|
public static function getPreferredEditor(
|
|
|
|
|
User $user, WebRequest $req, $useWikitextInMultiTab = false
|
|
|
|
|
) {
|
2020-07-07 19:58:12 +00:00
|
|
|
|
// VisualEditor shouldn't even call this method when it's disabled, but it is a public API for
|
|
|
|
|
// other extensions (e.g. DiscussionTools), and the editor preferences might have surprising
|
|
|
|
|
// values if the user has tried VisualEditor in the past and then disabled it. (T257234)
|
|
|
|
|
if ( !self::enabledForUser( $user ) ) {
|
|
|
|
|
return 'wikitext';
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-27 15:23:26 +00:00
|
|
|
|
switch ( $user->getOption( 'visualeditor-tabs' ) ) {
|
|
|
|
|
case 'prefer-ve':
|
|
|
|
|
return 'visualeditor';
|
|
|
|
|
case 'prefer-wt':
|
|
|
|
|
return 'wikitext';
|
|
|
|
|
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.
|
2020-05-07 13:30:52 +00:00
|
|
|
|
return $useWikitextInMultiTab ?
|
|
|
|
|
'wikitext' :
|
|
|
|
|
self::getLastEditor( $user, $req );
|
|
|
|
|
case 'remember-last':
|
|
|
|
|
default:
|
|
|
|
|
return self::getLastEditor( $user, $req );
|
2015-12-17 18:18:32 +00:00
|
|
|
|
}
|
2015-10-23 16:29:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-10 23:00:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param User $user
|
|
|
|
|
* @param WebRequest $req
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
2017-04-27 15:23:26 +00:00
|
|
|
|
private static function getLastEditor( User $user, WebRequest $req ) {
|
2016-04-11 22:56:33 +00:00
|
|
|
|
// This logic matches getLastEditor in:
|
|
|
|
|
// modules/ve-mw/init/targets/ve.init.mw.DesktopArticleTarget.init.js
|
|
|
|
|
$editor = $req->getCookie( 'VEE', '' );
|
|
|
|
|
// Set editor to user's preference or site's default if …
|
|
|
|
|
if (
|
|
|
|
|
// … user is logged in,
|
|
|
|
|
!$user->isAnon() ||
|
|
|
|
|
// … no cookie is set, or
|
|
|
|
|
!$editor ||
|
|
|
|
|
// value is invalid.
|
|
|
|
|
!( $editor === 'visualeditor' || $editor === 'wikitext' )
|
|
|
|
|
) {
|
|
|
|
|
$editor = $user->getOption( 'visualeditor-editor' );
|
2015-12-10 20:30:01 +00:00
|
|
|
|
}
|
2016-04-11 22:56:33 +00:00
|
|
|
|
return $editor;
|
2015-12-10 20:30:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-01 19:14:41 +00:00
|
|
|
|
/**
|
|
|
|
|
* Changes the Edit tab and adds the VisualEditor tab.
|
|
|
|
|
*
|
|
|
|
|
* This is attached to the MediaWiki 'SkinTemplateNavigation' hook.
|
|
|
|
|
*
|
2019-05-04 21:02:29 +00:00
|
|
|
|
* @param SkinTemplate $skin The skin template on which the UI is built.
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param array &$links Navigation links.
|
2013-08-01 19:14:41 +00:00
|
|
|
|
*/
|
2019-05-04 21:02:29 +00:00
|
|
|
|
public static function onSkinTemplateNavigation( SkinTemplate $skin, array &$links ) {
|
|
|
|
|
$config = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2015-08-25 15:53:55 +00:00
|
|
|
|
|
2015-10-23 16:29:56 +00:00
|
|
|
|
// Exit if there's no edit link for whatever reason (e.g. protected page)
|
|
|
|
|
if ( !isset( $links['views']['edit'] ) ) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2015-10-23 16:29:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-10 20:30:01 +00:00
|
|
|
|
$user = $skin->getUser();
|
2015-10-23 16:29:56 +00:00
|
|
|
|
if (
|
|
|
|
|
$config->get( 'VisualEditorUseSingleEditTab' ) &&
|
2015-12-10 20:30:01 +00:00
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'prefer-wt'
|
|
|
|
|
) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2015-12-10 20:30:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
$config->get( 'VisualEditorUseSingleEditTab' ) &&
|
2016-03-06 00:07:06 +00:00
|
|
|
|
!$user->isAnon() &&
|
|
|
|
|
!$user->getOption( 'visualeditor-autodisable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-betatempdisable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-hidetabdialog' ) &&
|
2018-03-21 19:26:55 +00:00
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'remember-last'
|
2015-10-23 16:29:56 +00:00
|
|
|
|
) {
|
2018-03-21 19:26:55 +00:00
|
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
|
|
|
|
$revWhere = ActorMigration::newMigration()->getWhere( $dbr, 'rev_user', $user );
|
|
|
|
|
foreach ( $revWhere['orconds'] as $key => $cond ) {
|
|
|
|
|
$tsField = $key === 'actor' ? 'revactor_timestamp' : 'rev_timestamp';
|
|
|
|
|
if (
|
|
|
|
|
$dbr->select(
|
|
|
|
|
[ 'revision' ] + $revWhere['tables'],
|
|
|
|
|
'1',
|
|
|
|
|
[
|
|
|
|
|
$cond,
|
|
|
|
|
$tsField . ' < ' . $dbr->addQuotes(
|
|
|
|
|
$config->get( 'VisualEditorSingleEditTabSwitchTime' )
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
__METHOD__,
|
|
|
|
|
[ 'LIMIT' => 1 ],
|
|
|
|
|
$revWhere['joins']
|
|
|
|
|
)->numRows() === 1
|
|
|
|
|
) {
|
|
|
|
|
$links['views']['edit']['class'] .= ' visualeditor-showtabdialog';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-10-23 16:29:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 23:29:12 +00:00
|
|
|
|
// Exit if the user doesn't have VE enabled
|
2020-06-05 16:35:29 +00:00
|
|
|
|
if (
|
|
|
|
|
!self::enabledForUser( $user ) ||
|
|
|
|
|
// T253941: This option does not actually disable the editor, only leaves the tabs/links unchanged
|
|
|
|
|
( $config->get( 'VisualEditorDisableForAnons' ) && $user->isAnon() )
|
|
|
|
|
) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2013-08-01 19:14:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$title = $skin->getRelevantTitle();
|
2015-08-25 04:08:50 +00:00
|
|
|
|
// Don't exit if this page isn't VE-enabled, since we should still
|
|
|
|
|
// change "Edit" to "Edit source".
|
2020-01-26 18:53:57 +00:00
|
|
|
|
$isAvailable = self::isVisualAvailable( $title, $skin->getRequest(), $user );
|
2015-08-10 23:29:12 +00:00
|
|
|
|
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$tabMessages = $config->get( 'VisualEditorTabMessages' );
|
2013-08-01 19:14:41 +00:00
|
|
|
|
// Rebuild the $links['views'] array and inject the VisualEditor tab before or after
|
|
|
|
|
// the edit tab as appropriate. We have to rebuild the array because PHP doesn't allow
|
|
|
|
|
// us to splice into the middle of an associative array.
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$newViews = [];
|
2013-08-01 19:14:41 +00:00
|
|
|
|
foreach ( $links['views'] as $action => $data ) {
|
|
|
|
|
if ( $action === 'edit' ) {
|
|
|
|
|
// Build the VisualEditor tab
|
|
|
|
|
$existing = $title->exists() || (
|
2014-09-25 05:06:57 +00:00
|
|
|
|
$title->inNamespace( NS_MEDIAWIKI ) &&
|
2013-08-01 19:14:41 +00:00
|
|
|
|
$title->getDefaultMessageText() !== false
|
|
|
|
|
);
|
2014-04-08 23:07:33 +00:00
|
|
|
|
$action = $existing ? 'edit' : 'create';
|
2013-08-01 19:14:41 +00:00
|
|
|
|
$veParams = $skin->editUrlOptions();
|
2017-05-04 22:27:27 +00:00
|
|
|
|
// Remove action=edit
|
|
|
|
|
unset( $veParams['action'] );
|
|
|
|
|
// Set veaction=edit
|
|
|
|
|
$veParams['veaction'] = 'edit';
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$veTabMessage = $tabMessages[$action];
|
2020-01-26 10:36:43 +00:00
|
|
|
|
// @phan-suppress-next-line PhanTypeInvalidDimOffset
|
2013-08-01 19:14:41 +00:00
|
|
|
|
$veTabText = $veTabMessage === null ? $data['text'] :
|
2014-09-25 05:06:57 +00:00
|
|
|
|
$skin->msg( $veTabMessage )->text();
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$veTab = [
|
2013-08-01 19:14:41 +00:00
|
|
|
|
'href' => $title->getLocalURL( $veParams ),
|
|
|
|
|
'text' => $veTabText,
|
|
|
|
|
'primary' => true,
|
|
|
|
|
'class' => '',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2013-08-01 19:14:41 +00:00
|
|
|
|
|
|
|
|
|
// Alter the edit tab
|
|
|
|
|
$editTab = $data;
|
2014-04-08 23:07:33 +00:00
|
|
|
|
if (
|
|
|
|
|
$title->inNamespace( NS_FILE ) &&
|
|
|
|
|
WikiPage::factory( $title ) instanceof WikiFilePage &&
|
|
|
|
|
!WikiPage::factory( $title )->isLocal()
|
|
|
|
|
) {
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$editTabMessage = $tabMessages[$action . 'localdescriptionsource'];
|
2014-04-08 23:07:33 +00:00
|
|
|
|
} else {
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$editTabMessage = $tabMessages[$action . 'source'];
|
2014-04-08 23:07:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-01 19:14:41 +00:00
|
|
|
|
if ( $editTabMessage !== null ) {
|
2014-09-25 05:06:57 +00:00
|
|
|
|
$editTab['text'] = $skin->msg( $editTabMessage )->text();
|
2013-08-01 19:14:41 +00:00
|
|
|
|
}
|
2015-12-10 20:30:01 +00:00
|
|
|
|
|
2017-04-27 15:23:26 +00:00
|
|
|
|
$editor = self::getLastEditor( $user, $skin->getRequest() );
|
2015-12-10 20:30:01 +00:00
|
|
|
|
if (
|
|
|
|
|
$isAvailable &&
|
|
|
|
|
$config->get( 'VisualEditorUseSingleEditTab' ) &&
|
|
|
|
|
(
|
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'prefer-ve' ||
|
|
|
|
|
(
|
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'remember-last' &&
|
|
|
|
|
$editor === 'visualeditor'
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
$editTab['text'] = $veTabText;
|
|
|
|
|
$newViews['edit'] = $editTab;
|
|
|
|
|
} elseif (
|
|
|
|
|
$isAvailable &&
|
|
|
|
|
(
|
|
|
|
|
!$config->get( 'VisualEditorUseSingleEditTab' ) ||
|
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'multi-tab'
|
|
|
|
|
)
|
|
|
|
|
) {
|
2015-08-25 03:46:53 +00:00
|
|
|
|
// Inject the VE tab before or after the edit tab
|
|
|
|
|
if ( $config->get( 'VisualEditorTabPosition' ) === 'before' ) {
|
|
|
|
|
$editTab['class'] .= ' collapsible';
|
|
|
|
|
$newViews['ve-edit'] = $veTab;
|
|
|
|
|
$newViews['edit'] = $editTab;
|
|
|
|
|
} else {
|
|
|
|
|
$veTab['class'] .= ' collapsible';
|
|
|
|
|
$newViews['edit'] = $editTab;
|
|
|
|
|
$newViews['ve-edit'] = $veTab;
|
|
|
|
|
}
|
2015-12-10 20:30:01 +00:00
|
|
|
|
} elseif (
|
|
|
|
|
!$config->get( 'VisualEditorUseSingleEditTab' ) ||
|
|
|
|
|
!$isAvailable ||
|
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'multi-tab' ||
|
|
|
|
|
(
|
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'remember-last' &&
|
|
|
|
|
$editor === 'wikitext'
|
|
|
|
|
)
|
|
|
|
|
) {
|
2015-08-25 03:46:53 +00:00
|
|
|
|
// Don't add ve-edit, but do update the edit tab (e.g. "Edit source").
|
2013-08-01 19:14:41 +00:00
|
|
|
|
$newViews['edit'] = $editTab;
|
2015-12-10 20:30:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
// This should not happen.
|
2013-08-01 19:14:41 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Just pass through
|
|
|
|
|
$newViews[$action] = $data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$links['views'] = $newViews;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-16 15:17:44 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called when the normal wikitext editor is shown.
|
2014-03-08 17:49:53 +00:00
|
|
|
|
* Inserts a 'veswitched' hidden field if requested by the client
|
2014-02-16 15:17:44 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param EditPage $editPage The edit page view.
|
|
|
|
|
* @param OutputPage $output The page view.
|
2014-02-16 15:17:44 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onEditPageShowEditFormFields( EditPage $editPage, OutputPage $output ) {
|
2014-08-13 05:54:51 +00:00
|
|
|
|
$request = $output->getRequest();
|
2014-03-08 17:49:53 +00:00
|
|
|
|
if ( $request->getBool( 'veswitched' ) ) {
|
2017-09-03 07:30:13 +00:00
|
|
|
|
$output->addHTML( Html::hidden( 'veswitched', '1' ) );
|
2014-02-16 15:17:44 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called when an edit is saved
|
|
|
|
|
* Adds 'visualeditor-switched' tag to the edit if requested
|
2020-02-06 21:10:24 +00:00
|
|
|
|
* Adds whatever tags from static::$tags are present in the vetags parameter
|
2014-02-16 15:17:44 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param RecentChange $rc The new RC entry.
|
2014-02-16 15:17:44 +00:00
|
|
|
|
*/
|
2017-05-04 22:17:29 +00:00
|
|
|
|
public static function onRecentChangeSave( RecentChange $rc ) {
|
2014-02-16 15:17:44 +00:00
|
|
|
|
$request = RequestContext::getMain()->getRequest();
|
2019-01-11 19:35:48 +00:00
|
|
|
|
if ( $request->getBool( 'veswitched' ) && $rc->getAttribute( 'rc_this_oldid' ) ) {
|
2016-09-27 15:36:28 +00:00
|
|
|
|
$rc->addTags( 'visualeditor-switched' );
|
2014-02-16 15:17:44 +00:00
|
|
|
|
}
|
2020-02-06 21:10:24 +00:00
|
|
|
|
|
|
|
|
|
$tags = explode( ',', $request->getVal( 'vetags' ) );
|
|
|
|
|
$tags = array_values( array_intersect( $tags, static::$tags ) );
|
|
|
|
|
if ( $tags ) {
|
|
|
|
|
$rc->addTags( $tags );
|
|
|
|
|
}
|
2014-02-16 15:17:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-01 19:14:41 +00:00
|
|
|
|
/**
|
|
|
|
|
* Changes the section edit links to add a VE edit link.
|
|
|
|
|
*
|
2015-02-19 18:09:34 +00:00
|
|
|
|
* This is attached to the MediaWiki 'SkinEditSectionLinks' hook.
|
2013-08-01 19:14:41 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param Skin $skin Skin being used to render the UI
|
|
|
|
|
* @param Title $title Title being used for request
|
|
|
|
|
* @param string $section The name of the section being pointed to.
|
|
|
|
|
* @param string $tooltip The default tooltip.
|
|
|
|
|
* @param array &$result All link detail arrays.
|
2019-12-15 04:30:43 +00:00
|
|
|
|
* @codingStandardsIgnoreStart
|
|
|
|
|
* @phan-param array{editsection:array{text:string,targetTitle:Title,attribs:array,query:array}} $result
|
|
|
|
|
* @codingStandardsIgnoreEnd
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param Language $lang The user interface language.
|
2013-08-01 19:14:41 +00:00
|
|
|
|
*/
|
2015-02-19 18:09:34 +00:00
|
|
|
|
public static function onSkinEditSectionLinks( Skin $skin, Title $title, $section,
|
2014-09-25 05:06:57 +00:00
|
|
|
|
$tooltip, &$result, $lang
|
|
|
|
|
) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$config = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2015-09-12 00:26:39 +00:00
|
|
|
|
|
2015-08-10 23:29:12 +00:00
|
|
|
|
// Exit if we're in parserTests
|
|
|
|
|
if ( isset( $GLOBALS[ 'wgVisualEditorInParserTests' ] ) ) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2015-08-10 23:29:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-13 21:45:53 +00:00
|
|
|
|
$user = $skin->getUser();
|
2015-08-10 23:29:12 +00:00
|
|
|
|
// Exit if the user doesn't have VE enabled
|
2020-06-05 16:35:29 +00:00
|
|
|
|
if (
|
|
|
|
|
!self::enabledForUser( $user ) ||
|
|
|
|
|
// T253941: This option does not actually disable the editor, only leaves the tabs/links unchanged
|
|
|
|
|
( $config->get( 'VisualEditorDisableForAnons' ) && $user->isAnon() )
|
|
|
|
|
) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2015-08-10 23:29:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Exit if we're on a foreign file description page
|
|
|
|
|
if (
|
|
|
|
|
$title->inNamespace( NS_FILE ) &&
|
|
|
|
|
WikiPage::factory( $title ) instanceof WikiFilePage &&
|
|
|
|
|
!WikiPage::factory( $title )->isLocal()
|
2013-08-01 19:14:41 +00:00
|
|
|
|
) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2013-08-01 19:14:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 22:18:35 +00:00
|
|
|
|
$editor = self::getLastEditor( $user, $skin->getRequest() );
|
2016-06-30 01:11:13 +00:00
|
|
|
|
if (
|
|
|
|
|
!$config->get( 'VisualEditorUseSingleEditTab' ) ||
|
2016-10-13 21:45:53 +00:00
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'multi-tab' ||
|
2016-06-30 01:11:13 +00:00
|
|
|
|
(
|
2016-10-13 21:45:53 +00:00
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) === 'remember-last' &&
|
2016-06-30 01:11:13 +00:00
|
|
|
|
$editor === 'wikitext'
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
// Don't add ve-edit, but do update the edit tab (e.g. "Edit source").
|
|
|
|
|
$tabMessages = $config->get( 'VisualEditorTabMessages' );
|
2018-10-13 01:10:42 +00:00
|
|
|
|
$sourceEditSection = $tabMessages['editsectionsource'];
|
2016-06-30 01:11:13 +00:00
|
|
|
|
$result['editsection']['text'] = $skin->msg( $sourceEditSection )->inLanguage( $lang )->text();
|
|
|
|
|
}
|
2013-08-01 19:14:41 +00:00
|
|
|
|
|
2016-06-30 01:11:13 +00:00
|
|
|
|
// Exit if we're using the single edit tab.
|
|
|
|
|
if (
|
|
|
|
|
$config->get( 'VisualEditorUseSingleEditTab' ) &&
|
2016-10-13 21:45:53 +00:00
|
|
|
|
$user->getOption( 'visualeditor-tabs' ) !== 'multi-tab'
|
2016-06-30 01:11:13 +00:00
|
|
|
|
) {
|
2019-02-02 20:03:27 +00:00
|
|
|
|
return;
|
2016-06-30 01:11:13 +00:00
|
|
|
|
}
|
2015-02-19 18:09:34 +00:00
|
|
|
|
|
2015-09-12 10:35:44 +00:00
|
|
|
|
// add VE edit section in VE available namespaces
|
2020-01-26 18:53:57 +00:00
|
|
|
|
if ( self::isVisualAvailable( $title, $skin->getRequest(), $user ) ) {
|
2019-10-20 12:12:02 +00:00
|
|
|
|
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable
|
2018-10-13 01:10:42 +00:00
|
|
|
|
$veEditSection = $tabMessages['editsection'];
|
2020-07-26 18:40:09 +00:00
|
|
|
|
|
|
|
|
|
$attribs = $result['editsection']['attribs'];
|
|
|
|
|
$attribs['class'] = ( $attribs['class'] ?? '' ) . ' mw-editsection-visualeditor';
|
|
|
|
|
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$veLink = [
|
2015-09-12 10:35:44 +00:00
|
|
|
|
'text' => $skin->msg( $veEditSection )->inLanguage( $lang )->text(),
|
|
|
|
|
'targetTitle' => $title,
|
2020-07-26 18:40:09 +00:00
|
|
|
|
'attribs' => $attribs,
|
2016-11-05 02:07:39 +00:00
|
|
|
|
'query' => [ 'veaction' => 'edit', 'section' => $section ],
|
2016-02-17 16:18:02 +00:00
|
|
|
|
'options' => [ 'noclasses', 'known' ]
|
|
|
|
|
];
|
2013-06-26 17:23:56 +00:00
|
|
|
|
|
2015-09-12 10:35:44 +00:00
|
|
|
|
$result['veeditsection'] = $veLink;
|
|
|
|
|
if ( $config->get( 'VisualEditorTabPosition' ) === 'before' ) {
|
|
|
|
|
krsort( $result );
|
|
|
|
|
// TODO: This will probably cause weird ordering if any other extensions added something
|
|
|
|
|
// already.
|
|
|
|
|
// ... wfArrayInsertBefore?
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-25 19:50:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-30 16:05:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* @param OutputPage $out
|
|
|
|
|
* @param Skin $sk
|
|
|
|
|
* @param string[] &$bodyAttrs
|
|
|
|
|
*/
|
|
|
|
|
public static function onOutputPageBodyAttributes( OutputPage $out, Skin $sk, &$bodyAttrs ) {
|
|
|
|
|
$specialTitle = $sk->getTitle();
|
|
|
|
|
|
|
|
|
|
// HACK: Replace classes generated by Skin::getPageClasses as if an article title
|
|
|
|
|
// was passed in, instead of a special page.
|
|
|
|
|
if ( $specialTitle && $specialTitle->isSpecial( 'CollabPad' ) ) {
|
|
|
|
|
$articleTitle = Title::newFromText( 'DummyPage' );
|
|
|
|
|
|
|
|
|
|
$specialClasses = $sk->getPageClasses( $specialTitle );
|
|
|
|
|
$articleClasses = $sk->getPageClasses( $articleTitle );
|
|
|
|
|
|
|
|
|
|
$bodyAttrs['class'] = str_replace( $specialClasses, $articleClasses, $bodyAttrs['class'] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-26 06:31:32 +00:00
|
|
|
|
/**
|
|
|
|
|
* Convert a namespace index to the local text for display to the user.
|
|
|
|
|
*
|
2019-02-02 19:50:26 +00:00
|
|
|
|
* @param int $nsIndex
|
2014-04-26 06:31:32 +00:00
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
private static function convertNs( $nsIndex ) {
|
|
|
|
|
global $wgLang;
|
|
|
|
|
if ( $nsIndex ) {
|
|
|
|
|
return $wgLang->convertNamespace( $nsIndex );
|
|
|
|
|
} else {
|
|
|
|
|
return wfMessage( 'blanknamespace' )->text();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 19:47:04 +00:00
|
|
|
|
/**
|
|
|
|
|
* Handler for the GetPreferences hook, to add and hide user preferences as configured
|
|
|
|
|
*
|
|
|
|
|
* @param User $user The user object
|
|
|
|
|
* @param array &$preferences Their preferences object
|
|
|
|
|
*/
|
2014-08-13 05:57:21 +00:00
|
|
|
|
public static function onGetPreferences( User $user, array &$preferences ) {
|
2014-08-13 08:15:42 +00:00
|
|
|
|
global $wgLang;
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2018-02-23 01:17:00 +00:00
|
|
|
|
|
2019-03-02 23:29:09 +00:00
|
|
|
|
if ( !ExtensionRegistry::getInstance()->isLoaded( 'BetaFeatures' ) ) {
|
2018-02-23 01:17:00 +00:00
|
|
|
|
// Config option for visual editing "alpha" state (no Beta Feature)
|
2018-02-26 22:57:36 +00:00
|
|
|
|
$namespaces = ApiVisualEditor::getAvailableNamespaceIds( $veConfig );
|
2014-09-16 17:35:57 +00:00
|
|
|
|
|
2018-02-23 01:17:00 +00:00
|
|
|
|
$visualEnablePreference = [
|
2013-09-30 16:18:46 +00:00
|
|
|
|
'type' => 'toggle',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
'label-message' => [
|
2014-04-26 06:31:32 +00:00
|
|
|
|
'visualeditor-preference-enable',
|
|
|
|
|
$wgLang->commaList( array_map(
|
2016-02-17 16:18:02 +00:00
|
|
|
|
[ 'self', 'convertNs' ],
|
2016-06-01 16:06:22 +00:00
|
|
|
|
$namespaces
|
2014-09-16 17:35:57 +00:00
|
|
|
|
) ),
|
2016-06-01 16:06:22 +00:00
|
|
|
|
count( $namespaces )
|
2016-02-17 16:18:02 +00:00
|
|
|
|
],
|
2014-04-07 09:42:41 +00:00
|
|
|
|
'section' => 'editing/editor'
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2015-08-11 22:31:43 +00:00
|
|
|
|
if ( $user->getOption( 'visualeditor-autodisable' ) ) {
|
2018-02-23 01:17:00 +00:00
|
|
|
|
$visualEnablePreference['default'] = false;
|
2015-08-11 22:31:43 +00:00
|
|
|
|
}
|
2018-02-23 01:17:00 +00:00
|
|
|
|
$preferences['visualeditor-enable'] = $visualEnablePreference;
|
2013-09-30 16:18:46 +00:00
|
|
|
|
}
|
2018-02-23 01:17:00 +00:00
|
|
|
|
|
|
|
|
|
// Config option for visual editing "deployed" state (opt-out)
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$preferences['visualeditor-betatempdisable'] = [
|
2013-07-24 01:11:56 +00:00
|
|
|
|
'type' => 'toggle',
|
|
|
|
|
'label-message' => 'visualeditor-preference-betatempdisable',
|
2015-09-29 01:19:56 +00:00
|
|
|
|
'section' => 'editing/editor',
|
|
|
|
|
'default' => $user->getOption( 'visualeditor-betatempdisable' ) ||
|
|
|
|
|
$user->getOption( 'visualeditor-autodisable' )
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2015-10-23 16:29:56 +00:00
|
|
|
|
|
2018-02-23 01:20:20 +00:00
|
|
|
|
// Config option for wikitext editing "deployed" state (opt-out)
|
2018-02-26 21:39:59 +00:00
|
|
|
|
if (
|
2018-02-26 22:58:39 +00:00
|
|
|
|
$veConfig->get( 'VisualEditorEnableWikitext' )
|
2018-02-26 21:39:59 +00:00
|
|
|
|
) {
|
2018-02-23 01:20:20 +00:00
|
|
|
|
$preferences['visualeditor-newwikitext'] = [
|
|
|
|
|
'type' => 'toggle',
|
|
|
|
|
'label-message' => 'visualeditor-preference-newwikitexteditor-enable',
|
|
|
|
|
'section' => 'editing/editor'
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-23 01:17:00 +00:00
|
|
|
|
// Config option for Single Edit Tab
|
2015-12-09 22:38:53 +00:00
|
|
|
|
if (
|
2018-02-26 22:57:36 +00:00
|
|
|
|
$veConfig->get( 'VisualEditorUseSingleEditTab' ) &&
|
2015-12-09 22:38:53 +00:00
|
|
|
|
!$user->getOption( 'visualeditor-autodisable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-betatempdisable' )
|
|
|
|
|
) {
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$preferences['visualeditor-tabs'] = [
|
2015-10-23 16:29:56 +00:00
|
|
|
|
'type' => 'select',
|
|
|
|
|
'label-message' => 'visualeditor-preference-tabs',
|
|
|
|
|
'section' => 'editing/editor',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
'options' => [
|
2015-10-23 16:29:56 +00:00
|
|
|
|
wfMessage( 'visualeditor-preference-tabs-remember-last' )->escaped() => 'remember-last',
|
|
|
|
|
wfMessage( 'visualeditor-preference-tabs-prefer-ve' )->escaped() => 'prefer-ve',
|
|
|
|
|
wfMessage( 'visualeditor-preference-tabs-prefer-wt' )->escaped() => 'prefer-wt',
|
|
|
|
|
wfMessage( 'visualeditor-preference-tabs-multi-tab' )->escaped() => 'multi-tab'
|
2016-02-17 16:18:02 +00:00
|
|
|
|
]
|
|
|
|
|
];
|
2015-10-23 16:29:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$api = [ 'type' => 'api' ];
|
2015-10-04 12:39:58 +00:00
|
|
|
|
$preferences['visualeditor-autodisable'] = $api;
|
2017-11-04 18:31:23 +00:00
|
|
|
|
// The diff mode is persisted for each editor mode separately,
|
|
|
|
|
// e.g. use visual diffs for visual mode only.
|
|
|
|
|
$preferences['visualeditor-diffmode-source'] = $api;
|
|
|
|
|
$preferences['visualeditor-diffmode-visual'] = $api;
|
2018-03-21 16:48:51 +00:00
|
|
|
|
$preferences['visualeditor-diffmode-historical'] = $api;
|
2015-10-23 16:29:56 +00:00
|
|
|
|
$preferences['visualeditor-editor'] = $api;
|
2015-10-04 12:39:58 +00:00
|
|
|
|
$preferences['visualeditor-hidebetawelcome'] = $api;
|
2015-10-23 16:29:56 +00:00
|
|
|
|
$preferences['visualeditor-hidetabdialog'] = $api;
|
2015-11-10 23:01:49 +00:00
|
|
|
|
$preferences['visualeditor-hidesourceswitchpopup'] = $api;
|
2016-04-04 16:31:39 +00:00
|
|
|
|
$preferences['visualeditor-hidevisualswitchpopup'] = $api;
|
2015-10-30 02:08:25 +00:00
|
|
|
|
$preferences['visualeditor-hideusered'] = $api;
|
2017-02-26 12:22:15 +00:00
|
|
|
|
$preferences['visualeditor-findAndReplace-diacritic'] = $api;
|
2015-10-04 12:39:58 +00:00
|
|
|
|
$preferences['visualeditor-findAndReplace-findText'] = $api;
|
|
|
|
|
$preferences['visualeditor-findAndReplace-replaceText'] = $api;
|
|
|
|
|
$preferences['visualeditor-findAndReplace-regex'] = $api;
|
|
|
|
|
$preferences['visualeditor-findAndReplace-matchCase'] = $api;
|
2015-12-03 17:25:06 +00:00
|
|
|
|
$preferences['visualeditor-findAndReplace-word'] = $api;
|
2012-11-05 20:46:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 19:47:04 +00:00
|
|
|
|
/**
|
|
|
|
|
* Handler for the GetBetaPreferences hook, to add and hide user beta preferences as configured
|
|
|
|
|
*
|
|
|
|
|
* @param User $user The user object
|
|
|
|
|
* @param array &$preferences Their preferences object
|
|
|
|
|
*/
|
2014-08-13 05:57:21 +00:00
|
|
|
|
public static function onGetBetaPreferences( User $user, array &$preferences ) {
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$coreConfig = RequestContext::getMain()->getConfig();
|
2018-01-02 09:36:14 +00:00
|
|
|
|
$iconpath = $coreConfig->get( 'ExtensionAssetsPath' ) . "/VisualEditor/images";
|
2013-11-08 16:33:53 +00:00
|
|
|
|
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$preferences['visualeditor-enable'] = [
|
2013-09-30 16:18:46 +00:00
|
|
|
|
'version' => '1.0',
|
|
|
|
|
'label-message' => 'visualeditor-preference-core-label',
|
|
|
|
|
'desc-message' => 'visualeditor-preference-core-description',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
'screenshot' => [
|
2014-03-22 20:43:28 +00:00
|
|
|
|
'ltr' => "$iconpath/betafeatures-icon-VisualEditor-ltr.svg",
|
|
|
|
|
'rtl' => "$iconpath/betafeatures-icon-VisualEditor-rtl.svg",
|
2016-02-17 16:18:02 +00:00
|
|
|
|
],
|
2013-10-30 20:57:05 +00:00
|
|
|
|
'info-message' => 'visualeditor-preference-core-info-link',
|
|
|
|
|
'discussion-message' => 'visualeditor-preference-core-discussion-link',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
'requirements' => [
|
2013-10-10 12:33:49 +00:00
|
|
|
|
'javascript' => true,
|
2020-06-10 11:13:59 +00:00
|
|
|
|
'unsupportedList' => $veConfig->get( 'VisualEditorBrowserUnsupportedList' ),
|
2016-02-17 16:18:02 +00:00
|
|
|
|
]
|
|
|
|
|
];
|
2016-09-01 19:04:54 +00:00
|
|
|
|
|
2018-03-08 14:40:48 +00:00
|
|
|
|
if (
|
|
|
|
|
$veConfig->get( 'VisualEditorEnableWikitextBetaFeature' ) &&
|
|
|
|
|
// Don't try to register as a beta feature if enabled by default
|
|
|
|
|
!$veConfig->get( 'VisualEditorEnableWikitext' )
|
|
|
|
|
) {
|
2016-09-21 20:24:04 +00:00
|
|
|
|
$preferences['visualeditor-newwikitext'] = [
|
|
|
|
|
'version' => '1.0',
|
|
|
|
|
'label-message' => 'visualeditor-preference-newwikitexteditor-label',
|
|
|
|
|
'desc-message' => 'visualeditor-preference-newwikitexteditor-description',
|
|
|
|
|
'screenshot' => [
|
|
|
|
|
'ltr' => "$iconpath/betafeatures-icon-WikitextEditor-ltr.svg",
|
|
|
|
|
'rtl' => "$iconpath/betafeatures-icon-WikitextEditor-rtl.svg",
|
|
|
|
|
],
|
|
|
|
|
'info-message' => 'visualeditor-preference-newwikitexteditor-info-link',
|
|
|
|
|
'discussion-message' => 'visualeditor-preference-newwikitexteditor-discussion-link',
|
|
|
|
|
'requirements' => [
|
|
|
|
|
'javascript' => true,
|
2020-06-10 11:13:59 +00:00
|
|
|
|
'unsupportedList' => $veConfig->get( 'VisualEditorBrowserUnsupportedList' ),
|
2017-09-20 13:31:00 +00:00
|
|
|
|
]
|
2016-09-21 20:24:04 +00:00
|
|
|
|
];
|
|
|
|
|
}
|
2018-01-25 21:36:05 +00:00
|
|
|
|
|
2018-03-08 14:40:48 +00:00
|
|
|
|
if (
|
|
|
|
|
$veConfig->get( 'VisualEditorEnableDiffPageBetaFeature' ) &&
|
|
|
|
|
// Don't try to register as a beta feature if enabled by default
|
|
|
|
|
!$veConfig->get( 'VisualEditorEnableDiffPage' )
|
|
|
|
|
) {
|
2018-01-25 21:36:05 +00:00
|
|
|
|
$preferences['visualeditor-visualdiffpage'] = [
|
|
|
|
|
'version' => '1.0',
|
|
|
|
|
'label-message' => 'visualeditor-preference-visualdiffpage-label',
|
|
|
|
|
'desc-message' => 'visualeditor-preference-visualdiffpage-description',
|
|
|
|
|
'screenshot' => [
|
|
|
|
|
'ltr' => "$iconpath/betafeatures-icon-VisualDiffPage-ltr.svg",
|
|
|
|
|
'rtl' => "$iconpath/betafeatures-icon-VisualDiffPage-rtl.svg",
|
|
|
|
|
],
|
|
|
|
|
'info-message' => 'visualeditor-preference-visualdiffpage-info-link',
|
|
|
|
|
'discussion-message' => 'visualeditor-preference-visualdiffpage-discussion-link',
|
|
|
|
|
'requirements' => [
|
|
|
|
|
'javascript' => true,
|
2020-06-10 11:13:59 +00:00
|
|
|
|
'unsupportedList' => $veConfig->get( 'VisualEditorBrowserUnsupportedList' ),
|
2018-01-25 21:36:05 +00:00
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
2013-08-12 05:50:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-11 22:31:43 +00:00
|
|
|
|
/**
|
|
|
|
|
* Implements the PreferencesFormPreSave hook, to remove the 'autodisable' flag
|
|
|
|
|
* when the user it was set on explicitly enables VE.
|
2017-05-04 22:59:27 +00:00
|
|
|
|
*
|
2015-08-11 22:31:43 +00:00
|
|
|
|
* @param array $data User-submitted data
|
2019-04-14 00:47:03 +00:00
|
|
|
|
* @param PreferencesFormOOUI $form A ContextSource
|
2015-08-11 22:31:43 +00:00
|
|
|
|
* @param User $user User with new preferences already set
|
2017-07-25 14:49:56 +00:00
|
|
|
|
* @param bool &$result Success or failure
|
2015-08-11 22:31:43 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onPreferencesFormPreSave( $data, $form, $user, &$result ) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2015-09-29 01:19:56 +00:00
|
|
|
|
// On a wiki where enable is hidden and set to 1, if user sets betatempdisable=0
|
|
|
|
|
// then set autodisable=0
|
|
|
|
|
// On a wiki where betatempdisable is hidden and set to 0, if user sets enable=1
|
|
|
|
|
// then set autodisable=0
|
2015-08-11 22:31:43 +00:00
|
|
|
|
if (
|
|
|
|
|
$user->getOption( 'visualeditor-autodisable' ) &&
|
2015-09-29 01:19:56 +00:00
|
|
|
|
$user->getOption( 'visualeditor-enable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-betatempdisable' )
|
2015-08-11 22:31:43 +00:00
|
|
|
|
) {
|
|
|
|
|
$user->setOption( 'visualeditor-autodisable', false );
|
2015-09-29 01:19:56 +00:00
|
|
|
|
} elseif (
|
|
|
|
|
// On a wiki where betatempdisable is hidden and set to 0, if user sets enable=0,
|
|
|
|
|
// then set autodisable=1
|
|
|
|
|
$veConfig->get( 'VisualEditorTransitionDefault' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-betatempdisable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-enable' ) &&
|
|
|
|
|
!$user->getOption( 'visualeditor-autodisable' )
|
|
|
|
|
) {
|
|
|
|
|
$user->setOption( 'visualeditor-autodisable', true );
|
2015-08-11 22:31:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-29 04:02:37 +00:00
|
|
|
|
/**
|
2020-02-07 07:22:23 +00:00
|
|
|
|
* Implements the ListDefinedTags and ChangeTagsListActive hooks, to
|
|
|
|
|
* populate core Special:Tags with the change tags in use by VisualEditor.
|
2015-01-29 04:02:37 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param array &$tags Available change tags.
|
2015-01-29 04:02:37 +00:00
|
|
|
|
*/
|
2012-11-22 02:26:29 +00:00
|
|
|
|
public static function onListDefinedTags( &$tags ) {
|
2020-02-07 07:22:23 +00:00
|
|
|
|
$tags = array_merge( $tags, static::$tags );
|
2012-11-22 02:26:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-05-25 19:50:48 +00:00
|
|
|
|
/**
|
2012-06-11 06:54:41 +00:00
|
|
|
|
* Adds extra variables to the page config.
|
2017-05-04 22:15:55 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param array &$vars Global variables object
|
|
|
|
|
* @param OutputPage $out The page view.
|
2012-05-25 19:50:48 +00:00
|
|
|
|
*/
|
2012-12-06 05:57:53 +00:00
|
|
|
|
public static function onMakeGlobalVariablesScript( array &$vars, OutputPage $out ) {
|
2020-03-16 23:30:26 +00:00
|
|
|
|
$pageLanguage = ApiParsoidTrait::getPageLanguage( $out->getTitle() );
|
2018-06-26 15:14:09 +00:00
|
|
|
|
|
2017-05-31 16:46:37 +00:00
|
|
|
|
$fallbacks = $pageLanguage->getConverter()->getVariantFallbacks(
|
|
|
|
|
$pageLanguage->getPreferredVariant()
|
|
|
|
|
);
|
2013-11-08 16:19:15 +00:00
|
|
|
|
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$vars['wgVisualEditor'] = [
|
2013-11-08 16:19:15 +00:00
|
|
|
|
'pageLanguageCode' => $pageLanguage->getHtmlCode(),
|
2014-01-26 22:59:30 +00:00
|
|
|
|
'pageLanguageDir' => $pageLanguage->getDir(),
|
2017-05-31 16:46:37 +00:00
|
|
|
|
'pageVariantFallbacks' => $fallbacks,
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2013-04-17 16:48:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds extra variables to the global config
|
2017-05-04 22:15:55 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param array &$vars Global variables object
|
2013-04-17 16:48:09 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onResourceLoaderGetConfigVars( array &$vars ) {
|
2014-08-13 08:15:42 +00:00
|
|
|
|
$coreConfig = RequestContext::getMain()->getConfig();
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$veConfig = MediaWikiServices::getInstance()->getConfigFactory()
|
|
|
|
|
->makeConfig( 'visualeditor' );
|
2020-06-24 14:53:01 +00:00
|
|
|
|
$extensionRegistry = ExtensionRegistry::getInstance();
|
2016-06-01 16:06:22 +00:00
|
|
|
|
$availableNamespaces = ApiVisualEditor::getAvailableNamespaceIds( $veConfig );
|
2016-06-24 15:04:32 +00:00
|
|
|
|
$availableContentModels = array_filter(
|
2016-06-01 16:06:22 +00:00
|
|
|
|
array_merge(
|
2020-06-24 14:53:01 +00:00
|
|
|
|
$extensionRegistry->getAttribute( 'VisualEditorAvailableContentModels' ),
|
2016-06-01 16:06:22 +00:00
|
|
|
|
$veConfig->get( 'VisualEditorAvailableContentModels' )
|
|
|
|
|
)
|
2016-06-24 15:04:32 +00:00
|
|
|
|
);
|
2013-06-03 22:23:45 +00:00
|
|
|
|
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$vars['wgVisualEditorConfig'] = [
|
2020-06-24 14:53:01 +00:00
|
|
|
|
'usePageImages' => $extensionRegistry->isLoaded( 'PageImages' ),
|
|
|
|
|
'usePageDescriptions' => $extensionRegistry->isLoaded( 'WikibaseClient' ),
|
2014-08-13 08:15:42 +00:00
|
|
|
|
'disableForAnons' => $veConfig->get( 'VisualEditorDisableForAnons' ),
|
2017-02-01 17:00:07 +00:00
|
|
|
|
'preloadModules' => $veConfig->get( 'VisualEditorPreloadModules' ),
|
2014-08-13 08:15:42 +00:00
|
|
|
|
'preferenceModules' => $veConfig->get( 'VisualEditorPreferenceModules' ),
|
2016-06-01 16:06:22 +00:00
|
|
|
|
'namespaces' => $availableNamespaces,
|
|
|
|
|
'contentModels' => $availableContentModels,
|
2015-01-27 05:47:31 +00:00
|
|
|
|
'pluginModules' => array_merge(
|
2020-06-24 14:53:01 +00:00
|
|
|
|
$extensionRegistry->getAttribute( 'VisualEditorPluginModules' ),
|
2017-05-04 22:27:27 +00:00
|
|
|
|
// @todo deprecate the global setting
|
|
|
|
|
$veConfig->get( 'VisualEditorPluginModules' )
|
2015-01-27 05:47:31 +00:00
|
|
|
|
),
|
2019-03-26 21:15:26 +00:00
|
|
|
|
'thumbLimits' => $coreConfig->get( 'ThumbLimits' ),
|
2016-08-04 23:28:53 +00:00
|
|
|
|
'galleryOptions' => $coreConfig->get( 'GalleryOptions' ),
|
2020-06-10 11:03:51 +00:00
|
|
|
|
'unsupportedList' => $veConfig->get( 'VisualEditorBrowserUnsupportedList' ),
|
2014-08-13 08:15:42 +00:00
|
|
|
|
'tabPosition' => $veConfig->get( 'VisualEditorTabPosition' ),
|
|
|
|
|
'tabMessages' => $veConfig->get( 'VisualEditorTabMessages' ),
|
2015-10-23 16:29:56 +00:00
|
|
|
|
'singleEditTab' => $veConfig->get( 'VisualEditorUseSingleEditTab' ),
|
2019-02-13 13:21:26 +00:00
|
|
|
|
'enableVisualSectionEditing' => $veConfig->get( 'VisualEditorEnableVisualSectionEditing' ),
|
2014-08-13 08:15:42 +00:00
|
|
|
|
'showBetaWelcome' => $veConfig->get( 'VisualEditorShowBetaWelcome' ),
|
2019-02-27 19:54:55 +00:00
|
|
|
|
'allowExternalLinkPaste' => $veConfig->get( 'VisualEditorAllowExternalLinkPaste' ),
|
2015-02-13 08:19:49 +00:00
|
|
|
|
'enableTocWidget' => $veConfig->get( 'VisualEditorEnableTocWidget' ),
|
2018-02-23 01:17:00 +00:00
|
|
|
|
'enableWikitext' => (
|
|
|
|
|
$veConfig->get( 'VisualEditorEnableWikitext' ) ||
|
|
|
|
|
$veConfig->get( 'VisualEditorEnableWikitextBetaFeature' )
|
|
|
|
|
),
|
2020-01-24 19:14:32 +00:00
|
|
|
|
'useChangeTagging' => $veConfig->get( 'VisualEditorUseChangeTagging' ),
|
2015-02-13 08:19:49 +00:00
|
|
|
|
'svgMaxSize' => $coreConfig->get( 'SVGMaxSize' ),
|
|
|
|
|
'namespacesWithSubpages' => $coreConfig->get( 'NamespacesWithSubpages' ),
|
2015-08-25 05:48:16 +00:00
|
|
|
|
'specialBooksources' => urldecode( SpecialPage::getTitleFor( 'Booksources' )->getPrefixedURL() ),
|
2016-10-25 20:44:26 +00:00
|
|
|
|
'rebaserUrl' => $coreConfig->get( 'VisualEditorRebaserURL' ),
|
2015-03-13 22:15:17 +00:00
|
|
|
|
'restbaseUrl' => $coreConfig->get( 'VisualEditorRestbaseURL' ),
|
2015-10-08 22:16:56 +00:00
|
|
|
|
'fullRestbaseUrl' => $coreConfig->get( 'VisualEditorFullRestbaseURL' ),
|
2019-05-13 18:37:11 +00:00
|
|
|
|
'allowLossySwitching' => $coreConfig->get( 'VisualEditorAllowLossySwitching' ),
|
2017-08-16 08:23:51 +00:00
|
|
|
|
'feedbackApiUrl' => $veConfig->get( 'VisualEditorFeedbackAPIURL' ),
|
|
|
|
|
'feedbackTitle' => $veConfig->get( 'VisualEditorFeedbackTitle' ),
|
2018-02-09 00:31:17 +00:00
|
|
|
|
'sourceFeedbackTitle' => $veConfig->get( 'VisualEditorSourceFeedbackTitle' ),
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2012-06-01 23:26:03 +00:00
|
|
|
|
}
|
2012-07-27 23:43:27 +00:00
|
|
|
|
|
2013-12-05 02:28:59 +00:00
|
|
|
|
/**
|
2014-07-22 23:49:06 +00:00
|
|
|
|
* Conditionally register the jquery.uls.data and jquery.i18n modules, in case they've already
|
2015-01-03 17:10:08 +00:00
|
|
|
|
* been registered by the UniversalLanguageSelector extension or the TemplateData extension.
|
2013-12-05 22:45:44 +00:00
|
|
|
|
*
|
2019-05-04 21:02:29 +00:00
|
|
|
|
* @param ResourceLoader $resourceLoader Client-side code and assets to be loaded.
|
2013-12-05 02:28:59 +00:00
|
|
|
|
*/
|
2019-05-04 21:02:29 +00:00
|
|
|
|
public static function onResourceLoaderRegisterModules( ResourceLoader $resourceLoader ) {
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$veResourceTemplate = [
|
2018-02-12 21:58:16 +00:00
|
|
|
|
'localBasePath' => dirname( __DIR__ ),
|
2015-01-27 05:47:31 +00:00
|
|
|
|
'remoteExtPath' => 'VisualEditor',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
];
|
2014-02-14 22:31:15 +00:00
|
|
|
|
|
2019-04-17 14:20:13 +00:00
|
|
|
|
// Only register VisualEditor core's local version of jquery.uls.data if it hasn't been
|
2015-07-07 01:34:35 +00:00
|
|
|
|
// installed locally already (presumably, by the UniversalLanguageSelector extension).
|
2019-04-17 14:20:13 +00:00
|
|
|
|
if ( !$resourceLoader->isModuleRegistered( 'jquery.uls.data' ) ) {
|
2016-02-17 16:18:02 +00:00
|
|
|
|
$resourceLoader->register( [
|
|
|
|
|
'jquery.uls.data' => $veResourceTemplate + [
|
|
|
|
|
'scripts' => [
|
2018-02-12 21:58:16 +00:00
|
|
|
|
'lib/ve/lib/jquery.uls/src/jquery.uls.data.js',
|
|
|
|
|
'lib/ve/lib/jquery.uls/src/jquery.uls.data.utils.js',
|
2016-02-17 16:18:02 +00:00
|
|
|
|
],
|
|
|
|
|
'targets' => [ 'desktop', 'mobile' ],
|
|
|
|
|
] ] );
|
2013-12-05 22:08:29 +00:00
|
|
|
|
}
|
2013-12-05 02:28:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-16 21:12:50 +00:00
|
|
|
|
/**
|
|
|
|
|
* Ensures that we know whether we're running inside a parser test.
|
2017-05-04 22:35:14 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param array &$settings The settings with which MediaWiki is being run.
|
2013-09-16 21:12:50 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onParserTestGlobals( array &$settings ) {
|
|
|
|
|
$settings['wgVisualEditorInParserTests'] = true;
|
|
|
|
|
}
|
2014-05-22 07:04:41 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2018-10-31 18:04:46 +00:00
|
|
|
|
* @param array &$redirectParams Parameters preserved on special page redirects
|
2014-05-22 07:04:41 +00:00
|
|
|
|
* to wiki pages
|
|
|
|
|
*/
|
|
|
|
|
public static function onRedirectSpecialArticleRedirectParams( &$redirectParams ) {
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$redirectParams[] = 'veaction';
|
2014-05-22 07:04:41 +00:00
|
|
|
|
}
|
2014-06-09 22:58:15 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If the user has specified that they want to edit the page with VE, suppress any redirect.
|
2017-05-04 22:59:27 +00:00
|
|
|
|
*
|
2014-06-09 22:58:15 +00:00
|
|
|
|
* @param Title $title Title being used for request
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param Article|null $article The page being viewed.
|
|
|
|
|
* @param OutputPage $output The page view.
|
|
|
|
|
* @param User $user The user-specific settings.
|
|
|
|
|
* @param WebRequest $request The request.
|
|
|
|
|
* @param MediaWiki $mediaWiki Helper class.
|
2014-06-09 22:58:15 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onBeforeInitialize(
|
|
|
|
|
Title $title, $article, OutputPage $output,
|
|
|
|
|
User $user, WebRequest $request, MediaWiki $mediaWiki
|
|
|
|
|
) {
|
2018-11-02 11:00:22 +00:00
|
|
|
|
if ( $request->getVal( 'veaction' ) ) {
|
2014-06-09 22:58:15 +00:00
|
|
|
|
$request->setVal( 'redirect', 'no' );
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-17 21:01:11 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2016-05-19 13:22:39 +00:00
|
|
|
|
* Set user preferences for new and auto-created accounts if so configured.
|
2015-04-17 21:01:11 +00:00
|
|
|
|
*
|
2015-07-16 14:13:41 +00:00
|
|
|
|
* Sets user preference to enable the VisualEditor account for new auto-
|
|
|
|
|
* created ('auth') accounts, if $wgVisualEditorAutoAccountEnable is set.
|
|
|
|
|
*
|
2016-05-19 13:22:39 +00:00
|
|
|
|
* Sets user preference to enable the VisualEditor account for new non-auto-
|
|
|
|
|
* created accounts, if the account's userID matches, modulo the value of
|
|
|
|
|
* $wgVisualEditorNewAccountEnableProportion, if set. If set to '1', all new
|
|
|
|
|
* accounts would have VisualEditor enabled; at '2', 50% would; at '20',
|
|
|
|
|
* 5% would, and so on.
|
|
|
|
|
*
|
2015-07-16 14:13:41 +00:00
|
|
|
|
* To be removed once no longer needed.
|
2017-05-04 22:15:55 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param User $user The user-specific settings.
|
2017-07-25 14:49:56 +00:00
|
|
|
|
* @param bool $autocreated True if the user was auto-created (not a new global user).
|
2015-07-16 14:13:41 +00:00
|
|
|
|
*/
|
2016-05-19 13:22:39 +00:00
|
|
|
|
public static function onLocalUserCreated( $user, $autocreated ) {
|
|
|
|
|
$config = RequestContext::getMain()->getConfig();
|
|
|
|
|
$enableProportion = $config->get( 'VisualEditorNewAccountEnableProportion' );
|
|
|
|
|
|
2015-07-16 14:13:41 +00:00
|
|
|
|
if (
|
2016-05-19 13:22:39 +00:00
|
|
|
|
// Only act on actual accounts (avoid race condition bugs)
|
2019-05-04 21:02:29 +00:00
|
|
|
|
$user->isLoggedIn() &&
|
2016-05-19 13:22:39 +00:00
|
|
|
|
// Only act if the default isn't already set
|
|
|
|
|
!User::getDefaultOption( 'visualeditor-enable' ) &&
|
|
|
|
|
// Act if either …
|
|
|
|
|
(
|
|
|
|
|
// … this is an auto-created account and we're configured so to do
|
|
|
|
|
(
|
|
|
|
|
$autocreated &&
|
|
|
|
|
$config->get( 'VisualEditorAutoAccountEnable' )
|
|
|
|
|
) ||
|
|
|
|
|
// … this is a real new account that matches the modulo and we're configured so to do
|
|
|
|
|
(
|
|
|
|
|
!$autocreated &&
|
|
|
|
|
$enableProportion &&
|
|
|
|
|
( ( $user->getId() % $enableProportion ) === 0 )
|
|
|
|
|
)
|
|
|
|
|
)
|
2015-07-16 14:13:41 +00:00
|
|
|
|
) {
|
|
|
|
|
$user->setOption( 'visualeditor-enable', 1 );
|
|
|
|
|
$user->saveSettings();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-20 21:13:36 +00:00
|
|
|
|
/**
|
|
|
|
|
* On login, if user has a VEE cookie, set their preference equal to it.
|
2017-05-04 22:31:20 +00:00
|
|
|
|
*
|
2017-05-04 22:59:27 +00:00
|
|
|
|
* @param User $user The user-specific settings.
|
2016-06-20 21:13:36 +00:00
|
|
|
|
*/
|
|
|
|
|
public static function onUserLoggedIn( $user ) {
|
|
|
|
|
$cookie = RequestContext::getMain()->getRequest()->getCookie( 'VEE', '' );
|
|
|
|
|
if ( $cookie === 'visualeditor' || $cookie === 'wikitext' ) {
|
2017-04-19 15:15:06 +00:00
|
|
|
|
$lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
|
2016-08-18 23:11:38 +00:00
|
|
|
|
DeferredUpdates::addUpdate( new AtomicSectionUpdate(
|
2017-04-19 15:15:06 +00:00
|
|
|
|
$lb->getLazyConnectionRef( DB_MASTER ),
|
2016-08-18 23:11:38 +00:00
|
|
|
|
__METHOD__,
|
|
|
|
|
function () use ( $user, $cookie ) {
|
2017-04-19 15:15:06 +00:00
|
|
|
|
if ( wfReadOnly() ) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 23:11:38 +00:00
|
|
|
|
$uLatest = $user->getInstanceForUpdate();
|
|
|
|
|
$uLatest->setOption( 'visualeditor-editor', $cookie );
|
|
|
|
|
$uLatest->saveSettings();
|
|
|
|
|
}
|
|
|
|
|
) );
|
2016-06-20 21:13:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-25 19:50:48 +00:00
|
|
|
|
}
|