I'm making a Google Forms add-on with Google Apps Script with an HTML file for its UI. I've pretty much taken the quickstart and changed a few things.
It's embarrassingly my first time doing any sort of HTML.
In my UI, I have a button:
<div class="sidebar branding-below">
<form>
<div class="block" id="button-bar">
<button id="deactivate" class="action" onclick="deactivatePressed()">Deactivate</button><br><br>
<div id="deactivation-confirmation"></div>
</div>
</form>
</div>
Here's the corresponding javascript that calls the google apps script that actually does the work:
function deactivatePressed() {
google.script.run.addTrigger(false);
document.getElementById('deactivation-confirmation').innerHTML = "Success!";
}
The button shows up and the function called is successful.
The issue is that pressing this button also opens up a new blank tab to a specific link that looks like this:
https://n-it2esyxcfj91uyg675645seyxh42jvgbfydr5e6u56y-0lu-script.googleusercontent.com/userCodeAppPanel?
In the console, it runs an error message that reads:
Unsafe JavaScript attempt to initiate navigation for frame with origin
'https://docs.google.com' from frame with URL
'https://n-it2esyxcfj91uyg675645seyxh42jvgbfydr5e6u56y-0lu-script.googleusercontent.com/userCodeAppPanel'.
The frame attempting navigation of the top-level window is sandboxed,
but the flag of 'allow-top-navigation' or
'allow-top-navigation-by-user-activation' is not set.
How do I make sure a new tab isn't opened when the script is run?
I'm sure it's in the HTML/js and isn't the Google Apps Script code since I commented out the body of the Google Apps Script function and the problem still occurred.
It's because the button was within the <form> tags.
Change it to this:
<div class="sidebar branding-below">
<div class="block" id="button-bar">
<button id="deactivate" class="action" onclick="deactivatePressed()">Deactivate</button><br><br>
<div id="deactivation-confirmation"></div>
</div>
</div>
Related
I will try to summarize this in a Requirements fashioned way, I hope this simplifies the question.
When clicking on an anchor tag, the web page navigates the user to a new page, where upon page load, the page is scrolled to the element which corresponds to the aforementioned anchor tag, which was previously clicked.
As you will see in the code I am trying to make use of the CSS scroll-behaviour property.
https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-behavior
So far I have tried out the code bellow, however when I run it I get an error message in the developer console stating:
TypeError: Cannot read property 'offsetTop' of undefined
Hence, I surmise that the window.onload function is not really fired on the page which I would like to load but the very same page on which I am located when clicking the anchor tag. How can I change the code so it would count for page intended.
HTML of Page A (where the anchor tag is located):
<a id="ship-it" href="services.html" class="services">
<div id="image-container_4">
<div id="image_4">
<div id="overlay_4"></div>
<h2 class="h2">We pack it and ship it</h2>
<img id=imageB src="/images/shipping.jpg" alt="">
</div>
</div>
</a>
HTML of Page B (where the target element is located):
<section id="manufacturing-section" class="section">
<img src="/images/manufacturingMelting2.jpg" alt="Magnetic Particle Inspection">
<div id="manufacturing-container">
<h2> <span>Manufacturing</span> <br> We provide high quality, low cost solutions to meet your requirements.</h2>
<p>
soemthing something something, DarkSide...
</p>
</div>
</section>
JS / CSS:
function scrollIt(element) {
window.scrollTo({
'behavior': 'smooth',
'left': 0,
'top': element.offsetTop
});
}
const serviceAnchor = document.querySelectorAll('.services');
//'serviceAnchor' is located on page A
const sections = document.querySelectorAll('.section');
// 'sections' is located on page B and represents the element the page should scroll to when the page has loaded after the corresponding anchor tag was clicked
serviceAnchor[0].addEventListener('click', () => {
window.onload = scrollIt(sections[0]);
});
serviceAnchor[1].addEventListener('click', () => {
window.onload = scrollIt(sections[1]);
});
serviceAnchor[2].addEventListener('click', () => {
window.onload = scrollIt(sections[2]);
});
serviceAnchor[3].addEventListener('click', () => {
window.onload = scrollIt(sections[3]);
});
The reason you're getting the error is it's impossible to run javascript across page loads. Assuming you're using a traditional site and not a single-page app, when the browser loads a new page, all javascript on the current page is stopped.
Browsers already support jumping to an element on page load using the www.site.com#myElementId syntax. If you want smooth scrolling, you'll need to pass the id of element to scroll in the url, or some other way like caching its id in localstorage, then run your smooth scrolling js on the pageload of the other page.
You can't navigate to a different page and then ask the browser to launch a piece of JavaScript. That would be a huge security issue, since I could make you click into a link to, let's say, my-bank.com then do a bit of JavaScript do access your secret cookies or local storage and hack into your account.
The only thing you can do is link to anchors inside the linked page, and the default scroll behavior (no smooth scrolling, for most browsers, since it's the least computationally and resources intensive) will be used:
<!-- not possible -->
<a onclick="navigateThenDoSomething()">Some link</a>
<!-- possible -->
Some link
If you own the target page, however, you can hide a target section in the query string then do a bit of magic in the target page's onload to smoothly scroll to your section:
<!-- source-page.html -->
Some link
// script running at target-page.html
const url = new URL(window.location);
const section = url.searchParams.get('section');
if (section) {
// scroll smoothly to `section` using
}
Since .scrollTo JS method with options has the same browser compatibility as scroll-behavior CSS property, and you're OK with that, you might get rid of your JS code and set:
html, body, .or-other-scrolling-container {scroll-behavior:smooth}
and use anchor links.
So HTML of Page A would be e.g.:
<a id="ship-it" href="services.html#manufacturing" class="services">
<div id="image-container_4">
<div id="image_4">
<div id="overlay_4"></div>
<h2 class="h2">We pack it and ship it</h2>
<img id=imageB src="/images/shipping.jpg" alt="">
</div>
</div>
</a>
And HTML of Page B (please note <a name="#manufacturing"> tag):
<a name="manufacturing"></a>
<section id="manufacturing-section" class="section">
<img src="/images/manufacturingMelting2.jpg" alt="Magnetic Particle Inspection">
<div id="manufacturing-container">
<h2>
<span>Manufacturing</span><br>
We provide high quality, low cost solutions to meet your requirements.
</h2>
<p>something something something, DarkSide...</p>
</div>
</section>
Working example:
html {scroll-behavior:smooth}
.long {height:100vh; background:#efc}
<a id="ship-it" href="#manufacturing" class="services">
<div id="image-container_4">
<div id="image_4">
<div id="overlay_4"></div>
<h2 class="h2">We pack it and ship it</h2>
<img id=imageB src="https://picsum.photos/50/50" alt="">
</div>
</div>
</a>
<section class="long">Placeholder to enable scroll</section>
<a name="manufacturing"></a>
<section id="manufacturing-section" class="section">
<img src="https://picsum.photos/400/220" alt="Magnetic Particle Inspection">
<div id="manufacturing-container">
<h2>
<span>Manufacturing</span><br>
We provide high quality, low cost solutions to meet your requirements.
</h2>
<p>something something something, DarkSide...</p>
</div>
</section>
Hope it helps.
I see many websites such as gitHub changing it's html content and URL without refreshing pages.
I find one possible way to do this in HTML Histroy API.
Here is the code.
HTML
<div class="container">
<div class="row">
<ul class="nav navbar-nav">
<li>Home</li>
<li>About</li>
<li>Contact</li>
</ul>
</div>
<div class="row">
<div class="col-md-6">
<div class="well">
Click on Links above to see history API usage using <code>pushState</code> method.
</div>
</div>
<div class="row">
<div class="jumbotron" id="contentHolder">
<h1>Home!</h1>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
</div>
</div>
</div>
</div>
home.html
This is home page
about.html
This is about page
contact.html
That one is content page
JAVASCRIPT
<script type="text/javascript">
jQuery('document').ready(function(){
jQuery('.historyAPI').on('click', function(e){
e.preventDefault();
var href = $(this).attr('href');
// Getting Content
getContent(href, true);
jQuery('.historyAPI').removeClass('active');
$(this).addClass('active');
});
});
// Adding popstate event listener to handle browser back button
window.addEventListener("popstate", function(e) {
// Get State value using e.state
getContent(location.pathname, false);
});
function getContent(url, addEntry) {
$.get(url)
.done(function( data ) {
// Updating Content on Page
$('#contentHolder').html(data);
if(addEntry == true) {
// Add History Entry using pushState
history.pushState(null, null, url);
}
});
}
</script>
This code is working fine even you go back or forward in browser.
But the problem is that when you refresh page it only shows the file which is being refreshed. For example, if you refresh the about.html then only the following will show: This is the about page.
Unlike the gitHub it can't show the complete page. As you see in gitHub, even you refresh a page it will show the page same as how it was before refreshing.
How can I do that?
Thanks...
You may use Routie or Director to do the routing. And within their callback functions write the code to update the part of your HTML page, for this you may use Fragment.js.
You can change DOM anytime you want without loading the page.
Use fundamental XMLHTTPRequest or Ajax to contact the server without refreshing the browser.
There are many frameworks which offer convenient url routing which can change content automatically without page refreshes. Angular JS is my favorite such framework which offers great routing capability among many other things.
You have to check/set the value of your variable on the event onload of the page.
Your code does not work - when you click on a particular link the page does refresh. correct me if i am wrong.
I am using a magento template which uses jquery.tabs.min.js for displaying different product information in different tabs.
Now I would like to send customers mails with a direct link to the review form, which is at the end of the third tab.
Unfortunatly the page if called from outside always opens with the first tab open.
So sending links with an additional hash from the tab id does not work.
I have already looked around many similiar threads but unfortunatly I am not very familiar with javascript, and I would need a realy detailed help, how to work this out and espacialy where to put the different snippets (i.e. inside the html of the page or in the js-file).
Something thar makes it maby more difficult is, that it would be helpful to not only open the third tab, but as well scroll down to the "review form" which is inside the third tab, at the bottom, and if there are more than a few reviews the visitor would not see the review directly.
So here is the html snippet, which represents my pages structure
<div id="product-tabs" class="gen-tabs gen-tabs-style-f">
<ul class="tabs clearer">
<li id="tab-description"><a class="current" href="#">Beschreibung</a></li>
<li id="tab-additional">Zusatzinformation</li>
<li id="tab-tabreviews">Bewertungen</li>
<li id="tab-product.tags">Schlagworte</li>
</ul>
<div class="tabs-panels">
<h2 class="acctab" id="acctab-description">Beschreibung</h2>
<div class="panel"> <h2>Details</h2>
CONTENT
</div>
<h2 class="acctab" id="acctab-additional">Zusatzinformation</h2>
<div class="panel"> <h2>Zusatzinformation</h2>
CONTENT
</div>
<h2 class="acctab" id="acctab-tabreviews">Bewertungen</h2><div class="panel">
<div class="box-collateral box-reviews" id="customer-reviews">
CONTENT OF CUSTOMER REVIEWS
<div class="form-add">
<h2>Schreiben Sie Ihre eigene Kundenmeinung</h2>
<form action="http://www.mydomain.com/review/product/post/id/8/" method="post" id="review-form">
-->>HERE IS MY REVIEW FORM<<--
</div>
</div>
<h2 class="acctab" id="acctab-product.tags">Schlagworte</h2><div class="panel">
<div class="box-collateral box-tags"> <h2>Schlagworte</h2>
CONTENT
</div>
</div>
Thanks a lot for any help in advance.
Update:
Maybe it is possible to extend the already existing function which routes the visitor "on click" directly to the review form, to work as well, depending on a parameter given with the URL (ie. a hashtag) ? Here is the peace of code from the template:
<?php //Open the "Reviews" tab, when "X Review(s)" or "Be the first to review this product" links are clicked ?>
<script type="text/javascript">
//<![CDATA[
jQuery(function($){$("#goto-reviews, #goto-reviews-form").click(function(){if($("#product-tabs").hasClass("accor")){$("#product-tabs .tabs-panels").data("tabs").click($(".tabs-panels .acctab").index($("#acctab-tabreviews")))}else{$("#product-tabs .tabs").data("tabs").click($("#tab-tabreviews").index())}})});
//]]>
</script>
If anybody could help me with that? Should be somehow easy if one have skills in JS ;-)
Have you tried adding the ID of the tab to the query string?
Http://www.mysite.com/product-URL.html#acctab-tabreviews
Adding the I'd portion of the li element with a hash should work
I have an HTML document with multiple pages using jQuery Mobile's data-role="page". I am trying to call a panel on the second page but am receiving the error
cannot read property 'nodeType' of undefined
The error occurs when I try to transition to the second page. My basic page structure is as follows:
<body>
<div data-role="page" id="page1">
Enter Page 2
</div>
<div data-role="page" id="page2">
<h3> tthis is page 2 </h3>
<input type="button" id="myButton"> My Button </input>
<div data-role="panel" id="myPanel">
<p> Panel content </p>
</div>
</div>
</body>
The panel is being called through a function, but I still receive the same error when I comment out the function.
$(document).ready(function() {
$('#myButton').on('click', function() {
$('#myPanel').panel('open')
})
})
The panel works if it is on the first page and if I define it on the first page and open it on the second, it still opens on the first. It is there when I hit the back button. I am using jQuery Mobile too is that has an effect on anything.
Why am I receiving this error? Is there a simple solution or do I need hack my way around this by creating the panel dynamically? Thanks.
First off, never use .ready() in jQuery Mobile.
Important: Use $(document).bind('pageinit'), not $(document).ready()
The first thing you learn in jQuery is to call code inside the $(document).ready() function so everything will execute as soon as the DOM is loaded. However, in jQuery Mobile, Ajax is used to load the contents of each page into the DOM as you navigate, and the DOM ready handler only executes for the first page. To execute code whenever a new page is loaded and created, you can bind to the pageinit event. This event is explained in detail at the bottom of this page.
Source: http://jquerymobile.com/demos/1.2.0/docs/api/events.html
Secondly, each page should have its' own panel with a different id, and the div containing the panel should be a direct child of data-role=page.
Panel markup/structure:
<div data-role="panel" id="id" data-position="left" data-display="push" data-theme="b">
<!-- Contents -->
</div>
Opening a panel:
Statically by using anchor/button:
Open
Dynamically:
$.mobile.activePage.find('[data-role=panel]').panel('open');
// Or
$('#panel_id').panel('open');
Closing a panel:
(in case data-dismissible is set to false)
Statically by using anchor/button (Note: It should be placed inside Panel div):
Close
Dynamically:
$.mobile.activePage.find('[data-role=panel]').panel('close');
// Or
$('#panel_id').panel('close');
Demo
I was wondering if it was possible to change another page that's not opened yet, when a user clicks a link from the first page. It's hard to explain, but I'll try to show you what I mean with an example below.
The html is more complex for the actual site, but here is a watered-down version:
Index:
<head>
<script type="text/javascript" src="external.js"></script>
</head>
<body>
<div id="container">
<div class="img">
<a href="PRODUCTPAGE.html">
<img src="product.jpg"/> </a>
</div>
<div class="img">
<a href="PRODUCTPAGE.html">
<img src="product2.jpg"/></a>
</div>
</body>
Product Page:
<head>
<script type="text/javascript" src="external.js"></script>
</head>
<body>
<div id="container">
<div id = "product1">
all of product 1 info and pictures
</div>
<div id = "product2">
all of product 2 info and pictures
</div>
So basically, is it possible just using javascript, no php or anything, when product1 image is clicked to only show the product1 info on the product page and when product2 is clicked only show the info for product 2 on the page. I've been trying to find something similar but as of yet haven't, which leads me to believe I may not be able to do it, but I thought I would ask.
My javascript document doesn't have much in it, because I haven't been able to figure it out, but I have been playing around trying to make their display = none. I haven't been able to get a variable to continue onto the next page, if you know what I mean. Sorry, I only have a basic understanding of Javascript.
The technique that you're looking for is a combination of DHTML (Dynamic HTML) and AJAX (Asynchronous JavaScript and XML).
DHTML:
The idea behind DHTML is that when the user requests an HTML page from the server, the server responds with that page, as well as other data that may be needed if a user were to perform certain actions, such as clicking on a product image.
The data that the server returns to the HTML page, upon initial pageload, is generally hidden by default. For instance, the DOM of the page is loaded, but it may have style="display:none" on the elements.
Once a user initiates a certain action, the page uses JavaScript to manipulate the elements on the page that are visible, as well as the ones that may be hidden.
Consider the following page:
<body>
<div id="page1">
<div id="container">
<div class="img">
<a id="product1" onclick="showProduct1();" href="#">
<img src="product.jpg"/> </a>
</div>
<div class="img">
<a id="product2" onclick="showProduct2();" href="#">
<img src="product.jpg"/> </a>
</div>
</div>
</div>
<div id="page2" style="display:none">
<div id="product_page_wrapper">
back to Product Categories
<div id="productDetails">
<div id="prod1">
...
...
</div>
<div id="prod2">
...
...
</div>
</div
</div>
</div>
</body>
The above page is split up into two sections, one with the id="page1" and the other id="page2". By default, we hide page 2.
When a user clicks on the link for a product, we hide page 1 and show page 2:
document.getElementById("page1").setAttribute("style","display:none");
document.getElementById("page2").setAttribute("style","display:block");
Additionally, depending on which link was clicked, we also unhide the product details for the product that was clicked, and hide the details for the product that wasn't. For example, if product 1 is clicked, we show product 1:
document.getElementById("prod2").setAttribute("style","display:none");
document.getElementById("prod1").setAttribute("style","display:block");
The end result is that only the page2 div is displayed. If the user clicks the "back to Product Categories" link, we reverse the process, hiding page2 and showing page1.
In summary, this type of manipulation can be done completely on the client-side, without any PHP or server-side code, simply using HTML, JavaScript, and CSS, as pointed out by #Marcel. However, the use of pure DHTML is more of an academic exercise than a practical solution, since the server-side maintains customer data, product data, and everything that would be required in a professional, revenue generating product.
AJAX:
AJAX, on the other hand, is quite similar to DHTML and may even be considered an extension of DHTML. The idea behind AJAX is that -- when the user initiates an action -- the page requests data from the server. When the server responds, the data is handed-off to a callback function that then manipulates the page using the data.
In your particular example, you might use a combination of both DHTML and AJAX to pull off the desired effects. Consider the following page, which uses AJAX to pull in the relevant HTML for the product the user selects:
<head>
<script type="text/javascript" src="external.js"></script>
<script>
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
httpRequest.onreadystatechange = displayContents;
httpRequest.open('GET', url);
httpRequest.send();
}
function displayContents() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
//alert(httpRequest.responseText);
document.getElementById("container").innerHTML = httpRequest.responseText;
} else {
alert('There was a problem with the request.');
}
}
</script>
</head>
<body>
<div id="container">
<div class="img">
<a id="product1" onclick="makeRequest('/getproduct?id=1')" href="#">
<img src="product.jpg"/> </a>
</div>
<div class="img">
<a id="product2" href="#" onclick="makeRequest('/getproduct?id=2')">
<img src="product2.jpg"/></a>
</div>
</div>
</body>
In the above example, when the user clicks on a link for a product, the server responds with just enough HTML to sufficiently replace the div#container portion of the page:
<span id="product">
<p>Product Name 1</p>
<p>Product details...</p>
</span>
This is injected into the page so that the DOM would then look like this:
<body>
<div id="container">
<span id="product">
<p>Product Name 1</p>
<p>Product details...</p>
</span>
</div>
</body>
Summary:
This question is tagged JavaScript, not jQuery, so the answers are focused on JavaScript, but the techniques described in the DHTML section are utilized in many JavaScript libraries. For example, see jQuery Mobile's Multi-Page Template for a demo of the technique you describe.
You could change the link to add parameter. This way PRODUCTPAGE.html knows which link you clicked.
<img src="product1.jpg"/>
<img src="product2.jpg"/>
Inside PRODUCTPAGE.html you could parse the URL using JavaScript and display only specific product's data.
Yes you can hide and show different parts of the DOM via javascript.
Check out this example of a toggle for an idea of what you need to do.