Adding border depending on the item state and preferences.
Some cleaning and refactor.
This commit is contained in:
parent
6de714b445
commit
88f50657c2
@ -5,13 +5,12 @@ import banner from 'browserify-banner';
|
|||||||
const STATIC_BANNER = "// ==UserScript==\n" +
|
const STATIC_BANNER = "// ==UserScript==\n" +
|
||||||
"// @name Idealista Enhancer\n" +
|
"// @name Idealista Enhancer\n" +
|
||||||
"// @description Just some information for idealista.com\n" +
|
"// @description Just some information for idealista.com\n" +
|
||||||
"// @version 0.1.0\n" +
|
"// @version 0.2.0\n" +
|
||||||
"// @author Midefos\n" +
|
"// @author Midefos\n" +
|
||||||
"// @namespace https://github.com/Midefos\n" +
|
"// @namespace https://github.com/Midefos\n" +
|
||||||
"// @match https://www.idealista.com/*\n" +
|
"// @match https://www.idealista.com/*\n" +
|
||||||
"// @license MIT\n" +
|
"// @license MIT\n" +
|
||||||
"// ==/UserScript==\n" +
|
"// ==/UserScript==\n\n";
|
||||||
"/* jshint esversion: 6 */\n\n";
|
|
||||||
|
|
||||||
browserify("./app.js")
|
browserify("./app.js")
|
||||||
.transform("babelify", { presets: ["@babel/preset-env"] })
|
.transform("babelify", { presets: ["@babel/preset-env"] })
|
||||||
|
17
src/CheckboxHTML.js
Normal file
17
src/CheckboxHTML.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import Log from "./Log.js";
|
||||||
|
|
||||||
|
export default class CheckboxHTML {
|
||||||
|
|
||||||
|
static create(id, value) {
|
||||||
|
const inputElement = document.createElement('input');
|
||||||
|
if (value) {
|
||||||
|
Log.debug(`Creating checkbox ${id}, value: ${value}`)
|
||||||
|
inputElement.setAttribute('checked', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inputElement.id = id;
|
||||||
|
inputElement.type = 'checkbox';
|
||||||
|
return inputElement.outerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import ButtonClass from "./ButtonClass.js";
|
import ButtonClass from "./ButtonClass.js";
|
||||||
|
import CheckboxHTML from "./CheckboxHTML.js";
|
||||||
import Preferences from "./Preferences.js";
|
import Preferences from "./Preferences.js";
|
||||||
|
|
||||||
export default class ConfigurationHTML {
|
export default class ConfigurationHTML {
|
||||||
@ -25,32 +26,32 @@ export default class ConfigurationHTML {
|
|||||||
|
|
||||||
<h3>Configuración global:</h3>
|
<h3>Configuración global:</h3>
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' id='enabled' checked='${Preferences.get('enabled')}'>
|
${CheckboxHTML.create('enabled', Preferences.get('enabled'))}
|
||||||
<span>Habilitado</span>
|
<span>Habilitado</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<h3>Busqueda:</h3>
|
<h3>Busqueda:</h3>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' id='percentages' checked='${Preferences.get('percentages')}'>
|
${CheckboxHTML.create('percentages', Preferences.get('percentages'))}
|
||||||
<span>Porcentajes</span>
|
<span>Porcentajes</span>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' id='garage' checked='${Preferences.get('garage')}'>
|
${CheckboxHTML.create('garage', Preferences.get('garage'))}
|
||||||
<span>Garaje</span>
|
<span>Garaje</span>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' id='exterior' checked='${Preferences.get('exterior')}'>
|
${CheckboxHTML.create('exterior', Preferences.get('exterior'))}
|
||||||
<span>Exterior</span>
|
<span>Exterior</span>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' id='lift' checked='${Preferences.get('lift')}'>
|
${CheckboxHTML.create('lift', Preferences.get('lift'))}
|
||||||
<span>Ascensor</span>
|
<span>Ascensor</span>
|
||||||
</label>
|
</label>
|
||||||
<br>
|
<br>
|
||||||
@ -71,7 +72,7 @@ export default class ConfigurationHTML {
|
|||||||
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.SAVE_CONFIG_CLASS_NAME}'>Guardar</button>
|
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.SAVE_CONFIG_CLASS_NAME}'>Guardar</button>
|
||||||
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.OPEN_CONFIG_CLASS_NAME}'>Cerrar</button>
|
<button class='${ButtonClass.IDEALISTA_BUTTON_CLASS} ${this.OPEN_CONFIG_CLASS_NAME}'>Cerrar</button>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
34
src/Item.js
34
src/Item.js
@ -4,6 +4,7 @@ export default class Item {
|
|||||||
|
|
||||||
static NAME_SELECTOR = '.item-link';
|
static NAME_SELECTOR = '.item-link';
|
||||||
static PRICE_SELECTOR = '.item-price';
|
static PRICE_SELECTOR = '.item-price';
|
||||||
|
|
||||||
static ROOM_SELECTOR = '.item-detail-char .item-detail:nth-child(1)';
|
static ROOM_SELECTOR = '.item-detail-char .item-detail:nth-child(1)';
|
||||||
static METERS_SELECTOR = '.item-detail-char .item-detail:nth-child(2)';
|
static METERS_SELECTOR = '.item-detail-char .item-detail:nth-child(2)';
|
||||||
static ADDITIONAL_INFORMATION_SELECTOR = '.item-detail-char .item-detail:nth-child(3)';
|
static ADDITIONAL_INFORMATION_SELECTOR = '.item-detail-char .item-detail:nth-child(3)';
|
||||||
@ -19,6 +20,7 @@ export default class Item {
|
|||||||
this.additionalInfo = this._extractAdditionalInfo();
|
this.additionalInfo = this._extractAdditionalInfo();
|
||||||
this.hasLift = this._extractLift();
|
this.hasLift = this._extractLift();
|
||||||
this.isExterior = this._extractExterior();
|
this.isExterior = this._extractExterior();
|
||||||
|
this.isInterior = this._extractInterior();
|
||||||
}
|
}
|
||||||
|
|
||||||
get _data() {
|
get _data() {
|
||||||
@ -36,25 +38,38 @@ export default class Item {
|
|||||||
&& nextElement.className.includes(ItemHTML.CONTAINER_CLASS_NAME);
|
&& nextElement.className.includes(ItemHTML.CONTAINER_CLASS_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isProperPrice(price) {
|
||||||
|
return this.price <= price;
|
||||||
|
}
|
||||||
|
|
||||||
|
isProperPriceMeter(priceMeter) {
|
||||||
|
return this.priceMeter <= priceMeter;
|
||||||
|
}
|
||||||
|
|
||||||
removeData() {
|
removeData() {
|
||||||
if (!this.isDataRendered()) return;
|
if (!this.isDataRendered()) return;
|
||||||
this._data.remove();
|
this._data.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
addData() {
|
addData() {
|
||||||
this._node.outerHTML += ItemHTML.createInformation(this);
|
this._node.insertAdjacentHTML('afterend', ItemHTML.createInformation(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
isFlat() {
|
isFlat() {
|
||||||
return this.name.includes('Piso');
|
return this._nameIncludes('Piso');
|
||||||
}
|
}
|
||||||
|
|
||||||
isHouse() {
|
isHouse() {
|
||||||
return this.name.includes('Casa');
|
return this._nameIncludes('Casa')
|
||||||
|
|| this._nameIncludes('Chalet');
|
||||||
}
|
}
|
||||||
|
|
||||||
isGround() {
|
isGround() {
|
||||||
return this.name.includes('Bajo');
|
return this._nameIncludes('Bajo');
|
||||||
|
}
|
||||||
|
|
||||||
|
_nameIncludes(name) {
|
||||||
|
return this.name.toLowerCase().includes(name.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
_extractName() {
|
_extractName() {
|
||||||
@ -79,8 +94,10 @@ export default class Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_extractAdditionalInfo() {
|
_extractAdditionalInfo() {
|
||||||
const additionalInfo = this._node.querySelector(Item.ADDITIONAL_INFORMATION_SELECTOR);
|
let additionalInfo = this._node.querySelector(Item.ADDITIONAL_INFORMATION_SELECTOR);
|
||||||
if (!additionalInfo) return null;
|
if (!additionalInfo) {
|
||||||
|
additionalInfo = this._node.querySelector(Item.METERS_SELECTOR);
|
||||||
|
}
|
||||||
return additionalInfo.textContent;
|
return additionalInfo.textContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,4 +111,9 @@ export default class Item {
|
|||||||
return this.additionalInfo.includes('exterior');
|
return this.additionalInfo.includes('exterior');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_extractInterior() {
|
||||||
|
if (!this.additionalInfo) return false;
|
||||||
|
return this.additionalInfo.includes('interior');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
111
src/ItemHTML.js
111
src/ItemHTML.js
@ -2,19 +2,49 @@ import Preferences from "./Preferences.js";
|
|||||||
|
|
||||||
export default class ItemHTML {
|
export default class ItemHTML {
|
||||||
|
|
||||||
|
static SUCCESS_CLASS_NAME = 'success';
|
||||||
|
static WARNING_CLASS_NAME = 'warning';
|
||||||
|
static ERROR_CLASS_NAME = 'error';
|
||||||
|
|
||||||
static CONTAINER_CLASS_NAME = 'midefos-idealista-container';
|
static CONTAINER_CLASS_NAME = 'midefos-idealista-container';
|
||||||
static get CONTAINER_SELECTOR() {
|
static get CONTAINER_SELECTOR() {
|
||||||
return `.${this.CONTAINER_CLASS_NAME}`;
|
return `.${this.CONTAINER_CLASS_NAME}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INFORMATION_CLASS_NAME = 'information'
|
||||||
|
static get INFORMATION_SELECTOR() {
|
||||||
|
return `.${this.INFORMATION_CLASS_NAME}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ITEM_STATE_CLASS_NAME(item) {
|
||||||
|
const desiredPrice = Preferences.get('max-price');
|
||||||
|
if (desiredPrice && !item.isProperPrice(desiredPrice)) {
|
||||||
|
return this.ERROR_CLASS_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
const desiredPricePerMeter = Preferences.get('max-price-per-meter');
|
||||||
|
if (desiredPricePerMeter && !item.isProperPriceMeter(desiredPricePerMeter)) {
|
||||||
|
return this.ERROR_CLASS_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._shouldCheckLift(item) && !item.hasLift) {
|
||||||
|
return this.ERROR_CLASS_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._shouldCheckExterior(item) && !item.isExterior) {
|
||||||
|
return this.ERROR_CLASS_NAME;
|
||||||
|
}
|
||||||
|
return this.SUCCESS_CLASS_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
static createInformation(item) {
|
static createInformation(item) {
|
||||||
return `
|
return `
|
||||||
<div class='${this.CONTAINER_CLASS_NAME}'>
|
<div class='${this.CONTAINER_CLASS_NAME} ${this.ITEM_STATE_CLASS_NAME(item)}'>
|
||||||
${this._createPercentagePriceHTML(item)}
|
${this._createPercentagePriceHTML(item)}
|
||||||
${this._createPriceHTML(item)}
|
${this._createPriceHTML(item)}
|
||||||
${this._createPriceMeterHTML(item)}
|
${this._createPriceMeterHTML(item)}
|
||||||
${this._createLiftHTML(item)}
|
${this._createLiftHTML(item)}
|
||||||
${this._createInteriorHTML(item)}
|
${this._createExteriorHTML(item)}
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,92 +55,115 @@ export default class ItemHTML {
|
|||||||
const thirtyPercent = Math.round(item.price * 30 / 100);
|
const thirtyPercent = Math.round(item.price * 30 / 100);
|
||||||
const fiftyPercent = Math.round(item.price * 50 / 100);
|
const fiftyPercent = Math.round(item.price * 50 / 100);
|
||||||
return `
|
return `
|
||||||
<div>
|
<div class='${this.INFORMATION_CLASS_NAME}'>
|
||||||
<span><strong>20%:</strong> ${twentyPercent}€</span>
|
${this._createIndividual('20%', twentyPercent)}
|
||||||
<span><strong>30%:</strong> ${thirtyPercent}€</span>
|
${this._createIndividual('30%', thirtyPercent)}
|
||||||
<span><strong>50%:</strong> ${fiftyPercent}€</span>
|
${this._createIndividual('50%', fiftyPercent)}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static _createPriceHTML(item) {
|
static _createPriceHTML(item) {
|
||||||
const desiredPrice = Preferences.get('max-price');
|
const desiredPrice = Preferences.get('max-price');
|
||||||
if (!desiredPrice) return ``;
|
if (!desiredPrice) return ``;
|
||||||
|
|
||||||
const desiredTwentyFivePercentMore = Math.round(desiredPrice * 1.25);
|
const desiredTwentyFivePercentMore = Math.round(desiredPrice * 1.25);
|
||||||
|
|
||||||
if (item.price <= desiredPrice) {
|
if (item.isProperPrice(desiredPrice)) {
|
||||||
return this._createSuccess('Precio');
|
return this._createSuccess('Precio');
|
||||||
} else if (item.price <= desiredTwentyFivePercentMore) {
|
} else if (item.isProperPrice(desiredTwentyFivePercentMore)) {
|
||||||
return this._createWarning('Precio');
|
return this._createWarning('Precio');
|
||||||
}
|
}
|
||||||
return this._createError('Precio');
|
return this._createError('Precio');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static _createPriceMeterHTML(item) {
|
static _createPriceMeterHTML(item) {
|
||||||
const desiredPricePerMeter = Preferences.get('max-price-per-meter');
|
const desiredPricePerMeter = Preferences.get('max-price-per-meter');
|
||||||
if (!desiredPricePerMeter) return `<span><strong>m²:</strong> ${item.priceMeter}€</span>`;
|
if (!desiredPricePerMeter) return this._createIndividual('m²', item.priceMeter);
|
||||||
|
|
||||||
const desiredTwentyFivePercentMore = Math.round(desiredPricePerMeter * 1.25);
|
const desiredTwentyFivePercentMore = Math.round(desiredPricePerMeter * 1.25);
|
||||||
|
|
||||||
if (item.priceMeter <= desiredPricePerMeter) {
|
if (item.priceMeter <= desiredPricePerMeter) {
|
||||||
return `<span class='success'><strong>m²:</strong> ${item.priceMeter}€</span>`;
|
return this._createTextSuccess('m²', item.priceMeter)
|
||||||
} else if (item.priceMeter <= desiredTwentyFivePercentMore) {
|
} else if (item.priceMeter <= desiredTwentyFivePercentMore) {
|
||||||
return `<span class='warning'><strong>m²:</strong> ${item.priceMeter}€</span>`;
|
return this._createTextWarning('m²', item.priceMeter)
|
||||||
}
|
}
|
||||||
return `<span class='error'><strong>m²:</strong> ${item.priceMeter}€</span>`;
|
return this._createTextError('m²', item.priceMeter)
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createLiftHTML(item) {
|
static _createLiftHTML(item) {
|
||||||
if (!Preferences.get('lift')) return ``;
|
if (!this._shouldCheckLift(item)) {
|
||||||
|
return ``;
|
||||||
|
}
|
||||||
|
|
||||||
if (!item.additionalInfo) {
|
if (!item.additionalInfo) {
|
||||||
if (item.isFlat()) return ``;
|
|
||||||
return this._createMissing('Ascensor');
|
return this._createMissing('Ascensor');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.hasLift) {
|
if (item.hasLift) {
|
||||||
return this._createSuccess('Ascensor',);
|
return this._createSuccess('Ascensor');
|
||||||
}
|
}
|
||||||
return this._createError('Ascensor');
|
return this._createError('Ascensor');
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createInteriorHTML(item) {
|
static _shouldCheckLift(item) {
|
||||||
if (!Preferences.get('exterior')) return ``;
|
return Preferences.get('lift')
|
||||||
|
&& !item.isHouse()
|
||||||
|
&& !item.isGround();
|
||||||
|
}
|
||||||
|
|
||||||
if (!item.additionalInfo) {
|
static _createExteriorHTML(item) {
|
||||||
if (!item.isFlat()) return ``;
|
if (!this._shouldCheckExterior(item)) {
|
||||||
return this._createMissing('Exterior');
|
return ``;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.isExterior) {
|
if (item.isExterior) {
|
||||||
return this._createSuccess('Exterior');
|
return this._createSuccess('Exterior');
|
||||||
}
|
}
|
||||||
return this._createError('Exterior');
|
|
||||||
|
if (item.isInterior) {
|
||||||
|
return this._createError('Exterior');
|
||||||
|
}
|
||||||
|
return this._createMissing('Exterior');
|
||||||
|
}
|
||||||
|
|
||||||
|
static _shouldCheckExterior(item) {
|
||||||
|
return Preferences.get('exterior')
|
||||||
|
&& !item.isHouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createSuccess(infoText) {
|
static _createSuccess(infoText) {
|
||||||
return this.__createIndividual('✓', infoText, 'success');
|
return this._createTextSuccess('✔️', infoText);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _createTextSuccess(strongText, infoText) {
|
||||||
|
return this._createIndividual(strongText, infoText, this.SUCCESS_CLASS_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createWarning(infoText) {
|
static _createWarning(infoText) {
|
||||||
return this.__createIndividual('✓', infoText, 'warning');
|
return this._createTextWarning('⚠️', infoText);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createMissing(infoText) {
|
static _createMissing(infoText) {
|
||||||
return this.__createIndividual('?', infoText, 'warning');
|
return this._createTextWarning('?', infoText);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _createTextWarning(strongText, infoText) {
|
||||||
|
return this._createIndividual(strongText, infoText, this.WARNING_CLASS_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createError(infoText) {
|
static _createError(infoText) {
|
||||||
return this.__createIndividual('✓', infoText, 'error');
|
return this._createTextError('🚫', infoText);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _createTextError(strongText, infoText) {
|
||||||
|
return this._createIndividual(strongText, infoText, this.ERROR_CLASS_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _createNeutral(infoText) {
|
static _createNeutral(infoText) {
|
||||||
return this.__createIndividual('ⓘ', infoText)
|
return this._createIndividual('ⓘ', infoText)
|
||||||
}
|
}
|
||||||
|
|
||||||
static __createIndividual(strongText, infoText, className = '') {
|
static _createIndividual(strongText, infoText, className = '') {
|
||||||
return `<span class='${className}'><strong>${strongText}</strong> ${infoText}</span>`;
|
return `<span class='${className}'><strong>${strongText}</strong> ${infoText}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,34 @@ export default class Styles {
|
|||||||
|
|
||||||
background-color: white;
|
background-color: white;
|
||||||
box-shadow: 0 3px 6px rgba(225, 245, 110, 0.16), 0 3px 6px rgba(225, 245, 110, 0.23);
|
box-shadow: 0 3px 6px rgba(225, 245, 110, 0.16), 0 3px 6px rgba(225, 245, 110, 0.23);
|
||||||
|
border: 3px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.INFORMATION_CLASS_NAME} {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.SUCCESS_CLASS_NAME} {
|
||||||
|
color: darkgreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.CONTAINER_CLASS_NAME}.${ItemHTML.SUCCESS_CLASS_NAME} {
|
||||||
|
border-color: rgba(61, 217, 61, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.WARNING_CLASS_NAME} {
|
||||||
|
color: darkorange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.ERROR_CLASS_NAME} {
|
||||||
|
color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.${ItemHTML.CONTAINER_CLASS_NAME}.${ItemHTML.ERROR_CLASS_NAME} {
|
||||||
|
border-color: rgba(217, 61, 61, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
.${MenuHTML.CONTAINER_CLASS_NAME} {
|
.${MenuHTML.CONTAINER_CLASS_NAME} {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -46,16 +72,6 @@ export default class Styles {
|
|||||||
border: 5px solid rgb(225, 245, 110);
|
border: 5px solid rgb(225, 245, 110);
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.success {
|
|
||||||
color: darkgreen;
|
|
||||||
}
|
|
||||||
.warning {
|
|
||||||
color: darkorange;
|
|
||||||
}
|
|
||||||
.error {
|
|
||||||
color: darkred;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
static add(style = null) {
|
static add(style = null) {
|
||||||
|
Loading…
Reference in New Issue
Block a user