2019-09-18 23:07:21 +00:00
|
|
|
/**
|
|
|
|
* @param {Object} mobile mobileFrontend component library
|
|
|
|
*/
|
|
|
|
module.exports = function ( mobile ) {
|
2019-02-07 16:34:18 +00:00
|
|
|
var
|
2019-10-17 22:46:07 +00:00
|
|
|
SKIN_MINERVA_TALK_SIMPLIFIED_CLASS = 'skin-minerva--talk-simplified',
|
2019-09-18 03:07:48 +00:00
|
|
|
toast = mobile.toast,
|
|
|
|
currentPage = mobile.currentPage(),
|
2019-02-07 16:34:18 +00:00
|
|
|
loader = mobile.rlModuleLoader,
|
2019-02-25 20:52:18 +00:00
|
|
|
api = new mw.Api(),
|
2019-09-05 23:52:27 +00:00
|
|
|
overlayManager = mobile.OverlayManager.getSingleton(),
|
2019-07-02 21:10:10 +00:00
|
|
|
// FIXME: This dependency shouldn't exist
|
2019-07-17 18:14:23 +00:00
|
|
|
skin = mobile.Skin.getSingleton(),
|
2019-11-25 13:08:42 +00:00
|
|
|
talkTitle = currentPage.titleObj.getTalkPage() ?
|
|
|
|
currentPage.titleObj.getTalkPage().getPrefixedText() :
|
|
|
|
undefined;
|
2017-07-12 15:12:40 +00:00
|
|
|
|
2019-10-17 22:46:07 +00:00
|
|
|
/**
|
|
|
|
* Render a type of talk overlay
|
|
|
|
* @param {string} className name of talk overlay to create
|
|
|
|
* @param {Object} talkOptions
|
|
|
|
* @return {Overlay|JQuery.Promise}
|
|
|
|
*/
|
|
|
|
function createOverlay( className, talkOptions ) {
|
|
|
|
// eslint-disable-next-line no-restricted-properties
|
|
|
|
var M = mw.mobileFrontend;
|
2017-07-12 15:12:40 +00:00
|
|
|
|
2019-10-17 22:46:07 +00:00
|
|
|
return mw.loader.getState( 'mobile.talk.overlays' ) === 'ready' ?
|
|
|
|
new ( M.require( 'mobile.talk.overlays/' + className ) )( talkOptions ) :
|
|
|
|
// otherwise pull it from ResourceLoader async
|
|
|
|
loader.loadModule( 'mobile.talk.overlays' ).then( function () {
|
|
|
|
return new ( M.require( 'mobile.talk.overlays/' + className ) )( talkOptions );
|
|
|
|
} );
|
2017-09-28 20:06:39 +00:00
|
|
|
}
|
|
|
|
|
2019-10-17 22:46:07 +00:00
|
|
|
function removeTalkSectionListeners() {
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$( '.section-heading' ).each( function () {
|
|
|
|
var $heading = $( this );
|
|
|
|
$heading.off( 'click.talkSectionOverlay' );
|
|
|
|
} );
|
2017-07-12 15:12:40 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 22:05:35 +00:00
|
|
|
/**
|
2019-10-17 22:46:07 +00:00
|
|
|
* @param {JQuery.Element} $heading
|
|
|
|
* @param {JQuery.Element} $headline
|
|
|
|
* @param {string} sectionId
|
|
|
|
* @return {JQuery.Promise} A promise that rejects if simplified mode is off.
|
|
|
|
* A promise that resolves to the TalkSectionOverlay otherwise (unless a
|
|
|
|
* network error occurs).
|
2019-07-24 22:05:35 +00:00
|
|
|
*/
|
2019-10-17 22:46:07 +00:00
|
|
|
function createTalkSectionOverlay( $heading, $headline, sectionId ) {
|
|
|
|
if ( !isSimplifiedViewEnabled() ) {
|
|
|
|
// If the simplified view is not enabled, we don't want to show the
|
|
|
|
// talk section overlay (e.g. when user clicks on a link in TOC)
|
|
|
|
return mobile.util.Deferred().reject();
|
2019-07-24 22:05:35 +00:00
|
|
|
}
|
2019-10-17 22:46:07 +00:00
|
|
|
|
|
|
|
// FIXME: Yes, this is hacky. Async code is needed to deal with the
|
|
|
|
// overlay opening in a scroll position that is not at the top. What
|
|
|
|
// causes this scroll to occur is code from Toggler.js which also
|
|
|
|
// listens to hash changes and causes the window to scroll to the top of
|
|
|
|
// the clicked on section after the overlay is open. We should probably
|
|
|
|
// stop the Toggler code from executing at all when the simplified view
|
|
|
|
// is enabled to prevent this code from happening, but MobileFrontend
|
|
|
|
// currently initializes the toggler code in mobile.init.js.
|
|
|
|
//
|
|
|
|
// https://github.com/wikimedia/mediawiki-extensions-MobileFrontend/blob/5c646a9881a787215b7d77c1d8b6b9126f302697/src/mobile.startup/Toggler.js#L216
|
|
|
|
return mobile.util.Deferred().resolve().then(
|
|
|
|
function () {
|
|
|
|
return createOverlay( 'TalkSectionOverlay', {
|
|
|
|
id: sectionId,
|
|
|
|
section: new mobile.Section( {
|
|
|
|
line: $headline.text(),
|
|
|
|
text: $heading.next().html()
|
|
|
|
} ),
|
|
|
|
// FIXME: Replace this api param with onSaveComplete
|
|
|
|
api: api,
|
|
|
|
title: talkTitle,
|
|
|
|
// T184273 using `currentPage` because 'wgPageName'
|
|
|
|
// contains underscores instead of spaces.
|
|
|
|
licenseMsg: skin.getLicenseMsg(),
|
|
|
|
onSaveComplete: function () {
|
|
|
|
toast.showOnPageReload( mw.message( 'minerva-talk-reply-success' ).text() );
|
|
|
|
window.location.reload();
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes code needed to display the TalkSectionOverlay
|
|
|
|
*/
|
|
|
|
function initTalkSection() {
|
|
|
|
// register route for each of the sub-headings
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$( '.section-heading' ).each( function () {
|
|
|
|
var
|
|
|
|
sectionId,
|
|
|
|
$heading = $( this ),
|
|
|
|
$headline = $heading.find( '.mw-headline' ),
|
|
|
|
sectionIdMatch = $heading.next().attr( 'class' ).match( /mf-section-(\d+)/ ),
|
|
|
|
headlineId = $headline.attr( 'id' );
|
|
|
|
|
|
|
|
if ( sectionIdMatch === null || sectionIdMatch.length !== 2 ) {
|
|
|
|
// If section id couldn't be parsed, there is no point in continuing
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sectionId = sectionIdMatch[ 1 ];
|
|
|
|
|
|
|
|
$heading.on( 'click.talkSectionOverlay', function ( ev ) {
|
|
|
|
ev.preventDefault();
|
|
|
|
window.location.hash = '#' + headlineId;
|
|
|
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
overlayManager.add( headlineId, function () {
|
|
|
|
return createTalkSectionOverlay( $heading, $headline, sectionId );
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes code needed to display the TalkSectionAddOverlay
|
|
|
|
*/
|
|
|
|
function initTalkSectionAdd() {
|
|
|
|
overlayManager.add( /^\/talk\/new$/, function () {
|
|
|
|
return createOverlay( 'TalkSectionAddOverlay', {
|
2019-02-21 23:20:45 +00:00
|
|
|
api: api,
|
2019-10-17 22:46:07 +00:00
|
|
|
title: talkTitle,
|
2019-07-11 00:56:04 +00:00
|
|
|
// T184273 using `currentPage` because 'wgPageName'
|
2019-02-21 23:20:45 +00:00
|
|
|
// contains underscores instead of spaces.
|
|
|
|
licenseMsg: skin.getLicenseMsg(),
|
2019-10-17 22:46:07 +00:00
|
|
|
|
|
|
|
currentPageTitle: currentPage.title,
|
|
|
|
onSaveComplete: function () {
|
2019-10-24 21:17:18 +00:00
|
|
|
toast.showOnPageReload( mw.message( 'minerva-talk-topic-feedback' ).text() );
|
|
|
|
window.location = currentPage.titleObj.getTalkPage().getUrl();
|
2019-10-17 22:46:07 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* T230695: In the simplified view, we need to display a "Read as wikipage"
|
|
|
|
* button which enables the user to switch from simplified mode to the regular
|
|
|
|
* version of the mobile talk page (with TOC and sections that you can
|
|
|
|
* expand/collapse).
|
|
|
|
*/
|
|
|
|
function renderReadAsWikiPageButton() {
|
|
|
|
$( '<button>' )
|
|
|
|
.addClass( 'minerva-talk-full-page-button' )
|
|
|
|
.text( mw.message( 'minerva-talk-full-page' ).text() )
|
|
|
|
.on( 'click', function () {
|
|
|
|
// We need to cleanup the listeners previously added in initTalkSection
|
|
|
|
// so that events like clicking on a section) won't cause
|
|
|
|
// scroll changes/things only needed for the simplified view
|
|
|
|
removeTalkSectionListeners();
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$( 'body' ).removeClass( 'skin-minerva--talk-simplified' );
|
|
|
|
$( this ).remove();
|
|
|
|
// send user back up to top of page so they don't land awkwardly in
|
|
|
|
// middle of page when it expands
|
|
|
|
window.scrollTo( 0, 0 );
|
|
|
|
} )
|
|
|
|
.appendTo( '#content' );
|
2019-09-18 03:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {JQuery.Event} ev
|
2019-10-17 22:46:07 +00:00
|
|
|
* @param {Function} onDismiss
|
|
|
|
* @param {Function} onFollowRoute
|
|
|
|
* @param {string} returnToQuery
|
2019-09-18 03:07:48 +00:00
|
|
|
* @return {undefined}
|
|
|
|
*/
|
2019-10-17 22:46:07 +00:00
|
|
|
function showDrawerIfEligible( ev, onDismiss, onFollowRoute, returnToQuery ) {
|
2019-09-18 03:07:48 +00:00
|
|
|
var
|
|
|
|
amcOutreach = mobile.amcOutreach,
|
2019-10-17 22:46:07 +00:00
|
|
|
amcCampaign = amcOutreach.loadCampaign();
|
2019-09-18 03:07:48 +00:00
|
|
|
|
|
|
|
// avoiding navigating to original URL
|
|
|
|
// DO NOT USE stopPropagation or you'll break click tracking in WikimediaEvents
|
|
|
|
ev.preventDefault();
|
|
|
|
|
2019-10-17 22:46:07 +00:00
|
|
|
if (
|
|
|
|
amcCampaign.showIfEligible(
|
|
|
|
amcOutreach.ACTIONS.onTalkLink,
|
|
|
|
onDismiss,
|
|
|
|
talkTitle,
|
|
|
|
returnToQuery
|
|
|
|
)
|
|
|
|
) {
|
2019-09-18 03:07:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-17 22:46:07 +00:00
|
|
|
onFollowRoute();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when user clicks on the add dicussion button located on a talk
|
|
|
|
* page
|
|
|
|
*
|
|
|
|
* @param {JQuery.Event} ev
|
|
|
|
*/
|
|
|
|
function amcAddTalkClickHandler( ev ) {
|
|
|
|
var
|
|
|
|
onFollowRoute = function () {
|
|
|
|
window.location.hash = '#/talk/new';
|
|
|
|
},
|
|
|
|
onDismiss = function () {
|
|
|
|
onFollowRoute();
|
|
|
|
|
|
|
|
toast.show( mw.message( 'mobile-frontend-amc-outreach-dismissed-message' ).text() );
|
|
|
|
};
|
|
|
|
|
|
|
|
showDrawerIfEligible( ev, onDismiss, onFollowRoute, '#/talk/new' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when user clicks on a talk button that links to the talk page
|
|
|
|
*
|
|
|
|
* @param {JQuery.Event} ev
|
|
|
|
*/
|
|
|
|
function amcTalkClickHandler( ev ) {
|
|
|
|
var
|
|
|
|
$button = $( ev.target ),
|
|
|
|
onFollowRoute = function () {
|
|
|
|
window.location = $button.attr( 'href' );
|
|
|
|
},
|
|
|
|
onDismiss = function () {
|
|
|
|
onFollowRoute();
|
|
|
|
|
|
|
|
toast.showOnPageReload( mw.message( 'mobile-frontend-amc-outreach-dismissed-message' ).text() );
|
|
|
|
};
|
|
|
|
|
|
|
|
showDrawerIfEligible( ev, onDismiss, onFollowRoute, '' );
|
2019-09-18 03:07:48 +00:00
|
|
|
}
|
|
|
|
|
2017-07-12 15:12:40 +00:00
|
|
|
/**
|
2019-10-17 22:46:07 +00:00
|
|
|
* @return {boolean}
|
|
|
|
*/
|
|
|
|
function isSimplifiedViewEnabled() {
|
|
|
|
// eslint-disable-next-line no-jquery/no-class-state, no-jquery/no-global-selector
|
|
|
|
return $( 'body' ).hasClass( SKIN_MINERVA_TALK_SIMPLIFIED_CLASS );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets up necessary event handlers related to the talk page and talk buttons.
|
|
|
|
* Also renders the "Read as wikipage" button for the simplified mode
|
|
|
|
* (T230695).
|
2017-07-12 15:12:40 +00:00
|
|
|
*/
|
|
|
|
function init() {
|
2019-10-17 22:46:07 +00:00
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
var $talk = $( '.talk' ),
|
|
|
|
// eslint-disable-next-line no-jquery/no-global-selector
|
|
|
|
$addTalk = $( '.minerva-talk-add-button' );
|
|
|
|
|
2019-09-18 03:07:48 +00:00
|
|
|
$talk.on( 'click', amcTalkClickHandler );
|
2019-10-17 22:46:07 +00:00
|
|
|
$addTalk.on( 'click', amcAddTalkClickHandler );
|
|
|
|
|
|
|
|
// We only want the talk section add overlay to show when the user is on the
|
|
|
|
// view action (default action) of the talk page and not when the user is on
|
|
|
|
// other actions of the talk page (e.g. like the history action)
|
|
|
|
if ( currentPage.titleObj.isTalkPage() && mw.config.get( 'wgAction' ) === 'view' ) {
|
|
|
|
initTalkSectionAdd();
|
|
|
|
}
|
|
|
|
// SkinMinerva sets a class on the body which effectively controls when this
|
|
|
|
// mode is on
|
|
|
|
if ( isSimplifiedViewEnabled() ) {
|
|
|
|
initTalkSection();
|
|
|
|
renderReadAsWikiPageButton();
|
|
|
|
}
|
2017-07-12 15:12:40 +00:00
|
|
|
}
|
|
|
|
|
2019-11-25 13:08:42 +00:00
|
|
|
if ( talkTitle ) {
|
|
|
|
init();
|
|
|
|
}
|
2019-09-18 23:07:21 +00:00
|
|
|
};
|