I have a question for you guys I'm not 100% sure how to implement this
chrome.app.window.onKeyDown = function(e) {
if (e.keyCode == 27 /* ESC */) { e.preventDefault(); }
};
I have my manifest going to my main.js file and in that file is
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('browser.html', {
state: "fullscreen"
});
});
How do I add that OnKeyDown to my main.js to get it to work? Or do I need to put that function into another file? Any help would be appreciated
Try this:
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create(
'browser.html',
{state: "fullscreen"},
function(win) {
win.contentWindow.onKeyDown = function(e) ...
}
);
});
Alternatively, you can link another script from your HTML:
browser.html:
...
<script src="xyz.js"></script>
And reference the same window object from xyz.js as:
chrome.app.window.current().onKeyDown = ...
I don't see chrome.app.window.onKeyDown in the Chrome API documentation.
The DOM window is available as win.contentWindow (not as win), assuming win is the argument to the chrome.app.window.create callback function. That's the window to which you should add a listener, using the addListener function. I'm not sure that onKeyDown as a property (...onKeyDown = function...) is defined.
It makes no difference whether you add the listener in the background.js page or the page referenced from the HTML file. I would think that the latter would be better, as a keydown event is only relevant to the user interface, not the background page. Also, whatever actions you take when a key is pressed probably are for the app page, not the background page.
Related
What is the best practice of adding event listeners to elements which may not appear on the page?
For example, let's say we have a comment form that appears on article pages to which a submit event listener is attached.
document.getElementById('commentform').addEventListener('submit', event => {
/* do something */
})
This code is placed in a script.js file of the site template which is loaded on every page. However, pages on which the comment form does not appear will cause an error:
Uncaught TypeError: Cannot read property 'addEventListener' of null...
How can we prevent this TypeError from occurring?
The simple way would be to just check to see if the element exists first...
const commentForm = document.getElementById('commentform');
if (commentForm) {
commentForm.addEventListener('submit', event => {
/* do something */
})
}
In modern environments, you can use optional chaining:
document.getElementById('commentform')?.addEventListener('submit', event => {
/* do something */
})
But an even better approach would be to have a setup such that the commentform on the page is completely attached to its associated script, so that one without the other doesn't ever come up. Often one would use a framework for this, to integrate the commentform's HTML with its submit listener. That's what I'd recommend for something professional. Lacking that, you could also put the commentform's script right next to the commentform:
<form id="commentform">
...
</form>
<script>
document.getElementById('commentform').addEventListener('submit', event => {
/* do something */
})
</script>
Notbestpractice
As #CertainPerformance says, in production code you'd want to set up your script loading so that never happens. However, one trick I've used in a userscript environment where I don't have as much control over the loading is to use a MutationObserver.
window.addEventListener('load', function() {
let button = document.querySelector('.blahblahblah');
if (button) {
button.click();
console.log('Button found early');
}
// This waits to run until ".somerootelement" has changed
let mo = new MutationObserver(function() {
document.querySelector('.blahblahblah').click();
console.log('Button found late');
});
mo.observe(document.querySelector('.somerootelement'), { childList: true });
});
But I would say 90% of the time this is an anti-pattern. Certainly if you can change the script loading so the dependencies load properly.
I'm having what seems to be a really simple issue that I really can't find a solution for:
In my code I have a script loaded in the header:
<script type="text/javascript" src="../js/viewdoc/index.js?v=1.33"></script>
In that specific script I declare the functions:
function addResizeListener(listener){
//Attach the back button function to window resize event
if(window.attachEvent) {
window.attachEvent('onresize', listener); //Old browsers
}
else if(window.addEventListener) {
window.addEventListener('resize', listener, true); //New browsers
}
}
and:
function removeResizeListener(listener){
//Remove the listener for the back button
if(window.detachEvent) {
window.detachEvent('onresize', listener);
}
else if(window.removeEventListener) {
window.removeEventListener('resize', listener, true);
}
}
then I load this file into the element with a loaderdoc id:
if ($('#loaderdoc').is(':empty')){
$('#loaderdoc').load('../viewdoc/welcome.php');
}
I use the function addResizeListener to bind a function to the window resize event, this works perfectly, and the index.js script ends.
In the end of the loaded file welcome.php i added the line
<script src="../js/viewdoc/welcome.js"></script>
welcome.js is a script that uses the functions removeResizeListener and addResizeListener, but I get the error:
Uncaught ReferenceError: addResizeListener is not defined
Why is this? Wasn't the functions defined and loaded before the script was added to the document?
Sorry if this was answered before, I just couldn't really find it, or maybe I don't know he right way to search for it yet.
And thanks for reading!
jQuery's .load() is async. Thus welcome.js will be executed, before the functions are defined. You have to use a callback. See https://api.jquery.com/load/
If i put some script in HTML file to change the animation play state,it's works.But when i put the script in a script file,it's not working.Can anyone tell me why?
script like this:
var buttons=document.getElementsByTagName("button");
for(var i=0;i<buttons.length;i++) {
console.log(buttons.length);
buttons[i].onclick=function(e) {
document.getElementById("para")
.style.WebkitAnimationPlayState=e.target.innerHTML;
};
}
The elements may not be defined in document. Try placing the existing script within load event handler of window
function toggleAnimationPlayState() {
var buttons=document.getElementsByTagName("button");
for(var i=0;i<buttons.length;i++) {
console.log(buttons.length);
buttons[i].onclick=function(e) {
document.getElementById("para")
.style.WebkitAnimationPlayState=e.target.innerHTML;
};
}
}
window.addEventListener("load", toggleAnimationPlayState);
Your script dependens on the existing of this Button :
=document.getElementsByTagName("button");
So,
it works because the script has been running after rendering the button .
It does not work because either :
Fail to import script. (check browser's console)
OR
Import the script BEFORE rendering the button .
Solution :
follow this order .
<button>....</button>
.......
<script src="/uri/of/script.js"></script>
OR, run your code inside onload listner of window
$("#submit").click(function(event) {
var jsonResponse = ....
var val = jsonResponse.results[0].myId;
externalFunc(val);
});
this is all in a js file in DOCUMENTROOT/tabs/sp/js/sp.js, while the externalFunc function is found in DOCUMENTROOT/tabs/ru/js/ru.js. I put an alert in externalFunc that isn't popping up, and chrome dev tools doesn't recognize externalFunc, so it is a scope issue. How do I access this function only after the click event though?
Did you include DOCUMENTROOT/tabs/ru/js/ru.js file in your html document. if not please add it. this should solve your problem.
What seems to me is the reference issues, i mean your function file is been declared below the file which has the click event, you can try something like this:
<script src='ru.js'></script> //<----the function file
<script src='sp.js'></script> //<----the click event file
In my HTML-head i have this script included:
<script id="mode" type="text/javascript" src="article.js"></script>
With a button click I'd like to change the source of the script to customers.js so that it then looks like this:
<script id="mode" type="text/javascript" src="customers.js"></script>
The point is that I don't want the article.js to be included in my page then anymore, so I can't just use .append().
So, click on the article button -> only article.js included, click on the customers button -> only customers.js included.
I tried to solve this with jQuery this way, but I doesn' seem to work...:
$("#btArticle").click(function(){
$("#mode").attr("src","article.js");
});
$("#btCustomers").click(function(){
$("#mode").attr("src","customers.js");
});
Do you know where my mistake is?
Update: There are methods with the same name in customers.js and article.js. So there's a onSave() method in both of them and when I clicked the customer button before, I want the onSave() method of customers.js to be executed, not the one in articles.js.
The point is that I don't want the article.js to be included in my page then anymore, so I can't just use .append().
Once the script has been downloaded and evaluated, anything it leaves lying around will remain unless explicitly removed; they're not linked to the script element itself and removing it won't have any effect on them.
The only way to get rid of the stuff article.js leaves lying around is to remove or overwrite each and every thing it creates and keeps.
Concrete example:
// article.js
var foo = "bar";
jQuery(function($) {
$(".stuff").click(function() {
alert("You clicked stuff!");
});
});
If the article.js listed above is processed, you can remove the script element that loaded it, and that will have no effect on the foo global variable or the event handler that it hooked up.
If you want to have scripts that you can unload, have them use the module pattern with a single global symbol they add by assigning to a property on window, e.g.:
// article.js
window.articleScript = (function() {
var foo = "bar";
jQuery(function($) {
$(".stuff").bind("click.article", function() {
alert("You clicked stuff!");
});
});
function remove() {
$(".stuff").unbind("click.article");
try {
delete window.articleScript;
}
catch (e) { // Early IEs throw incorrectly on the above
window.articleScript = undefined;
}
}
return {
remove: remove
};
})();
You can then remove it by doing this:
articleScript.remove();
Re your comment on the question:
Maybe I should've mentioned that there are methods in both files with the same name.
If you have global function declarations in customers.js that use the same name as global function declarations in articles.js, when you load customers.js, it will replace those functions.
So if you have this in articles.js:
function foo() {
alert("Articles!");
}
...and this in customers.js:
function foo() {
alert("Customers!");
}
And you have a button:
<input type="button" onclick="foo();" value="Foo">
When you've loaded just articles.js and not customers.js, clicking that button gives you "Articles!". If you then load customers.js, clicking the button will give you "Customers!".
That works because the event handler calls foo(), but the event handler itself is not foo. The onclick attribute creates a hidden event handler for you. The equivalent jQuery would be:
$("input[type='button'][value='Foo']").click(function() {
foo();
});
Note that just doing .click(foo) will do something very different: It will hook up the function that foo points to at that moment as the event handler. Even if you change what foo points to later (by loading customers.js), that won't change the fact that the old function is hooked up as a handler.
FWIW, from the question and your comments, I think I'd recommend sitting back and reviewing your strategy for this page/app. All of this swapping of code in and out and such seems like a design problem.
You are not actually loading and running the respective scripts, you are just changing the source for that tag. Use .getScript() to load and run the appropriate JavaScript file:
http://api.jquery.com/jQuery.getScript/