this is more just braindump notes,
we have a fancypants website for our apartment where we pay rent, so we are actually able to independently pay our parts of the rent on the website. this however led to a build up of confusion over time.
the table is structured like a balance sheet, so yuo can paste it into google docs. and the easy thing to do is to just add it up per person using the SUMIF function.
=-1 * SUMIF(B13:B110, "*Joly*", C13:C110)
=-1 * SUMIF(B13:B110, "*Brie*", C13:C110)
=-1* SUMIF(B13:B110, "*Cho*", C13:C110)
= SUMIF(C13:C110, ">0", C13:C110)
in English it is
“for each row, if column B contains the 2585 then add column C to sum”.
Oh, for the final one is, The Charges are + so sum those. (what we’ve paid is -) –> this conversion, from the $(xyz) to +/- format, is done automatically when pasted into google sheets.
querySelectorAll.forEach
find the table
The core is the function filterAndSum(). Specifically, I select all table rows that are not “hidden”. I use the “querySelectorAll” function.
var rows = document.querySelectorAll('tr:not(.hidden)');
(Note: I noticed actually each row is repeated twice, so I had to filter to only select rows that did NOT have a “hidden” in their class.)
This returns an array which I iterate through using a for loop.
for (let i=0; i <rows.length; i++) {
For each row in the array: If the text string in that table row contains e.g. my name,
if (row.textContent.includes("orangenarwhals")) {
then I look for the $$$ in that row. So I use another querySelector, and look at table-data, or “td”, with class “mat-column-Amount”. In the below code, that’s what the “period” is for, it is a CSS class selctor. (see examples at https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors e.g. you can specific child with “>”)
row.querySelector('td.mat-column-Amount').textContent;
Then I used some copy-pasta to remove the $, (), and the comma from the string, e.g. $(1,234.53) turns into 1234.53
var punctuation = '$,()';
var regex = new RegExp('[' + punctuation + ']', 'g');
some_string.replace(regex, '')
Then I can use the built-in parseFloat to get a float, which I can them sum.
parseFloat
So the whole function looks like this.
function filterAndSum(str_filter) {
var punctuation = '($,)';
var regex = new RegExp('[' + punctuation + ']', 'g');
//console.log(row.textContent);
var rows = document.querySelectorAll('tr:not(.hidden)');
var sum = 0;
for (let i=0; i <rows.length; i++) {
var row = rows[i];
if (row.textContent.includes(str_filter)) {
var str_amt = row.querySelector('td.mat-column-Amount').textContent;
var amt = parseFloat(str_amt.replace(regex, ''));
console.log('amount: ', amt);
sum += amt;
}
}
console.log('if filter by string', str_filter, 'there is sum', sum);
return sum;
}
click
The other problem to solve is. That only a few months are revealed at first, so have to click “show more” button. So I can use the built-in click() to do so.
document.querySelector('div.data-grid__show-more-container').childNodes[0].click();
This is the html
<div class="data-grid__show-more-container ng-star-inserted">
<a bdi18n="Global.Component.Grid.ShowMore">Show more</a>
</div>
And to keep clicking until there’s no more to click..
function clickMores() {
try{
while (true){
document.querySelector('div.data-grid__show-more-container').childNodes[0].click();
}
}
catch (e) {
console.log('done clicking "Show Mores"');
}
}
Later on I added a sleep function, to allow for page load issues. This is from the internet, titled “ES6 vanilla sleep” or something like that. I guess ES6 is the latest-er version of javascript.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Which then can be used (note “async”) like so:
async function clickMores() {
try{
while (true){
document.querySelector('div.data-grid__show-more-container').childNodes[0].click();
await sleep(1000);
}
Show the information: make a div
then for the lulz I wanted to show the information. So create a div. Add text. Style. Figure out where to put it.
var my_div = document.createElement('div');
my_div.innerHTML = 'Please wait 10 seconds for the magic to happen :)';
my_div.setAttribute("style", "font-size: 35px; color:red;");
document.querySelector('body').prepend(my_div);
Later we can clean up this div
my_div.setAttribute('style', "visibility: hidden;");
templates with backticks
so i think python might have copied this from javascript… you can put expressions inside a string. just use backticks instead of quotes.
my_info_div.innerHTML = `Cool Info: Sum for N is ${filterAndSum('orangenarwhals')}`
all together
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://bradleyproperties.managebuilding.com/Resident/portal/payments
// @icon https://www.google.com/s2/favicons?sz=64&domain=managebuilding.com
// @grant none
// ==/UserScript==
async function clickMores() {
console.log('trying to click');
try{
while (true){
console.log('clicking');
document.querySelector('div.data-grid__show-more-container').childNodes[0].click();
await sleep(1000);
}
}
catch (e) {
console.log('done clicking "Show Mores"');
}
}
function filterAndSum(str_filter) {
var punctuation = '($,)';
var regex = new RegExp('[' + punctuation + ']', 'g');
//console.log(row.textContent);
var rows = document.querySelectorAll('tr:not(.hidden)');
var sum = 0;
for (let i=0; i <rows.length; i++) {
var row = rows[i];
if (row.textContent.includes(str_filter)) {
//console.log('found string', row.textContent);
var str_amt = row.querySelector('td.mat-column-Amount').textContent;
var amt = parseFloat(str_amt.replace(regex, ''));
console.log('amount: ', amt);
sum += amt;
}
}
console.log('if filter by string', str_filter, 'there is sum', sum);
return sum;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async function() {
console.log('hi');
'use strict';
var my_div = document.createElement('div');
my_div.innerHTML = 'Please wait 10 seconds for the magic to happen :)';
my_div.setAttribute("style", "font-size: 35px; color:red;");
document.querySelector('body').prepend(my_div);
console.log('Taking an 4 sec break...');
await sleep(4000);
console.log('4 seconds later...');
my_div.innerHTML = 'Please wait for the magic to happen, we are clicking the page for you :)';
my_div.setAttribute("style", "font-size: 35px; color:red;");
document.querySelector('table').parentElement.prepend(my_div);
clickMores();
await sleep(2500); // i guess must wait for the clicks if they're asynchronous?
var charges = filterAndSum('Charge');
var expect_A = charges / 3.5 * .5;
var expect_B = charges / 3.5;
var expect_C = charges / 3.5 * 2;
var AAA = filterAndSum('nameA');
var BBB = filterAndSum('nameB');
var CCC = filterAndSum('nameC');
var my_info_div = document.createElement('div');
my_info_div.innerHTML = `Cool Info:
<br> Sum for A is ${AAA}
<br> Sum for B is ${BBB}
<br> Sum for C is ${CCC}
<br>
<br> Total Charges are ${charges}
<br> Total Paid is ${AAA+BBB+CCC}
<br> Diff is ${charges - (AAA+BBB+CCC)}
<br> ============================
<br> Approx. Expectations (note that we are rounding to cents so won't quite match),
<br>
<br> A: ${expect_A}, Diff is ${expect_A - AAA}, aka ${Math.round(expect_A - AAA)}
<br> B: ${expect_B}, Diff is ${expect_B - BBB}, aka ${Math.round(expect_B - BBB)}
<br> C: ${expect_C}, Diff is ${expect_C - CCC}, aka ${Math.round(expect_C - CCC)}
`;
my_info_div.setAttribute("style", "font-size: 35px; color:blue;");
document.querySelector('table').parentElement.prepend(my_info_div);
my_div.setAttribute('style', "visibility: hidden;");
}
Misc. Notes
IKEA - get all URLs on shopping cart
document.querySelectorAll("[data-testid=product_name]").forEach(function getHref(result){
console.log(`${result.childNodes[0].href}`);
});
XPath
xpath=//div[contains(text(), "orangenarwhals")]/..//following-sibling::td[contains(@class, "mat-column-Amount")]/b/text()
amts_iterator = document.evaluate(xpath, document.body, null, XPathResult.ANY_TYPE,
null);
var amt = amts_iterator.iterateNext();
while (amt) {
sum += blahblah(amt);
amt = amts_iterator.iterateNext();
};
http://ponderer.org/download/xpath/