diff --git a/build/images/background.png b/build/images/background.png new file mode 100644 index 0000000..2752d59 Binary files /dev/null and b/build/images/background.png differ diff --git a/build/images/coin.png b/build/images/coin.png new file mode 100644 index 0000000..dabfc1e Binary files /dev/null and b/build/images/coin.png differ diff --git a/build/images/sliderback.png b/build/images/sliderback.png new file mode 100644 index 0000000..e3997b2 Binary files /dev/null and b/build/images/sliderback.png differ diff --git a/build/manifest.json b/build/manifest.json index 4d1703d..260ac69 100644 --- a/build/manifest.json +++ b/build/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "DogMoneyMode", - "version": "1.3", + "version": "2.0", "description": "Browser extension that makes fiat prices display in Dogecoin. Fiat Supported: USD, GBP, EUR.", "permissions": ["storage"], "action": { diff --git a/build/popup.html b/build/popup.html index 12cefe5..8667120 100644 --- a/build/popup.html +++ b/build/popup.html @@ -6,43 +6,38 @@ * { font-family: 'Comic Sans MS', cursive, sans-serif; } - body { - background-color: #fae0d4; - padding: 5px; - width: 250px; + background-color: #23292B; + background: url('./images/background.png'); + background-position: center; + background-size: cover; text-align: center; + width: 300px; + height: 300px; + margin: 0; + padding: 0; } - - h1 { - margin-top: 0; - } - - h5 { - margin: 14px 0px; - font-size: 12px; - } - - - select { - padding: 10px; - font-size: 16px; - border-radius: 12px; + :root { + --switch-width: 180px; + --switch-height: 120px; + --slider-size: calc(var(--switch-height) - 0px); + --slider-move: calc(var(--switch-width) - var(--switch-height)); } - .switch { + top: 95px; position: relative; display: inline-block; - width: 150px; - height: 68px; + width: var(--switch-width); + height: var(--switch-height); + background: url('./images/sliderback.png') no-repeat; + background-size: 100% 100%; + border-radius: var(--switch-height); } - .switch input { opacity: 0; width: 0; height: 0; } - .slider { position: absolute; cursor: pointer; @@ -53,74 +48,85 @@ background-color: #ccc; -webkit-transition: .4s; transition: .4s; + border-radius: var(--switch-height); } - .slider:before { position: absolute; content: ""; - height: 58px; - width: 58px; - left: 5px; - bottom: 5px; + height: var(--slider-size); + width: var(--slider-size); + left: 0px; + bottom: 0px; background-color: white; -webkit-transition: .4s; transition: .4s; + border-radius: var(--switch-height); + background-image: url('images/coin.png'); + background-position: center; + background-size: cover; + z-index: 2; } - input:checked + .slider { - background-color: #2196F3; + -webkit-transition: .4s; + transition: .4s; + border-radius: var(--switch-height); + background-color: transparent; + background: url('./images/sliderback.png'); + } + .slider::after { + content: ""; + position: absolute; + border-radius: var(--switch-height); + left: 0%; + top: 0; + right: 0; + bottom: 0; + background-color: white; + transition: .4s; + z-index: 1; + } + input:checked + .slider::after { + left: 60px; } - input:focus + .slider { box-shadow: 0 0 1px #2196F3; } - input:checked + .slider:before { - -webkit-transform: translateX(75px); - -ms-transform: translateX(75px); - transform: translateX(75px); + -webkit-transform: translateX(var(--slider-move)); + -ms-transform: translateX(var(--slider-move)); + transform: translateX(var(--slider-move)); } - - - .slider.round { - border-radius: 68px; - } - - .slider.round:before { - border-radius: 50%; - } - - #tips { - display:block; + input:checked + .slider:before { + -webkit-filter: grayscale(0%); + -moz-filter: grayscale(0%); + -o-filter: grayscale(0%); + -ms-filter: grayscale(0%); + filter: grayscale(0%); } - .tip-content { - display: none; + input + .slider:before { + -webkit-filter: grayscale(100%); + -moz-filter: grayscale(100%); + -o-filter: grayscale(100%); + -ms-filter: grayscale(100%); + filter: grayscale(100%); } - .tip-content img { - width: 250px; - height: 250px; - } -

DogMoneyMode

- + + diff --git a/build/scripts/content.js b/build/scripts/content.js index 765b83a..3d155c8 100644 --- a/build/scripts/content.js +++ b/build/scripts/content.js @@ -1 +1 @@ -(()=>{"use strict";class e{static USD="usd";static EUR="eur";static CNY="cny";static JPY="jpy";static GBP="gbp";static INR="inr";static RUB="rub";static getCurrencyBySymbol(e){return e.includes("$")?"usd":e.includes("€")?"eur":e.includes("元")?"cny":e.includes("円")?"jpy":e.includes("£")?"gbp":e.includes("₹")?"inr":!!e.includes("₽")&&"rub"}static getCurrencyRegex(e){let t=null,r=null;switch(e){case"usd":return t="$".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(${t}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`,new RegExp(r);case"eur":return t="€".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(${t}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`,new RegExp(r);case"cny":return t="元".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)(${t}\\s*)`,new RegExp(r);case"jpy":return t="円".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)(${t}\\s*)`,new RegExp(r);case"gbp":return t="£".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(${t}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`,new RegExp(r);case"inr":return t="₹".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(${t}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`,new RegExp(r);case"rub":return t="₽".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(${t}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`,new RegExp(r);default:return null}}}let t=[];t.push(new class{constructor(){}replace(t){if(/^(www\.)?amazon\.[a-z\.]{2,5}$/.test(window.location.hostname)){let r=document.querySelectorAll(".a-price"),n=!1;r.forEach((function(r){if(!r.textContent.includes("Ð")){let o=r.querySelector(".a-price-symbol"),a=o?o.textContent:null,c=r.querySelector(".a-offscreen"),i=c?c.textContent:null;if(a&&!n){let t=e.getCurrencyBySymbol(a||i);t&&(n=t,console.log(`Detected ${t}`))}let l=r.querySelectorAll(".a-price-whole, .a-price-fraction");if(c&&l.length>0){let e=c.textContent.replace(a,"").replace(/,/g,""),r=(parseFloat(e)/parseFloat(t[n])).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2});c.textContent="Ð"+r,o&&(o.textContent="Ð");let[i,s]=r.split(".");l[0].textContent=i+l[0].querySelector(".a-price-decimal").textContent,l[1].textContent=s}}}))}}}),t.push(new class{replace(e){let t=e.usd;if(/^(www\.)?newegg\.[a-z\.]{2,5}$/.test(window.location.hostname)){let e=document.querySelectorAll(".price-current"),r=document.querySelectorAll(".goods-price-current");e.forEach((function(e){if(!e.textContent.includes("Ð")){let r=e.querySelector("strong"),n=e.querySelector("sup"),o=Array.from(e.childNodes).findIndex((e=>3===e.nodeType&&e.nodeValue.includes("$")));if(r&&n&&o>-1){let a=r.textContent.replace(/,/g,"")+"."+n.textContent.replace(/,/g,""),c=(parseFloat(a)/parseFloat(t)).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2}),[i,l]=c.split(".");r.textContent=i,n.textContent=l;let s=e.childNodes[o];s.nodeValue=s.nodeValue.replace(fiat_currency_symbol,"Ð")}}})),r.forEach((function(e){if(!e.textContent.includes("Ð")){let r=e.querySelector(".goods-price-value strong"),n=e.querySelector(".goods-price-value sup"),o=e.querySelector(".goods-price-symbol");if(r&&n){let e=r.textContent.replace(/,/g,"")+"."+n.textContent.replace(/,/g,""),a=(parseFloat(e)/parseFloat(t)).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2}),[c,i]=a.split(".");r.textContent=c,n.textContent=i,o&&(o.textContent="Ð")}}}))}}});const r=new class{constructor(){this.localStorageKey="dmm-app-state"}async setAppState(e){const t={};return t[this.localStorageKey]=e,new Promise(((e,r)=>{chrome.storage.local.set(t,(()=>{if(chrome.runtime.lastError)return r(chrome.runtime.lastError);e()}))}))}async getAppState(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(r=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(r[this.localStorageKey]||{dogMoneyModeEnabled:!1,comicSansModeEnabled:!1})}))}))}},n=new class{constructor(){this.localStorageKey="dmm-exchange-rates",this.timeToLive=12e4}async _fetchRates(){const e=await fetch("https://api.coingecko.com/api/v3/simple/price?ids=dogecoin&vs_currencies=USD,EUR,CNY,JPY,GBP,INR,RUB"),t=(await e.json()).dogecoin,r={updatedOn:Date.now(),rates:t};return new Promise(((e,t)=>{chrome.storage.local.set({[this.localStorageKey]:r},(()=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(r)}))}))}async getRates(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(async r=>{let n=r[this.localStorageKey];if(!n||Date.now()-n.updatedOn>this.timeToLive)try{n=await this._fetchRates()}catch(e){return t(e)}e(n.rates)}))}))}};let o=r.getAppState(),a=n.getRates(),c=null;function i(t){if(!(t.tagName&&"input"===t.tagName.toLowerCase()||t.isContentEditable))if(t.childNodes.length>0)Array.from(t.childNodes).forEach((e=>i(e)));else{let r=function(t){let r=!1,n=e.getCurrencyBySymbol(t),o=e.getCurrencyRegex(n);if(!n||!o)return{text:t,replaced:r};for(;;){var a=t.match(o);if(!a)break;var c=a.reduce((function(e,t){return e.length>t.length?e:t}));if(1===c.length)break;var i=l(n,c,o);if(null!==i){var s={};i<1?(s.minimumFractionDigits=3,s.maximumFractionDigits=3):i<100?(s.minimumFractionDigits=2,s.maximumFractionDigits=2):(s.minimumFractionDigits=0,s.maximumFractionDigits=0);let e=t.indexOf(c);t=e>0&&"-"===t.charAt(e-1)?t.replace(c,` Ð${i.toLocaleString("en-US",s)}`):t.replace(c,`Ð${i.toLocaleString("en-US",s)}`),r=!0}}return{text:t,replaced:r}}(t.textContent);r.replaced&&(t.textContent=r.text)}}function l(t,r,n){const o=new RegExp(n.source,n.flags).exec(r);if(!o)return null;let c=2;return-1!==[e.CNY,e.JPY].indexOf(t)&&(c=1),parseFloat(o[c].replace(/[, ]/g,""))/a[t]}!async function e(){try{clearInterval(c);let l=o;o=await r.getAppState(),o.dogMoneyModeEnabled?(a=await n.getRates(),t.forEach((e=>{e.replace(a)})),i(document.body)):l.dogMoneyModeEnabled&&location.reload(),o.comicSansModeEnabled?document.documentElement.classList.add("dogmoneymode-comic-sans"):document.documentElement.classList.remove("dogmoneymode-comic-sans"),c=setInterval(e,500)}catch(e){console.error(e)}}()})(); \ No newline at end of file +(()=>{"use strict";class e{static USD="usd";static EUR="eur";static CNY="cny";static JPY="jpy";static GBP="gbp";static INR="inr";static RUB="rub";static getCurrencyBySymbol(e){return e.includes("$")?"usd":e.includes("€")?"eur":e.includes("元")?"cny":e.includes("円")?"jpy":e.includes("£")?"gbp":e.includes("₹")?"inr":!!e.includes("₽")&&"rub"}static getCurrencyRegex(e){let t=null,r=null;switch(e){case"usd":t="$";break;case"eur":t="€";break;case"gbp":t="£";break;case"inr":t="₹";break;case"rub":t="₽";break;case"cny":return t="元".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${t}\\s*)`,new RegExp(r);case"jpy":return t="円".replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),r=`(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${t}\\s*)`,new RegExp(r);default:return null}return r=`(?0){let e=c.textContent.replace(a,"").replace(/,/g,""),t=(parseFloat(e)/parseFloat(n[o])).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2});c.textContent="Ð"+t,r&&(r.textContent="Ð");let[i,s]=t.split(".");l[0].textContent=i+l[0].querySelector(".a-price-decimal").textContent,l[1].textContent=s}}}))}}}),t.push(new class{replace(e,t,r){let n=r.usd;if(/^(www\.)?newegg\.[a-z\.]{2,5}$/.test(e.location.hostname)){let e=t.querySelectorAll(".price-current"),r=t.querySelectorAll(".goods-price-current");e.forEach((function(e){if(!e.textContent.includes("Ð")){let t=e.querySelector("strong"),r=e.querySelector("sup"),o=Array.from(e.childNodes).findIndex((e=>3===e.nodeType&&e.nodeValue.includes("$")));if(t&&r&&o>-1){let a=t.textContent.replace(/,/g,"")+"."+r.textContent.replace(/,/g,""),c=(parseFloat(a)/parseFloat(n)).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2}),[i,l]=c.split(".");t.textContent=i,r.textContent=l;let s=e.childNodes[o];s.nodeValue=s.nodeValue.replace(fiat_currency_symbol,"Ð")}}})),r.forEach((function(e){if(!e.textContent.includes("Ð")){let t=e.querySelector(".goods-price-value strong"),r=e.querySelector(".goods-price-value sup"),o=e.querySelector(".goods-price-symbol");if(t&&r){let e=t.textContent.replace(/,/g,"")+"."+r.textContent.replace(/,/g,""),a=(parseFloat(e)/parseFloat(n)).toLocaleString("en",{minimumFractionDigits:2,maximumFractionDigits:2}),[c,i]=a.split(".");t.textContent=c,r.textContent=i,o&&(o.textContent="Ð")}}}))}}}),t.push(new class{constructor(){this.exchangeRates=null}replace(e,t,r){if(this.exchangeRates=r,!(t.tagName&&"input"===t.tagName.toLowerCase()||t.isContentEditable))if(t.childNodes&&t.childNodes.length>0)Array.from(t.childNodes).forEach((t=>this.replace(e,t,r)));else{let e=this.processMatches(t.textContent,r);e.replaced&&(t.textContent=e.text)}}processMatches(t,r){let n=!1;if(!t)return{text:t,replaced:n};let o=e.getCurrencyBySymbol(t),a=e.getCurrencyRegex(o);if(!o||!a)return{text:t,replaced:n};for(;;){var c=t.match(a,"g");if(!c)break;console.log(a),console.log(t);var i=c.reduce((function(e,t){return e.length>t.length?e:t}));if(1===i.length)break;var l=this.convertToDogecoin(o,i,a,r);if(null!==l){var s={};l<1?(s.minimumFractionDigits=3,s.maximumFractionDigits=3):l<100?(s.minimumFractionDigits=2,s.maximumFractionDigits=2):(s.minimumFractionDigits=0,s.maximumFractionDigits=0);let e=t.indexOf(i);t=e>0&&"-"===t.charAt(e-1)?t.replace(i,` Ð${l.toLocaleString("en-US",s)}`):t.replace(i,`Ð${l.toLocaleString("en-US",s)}`),n=!0}}return{text:t,replaced:n}}convertToDogecoin(t,r,n,o){const a=new RegExp(n.source,n.flags).exec(r);if(!a)return null;let c=0;return[e.CNY,e.JPY].indexOf(t)>-1&&(c=1),parseFloat(a[c].replace(/[^\d.]/g,""))/o[t]}});const r=new class{constructor(){this.localStorageKey="dmm-app-state"}async setAppState(e){const t={};return t[this.localStorageKey]=e,new Promise(((e,r)=>{chrome.storage.local.set(t,(()=>{if(chrome.runtime.lastError)return r(chrome.runtime.lastError);e()}))}))}async getAppState(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(r=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(r[this.localStorageKey]||{dogMoneyModeEnabled:!1,comicSansModeEnabled:!1})}))}))}},n=new class{constructor(){this.localStorageKey="dmm-exchange-rates",this.timeToLive=12e4}async _fetchRates(){const e=await fetch("https://api.coingecko.com/api/v3/simple/price?ids=dogecoin&vs_currencies=USD,EUR,CNY,JPY,GBP,INR,RUB"),t=(await e.json()).dogecoin,r={updatedOn:Date.now(),rates:t};return new Promise(((e,t)=>{chrome.storage.local.set({[this.localStorageKey]:r},(()=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(r)}))}))}async getRates(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(async r=>{let n=r[this.localStorageKey];if(!n||Date.now()-n.updatedOn>this.timeToLive)try{n=await this._fetchRates()}catch(e){return t(e)}e(n.rates)}))}))}};let o=r.getAppState(),a=n.getRates(),c=null;!async function e(){try{clearInterval(c);let i=o;o=await r.getAppState(),o.dogMoneyModeEnabled?(a=await n.getRates(),t.forEach((e=>{e.replace(window,document.body,a)}))):i.dogMoneyModeEnabled&&location.reload(),c=setInterval(e,500)}catch(e){console.error(e)}}()})(); \ No newline at end of file diff --git a/build/scripts/popup.js b/build/scripts/popup.js index 9ef5c2e..c6f0c22 100644 --- a/build/scripts/popup.js +++ b/build/scripts/popup.js @@ -1 +1 @@ -(()=>{"use strict";let e=new class{constructor(){this.localStorageKey="dmm-app-state"}async setAppState(e){const t={};return t[this.localStorageKey]=e,new Promise(((e,o)=>{chrome.storage.local.set(t,(()=>{if(chrome.runtime.lastError)return o(chrome.runtime.lastError);e()}))}))}async getAppState(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(o=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(o[this.localStorageKey]||{dogMoneyModeEnabled:!1,comicSansModeEnabled:!1})}))}))}};!async function(){try{let n=await e.getAppState(),c=document.getElementById("dogmoneymode-toggle"),a=document.getElementById("comicsans-toggle");c.checked=n.dogMoneyModeEnabled,a.checked=n.comicSansModeEnabled,c.addEventListener("change",(function(t){n.dogMoneyModeEnabled=t.target.checked,e.setAppState(n)})),a.addEventListener("change",(function(t){n.comicSansModeEnabled=t.target.checked,e.setAppState(n)}));var t=document.getElementById("tips"),o=document.getElementById("tip-content");t.addEventListener("click",(function(e){e.preventDefault(),"none"===window.getComputedStyle(o).display?o.style.display="block":o.style.display="none"}))}catch(e){console.error(e)}}()})(); \ No newline at end of file +(()=>{"use strict";let e=new class{constructor(){this.localStorageKey="dmm-app-state"}async setAppState(e){const t={};return t[this.localStorageKey]=e,new Promise(((e,o)=>{chrome.storage.local.set(t,(()=>{if(chrome.runtime.lastError)return o(chrome.runtime.lastError);e()}))}))}async getAppState(){return new Promise(((e,t)=>{chrome.storage.local.get(this.localStorageKey,(o=>{if(chrome.runtime.lastError)return t(chrome.runtime.lastError);e(o[this.localStorageKey]||{dogMoneyModeEnabled:!1,comicSansModeEnabled:!1})}))}))}};!async function(){try{let t=await e.getAppState(),o=document.getElementById("dogmoneymode-toggle");o.checked=t.dogMoneyModeEnabled,o.addEventListener("change",(function(o){t.dogMoneyModeEnabled=o.target.checked,e.setAppState(t)}))}catch(e){console.error(e)}}()})(); \ No newline at end of file diff --git a/src/Utilities.js b/src/Utilities.js index 4743b62..314e70e 100644 --- a/src/Utilities.js +++ b/src/Utilities.js @@ -35,41 +35,38 @@ class Currency { static getCurrencyRegex(currency) { - let escapedSymbol = null; + let symbol = null; let regexPattern = null; switch(currency) { - case "usd": - escapedSymbol = "$".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(${escapedSymbol}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`; - return new RegExp(regexPattern); + case "usd": + symbol = "$"; + break; case "eur": - escapedSymbol = "€".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(${escapedSymbol}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`; - return new RegExp(regexPattern); - case "cny": - escapedSymbol = "元".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)(${escapedSymbol}\\s*)`; - return new RegExp(regexPattern); - case "jpy": - escapedSymbol = "円".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)(${escapedSymbol}\\s*)`; - return new RegExp(regexPattern); + symbol = "€"; + break; case "gbp": - escapedSymbol = "£".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(${escapedSymbol}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`; - return new RegExp(regexPattern); + symbol = "£"; + break; case "inr": - escapedSymbol = "₹".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(${escapedSymbol}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`; - return new RegExp(regexPattern); + symbol = "₹"; + break; case "rub": - escapedSymbol = "₽".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - regexPattern = `(${escapedSymbol}\\s*)(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d+)?)`; + symbol = "₽"; + break; + case "cny": + symbol = "元".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${symbol}\\s*)`; + return new RegExp(regexPattern); + case "jpy": + symbol = "円".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${symbol}\\s*)`; return new RegExp(regexPattern); default: return null; } + regexPattern = `(? { - priceReplacer.replace(exchangeRates); + priceReplacers.forEach(priceReplacer => { + priceReplacer.replace(window, document.body, exchangeRates); }); - // Start processing at the body tag - processNodesRecursively(document.body); -} - - - - - -function processNodesRecursively(node) { - - // If this node is an input field or contenteditable, skip processing - if (node.tagName && node.tagName.toLowerCase() === 'input') return; - if (node.isContentEditable) return; - - - // If this node has children, recursively process the children first - if (node.childNodes.length > 0) { - Array.from(node.childNodes).forEach(child => processNodesRecursively(child)); - } - else { - let result = processMatches(node.textContent); - if (result.replaced) { - node.textContent = result.text; - } - } -} - - - - -function processMatches(text) { - - let replaced = false; - let currencyToUse = Currency.getCurrencyBySymbol(text); - let regexToMatch = Currency.getCurrencyRegex(currencyToUse); - - if(!currencyToUse || !regexToMatch){ - return {text, replaced}; - } - - while (true) { - var matches = text.match(regexToMatch); - if (!matches) break; // exit the loop if no more matches - - // find the longest match - var longestMatch = matches.reduce(function(a, b) { return a.length > b.length ? a : b; }); - - - if(longestMatch.length === 1){ - break; - } - - // process the longest match - var dogecoinAmount = convertToDogecoin(currencyToUse, longestMatch, regexToMatch); - if (dogecoinAmount !== null) { - var fractionDigitsOptions = {}; - - if (dogecoinAmount < 1) { - //dogecoin did a thing, show 3 decimal points - fractionDigitsOptions.minimumFractionDigits = 3; - fractionDigitsOptions.maximumFractionDigits = 3; - } - else if (dogecoinAmount < 100) { - //only show decimal points if we have less than 100 - fractionDigitsOptions.minimumFractionDigits = 2; - fractionDigitsOptions.maximumFractionDigits = 2; - } - else { - fractionDigitsOptions.minimumFractionDigits = 0; - fractionDigitsOptions.maximumFractionDigits = 0; - } - - let index = text.indexOf(longestMatch); - if (index > 0 && text.charAt(index - 1) === '-') { - text = text.replace(longestMatch, ` Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); - } else { - text = text.replace(longestMatch, `Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); - } - - replaced = true; - } - - } - - return {text, replaced}; } - - -function convertToDogecoin(currencyToUse, currencyStr, regexToMatch) { - - //if we don't clone the regex we can have issues - const match = new RegExp(regexToMatch.source, regexToMatch.flags).exec(currencyStr); - - if (!match) { - return null; // not a valid currency string - } - - let matchIndex = 2; - - if([Currency.CNY, Currency.JPY].indexOf(currencyToUse) > -1) { - matchIndex = 1; - } - - // Remove the currency symbol, spaces, and commas, then parse as a float - const valueInCurrency = parseFloat(match[matchIndex].replace(/[, ]/g, '')); - - - // Convert to Dogecoin - return valueInCurrency / exchangeRates[currencyToUse]; -} \ No newline at end of file diff --git a/src/popup.js b/src/popup.js index 82d4ce8..d57d88d 100644 --- a/src/popup.js +++ b/src/popup.js @@ -9,34 +9,13 @@ let appStateStore = new AppStateStore(); let appState = await appStateStore.getAppState(); let dogMoneyModeToggleButton = document.getElementById("dogmoneymode-toggle"); - let comicSansModeToggleButton = document.getElementById("comicsans-toggle"); dogMoneyModeToggleButton.checked = appState.dogMoneyModeEnabled; - comicSansModeToggleButton.checked = appState.comicSansModeEnabled; - dogMoneyModeToggleButton.addEventListener("change", function(e) { appState.dogMoneyModeEnabled = e.target.checked; appStateStore.setAppState(appState); }); - comicSansModeToggleButton.addEventListener("change", function(e) { - appState.comicSansModeEnabled = e.target.checked; - appStateStore.setAppState(appState); - }); - - - var tipsButton = document.getElementById('tips'); - var tipContent = document.getElementById('tip-content'); - - tipsButton.addEventListener('click', function(event) { - event.preventDefault(); - if (window.getComputedStyle(tipContent).display === 'none') { - tipContent.style.display = 'block'; - } else { - tipContent.style.display = 'none'; - } - }); - } catch (error) { console.error(error); } diff --git a/src/websites/AmazonPriceReplacer.js b/src/price-replacers/AmazonPriceReplacer.js similarity index 92% rename from src/websites/AmazonPriceReplacer.js rename to src/price-replacers/AmazonPriceReplacer.js index 45cdd22..2376c7e 100644 --- a/src/websites/AmazonPriceReplacer.js +++ b/src/price-replacers/AmazonPriceReplacer.js @@ -6,11 +6,11 @@ class AmazonPriceReplacer { } - replace(exchangeRates) { + replace(windowObj, node, exchangeRates) { - if (/^(www\.)?amazon\.[a-z\.]{2,5}$/.test(window.location.hostname)) { + if (/^(www\.)?amazon\.[a-z\.]{2,5}$/.test(windowObj.location.hostname)) { - let priceElements = document.querySelectorAll('.a-price'); + let priceElements = node.querySelectorAll('.a-price'); let detectedCurrency = false; priceElements.forEach(function(priceElement) { diff --git a/src/price-replacers/GenericPriceReplacer.js b/src/price-replacers/GenericPriceReplacer.js new file mode 100644 index 0000000..95d1cb5 --- /dev/null +++ b/src/price-replacers/GenericPriceReplacer.js @@ -0,0 +1,128 @@ +import { Currency } from '../Utilities' + +class GenericPriceReplacer { + + constructor() { + this.exchangeRates = null; + } + + + + + replace(windowObj, node, exchangeRates) { + + this.exchangeRates = exchangeRates; + + // If this node is an input field or contenteditable, skip processing + if (node.tagName && node.tagName.toLowerCase() === 'input') return; + if (node.isContentEditable) return; + + + // If this node has children, recursively process the children first + if (node.childNodes && node.childNodes.length > 0) { + Array.from(node.childNodes).forEach(child => this.replace(windowObj, child, exchangeRates)); + } + else { + let result = this.processMatches(node.textContent, exchangeRates); + if (result.replaced) { + node.textContent = result.text; + } + } + } + + + + + processMatches(text, exchangeRates) { + + + let replaced = false; + + if(!text) { + return {text, replaced}; + } + + let currencyToUse = Currency.getCurrencyBySymbol(text); + let regexToMatch = Currency.getCurrencyRegex(currencyToUse); + + if(!currencyToUse || !regexToMatch){ + return {text, replaced}; + } + + while (true) { + var matches = text.match(regexToMatch, "g"); + if (!matches) break; // exit the loop if no more matches + + console.log(regexToMatch); + console.log(text); + // find the longest match + var longestMatch = matches.reduce(function(a, b) { return a.length > b.length ? a : b; }); + + + if(longestMatch.length === 1){ + break; + } + + // process the longest match + var dogecoinAmount = this.convertToDogecoin(currencyToUse, longestMatch, regexToMatch, exchangeRates); + if (dogecoinAmount !== null) { + var fractionDigitsOptions = {}; + + if (dogecoinAmount < 1) { + //dogecoin did a thing, show 3 decimal points + fractionDigitsOptions.minimumFractionDigits = 3; + fractionDigitsOptions.maximumFractionDigits = 3; + } + else if (dogecoinAmount < 100) { + //only show decimal points if we have less than 100 + fractionDigitsOptions.minimumFractionDigits = 2; + fractionDigitsOptions.maximumFractionDigits = 2; + } + else { + fractionDigitsOptions.minimumFractionDigits = 0; + fractionDigitsOptions.maximumFractionDigits = 0; + } + + let index = text.indexOf(longestMatch); + if (index > 0 && text.charAt(index - 1) === '-') { + text = text.replace(longestMatch, ` Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); + } else { + text = text.replace(longestMatch, `Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); + } + + replaced = true; + } + + } + + return {text, replaced}; + } + + + + convertToDogecoin(currencyToUse, currencyStr, regexToMatch, exchangeRates) { + + //if we don't clone the regex we can have issues + const match = new RegExp(regexToMatch.source, regexToMatch.flags).exec(currencyStr); + + if (!match) { + return null; // not a valid currency string + } + + let matchIndex = 0; + + if([Currency.CNY, Currency.JPY].indexOf(currencyToUse) > -1) { + matchIndex = 1; + } + + // Remove the currency symbol, spaces, and commas, then parse as a float + const valueInCurrency = parseFloat(match[matchIndex].replace(/[^\d.]/g, '')); + + + // Convert to Dogecoin + return valueInCurrency / exchangeRates[currencyToUse]; + } + +} + +export { GenericPriceReplacer }; \ No newline at end of file diff --git a/src/websites/NewEggPriceReplacer.js b/src/price-replacers/NewEggPriceReplacer.js similarity index 90% rename from src/websites/NewEggPriceReplacer.js rename to src/price-replacers/NewEggPriceReplacer.js index 1be7036..0ff2ff9 100644 --- a/src/websites/NewEggPriceReplacer.js +++ b/src/price-replacers/NewEggPriceReplacer.js @@ -2,15 +2,16 @@ class NewEggPriceReplacer { - replace(exchangeRates) { + + replace(windowObj, node, exchangeRates) { let dogecoinValue = exchangeRates.usd; - if (/^(www\.)?newegg\.[a-z\.]{2,5}$/.test(window.location.hostname)) { + if (/^(www\.)?newegg\.[a-z\.]{2,5}$/.test(windowObj.location.hostname)) { - let priceElements = document.querySelectorAll('.price-current'); - let goodsPriceElements = document.querySelectorAll('.goods-price-current'); + let priceElements = node.querySelectorAll('.price-current'); + let goodsPriceElements = node.querySelectorAll('.goods-price-current'); priceElements.forEach(function(priceElement) { if(!priceElement.textContent.includes('Ð')){ diff --git a/src/tests.js b/src/tests.js new file mode 100644 index 0000000..1d8cbc7 --- /dev/null +++ b/src/tests.js @@ -0,0 +1,61 @@ + +import { AmazonPriceReplacer } from './price-replacers/AmazonPriceReplacer'; +import { NewEggPriceReplacer } from './price-replacers/NewEggPriceReplacer'; +import { GenericPriceReplacer } from './price-replacers/GenericPriceReplacer'; + +let exchangeRates = { + usd:0.060374, + eur:0.057129, + cny:0.441425, + jpy:9.0, + gbp:0.04966732, + inr:5.03, + rub:5.82 +}; + +let priceReplacers = []; + +priceReplacers.push(new AmazonPriceReplacer()); +priceReplacers.push(new NewEggPriceReplacer()); +priceReplacers.push(new GenericPriceReplacer()); + + + + +async function runAllTests() { + + let tests = document.getElementsByClassName("test"); + let mockWindow = { + location: { + hostname: "https://www.amazon.com/" + } + }; + + for (let test of tests) { + let expected = test.getElementsByClassName("expected")[0].textContent.trim(); + let resultElement = test.getElementsByClassName("result")[0]; + + priceReplacers.forEach(priceReplacer => { + priceReplacer.replace(mockWindow, resultElement, exchangeRates); + }); + + let result = resultElement.textContent.trim(); + + console.log(`${expected}|${result}`); + + if (expected === result) { + resultElement.classList.add("pass"); + } else { + resultElement.classList.add("fail"); + } + + // Add a 2.5-second lag between each test + await new Promise(resolve => setTimeout(resolve, 50)); + } + +} + + +document.getElementById("run-button").onclick = async function() { + await runAllTests(); +}; \ No newline at end of file diff --git a/tests/tests.html b/tests/tests.html new file mode 100644 index 0000000..1542379 --- /dev/null +++ b/tests/tests.html @@ -0,0 +1,319 @@ + + + + + Tests + + + + +

DogMoneyMode Testing Tool

+

tip: be sure to disabled the DogMoneyMode extension before running tests.

+ + + +
Basic Tests
+
+
Input
+
Expected
+
Result
+
+
+ +
+
$100.00
+
Ð1,656
+
$100.00
+
+ + +
+
€100.00
+
Ð1,750
+
€100.00
+
+ + +
+
100.00元
+
Ð227
+
100.00元
+
+ + +
+
1,000円
+
Ð111
+
1,000円
+
+ + +
+
£100.00
+
Ð2,013
+
£100.00
+
+ + +
+
₹1,000.00
+
Ð199
+
₹1,000.00
+
+ + +
+
₽1,000.00
+
Ð172
+
₽1,000.00
+
+
+ + + +
USD Tests
+
+
Input
+
Expected
+
Result
+
+
+
+
$1.00
+
Ð16.56
+
$1.00
+
+ +
+
$0.02
+
Ð0.331
+
$0.02
+
+ +
+
$.99
+
Ð16.40
+
$.99
+
+ +
+
$0.50
+
Ð8.28
+
$0.50
+
+ +
+
$1,999.99
+
Ð33,127
+
$1,999.99
+
+ +
+
$100,999
+
Ð1,672,889
+
$100,999
+
+ +
+
$1,234.56
+
Ð20,449
+
$1,234.56
+
+ +
+
$123
+
Ð2,037
+
$123
+
+ +
+
$12
+
Ð199
+
$12
+
+ +
+
$345.678
+
Ð5,726
+
$345.678
+
+ +
+
$7890
+
Ð130,685
+
$7890
+
+ +
+
$0.001
+
Ð0.017
+
$0.001
+
+ +
+
$0
+
Ð0.000
+
$0
+
+ +
+
$5,000,000.00
+
Ð82,817,107
+
$5,000,000.00
+
+ +
+
$75 to $350
+
Ð1,242 to Ð5,797
+
$75 to $350
+
+ +
+ + + +
EUR Tests
+
+
Input
+
Expected
+
Result
+
+
+
+
€1.00
+
Ð17.50
+
€1.00
+
+ +
+
€0.02
+
Ð0.350
+
€0.02
+
+ +
+
€.99
+
Ð17.33
+
€.99
+
+ +
+
€0.50
+
Ð8.75
+
€0.50
+
+ +
+
€1,999.99
+
Ð35,008
+
€1,999.99
+
+ +
+
€100,999
+
Ð1,767,911
+
€100,999
+
+ +
+
€1,234.56
+
Ð21,610
+
€1,234.56
+
+ +
+
€123
+
Ð2,153
+
€123
+
+ +
+
€12
+
Ð210
+
€12
+
+ +
+
€345.678
+
Ð6,051
+
€345.678
+
+ +
+
€7890
+
Ð138,108
+
€7890
+
+ +
+
€0.001
+
Ð0.018
+
€0.001
+
+ +
+
€0
+
Ð0.000
+
€0
+
+ +
+
€5,000,000.00
+
Ð87,521,224
+
€5,000,000.00
+
+ +
+
€75 to €350
+
Ð1,313 to Ð6,126
+
€75 to €350
+
+ +
+ + + + + + + diff --git a/tests/tests.js b/tests/tests.js new file mode 100644 index 0000000..5f2ce19 --- /dev/null +++ b/tests/tests.js @@ -0,0 +1,406 @@ +/******/ (() => { // webpackBootstrap +/******/ "use strict"; +var __webpack_exports__ = {}; + +;// CONCATENATED MODULE: ./src/Utilities.js +class Currency { + + static USD = "usd"; + static EUR = "eur"; + static CNY = "cny"; + static JPY = "jpy"; + static GBP = "gbp"; + static INR = "inr"; + static RUB = "rub"; + + static getCurrencyBySymbol(text) { + if (text.includes("$")) { + return "usd"; + } + if (text.includes("€")) { + return "eur"; + } + if (text.includes("元")) { + return "cny"; + } + if (text.includes("円")) { + return "jpy"; + } + if (text.includes("£")) { + return "gbp"; + } + if (text.includes("₹")) { + return "inr"; + } + if (text.includes("₽")) { + return "rub"; + } + return false; + } + + static getCurrencyRegex(currency) { + + let symbol = null; + let regexPattern = null; + + switch(currency) { + case "usd": + symbol = "$"; + break; + case "eur": + symbol = "€"; + break; + case "gbp": + symbol = "£"; + break; + case "inr": + symbol = "₹"; + break; + case "rub": + symbol = "₽"; + break; + case "cny": + symbol = "元".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${symbol}\\s*)`; + return new RegExp(regexPattern); + case "jpy": + symbol = "円".replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + regexPattern = `(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?|\\d*(?:\\.\\d*)?)(${symbol}\\s*)`; + return new RegExp(regexPattern); + default: + return null; + } + regexPattern = `(? 0) { + // Remove currency symbol and commas before conversion to float + let fiat = offscreenElement.textContent.replace(currencySymbol, '').replace(/,/g, ''); + let dogefy = (parseFloat(fiat) / parseFloat(exchangeRates[detectedCurrency])).toLocaleString('en', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + + offscreenElement.textContent = 'Ð' + dogefy; + + if (currencySymbolElement) { + currencySymbolElement.textContent = 'Ð'; + } + + let [whole, fraction] = dogefy.split('.'); + visiblePriceElements[0].textContent = whole + visiblePriceElements[0].querySelector('.a-price-decimal').textContent; + visiblePriceElements[1].textContent = fraction; + } + } + + + + }); + + } + } + +} + + +;// CONCATENATED MODULE: ./src/price-replacers/NewEggPriceReplacer.js + +class NewEggPriceReplacer { + + + + replace(windowObj, node, exchangeRates) { + + let dogecoinValue = exchangeRates.usd; + + if (/^(www\.)?newegg\.[a-z\.]{2,5}$/.test(windowObj.location.hostname)) { + + + let priceElements = node.querySelectorAll('.price-current'); + let goodsPriceElements = node.querySelectorAll('.goods-price-current'); + + priceElements.forEach(function(priceElement) { + if(!priceElement.textContent.includes('Ð')){ + let strongElement = priceElement.querySelector('strong'); + let supElement = priceElement.querySelector('sup'); + let dollarSymbolIndex = Array.from(priceElement.childNodes).findIndex(node => node.nodeType === 3 && node.nodeValue.includes('$')); + + if (strongElement && supElement && dollarSymbolIndex > -1) { + let fiat = strongElement.textContent.replace(/,/g, '') + '.' + supElement.textContent.replace(/,/g, ''); + let dogefy = (parseFloat(fiat) / parseFloat(dogecoinValue)).toLocaleString('en', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + + let [whole, fraction] = dogefy.split('.'); + strongElement.textContent = whole; + supElement.textContent = fraction; + + let textNode = priceElement.childNodes[dollarSymbolIndex]; + textNode.nodeValue = textNode.nodeValue.replace(fiat_currency_symbol, 'Ð'); + } + } + }); + + + goodsPriceElements.forEach(function(priceElement) { + if(!priceElement.textContent.includes('Ð')){ + let strongElement = priceElement.querySelector('.goods-price-value strong'); + let supElement = priceElement.querySelector('.goods-price-value sup'); + let currencySymbolElement = priceElement.querySelector('.goods-price-symbol'); + + if (strongElement && supElement) { + let fiat = strongElement.textContent.replace(/,/g, '') + '.' + supElement.textContent.replace(/,/g, ''); + let dogefy = (parseFloat(fiat) / parseFloat(dogecoinValue)).toLocaleString('en', { + minimumFractionDigits: 2, + maximumFractionDigits: 2 + }); + + let [whole, fraction] = dogefy.split('.'); + strongElement.textContent = whole; + supElement.textContent = fraction; + + if (currencySymbolElement) { + currencySymbolElement.textContent = 'Ð'; + } + } + } + }); + } + + + } + +} + + +;// CONCATENATED MODULE: ./src/price-replacers/GenericPriceReplacer.js + + +class GenericPriceReplacer { + + constructor() { + this.exchangeRates = null; + } + + + + + replace(windowObj, node, exchangeRates) { + + this.exchangeRates = exchangeRates; + + // If this node is an input field or contenteditable, skip processing + if (node.tagName && node.tagName.toLowerCase() === 'input') return; + if (node.isContentEditable) return; + + + // If this node has children, recursively process the children first + if (node.childNodes && node.childNodes.length > 0) { + Array.from(node.childNodes).forEach(child => this.replace(windowObj, child, exchangeRates)); + } + else { + let result = this.processMatches(node.textContent, exchangeRates); + if (result.replaced) { + node.textContent = result.text; + } + } + } + + + + + processMatches(text, exchangeRates) { + + + let replaced = false; + + if(!text) { + return {text, replaced}; + } + + let currencyToUse = Currency.getCurrencyBySymbol(text); + let regexToMatch = Currency.getCurrencyRegex(currencyToUse); + + if(!currencyToUse || !regexToMatch){ + return {text, replaced}; + } + + while (true) { + var matches = text.match(regexToMatch, "g"); + if (!matches) break; // exit the loop if no more matches + + console.log(regexToMatch); + console.log(text); + // find the longest match + var longestMatch = matches.reduce(function(a, b) { return a.length > b.length ? a : b; }); + + + if(longestMatch.length === 1){ + break; + } + + // process the longest match + var dogecoinAmount = this.convertToDogecoin(currencyToUse, longestMatch, regexToMatch, exchangeRates); + if (dogecoinAmount !== null) { + var fractionDigitsOptions = {}; + + if (dogecoinAmount < 1) { + //dogecoin did a thing, show 3 decimal points + fractionDigitsOptions.minimumFractionDigits = 3; + fractionDigitsOptions.maximumFractionDigits = 3; + } + else if (dogecoinAmount < 100) { + //only show decimal points if we have less than 100 + fractionDigitsOptions.minimumFractionDigits = 2; + fractionDigitsOptions.maximumFractionDigits = 2; + } + else { + fractionDigitsOptions.minimumFractionDigits = 0; + fractionDigitsOptions.maximumFractionDigits = 0; + } + + let index = text.indexOf(longestMatch); + if (index > 0 && text.charAt(index - 1) === '-') { + text = text.replace(longestMatch, ` Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); + } else { + text = text.replace(longestMatch, `Ð${dogecoinAmount.toLocaleString('en-US', fractionDigitsOptions)}`); + } + + replaced = true; + } + + } + + return {text, replaced}; + } + + + + convertToDogecoin(currencyToUse, currencyStr, regexToMatch, exchangeRates) { + + //if we don't clone the regex we can have issues + const match = new RegExp(regexToMatch.source, regexToMatch.flags).exec(currencyStr); + + if (!match) { + return null; // not a valid currency string + } + + let matchIndex = 0; + + if([Currency.CNY, Currency.JPY].indexOf(currencyToUse) > -1) { + matchIndex = 1; + } + + // Remove the currency symbol, spaces, and commas, then parse as a float + const valueInCurrency = parseFloat(match[matchIndex].replace(/[^\d.]/g, '')); + + + // Convert to Dogecoin + return valueInCurrency / exchangeRates[currencyToUse]; + } + +} + + +;// CONCATENATED MODULE: ./src/tests.js + + + + + +let exchangeRates = { + usd:0.060374, + eur:0.057129, + cny:0.441425, + jpy:9.0, + gbp:0.04966732, + inr:5.03, + rub:5.82 +}; + +let priceReplacers = []; + +priceReplacers.push(new AmazonPriceReplacer()); +priceReplacers.push(new NewEggPriceReplacer()); +priceReplacers.push(new GenericPriceReplacer()); + + + + +async function runAllTests() { + + let tests = document.getElementsByClassName("test"); + let mockWindow = { + location: { + hostname: "https://www.amazon.com/" + } + }; + + for (let test of tests) { + let expected = test.getElementsByClassName("expected")[0].textContent.trim(); + let resultElement = test.getElementsByClassName("result")[0]; + + priceReplacers.forEach(priceReplacer => { + priceReplacer.replace(mockWindow, resultElement, exchangeRates); + }); + + let result = resultElement.textContent.trim(); + + console.log(`${expected}|${result}`); + + if (expected === result) { + resultElement.classList.add("pass"); + } else { + resultElement.classList.add("fail"); + } + + // Add a 2.5-second lag between each test + await new Promise(resolve => setTimeout(resolve, 50)); + } + +} + + +document.getElementById("run-button").onclick = async function() { + await runAllTests(); +}; +/******/ })() +; \ No newline at end of file diff --git a/tests/usd.html b/tests/usd.html deleted file mode 100644 index 1d1e136..0000000 --- a/tests/usd.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - USD Test Prices - - - -
Test 1 - (USD1.00): $1.00
-
Test 2 - (USD0.02): $0.02
-
Test 3 - (USD.99): $.99
-
Test 4 - (USD0.50): $0.50
-
Test 5 - (USD 1,999.99): $ 1,999.99
-
Test 6 - (USD 100,999): $ 100,999
-
Test 7 - (USD1,234.56): $1,234.56
-
Test 8 - (USD 123): $ 123
-
Test 9 - (USD12): $12
-
Test 10 - (USD 345.678): $ 345.678
-
Test 11 - (USD 7890): $ 7890
-
Test 12 - (USD 0.001): $ 0.001
-
Test 13 - (USD0): $0
-
Test 14 - (USD 5,000,000.00): $ 5,000,000.00
-
Test 15 - $75 to $350
-
Test 16 - The typical range for exterminator costs is from $111 to $261, with a national average of $176. The main cost factors for hiring an exterminator ...
-
Test 17 - Professional mouse extermination will generally cost between $200 and $600. Your final pricing will depend on factors such as the infestation ...
- - - diff --git a/webpack.test.config.js b/webpack.test.config.js new file mode 100644 index 0000000..40433ee --- /dev/null +++ b/webpack.test.config.js @@ -0,0 +1,14 @@ +const path = require('path'); + +module.exports = { + entry: { + content: './src/tests.js' + }, + optimization: { + minimize: false + }, + output: { + filename: 'tests.js', + path: __dirname + '/tests/', + }, +}; \ No newline at end of file