Bookmarklet to save URL in Google Spreadsheet - post

I want to create a simple bookmarklet, that grabs the URL of the current webpage "location.ref" and saves it in a Google Spreadsheet. After it saves it, I want to stay on the current webpage.
The only way I know of writing to Google Spreadsheet is using Google App Script. So I wrote a simple script that does just that:
function doGet(request) {
var ss = SpreadsheetApp.openByUrl( "https://docs.google.com/spreadsheet/ccc?key=<MY-SPREADSHEET-ID>");
var sheet = ss.getSheets()[0];
var headers = ["Timestamp", "url"];
var nextRow = sheet.getLastRow();
var cell = sheet.getRange('a1');
var col = 0;
for (i in headers){
if (headers[i] == "Timestamp"){
val = new Date();
} else {
val = request.parameter[headers[i]];
}
cell.offset(nextRow, col).setValue(val);
col++;
}
return ContentService.createTextOutput(request.parameter.url)
.setMimeType(ContentService.MimeType.TEXT);
}
I published this as a webapp. I wrote the bookmarklet:
<a href="javascript:(
function(){
alert(window.open('https://script.google.com/macros/s/<MYWEBAPP>/exec?url='+encodeURIComponent(location.href), '_self'));
}
)();">
BOOKMARK
</a>
So far so good. It actually works when I click on the bookmarklet, it does grab the URL of the current webpage and save it in my spreadsheet. But then, the webapp returns a text response and the bookmarklet displays the text causing me to move away from my current website.
Is there a way to ignore the response? GAS webapp script requires me to use doGet() that has to return something. Is there a way to not return anything from GAS script? Alternatively, is there a way i could use some other call to replace window.open to invoke the webapp that would allow me to store the response in a variable and ignore it?

