Detecting content loaded on ajax div - javascript

I am using the ajaxpage function provided by the code on Dynamic Drive (http://www.dynamicdrive.com/dynamicindex17/ajaxcontent.htm).
I am trying to make the original page that sent the ajax content request to the div to detect once the div is loaded.
This is what I have tried:
A lot of research points to this
functionality in jQuery. I do not wish to use jQuery at all in this
project.
Including script in the loaded content. This doesn't work
and I believe it's due to limitations of this functionality.
I have
tried monitoring different states of the div, however nothing seems
to change.
All I really need is a way to call a function on the main page once the div content is loaded.

Modify ajaxpage function , add another parameter for a callback function, call your function within onreadystatechange. but I recommend you to use jQuery instead.
UPDATE:
Here's what I did. I added new a parameter called callback to your function ajaxpage , when you fire the ajax event onreadystatechange if I we get a true value from loadpage we excecute the callback and to identify which page or content was I'm adding the *page_request* and containerid arguments. Now you can add that callback function to your ajaxpage function in this case I did it with the function called myCallbackFunction.
I don't recommend you this approach there a better ways and best practices, if you're learning avoid this it seems out of date.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Ajax Rotating Includes Script</title>
<script type="text/javascript">
/***********************************************
* Dynamic Ajax Content- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
***********************************************/
var loadedobjects = ""
var rootdomain = "http://" + window.location.hostname
function ajaxpage(url, containerid, callback) {
var page_request = false
if (window.XMLHttpRequest) // if Mozilla, Safari etc
page_request = new XMLHttpRequest()
else if (window.ActiveXObject) { // if IE
try {
page_request = new ActiveXObject("Msxml2.XMLHTTP")
} catch (e) {
try {
page_request = new ActiveXObject("Microsoft.XMLHTTP")
} catch (e) {}
}
} else
return false
page_request.onreadystatechange = function () {
if (loadpage(page_request, containerid)) {
if (callback)
callback(page_request, containerid);
}
}
page_request.open('GET', url, true)
page_request.send(null)
}
function loadpage(page_request, containerid) {
if (page_request.readyState == 4 && (page_request.status == 200 || window.location.href.indexOf("http") == -1)) {
document.getElementById(containerid).innerHTML = page_request.responseText
return true;
}
return false;
}
function loadobjs() {
if (!document.getElementById)
return
for (i = 0; i < arguments.length; i++) {
var file = arguments[i]
var fileref = ""
if (loadedobjects.indexOf(file) == -1) { //Check to see if this object has not already been added to page before proceeding
if (file.indexOf(".js") != -1) { //If object is a js file
fileref = document.createElement('script')
fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", file);
} else if (file.indexOf(".css") != -1) { //If object is a css file
fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", file);
}
}
if (fileref != "") {
document.getElementsByTagName("head").item(0).appendChild(fileref)
loadedobjects += file + " " //Remember this object as being already added to page
}
}
}
function myCallbackFunction(page_request,containerid) {
// Do your stuff here
console.log("page_request", page_request);
console.log("container id", containerid);
}
</script>
<style type="text/css">
#leftcolumn{
float:left;
width:150px;
height: 400px;
border: 3px solid black;
padding: 5px;
padding-left: 8px;
}
#leftcolumn a{
padding: 3px 1px;
display: block;
width: 100%;
text-decoration: none;
font-weight: bold;
border-bottom: 1px solid gray;
}
#leftcolumn a:hover{
background-color: #FFFF80;
}
#rightcolumn{
float:left;
width:550px;
min-height: 400px;
border: 3px solid black;
margin-left: 10px;
padding: 5px;
padding-bottom: 8px;
}
* html #rightcolumn{ /*IE only style*/
height: 400px;
}
</style>
</head>
<body>
<div id="leftcolumn">
Porsche Page
Ferrari Page
Aston Martin Page
<div style="margin-top: 2em">Load CSS & JS files</div>
Load "style.css" and "tooltip.js"
</div>
<div id="rightcolumn"><h3>Choose a page to load.</h3></div>
<div style="clear: left; margin-bottom: 1em"></div>
</body>
</html>

