What is the alternative to `alert` in metro apps? - javascript

I created my first app on Windows 8 vs 2012 and it runs and works fine. But when I try to say "helloworld" from JavaScript like this:
alert("Hello World");
I get an error:
Unhandled exception at line 21,
column 13 in ms-appx://1af489cf-bac6-419b-8542-fdc18bdd2747/default.html
0x800a1391 - JavaScript runtime error: 'alert' is undefined
What is the alternative if alert is obsolete?

You should use Windows.UI.Popups.MessageDialog:
(new Windows.UI.Popups.MessageDialog("Content", "Title")).showAsync().done();
However, you should be aware that:
This is not blocking like the familiar alert
Because it's not blocking you may try to show them multiple messages boxes; this isn't allow.
I answered another question like this here. Here's the code to allow you to call alert, and have multiple messages in flight:
(function () {
var alertsToShow = [];
var dialogVisible = false;
function showPendingAlerts() {
if (dialogVisible || !alertsToShow.length) {
return;
}
dialogVisible = true;
(new Windows.UI.Popups.MessageDialog(alertsToShow.shift())).showAsync().done(function () {
dialogVisible = false;
showPendingAlerts();
})
}
window.alert = function (message) {
if (window.console && window.console.log) {
window.console.log(message);
}
alertsToShow.push(message);
showPendingAlerts();
}
})();

Remember that alert is not a JavaScript function, it's a browser (host) function, therefore, it's not available in non browser environments.
This link tells you to do the following
Replace all alert functions with firing an event window.external.notify("message");
Use scriptnotify event in webview to get that message.
Show metro own dialog: MessageDialog

javascript:
(function () {
window.alert = function (message) {
window.external.notify( message);
}
//do some test
alert("a");
alert("b");
alert("c");
window.setInterval(function () {
alert("e");
alert("f");
}, 5000);
window.setInterval(function () {
alert("d");
alert("2");
}, 10000);
})();
C#:
//register ScriptNotify event
webView2.ScriptNotify += webView2_ScriptNotify;
async void webView2_ScriptNotify(object sender, NotifyEventArgs e)
{
MSG.Alert(e.Value);
}
public class MSG
{
static List<string> messages = new List<string>();
public static void Alert(string message)
{
messages.Add(message);
if (messages.Count == 1)
{
Show(messages.First());
}
}
private static async Task Show(string message)
{
MessageDialog md = new MessageDialog(message, "Title");
md.Commands.Add(
new UICommand("OK", new UICommandInvokedHandler((cmd) =>
{
messages.RemoveAt(0);
})));
await md.ShowAsync();
while (messages.Count > 0)
{
await Show(messages.First());
}
}
}

Related

Long operations crash Office addin (JS)

