Pull URL parameters into a WordPress "Raw HTML" content element - wordpress

I'm using the URL Params plugin to pull parameters into regular content using a short code. But I have to use a Raw HTML block to insert Typeform code into the page and I want to be able to pass a URL parameter into the Typeform code to track the source of the form submission.
I can't figure out how to do it. The form is working fine at: https://HelloExit.com/instant-valuation
But I want to be able to send people to https://HelloExit.com/instant-valuation/?source=XXXX and pull the XXXX into the Typeform code as the "source" value in the "data-url"
Here's what I tried:
<script>
function getUrlVars() {
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
vars[key] = value;
});
return vars;
}
var source = getUrlVars()["source"];
</script>
<div
class="typeform-widget"
data-url="https://xgenius.typeform.com/to/zZHPPk?source=<script>document.write(source)</script>"
data-transparency="100"
data-hide-headers=true
data-hide-footer=true
style="width: 100%; height: 500px;">
</div>
<!-- Typeform embed code -->
<script>(function() { var qs,js,q,s,d=document, gi=d.getElementById,
ce=d.createElement, gt=d.getElementsByTagName, id="typef_orm",
b="https://embed.typeform.com/"; if(!gi.call(d,id)) { js=ce.call(d,"script"); js.id=id;
js.src=b+"embed.js"; q=gt.call(d,"script")[0]; q.parentNode.insertBefore(js,q) } })()
</script><div style="font-family: Sans-Serif;font-size: 12px;color: #999;opacity: 0.5;padding-top: 5px;"> powered by Typeform</div>
Any assistance would be greatly appreciated!