Related

Want web page (js) file upload without form submission with servlet

I am attempting to write a web page that allows an upload of one or more files to a servlet without making a form submission.
I'm willing to use jQuery and/or Ajax; I do not want to use other third-party libraries.
I have a servlet that works WITH a form submission; I can make alterations to that if necessary to make it work without a form submission:
package ajaxdemo;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
/* The Java file upload Servlet example */
#WebServlet(name = "FileUploadServlet", urlPatterns = { "/fileuploadservlet" })
#MultipartConfig
(
fileSizeThreshold = 1024 * 1024 * 1, // 1 MB
maxFileSize = 1024 * 1024 * 10, // 10 MB
maxRequestSize = 1024 * 1024 * 100 // 100 MB
)
public class FileUploadServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Request-Method", "POST");
/* Receive file uploaded to the Servlet from the HTML5 form */
System.out.println("FileUploadServlet.doPost() invoked");
Part filePart = request.getPart("file");
String fileName = filePart.getSubmittedFileName();
for (Part part : request.getParts())
{
part.write("C:\\tmp\\" + fileName);
}
response.getWriter().print("The file uploaded sucessfully.");
response.getWriter().print("Filename: " + fileName + " saved in //tmp");
}
}
This works with the following input form:
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>File Upload Form</title>
</head>
<body>
<h3>File Upload:</h3>
Select a file to upload: <br />
<form action = "UploadFile.jsp" method = "post"
enctype = "multipart/form-data">
<input type = "file" name = "file" size = "50" />
<br />
<input type = "submit" value = "Upload File" />
</form>
</body>
</html>
In trying to make it work without the form submission, I have the following page:
<html>
<head>
<!-- after https://www.w3schools.com/howto/howto_css_modals.asp -->
<style>
body{font-family: Arial, Helvetica, sans-serif; }
/* file Upload dialog (from w3schools howto_css_modals) */
.fileUploadDialogClass
{
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* "Modal Content" (from w3schools howto_css_modals) */
.fileUploadDialogClassContentClass
{
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}
/* "The Close Button" (from w3schools howto_css_modals) */
.fileUploadDialogCloseButtonClass
{
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
/* (from w3schools howto_css_modals) */
.fileUploadDialogCloseButtonClass:hover,
.fileUploadDialogCloseButtonClass:focus
{
color: #000;
text-decoration: none;
cursor: pointer;
}
#upperLeft { background-color: lightgreen; border: 3px solid; }
#licenseeCityState {background-color: lightblue; }
#buttonDiv button { width: 100%; }
#mainTable { width: 100%; }
#mainTable { border: 1px solid; }
</style>
</head>
<body>
<script src="http://code.jquery.com/jquery-3.6.0.js"></script>
<!-- file upload popup dialog -->
<div id="fileUploadDialog" class="fileUploadDialogClass">
<div class="fileUploadDialogClassContentClass">
<span class="fileUploadDialogCloseButtonClass">×</span> <!-- 'times' is an 'x' for urh corner -->
<P>Select a file, then upload it to be read</P>
<br><input type="file" id="fileUploadChooserButton">
<br><button id="fileUploadButton">Upload</button>
</div>
</div>
<table>
<tr>
<td>
<div id='buttonDiv'>
<table id='buttonTable'>
<tr><td><button id='openButton'>Open File</button></td></tr>
<tr><td><button id='closeButton'>Close</button></td></tr>
</table>
</div>
</td>
<td style="vertical-align: top">
<div id='lowerRight'>
<table id='mainTable'>
<tr><td><div id="idString">xxx</div></td></tr>
</table>
</div>
</td>
</tr>
</table>
<script>
document.getElementById("idString").innerText = "xyz2"; // used to keep track of which version is displayed.
var fileUploadDialog = document.getElementById("fileUploadDialog");
var fileUploadDialogDisplayButton = document.getElementById("openButton");
var fileUploadDialogCloseButton = document.getElementsByClassName("fileUploadDialogCloseButtonClass")[0];
var fileUploadButton = document.getElementById("fileUploadButton");
//fileUploadButton.onclick = uploadFile();
fileUploadDialogDisplayButton.onclick = function() { fileUploadDialog.style.display = "block"; }
fileUploadDialogCloseButton.onclick = function() { fileUploadDialog.style.display = "none"; }
//async function uploadFile()
fileUploadButton.onclick = function()
{
console.log("uploadFile() invoked");
let formData = new FormData();
var fileUploadChooserButton = document.getElementById("fileUploadChooserButton");
var files = fileUploadChooserButton.files;
formData.append(files.name, files[0], files[0].name || "no filename")
;
console.log("about to await fetch");
// await fetch('http://localhost:8080/AjaxWithJSP/fileuploadservlet', { method: "POST", body: formData });
const xmlRequest = new XMLHttpRequest();
xmlRequest.onload = () =>
{
alert(xmlRequest.status + " reported as onload status");
};
//http://localhost:8080/AjaxWithJSP/LittleTable.html
xmlRequest.open('POST', 'http://localhost:8080/AjaxWithJSP/fileuploadservlet', true);
xmlRequest.setRequestHeader("Content-type", "multipart/form-data");
xmlRequest.send(formData);
}
window.onclick = function(event) { if(event.target == fileUploadDialog) { fileUploadDialog.style.display = "none"; } }
</script>
</body>
</html>
This produces an error message from the server (in the eclipse console) saying that no multipart boundary is found.
If I comment out the JavaScript line setting the request header, the error message is that filePart is null, so getSubmittedFileName() can't be called on it.
I found another explanation of doing it that involved await fetch(...) instead of xmlRequest.send(...); I have it commented out above. I couldn't make it work either.
Eventually, I want to allow the user to upload multiple files, and return a JSON structure with which I'll display a table. But I haven't figured out how to get the first file uploaded yet.
xmlRequest.setRequestHeader("Content-type", "multipart/form-data");
The multipart/form-data has a mandatory parameter describing the boundary that appears between each of the multiple parts.
Under normal circumstances, xhr or fetch will generate the whole Content-Type header, including the boundary parameter from the FormData object.
Here, you've overridden the Content-type and set it to multipart/form-data without a boundary.
Just don't do that.

Uncaught TypeError: chrome.runtime.sendMessages is not a function in Chrome Extension Development

I am working on a Chrome extension using manifest 3. I have a timer in the popup HTML page which is triggered when the button is pressed. I realized that the timer resets every time the popup is opened whereas I want it to remain running in the background.
So I thought the only answer would be to tie the popup page to the background.js. I created a state for the timer called pomo_state. Then I send a message from the popup.js to the background.js which either turns the state to OFF or ON depending on the button pressed by the user in the popup page. Then I am planning to run the timer in the background and dynamically update the popup.html every time it is opened by having it retrieve the timer from the background.
But I couldn't even get past the sending and receiving of the pomo_state. I got the error in the title. And when I changed it to chrome.extensions.runtime.sendMessages, I got an error saying message was undefined or something like that. Also right now in my popup.js I have the timer code for now, but putting it in the background.js will be another problem since I got an error for background.js not registering in the manifest when I did that. Also I should say that looking at other questions that had the same error, I couldn't really find a concrete answer. And I was wondering what I am screwing up below is probably really basic.
I will attach part of my background.js, popup.html and popup.js. Hopefully it will be sufficient. Thanks!
background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) =>{
if (request.message === 'get_name'){
chrome.storage.local.get('name', data =>{
if (chrome.runtime.lastError){
sendResponse({
message: 'fail'
});
return;
}
sendResponse({
message: 'success',
payload: data.name
})
});
return true;
} else if (request.message === 'pomo_change'){
chrome.storage.local.set({
pomo:request.payload
}, () => {
if (chrome.runtime.lastError){
sendResponse({message: 'fail'});
return;
}
sendResponse({message: 'success'});
})
return true;
}
});
popup.js
const start_pom = document.getElementById("start_pom");
let colorSwitchCounter = 1;
const startingMinutes = 25;
let time = startingMinutes*60;
const countdownEl = document.getElementById("countdown-timer");
setInterval(updateCountdown,1000);
function updateCountdown(){
const minutes = Math.floor(time / 60);
let seconds = time%60;
countdownEl.innerHTML = `${minutes}: ${seconds}`;
console.log(`${minutes}: ${seconds}`);
time--;
}
start_pom.addEventListener("click", ()=>{
console.log("I was clicked", colorSwitchCounter);
colorSwitchCounter = colorSwitchCounter +1;
if(colorSwitchCounter%2 ==0){
chrome.runtime.sendMessage({
message: 'pomo_change',
payload: 'ON'
}, response =>{
if (response.message === 'success'){
start_pom.innerHTML= 'Stop Pomodoro';
start_pom.style.backgroundColor = "#de7878";
}
});
}
else{
chrome.runtime.sendMessages({
message: 'pomo_change',
payload: 'OFF'
}, response =>{
if (response.message === 'success'){
start_pom.innerHTML= 'Start Pomodoro';
start_pom.style.backgroundColor = "#de7878";
}
});
}
})
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body{
padding:0px;
height: wrap-content;
width: 255px;
background-color: whitesmoke;
}
section{
padding:10px;
margin-bottom: 5px;
}
.hero-area{
color: black;
text-align: center;
font-size: 10px;
border-bottom: 1px solid lightgrey;
}
.button{
text-align: center;
width: 50%;
height: wrap-content;
margin: auto;
padding:10px;
display: flex;
background-color: #78A3DE;
color:white;
font-weight: 200;
cursor: pointer;
border:none;
}
.button:hover{
background-color:#78a3de91;
}
.pom-area-info-timer{
text-align: center;
font-size: 20px;
}
.pom-area-info-status{
text-align: center;
font-size: 10px;
}
</style>
</head>
<body>
<section class = 'hero-area'>
<h1>Good Evening. Yuck exam season!</h1>
</section>
<section class = 'pom-area'>
<button id = "start_pom" class = "button pom-area-start-button">Start Pomodoro</button>
<div class = 'pom-area-info'>
<div class = "pom-area-info-timer">
<h1 id = countdown-timer>25:00</h1>
</div>
<div class = "pom-area-info-status">
STUDY TIME!
</div>
</div>
</section>
<section class = 'settings'>
<button id = "start_settings" class = "button settings-button">Settings</button>
</section>
<script src = "./popup_script.js"></script>
<script src="lib/easytimer/dist/easytimer.min.js"></script>
<div id="countdownExample">
<div class="values"></div>
</div>
</body>
</html>

