MediaWiki:Gadget-infoboxExport.js

/** * Quick FAMEData Infobox Export. * See Help:Infobox export gadget. * * Gadget for export information from infoboxes to FAMEData. * The export window is shown by double clicking. */ ( function ( mw, $ ) {	var wikidataInfoboxExport = function {		var _this = this;

/**		 * Returns an array of elements with duplicate values deleted */		this.unique = function ( array ) { return $.grep( array, function ( el, index ) {				return index === $.inArray( el, array );			} ); };

this.months = [ 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ];		this.monthsGen = months;

// Site and user language setup var contentLanguage = mw.config.get( 'wgContentLanguage' ); var userLanguage = mw.user.options.get( 'language' ) || contentLanguage; var languages = [ 'en' ]; languages.unshift( contentLanguage ); languages.unshift( userLanguage ); languages = this.unique( languages );

// Main config this.config = Object.assign( {			version: '2.2.15',			project: mw.config.get( 'wgDBname' ),			language: userLanguage,			userLanguage: userLanguage,			contentLanguage: contentLanguage,			languages: languages,			storageKey: 'infoboxExportConfig',			references: {},			units: {},			fixedValues: [],			misLang: {				ain: 'Q20968488',				atv: 'Q2640863',				bua: 'Q33120',				chm: 'Q973685',				enf: 'Q29942',				evn: 'Q30004',				izh: 'Q33559',				jdt: 'Q56495',				jmy: 'Q53493410',				orv: 'Q35228',				phn: 'Q36734', // phn-latn or phn-phnx				sga: 'Q35308',				yrk: 'Q36452'			},			centuries: [ 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII',				'VIII', 'IX', 'X', 'XI', 'XII', 'XIII', 'XIV', 'XV',				'XVI', 'XVII', 'XVIII', 'XIX', 'XX', 'XXI', 'XXII' ],		}, window.wieConfig || {} );

this.i18n = {};

this.api = null; this.wdApi = null; this.commonsApi = null;

this.baseRevId; this.propertyIds = [ 'P2076', 'P2077' ]; // Temperature and pressure for qualifiers this.typesMapping = { 'commonsMedia': 'string', 'external-id': 'string', 'url': 'string', 'wikibase-item': 'wikibase-entityid' };		this.alreadyExistingItems = {}; this.windowManager;

/**		 * Returns localized config value */		this.getConfig = function ( key ) { if ( key in this.config ) { return this.config[ key ]; }

console.warn( 'Config missed for "' + key + '"' ); return undefined; };

/**		 * Returns translated value */		this.getI18n = function ( key ) { if ( key in this.i18n ) { return this.i18n[ key ]; }

console.warn( 'I18n missed for "' + key + '"' ); return key; };

/**		 * Compares the values of the infobox and FAMEData */		this.canExportValue = function ( $field, claims, callbackIfCan ) { if ( !claims || !( claims.length ) ) { // Can't export only if image is local and large var $localImg = $field.find( '.image img[src*="/wikipedia/' + _this.getConfig( 'contentLanguage' ) + '/"]' ); if ( !$localImg.length || $localImg.width < 80 ) { callbackIfCan; }				return; }

switch ( claims[ 0 ].mainsnak.datatype ) { case 'quantity': for ( var i = 0; i < claims.length; i++ ) { var parsedTime = _this.createTimeSnak( ( $field.text.match( /\(([^)]*\d\d\d\d)[,)\s]/ ) || [] )[ 1 ] );						if ( parsedTime && ( claims[ i ].qualifiers || {} ).P585 ) {							var claimPrecision = claims[ i ].qualifiers.P585[ 0 ].datavalue.value.precision;							if ( parsedTime.precision < claimPrecision ) {								claims[ i ].qualifiers.P585[ 0 ].datavalue.value.precision = parsedTime.precision;							} else if ( parsedTime.precision > claimPrecision ) { // FIXME: Specify the date in FAMEData later								parsedTime.precision = claimPrecision;							}							var p585 = parsedTime ? _this.formatDataValue( { type: 'time', value: parsedTime } )[ 0 ].innerText : '';

if ( _this.formatDataValue( claims[ i ].qualifiers.P585[ 0 ].datavalue )[ 0 ].innerText !== p585 ) { claims[ i ].qualifiers.P585[ 0 ].datavalue.value.precision = claimPrecision; continue; }						}						return; }					callbackIfCan( true ); break;

case 'wikibase-item': value = _this.parseItems( $field, $field, function ( values ) {						var duplicates = [];						for ( var i = 0; i < values.length; i++ ) {							for ( var j = 0; j < claims.length; j++ ) {								if ( values[ i ].wd.value.id === claims[ j ].mainsnak.datavalue.value.id ) {									duplicates.push( values[ i ].wd.value.id );								}							}						}						if ( duplicates.length < values.length ) {							if ( duplicates.length > 0 ) {								var propertyId = claims[ 0 ].mainsnak.property;								_this.alreadyExistingItems[ propertyId ] = duplicates;								if ( propertyId === 'P166' && values.length === claims.length )									return;							}							if ( claims.length > 0 ) {								if ( claims[ 0 ].mainsnak.property === 'P19' || claims[ 0 ].mainsnak.property === 'P20' )									return;							}							callbackIfCan( true );						}					} ); }			// By default we can't export if there are claims already };

/**		 * Claim's GUID generation */		this.claimGuid = function ( entityId ) { var getRandomHex = function ( min, max ) { return ( Math.floor( Math.random * ( max - min + 1 ) ) + min ).toString( 16 ); };

var template = 'xx-x-x-x-xxx'; var guid = ''; for ( var i = 0; i < template.length; i++ ) { if ( template.charAt( i ) === '-' ) { guid += '-'; continue; }

var hex; if ( i === 3 ) { hex = getRandomHex( 16384, 20479 ); } else if ( i === 4 ) { hex = getRandomHex( 32768, 49151 ); } else { hex = getRandomHex( 0, 65535 ); }

while ( hex.length < 4 ) { hex = '0' + hex; }

guid += hex; }

return entityId + '$' + guid; };

this.guessDateAndPrecision = function ( timestamp ) { var dateParts = timestamp.match( _this.getConfig( 'reCentury' ) ); var isoDate; if ( dateParts ) { isoDate = new Date( 0 ); isoDate.setFullYear( _this.getConfig( 'centuries' ).indexOf( dateParts[ 1 ].toUpperCase ) * 100 + 1 ); return { isoDate: isoDate, precision: 7, };			}

dateParts = timestamp.match( _this.getConfig( 'reMonthYear' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 2 ], _this.months.indexOf( dateParts[ 1 ] ) ) ); return { isoDate: isoDate, precision: 10, };			}

dateParts = timestamp.match( _this.getConfig( 'reTextDate' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 3 ], _this.monthsGen.indexOf( dateParts[ 2 ] ), dateParts[ 1 ] ) ); return { isoDate: isoDate, precision: 11, };			}

dateParts = timestamp.match( _this.getConfig( 'reDotDate' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 3 ] < 100 ? 1900 + parseInt( dateParts[ 3 ] ) : dateParts[ 3 ], dateParts[ 2 ] - 1, dateParts[ 1 ] ) ); return { isoDate: isoDate, precision: 11, };			}

dateParts = timestamp.match( _this.getConfig( 'reIsoDate' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 1 ] < 100 ? 1900 + parseInt( dateParts[ 1 ] ) : dateParts[ 1 ], dateParts[ 2 ] - 1, dateParts[ 3 ] ) ); return { isoDate: isoDate, precision: 11, };			}

dateParts = timestamp.match( _this.getConfig( 'reDecade' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 1 ], 0 ) ); return { isoDate: isoDate, precision: 8, };			}

dateParts = timestamp.match( _this.getConfig( 'reYear' ) ); if ( dateParts ) { isoDate = new Date( Date.UTC( dateParts[ 1 ], 0 ) ); return { isoDate: isoDate, precision: 9, };			}

if ( timestamp.match( _this.getConfig( 'rePresent' ) ) ) { return 'novalue'; }

if ( timestamp.match( _this.getConfig( 'reUnknown' ) ) ) { return 'somevalue'; }		};

