GM_xmlhttprequest Problems & Tutorial somewhere? - javascript

I'm learning JS & keep running into the problem of how to put documentation together to do this or that. e.g. Greasemonkey is documented, but you have to know a lot of other context not even referred to to use the greasepot wiki very well.
I've been trying various combinations of the following, for example, and I can only ever get "undefined" from the GM_xmhttprequest function, though:
var url = "https://en.wikipedia.org/wiki/CURL?action=render";
var fetchContent = console.log( function getContent(url) {
if (url.length < 0) {
return 0 ;
}
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: {
"User-Agent": "Mozilla/5.0", // If not specified, navigator.userAgent will be used.
//"Accept": "text/xml" // If not specified, browser defaults will be used.
},
onload: function(response) {
//var responseXML = null;
alert(response.responseText);
// Inject responseXML into existing Object (only appropriate for XML content).
/*
if (!response.responseXML) {
responseXML = new DOMParser()
.parseFromString(response.responseText, "text/xml");
}
GM_log([
response.status,
response.statusText,
response.readyState,
response.responseHeaders,
response.responseText,
response.finalUrl,
responseXML
].join("\n"));
*/
}
});
} )
Yet I'm not sure I'm using it correctly:
Need to define something in 'onload'??
Need to create a var prior? (e.g. var responseHoldingObject = new Object(); ?) ?
etc.
And any advice to get the page-fetching I'm looking for going is appreciated. Goal is to fetch content and ultimately append it within another page (e.g. such as within textarea or div).

Learning JS with GreaseMonkey might be a bit advanced.
fetchContent will be assigned the return value of console.log, which is undefined because console.log does not return a value. And what you're logging is the function getContent itself. getContent is never evaluated.
Finally, you can never get a response from an asynchronous function to use outside of the callback reliably (except with polling). Basically it should be something like this (untested):
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: {
"User-Agent": "Mozilla/5.0", // If not specified, navigator.userAgent will be used.
//"Accept": "text/xml" // If not specified, browser defaults will be used.
},
onload: function(response) {
/* use response here */
}
});
/* can't use response here */
without the fetchContent = console.log thing.

Related

How to get synchronous result for jsonpCallback?

I want to call jsonpcallback function in while or for loop. But I am getting asynchronous results. How to achieve that in jsonpcallback. Kindly anyone help me out to fix this or provide any other solution.
window.onPublitoryOebPart = function(json) {
window.publitoryOebPartJson = json;
content = patchEditedContent(json);
saveOebPartToc(content);
}
i = 0;
while(i < $("#oeb_parts_count").val()) {
return unless $("#oeb-part-file-url-"+i).length > 0
fileUrl = $("#oeb-part-file-url-"+i).html();
$.ajax({
url: fileUrl,
crossDomain: true,
dataType: "script",
jsonpCallback: "onPublitoryOebPart"
})
i++;
}
JavaScript can't get a "synchronous" JSONP result. This is because JSONP involves creating a new script element; such a dynamically created script element can only load the resource asynchronously.
Just use the success callback for the JSONP request and handle the response asynchronously. Manually specifying the jsonpCallback is only required/useful if the service doesn't allow a dynamic function to be specified.
If using success callback in a loop, it's also important to read up on closures (and then read more).
For instance:
var i = 0; // Don't forget the "var"
while(i < $("#oeb_parts_count").val()) {
var elm = $("#oeb-part-file-url-"+i);
if (!elm.length) { return; } // Make sure to use valid syntax
var fileUrl = elm.html();
$.ajax({
url: fileUrl,
crossDomain: true,
dataType: "script",
success: function (i, fileUrl) {
// Return a closure, the i and fileUrl parameters above
// are different variables than the i in the loop outside.
return function (data) {
// Do callback stuff in here, you can use i, fileUrl, and data
// (See the links for why this works)
alert("i: " + i + " data: " + data);
};
})(i, fileUrl) // invocation "binds" the closure
});
i++;
}
It may be cleaner simply to create a closure via a named function, but it's all the same concept.
Synchronous XHR requests are also highly discouraged; XHR is not JSONP, even though such requests are also created with the jQuery.ajax function.

