.appendchild executing twice in CKeditor - javascript

I'm using the simpleuploads plugin for CKeditor. Everything's working perfect except for one itsy bitsy problem.
I'm trying wrap an uploaded image object in a div like so
<div class="image-container>
<img class="addedImg>
</div>
and have added the following at the bottom of /app/assets/javascripts/ckeditor/config.js
CKEDITOR.on('instanceReady', function(e) {
e.editor.on( 'simpleuploads.finishedUpload' , function(ev)
{
var element = ev.data.element;
if (element.getName() == 'img')
{
var img = element.$,
doc = img.ownerDocument,
div = doc.createElement('div');
img.setAttribute('class', 'addedImg');
img.removeAttribute('width');
img.removeAttribute('height');
div.setAttribute('class', 'image-container');
img.parentNode.replaceChild(div, img);
div.appendChild(img);
}
});
});
The problem is div is wrapped in another div like so:
<div class="image-container">
<div class="image-container">
<img class="addedImg">
</div>
</div>
How do I get the script to execute only once?
EDIT:
Issue caused by my custom assets/javascripts/ckeditor/config.js being loaded, and then the galetahub gem's assets/ckeditor/config.js being loaded again. Not sure where the problem lies. Will post more details if solution is found.

The code is fine, but that file is being included twice so the listener is executed twice. The problem can be avoided by stopping the finishedUpload event after is being executed the first time:
CKEDITOR.on('instanceReady', function(e) {
e.editor.on( 'simpleuploads.finishedUpload' , function(ev)
{
var element = ev.data.element;
if (element.getName() == 'img')
{
var img = element.$,
doc = img.ownerDocument,
div = doc.createElement('div');
img.setAttribute('class', 'addedImg');
img.removeAttribute('width');
img.removeAttribute('height');
div.setAttribute('class', 'image-container');
img.parentNode.replaceChild(div, img);
div.appendChild(img);
ev.stop(); // Stop the event in case the listener is inserted twice
}
});
});

Related

Toggle image source with jQuery

