How to make Mutationobserver console.log() my changes only one time - javascript

for example:
<div id="someId">
<h1>someText</h1>
</div>
someText =>> someText keeps changing over time
let observer = new MutationObserver((mutations,observer)=>{
mutations.forEach(muta=>{
console.log((muta.target as Element).innerHTML)
})
})
const config = {childList: true};
let div = document.getElementById('someId');
observer.observe((div as Node), config);
how to make it so that the text is displayed once and at the same time do not turn off the observer
I tried to do like this:
let observer = new MutationObserver((mutations,observer)=>{
mutations.forEach(muta=>{
console.log((muta.target as Element).innerHTML)
observer.disconnect()
})
})
but I don't want to shutdown the Observer so that when new changes arrive, print them to the console again only once

Related

How to reuse MotorCortex incidents

I have a clip that I develop and I want to reuse a fade in incident instead o creating a new incident every time is this possible? The way I am doing it at the moment looks like this:\
const attrs = {animatedAttrs:{opacity:1}}
const props = {selector:".elem",duration:1000}
const fadeInOne = new CSSEffect(attrs,props)
const fadeInTwo = new CSSEffect(attrs,props)
clip.addIncindet(fadeOne,1000)
// do something else and then later on
clip.addIncident(fadeTwo,1000)
Is there a better way to do this?
To accomplish what you want you could do the following:
const attrs = {animatedAttrs:{opacity:1}}
const props = {selector:".elem",duration:1000}
const fadeIn = () => new CSSEffect(attrs,props)
clip.addIncindet(fadeIn(),1000)
// do something else and then later on
clip.addIncident(fadeIn(),1000)
Note *: you could add argument to the fadeIn function and make some of the data dynamic such as the selector or the duration, or event add different easing.

How can I group Javascript actions that force reflow?

I have a project which is responsible for managing the rendering of elements, but I'm running into a performance issue replacing elements and then focusing on whatever had focus before.
Below is a minimal example that replicates the performance issue:
const renderPage = () => {
// get the old section element
const oldSection = document.querySelector('section')
// create a new section element (we'll replaceWith later)
const newSection = document.createElement('section')
// create the render button
const newButton = document.createElement('button')
newButton.innerHTML = 'Render Page'
newButton.onclick = renderPage
newSection.appendChild(newButton)
// create a bunch of elements
const dummyDivs = [...new Array(100000)].forEach(() => {
const dummy = document.createElement('div')
dummy.innerHTML = 'dummy'
newSection.appendChild(dummy)
})
// replace the old page with the new one (causes forced reflow)
oldSection.replaceWith(newSection)
// reattach focus on the button (causes forced reflow)
newButton.focus()
}
window.renderPage = renderPage
<section>
<button onclick="renderPage()">Render</button>
</section>
When running this locally, I see the following in the performance report in Chrome/Edge
Both replaceWith and focus are triggering forced reflow. Is there a way to batch or group these actions so that only a single reflow occurs? I realize that there's no way to really get around this happening at all, but if I can batch them, I think that might improve my performance.
Indeed, focus always causes a reflow: What forces layout / reflow
So what you may do, is to reduce the reflowtime by inserting the new button standalone, initiate focus and after that you can append other childs:
Working example: Example
const renderPage = () => {
// get the old section element
const oldSection = document.querySelector('section')
// create a new section element (we'll replaceWith later)
const newSection = document.createElement('section')
// create the render button
const newButton = document.createElement('button')
newButton.innerHTML = 'Render Page'
newButton.onclick = renderPage
newSection.appendChild(newButton)
// create a bunch of elements
const dummies = []; // store in seperate array
const dummyDivs = [...new Array(100000)].forEach(() => {
const dummy = document.createElement('div')
dummy.innerHTML = 'dummy';
dummies.push(dummy)
})
// insert new section only with new button
oldSection.replaceWith(newSection)
newButton.focus(); // always causes reflow; but fast because it's only one element
// store all other nodes after focus
newSection.append(...dummies)
}
window.renderPage = renderPage

How do I continuously listen for a new item while scraping a website

I am using puppeteer to scrape a website that is being live updated, to report the latest item elsewhere.
Currently the way I was thinking accomplishing this is to run a setInterval call on my async scrape and to compare if the last item has changed, checking every 30 seconds. I assume there has to be a better way of doing this then that.
Here is my current code:
const puppeteer = require('puppeteer');
playtracker = async () => {
console.log('loading');
const browser = await puppeteer.launch({});
const page = await browser.newPage();
await page.goto('URL-Being-Scraped');
await page.waitForSelector('.playlist-tracklist-view');
let html = await page.$$eval('.playlist-tracklist-view > .playlist-track', tracks => {
tracks = tracks.filter(track => track.querySelector('.playlist-trackname').textContent);
tracks = tracks.map(el => el.querySelector('.playlist-trackname').textContent);
return tracks;
});
console.log('logging', html[html.length-1]);
};
setInterval(playtracker, 30000)
There is an api called "MutationObserver". You can check that out on MDN. Here's the link https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
What it is doing is basically do whatever you want to do when the spesific element has changed. Lets say you have a list you want to listen. What you would do is
const listElement = document.querySelector( [list element] );
const callbackFunc = funcion foo () {
//do something
}
const yourMutationObserver = new MutationObserver(callbackFunc)
yourMutationObserver.observe(listElement)
You can disconnect your mutation observer with yourMutationObserver.disconnect() method whenever you want.
This could help too if you confused about how to implement it https://stackoverflow.com/a/48145840/14138428

