Benutzer:Nw520/currencyConverter.js
(Weitergeleitet von Benutzer:Naseweis520/currencyConverter.js)
Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.
- Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
- Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
- Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
- Opera: Strg+F5
/* = CurrencyConverter =
* Dies ist nur ein Proof-of-Concept um zu testen, inwiefern ein Währungsumrechner umsetzbar ist
*
* == ToDo Liste ==
* * Nachkommastellen sinnvoll runden (10er Schritte? bei 10/90 ab-/aufrufen?)
* * Festlegen einer Referenzwährung (EUR oder USD, je nachdem was in Wikidata gespeichert ist)
* * Stand des Wechselkurses darstellen (ggf. als title)
* * Bei vCards Währung aus data-currency-Parameter beziehen
* * Sinnvoll kommentieren
* * Falls gewünscht: Zusätzliche Klasse für Preisangaben die nicht mit getrennt sind (Grundlage: Hilfe:Angabe_von_Telefonnummern,_Währungen_und_Öffnungszeiten#Währungen)
* * Erkennung von Preisspannen im Format `12-34 €`
* * Erkennung von Alternativen im Format `12/13 €`
* * Einstellbare Ziel-Währung
* * Währungskurse von Wikidata beziehen
* ** Ggf. in Browser für x Tage speichern
* * Erkennung und Umwandeln von Preisangaben in Fließtext (Realisierbarkeit noch fraglich)
*/
( function () {
var CLASS_PRICEMARK = 'pricemark';
var CLASS_PRICEMARK_CONVERTED = 'pricemark-converted';
var CLASS_PRICEMARK_LOCAL = 'pricemark-local';
var CLASS_PRICEMARK_NOCONVERSION = 'pricemark-noconversion';
var TAG = 'nw520.currencyConverter'; // Prefix for log output
var currencyExchangeRateMap = {};
var currencyPreSigns = [];
var currencyPostSigns = [];
var currencySignMap = {};
var currencyUpdateMap = {};
var currencyWdMap = {};
var regexp = null;
class PricemarkDefinition {
constructor( value, currency, match ) {
this.value = value;
this.currency = currency;
this.match = match;
}
getFormattedPrice( isoId ) {
var out = this.getPrice( isoId ).toLocaleString( 'de', {
maximumFractionDigits: 2,
minimumFractionDigits: 2
} );
if ( out.substr( out.length - 3 ) === ',00' ) {
out = out.substr( 0, out.length - 3 );
}
return out;
}
getPrice( isoId ) {
if ( this.requiresConversion( isoId ) ) {
return this.getPriceUsd() * ( 1 / currencyExchangeRateMap[ isoId ] );
} else { // No conversion needed
return this.value;
}
}
getPriceUsd() {
return this.value * currencyExchangeRateMap[ this.currency ];
}
requiresConversion( isoId ) {
return isoId !== this.currency;
}
}
setup();
/* Erster Versuch Fließtext Währungsangaben bei Klick zu erkennen. vCard müssten ausgeschlossen werden.
* Darstellen des umgerechneten Werts (ohne bestehende EventListener zu töten) problematisch
function attachClickListener() {
$("#bodyContent").click(function(e) {
e.preventDefault();
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var anchor = selection.anchorNode;
var pricemarks = findPricemarks(anchor.textContent);
if(pricemarks.length > 0) {
var clickedPricemark = filter(selection.anchorOffset, pricemarks);
} else {
// Nicht auf Preisangabe geklickt
}
});
function filter(offset, pricemarks) {
var result = null;
for(i = 0; i < pricemarks.length && result === null; i++) {
var pricemark = pricemarks[i];
if(pricemark.range[0] <= offset && offset <= pricemark.range[1]) {
result = pricemark;
}
}
return result;
}
}
*/
function setup() {
setupCurrencies();
setupRegex();
injectInVcards();
// attachClickListener();
}
function setupCurrencies() {
add( 'EUR', 'Q4916', [ '€', 'Euro' ], 1.15, '2019-01-14', true, false );
add( 'USD', 'Q4917', [ '$', 'US$', '$US' ], 1, null, true, true );
add( 'VND', 'Q192090', [ '₫', 'Dong' ], 0.000043, '2019-01-14', true, true );
console.debug( `[${TAG}]`, currencyExchangeRateMap, currencyPreSigns, currencySignMap, currencyWdMap );
function add( isoId, wdId, signList, conversionToEur, lastUpdate, allowPostfix, allowPrefix ) {
isoId = isoId.toUpperCase();
// Store exchange rate
currencyExchangeRateMap[ isoId ] = conversionToEur;
// Store wikidata id
currencyWdMap[ isoId ] = wdId;
// Store last update date
currencyUpdateMap[ isoId ] = lastUpdate;
register( isoId, isoId );
if ( typeof signList === 'string' ) {
console.warn( `[${TAG}] ${isoId}: Please pass alternative signs in an array, not as a string!` );
register( signList, isoId );
} else if ( typeof signList === 'object' ) {
signList.forEach( function ( val, i ) {
register( val, isoId );
} );
}
function register( sign, isoId ) {
// Store pre sign for regex generation
if ( allowPrefix ) {
currencyPreSigns.push( sign );
}
// Store post sign for regex generation
if ( allowPostfix ) {
currencyPostSigns.push( sign );
}
// Map alternative to ISO 4217
currencySignMap[ sign ] = isoId;
}
}
}
function setupRegex() {
// Backslashs are encoded as "\\"
// RegExp can be tested on https://regex101.com/ and visualised on https://www.debuggex.com/ . Don't forget to replace "\\" with "\"
var expression = `(^| |\\u00a0)((${currencyPreSigns.join( '|' ).replace( new RegExp( '\\$', 'g' ), '\\$' )})( |\\u00a0))?(\\d+)((\\.\\d{3})*)(,(\\d{1,2}|-))?(( |\\u00a0)(${currencyPostSigns.join( '|' ).replace( new RegExp( '\\$', 'g' ), '\\$' )}))?($|[ \\u00a0;)]|([.,]($|[ \\u00a0])))`;
console.debug( `[${TAG}] ${expression}` );
regexp = new RegExp( expression, 'gmu' );
}
function findPricemarks( text ) {
var pricemarks = [];
var match;
do {
match = regexp.exec( text );
if ( match !== null ) {
var newPricemark = matchToPricemark( match );
if ( newPricemark !== null ) {
pricemarks.push( newPricemark );
}
}
} while ( match );
// Reset regex state
regexp.lastIndex = 0;
return pricemarks;
function matchToPricemark( match ) {
/* 0: Full match
* 1: Prefixed character
* 2: –
* 3: Prefixed currency
* 4: Separator between 3 and 5
* 5: Digits before . and ,
* 6: . and digits - repeatedly
* 7: –
* 8: –
* 9: Digits after , or dash
* 10: -
* 11: Separator between 9 and 12
* 12: Postfixed currency
* 13: Postfixed character
* 14: -
*/
// Exactly one currency (pre- or postfixed is set)
if ( match[ 3 ] === undefined && match[ 12 ] !== undefined || match[ 3 ] !== undefined && match[ 12 ] === undefined ) {
var currency = ( match[ 3 ] === undefined ? match[ 12 ] : match[ 3 ] );
return new PricemarkDefinition( parsePrice( match ), currencySignMap[ currency ], match );
} else {
return null;
}
function parsePrice( match ) {
return parseFloat( `${match[ 5 ]}${match[ 6 ].replace( new RegExp( '\\.', 'g' ), '' )}.${match[ 9 ] === undefined || match[ 9 ] === '-' ? '00' : match[ 9 ]}` );
}
}
}
function injectInVcards() {
$( '.listing-price' ).each( function () {
var pricemarks = findPricemarks( this.textContent );
var result = this.textContent;
$.each( pricemarks, function ( i, pricemark ) {
var pricemarkText = pricemark.match[ 0 ].substring( pricemark.match[ 1 ].length, pricemark.match[ 0 ].length - pricemark.match[ 13 ].length );
// @TODO: Hardcoded currency, hardcoded internalisation
result = result.replace( pricemark.match[ 0 ],
pricemark.match[ 1 ] + // Pre- and suffixed characters are replaced too in order to differentiate between multiple occurences of same value with differentiating pre- or suffixed characters
`<span class="${CLASS_PRICEMARK} ${pricemark.requiresConversion( 'EUR' ) ? '' : CLASS_PRICEMARK_NOCONVERSION}">` +
`<span class="${CLASS_PRICEMARK_LOCAL}" data-currency="${pricemark.currency}">` +
`${pricemarkText}` +
'</span>' +
( pricemark.requiresConversion( 'EUR' ) ? `<span class="${CLASS_PRICEMARK_CONVERTED}" data-currency="EUR"> (${pricemark.getFormattedPrice( 'EUR' )} €)</span>` : '' ) +
'</span>' +
pricemark.match[ 13 ]
);
} );
$( this ).html( result );
} );
}
}() );