Is it possible to update text message in WL.BusyIndicator? - ibm-mobilefirst

I create a new WL.BusyIndicator via this code just before I start a long running process...
if (gblShowBusyIndicator) {
busyIndicator = new WL.BusyIndicator('loader',
{text: 'Refreshing local sales data...',
opacity: 0.85,
fullScreen: true});
busyIndicator.show();
}
Is it possible to update the "text" parameter intermittently during that process? I tried calling this function, but it didn't work. Any ideas?
function setBusyIndicatorStatus(status) {
try {
if (busyIndicator.isVisible()) {
busyIndicator({text: status});
}
} catch (e) {
if (gblLoggerOn) WL.Logger.debug(">> setBusyIndicatorStatus(" + status + ") failure... discarding");
}
}

After some additional thought, here's how I solved the problem, but I'd like to know if there's a better way than toggling show/hide w different status messages at certain points in my code.
Thanks!
function setBusyIndicatorStatus(view, status) {
if (gblLoggerOn) WL.Logger.debug(">> setBusyIndicatorStatus(" + view + ", " + status + ")");
try {
if (busyIndicator.isVisible()) busyIndicator.hide();
} catch (e) {
if (gblLoggerOn) WL.Logger.debug(">> setBusyIndicatorStatus(" + view + ", " + status + ") failure... discarding");
}
busyIndicator = null;
var options = {text: null, opacity: 0.85, fullScreen: true};
options.text = status;
busyIndicator = new WL.BusyIndicator(view, options);
busyIndicator.show();
}

Related

Is there any reason why no error found in calling navigator.mediaDevices.getUserMedia

I'm writing Webrtc chrome desktop app by accessing 2 camera simultaneously using latest Chrome Windows version.
Accessing camera list by navigator.mediaDevices.enumerateDevices() is ok but accessing these device by their specific id using navigator.mediaDevices.getUserMedia not work.
It only occurs sometimes. But no error in the catch.
So, I tried navigator.mediaDevices.getUserMedia is really exists or not.
if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
}
Yes, it was.
Just not getting any log info in calling navigator.mediaDevices.getUserMedia()
getVideoSources_ = function() {
return new Promise(function(resolve, reject) {
if (typeof navigator.mediaDevices.enumerateDevices === 'undefined') {
alert('Your browser does not support navigator.mediaDevices.enumerateDevices, aborting.');
reject(Error("Your browser does not support navigator.mediaDevices.enumerateDevices, aborting."));
return;
}
requestVideoSetTimeout = 500;
navigator.mediaDevices.enumerateDevices().then((devices) => {
// get the list first by sorting mibunsho camera in first place
for (var i = 0; i < devices.length; i++) {
log("devices[i]", JSON.stringify(devices[i]));
log("devices[i].label", devices[i].label);
if (devices[i].kind === 'videoinput' && devices[i].deviceId && devices[i].label) {
if (devices[i].label.indexOf("USB_Camera") > -1) {
deviceList[1] = devices[i];
} else {
deviceList[0] = devices[i];
}
}
}
// request video by sorted plan
for (var i = 0; i < deviceList.length; i++) {
requestVideo_(deviceList[i].deviceId, deviceList[i].label, resolve, reject);
requestVideoSetTimeout = 1000; // change requestVideoSetTimeout for next video request
}
}).catch((err) => {
log("getVideoSources_:" + err.name + ": " + err.message);
reject(Error("getVideoSources_ catch error"));
});
});
}
getVideoSources_().then(function(result) {
....
}).catch(function(err) {
....
});
function requestVideo_(id, label, resolve, reject) {
if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
log("navigator.mediaDevices.getUserMedia found!");
navigator.mediaDevices.getUserMedia({
video: {
deviceId: {exact: id},
width: 640,
height: 480,
frameRate: {
ideal: 20,
max: 20
}
},
audio: false}).then(
(stream) => {
log("***requestVideo_", id);
log("***requestVideo_", label);
log("***requestVideo_", stream);
// USB_Camera is face camera
if (label.indexOf("USB_Camera") > -1) {
log("***requestVideo_001");
myStream2 = stream;
log("***requestVideo_myStream2", myStream2);
} else {
log("***requestVideo_002");
myStream = stream;
log("***requestVideo_myStream", myStream);
getUserMediaOkCallback_(myStream, label);
}
resolve("###Video Stream got###");
stream.getVideoTracks()[0].addEventListener('ended', function(){
log("***Camera ended event fired. " + id + " " + label);
endedDevice[id] = label;
});
},
getUserMediaFailedCallback_
).catch((error) => {
log('requestVideo_: ' + error.name);
reject(Error("requestVideo_ catch error" + error.name));
});
}
}
function getUserMediaFailedCallback_(error) {
log("getUserMediaFailedCallback_ error:", error.name);
alert('User media request denied with error: ' + error.name);
}
#Kaiido is right, resolve is called in a for-loop here, which is all over the place, and before all the code has finished. Any error after this point is basically lost.
This is the promise constructor anti-pattern. In short: Don't write app code inside promise constructors. Don't pass resolve and reject functions down. Instead, let functions return promises up to you, and add all app code in then callbacks on them. Then return all promises so they form a single chain. Only then do errors propagate correctly.
See Using promises on MDN for more.

