Parsing a web page using Javascript (ajax and jquery involved) - javascript

Trying to parse an ajax requested page for the word "function" and store the last matched character in an array. The only errors JSLint is returning are
unexpected ('space')
and
Combine this statement with the previous 'var' statement,
neither of which I believe should effect whether or not the code is executed. Any help is appreciated.
/*jslint browser: true*/
/*global $, jQuery, alert*/
$(document).ready(function () {
"use strict";
//retrieve page
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://abs.twimg.com/c/swift/en/init.27d18bf5a2b7d3e5fbcdbb86f85e7a534b11f06b.js", true);
xhr.responseType = "text";
xhr.send();
xhr.onload = function () {
//set variables to be compared
var page = xhr.responseText;
var word = "function";
//page and word locations
var i = 0;
var n = 0;
var page_loc = page[i];
var word_loc = word[n];
//matched result storage
var chain = [""];
// compare
while (n < word.length - 1) {
if (page_loc === word_loc) {
n = n + 1;
i = i + 1;
console.log(i);
} else {
i = i + 1;
}
}
//place matched result
chain.push(page_loc);
console.log(chain);
};
});

So regarding your comment and question.
You don't need to iterate over that string, if you only want to check whether a given string is present in a response, you can use a built-in function indexOf() or in newer browsers includes().
So the code would look as follow:
$(document).ready(function () {
"use strict";
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://abs.twimg.com/c/swift/en/init.27d18bf5a2b7d3e5fbcdbb86f85e7a534b11f06b.js", true);
xhr.responseType = "text";
xhr.onload = function () {
var page = xhr.responseText;
var word = "function";
if (page.indexOf(word) !== -1)
console.log([word[word.length-1]]);
};
xhr.send();
});

Related

Remove JSON Objects With Date Already Passed