/**		 * Format dates as datavalue for FAMEData */		this.createTimeSnak = function ( timestamp, forceJulian ) { if ( !timestamp ) { return; }			var result = { timezone: 0, before: 0, after: 0 }; var isoDate; var dateParts;

if ( timestamp.match( /\s\([^\)]*\)\s/ ) ) {				forceJulian = true;			}			timestamp = timestamp.replace( /\([^\)]*\)/, '' ).trim;

var isBce = false; var bceMatch = timestamp.match( _this.getConfig( 'reBce' ) ); if ( bceMatch ) { isBce = true; timestamp = timestamp.replace( bceMatch[ 0 ], '' ).trim; } else { var ceMatch = timestamp.match( _this.getConfig( 'reCe' ) ); if ( ceMatch ) { timestamp = timestamp.replace( ceMatch[ 0 ], '' ).trim; }			}

var guess = _this.guessDateAndPrecision( timestamp ); if ( typeof guess !== 'object' ) { return guess; }

try { guess.isoDate.setUTCHours( 0 ); guess.isoDate.setUTCMinutes( 0 ); guess.isoDate.setUTCSeconds( 0 );

result.time = ( isBce ? '-' : '+' ) + guess.isoDate.toISOString.replace( /\.000Z/, 'Z' ); result.precision = guess.precision; } catch ( e ) { return; }			if ( result.precision < 11 ) { result.time = result.time.replace( /-\d\dT/, '-00T' ); }			if ( result.precision < 10 ) { result.time = result.time.replace( /-\d\d-/, '-00-' ); }

result.calendarmodel = 'http://famedata.org/entity/Q' + ( forceJulian || guess.isoDate < new Date( Date.UTC( 1582, 9, 15 ) ) ? '1985786' : '1985727' ); return result; };

/**		 * Error display */		this.errorDialog = function ( title, message ) { var errorDialog = new OO.ui.MessageDialog; _this.windowManager.addWindows( [ errorDialog ] ); _this.windowManager.openWindow( errorDialog, {				title: title,				message: message			} ); };

/**		 * Extract reference URL */		this.getReference = function ( $field ) { var references = []; var $notes = $field.find( 'sup.reference a' ); for ( var i = 0; i < $notes.length; i++ ) { var $externalLinks = $( decodeURIComponent( $notes[ i ].hash ).replace( /[!"$%&'*+,.\/:;<=>?@[\\\]^`{|}~]/g, '\\$&' ) + ' a[rel="nofollow"]' );				for ( var j = 0; j < $externalLinks.length; j++ ) {					var $externalLink = $( $externalLinks.get( j ) );					if ( !$externalLink.attr( 'href' ).match( /(wikipedia.org|webcitation.org|archive.is)/ ) ) {						var source = {							snaks: {								P854: [ {									property: 'P854',									datatype: 'url',									snaktype: 'value',									datavalue: {										type: 'string',										value: $externalLink.attr( 'href' ).replace( /^\/\//, 'https://' )									}								} ]							}						};

// P813 if ( _this.getConfig( 'markChecked' ) !== '' ) { var $accessed = $externalLinks.parent.find( 'small:contains("' + _this.getConfig( 'markChecked' ) + '")' ); if ( $accessed.length ) { var accessDate = _this.createTimeSnak( $accessed.first.text ); if ( accessDate ) { source.snaks.P813 = [ { property: 'P813', datatype: 'time', snaktype: 'value', datavalue: { type: 'time', value: accessDate }									} ];								}							}						}

// P1065 + P2960 if ( _this.getConfig( 'markArchived' ) !== '' ) { var $archiveLinks = $externalLinks.filter( 'a:contains("' + _this.getConfig( 'markArchived' ) + '")' ); if ( $archiveLinks.length ) { var $archiveLink = $archiveLinks.first; source.snaks.P1065 = [ { property: 'P1065', datatype: 'url', snaktype: 'value', datavalue: { type: 'string', value: $archiveLink.attr( 'href' ).replace( /^\/\//, 'https://' ) }								} ];

var archiveDate = _this.createTimeSnak( $archiveLink.parent.text.replace( _this.getConfig( 'markArchived' ), '' ).trim ); if ( archiveDate ) { source.snaks.P2960 = [ { property: 'P2960', datatype: 'time', snaktype: 'value', datavalue: { type: 'time', value: archiveDate }									} ];								}							}						}

references.push( source ); break; }				}			}			references.push( { snaks: _this.getConfig( 'references' ) } ); return references; };

/**		 * Format sources for display */		this.formatDomains = function ( references ) { var $result = $( ' ' ); for ( var i = 0; i < references.length; i++ ) { var p854 = references[ i ].snaks.P854; if ( p854 ) { var domain = p854[ 0 ].datavalue.value.replace( 'http://',  ).replace( 'https://',  ).replace( 'www.', '' ); if ( domain.indexOf( '/' ) > 0 ) { domain = domain.substr( 0, domain.indexOf( '/' ) ); }					$result.append( $( '' ).attr( 'href', p854[ 0 ].datavalue.value ).text( '[' + domain + ']' ) ); }			}			return $result; };

/**		 * Formatting FAMEData values for display to the user */		this.formatDataValue = function ( datavalue ) { var $label = $( ' ' ); switch ( datavalue.type ) { case 'time': var bceMark = ( datavalue.value.time.charAt( 0 ) === '-' ? _this.getI18n( 'bcePostfix' ) : '' );

if ( datavalue.value.precision === 7 ) { $label.text( _this.getConfig( 'centuries' )[ Math.floor( ( datavalue.value.time.substr( 1, 4 ) - 1 ) / 100 ) ] + _this.getI18n( 'agePostfix' ) + bceMark ); break; }					var options = { timeZone: 'UTC', };					if ( datavalue.value.precision > 7 ) { options.year = 'numeric'; }					if ( datavalue.value.precision > 9 ) { options.month = 'long'; }					if ( datavalue.value.precision > 10 ) { options.day = 'numeric'; }					var parsedDate = new Date( Date.parse( datavalue.value.time.substring( 1 ).replace( /-00/g, '-01' ) ) ); $label.text( parsedDate.toLocaleString( _this.getConfig( 'userLanguage' ), options ) + ( datavalue.value.precision === 8 ? _this.getI18n( 'decadePostfix' ) : '' ) + bceMark ); break;

case 'quantity': $label.append( $( ' ' ).text( datavalue.value.amount ) ); if ( datavalue.value.bound ) { $label.append( $( ' ' ).text( ' ± ' + datavalue.value.bound ) ); }					if ( datavalue.value.unit !== '1' ) { var unitId = datavalue.value.unit.substr( datavalue.value.unit.indexOf( 'Q' ) ); var name = ( ( _this.getConfig( 'units' )[ unitId ] || {} ).label || {} ).value || unitId; var description = ( ( _this.getConfig( 'units' )[ unitId ] || {} ).description || {} ).value || _this.getI18n( 'noDescription' ); $label.append( ' ' ).append( $( ' ' ).attr( 'title', description ).text( name ) ); }					break;

case 'wikibase-entityid': $label.append( $( ' ' ).text( datavalue.value.label ? datavalue.value.label : datavalue.value.id ) ) .append( datavalue.value.description ? ' — ' + datavalue.value.description : '' ); break; }

for ( var propertyId in datavalue.qualifiers ) { if ( !datavalue.qualifiers.hasOwnProperty( propertyId ) ) { continue; }				if ( propertyId === 'P1480' && datavalue.qualifiers[ propertyId ][ 0 ].datavalue.value.id === 'Q5727902' ) { $label.prepend( $( ' ' ).attr( 'title', _this.getI18n( 'circaTitle' ) ).text( _this.getI18n( 'circaPrefix' ) ), ' ' ); } else { var formatted = _this.formatDataValue( datavalue.qualifiers[ propertyId ][ 0 ].datavalue ); if ( formatted && $( ' ' ).append( formatted ).text ) { $label.append( $( ' ' ).text( ' (' ).append( formatted ).append( ')' ) ); }				}			}

return $label; };