jQuery ajax returned data: json and html mix?

I have this ajax request to get the data from my server, and the dataType is always html by default. But sometimes it would return json from the server, so I want to check if the returned data is html then execute A else execute B. Is it possible?
My jquery,
$.ajax({
type: "GET",
dataType: "html",
url: request_url,
context: $('#meat'),
async: true,
beforeSend: function () {},
success: function (returndata, status, jqXHR) {
if ($.parseJSON(returndata) === false) A;
else B.
}
});
I get this error when the returned data is html,
SyntaxError: JSON.parse: unexpected character
So how can I make this code versatile?
I'm not sure if there is a better way, but you could try... catch
$.ajax({
type: "GET",
url: request_url,
context: $('#meat'),
async: true,
beforeSend: function() {
},
success: function (returndata, status, jqXHR) {
var parsed;
try
{
parsed = $.parseJSON(returndata);
// Execute B
}
catch(e)
{
// treat as html then
// do parsing here
parsed = returnData;
// Execute A
}
}
});
Essentially, your code is just plain wrong - your serverside API is violating all principles of predictability if the return type can vary in an inconsistent manner. Your code should never have to guess at the type of the returned data.
Having said that, a simple try/catch will help as a workaround for the erratic behaviour if you don't want to fix it. Ie.
try {
if ($.parseJSON(returndata) === false) A;
} catch(e) {
// Treat as HTML here.
}
It's not pretty, but that's what you get for having an unpredictable API that isn't pretty to begin with.
may be you need to handle it like this
try{
var response=jQuery.parseJSON('response from server');
if(typeof response =='object')
{
//control would reach this point if the data is returned as json
}
else
{
//control would reach this point if data is plain text
if(response ===false)
{
//the response was a string "false", parseJSON will convert it to boolean false
}
else
{
//the response was something else
}
}
}
catch(exp){
//controls reaches here, if the data is html
}
Since you need to check the html data as well, you may need to take care of this,
Might also need to use a try / catch for exceptions if it is possible that parseJSON is going to be dealing with something other than JSON values (i.e. HTML)
REF:How can I check if a value is a json object?
EDIT:Edited to make code more precise towards solution

How to send AJAX with dataType as script?

