mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/DiscussionTools
synced 2024-11-28 18:21:50 +00:00
0cb756f248
This will avoid a flash of the empty-state while we're reloading the page to get new tabs. Refactor out the new topic controller's clear behavior from its teardown behavior, so we can still wipe out the storage when redirecting. Bug: T288314 Bug: T288320 Change-Id: I6a5313b5e5b3bc9925e5cdaea04d8fbd3dc796af
282 lines
8.3 KiB
JavaScript
282 lines
8.3 KiB
JavaScript
var
|
|
utils = require( './utils.js' ),
|
|
CommentController = require( './CommentController.js' ),
|
|
HeadingItem = require( './HeadingItem.js' );
|
|
|
|
function NewTopicController( $pageContainer, parser ) {
|
|
this.container = new OO.ui.PanelLayout( {
|
|
classes: [ 'ext-discussiontools-ui-newTopic' ],
|
|
expanded: false,
|
|
padded: true,
|
|
framed: true
|
|
} );
|
|
this.$notices = $( '<div>' ).addClass( 'ext-discussiontools-ui-newTopic-notices' );
|
|
|
|
this.sectionTitle = new OO.ui.TextInputWidget( {
|
|
// Wrap in a <h2> element to inherit heading font styles
|
|
$element: $( '<h2>' ),
|
|
classes: [ 'ext-discussiontools-ui-newTopic-sectionTitle' ],
|
|
placeholder: mw.msg( 'discussiontools-newtopic-placeholder-title' ),
|
|
spellcheck: true
|
|
} );
|
|
this.sectionTitle.$input.attr( 'aria-label', mw.msg( 'discussiontools-newtopic-placeholder-title' ) );
|
|
this.sectionTitleField = new OO.ui.FieldLayout( this.sectionTitle, {
|
|
align: 'top'
|
|
} );
|
|
this.prevTitleText = '';
|
|
|
|
this.container.$element.append( this.$notices, this.sectionTitleField.$element );
|
|
|
|
// HeadingItem representing the heading being added, so that we can pretend we're replying to it
|
|
var comment = new HeadingItem( {
|
|
startContainer: this.sectionTitleField.$element[ 0 ],
|
|
startOffset: 0,
|
|
endContainer: this.sectionTitleField.$element[ 0 ],
|
|
endOffset: this.sectionTitleField.$element[ 0 ].childNodes.length
|
|
} );
|
|
comment.id = utils.NEW_TOPIC_COMMENT_ID;
|
|
comment.isNewTopic = true;
|
|
|
|
NewTopicController.super.call( this, $pageContainer, comment, parser );
|
|
}
|
|
|
|
OO.inheritClass( NewTopicController, CommentController );
|
|
|
|
/* Static properties */
|
|
|
|
NewTopicController.static.initType = 'section';
|
|
|
|
NewTopicController.static.suppressedEditNotices = [
|
|
// Ignored because we have a custom warning for non-logged-in users.
|
|
'anoneditwarning',
|
|
// Ignored because it contains mostly instructions for signing comments using tildes.
|
|
// (Does not appear in VE notices right now, but just in case.)
|
|
'talkpagetext',
|
|
// Ignored because the empty state takeover has already explained
|
|
// that this is a new article.
|
|
'newarticletext',
|
|
'newarticletextanon'
|
|
];
|
|
|
|
/* Methods */
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.setup = function ( mode ) {
|
|
var rootScrollable = OO.ui.Element.static.getRootScrollableElement( document.body );
|
|
|
|
this.$pageContainer.append( this.container.$element );
|
|
NewTopicController.super.prototype.setup.call( this, mode );
|
|
|
|
// The section title field is added to the page immediately, we can scroll to the bottom and focus
|
|
// it while the content field is still loading.
|
|
rootScrollable.scrollTop = rootScrollable.scrollHeight;
|
|
this.focus();
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.setupReplyWidget = function ( replyWidget, data ) {
|
|
NewTopicController.super.prototype.setupReplyWidget.call( this, replyWidget, data );
|
|
|
|
this.$notices.empty();
|
|
for ( var noticeName in this.replyWidget.commentDetails.notices ) {
|
|
if ( this.constructor.static.suppressedEditNotices.indexOf( noticeName ) !== -1 ) {
|
|
continue;
|
|
}
|
|
var noticeItem = this.replyWidget.commentDetails.notices[ noticeName ];
|
|
var $noticeElement = $( '<div>' )
|
|
.addClass( 'ext-discussiontools-ui-replyWidget-notice' )
|
|
.html( typeof noticeItem === 'string' ? noticeItem : noticeItem.message );
|
|
this.$notices.append( $noticeElement );
|
|
}
|
|
|
|
var title = this.replyWidget.storage.get( this.replyWidget.storagePrefix + '/title' );
|
|
if ( title && !this.sectionTitle.getValue() ) {
|
|
// Don't overwrite if the user has already typed something in while the widget was loading.
|
|
// TODO This should happen immediately rather than waiting for the reply widget to load,
|
|
// then we wouldn't need this check, but the autosave code is in ReplyWidget.
|
|
this.sectionTitle.setValue( title );
|
|
}
|
|
|
|
this.sectionTitle.connect( this, { change: 'onSectionTitleChange' } );
|
|
this.sectionTitle.$input.on( 'blur', this.onSectionTitleBlur.bind( this ) );
|
|
|
|
replyWidget.connect( this, {
|
|
clear: 'clear',
|
|
clearStorage: 'clearStorage'
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.focus = function () {
|
|
this.sectionTitle.focus();
|
|
};
|
|
|
|
/**
|
|
* Restore the widget to its original state
|
|
*/
|
|
NewTopicController.prototype.clear = function () {
|
|
// This is going to get called as part of the teardown chain from replywidget
|
|
this.sectionTitle.setValue( '' );
|
|
this.sectionTitleField.setWarnings( [] );
|
|
};
|
|
|
|
/**
|
|
* Remove any storage that the widget is using
|
|
*/
|
|
NewTopicController.prototype.clearStorage = function () {
|
|
// This is going to get called as part of the teardown chain from replywidget
|
|
if ( this.replyWidget ) {
|
|
this.replyWidget.storage.remove( this.replyWidget.storagePrefix + '/title' );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.teardown = function ( abandoned ) {
|
|
NewTopicController.super.prototype.teardown.call( this, abandoned );
|
|
|
|
this.container.$element.detach();
|
|
|
|
if ( mw.config.get( 'wgDiscussionToolsStartNewTopicTool' ) ) {
|
|
var uri;
|
|
try {
|
|
uri = new mw.Uri();
|
|
} catch ( err ) {
|
|
// T106244: URL encoded values using fallback 8-bit encoding (invalid UTF-8) cause mediawiki.Uri to crash
|
|
return;
|
|
}
|
|
delete uri.query.action;
|
|
delete uri.query.veaction;
|
|
delete uri.query.section;
|
|
history.replaceState( null, document.title, uri.toString() );
|
|
mw.config.set( 'wgDiscussionToolsStartNewTopicTool', false );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.doIndentReplacements = function ( wikitext ) {
|
|
// No indent replacements when posting new topics
|
|
return wikitext;
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.undoIndentReplacements = function ( wikitext ) {
|
|
// No indent replacements when posting new topics
|
|
return wikitext;
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.getUnsupportedNodeSelectors = function () {
|
|
// No unsupported nodes when posting new topics
|
|
return {};
|
|
};
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
NewTopicController.prototype.getApiQuery = function ( comment, pageName, checkboxes ) {
|
|
var data = NewTopicController.super.prototype.getApiQuery.call( this, comment, pageName, checkboxes );
|
|
|
|
// Rebuild the tags array and remove the reply tag
|
|
var tags = ( data.dttags || '' ).split( ',' );
|
|
var replyTag = tags.indexOf( 'discussiontools-reply' );
|
|
if ( replyTag !== -1 ) {
|
|
tags.splice( replyTag, 1 );
|
|
}
|
|
// Add the newtopic tag
|
|
tags.push( 'discussiontools-newtopic' );
|
|
|
|
data = $.extend( {}, data, {
|
|
paction: 'addtopic',
|
|
sectiontitle: this.sectionTitle.getValue(),
|
|
dttags: tags.join( ',' )
|
|
} );
|
|
|
|
return data;
|
|
};
|
|
|
|
/**
|
|
* Generate a default edit summary based on the section title.
|
|
*
|
|
* @param {string} titleText Section title
|
|
* @return {string}
|
|
*/
|
|
NewTopicController.prototype.generateSummary = function ( titleText ) {
|
|
return titleText ? mw.msg( 'newsectionsummary', titleText ) : '';
|
|
};
|
|
|
|
/**
|
|
* Handle 'change' events for the section title input.
|
|
*
|
|
* @private
|
|
*/
|
|
NewTopicController.prototype.onSectionTitleChange = function () {
|
|
var titleText = this.sectionTitle.getValue();
|
|
var prevTitleText = this.prevTitleText;
|
|
|
|
if ( prevTitleText !== titleText ) {
|
|
this.replyWidget.storage.set( this.replyWidget.storagePrefix + '/title', titleText );
|
|
|
|
var generatedSummary = this.generateSummary( titleText );
|
|
var generatedPrevSummary = this.generateSummary( prevTitleText );
|
|
|
|
var currentSummary = this.replyWidget.editSummaryInput.getValue();
|
|
|
|
// Fill in edit summary if it was not modified by the user yet
|
|
if ( currentSummary === generatedPrevSummary ) {
|
|
this.replyWidget.editSummaryInput.setValue( generatedSummary );
|
|
}
|
|
}
|
|
|
|
this.prevTitleText = titleText;
|
|
|
|
this.checkSectionTitleValidity();
|
|
};
|
|
|
|
/**
|
|
* Handle 'blur' events for the section title input.
|
|
*
|
|
* @private
|
|
*/
|
|
NewTopicController.prototype.onSectionTitleBlur = function () {
|
|
var offsetBefore = this.replyWidget.$element.offset().top;
|
|
|
|
this.checkSectionTitleValidity();
|
|
|
|
var offsetChange = this.replyWidget.$element.offset().top - offsetBefore;
|
|
// Ensure the rest of the widget doesn't move when the validation
|
|
// message is triggered by a blur. (T275923)
|
|
window.scrollBy( 0, offsetChange );
|
|
};
|
|
|
|
/**
|
|
* Check if the section title is valid, and display a warning message.
|
|
*
|
|
* @private
|
|
*/
|
|
NewTopicController.prototype.checkSectionTitleValidity = function () {
|
|
if ( !this.sectionTitle.getValue() ) {
|
|
// Show warning about missing title
|
|
this.sectionTitleField.setWarnings( [
|
|
mw.msg( 'discussiontools-newtopic-missing-title' )
|
|
] );
|
|
} else {
|
|
this.sectionTitleField.setWarnings( [] );
|
|
}
|
|
};
|
|
|
|
module.exports = NewTopicController;
|