I'm using the Google Book Viewer API to show book previews based on metadata found on the page. This is in a system I don't control, although I can append scripts and markup.
Only some pages contain information about books that have previews available. The book viewer is inside a div which, if the preview isn't found, is empty and looks ridiculous; so my strategy is to hide the div via CSS, then, if a preview is found, change the ID of the div so that it is no longer hidden. If I do that, though, when the div appears, the preview does not show correctly; if you zoom in and out with your browser, it does, but otherwise no.
Here's an example of it working. (I've simplified the script--normally I traverse the page to get the metadata, whereas here I'm just supplying it in a string.) Everything is there except the CSS:
https://googledrive.com/host/0BxoVkXnTNNDoV3NpQUtsNDEyaTQ/gbpreview.htm
And here it is with the CSS, not working:
https://googledrive.com/host/0BxoVkXnTNNDoV3NpQUtsNDEyaTQ/gbpreview2.htm
Anyone know how I might fix this, or can you think of an alternative strategy to achieve what I'm looking for?
And here is the code:
<style type="text/css">#GoogleBooksPreview {display: none;} </style>
<div id="GoogleBooksPreview">
<div id="viewerCanvas" style="height: 600px;">
</div>
</div>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">var gbsWidget = document.getElementById('GoogleBooksPreview');
function gbsFound() {
gbsWidget.id = 'gbsFound';
}
function initialize() {
var viewer = new google.books.DefaultViewer(document.getElementById('viewerCanvas'), {
showLinkChrome: false
});
viewer.load(['ISBN:9780596805524', 'OCLC:502415271'], null, gbsFound);
}
google.load("books", "0");
google.setOnLoadCallback(initialize);
</script>
It looks like the recommended way to handle this is to hide the div on failure, rather than unhide the div on success, see here. I'm guessing this is necessary because the viewer needs to know the height of the canvas (which it won't have if the container is hidden).
See a working example here: http://jsfiddle.net/67pay4r2/.
Or without adding a hidden class like: http://jsfiddle.net/67pay4r2/1/.
I have added a hidden class to the widget div, which is removed when the initialize function starts, and then added back if the viewer load fails. This will prevent users with JS disabled from seeing the div.
Related
I have a website project, I created buttons such as "About Me" "Other" when clicked it should lead the user to another part of the website that looks different but still be in the same website sort of like I would "display: none" and hide the rest of the content onclick of a button and let new code fill the page.
If I am getting your question correct, and you want the link to be the exact same but load different content inside the page, you may want to use jquery and the load function to change a div on your page. Normally though, for navigating to those types of pages, you would just change the page as they should be placed in the same domain (www.yourdomain.com\aboutme.html, www.yourdomain.com\other.html).
The pages need to be on the same domain for this to work, which is why I just have some js files showing in the snippet.
function load(link){
$('#contentarea').load(link);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onclick="load('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js')">Load Jquery Script Text</button>
<button onclick="load('https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js')">Load Flower</button>
<div id="contentarea">
</div>
I don't fully understand your question, but I think what you want is that when the user clicks a button, the browser scrolls to a chapter of the webpage.
You don't even need JavaScript or jQuery for this, just create an anchor tag.
with the href attribute referring to the id of the div or section (This works for any tag, not only div and section), assuming that the id is "aboutMe", you will be adding this:
About Me
And the div or section would be:
<div id="aboutMe">
...
</div>
The browser will scroll automatically so the viewport is displaying the section. You can also make it smooth by:
html {
scroll-behavior: smooth;
}
You may also add scroll padding just so if your navbar is too big, it doesn't show over the text.
html {
scroll-behavior: smooth;
scroll-padding: 70px;
}
I hope this is what you are looking for.
Take a look at this simple HTML:
<div id="wrap1">
<iframe id="iframe1"></iframe>
</div>
<div id="warp2">
<iframe id="iframe2"></iframe>
</div>
Let's say I wanted to move the wraps so that the #wrap2 would be before the #wrap1. The iframes are polluted by JavaScript. I am aware of jQuery's .insertAfter() and .insertBefore(). However, when I use those, the iFrame loses all of its HTML, and JavaScript variables and events.
Lets say the following was the iFrame's HTML:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
// The variable below would change on click
// This represents changes on variables after the code is loaded
// These changes should remain after the iFrame is moved
variableThatChanges = false;
$(function(){
$("body").click(function(){
variableThatChanges = true;
});
});
</script>
</head>
<body>
<div id='anything'>Illustrative Example</div>
</body>
</html>
In the above code, the variable variableThatChanges would...change if the user clicked on the body. This variable, and the click event, should remain after the iFrame is moved (along with any other variables/events that have been started)
My question is the following: with JavaScript (with or without jQuery), how can I move the wrap nodes in the DOM (and their iframe childs) so that the iFrame's window stays the same, and the iFrame's events/variables/etc stay the same?
It isn't possible to move an iframe from one place in the dom to another without it reloading.
Here is an example to show that even using native JavaScript the iFrames still reload:
http://jsfiddle.net/pZ23B/
var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);
This answer is related to the bounty by #djechlin
A lot of search on the w3/dom specs and didn't find anything final that specifically says that iframe should be reloaded while moving in the DOM tree, however I did find lots of references and comments in the webkit's trac/bugzilla/microsoft regarding different behavior changes over the years.
I hope someone will find anything specific regarding this issue, but for now here are my findings:
According to Ryosuke Niwa - "That's the expected behavior".
There was a "magic iframe" (webkit, 2010), but it was removed in 2012.
According to MS - "iframe resources are freed when removed from the DOM". When you appendChild(node) of existing node - that node is first removed from the dom.
Interesting thing here - IE<=8 didn't reload the iframe - this behavior is (somewhat) new (since IE>=9).
According to Hallvord R. M. Steen comment, this is a quote from the iframe specs
When an iframe element is inserted into a document that has a browsing context, the user agent must create a new browsing context, set the element's nested browsing context to the newly-created browsing context, and then process the iframe attributes for the "first time".
This is the most close thing I found in the specs, however it's still require some interpretation (since when we move the iframe element in the DOM we don't really do a full remove, even if the browsers uses the node.removeChild method).
Whenever an iframe is appended and has a src attribute applied it fires a load action similarly to when creating an Image tag via JS. So when you remove and then append them they are completely new entities and they refresh. Its kind of how window.location = window.location will reload a page.
The only way I know to reposition iframes is via CSS. Here is an example I put together showing one way to handle this with flex-box:
https://jsfiddle.net/3g73sz3k/15/
The basic idea is to create a flex-box wrapper and then define an specific order for the iframes using the order attribute on each iframe wrapper.
<style>
.container{
display: flex;
flex-direction: column;
}
</style>
<div class="container">
<div id="wrap1" style="order: 0" class="iframe-wrapper">
<iframe id="iframe1" src="https://google.com"></iframe>
</div>
<div id="warp2" style="order: 1" class="iframe-wrapper">
<iframe id="iframe2" src="https://bing.com"></iframe>
</div>
</div>
As you can see in the JS fiddle these order styles are inline to simplify the flip button so rotate the iframes.
I sourced the solution from this StackOverflow question: Swap DIV position with CSS only
Hope that helps.
If you have created the iFrame on the page and simply need to move it's position later try this approach:
Append the iFrame to the body and use a high z-index and top,left,width,height to put the iFrame where you want.
Even CSS zoom works on the body without reloading which is awesome!
I maintain two states for my "widget" and it is either injected in place in the DOM or to the body using this method.
This is useful when other content or libraries will squish or squash your iFrame.
BOOM!
Unfortunately, the parentNode property of an HTML DOM element is read-only. You can adjust the positions of the iframes, of course, but you can't change their location in the DOM and preserve their states.
See this jsfiddle I created that provides a good test bed. http://jsfiddle.net/RpHTj/1/
Click on the box to toggle the value. Click on the "move" to run the javascript.
This question is pretty old... but I did find a way to move an iframe without it reloading. CSS only. I have multiple iframes with camera streams, I dont like when they reload when i swap them. So i used a combination of float, position:absolute, and some dummy blocks to move them around without reloading them and having the desired layout on demand (resizing and all).
If you are using the iframe to access pages you control, you could create some javascript to allow your parent to communicate with the iframe via postMessage
From there, you could build login inside the iframe to record state changes, and before moving dom, request that as a json object.
Once moved, the iframe will reload, you can pass the state data into the iframe and the iframe listening can parse the data back into the previous state.
PaulSCoder has the right solution. Never manipulate the DOM for this purpose. The classic approach for this is to have a relative position and "flip" the positions in the click event. It's only not wise to put the click event on the body, because it bubbles from other elements too.
$("body").click(function () {
var frame1Height = $(frame1).outerHeight(true);
var frame2Height = $(frame2).outerHeight(true);
var pos = $(frame1).css("top");
if (pos === "0px") {
$(frame1).css("top", frame2Height);
$(frame2).css("top", -frame1Height);
} else {
$(frame1).css("top", 0);
$(frame2).css("top", 0);
}
});
If you only have content that is not cross-domain you could save and restore the HTML:
var htmlContent = $(frame).contents().find("html").children();
// do something
$(frame).contents().find("html").html(htmlContent);
The advantage of the first method is, that the frame keeps on doing what it was doing. With the second method, the frame gets reloaded and starts it's code again.
At least in some circumstances a shadow dom with slotting might be an option.
<template>
<style>div {outline:1px solid black; height:45px}</style>
<div><slot name="a" /></div>
<div><slot name="b" /></div>
</template>
<div id="shadowhost">
<iframe src="data:text/html,<button onclick='this.innerText+=`!`'>!</button>"
slot="a" height=40px ></iframe>
</div>
<button onclick="ifr.slot= (ifr.slot=='a') ? 'b' : 'a';">swap</button>
<script>
document.querySelector('#shadowhost').attachShadow({mode: 'open'}).appendChild(
document.querySelector('template').content
);
ifr=document.querySelector('iframe');
</script>
In response to the bounty #djechlin placed on this question, I have forked the jsfiddle posted by #matt-h and have come to the conclusion that this is still not possible.
http://jsfiddle.net/gr3wo9u6/
//this does not work, the frames reload when appended back to the DOM
function swapFrames() {
var w1 = document.getElementById('wrap1');
var w2 = document.getElementById('wrap2');
var f1 = w1.querySelector('iframe');
var f2 = w2.querySelector('iframe');
w1.removeChild(f1);
w2.removeChild(f2);
w1.appendChild(f2);
w2.appendChild(f1);
//f1.parentNode = w2;
//f2.parentNode = w1;
//alert(f1.parentNode.id);
}
<script>
function myFunction() {
if (/menu/.test(window.location.href)) {
document.getElementById('searchfield').display = 'none';
}
}
</script>
I would like to do this with JavaScript or JQuery -- thus far my attempts are not working. I have a div that is to be present on all pages but 1 page; in which I would like to hide it with JavaScript if that page.
Note: This is a Wordpress website; the above was inserted in the header.php head of the document. Same location of repetitive div.
This is easier with CSS.
HTML (make sure all of your pages have some unique identifier, generally on the body tag):
<body id="page-1">
<div id="menu">
[ ... ]
CSS
#page-1 #menu{
display:none;
}
Edit
I see you're working in WordPress. WP automatically adds unique classes to the body tag. Generally you can use something like this for your CSS:
.page.page-id-34{
/*
34 should be swapped with the page id.
You can customize the classes,
so just Inspect Element and see what it is for your page
*/
display:none;
}
myFunction is never called. You'll need to explicitly call it when the page is ready $(myFunction);, or if you want, call it in the footer (or close to it) directly with myFunction();.
An alternative, since this is a WordPress site, is to add PHP code to not show that div (or even send it to client!) based on a filter.
Another alternative is using CSS to block out that specific div on the page that's loaded.
I have a module on my website that loads quite strangely, so I want to hide the div while the page loads, then reveal it on document ready. The following (simplified) code works just fine:
<div class="slideshow" style="display:none;">
This div should be hidden during load
</div>
<script type="text/javascript">
$(document).ready(function() {
$('.slideshow').show();
});
</script>
This works as intended. But what happens to users with Javascript disabled? Will the div remain hidden to them? How can I make sure all users will see the widget?
A quite common way is, to add a class .nojs to your <body> or <html> element and remove it via Javascript e.g. onload. Like this you can simple handle the two different states via CSS:
.slideshow {
display: none;
}
html.nojs .slideshow {
display: block;
}
Might want to try http://www.modernizr.com/ in this context.
You should remove the display:none style from the div and explicitly hide it in your document.ready function. That way, without javascript it will be visible from the start.
Personally, I prefer to use CSS to my advantage for such things. I add this line of script just inside my template HTML body tag.
<script type="text/javascript">document.body.className = "JS";</script>
Then, for the scenario you describe, I would use an additional CSS class on the div, like so.
<div class="slideshow initially-hidden">
This div should be hidden during load
</div>
With a matching style accounting for the class added via JavaScript in the template.
body.JS .initially-hidden {
display: none;
}
Your elements with a class of "initially-hidden" will now only be invisible if JavaScript is enabled. If it is disabled, they will be visible.
<div class="slideshow">
This div should be hidden during load
</div>
<script type="text/javascript">
$('.slideshow').hide();
$(document).ready(function() {
$('.slideshow').show();
});
</script>
If they have javascript disabled, it won't be shown... You can make sure they all see it by not hiding it in the first place.
But what happens to users with Javascript disabled? Will the div remain hidden to them?
Since the code you have to show the div cannot run, yes it will remain hidden.
How can I make sure all users will see the widget?
Make use of <noscript> to render the div as hidden when Javascript is not enabled, or load the div as visible and hide it with Javascript some point prior to the full page being loaded.
i have one website which is working on templates.
in the template there is one main image & i want to replace that main image on some pages only not on full website. what i am looking for is to change the main image to new image on page where i need with ajax.
when i see the css of that template i found following code to show image
.top-bg{
background:url(../images/top-bg.jpg)
top center no-repeat;
position:relative;
}
and on php page i found following line which bring image.
<div class="top-bg">
i need ajax / jquery code to change image.
my basic logic is, i will get that image URL from MYSQL databse and assign to one variable and then i will change the image which come from database, actually its one page displaying products and i want to display main image of product with ref to loaded product, i hope you will understand what i need at the end...
Thanks
Thanks for every one how reply, i found the solution
$(document).ready(
function(){
$('#imageContainer').css("background-image", "url(images/cube.jpg)");
}
);
this did trick for me what i need, any way thanks and also for -ve voting thanks... :((
While I think Ajax is the wrong solution for your problem, I'll offer you the following (which, at least, meets your question):
$('#changeImage').click(
function(){
$('#imageContainer').load('http://path.to.php/file.php #imageID');
return false;
}
);
Clicking an element of id="changeImage" will load the contents of id="imageID" from the php file located at the url of http://path.to.php/file.php into an element (presumably div, but whatever) of id="imageContainer".
That said, I'd suggest following #Nick Craver and #Aaron Digulla's advice and use CSS.
If you view source there's a working demo of jQuery's load on my site (posted in response to a different SO question) at http://davidrhysthomas.co.uk/play/loadDemo.html.
Edited in response to comment from OP.
To do this automatically, on page-load:
$(document).ready(
function(){
$('#imageContainer').load('http://path.to.php/file.php #imageID');
}
);
You don't need any JavaScript at all for this, just include another stylesheet (or <style> block) on the webpages you want the imaged changed on. Just have this in there:
.top-bg { background:url(../images/other-image.jpg); }
Or the <style> version:
<style type="text/css">
.top-bg { background:url(../images/other-image.jpg); }
</style>
As long as this is declared after that template stylesheet, that background property will override the template one, and you'll have your custom image on just those pages.
I think AJAX is the wrong approach here. AJAX should be used to load new data when the user interacts with the web page.
Your problem can be solved much more simple: If you can add an AJAX call to the code of the page, why not simply add a new CSS style:
.tob-bg {
background:url(../images/other.jpg) top center no-repeat;
}
Or create a second template and use that for all but the main page.