How do I stop multiple bookmarklets from appearing? - javascript

I am in the process of making a bookmarklet that pops up a div with various things in it... when you click on the link to open the bookmarklet twice, two bookmarklets pop up. how do I prevent this from happening?
index.html:
<html>
<head>
<title>Bookmarklet Home Page</title>
<link rel="shortcut icon" href="favicon.ico" />
</head>
<body>
click here
</body>
</html>
code.js:
function toggle_bookmarklet() {
bookmarklet = document.getElementById("bookmarklet");
if (bookmarklet.style.display == "none") {
bookmarklet.style.display = "";
}
else {
bookmarklet.style.display = "none";
}
}
div = document.createElement("div");
div.id = "bookmarklet";
div.style.margin = "auto";
div.style.position = "fixed";
content = "";
content += "<a href='javascript:void(0);'><div id='xbutton' onClick='javascript:toggle_bookmarklet();'>x</div></a>";
div.innerHTML = content;
document.body.appendChild(div);

Just check for the existence of div before creating it.
var div = document.getElementById("bookmarklet");
if (!div)
{
div = document.createElement("div");
div.id = "bookmarklet";
div.style.margin = "auto";
div.style.position = "fixed";
}
Also, since you already have a global reference to div, you don't need to search for it by id in toggle_bookmarklet. You can just reference div. I'd try to choose a more unique name though, so as to avoid running in to naming collisions.
Edit: For that matter, if you are going to use a global variable, you can simplify further. Don't even bother giving it an id, just use the global reference:
function toggle_bookmarklet() {
bookmarkletEl.style.display = bookmarkletEl.style.display == "none" ? "" : "none";
}
if (!window.bookmarkletEl) {
var bookmarkletEl = ddocument.createElement("div");
bookmarkletEl.style.margin = "auto";
bookmarkletEl.style.position = "fixed";
}

Related

Popup won't close

