Wrapping content elements causes inline scripts to fire - javascript

I am writing a jQuery plugin. In this plugin I wrap the existing BODY contents in a DIV and hide them.
var $originalBodyContents = $('body').wrapInner('<div>').children('div').hide();
The plugin then appends its own overlay DIV to the BODY and does it's plugin magic. When the user exits the plugin removes its overlay DIV, and unwraps them.
$originalBodyContents.children().unwrap();
This is working great, as you can see in this demo:
http://jsfiddle.net/vKddB/1/
However, if there are content scripts on the page then they are all reloaded when the wrap occurs and they run their code again. This is causing a lot of unexpected behavior, as you can see in this demo:
http://jsfiddle.net/vKddB/3/
In the above demo you'll see that the "Show Alert" button shows an alert that says "hello!" when clicked. If you fire the plugin and close the plugin you'll notice that the "Show Alert" button now has two click handlers tied to it so it shows two alerts when clicked.
My plugin will not have control over the contents of the page it is running on. Is there a way I can prevent the inline scripts from re-running when I wrap the body contents in a DIV?

$('script', $('body')).remove(); before your code

If you want your plugin to work on arbitrary pages, you might want to consider an alternative approach where your overlay just covers the original contents. I believe this would be more reliable than tricks such as wrapping and hiding, moving/deleting script nodes, etc.

I just want to share my aproach in bulding an overlay maybe it will help someone.
It's a little different, the div is added on the page and does not hide the existing div elements. Maybe a little faster as the script does not search all div dom elements.
first
//create the overlay with
$('<div class="overlay" />').appendTo('body').show();
//close the overlay with
$('.overlay').remove();
//css used for overlay
.overlay
{
background-color: #363636;
background-image: url('a_nice_bg_image.png');
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
display: none;
z-index: 1000;
opacity: .55;
filter:alpha(opacity=55);
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=55)";
}

Append the div to the body, set its position to absolute, set a high z-index and resize it to cover the whole content.
var $overlay = $('<div>')
.css({
position: 'absolute',
top: 0,
left: 0,
width: $(document).width() + 'px',
height: $(document).height() + 'px',
backgroundColor: '#f00',
'z-index': 10000
})
.appendTo('body');
Like this (your original code with minimal modifications): http://jsfiddle.net/Ya3DG/4/ :)

Related

Issues using a simple jQuery script to grab one div height & make another div the same size

Basically I want to get the height of .r-side and have it applied to the height of .l-side so that these two elements are always the same height even if the window is resized, and positioned on top of each other. I'm not sure what's wrong with my jQuery.
Here's what I got:
$(window).load(function(){
$(".l-side").css({'height':($(".r-side").height()+'px')});
});
Using jQuery 3.1.1. And here's a jsFiddle of the issue I'm having.
I'm open to other methods than jQuery to accomplish this but in my research I only found solutions that were specific to columns, and these divs need to be positioned directly on top of each other.
You have referenced .l-side and .r-side as classes in the jQuery, and coded them as ID's in the markup :)
In the snippet I altered your widths so it displays in the preview window, but you can see the heights now match.
$(window).load(function() {
$("#r-side").css({
'height': ($("#l-side").height() + 'px')
});
});
#l-side img {
width: 100px;
}
#r-side {
width: 100px;
height: 100px;
background-color: black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="l-side"><img src="http://connor.la/sandbox/refsmaster/images/forever-2.jpg"></div>
<div id="r-side"></div>
Please use id selector '#' as you have used id not classes and use document.ready instead of window.load.$(document).ready(function(){
$("#r-side").css({'height':($("#l-side").height()+'px')});
});

Bootstrap - Switching between Div with Jquery

So I'm using bootstrap as my responsive framework and I have a container, row I also have two div's that I'm going to be switching between using a button. So I setup my HTML and my second div I set the display to "none" to hide it. However when using Jquery fadeIn/fadeOut you can see there is some shifting/expanding in terms of the Height.
Now I think to get around this I have to set the position to Absolute and also change the z-index of the first and second div so one is hidden behind the other. Using absolute however breaks the bootstrap container... So is there a way to switch the Div without the shifting in height when the button is clicked. Added some source so you can see what happens when to buttons are clicked.
http://www.bootply.com/hBNIHfCpxR
Try this:
http://www.bootply.com/PIG2icyErI
Relevant CSS:
.row {
position: relative;
padding-top: 50px;
}
#content-one, #content-two {
position: absolute;
width: 100%;
top: 0;
}

