I am trying to "install" a Google script as a menu item in a Google Site (a new Google Site--not the "Classic Google Site").
This script is supposed to add a new line to a spreadsheet that is embedded in the Site. That spreadsheet (named "Catalog") is a Google Sheet and the script (I want to run from the Google Site) is already installed as a bound script in the Sheet and works when toggled from the S
heet.
The script essentially adds a new line at the bottom of my song catalog to create a new line to add a new song.
The script that is working in the spreadsheet is:
function addSong() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var numRows = sheet.getLastRow()
sheet.appendRow([numRows+1]);
}
My problem is I do not know how to access the script from the site. I.e., I do not know how to reference the script in the site menu (by URL or what?) to get it to run.
The way I envision it working is that I have a sub-page under my "Catalog" menu in the site called "Add Song" and when I toggle it, I want the script to run and add a line to the Catalog Sheet.
Any help?
Updated with a cleaner example:
Firstly, the best way to access your GAS script from elsewhere is probably to publish it as a Web App. That way the script can be called via its published URL. The main requirement for a Web App is that it has a doGet() function as an entry point.
I'm pretty sure that you can only associate a new Google Sites menu item with another page within the same site. So you can’t invoke the WebApp (via it's URL) directly from a menu. But on that new Sites page the menu item takes you to, you can either:
associate a Sites button with the Web App URL (if that helps), or
embed some HTML code with JavaScript in the page that is invoked when the page is loaded; a bit more complicated, but it does mean the call to the Web App would be automated.
The code below is a simple web app, which is a bound function within a sheet. If you publish this (Publish >> Deploy as a WebApp...) and then grab the url you can associate this with a button or call from the page.
function doGet(request){
addSong(request.parameter.song); // Call your own function.
var response = {status: "SUCCESS", data: request.parameter.song};
// Return the response.
return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}
function addSong(song) {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var numRows = sheet.getLastRow()
sheet.appendRow([numRows+1,song]);
}
To use a button add the following as a link with the button:
https://script.google.com/macros/s/<your web app ref>/exec?song=%22Bohemian%20Rhapsody%22
The code below is an example of automatically calling the WebApp from embedded HTML in the Sites web page accessed via the menu. There are other ways of invoking the Web App from JavaScript, but XMLHttpRequest() works with most browsers.
<!DOCTYPE html>
<html>
<body onload="test('https://script.google.com/macros/s/<your web app ref>/exec?song=StairwaytoHeaven') ;">
<p id="message">? </p>
<script>
function test(url) {
var XHR = new XMLHttpRequest();
XHR.onreadystatechange = function() {
if(XHR.readyState == 4) {
if(XHR.status == 200) {
console.log("SUCCESS: status = "+XHR.status);
document.getElementById("message").innerHTML = XHR.responseText;
console.log(XHR.responseText);
} else {
console.log("FAILURE: status = "+XHR.readystate+" "+XHR.status);
document.getElementById("message").innerHTML = "Failure";
}
}
}
XHR.open("GET", url + ((/\?/).test(url) ? "&" : "?") + Date.now()); // Add timestamp to disable caching, if required.
XHR.send();
return;
}
</script>
</body>
</html>
Related
I have a problem with some Google Script stuff. Basically, my goal is to have the script check to see if a client's case was resolved and then send an email to them that the issue has been resolved. I've gotten the logic done on when to send an email, but every time I try and implement it into the spreadsheet, I get the error:
Error
You do not have permission to call MailApp.sendEmail. Required permissions: https://www.googleapis.com/auth/script.send_mail (line 8).
I've got a simple function to test the functionality of it, and when run in the script editor it works fine, but not on the spreadsheet. Here is my sample function:
function myFunction(row) {
var sheet = SpreadsheetApp.getActiveSheet();
var rng = sheet.getRange(row, 1, 1, 2);
var ara = rng.getValues();
var email = ara[0][0];
MailApp.sendEmail(email, "TEST", "This is a test of sendEmail().");
return "Email sent.";}
According to the Apps Script Custom Functions documentation:
If your custom function throws the error message You do not have permission to call X service., the service requires user authorization and thus cannot be used in a custom function.
To use a service other than those listed above, create a custom menu that runs an Apps Script function instead of writing a custom function. A function that is triggered from a menu will ask the user for authorization if necessary and can consequently use all Apps Script services.
Method 1
Basically, you can replicate the wanted behavior of the two functions above with this:
function SendEmail() {
var message = "This is your response";
var subject = "You have feed back in the parking lot";
var ss = SpreadsheetApp.getActiveSheet();
var textrange = ss.getRange("F2");
var emailAddress = ss.getRange("B2").getValue();
if (textrange.isBlank() == false)
MailApp.sendEmail(emailAddress, subject, message);
}
And in order to trigger the execution of this function, you can make use of Apps Script triggers and choose one which is the most convenient for your use-case.
Method 2
You can also create a custom menu and with the option of triggering the above function. You only need to add this:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("My Menu")
.addItem("Send Email", "SendEmail")
.addToUi();
}
And this is how it will look like on the Spreadsheet:
Reference
Apps Script Custom Functions;
Apps Script Range Class - isBlank();
Apps Script Custom Menus;
Apps Script Triggers.
I encountered the same problem today "You do not have permission to call MailApp.sendEmail".
I solved this by doing the next steps:
open "Tools" -> "Script editor"
in "Script editor" click on "View" -> "Show manifest file"
open the "appscript.json" file that appeared in the left section of your screen and add "https://www.googleapis.com/auth/script.send_mail" to the oauthScopes, like this:
{
"oauthScopes": ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/script.send_mail"],
}
PS: I assigned the script to an image, which basically acts like a button.
I have a blog where I format links in a specific way, by adding mouseover/hover text with a basic description of the link in the following format: {page title} [by {author(s)} # {publication date & time}] | {website}. Here’s a screencap with an example.
As you can imagine, manually entering that title text for every single link gets quite tiresome. I’ve been doing this for years and I’m dying for a way to automate it.
Is there a way to automatically generate a target webpage’s title, and possibly the site/domain, in link mouseover texts across an entire website? (Ideally it would be formatted as indicated above, with author(s) and posted date/time and all, but that would likely involve too much coding for me.)
Please keep in mind that I only have a moderate, self-taught grasp of HTML and CSS.
Update: Anik Raj below provided an answer below that’s perfect – a bit of JS to generate a mouseover tooltip with the target page’s title – but I can’t get the script to work on my Blogger blog. I first saved the code to a .js file in my Dropbox and tried linking to it using the following code (which works fine for other external JS scripts):
<!-- Link hover title preview script (source: https://stackoverflow.com/questions/49950669/how-to-generate-target-webpage-title-in-link-mouseover-text/49951153#49951153) -->
<script async='async' src='https://dl.dropboxusercontent.com/s/h6enekx0rt9auax/link_hover_previews.js' type='text/javascript'/>
… But nothing happens. And when I insert the script in the page HTML, I get the following error (screencap here) and Blogger won’t let me save the template:
Error parsing XML, line 4002, column 21: The content of elements must consist of well-formed character data or markup.
I know nothing of code, JS included, so I don’t know how to fix it. I’ve tried several online JS validation tools; some identify an error there, others don’t. It clearly works just fine in the JSFiddle Anik provided.
If anyone could fix the code so it works in Blogger, you’d be my hero.
Edit: this works only under the same domain as other domains have CORS disabled.
The easiest way would be to add a java script file to the html file.
This is a simple script to set the title of the link as its hover text.
<script type = "text/javascript">
//get all links on the webpage
var links = document.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
(function(i) {
// for every link, make a request using its href property and fetch its html
var request = makeHttpObject();
request.open("GET", links[i].href, true);
request.send(null);
request.onreadystatechange = function() {
if (request.readyState == 4) {
//on request received, process the html and set the title parameter
const doc = new DOMParser().parseFromString(request.responseText, "text/html");
const title = doc.querySelectorAll('title')[0];
if (title) links[i].setAttribute("title", title.innerText)
}
};
})(i);
}
//helper function to create requests
function makeHttpObject() {
try {
return new XMLHttpRequest();
} catch (error) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (error) {}
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (error) {}
throw new Error("Could not create HTTP request object.");
}
</script>
Adding this script to the end will add hover text to all links.
See this JS Fiddle example -> https://jsfiddle.net/mcdvswud/11/
I owned a google form, how can I get the js script of it?
I click the Script Editor but there is no corresponding js I can find.
I have already searched on internet but no expected answers.
--
update on 20/08/2017
Assume that I owned a form like this :
Sample Form.
How can I get the corresponding google script of this form?
i.e.,
function myFunction() {
// Create a new form, then add a checkbox question, a multiple choice question,
// a page break, then a date question and a grid of questions.
var form = FormApp.create('Sample Form');
var sect1 = form.addSectionHeaderItem();
var item = form.addCheckboxItem();
item.setTitle('What condiments would you like on your hot dog?');
item.setChoices([item.createChoice('Ketchup'), item.createChoice('Mustard'), item.createChoice('Relish')]);
var item2 = form.addMultipleChoiceItem().setTitle('Do you prefer cats or dogs?');
// .setChoiceValues(['Cats','Dogs'])
// .showOtherOption(true);
var sect2 = form.addSectionHeaderItem();
form.addPageBreakItem().setTitle('Getting to know you');
form.addDateItem().setTitle('When were you born?');
var sect3 = form.addSectionHeaderItem();
var break2 = form.addPageBreakItem().setTitle('Getting to know you 2');
var choice1 = item2.createChoice('cat', FormApp.PageNavigationType.CONTINUE);
var choice2 = item2.createChoice('dog', break2);
item2.setChoices([choice1, choice2]);
form.addGridItem().setTitle('Rate your interests').setRows(['Cars', 'Computers', 'Celebrities']).setColumns(['Boring', 'So-so', 'Interesting']);
Logger.log('Published URL: ' + form.getPublishedUrl());
Logger.log('Editor URL: ' + form.getEditUrl());
}
Google Script Editor is a way that Google allows people to make their forms (and many other Google services) more flexible and customizable. You can even create Add-ons using Google Scripts. But there is not such thing as a default user script for each form; all forms begin with no user Google Scripts at all and it is up to you to add some more functionality by writing some new scripts.
Now, if you mean to get the javascript source of that form, then you can use Developer Tools in Chrome (F12 key in Windows) and go to sources, there you'll see all the cripts that Google uses for the forms:
And if you left click the form and view the source of it, you'll see some more small script blocks mostly related to the data that the Google Form has:
<script>_docs_flag_initialData={ ....
<script>;this.gbar_={CONFIG:[[[0,"www.gstatic.com", ....
<script type="text/javascript">var FB_PUBLIC_LOAD_DATA_ = [null,[null, ....
Another approach can be to create a html form yourself and send a request to a Google Apps Script Web app. See this example if you want to try it out: https://gist.github.com/mhawksey/1276293
Regards, Peter
I am creating a button in javascript (I can't create it using HTML - system limitation) and I want this button to go to a certain url (REST - getting JSON file). Afterwards, I'd like to display an alert with the value from that file and/or save the value from JSON file on a page where the button is placed. So far, I figured how to call the REST URI. Could anyone help me move forward with that?
<script>
oraclecrmod.onReady(function() {
if(oraclecrmod.ctx.isObject("Account") && oraclecrmod.ctx.isDetailPage()) {
var on_click = function httpGet("https://example.crmondemand.com/OnDemand/user/Rest/027/Accounts")
{
var xmlHttp = null;
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", "https://example.crmondemand.com/OnDemand/user/Rest/027/Accounts", false );
xmlHttp.send( null );
return xmlHttp.responseText;
}
// Read the "Test Read" button on the main Account TitleBar
var tb = oraclecrmod.getTitleBar("AccountFormTB");
var bt = oraclecrmod.createButton({
id:"TestBtn",
text:"Test Read",
parent:tb
});
bt.on("click",on_click);
}
});
</script>
Is this better? How can I improve it? It still doesn't work.
Once you navigate to another page, your current JavaScript will stop executing. The current Document gets unloaded when you navigate pages.
See the HTML5 spec for more details: http://www.w3.org/TR/html5/browsers.html#the-location-interface
I have made an extension that will track what manga a person reads on a manga site and list what chapter they last read for it in their favorites page. And I've recently come up with a useful feature to make the extension a little bit better. I would like to give the user the option to be able to track only manga that they have Favorited on the site. So as they are reading, the extension will constantly check in the background if it is in their favorites and if so then save it and if not don't save it.
The website has a favorites page that holds a list of all of the manga a person has Favorited. I would like to be able to constantly grab the names of each manga listed on that page in the background hidden from the user.
So my question is, is there any way to grab the html of a specific page in the background and constantly grab specific data such as text of certain elements to save to an array, without the user having to actually be on the favorites page?
Edit:
Solution
var barray = [];
function getbm(callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(data) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var data = xhr.responseText;
callback(data);
} else {
callback(null);
}
}
}
var url = 'http://mangafox.me/bookmark/index.php?status=all';
xhr.open('GET', url, true);
xhr.send();
};
function res(data) {
var parsed = $.parseHTML(data);
parsed = $('<div />').append(parsed);
parsed.find('h2.title').each(function(){
var bmanga = $(this).children('a.title').text();
barray.push({"manga": bmanga});
});
chrome.storage.local.set({'bData': barray})
};
getbm(res);
It heavily depends on how the page in question is constructed.
If the page is static (HTTP response includes the data you need), then scraping the page via XMLHttpRequest is the way to go.
If the page is dynamic (no data initially, and JavaScript on the page then queries the server to fill it), then XHR route will not work. You can try to observe network requests made by that page and replicate them.
Of note: while it's unlikely, check if the site has a public API. That will save you the reverse-engineering efforts and lets you avoid the grey area of automated data scraping.
Also, see if you can somehow check from the page you're normally tracking if the item is favourited or not. It will be easier than scraping another page.