- {this.mergedFromTemplate.article} || {this.mergedFromTemplate.date} ||
- {this.mergedFromTemplate.talk} || {this.mergedFromTemplate.target} ||
- {this.mergedFromTemplate.afd}
-
);
+ this.$element.append(
+ this.renderButtons(),
+ this.renderHeader(),
+ renderPreviewPanel(
+ this.mergedFromTemplate
+ ),
+ this.renderTemplateOptions()
+ );
+ }
+
+ /**
+ * Refreshes the page's label
+ */
+ refreshLabel(): void {
+ this.label = mw.message(
+ 'deputy.cte.mergedFrom.label',
+ this.mergedFromTemplate.article || '???'
+ ).text();
+ if ( this.outlineItem ) {
+ this.outlineItem.setLabel( this.label );
+ }
+ }
+
+ /**
+ * Renders the set of buttons that appear at the top of the page.
+ *
+ * @return A element.
+ */
+ renderButtons(): JSX.Element {
+ const buttonSet =
;
+
+ const deleteButton = new OO.ui.ButtonWidget( {
+ icon: 'trash',
+ title: mw.message( 'deputy.cte.mergedFrom.remove' ).text(),
+ framed: false,
+ flags: [ 'destructive' ]
+ } );
+ deleteButton.on( 'click', () => {
+ this.mergedFromTemplate.destroy();
+ } );
+
+ buttonSet.appendChild( unwrapWidget( deleteButton ) );
+
+ return buttonSet;
+ }
+
+ /**
+ * @return The rendered header of this PageLayout.
+ */
+ renderHeader(): JSX.Element {
+ return
{ this.label }
;
+ }
+
+ /**
+ * @return The options for this template
+ */
+ renderTemplateOptions(): JSX.Element {
+ const layout = new OO.ui.FieldsetLayout( {
+ icon: 'parameter',
+ label: mw.message( 'deputy.cte.templateOptions' ).text(),
+ classes: [ 'cte-fieldset' ]
+ } );
+
+ const rowDate = this.mergedFromTemplate.date;
+ const parsedDate =
+ ( rowDate == null || rowDate.trim().length === 0 ) ?
+ undefined : (
+ !isNaN( new Date( rowDate.trim() + ' UTC' ).getTime() ) ?
+ ( new Date( rowDate.trim() + ' UTC' ) ) : (
+ !isNaN( new Date( rowDate.trim() ).getTime() ) ?
+ new Date( rowDate.trim() ) : null
+ )
+ );
+
+ const inputs = {
+ article: new mw.widgets.TitleInputWidget( {
+ $overlay: this.parent.$overlay,
+ required: true,
+ value: this.mergedFromTemplate.article || '',
+ placeholder: mw.message( 'deputy.cte.mergedFrom.article.placeholder' ).text()
+ } ),
+ date: new mw.widgets.datetime.DateTimeInputWidget( {
+ $overlay: this.parent.$overlay,
+ required: true,
+ calendar: null,
+ icon: 'calendar',
+ clearable: true,
+ value: parsedDate
+ } ),
+ target: new mw.widgets.TitleInputWidget( {
+ $overlay: this.parent.$overlay,
+ value: this.mergedFromTemplate.target || '',
+ placeholder: mw.message( 'deputy.cte.mergedFrom.target.placeholder' ).text()
+ } ),
+ afd: new mw.widgets.TitleInputWidget( {
+ $overlay: this.parent.$overlay,
+ value: this.mergedFromTemplate.afd || '',
+ placeholder: mw.message( 'deputy.cte.mergedFrom.afd.placeholder' ).text(),
+ validate: ( title: string ) => {
+ // TODO: l10n
+ return title.trim().length === 0 || title.startsWith(
+ new mw.Title( 'Articles for deletion/', nsId( 'wikipedia' ) )
+ .toText()
+ );
+ }
+ } ),
+ talk: new OO.ui.CheckboxInputWidget( {
+ $overlay: this.parent.$overlay,
+ selected: yesNo( this.mergedFromTemplate.target )
+ } )
+ };
+ const fieldLayouts = {
+ article: new OO.ui.FieldLayout( inputs.article, {
+ $overlay: this.parent.$overlay,
+ align: 'top',
+ label: mw.message( 'deputy.cte.mergedFrom.article.label' ).text(),
+ help: mw.message( 'deputy.cte.mergedFrom.article.help' ).text()
+ } ),
+ date: new OO.ui.FieldLayout( inputs.date, {
+ $overlay: this.parent.$overlay,
+ align: 'left',
+ label: mw.message( 'deputy.cte.mergedFrom.date.label' ).text(),
+ help: mw.message( 'deputy.cte.mergedFrom.date.help' ).text()
+ } ),
+ target: new OO.ui.FieldLayout( inputs.target, {
+ $overlay: this.parent.$overlay,
+ align: 'left',
+ label: mw.message( 'deputy.cte.mergedFrom.target.label' ).text(),
+ help: mw.message( 'deputy.cte.mergedFrom.target.help' ).text()
+ } ),
+ afd: new OO.ui.FieldLayout( inputs.afd, {
+ $overlay: this.parent.$overlay,
+ align: 'left',
+ label: mw.message( 'deputy.cte.mergedFrom.afd.label' ).text(),
+ help: mw.message( 'deputy.cte.mergedFrom.afd.help' ).text()
+ } ),
+ talk: new OO.ui.FieldLayout( inputs.talk, {
+ $overlay: this.parent.$overlay,
+ align: 'inline',
+ label: mw.message( 'deputy.cte.mergedFrom.talk.label' ).text(),
+ help: mw.message( 'deputy.cte.mergedFrom.talk.help' ).text()
+ } )
+ };
+
+ for ( const _field in inputs ) {
+ const field = _field as MergedFromTemplateParameter;
+ const input = inputs[ field ];
+
+ // Attach the change listener
+ input.on( 'change', ( value: string ) => {
+ if ( input instanceof OO.ui.CheckboxInputWidget ) {
+ this.mergedFromTemplate[ field ] = value ? 'yes' : 'no';
+ } else if ( input instanceof mw.widgets.datetime.DateTimeInputWidget ) {
+ this.mergedFromTemplate[ field ] =
+ new Date( value ).toLocaleDateString( 'en-GB', {
+ year: 'numeric', month: 'long', day: 'numeric'
+ } );
+ if ( value.length > 0 ) {
+ fieldLayouts[ field ].setWarnings( [] );
+ }
+ } else {
+ this.mergedFromTemplate[ field ] = value;
+ }
+
+ this.mergedFromTemplate.save();
+ } );
+
+ if ( input instanceof OO.ui.TextInputWidget ) {
+ // Rechecks the validity of the field.
+ input.setValidityFlag();
+ }
+ }
+
+ inputs.article.on( 'change', () => {
+ this.refreshLabel();
+ } );
+
+ layout.addItems( getObjectValues( fieldLayouts ) );
+
+ return unwrapWidget( layout );
}
/**
diff --git a/src/modules/cte/ui/pages/SplitArticleTemplateRowPage.tsx b/src/modules/cte/ui/pages/SplitArticleTemplateRowPage.tsx
index e0f45ce2..df65908f 100644
--- a/src/modules/cte/ui/pages/SplitArticleTemplateRowPage.tsx
+++ b/src/modules/cte/ui/pages/SplitArticleTemplateRowPage.tsx
@@ -31,13 +31,11 @@ function initSplitArticleTemplateRowPage() {
extends OO.ui.PageLayout
implements AttributionNoticePageLayout, SplitArticleTemplateRowPageData {
+ label: string;
+
splitArticleTemplateRow: SplitArticleTemplateRow;
parent: ReturnType
;
- // Elements
- inputs: Record;
- fieldLayouts: Record;
-
/**
* @param config Configuration to be passed to the element.
*/
@@ -51,16 +49,13 @@ function initSplitArticleTemplateRowPage() {
}
const finalConfig = {
- label: `${
- splitArticleTemplateRow.to || '???'
- } on ${splitArticleTemplateRow.date || '???'}`,
classes: [ 'cte-page-row' ]
};
super( splitArticleTemplateRow.id, finalConfig );
this.parent = parent;
this.splitArticleTemplateRow = splitArticleTemplateRow;
- this.label = finalConfig.label;
+ this.refreshLabel();
this.splitArticleTemplateRow.parent.addEventListener( 'destroy', () => {
parent.rebuildPages();
@@ -72,6 +67,20 @@ function initSplitArticleTemplateRowPage() {
this.$element.append( this.render().$element );
}
+ /**
+ * Refreshes the page's label
+ */
+ refreshLabel(): void {
+ this.label = mw.message(
+ 'deputy.cte.splitArticle.entry.short',
+ this.splitArticleTemplateRow.to || '???',
+ this.splitArticleTemplateRow.date || '???'
+ ).text();
+ if ( this.outlineItem ) {
+ this.outlineItem.setLabel( this.label );
+ }
+ }
+
/**
* Renders this page. Returns a FieldsetLayout OOUI widget.
*
@@ -134,7 +143,7 @@ function initSplitArticleTemplateRowPage() {
)
);
- this.inputs = {
+ const inputs = {
to: new mw.widgets.TitleInputWidget( {
$overlay: this.parent.$overlay,
required: true,
@@ -171,27 +180,27 @@ function initSplitArticleTemplateRowPage() {
}
} )
};
- this.fieldLayouts = {
- to: new OO.ui.FieldLayout( this.inputs.to, {
+ const fieldLayouts = {
+ to: new OO.ui.FieldLayout( inputs.to, {
$overlay: this.parent.$overlay,
align: 'top',
label: mw.message( 'deputy.cte.splitArticle.to.label' ).text(),
help: mw.message( 'deputy.cte.splitArticle.to.help' ).text()
} ),
// eslint-disable-next-line camelcase
- from_oldid: new OO.ui.FieldLayout( this.inputs.from_oldid, {
+ from_oldid: new OO.ui.FieldLayout( inputs.from_oldid, {
$overlay: this.parent.$overlay,
align: 'left',
label: mw.message( 'deputy.cte.splitArticle.from_oldid.label' ).text(),
help: mw.message( 'deputy.cte.splitArticle.from_oldid.help' ).text()
} ),
- date: new OO.ui.FieldLayout( this.inputs.date, {
+ date: new OO.ui.FieldLayout( inputs.date, {
$overlay: this.parent.$overlay,
align: 'left',
label: mw.message( 'deputy.cte.splitArticle.date.label' ).text(),
help: mw.message( 'deputy.cte.splitArticle.date.help' ).text()
} ),
- diff: new OO.ui.FieldLayout( this.inputs.diff, {
+ diff: new OO.ui.FieldLayout( inputs.diff, {
$overlay: this.parent.$overlay,
align: 'left',
label: mw.message( 'deputy.cte.splitArticle.diff.label' ).text(),
@@ -199,9 +208,9 @@ function initSplitArticleTemplateRowPage() {
} )
};
- for ( const _field in this.inputs ) {
+ for ( const _field in inputs ) {
const field = _field as SplitArticleTemplateRowParameter;
- const input = this.inputs[ field ];
+ const input = inputs[ field ];
// Attach the change listener
input.on( 'change', ( value: string ) => {
@@ -211,7 +220,7 @@ function initSplitArticleTemplateRowPage() {
year: 'numeric', month: 'long', day: 'numeric'
} );
if ( value.length > 0 ) {
- this.fieldLayouts[ field ].setWarnings( [] );
+ fieldLayouts[ field ].setWarnings( [] );
}
} else {
this.splitArticleTemplateRow[ field ] = value;
@@ -225,22 +234,14 @@ function initSplitArticleTemplateRowPage() {
}
}
- this.inputs.to.on( 'change', () => {
- this.outlineItem.setLabel(
- `${
- this.splitArticleTemplateRow.to || '???'
- } on ${this.splitArticleTemplateRow.date || '???'}`
- );
+ inputs.to.on( 'change', () => {
+ this.refreshLabel();
} );
- this.inputs.date.on( 'change', () => {
- this.outlineItem.setLabel(
- `${
- this.splitArticleTemplateRow.to || '???'
- } on ${this.splitArticleTemplateRow.date || '???'}`
- );
+ inputs.date.on( 'change', () => {
+ this.refreshLabel();
} );
- return getObjectValues( this.fieldLayouts );
+ return getObjectValues( fieldLayouts );
}
/**
diff --git a/src/util/yesNo.ts b/src/util/yesNo.ts
new file mode 100644
index 00000000..2cb3ab0a
--- /dev/null
+++ b/src/util/yesNo.ts
@@ -0,0 +1,28 @@
+/**
+ * Performs {{yesno}}-based string interpretation.
+ *
+ * @param value The value to check
+ * @param pull Depends which direction to pull unspecified values.
+ * @return If `pull` is true,
+ * any value that isn't explicitly a negative value will return `true`. Otherwise,
+ * any value that isn't explicitly a positive value will return `false`.
+ */
+export default function ( value: string|number|boolean, pull = true ): boolean {
+ if ( pull ) {
+ return value !== false &&
+ value !== 'no' &&
+ value !== 'n' &&
+ value !== 'false' &&
+ value !== 'f' &&
+ value !== 'off' &&
+ +value !== 0;
+ } else {
+ return value !== true &&
+ value !== 'yes' &&
+ value !== 'y' &&
+ value !== 't' &&
+ value !== 'true' &&
+ value !== 'on' &&
+ value !== '1';
+ }
+}