Javascript+HTA, reload iframe and keep scroll position - javascript

I created an account a very long time ago but I never really use it, as I always manage to find the answers to my questions in already solved threads. So, this is the first time since I'm working on my current program that I was not able to find a working answer on SO. However, if I simply missed it, please be nice to me ^^
A bit of context that may explain why I can't manage to apply any given solution despite many threads exists about this... I am doing:
A HTA Interface
With an iframe to a local text file
And a link to a js file that I want to use to refresh the iframe every 500 ms.
The goal is to make a chat; people can write on the text file and it automatically appears on the HTA interface.
I don't know ANYTHING about JS, frankly. So I found here that piece of code to refresh the iframe.
window.setInterval(function() {
document.getElementById('chatbox').contentWindow.location.reload();
}, 500);
It works, but upon refreshing the iframe, it scrolls back to the top; which makes the chat unreadable, as you can guess. Many solutions that I've read on SO won't work for me, maybe because it doesn't fit with this way of refreshing iframes, or with HTA, or I'm just too dumb with js to know how to make them work.
If anyone has a solution that I could just copy and use, even if I don't understand what I'm doing - it won't be very satisfying intellectually but at least I could focus on finishing my interface :) thanks a lot!

If you refresh the iframe by updating innerHTML from the text file, instead of doing a reload, it won't change the scroll position. Here's an example HTA:
<!DOCTYPE html>
<meta http-equiv="x-ua-compatible" content="ie=9">
<html>
<head>
<script>
function Refresh() {
var Iframe = document.getElementById("chatbox").contentWindow;
window.setInterval(function() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fh = fso.OpenTextFile(".\\Chat.txt",1);
var FileContents = fh.AtEndOfStream ? "" : fh.ReadAll();
fh.Close();
Iframe.document.body.innerHTML = "<pre>" + FileContents + "</pre>"
}, 500);
}
</script>
<style>
#chatbox {height:30em;}
</style>
</head>
<body onload="Refresh()">
<iframe id=chatbox title="Chat Box">
</iframe>
</body>
</html>

Related

How to rewrite an iframe multiple times with a script that declares a constant

I'm writing an in-browser HTML editor where users write HTML code that is sent (on every keystroke) to an iframe for preview purposes. This is the code I have now:
onCodeChange(html) {
iframe.contentDocument.open();
iframe.contentDocument.write(html);
iframe.contentDocument.close();
}
The problem appears when users try to add <script> tags with a const in them:
<!doctype html>
<html>
<body>
<script>
const a = 42;
</script>
</body>
</html>
When a user types in ... const a = 4 ... everything is fine (initial declaration of a as 4), but when they finish typing ... const a = 42 ... (redeclaration of a as 42), then an error is thrown:
Uncaught SyntaxError: Identifier 'a' has already been declared
I think that this happens because the JavaScript context remains the same even if the document is rewritten.
I have tried using srcdoc:
onCodeChange(html) {
iframe.srcdoc = html;
}
It works, but causes the iframe to flicker (I imagine that it unloads and loads the iframe) and I don't want users to have seizures...
I'm currently thinking about having two iframes (one on top of the other), using srcdoc, and swapping their z-index on load. It's very weird, but could fix the flickering.
Is there anything else I can do?
Just wrap your script with an IIFE every time you want to change the code.
<!doctype html>
<html>
<body>
<script>
(function(){const a = 42;})();
</script>
</body>
</html>

How to run code only when iframe loaded

I have been battling with this issue for a few days now and finally found a partial solution but I think it could be improved.
In my project, I have a series of iframes that contain videos. When a link is clicked are displayed with a slide transition and when the link is clicked again the video stops and the span containing the iframe is hidden also with a transition.
This is achieved by adding and removing a css class of "open" that has a height and a transition in it. In addition to this I have an event listener that collapses the containing span also when the video finishes. All this works fine and to save time I am not posting the code.
The issue I was having was with slow page loading times, so I removed the src attribute for the iframes from the html and moved it to my js file and assigned it only after the click is performed. This wasn't working and I realised I needed the iframe to fully load before running the rest of the code inside the "click" method. So I delayed this part of the code by 100ms.
All this works, but I feel it would be better to have the rest of the code run not after a 100ms lapse but when the iframe is loaded (in case page viewed by slower computers). Not sure how to do this.
Here is the code as it stands now:
var player;
var frame = $("#frame");
frame.bind("load", function () {
player = $(this).contents().find("#myVid");
player.on('ended', function () {
frame.removeClass("open");
});
});
$("#clickableLink").click(function(){
if (frame.hasClass("open")) {
frame.removeClass("open");
frame.contents().find('#myVid').get(0).pause();
} else {
function delayed(){
frame.addClass("open");
frame.contents().find('#myVid').get(0).play();
}
frame.attr("src","iframe.html");
setTimeout(delayed, 100);
}
});
Fairly new to development so I am looking for the simplest way to do this. Any help appreciated.
Here is a super simple example of calling code when the iframe has loaded. Check out the onload attribute of the iframe tag:
<head>
<script>
function frameLoaded() {
alert('frame loaded!');
};
</script>
</head>
<body>
<iframe id="frame" src="https://en.wikipedia.org/wiki/HTML_element#Frames" onload="frameLoaded(this)" />
</body>

