load function declared in service objects doesn't execute - ibm-sbt

Trying to get my communities list(and profile as well) using javascript ibmsbt api passing object with load function to getMyCommunities function has no result. Function assigned to load property simply doesn't get executed.
Here is the code:
var communityService = new CommunityService();
communityService.getMyCommunities({
load: function(communities) {
var ul = document.getElementById("communities")
for (var i=0; i<communities.length; i++) {
var community = communities[i];
var li = document.createElement("li");
ul.appendChild(li);
li.setAttribute("id", "community" + i);
dom.setText("community" + i, community.getTitle());
}
},
error: function(error) {
console.error("Error: "+error.message);
}
});
But when I'm using promises everything works like a charm. Here it is:
var cp = communityService.getMyCommunities();
cp.then(
function(communities){
var ul = document.getElementById("communities")
for (var i=0; i<communities.length; i++) {
var community = communities[i];
var li = document.createElement("li");
ul.appendChild(li);
li.setAttribute("id", "community" + i);
dom.setText("community" + i, community.getTitle());
}
},
function(error){
console.error("Error: " + error.message);
});
API documentation on the part of load function says:
This function is invoked when the call to get my communities completes. The function expects to receive one parameter, the communities object - an array of my communities.
api doc
What am I missing?

our API documentation is out of date. We only support the Promise syntax for asynchronous calls. I'll get the API documentation updated but in the meantime you can use the documentation in the SDK download.
regards Mark

Related

I need to know how to add images from a files on my windows 10 PC to a google apps script HTML website

