I am trying to write a bookmarklet that sends me a desktop notification when CI on GitHub completes. Notification.requestPermission runs correctly, and asks me for permission, and the console.log statements run correctly, but the notification does not appear. Here is the text of the bookmarklet script:
(function() {
Notification.requestPermission().then(() => {
const search = setInterval(() => {
if (window.find("All checks have passed")) {
console.log('all checks passed');
clearTimeout(search);
new Notification('Github checks passed!');
} else {
console.log('checks pending');
}
}, 1000);
});
})();
i.e.
javascript:(function() {Notification.requestPermission().then(() => {const search = setInterval(() => {if (window.find("All checks have passed")) {console.log('all checks passed');clearTimeout(search);new Notification('Github checks passed!');} else {console.log('checks pending');}}, 1000);});})();
Is this a sandboxing thing?
I have tried with the same code you have written and tried to add few tweaks and verify the existing code.
I have seen that there not an issue with your code. I have tried to simulate the same situation with your code and it works.
In order to work on your code, I have added dummy text in the HTML body after 5 seconds of page loads, meanwhile, setTimeout function logs checks pending
After 5 seconds it a text in the body and after that it goes to search the text and the code works fine.
Here my little tweaks which might help you to identify the root cause. I guess if your code is working on these tweaks, it means that somehow in your real situation the text might not found from the HTML template.
Yes, one more thing you should keep in mind that you must allow notification when the browser asks in popup, Once you allow the show the notification, in the next attempt it will populate the notification with suggested text.
Following code, I have tried.
minify version:
javascript:(function(){Notification.requestPermission().then(()=>{let e=0;console.log("find:",window.find("All checks have passed"));const n=setInterval(()=>{if(window.find("All checks have passed"))clearTimeout(n),new Notification("Github checks passed!");else{if(5===e){const e=document.createElement("label");e.innerHTML="All checks have passed",document.body.appendChild(e)}console.log("checks pending")}e+=1},1e3)})})();
beautify version:
javascript: (function() {
Notification.requestPermission().then(() => {
let counter = 0;
console.log("find:", window.find("All checks have passed"));
const interval = setInterval(() => {
if (window.find("All checks have passed")){
clearTimeout(interval);
console.log("checks passed");
new Notification("Github checks passed!");
} else {
if (5 === counter) {
const el = document.createElement("label");
el.innerHTML = "All checks have passed";
document.body.appendChild(el);
}
console.log("checks pending");
}
counter += 1;
}, 1000)
})
})();
I have also attached the screenshots for your reference.
For your reference, this code will work in the console also it will populate the message in your console also.
Hope it might clear your idea.
This code is 100% working, so if you still face the trouble, let me know I will definitely try to help you.
As others have said, the code works as expected.
My guess is you're having problems with the setInterval function. On firefox, setInterval doesn't run when the tab isn't on focus (you also lose focus when you execute the bookmarklet from the bookmark tab).
I assume you navigated to a different tab which results in the timer stopping. Unfortunately I don't think there's an easy solution to get the result you want.
See here for reference: SetInterval not running in Firefox when lost focus on tab/window
Related
Imagine I have the following simple html:
const inEl = document.querySelector("input")
const buttonEl = document.querySelector("button")
inEl.oninput = (() => {
buttonEl.remove()
setTimeout(() => {
document.body.appendChild(buttonEl)
}, 100)
})
.b {
background: blue;
}
<input>
<button>weee</button>
As you can see, as someone types in the input, the button is temporarily removed from the DOM. I'd like to add a cypress test that checks that the button is NOT removed from the dom (so it would need to fail for the above scenario).
It seems simple enough, but because cypress is so good at waiting for things to appear, I'm not totally sure how to write this test.
It feels like what I need is a way to throw an error if a cypress command does pass. Something like
cy.get("input").type("hello")
cy.get("button").should("not.exist") //if this passes then throw an error!
Any help on how to do this seemingly simple thing would be appreciated. Thanks!
https://docs.cypress.io/guides/core-concepts/retry-ability#Disable-retry
You can set the timeout to 0 to disable retry
so you could add
cy.get("button", { timeout: 0 }).should("not.exist")
to make sure the button does not flicker.
One possibility is to spy on the remove method
let spy;
cy.get("button").then($button => {
spy = cy.spy($button[0], 'remove')
})
cy.get("input").type("hello")
.should(() => expect(spy).to.not.have.been.called)
If you try to do visibility or existence checks you run the risk of false results, because that script will run quite quickly.
If you want to do so, you could control the clock
// This passes if the remove/append runs
cy.clock()
cy.visit(...)
cy.get("input").type("h") // one letter only
cy.tick(20) // 10ms is default delay in .type()
cy.get('button').should('not.exist') // clock is frozen part way through setTimeout
cy.tick(100)
cy.get('button').should('exist') // clock has moved past setTimeout completion
// This checks the remove/append does not run
cy.clock()
cy.visit(...)
cy.get("input").type("h") // one letter only
cy.tick(20)
cy.get('button').should('exist') // fails here if the button is removed
cy.tick(100)
cy.get('button').should('exist')
I want to get the currentFrame of my Flash movie when it is loaded. I followed the the tutorial found here http://learnswfobject.com/advanced-topics/executing-javascript-when-the-swf-has-finished-loading/index.html and SWFOBJECT CurrentFrame Javascript. I am using SWFObject 2.3 beta. This works perfectly fine on Internet Explorer however it does not work on Google Chrome.
In Chrome I get the error
Uncaught TypeError: e.ref.currentFrame is not a function
Checking e it returns [object Object]
Checking e.ref returns [object HTMLObjectElement]
Checking e.ref.totalFrames returns undefined
var flashvars = {};
var params = {};
var attributes = {};
function mycall(e){
setInterval(function(){console.log("Frame: " + e.ref.currentFrame)},1000);
}
swfobject.embedSWF("notmyswf.swf", "course", "100%", "100%", "6.0.0", false, flashvars, params, attributes, mycall);
Why is this not working on Chrome but works well with IE? Is the event e not detected? Is there a work-around on how to make this work on Chrome?
The purpose of this is for me to create a check if the user is really using the course he has opened and not just leaving it idle. I have already added a code that will check idle but it is not enough. Most learners, have figured out a way to just open a course, leave it there to accumulate hours of training. Some even have a program running in their computers that will just move the mouse 1-pixel every few seconds so that the computer does not go to idle. If I can check the current frame of the Flash movie, I can create a function that will calculate the current page the user is viewing every 15 minutes. If he is stuck in the same page I can then show a prompt that the user must click in order to continue viewing the course or it will automatically close.
I suggest dropping the SWF-based currentFrame approach in favor of monitoring your calls to the database using JavaScript. (Based on your comments, it sounds like the DB calls are being sent by JS, so this shouldn't be a problem.)
If the course bookmark is auto-saved every 3 minutes (as described in your comments), you can cache the value in your page's JS and do a compare every time the save is performed. If the value hasn't changed in x number of minutes, you can display your timeout warning.
If you're using a SCORM wrapper (or similar), this is really simple, just modify the wrapper to include your timer code. Something like:
//Old code (pseudocode, not tested)
function setBoomark (val){
API.SetValue("cmi.core.lesson_location", val);
}
//New code (pseudocode, not tested)
var current_location = "";
var activityTimer;
function disableCourse(){
//do stuff to disable course because it timed out
}
function setBoomark (val){
API.SetValue("cmi.core.lesson_location", val);
if(val === current_location){
//do nothing, timer keeps ticking
} else {
//reset timer using new bookmark value
if(activityTimer){ clearTimeout(activityTimer); }
activityTimer = setTimeout(disableCourse, 15000);
//Update current_location value
current_location = val;
}
}
This is a rough sketch but hopefully you get the idea.
I feel stupid!
It did not work in Chrome and Firefox because I used the wrong casing for the functions but in IE11 it works no matter the case.
So the correct functions are:
e.ref.CurrentFrame() //I used currentFrame() which still works in IE11
e.ref.TotalFrames() //I used totalFrames() which still works in IE11
e.ref.PercentLoaded() //I used this correctly and was able to get the value
I am building a note taking app for Chrome and I want the app to save its progress when the user stops typing, but I can't get chrome.idle to trigger a state change
chrome.idle.setDetectionInterval(10);
chrome.idle.onStateChanged.addListener(
function (newState) {
var messageElement = document.querySelector("#message");
messageElement.innerHTML = "idle";
if (newState === "idle")
save();
}
);
Chrome requires a permission to access the idle functionality so I have included the idle permission in the manifest. However, when I load the app with the extensions tool and view the permissions, it says I have no special permissions. Could this have anything to do with why the idle state change isn't triggering my function?
In case anyone else runs into this, the issue is that the minimum value setDetectionInterval will accept is 15. I found some code that is trying to do exactly what I am doing in a Safari Online book...
chrome.idle.setDetectionInterval(15);
chrome.idle.onStateChanged.addListener(
function (state) {
if (state === "idle" && dirty)
save();
}
);
This code is almost exactly the same, but this version works and mine didn't. The console prints an error that says the minimum value for the interval is 15 seconds where I was trying to check every 10. So I switched my code to check every 15 seconds and everything worked
I came here like many beginners :D So without wasting a time I will explain my problems.
http://heavenpro.lt/ukv - website of demo. There a 2 users etc.
sekret - demo
demo - demo
(for login) if you will see any error - would be happy to know to have a chance to solve it.
When users turned off (Išj. - button) demo user sees log: Waiting for student (Laukiama studento)
after sekret turn it on (Įjungt - button) everything seems okay, demo user sees active user, after clicking to next one - gives alert that was changed student and if you want to update information (to see new one) however.. after turning off (Išj. button) Works good in all browsers except IE.. Seems that clearInterval not works and after lot of sent queries and respons it pops out more than one Alert window..
Hope you understood that i mean.
var sid = "{$i->sid}";
var mid = "{$i->mid}";
var update_st = setInterval(function(){
$.post(
'ajax/check-student.php',
{ sid: sid, mid: mid },
function(resp){
if(resp == "next") {
var cf = confirm('Buvo pakeistas studentas besiginantis darbą. Ar rodyti sekantį studentą?');
clearInterval(update_st);
if (cf) {
window.location = "?";
}
else {
alert('Kai norėsite perjungti kitą vartotoją, prašome perkrauti puslapį.');
clearInterval(update_st);
}
}
else if (resp == "none") {
alert("Gynimas baigtas. Ačiū už dalyvavimą vertinimo komisijoje.");
clearInterval(update_st); // this place not works..
window.location = "?";
}
});
}, 250);
Tested lot times.. seems sometimes works normaly.. Tested on IE 9..
Of maybe can anyone offer any others ideas to do same way? Without many queries per second sending to file...
You can use setTimeout instead of setInterval, many reasons...
So you will call function that creates setTimeout! And this method will guarantee that your code will be executes iff query to server is done!
var a = function(){
var timer = setTimeout(function(){
// ok your ajax query success of error whatever
a();
console.log(2)
}, 1000);
}
a();
You must put your query inside setTimeout, and call a function after query done or whatever!
So demo
In this instance, I load a single paypal page, in which I am prompted to login. Once I login, the page changes, through the use of other javascripts on paypal's end. The address does not change on this transition, nor does the source code in any material way. I am trying to find a way to have my script wait long enough after the first click to be able to get the element that loads after. I thought I could do this fairly simple using the following:
document.getElementById("submitLogin").click();
window.onload = function() {
document.getElementById("continue").click();
};
When the script is executed, the first button is clicked, the page transitions, but it won't click the second button that loads. My javascript console does not report any errors, suggesting that it is able to "get" the element. Not sure why it won't click it though.
If nothing else, you could always poll for the existence of the "continue" element at some interval:
function clickContinue() {
var button = document.getElementById("continue");
return button ? button.click() : setTimeout(clickContinue, 100);
}
document.getElementById("submitLogin").click();
clickContinue();
If you go this route, you'll probably want to include a failsafe so it doesn't run too long, in case something unexpected happens. Something like this should work:
clickContinue.interval = 100; // Look for "continue" button every 0.1 second
clickContinue.ttl = 10000; // Approximate time to live: 10 seconds ~ 10,000 ms
clickContinue.tries = clickContinue.ttl / clickContinue.interval | 0;
function clickContinue() {
var button = document.getElementById("continue"),
interval = clickContinue.interval;
return button ? button.click() :
clickContinue.tries-- && setTimeout(clickContinue, interval);
}
// ...
Take a look at PayPal's API docs and see if they provide a way to set up a callback to handle this, though. This polling technique should probably only be used as a last resort.