Check browser width and execute a Javascript file and override another Javascript

There is an HTML file with many embedded YouTube videos.Page load times were slow so I decided to use this JS file to force the page load an image instead of iframe, until the user clicks on it. http://www.skipser.com/p/2/p/youtube-video-embed-like-google-plus.html
CSS checks if the visitor uses mobile and optimizes the layout for mobile.I modified the above mentioned JS script to show smaller thumbnails so it will work better on mobile(no need to scroll horizontally).I have 2 version of that JS script now.
The goal: Check if visitor uses desktop.If yes, execute the regular gplus-youtubeembed.js.If visitor uses mobile then execute gplus-youtubeembed-mobile.js
This was the original HTML.It would only load the desktop version of JS.As a result, mobile visitors would see a very large video thumbnail.
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<meta name="viewport" content="width=device-width; initial-scale=1.0; user-scalable=yes">
<script src=gplus-youtubeembed.js></script>
<link rel=stylesheet type="text/css" href="css/style.css" media=screen />
<title>Page Title</title>
</head>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
<script>optimizeYouTubeEmbeds()</script> <!--needed to load image instead of iframe-->
</body>
</html>
Then I used this method http://www.coalmarch.com/blog/how-to-execute-javascript-based-on-screen-size-using-jquery
if ( $(window).width() > 700) {
//added the content of gplus-youtubeembed.js here
}
else {
//added the content of gplus-youtubeembed-mobile.js here
}
I named that gplus-youtubeembed-combine.js and replaced gplus-youtubeembed.js with gplus-youtubeembed-combined.js , in the HTML doc.
The outcome: The only JS that gets executed is the mobile version.Desktop visitors see small thumbnails.Everyting works fine in mobile.Why doesn't the gplus-youtubeembed-combined.js work properly ? It's supposed to detect if the screen width is over 700 and execute the gplus-youtubeembed.js file but it doesn't.Any help is appreciated.Thanks !
From what I understand
if ( $(window).width() > 700) {
//added the content of gplus-youtubeembed.js here
}
else {
//added the content of gplus-youtubeembed-mobile.js here
}
works only when a window is first loaded or refreshed. Try changing the size of your window and refresh your page. If the code works, you'll need something to reload the script or the page on resize.
Something like this:
$(window).resize(function() {
// add the stuff here to execute the your slider again;
});
or this might do the trick:
<script>
function refresh() { location.reload(); }
</script>
<body onresize="refresh()">
I'm no expert but I had similar issue just a few minutes ago. Hope I helped.
Here is a little more detail on the second code that you asked for.
I'm only sharing with you what I'm learning as I go. I'm a real noob. Having the same problem as you but with a different snippet.
$(document).ready(function(){
$(window).on('resize', function(){
if ($(window).width() > 700) {
// code here
} esle {
// code here
}
});
});
But you said refreshing your page didn't make the JS run. Which means this method might not help you. Have you checked to make sure both JS run and work regardless of page width? Maybe test each JS individually to make sure the mobile version is good.
Sorry if I can't be much help to you. I'm learning as I try to solve my own issues. Thought yours was close to the issue I was having.
Problem was fixed.When I copy/pasted two JS files into the if/else statement, something broke the "if" statement so "else" was always being executed.I confirmed this by swapping the mobile and desktop versions and changing ">" to "<".In that case only desktop version would load.
Instead of copy/pasting the entire JS files into else/if, I left the common part out and added only the portion that was different in desktop/mobile version.Sounds simple, but it didn't come to my mind at the beginning.
The author of the original JS did not provide the mobile friendly version of the JS so people who use that code on their website might benefit from this post.One issue with the below code is that on mobile version, the image doesn't have a play button.It only has a thumbnail so make sure the visitor knows it's a video.This can be fixed by further tweaking the code but that's another topic.
Working version.
gplus-youtubeembedded-combine.js
// gplus-youtubeembed - Makes embedded YouTube video iframes Google+ style to improve page loading speed.
// Copyright (c) 2013 by Arun - http://www.skipser.com
// Licensed under the GNU LGPL license: http://www.gnu.org/copyleft/lesser.html
// For usage details, read - http://www.skipser.com/510
// Call this function at the end of the closing </body> tag.
function optimizeYouTubeEmbeds() {
// Get all iframes
var frames = document.getElementsByTagName( 'iframe' );
// Loop through each iframe in the page.
for ( var i = 0; i < frames.length; i++ ) {
// Find out youtube embed iframes.
if ( frames[ i ].src && frames[ i ].src.length > 0 && frames[ i ].src.match(/http(s)?:\/\/www\.youtube\.com/)) {
// For Youtube iframe, extract src and id.
var src=frames[i].src;
var p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;
var id=(src.match(p) ? RegExp.$1 : false);
if(id == false) { continue;}
// Get width and height.
var w=frames[i].width;
var h=frames[i].height;
if(src == '' || w=='' || h=='') {continue;}
if ( $(window).width() > 700) {
// Thease are to position the play button centrally.
var pw=Math.ceil(w/2-38.5);
var ph=Math.ceil(h/2+38.5);
// The image+button overlay code.
var code='<div alt="For this Google+ like YouTube trick, please see http://www.skipser.com/510" style="width:'+w+'px; height:'+h+'px; margin:0 auto"><img src="http://i.ytimg.com/vi/'+id+'/hqdefault.jpg" style="width:'+w+'px; height:'+h+'px;" /><div style="background: url(\'data:image/png;base64,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\') no-repeat scroll 0 0 transparent;height: 77px;width: 77px; position:relative; margin-left:'+pw+'px; margin-top:-'+ph+'px;z-index:5;"></div></div>';
}
else {
var pw=Math.ceil(w/7.5-1.5);
var ph=Math.ceil(h/4.7+10);
var code='<div alt="For this Google+ like YouTube trick, please see http://www.skipser.com/510" style="max-width:100%;height:auto; margin:0 auto"><img src="http://i.ytimg.com/vi/'+id+'/hqdefault.jpg" style="max-width:100%;height:auto;" /> <div style="background: url(\'data:image/png;base64,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\') no-repeat scroll 0 0 transparent;height: 77px;width: 77px; position:relative; margin-left:'+pw+'px; margin-top:-'+ph+'px;z-index:5;"></div><br><br><br></div>';
}
// Replace the iframe with a the image+button code.
var div = document.createElement('div');
div.innerHTML=code;
div=div.firstChild;
frames[i].parentNode.replaceChild(div, frames[i]);
i--;
}
}
}
// Replace preview image of a video with it's iframe.
function LoadYoutubeVidOnPreviewClick(id,w ,h) {
var code='<iframe src="https://www.youtube.com/embed/'+id+'/?autoplay=1&autohide=1&border=0&wmode=opaque&enablejsapi=1" width="'+w+'" height="'+h+'" frameborder=0 allowfullscreen style="border:1px solid #ccc;" ></iframe>';
var iframe = document.createElement('div');
iframe.innerHTML=code;
iframe=iframe.firstChild;
var div=document.getElementById("skipser-youtubevid-"+id);
div.parentNode.replaceChild( iframe, div)
}
I've implemented the code here (it's my website) http://www.veryslowpc.com/security-measures.html
The outcome: in order to reduce page load times, embedded video iframes don't load until the user clicks on them, and the thumbnails are within page width when viewed on mobile.
Thank you for suggestions.
EDIT: The code should display the play button now.