phantomjs XHR response code is null

I am using the below code to automate a web page. The web page has an XHR call which is triggered upon submitting the form. By using "onResourceRequest" and "onResponseReceived" I can look into the request body, but the response status code is always null.
PhantomJS version: 2.1.1
var page = require('webpage').create(), testindex = 0, loadInProgress = false;
var config = require('../../config/config.json');
var system = require('system');
console.log('Running Iteration 1 ...');
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
start = new Date().getTime(),
condition = false,
interval = setInterval(function() {
if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
// If not time-out yet and condition not yet fulfilled
condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
} else {
if(!condition) {
// If condition still not fulfilled (timeout but condition is 'false')
console.log("'waitFor()' timeout");
phantom.exit(1);
} else {
// Condition fulfilled (timeout and/or condition is 'true')
console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
clearInterval(interval); //< Stop this interval
}
}
}, 250); //< repeat check every 250ms
};
page.onError = function (msg, trace) {
console.log(msg);
trace.forEach(function(item) {
console.log(' ', item.file, ':', item.line);
});
};
page.onConsoleMessage = function(msg, lineNum, sourceId) {
console.log(colors.cyan('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")'));
};
page.onLoadStarted = function() {
loadInProgress = true;
console.log("load started ", page.url);
};
page.onResourceRequested = function(request) {
console.log('Request ' + request.url);
console.log('Request Header :', JSON.stringify(request.headers));
console.log('Request Body :', request.postData);
};
page.onResourceReceived = function(response) {
console.log('Receive ' + response.url, response.status);
if(response.status === null) {
console.log(JSON.stringify(response));
}
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log("load finished ", page.url);
};
var steps = [
function () {
page.open(config.url, function (status) {
if (status !== 'success'){
console.log('Unable to access ', config.url); //This is a HTTPS endpoint
} else {
waitFor(function() {
// Check in the page if a specific element is now visible
return page.evaluate(function() {
return document.getElementById('code').value;
});
}, function() {
console.log("The page dialog should be visible now.");
// phantom.exit();
});
}
});
},
function () {
var isPostMessageSupported = page.evaluate(function() {
if(window.postMessage){
return true;
} else{
return false;
}
});
console.log('POST Message Support : ', isPostMessageSupported);
var guid = page.evaluate(function() {
return document.getElementById('guid').value;
});
console.log('GUID : ', guid);
page.evaluate( function () {
document.getElementById('userid').value = 'myusername';
document.getElementById('pass').value = 'mypassword';
});
},
function () {
page.evaluate(function () {
document.getElementById('myform').submit();
return;
});
},
function () {
page.render('iteration1.png');
},
];
function done(){
console.log('##completed');
}
setInterval(function() {
if (!loadInProgress && typeof steps[testindex] == "function") {
console.log("step " + (testindex + 1));
steps[testindex]();
testindex++;
}
if (typeof steps[testindex] != "function") {
console.log("test complete!");
done();
phantom.exit();
}
}, 50);
The response that I recieve for the XHR call is
{"contentType":null,"headers":[],"id":42,"redirectURL":null,"stage":"end","status":null,"statusText":null,"time":"2018-04-12T04:15:04.402Z","url":"https://example.com/p"}
I have tried all the phantomJS command line arguments
phantomjs --web-security=false --ssl-protocol=tlsv1 --ignore-ssl-errors=true phantomjs/iterations/iteration1.js
I have also tried adding header "Connection:keep-alive". But nothing solves my problem.
I am not sure what could be the problem here.