You're close, but you'll need to use Javascript to alter the data-url attribute of your div.
// ...
var source = getUrlVars()["source"];
// concatenate the url with your source variable
var newUrl = `https://xgenius.typeform.com/to/zZHPPk?source=${source}`;
// get the element whose attributes you want to dynamically set
// https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
var widgetElement = document.querySelector('.typeform-widget');
// set the source attribute
// https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute
widgetElement.setAttribute('data-url', newUrl);
Test this carefully, as it might still end up with a race condition (that is, the Typeform embed code might start running before you've updated the data-url attribute that it references).

Related

Disqus Comments affecting my pagespeed. How can I either lazy load or click to show comments?

Hi I've static website(made with Hugo) with Disqus installed. My website load time is really affected by ~30% in negative. So, I wish I could prevent it from loading it until a person reaches to that section or a better approach is that there'll be 'show comments' button that totally leave on visitor to decide.
I'm already using lazyload(lozad js library) but it's not working with disqus even I tried following code too
var iframes = doc.querySelectorAll('iframe');
iframes.forEach(function (e){
e.classList.add('lozad'); // adds required 'lozad' class
var iframeAttr = e.getAttribute('src');
e.setAttribute('data-src', iframeAttr); // lozad needs source data in data-src attribute
e.setAttribute('src', ''); // empty src attribute so that library use it at right time
});
Zachary wrote a tutorial for Hugo sites on how to display a Show comments button and have the Disqus comments only displayed when a reader click on the button.
As a bonus, the Disqus Javascript file embed.js will only load when the button is clicked.
To add this to your site, first, create a partial and name it disqus.html. Inside this file, put the following code:
<div id="disqus-container">
{{ with .Site.DisqusShortname }}
<button id="disqus-button" onclick="showComments()">Show comments</button>
<div id="disqus-comments">
{{ $isDummyName := eq . "yourdiscussshortname" }}
{{ $isServer := $.Site.IsServer }}
{{ if or $isDummyName $isServer }}
<p>Disqus comments are disabled.</p>
<script type="application/javascript">
function showComments() {
{{ partial "disqus-js-common.js" . | safeJS }}
}
</script>
{{ else }}
<div id="disqus_thread">
</div>
<script type="application/javascript">
function showComments() {
{{ partial "disqus-js-main.js" . | safeJS }}
{{ partial "disqus-js-common.js" . | safeJS }}
}
</script>
{{ end }}
<noscript>Enable JavaScript to view Disqus comments.</noscript>
</div>
{{ end }}
</div>
Then, create two Javascript files. First one call it disqus-js-common.js. Inside this file, add the following code:
// Remove button
var disqusButton = document.getElementById('disqus-button');
disqusButton.parentNode.removeChild(disqusButton);
// Un-hide comments
var disqusComments = document.getElementById('disqus-comments');
disqusComments.style.display = 'block';
The second Javascript file call it disqus-js-main.js. And inside this one, add the following code:
// Config
var disqus_config = function () {
};
// Build and append comments
var d = document;
var s = d.createElement('script');
s.async = true;
s.src = '//' + "{{ . }}" + '.disqus.com/embed.js';
s.setAttribute('data-timestamp', + new Date());
(d.head || d.body).appendChild(s);
Finally, add a little bit of CSS to make everything looks better:
#disqus-container {
font-size: 0.85rem;
border: 1px solid;
padding: 1.5rem;
}
#disqus-button {
width: 100%;
}
#disqus-comments {
display: none;
}
#disqus-comments,
#disqus-comments iframe {
max-height: 65vh !important;
overflow-y: auto;
}
Source
You can use the IntersectionObserver API to lazily load & initialize Disqus only once a user scrolls to a particular part of the page. The IO API is well-supported in modern browsers, so you wouldn't need to load any other lazy loading package (or custom JS) that'd further bog down your site.
Here's an example I got working. It uses the div that Disqus uses to mount its comments to as the point on the page that triggers everything to load & initialize. Note that a good chunk of this (it's commented) is copied straight from their documentation.
<script>
let mountNode = document.querySelector("#disqus_thread");
let options = {
rootMargin: "0px",
threshold: 0,
};
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
console.log("Initialize Disqus!");
//-- Copied from their documentation: START
var disqus_config = function () {
this.page.url = "https://whatever.com";
this.page.identifier = "whatever!";
};
var d = document,
s = d.createElement("script");
s.src = "https://your-shortname.disqus.com/embed.js";
s.setAttribute("data-timestamp", +new Date());
(d.head || d.body).appendChild(s);
//-- Copied from their documentation: END
// After initializing, we don't need this observer anymore.
observer.unobserve(mountNode);
return;
}
});
}, options);
observer.observe(mountNode);
</script>
All that said, even this sort of approach is gonna get you so far. Building comments and a form client-side is an inherently expensive set of tasks, and so you're still gonna see some detrimental effects to page performance. If not load time, then the blocking of the main thread by all that Disqus is executing on the page when it starts up. You're also gonna miss out on the SEO benefit of having status HTML comments on your page.
All of this represents the bulk of the reasons I ditched disqus on my own site and built my own service for it, which I eventually opened up to the public. It integrates with different platforms (not yet Hugo, but it's down the road hopefully), and spits out statically-rendered comments and avoides the-side bloat, etc. Keep it in mind for any future rebuild you go through:
https://jamcomments.com/
It can be achieved with pure HTML and JavaScript
But since I really like Alpine.js this is how it can be done
<button
x-data="disqusComponent()"
x-show="!loaded"
#click="toggle()"
>Show/Post Comments
</button>
<div id="disqus_thread"></div>
See Load Disqus Comments on demand

css not overriding external css? [duplicate]

I have a simple page that has some iframe sections (to display RSS links). How can I apply the same CSS format from the main page to the page displayed in the iframe?
Edit: This does not work cross domain unless the appropriate CORS header is set.
There are two different things here: the style of the iframe block and the style of the page embedded in the iframe. You can set the style of the iframe block the usual way:
<iframe name="iframe1" id="iframe1" src="empty.htm"
frameborder="0" border="0" cellspacing="0"
style="border-style: none;width: 100%; height: 120px;"></iframe>
The style of the page embedded in the iframe must be either set by including it in the child page:
<link type="text/css" rel="Stylesheet" href="Style/simple.css" />
Or it can be loaded from the parent page with Javascript:
var cssLink = document.createElement("link");
cssLink.href = "style.css";
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
frames['iframe1'].document.head.appendChild(cssLink);
I met this issue with Google Calendar. I wanted to style it on a darker background and change font.
Luckily, the URL from the embed code had no restriction on direct access, so by using PHP function file_get_contents it is possible to get the
entire content from the page. Instead of calling the Google URL, it is possible to call a php file located on your server, ex. google.php, which will contain the original content with modifications:
$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');
Adding the path to your stylesheet:
$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);
(This will place your stylesheet last just before the head end tag.)
Specify the base url form the original url in case css and js are called relatively:
$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);
The final google.php file should look like this:
<?php
$content = file_get_contents('https://www.google.com/calendar/embed?src=%23contacts%40group.v.calendar.google.com&ctz=America/Montreal');
$content = str_replace('</title>','</title><base href="https://www.google.com/calendar/" />', $content);
$content = str_replace('</head>','<link rel="stylesheet" href="http://www.yourwebsiteurl.com/google.css" /></head>', $content);
echo $content;
Then you change the iframe embed code to:
<iframe src="http://www.yourwebsiteurl.com/google.php" style="border: 0" width="800" height="600" frameborder="0" scrolling="no"></iframe>
Good luck!
If the content of the iframe is not completely under your control or you want to access the content from different pages with different styles you could try manipulating it using JavaScript.
var frm = frames['frame'].document;
var otherhead = frm.getElementsByTagName("head")[0];
var link = frm.createElement("link");
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", "style.css");
otherhead.appendChild(link);
Note that depending on what browser you use this might only work on pages served from the same domain.
var $head = $("#eFormIFrame").contents().find("head");
$head.append($("<link/>", {
rel: "stylesheet",
href: url,
type: "text/css"
}));
Here is how to apply CSS code directly without using <link> to load an extra stylesheet.
var head = jQuery("#iframe").contents().find("head");
var css = '<style type="text/css">' +
'#banner{display:none}; ' +
'</style>';
jQuery(head).append(css);
This hides the banner in the iframe page. Thank you for your suggestions!
If you control the page in the iframe, as hangy said, the easiest approach is to create a shared CSS file with common styles, then just link to it from your html pages.
Otherwise it is unlikely you will be able to dynamically change the style of a page from an external page in your iframe. This is because browsers have tightened the security on cross frame dom scripting due to possible misuse for spoofing and other hacks.
This tutorial may provide you with more information on scripting iframes in general. About cross frame scripting explains the security restrictions from the IE perspective.
An iframe is universally handled like a different HTML page by most browsers. If you want to apply the same stylesheet to the content of the iframe, just reference it from the pages used in there.
The above with a little change works:
var cssLink = document.createElement("link")
cssLink.href = "pFstylesEditor.css";
cssLink.rel = "stylesheet";
cssLink.type = "text/css";
//Instead of this
//frames['frame1'].document.body.appendChild(cssLink);
//Do this
var doc=document.getElementById("edit").contentWindow.document;
//If you are doing any dynamic writing do that first
doc.open();
doc.write(myData);
doc.close();
//Then append child
doc.body.appendChild(cssLink);
Works fine with ff3 and ie8 at least
The following worked for me.
var iframe = top.frames[name].document;
var css = '' +
'<style type="text/css">' +
'body{margin:0;padding:0;background:transparent}' +
'</style>';
iframe.open();
iframe.write(css);
iframe.close();
Expanding on the above jQuery solution to cope with any delays in loading the frame contents.
$('iframe').each(function(){
function injectCSS(){
$iframe.contents().find('head').append(
$('<link/>', { rel: 'stylesheet', href: 'iframe.css', type: 'text/css' })
);
}
var $iframe = $(this);
$iframe.on('load', injectCSS);
injectCSS();
});
use can try this:
$('iframe').load( function() {
$('iframe').contents().find("head")
.append($("<style type='text/css'> .my-class{display:none;} </style>"));
});
If you want to reuse CSS and JavaScript from the main page maybe you should consider replacing <IFRAME> with a Ajax loaded content. This is more SEO friendly now when search bots are able to execute JavaScript.
This is jQuery example that includes another html page into your document. This is much more SEO friendly than iframe. In order to be sure that the bots are not indexing the included page just add it to disallow in robots.txt
<html>
<header>
<script src="/js/jquery.js" type="text/javascript"></script>
</header>
<body>
<div id='include-from-outside'></div>
<script type='text/javascript'>
$('#include-from-outside').load('http://example.com/included.html');
</script>
</body>
</html>
You could also include jQuery directly from Google: http://code.google.com/apis/ajaxlibs/documentation/ - this means optional auto-inclusion of newer versions and some significant speed increase. Also, means that you have to trust them for delivering you just the jQuery ;)
My compact version:
<script type="text/javascript">
$(window).load(function () {
var frame = $('iframe').get(0);
if (frame != null) {
var frmHead = $(frame).contents().find('head');
if (frmHead != null) {
frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
//frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
}
}
});
</script>
However, sometimes the iframe is not ready on window loaded, so there is a need of using a timer.
Ready-to-use code (with timer):
<script type="text/javascript">
var frameListener;
$(window).load(function () {
frameListener = setInterval("frameLoaded()", 50);
});
function frameLoaded() {
var frame = $('iframe').get(0);
if (frame != null) {
var frmHead = $(frame).contents().find('head');
if (frmHead != null) {
clearInterval(frameListener); // stop the listener
frmHead.append($('style, link[rel=stylesheet]').clone()); // clone existing css link
//frmHead.append($("<link/>", { rel: "stylesheet", href: "/styles/style.css", type: "text/css" })); // or create css link yourself
}
}
}
</script>
...and jQuery link:
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js" type="text/javascript"></script>
As many answers are written for the same domains, I'll write how to do this in cross domains.
First, you need to know the Post Message API. We need a messenger to communicate between two windows.
Here's a messenger I created.
/**
* Creates a messenger between two windows
* which have two different domains
*/
class CrossMessenger {
/**
*
* #param {object} otherWindow - window object of the other
* #param {string} targetDomain - domain of the other window
* #param {object} eventHandlers - all the event names and handlers
*/
constructor(otherWindow, targetDomain, eventHandlers = {}) {
this.otherWindow = otherWindow;
this.targetDomain = targetDomain;
this.eventHandlers = eventHandlers;
window.addEventListener("message", (e) => this.receive.call(this, e));
}
post(event, data) {
try {
// data obj should have event name
var json = JSON.stringify({
event,
data
});
this.otherWindow.postMessage(json, this.targetDomain);
} catch (e) {}
}
receive(e) {
var json;
try {
json = JSON.parse(e.data ? e.data : "{}");
} catch (e) {
return;
}
var eventName = json.event,
data = json.data;
if (e.origin !== this.targetDomain)
return;
if (typeof this.eventHandlers[eventName] === "function")
this.eventHandlers[eventName](data);
}
}
Using this in two windows to communicate can solve your problem.
In the main windows,
var msger = new CrossMessenger(iframe.contentWindow, "https://iframe.s.domain");
var cssContent = Array.prototype.map.call(yourCSSElement.sheet.cssRules, css_text).join('\n');
msger.post("cssContent", {
css: cssContent
})
Then, receive the event from the Iframe.
In the Iframe:
var msger = new CrossMessenger(window.parent, "https://parent.window.domain", {
cssContent: (data) => {
var cssElem = document.createElement("style");
cssElem.innerHTML = data.css;
document.head.appendChild(cssElem);
}
})
See the Complete Javascript and Iframes tutorial for more details.
Other answers here seem to use jQuery and CSS links.
This code uses vanilla JavaScript. It creates a new <style> element. It sets the text content of that element to be a string containing the new CSS. And it appends that element directly to the iframe document's head.
var iframe = document.getElementById('the-iframe');
var style = document.createElement('style');
style.textContent =
'.some-class-name {' +
' some-style-name: some-value;' +
'}'
;
iframe.contentDocument.head.appendChild(style);
When you say "doc.open()" it means you can write whatever HTML tag inside the iframe, so you should write all the basic tags for the HTML page and if you want to have a CSS link in your iframe head just write an iframe with CSS link in it. I give you an example:
doc.open();
doc.write('<!DOCTYPE html><html><head><meta charset="utf-8"/><meta http-quiv="Content-Type" content="text/html; charset=utf-8"/><title>Print Frame</title><link rel="stylesheet" type="text/css" href="/css/print.css"/></head><body><table id="' + gridId + 'Printable' + '" class="print" >' + out + '</table></body></html>');
doc.close();
You will not be able to style the contents of the iframe this way. My suggestion would be to use serverside scripting (PHP, ASP, or a Perl script) or find an online service that will convert a feed to JavaScript code. The only other way to do it would be if you can do a serverside include.
Incase if you have access to iframe page and want a different CSS to apply on it only when you load it via iframe on your page, here I found a solution for these kind of things
this works even if iframe is loading a different domain
check about postMessage()
plan is, send the css to iframe as a message like
iframenode.postMessage('h2{color:red;}','*');
* is to send this message irrespective of what domain it is in iframe
and receive the message in iframe and add the received message(CSS) to that document head.
code to add in iframe page
window.addEventListener('message',function(e){
if(e.data == 'send_user_details')
document.head.appendChild('<style>'+e.data+'</style>');
});
I think the easiest way is to add another div, in the same place as the iframe, then
make its z-index bigger than the iframe container, so you can easly just style your own div. If you need to click on it, just use pointer-events:none on your own div, so the iframe would be working in case you need to click on it ;)
I hope It will help someone ;)
I found another solution to put the style in the main html like this
<style id="iframestyle">
html {
color: white;
background: black;
}
</style>
<style>
html {
color: initial;
background: initial;
}
iframe {
border: none;
}
</style>
and then in iframe do this (see the js onload)
<iframe onload="iframe.document.head.appendChild(ifstyle)" name="log" src="/upgrading.log"></iframe>
and in js
<script>
ifstyle = document.getElementById('iframestyle')
iframe = top.frames["log"];
</script>
It may not be the best solution, and it certainly can be improved, but it is another option if you want to keep a "style" tag in parent window
Here, There are two things inside the domain
iFrame Section
Page Loaded inside the iFrame
So you want to style those two sections as follows,
1. Style for the iFrame Section
It can style using CSS with that respected id or class name. You can just style it in your parent Style sheets also.
<style>
#my_iFrame{
height: 300px;
width: 100%;
position:absolute;
top:0;
left:0;
border: 1px black solid;
}
</style>
<iframe name='iframe1' id="my_iFrame" src="#" cellspacing="0"></iframe>
2. Style the Page Loaded inside the iFrame
This Styles can be loaded from the parent page with the help of Javascript
var cssFile = document.createElement("link")
cssFile.rel = "stylesheet";
cssFile.type = "text/css";
cssFile.href = "iFramePage.css";
then set that CSS file to the respected iFrame section
//to Load in the Body Part
frames['my_iFrame'].document.body.appendChild(cssFile);
//to Load in the Head Part
frames['my_iFrame'].document.head.appendChild(cssFile);
Here, You can edit the Head Part of the Page inside the iFrame using this way also
var $iFrameHead = $("#my_iFrame").contents().find("head");
$iFrameHead.append(
$("<link/>",{
rel: "stylesheet",
href: urlPath,
type: "text/css" }
));
We can insert style tag into iframe.
<style type="text/css" id="cssID">
.className
{
background-color: red;
}
</style>
<iframe id="iFrameID"></iframe>
<script type="text/javascript">
$(function () {
$("#iFrameID").contents().find("head")[0].appendChild(cssID);
//Or $("#iFrameID").contents().find("head")[0].appendChild($('#cssID')[0]);
});
</script>
var link1 = document.createElement('link');
link1.type = 'text/css';
link1.rel = 'stylesheet';
link1.href = "../../assets/css/normalize.css";
window.frames['richTextField'].document.body.appendChild(link1);
This is how I'm doing in production. It's worth bearing in mind that if the iframe belongs to other website, it will trigger the CORS error and will not work.
var $iframe = document.querySelector(`iframe`);
var doc = $iframe.contentDocument;
var style = doc.createElement("style");
style.textContent = `*{display:none!important;}`;
doc.head.append(style);
In some cases you may also want to attach a load event to the iframe:
var $iframe = document.querySelector(`iframe`);
$iframe.addEventListener("load", function() {
var doc = $iframe.contentDocument;
var style = doc.createElement("style");
style.textContent = `*{display:none!important;}`;
doc.head.append(style);
});
There is a wonderful script that replaces a node with an iframe version of itself.
CodePen Demo
Usage Examples:
// Single node
var component = document.querySelector('.component');
var iframe = iframify(component);
// Collection of nodes
var components = document.querySelectorAll('.component');
var iframes = Array.prototype.map.call(components, function (component) {
return iframify(component, {});
});
// With options
var component = document.querySelector('.component');
var iframe = iframify(component, {
headExtra: '<style>.component { color: red; }</style>',
metaViewport: '<meta name="viewport" content="width=device-width">'
});
As an alternative, you can use CSS-in-JS technology, like below lib:
https://github.com/cssobj/cssobj
It can inject JS object as CSS to iframe, dynamically
This is just a concept, but don't implement this without security checks and filtering! Otherwise script could hack your site!
Answer: if you control target site, you can setup the receiver script like:
1) set the iframe link with style parameter, like:
http://your_site.com/target.php?color=red
(the last phrase is a{color:red} encoded by urlencode function.
2) set the receiver page target.php like this:
<head>
..........
$col = FILTER_VAR(SANITIZE_STRING, $_GET['color']);
<style>.xyz{color: <?php echo (in_array( $col, ['red','yellow','green'])? $col : "black") ;?> } </style>
..........
Well, I have followed these steps:
Div with a class to hold iframe
Add iframe to the div.
In CSS file,
divClass { width: 500px; height: 500px; }
divClass iframe { width: 100%; height: 100%; }
This works in IE 6. Should work in other browsers, do check!