I am trying to sort Shopify Blog Posts by a metafield called "Event Date." I call on my articles.JSON but it does not come with the metafields.JSON so I then have to take that array and put it through a foreach function to attach the metafields to each article.
This is how the metafields.json for each article is setup:
{
"metafields":[
{
"id":5994805788772,
"namespace":"global",
"key":"Event-Date",
"value":"1549256400",
"value_type":"string",
"description":null,
"owner_id":15977611364,
"created_at":"2019-02-06T18:31:44-05:00",
"updated_at":"2019-02-06T18:31:44-05:00",
"owner_resource":"article"
},
{
"id":5994805821540,
"namespace":"global",
"key":"Event-Time",
"value":"6:00pm - 8:00pm",
"value_type":"string",
"description":null,
"owner_id":15977611364,
"created_at":"2019-02-06T18:31:45-05:00",
"updated_at":"2019-02-06T18:31:45-05:00",
"owner_resource":"article"
},
{
"id":6010564542564,
"namespace":"global",
"key":"Location",
"value":"18th Street Location",
"value_type":"string",
"description":null,
"owner_id":15977611364,
"created_at":"2019-02-07T13:16:05-05:00",
"updated_at":"2019-02-07T14:05:08-05:00",
"owner_resource":"article"
}
]
}
How I attach the metafields.JSON below:
var request = new XMLHttpRequest();
request.open('GET', '/admin/blogs/43130421348/articles.json');
request.responseType = 'json';
request.send();
request.onload = function() {
var articleList = request.response;
var articleArray = articleList.articles;
var date = new Date();
var ticks = Math.floor(date.getTime() / 1000);
var count = 0;
articleArray.forEach(function(entry,index, object){
var metaRequest = new XMLHttpRequest();
metaRequest.open('GET', '/admin/blogs/43130421348/articles/'+ entry.id + '/metafields.json');
metaRequest.responseType = 'json';
metaRequest.send();
console.log(index);
metaRequest.onload = function() {
var articleMetaObj = metaRequest.response;
var articleMetaArr = articleMetaObj.metafields;
entry.metafields = articleMetaArr;
var eventDate = entry.metafields[0].value;
}
});
};
I'm now trying to get rid of any article that has a date ("Key": "Event-Date") that has already passed compared to the current date. I've looked at the following Stack Overflow Post on removing objects in a foreach loop but none of its solutions prove to actually get rid of all the articles. It will get rid all of them occasionally but sometimes leave in one of the objects.
I've also tried an array filter but all I've gotten back is an empty array when I've used it. I've been stuck on this for a bit now so any help on solving it is much appreciated.
I think it would be easiest if you waited until you attached all of the metadata, and then once it is all completed, use articleArray.filter to take out the ones you don't want. To do this, you have two options:
Option 1 - The Old Ways (setInterval)
Here, we keep count as the metadata is retrieved, and create an interval to check when they all have completed. Once done, a function is called (finish) that allows for continued processing.
var request = new XMLHttpRequest();
request.open('GET', '/admin/blogs/43130421348/articles.json');
request.responseType = 'json';
request.send();
request.onload = function () {
var articleList = request.response;
var articleArray = articleList.articles;
var date = new Date();
var ticks = Math.floor(date.getTime() / 1000);
var count = 0; //to keep track of how many metafields have been retrieved
var checkInterval = null;
articleArray.forEach(function (entry, index) {
var metaRequest = new XMLHttpRequest();
metaRequest.open('GET', '/admin/blogs/43130421348/articles/' + entry.id + '/metafields.json');
metaRequest.responseType = 'json';
metaRequest.send();
console.log(index);
metaRequest.onload = function () {
var articleMetaObj = metaRequest.response;
var articleMetaArr = articleMetaObj.metafields;
entry.metafields = articleMetaArr;
count++;
};
});
//Function to continue processing
var finish = function () {
articleArray = articleArray.filter(a => new Date(a.metafields[0].value).getTime() < date.getTime());
//Continue on...
};
//Wait until all metafields are retrieved to continue
checkInterval = setInterval(function () {
if (count === articleArray.length - 1) {
clearInterval(checkInterval);
finish();
}
}, 500);
};
Option 2 - The New Razmatazz (Promises & async/await)
Promises and async/await allow for writing some much nicer looking code when dealing with asynchronous operations.
If you feel like using these, I would suggest digging into the documentation to get more familiar, but here is what it could look like for your task.
//Functions that return Promises can be awaited...
var get = url => new Promise((resolve, reject) => {
var request = new XMLHttpRequest();
request.open('GET', url);
request.responseType = 'json';
//resolve is called when successful
request.onload = () => resolve(request.response);
//reject is called when there's a problem
request.onerror = err => reject(err);
request.send();
});
//await keyword must appear in an async function
var getArticles = async () => {
var articleList = await get('/admin/blogs/43130421348/articles.json');
return articleList.articles;
};
//Promise.all takes an array of promises and resolves when all of them are finished
//This lets you skip the messy setInterval stuff
var getArticleMetafields = async articles => {
var requests = [];
articles.forEach(a => {
var url = '/admin/blogs/43130421348/articles/' + a.id + '/metafields.json';
var promise = get(url);
requests.push(promise);
});
var responses = await Promise.all(requests);
responses.forEach((response, i) => {
articles[i].metafields = response.metafields;
});
return articles;
};
//Notice the async on the handler
document.addEventListener('DOMContentLoaded', async () => {
var articles = await getArticles();
articles = await getArticleMetafields(articles);
var date = new Date();
articles = articles.filter(a => new Date(a.metafields[0].value) < date);
//Continue...
});
Hope this helps. Cheers!
Is your entry the article? Then you could ignore using:
request.onload = function() {
var articleList = request.response;
var articleArray = articleList.articles;
var date = new Date();
var ticks = Math.floor(date.getTime() / 1000);
var count = 0;
articleArray.forEach(function(entry,index, object){
if(entry.'Key' !== 'Event-Date'){
var metaRequest = new XMLHttpRequest();
metaRequest.open('GET', '/admin/blogs/43130421348/articles/'+ entry.id + '/metafields.json');
metaRequest.responseType = 'json';
metaRequest.send();
console.log(index);
metaRequest.onload = function() {
var articleMetaObj = metaRequest.response;
var articleMetaArr = articleMetaObj.metafields;
entry.metafields = articleMetaArr;
var eventDate = entry.metafields[0].value;
}
}
});

How can I make AJAX work for me?

I make APIs all the time and I'm working on one called Swerer. Swerer is an easy and efficient way to use AJAX. Now the problem is when I use Swerer.getFile("file.txt") it returns undefined instead of the content. Any help would be appreciated.
/*
Complex.js 1.0.0
Dec 14, 2017
*/
(function(){
if(!document){
throw new Error("Complex.js needs a window with a document");
}
})();
var toString = Object.prototype.toString;
// Make X
X = function(){
};
X.extend = function(){
var target = arguments[0], obj, arg = arguments;
for (var i = 0; i < arg.length; i++) {
if(toString.call(arg[i]) == "[object Boolean]"){
if(arg[i] !== false){
if(!target){
obj = [];
}else{
for(i in target){
target[i] = obj[i];
}
}
}else{
obj = [];
}
}
}
return obj;
};
// Make constructors
X.extend({
// We are going to make something called Swerer
Swerer: function(){
X.call(this);
},
isFunction: function(obj){
if(toString.call(obj) == "[object Function]"){
return true;
}
},
});
var Swerer = X.Swerer;
Swerer = {};
// Note:
// When we are refering to Swerer in a Swerer function we can use the keyword 'this'
/*
Swerer.get("file.type", function(){
func(arg);
});
*/
// Xhr (XML Http Request) is built into Swerer
(XMLHttpRequest) ? Swerer.xhr = new XMLHttpRequest() : Swerer.xhr = new ActiveXObject("Microsoft.XMLHTTP");
Swerer.getFile = function(file){
var xhttp = this.xhr, content;
if(this.readyState == 4 && this.status == 200){
content = this.responseText;
}
xhttp.open("GET", file, true);
xhttp.send();
return content;
};
If you see any problems post a jsfiddle and I'll try to fix it. Thank you!
I must admit that I only focus on the XHR part of the code, but that should look something like this:
// Xhr (XML Http Request) is built into Swerer
(XMLHttpRequest) ? Swerer.xhr = new XMLHttpRequest() : Swerer.xhr = new ActiveXObject("Microsoft.XMLHTTP");
Swerer.getFile = function(file){
var xhttp = this.xhr;
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
return xhttp.responseText;
}
};
xhttp.open("GET", file, true);
xhttp.send();
};

