diff --git a/README.md b/README.md index 0893be2..66a0871 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,7 @@ Extension chrome pour Equideow qui permet d'obtenir plus facilement les différentes informations du jeux comme le blup, le PG, les compétences mais aussi d'afficher un coefficient de victoire pour mieux gérer ses blups notamment -Il s'agit la des nouvelles et anciennes version de l'extension trouvable en stores. -Ainsi que de la version vX.Y.Z qui est ma version personnel (incluant des features de l'abonnement VIP). -La version vX.Y.Z n'arrivera jamais dans les store et est buggué et non fiable. +Il s'agit la des nouvelles et anciennes version de l'extension trouvable en stores. --- ## Better Howrse @@ -13,11 +11,9 @@ Small chrome extension for Howrse that allow you to get more informations about your horses and competition difficulties. Here are available all recents and pasts updates of the browser extension that you can find on the stores. -There is also the vX.Y.Z which is my personnal version of the extension (that adds some VIP sub features). -The vX.Y.Z will never made it to the stores and is buggy and unreliable --- -[![Last Version](https://img.shields.io/badge/last%20version-v1.4.0-informational)](#) +[![Last Version](https://img.shields.io/badge/last%20version-v2.0.0-informational)](#) [![DeepScan grade](https://deepscan.io/api/teams/17688/projects/21040/branches/592899/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=17688&pid=21040&bid=592899) [![Chrome Web Store](https://img.shields.io/chrome-web-store/v/gkopbgamdhaolbjalfcbmbjkjcmgffjp)](https://chrome.google.com/webstore/detail/better-equideow/gkopbgamdhaolbjalfcbmbjkjcmgffjp) diff --git a/_locales/no/messages.json b/_locales/no/messages.json new file mode 100644 index 0000000..7dc5700 --- /dev/null +++ b/_locales/no/messages.json @@ -0,0 +1,10 @@ +{ + "appName": { + "message": "Better Howrse", + "description": "Navnet på utvidelsen." + }, + "appDesc": { + "message": "Denne utvidelsen viser mer informasjon i spillet om hester og konkurranser for å få deg til å føle deg mer komfortabel når du spiller.", + "description": "Beskrivelse av utvidelsen.Beskrivelse av utvidelsen." + } +} \ No newline at end of file diff --git a/competitionsDiffDisplay.js b/competitionsDiffDisplay.js deleted file mode 100644 index 3666c33..0000000 --- a/competitionsDiffDisplay.js +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2022. Gwen Tripet-Costet - * This file is part of Better Equideow (Better Howrse). - * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -let isFrenchApp; - -if (window.location.host.match(/.+equideow.+/)) { - isFrenchApp = true; -} - -const reducer = (a, b) => a + b; - -let age; -let staminaTotalBonusValue; -let speedTotalBonusValue; -let dressageTotalBonusValue; -let gallopTotalBonusValue; -let trotTotalBonusValue; -let jumpingTotalBonusValue; - -function convert(x) { - return x.join(',').replace(/[^0-9\.,]/g, '').split(',').map((i) => Number(i)); -} - -function calcPoints(primarySkill, secondarySkill, lastSkill) { - return (primarySkill * 0.45 + secondarySkill * 0.3 + lastSkill * 0.2 + age * 0.05); -} - -function competitionsDiffDisplay() { - const characteristics = document.getElementById('characteristics-body-content'); - const ageStr = characteristics.getElementsByClassName('align-right')[0].textContent; - const ageStrArr = ageStr.match(/[1-9]\d*/g); - let ageIntArr; - - if (ageStrArr) { - ageIntArr = ageStrArr.map((i) => Number(i)); - } else return; - - if (ageIntArr.length > 1) { - age = ageIntArr[0] * 12 + ageIntArr[1]; - } else if (ageIntArr.length === 1) { - age = ageIntArr[0] * 12; - } else { - return; - } - - const stamina = parseFloat(document.getElementById('enduranceValeur').innerText); - const speed = parseFloat(document.getElementById('vitesseValeur').innerText); - const dressage = parseFloat(document.getElementById('dressageValeur').innerText); - const gallop = parseFloat(document.getElementById('galopValeur').innerText); - const trot = parseFloat(document.getElementById('trotValeur').innerText); - const jumping = parseFloat(document.getElementById('sautValeur').innerText); - - const bonusHtml = document.getElementById('bonuses-body-content'); - - - if (!bonusHtml.outerHTML.match(/(Ce cheval n'a aucun bonus.|This horse doesn't have any bonuses.|Cette jument n'a aucun bonus.|This mare doesn't have any bonuses.)/)) { - const staminaBonuses = bonusHtml.outerHTML.match(/(endurance|stamina).+?[1-9]\d*/g); - const staminaBonusesValues = convert(staminaBonuses); - - - const speedBonuses = bonusHtml.outerHTML.match(/(vitesse|speed).+?[1-9]\d*/g); - const speedBonusesValues = convert(speedBonuses); - - - const dressageBonuses = bonusHtml.outerHTML.match(/dressage.+?[1-9]\d*/g); - const dressageBonusesValues = convert(dressageBonuses); - - - const gallopBonuses = bonusHtml.outerHTML.match(/(galop|gallop).+?[1-9]\d*/g); - const gallopBonusesValues = convert(gallopBonuses); - - const trotBonuses = bonusHtml.outerHTML.match(/trot.+?[1-9]\d*/g); - const trotBonusesValues = convert(trotBonuses); - - - const jumpingBonuses = bonusHtml.outerHTML.match(/(saut|jumping).+?[1-9]\d*/g); - const jumpingBonusesValues = convert(jumpingBonuses); - - // all bonuses - - staminaTotalBonusValue = staminaBonusesValues.reduce(reducer); - speedTotalBonusValue = speedBonusesValues.reduce(reducer); - dressageTotalBonusValue = dressageBonusesValues.reduce(reducer); - gallopTotalBonusValue = gallopBonusesValues.reduce(reducer); - trotTotalBonusValue = trotBonusesValues.reduce(reducer); - jumpingTotalBonusValue = jumpingBonusesValues.reduce(reducer); - } - - const totalStamina = stamina + staminaTotalBonusValue; - const totalSpeed = speed + speedTotalBonusValue; - const totalDressage = dressage + dressageTotalBonusValue; - const totalGallop = gallop + gallopTotalBonusValue; - const totalTrot = trot + trotTotalBonusValue; - const totalJumping = jumping + jumpingTotalBonusValue; - - const competitionsHTML = document.getElementById('competition-body-content'); - const competitionTitle = document.getElementById('competition-head-title'); - const competitions = competitionsHTML.querySelectorAll('a'); - - competitionTitle.style.display = 'flex'; - competitionTitle.style.flexFlow = 'column nowrap'; - const hintHTML = `${isFrenchApp ? 'Plus le coeff est élevé plus il y a de chances de gagner' : 'The higher the coefficient, the greater the chance of winning'}`; - const parsedHintHtml = parser.parseFromString(hintHTML, `text/html`); - const hintTags = parsedHintHtml.getElementsByTagName(`span`); - - for (const tag of hintTags) { - competitionTitle.appendChild(tag); - } - - competitions.forEach((competition) => { - const diffDiv = document.createElement('div'); - diffDiv.style.margin = '0 0 0.2em 0'; - diffDiv.style.color = '#993322'; - - let coeff; - - switch (competition.innerText) { - case 'Trot': - coeff = calcPoints(totalTrot, totalSpeed, totalDressage) / trot; - break; - case 'Galop': - case 'Gallop': - coeff = calcPoints(totalGallop, totalSpeed, totalDressage) / gallop; - break; - case 'Dressage': - coeff = calcPoints(totalDressage, totalTrot, totalGallop) / dressage; - break; - case 'Cross': - case 'Cross-country': - coeff = calcPoints(totalStamina, totalDressage, totalJumping) / stamina; - break; - case 'Cso': - case 'Show jumping': - coeff = calcPoints(totalJumping, totalDressage, totalSpeed) / jumping; - break; - case 'Barrel racing': - coeff = calcPoints(totalSpeed, totalStamina, totalGallop) / speed; - break; - case 'Cutting': - coeff = calcPoints(totalStamina, totalDressage, totalSpeed) / stamina; - break; - case 'Trail class': - coeff = calcPoints(totalDressage, totalTrot, totalJumping) / dressage; - break; - case 'Reining': - coeff = calcPoints(totalGallop, totalDressage, totalStamina) / gallop; - break; - case 'Western pleasure': - coeff = calcPoints(totalTrot, totalStamina, totalDressage) / trot; - break; - } - - if (coeff) { - const diffDivHTML = `Coeff: ${coeff.toFixed(2)}`; - - const parsedDiffDivHTML = parser.parseFromString(diffDivHTML, `text/html`); - const diffDivTags = parsedDiffDivHTML.getElementsByTagName(`span`); - - for (const tag of diffDivTags) { - diffDiv.appendChild(tag); - } - competition.parentNode.insertBefore(diffDiv, competition.nextSibling); - } - }); -} - -if (window.location.href.indexOf('elevage/chevaux/cheval') > -1) { - setTimeout(() => { - competitionsDiffDisplay(); - }, 250); -} diff --git a/foodSelect.js b/foodSelect.js new file mode 100644 index 0000000..91912fc --- /dev/null +++ b/foodSelect.js @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022. Gwen Tripet-Costet + * This file is part of Better Equideow (Better Howrse). + * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +class FoodSelect { + constructor() { + this.feedingBtn = this.setHTMLElement("#boutonNourrir") + this.haySlider = this.setHTMLElement("#haySlider") || null // entire bloc containing ol, script, li, span + this.haySelectors = this.haySlider?.getElementsByTagName("span") // all span selectors from 0 to 20 + this.oatsSlider = this.setHTMLElement("#oatsSlider") || null + this.oatsSelectors = this.oatsSlider?.getElementsByTagName("span") + } + + setHTMLElement(element) { + return document.querySelector(element) + }; + + getFoodIndex(foodNode) { + const foodValue = foodNode.innerHTML + const foodIndex = parseInt(foodValue) + return foodIndex + } + + + async run() { + // will get the value eg: XX/20 for hay and X/16 for oats. + const fourrageNode = document.getElementsByClassName( + "section-fourrage section-fourrage-target" + ) + const avoineNode = document.getElementsByClassName( + "section-avoine section-avoine-target" + ) + + if (fourrageNode.length > 0) { + const fourrageIndex = this.getFoodIndex(fourrageNode[0]) + this.haySelectors[fourrageIndex].click() + } + + if (avoineNode.length > 0) { + const avoineIndex = this.getFoodIndex(avoineNode[0]) + this.oatsSelectors[avoineIndex].click() + } + } +} + +if (window.location.href.indexOf("elevage/chevaux/cheval?") > -1) { + const foodSelect = new FoodSelect() + if (foodSelect.feedingBtn !== null) + foodSelect.feedingBtn.addEventListener("click", () => { + foodSelect.run() + }) + + /** + * @description generate a new FoodSelect() because after #loading style change, + * it seems like the different this.elements from foodSelect are erased .. + * @todo fix it... + */ + const startObserver = () => { + observer.start().then(() => { + let newFoodSelect = new FoodSelect() + newFoodSelect.run() + startObserver() + }) + } + + startObserver() +} \ No newline at end of file diff --git a/horseStats.js b/horseStats.js new file mode 100644 index 0000000..c575c06 --- /dev/null +++ b/horseStats.js @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022. Gwen Tripet-Costet + * This file is part of Better Equideow (Better Howrse). + * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +class HorseStats { + constructor() { + this.lang = translation.getLang(window.location.href) + this.characteristicsContainer = document.getElementById('characteristics-body-content') + this.bonusContainer = document.getElementById('bonuses-body-content') + this.competitionsContainer = document.getElementById('competition-body-content') + this.competitions = this.competitionsContainer.querySelectorAll('a') + this.competitionTitle = document.getElementById('competition-head-title') + + this.parser = new DOMParser() + this.age = this.calcAge() + + this.staminaBase = this.calcStatBase('enduranceValeur') + this.staminaBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'stamina')}).+?[1-9]\d*`, "g")) + this.staminaTotal = this.calcStatTotal(this.staminaBase, this.staminaBonuses) + + this.speedBase = this.calcStatBase('vitesseValeur') + this.speedBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'speed')}).+?[1-9]\d*`, "g")) + this.speedTotal = this.calcStatTotal(this.speedBase, this.speedBonuses) + + this.dressageBase = this.calcStatBase('dressageValeur') + this.dressageBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'dressage')}).+?[1-9]\d*`, "g")) + this.dressageTotal = this.calcStatTotal(this.dressageBase, this.dressageBonuses) + + this.gallopBase = this.calcStatBase('galopValeur') + this.gallopBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'gallop')}).+?[1-9]\d*`, "g")) + this.gallopTotal = this.calcStatTotal(this.gallopBase, this.gallopBonuses) + + this.trotBase = this.calcStatBase('trotValeur') + this.trotBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'trot')}).+?[1-9]\d*`, "g")) + this.trotTotal = this.calcStatTotal(this.trotBase, this.trotBonuses) + + this.jumpingBase = this.calcStatBase('sautValeur') + this.jumpingBonuses = this.calcStatBonus(new RegExp(`(${translation.get(this.lang, 'stat', 'jumping')}).+?[1-9]\d*`, "g")) + this.jumpingTotal = this.calcStatTotal(this.jumpingBase, this.jumpingBonuses) + } + + convert(value) { + if (value !== null) { + return value.join(',').replace(/[^0-9\.,]/g, '').split(',').map((i) => Number(i)) + } + } + + calcAge() { + const ageStr = this.characteristicsContainer.getElementsByClassName('align-right')[0].textContent + const ageStrArr = ageStr.match(/[1-9]\d*/g) + + let ageIntArr + if (ageStrArr) { + ageIntArr = ageStrArr.map((i) => Number(i)) + } else return + + if (ageIntArr.length > 1) { + return this.age = ageIntArr[0] * 12 + ageIntArr[1] + } else if (ageIntArr.length === 1) { + return this.age = ageIntArr[0] * 12 + } else { + return + } + } + + calcStatBase(stat) { + return parseFloat(document.getElementById(stat).innerText) + } + + calcStatBonus(stat) { + if (this.bonusContainer.childElementCount !== 4) { + const statBonuses = this.bonusContainer.outerHTML.match(stat) + return this.convert(statBonuses) + } + } + + calcStatTotal(statBase, statBonuses) { + const totalBonusValue = statBonuses?.reduce((a, b) => a + b) || 0 + return statBase + totalBonusValue + } + + calcCoeff(primarySkill, secondarySkill, lastSkill) { + return (primarySkill * 0.45 + secondarySkill * 0.3 + lastSkill * 0.2 + this.age * 0.05) + } + + competitionsDiffDisplay() { + this.competitionTitle.style.display = 'flex' + this.competitionTitle.style.flexFlow = 'column nowrap' + const hintHTML = ` ${this.isFrenchApp ? 'Plus le coeff est élevé plus il y a de chances de gagner' : 'The higher the coefficient, the greater the chance of winning'} ` + const parsedHintHtml = this.parser.parseFromString(hintHTML, `text/html`) + const hintTags = parsedHintHtml.getElementsByTagName(`span`) + + for (const tag of hintTags) { + this.competitionTitle.appendChild(tag) + } + + this.competitions.forEach((competition) => { + const diffDiv = document.createElement('div') + diffDiv.style.margin = '0 0 0.2em 0' + diffDiv.style.color = '#993322' + + let coeff + + switch (competition.innerText) { + case translation.get(this.lang, 'competition', 'trot'): + coeff = this.calcCoeff(this.trotTotal, this.speedTotal, this.dressageTotal) / this.trotBase + break + case translation.get(this.lang, 'competition', 'gallop'): + coeff = this.calcCoeff(this.gallopTotal, this.speedTotal, this.dressageTotal) / this.gallopBase + break + case translation.get(this.lang, 'competition', 'dressage'): + coeff = this.calcCoeff(this.dressageTotal, this.trotTotal, this.gallopTotal) / this.dressageBase + break + case translation.get(this.lang, 'competition', 'crossCountry'): + coeff = this.calcCoeff(this.staminaTotal, this.dressageTotal, this.jumpingTotal) / this.staminaBase + break + case translation.get(this.lang, 'competition', 'showJumping'): + coeff = this.calcCoeff(this.jumpingTotal, this.dressageTotal, this.speedTotal) / this.jumpingBase + break + case translation.get(this.lang, 'competition', 'barrelRacing'): + coeff = this.calcCoeff(this.speedTotal, this.staminaTotal, this.gallopTotal) / this.speedBase + break + case translation.get(this.lang, 'competition', 'cutting'): + coeff = this.calcCoeff(this.staminaTotal, this.dressageTotal, this.speedTotal) / this.staminaBase + break + case translation.get(this.lang, 'competition', 'trailClass'): + coeff = this.calcCoeff(this.dressageTotal, this.trotTotal, this.jumpingTotal) / this.dressageBase + break + case translation.get(this.lang, 'competition', 'reining'): + coeff = this.calcCoeff(this.gallopTotal, this.dressageTotal, this.staminaTotal) / this.gallopBase + break + case translation.get(this.lang, 'competition', 'westernPleasure'): + coeff = this.calcCoeff(this.trotTotal, this.staminaTotal, this.dressageTotal) / this.trotBase + break + } + + if (coeff) { + const diffDivHTML = ` Coeff: ${coeff.toFixed(2)} ` + + const parsedDiffDivHTML = this.parser.parseFromString(diffDivHTML, `text/html`) + const diffDivTags = parsedDiffDivHTML.getElementsByTagName(`span`) + + for (const tag of diffDivTags) { + diffDiv.appendChild(tag) + } + competition.parentNode.insertBefore(diffDiv, competition.nextSibling) + } + }) + } + + run() { + this.competitionsDiffDisplay() + } +} + +if (window.location.href.indexOf('elevage/chevaux/cheval') > -1) { + const horseStats = new HorseStats() + horseStats.run() +} diff --git a/loadingDisplayObserver.js b/loadingDisplayObserver.js new file mode 100644 index 0000000..f7a20eb --- /dev/null +++ b/loadingDisplayObserver.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022. Gwen Tripet-Costet + * This file is part of Better Equideow (Better Howrse). + * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License along with this program. If not, see . + */ + +class LoadingDisplayObserver { + constructor() { + this.targetNode = document.querySelector('#loading'); + this.config = { attributes: true, attributeFilter: ['style'] }; + } + start() { + return new Promise((resolve) => { + this.observer = new MutationObserver((mutationsList) => { + for (let mutation of mutationsList) { + if (mutation.type === 'attributes' && mutation.attributeName === 'style') { + let element = mutation.target; + let display = window.getComputedStyle(element, null).getPropertyValue("display"); + if (display === "none") { + resolve(); + } + } + } + }); + this.observer.observe(this.targetNode, this.config); + }); + } + stop() { + this.observer.disconnect(); + } +} + +const observer = new LoadingDisplayObserver(); \ No newline at end of file diff --git a/manifest.json b/manifest.json index a9bdf7f..c16f2df 100644 --- a/manifest.json +++ b/manifest.json @@ -2,12 +2,8 @@ "name": "__MSG_appName__", "description": "__MSG_appDesc__", "default_locale": "fr", - "version": "1.4.0", + "version": "2.0.0", "manifest_version": 3, - "action": { - "default_title": "Click to see your horse sells", - "default_popup": "popup.html" - }, "author": "TC-Dev", "icons": { "16": "/images/icon-16x16.png", @@ -17,9 +13,19 @@ }, "content_scripts": [ { - "matches": ["*://*.equideow.com/*", "*://*.howrse.com/*"], + "matches": [ + "*://*.equideow.com/*", + "*://*.howrse.com/*", + "*://*.howrse.no/*" + ], "run_at": "document_end", - "js": ["moreInfos.js", "competitionsDiffDisplay.js", "foodSelect.js"] + "js": [ + "translation.js", + "loadingDisplayObserver.js", + "moreInfos.js", + "horseStats.js", + "foodSelect.js" + ] } ] -} +} \ No newline at end of file diff --git a/moreInfos.js b/moreInfos.js index cc21fe2..b36b6ef 100644 --- a/moreInfos.js +++ b/moreInfos.js @@ -6,250 +6,158 @@ * You should have received a copy of the GNU General Public License along with this program. If not, see . */ -const regexpBlupHtml = - /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?<\/strong><\/td>/; -const regexpPGHtml = - /Total.+[+-]?(?=\d*[.eE])(?=\.?\d)\d*\.?\d*(?:[eE][+-]?\d+)?<\/strong>/; -const regexpSkillsHtml = - /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?<\/span>/; -const regexpPetHtmlOthers = - /

.*<\/h3>/; -const regexpPetHtmlSelf = - /

.*<\/h3>/; - -const regexpFloat = /[+-]?(?=\d*[.eE])(?=\.?\d)\d*\.?\d*(?:[eE][+-]?\d+)?/; -const regexpValue = /\>(.*?)\ { - return new Promise((resolve) => { - const styleObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.target.style.display === "none") { - resolve(); - } - }); - }); - - styleObserver.observe(loader, { - attributes: true, - attributeFilter: ["style"], - }); - }); -}; - -// was used as test but could be useful in the future depending on URLparams update -/* const detectSelectedTab = () => { - return new Promise((resolve) => { - const childChangeObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - if (mutation.target.className.match("selected")) { - // first time clicking on horse = empty 'style', then 'style="display: block;"' - resolve("horse"); - } else { - resolve("other"); - } - }); - }); - - childChangeObserver.observe(tabChevaux, { - attributes: true, - attributeFilter: ["class"], - }); - }); -}; */ - -function querySelectorAllLive(el, selector) { - const result = Array.prototype.slice.call(el.querySelectorAll(selector)); - - const nodeObserver = new MutationObserver((mutations) => { - mutations.forEach((mutation) => { - [].forEach.call(mutation.addedNodes, (node) => { - if (node.nodeType === NODE.ELEMENT_NODE && node.matches(selector)) { - result.push(node); - nodeObserver.disconnect(); - } - }); - }); - }); - - nodeObserver.observe(el, { childList: true, subtree: true }); - - return result; -} +class MoreInfos { + constructor() { + this.regexpBlupHtml = + /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?<\/strong><\/td>/ + this.regexpPGHtml = + /Total.+[+-]?(?=\d*[.eE])(?=\.?\d)\d*\.?\d*(?:[eE][+-]?\d+)?<\/strong>/ + this.regexpSkillsHtml = + /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?<\/span>/ + this.regexpPetHtmlOthers = + /