im trying to create own POST request. Here is my function:
function sendPost(o) {
var h = new XMLHttpRequest();
h.onreadystatechange = requestComplete;
function requestComplete() {
if ( h.readyState === 4 ) {
if ( h.status === 200 ) {
if ( o.done ) {
o.done(h.responseText);
}
} else {
if ( o.fail ) {
o.fail(h.responseText);
}
}
}
}
h.open('POST', o.url, true);
h.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
h.send(o.data);
}
Everything is OK, but im confused, how to set its dataType to script, like in jQuery:
$.ajax({
url: 'someurl.php',
type: 'POST',
dataType: 'script' // <-- how to do this?
});
dataType has very little to do with sending Ajax requests. It is primarily about what jQuery does with the response.
From the documentation:
"script": Evaluates the response as JavaScript and returns it as plain text. Disables caching by appending a query string parameter, "_=[TIMESTAMP]", to the URL unless the cache option is set to true.
So there is some modification to do with sending here.
Take o.data
Get a timestamp from a new Date()
Check (by looking at indexOf('?') if it has a query string already
Append either ? or & to the URL followed by the time stamp
The rest is all about processing the response:
Evaluates the response as JavaScript
So:
eval(h.responseText);
This is all rather nasty though. Generally speaking, if you want to dynamically load a script, you are usually better off doing it by adding a <script> element to a page.

Javascript prototype constant declaration

I am working with a RESTful API, and my Javascript code is making REST queries via jQuery's $.ajax() call.
I have implemented a javascript Rest class, which I will show below (greatly simplified):
var Rest = function (baseUrlPath, errorMessageHandler) {
...
};
// Declare HTTP response codes as constants
Rest.prototype.STATUS_OK = 200;
Rest.prototype.STATUS_BAD_REQUEST = 400;
... // other rest methods
Rest.prototype.post = function (params) {
$.ajax({
type: 'POST',
url: params.url,
data: params.data,
dataType: 'json',
contentType: 'application/json; charset=utf-8',
beforeSend: this._authorize,
success: params.success,
error: params.error || this._getAjaxErrorHandler(params.errorMessage)
});
};
... // more rest methods
Rest.prototype.executeScenario = function (scenarioRef) {
var self = this;
this.post({
url: 'myurlgoeshere',
data: 'mydatagoeshere',
success: function (data, textStatus, xhr) {
if (xhr.status == 200) {
console.log("everything went ok");
}
},
error: function (xhr, textStatus, errorMsg) {
// TODO: constants
if (404 == xhr.status) {
self.errorMessageHandler("The scenario does not exist or is not currently queued");
} else if (403 == xhr.status) {
self.errorMessageHandler("You are not allowed to execute scenario: " + scenarioRef.displayName);
} else if(423 == xhr.status) {
self.errorMessageHandler("Scenario: " + scenarioRef.displayName + " is already in the queue");
}
}
});
};
The code works as intended, however I have decided to add some constants to help beautify the code and improve readability. I have for example several places in my code where I am checking for xhr.status == 200 or xhr.status == 400 and so on.
I can declare class variables as Rest.prototype.STATUS_OK = 200;
But variable is editable, and I cannot think of how to make them constant. In my code for example I can do a this.STATUS_OK = 123; and this will modify the variable. I have played around with the const keyword, with no luck.
i have seen this: Where to declare class constants?, but it was not much help.
Can someone point me in the right direction as to how to make these fields a constant literal instead of a variable?
Using ECMAScript 5's Object.defineProperty you can make a value un-settable:
Object.defineProperty(Rest, "STATUS_OK", {
enumerable: false, // optional; if you care about your enumerated keys
configurable: false,
writable: false,
value: 200
});
Or, since those are the default values, simply do:
Object.defineProperty(Rest, "STATUS_OK", { value: 200 });
This makes Rest.STATUS_OK yield 200 when accessed, but it will not respond to attempts to redefine it or delete it. Furthermore, configurable: false will prevent any attempt to redefine the property with a subsequent defineProperty call.
However, this doesn't work in older browsers that don't support ES5's defineProperty (notably IE8 and below).
This will not be possible in Javascript. Best thing you could probably do, is create some closure like stuff:
var StatusCode = (function() {
var STATUS_OK = 200,
STATUS_BAD_REQUEST = 400;
return {
getOk: function() {
return STATUS_OK;
},
getBadRequest: function() {
return STATUS_BAD_REQUEST;
}
}
});
And use it like StatusCode.getOk() === 200. This would help you to not be able to change those 'constants', but will again be bad for your readability (this is probably opinion based).
I would just keep those constants all uppercase to mark them as constant, although they could be changed.
You could define the statuses as getters, but AFAIK this won't work in IE8 and older.
var Rest = function (baseUrlPath, errorMessageHandler) {
this.STATUS_OK = 123; // trying to override.
};
// Declare HTTP response codes as constants
Rest.prototype = {
get STATUS_OK(){ return 200; },
get STATUS_BAD_REQUEST(){ return 400; }
}
var client = new Rest();
console.log( client.STATUS_OK ); // 200!
client.STATUS_OK = 123;
console.log( client.STATUS_OK ); // still 200!
More on getters and setters: http://ejohn.org/blog/javascript-getters-and-setters/
Javascript doesn't have a good support to create immutable constants.
Even the const keyword isn't recommended because doesn't work in some browsers.
I think the best way todo it is using Object.freeze:
Rest.Status = {};
Rest.Status.Ok = "Ok";
Object.freeze(Rest.Status);
Object.freeze will silent ignore changes in the Status object.
By example:
Rest.Status.Ok = "foo";
Rest.Status.Ok; //=> "Ok"
But just work in ECMAScript 5 or above.
Above I have placed the status in a Status object, I think that it is more interesting than prototype, because prototype is more close to instance methods, properties etc.
And the Status object seen like a enumeration.

Is there a recommended common pattern to memoize ajax calls?

I'm working with some government data published via Socrata's SODA api.
This API provides a way to retrieve rows via a REST call. The API allows limited parameterization of the query - basically you can do a full text search, and nothing else. I cannot find a way to shape the data returned - for example only return certain columns of the data.
As a result, basically I can only get all rows and all columns of each data view. This is ok, I guess, but I'd like to cache it - memoize it to use the underscore term.
Is there a pattern for memoization of ajax calls with jQuery?
EDIT: To give you an idea of what I'm talking about, here's what I'm doing currently.
function onclick(event) {
var $t = $(event.currentTarget);
var itemId = $t.attr('data-itemid');
var url = getRestUrl(itemId);
if (typeof datacache[itemId] === "undefined") {
$.ajax({
url : url,
cache : true,
type : "GET",
dataType : "json",
error : function(xhr,status,error) {
raiseError(error);
},
success : function(response, arg2, xhr) {
datacache[itemId] = response;
doSomethingWithTheData(url, itemId);
}});
}
else {
doSomethingWithTheData(url, itemId);
}
}
// then, doSomethingWithTheData() simply references datacache[itemId]
This seems like it's faster though I haven't measured it. What I really want to know is, is there a common pattern that does something like this, that I can employ, so that everyone who reads the code will immediately see what I'm doing??
You might be able to do something like is done with autocomplete lookups (this is very much from memory, but you'll get the idea):
var searchCache = {}, searchXhr = null;
function Search(term) {
if (term in searchCache) {
return doSomethingWithTheData(searchCache[term]);
}
if (searchXhr != null) {
searchXhr.abort();
}
searchXhr = $.ajax({
url : url,
cache : true,
type : "GET",
dataType : "json",
error : function(xhr, status, error) {
raiseError(error);
},
success : function(response, arg2, xhr) {
searchCache[term] = response;
if (xhr == searchXhr) {
doSomethingWithTheData(response);
searchXhr = null;
}
}
});
}
I'm not necessarily the best expert for Javascript question, but I might be able to help you with your use of SODA.
If you're looking for more flexibility in your queries, and you can do an HTTP POST, you could look at using our query syntax to do a more targeted query: http://dev.socrata.com/querying-datasets. Our query syntax is fairly complex, but I can help you figure out how to structure your query if you hit any snags.
Unfortunately, since that'd require a POST, you'll need to break out of the XHR cross-domain lockbox by going through a proxy or something similar.
Also, FYI, we're working on a whole new syntax that'll allow you to specify queries as URL parameters, so you'll be able to perform simple requests such as /resources/agencies?acronym=CIA or /resources/agencies?$where='budget > 10000000'. It should be pretty awesome.
You would only cache ajax requests that you know won't change, like the Facebook SDF for example. It seems like in your example, you're requesting something UI related that might be inappropriate to cache? Otherwise, you might try something like this:
var store = {};
/**
* Memoized $.getScript
*
* Cache one script response per url
* Reference, see http://msdn.microsoft.com/en-us/magazine/gg723713.aspx
*
* #example $.memoizedGetScript( url ).then( successCallback, errorCallback );
* #param {String} url
* #param {Function} callback (optional)
* #returns {*}
*/
$.memoizedGetScript = function(url, callback) {
var callback = callback || {};
store.cachedScripts = {};
if (!store.cachedScripts[url]) {
store.cachedScripts[url] = $.Deferred(function(d) {
$.getScript(url).then(
d.resolve(),
d.reject()
);
}).promise();
}
return store.cachedScripts[url].done(callback);
};

Categories