JS launches before CSS

This is currently happening in chrome, in firefox I haven't had this issue (yet).
Here is a VERY simplified version of my problem.
HTML:
<div class="thumbnail">
Click me!
</div>
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
}
a {
position: absolute;
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
Javascript:
$(document).ready(function () {
var $parent = $('#clickMe').parent();
function resize() {
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
$(window).on('resize', resize);
resize();
});
The problem:
So what does this give when I resize (without dragging)? Well javascript launches first and sets the position of the <a></a> , then CSS applies the height change if we are < 992 px.
Logically the button is now visually at the outside of the div and not on the border like I had originally defined it to be.
Temporary solution proposed in this post.
jQuery - how to wait for the 'end' of 'resize' event and only then perform an action?
var doit;
$(window).on('resize', function(){ clearTimeout(doit); doit = setTimeout(resize, 500); });
Temporary solution is not what I'm looking for:
However, in my situation I don't really need to only call 'resize' when the resizing event is actually done. I just want my javascript to run after the css is finished loading/ or finished with it's changes. And it just feels super slow using that function to 'randomely' run the JS when the css might be finished.
The question:
Is there a solution to this? Anyone know of a technique in js to wait till css is completely done applying the modifications during a resize?
Additional Information:
Testing this in jsfiddle will most likely not give you the same outcome as I. My css file has many lines, and I'am using Twitter Bootstrap. These two take up a lot of ressources, slowing down the css application (I think, tell me if I'm wrong).
Miljan Puzović - proposed a solution by loading css files via js, and then apply js changes when the js event on css ends.
I think that these simple three steps will achieve the intended behavior (please read it carefully: I also suggest to read more about the mentioned attributes to deeply understand how it works):
Responsive and fluid layout issues should always be primarily (if not scrictly) resolved with CSS.
So, remove all of your JavaScript code.
You have positioned the inner a#clickMe element absolutely.
This means that it will be positioned within its closest relatively positioned element. By the style provided, it will be positioned within the body element, since there is no position: relative; in any other element (the default position value is static). By the script provided, it seems that it should be positioned within its direct parent container. To do so, add position: relative; to the div.thumbnail element.
By the script you provided, it seems that you need to place the a#clickMe at the bottom of div.thumbnail.
Now that we are sure that the styles added to a#clickMe is relative to div.thumbnail, just add bottom: 0px; to the a#clickMe element and it will be positioned accordingly, independently of the height that its parent has. Note that this will automatically rearrange when the window is resized (with no script needed).
The final code will be like this (see fiddle here):
JS:
/* No script needed. */
CSS:
div {
width: 200px;
height: 300px;
background-color: purple;
position: relative; //added
}
a {
position: absolute;
bottom: 0px; //added
}
#media (max-width: 991px) {
div {
height: 200px;
}
}
If you still insist on media query change detection, see these links:
http://css-tricks.com/media-query-change-detection-in-javascript-through-css-animations/
http://css-tricks.com/enquire-js-media-query-callbacks-in-javascript/
http://tylergaw.com/articles/reacting-to-media-queries-in-javascript
http://davidwalsh.name/device-state-detection-css-media-queries-javascript
Twitter Bootstrap - how to detect when media queries starts
Bootstrap: Responsitive design - execute JS when window is resized from 980px to 979px
I like your temporary solution (I did that for a similar problem before, I don't think half a second is too long for a user to wait but perhaps it is for your needs...).
Here's an alternative that you most likely have thought of but I don't see it mentioned so here it is. Why not do it all through javascript and remove your #media (max-width.... from your css?
function resize() {
var width = (window.innerWidth > 0) ? window.innerWidth : screen.width;
if(width<992){
$("div").each(function(e,obj){$(obj).height(200);});
}
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
In the html page, put the link to css file in head section; next, put the link to js file just before the /body tag and see what happens. In this way css will load always before js.
Hope this help you.
Did you try to bind the resize handler not to the window but to the object you want to listen to the resize ?
Instead of
$(window).on('resize', resize);
You can try
$("#clickMe").on('resize', resize);
Or maybe
$("#clickMe").parent().on('resize', resize);
var didResize = false;
$(window).resize(function() {
didResize = true;
});
setInterval(function() {
if (didResize) {
didResize = false;
console.log('resize');
}
}, 250);
I agree with falsarella on that you should try to use only CSS to do what you are trying to do.
Anyway, if you want to do something with JS after the CSS is applied, I think you can use requestAnimationFrame, but I couldn't test it myself because I wasn't able to reproduce the behavior you explain.
From the MDN doc:
The window.requestAnimationFrame() method tells the browser that you
wish to perform an animation and requests that the browser call a
specified function to update an animation before the next repaint. The
method takes as an argument a callback to be invoked before the
repaint.
I would try something like this:
var $parent = $('#clickMe').parent();
function resize(){
$('#clickMe').offset({
top: $parent.offset().top + $parent.height()-$('#clickMe').height()
});
}
window.onresize = function(e){
window.requestAnimationFrame(resize);
}
window.requestAnimationFrame(resize);
Anyone know of a technique to wait till css is completely done loading?
what about $(window).load(function() { /* ... */ } ?
(it executes the function only when the page is fully loaded, so after css loaded)

Transparent DIV Overlay

OK, here's what I'm trying to do :
I have a page structure, with several divs, nested divs, etc
I want to handle 2 different types of events : click and hover.
For those 2 events, I want a transparent DIV overlay (with some colour tint?) above the aforementioned div covering all of it.
How can this be done?
Any ideas?
Here's a fiddle : http://jsfiddle.net/cFw7d/2/ (though I somehow can't make it show properly - it's a jQuery Mobile page actually...)
I would go for the :after pseudo class in this case.
Just add on the CSS the following:
.msp-selected-hover:after {
content: ' ';
position: absolute;
background: rgba(0,0,120,0.4);
top: 0;
left: 0;
bottom: 0;
right: 0;
}
You might want to create different classes for hover and clicks as well as targetting just certain elements.
Your edited fiddle: http://jsfiddle.net/cFw7d/3/
If you want a block on top of another block, and be able to click on the block below, you will have to use pointer-events: none CSS3 property.
https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

How can I lay a div over every image on the page using jQuery?

I'm wondering how can I put a div over every image element on the page using jQuery? I want to make it where when you right click on the image, you'll just be right clicking on a div and then it will be harder to save, and people that don't know HTML and stuff wont be able to get the image since they wont even know about "View page source" option. Can someone help?
Thanks in advance.
You can drop a new DIV on top of the images using absolute positioning:
.hider {
z-index: 1000;
position: absolute;
}
and this code:
$('img').each(function() {
var pos = $(this).position();
$('<div/>', {title: this.alt})
.addClass('hider')
.css({
width: this.width, height: this.height,
left: pos.left, top: pos.top,
})
.insertAfter(this);
});
See http://jsfiddle.net/alnitak/KRgnK/ for a working demo
EDIT updated to copy the original image's alt tag onto the overlay div.
If blocking the right-click on the image is important, I recommend a simple CSS approach where the image is just the background of a DIV. You cannot right-click to download these images regardless of any JavaScript.
As mentioned, you'll be missing the alt image attribute so proceed accordingly.
The HTML...
<div id="myImage"></div>
And the CSS...
<style>
#myImage {
background-image: url(theGraphic.jpg);
background-repeat: no-repeat;
width: 100px; /* theGraphic.jpg width */
height: 100px; /* theGraphic.jpg height */
}
</style>
To disable right click entirely, you can use jquery like so:
$(document).ready(function(){
$('img').bind("contextmenu",function(e){
return false;
});
});
try this:
$('body img').wrap('<div />');
Click Here

Categories