Chrome extension: Not downloading after clicking button - javascript

I'm trying to download a file to my downloads file. I'm creating a button on the web-page dynamically and id like to download something when that button is pressed. For what ever reason when I click the button nothing happens and I don't know why. Please help
background.js code
function SendRequest(url, callback){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
};
xhr.open("GET", url, true);
xhr.send();
}
var objurl = localStorage.getItem("OBJURL");
function EditContent(objurl){
chrome.downloads.download({url:objurl,filename:"Object Edit - Chrome Extension.rbxl",conflictAction:"overwrite"})
}
item.js
contentInput.onclick = function(){
var assetid = $('.thumbnail-span').attr("data-3d-url")
var baseurl = 'http://www.roblox.com'
SendRequest(baseurl + assetid, function (response) {
var response = response; //Easy Peasy
var jsonObject = JSON.parse(response); //Parse the response
localStorage.setItem("URL1", jsonObject.Url); //It's saved!
var test = localStorage.getItem("URL1"); //Let's grab it and save it to a variable
console.log(test); //Logs "Hello World!"
});
var url1 = localStorage.getItem("URL1");
SendRequest(url1, function (response1) {
var response = response1; //Easy Peasy
var jsonObject = JSON.parse(response); //Parse the response
localStorage.setItem("OBJ", jsonObject.obj); //It's saved!
});
var hashdecode = "http://roblox.com/thumbnail/resolve-hash/"
var objhash = localStorage.getItem("OBJ");
SendRequest(hashdecode + objhash, function (objresponse) {
var response = objresponse; //Easy Peasy
var jsonObject = JSON.parse(response); //Parse the response
localStorage.setItem("OBJURL", jsonObject.Url); //It's saved!
});
chrome.extension.sendRequest({
action: "EditContent",
})
}

Oh boy. There's a lot wrong here. And I mean a lot.
chrome.extension.sendRequest is deprecated. Use chrome.runtime.sendMessage instead.
That said, you're sending the message, but nothing actually listens to it. action: "something" doesn't mean anything a priori, you need to react to that yourself:
// background.js
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse){
if(message.action == "EditContent") {
/* do stuff */
}
}
);
localStorage is NOT shared between the content script and the background script. In fact, background script has its own copy of localStorage (bound to chrome-extension://whateverisyourid/ domain) and the content script shares it with the page.
You should either use chrome.storage, which is shared but works differently, or pass what you need in the message, i.e. a message like:
{action: "EditContent", objurl: jsonObject.Url}
And use it:
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse){
if(message.action == "EditContent") {
EditContent(message.objurl)
}
}
);
A function defined in the background script (SendRequest) cannot be called in the content script. You need to move it to the content script, or call it from the background script.
Your SendRequest is asynchronous. If you write something like:
function f(){
action1();
SendRequest(url1, function(response){
action2();
});
action3();
SendRequest(url2, function(response){
action4();
});
action5();
}
f();
then this is what will happen:
action1()
SendRequest will queue a request with url1, but not wait for it
action3()
SendRequest will queue a request with url2, but not wait for it
action5()
Your function f() terminates, next in queue is the first request.
When the request finishes, action2() is run.
Next in queue is the second request.
When the request finishes, action4() is run.
This might even get swapped, I suppose, depending on which request finishes first.
You see the problem? You need to chain asynchronous calls instead:
function f(){
action1();
SendRequest(url1, function(response){
action2();
action3();
SendRequest(url2, function(response){
action4();
action5();
});
});
}
This might not be the full list of problems, and certainly is not a full working code.
Please, please debug your extensions next time. You can access errors from the content script in the page's console (Ctrl+Shift+J), and background page's console from chrome://extensions in Developer Mode.

Related

How to rerun and stop app script based on the execution log info?