this.getWikidataIds = function ( titles, callback ) { var languages = titles.map( function ( item ) {				return item.language;			} ); languages = $.merge( languages, _this.getConfig( 'languages' ) ); languages = _this.unique( languages );

var sites = titles.map( function ( item ) {				return item.project;			} );

_this.wdApi.get( {				action: 'wbgetentities',				sites: sites,				languages: languages,				props: [ 'labels', 'descriptions', 'claims' ],				titles: titles.map( function ( item ) { return item.label; } )			} ).done( function ( data ) {				if ( data.success ) {					var valuesObj = {};					var value;

for ( var entityId in data.entities ) { if ( !data.entities.hasOwnProperty( entityId ) || !entityId.match( /^Q/ ) ) { continue; }

var entity = data.entities[ entityId ]; var label = entity.labels[ _this.getConfig( 'userLanguage' ) ] || entity.labels.en || entity.labels[ Object.keys( entity.labels )[ 0 ] ] || ''; var description = entity.descriptions[ _this.getConfig( 'userLanguage' ) ] || entity.descriptions.en || entity.descriptions[ Object.keys( entity.descriptions )[ 0 ] ] || '';

if ( ( ( ( ( ( ( ( entity || {} ).claims || {} ).P31 || [] )[ 0 ] || {} ).mainsnak || {} ).datavalue || {} ).value || {} ).id === 'Q4167410' ) { continue; // skip disambigs }

var subclassFound = false; var subclassEntity = null; var subclassPropertyIds = [ 'P17', 'P31', 'P131', 'P279', 'P361' ]; for ( var candidateId in data.entities ) { if ( !data.entities.hasOwnProperty( candidateId ) || !candidateId.match( /^Q/ ) || entityId === candidateId ) { continue; }

subclassFound = subclassPropertyIds.find( function ( propertyId ) {								var values = ( ( ( data.entities[ candidateId ] || {} ).claims || {} )[ propertyId ] || [] );								return values.find( function ( statement ) { var result = ( ( ( statement.mainsnak || {} ).datavalue || {} ).value || {} ).id === entityId; if ( result ) { subclassEntity = data.entities[ candidateId ]; }									return result; } );							} );

if ( subclassFound ) { break; }						}

if ( subclassFound ) { if ( subclassEntity ) { var subclassLabel = subclassEntity.labels[ _this.getConfig( 'userLanguage' ) ] || subclassEntity.labels.en || subclassEntity.labels[ Object.keys( subclassEntity.labels )[ 0 ] ]; var text = _this.getI18n( 'morePreciseValue' ) .replace( '$1', label.value ) .replace( '$2', subclassLabel.value ); mw.notify( text, {									type: 'warn',									tag: 'wikidataInfoboxExport-warn-precise'								} ); }							continue; // skip values for which there are more accurate values }

value = { wd: { type: 'wikibase-entityid', value: { id: entityId, label: label ? label.value : label, description: description ? description.value : description }							}						};						if ( label ) { var results = titles.filter( function ( item ) {								return item.label.toLowerCase === label.value.toLowerCase;							} ); if ( results.length === 1 ) { value.wd.qualifiers = results[ 0 ].qualifiers; }						}						value.label = _this.formatDataValue( value.wd ); delete value.wd.value.label; delete value.wd.value.description; valuesObj[ entityId ] = value; }

callback( valuesObj ); }			} );		};

this.parseItems = function ( $content, $wrapper, callback ) { var processWbGetItems = function ( valuesObj ) { var values = $.map( valuesObj, function ( value, index ) {					return [ value ];				} ); if ( values.length === 1 ) { value = values.pop; _this.addQualifiers( $wrapper, value.wd, value.label, function ( value ) {						callback( [ value ] );					} ); } else if ( callback ) { callback( values ); }			};

var titles = [];

for ( var k = 0; k < _this.getConfig( 'fixedValues' ).length; k++ ) { var fixedValue = _this.getConfig( 'fixedValues' )[ k ]; var regexp = new RegExp( fixedValue.search ); if ( $content.attr( 'data-wikidata-property-id' ) === fixedValue.property &&					$content.text.match( regexp )				) { var valuesObj = {}; var value = { wd: { type: 'wikibase-entityid', value: { id: fixedValue.item, label: fixedValue.label, description: '' }						}					};					value.label = _this.formatDataValue( value.wd ); delete value.wd.value.label; delete value.wd.value.description; valuesObj[ fixedValue.item ] = value; processWbGetItems( valuesObj ); return; }			}

var $links = $content.find( 'a[title][class!=image][class!=new]' ); var redirects = [];

if ( $links.length ) { for ( var j = 0; j < $links.length; j++ ) { var $link = $( $links[ j ] ); if ( $link.parents( '[data-wikidata-qualifier-id]' ).length ) { continue; }					var extractedUrl = decodeURIComponent( $link.attr( 'href' ) ).replace( /^.*\/wiki\//, '' ); if ( extractedUrl ) { extractedUrl = extractedUrl.replace( /_/g, ' ' ).trim; var value = { label: extractedUrl.charAt( 0 ).toUpperCase + extractedUrl.substr( 1, extractedUrl.length - 1 ), language: _this.getConfig( 'contentLanguage' ), project: _this.getConfig( 'project' ), qualifiers: {} };						var match = $links[ j ].innerHTML.match( _this.getConfig( 'reSinceYear' ) ); if ( !match ) { match = $links[ j ].innerHTML.match( _this.getConfig( 'reUntilYear' ) ); }						var extractedYear = match ? _this.createTimeSnak( match[ 1 ] ) : _this.createTimeSnak( ( $links[ j ].nextSibling || {} ).textContent ); if ( extractedYear ) { value.qualifiers.P585 = [ { property: 'P585', datatype: 'time', snaktype: 'value', datavalue: { type: 'time', value: extractedYear }							} ];						}						if ( $link.hasClass( 'extiw' ) ) { var m = $links[ j ].getAttribute( 'href' ).match( /^https:\/\/([a-z\-]+)\.(wik[^\.]+)\./ ); if ( m && m[ 2 ] !== 'wikimedia' ) { value.language = m[ 1 ]; value.project = m[ 1 ] + m[ 2 ].replace( 'wikipedia', 'wiki' ); }						}						if ( $link.hasClass( 'mw-redirect' ) ) { redirects.push( extractedUrl ); }						titles.push( value ); if ( $( $links[ j ] ).find( 'img' ) ) { redirects.push( extractedUrl ); }					}				}			} else if ( $content.text.trim ) { // If no links found try to search for articles by text value var parts = $content.text.split( /[\n,;]+/ ); for ( var i in parts ) { var year = ''; var articleTitle = parts[ i ].replace( /\([^)]*\)/, function ( match ) { year = match.replace( /\(\)/, '' ); return ''; } ).trim;					if ( articleTitle ) {						var value = {							label: articleTitle.charAt( 0 ).toUpperCase + articleTitle.substr( 1, articleTitle.length - 1 ),							language: _this.getConfig( 'language' ),							project: _this.getConfig( 'project' ),							qualifiers: {}						};						if ( _this.createTimeSnak( year ) ) {							value.qualifiers.P585 = [ {								property: 'P585',								datatype: 'time',								snaktype: 'value',								datavalue: {									type: 'time',									value: _this.createTimeSnak( year )								}							} ];						}						titles.push( value );					}				}				titles = _this.unique( titles );			}			if ( redirects.length ) {				_this.api.get( { action: 'query', redirects: 1, titles: redirects } ).done( function ( data ) { if ( data.query && data.query.redirects ) { for ( var i = 0; i < data.query.redirects.length; i++ ) { for ( var j = 0; j < titles.length; j++ ) { var lcTitle = titles[ j ].label.substr( 0, 1 ).toLowerCase + titles[ j ].label.substr( 1 ); var lcRedirect = data.query.redirects[ i ].from.substr( 0, 1 ).toLowerCase + data.query.redirects[ i ].from.substr( 1 ); if ( lcTitle === lcRedirect ) { titles.splice( j + 1, 0, {										label: data.query.redirects[ i ].to,										language: _this.getConfig( 'contentLanguage' ),										project: _this.getConfig( 'project' ),										year: titles[ j ].year									} ); j++; }							}						}					}

_this.getWikidataIds( titles, processWbGetItems ); } );			} else {				_this.getWikidataIds( titles, processWbGetItems );			}		};

/**		 * Parsing the number and (optionally) the accuracy */		this.parseQuantity = function ( text, forceInteger ) { var out = { value: {}, };			text = text.replace( /,/g, '.' ).replace( /[−–—]/g, '-' ).trim;

// Sourcing circumstances (P1480) = circa (Q5727902) var circaMatch = text.match( _this.getConfig( 'reCirca' ) ); if ( circaMatch ) { out.qualifiers = { P1480: [ { property: 'P1480', snaktype: 'value', datavalue: { type: 'wikibase-entityid', value: { id: 'Q5727902' } }					} ],				};				text = text.replace( circaMatch[ 0 ], '' ); }

var magnitude = 0; if ( text.match( _this.getConfig( 're10_3' ) ) ) { magnitude += 3; } else if ( text.match( _this.getConfig( 're10_6' ) ) ) { magnitude += 6; } else if ( text.match( _this.getConfig( 're10_9' ) ) ) { magnitude += 9; } else if ( text.match( _this.getConfig( 're10_12' ) ) ) { magnitude += 12; } else { var match = text.match( /[\*|·]10(-?\d+)/ ); if ( match ) { text = text.replace( /[\*|·]10(-?\d+)/, '' ); magnitude += parseInt( match[ 1 ] ); }			}			var decimals = text.split( '±' ); if ( magnitude === 0 && forceInteger ) { decimals[ 0 ] = decimals[ 0 ].replace( /\./g, '' ).trim; }

var amount; var bound; var interval = decimals[ 0 ].split( '-' ); if ( magnitude === 0 &&				decimals.length === 1 &&				interval.length === 2 &&				interval[ 0 ].length !== 0 &&				interval[ 1 ].length !== 0			) { out.value.lowerBound = interval[ 0 ].replace( /[^0-9.+-]/g, '' ); out.value.upperBound = interval[ 1 ].replace( /[^0-9.+-]/g, '' ); parts = out.value.lowerBound.match( /(\d+)\.(\d+)/ ); fractional = parts ? parts[ 2 ].length : 0; out.value.amount = ( ( parseFloat( out.value.upperBound ) + parseFloat( out.value.lowerBound ) ) / 2 ) .toFixed( fractional + 1 ); out.value.bound = ( ( parseFloat( out.value.upperBound ) - parseFloat( out.value.lowerBound ) ) / 2 ) .toFixed( fractional + 1 ); return out; } else { amount = parseFloat( decimals[ 0 ].replace( /[^0-9.+-]/g, '' ) ); }

if ( isNaN( amount ) ) { return; }

var parts = amount.toString.match( /(\d+)\.(\d+)/ ); var integral = parts ? parts[ 1 ].length : amount.toString.length; var fractional = parts ? parts[ 2 ].length : 0; if ( magnitude >= 0 ) { if ( magnitude <= fractional ) { out.value.amount = ( ( '1e' + magnitude ) * amount ).toFixed( fractional - magnitude ); } else { out.value.amount = ( ( '1e' + fractional ) * amount ).toFixed( 0 ).replace( /$/, new Array( magnitude - fractional + 1 ).join( '0' ) ); }			} else { if ( magnitude >= -integral ) { out.value.amount = ( ( '1e' + magnitude ) * amount ).toFixed( fractional - magnitude ); } else { out.value.amount = ( ( '1e-' + integral ) * amount ).toFixed( integral + fractional ).replace( /0\./, '0.' + new Array( -magnitude - integral + 1 ).join( '0' ) ); }			}

if ( decimals.length > 1 ) { bound = parseFloat( decimals[ 1 ].replace( /[^0-9.+-]/g, '' ) ); }

if ( !isNaN( bound ) ) { if ( decimals.length > 1 && decimals[ 1 ].indexOf( '%' ) > 0 ) { bound = amount * bound / 100; } else { parts = bound.toString.match( /(\d+)\.(\d+)/ ); integral = parts ? parts[ 1 ].length : amount.toString.length; fractional = parts ? parts[ 2 ].length : 0; }				if ( magnitude >= 0 ) { if ( magnitude <= fractional ) { out.value.lowerBound = ( ( '1e' + magnitude ) * ( amount - bound ) ).toFixed( fractional - magnitude ); out.value.upperBound = ( ( '1e' + magnitude ) * ( amount + bound ) ).toFixed( fractional - magnitude ); out.value.bound = ( ( '1e' + magnitude ) * bound ).toFixed( fractional - magnitude ); // need to show it to user } else { out.value.lowerBound = ( ( '1e' + fractional ) * ( amount - bound ) ).toFixed( 0 ).replace( /$/, new Array( magnitude - fractional + 1 ).join( '0' ) ); out.value.upperBound = ( ( '1e' + fractional ) * ( amount + bound ) ).toFixed( 0 ).replace( /$/, new Array( magnitude - fractional + 1 ).join( '0' ) ); out.value.bound = ( ( '1e' + fractional ) * bound ).toFixed( 0 ).replace( /$/, new Array( magnitude - fractional + 1 ).join( '0' ) ); }				} else { if ( magnitude >= -integral ) { out.value.lowerBound = ( ( '1e' + magnitude ) * ( amount - bound ) ).toFixed( fractional - magnitude ); out.value.upperBound = ( ( '1e' + magnitude ) * ( amount + bound ) ).toFixed( fractional - magnitude ); out.value.bound = ( ( '1e' + magnitude ) * bound ).toFixed( fractional - magnitude ); } else { out.value.lowerBound = ( ( '1e-' + integral ) * ( amount - bound ) ).toFixed( integral + fractional ).replace( /0\./, '0.' + new Array( -magnitude - integral + 1 ).join( '0' ) ); out.value.upperBound = ( ( '1e-' + integral ) * ( amount + bound ) ).toFixed( integral + fractional ).replace( /0\./, '0.' + new Array( -magnitude - integral + 1 ).join( '0' ) ); out.value.bound = ( ( '1e-' + integral ) * bound ).toFixed( integral + fractional ).replace( /0\./, '0.' + new Array( -magnitude - integral + 1 ).join( '0' ) ); }				}			}			return out; };

/**		 * Recognition of units of measurement in the infobox parameter and its label */		this.recognizeUnits = function ( text, units, label ) { if ( Array.isArray( units ) && units.length === 0 ) { return [ '1' ]; }			var result = []; for ( var idx in units ) { if ( !units.hasOwnProperty( idx ) ) { continue; }				var item = parseInt( idx ) >= 0 ? units[ idx ] : idx; var search = _this.getConfig( 'units' )[ item ].search; for ( var j = 0; j < search.length; j++ ) { var expr = search[ j ]; if ( search[ j ].charAt( 0 ) !== '^' ) { expr = '[\\d\\s\\.]' + expr; if ( search[ j ].length < 5 ) { expr = expr + '\\.?$'; }					}					if ( text.match( new RegExp( expr ) ) ) { result.push( item ); break; } else if ( search[ j ].charAt( 0 ) !== '^' && label && label.match( new RegExp( '\\s' + search[ j ] + ':?$' ) ) ) { result.push( item ); break; }				}			}			return result; };

/**		 * Create all statements in FAMEData and mark properties exported */		this.createClaims = function ( propertyId, values, refUrl, revIds ) { var value = values.shift; revIds = revIds || []; if ( !value ) { // All statements are added $( '.no-wikidata[data-wikidata-property-id=' + propertyId + ']' ) .removeClass( 'no-wikidata' ) .off( 'dblclick', _this.clickEvent ); return; } else { value = JSON.parse( value ); }			if ( _this.getConfig( 'properties' )[ propertyId ] === undefined ) { mw.notify( _this.getI18n( 'noPropertyData' ).replace( '$1', propertyId ), {					type: 'error',					tag: 'wikidataInfoboxExport-property-error'				} ); return; }			var datatype = _this.getConfig( 'properties' )[ propertyId ].datatype; var mainsnak = value.value.toString.match( /^(novalue|somevalue)$/ ) ? {				snaktype: value.value, property: propertyId } : {				snaktype: 'value', property: propertyId, datavalue: { type: _this.typesMapping[ datatype ] ? _this.typesMapping[ datatype ] : datatype, value: value.value }			};			var claim = { type: 'statement', mainsnak: mainsnak, id: _this.claimGuid( mw.config.get( 'wgWikibaseItemId' ) ), references: refUrl, rank: 'normal' };			if ( value.qualifiers ) { claim.qualifiers = value.qualifiers; }

_this.wdApi.postWithToken( 'csrf', {				action: 'wbsetclaim',				claim: JSON.stringify( claim ),				baserevid: _this.baseRevId,				tags: 'InfoboxExport gadget'			} ).done( function ( claimData ) {				if ( claimData.success ) {					var valuesLeftStr = values.length ? _this.getI18n( 'valuesLeft' ).replace( '$1', values.length ) : '';					mw.notify( _this.getI18n( 'valueSaved' ).replace( '$1', propertyId ) + valuesLeftStr, { tag: 'wikidataInfoboxExport-success' } );

_this.baseRevId = claimData.pageinfo.lastrevid; revIds.push( _this.baseRevId ); _this.createClaims( propertyId, values, refUrl, revIds ); } else { _this.errorDialog( _this.getI18n( 'valueFailed' ), JSON.stringify( claimData ) ); }			} ).fail( function { mw.notify( _this.getI18n( 'valueFailed' ), {					type: 'error',					tag: 'wikidataInfoboxExport-error'				} ); } );		};

/**		 * Wrapper for property preloading that excludes already loaded properties */		this.loadProperties = function ( propertyIds ) { if ( !propertyIds || !propertyIds.length ) { return; }

var realPropertyIds = []; for ( var i in propertyIds ) { var propertyId = propertyIds[ i ]; if ( propertyId && _this.getConfig( 'properties' )[ propertyId ] === undefined ) { realPropertyIds.push( propertyId ); }			}

if ( realPropertyIds.length ) { _this.realLoadProperties( realPropertyIds ); }		};

/**		 * Preload information on all properties */		this.realLoadProperties = function ( propertyIds ) { if ( !propertyIds || !propertyIds.length ) { return; }

var units = []; _this.wdApi.get( {				action: 'wbgetentities',				languages: _this.getConfig( 'languages' ),				props: [ 'labels', 'datatype', 'claims' ],				ids: propertyIds			} ).done( function ( data ) {				if ( !data.success ) {					return;				}

for ( var propertyId in data.entities ) { if ( !data.entities.hasOwnProperty( propertyId ) ) { continue; }					var entity = data.entities[ propertyId ]; var label = entity.labels[ _this.getConfig( 'language' ) ] ? entity.labels[ _this.getConfig( 'language' ) ].value : entity.labels.en.value; _this.config.properties[ propertyId ] = { datatype: entity.datatype, label: label.charAt( 0 ).toUpperCase + label.slice( 1 ), constraints: { qualifier: [] }, units: [] };					if ( propertyId === 'P1128' || propertyId === 'P2196' ) { _this.config.properties[ propertyId ].constraints.integer = 1; }					if ( entity.claims ) { // Property restrictions if ( entity.claims.P2302 ) { for ( var i in entity.claims.P2302 ) { var type = ( ( ( ( entity.claims.P2302[ i ] || {} ).mainsnak || {} ).datavalue || {} ).value || {} ).id; switch ( type ) { case 'Q19474404': case 'Q21502410': _this.config.properties[ propertyId ].constraints.unique = 1; break; case 'Q21510856': // Required var qualifiers = ( ( ( entity.claims.P2302[ i ] || {} ).qualifiers || {} ).P2306 || [] ); for ( var idx = 0; idx < qualifiers.length; idx++ ) { var qualifierId = ( ( ( qualifiers[ idx ] || {} ).datavalue || {} ).value || {} ).id; if ( qualifierId ) { _this.getConfig( 'properties' )[ propertyId ].constraints.qualifier.push( qualifierId.toString ); }										}										break; case 'Q21514353': // Units var qualifiers = ( ( ( entity.claims.P2302[ i ] || {} ).qualifiers || {} ).P2305 || [] ); for ( var idx = 0; idx < qualifiers.length; idx++ ) { var unitId = ( ( ( qualifiers[ idx ] || {} ).datavalue || {} ).value || {} ).id; if ( unitId ) { _this.config.properties[ propertyId ].units.push( unitId ); units.push( unitId ); }										}										break; }							}						}					}				}

for ( var idx = 0; idx < _this.unique( units ).length; idx += 50 ) { _this.wdApi.get( {						action: 'wbgetentities',						languages: _this.getConfig( 'languages' ),						props: [ 'labels', 'descriptions', 'aliases', 'claims' ],						ids: _this.unique( units ).slice( idx, idx + 50 )					} ).done( function ( unitData ) {						if ( !unitData.success ) {							return;						}

for ( var unitId in unitData.entities ) { var unit = unitData.entities[ unitId ]; var unitSearch = _this.getConfig( 'units' )[ unitId ] ? _this.getConfig( 'units' )[ unitId ].search : [];							if ( !_this.getConfig( 'units' )[ unitId ] ) { _this.config.units[ unitId ] = {}; }

// Label if ( unit.labels ) { _this.config.units[ unitId ].label = unit.labels[ _this.getConfig( 'userLanguage' ) ] || unit.labels.en || unit.labels[ Object.keys( unit.labels )[ 0 ] ];

if ( unit.labels[ _this.getConfig( 'userLanguage' ) ] ) { unitSearch.push( unit.labels[ _this.getConfig( 'userLanguage' ) ].value.replace( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&' ) ); }							}

// Description if ( unit.descriptions ) { _this.config.units[ unitId ].description = unit.descriptions[ _this.getConfig( 'userLanguage' ) ] || unit.descriptions.en || unit.descriptions[ Object.keys( unit.labels )[ 0 ] ]; }

// Aliases if ( unit.aliases && unit.aliases[ _this.getConfig( 'userLanguage' ) ] ) { for ( var i in unit.aliases[ _this.getConfig( 'userLanguage' ) ] ) { unitSearch.push( unit.aliases[ _this.getConfig( 'userLanguage' ) ][ i ].value.replace( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&' ) ); }							}

// Units (P5061) if ( unit.claims && unit.claims.P5061 ) { for ( var i in unit.claims.P5061 ) { var claim = unit.claims.P5061[ i ]; if ( claim.mainsnak &&										claim.mainsnak.datavalue &&										claim.mainsnak.datavalue.value									) { unitSearch.push( claim.mainsnak.datavalue.value.text.replace( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&' ) ); }								}							}							_this.config.units[ unitId ].search = _this.unique( unitSearch );

_this.saveConfig; }					} );				}			} );		};

this.checkForMisLang = function ( wd ) { var lang = wd.value.language; if ( 'misLang' in _this.config && lang in _this.getConfig( 'misLang' ) ) { wd.value.language = 'mis'; if ( !( 'qualifiers' in wd ) ) { wd.qualifiers = {}; }				wd.qualifiers.P585 = [ { property: 'P407', snaktype: 'value', datavalue: { type: 'wikibase-entityid', value: { id: _this.getConfig( 'misLang' )[ lang ] } }				} ];			}

return wd; };

this.addQualifiers = function ( $field, value, $label, callback ) { var $qualifiers = $field.find( '[data-wikidata-qualifier-id]' ); if ( $qualifiers.length ) { $label = $( ' ' ).append( $label ); }

var addQualifierValue = function ( qualifierId, qualifierValue, qualifierLabel ) { if ( value.qualifiers === undefined ) { value.qualifiers = {}; }				if ( value.qualifiers[ qualifierId ] === undefined ) { value.qualifiers[ qualifierId ] = []; }				var datatype = _this.getConfig( 'properties' )[ qualifierId ].datatype; value.qualifiers[ qualifierId ].push( {					snaktype: 'value',					property: qualifierId,					datavalue: {						type: _this.typesMapping[ datatype ] ? _this.typesMapping[ datatype ] : datatype,						value: qualifierValue					}				} ); $label.append( $( ' ' )					.append( $( '' ) .attr( 'href', '//famedata.org/wiki/Property:' + qualifierId ) .text( _this.getConfig( 'properties' )[ qualifierId ].label ) )					.append( $( ' ' ).text( ': ' ) )					.append( qualifierLabel )				); };

var qualifierTitles = {}; for ( var q = 0; q < $qualifiers.length; q++ ) { var $qualifier = $( $qualifiers[ q ] ); var qualifierId = $qualifier.data( 'wikidata-qualifier-id' ); var qualifierValue = $qualifier.text.replace( '\n', ' ' ).trim; switch ( _this.getConfig( 'properties' )[ qualifierId ].datatype ) { case 'monolingualtext': qualifierValue = { text: $qualifier.text.replace( '\n', ' ' ).trim, language: $qualifier.attr( 'lang' ) || _this.getConfig( 'language' ) };						addQualifierValue( qualifierId, qualifierValue, $qualifier.text ); break;

case 'string': qualifierValue = $qualifier.text.replace( '\n', ' ' ).trim; addQualifierValue( qualifierId, qualifierValue, $qualifier.text ); break;

case 'time': qualifierValue = _this.createTimeSnak( qualifierValue ); addQualifierValue( qualifierId, qualifierValue, $qualifier.text ); break;

case 'wikibase-item': if ( qualifierTitles[ qualifierId ] === undefined ) { qualifierTitles[ qualifierId ] = []; }

var $links = $qualifier.find( 'a[title][class!=image][class!=new]' ); if ( $links.length ) { for ( var l = 0; l < $links.length; l++ ) { var $link = $( $links[ l ] ); var extractedUrl = decodeURIComponent( $link.attr( 'href' ) ).replace( /^.*\/wiki\//, '' ); if ( extractedUrl ) { extractedUrl = extractedUrl.replace( /_/g, ' ' ).trim; var title = { label: extractedUrl.charAt( 0 ).toUpperCase + extractedUrl.substr( 1, extractedUrl.length - 1 ), language: _this.getConfig( 'contentLanguage' ), project: _this.getConfig( 'project' ), qualifiers: {} };									if ( $link.hasClass( 'extiw' ) ) { var m = $link.attr( 'href' ).match( /^https:\/\/([a-z\-]+)\.(wik[^\.]+)\./ ); if ( m && m[ 2 ] !== 'wikimedia' ) { title.language = m[ 1 ]; title.project = m[ 1 ] + m[ 2 ].replace( 'wikipedia', 'wiki' ); }									}									qualifierTitles[ qualifierId ].push( title ); }							}						} else { qualifierTitles[ qualifierId ].push( {								label: qualifierValue.charAt( 0 ).toUpperCase + qualifierValue.substr( 1, qualifierValue.length - 1 ),								language: _this.getConfig( 'contentLanguage' ),								project: _this.getConfig( 'project' ),								qualifiers: {}							} ); }						break; }			}

var processItemTitles = function ( itemTitles, callback ) { if ( Object.keys( itemTitles ).length ) { var qualifierId = Object.keys( itemTitles ).shift; var qualifierItemTitles = itemTitles[ qualifierId ]; delete itemTitles[ qualifierId ]; _this.getWikidataIds( qualifierItemTitles, function ( valuesObj ) {						for ( var entityId in valuesObj ) {							var valueObj = valuesObj[ entityId ];							addQualifierValue( qualifierId, valueObj.wd.value, valueObj.label );						}						processItemTitles( itemTitles, callback );					} ); } else { callback( {						wd: value,						label: $label					} ); }			};			processItemTitles( qualifierTitles, callback ); };

/**		 * Parsing values from parameters before displaying a dialog */		this.prepareDialog = function ( $field, propertyId ) { var values = []; var datatype = _this.getConfig( 'properties' )[ propertyId ].datatype;

var $content = $field.clone; $content.find( 'sup.reference' ).remove; $content.find( '.printonly' ).remove; $content.find( '[style*="display:none"]' ).remove;

var $wrapper = $content; var $row = $field.closest( 'tr' ); if ( $row.length === 1 && $row.find( '[data-wikidata-property-id]' ).length === 1 ) { $wrapper = $row.clone; }

switch ( datatype ) { case 'commonsMedia': var $imgs = $content.find( 'img' ); $imgs.each( function {						var $img = $( this );						var src = $img.attr( 'src' );						if ( !src.match( /upload.wikimedia.org\/wikipedia\/commons/ ) ) {							return;						}						var srcParts = src.split( '/' );						var fileName = srcParts.pop;						if ( fileName.match( /(?:^|-)\d+px-/ ) ) {							fileName = srcParts.pop;						}						fileName = decodeURIComponent( fileName );						fileName = fileName.replace( /_/g, ' ' );						var value = { value: fileName };						var $label = $img.clone							.attr( 'title', fileName )							.css( 'border', '1px dashed #a2a9b1' );

_this.addQualifiers( $wrapper, value, $label, function ( valueObj ) {							values.push( valueObj );						} ); } );					break;

case 'external-id': var externalId = $content.data( 'wikidata-external-id' ) || $content.text; if ( propertyId === 'P345' ) { // IMDb externalId = $content.find( 'a' ).first.attr( 'href' ); externalId = externalId.substr( externalId.lastIndexOf( '/', externalId.length - 2 ) ).replace( /\//g, '' ); } else { externalId = externalId.toString.replace( /^ID\s/,  ).replace( /\s/g,  ); }					var sparql = 'SELECT * WHERE { ?item wdt:' + propertyId + ' "' + externalId + '" }';

$.ajax( {						url: 'https://query.wikidata.org/sparql?format=json&query=' + sparql,						success: function ( data ) {							var $label = $( ' ' )							} ); }					}					break;

case 'monolingualtext': var $items = $content.find( 'span[lang]' ); $items.each( function {						var $item = $( this );						values.push( { wd: _this.checkForMisLang( {								value: {									text: $item.text.trim,									language: $item.attr( 'lang' ).trim								}							} ) } );					} );					if ( !values.length ) { var text = $content.text.trim; if ( text ) { var $items = mw.util.$content.find( 'span[lang]' ); $items.each( function {								$item = $( this );								if ( $item.text.trim.startsWith( text ) ) {									values.push( { wd: _this.checkForMisLang( {											value: {												text: text,												language: $item.attr( 'lang' ).trim											}										} ) } );								}							} );						}					}					var valueLanguages = []; for ( var i in values ) { var valueLanguage = values[ i ].wd.value.language; if ( valueLanguages.indexOf( valueLanguage ) > -1 ) { continue; }						valueLanguages.push( valueLanguage ); values[ i ].label = $( ' ' ) .append( $( ' ' ).css( 'color', '#666' ).text( '(' + valueLanguage + ') ' ) ) .append( $( ' ' ).text( values[ i ].wd.value.text ) ); }					values = values.filter( function ( item ) {						return item.label !== undefined;					} ); break;

case 'quantity': var text = $content.text .replace( /[\u00a0\u25bc\u25b2]/g, ' ' ) .replace( /\s*\(([^)]*\))/g, '' )						.trim;

// Hack for time in formats "hh:mm:ss" and "00m 00s""					var match = text.replace( _this.getConfig( 'reMinSec' ), '$1:$2' )						.match( /^(?:(\d+):)?(\d+):(\d+)$/ );					if ( match ) {						var amount = 0;						for ( var i = 1; i < match.length; i++ ) {							if ( match[ i ] !== undefined ) {								amount = amount * 60 + parseInt( match[ i ], 10 );							}						}

text = amount + _this.getI18n( 'unitSec' ); }

var result = { wd: _this.parseQuantity( text, _this.getConfig( 'properties' )[ propertyId ].constraints.integer ) }; if ( !result.wd || !result.wd.value ) { break; }

_this.addQualifiers( $wrapper, result.wd, _this.formatDataValue( result.wd ), function ( valueObj ) {						result = valueObj;					} );

if ( _this.getConfig( 'properties' )[ propertyId ].constraints.qualifier.indexOf( 'P585' ) !== -1 ) { var yearMatch = $content.text.match( /\(([^)]*[12]\s?\d\d\d)[,)\s]/ );						if ( !yearMatch ) {							yearMatch = $field.closest( 'tr' ).find( 'th' ).first.text.match( /\(([^)]*[12]\s?\d\d\d)[,)\s]/ ); }						if ( yearMatch ) { if ( extractedDate = _this.createTimeSnak( yearMatch[ 1 ].replace( /(\d)\s(\d)/, '$1$2' ) ) ) { result.wd.qualifiers = { P585: [ { snaktype: 'value', property: 'P585', datavalue: { type: 'time', value: extractedDate }									} ]								};							}						}					}

var qualifierMatch = $content.text.match( /\(([^\)]*)/ ); if ( qualifierMatch ) { var qualifierQuantity = _this.parseQuantity( qualifierMatch[ 1 ] ); if ( qualifierQuantity ) { var supportedProperties = [ 'P2076', 'P2077' ]; for ( var j = 0; j < supportedProperties.length; j++ ) { var units = _this.recognizeUnits( qualifierMatch[ 1 ], _this.getConfig( 'properties' )[ supportedProperties[ j ] ].units ); if ( units.length === 1 ) { qualifierQuantity.value.unit = 'http://famedata.org/entity/' + units[ 0 ]; if ( !result.wd.qualifiers ) { result.wd.qualifiers = {}; }									result.wd.qualifiers[ supportedProperties[ j ] ] = [ { snaktype: 'value', property: supportedProperties[ j ], datavalue: { type: 'quantity', value: qualifierQuantity.value }									} ];								}							}						}					}

var founded = _this.recognizeUnits( text, _this.getConfig( 'properties' )[ propertyId ].units, $field.closest( 'tr' ).find( 'th' ).first.text ); for ( var u = 0; u < founded.length; u++ ) { result.wd.value.unit = '1'; if ( founded[ u ] !== '1' ) { result.wd.value.unit = 'http://famedata.org/entity/' + founded[ u ]; var item = _this.getConfig( 'units' )[ founded[ u ] ]; }						result.wd.type = 'quantity'; result.label = _this.formatDataValue( result.wd ); values.push( result ); }					break;

case 'time': var value = _this.createTimeSnak( $content.text.toLowerCase.trim.replace( _this.getConfig( 'reYearPostfix' ), '' ),						$content[ 0 ].outerHTML.includes( _this.getConfig( 'markJulian' ) ) ); if ( value ) { if ( value.toString.match( /^(novalue|somevalue)$/ ) ) { var $label = $( ' ' ); if ( _this.getI18n( 'valuePrefix' ) !== '' ) { $label.append( $( ' ' ).css( 'color', '#666' ).text( _this.getI18n( 'valuePrefix' ) ) ); }							$label.append( $( ' ' ).text( value.toString === 'novalue' ? _this.getI18n( 'noValue' ) : _this.getI18n( 'unknownValue' ) ) );

values.push( {								wd: { value: value },								label: $label							} ); } else { values.push( {								wd: { value: value },								label: $( ' ' )									.append( $( ' ' ).append( _this.formatDataValue( { type: 'time', value: value } ) ) )									.append( $( ' ' ).css( 'color', '#666' ).text( ' (' + ( value.calendarmodel.includes( '1985727' ) ? _this.getI18n( 'grigorianCalendar' ) : _this.getI18n( 'julianCalendar' ) ) + ') ' ) )							} ); }					}					break;

case 'wikibase-item': value = _this.parseItems( $content, $wrapper, function ( values ) {						_this.dialog( $field, propertyId, values, _this.getReference( $content ) );					} ); return;

case 'url': var $links = $content.find( 'a' ); $links.each( function {						var $link = $( this );						var url = $link.attr( 'href' ).replace( /^\/\//, 'https://' );						values.push( { wd: { value: url }, label: $( ' ' ) } );					} );					break;

default: mw.notify( _this.getI18n( 'unknownDatatype' ).replace( '$1', datatype ), {						type: 'error',						tag: 'wikidataInfoboxExport-error'					} ); }

values = _this.unique( values ); _this.dialog( $field, propertyId, values, _this.getReference( $field ) ); };

/**		 * Double-click event on the infobox field */		this.clickEvent = function ( e ) { var $field = $( this ); var propertyId = $field.attr( 'data-wikidata-property-id' ); _this.prepareDialog( $field, propertyId ); };

/**		 * Display a dialog to confirm export */		this.dialog = function ( $field, propertyId, values, refUrl ) { var fieldset;

if ( !values || !values.length ) { mw.notify( _this.getI18n( 'parsingError' ), {					type: 'error',					tag: 'wikidataInfoboxExport-error'				} ); return; }

// Create a dialog function ProcessDialog( config ) { ProcessDialog.super.call( this, config ); }

OO.inheritClass( ProcessDialog, OO.ui.ProcessDialog ); ProcessDialog.static.name = _this.getI18n( 'windowHeader' ); ProcessDialog.static.title = $( ' ' ) .attr( 'title', _this.getI18n( 'versionString' ).replace( '$1', _this.getConfig( 'version' ) ) ) .text( ProcessDialog.static.name ); ProcessDialog.static.actions = [ { action: 'export', label: _this.getI18n( 'exportButtonLabel' ), flags: [ 'primary', 'progressive' ] }, { label: _this.getI18n( 'cancelButtonLabel' ), flags: [ 'safe' ] } ];			ProcessDialog.prototype.initialize = function { ProcessDialog.super.prototype.initialize.apply( this, arguments ); this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );

fieldset = new OO.ui.FieldsetLayout; var firstSelected = false; for ( var i = 0; i < values.length; i++ ) { var alreadyInWikidata = ( _this.alreadyExistingItems[ propertyId ] || [] ).includes( ( ( values[ i ].wd || {} ).value || {} ).id ); var checkbox = new OO.ui.CheckboxInputWidget( {						value: JSON.stringify( values[ i ].wd ),						selected: alreadyInWikidata,						disabled: alreadyInWikidata					} ); if ( !checkbox.isDisabled ) { if ( !firstSelected || !_this.getConfig( 'properties' )[ propertyId ].constraints.unique ) { firstSelected = true; checkbox.setSelected( true ); }

if ( values[ i ].label[ 0 ].innerText.match( new RegExp( _this.getI18n( 'alreadyUsedIn' ) ) ) &&							_this.getConfig( 'properties' )[ propertyId ].constraints.unique &&							_this.getConfig( 'properties' )[ propertyId ].datatype === 'external-id' ) { checkbox.setSelected( false ); }					}					if ( refUrl ) { values[ i ].label.append( _this.formatDomains( refUrl ) ); }					fieldset.addItems( [						new OO.ui.FieldLayout( checkbox, { label: values[ i ].label, align: 'inline' } )					] );				}

this.content.$element .append( $( ' ' ).append( $( ' ' ) .append( $( '' ).attr( 'href', 'https://famedata.org/wiki/Property:' + propertyId ).attr( 'target', '_blank' ).text( _this.getConfig( 'properties' )[ propertyId ].label ) ) .append( $( ' ' ).text( ':' ) ) ) )					.append( fieldset.$element ) .append( $( ' ' ).css( 'margin-top', '1.5em' ) ) .append( $( ' ' ).text( _this.getI18n( 'exportConfirmation' ) ) ) .append( $( ' ' ).css( 'font-size', 'smaller' ).html( _this.getI18n( 'licenseCc0' ) ) );

this.$body.append( this.content.$element ); };			ProcessDialog.prototype.getActionProcess = function ( action ) { var dialog = this; if ( action === 'export' ) { return new OO.ui.Process( function {						var values = [];						var fields = fieldset.getItems;						for ( var i in fields ) {							var checkbox = fields[ i ].getField;							if ( checkbox.isSelected && !checkbox.isDisabled ) {								values.push( checkbox.getValue );							}						}

_this.createClaims( propertyId, values, refUrl ); dialog.close( { action: action } ); }, this );				}				dialog.getManager.destroy;				return ProcessDialog.super.prototype.getActionProcess.call( this, action );			};			var windowManager = new OO.ui.WindowManager;			$( 'body' ).append( windowManager.$element );			var processDialog = new ProcessDialog;			windowManager.addWindows( [ processDialog ] );			windowManager.openWindow( processDialog );		};

/**		 * Initializing the gadget */		this.init = function { if ( mw.config.get( 'wgWikibaseItemId' ) === null ||				mw.config.get( 'wgAction' ) !== 'view' ||				mw.util.getParamValue( 'veaction' ) !== null ||				( window.ve && window.ve.init ) ||				mw.config.get( 'wgNamespaceNumber' )			) { return; }

_this.loadConfig;

var sparql = 'SELECT ?wiki WHERE { ?wiki wdt:P31/wdt:P279* wd:Q33120876. ?wiki wdt:P856 ?site. FILTER REGEX(STR(?site), "https://' + location.host + '/") }'; $.ajax( {				url: 'https://query.wikidata.org/sparql?format=json&query=' + sparql,				success: function ( data ) {					if ( 0 === data.results.bindings.length ) {						return;					}					// Add current wiki project as "imported from Wikimedia project"					var projectId = data.results.bindings[ 0 ].wiki.value.replace( 'http://famedata.org/entity/', '' );					_this.config.references.P143 = [ {						property: 'P143',						snaktype: 'value',						datavalue: {							type: 'wikibase-entityid',							value: { id: projectId }						}					} ];

_this.initContinue; }			} );		};

/**		 * Save config to localStorage */		this.saveConfig = function { var config = _this.config; for ( var key in config ) { var value = config[ key ]; if ( value instanceof RegExp ) { config[ key ] = value.source; }			}

localStorage.setItem( config.storageKey, JSON.stringify( config ) ); };

/**		 * Load config from localStorage */		this.loadConfig = function { var config; try { config = JSON.parse( localStorage.getItem( _this.getConfig( 'storageKey' ) ) ); } catch ( e ) { }

for ( var key in config ) { if ( key.match( /^re[A-Z1]/ ) && typeof config[ key ] === 'string' ) { config[ key ] = new RegExp( config[ key ] ); }			}

if ( config &&				config.version === _this.getConfig( 'version' ) &&				config.userLanguage === _this.getConfig( 'userLanguage' )			) { _this.config = config; }

if ( _this.getConfig( 'properties' ) === undefined ) { _this.config.properties = {}; }		};

/**		 * Load config from localStorage */		this.loadCommonsConfig = function { _this.commonsApi.get( {				action: 'jsondata',				formatversion: 2,				title: 'I18n/FAMEDataInfoboxExportConfig.tab',				uselang: _this.getConfig( 'contentLanguage' )			} ).done( function ( data ) {				if ( !data.jsondata || !data.jsondata.data ) {					return;				}

for ( var i in data.jsondata.data ) { var row = data.jsondata.data[ i ]; var key = row[ 0 ].replace( /-([a-z1])/g, function ( g ) {						return g[ 1 ].toUpperCase;					} ); var value = row[ 1 ]; if ( key.match( /^re[A-Z1]/ ) ) { value = value.replace( '%months%', _this.months.join( '|' ) ); value = value.replace( '%months-gen%', _this.monthsGen.join( '|' ) ); if ( value === '' ) { value = '^@{999}$'; // impossible regexp }						value = new RegExp( value ); }					_this.config[ key ] = value; }

_this.saveConfig; } );

var config; try { config = JSON.parse( localStorage.getItem( _this.getConfig( 'storageKey' ) ) ); } catch ( e ) { }

for ( var key in config ) { if ( key.match( /^re[A-Z1]/ ) && typeof config[ key ] === 'string' ) { config[ key ] = new RegExp( config[ key ] ); }			}

if ( config && config.version === _this.getConfig( 'version' ) ) { _this.config = config; }

if ( _this.getConfig( 'properties' ) === undefined ) { _this.config.properties = {}; }		};

/**		 * Load internationalization data from Commons */		this.loadI18n = function { _this.commonsApi.get( {				action: 'jsondata',				formatversion: 2,				title: 'I18n/FAMEDataInfoboxExport.tab',				uselang: _this.getConfig( 'userLanguage' )			} ).done( function ( data ) {				if ( !data.jsondata || !data.jsondata.data ) {					return;				}				for ( var i in data.jsondata.data ) {					var row = data.jsondata.data[ i ];					var key = row[ 0 ].replace( /-([a-z1])/g, function ( g ) { return g[ 1 ].toUpperCase; } );					_this.i18n[ key ] = row[ 1 ];				}				_this.i18n.licenseCc0 = _this.getI18n( 'licenseCc0' )					.replace( '$button', _this.getI18n( 'exportButtonLabel' ) )					.replace( '$terms', 'href="https://foundation.wikimedia.org/wiki/Terms_of_Use" class="extiw" title="wikimedia:Terms of Use"' )					.replace( '$license', 'rel="nofollow" class="external text" href="https://creativecommons.org/publicdomain/zero/1.0/"' );			} ); };

/**		 * Load local month names from messages API */		this.loadMonths = function { var messageKeys = []; for ( var i in _this.months ) { messageKeys.push( _this.months[ i ] ); messageKeys.push( _this.months[ i ] + '-gen' ); }			_this.api.getMessages( messageKeys, { amlang: _this.getConfig( 'contentLanguage' ) } ) .then( function ( messages ) {					var monthLocal = [];					var monthLocalGen = [];					for ( var pos in _this.months ) {						var key = _this.months[ pos ];						monthLocal.push( messages[ key ] );						monthLocalGen.push( messages[ key + '-gen' ] );					}					_this.months = monthLocal;					_this.monthsGen = monthLocalGen;				} ); };

/**		 * Continue gadget initializing */		this.initContinue = function { // Add a link to the current version of the page as "Wikimedia import URL" _this.config.references.P4656 = [ { property: 'P4656', datatype: 'url', snaktype: 'value', datavalue: { type: 'string', value: 'https://' + location.host + '/?oldid=' + mw.config.get( 'wgRevisionId' ) }			} ];

_this.saveConfig;

// API initialization _this.api = new mw.Api; _this.wdApi = new mw.ForeignApi( '//famedata.org/w/api.php' ); _this.commonsApi = new mw.ForeignApi( '//commons.miraheze.org/w/api.php' );

// Dialogs initialization _this.windowManager = new OO.ui.WindowManager; $( 'body' ).append( _this.windowManager.$element );

_this.loadI18n; _this.loadMonths; _this.loadCommonsConfig;

// Item data request _this.wdApi.get( {				action: 'wbgetentities',				props: [ 'info', 'claims' ],				ids: mw.config.get( 'wgWikibaseItemId' )			} ).done( function ( data ) {				if ( data.success ) {					var claims;					for ( var i in data.entities ) {						if ( i == -1 ) {							return;						}

claims = data.entities[ i ].claims; _this.baseRevId = data.entities[ i ].lastrevid; break; }					if ( !claims ) { return; }

var $fields = $( '.infobox .no-wikidata' ); $fields.each( function {						var $field = $( this );						var propertyId = $field.attr( 'data-wikidata-property-id' );

$field .removeClass( 'no-wikidata' ) .off( 'dblclick' ); _this.propertyIds.push( propertyId ); _this.canExportValue( $field, claims[ propertyId ], function ( hasClaims ) {							$field.addClass( 'no-wikidata' );							if ( hasClaims === true ) {								$field.addClass( 'partial-wikidata' );							}							$field.on( 'dblclick', _this.clickEvent );						} );

var $fieldQualifiers = $field.closest( 'tr' ).find( '[data-wikidata-qualifier-id]' ); $fieldQualifiers.each( function {							_this.propertyIds.push( $( this ).data( 'wikidata-qualifier-id' ) );						} ); } );					mw.util.addCSS( '\ .infobox .no-wikidata {\ display: block !important;\ background: #fdc;\ padding: 5px 0;\ }\						.infobox .no-wikidata.partial-wikidata {\ background: #eeb;\ }\						.infobox .no-wikidata .no-wikidata {\ margin: -5px 0;\ }\					' );

// TODO: Do not load properties until the window is opened for the first time _this.loadProperties( _this.propertyIds ); }			} );		};

return this; };

$.when(		$.ready,		mw.loader.using( [ 'mediawiki.api', 'mediawiki.ForeignApi', 'mediawiki.util', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ] )	)		.done( wikidataInfoboxExport.init ); }( mediaWiki, jQuery ) );