OL3 add backup url

I'm trying to add a backup route for a tiles with ol3. I would like to test on the errorload event if the source url starting by "http".
If "yes" : replace this tile by a custom tile.
If "no" : change the source url of this tile by another one and retry
I think i need to use something like that :
layerTile.getSource().setUrl('file:///local/{z}/{x}/{y}.jpg');
var errorTilePath='https://image.noelshack.com/fichiers/2017/14/1491403614-errortile.png';
var serverBackup='http://otile1.mqcdn.com/tiles/1.0.0/map/';
layerTile.getSource().setTileLoadFunction((function() {
var tileLoadFn = layerTile.getSource().getTileLoadFunction();
return function(tile, src) {
var image = tile.getImage();
image.onload = function() {console.log('Tile ok : ' + src); };
image.onerror = function() {
console.log('Tile error : ' + src);
console.log(tile);
if (src.substr(0,4)!='http') {
var tmp=src.split('/').reverse();
var serverBackupPath=serverBackup+tmp[2]+'/'+tmp[1]+'/'+tmp[0].split('.')[0]+'.png';
console.log("Second url : " + serverBackupPath)
src=serverBackupPath;
tile.getImage().src=src;
var image = tile.getImage();
image.onload = function() {console.log('Tile backup ok : ' + src);};
image.onerror = function() {console.log('Tile backup error : ' + src); src=errorTilePath; tile.getImage().src=src; tileLoadFn(tile, src);}
} else {
console.log('Custom tile : ');
src=errorTilePath;
tile.getImage().src=src;
}
tileLoadFn(tile, src);
};
tileLoadFn(tile, src);
};
})());
With that, I can see that the backup tile is downloaded but not visible on map.
Certainely, I misunderstood something.
Thanks in advance if somebody could help me.
Oups, without code my answer is null.
layerTile.getSource().setUrl('file:///local/{z}/{x}/{y}.jpg');
var serverBackup='https://{a-c}.tile.openstreetmap.org/';
var errorTilePath=urlBase+'css/images/error.png';
layerTile.getSource().setTileLoadFunction((function() {
return function(tile, src) {
if (UrlExists(src)) {
tile.getImage().src=src;
} else {
if (src.substr(0,4)=='file') {
var tmp=src.split('/').reverse();
src='https://'+['a', 'b', 'c'].sort(function() {return 0.5 - Math.random()})[0]+'.tile.openstreetmap.org/'+tmp[2]+'/'+tmp[1]+'/'+tmp[0].split('.')[0]+'.png';
if (UrlExists(src)) {
tile.getImage().src=src;
} else {
tile.getImage().src=errorTilePath;
}
} else {
tile.getImage().src=errorTilePath;
}
}
};
})());
function UrlExists(url){
try {
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status==200||http.status==403;
} catch(err){return false;}
}

How to add a function to another jQuery function?

