Asynchronous command

Talk about add-ons and extension development.
Post Reply
rashmani
Posts: 10
Joined: August 21st, 2014, 2:15 am

Asynchronous command

Post by rashmani »

Hi there,

I'm trying to write a little of code for a custom button (using Custom Buttons ext.) that performs the following steps:
- enable quick filter for unread messages
- select all of them
- apply filters to selected messages
- disable quick filtering of unread messages
My script should wait for each step to be executed before executing next one.
To accomplish this, I've tried to use Promise, as explained here https://developer.mozilla.org/en-US/doc ... m/Examples

But this doesn't work, I think because I can't just turn something asynchronous into a promise... or maybe I do it wrong.
This is what I have:

Code: Select all

var promiseFilter = promiseApplyFiltersToSelection();

promiseFilter.then(
	function(success) {
	  	gFolderDisplay.clearSelection();
		alert(uneval(success));
	},
	function(failure) {
		alert("Something went wrong while applying filters: " + uneval(failure));
	}
);

function promiseApplyFiltersToSelection() {
  try {
	document.getElementById("qfb-unread").click(); // select all unread
	goDoCommand("cmd_applyFiltersToSelection"); // apply filters
    
    return Promise.resolve('Filters applied'); // this makes the success function trigger
  } catch(ex) {
    return Promise.reject(ex);
  }
}
This pops up the alert right away, then enable the unread filter but does not select anything...

Anyone can explain and/or point me in the right direction?

TIA,
rash*
rashmani
Posts: 10
Joined: August 21st, 2014, 2:15 am

Re: Asynchronous command

Post by rashmani »

Well,

some progress but still far from target. Of course I have a couple of error/missings in my code, that I've modified to this:

Code: Select all

var promiseFilter = promiseApplyFiltersToSelection();

promiseFilter.then(
	function(success) {
	  	gFolderDisplay.clearSelection();
		document.getElementById("qfb-unread").click(); // reset unread filter
		alert(uneval(success));
	},
	function(failure) {
		alert("Something went wrong while applying filters: " + uneval(failure));
	}
);

function promiseApplyFiltersToSelection() {
  try {
	document.getElementById("qfb-unread").click(); // filter unread
	goDoCommand("cmd_selectAll"); // select all
	goDoCommand("cmd_applyFiltersToSelection"); // apply filters
    
    return Promise.resolve('Filters applied'); // this makes the success function trigger
  } catch(ex) {
    return Promise.reject(ex);
  }
}
Nevertheless, this code doesn't work, almost: when I click my button, TB hangs processing all messages in current folder, not just unread ones. So for some reason filtering unread, then selecting all, then applying filters to selection do not happen in wanted time sequence (meanwhile I see no activity by TB, filters are applied though).
Should I wrap each step in a promise-returning function and chain those functions with .then()?
Or am I missing some deeper understanding here?

TIA,
rash*
morat
Posts: 6426
Joined: February 3rd, 2009, 6:29 pm

Re: Asynchronous command

Post by morat »

Try using the nsIMsgOperationListener callback.

Code: Select all

void applyFilters(in nsMsgFilterTypeType aFilterType,
                  in nsIArray aMsgHdrList,
                  in nsIMsgFolder aFolder,
                  in nsIMsgWindow aMsgWindow,
                  [optional] in nsIMsgOperationListener aCallback);

Code: Select all

var operationListener = {
  onStopOperation: function (aResult) {
    if (Components.isSuccessCode(aResult)) {
      Application.console.log("Apply filters succeeded.");
    } else {
      Application.console.log("Apply filters failed: " + aResult);
    }
  },
};
var folder = gFolderDisplay.displayedFolder;
var enumerator = folder.messages;
var mutableArray = Components.classes["@mozilla.org/array;1"].
  createInstance(Components.interfaces.nsIMutableArray);
while (enumerator.hasMoreElements()) {
  var msgHdr = enumerator.getNext().
    QueryInterface(Components.interfaces.nsIMsgDBHdr);
  if (!(msgHdr.flags & Components.interfaces.nsMsgMessageFlags.Read)) {
    mutableArray.appendElement(msgHdr, false /*weak*/);
  }
}
if (mutableArray.length) {
  var filterType = Components.interfaces.nsMsgFilterType.Manual;
  MailServices.filters.applyFilters(filterType, mutableArray,
    folder, msgWindow, operationListener);
} else {
  Application.console.log("No unread messages.");
}
http://dxr.mozilla.org/comm-release/sou ... ervice.idl
http://dxr.mozilla.org/comm-release/sou ... stener.idl
rashmani
Posts: 10
Joined: August 21st, 2014, 2:15 am

Re: Asynchronous command

Post by rashmani »

Woh! It works a treat, and it was galaxies beyond my TB's API knowledge.
Huge thanks, also for teaching me something new.

Kudos,
rash*
morat
Posts: 6426
Joined: February 3rd, 2009, 6:29 pm

Re: Asynchronous command

Post by morat »

You're welcome.
Post Reply