I want to do something interesting, so for example i have an image on my website and i want to change it when a button is triggered, but then i want to revert it back to the original when the button is clicked again (or add the same img to it) and repeat this all the time when the event is clicked. How can I achieve this ?
Here is my current Jquery but only that works for one time click
$('#menu-btn').on({
'click': function () {
$('#div1').attr('src', 'images/card-light.png');
}
});
Html code
<button id="menu-btn">click me</button>
<img id="div1" src="./images/card-dark.png">
Assets
images/card-dark.png
images/card-light.png
On document load, store the image source in a variable. In our case, it's called prev.
Inside the toggle function, we check whether the source of the image is equal to the source when it was loaded. If it was, we change the source to another image. When the source is changed and we call the toggle function again, we know that the source is different from the previous one, so we revert it back to the original source.
$(document).ready(function() {
var img = $('#img');
var prev = img[0].src;
function toggle(img) {
let src = img.src;
if (src == prev) {
img.src = "https://pbs.twimg.com/profile_images/453956388851445761/8BKnRUXg_400x400.png";
img.height="48";
} else {
img.src = prev;
}
}
$('button').on('click', function() {
toggle(img[0]);
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" height="48"></script>
<img id="img" src="https://www.gravatar.com/avatar/0fdacb141bca7fa57c392b5f03872176?s=48&d=identicon&r=PG&f=1">
<button>Toggle</button>
We can take it a step further by using data attributes to store the two sources so you can easily extend this for multiple images.
$(document).ready(function() {
var img = $('#img');
var prev = img[0].src;
function toggle(i) {
let src = i[0].src;
let dsrc = i.data('switch-with');
if(dsrc==src){
i[0].src=prev;
}else{
i[0].src=dsrc;
i[0].height="48";
}
}
$('button').on('click', function() {
toggle(img);
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" height="48"></script>
<img id="img" src="https://www.gravatar.com/avatar/0fdacb141bca7fa57c392b5f03872176?s=48&d=identicon&r=PG&f=1" data-switch-with="https://pbs.twimg.com/profile_images/453956388851445761/8BKnRUXg_400x400.png">
<button>Toggle</button>

JS function when clicking parent element but return false when clicking child element

I have an image gallery on my site and when you click on it, it opens into a lightbox kind of effect.
I want them to be able to click off of the preview image on the lightbox background and close the preview but not if they click on the actual preview image itself.
function get_image_preview(){
var lightbox = document.getElementById("lightbox");
var image_src = document.getElementById("gallery_image").src;
lightbox.style.display = "block";
lightbox.setAttribute("onclick", "end_image_preview()");
var new_image = document.createElement("img");
new_image.setAttribute("id", "preview_image");
new_image.setAttribute("src", image_src);
new_image.setAttribute("onclick", "return false");
lightbox.appendChild(new_image);
}
function end_image_preview(){
var lightbox = document.getElementById("lightbox");
lightbox.style.display = "none";
lightbox.innerHTML = "";
}
So basically this line:
lightbox.setAttribute("onclick", "end_image_preview()");
does what it is supposed to do and close the preview.
However, the preview is a child of this and I want them to be able to click on the image without ending the preview, so I tried this:
new_image.setAttribute("onclick", "return false");
I think you mignt want to use event.stopPropagation():
function new_image_click(e) {
e.stopPropagation();
}
new_image.setAttribute("onclick", "new_image_click(event)");
in your end image preview click listener make sure that the element does not have in its ancestor the preview element it self, lets say that you gave the preview element the id "preview"
in end_image_preview
function end_image_preview(e) {
if (e.closest('#preview')) {
return
}
// here do what you already doing
}

Load content in div from a href tag in jQuery

I want to load all images before displaying them in a slideshow. I have been searching a lot but nothing seems to work. This is what i have so far and it doesn't work. I am loading images from the <a> tag from another div.
$('.slideshow').load(function(){
if (loaded<length){
first = $(settings.thumb).eq(loaded).find('a').attr("href");
$('<img src="'+first1+'"/>').appendTo('.slideshow');
}
else{ $('.slideshow').show(); }
loaded++;
});
Add an event listener to each image to respond to when the browser has finished loading the image, then append it to your slideshow.
var $images = $("#div_containing_images img");
var numImages = $images.length;
var numLoaded = 0;
var $slideshow = $(".slideshow");
$images.each(function() {
var $thisImg = $(this);
$thisImg.on("load", function() {
$thisImg.detach().appendTo($slideshow);
numLoaded++;
if (numLoaded == numImages) {
$slideshow.show();
}
});
});
It's a good idea to also listen for the error event as well, in case the image fails to load. That way you can increase numLoaded to account for broken image. Otherwise, your slideshow will never be shown in the event the image is broken.
Also note, that by calling detach() followed by appendTo() I am am moving the image in the DOM. If instead, you want to copy the image, use clone() instead of detach().
* EDIT TO MODIFY USER'S EXACT USE CASE *
var $images = $("li.one_photo a");
var numImages = $images.length;
var numLoaded = 0;
$images.each(function() {
$('<img />',
{ src: $(this).attr("href") })
.appendTo('.slideshow')
.on("load error", function() {
numLoaded++;
if(numLoaded == numImages) {
$('.slideshow').show();
}
});
});
* EDIT #2 *
Just realized you were putting everything in the $(".slideshow").load() function. Since $(".slideshow") represents a DIV, it will never raise a load event, and the corresponding function will never execute. Edited above accordingly.

Javascript image src on click of image

I'm trying to create a simple image swapper. So I have 20 images on the page, and 1 large one. I want the user to click one of the smaller images from the 20 and it be output into the place of the big image source.
I've only just started but even so my code doesn't seem to validate as the script fails before it even gets to the console.log. Also not sure if I'm using thisID correctly.
<img id='avatar-output' onclick='selectAvatar(thisID)' src='images/avatars/$number.png' />
<script>
function selectAvatar(thisID){
var imageSource = document.getElementById ("avatar-output").src;
console.log("Avatar source is " imageSource);
}
</script>
HTML:
<img id='avatar-output' src='images/avatars/$number.png' />
<img class='avatar-small' src='images/avatars/1.png' />
<img class='avatar-small' src='images/avatars/2.png' />
<img class='avatar-small' src='images/avatars/3.png' />
JS:
var els = document.getElementsByClassName('avatar-small'),
target = document.getElementById("avatar-output"),
handler = function() { target.src = this.src; };
for (var i=0; i<els.length; ++i) els[i].onclick = handler;
Demo
Or, if all small images are together, better use event delegation:
var target = document.getElementById("avatar-output");
document.getElementById("avatar-small-wrapper").onclick = function(e) {
if(e.target.tagName.toLowerCase() === 'img') target.src = e.target.src;
};
Demo
Notes
Better separation of content (html) and behavior (inline JS)
<script> element needs type="text/javascript" attribute
Avoid running JavaScript in global scope to avoid creating global variables, polluting window. Run in in a closure: (function(){ /* code here */ })()
You have a typo in it, change
var imageSource = document.getElementById ("avatar-output").src;
to
var imageSource = document.getElementById("avatar-output").src;
since there is a space where it shouldn't be.
Edit: oh and another one in the
console.log("Avatar source is " imageSource);
line. Add a + between your string and your variable like this:
console.log("Avatar source is " + imageSource);

JavaScript windows.onload or referencing new elements?

I'm trying to create a lightbox and I'm having trouble.
I think the problem is either because I have 2 window.onloads or because I'm trying to reference a newly created DOM element. I added some comments in the code below that explain what I'm trying to do.
//open lightbox
window.onload = showLargeImage;
function showLargeImage() {
var enlargeButton = document.getElementById("thumb1"); // thumb1 is a thumbnail you click to get the lightbox
enlargeButton.onclick = handleClick;
}
function handleClick() {
var lightboxContainerId = document.getElementById("lightboxContainer");
lightboxContainerId.innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
} // the inner HTML creates the lightbox.
//close lightbox
window.onload = reduceImage; // i'm pretty sure that this windo.onload is the problem... or, that I'm referencing "imageButton" which is new to the DOM
function reduceImage() {
var reduceButton = document.getElementById("imageButton"); // you're supposed to click the big image in the lightbox to get close it.
reduceButton.onclick = handleReduceClick;
}
function handleReduceClick() {
var shadeId = document.getElementById("lightboxContainer");
shadeId.innerHTML = "say what"; // closing the lightbox simply strips everything out of the lightboxContainer
alert("oh yeah");
}
Here are a few reasons why your code is not working:
showLargeImage and reduceImage are missing invocation parentheses in the places where they are being assigned to window.onload. Without parentheses, window.onload is being assigned a function, but that function is not getting called. You should, for instance, have window.onload = showLargeImage();
As you suspected, the second window.onload is overwriting the first.
reduceButton is (as you also suspected) being assigned before it exists, causing an error.
Here is one solution that may work for you.
HTML:
<!DOCTYPE html>
<html><head><title></title>
</head><body>
View
<div id="lightboxcontainer"></div>
</body></html>
JavaScript:
window.onload = function() {
// click link to show
var enlargeButton = document.getElementById('thumb');
enlargeButton.onclick = function() {
var lightboxContainerId = document.getElementById('lightboxcontainer');
lightboxContainerId.innerHTML = '<img src="http://placehold.it/350x150"' +
'width="350" height="150 alt="Thumb 1">' +
'<p>Click image to hide.</p>';
};
// click image to hide
var reduceButton = document.getElementById('lightboxcontainer');
reduceButton.onclick = function() {
reduceButton.innerHTML = ''; // removes lightbox contents
};
};
Live demo: http://jsfiddle.net/ericmathison/BxwYY/7/
If the code is placed at the end of the <body> (or anywhere after your lightbox elements), just use this:
document.getElementById("thumb1").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
document.getElementById("imageButton").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = "say what";
alert("oh yeah");
};
}
This will do everything you want.

Categories

Resources