I am looking to run below app script with multiple var url such as
https://www.testurl.com/link1=processing
https://www.testurl.com/link2=processing
https://www.testurl.com/link3=processing
How to add multiple url to below code:
function url() {
var url = 'https://www.testurl.com/link1=processing';
var options = {
'method': 'get'
};
var response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
Each run with single url shows below execution log
3:33:30 AM Notice Execution started
3:33:31 AM Info {"status":200,"message":"Import 25 of 200 completed."}
3:33:31 AM Notice Execution completed
I am looking to rerun script for first url till i get the log message containing "is not triggered" and then run second url and rerun till i get the log message containing "is not triggered" and then run third url and rerun till i get the log message containing "is not triggered" and then stop.
3:33:30 AM Notice Execution started
3:33:31 AM Info {"status":403,"message":"Import #16 is not triggered. Request skipped."}
3:33:31 AM Notice Execution completed
There is really no way for me to test this but I think it illustrates how this can be done:
function getUrls() {
try {
var urls = [ 'https://www.testurl.com/link1=processing',
'https://www.testurl.com/link2=processing',
'https://www.testurl.com/link3=processing' ];
function getUrl(url) {
var options = { 'method': 'get' };
var response = UrlFetchApp.fetch(url, options);
while( response.message.indexOf("is not triggered") < 0 ) {
Logger.log(response);
response = UrlFetchApp.fetch(url, options);
}
}
urls.forEach( getUrl );
}
catch(err) {
Logger.log(err);
}
}

Calling a Facebook batch call using Appcelerator Module.Facebook

I spend about 2 hrs looking to do a batch call using Appcelerator Module.Facebook. I needed to get the Profile name and Picture. And I thought I wanted to do this in one HTTP request instead of two.
After a deep dive i finally found a way to do. I will post my answer in the answer section below.
Incase anyone else comes up against this..
var fb = require('facebook');
var log = require("log");
...
// After logging in
// gets user profile image and name uses a batch method example
function getUserInfo(userId) {
var batch = 'batch=[{"method":"GET", "relative_url":"me"},{"method":"GET", "relative_url":"me/picture"}]&access_token=' + fb.getAccessToken();
var url = "https://graph.facebook.com?" + batch;
var client = Ti.Network.createHTTPClient({
// function called when the response data is available
onload : function(e) {
log.args(this.responseText);
},
// function called when an error occurs, including a timeout
onerror : function(e) {
log.args(e.error);
},
timeout : 5000 // in milliseconds
});
// Prepare the connection.
client.open("POST", url);
// Send the request.
client.send();
}
This is how you would do a batch call using AppC, however there is a better way to get the info that i needed. In my case I only needed the Facebook name and picture
function getGraphPath(userId) {
fb.requestWithGraphPath('me?fields=id,name,picture', {}, 'GET', function(e) {
if (e.success) {
log.args('Modules.Facebook.requestWithGraphPath', JSON.parse(e.result));
} else if (e.error) {
log.args(e.error);
} else {
log.args('Unknown response');
}
});
}

Get JSON data from external URL and display it in a div as plain text

I have an external resource similar to https://www.googleapis.com/freebase/v1/text/en/bob_dylan which returns a JSON. I want to display the value of result key in a div in html (lets say the name of the div is "summary"). Also the value of result key should be displayed in plain text.
The URL returns the json:
{ "result": "Bob Dylan, born Robert Allen Zimmerman, is an American
singer-songwriter, author, poet, and painter, who has been a major
figure in popular music for five decades. Much of Dylan's most
celebrated work dates from the 1960s, when he became an ......." }
The JSON has just the result key, no other keys
Basically I do not want to use anything other than plain HTML and JavaScript. I am a relative beginner to JavaScript and therefore I ask for commented code.
Here is one without using JQuery with pure JavaScript. I used javascript promises and XMLHttpRequest
You can try it here on this fiddle
HTML
<div id="result" style="color:red"></div>
JavaScript
var getJSON = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
} else {
reject(status);
}
};
xhr.send();
});
};
getJSON('https://www.googleapis.com/freebase/v1/text/en/bob_dylan').then(function(data) {
alert('Your Json result is: ' + data.result); //you can comment this, i used it to debug
result.innerText = data.result; //display the result in an HTML element
}, function(status) { //error detection....
alert('Something went wrong.');
});
You can do this with JSONP like this:
function insertReply(content) {
document.getElementById('output').innerHTML = content;
}
// create script element
var script = document.createElement('script');
// assing src with callback name
script.src = 'http://url.to.json?callback=insertReply';
// insert script to document and load content
document.body.appendChild(script);
But source must be aware that you want it to call function passed as callback parameter to it.
With google API it would look like this:
function insertReply(content) {
document.getElementById('output').innerHTML = content;
}
// create script element
var script = document.createElement('script');
// assing src with callback name
script.src = 'https://www.googleapis.com/freebase/v1/text/en/bob_dylan?callback=insertReply';
// insert script to document and load content
document.body.appendChild(script);
Check how data looks like when you pass callback to google api:
https://www.googleapis.com/freebase/v1/text/en/bob_dylan?callback=insertReply
Here is quite good explanation of JSONP: http://en.wikipedia.org/wiki/JSONP
Since it's an external resource you'd need to go with JSONP because of the Same origin policy.
To do that you need to add the querystring parameter callback:
$.getJSON("http://myjsonsource?callback=?", function(data) {
// Get the element with id summary and set the inner text to the result.
$('#summary').text(data.result);
});
If you want to use plain javascript, but avoid promises, you can use Rami Sarieddine's solution, but substitute the promise with a callback function like this:
var getJSON = function(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
callback(null, xhr.response);
} else {
callback(status);
}
};
xhr.send();
};
And you would call it like this:
getJSON('https://www.googleapis.com/freebase/v1/text/en/bob_dylan', function(err, data) {
if (err != null) {
alert('Something went wrong: ' + err);
} else {
alert('Your Json result is: ' + data.result);
result.innerText = data.result;
}
});
You can use $.ajax call to get the value and then put it in the div you want to. One thing you must know is you cannot receive JSON Data. You have to use JSONP.
Code would be like this:
function CallURL() {
$.ajax({
url: 'https://www.googleapis.com/freebase/v1/text/en/bob_dylan',
type: "GET",
dataType: "jsonp",
async: false,
success: function(msg) {
JsonpCallback(msg);
},
error: function() {
ErrorFunction();
}
});
}
function JsonpCallback(json) {
document.getElementById('summary').innerHTML = json.result;
}
To display the Json data using Robin Hartman code. You need to add, the below line.
The code he gave gives you Object, object. this code retrieves the data in a better way.
result.innerText =JSON.stringify(data);
Since the desired page will be called from a different domain you need to return jsonp instead of a json.
$.get("http://theSource", {callback : "?" }, "jsonp", function(data) {
$('#summary').text(data.result);
});

