I am creating a javascript xpcom component Its source is as follows-
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
function callback() { }
callback.prototype = {
classDescription: "My Hello World Javascript XPCOM Component",
classID: Components.ID("{3459D788-D284-4ef0-8AFF-96CBAF51BD35}"),
contractID: "#jscallback.p2psearch.com/f2f;1",
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.ICallback]),
received:function(data){
alert("Received: " +data);
},
status:function(data){
alert("Status: "+data);
},
expr:function(data){
alert("Expr: "+expr);
}
};
var components = [callback];
function NSGetModule(compMgr, fileSpec) {
return XPCOMUtils.generateModule(components);
}
When I call it using:
try {
const p2pjcid = "#jscallback.p2psearch.com/f2f;1";
var jobj = Components.classes[p2pjcid].createInstance();
jobj = jobj.QueryInterface(Components.interfaces.ICallback);
jobj.received("Hello from javascript")
}
catch (err) {
alert(err);
return;
}
I get Error as :
[Exception... "'[JavaScript Error: "alert is not defined" {file: "file:///C:/Documents%20and%20Settings/mypc/Application%20Data/Mozilla/Firefox/Profiles/ngi5btaf.default/extensions/spsarolkar#gmail/components/callback.js" line: 11}]' when calling method: [ICallback::received]" nsresult: "0x80570021 (NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS)" location: "JS frame :: chrome://sample/content/clock.js :: initClock :: line 28" data: yes]
That's because alert is not defined in XPCOM code (though you can get the component). It's not a good idea to alert in an extension as it blocks the user from interacting with the page(s) they are on. Use the non-modal toaster-box notification function:
const alert = Components.classes['#mozilla.org/alerts-service;1']
.getService(Components.interfaces.nsIAlertsService)
.showAlertNotification;
Use it in the following syntax: alert(icon, title, body).
Here's more info on MDC.
You can also use dump() from a JavaScript component.
Related
I am very new to Jasmine. I am intending to use it for with vanilla javascript project. The initial configuration was a breeze but I am receiving object not defined error while using spyOn.
I have downloaded the version 3.4.0 Jasmine Release Page and added the files 'as is' to my project. I then have changed jasmine.json file accordingly and see the all the example tests passing. However when try spyOn on a private object, I am getting undefined error,
if (typeof (DCA) == 'undefined') {
DCA = {
__namespace: true
};
}
DCA.Audit = {
//this function needs to be tested
callAuditLogAction: function (parameters) {
//Get an error saying D365 is not defined
D365.API.ExecuteAction("bu_AuditReadAccess", parameters,
function (result) { },
function (error) {
if (error != undefined && error.message != undefined) {
D365.Utility.alertDialog('An error occurred while trying to execute the Action. The response from server is:\n' + error.message);
}
}
);
}
}
and my spec class
describe('Audit', function(){
var audit;
beforeEach(function(){
audit = DCA.Audit;
})
describe('When calling Audit log function', function(){
beforeEach(function(){
})
it('Should call Execute Action', function(){
var D365 = {
API : {
ExecuteAction : function(){
console.log('called');
}
}
}
// expectation is console log with say hello
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
})
})
As you can see my spec class does not know about actual D365 object. I was hoping to stub the D365 object without having to inject it. Do I need to stub out whole 365 library and link it to my test runner html?
I got it working after some pondering. So the library containing D365 should still need to be added to my test runner html file. after that I can fake the method call like below,
it('Should call Execute Action', function(){
spyOn(D365.API, 'ExecuteAction').and.callFake(() => console.log('hello'));
var params = audit.constructActionParameters("logicalName", "someId", 'someId');
audit.callAuditLogAction(params);
})
it is now working.
WKWebView not able to trigger javascript in the loaded Web Page.
Scenario:
If user click image in Website, it should get update.
Using javascript to update the image on the website, if the user clicks a image.
included .js file in project
configured WKWebview
Enabled JavaScript
Added Script in WKWebview
Function in JS file like :
function captureImage(bucket,fileName){
window.webkit.messageHandlers.captureImage.postMessage("showCamera")
}
Accessing this function in Swift like:
webViewPWA.configuration.userContentController.add(self, name: "captureImage")
///This function handles the event generated by javascript
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Webview Message received: \(message.name) with body: \(message.body)")
if (message.name == "captureImage"){
print("\(message.body)")
let body = message.body
if let action:String = body as? String {
switch action {
case "showCamera":
print("camera image triggering, capture image for JS")
//take necessary action
break
default:
break
}
}
}
return
}
Thanks in advance!
Once the picture is captured on the device in UIImagePickerControllerDelegate method like:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
imagePicker.dismiss(animated: true, completion: nil)
imageView.image = info[.originalImage] as? UIImage
}
You can run any JS you want in a WKWebView by using evaluateJavaScript() and get a result in Swift.
webView.evaluateJavaScript("document.getElementById('someElement').innerText") { (response, error) in
guard error == nil else {
print("evaluateJavaScript error -- \(String(describing: error))")
return
}
print("evaluateJavaScript response -- \(String(describing: response))")
}
it would also be nice to have something similar to WebBridge.js that provides functions for communicating with the build ing WKWebView in iOS and he android webview
and inside of the WebBridge.js you can define:
/* install global handler for WebView to call methods */
if (!window.WebBridge) {
window.WebBridge = (function () {
var actions = []
return {
receive: function (actionName, json) {
if (typeof actions[actionName] !== 'undefined') {
actions[actionName](json)
}
},
registerActionHandler: function (actionName, method) {
actions[actionName] = method
}
}
})()
}
then from Swift file you can narrow down the structure of your JS calls:
self.webView.evaluateJavaScript("WebBridge.receive('yourCustomActionName', '{\"yourRey\": \"yourValue\"}')") { (response, error) in
guard error == nil else {
print("evaluateJavaScript error -- \(String(describing: error))")
return
}
print("evaluateJavaScript response -- \(String(describing: response))")
}
So this is the (snipped) code for a chatbot. I want to override the sendMessage() function to just echo the message argument. In this case, the original function runs and gives an error at the 2nd line of the function. Obviously, modules aren't loaded and I don't need them to. This is a test for the eventHandler to echo the right messages. Ideas?
var modules = require('./modules');
console.log('[tose] Loading modules: ', Object.keys(modules));
function eventHandler(channel, type, data, react=()=>{}) {
switch (type) {
case 'new_message':
console.log('[tose][new_message]', channel, 'from:', data.cid, 'message:', data.message);
if (regexTemplates.testSearch.test(data.message.toLowerCase())) {
...
} else {
sendMessage(channel, data.cid, data.message); // Basic echo message
}
break;
}
}
// The function to be stubbed
function sendMessage(channel, cid, message) {
console.log('[tose][send_message]', channel, 'to:', cid, 'message:', message);
coms[channel].sendMessage(cid, message); // Getting error here thus not really stubbed
}
exports.eventHandler = eventHandler;
exports.sendMessage = sendMessage
And the test:
describe('Tose core', function() {
describe('Process messages', function() {
before(function() {
var stub = sinon.stub(tose, 'sendMessage').callsFake(function(channel, cid, message) {
assert.equal(message, 'Test message');
return message
});
});
after(function() {
tose.sendMessage.restore();
});
it('should echo messages', function() {
var data = {message: 'Test message'}
tose.eventHandler('test', 'new_message', data)
assert(tose.sendMessage.calledOnce);
});
});
});
The problem here is that when you use Sinon to stub an object's function, you're stubbing that (and only that) object's function.
Your code (the first code block) is using the local definition of the sendMessage function.
When you stub the tose object (in the second code block), you are changing the sendMessage function thats on the tose object and not the local definition of the function.
There are many different ways you could approach this, one of which is:
var modules = require('./modules');
var functions = {
eventHandler: eventHandler,
sendMessage: sendMessage,
};
console.log('[tose] Loading modules: ', Object.keys(modules));
function eventHandler(channel, type, data, react=()=>{}) {
switch (type) {
case 'new_message':
console.log('[tose][new_message]', channel, 'from:', data.cid, 'message:', data.message);
if (regexTemplates.testSearch.test(data.message.toLowerCase())) {
...
} else {
functions.sendMessage(channel, data.cid, data.message); // Basic echo message
}
break;
}
}
// The function to be stubbed
function sendMessage(channel, cid, message) {
console.log('[tose][send_message]', channel, 'to:', cid, 'message:', message);
coms[channel].sendMessage(cid, message); // Getting error here thus not really stubbed
}
module.exports = functions;
Note: functions is not a descriptive name - feel free to change it to something that is more meaningful.
I've just started using bluebird promises and am getting a confusing error
Code Abstract
var
jQueryPostJSON = function jQueryPostJSON(url, data) {
return Promise.resolve(
jQuery.ajax({
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST",
url: url,
data: JSON.stringify(data)
})
).then(function(responseData) {
console.log("jQueryPostJSON response " + JSON.stringify(responseData, null, 2));
return responseData;
});
},
completeTask = function completeTask(task, variables) {
console.log("completeTask called for taskId: "+task.id);
//FIXME reform variables according to REST API docs
var variables = {
"action" : "complete",
"variables" : []
};
spin.start();
return jQueryPostJSON(hostUrl + 'service/runtime/tasks/'+task.id, variables)
.then(function() {
gwl.grrr({
msg: "Completed Task. Definition Key: " + task.taskDefinitionKey,
type: "success",
displaySec: 3
});
spin.stop();
return null;
});
}
The jQueryPostJSON function seems to work fine as is when used else where, but in that case there is data returned from the server.
When it's used within complete task, the POST is successful as can be seen on the server side, but the then function is never called instead in the console I get the error
completeTask called for taskId: 102552
bundle.js:20945 spin target: [object HTMLDivElement]
bundle.js:20968 spinner started
bundle.js:1403 Warning: a promise was created in a handler but was not returned from it
at jQueryPostJSON (http://localhost:9000/dist/bundle.js:20648:22)
at Object.completeTask (http://localhost:9000/dist/bundle.js:20743:14)
at http://localhost:9000/dist/bundle.js:21051:15
From previous event:
at HTMLDocument.<anonymous> (http://localhost:9000/dist/bundle.js:21050:10)
at HTMLDocument.handleObj.handler (http://localhost:9000/dist/bundle.js:5892:30)
at HTMLDocument.jQuery.event.dispatch (http://localhost:9000/dist/bundle.js:10341:9)
at HTMLDocument.elemData.handle (http://localhost:9000/dist/bundle.js:10027:28)
bundle.js:1403 Unhandled rejection (<{"readyState":4,"responseText":"","sta...>, no stack trace)
The warning I get the reason for, that's not the issue.
It's the Unhandled rejection and the fact that there was in fact no error from the POST.
line 21050 is here I am testing the combination of these to functions from separate modules
jQuery(document).bind('keydown', 'ctrl+]', function() {
console.log("test key pressed");
api.getCurrentProcessInstanceTask()
.then(function(task) {
api.completeTask(task);
});
});
Output from the first function call api.getCurrentProcessInstanceTask() seems to indicate it is working correctly, but here it is anyway
getCurrentProcessInstanceTask = function getCurrentProcessInstanceTask() {
if (!currentProcess || !currentProcess.id) {
return Promise.reject(new Error("no currentProcess is set, cannot get active task"));
}
var processInstanceId = currentProcess.id;
return Promise.resolve(jQuery.get(hostUrl + "service/runtime/tasks", {
processInstanceId: processInstanceId
}))
.then(function(data) {
console.log("response: " + JSON.stringify(data, null, 2));
currentProcess.tasks = data.data;
// if(data.data.length > 1){
// throw new Error("getCurrentProcessInstanceTask expects single task result. Result listed "+data.data.length+" tasks!");
// }
console.log("returning task id: "+data.data[0].id);
return data.data[0];
});
},
You're getting the warning because you are - as it says - not returning the promise from the then handler.
Where the rejection is coming from would best be tracked by catching it and logging it. That there is no stack trace suggests that you (or one of the libs you use) is throwing a plain object that is not an Error. Try finding and fixing that.
Your call should look like this:
api.getCurrentProcessInstanceTask().then(function(task) {
return api.completeTask(task);
// ^^^^^^
}).catch(function(err) {
// ^^^^^
console.error(err);
});
I want to pass string value from c# to JavaScript using JSON. So I created an example plugin name: Echo.cs (in CordovaWP namespace), and an "echo" method in Echo class. Like this tutorial.
In index.js, I called:
cordova.exec(function (result)
{
alert("OK");
}, function (error) {
alert("KO");
}, "CordovaWP.Echo", "echo", "ok");
But I can't get debug in echo method. And have nothing found!
Use as below:
cordova.exec(function (result)
{
alert("OK");
}, function (error) {
alert("KO");
}, "CordovaWP.Echo", "echo", ["ok"]);
Parameters should always be sent as an array from JS to cs
Please can you also post your CS code:
Check sample below SMS example:
JS:
var sendSMS = function(phoneNumber,smsBody){
cordova.exec(function(){console.log("success SMS");},function(){console.log("Error SMS");},"SMS", "sendSMS", [phoneNumber,smsBody]);
};
CS:
namespace Cordova.Extension.Commands{
public class SMS : BaseCommand
{
public void sendSMS(string arg)
{
string recipient = JsonHelper.Deserialize<string[]>(arg)[0];
string smsBody = JsonHelper.Deserialize<string[]>(arg)[1];
SmsComposeTask composeSMS = new SmsComposeTask();
composeSMS.Body = smsBody;
composeSMS.To = recipient;
composeSMS.Show();
this.DispatchCommandResult();
}
}
}