XMLHttpRequest does not execute in a Safari

BackGround
Currently working on a webpage which must work for both Mac OS and Windows. Currently. I have tested this code on IE and it works great, however when it comes to Mac OS it seems to now execute correctly as how it does with Windows.
Problem
I isolated the issue which is causing the problem in Mac OS. This call out to a Sharepoint Doc lib, which in turn returns a byte array that I later create a Base64 string is causing the issue. I have read the doc on the compatibility of XMLHttpRequest with Safari in the below and shows that it is compatible. Not sure why it work so well in IE but does not work in Safari.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
Code
function GetImgB64(relativeUrl) {
var defferedVarVlalue = jQuery.Deferred();
var b64Img;
$.when(TokenForSharePoint()).then(function (sharepointToken) {
var url = "https://<tenant>.com/sites/<site>/_api/web/GetFileByServerRelativeUrl('" + relativeUrl + "')/$value";
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url, false);
xmlhttp.setRequestHeader("Authorization", "Bearer " + sharepointToken);
xmlhttp.responseType = 'arraybuffer';
xmlhttp.onloadend = function (e) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var arr = new Uint8Array(this.response);
var raw = '';
var i, j, subArray, chunk = 5000;
for (i = 0, j = arr.length; i < j; i += chunk) {
subArray = arr.subarray(i, i + chunk);
raw += String.fromCharCode.apply(null, subArray);
}
b64Img = btoa(raw);
}
else {
errorResults.Location = url;
errorResults.ErrorCode = xmlhttp.status;
errorResults.ErrorResponseText = xmlhttp.statusText;
errorResults.ErrorMessage = "Unable to Load Image",
ErrorHandler(errorResults);
}
};
xmlhttp.onerror = function (error) {
MessageWindow();
};
xmlhttp.send();
return defferedVarVlalue.resolve(b64Img);
});
return defferedVarVlalue.promise();
};
also my script doesn't work with safari

Storing the value of variable in JS