I want to add images to a google apps script hosted webpage.
I tried looking around the menus and checking google.
I want it to display the image at the desired size
Images from Albums in my Google Photo Library in a Web App
function doGet(e){
return displayAlbums(true);
}
//used for web app and dialog depending upon weather web parameter is true or not. If it's not provided then it's false.
function displayAlbums(web) {
var web=web||false;
//different color backgrounds for each album
var bgA=['#f3eeb3','#f3e2b3','#f3ceb3','#f3b3b6','#f3b3b6','#f3b3ef','#b3eaf3','#b3f3e3','#b3f3cb','#bdf3b3']
var html='';
var n=0;
var albumsA=listAlbums();
for(var i=0;i<albumsA.length;i++) {
html+='<html><head></head><body>';
html+=Utilities.formatString('<div id="d-%s" style="margin:auto;max-width:500px;background-color:%s;">',i,bgA[i]);
html+=Utilities.formatString('<h1>%s</h1>', albumsA[i].title);
var images=listImagesOfAnAlbum(albumsA[i].id);
for(var j=0;j<images.length;j++) {
html+=Utilities.formatString('<br />%s - %s<br /><img src="%s" width="500" />',j+1,images[j].filename, images[j].baseUrl);
}
html+='</div></body></html>';
}
if(!web) {
var userInterface=HtmlService.createHtmlOutput(html).setWidth(600).setHeight(500);
SpreadsheetApp.getUi().showModelessDialog(userInterface, 'Displaying my Albums');
}else{
var output=HtmlService.createHtmlOutput(html).setWidth(600).setHeight(500);
return output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL).addMetaTag('viewport', 'width=360, initial-scale=1');
}
}
function listAlbums() {
var token=null;
var fA=[];
var n=0;
do{
var params = {muteHttpExceptions:true,headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()}};
var url=Utilities.formatString('https://photoslibrary.googleapis.com/v1/albums?pageSize=50%s',(token!=null)?"&pageToken=" + token:"");
var resp=UrlFetchApp.fetch(url,params);
var js=JSON.parse(resp.getContentText());
for(var i=0;i<js.albums.length;i++) {
fA.push({id:js.albums[i].id,title:js.albums[i].title,count:js.albums.mediaItemsCount});
}
token=js.nextPageToken;
}while(token!=null);
Logger.log(fA);
return fA;
}
function listImagesOfAnAlbum(albumId) {
var albumId= albumId || 'Default Id for debugging';
var token=null;
var iA=[];
var n=0;
do{
var params = {
method:"post",
muteHttpExceptions:true,
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
payload:{"albumId": albumId,"pageSize":"50","pageToken":token}};
var url="https://photoslibrary.googleapis.com/v1/mediaItems:search";
var resp=UrlFetchApp.fetch(url,params);
var js=JSON.parse(resp.getContentText());
for(var i=0;i<js.mediaItems.length;i++) {
iA.push({filename:js.mediaItems[i].filename,baseUrl:js.mediaItems[i].baseUrl});
}
token=js.nextPageToken;
}while(token!=null);
return iA;
}
Google Photos API
I added this to the manifest file:
"exceptionLogging": "STACKDRIVER",
"oauthScopes": ["https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/photoslibrary", "https://www.googleapis.com/auth/script.container.ui", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.scriptapp", "https://www.googleapis.com/auth/spreadsheets"]
Also adding this to your google scripts even though you don't need it will provoke the authenticator to added the need scopes. And also setup the Drive API in Resources Advanced Google Services.
//DriveApp.getFiles();
function listFiles() {
var files = Drive.Files.list({
fields: 'nextPageToken, items(id, title)',
maxResults: 10
}).items;
for (var i = 0; i < files.length; i++) {
var file = files[i];
Logger.log('\n%s-Title: %s Id: %s',i+1,file.title,file.id);
}
}
This is a technique describe by Bruce McPherson as borrowing a Token you can read about it here
I had already loaded the Oauth2 and GOA libraries. According the Mr. McPherson you will need to install the GOA Library although I never actively used it. He has a walk through here Just go through his little slide presentation. This may seem like a lot of trouble and it is. But it does provide you with programmatic access to the photo library. Fortunately, Google does all this for us on most of our libraries.
From Your Personal Computer to your Website with DataURI's
Another way to get images right off of your Google Drive and into your webapp website.
The Javascript in the <script> tags of your website:
google.script.run
.withSuccessHandler(function(iObj){
console.log(iObj);
for(var i=0;i<iObj.iA.length;i++) {
if(i==iObj.iA.length-1) {
$('#header').css('background-image','URL(' + iObj[iObj.iA[i]] + ')');
}else{
$('#' + iObj.iA[i]).attr('src',iObj[iObj.iA[i]]);
}
}
})
.getSimpleSiteImages();
});
The Google Apps Script:
function getSimpleSiteImages() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('SimpleSite');
var rg=sh.getDataRange();
var vA=rg.getValues();
var oObj={iA:[]};
for(var i=0;i<vA.length;i++) {
oObj.iA[i]=vA[i][2];
oObj[oObj.iA[i]]=getDataURI(vA[i][1]);
}
return oObj;
}
function getDataURI(fileId) {
var file=DriveApp.getFileById(fileId);
return file.getBlob().getDataAsString();
}
The Google Apps Script That Makes the DataURI:
function convImageUrl(url){
var blob=UrlFetchApp.fetch(url).getBlob();
var b64Url='data:' + blob.getContentType() + ';base64,' + Utilities.base64Encode(blob.getBytes());
return b64Url;
}
Just save on your google drive and upload them into your images.

Add vimeo event listeners for multiple videos on same page

I have multiple Vimeo videos iframes on the same page. So I want to add event listeners for all the iframes. But somehow it is not working for me.
here is the code which I add on document.ready.
var iframes = document.querySelectorAll('iframe');
var player;
//loop through all and add event
for (i = 0; i < iframes.length; i++) {
// when vimeo player is ready add other events
player = $f(iframes[i]);
player.addEvent('ready', function () {
player.addEvent('play', onPlay);
player.addEvent('pause', onPause);
});
function onPlay(el) {
console.log('play');
}
function onPause(el) {
console.log('pause');
}
}
I get all the iframes in variable 'iframes', it also loops through all and add ready event. But cannot add play and pause events. Where am I going wrong?
The following code would help you with attaching events to your frames.
<script>
$(document).ready(function () {
var x = document.querySelectorAll("iframe");
var nodelist = x.length;
alert(nodelist);
for (i = 0; i < nodelist; i++) {
var player = new Vimeo.Player(x[i]);
player.on('play', function () {
console.log('played the video!');
});
player.on('ended', function () {
console.log('ended the video!');
});
}
});
</script>
Actually multiple videos play/pause issue as mentioned in my question got solved using froogaloop2.js. I am not writing any extra code for this now as specified by me in question. and my iframe src url does not append api=1 param.