I just created a (JS) Word Add-in and found that long synchronous operations can make it crash. In these cases, the following error is displayed - [ADD-IN ERROR Sorry, we had to restart because this add-in wasn't responding.]
The following code is ran on a button click.
function scanText() {
Word.run(function (context) {
var body = context.document.body;
context.load(body, 'text');
return context.sync().then(function () {
var r = thisOperationCanTakeALongTimeIfDocIsLarge(body.text);
});
})
.catch(errorHandler);
}
How do I prevent this from happening? should I make the long operation asynchronous? How is this achieved in this context?
I have finally found a good way to solve this... I use a WebWorker like so:
function scanText() {
var w;
if (typeof (w) == "undefined") {
w = new Worker("./Scripts/myWebWorker.js");
}
else
{
showNotification("Sorry! No Web Worker support.");
}
w.onmessage = function (event) {
showNotification(event.data);
};
Word.run(function (context) {
var body = context.document.body;
context.load(body, 'text');
return context.sync().then(function () {
w.postMessage(body.text);
});
})
.catch(errorHandler);
}
And the myWebWorker.js file:
self.importScripts([...some scripts i need...]);
self.addEventListener("message", function (e) {
var r = thisOperationCanTakeALongTimeIfDocIsLarge(e.data);
postMessage(r);
}, false);

Is it possible to return the result of a JS confirmation dialog presented by JXBrowser back to the JS section that called it?

I'm using JavaFX/JXBrowser to show an alert/dialog when the web page loaded into the Browser calls on Window.alert or window.confirm. However, I can't figure out how to return the result of the confirmation dialog (true/false) to JS. Since alert.showAndWait() is a blocking function, JS should wait for this result. However, showAndWait is also called in a Platform.runLater runnable, so I can't return the result. Short of writing JS functions to do the true/false code and calling those based on the result of showAndWait, is there any other option?
browser.setDialogHandler(new DialogHandler() {
#Override
public CloseStatus onConfirmation(DialogParams params) {
Platform.runLater(new Runnable() {
#Override
public void run() {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Yes/No");
alert.setHeaderText(null);
alert.setContentText("Yes/No");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent())
{
if(result.get()==ButtonType.YES)
{
//Send true to calling JS function
}else
{
//Send false to calling JS function
}
}else
{
System.out.println("No result!");
}
}
});
return null; //because I need to return something and I can't figure out how to get values from the runnable
}
...
}
You can use the following approach:
#Override
public CloseStatus onConfirmation(DialogParams params) {
final AtomicReference<CloseStatus> status = new AtomicReference<CloseStatus>();
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Yes/No");
alert.setHeaderText(null);
alert.setContentText("Yes/No");
Optional<ButtonType> result = alert.showAndWait();
if (result.isPresent()) {
if (result.get() == ButtonType.YES) {
status.set(CloseStatus.OK);
} else {
status.set(CloseStatus.CANCEL);
}
} else {
System.out.println("No result!");
}
}
});
try {
latch.await();
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
return status.get();
}

Protractor - StaleElementReferenceException occurs sporadically