Popup won't close when i click close button, i tried debugging with console.log and it looks like closeButton.onclick function doesn't run at all for some reason.
When running close() function manually from the console everything works fine.
class Popup {
constructor(content){
this.div = document.createElement("div");
this.div.className = "block";
//tried positioning popup into the center of the screen, doesn't work yet
this.div.style.position = "fixed";
this.div.style.margin = "auto auto";
//caption
this.caption = document.createElement("div");
this.caption.style.textAlign = "right";
//closeButton
this.closeButton = document.createElement("button");
this.closeButton.textContent = "X";
this.closeButton.onclick = this.close;
document.body.appendChild(this.div);
this.div.appendChild(this.caption);
this.caption.appendChild(this.closeButton);
this.div.innerHTML += content;
}
close(){
this.div.parentNode.removeChild(this.div);
delete this;
}
}
new Popup("close me");
That's how it looks like:
var popup = new Popup("hm hello");
SOLUTION:
The issue was happening because:
I was appending content of the popup right into main div using +=. That made DOM refresh and onclick trigger reset.
this.closeButton.onclick = this.close; here onclick trigger will execute close function and also will overwrite this keyword, so it contains a button that called trigger, not the Popup object. I decided to put Popup into a variable that is visible to onclick function. Now everything works fine.
class Popup {
constructor(content){
this.div = document.createElement("div");
this.div.className = "block";
this.div.style.position = "fixed";
this.div.style.margin = "auto auto";
//делоем капшон
this.caption = document.createElement("div");
this.caption.style.textAlign = "right";
//кнопка закрытия
this.closeButton = document.createElement("button");
this.closeButton.textContent = "X";
let popup = this;
this.closeButton.onclick = function(){popup.close()};
this.content = document.createElement("div");
this.content.innerHTML = content;
this.caption.appendChild(this.closeButton);
this.div.appendChild(this.caption);
this.div.appendChild(this.content);
document.body.appendChild(this.div);
}
close(){
this.div.parentNode.removeChild(this.div);
delete this;
}
}
new Popup("hello guys");
The issue is that right here:
this.div.innerHTML += content;
When you assign a value to .innerHTML, the entire previous value is overwritten with the new value. Even if the new value contains the same HTML string as the previous value, any DOM event bindings on elements in the original HTML will have been lost. The solution is to not use .innerHTML and instead use .appendChild. To accomplish this in your case (so that you don't lose the existing content), you can create a "dummy" element that you could use .innerHTML on, but because of performance issues with .innerHTML, it's better to set non-HTML content up with the .textContent property of a DOM object.
You were also going to have troubles inside close() locating the correct parentNode and node to remove, so I've updated that.
class Popup {
constructor(content){
this.div = document.createElement("div");
this.div.className = "block";
this.div.style.position = "fixed";
this.div.style.margin = "auto auto";
//caption
this.caption = document.createElement("div");
this.caption.style.textAlign = "right";
//closeButton
this.closeButton = document.createElement("button");
this.closeButton.textContent = "X";
this.closeButton.addEventListener("click", this.close);
this.caption.appendChild(this.closeButton);
this.div.appendChild(this.caption);
// Create a "dummy" wrapper that we can place content into
var dummy = document.createElement("div");
dummy.textContent = content;
// Then append the wrapper to the existing element (which won't kill
// any event bindings on DOM elements already present).
this.div.appendChild(dummy);
document.body.appendChild(this.div);
}
close() {
var currentPopup = document.querySelector(".block");
currentPopup.parentNode.removeChild(currentPopup);
delete this;
}
}
var popup = new Popup("hm hello");
I've finally found a final solution.
As Scott Marcus mentioned in his answer, i will have troubles inside close function, so i decided to put Popup object into a variable that is visible to close function. Everything works fine without applying classes. Though it may look like a bad code.
class Popup {
constructor(content){
this.div = document.createElement("div");
this.div.className = "block";
this.div.style.position = "fixed";
this.div.style.margin = "auto auto";
//делоем капшон
this.caption = document.createElement("div");
this.caption.style.textAlign = "right";
//кнопка закрытия
this.closeButton = document.createElement("button");
this.closeButton.textContent = "X";
let popup = this;
this.closeButton.onclick = function(){popup.close()};
this.content = document.createElement("div");
this.content.innerHTML = content;
this.caption.appendChild(this.closeButton);
this.div.appendChild(this.caption);
this.div.appendChild(this.content);
document.body.appendChild(this.div);
}
close(){
this.div.parentNode.removeChild(this.div);
delete this;
}
}
new Popup("hello guys")
P.S.
What's the point of this restriction?

Javascript element.display = "none" still shows div

So I'm building a website where I create elements with javascript and give content to them stored in array that I get from database, which I was able to successfully accomplish. However, I want to not display the div parent that contains all other elements added through javascript when a user clicks on a button within the div that I want not to display. However, I noticed two problems that I want to figured out why it's worked as it is. First, when I click on the button, and I apply display none to its parent, it always applies display none on the last created div instead of the corresponding div parent of the element it was clicked. Also, even though the display none is applied to the last div (though like I said, I want it to apply display none to the parent of the clicked button), the last div is still displayed on the page though it's display is none.
I need help figuring out these two problems. Any help will be appreciated. Thanks. Btw, please don't mark duplicate because I did look up for similar problems but none of the solutions apply to the problem I'm having.
Here is the javascript code:
var j = 0;
for (var i = 0; i < array.length; i++) {
var mydiv = document.createElement('div');
var element = document.createElement('p');
var element2 = document.createElement('p');
var raiseRating = document.createElement('button');
var lowerRating = document.createElement('button');
var rating = document.createElement('h1');
var flag = document.createElement('button');
// Index is set to hold the id so it can be used to identify the quotations whose button was clicked
index[i] = array[i][j+3];
//raiseRating.id = "raiseRating";
raiseRating.innerHTML = "+";
// lowerRating.id = "lowerRating";
lowerRating.innerHTML = "-";
flag.innerHTML = "flag"
rating.innerHTML = array[i][j+2];
element.innerHTML = '\"' + array[i][j] + '\"';
element2.innerHTML = '\--' + array[i][j+1];
mydiv.appendChild(element);
mydiv.appendChild(element2);
mydiv.appendChild(raiseRating);
mydiv.appendChild(rating);
mydiv.appendChild(lowerRating);
mydiv.appendChild(flag);
if (document.body.appendChild(mydiv)) {
flag.addEventListener("click", function(){
console.log("this should print");
mydiv.style.display = "none";
//console.log(mydiv);
});
}
}
UPDATE: Here is the html since someone asked for it
<!doctype html>
<html lang="en">
<head>
<title>Quotation Service</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
<link href="https://fonts.googleapis.com/css?family=Cookie"
rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Quicksand"
rel="stylesheet">
</head>
<body>
<div class="top-bar">
<h1>Quotes</h1>
<a href="register.php" >Register</a>
Login
Add Quote
</div>
</body>
</html>
I did not know what var array was so I just removed.This should point you in the right direction. The problem is your closures. I commented so you could notice. Read about them!
var j = 0;
for (var i = 0; i < 10; i++) {
var mydiv = document.createElement('div');
var element = document.createElement('p');
var element2 = document.createElement('p');
var raiseRating = document.createElement('button');
var lowerRating = document.createElement('button');
var rating = document.createElement('h1');
var flag = document.createElement('button');
// Index is set to hold the id so it can be used to identify the quotations whose button was clicked
//raiseRating.id = "raiseRating";
raiseRating.innerHTML = "+";
// lowerRating.id = "lowerRating";
lowerRating.innerHTML = "-";
flag.innerHTML = "flag"
mydiv.appendChild(element);
mydiv.appendChild(element2);
mydiv.appendChild(raiseRating);
mydiv.appendChild(rating);
mydiv.appendChild(lowerRating);
mydiv.appendChild(flag);
/** CLOSURE STARTS **/
(function(flag, node){
if (document.body.appendChild(node)) {
flag.addEventListener("click", function(){
console.log("this should print");
node.style.display = "none";
});
}
}(flag, mydiv));
/**CLOSURE ENDS **/
}

Can't find DIV in JS

I'm creating a webPage, I need to get an element by ID, but when I try to do it, the element returned is a null object.
I think because the div that I want to get is added in the HTML code when I press a button, but my JS code is compiled when the page is loaded, so JS can't find the div... How can I select my div with JS?
<html><head><script>
function getDiv(){
var div = document.getElementById('div_name');
div.innerHTML = "SOMETHING"; //div is null
//<div id="div_name"></div> isn't added when the page is loaded
}
function addDiv()
{
var iDiv = document.createElement('div');
iDiv.id = 'div_name';
document.getElementsByTagName('body')[0].appendChild(iDiv);
}
</script></head>
<body>
<button onClick="getDiv()">GETDIV</button>
<!-- Pretend that with this button I add the div with 'div_name' in my HTML
page -->
<button onClick="addDiv()">ADDDIV</button>
</body></html>
Refer below code :-
<!DOCTYPE html>
<html>
<head>
<title></title>
<script>
function addDiv(){
var div = document.getElementById('div_name');
var isDivPresent = (div && (div !== null ));
if(isDivPresent){
return;
}
var createDiv = document.createElement("div");
createDiv.setAttribute("id", "div_name");
createDiv.style.backgroundColor = "lightblue";
createDiv.style.width='250px';
createDiv.style.height='300px';
document.getElementsByTagName('body')[0].appendChild(createDiv);
}
function getDiv(){
var div = document.getElementById('div_name');
var isDivPresent = (div && (div !== null ));
if(!isDivPresent) {
addDiv();
getDiv();
}else {
div.innerHTML = "SOMETHING";
}
}
</script>
</head>
<body>
<button onClick="addDiv()">ADDDIV</button>
<button onClick="getDiv()">GETDIV</button>
</body>
</html>
function getDiv(){
var div = document.getElementById('div_name');
div.innerHTML = "SOMETHING"; //div is null
}
function addDiv(){
if(!document.getElementById('div_name')){
var div = document.createElement("div");
div.id = 'div_name';
div.innerHTML = "Added Through add div";
document.body.appendChild(div);
}
}
<button onClick="getDiv()">GETDIV</button>
<button onClick="addDiv()">ADDDIV</button>
here is a code that works as you whish. The main differences is :
I used onclick as attribute name instead of onClick
function addDiv() {
var div = document.createElement('div');
div.id = 'div_name';
document.body.appendChild(div);
div.innerHTML = 'initial content';
}
function updateDiv() {
var div = document.getElementById('div_name');
div.innerHTML = 'new content';
}
<!DOCTYPE html>
<html>
<head></head>
<body>
<button onclick="addDiv();">add div</button>
<button onclick="updateDiv();">replace div content</button>
</body>
</html>
If you click the GETDIV button without clicking the ADDDIV button first, then the div you're looking for isn't anywhere in the document body. So I would change the getDiv() like so:
function getDiv(){
var div = document.getElementById('div_name');
if(!div) { // if div is not added yet, then add it
addDiv();
}
div.innerHTML = "SOMETHING"; //div is null
}

Create div above other div only with javascript

I need create a div above another div, but I dont have access to the css file, thus everything needs to be done via JavaScript.
This is my wrong code:
var div = document.getElementById("down");
var divAbove = document.createElement("div");
divAbove.id = "up";
divAbove.style.background = "red";
divAbove.style.position = "absolute";
divAbove.style.width = "150px"
div.appendChild(divAbove );
I can't see the new div.
If you can pinpoint the container element you can make use of .insertBefore()
More Info (docs)
var container = document.getElementById("container");
var div = document.getElementById("down");
var divAbove = document.createElement("div");
divAbove.id = "up";
divAbove.style.backgroundColor = "red";
divAbove.style.width = "110px"
divAbove.style.height = "60px"
divAbove.innerHTML = "Added via JS"
container.insertBefore(divAbove, div);
<div id='container'>
<div id='down' style='height: 60px; width: 110px; background-color: yellow'>
Existing element
</div>
</div>
This work.
var div = document.getElementById("down");
var divAbove=document.createElement("div");
divAbove.id = "up";
divAbove.style.background = "red";
divAbove.style.position = "absolute";
divAbove.style.width = "150px";
divAbove.style.height= "150px";
div.appendChild(divAbove);
From this point I would say that the div is there, but due to a typo in divAbov.style.background = "red"; it does not have a visible background. Try fixing the typo.
If the problem persists, please post your console log if there is any errors in there.
The reason you can't see new div is that you didn't give any body to it. For example, it may be a case to write before appending divAbove the following:
divAbove.innerHTML = "Hello World";

tag onclick being processed twice

I want clicking on an "expando" to toggle between its states: expanded and collapsed.
I'm still pretty new to DOM/JS, so my style here is probably awful; If you have any style guidelines let me know, but for right now I want to get the code working. I've tried a few different ways, like setting the expand or collapse behavior in dom's onclick (and changing it in the expand and collapse functions), but if I do that, then for some reason clicking doesn't trigger a collapse, but it will trigger an expand.
The problem with the code below is that I can expand an expando, but when I click on it, it also triggers the collapse, so it expands and then immediately collapses back.
var expandos = document.getElementsByTagName("expando");
var uid = 0;
for(var i=0; i<expandos.length; ++i) {
var dom = expandos[i];
dom.id = "expando_"+uid++;
var iframe = document.createElement("iframe");
iframe.src = dom.innerHTML;
iframe.name = dom.id +".big";
iframe.id = iframe.name;
iframe.scrolling = "no";
iframe.style.display = "inline";
iframe.onclick = collapse(dom);
var p = document.createElement("p");
var text = document.createTextNode(dom.innerHTML);
p.id = dom.id+".small";
p.style.display = "inline";
p.appendChild(text);
p.onclick = expand(dom);
dom.innerHTML = "";
/* We have to clear the innerHTML to prevent the original text from
showing up in addition to the text added by p.
*/
dom.appendChild(iframe);
dom.appendChild(p);
/* We have to append iframe and p **after** we clear innerHTML
because otherwise clearing innerHTML will clear the appended
children.
*/
function expand(dom) {
return function() {
alert("Expanding "+dom.id);
var iframe = document.getElementById(dom.id+".big");
var p = document.getElementById(dom.id+".small");
p.style.display = "none";
iframe.style.display = "initial";
dom.onclick = collapse(dom);
}
}
function collapse(dom) {
return function() {
alert("Collapsing "+dom.id);
var iframe = document.getElementById(dom.id+".big");
var p = document.getElementById(dom.id+".small");
p.style.display = "initial";
iframe.style.display = "none";
dom.onclick = expand(dom);
}
}
collapse(dom)();
}
The sample HTML I'm testing on:
<body>
<expando>The quick brown</expando> fox jumps over <expando>the lazy dog</expando>.
<script src="loadExpandos.js"></script>
</body>
In the same directory, I have files named "The quick brown" and "the lazy dog", and they expand properly.
A quick fix for to get the basic functionality you want is to combine your expand and collapse into a single function and have an if/else block that checks the state. Not 100% on what caused your original issue, but I'd guess it has something to do with your onClick events not being cleared.
function clickHandler(dom) {
return function() {
var iframe = document.getElementById(dom.id+".big");
var p = document.getElementById(dom.id+".small");
if(p.style.display === "initial"){
p.style.display = "none";
iframe.style.display = "initial";
} else {
p.style.display = "initial";
iframe.style.display = "none";
}

Categories

Resources