Getting a not defined error with scripts embedded in an iFrame

I have a knowledge base for my work. I'm trying to get full html w/scripting setup within a iFrame instance.
Below is a Chrome expansion of my setup. When I click the button in my div/iframe, I get a Uncaught ReferenceError: test is not defined error.
Thoughts?
http://bytes.com/topic/javascript/answers/153274-script-iframe-can-not-call-functions-defined-parent-document
Per link:
Functions are not properties of the document, but of the window.
Try
parent.foo();
or
top.foo();
<button onclick='parent.test();'>test</button> works now... top.test() works too, BUT, I'd like a way to normalize this. Its not very intuitive.
Is there a way to NOT have to prefix top. or parent.?
Make sure the jQuery library is being called before any other script inside your <head> section.
Most of the times I get this error, I just change the order the scripts being called on the page (always under jQuery) and it solves the problem.
This is a late answer, but I'll share my solution.
I needed an iframe as a preview container. So parent.something would be a hassle.
This seems to work:
<iframe id='iframe' sandbox="allow-same-origin allow-scripts"></iframe>
And populate it with this (example using jquery):
$(function() {
let $iframe = $('#iframe');
$iframe.ready(function() {
let ifhead = `
<meta charset="UTF-8"><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"><\/script>`;
let ifbody = `<h1>My Body</h1>`;
let ifscript = `$(function() { $('h1').css('color', 'blue')})`;
let html = `<html><head>${ifhead}</head><body>${ifbody}<script>${ifscript}<\/script></body></html>`;
document.getElementById("iframe").contentWindow.document.open();
document.getElementById("iframe").contentWindow.document.write(html);
document.getElementById("iframe").contentWindow.document.close();
});
});
Now the iframe acts as a stand-alone page.