Best way to retrieve image from server using ajax [duplicate]

Is it possible to reload an image with an identical file name from a server using jQuery?
For example, I have an image on a page, however, the physical image can change based on user actions. Note, this does not mean the file name changes, but the actual file itself.
ie:
User views image on default page
User uploads new image
Default image on page does not change(I assume this is due to the file name being identical, the browser uses the cached version)
Regardless of how often the code below is called, the same issue persists.
$("#myimg").attr("src", "/myimg.jpg");
In the jQuery documentation, the "load" function would be perfect if it had a default method of firing the event as opposed to binding a callback function to a successful/complete load of an element.
Any assistance is greatly appreciated.
It sounds like it's your browser caching the image (which I now notice you wrote in your question). You can force the browser to reload the image by passing an extra variable like so:
d = new Date();
$("#myimg").attr("src", "/myimg.jpg?"+d.getTime());
It's probably not the best way, but I've solved this problem in the past by simply appending a timestamp to the image URL using JavaScript:
$("#myimg").attr("src", "/myimg.jpg?timestamp=" + new Date().getTime());
Next time it loads, the timestamp is set to the current time and the URL is different, so the browser does a GET for the image instead of using the cached version.
This could be one of the two problems you mention yourself.
The server is caching the image
The jQuery does not fire or at least doesn't update the attribute
To be honest, I think it's number two. Would be a lot easier if we could see some more jQuery. But for a start, try remove the attribute first, and then set it again. Just to see if that helps:
$("#myimg").removeAttr("src").attr("src", "/myimg.jpg");
Even if this works, post some code since this is not optimal, imo :-)
with one line with no worries about hardcoding the image src into the javascript (thanks to jeerose for the ideas:
$("#myimg").attr("src", $("#myimg").attr("src")+"?timestamp=" + new Date().getTime());
To bypass caching and avoid adding infinite timestamps to the image url, strip the previous timestamp before adding a new one, this is how I've done it.
//refresh the image every 60seconds
var xyro_refresh_timer = setInterval(xyro_refresh_function, 60000);
function xyro_refresh_function(){
//refreshes an image with a .xyro_refresh class regardless of caching
//get the src attribute
source = jQuery(".xyro_refresh").attr("src");
//remove previously added timestamps
source = source.split("?", 1);//turns "image.jpg?timestamp=1234" into "image.jpg" avoiding infinitely adding new timestamps
//prep new src attribute by adding a timestamp
new_source = source + "?timestamp=" + new Date().getTime();
//alert(new_source); //you may want to alert that during developement to see if you're getting what you wanted
//set the new src attribute
jQuery(".xyro_refresh").attr("src", new_source);
}
This works great! however if you reload the src multiple times, the timestamp gets concatenated to the url too. I've modified the accepted answer to deal with that.
$('#image_reload_button').on('click', function () {
var img = $('#your_image_selector');
var src = img.attr('src');
var i = src.indexOf('?dummy=');
src = i != -1 ? src.substring(0, i) : src;
var d = new Date();
img.attr('src', src + '?dummy=' + d.getTime());
});
Have you tried resetting the image containers html. Of course if it's the browser that is caching then this wouldn't help.
function imageUploadComplete () {
$("#image_container").html("<img src='" + newImageUrl + "'>");
}
Some times actually solution like -
$("#Image").attr("src", $('#srcVal').val()+"&"+Math.floor(Math.random()*1000));
also not refresh src properly, try out this, it worked for me ->
$("#Image").attr("src", "dummy.jpg");
$("#Image").attr("src", $('#srcVal').val()+"&"+Math.floor(Math.random()*1000));
Using "#" as a delimiter might be useful
My images are kept in a "hidden" folder above "www" so that only logged users are allowed access to them. For this reason I cannot use the ordinary <img src=/somefolder/1023.jpg> but I send requests to the server like <img src=?1023> and it responds by sending back the image kept under name '1023'.
The application is used for image cropping, so after an ajax request to crop the image, it is changed as content on the server but keeps its original name. In order to see the result of the cropping, after the ajax request has been completed, the first image is removed from the DOM and a new image is inserted with the same name <img src=?1023>.
To avoid cashing I add to the request the "time" tag prepended with "#" so it becomes like <img src=?1023#1467294764124>. The server automatically filters out the hash part of the request and responds correctly by sending back my image kept as '1023'. Thus I always get the last version of the image without much server-side decoding.
Based on #kasper Taeymans' answer.
If u simply need reload image (not replace it's src with smth new), try:
$(function() {
var img = $('#img');
var refreshImg = function(img) {
// the core of answer is 2 lines below
var dummy = '?dummy=';
img.attr('src', img.attr('src').split(dummy)[0] + dummy + (new Date()).getTime());
// remove call on production
updateImgVisualizer();
};
// for display current img url in input
// for sandbox only!
var updateImgVisualizer = function() {
$('#img-url').val(img.attr('src'));
};
// bind img reload on btn click
$('.img-reloader').click(function() {
refreshImg(img);
});
// remove call on production
updateImgVisualizer();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img id="img" src="http://dummyimage.com/628x150/">
<p>
<label>
Current url of img:
<input id="img-url" type="text" readonly style="width:500px">
</label>
</p>
<p>
<button class="img-reloader">Refresh</button>
</p>
I may have to reload the image source several times. I found a solution with Lodash that works well for me:
$("#myimg").attr('src', _.split($("#myimg").attr('src'), '?', 1)[0] + '?t=' + _.now());
An existing timestamp will be truncated and replaced with a new one.
If you need a refresh of the exact URL and your browser has the image cached, you can use AJAX and a request header to force your browser to download a new copy (even if it isn't stale yet). Here's how you'd do that:
var img = $("#myimg");
var url = img.attr("src");
$.ajax({
url: url,
headers: { "Cache-Control": "no-cache" }
}).done(function(){
// Refresh is complete, assign the image again
img.attr("src", url);
});
Nothing else worked for me because while appending a token to the query string would download the new image, it didn't invalidate the image in the cache at the old URL so future requests would continue to show the old image. The old URL is the only one sent to the browser, and the server was directing the client to cache the image for longer than it should.
If this still doesn't refresh the image for you, see if this answer helps. For more information, here is documentation on the Cache-Control request header.
In the html:
foreach (var item in images) {
<Img src="#Url.Content(item.ImageUrl+"?"+DateTime.Now)" >
}
I simply do this in html:
<script>
$(document).load(function () {
d = new Date();
$('#<%= imgpreview.ClientID %>').attr('src','');
});
</script>
And reload the image in code behind like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
image.Src = "/image.jpg"; //url caming from database
}
}

How to make dynamically created Divs with meteor and then store & recall them based on ID from the database

Below I have a basic template that has a numerical input form. When you type a number in the form and click Add a list of Divs get created. The Divs are created with a class of "synth" and an id of "synth" + a number. The numbers go in succession based on a counter.
I want to not only store this information in the database but do so in a manner that (eventually) when a user logs in they will have access to their list of Divs as a "saved state" from their previous log in.
I am not even sure if I am going about this in an appropriate manner. I am simply sticking the createSynth() function in the Collection insert for lists. I have a feeling to do this "correctly" I should have two events that work in parallel - one sending to the lists Collection and the other to the dom/Template. These two blocks would then exchange data (some how) which in conjunction create the illusion of a "saved state".
Below is the code I have thus far.
HTML
<head>
<title></title>
</head>
<body>
{{> start}}
</body>
<template name="start">
<input id ="amount" type ="number" />
<input id ="submit" type="button" value="Add" />
<div id="applicationArea"></div>
</template>
Javascript
var lists = new Meteor.Collection("Lists");
var counter = 0;
counterSynth = 0;
if (Meteor.isClient) {
'use strict';
Template.start.events({
'mousedown #submit' : function () {
var amount = document.getElementById("amount").value;
for(i=0;i<amount;i++) {
lists.insert({SoundCircle:createSynth()}); // I am inserting the entire function call, is this the right path?
}
function createSynth() {
var synth = document.createElement("div");
synth.className = "synth";
synth.id = "synth" + (counterSynth++);
applicationArea.appendChild(synth);
};
},
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
You have to use a slightly different approach to this, basically just insert your stuff into the collection, and use handlebars to get it out. I'm not entirely sure what you were doing but you should get a good idea with the below
Server js
synths = new Meteor.Collection('synths'); //This will store our synths
Client js:
synths = new Meteor.Collection('synths'); //This will store our synths
Template.start.events({
'mousedown #submit' : function () {
var amount = document.getElementById("amount").value;
for(i=0;i<amount;i++) {
lists.insert({class:"synth", id:counterSynth});
}
},
});
Template.start.synth = function() {
return synths.find(); //This gives data to the html below
}
HTML:
{{#each synth}}
<div class="{{class}}" id="synth{{id}}">
Synth stuff here
</div>
{{/each}
It's probably best to dynamically recreate the DIVs every time you need them on the client, so the DIV is not stored on the server. If you really want to hard code/store the DIV on the server you would need to simply save the HTML as a string, to a Meteor collection.

Is there a cross-domain iframe height auto-resizer that works?

I tried a few solutions but wasn't successful. I'm wondering if there is a solution out there preferably with an easy-to-follow tutorial.
You have three alternatives:
1. Use iFrame-resizer
This is a simple library for keeping iFrames sized to their content. It uses the PostMessage and MutationObserver APIs, with fall backs for IE8-10. It also has options for the content page to request the containing iFrame is a certain size and can also close the iFrame when your done with it.
https://github.com/davidjbradshaw/iframe-resizer
2. Use Easy XDM (PostMessage + Flash combo)
Easy XDM uses a collection of tricks for enabling cross-domain communication between different windows in a number of browsers, and there are examples for using it for iframe resizing:
http://easyxdm.net/wp/2010/03/17/resize-iframe-based-on-content/
http://kinsey.no/blog/index.php/2010/02/19/resizing-iframes-using-easyxdm/
Easy XDM works by using PostMessage on modern browsers and a Flash based solution as fallback for older browsers.
See also this thread on Stackoverflow (there are also others, this is a commonly asked question). Also, Facebook would seem to use a similar approach.
3. Communicate via a server
Another option would be to send the iframe height to your server and then poll from that server from the parent web page with JSONP (or use a long poll if possible).
I got the solution for setting the height of the iframe dynamically based on it's content. This works for the cross domain content.
There are some steps to follow to achieve this.
Suppose you have added iframe in "abc.com/page" web page
<div>
<iframe id="IframeId" src="http://xyz.pqr/contactpage" style="width:100%;" onload="setIframeHeight(this)"></iframe>
</div>
Next you have to bind windows "message" event under web page "abc.com/page"
window.addEventListener('message', function (event) {
//Here We have to check content of the message event for safety purpose
//event data contains message sent from page added in iframe as shown in step 3
if (event.data.hasOwnProperty("FrameHeight")) {
//Set height of the Iframe
$("#IframeId").css("height", event.data.FrameHeight);
}
});
On iframe load you have to send message to iframe window content with "FrameHeight" message:
function setIframeHeight(ifrm) {
var height = ifrm.contentWindow.postMessage("FrameHeight", "*");
}
On main page that added under iframe here "xyz.pqr/contactpage" you have to bind windows "message" event where all messages are going to receive from parent window of "abc.com/page"
window.addEventListener('message', function (event) {
// Need to check for safety as we are going to process only our messages
// So Check whether event with data(which contains any object) contains our message here its "FrameHeight"
if (event.data == "FrameHeight") {
//event.source contains parent page window object
//which we are going to use to send message back to main page here "abc.com/page"
//parentSourceWindow = event.source;
//Calculate the maximum height of the page
var body = document.body, html = document.documentElement;
var height = Math.max(body.scrollHeight, body.offsetHeight,
html.clientHeight, html.scrollHeight, html.offsetHeight);
// Send height back to parent page "abc.com/page"
event.source.postMessage({ "FrameHeight": height }, "*");
}
});
What I did was compare the iframe scrollWidth until it changed size while i incrementally set the IFrame Height. And it worked fine for me. You can adjust the increment to whatever is desired.
<script type="text/javascript">
function AdjustIFrame(id) {
var frame = document.getElementById(id);
var maxW = frame.scrollWidth;
var minW = maxW;
var FrameH = 100; //IFrame starting height
frame.style.height = FrameH + "px"
while (minW == maxW) {
FrameH = FrameH + 100; //Increment
frame.style.height = FrameH + "px";
minW = frame.scrollWidth;
}
}
</script>
<iframe id="RefFrame" onload="AdjustIFrame('RefFrame');" class="RefFrame"
src="http://www.YourUrl.com"></iframe>
I have a script that drops in the iframe with it's content. It also makes sure that iFrameResizer exists (it injects it as a script) and then does the resizing.
I'll drop in a simplified example below.
// /js/embed-iframe-content.js
(function(){
// Note the id, we need to set this correctly on the script tag responsible for
// requesting this file.
var me = document.getElementById('my-iframe-content-loader-script-tag');
function loadIFrame() {
var ifrm = document.createElement('iframe');
ifrm.id = 'my-iframe-identifier';
ifrm.setAttribute('src', 'http://www.google.com');
ifrm.style.width = '100%';
ifrm.style.border = 0;
// we initially hide the iframe to avoid seeing the iframe resizing
ifrm.style.opacity = 0;
ifrm.onload = function () {
// this will resize our iframe
iFrameResize({ log: true }, '#my-iframe-identifier');
// make our iframe visible
ifrm.style.opacity = 1;
};
me.insertAdjacentElement('afterend', ifrm);
}
if (!window.iFrameResize) {
// We first need to ensure we inject the js required to resize our iframe.
var resizerScriptTag = document.createElement('script');
resizerScriptTag.type = 'text/javascript';
// IMPORTANT: insert the script tag before attaching the onload and setting the src.
me.insertAdjacentElement('afterend', ifrm);
// IMPORTANT: attach the onload before setting the src.
resizerScriptTag.onload = loadIFrame;
// This a CDN resource to get the iFrameResizer code.
// NOTE: You must have the below "coupled" script hosted by the content that
// is loaded within the iframe:
// https://unpkg.com/iframe-resizer#3.5.14/js/iframeResizer.contentWindow.min.js
resizerScriptTag.src = 'https://unpkg.com/iframe-resizer#3.5.14/js/iframeResizer.min.js';
} else {
// Cool, the iFrameResizer exists so we can just load our iframe.
loadIFrame();
}
}())
Then the iframe content can be injected anywhere within another page/site by using the script like so:
<script
id="my-iframe-content-loader-script-tag"
type="text/javascript"
src="/js/embed-iframe-content.js"
></script>
The iframe content will be injected below wherever you place the script tag.
Hope this is helpful to someone. 👍
I ran into this issue while working on something at work (using React). Basically, we have some external html content that we save into our document table in the database and then insert onto the page under certain circumstances when you're in the Documents dataset.
So, given n inlines, of which up to n could contain external html, we needed to devise a system to automatically resize the iframe of each inline once the content fully loaded in each. After spinning my wheels for a bit, this is how I ended up doing it:
Set a message event listener in the index of our React app which checks for a a specific key that we will set from the sender iframe.
In the component that actually renders the iframes, after inserting the external html into it, I append a <script> tag that will wait for the iframe's window.onload to fire. Once that fires, we use postMessage to send a message to the parent window with information about the iframe id, computed height, etc.
If the origin matches and the key is satisfied in the index listener, grab the DOM id of the iframe that we pass in the MessageEvent object
Once we have the iframe, just set the height from the value that is passed from the iframe postMessage.
// index
if (window.postMessage) {
window.addEventListener("message", (messageEvent) => {
if (
messageEvent.data.origin &&
messageEvent.data.origin === "company-name-iframe"
) {
const iframe = document.getElementById(messageEvent.data.id)
// this is the only way to ensure that the height of the iframe container matches its body height
iframe.style.height = `${messageEvent.data.height}px`
// by default, the iframe will not expand to fill the width of its parent
iframe.style.width = "100%"
// the iframe should take precedence over all pointer events of its immediate parent
// (you can still click around the iframe to segue, for example, but all content of the iframe
// will act like it has been directly inserted into the DOM)
iframe.style.pointerEvents = "all"
// by default, iframes have an ugly web-1.0 border
iframe.style.border = "none"
}
})
}
// in component that renders n iframes
<iframe
id={`${props.id}-iframe`}
src={(() => {
const html = [`data:text/html,${encodeURIComponent(props.thirdLineData)}`]
if (window.parent.postMessage) {
html.push(
`
<script>
window.onload = function(event) {
window.parent.postMessage(
{
height: document.body.scrollHeight,
id: "${props.id}-iframe",
origin: "company-name-iframe",
},
"${window.location.origin}"
);
};
</script>
`
)
}
return html.join("\n")
})()}
onLoad={(event) => {
// if the browser does not enforce a cross-origin policy,
// then just access the height directly instead
try {
const { target } = event
const contentDocument = (
target.contentDocument ||
// Earlier versions of IE or IE8+ where !DOCTYPE is not specified
target.contentWindow.document
)
if (contentDocument) {
target.style.height = `${contentDocument.body.scrollHeight}px`
}
} catch (error) {
const expectedError = (
`Blocked a frame with origin "${window.location.origin}" ` +
`from accessing a cross-origin frame.`
)
if (error.message !== expectedError) {
/* eslint-disable no-console */
console.err(
`An error (${error.message}) ocurred while trying to check to see ` +
"if the inner iframe is accessible or not depending " +
"on the browser cross-origin policy"
)
}
}
}}
/>
Here is an alternative implementation.
Basically if you able to edit page at other domain you can place another iframe page that belongs to your server which saving height to cookies.
With an interval read cookies when it is updated, update the height of the iframe. That is all.
Edit: 2019 December
The solution above basically uses another iframe inside of an iframe 3rd iframe is belongs to the top page domain, which you call this page with a query string that saves size value to a cookie, outer page checks this query with some interval. But it is not a good solution so you should follow this one:
In Top page :
window.addEventListener("message", (m)=>{iframeResizingFunction(m)});
Here you can check m.origin to see where is it comes from.
In frame page:
window.parent.postMessage({ width: 640, height:480 }, "*")
Although, please don't forget this is not so secure way. To make it secure update * value (targetOrigin) with your desired value.
Please follow documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
I found another server side solution for web dev using PHP to get the size of an iframe.
First is using server script PHP to an external call via internal function: (like a file_get_contents with but curl and dom).
function curl_get_file_contents($url,$proxyActivation=false) {
global $proxy;
$c = curl_init();
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7");
curl_setopt($c, CURLOPT_REFERER, $url);
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_FOLLOWLOCATION, 1);
if($proxyActivation) {
curl_setopt($c, CURLOPT_PROXY, $proxy);
}
$contents = curl_exec($c);
curl_close($c);
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
#$dom->loadHTML($contents);
$form = $dom->getElementsByTagName("body")->item(0);
if ($contents) //si on a du contenu
return $dom->saveHTML();
else
return FALSE;
}
$url = "http://www.google.com"; //Exernal url test to iframe
<html>
<head>
<script type="text/javascript">
</script>
<style type="text/css">
#iframe_reserve {
width: 560px;
height: 228px
}
</style>
</head>
<body>
<div id="iframe_reserve"><?php echo curl_get_file_contents($url); ?></div>
<iframe id="myiframe" src="http://www.google.com" scrolling="no" marginwidth="0" marginheight="0" frameborder="0" style="overflow:none; width:100%; display:none"></iframe>
<script type="text/javascript">
window.onload = function(){
document.getElementById("iframe_reserve").style.display = "block";
var divHeight = document.getElementById("iframe_reserve").clientHeight;
document.getElementById("iframe_reserve").style.display = "none";
document.getElementById("myiframe").style.display = "block";
document.getElementById("myiframe").style.height = divHeight;
alert(divHeight);
};
</script>
</body>
</html>
You need to display under the div (iframe_reserve) the html generated by the function call by using a simple echo curl_get_file_contents("location url iframe","activation proxy")
After doing this a body event function onload with javascript take height of the page iframe just with a simple control of the content div (iframe_reserve)
So I used divHeight = document.getElementById("iframe_reserve").clientHeight; to get height of the page external we are going to call after masked the div container (iframe_reserve). After this we load the iframe with its good height that's all.

Resources