Add Show Dialog custom html to Google Slides Script

I'm trying to make this dialog popup for the duration of the execution of the AddConclusionSlide function, but I get the exception: "TypeError: Cannot find function show in object Presentation." Is there an alternative to "show" for Google Slides Script (This works perfectly in google docs)?
function AddConclusionSlide() {
htmlApp("","");
var srcId = "1Ar9GnT8xPI3ZYum9uko_2yTm9LOp7YX3mzLCn3hDjuc";
var srcPage = 6;
var srcSlide = SlidesApp.openById(srcId);
var dstSlide = SlidesApp.getActivePresentation();
var copySlide = srcSlide.getSlides()[srcPage - 1];
dstSlide.appendSlide(copySlide);
Utilities.sleep(3000); // change this value to show the "Running script, please wait.." HTML window for longer time.
htmlApp("Finished!","");
Utilities.sleep(3000); // change this value to show the "Finished! This window will close automatically. HTML window for longer time.
htmlApp("","close"); // Automatically closes the HTML window.
}
function htmlApp (status,close) {
var ss = SlidesApp.getActivePresentation();
var htmlApp = HtmlService.createTemplateFromFile("html");
htmlApp.data = status;
htmlApp.close = close;
ss.show(htmlApp.evaluate()
.setWidth(300)
.setHeight(200));
}
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
img {
display: block;
margin-left: auto;
margin-right: auto;
width: 25%;
}
.gap-10 {
width: 100%;
height: 20px;
}
.gap-20 {
width: 100%;
height: 40px;
}
.gap-30 {
width: 100%;
height: 60px;
}
</style>
</head>
<body>
<div class="container">
<div>
<p align="justify" style="font-family:helvetica,garamond,serif;font-size:12px;font-style:regular;" class="light">
Function is running... This could take a while. It's a lot of data...</p>
</div>
<p id="status">(innerHTML).</p>
<div id="imageico"></div>
<script>
var imageContainer = document.getElementById("imageico");
if (<?= data ?> != "Finished!"){
document.getElementById("status").innerHTML = "";
} else {
document.getElementById("status").innerHTML = "";
}
if (<?= close ?> == "close"){
google.script.host.close();
}
</script>
</body>
</html>
Unlike Spreadsheet object, Slide object doesn't have a show method. So, class ui needs to be used:
SlidesApp.getUi().showModalDialog(htmlApp.evaluate()
.setWidth(300)
.setHeight(200), "My App")