Since my main language is C, I am used to pointers and I love them. Now I have some project which I need to finish in Javascript and I've got a problem which I don't know how to solve.
I want to store the value of a variable which I got from GET request. I have a script to send GET to PHP page, which then sends GET to my daemon written in C. When I get the string I wanted, I use length to measure the size of the string I got and in next GET request I want to send that number of bytes I got as the URL parameter.
window.onload = function() {
if (bytes === undefined) {
var bytes = 0;
}
var url = "/test/log.php?q=" + bytes;
function httpGet(url) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", url, true);
xhttp.onload = function(e) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
console.log(xhttp.responseText);
var option = "";
obj = JSON.parse(xhttp.responseText);
for (var key in obj) {
option += obj[key];
}
document.getElementById("list").innerHTML = asdf;
bytes = option.length;
}
};
xhttp.onerror = function(e) {
console.error(xhttp.statusText);
}
};
xhttp.send();
}
var updateInterval = 2000;
function update() {
httpGet(url);
setTimeout(update, updateInterval);
}
update();
}
So, the focus is on the variable bytes. It should have the value 0 when the script is a first time called, and after every loop (it loops every 2 seconds, I didn't show the loop in the code) it should have the value of the previous length of received string.
You just need to make sure to add the bytes param onto your url in a way that changes with each call rather than just once at page load when it will always be 0.
window.onload = function() {
if (bytes === undefined) {
var bytes = 0;
}
var url = "/test/log.php?q=";
function httpGet(url) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", url, true);
xhttp.onload = function(e) {
if (xhttp.readyState === 4) {
if (xhttp.status === 200) {
console.log(xhttp.responseText);
var option = "";
obj = JSON.parse(xhttp.responseText);
for (var key in obj) {
option += obj[key];
}
document.getElementById("list").innerHTML = asdf;
bytes = option.length;
}
};
xhttp.onerror = function(e) {
console.error(xhttp.statusText);
}
};
xhttp.send();
}
var updateInterval = 2000;
function update() {
httpGet(url + bytes);
setTimeout(update, updateInterval);
}
update();
}
Instead of a fixed value of url make it to a function and it will give you always the current Url with the modified version of bytes, if you modify it
You have only to change this parts
var url = ...
// to
function getUrl() {
return "/test/log.php?q=" + bytes;
}
...
// and
xhttp.open("GET", url, true);
// to
xhttp.open("GET", getUrl(), true);
I'd declare the variable in a context that doesn't empty its value when the function is called. So, you can declare your variable "bytes" before the function, and then looping through that function. In this case, the variable will hold the last value until you overwrite it.
That should work!

Intermittent behavior in my AJAX, Greasemonkey script

I've a small Greasemonkey script that doesn't include any random part, but its results change with each page reload.
I'm a noob and I'm probably doing something wrong, but I don't know what. I hope you'll be able to help me.
The code is too large and too poorly written to be reproduced here, so I'll try to sum up my situation:
I have a list of links which have href=javascript:void(0) and onclick=f(link_id).
f(x) makes an XML HTTP request to the server, and returns the link address.
My script is meant to precompute f(x) and change the href value when the page loads.
I have a function wait() that waits for the page to load, then a function findLinks() that gets the nodes that are to be changed (with xpath).
Then a function sendRequest() that sends the xhr to the server. And, finally handleRequest() that asynchronously (r.onreadystatechange) retrieves the response, and sets the nodes previously found.
Do you see anything wrong with this idea?
Using a network analyzer, I can see that the request is always sent fine, and the response also.
Sometimes the href value is changed, but sometimes for some links it isn't and remains javascript:void(0).
I really don't see why it works only half the time...
function getUrlParameterFromString(urlString, name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(urlString);
if (results == null) {
return "";
} else {
return results[1];
}
}
function getUrlParameter(name) {
return getUrlParameterFromString(window.location.href, name);
}
function wait() {
var findPattern = "//a";
var resultLinks = document.evaluate(findPattern, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (resultLinks == null || resultLinks.snapshotLength == 0) {
return setTimeout(_wait, 100);
} else {
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
sendRequest(linkId, node);
}
}
}
function sendRequest(linkId, nodeToModify) {
window.XMLHttpRequest ? r = new XMLHttpRequest : window.ActiveXObject && (r = new ActiveXObject("Microsoft.XMLHTTP"));
if (r) {
r.open("POST", "some_url", !0);
r.onreadystatechange = function () {
handleRequest(nodeToModify, linkId, r);
}
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
r.send(linkId);
}
}
function handleRequest(nodeToModify, num, r) {
if (r.readyState == 4) {
if (r.status == 200) {
console.log('handleRequest() used');
var a = r.responseText;
if (a == null || a.length < 10) {
sendRequest(num, nodeToModify);
} else {
var url = unescape((getUrlParameterFromString(a, "url")).replace(/\+/g, " "));
nodeToModify.setAttribute('href', url);
nodeToModify.setAttribute('onclick', "");
}
} else {
alert("An error occurred: " + r.statusText)
}
}
}
wait();
It looks like that script will change exactly 1 link. Look-up "closures"; this loop:
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
sendRequest(linkId, node);
}
needs a closure so that sendRequest() gets the correct values. Otherwise, only the last link will be modified.
Try:
for (var i = 0, len = resultLinks.snapshotLength; i < len; i++) {
var node = resultLinks.snapshotItem(i);
var s = node.getAttribute('onclick');
var linkId = s.substring(2, s.length - 1); // f(x)->x
//-- Create a closure so that sendRequest gets the correct values.
( function (linkId, node) {
sendRequest (linkId, node);
}
)(linkId, node);
}

Categories

Resources