Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/* <nowiki> */
/* Bharat Mitra: warn module */
( function () {
	'use strict';
	var BM = window.BharatMitra;
	/* Warning types: base template and the levels it offers.
	   levels: null means a single notice with no level. */
	var TYPES = [
		{ key: 'vandalism', label: 'Vandalism', base: 'uw-vandalism', levels: [ '1', '2', '3', '4', '4im' ] },
		{ key: 'advertising', label: 'Advertising', base: 'uw-advert', levels: [ '1', '2', '3', '4', '4im' ] },
		{ key: 'unsourced', label: 'Unsourced', base: 'uw-unsourced', levels: [ '1', '2', '3', '4' ] },
		{ key: 'npa', label: 'Personal attacks', base: 'uw-npa', levels: [ '1', '2', '3', '4' ] },
		{ key: 'harassment', label: 'Harassment', base: 'uw-harass', levels: [ '1', '2', '3', '4', '4im' ] },
		{ key: 'copyright', label: 'Copyright', base: 'uw-copyright', levels: null },
		{ key: 'test', label: 'Test edits', base: 'uw-test', levels: [ '1', '2', '3' ] },
		{ key: 'npov', label: 'Point of view', base: 'uw-npov', levels: [ '1', '2', '3', '4' ] },
		{ key: 'blanking', label: 'Blanking', base: 'uw-blank', levels: null },
		{ key: 'username', label: 'Username', base: 'uw-username', levels: null }
	];
	var TYPEMAP = {}, BASEMAP = {};
	TYPES.forEach( function ( t ) { TYPEMAP[ t.key ] = t; BASEMAP[ t.base ] = t; } );
	var RANK = { '1': 1, '2': 2, '3': 3, '4': 4, '4im': 5 };

	function analyze( content ) {
		var found = [];
		var re = /\{\{(?:subst:)?(uw-[a-z0-9-]+?)(4im|[1-4])?(?:\||\}\})/g;
		var m;
		while ( ( m = re.exec( content || '' ) ) !== null ) {
			var t = BASEMAP[ m[ 1 ] ];
			if ( !t ) { continue; }
			found.push( { type: t.key, level: m[ 2 ] || '', pos: m.index } );
		}
		return found;
	}
	function suggestFor( t, found ) {
		if ( !t.levels ) { return ''; }
		var max = '';
		found.forEach( function ( f ) {
			if ( f.type !== t.key || !f.level ) { return; }
			if ( !max || RANK[ f.level ] > RANK[ max ] ) { max = f.level; }
		} );
		if ( !max ) { return t.levels[ 0 ]; }
		var idx = t.levels.indexOf( max );
		if ( idx === -1 ) { return t.levels[ t.levels.length - 1 ]; }
		return t.levels[ Math.min( idx + 1, t.levels.length - 1 ) ];
	}
	function clampLevel( t, level ) {
		if ( !t.levels ) { return ''; }
		if ( t.levels.indexOf( level ) !== -1 ) { return level; }
		var best = t.levels[ 0 ];
		t.levels.forEach( function ( l ) {
			if ( RANK[ l ] <= ( RANK[ level ] || 0 ) ) { best = l; }
		} );
		return best;
	}
	function buildBlock( t, levelSuffix, article, comment ) {
		var out = '{{subst:' + t.base + levelSuffix;
		var a = BM.core.cleanParam( article );
		var c = BM.core.cleanParam( comment );
		if ( a ) { out += '|' + a; }
		if ( c ) { out += '|' + c; }
		out += '}}';
		return out + BM.SIG;
	}

	BM.register( 'warn', {
		open: function () {
			var user = BM.targetUser();
			if ( !user ) { mw.notify( 'This option is only available on user pages.', { type: 'error' } ); return; }
			var talk = 'User talk:' + user;
			$.when( BM.core.getConfig(), BM.core.getPage( talk ) ).then( function ( cfg, page ) {
				var found = analyze( page.content );
				var last = found.length ? found[ found.length - 1 ] : null;
				var suggested = {};
				TYPES.forEach( function ( t ) { suggested[ t.key ] = suggestFor( t, found ); } );
				var info;
				if ( last ) {
					var lt = TYPEMAP[ last.type ];
					info = 'Last warning found: ' + lt.label +
						( lt.levels ? ' (level ' + ( last.level || '1' ) + ')' : ' (standard notice)' ) +
						'. With the level set to automatic, the next level of the same type will be chosen.';
				} else {
					info = 'No earlier warnings were found on this talk page.';
				}
				var ns = mw.config.get( 'wgNamespaceNumber' );
				var articleDefault = ( ns === 0 ) ? mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ) : '';
				function resolveLevel( typeKey, choice ) {
					var t = TYPEMAP[ typeKey ];
					if ( !t || !t.levels ) { return ''; }
					if ( choice === 'auto' ) { return suggested[ typeKey ]; }
					return clampLevel( t, choice );
				}
				BM.core.dialog( {
					title: 'Warn user: ' + user,
					help: 'The warning will be added under this month\'s section. A preview is always shown before sending.',
					info: info,
					fields: [
						{ name: 'type', label: 'Type of warning', type: 'select', required: true,
							options: TYPES.map( function ( t ) { return [ t.key, t.label ]; } ),
							value: last ? last.type : 'vandalism' },
						{ name: 'level', label: 'Level', type: 'select', required: true,
							options: [ [ 'auto', 'Automatic (based on previous warnings)' ],
								[ '1', 'Level 1' ], [ '2', 'Level 2' ], [ '3', 'Level 3' ],
								[ '4', 'Level 4' ], [ '4im', 'Level 4im' ] ],
							value: cfg.warnLevel || 'auto' },
						{ name: 'article', label: 'Related page (optional)', type: 'text', value: articleDefault },
						{ name: 'comment', label: 'Your comment (optional)', type: 'textarea', rows: 3 }
					],
					preview: function ( v ) {
						var t = TYPEMAP[ v.type ];
						return buildBlock( t, resolveLevel( v.type, v.level ), v.article, v.comment );
					},
					previewTitle: function () { return talk; },
					submitLabel: 'Send warning',
					success: 'Warning added.',
					onSubmit: function ( v ) {
						var t = TYPEMAP[ v.type ];
						var lvl = resolveLevel( v.type, v.level );
						var block = buildBlock( t, lvl, v.article, v.comment );
						return BM.core.appendUnderMonth( talk, block,
							'Warning issued (' + t.label + ( lvl ? ', level ' + lvl : '' ) + ') (using [[Bharatpedia:Bharat Mitra|Bharat Mitra]])' );
					}
				} );
				/* The level list must only offer the chosen type's levels */
				var $type = $( 'select[data-bm-field="type"]' );
				var $level = $( 'select[data-bm-field="level"]' );
				function syncLevels() {
					var t = TYPEMAP[ $type.val() ];
					if ( !t ) { return; }
					var cur = $level.val();
					$level.empty();
					if ( !t.levels ) {
						$level.append( $( '<option>' ).attr( 'value', 'single' ).text( 'Standard notice' ) );
						$level.val( 'single' );
						return;
					}
					$level.append( $( '<option>' ).attr( 'value', 'auto' )
						.text( 'Automatic (based on previous warnings)' ) );
					t.levels.forEach( function ( l ) {
						$level.append( $( '<option>' ).attr( 'value', l ).text( 'Level ' + l ) );
					} );
					var want = ( cur && cur !== 'single' ) ? cur : ( cfg.warnLevel || 'auto' );
					if ( want !== 'auto' ) { want = clampLevel( t, want ); }
					$level.val( want );
				}
				$type.on( 'change', syncLevels );
				syncLevels();
			} ).catch( function () {
				mw.notify( 'The talk page could not be read.', { type: 'error' } );
			} );
		}
	} );
}() );
/* </nowiki> */