Method fired multiple times on click event

I'm building a web app in which the user can type in any key word or statement and get in return twenty results from wikipedia using the wikipedia API. AJAX works just fine. When the web app pulls data from wikipedia it should display each result in a DIV created dynamically.
What happens is that, when the click event is fired, the twenty DIVs are created five times, so one hundred in total. I don't know why but, as you can see in the snippet below, the web app creates twenty DIVs for each DOM element that has been hidden (through .hide) when the click event is fired.
Here's is the code:
function main() {
function positive() {
var bar = document.getElementById("sb").childNodes[1];
var value = bar.value;
if (!value) {
window.alert("Type in anything to start the research");
} else {
var ex = /\s+/g;
var space_count = value.match(ex);
if (space_count == null) {
var new_text = value;
} else {
new_text = value.replace(ex, "%20");
//console.log(new_text);
}
url = "https://en.wikipedia.org/w/api.php?action=query&format=json&prop=&list=search&continue=-%7C%7C&srsearch=" + new_text + "&srlimit=20&sroffset=20&srprop=snippet&origin=*";
var request = new XMLHttpRequest();
request.open("GET", url);
//request.setRequestHeader("Api-User-Agent", "Example/1.0");
request.onload = function() {
var data = JSON.parse(request.responseText);
render(data);
//console.log(data);
}
request.send();
}
}
function render(data) {
$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {
$("#sb input").css({
"float":"left",
"margin-left":"130px"
});
$("#first_btn").css({
"float":"left"
});
var title = data.query.search[0].title;
var new_text = document.createTextNode(title);
var new_window = document.createElement("div");
new_window.appendChild(new_text);
new_window.setAttribute("class", "window");
var position = document.getElementsByTagName("body")[0];
position.appendChild(new_window);
//}
});
}
var first_btn = document.getElementById("first_btn");
first_btn.addEventListener("click", positive, false);
}
$(document).ready(main);
html {
font-size: 16px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;ù
}
.align {
text-align: center;
}
#first_h1 {
margin-top: 30px;
}
#first_h3 {
margin-bottom: 30px;
}
#sb {
margin-bottom: 10px;
}
#second_h1 {
margin-top: 30px;
}
#second_h3 {
margin-bottom: 30px;
}
.window {
width: 70%;
height: 150px;
border: 3px solid black;
margin: 0 auto;
margin-top: 20px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Wikipedia Viewer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="css/main.css">
</head>
<body>
<h1 class="align" id="first_h1">Wikipedia Viewer</h1>
<h3 class="align" id="first_h3">Type in a key word about the topic you are after<br>and see what Wkipedia has for you..</h3>
<p class="align" id="sb">
<input type="text" name="search_box" placeholder="Write here">
<label for="search_box">Your search starts here...</label>
</p>
<p class="align" id="first_btn">
<input type="submit" value="SEND">
</p>
<h1 class="align" id="second_h1">...Or...</h1>
<h3 class="align" id="second_h3">If you just feel eager of random knowledge,<br>punch the button below and see what's next for you...</h3>
<p class="align" id="second_btn">
<input type="submit" value="Enjoy!">
</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
window.jQuery || document.write('<script src="js/jquery-3.2.1.min.js"><\/script>')
</script>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
I made the code easier to read by erasing the for loop. As you can see, even with just one result, it is displayed five times.
Do you know guys why it happens?
thanks
The line:
$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {})
Says, for every element in this "list", hide the element and run this block of code after hidden.
This code is the culprit:
$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow",
function() {...});
The callback function is called five times, one for each ID listed, not once for all of them, as you might expect.
A workaround is to create a class (say, "hideme"), apply it to each element you want to hide, and write:
$('.hideme').hide("slow", function() {...});
function render(data) {
$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {
$("#sb input").css({
"float":"left",
"margin-left":"130px"
});
$("#first_btn").css({
"float":"left"
});
}); // Finish it here..
var title = data.query.search[0].title;
var new_text = document.createTextNode(title);
var new_window = document.createElement("div");
new_window.appendChild(new_text);
new_window.setAttribute("class", "window");
var position = document.getElementsByTagName("body")[0];
position.appendChild(new_window);
//}
// }); Move this line..
}
As described in the docs:
complete: A function to call once the animation is complete, called once per matched element.
Which means this line will call the handle function 5 times with 5 matched elements.
$("#first_h1, #first_h3, #sb label, #second_h1, #second_h3").hide("slow", function() {
The easiest solution is moving the render codes outside of the hide event handler

Prevent Firefox from moving after `.exitFullscreen()`

Firefox is exhibiting this behavior (bug?) that occurs after exiting a full screened <img> where the user ends up at the element that sits above the <img> the user had just viewed in fullscreen. In short my question is:
How can I prevent Firefox from scrolling up after exiting fullscreen mode?
The MCVE posted as a Snippet doesn't function due to SO's strict security measures so I have provided a plunker. All the details are commented in the Snippet and Plunker. In addition I have added a simple interface to not only reproduce the issue but to change the layout to test different combinations as well. Thank you for your valuable time.
SNIPPET (doesn't function--review this plunker instead)
/* Several attempts to use the .focus() method
|| and focus events did not work for me, neither
|| has tabindex and anchors. If it appears that
|| my implementation is wrong (a strong possibility)
|| please inform me.
*/
$('a').click(function(e) {
var tgt = $(this).prev();
fs(tgt[0]);
$(this).focus();
});
/* This function is for the MCVE
|| It enables the ~select~ to remove and re-insert
|| the test elements. By doing so, we can see
|| how the test elements behave in different
|| combinations. What I found out about FF is
|| that when exiting a full screened ~img~ that's
|| positioned last is that it will lose focus
|| and the viewport is scrolled up to the element
|| above it.
*/
$('#sel1').on('change', function(e) {
var V = $(this).val();
var first = $('#' + V).find(':first').attr('id');
if ($('#' + V).hasClass('media')) {
$('#' + V).fadeOut('#' + first);
} else {
$('#' + V).fadeIn('#' + first);
}
$('#' + V).toggleClass('media');
});
/* These 2 functions are responsible for
|| full screen. Please inform me if there's a
|| better way, or if anything is outdated. I
|| have researched the Fullscreen API and I
|| haven't found any updates of any use. I've
|| used these functions for the last 3 years
|| so maybe I might've missed something
|| critical.
*/ // There's no ms prefixes because I'm not concerned about IE.
var isFullScreen = function() {
return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
}
function fs(target) {
if (!isFullScreen()) {
if (target.requestFullscreen) {
target.requestFullscreen();
} else if (target.webkitRequestFullscreen) {
target.webkitRequestFullscreen();
} else if (target.mozRequestFullScreen) {
target.mozRequestFullScreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
}
}
/* These styles are here for the demo itself
|| and are not a cause of the problem at hand
*/
* {
margin: 0;
padding: 0
}
body {
font: 400 16px/1.3 Consolas;
height: 100%;
width: 100%;
background: #333;
color: #fed
}
a {
margin: 0 auto 50px;
display: block;
width: 48px;
height: 48px;
text-align: center;
cursor: pointer;
background-size: contain;
}
.vid,
.img,
.gif,
.svg {
display: block;
margin: 20px auto;
}
.expand {
background: url(http://imgh.us/expand_2.svg)no-repeat;
}
header {
padding: 15px 10px;
margin: 15px auto;
}
fieldset {
border: 10px solid tomato;
width: 20ch
}
legend {
font-size: 1.2em;
}
dt {
text-decoration: underline;
font: 1.1em;
}
dd {
margin-left: 20px
}
.note,
dt {
color: #ffcc33
}
.demo {
width: 450px;
padding: 10px;
counter-reset: step;
}
.demo li::before {
counter-increment: step;
content: "» " counter(step) ". ";
text-indent: -150px;
margin-left: 30px;
color: cyan;
}
.fs:-webkit-full-screen {
max-width: 100%;
height: auto;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title>Prevent Firefox from Moving After .exitFullscreen()</title>
<style>
</style>
</head>
<body>
<header>
<dl>
<dt>Objective</dt>
<dd>Prevent Firefox from Moving After .exitFullscreen()</dd>
<dt>Behavior</dt>
<dd><b class='note'>Expected: </b>When exiting fullscreen mode, we should be at the same position that we were at before</dd>
<dd><b class='note'>Experienced: </b>In FF, when exiting fullscreen mode, we are scrolled up as if the element above has a higher tab priority or more than likely is that tab index and focus are being ignored by FF.</dd>
<dt>Question</dt>
<dd><b><mark>How can I prevent Firefox from scrolling up after exiting fullscreen mode?</mark></b></dd>
</dl>
</header>
<section>
<ol class='demo'>
<li>To reproduce issue, use the <select> to remove items C, D, E, and F.</li>
<li>Next, fullscreen item B by clicking the icon below it.</li>
<li>Then exit full screen mode by hitting <kbd>ESC</kbd>.</li>
<li>Notice we have jumped up the page.</li>
</ol>
</section>
<!--This ~select~ is for the MCVE - details are
commented below in the ~script~ block-->
<section>
<fieldset>
<legend>Remove and Re-insert Elements</legend>
<select id='sel1'>
<option value="">----</option>
<option value='A'><video> src=MP4</option>
<option value='B'><img> src=PNG</option>
<option value='C'><video> poster=GIF</option>
<option value='D'><img> src=SVG</option>
<option value='E'><div> &nbsp;</option>
<option value='F'><iframe> srcdoc="<DIV><div>"</option>
</select>
</fieldset>
<!--I tried using the ~a~nchors, -id-, -name-, and -tabindex-
FF was ignoring my attempts to keep or get focus. Using named or
id ~a~nchors failed since the distance between desired spot
and the spot FF ends up at is short.-->
<div id='A' class='media'>
<video id="vid1" class="vid fs" src="http://html5demos.com/assets/dizzy.mp4" controls></video>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='B' class='media'>
<img id='img1' class='img fs' src='http://imgh.us/Lenna.png'>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='C' class='media'>
<video id='gif1' class='gif fs' poster='http://imgh.us/gir_zim.gif' width='300' height='300'></video>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<div id='D' class='media'>
<img id='svg1' class='svg fs' src='http://www.clker.com/cliparts/j/g/8/S/V/O/test.svg' width='auto' height='500'>
<a href='#/' class='expand' tab-index='1'></a>
</div>
<!--Subjects E and F were added to see if a "dummy"
element were to be the last element so that FF
would exit fullscreen on the last ~img~ correctly.
I got mixed results.-->
<div id='E' class='media'>
<div id='div1' class='fs'> </div>
<a href='#/' class='expand' tab-index='1' height='1' width='1'></a>
</div>
<div id='F' class='media'>
<iframe id='ifm1' class='fs' srcdoc="<div style='color:lime'>iframe srcdoc</div><div style='color:cyan'>2 divs</div>" allowfullscreen></iframe>
<a href='#/' class='expand' tab-index='1' height='1' width='1'></a>
</div>
<footer class='bottom'> </footer>
</section>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
</script>
</body>
</html>
Define variables initially.
var sx,sy;
Save scrollbar position before entering Fullscreen
var d= document, r= d.documentElement, b= d.body;
sx= r.scrollLeft || b.scrollLeft || 0;
sy= r.scrollTop || b.scrollTop || 0;
When player exit full screen,
window.scrollTo(sx,sy);
Hope this helps!
This answer is fully credited to #Kaido and I'll readily replace this answer if and when Kaido posts an answer.
My attempts at using the scroll methods didn't work is because I was listening to click events when I should've been listening for the onmozfullscreenchange
Plunker
Demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prevent Firefox from Moving After .exitFullscreen()</title>
<style>
button {
display: block;
padding: 0;
width: 32px;
height: 32px;
text-align: center;
cursor: pointer;
background-size: contain;
}
.expand {
background: url(http://imgh.us/expand_2.svg)no-repeat;
}
</style>
</head>
<body>
<div id='A' class='media'>A
<video id="vid1" class="vid fs" src="http://html5demos.com/assets/dizzy.mp4" controls></video>
</div>
<div id='B' class='media'>B
<img id='img1' class='img fs' src='http://imgh.us/Lenna.png'>
<button class='expand'></button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
<script>
$('button').click(function(e) {
e.preventDefault();
var tgt = $(this).prev();
fs(tgt[0]);
});
/* This function is for the MCVE
|| It enables the ~select~ to remove and re-insert
|| the test elements. By doing so, we can see
|| how the test elements behave in different
|| combinations. What I found out about FF is
|| that when exiting a full screened ~img~ that's
|| positioned last is that it will lose focus
|| and the viewport is scrolled up to the element
|| above it.
*/
$('#sel1').on('change', function(e) {
var V = $(this).val();
var first = $('#' + V).find(':first').attr('id');
if ($('#' + V).hasClass('media')) {
$('#' + V).fadeOut('#' + first);
} else {
$('#' + V).fadeIn('#' + first);
}
$('#' + V).toggleClass('media');
});
/* These 2 functions are responsible for
|| full screen.
*/ // There's no ms prefixes because I'm not concerned about IE.
var isFullScreen = function() {
return !!(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement);
}
// SOLUTION XXXXXXXXXX]START[XXXXXXXXXXXXXXX
var yOffset;
document.onmozfullscreenchange = function() {
if (!isFullScreen()) {
window.scrollTo(0, yOffset);
}
};
// SOLUTION XXXXXXXXXXX]END[XXXXXXXXXXXXXXXX
function fs(target) {
if (!isFullScreen()) {
yOffset = pageYOffset;
if (target.requestFullscreen) {
target.requestFullscreen();
} else if (target.webkitRequestFullscreen) {
target.webkitRequestFullscreen();
} else if (target.mozRequestFullScreen) {
target.mozRequestFullScreen();
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
}
}
</script>
</body>
</html>

Categories