var controller = require( 'ext.discussionTools.init' ).controller, modifier = require( 'ext.discussionTools.init' ).modifier, utils = require( 'ext.discussionTools.init' ).utils, logger = require( 'ext.discussionTools.init' ).logger, ModeTabSelectWidget = require( './ModeTabSelectWidget.js' ), ModeTabOptionWidget = require( './ModeTabOptionWidget.js' ), featuresEnabled = mw.config.get( 'wgDiscussionToolsFeaturesEnabled' ) || {}, enable2017Wikitext = featuresEnabled.sourcemodetoolbar; require( './AbandonCommentDialog.js' ); require( './AbandonTopicDialog.js' ); /** * @external CommentController * @external CommentItem * @external CommentDetails */ /** * DiscussionTools ReplyWidget class * * @class mw.dt.ReplyWidget * @extends OO.ui.Widget * @constructor * @param {CommentController} commentController Comment controller * @param {CommentItem} comment Comment item * @param {CommentDetails} commentDetails * @param {Object} [config] Configuration options * @param {Object} [config.input] Configuration options for the comment input widget */ function ReplyWidget( commentController, comment, commentDetails, config ) { var widget = this; config = config || {}; // Parent constructor ReplyWidget.super.call( this, config ); this.pending = false; this.commentController = commentController; this.comment = comment; this.commentDetails = commentDetails; this.isNewTopic = !!comment.isNewTopic; this.pageName = commentDetails.pageName; this.oldId = commentDetails.oldId; var contextNode = utils.closestElement( comment.range.endContainer, [ 'dl', 'ul', 'ol' ] ); this.context = contextNode ? contextNode.nodeName.toLowerCase() : 'dl'; // TODO: Should storagePrefix include pageName? this.storagePrefix = 'reply/' + comment.id; this.storage = mw.storage.session; // eslint-disable-next-line no-jquery/no-global-selector this.contentDir = $( '#mw-content-text' ).css( 'direction' ); var inputConfig = $.extend( { placeholder: this.isNewTopic ? mw.msg( 'discussiontools-replywidget-placeholder-newtopic' ) : mw.msg( 'discussiontools-replywidget-placeholder-reply', comment.author ), authors: comment.getHeading().getAuthorsBelow() }, config.input ); this.replyBodyWidget = this.createReplyBodyWidget( inputConfig ); this.replyButtonLabel = this.isNewTopic ? mw.msg( 'discussiontools-replywidget-newtopic' ) : mw.msg( 'discussiontools-replywidget-reply' ); this.replyButton = new OO.ui.ButtonWidget( { flags: [ 'primary', 'progressive' ], label: this.replyButtonLabel, title: this.replyButtonLabel + ' ' + // TODO: Use VE keyboard shortcut generating code ( $.client.profile().platform === 'mac' ? '⌘⏎' : mw.msg( 'visualeditor-key-ctrl' ) + '+' + mw.msg( 'visualeditor-key-enter' ) ) } ); this.cancelButton = new OO.ui.ButtonWidget( { flags: [ 'destructive' ], label: mw.msg( 'discussiontools-replywidget-cancel' ), framed: false, title: mw.msg( 'discussiontools-replywidget-cancel' ) + ' ' + // TODO: Use VE keyboard shortcut generating code ( $.client.profile().platform === 'mac' ? '⎋' : mw.msg( 'visualeditor-key-escape' ) ) } ); this.modeTabSelect = new ModeTabSelectWidget( { classes: [ 'ext-discussiontools-ui-replyWidget-modeTabs' ], items: [ new ModeTabOptionWidget( { label: mw.msg( 'discussiontools-replywidget-mode-visual' ), data: 'visual' } ), new ModeTabOptionWidget( { label: mw.msg( 'discussiontools-replywidget-mode-source' ), data: 'source' } ) ], framed: false } ); this.modeTabSelect.$element.attr( 'aria-label', mw.msg( 'visualeditor-mweditmode-tooltip' ) ); // Make the option for the current mode disabled, to make it un-interactable // (we override the styles to make it look as if it was selected) this.modeTabSelect.findItemFromData( this.getMode() ).setDisabled( true ); this.$headerWrapper = $( '
' ).addClass( 'ext-discussiontools-ui-replyWidget-headerWrapper' ); this.$headerWrapper.append( // Visual mode toolbar attached here by CommentTarget#attachToolbar this.modeTabSelect.$element ); this.$preview = $( '
' ) .addClass( 'ext-discussiontools-ui-replyWidget-preview' ) .attr( 'data-label', mw.msg( 'discussiontools-replywidget-preview' ) ) // Set preview direction to content direction .attr( 'dir', this.contentDir ); this.$actionsWrapper = $( '
' ).addClass( 'ext-discussiontools-ui-replyWidget-actionsWrapper' ); this.$actions = $( '
' ).addClass( 'ext-discussiontools-ui-replyWidget-actions' ).append( this.cancelButton.$element, this.replyButton.$element ); this.editSummaryInput = new OO.ui.TextInputWidget( { classes: [ 'ext-discussiontools-ui-replyWidget-editSummary' ] } ); mw.widgets.visibleCodePointLimit( this.editSummaryInput, mw.config.get( 'wgCommentCodePointLimit' ) ); this.editSummaryField = new OO.ui.FieldLayout( this.editSummaryInput, { align: 'top', classes: [ 'ext-discussiontools-ui-replyWidget-editSummaryField' ], label: mw.msg( 'discussiontools-replywidget-summary' ) } ); this.advancedToggle = new OO.ui.ButtonWidget( { label: mw.msg( 'discussiontools-replywidget-advanced' ), indicator: 'down', framed: false, flags: [ 'progressive' ], classes: [ 'ext-discussiontools-ui-replyWidget-advancedToggle' ] } ); this.advanced = new OO.ui.MessageWidget( { type: 'message', $content: this.editSummaryField.$element, classes: [ 'ext-discussiontools-ui-replyWidget-advanced' ] } ).toggle( false ).setIcon( '' ); this.$footer = $( '
' ).addClass( 'ext-discussiontools-ui-replyWidget-footer' ); if ( this.pageName !== mw.config.get( 'wgRelevantPageName' ) ) { this.$footer.append( $( '

' ).append( mw.message( 'discussiontools-replywidget-transcluded', this.pageName ).parseDom() ) ); } var $footerLinks = $( '