I'm trying to add this short function - which swaps images according to the active tab in jQuery UI Tabs - below to the larger function below, which is the jQuery Address plugin that adds forward/back and #URL functions to UI Tabs: http://www.asual.com/jquery/address/
I need to add the shorter function so it fires when the tab changes - so it changes the image in #headerwrapper - but I can't quite tell exactly where the tab change is fired in the main address function. Any ideas on how to add this shorter function to jQuery Address?
Image change function I need to add to the main function below to run when the tab change fires:
var img = $(ui.panel).data("image");
$("#headerwrapper")
.animate({ opacity: 'toggle' }, function() {
$(this).css("background-image", "url(" + img + ")")
.animate({ opacity: 'toggle' });
});
}
Main jQuery Tabs Address function:
<script type="text/javascript">
var tabs,
tabulation = false,
initialTab = 'home',
navSelector = '#tabs .ui-tabs-nav',
navFilter = function(el) {
return $(el).attr('href').replace(/^#/, '');
},
panelSelector = '#tabs .ui-tabs-panel',
panelFilter = function() {
$(panelSelector + ' a').filter(function() {
return $(navSelector + ' a[title=' + $(this).attr('title') + ']').size() != 0;
}).each(function(event) {
$(this).attr('href', '#' + $(this).attr('title').replace(/ /g, '_'));
});
};
if ($.address.value() == '') {
$.address.value(initialTab);
}
$.address.init(function(event) {
$(panelSelector).attr('id', initialTab);
$(panelSelector + ' a').address(function() {
return navFilter(this);
});
panelFilter();
tabs = $('#tabs')
.tabs({
load: function(event, ui) {
$(ui.panel).html($(panelSelector, ui.panel).html());
panelFilter();
},
fx: {
opacity: 'toggle',
duration: 'fast'}
})
.css('display', 'block');
$(navSelector + ' a').click(function(event) {
tabulation = true;
$.address.value(navFilter(event.target));
tabulation = false;
return false;
});
}).change(function(event) {
var current = $('a[href=#' + event.value + ']:first');
$.address.title($.address.title().split(' - ')[0] + ' - ' + current.text());
if (!tabulation) {
tabs.tabs('select', current.attr('href'));
}
}).history(true);
document.write('<style type="text/css"> #tabs { display: none; } </style>');
</script>

dojo.connect / dojo.hitch scope problem?

I have a programmer class that populates a ul with project names and checkboxes - when a checkbox is clicked a popup dialog is supposed to show with the programmers id and the project name. dojo.connect is supposed to setup onclick for each li but the project (i) defaults to the last value (windows). Any ideas why this is happening?
...
projects: {"redial", "cms", "android", "windows"},
name: "Chris",
id: "2",
constructor: function(programmer) {
this.name = programmer.name;
this.id = programmer.id;
this.projects = programmer.projects;
},
update: function(theid, project) {
alert(theid + ", " + project);
},
postCreate: function() {
this.render();
// add in the name of the programmer
this.programmerName.innerHTML = this.name;
for(var i in this.projects) {
node = document.createElement("li");
this.programmerProjects.appendChild(node);
innerNode = document.createElement("label");
innerNode.setAttribute("for", this.id + "_" + i);
innerNode.innerHTML = i;
node.appendChild(innerNode);
tickNode = document.createElement("input");
tickNode.setAttribute("type", "checkbox");
tickNode.setAttribute("id", this.id + "_" + i);
if(this.projects[i] == 1) {
tickNode.setAttribute("checked", "checked");
}
dojo.connect(tickNode, 'onclick', dojo.hitch(this, function() {
this.update(this.id, i)
}));
node.appendChild(tickNode);
}
},
Just found out that extra parameters can be attached to the hitch:
dojo.connect(tickNode, 'onclick', dojo.hitch(this, function() {
this.update(this.id, i)
}));
should be:
dojo.connect(tickNode, 'onclick', dojo.hitch(this, "update", this.id, i));
Why are you calling this.render()? Is that your function or the widget base (i.e. already in the lifecycle)? For good measure make sure to call this.inherited(arguments); in postCreate.
My guess would be that tickNode is not in the DOM yet for the connect to work. Try appending the checkbox before you setup the connect. The last one is being fired because it is being held on by reference. You can try something like this instead:
for(var i = 0; i < this.projects.length; i++) {
var p = this.projects[i];
node = document.createElement("li");
this.programmerProjects.appendChild(node);
innerNode = document.createElement("label");
innerNode.setAttribute("for", this.id + "_" + p);
innerNode.innerHTML = p;
node.appendChild(innerNode);
tickNode = document.createElement("input");
tickNode.setAttribute("type", "checkbox");
tickNode.setAttribute("id", this.id + "_" + p);
if(i == 0) { //first item checked?
tickNode.setAttribute("checked", "checked");
}
node.appendChild(tickNode);
dojo.connect(tickNode, 'onclick', function(e) {
dojo.stopEvent(e);
this.update(this.id, p);
});
}
I would consider looking into dojo.create as well instead of createElement as well. Good luck!
Alternatively, and I think it's cleaner, you can pass the context into dojo.connect as the third parameter:
dojo.connect(tickNode, 'onclick', this, function() {
this.update(this.id, i);
});