I know it's been over a year but I was trying to do exactly this. It took me a while to figure out, but this works. The 1 second delay was necessary to let the script finish loading.
javascript:(function(){
my_window=window.open('https://script.google.com/macros/s/<MYWEBAPP>/exec?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title));
(window.setTimeout(function(){my_window.close();},1000));
void(0);
})();

Instead of using window.open you may consider sending a HTTP GET request using XMLHttpRequest.
Refer here on its usage.

Change _self to something else, e.g. bookmarker and it will open in a new window or tab. If you use it on many pages, they will all reuse the same tab if it keeps the same name.

Related

Can I use IMPORTXML to scrape a Quora query into Sheets?

I am trying to scrape the results from a Quora search query using ImportXML.
The URL is of this form: https://www.quora.com/search?q=scrape%20Quora&time=year
I've tried using ImportXML, and can't get anything to work. As an example, I inspected the questions, and found they were inside a div with a class name of 'q-text puppeteer_test_question_title'. So I tried to import like this, but I just get #N/A:
importxml("https://www.quora.com/search?q=scrape%20Quora&time=year","//div[#class='q-text puppeteer_test_question_title']")
This is clearly not working: is there a fix or just not possible (and why)?
Thank you.
Quora (as of now) runs on JavaScript and google sheets import formulae do not support the scrapping of JS elements:
You can try to fetch the first 3 responses this way (quickly written, could be improved)
function myFunction() {
var options = {
'muteHttpExceptions': true,
'followRedirects': false
};
var url = 'https://www.quora.com/search?q=scrape%20Quora&time=year'
var jsonStrings = UrlFetchApp.fetch(url,options).getContentText().split('window.ansFrontendGlobals.data.inlineQueryResults.results["')
jsonStrings.forEach((jsonString,i) => {
if (i > 0) {
console.log(jsonString.split('"] = ')[1].split('\n')[0])
}
})
}
and then parse the complex json inside. However, other answers are transmitted by quora when scrolling down by ajax asynchronous request.

Google apps script, priority between onclick and href

I have a button (in HTML) that both calls for a function LoginInfoInput(...) and redirect to a page (href="..."), that is:
<a onclick="LoginInfoInput('<?!= userID; ?>')" href="<?= ScriptApp.getService().getUrl(); ?>?v=form&userID=<?!= userID; ?>" class="waves-effect waves-light btn-large">Log In</a>,
where LoginInfoInput(...) is a javascript function that will trigger my google apps script (GS) function. The triggered GS function will then insert data into my spreadsheet. Meanwhile, the redirected URL will pass though my doGet() function. To determine the outcome, it gets data from my spreadsheet. My problem is that the spreadsheet is not always updated in time before redirecting the page takes action.
My attempt to solve the problem has been to wait/pause with a while-loop. However, when the while-loop is active during which the data becomes available in a spreadsheet (at least visually) does not work, i.e., the interesting data is not accessible. Note, I have also during the while-loop added the option to update the variable that stores the spreadsheet data (calling SpreadsheetApp.openByUrl(url)), however, without any improvement.
Update
My LoginInfoInput() (in JavaScript) is as follows:
function LoginInfoInput(userID){
var userLO = document.getElementById("id_loginLO").value;
var userPassword = document.getElementById("id_password").value;
google.script.run.LoginAdd(userLO, userPassword, userID);
}
Solution
My solution was a combination of the answer provided by #IMTheNachoMan see below and my discovery that the added data in GS to Spreadsheet can be delayed if not forcing the data to be updated. To force an update, one call SpreadsheetApp.flush(); link after inserting the data in Spreadsheet, in the GS function. From my understanding, the data needs to be in my Spreadsheet before I change my (GS)-based page as it will try to access the Spreadsheet at the time my (GS)-based page is called rather than when I call for my Spreadsheet when the data is available (by waiting/using while-loop).
Replace your <a... with this:
<a onclick="return LoginInfoInput(this, '<?!= userID; ?>');" href="<?= ScriptApp.getService().getUrl(); ?>?v=form&userID=<?!= userID; ?>" class="waves-effect waves-light btn-large">Log In</a>
Replace your function with this:
function LoginInfoInput(a, userID)
{
if(a.className == "done")
{
return true;
}
else
{
google.script.run.withSuccessHandler(function(){
a.className = "done";
a.click();
}).LoginAdd();
}
}
When the user clicks the link, className is not done so it calls your GAS function and returns false so the href is not opened. When the GAS function is done, it sets the className and then sets the clicks the link again. This time it returns true so the href would get run.
Does that make sense?
Note, you can also use withUserObject to pass the URL from a around.
Reference: https://developers.google.com/apps-script/guides/html/reference/run

Google Script to open URL in same window as Spreadsheet

I'm trying to work around the lack of API for Google Spreahsheet's Filter Views, by passing the filter view's URL into a hyperlink displayed in a sidebar.
Importantly: I want the filter view URL to open in the same window as, and thus replace, the spreadsheet. The hyperlink target should then be _self
function listFilterViews(){
var uiInstance = UiApp.createApplication()
.setTitle('Teacher Views');
var panel = uiInstance.createVerticalPanel();
panel.setSpacing(5)
var scroll = uiInstance.createScrollPanel();
scroll.setHeight("100%")
var url = "https://docs.google.com/blablabla"
var link = uiInstance.createAnchor("click me", url)
link.setTarget("_self")
panel.add(link);
scroll.add(panel)
uiInstance.add(scroll);
SpreadsheetApp.getUi().showSidebar(uiInstance);
}
However, the URL doesn't open in the same window as expected but in an other window instead. How can I fix this?
According to the setTarget documentation:
"(setting a target to _self) will only work if the app is being shown as a standalone service. It will have no effect when called inside a dialog, such as in a Google Spreadsheet."
Apps Script intentionally prevents scripts from being able to switch the view of the current window, as a security measure.

Caching visited page in Jquery Mobile

I work on Jquery Mobile/Phonegap app for android.
I´d like my app to "remember" that(if) the user has visited one of my pages. For example if he once visits "page1.html", this action should be cached in the phone memory, so that when the user opens the app again there should be possibility to navigate to this "page2.html" directly from "index.thml".
Please, if you have a code suggestion, tell me also how/where do I use it, because sometimes for starters like me it is realy hard to understand what to do with a little piece code.
Thank you very much!
You can use HTML5 local storage for this purpose.
Each time when a page is shown you can save/update the current page URL to a local storage variable, say 'lastVisit', as below:
$(document).on('pageshow', function (event, data) {
var currentPage = $('.ui-page-active').data('url');
localStorage.setItem("lastVisit", currentPage);
});
If you are not getting $('.ui-page-active').data('url'), then you can use $.mobile.activePage.attr('id') which will give you the current page id.
So next time, when the user opens the app again, you can check whether this local storage variable is set and can action accordingly.
The code will look like as below:
$(document).on('mobileinit', function(){
var lastVisit = '';
if(localStorage.getItem("lastVisit") != null){
lastVisit = localStorage.getItem("lastVisit");
}
if(lastVisit){
document.location.href = lastVisit;
}
});
You can use these codes in the header section scripts.

Is it possible to post a link that targets a specific choice in an accordeon so to open automatically?

I have a page that contains multiple topics in accordion.
How can I post a link (on social media or other places) so when the user clicks it can view the topic I want without making him choose the desired one to view it?
The website is built in Joomla 2.5 using its native (mootools) accordions.
A temporary solution came to my mind is to make single pages containing only the content I want, but it won't help them view the other topics contained in the same page, unless the user clicks the same category.
MooAccordion has a display option. You could use like:
window.addEvent('domready', function () {
var index = window.location.search; // get query string
index = index.replace("?", ''); // remove the ?
index = index.length ? index : 0; // in case there in no query, display first
var myAccordion = new Fx.Accordion($('accordion'), '#accordion h2', '#accordion .content', {
display: index // the actual behavior you are looking for
});
});
Read more at Mootools docs
So you could try these links as demo:
http://jsfiddle.net/brM2v/show/?0
http://jsfiddle.net/brM2v/show/?1
http://jsfiddle.net/brM2v/show/?2

Resources