Skip to content

Commit 5b50057

Browse files
committed
fix: Remove price per m2 from rental ads
Added logic to check if ad is type of RENT and when yes omit price per m2 extraction Removed location.hostname passing from contentscript to sites Small refactorings Fixes realreality#74
1 parent 2afd012 commit 5b50057

File tree

5 files changed

+83
-39
lines changed

5 files changed

+83
-39
lines changed

src/js/contentscript.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import App from './components/App.vue';
1616
RR.logInfo('contentscript loaded');
1717

1818
chrome.runtime.sendMessage({ 'switchIconOn': true });
19+
const POLL_ADDRESS_TIMEOUT = 500;
1920

2021
const initVueTranslations = () => {
2122
return new Promise((resolve, reject) => {
@@ -66,7 +67,7 @@ const loadPanel = function(address) {
6667
address,
6768
details: {
6869
price: {
69-
perSquareMeter: pageDataExtractor.getPrices(window.location.host)
70+
perSquareMeter: pageDataExtractor.extractSquarePrice()
7071
}
7172
}
7273
}
@@ -78,7 +79,7 @@ const loadPanel = function(address) {
7879
let addressOfProperty;
7980
function initApp() {
8081
RR.logInfo('Initializing app widget');
81-
addressOfProperty = pageDataExtractor.getAddress(window.location.host);
82+
addressOfProperty = pageDataExtractor.getAddress();
8283
RR.logDebug('Address parsed: ', addressOfProperty);
8384

8485
if (RR.String.isNotBlank(addressOfProperty)) {
@@ -94,13 +95,13 @@ function initApp() {
9495
let pollAddressTimerId;
9596
function pollAddress() {
9697
//RR.logDebug('Polling address...'); // you can filter it out in console with regexp filter ^(?=.*?\b.*\b)((?!Poll).)*$ (match all except lines with 'Poll' match)
97-
const currentAddressOfProperty = pageDataExtractor.getAddress(window.location.host);
98+
const currentAddressOfProperty = pageDataExtractor.getAddress();
9899
//RR.logDebug('Polled address:', currentAddressOfProperty);
99100
if (currentAddressOfProperty !== addressOfProperty) {
100101
$(document).trigger(RR.ADDRESS_CHANGED_EVENT);
101102
clearTimeout(pollAddressTimerId);
102103
}
103-
pollAddressTimerId = setTimeout(pollAddress, 500);
104+
pollAddressTimerId = setTimeout(pollAddress, POLL_ADDRESS_TIMEOUT);
104105
}
105106

106107
$(document).on(RR.ADDRESS_CHANGED_EVENT, (event) => {

src/js/sites/index.js

+62-25
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
const RENT = 'rent';
2+
const SALE = 'sale';
3+
14
const textOrNull = textElement => {
25
if (textElement === null) {
36
return null;
@@ -6,57 +9,91 @@ const textOrNull = textElement => {
69
}
710
};
811

9-
export const siteHosts = {
12+
const sites = {
1013
SREALITY: {
11-
hostString: 'sreality.cz'
14+
id: 'sreality',
1215
},
1316
BEZREALITKY: {
14-
hostString: 'bezrealitky.cz'
17+
id: 'bezrealitky',
1518
},
1619
MAXIREALITY: {
17-
hostString: 'maxirealitypraha.cz'
20+
id: 'maxirealitypraha',
1821
},
1922
REALITY_IDNES: {
20-
hostString: 'reality.idnes.cz'
23+
id: 'idnes',
2124
}
2225
};
2326

24-
/**
25-
*
26-
* @param {{ hostString: String }} hostId
27-
* @param {String} host
28-
* @return {Number|undefined}
29-
*/
30-
export const isCurrentHost = (hostId, host) => host.includes(hostId.hostString);
31-
3227
const priceAreaGuard = (price, area) => (area && !isNaN(area) && (price && !isNaN(price))) && price / area;
3328

29+
const getHostPredicate = (locationHost) => (siteHost) => locationHost.includes(siteHost);
30+
31+
const containsBoxWords = (selector, words) => {
32+
const containsNodeWord = (node, word) => node.textContent.includes(word);
33+
34+
const node = document.querySelector(selector);
35+
if (!node || !words.length) {
36+
return false;
37+
}
38+
39+
const mapWords = (word) => containsNodeWord(node, word);
40+
// ['foo'] => [true]
41+
// ['foo', 'bar', 'baz'] => [true, false, true] => false
42+
return words.map(mapWords).filter(Boolean).length === words.length;
43+
};
44+
45+
// this is business logic, so it may contain site specific settings/params
46+
// underneath it should only call some generic functions
47+
const extractAdType = (locationHost) => {
48+
const verify = getHostPredicate(locationHost);
49+
50+
if (verify(sites.SREALITY.id) || verify(sites.SREALITY.id) || verify(sites.MAXIREALITY.id)) {
51+
if (/pronajem/i.test(location.pathname)) {
52+
return RENT;
53+
}
54+
return SALE;
55+
}
56+
57+
if (verify('bezrealitky')) {
58+
const selector = '.box-params.col-1';
59+
return containsBoxWords(selector, ['typ', 'nabídky', 'Pronájem']) ? RENT : SALE;
60+
}
61+
};
62+
3463
// TODO add extractor's methods for sites dynamically
3564
export const extractors = {
36-
getAddress(host) {
37-
if (isCurrentHost(siteHosts.SREALITY, host)) {
65+
getAddress() {
66+
const verify = getHostPredicate(window.location.host);
67+
if (verify(sites.SREALITY.id)) {
3868
return textOrNull(document.querySelector('.location-text'));
3969
}
4070

41-
if (isCurrentHost(siteHosts.BEZREALITKY, host)) {
71+
if (verify(sites.BEZREALITKY.id)) {
4272
return textOrNull(document.querySelector('header h2'));
4373
}
4474

45-
if (isCurrentHost(siteHosts.MAXIREALITY, host)) {
75+
if (verify(sites.MAXIREALITY.id)) {
4676
const addressRow = Array.from(document.querySelectorAll('tr'))
4777
.filter(node => node.textContent.includes('Adresa'))[0];
4878
return addressRow && addressRow.querySelector('td').innerHTML.replace(/<br>/g, ' ').trim();
4979
}
5080

51-
if (isCurrentHost(siteHosts.REALITY_IDNES, host)) {
81+
if (verify(sites.REALITY_IDNES.id)) {
5282
return textOrNull(document.querySelector('.realAddress'));
5383
}
5484

5585
RR.logError('cannot parse address on page: ', window.location);
5686
return null;
5787
},
58-
getPrices(host) {
59-
if (isCurrentHost(siteHosts.SREALITY, host)) {
88+
extractSquarePrice() {
89+
const adType = extractAdType(window.location.host);
90+
const verify = getHostPredicate(window.location.host);
91+
92+
if (adType === RENT) {
93+
return;
94+
}
95+
96+
if (verify(sites.SREALITY.id)) {
6097
const propertyParams = Array.from(document.querySelectorAll('.params li'));
6198
const priceRow = propertyParams.filter(p => p.innerHTML.includes('Celková cena'))[0];
6299
const areaRow = propertyParams.filter(p => p.innerHTML.includes('Užitná'))[0];
@@ -66,7 +103,7 @@ export const extractors = {
66103
return priceAreaGuard(price, area);
67104
}
68105

69-
if (isCurrentHost(siteHosts.BEZREALITKY, host)) {
106+
if (verify(sites.BEZREALITKY.id)) {
70107
const propertyParams = Array.from(document.querySelectorAll('.box-params .row'));
71108
const areaRow = propertyParams.filter(item => item.innerHTML.includes('plocha'))[0]; // returns DOM node
72109
const priceRow = propertyParams.filter(item => item.innerHTML.includes('cena'))[0]; // returns DOM node
@@ -80,7 +117,7 @@ export const extractors = {
80117
return priceAreaGuard(price, area);
81118
}
82119

83-
if (isCurrentHost(siteHosts.MAXIREALITY, host)) {
120+
if (verify(sites.MAXIREALITY.id)) {
84121
const areaRow = Array.from(document.querySelectorAll('#makler_zaklad > table tr'))
85122
.filter(node => node.innerHTML.includes('Užitná plocha'))[0];
86123
const priceNode = document.querySelector('.two.price');
@@ -90,12 +127,12 @@ export const extractors = {
90127
return priceAreaGuard(price, area);
91128
}
92129

93-
if (isCurrentHost(siteHosts.REALITY_IDNES, host)) {
130+
if (verify(sites.REALITY_IDNES.id)) {
94131
const areaText = $('.parameters .leftCol dt:contains("Užitná plocha")').next().text();
95132
const area = Number.parseInt(areaText); // eg. when text is "34 m2" Number.parseInt can strip text parts and parse it as just 34
96133

97-
const priceText = document.querySelectorAll('.priceBox strong')[0].innerHTML;
98-
const price = Number.parseInt(priceText.replace(/&nbsp;/gi,''));
134+
const priceText = document.querySelectorAll('.priceBox strong')[0].innerHTML;
135+
const price = Number.parseInt(priceText.replace(/&nbsp;/gi, ''));
99136

100137
return priceAreaGuard(price, area);
101138
}

src/js/sites/index.spec.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ describe('extractors', () => {
2525
});
2626

2727
it('should return price per m2', () => {
28-
expect(extractors.getPrices(window.location.host)).to.equal(22222.222222222223);
28+
expect(extractors.extractSquarePrice()).to.equal(22222.222222222223);
2929
});
3030

3131
it('should return address', () => {
32-
expect(extractors.getAddress(window.location.host)).to.equal('Komenského, Vlašim, Středočeský kraj');
32+
expect(extractors.getAddress()).to.equal('Komenského, Vlašim, Středočeský kraj');
3333
});
3434
});
3535

@@ -43,11 +43,11 @@ describe('extractors', () => {
4343
});
4444

4545
it('should return price per m2', () => {
46-
expect(extractors.getPrices(window.location.host)).to.equal(57042.25352112676);
46+
expect(extractors.extractSquarePrice()).to.equal(57042.25352112676);
4747
});
4848

4949
it('should return address', () => {
50-
expect(extractors.getAddress(window.location.host)).to.equal('Ortenovo náměstí, Praha 7 - Holešovice');
50+
expect(extractors.getAddress()).to.equal('Ortenovo náměstí, Praha 7 - Holešovice');
5151
});
5252
});
5353

@@ -61,11 +61,11 @@ describe('extractors', () => {
6161
});
6262

6363
it('should return price per m2', () => {
64-
expect(extractors.getPrices(window.location.host)).to.equal(64805.194805194806);
64+
expect(extractors.extractSquarePrice()).to.equal(64805.194805194806);
6565
});
6666

6767
it('should return address', () => {
68-
expect(extractors.getAddress(window.location.host)).to.equal('Praha - Smíchov Vrázova');
68+
expect(extractors.getAddress()).to.equal('Praha - Smíchov Vrázova');
6969
});
7070
});
7171

@@ -83,11 +83,11 @@ describe('extractors', () => {
8383
});
8484

8585
it('should return price per m2', () => {
86-
expect(extractors.getPrices(window.location.host)).to.equal(31888.88888888889);
86+
expect(extractors.extractSquarePrice()).to.equal(31888.88888888889);
8787
});
8888

8989
it('should return address', () => {
90-
expect(extractors.getAddress(window.location.host)).to.equal('Praha 5, Hlubočepy, Machatého');
90+
expect(extractors.getAddress()).to.equal('Praha 5, Hlubočepy, Machatého');
9191
});
9292
});
9393
});

src/js/utils.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ export const streetNamePredicate = (address) => {
77
return address;
88
};
99

10-
export const formatPrice = price => Math.round(price) + ' Kč';
10+
export const formatPrice = price => {
11+
const formatter = new Intl.NumberFormat('cs', {
12+
style: 'currency',
13+
currency: 'CZK',
14+
minimumFractionDigits: 0,
15+
});
16+
return formatter.format(Math.round(price));
17+
};
1118

1219
/**
1320
* Call ga (google analytics) in context of current page - we cannot directly call page functions here

src/templates/panel.html

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<!-- Google Analytics from Real Reality Chrome Extension -->
55
<script>
66
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
7-
87
ga('create', 'UA-85464417-1', 'auto', 'rr');
98
ga('rr.send', 'pageview');
109
</script>

0 commit comments

Comments
 (0)