Is it possible to change domparser element to string?

I have some HTML string. Use domparser to update some values, now i need back to HTML string format with updated values... Bcoz document.write accept only string.
Checkout the Sample patch,
const domName = 'MOBILE_NO';
// Below dom was getting from api.
const dom = '<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Please do not refresh this page...</h1></center><form method="post" name="paytm_form"><input type="hidden" name="MOBILE_NO" value="xxxxxxxx"></form></body></html>';
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(dom, 'text/html');
parsedHtml.getElementsByName(domName)[0].setAttribute('value', '1234567890');
// now i need to replace current update data entire screen
document.write(parsedHtml)
Thanks,
Gopal.R
Bcoz document.write accept only string.
Using document.write is almost always poor practice.
But, if for some reason you really need to, what you get back from parseFromString is a Document object. It has a single documentElement, which you can get the innerHTML or outerHTML of:
document.write(parsedHtml.documentElement.innerHTML);
// or
document.write(parsedHtml.documentElement.outerHTML);
Live Example:
const domName = 'MOBILE_NO';
// Below dom was getting from api.
const dom = '<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Please do not refresh this page...</h1></center><form method="post" name="paytm_form"><input type="hidden" name="MOBILE_NO" value="xxxxxxxx"></form></body></html>';
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(dom, 'text/html');
parsedHtml.getElementsByName(domName)[0].setAttribute('value', '1234567890');
// now i need to replace current update data entire screen
document.write(parsedHtml.documentElement.innerHTML);
But, again, probably better to just append to the page, e.g.
document.body.appendChild(parsedHtml.documentElement);
Live Example:
const domName = 'MOBILE_NO';
// Below dom was getting from api.
const dom = '<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Please do not refresh this page...</h1></center><form method="post" name="paytm_form"><input type="hidden" name="MOBILE_NO" value="xxxxxxxx"></form></body></html>';
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(dom, 'text/html');
parsedHtml.getElementsByName(domName)[0].setAttribute('value', '1234567890');
document.body.appendChild(parsedHtml.documentElement);
Or loop through it and append its children:
let child = parsedHtml.documentElement.firstChild;
while (child) {
let next = child.nextSibling;
document.documentElement.appendChild(child);
child = next;
}
Live Example:
const domName = 'MOBILE_NO';
// Below dom was getting from api.
const dom = '<html><head><title>Merchant Checkout Page</title></head><body><center><h1>Please do not refresh this page...</h1></center><form method="post" name="paytm_form"><input type="hidden" name="MOBILE_NO" value="xxxxxxxx"></form></body></html>';
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(dom, 'text/html');
parsedHtml.getElementsByName(domName)[0].setAttribute('value', '1234567890');
let child = parsedHtml.documentElement.firstChild;
while (child) {
let next = child.nextSibling;
document.documentElement.appendChild(child);
child = next;
}

How to make Gnome Shell extension query for changes

I've been battling the horrendous Gnome API documentation and came up with this extension:
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const GLib = imports.gi.GLib;
let label;
function init() {
label = new St.Bin({ style_class: 'panel-label' });
let stuff = GLib.spawn_command_line_sync("cat /home/user/temp/hello")[1].toString();
let text = new St.Label({ text: stuff });
label.set_child(text);
}
function enable() {
Main.panel._rightBox.insert_child_at_index(label, 0);
}
function disable() {
Main.panel._rightBox.remove_child(label);
}
This should read whatever is in the hello file and display it in the top panel. However, if I change the contents of the hello file, I have to restart Gnome for that new content to be shown. Now, surely there is a way to do this dynamically but I just couldn't find anything in the documentation. The message in the panel should basically always mirror whatever is in the file. Any ideas how to do this?
You'll want to obtain a Gio.File handle for your hello file, and then monitor it:
let helloFile = Gio.File.new_for_path('/home/user/temp/hello');
let monitor = helloFile.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', function (file, otherFile, eventType) {
// change your UI here
});
This worked for me. It will refresh the label value each 30 seconds.
Add the following import
const Mainloop = imports.mainloop;
In your init method
Mainloop.timeout_add(30000, function () {
let stuff = GLib.spawn_command_line_sync("your_command")[1].toString();
let label = new St.Label({ text: stuff });
button.set_child(label);return true});

Categories

Resources