How do I handle the *response* when I get one back from an XMLHttpRequest "Post" operation?

I'm having a great deal of difficulty with this - I seem to be going in circles.
What I'm trying to do is POST data to a web service from a javascript on a client.
in the examples below, valFname, valLname, valPhone, and valZip all have valid string values:
function checkOffers(){
// data collection from loaded form...
var postData = "'FirstName':'" + valFname ;
postData +="','LastName':'" + valLname ;
postData +="','PhoneNumber':'" + valPhone ;
postData += "','Zipcode':'" + valZip+"'";
initialize(postData);
}
function initialize(postData) {
//var postMsg = createSoapHeader(msg);
var url = "https://server.company.com:9999/analytics/webservices/webservice.asmx/SamplePriorityOfferList";
request.open("POST", url, false)
request.onreadystatechange = function(){
if(this.readyState===4){
//request is complete. handle it
processData;
}
};
request.send(postData);
}
function processData(){
response = request.responseXML.xml;
alert("Returned Data:" + response);
}
I am calling the checkOffers function on the PageLoad event - I want the web service to fire without having to click a button, link, etc.
I'm getting nulls back from my request, but should be getting data.
Any comments, tips, or suggestions are greatly appreciated.
This line:
if(this.readyState===4){
should be:
if(this.readyState==4){
That should at least get you seeing the alert.

Intercept all ajax calls?

I'm trying to intercept all AJAX calls in order to check if that AJAX response contains specific error code that I send as JSON from my PHP script (codes: ACCESS_DENIED, SYSTEM_ERROR, NOT_FOUND).
I know one can do something like this:
$('.log').ajaxSuccess(function(e, xhr, settings) {
});
But - does this work only if "ajaxSuccess" event bubble up to .log div? Am I correct? Can I achieve what I want by binding "ajaxSuccess" event to document?
$(document).ajaxSuccess(function(e, xhr, settings) {
});
I can do this in either jQuery or raw JavaScript.
If you're using jQuery, $.ajaxSuccess is a good option, but here's a generic option that will intercept XHR calls from all frameworks (I've tested it with ExtJS and jQuery - it should work even if multiple frameworks are loaded concurrently). It's been tested to work with IE8, Chrome and Firefox.
(function(XHR) {
"use strict";
var open = XHR.prototype.open;
var send = XHR.prototype.send;
XHR.prototype.open = function(method, url, async, user, pass) {
this._url = url;
open.call(this, method, url, async, user, pass);
};
XHR.prototype.send = function(data) {
var self = this;
var oldOnReadyStateChange;
var url = this._url;
function onReadyStateChange() {
if(self.readyState == 4 /* complete */) {
/* This is where you can put code that you want to execute post-complete*/
/* URL is kept in this._url */
}
if(oldOnReadyStateChange) {
oldOnReadyStateChange();
}
}
/* Set xhr.noIntercept to true to disable the interceptor for a particular call */
if(!this.noIntercept) {
if(this.addEventListener) {
this.addEventListener("readystatechange", onReadyStateChange, false);
} else {
oldOnReadyStateChange = this.onreadystatechange;
this.onreadystatechange = onReadyStateChange;
}
}
send.call(this, data);
}
})(XMLHttpRequest);
I've posted a more specific example on github which intercepts AJAX calls and posts the AJAX call durations back to the server for statistical analysis.
From http://api.jquery.com/ajaxSuccess/ :
Whenever an Ajax request completes successfully, jQuery triggers the ajaxSuccess event. Any and all handlers that have been registered with the .ajaxSuccess() method are executed at this time.
So the selector doesn't define the position where you are "catching" the event (because, honestly, ajax event by its nature doesn't start from a DOM element), but rather defines a scope to which the handling will be defaulted (i.e. this will poitn to that/those element(s)).
In summary - it should be exactly what you wish for
The best way, which I found https://lowrey.me/intercept-2/
const intercept = (urlmatch, callback) => {
let send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
this.addEventListener('readystatechange', function() {
if (this.responseURL.includes(urlmatch) && this.readyState === 4) {
callback(this);
}
}, false);
send.apply(this, arguments);
};
};
Try using Mockjax.js http://code.appendto.com/plugins/jquery-mockjax
It lets you hijack AJAX calls to the server and mock the location.

Categories