.*<\/h3>/ + this.regexpPetHtmlSelf = + /

.*<\/h3>/ + + this.regexpFloat = /[+-]?(?=\d*[.eE])(?=\.?\d)\d*\.?\d*(?:[eE][+-]?\d+)?/ + this.regexpValue = /\>(.*?)\ -1 + this.sellsLocation = window.location.href.indexOf("marche/vente") > -1 + this.boxesLocation = window.location.href.indexOf("centre/box") > -1 + this.communauteLocation = + window.location.href.indexOf("communaute/?type=tab") > -1 + + this.locationAllowed = this.elevageLocation || this.sellsLocation || this.boxesLocation || this.communauteLocation + } + + querySelectorAllLive(element, selector) { + const result = Array.prototype.slice.call(element.querySelectorAll(selector)) -const parser = new DOMParser(); + const nodeObserver = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + [].forEach.call(mutation.addedNodes, (node) => { + if (node.nodeType === NODE.ELEMENT_NODE && node.matches(selector)) { + result.push(node) + nodeObserver.disconnect() + } + }) + }) + }) -function parseHTML(targetDiv, html, selector) { - const parsedTargetDivHTML = parser.parseFromString(html, `text/html`); - const targetDivTags = querySelectorAllLive(parsedTargetDivHTML, selector); + nodeObserver.observe(element, { childList: true, subtree: true }) - for (const tag of targetDivTags) { - targetDiv.appendChild(tag); + return result } -} -const elevageLocation = - window.location.href.indexOf("elevage/chevaux/?elevage") > -1; -const sellsLocation = window.location.href.indexOf("marche/vente") > -1; -const boxesLocation = window.location.href.indexOf("centre/box") > -1; -const communauteLocation = - window.location.href.indexOf("communaute/?type=tab") > -1; + parseHTML(targetDiv, html, selector) { + const parsedTargetDivHTML = this.parser.parseFromString(html, `text/html`) + const targetDivTags = this.querySelectorAllLive(parsedTargetDivHTML, selector) -let locationAllowed; -if (elevageLocation || sellsLocation || boxesLocation || communauteLocation) { - locationAllowed = true; -} + for (const tag of targetDivTags) { + targetDiv.appendChild(tag) + } + } -function moreInfos() { - const isDetailedView = document.getElementById("detail-chevaux"); - const names = document.getElementsByClassName("horsename"); - const namesArr = Array.from(names); - - namesArr.forEach((name) => { - fetch(name.href) - .then((res) => res.text()) - .then((data) => { - const infoDiv = document.createElement("div"); - infoDiv.className = "infodiv"; - infoDiv.style.display = "flex"; - infoDiv.style.flexFlow = "column nowrap"; - infoDiv.style.margin = ".25em 0"; - infoDiv.style.color = "#993322"; - - if (!boxesLocation && locationAllowed) { - const blupHtml = data.match(regexpBlupHtml); - const PetHtml = - data.match(regexpPetHtmlOthers) || data.match(regexpPetHtmlSelf); - if (blupHtml) { - const blupFloat = blupHtml[0].match(regexpFloat); - parseHTML( - infoDiv, - '

Blup: ' + + run() { + const isDetailedView = document.getElementById("detail-chevaux") + const names = document.getElementsByClassName("horsename") + const namesArr = Array.from(names) + + namesArr.forEach((name) => { + fetch(name.href) + .then((res) => res.text()) + .then((data) => { + const infoDiv = document.createElement("div") + infoDiv.className = "infodiv" + infoDiv.style.display = "flex" + infoDiv.style.flexFlow = "column nowrap" + infoDiv.style.margin = ".25em 0" + infoDiv.style.color = "#993322" + + if (!this.boxesLocation && this.locationAllowed) { + const blupHtml = data.match(this.regexpBlupHtml) + const PetHtml = + data.match(this.regexpPetHtmlOthers) || data.match(this.regexpPetHtmlSelf) + if (blupHtml) { + const blupFloat = blupHtml[0].match(this.regexpFloat) + this.parseHTML( + infoDiv, + '

Blup: ' + blupFloat[0] + "

", - "p" - ); - } - if (PetHtml) { - const PetName = PetHtml[0].match(regexpValue); - parseHTML( - infoDiv, - `

${ - isFrenchApp ? "Familier: " : "Pet: " - }${PetName[1]}

`, - "p" - ); + "p" + ) + } + + if (PetHtml) { + const PetName = PetHtml[0].match(this.regexpValue) + this.parseHTML( + infoDiv, + `

${translation.get(this.lang, 'other', 'pet')}${PetName[1]}

`, + "p" + ) + } + + // pegase / VIP + if ( + !isDetailedView && + !(this.sellsLocation) + ) { + const PGHtml = data.match(this.regexpPGHtml) + if (PGHtml) { + const PGFloat = PGHtml[0].match(this.regexpFloat) + this.parseHTML( + infoDiv, + `

${translation.get(this.lang, 'other', 'pg')}${PGFloat[0]}

`, + "p" + ) + } + } } - // pegase / VIP if ( - !isDetailedView && - !(window.location.href.indexOf("marche/vente") > -1) + (this.elevageLocation && !isDetailedView) || this.boxesLocation ) { - const PGHtml = data.match(regexpPGHtml); - if (PGHtml) { - const PGFloat = PGHtml[0].match(regexpFloat); - parseHTML( + const skillsHtml = data.match(this.regexpSkillsHtml) + if (skillsHtml) { + const skillsFloat = skillsHtml[0].match(this.regexpFloat) + this.parseHTML( infoDiv, - `

${ - isFrenchApp ? "PG: " : "GP: " - }${PGFloat[0]}

`, + `

${translation.get(this.lang, 'other', 'skills')}${skillsFloat[0]}

`, "p" - ); + ) } } - } - - if ( - (window.location.href.indexOf("elevage/chevaux/?elevage") > -1 && - !isDetailedView) || - window.location.href.indexOf("centre/box") > -1 - ) { - const skillsHtml = data.match(regexpSkillsHtml); - if (skillsHtml) { - const skillsFloat = skillsHtml[0].match(regexpFloat); - parseHTML( - infoDiv, - `

${ - isFrenchApp ? "Compétences: " : "Skills: " - }${skillsFloat[0]}

`, - "p" - ); + + if (this.locationAllowed) { + name.parentNode.insertBefore(infoDiv, name.nextSibling) + + // remove
element before affixes in some views (cf: detailed view in breeding) + const br = name.parentNode.querySelector("br") + br && br.remove() + return } - } - - if (locationAllowed) { - name.parentNode.insertBefore(infoDiv, name.nextSibling); - - // remove
element before affixes in some views (cf: detailed view in breeding) - const br = name.parentNode.querySelector("br"); - br && br.remove(); - return; - } - return; - }); - }); + return + }) + }) + } } -/** - * handle the pages at the bottom of the community horse tab during a research to update infodiv after clicking them - */ -const handleDataPages = () => { - const dataPages = document.querySelectorAll("a[data-page]"); - if (dataPages.length > 0) { - dataPages.forEach((datapage) => { - datapage.addEventListener("click", async () => { - await updateAfterLoading(); - moreInfos(); - handleDataPages(); - }); - }); - } -}; - -const handleCurrentTab = async () => { - if (window.location.href.indexOf("communaute/?type=tab-che") > -1) { - setTimeout(() => { - const searchBtnCommunaute = document.querySelector("#searchHorseButton"); - searchBtnCommunaute.addEventListener("click", async () => { - await updateAfterLoading(); - moreInfos(); - handleDataPages(); - }); - }, 400); - } else return; -}; - -window.onload = async () => { - if (locationAllowed) { - setTimeout(() => { - moreInfos(); - }, 500); - } +const moreInfos = new MoreInfos() - if (elevageLocation) { - const breedingsBtn = document.getElementsByClassName("tab-action-select"); - Array.from(breedingsBtn).forEach((breedingBtn) => { - breedingBtn.addEventListener("click", async () => { - await updateAfterLoading(); - moreInfos(); - }); - }); - } +if (moreInfos.locationAllowed) { + moreInfos.run() - if (communauteLocation) { - await handleCurrentTab(); - const tabs = document.getElementsByClassName("tab-style-6-0-0"); - Array.from(tabs).forEach((tab) => { - tab.addEventListener("click", async () => { - await handleCurrentTab(); - }); - }); + const startObserver = () => { + observer.start().then(() => { + moreInfos.run() + startObserver() + }) } -}; + startObserver() +} diff --git a/popup.css b/popup.css deleted file mode 100644 index 8fcd880..0000000 --- a/popup.css +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (c) 2022. Gwen Tripet-Costet - * This file is part of Better Equideow (Better Howrse). - * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -img { - margin: 0.5em 0; -} diff --git a/popup.html b/popup.html deleted file mode 100644 index e9c2ecd..0000000 --- a/popup.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/popup.js b/popup.js deleted file mode 100644 index 0bb0070..0000000 --- a/popup.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2022. Gwen Tripet-Costet - * This file is part of Better Equideow (Better Howrse). - * Better Equideow (Better Howrse) is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * Better Equideow (Better Howrse) is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public License along with this program. If not, see . - */ - -const links = document.getElementsByTagName('a'); - -Array.from(links).forEach((a) => { - a.addEventListener('click', () => { - window.close(); - }); -}); diff --git a/translation.js b/translation.js new file mode 100644 index 0000000..ed001af --- /dev/null +++ b/translation.js @@ -0,0 +1,102 @@ +class Translation { + constructor() { + this.data = { + fr: { + stat: { + stamina: 'endurance', + speed: 'vitesse', + dressage: 'dressage', + gallop: 'galop', + trot: 'trot', + jumping: 'saut' + }, + competition: { + trot: 'Trot', + gallop: 'Galop', + dressage: 'Dressage', + crossCountry: 'Cross', + showJumping: 'Cso', + barrelRacing: 'Barrel racing', + cutting: 'Cutting', + trailClass: 'Trail class', + reining: 'Reining', + westernPleasure: 'Western pleasure' + }, + other: { + pet: 'Compagnon: ', + pg: 'PG: ', + skills: 'Compétences: ' + } + }, + en: { + stat: { + stamina: 'stamina', + speed: 'speed', + dressage: 'dressage', + gallop: 'gallop', + trot: 'trot', + jumping: 'jumping' + }, + competition: { + trot: 'Trot', + gallop: 'Gallop', + dressage: 'Dressage', + crossCountry: 'Cross-country', + showJumping: 'Show jumping', + barrelRacing: 'Barrel racing', + cutting: 'Cutting', + trailClass: 'Trail class', + reining: 'Reining', + westernPleasure: 'Western pleasure' + }, + other: { + pet: 'Pet: ', + pg: 'GP: ', + skills: 'Skills: ' + } + }, + no: { + stat: { + stamina: 'utholdenhet', + speed: 'hurtighet', + dressage: 'dressur', + gallop: 'galopp', + trot: 'trav', + jumping: 'hopp' + }, + competition: { + trot: 'Travløp', + gallop: 'Galoppløp', + dressage: 'Dressurkonkurranser', + crossCountry: 'Terrengløp', + showJumping: 'Sprangridning', + barrelRacing: 'Tønneløp', + cutting: 'Cutting', + trailClass: 'Trail class', + reining: 'Reining', + westernPleasure: 'Western pleasure' + }, + other: { + pet: 'Følgesvenner: ', + pg: 'GP: ', + skills: 'Ferdigheter: ' + } + } + } + } + + getLang(url) { + const hostname = (new URL(url)).hostname + if (hostname.includes('equideow')) { + return 'fr' + } + + return hostname.match(/\.([^.]+)$/)[1] + } + + get(lang, category, key) { + return this.data[lang][category][key] + } +} + +const translation = new Translation() \ No newline at end of file