I've stuck with problem with Stale Element Reference Exception using protractor/jasmine2.
My spec:
var LoginPage = require('../pages/login_page.js');
var WelcomePage = require('../pages/welcome_page.js');
describe('Test -> testing something', function () {
var loginPage;
var EC = protractor.ExpectedConditions;
var waitTimeout = 10000;
function logIn() {
loginPage.setUser('user');
loginPage.setPassword('password');
loginPage.login();
}
beforeEach(function () {
browser.ignoreSynchronization = true;
loginPage = new LoginPage();
browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout);
logIn();
var welcomePage = new WelcomePage();
browser.wait(EC.visibilityOf(welcomePage.usersButton), waitTimeout);
welcomePage.usersButton.click();
});
The problem is that StaleElementReferenceException occurs randomly on the last line of beforeEach function when I want to click on the usersButton.
No idea why ExpectedCondition do not work (have tried as well different EC like presenceOf, elementToBeClickable etc. but none solved problem).
See page with usersButton defined for reference:
'use strict';
var WelcomePage = function () {
};
WelcomePage.prototype = Object.create({}, {
usersButton: {
get: function () {
return element(by.css('#users a'));
}
}
});
module.exports = WelcomePage;
I think that some generic retry_mechanism would be needed to handle it, Anyone has similiar issue ?
Finally written function like that
var clickOn = function (element) {
browser.wait(EC.visibilityOf(element), waitTimeout).then(function() {
element.click();
});}
which is invoked like this:
clickOn(welcomePage.usersButton);
Update:
Have tested it several times and when I am running tests on selenium grid I am still getting Stale Element exception on this exact element. So provided solution did not work ...
Failed: stale element reference: element is not attached to the page document (Session info: chrome=45.0.2454.93) (Driver info: chromedriver=2.19.346078 (6f1f0cde889532d48ce8242342d0b84f94b114a1),platform=Windows NT 6.1 SP1 x86_64) (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 15 milliseconds For documentation on this error, please visit: http://seleniumhq.org/exceptions/stale_element_reference.html Build info: version: '2.47.1', revision: '411b314', time: '2015-07-30 03:03:16' System info: host: 'ITHFPC17', ip: '10.98.0.48', os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.8.0_40' Driver info: org.openqa.selenium.chrome.ChromeDriver Capabilities [{applicationCacheEnabled=false, rotatable=false, mobileEmulationEnabled=false, chrome={userDataDir=C:\Users\SELENI~1\AppData\Local\Temp\scoped_dir2384_11396}, takesHeapSnapshot=true, databaseEnabled=false, handlesAlerts=true, hasTouchScreen=false, version=45.0.2454.93, platform=XP, browserConnectionEnabled=false, nativeEvents=true, acceptSslCerts=true, locationContextEnabled=true, webStorageEnabled=true, browserName=chrome, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}] Session ID: 3244710644015ee170986333564ab806
Failed: Wait timed out after 10032ms
The next approach is to wait until element is present, afterwards if it's visible and afterwards if it's clickable... but it doesn't work as well. The strange thing is that on selenium grid everything works fine but when I am trying to run test locally then getting previously mentioned exception.
exports.clickOn = function (element) {
browser.wait(EC.presenceOf(element), waitTimeout).then(function () {
browser.wait(EC.visibilityOf(element), waitTimeout)
}).then(function () {
browser.wait(EC.elementToBeClickable(element), waitTimeout)
}).then(function () {
element.click();
});
};
Anyone has any idea how to deal with it ? ... I am stuck.
Wait until the element is eligible to be clicked on by resolving the promise that the wait until elementToBeClickable() function returns. Also make sure that your actions before click() are completed, so that protractor can find the element as intended. Probably chaining all the actions to one another can be a good solution. That way the StaleElementReferenceException error can be avoided. Here's how -
browser.wait(EC.presenceOf(loginPage.userLogin), waitTimeout).then(function(){
logIn();
}).then(function(){
var welcomePage = new WelcomePage();
}).then(function(){
browser.wait(EC.elementToBeClickable(welcomePage.usersButton), waitTimeout).then(function(){
welcomePage.usersButton.click();
});
});
Hope it helps.
Finally I've managed this problem by adding 'not nice' simple retrying mechanism.
exports.clickOnElementWithWait = function (element, attempts) {
if (attempts == null) {
attempts = 10;
}
return element.click().then(function (found) {
}, function (err) {
if (attempts > 0) {
browser.sleep(100);
return exports.clickOnElementWithWait(element, attempts - 1);
} else {
throw err;
}
});
};
Update: Unfortunately it works as well randomly. The number of exceptions decreased but still ...
I have Java code which helped me when I've experienced it in pure selenium/junit and wondering if it's any free tool to convert it to javascript ?
Anyone could help me ?
public class RetryMechanism {
private static final int DEFAULT_RETRY_NR = 20;
private static final long DEFAULT_WAIT_TIME_IN_MILLI = 1000;
private int numberOfRetries;
private int numberOfTriesLeft;
private static long timeToWait;
public RetryMechanism() {
this(DEFAULT_RETRY_NR, DEFAULT_WAIT_TIME_IN_MILLI);
}
public RetryMechanism(int numberOfRetries, long timeToWait) {
this.numberOfRetries = numberOfRetries;
numberOfTriesLeft = numberOfRetries;
this.timeToWait = timeToWait;
}
public boolean shouldRetry() {
return numberOfTriesLeft > 0;
}
public void errorOccurred(Throwable throwable) throws Exception {
numberOfTriesLeft--;
if (!shouldRetry()) {
throw new Exception("Retry Failed: Total " + numberOfRetries
+ " attempts made at interval " + getTimeToWait()
+ "ms.\n"
+ "Error message is : " + throwable.getMessage()
+ "\n"
+ "Caused by : " + throwable.getCause());
}
waitUntilNextTry();
}
public static long getTimeToWait() {
return timeToWait;
}
public static void waitUntilNextTry() {
try {
Thread.sleep(getTimeToWait());
} catch (InterruptedException ignored) {
}
}
public interface Action {
void doJob();
}
public static void retry(Action action) throws Exception {
RetryMechanism retry = new RetryMechanism();
while (retry.shouldRetry()) try {
action.doJob();
break;
} catch (Exception e) {
retry.errorOccurred(e);
}
}
}

The only option is to include that block of code into each of my functions?

Several of my functions require the UniversalXPConnect privilege to be enabled.
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
So, my functions look like this:
function oneOfMyFunctions() {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// ...
}
Actually, I also try to catch the exception when the privilege is denied. Looks as follows:
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
// ...
} catch (e) {
// ...
}
I'd rather to make that a separate function and call it from within my functions as follows:
function oneOfMyFunctions() {
if (enablePrivilege()) {
// ...
} else {
// ...
}
}
Given that the enablePrivilege function would be as follows:
function enablePrivilege() {
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
} catch (e) {
return false;
}
return true;
}
But, for security reasons, that is impossible as the privilege is granted only in the scope of the requesting function.
So, the only option is to include that block of code into each of my functions?
UPDATE:
As I am going to also try to catch some other exceptions I've ended up with the following design:
function readFile(path, start, length) {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var file = Components.classes['#mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(path);
var istream = Components.classes['#mozilla.org/network/file-input-stream;1'].createInstance(Components.interfaces.nsIFileInputStream);
istream.init(file, -1, -1, false);
istream.QueryInterface(Components.interfaces.nsISeekableStream);
istream.seek(0, start);
var bstream = Components.classes['#mozilla.org/binaryinputstream;1'].createInstance(Components.interfaces.nsIBinaryInputStream);
bstream.setInputStream(istream);
return bstream.readBytes(length);
}
var filepath = 'C:\\test.txt', start = 440, length = 5;
try {
console.log(readFile(filepath, start, length));
} catch (e) {
if (e.name == 'Error') console.log('The privilege to read the file is not granted.');
else console.log('An error happened trying to read the file.');
}
You could make enablePrivilege a sort of wrapper function that accepts a function as a parameter that it then calls inside itself, like so
function enablePrivilege(funcParam) {
//enable privileges, in try-catch
funcParam();
}
so that when you call it like so
enablePrivilege(oneOfMyFunctions);
the function that needs the privileges should have them since it is called inside the scope of enablePrivilege.

memory leak in ajax - setInterval

I have an ajax code which causes memory leak (especially in IE).
function setStatus() {
var formInput=$(this).serialize();
$.getJSON('CheckStatus.action', formInput, function(data) {
if(data == false) {
function getEventsPeriodicaly() {
getEvents();
};
var timer = setInterval(function () {getEventsPeriodicaly();}, 5000);
}
}
);
}
function getEvents() {
var formInput=$(this).serialize();
$.getJSON('StartEP.action', formInput,function(data) {
var txt = $("#txtEventsArea");
if(data != null && data.toString().length!=0) {
txt.val(data.join('\n') + '\n' + txt.val());
data=null;
}
}
)}
StartEP
public String startEP() throws Exception {
logger.info("[EP] In startEP");
try {
synchronized(status) {
if(!getStatus()) {
EventProcessor amiep = EventProcessor.getInstance();
amiep.addObserver(this);
new Thread(amiep).start();
setStatus(true);
}
}
} catch (Exception ex) {
logger.error("Unable to start EP", ex);
return ERROR;
}
logger.info("[EP] In startEP, before loop");
while(!gotNewData) {
Thread.sleep(4000);
}
gotNewData = false;
logger.info("[EP] Out startEP");
return SUCCESS;
}
The StartEP action returns messages (about 5KB on each request). First I thought it concerned with setting text to textarea, but after some tests got that it is not the reason. Could it be setInterval method?
Is there any considerations?
thanks
I would say this looks pretty suspect:
while(!gotNewData) {
Thread.sleep(4000);
}
Where is gotNewData set? If you call the web service once and set gotNewData to true and then call another web service and set gotNewData to false I don't think there is a guarantee that you're setting the variable within the same instance of the application. Therefore, if you are not, then every time you're hitting the web service you are starting a new thread and then continually putting it back to sleep.

Categories