' ).append( + mw.message( 'abusefilter-blocked-domains-notif-body', [ url.hostname ] ).parse() + ); + const notification = mw.notification.notify( [ $content, $reviewLink ], { + autoHideSeconds: 'long', + type: 'warn', + classes: 'mw-abusefilter-blocked-domains-notif', + tag: 'mw-abusefilter-blocked-domains-notif' + } ); + + $reviewLink.on( + 'click', + { url, wikitext, cursorPosition, notification }, + reviewClickHandler + ); +} + +/** + * Query the blocked domains list and check the given URL against it. + * If there's a match, a warning is displayed to the user. + * + * @param {string} wikitext + * @param {string} urlStr + * @param {number} cursorPosition + */ +function checkIfBlocked( wikitext, urlStr, cursorPosition ) { + const url = parseUrl( urlStr ); + if ( !url ) { + // Likely an invalid URL. + return; + } + loadBlockedExternalDomains().then( () => { + if ( blockedExternalDomains.includes( url.hostname ) ) { + showWarning( wikitext, url, cursorPosition ); + } + } ); +} + +/** + * (Re-)add the keyup listener to the textarea. + * + * @param {jQuery|CodeMirror} [editor] + * @param {string} [event] + */ +function addEditorListener( editor = $textarea, event = 'input.blockedexternaldomains' ) { + editor.off( event ); + editor.on( event, () => { + const cursorPosition = $textarea.textSelection( 'getCaretPosition' ), + context = $textarea.textSelection( 'getContents' ) + .slice( 0, cursorPosition ), + // TODO: somehow use the same regex as the MediaWiki parser + matches = /.*\b\[?(https?:\/\/[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))(?:.*?])?$/.exec( context ); + + if ( matches ) { + checkIfBlocked( matches[ 0 ], matches[ 1 ], cursorPosition ); + } + } ); +} + +/** + * Script entrypoint. + * + * @param {jQuery} $form + */ +function init( $form ) { + $textarea = $form.find( '#wpTextbox1' ); + + /** + * Skin doesn't support this clientside solution if the textarea is not present in page. + * We also want to use the JavaScript URL API, so IE is not supported. + */ + if ( !$textarea.length || !( 'URL' in window ) ) { + return; + } + + addEditorListener(); + + // WikiEditor integration; causes the 'Review link' link to open the link insertion dialog. + mw.hook( 'wikiEditor.toolbarReady' ).add( function ( $wikiEditorTextarea ) { + wikiEditorCtx = $wikiEditorTextarea.data( 'wikiEditor-context' ); + } ); + + // CodeMirror integration. + mw.hook( 'ext.CodeMirror.switch' ).add( function ( _enabled, $editor ) { + $textarea = $editor; + addEditorListener( $editor[ 0 ].CodeMirror, 'change' ); + } ); +} + +mw.hook( 'wikipage.editform' ).add( init ); diff --git a/modules/wikieditor/ext.abuseFilter.wikiEditor.less b/modules/wikieditor/ext.abuseFilter.wikiEditor.less new file mode 100644 index 000000000..8dce3c920 --- /dev/null +++ b/modules/wikieditor/ext.abuseFilter.wikiEditor.less @@ -0,0 +1,5 @@ +.mw-abusefilter-blocked-domains-notif-review-link { + display: inline-block; + font-weight: bold; + margin-top: 15px; +}