Possible to flash a Browser window using Javascript?

Like many programs flash their window on the taskbar / dock to alert the user to switch to the program,
Is it possible to flash the Browser window using Javascript? (FireFox-only scripts are also welcome)
This is useful for web-based Chat / Forum / Community-based software where there is lots of real-time activity.
#Hexagon Theory: Why would you ever rewrite the whole head element just to change the value of one element in the head? Your solution is horribly inefficient on multiple levels.
<html>
<head>
<link rel="icon" href="on.png" type="image/png" id="changeMe" />
<script type="text/javascript" src="flash.js"></script>
</head>
<body>
</body>
</html>
flash.js:
function Flasher(speed) {
var elem = document.getElementById('changeMe');
this.timer = setTimeout(function() {
elem.href = elem.href == 'on.png' ? 'off.png' : 'on.png';
}, speed);
this.stop = function() { clearTimeout(this.timer); }
}
/* sample usage
*
* var flasher = new Flasher(1000);
* flasher.stop();
*/
It didn't really have to be a class but it helped keep the global namespace clean. That's untested but if simply changing the href doesn't work for some reason, clone the link node, change the href and replace the old link with the cloned one.
At this point, it seems only causing an alert dialog to pop up does the trick... this seems a bit too intrusive, I feel, particularly given the use you're trying to put it to. Instead of causing it to flash, though, you could modify document.title to grab the user's attention, either by prepending some signal (perhaps the string "NEW!") to the site's name, and then using an interval to constantly change it to "", which would then give a nice little "flashing" illusion.
Bare-bones example:
<html>
<head>
<title>Chat System</title>
<script>
var timer, old_t = document.title, blink_amount = 5, cur_b = 0;
function notify()
{
cur_b = 0;
timer = setInterval(function()
{
if (cur_b < blink_amount * 2)
{
cur_b++;
document.title = (document.title.indexOf('NEW! ') != -1) ? old_t : 'NEW! ' + old_t;
}
else
{
clearInterval(timer);
}
}, 600);
}
notify();
// From here, it's just a matter of calling the
// notify() function whenever you detect a new message.
</script>
</head>
<body>
</body>
</html>
Hey, another interesting solution to this question hit me just now. Why not really grab the user's attention by making the icon flash in their browser? You could, for example, make two icons (on.png and off.png in my example below) and repeatedly swap them out to really catch a user's eye. The following is a bare-bones implementation; do keep in mind that you will need to reference this script remotely or put it in the body of the page because it uses a method that repeatedly replaces the content of the <head> tag. Give it a try, though; I rather like the simplicity of it.
page.html:
<html>
<head>
<link rel="icon" href="on.png" type="image/png" />
<script type="text/javascript" src="flash.js"></script>
</head>
<body>
</body>
</html>
flash.js:
var timer, speed = 175;
function flash()
{
head_html = document.getElementsByTagName('head')[0].innerHTML;
if (head_html.indexOf('href="on.png"') != -1)
document.getElementsByTagName('head')[0].innerHTML = head_html.replace('on.png', 'off.png');
else
document.getElementsByTagName('head')[0].innerHTML = head_html.replace('off.png', 'on.png');
timer = setTimeout('flash()', speed);
}
function kill_flash() {clearTimeout(timer);}
flash();
Mozilla previously had Window.getAttention() but by 2018 no browsers were listed supporting it. https://web.archive.org/https://developer.mozilla.org/en-US/docs/Web/API/Window/getAttention
Its behavior:
Windows, the taskbar button for the window flashes
Linux, some window managers flash the taskbar button, others focus the window immediately
Macintosh, the icon in the upper right corner of the desktop flashes
Window.Focus() should do it on Windows, not sure on other platforms though. You might find it brings the Window to the foreground if it's minimised though, which would be very annoying :)

Categories

Resources