The following is a screenshot of two objects in my Chrome console. Both were created by a Javascript function that interacts with a Google Script file. The first was defined with the key-value pair, the second was defined as empty and then had key-value pairs added to it by a for-loop.
The bottom one appears empty, but is actually not. The info button tells me that it was 'evaluated just now'.
The problem is that I am sending this object to a Google Script function, and when I do that, it comes through as an empty object. Is there any way to force the object into the first form before executing the code that sends it to Google Scripts?
Setting a timeout on the execution of the Google Script call works, but only when the for loop that creates the object has finished in time.
My code looks like this:
function logIt(blob) {
var page_labs = {};
PDFJS.getDocument({data: blob}).then(function (PDFdoc) {
for (var i=1; i<=PDFdoc.numPages; i++) {
PDFdoc.getPage(i).then(function (PDFpage) {
var page_number = PDFpage.pageIndex + 1;
var labs = ''
PDFpage.getTextContent().then(function (text) {
for (var j in text.items) {
var item = text.items[j]
if (item.str.substr(0,1) == '♩') {
labs += '♩'
}
}
page_labs['Page ' + page_number.toString()] = labs
})
})
}
})
console.log({'Page 1': '♩♩♩♩♩♩♩♩♩♩♩♩'})
console.log(page_labs);
google.script.run.lofNumbers(page_labs)
}
console.log it by using JSON.stringify method,
example:
console.log(JSON.stringify(page_labs))
Related
My script takes CSV input and from that finds a user's name. It then creates a URL given the user's name.
From there, the script opens the user's URL, collects some data about the user, and puts that info into an array for later output.
My problem is with the window.document.addEventListener. the specific code line is as follows:
element.document.addEventListener("DOMContentLoaded",getSomething(),false);
The strange behavior is as follows:
With the statement above, the listener fires and getSomething() code begins execution. However, the page is not loaded. in the console I can see that the page contents are simply nothing more than an empty body.
Changing "getSomething()" to "getSomething" (in the addEventListener code line) causes the pages to eventually load, however, the getSomething function is never executed (apparently addEventListener did not fire.)
some introduction to the code that follows:
variable testURLs is an array containing a user's URL.
function controlOpenWindows() is not fully set up but its intent is to determine when a window is ready to close, and when data from as many as four opened windows is collected, all four will close and four more will open. four is arbitrary. there are over 900 user URLs so just limiting number open at any one time.
The function that closes the previously opened windows makes the call to open more windows.
Please note that you would need a login id and password to open specific user pages. so passing the URL to you in this post would not be helpful. I'm hoping you can help without that specific info.
function closeOpenedWindow(index){
switch (index) {
case 0:
blnZero=true;
break;
case 1:
blnOne=true;
break;
case 2:
blnTwo=true;
break;
case 3:
blnThree=true;
}
if (blnZero===true && blnOne===true && blnTwo===true && blnThree===true) {
for (p=0; p<4; p++) {
openedWindow[p].close();
count +=1;
controlOpenWindows();
}
}
}
function controlOpenWindows() {
debugger;
testURLs=[];
blnZero=false;
blnOne=true;
blnTwo=true;
blnThree=true;
if (editorProfileURL.length>=4) {
testURLs[0]= editorProfileURL.shift();
testURLs[1] =editorProfileURL.shift();
testURLs[2]=editorProfileURL.shift();
testURLs[3]=editorProfileURL.shift();
} else {
for (n=0; n<editorProfileURL.length; n++) {
testURLs[n]=editorProfileURL[n];
}
}
testURLs.forEach(openWindow);
}
controlOpenWindows();
function openWindow(element1, index1, array1) {
openedWindow[index1]= window.open(element1);
}
function loaded(element, index, array) {
element.document.addEventListener("DOMContentLoaded", getSomething(), false);
}
openedWindow.forEach(loaded);
function getSomething() {
debugger;
var whichPage=this.document.URL;
function whichIndex(element, index, array) {
if (element.document.URL==whichPage) {
return element.document.URL;
}
}
var foundIndex=openedWindow.findIndex(whichIndex);
var reg=/The page you were looking for doesn*/g;
if (openedWindow[0].document.getElementsByClassName("container not-found").length>0) {
if(openedWindow[foundIndex].document.getElementsByClassName("container not-found")[foundIndex].innerHTML.match(reg)) {
closeOpenedWindow(foundIndex);
}
} else {
var firstEdit=openedWindow[foundIndex].document.getElementsByClassName("user-last-edit")[0].innerHTML;
var lastEditDaysAgo=openedWindow[foundIndex].document.getElementsByClassName("transaction-header-time")[0].innerHTML;
var rank=openedWindow[foundIndex].doucment.getElementsByClassName("user-rank")[0].innerHTML;
var editCount=openedWindow[foundIndex].document.getElementsByClassName("user-stats-value")[1].innerHTML;
updatedEditorInfo.push();
updatedEditorInfo.push(firstEdit + ",");
updatedEditorInfo.push(lastEditDaysAgo+ ",");
updatedEdtiorInfo.push(rank + ",");
updatedEditorInfo.push(editoCount + ",");
updatedEditorInfo.push("\n");
console.log(updatedEditorInfo);
alert(updatedEditorInfo);
//closeOpenedWindow();
//controlOpenWindows();
}
closeOpenedWindow(foundIndex);
controlOpenWindows();
}
Thanks for taking a look.
You need to pass a reference to the function instead of calling it directly:
element.document.addEventListener("DOMContentLoaded",getSomething,false);
So,I am trying to use the twitch API:
https://codepen.io/sterg/pen/yJmzrN
If you check my codepen page you'll see that each time I refresh the page the status order changes and I can't figure out why is this happening.
Here is my javascript:
$(document).ready(function(){
var ur="";
var tw=["freecodecamp","nightblue3","imaqtpie","bunnyfufuu","mushisgosu","tsm_dyrus","esl_sc2"];
var j=0;
for(var i=0;i<tw.length;i++){
ur="https://api.twitch.tv/kraken/streams/"+tw[i];
$.getJSON(ur,function(json) {
$(".tst").append(JSON.stringify(json));
$(".name").append("<li> "+tw[j]+"<p>"+""+"</p></li>");
if(json.stream==null){
$(".stat").append("<li>"+"Offline"+"</li>");
}
else{
$(".stat").append("<li>"+json.stream.game+"</li>");
}
j++;
})
}
});
$.getJSON() works asynchronously. The JSON won't be returned until the results come back. The API can return in different orders than the requests were made, so you have to handle this.
One way to do this is use the promise API, along with $.when() to bundle up all requests as one big promise, which will succeed or fail as one whole block. This also ensures that the response data is returned to your code in the expected order.
Try this:
var channelIds = ['freecodecamp', 'nightblue3', 'imaqtpie', 'bunnyfufuu', 'mushisgosu', 'tsm_dyrus', 'esl_sc2'];
$(function () {
$.when.apply(
$,
$.map(channelIds, function (channelId) {
return $.getJSON(
'https://api.twitch.tv/kraken/streams/' + encodeURIComponent(channelId)
).then(function (res) {
return {
channelId: channelId,
stream: res.stream
}
});
})
).then(function () {
console.log(arguments);
var $playersBody = $('table.players tbody');
$.each(arguments, function (index, data) {
$playersBody.append(
$('<tr>').append([
$('<td>'),
$('<td>').append(
$('<a>')
.text(data.channelId)
.attr('href', 'https://www.twitch.tv/' + encodeURIComponent(data.channelId))
),
$('<td>').text(data.stream ? data.stream.game : 'Offline')
])
)
})
})
});
https://codepen.io/anon/pen/KrOxwo
Here, I'm using $.when.apply() to use $.when with an array, rather than list of parameters. Next, I'm using $.map() to convert the array of channel IDs into an array of promises for each ID. After that, I have a simple helper function with handles the normal response (res), pulls out the relevant stream data, while attaching the channelId for use later on. (Without this, we would have to go back to the original array to get the ID. You can do this, but in my opinion, that isn't the best practice. I'd much prefer to keep the data with the response so that later refactoring is less likely to break something. This is a matter of preference.)
Next, I have a .then() handler which takes all of the data and loops through them. This data is returned as arguments to the function, so I simply use $.each() to iterate over each argument rather than having to name them out.
I made some changes in how I'm handling the HTML as well. You'll note that I'm using $.text() and $.attr() to set the dynamic values. This ensures that your HTML is valid (as you're not really using HTML for the dynamic bit at all). Otherwise, someone might have the username of <script src="somethingEvil.js"></script> and it'd run on your page. This avoids that problem entirely.
It looks like you're appending the "Display Name" in the same order every time you refresh, by using the j counter variable.
However, you're appending the "Status" as each request returns. Since these HTTP requests are asynchronous, the order in which they are appended to the document will vary each time you reload the page.
If you want the statuses to remain in the same order (matching the order of the Display Names), you'll need to store the response data from each API call as they return, and order it yourself before appending it to the body.
At first, I changed the last else condition (the one that prints out the streamed game) as $(".stat").append("<li>"+jtw[j]+": "+json.stream.game+"</li>"); - it was identical in meaning to what you tried to achieve, yet produced the same error.
There's a discrepancy in the list you've created and the data you receive. They are not directly associated.
It is a preferred way to use $(".stat").append("<li>"+json.stream._links.self+": "+json.stream.game+"</li>");, you may even get the name of the user with regex or substr in the worst case.
As long as you don't run separate loops for uploading the columns "DisplayName" and "Status", you might even be able to separate them, in case you do not desire to write them into the same line, as my example does.
Whatever way you're choosing, in the end, the problem is that the "Status" column's order of uploading is not identical to the one you're doing in "Status Name".
This code will not preserve the order, but will preserve which array entry is being processed
$(document).ready(function() {
var ur = "";
var tw = ["freecodecamp", "nightblue3", "imaqtpie", "bunnyfufuu", "mushisgosu", "tsm_dyrus", "esl_sc2"];
for (var i = 0; i < tw.length; i++) {
ur = "https://api.twitch.tv/kraken/streams/" + tw[i];
(function(j) {
$.getJSON(ur, function(json) {
$(".tst").append(JSON.stringify(json));
$(".name").append("<li> " + tw[j] + "<p>" + "" + "</p></li>");
if (json.stream == null) {
$(".stat").append("<li>" + "Offline" + "</li>");
} else {
$(".stat").append("<li>" + json.stream.game + "</li>");
}
})
}(i));
}
});
This code will preserve the order fully - the layout needs tweaking though
$(document).ready(function() {
var ur = "";
var tw = ["freecodecamp", "nightblue3", "imaqtpie", "bunnyfufuu", "mushisgosu", "tsm_dyrus", "esl_sc2"];
for (var i = 0; i < tw.length; i++) {
ur = "https://api.twitch.tv/kraken/streams/" + tw[i];
(function(j) {
var name = $(".name").append("<li> " + tw[j] + "<p>" + "" + "</p></li>");
var stat = $(".stat").append("<li></li>")[0].lastElementChild;
console.log(stat);
$.getJSON(ur, function(json) {
$(".tst").append(JSON.stringify(json));
if (json.stream == null) {
$(stat).text("Offline");
} else {
$(stat).text(json.stream.game);
}
}).then(function(e) {
console.log(e);
}, function(e) {
console.error(e);
});
}(i));
}
});
I want to write a script to resolve double redirects automatically after a page move. Here is what I have started with:
(function () {
var api = new mw.Api();
api.get( {
action: 'query',
list: 'backlinks',
blpageid: mw.config.get('wgArticleId'),
blfilterredir: 'redirects',
blredirect: true,
bllimit: 500
} ).done( function (data) {
var fixed = 0;
redirects = data.query.backlinks;
for (var i=0; i<redirects.length; i++) {
var doubles = redirects[i].redirlinks;
if (doubles === undefined) {
continue;
}
for (var j=0; j<doubles.length; j++) {
console.log(doubles[j]);
fixed ++;
}
}
mw.notify(fixed);
} );
})();
The problem is that if I run this function on a page like Wikipedia:Blocking policy the script returns some pages that are not actually double-redirects, but merely redirects containing links to it.
I can check each of them to see where they are actually pointing to, but isn't there any better way? i.e. a simple method to retrieve double redirects only.
If you are happy with using python and the pywikibot framework there is https://m.mediawiki.org/wiki/Manual:Pywikibot/redirect.py which should do what you want.
Otherwise you might want to work with the output of Special:DoubleRedirects.
I got a table with remote datasource. in one cell I got the userID. Because I want to show the username instead of the user ID I made a custom template function:
function getUserName(pmcreator){
var user = '';
var data = ''
ds_userList.fetch(function(){
var data = this.data();
for(var i = 0, length = data.length; i < length; i++){
if(data[i].uID == pmcreator){
console.log(data[i].uLastname)
user = data[i].uLastname
}
}
});
return user
}
But its not working as it should, the cells stay empty. I got no errors but I see that the remote request to fetch the usernames is not completed before the grid is filled out. I thought the custom function of fetch is waiting for the results to return but it don't seems so.
Any Idea? I find thousends of examples but all with static local data. I need one with both remote, the grid conent and the template data.
This is probably due the fact that when yuo call the dataSource.fetch it fires off an async function, which causes the thread running the template to continue on. According to kendo you will need to return a control, then set the content of that control inside the callback.
Quick sample using Northwind categories...
Here is the template function
function getDetails(e) {
$.getJSON("http://services.odata.org/V3/Northwind/Northwind.svc/Categories", null, function(data) {
var category = data.value.filter(function(item, i) {
return item.CategoryID === e.CategoryID;
});
$("#async_" + e.CategoryID).html(category[0].Description);
});
return "<div id='async_" + e.CategoryID + "'></div>";
}
http://jsbin.com/ODENUBe/2/edit
I kept getting a recursive error maximum call stack when I just tried to fetch the dataSource, so I switched to a simple getJSON, but it should work pretty much the same.
I grabbed a bit of code to do some paging with jQuery, via Luca Matteis here
Paging Through Records Using jQuery
I've made some edits to the paging script so that I can use the same code to provide paging of different content in different locations on the same site.
For the most part, I think it works, except that I get a jsonObj is undefined error in firebug.
When I use alert(jsonObj.toSource()), I am shown the variables that I am trying to populate, but at the same time, the script dies because of the error.
I can't figure out why I am getting this conflict of 'undefined' and yet I can easily out put the 'undefined' values in an alert. I can even say alert(jsonObj.name), and it will give me that value, but still launch an jsonObj is undefined error.
Here's the code I'm using
var pagedContent = {
data: null
,holder: null
,currentIndex : 0
,init: function(data, holder) {
this.data = data;
this.holder=holder;
this.show(0); // show last
}
,show: function(index) {
var jsonObj = this.data[index];
if(!jsonObj) {
return;
}
var holdSubset='';
for(i=0;i<=4; i++){
jsonObj=this.data[index+i];
this.currentIndex = index;
if(this.holder=='div#firstList'){
var returnedId = jsonObj.id;
var returnedName = jsonObj.name;
var calcScore=this.data[index+i].score/this.data[0].score*100;
var resultInput="<div ' id='"+returnedId+"'><div class='name'>"+returnedName+"</div><div class='score'><div style='width:"+calcScore+"%;'></div></div>";
}
if(this.holder=='div#secondList'){
var name=jsonObj.name;
var city=jsonObj.city;
var region=jsonObj.state;
var resultInput='<li><div>'+name+'</div<div>'+city+'</div><div>'+region+'</div></li>';
}
holdSubset= holdSubset+resultInput;
}
jQuery(this.holder).html('<br/>'+holdSubset);
if(index!=0){
var previous = jQuery("<a>").attr("href","#").click(this.previousHandler).text("< previous");
jQuery(this.holder).append(previous);
}
if(index+i<this.data.length){
var next = jQuery("<a style='float:right;'>").attr("href","#").click(this.nextHandler).text("next >");
jQuery(this.holder).append(next);
}
}
,nextHandler: function() {
pagedContent.show(pagedContent.currentIndex + 5);
return false;
}
,previousHandler: function() {
pagedContent.show(pagedContent.currentIndex - 5);
return false
}
};
I call the function like this
pagedContent.init(json.users.locations, 'div#secondList');
The json looks like this
{"locations" : [ {"id":"21319","name":"Naugatuck American Legion","city":"Ansonia","region":"Connecticut"},{"id":"26614","name":"Studio B789","city":"Acton","region":"Maine"},{"id":"26674","name":"Deering Grange Hall","city":"Bailey Island","region":"Maine"},{"id":"27554","name":"Accu Billiards","city":"Acushnet","region":"Massachusetts"}]}
I may have found the problem with your code:
for(i=0;i<=4; i++){
jsonObj=this.data[index+i];
(...)
When you call show(0) you set index to 0. You expect a fixed number of items in the array (5 in the range [0..4]) but there are only 4 locations in your data.
If you are using console.log to trace the problems in firebug you might find that it is a problem with firebug. Try just running console.log on it's own.
If it is a problem with firebug try updating it. There are some development versions around which might fix the problem.
I had a similar problem and fixed it by doing the above.