CasperJS: Iterating through URL's

I'm pretty new to CasperJS, but isn't there a way to open a URL and execute CasperJS commands in for loops? For example, this code doesn't work as I expected it to:
casper.then(function() {
var counter = 2013;
for (i = counter; i < 2014; i++) {
var file_name = "./Draws/wimbledon_draw_" + counter + ".json";
// getting some local json files
var json = require(file_name);
var first_round = json["1"];
for (var key in first_round) {
var name = first_round[key].player_1.replace(/\s+/g, '-');
var normal_url = "http://www.atpworldtour.com/Tennis/Players/" + name;
// the casper command below only executes AFTER the for loop is done
casper.thenOpen(normal_url, function() {
this.echo(normal_url);
});
}
}
});
Instead of Casper is calling thenOpen on each new URL per iteration, it gets only called AFTER the for loop executes. Casper thenOpen then gets called with the last value normal_url is set to. Is there no Casper command to have it work each iteration within the for loop?
Follow up: How do we make casper thenOpen return a value on the current iteration of the for loop?
Say for example, I needed a return value on that thenOpen (maybe if the HTTP status is 404 I need to evaluate another URL so I want to return false). Is this possible to do?
Editing casper.thenOpen call above:
var status;
// thenOpen() only executes after the console.log statement directly below
casper.thenOpen(normal_url, function() {
status = this.status(false)['currentHTTPStatus'];
if (status == 200) {
return true;
} else {
return false;
}
});
console.log(status); // This prints UNDEFINED the same number of times as iterations.
If you need to get context then use the example here:
https://groups.google.com/forum/#!topic/casperjs/n_zXlxiPMtk
I used the IIFE (immediately-invoked-function-expression) option.
Eg:
for(var i in links) {
var link = links[i];
(function(index) {
var link = links[index]
var filename = link.replace(/#/, '');
filename = filename.replace(/\//g, '-') + '.png';
casper.echo('Attempting to capture: '+link);
casper.thenOpen(vars.domain + link).waitForSelector('.title h1', function () {
this.capture(filename);
});
})(i);
}
links could be an array of objects and therefore your index is a reference to a group of properties if need be...
var links = [{'page':'some-page.html', 'filename':'page-page.png'}, {...}]
As Fanch and Darren Cook stated, you could use an IIFE to fix the url value inside of the thenOpen step.
An alternative would be to use getCurrentUrl to check the url. So change the line
this.echo(normal_url);
to
this.echo(this.getCurrentUrl());
The problem is that normal_url references the last value that was set but not the current value because it is executed later. This does not happen with casper.thenOpen(normal_url, function(){...});, because the current reference is passed to the function. You just see the wrong url, but the correct url is actually opened.
Regarding your updated question:
All then* and wait* functions in the casperjs API are step functions. The function that you pass into them will be scheduled and executed later (triggered by casper.run()). You shouldn't use variables outside of steps. Just add further steps inside of the thenOpen call. They will be scheduled in the correct order. Also you cannot return anything from thenOpen.
var somethingDone = false;
var status;
casper.thenOpen(normal_url, function() {
status = this.status(false)['currentHTTPStatus'];
if (status != 200) {
this.thenOpen(alternativeURL, function(){
// do something
somethingDone = true;
});
}
});
casper.then(function(){
console.log("status: " + status);
if (somethingDone) {
// something has been done
somethingDone = false;
}
});
In this example this.thenOpen will be scheduled after casper.thenOpen and somethingDone will be true inside casper.then because it comes after it.
There are some things that you need to fix:
You don't use your counter i: you probably mean "./Draws/wimbledon_draw_" + i + ".json" not "./Draws/wimbledon_draw_" + counter + ".json"
You cannot require a JSON string. Interestingly, you can require a JSON file. I still would use fs.read to read the file and parse the JSON inside it (JSON.parse).
Regarding your question...
You didn't schedule any commands. Just add steps (then* or wait*) behind or inside of thenOpen.

Less CSS and local storage issue

I'm using LESS CSS (more exactly less.js) which seems to exploit LocalStorage under the hood. I had never seen such an error like this before while running my app locally, but now I get "Persistent storage maximum size reached" at every page display, just above the link the unique .less file of my app.
This only happens with Firefox 12.0 so far.
Is there any way to solve this?
P.S.: mainly inspired by Calculating usage of localStorage space, this is what I ended up doing (this is based on Prototype and depends on a custom trivial Logger class, but this should be easily adapted in your context):
"use strict";
var LocalStorageChecker = Class.create({
testDummyKey: "__DUMMY_DATA_KEY__",
maxIterations: 100,
logger: new Logger("LocalStorageChecker"),
analyzeStorage: function() {
var result = false;
if (Modernizr.localstorage && this._isLimitReached()) {
this._clear();
}
return result;
},
_isLimitReached: function() {
var localStorage = window.localStorage;
var count = 0;
var limitIsReached = false;
do {
try {
var previousEntry = localStorage.getItem(this.testDummyKey);
var entry = (previousEntry == null ? "" : previousEntry) + "m";
localStorage.setItem(this.testDummyKey, entry);
}
catch(e) {
this.logger.debug("Limit exceeded after " + count + " iteration(s)");
limitIsReached = true;
}
}
while(!limitIsReached && count++ < this.maxIterations);
localStorage.removeItem(this.testDummyKey);
return limitIsReached;
},
_clear: function() {
try {
var localStorage = window.localStorage;
localStorage.clear();
this.logger.debug("Storage clear successfully performed");
}
catch(e) {
this.logger.error("An error occurred during storage clear: ");
this.logger.error(e);
}
}
});
document.observe("dom:loaded",function() {
var checker = new LocalStorageChecker();
checker.analyzeStorage();
});
P.P.S.: I didn't measure the performance impact on the UI yet, but a decorator could be created and perform the storage test only every X minutes (with the last timestamp of execution in the local storage for instance).
Here is a good resource for the error you are running into.
http://www.sitepoint.com/building-web-pages-with-local-storage/#fbid=5fFWRXrnKjZ
Gives some insight that localstorage only has so much room and you can max it out in each browser. Look into removing some data from localstorage to resolve your problem.
Less.js persistently caches content that is #imported. You can use this script to clear content that is cached. Using the script below you can call the function destroyLessCache('/path/to/css/') and it will clear your localStorage of css files that have been cached.
function destroyLessCache(pathToCss) { // e.g. '/css/' or '/stylesheets/'
if (!window.localStorage || !less || less.env !== 'development') {
return;
}
var host = window.location.host;
var protocol = window.location.protocol;
var keyPrefix = protocol + '//' + host + pathToCss;
for (var key in window.localStorage) {
if (key.indexOf(keyPrefix) === 0) {
delete window.localStorage[key];
}
}
}

Add a click function dynamically within a for loop using closure

I am trying to create a dynamic accordion. My problem is that I can not seem to get a reference to the i variable inside the for loop. I know it is a scope problem but I thought this closure would do the trick.... Please someone help me out as this is driving me completely insane.
jQuery(function(){
var tables = jQuery('table');
var tableHeadings = jQuery('h3');
for(i =0 , ii = tableHeadings.length; i < ii; i++){
(function(){
var index = i;
tables.eq(index).addClass('table-' + index);
tableHeadings.eq(index).click(function(){
tables.eq(index).slideToggle();
});
})();
}
});
Better yet:
tableHeadings.each(function(index, element) {
tables.eq(index).addClass('table-' + index);
tableHeadings.eq(index).click(function() {
tables.eq(index).slideToggle();
});
});

Resources