Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*


== User Info Popup ==

Adds an "i" (info) icon at the top of user-related pages
(e.g. user pages, user talk pages, "Contributions" pages, etc.)

The color of the "i" icon represents the amount of time passed since the user last edited:
* Green – user last edited less than 20 minutes ago
* Orange – user last edited more than 20 minutes ago, but less than 3 months ago
* Red – user last edited more than 3 months ago

Hover over the "i" icon to quickly view useful information about the relevant user:
* Registration date
* Number of edits
* Time elapsed since last edit
* User groups (rights), incl. global ones
* Latest block time (incl. range and global blocks, when applicable)
* Gender (if disclosed)

See full documentation at:
[[User:Guycn2/UserInfoPopup]]

See also:
* [[User:Guycn2/UserInfoPopup.css]] – for the corresponding style sheet

Skins supported:
Vector (both 2022 and 2010), Monobook, Timeless, and Minerva.
Also fully supported on the mobile interface.

Dependencies:
* mediawiki.api
* mediawiki.language.months
* mediawiki.user
* mediawiki.util
* user.options
* oojs-ui-core


Written by: [[User:Guycn2]]


*/

( async () => {
	
	'use strict';
	
	const username = mw.config.get( 'wgRelevantUserName' );
	
	if ( !username || mw.config.get( 'userInfoPopupLoaded' ) ) {
		return;
	}
	
	mw.config.set( 'userInfoPopupLoaded', true );
	
	await mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] );
	
	const isAnon = mw.util.isIPAddress( username );
	
	const api = new mw.Api();
	
	async function checkIfUserExists() {
		
		if ( isAnon ) {
			return true;
		}
		
		const data = await api.get( { list: 'users', ususers: username } );
		
		if ( data.query.users[ 0 ].userid ) {
			return true;
		}
		
		return false;
		
	}
	
	if ( !( await checkIfUserExists() ) ) {
		return;
	}
	
	mw.loader.load(
		'https://en.wikipedia.org/w/index.php?title=User:Guycn2/UserInfoPopup.css&action=raw&ctype=text/css',
		'text/css'
	);
	
	const scriptData = {
		lang: mw.config.get( 'wgUserLanguage' ),
		skin: mw.config.get( 'skin' ),
		secsFromLastEdit: await calcSecsFromLastEdit()
	};
	
	createInfoIcon();
	
	await $.when( mw.loader.using( 'oojs-ui-core' ), $.ready );
	
	addInfoIconToPage();
	
	attachEventListeners();
	
	function i18n( key ) {
		
		const messages = {
			
			en: {
				infoIconAlt: 'Info icon',
				femaleSymbolAlt: 'Female',
				maleSymbolAlt: 'Male',
				fetchingData: 'Fetching data…',
				regUnknown: 'Unknown',
				joined: 'Joined:',
				editCount: 'Edits:',
				lastEdited: 'Last edited:',
				lastEditedNever: 'Never',
				lastEditedUnknown: 'Unknown',
				groups: 'Groups:',
				noGroups: 'None',
				lastBlocked: 'Last blocked:',
				neverBlocked: 'Never',
				partiallyBlocked: 'Currently blocked (partially)',
				fullyBlocked: 'Currently blocked',
				rangeBlockedPartially: 'Currently range-blocked (partially)',
				rangeBlockedFully: 'Currently range-blocked',
				globallyBlocked: 'Currently blocked globally',
				globallyLocked: 'Currently locked globally',
				ago: '$1 ago',
				seconds: [ '1 second', '$1 seconds' ],
				minutes: [ '1 minute', '$1 minutes' ],
				hours: [ '1 hour', '$1 hours' ],
				days: [ '1 day', '$1 days' ],
				weeks: [ '1 week', '$1 weeks' ],
				months: [ '1 month', '$1 months' ],
				years: [ '1 year', '$1 years' ]
			},
			
			he: {
				infoIconAlt: 'צלמית מידע',
				femaleSymbolAlt: 'נקבה',
				maleSymbolAlt: 'זכר',
				fetchingData: 'המידע בטעינה…',
				regUnknown: 'לא ידוע',
				joined: 'הרשמה:',
				editCount: 'עריכות:',
				lastEdited: 'עריכה אחרונה:',
				lastEditedNever: 'אין',
				lastEditedUnknown: 'לא ידוע',
				groups: 'קבוצות:',
				noGroups: 'ללא',
				lastBlocked: 'חסימה אחרונה:',
				neverBlocked: 'אין',
				partiallyBlocked: 'חסימה פעילה כעת (חלקית)',
				fullyBlocked: 'חסימה פעילה כעת',
				rangeBlockedPartially: 'חסימת טווח פעילה כעת (חלקית)',
				rangeBlockedFully: 'חסימת טווח פעילה כעת',
				globallyBlocked: 'חסימה גלובלית פעילה כעת',
				globallyLocked: 'נעילה גלובלית פעילה כעת',
				ago: 'לפני $1',
				seconds: [ 'שנייה', '$1 שניות' ],
				minutes: [ 'דקה', '$1 דקות' ],
				hours: [ 'שעה', 'שעתיים', '$1 שעות' ],
				days: [ 'יום', 'יומיים', '$1 ימים' ],
				weeks: [ 'שבוע', 'שבועיים', '$1 שבועות' ],
				months: [ 'חודש', 'חודשיים', '$1 חודשים' ],
				years: [ 'שנה', 'שנתיים', '$1 שנים' ]
			}
			
		};
		
		if (
			messages[ scriptData.lang ] &&
			messages[ scriptData.lang ][ key ]
		) {
			
			return messages[ scriptData.lang ][ key ];
			
		} else {
			
			return messages.en[ key ];
			
		}
		
	}
	
	async function calcSecsFromLastEdit() {
		
		const params = {
			list: 'usercontribs',
			ucuser: username,
			ucprop: 'timestamp',
			uclimit: 1
		};
		
		const data = await api.get( params );
		
		if ( data.query.usercontribs.length === 0 ) {
			return null;
		}
		
		const lastEditTime =
			new Date( data.query.usercontribs[ 0 ].timestamp ).getTime();
		
		return ( mw.now() - lastEditTime ) / 1000;
		
	}
	
	function createInfoIcon() {
		
		const $img = $( '<img>' )
			.addClass( 'user-info-popup-icon' )
			.attr( {
				alt: i18n( 'infoIconAlt' ),
				width: '20.3',
				height: '20.3'
			} );
		
		if ( scriptData.secsFromLastEdit === null ) {
			
			$img
			.addClass( 'user-info-popup-grey-icon' )
			.attr( 'src', 'https://upload.wikimedia.org/wikipedia/commons/d/df/Information_grey.svg' );
			
		} else if ( scriptData.secsFromLastEdit < 60 * 20 ) {
			
			$img
			.addClass( 'user-info-popup-green-icon' )
			.attr( 'src', 'https://upload.wikimedia.org/wikipedia/commons/7/7d/Information_green.svg' );
			
		} else if ( scriptData.secsFromLastEdit < 60 * 60 * 24 * 30 * 3 ) {
			
			$img
			.addClass( 'user-info-popup-orange-icon' )
			.attr( 'src', 'https://upload.wikimedia.org/wikipedia/commons/f/f0/Information_orange.svg' );
			
		} else {
			
			$img
			.addClass( 'user-info-popup-red-icon' )
			.attr( 'src', 'https://upload.wikimedia.org/wikipedia/commons/5/55/Information_red.svg' );
			
		}
		
		scriptData.$indicator = $( '<div>' )
			.addClass( 'mw-indicator' )
			.attr( { id: 'mw-indicator-user-info-popup-indicator', tabindex: '0' } )
			.append( $img );
		
	}
	
	function addInfoIconToPage() {
		
		const $throbberImg = $( '<img>' ).attr( {
			alt: i18n( 'fetchingData' ),
			id: 'user-info-popup-throbber',
			src: 'https://upload.wikimedia.org/wikipedia/commons/f/f8/Ajax-loader(2).gif'
		} );
		
		const $placeholderText = $( '<p>' )
			.attr( 'id', 'user-info-popup-placeholder-text' )
			.text( i18n( 'fetchingData' ) );
		
		scriptData.$popupPlaceholder = $( '<div>' )
			.attr( 'id', 'user-info-popup-placeholder' )
			.append( $throbberImg, $placeholderText );
		
		scriptData.popup = new OO.ui.PopupWidget( {
			$content: scriptData.$popupPlaceholder,
			align: 'backwards',
			autoFlip: false,
			id: 'user-info-popup-popup',
			hideWhenOutOfView: false,
			padded: true,
			position: 'below',
			width: 225
		} );
		
		scriptData.$indicator.append( scriptData.popup.$element );
		
		if (
			scriptData.skin === 'vector-2022' &&
			$( '.vector-page-toolbar-container:has( #ca-nstab-user )' ).length
		) {
			
			scriptData.$indicator
			.insertBefore( '.vector-page-tools-landmark:has( #vector-page-tools-dropdown )' );
			
		} else {
			
			const $indicatorsContainer = $( '.mw-indicators' );
			
			if (
				!window.matchMedia( '( orientation: portrait )' ).matches ||
				scriptData.skin === 'vector-2022' ||
				scriptData.skin === 'vector' ||
				( scriptData.skin === 'monobook' && !$( '#sidebar-toggle:visible' ).length )
			) {
				
				scriptData.popup.setAlignment( 'forwards' );
				
				scriptData.popup.setPosition( 'before' );
				
				if ( $indicatorsContainer.children( '.mw-indicator' ).length >= 6 ) {
					scriptData.popup.setAutoFlip( true );
				}
				
			}
			
			if ( scriptData.skin === 'minerva' ) {
				
				scriptData.$indicator
				.css( 'float', $( 'body.rtl' ).length ? 'left' : 'right' )
				.appendTo( '.header-container' );
				
			} else {
				
				$indicatorsContainer.prepend( scriptData.$indicator );
				
			}
			
		}
		
	}
	
	function attachEventListeners() {
		
		scriptData.popup.on( 'ready', () => {
			
			// Prevent mobile browsers from occasionally jumping
			// to the top of the page when tapping the "i" icon.
			window.scrollTo( scriptData.posX, scriptData.posY );
			
			if (
				document.documentElement.clientWidth < 600 &&
				scriptData.skin === 'vector-2022' &&
				scriptData.popup.$element.hasClass( 'oo-ui-popupWidget-anchored-top' )
			) {
				adaptPopupPosition();
			}
			
			scriptData.popup.$element.hide().fadeIn();
			
		} );
		
		scriptData.$indicator.on( 'mouseenter focusin keydown', e => {
			
			if ( e.type === 'keydown' ) {
				
				if ( ![ 'Enter', ' ' ].includes( e.key ) ) {
					return;
				}
				
				if ( e.key === ' ' ) {
					e.preventDefault();
				}
				
			}
			
			clearTimeout( scriptData.mouseLeaveTimeout );
			
			scriptData.mouseEnterTimeout = setTimeout( openPopup, 200 );
			
		} );
		
		scriptData.$indicator.on( 'mouseleave focusout', () => {
			
			if (
				document.activeElement.id === 'mw-indicator-user-info-popup-indicator' ||
				document.activeElement.parentElement.classList.contains(
					'user-info-popup-value'
				)
			) {
				return;
			}
			
			clearTimeout( scriptData.mouseEnterTimeout );
			
			scriptData.mouseLeaveTimeout = setTimeout( closePopup, 2500 );
			
		} );
		
		$( document ).on( 'keydown', e => {
			if ( e.key === 'Escape' ) {
				closePopup();
			}
		} );
		
		$( document ).on( 'click', closePopup );
		
		$( '.oo-ui-fieldsetLayout-header, .ext-discussiontools-init-section-bar' )
		.on( 'click', closePopup );
		
		scriptData.$indicator.on( 'click', e => e.stopPropagation() );
		
	}
	
	function adaptPopupPosition() {
		
		const innerBody = document.querySelector( '.mw-page-container' );
		
		const innerBodyRect = innerBody.getBoundingClientRect();
		
		const indicator = scriptData.$indicator[ 0 ];
		
		const indicatorRect = indicator.getBoundingClientRect();
		
		const dir = $( 'body.rtl' ).length ? 'left' : 'right';
		
		const pos =
			Math.abs( indicatorRect[ dir ] - innerBodyRect[ dir ] ) -
			indicator.offsetWidth / 2;
		
		scriptData.popupCss = mw.util.addCSS(
			`#user-info-popup-popup { ${ dir }: ${ pos }px !important; }`
		);
		
	}
	
	function openPopup() {
		
		if ( !scriptData.popup.isVisible() ) {
			
			// posX and posY are used to prevent mobile browsers from 
			// occasionally jumping to the top of the page when tapping
			// the "i" icon. See the popup's "ready" event listener above.
			scriptData.posX = window.scrollX;
			scriptData.posY = window.scrollY;
			
			scriptData.popup.toggle( true );
			
			if ( !scriptData.dataFetched ) {
				
				getUserData().then( fillPopupContent );
				
				scriptData.dataFetched = true;
				
			}
			
		}
		
	}
	
	function closePopup() {
		
		clearTimeout( scriptData.mouseLeaveTimeout );
		
		if ( scriptData.popup.isVisible() ) {
			
			scriptData.popup.$element.fadeOut( () => {
				
				scriptData.popup.toggle( false );
				
				scriptData.popup.$element.show();
				
				if ( scriptData.popupCss ) {
					scriptData.popupCss.disabled = true;
				}
				
			} );
			
		}
		
	}
	
	async function getUserData() {
		
		let params;
		
		if ( isAnon ) {
			
			params = {
				list: 'blocks|globalblocks|logevents|usercontribs',
				bkip: username,
				bkprop: 'flags|user',
				bklimit: 2,
				bgip: username,
				bgprop: 'address',
				bglimit: 1,
				leaction: 'block/block',
				letitle: `User:${ username }`,
				leprop: 'timestamp',
				lelimit: 1,
				ucuser: username,
				ucprop: '',
				uclimit: 'max'
			};
			
		} else {
			
			params = {
				list: 'blocks|logevents|usercontribs|users',
				meta: 'globaluserinfo',
				bkusers: username,
				bkprop: 'flags',
				bklimit: 1,
				leaction: 'block/block',
				letitle: `User:${ username }`,
				leprop: 'timestamp',
				lelimit: 1,
				ucuser: username,
				ucdir: 'newer',
				ucprop: 'timestamp',
				uclimit: 1,
				ususers: username,
				usprop: 'editcount|gender|groupmemberships|registration',
				guiuser: username,
				guiprop: 'groups'
			};
			
		}
		
		const data = await api.get( params );
		
		if ( isAnon ) {
			
			const editCount = data.query.usercontribs.length;
			
			scriptData.editCount = await renderAnonEditCount( editCount );
			
			scriptData.isGloballyBlocked = data.query.globalblocks.length;
			
			if ( scriptData.isGloballyBlocked ) {
				scriptData.globalBlockTarget = data.query.globalblocks[ 0 ].address;
			}
			
		} else {
			
			scriptData.gender = data.query.users[ 0 ].gender;
			
			if ( data.query.users[ 0 ].registration ) {
				
				scriptData.regDate =
					await formatDate( data.query.users[ 0 ].registration, true );
				
			} else if ( data.query.usercontribs[ 0 ] ) {
				
				scriptData.regDate =
					await formatDate( data.query.usercontribs[ 0 ].timestamp, true );
				
			} else {
				
				scriptData.regDate = i18n( 'regUnknown' );
				
			}
			
			scriptData.editCount = data.query.users[ 0 ].editcount.toLocaleString();
			
			const localGroups =
				data.query.users[ 0 ].groupmemberships.map( item => item.group );
			
			scriptData.localGroups = await renderGroups( localGroups );
			
			if ( data.query.globaluserinfo.groups ) {
				
				const globalGroups = data.query.globaluserinfo.groups.filter(
					item => !localGroups.includes( item )
				);
				
				scriptData.globalGroups = await renderGroups( globalGroups );
				
				scriptData.isLocked = data.query.globaluserinfo.locked === '';
				
			}
			
		}
		
		const blocks = data.query.blocks;
		
		scriptData.isBlocked = blocks.length;
		
		if ( scriptData.isBlocked ) {
			
			if ( isAnon && blocks[ 0 ].user !== username && blocks[ 1 ] ) {
				blocks.shift();
			}
			
			scriptData.isPartiallyBlocked = blocks[ 0 ].partial === '';
			
			scriptData.isRangeBlocked = isAnon && blocks[ 0 ].user !== username;
			
			if ( scriptData.isRangeBlocked ) {
				scriptData.rangeBlockTarget = blocks[ 0 ].user;
			}
			
		} else if ( data.query.logevents.length ) {
			
			scriptData.lastBlockDate =
				await formatDate( data.query.logevents[ 0 ].timestamp, false );
			
		}
		
	}
	
	async function renderAnonEditCount( editCount ) {
		
		if ( editCount < 500 ) {
			return editCount.toLocaleString();
		}
		
		await mw.loader.using( 'mediawiki.user' );
		
		const rights = await mw.user.getRights();
		
		const maxAnonEditCount = rights.includes( 'apihighlimits' ) ? 5000 : 500;
		
		if ( editCount === maxAnonEditCount ) {
			return `${ editCount.toLocaleString() }+`;
		} else {
			return editCount.toLocaleString();
		}
		
	}
	
	async function renderGroups( groups ) {
		
		if ( groups.length === 0 ) {
			return '';
		}
		
		let sysMsgGroups = '';
		
		groups.forEach( ( group, index ) => {
			
			sysMsgGroups += `{${ '{' }int:group-${ group }}}`;
			
			if ( index < groups.length - 1 ) {
				sysMsgGroups += ', ';
			}
			
		} );
		
		const params = {
			action: 'parse',
			uselang: scriptData.lang,
			text: sysMsgGroups,
			prop: 'text',
			contentmodel: 'wikitext',
			disablelimitreport: true
		};
		
		const data = await api.get( params );
		
		return $( data.parse.text[ '*' ] ).find( 'p' ).text().trim();
		
	}
	
	async function formatDate( timestamp, includeDay ) {
		
		await mw.loader.using( 'mediawiki.language.months' );
		
		const date = new Date( timestamp );
		const monthName = mw.language.months.names[ date.getMonth() ];
		const monthNameGen = mw.language.months.genitive[ date.getMonth() ];
		const year = date.getFullYear();
		
		if ( includeDay ) {
			
			const day = date.getDate();
			
			await mw.loader.using( 'user.options' );
			
			if ( mw.user.options.get( 'date' ) === 'mdy' ) {
				return `${ monthName } ${ day }, ${ year }`;
			} else {
				return `${ day } ${ monthNameGen } ${ year }`;
			}
			
		} else {
			
			return `${ monthName } ${ year }`;
			
		}
		
	}
	
	function fillPopupContent() {
		
		const $container = $( '<aside>' ).attr( 'id', 'user-info-popup-content' );
		
		const $header = $( '<header>' ).attr( 'id', 'user-info-popup-header' );
		
		$header.append(
			$( '<bdi>' )
			.attr( 'id', 'user-info-popup-username' )
			.text( mw.util.prettifyIP( username ) )
		);
		
		const $ul = $( '<ul>' ).attr( 'id', 'user-info-popup-list' );
		
		$container.append( $header, $ul );
		
		if ( !isAnon ) {
			
			addListItem( $ul, i18n( 'joined' ), scriptData.regDate );
			
		}
		
		const editCounterUrl =
			`https://xtools.wmcloud.org/ec/${ mw.config.get( 'wgServerName' ) }/${ encodeURIComponent( username ) }`;
		
		addListItem(
			$ul,
			i18n( 'editCount' ),
			`<a target="_blank" href="${ editCounterUrl }">${ scriptData.editCount }</a>`
		);
		
		const contribsUrl = mw.util.getUrl( `Special:Contributions/${ username }` );
		
		let lastEditedText;
		
		if ( scriptData.editCount === ( 0 ).toLocaleString() ) {
			lastEditedText = i18n( 'lastEditedNever' );
		} else if ( scriptData.secsFromLastEdit === null ) {
			lastEditedText = i18n( 'lastEditedUnknown' );
		} else {
			lastEditedText = i18n( 'ago' ).replace( '$1', calcTimeFromLastEdit() );
		}
		
		addListItem(
			$ul,
			i18n( 'lastEdited' ),
			`<a href="${ contribsUrl }">${ lastEditedText }</a>`
		);
		
		if ( !isAnon ) {
			
			const localGroupsUrl = mw.util.getUrl( `Special:UserRights/${ username }` );
			
			const globalGroupsUrl =
				mw.util.getUrl( `m:Special:GlobalUserRights/${ username }` );
			
			let groupsHtml;
			
			if ( !scriptData.localGroups && !scriptData.globalGroups ) {
				groupsHtml =
					`<a href="${ localGroupsUrl }">${ i18n( 'noGroups' ) }</a>`;
			}
			
			if ( scriptData.localGroups && !scriptData.globalGroups ) {
				groupsHtml =
					`<a href="${ localGroupsUrl }">${ scriptData.localGroups }</a>`;
			}
			
			if ( !scriptData.localGroups && scriptData.globalGroups ) {
				groupsHtml =
					`<a href="${ globalGroupsUrl }">${ scriptData.globalGroups }</a>`;
			}
			
			if ( scriptData.localGroups && scriptData.globalGroups ) {
				groupsHtml =
					`<a href="${ localGroupsUrl }">${ scriptData.localGroups }</a>,
					<a href="${ globalGroupsUrl }">${ scriptData.globalGroups }</a>`;
			}
			
			addListItem( $ul, i18n( 'groups' ), groupsHtml );
			
		}
		
		let lastBlockText;
		
		let blockLogUrl = mw.util.getUrl( 'Special:Log', {
			type: 'block',
			page: `User:${ username }`
		} );
		
		if ( scriptData.isGloballyBlocked ) {
			
			lastBlockText = i18n( 'globallyBlocked' );
			
			blockLogUrl = mw.util.getUrl( 'm:Special:Log', {
				type: 'gblblock',
				page: `User:${ scriptData.globalBlockTarget }`
			} );
			
		} else if ( scriptData.isLocked ) {
			
			lastBlockText = i18n( 'globallyLocked' );
			
			blockLogUrl = mw.util.getUrl( 'm:Special:Log', {
				type: 'globalauth',
				page: `User:${ username }@global`
			} );
			
		} else if ( scriptData.isBlocked ) {
			
			if ( scriptData.isRangeBlocked ) {
				
				if ( scriptData.isPartiallyBlocked ) {
					lastBlockText = i18n( 'rangeBlockedPartially' );
				} else {
					lastBlockText = i18n( 'rangeBlockedFully' );
				}
				
				blockLogUrl = mw.util.getUrl( 'Special:Log', {
					type: 'block',
					page: `User:${ scriptData.rangeBlockTarget }`
				} );
				
			} else {
				
				if ( scriptData.isPartiallyBlocked ) {
					lastBlockText = i18n( 'partiallyBlocked' );
				} else {
					lastBlockText = i18n( 'fullyBlocked' );
				}
				
			}
			
		} else {
			
			lastBlockText = scriptData.lastBlockDate || i18n( 'neverBlocked' );
			
		}
		
		addListItem(
			$ul,
			i18n( 'lastBlocked' ),
			`<a href="${ blockLogUrl }">${ lastBlockText }</a>`
		);
		
		if ( !isAnon && scriptData.gender !== 'unknown' ) {
			
			const images = {
				
				female: {
					alt: i18n( 'femaleSymbolAlt' ),
					path: 'https://upload.wikimedia.org/wikipedia/commons/8/8a/Light_pink_Venus_symbol.svg'
				},
				
				male: {
					alt: i18n( 'maleSymbolAlt' ),
					path: 'https://upload.wikimedia.org/wikipedia/commons/2/29/Light_blue_Mars_symbol.svg'
				}
				
			};
			
			$( '<img>' ).attr( {
				alt: images[ scriptData.gender ].alt,
				id: 'user-info-popup-gender-symbol',
				src: images[ scriptData.gender ].path,
				width: '16.6',
				height: '16.6'
			} ).appendTo( $header );
			
		}
		
		scriptData.$popupPlaceholder.replaceWith( $container );
		
	}
	
	function addListItem( $ul, property, value ) {
		
		const $li = $( '<li>' );
		
		const $property = $( '<span>' )
			.addClass( 'user-info-popup-property' )
			.text( property );
		
		const $value = $( '<span>' )
			.addClass( 'user-info-popup-value' )
			.html( value );
		
		$li.append( $property, ' ', $value ).appendTo( $ul );
		
	}
	
	function calcTimeFromLastEdit() {
		
		const secs = scriptData.secsFromLastEdit;
		
		const days = secs / 60 / 60 / 24;
		
		if ( secs < 60 ) {
			
			let fullSecs = Math.floor( secs );
			
			if ( fullSecs < 1 ) {
				fullSecs = 1;
			}
			
			const secsArrLength = i18n( 'seconds' ).length;
			
			if ( fullSecs < secsArrLength ) {
				
				return i18n( 'seconds' )[ fullSecs - 1 ];
				
			} else {
				
				return i18n( 'seconds' )[ secsArrLength - 1 ].replace( '$1', fullSecs );
				
			}
			
		} else if ( secs < 60 * 60 ) {
			
			const fullMins = Math.floor( secs / 60 );
			
			const minsArrLength = i18n( 'minutes' ).length;
			
			if ( fullMins < minsArrLength ) {
				
				return i18n( 'minutes' )[ fullMins - 1 ];
				
			} else {
				
				return i18n( 'minutes' )[ minsArrLength - 1 ].replace( '$1', fullMins );
				
			}
			
		} else if ( secs < 60 * 60 * 24 ) {
			
			const fullHours = Math.floor( secs / 60 / 60 );
			
			const hoursArrLength = i18n( 'hours' ).length;
			
			if ( fullHours < hoursArrLength ) {
				
				return i18n( 'hours' )[ fullHours - 1 ];
				
			} else {
				
				return i18n( 'hours' )[ hoursArrLength - 1 ].replace( '$1', fullHours );
				
			}
			
		} else if ( days < 7 ) {
			
			const fullDays = Math.floor( days );
			
			const daysArrLength = i18n( 'days' ).length;
			
			if ( fullDays < daysArrLength ) {
				
				return i18n( 'days' )[ fullDays - 1 ];
				
			} else {
				
				return i18n( 'days' )[ daysArrLength - 1 ].replace( '$1', fullDays );
				
			}
			
		} else if ( days < 30 ) {
			
			const fullWeeks = Math.floor( days / 7 );
			
			const weeksArrLength = i18n( 'weeks' ).length;
			
			if ( fullWeeks < weeksArrLength ) {
				
				return i18n( 'weeks' )[ fullWeeks - 1 ];
				
			} else {
				
				return i18n( 'weeks' )[ weeksArrLength - 1 ].replace( '$1', fullWeeks );
				
			}
			
		} else if ( days < 365 ) {
			
			let fullMonths = Math.floor( days / 30 );
			
			if ( fullMonths === 12 ) {
				fullMonths = 11;
			}
			
			const monthsArrLength = i18n( 'months' ).length;
			
			if ( fullMonths < monthsArrLength ) {
				
				return i18n( 'months' )[ fullMonths - 1 ];
				
			} else {
				
				return i18n( 'months' )[ monthsArrLength - 1 ].replace( '$1', fullMonths );
				
			}
			
		} else {
			
			const fullYears = Math.floor( days / 365 );
			
			const yearsArrLength = i18n( 'years' ).length;
			
			if ( fullYears < yearsArrLength ) {
				
				return i18n( 'years' )[ fullYears - 1 ];
				
			} else {
				
				return i18n( 'years' )[ yearsArrLength - 1 ].replace( '$1', fullYears );
				
			}
			
		}
		
	}
	
} )();