I have two content Scripts in main.js of Firefox Addon :
contentScript A is inside 'panel' module (module A)
contentScript B is inside 'page-mod' module (module B)
How can they communicate or exchange messages ?
I tried to do this by using the following steps : 1. sending message from contentScript A to AddonScript A 2. sending message from AddonScript A to AddonScript B by including module B in A 3. sending message from AddonScript B to contentScript B.
However , it doesn't work (rather it does work intermittently , may be due to some errors in code).
.
Is this method ok ?
Can any one please comment on any better method ?
.
Thanx
Due to how the SDK's security model, any communication between your panel and your page-mod need to be routed through the main add-on code itself. Here is an example that takes data from a form implemented in a Panel and sends it through the main script into a page-mod:
https://builder.addons.mozilla.org/addon/1035008/latest/
The key piece of code is this one:
var pagemod = require("page-mod").PageMod({
include: [target],
contentScriptFile: [data.url('jquery-1.7.1.min.js'), data.url('page-mod.js')],
onAttach: function(worker) {
// console.log('attached...');
// when we get a panel-message event from the panel
panel.port.on('panel-message', function(data) {
// we emit the same message through to the page-mod
worker.port.emit('panel-message', data);
});
}
});
You'll notice that, when the page-mod is attached, I set up the panel instance to catch the 'panel-message' event and then emit it directly into the current page-mod worker.
Related
I am having problems with the event handler in my office addin . Below is an example code i got from microsoft website to explain what i mean.
I have a manifest file that uses the on-send hook as well as a click-based event triggering.
My button calls appendMessageBodyOnClick and onsend i call appendMessageBodyOnSend. Both function primarily do the same thing. I never want to block sending emails regardless.
The problem is that the event object is not properly cleaned up i think.
Scenario 1
When i click my button ; which calls event.completed(), and then after i try to send the message, it says my app is blocking the message, but then when i try to send again it goes through.
Scenario 2
When i leave the subject empty and then send the message, as expected i am prompted that the subject is empty. If i cancel sending the message on this note and then click on my button, the message tries to send as though i clicked send.
I am supposing the is some sort or state clean up issue. What am i doing wrong here?
Function-File.js
function appendMessageBodyOnClick(event) {
// Append string to message body
event.completed();
}
// In the following example, the checkMessage function has
// been registered as an event handler for ItemSend.
function appendMessageBodyOnSend(event) {
// Append string to message body
event.completed({allowEvent = true});
}
Not sure if this will help, but I also have faced some seemingly inconsistent behavior while understanding how to signal that event is fully completed. Once I got my edge cases fixed, then it worked.
One suggestion: Appending string to message body should be an async function. Call the event.completed() from inside the callback function. (i.e: make sure when you are calling event.completed(), nothing else is pending -like another async result)
Something like the following:
Office.context.mailbox.item.body.setAsync("new body", function(asyncResult) {
// handle success and failure
event.completed()
});
Same would be for your scenario 2, make sure event.completed() is called at the very end.
I am making module for SocialEngine 4.8.9. Basically I am buildin chat module and I want to sync SocialEngine message with my chat box. So I need an event that is called after sending message so that I can insert into my table.
Or is there any event that is called after inserting values into database.
SocialEngine has many hooks and you can attach your operations to these hooks. One of these hooks is onItemCreateAfter. This event will be called when a model item is created in the database.
If you check the Messages module's manifest file you'll see the messages module have 2 model items named messages_message and messages_conversation so you can use the onItemCreateAfter hook to attach your operations when any of these 2 items are created.
For this example let's say you have created a module via SocialEngine's SDK and your module name is mymodule. You can begin using the hook in 2 steps:
Attaching your operations to the onItemCreateAfter hook in your module's manifest file. You can check manifest files from other modules to get an idea how you should write the following code in the manifest array.
File : application/modules/Mymodule/settings/manifest.php
'hooks' => array(
array(
'event' => 'onItemCreateAfter',
'resource' => 'Mymodule_Plugin_Core',
),
),
Create the plugin file that will be called by the hook. in the following code $payload object will contains the message item.
File : application/modules/Mymodule/Plugin/Core.php
class Mymodule_Plugin_Core
{
public function onItemCreateAfter($event)
{
$payload = $event->getPayload();
if( $payload instanceof Core_Model_Item_Abstract ) {
//Your code here
}
}
}
There is no default hook for composing message.You can create new custom hook for the messages and can call that hook when everytime message is send.
Example:http://social-engine-tutorials.blogspot.in/2012/03/social-engine-4-hook-example.html
I have a ServiceWorker registered on my page and want to pass some data to it so it can be stored in an IndexedDB and used later for network requests (it's an access token).
Is the correct thing just to use network requests and catch them on the SW side using fetch, or is there something more clever?
Note for future readers wondering similar things to me:
Setting properties on the SW registration object, e.g. setting self.registration.foo to a function within the service worker and doing the following in the page:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
Results in TypeError: reg.foo is not a function. I presume this is something to do with the lifecycle of a ServiceWorker meaning you can't modify it and expect those modification to be accessible in the future, so any interface with a SW likely has to be postMessage style, so perhaps just using fetch is the best way to go...?
So it turns out that you can't actually call a method within a SW from your app (due to lifecycle issues), so you have to use a postMessage API to pass serialized JSON messages around (so no passing callbacks etc).
You can send a message to the controlling SW with the following app code:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
Combined with the following in the SW code:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
Which results in the following in my SW's console:
postMessage received Object {hello: "world"}
So by passing in a message (JS object) which indicates the function and arguments I want to call my event listener can receive it and call the right function in the SW. To return a result to the app code you will need to also pass a port of a MessageChannel in to the SW and then respond via postMessage, for example in the app you'd create and send over a MessageChannel with the data:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(event.data);
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
and then you can respond via it in your Service Worker within the message handler:
evt.ports[0].postMessage({'hello': 'world'});
To pass data to your service worker, the above mentioned is a good way. But in case, if someone is still having a hard time implementing that, there is an other hack around for that,
1 - append your data to get parameter while you load service-worker (for eg., from sw.js -> sw.js?a=x&b=y&c=z)
2- Now in service worker, fetch those data using self.self.location.search.
Note, this will be beneficial only if the data you pass do not change for a particular client very often, other wise it will keep changing the loading url of service worker for that particular client and every time the client reloads or revisits, new service worker is installed.
I used the browser module (https://github.com/shinout/browser) to test form submission in node.js and it was successful by running the following code:
var $b = new browser();
$b.submit({
from : 'https://accounts.google.com/Login',
selector: "#gaia_loginform",
data : {
Email : "XXXXXX#gmail.com",
Passwd : "XXXXXXXX"
}
});
// authenticated access
$b.browse('https://mail.google.com/mail/u/0/?ui=html&zy=d')
.after(); // browse after previously registered function
$b.on("end", function(err, out) {
console.log(out.url, out.result, out.responseHeaders);
});
$b.run();
But when I add additional code after $b.run()
$b.browse('https://mail.google.com').after();
$b.run();
I got the following error:
Junjo.register cannot be called when the template is frozen.
I don't know why. Any help would be appreciated.
From what I was able to read from sources, the browser module does not support running multiple jobs with single browser instance. Method $b.run() marks the object as frozen, which causes methods like browse to throw the error you are getting.
I'm using the MVVM Light Toolkit. I could not find any Ctor of Messenger or Notification class to send a empty message.
ViewModel1:
private int _selectedWeeklyRotation;
public int SelectedWeeklyRotation
{
get { return _selectedWeeklyRotation; }
set
{
if(_selectedWeeklyRotation == value)
return;
_selectedWeeklyRotation = value;
this.OnPropertyChanged("SelectedWeeklyRotation");
if(value > 1)
Messenger.Default.Send();
}
}
ViewModel2:
Ctor:
Messenger.Default.Register(this, CreateAnotherTimeTable);
private void CreateAnotherTimeTable()
{
}
I just need to send a Notification to another ViewModel, no sending of data at all.
Is that possible with MVVM Light Toolkit library?
Unless I'm misunderstanding something, couldn't you accomplish this by creating and sending a custom "signal message" type via the Messenger?
public class WeeklyRotationSignal {}
Messenger.Default.Send(new WeeklyRotationSignal());
Then register to that in another view model:
Messenger.Default.Register<WeeklyRotationSignal>(this, msg => doWork);
You can try sending a simple message with a string tag and receive that message by matching the string tag. Something like this:
Sender portion of the code located possibly in something like ViewModel1.cs
Messenger.Default.Send<string>("Dummy text message", "String_ToHelpMatchTheMsg");
Receiving end portion of the code responding to that message above, possibly located in some other file, something like ViewModel2.cs
...
Messenger.Default.Register<string>(this, "String_ToHelpMatchTheMsg", executeThisFunction);
private void executeThisFunction(string strMsg)
{
//your code would go here to run upon receiving the message
// The following line will display: "Dummy text message"
System.Windows.Browser.HtmlPage.Window.Alert("msg passed: " + strMsg);
}
Please note that you dont have to do anything with the text message that is passed around with the messaging code above. Just one part of the code sending some ping to another part of the code to ask some other section to execute some code. The important string is the one where I used "String_ToHelpMatchTheMsg" because that is the key used to match the sender and the receiver. Almost like creating your own quasi-event, once the Send method runs, the Register method is notified and fire its own function to run also.
I used this with a Close button on a Child Window to close it. The Close button on the View of the Child Window binds to a relay command on its childWindowViewModel. That relay command has the code above to send a message to the ParentViewModel. The Register portion on the ParentViewModel responds to that message by firing a method that closes the ChildWindow which was initially instantied from that parentViewModel.
Once you get more familiar with messaging, there are more attributes that you will be able to use so that the receiver can call back the sender to give a status or some data back. Look for Delegates and lambda function to achieve this.
All this to avoid placing code in the code behind to close the child window! :-)
Use as you see fit.
Cheers.
Mario
There really isn't a way to accomplish this and in someways defies the point of the messenger class. I didn't want to write a your doing it wrong post, but I feel I am stuck. The way the messenger class works is that you have two parties that both subscribe to the same concept, its an observer model. Without that similar concept or message there really isn't a way to tie the two objects together. The generic message whether a simple string or custom message act as the meeting point of the Subscribing and Publishing classes.
If the ViewModel publishing knows the type of ViewModel its trying to Send to it could...
Messenger.Default.Send<Type>(typeof(ViewModelToSendTo);
This would act as a very simple interaction point, you also wouldn't have to create a custom class. Some purist may have an issue with this approach as it couples the publishing class to the subscriber.
I don't think that it is possible and frankly I don't see the point of having that kind of message. You could just as well send a string "SelectedWeeklyRotation". It seems strange to have an empty message that has some kind of meaning as you increase the number of broadcast messages - and receivers in your application.
In the version of MVVM Light that I'm using it is not even possible to send an empty message.
However I did see a method in the ViewModelBase that is :
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
This might be of interest for you.