mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-27 15:50:29 +00:00
Merge "Use reliability API to detect blocked external links"
This commit is contained in:
commit
c90200d24b
|
@ -75,6 +75,17 @@ class ApiEditCheckReferenceUrl extends ApiBase {
|
|||
return $matches !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the required extensions are available for this API to be usable
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isAvailable(): bool {
|
||||
return ExtensionRegistry::getInstance()->isLoaded( 'SpamBlacklist' ) ||
|
||||
// BlockedExternalDomains is within AbuseFilter:
|
||||
ExtensionRegistry::getInstance()->isLoaded( 'AbuseFilter' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
|
|
@ -1893,6 +1893,7 @@
|
|||
"visualeditor-linkinspector-educationpopup-text",
|
||||
"visualeditor-linkinspector-educationpopup-title",
|
||||
"visualeditor-linkinspector-illegal-title",
|
||||
"visualeditor-linkinspector-invalid-blocked",
|
||||
"visualeditor-linkinspector-invalid-external",
|
||||
"visualeditor-linknodeinspector-add-label",
|
||||
"visualeditor-linknodeinspector-title",
|
||||
|
|
|
@ -275,6 +275,7 @@
|
|||
"visualeditor-linkinspector-educationpopup-text": "Link important words to other wiki articles or even other websites. It will help readers understand the context.",
|
||||
"visualeditor-linkinspector-educationpopup-title": "Links",
|
||||
"visualeditor-linkinspector-illegal-title": "Invalid page title",
|
||||
"visualeditor-linkinspector-invalid-blocked": "People at this wiki decided to block links to this site. Please try another link.",
|
||||
"visualeditor-linkinspector-invalid-external": "Enter a full URL, e.g. https://example.org",
|
||||
"visualeditor-linknodeinspector-add-label": "Add label",
|
||||
"visualeditor-linknodeinspector-title": "Simple link",
|
||||
|
|
|
@ -296,6 +296,7 @@
|
|||
"visualeditor-linkinspector-educationpopup-text": "Text shown in education popup for the link inspector tool.",
|
||||
"visualeditor-linkinspector-educationpopup-title": "Title shown at the top of education popup for the link inspector tool.\n{{Identical|Link}}",
|
||||
"visualeditor-linkinspector-illegal-title": "Warning that the entered text is not a valid page title.",
|
||||
"visualeditor-linkinspector-invalid-blocked": "Warning that the entered URL is blocked",
|
||||
"visualeditor-linkinspector-invalid-external": "Warning that the entered URL is not valid.",
|
||||
"visualeditor-linknodeinspector-add-label": "Label of button that converts an auto-numbered, external, labelless link into a labeled external link",
|
||||
"visualeditor-linknodeinspector-title": "Title of inspector for editing auto-numbered, external, labelless links.\n\nSee also:\n* {{msg-mw|Visualeditor-annotationbutton-linknode-tooltip}}",
|
||||
|
|
|
@ -25,6 +25,7 @@ use MediaWiki\ChangeTags\Hook\ListDefinedTagsHook;
|
|||
use MediaWiki\Diff\Hook\DifferenceEngineViewHeaderHook;
|
||||
use MediaWiki\Diff\Hook\TextSlotDiffRendererTablePrefixHook;
|
||||
use MediaWiki\EditPage\EditPage;
|
||||
use MediaWiki\Extension\VisualEditor\EditCheck\ApiEditCheckReferenceUrl;
|
||||
use MediaWiki\Hook\BeforeInitializeHook;
|
||||
use MediaWiki\Hook\BeforePageDisplayHook;
|
||||
use MediaWiki\Hook\CustomEditorHook;
|
||||
|
@ -1195,6 +1196,7 @@ class Hooks implements
|
|||
'editCheckTagging' => $veConfig->get( 'VisualEditorEditCheckTagging' ),
|
||||
'editCheck' => $veConfig->get( 'VisualEditorEditCheck' ),
|
||||
'editCheckABTest' => $veConfig->get( 'VisualEditorEditCheckABTest' ),
|
||||
'editCheckReliabilityAvailable' => ApiEditCheckReferenceUrl::isAvailable(),
|
||||
'namespacesWithSubpages' => $namespacesWithSubpagesEnabled,
|
||||
'specialBooksources' => urldecode( SpecialPage::getTitleFor( 'Booksources' )->getPrefixedURL() ),
|
||||
'rebaserUrl' => $coreConfig->get( 'VisualEditorRebaserURL' ),
|
||||
|
|
|
@ -88,6 +88,8 @@ ve.ui.MWLinkAnnotationInspector.prototype.initialize = function () {
|
|||
}
|
||||
);
|
||||
|
||||
this.onExternalLinkInputChangeDebounced = ve.debounce( this.onExternalLinkInputChange, 750 );
|
||||
|
||||
// Events
|
||||
this.linkTypeIndex.connect( this, { set: 'onLinkTypeIndexSet' } );
|
||||
this.labelInput.connect( this, { change: 'onLabelInputChange' } );
|
||||
|
@ -100,7 +102,7 @@ ve.ui.MWLinkAnnotationInspector.prototype.initialize = function () {
|
|||
enter: 'onLinkInputEnter'
|
||||
} );
|
||||
this.externalAnnotationInput.getTextInputWidget().connect( this, {
|
||||
change: 'onExternalLinkInputChange',
|
||||
change: 'onExternalLinkInputChangeDebounced',
|
||||
enter: 'onLinkInputEnter'
|
||||
} );
|
||||
// this.internalAnnotationInput is already bound by parent class
|
||||
|
@ -301,16 +303,26 @@ ve.ui.MWLinkAnnotationInspector.prototype.onInternalLinkInputChange = function (
|
|||
* @param {string} value Current value of input widget
|
||||
*/
|
||||
ve.ui.MWLinkAnnotationInspector.prototype.onExternalLinkInputChange = function () {
|
||||
this.externalAnnotationInput.getTextInputWidget().getValidity()
|
||||
.then(
|
||||
() => {
|
||||
this.externalAnnotationField.setErrors( [] );
|
||||
this.updateSize();
|
||||
}, () => {
|
||||
this.externalAnnotationField.setErrors( [ ve.msg( 'visualeditor-linkinspector-invalid-external' ) ] );
|
||||
this.updateSize();
|
||||
this.externalAnnotationInput.getValidity().then(
|
||||
() => {
|
||||
// clear any invalid-protocol errors
|
||||
this.externalAnnotationField.setErrors( [] );
|
||||
}, ( errortype ) => {
|
||||
// Messages that can be used here:
|
||||
// * visualeditor-linkinspector-invalid-blocked
|
||||
// * visualeditor-linkinspector-invalid-external
|
||||
this.externalAnnotationField.setErrors( [ ve.msg( 'visualeditor-linkinspector-' + errortype ) ] );
|
||||
if ( errortype === 'invalid-blocked' ) {
|
||||
// This has been quite async, so:
|
||||
this.actions.forEach( { actions: [ 'done', 'insert' ] }, ( action ) => {
|
||||
action.setDisabled( true );
|
||||
} );
|
||||
ve.track( 'activity.editCheckReliability', { action: 'link-blocked' } );
|
||||
}
|
||||
);
|
||||
}
|
||||
).always( () => {
|
||||
this.updateSize();
|
||||
} );
|
||||
|
||||
if ( this.isActive && !this.trackedExternalLinkInputChange && !this.switchingLinkTypes ) {
|
||||
ve.track( 'activity.' + this.constructor.static.name, { action: 'external-link-input' } );
|
||||
|
|
|
@ -72,3 +72,33 @@ ve.ui.MWExternalLinkAnnotationWidget.static.createExternalLinkInputWidget = func
|
|||
ve.ui.MWExternalLinkAnnotationWidget.prototype.createInputWidget = function ( config ) {
|
||||
return this.constructor.static.createExternalLinkInputWidget( config );
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the validity of current value
|
||||
*
|
||||
* @see OO.ui.TextInputWidget#getValidity
|
||||
*
|
||||
* @return {jQuery.Promise} A promise that resolves if the value is valid,
|
||||
* rejects if not. If it's rejected, it'll resolve with an error code.
|
||||
*/
|
||||
ve.ui.MWExternalLinkAnnotationWidget.prototype.getValidity = function () {
|
||||
const url = this.input.getValue().trim();
|
||||
return this.input.getValidity().then(
|
||||
// input validity check covers whether it's a valid external link, now check whether it's blocked:
|
||||
() => {
|
||||
if ( mw.config.get( 'wgVisualEditorConfig' ).editCheckReliabilityAvailable ) {
|
||||
return ( new mw.Api().get( {
|
||||
action: 'editcheckreferenceurl',
|
||||
url: url,
|
||||
formatversion: 2
|
||||
} ) ).then( ( reliablityResults ) => {
|
||||
if ( reliablityResults && reliablityResults.editcheckreferenceurl[ url ] === 'blocked' ) {
|
||||
return ve.createDeferred().reject( 'invalid-blocked' );
|
||||
}
|
||||
} );
|
||||
}
|
||||
},
|
||||
// invalid link, so provide a reason
|
||||
() => ve.createDeferred().reject( 'invalid-external' )
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue