Bug 1499617 - Folder tab (3-pane) WebExtensions API; r=mkmelin
This commit is contained in:
Родитель
71005c0395
Коммит
d080e8cc4b
|
@ -50,6 +50,15 @@
|
|||
"scopes": ["addon_parent"],
|
||||
"manifest": ["legacy"]
|
||||
},
|
||||
"mailTabs": {
|
||||
"url": "chrome://messenger/content/parent/ext-mailTabs.js",
|
||||
"schema": "chrome://messenger/content/schemas/mailTabs.json",
|
||||
"scopes": ["addon_parent"],
|
||||
"manifest": ["mailTabs"],
|
||||
"paths": [
|
||||
["mailTabs"]
|
||||
]
|
||||
},
|
||||
"pkcs11": {
|
||||
"url": "chrome://messenger/content/parent/ext-pkcs11.js",
|
||||
"schema": "chrome://messenger/content/schemas/pkcs11.json",
|
||||
|
|
|
@ -16,6 +16,7 @@ messenger.jar:
|
|||
content/messenger/parent/ext-composeAction.js (parent/ext-composeAction.js)
|
||||
content/messenger/parent/ext-legacy.js (parent/ext-legacy.js)
|
||||
content/messenger/parent/ext-mail.js (parent/ext-mail.js)
|
||||
content/messenger/parent/ext-mailTabs.js (parent/ext-mailTabs.js)
|
||||
content/messenger/parent/ext-pkcs11.js (../../../../browser/components/extensions/parent/ext-pkcs11.js)
|
||||
content/messenger/parent/ext-tabs.js (parent/ext-tabs.js)
|
||||
content/messenger/parent/ext-windows.js (parent/ext-windows.js)
|
||||
|
@ -26,6 +27,7 @@ messenger.jar:
|
|||
content/messenger/schemas/commands.json (schemas/commands.json)
|
||||
content/messenger/schemas/composeAction.json (schemas/composeAction.json)
|
||||
content/messenger/schemas/legacy.json (schemas/legacy.json)
|
||||
content/messenger/schemas/mailTabs.json (schemas/mailTabs.json)
|
||||
content/messenger/schemas/pkcs11.json (../../../../browser/components/extensions/schemas/pkcs11.json)
|
||||
content/messenger/schemas/tabs.json (schemas/tabs.json)
|
||||
content/messenger/schemas/windows.json (schemas/windows.json)
|
||||
|
|
|
@ -37,6 +37,10 @@ module.exports = {
|
|||
"Tab": true,
|
||||
"Window": true,
|
||||
"WindowEventManager": true,
|
||||
"convertFolder": true,
|
||||
"convertMessage": true,
|
||||
"folderPathToURI": true,
|
||||
"folderURIToPath": true,
|
||||
"getTabBrowser": true,
|
||||
"makeWidgetId": true,
|
||||
"tabGetSender": true,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "MailServices", "resource:///modules/MailServices.jsm");
|
||||
|
||||
var {
|
||||
ExtensionError,
|
||||
} = ExtensionUtils;
|
||||
|
@ -504,9 +506,21 @@ Object.assign(global, { tabTracker, windowTracker });
|
|||
* Extension-specific wrapper around a Thunderbird tab.
|
||||
*/
|
||||
class Tab extends TabBase {
|
||||
/** Removes some useless properties from a tab object. */
|
||||
/** Returns true if this tab is a 3-pane tab. */
|
||||
get isMail3Pane() {
|
||||
return this.nativeTab.mode.type == "folder";
|
||||
}
|
||||
|
||||
/** Overrides the matches function to enable querying for 3-pane tabs. */
|
||||
matches(queryInfo, context) {
|
||||
let result = super.matches(queryInfo, context);
|
||||
return result && (!queryInfo.isMail3Pane || this.isMail3Pane);
|
||||
}
|
||||
|
||||
/** Adds the isMail3Pane property and removes some useless properties from a tab object. */
|
||||
convert(fallback) {
|
||||
let result = super.convert(fallback);
|
||||
result.isMail3Pane = this.isMail3Pane;
|
||||
|
||||
// These properties are not useful to Thunderbird extensions and are not returned.
|
||||
for (let key of [
|
||||
|
@ -988,3 +1002,79 @@ extensions.on("startup", (type, extension) => { // eslint-disable-line mozilla/b
|
|||
defineLazyGetter(extension, "windowManager",
|
||||
() => new WindowManager(extension));
|
||||
});
|
||||
|
||||
/**
|
||||
* The following functions turn nsIMsgFolder references into more human-friendly forms.
|
||||
* A folder can be referenced with the account key, and the path to the folder in that account.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a folder URI to a human-friendly path.
|
||||
* @return {String}
|
||||
*/
|
||||
function folderURIToPath(uri) {
|
||||
let path = Services.io.newURI(uri).filePath;
|
||||
return path.split("/").map(decodeURIComponent).join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a human-friendly path to a folder URI. This function does not assume that the
|
||||
* folder referenced exists.
|
||||
* @return {String}
|
||||
*/
|
||||
function folderPathToURI(accountId, path) {
|
||||
let rootURI = MailServices.accounts.getAccount(accountId).incomingServer.rootFolder.URI;
|
||||
if (path == "/") {
|
||||
return rootURI;
|
||||
}
|
||||
return rootURI + path.split("/").map(encodeURIComponent).join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an nsIMsgFolder to a simple object for use in messages.
|
||||
* @return {Object}
|
||||
*/
|
||||
function convertFolder(folder, accountId) {
|
||||
if (!folder) {
|
||||
return null;
|
||||
}
|
||||
if (!accountId) {
|
||||
let server = folder.server;
|
||||
let account = MailServices.accounts.FindAccountForServer(server);
|
||||
accountId = account.key;
|
||||
}
|
||||
return {
|
||||
accountId,
|
||||
name: folder.prettyName,
|
||||
path: folderURIToPath(folder.URI),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an nsIMsgHdr to a simle object for use in messages.
|
||||
* This function WILL change as the API develops.
|
||||
* @return {Object}
|
||||
*/
|
||||
function convertMessage(msgHdr) {
|
||||
if (!msgHdr) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
messageId: msgHdr.messageId,
|
||||
read: msgHdr.isRead,
|
||||
flagged: msgHdr.isFlagged,
|
||||
ccList: msgHdr.ccList,
|
||||
bccList: msgHdr.bccList,
|
||||
author: msgHdr.mime2DecodedAuthor,
|
||||
subject: msgHdr.mime2DecodedSubject,
|
||||
recipients: msgHdr.mime2DecodedRecipients,
|
||||
};
|
||||
}
|
||||
|
||||
Object.assign(global, {
|
||||
convertFolder,
|
||||
convertMessage,
|
||||
folderPathToURI,
|
||||
folderURIToPath,
|
||||
});
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "MailServices", "resource:///modules/MailServices.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "QuickFilterManager",
|
||||
"resource:///modules/QuickFilterManager.jsm");
|
||||
|
||||
const LAYOUTS = ["standard", "wide", "vertical"];
|
||||
// From nsIMsgDBView.idl
|
||||
const SORT_TYPE_MAP = new Map(
|
||||
Object.keys(Ci.nsMsgViewSortType).map(key => [Ci.nsMsgViewSortType[key], key])
|
||||
);
|
||||
const SORT_ORDER_MAP = new Map(
|
||||
Object.keys(Ci.nsMsgViewSortOrder).map(key => [Ci.nsMsgViewSortOrder[key], key])
|
||||
);
|
||||
|
||||
/**
|
||||
* Converts a mail tab to a simle object for use in messages.
|
||||
* @return {Object}
|
||||
*/
|
||||
function convertMailTab(tab, context) {
|
||||
let mailTabObject = {
|
||||
id: tab.id,
|
||||
windowId: tab.windowId,
|
||||
active: tab.active,
|
||||
sortType: null,
|
||||
sortOrder: null,
|
||||
layout: LAYOUTS[Services.prefs.getIntPref("mail.pane_config.dynamic")],
|
||||
folderPaneVisible: null,
|
||||
messagePaneVisible: null,
|
||||
};
|
||||
|
||||
let nativeTab = tab.nativeTab;
|
||||
let { folderDisplay } = nativeTab;
|
||||
if (folderDisplay.view.displayedFolder) {
|
||||
let { folderPaneVisible, messagePaneVisible } = nativeTab.mode.persistTab(nativeTab);
|
||||
mailTabObject.sortType = SORT_TYPE_MAP.get(folderDisplay.view.primarySortType);
|
||||
mailTabObject.sortOrder = SORT_ORDER_MAP.get(folderDisplay.view.primarySortOrder);
|
||||
mailTabObject.folderPaneVisible = folderPaneVisible;
|
||||
mailTabObject.messagePaneVisible = messagePaneVisible;
|
||||
}
|
||||
if (context.extension.hasPermission("accountsRead")) {
|
||||
mailTabObject.displayedFolder = convertFolder(folderDisplay.displayedFolder);
|
||||
}
|
||||
return mailTabObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for changes in the UI to fire events.
|
||||
*/
|
||||
var uiListener = new class extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.listenerCount = 0;
|
||||
this.handleSelect = this.handleSelect.bind(this);
|
||||
this.lastSelected = new WeakMap();
|
||||
}
|
||||
|
||||
handleSelect(event) {
|
||||
let tab = tabTracker.activeTab;
|
||||
if (event.target.id == "folderTree") {
|
||||
let folder = tab.folderDisplay.displayedFolder;
|
||||
if (this.lastSelected.get(tab) == folder) {
|
||||
return;
|
||||
}
|
||||
this.lastSelected.set(tab, folder);
|
||||
this.emit("folder-changed", tab, folder);
|
||||
return;
|
||||
}
|
||||
if (event.target.id == "threadTree") {
|
||||
this.emit("messages-changed", tab, tab.folderDisplay.view.dbView.getSelectedMsgHdrs());
|
||||
}
|
||||
}
|
||||
|
||||
addListenersToWindow(window) {
|
||||
window.addEventListener("select", uiListener.handleSelect);
|
||||
}
|
||||
removeListenersFromWindow(window) {
|
||||
window.removeEventListener("select", uiListener.handleSelect);
|
||||
}
|
||||
incrementListeners() {
|
||||
this.listenerCount++;
|
||||
if (this.listenerCount == 1) {
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
this.addListenersToWindow(window);
|
||||
}
|
||||
windowTracker.addOpenListener(this.addListenersToWindow);
|
||||
}
|
||||
}
|
||||
decrementListeners() {
|
||||
this.listenerCount--;
|
||||
if (this.listenerCount == 0) {
|
||||
for (let window of windowTracker.browserWindows()) {
|
||||
this.removeListenersFromWindow(window);
|
||||
}
|
||||
windowTracker.removeOpenListener(this.addListenersToWindow);
|
||||
this.lastSelected = new WeakMap();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PermissionedEventManager extends EventManager {
|
||||
constructor({ permission, context, name, register }) {
|
||||
super({ context, name, register });
|
||||
this.permission = permission;
|
||||
}
|
||||
addListener(callback) {
|
||||
let { extension } = this.context;
|
||||
if (!extension.hasPermission(this.permission)) {
|
||||
throw new ExtensionError(
|
||||
`The "${this.permission}" permission is required to use ${this.name}.`
|
||||
);
|
||||
}
|
||||
return super.addListener(callback);
|
||||
}
|
||||
}
|
||||
|
||||
this.mailTabs = class extends ExtensionAPI {
|
||||
getAPI(context) {
|
||||
let { extension } = context;
|
||||
let { tabManager } = extension;
|
||||
|
||||
/**
|
||||
* Gets the tab for the given tab id, or the active tab if the id is null.
|
||||
*
|
||||
* @param {?Integer} tabId The tab id to get
|
||||
* @return {Tab} The matching tab, or the active tab
|
||||
*/
|
||||
function getTabOrActive(tabId) {
|
||||
let tab;
|
||||
if (tabId) {
|
||||
tab = tabManager.get(tabId);
|
||||
} else {
|
||||
tab = tabManager.wrapTab(tabTracker.activeTab);
|
||||
tabId = tab.id;
|
||||
}
|
||||
|
||||
if (tab && tab.isMail3Pane) {
|
||||
return tab;
|
||||
}
|
||||
throw new ExtensionError(`Invalid mail tab ID: ${tabId}`);
|
||||
}
|
||||
|
||||
return {
|
||||
mailTabs: {
|
||||
async getAll() {
|
||||
return Array.from(tabManager.query({
|
||||
// All of these are needed for tabManager to return every tab we want.
|
||||
"currentWindow": null,
|
||||
"index": null,
|
||||
"isMail3Pane": true,
|
||||
"lastFocusedWindow": null,
|
||||
"screen": null,
|
||||
"windowId": null,
|
||||
"windowType": null,
|
||||
}, context), (tab) => convertMailTab(tab, context));
|
||||
},
|
||||
|
||||
async getCurrent() {
|
||||
let tab = tabManager.wrapTab(tabTracker.activeTab);
|
||||
if (!tab || !tab.isMail3Pane) {
|
||||
return null;
|
||||
}
|
||||
return convertMailTab(tab, context);
|
||||
},
|
||||
|
||||
async update(tabId, args) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let window = tab.window;
|
||||
|
||||
let {
|
||||
displayedFolder,
|
||||
layout,
|
||||
folderPaneVisible,
|
||||
messagePaneVisible,
|
||||
sortOrder,
|
||||
sortType,
|
||||
} = args;
|
||||
|
||||
if (displayedFolder && extension.hasPermission("accountsRead")) {
|
||||
let uri = folderPathToURI(displayedFolder.accountId, displayedFolder.path);
|
||||
if (tab.active) {
|
||||
let treeView = Cu.getGlobalForObject(tab.nativeTab).gFolderTreeView;
|
||||
let folder = MailServices.folderLookup.getFolderForURL(uri);
|
||||
if (folder) {
|
||||
treeView.selectFolder(folder);
|
||||
} else {
|
||||
throw new ExtensionError(
|
||||
`Folder "${displayedFolder.path}" for account ` +
|
||||
`"${displayedFolder.accountId}" not found.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
tab.nativeTab.folderDisplay.showFolderUri(uri);
|
||||
}
|
||||
}
|
||||
|
||||
if (sortType && sortType in Ci.nsMsgViewSortType &&
|
||||
sortOrder && sortOrder in Ci.nsMsgViewSortOrder) {
|
||||
tab.nativeTab.folderDisplay.view.sort(Ci.nsMsgViewSortType[sortType],
|
||||
Ci.nsMsgViewSortOrder[sortOrder]);
|
||||
}
|
||||
|
||||
// Layout applies to all folder tabs.
|
||||
if (layout) {
|
||||
Services.prefs.setIntPref("mail.pane_config.dynamic", LAYOUTS.indexOf(layout));
|
||||
}
|
||||
|
||||
if (typeof folderPaneVisible == "boolean") {
|
||||
if (tab.active) {
|
||||
let document = window.document;
|
||||
let folderPaneSplitter = document.getElementById("folderpane_splitter");
|
||||
folderPaneSplitter.setAttribute("state", folderPaneVisible ? "open" : "collapsed");
|
||||
} else {
|
||||
tab.nativeTab.folderDisplay.folderPaneVisible = folderPaneVisible;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof messagePaneVisible == "boolean") {
|
||||
if (tab.active) {
|
||||
if (messagePaneVisible == window.IsMessagePaneCollapsed()) {
|
||||
window.MsgToggleMessagePane();
|
||||
}
|
||||
} else {
|
||||
tab.nativeTab.messageDisplay._visible = messagePaneVisible;
|
||||
if (!messagePaneVisible) {
|
||||
// Prevent the messagePane from showing if a message is selected.
|
||||
tab.nativeTab.folderDisplay._aboutToSelectMessage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async getSelectedMessages(tabId) {
|
||||
if (!extension.hasPermission("messagesRead")) {
|
||||
throw new ExtensionError(
|
||||
`The "messagesRead" permission is required to use mailTabs.getSelectedMessages.`
|
||||
);
|
||||
}
|
||||
|
||||
let tab = getTabOrActive(tabId);
|
||||
let { folderDisplay } = tab.nativeTab;
|
||||
return [...folderDisplay.view.dbView.getSelectedMsgHdrs()].map(convertMessage);
|
||||
},
|
||||
|
||||
async setQuickFilter(tabId, state) {
|
||||
let tab = getTabOrActive(tabId);
|
||||
let nativeTab = tab.nativeTab;
|
||||
let window = Cu.getGlobalForObject(nativeTab);
|
||||
|
||||
let filterer;
|
||||
if (tab.active) {
|
||||
filterer = window.QuickFilterBarMuxer.activeFilterer;
|
||||
} else {
|
||||
filterer = nativeTab._ext.quickFilter;
|
||||
}
|
||||
filterer.clear();
|
||||
|
||||
filterer.visible = (state.show !== false);
|
||||
for (let s of ["unread", "starred", "contact", "attachment"]) {
|
||||
let key = (s == "contact") ? "addrBook" : s;
|
||||
let value = state[s];
|
||||
if (value === null) {
|
||||
delete filterer.filterValues[key];
|
||||
} else {
|
||||
filterer.filterValues[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.tags) {
|
||||
filterer.filterValues.tags = {
|
||||
mode: "OR",
|
||||
tags: {},
|
||||
};
|
||||
for (let tag of MailServices.tags.getAllTags({})) {
|
||||
filterer.filterValues.tags[tag.key] = null;
|
||||
}
|
||||
if (typeof state.tags == "object") {
|
||||
filterer.filterValues.tags.mode = (state.tags.mode == "any") ? "OR" : "AND";
|
||||
for (let [key, value] of Object.entries(state.tags.tags)) {
|
||||
filterer.filterValues.tags.tags[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state.text) {
|
||||
filterer.filterValues.text = {
|
||||
states: {
|
||||
recipients: state.text.recipients || false,
|
||||
sender: state.text.sender || false,
|
||||
subject: state.text.subject || false,
|
||||
body: state.text.body || false,
|
||||
},
|
||||
text: state.text.text,
|
||||
};
|
||||
}
|
||||
|
||||
if (tab.active) {
|
||||
window.QuickFilterBarMuxer.deferredUpdateSearch();
|
||||
window.QuickFilterBarMuxer.reflectFiltererState(filterer, window.gFolderDisplay);
|
||||
}
|
||||
// Inactive tabs are updated when they become active, except the search doesn't. :(
|
||||
},
|
||||
|
||||
onDisplayedFolderChanged: new PermissionedEventManager({
|
||||
permission: "accountsRead",
|
||||
context,
|
||||
name: "mailTabs.onDisplayedFolderChanged",
|
||||
register: (fire) => {
|
||||
let listener = (event, tab, folder) => {
|
||||
fire.sync(tabTracker.getId(tab), convertFolder(folder));
|
||||
};
|
||||
|
||||
uiListener.on("folder-changed", listener);
|
||||
uiListener.incrementListeners();
|
||||
return () => {
|
||||
uiListener.off("folder-changed", listener);
|
||||
uiListener.decrementListeners();
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
onSelectedMessagesChanged: new PermissionedEventManager({
|
||||
permission: "messagesRead",
|
||||
context,
|
||||
name: "mailTabs.onSelectedMessagesChanged",
|
||||
register: (fire) => {
|
||||
let listener = (event, tab, messages) => {
|
||||
fire.sync(tabTracker.getId(tab), messages.map(convertMessage));
|
||||
};
|
||||
|
||||
uiListener.on("messages-changed", listener);
|
||||
uiListener.incrementListeners();
|
||||
return () => {
|
||||
uiListener.off("messages-changed", listener);
|
||||
uiListener.decrementListeners();
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,282 @@
|
|||
[
|
||||
{
|
||||
"namespace": "manifest",
|
||||
"types": [
|
||||
{
|
||||
"$extend": "OptionalPermission",
|
||||
"choices": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"mailTabs"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"namespace": "mailTabs",
|
||||
"permissions": [
|
||||
"mailTabs"
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"id": "QuickFilterTagsDetail",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"description": "Object keys are tags to filter on, values are <code>true</code> if the message must have the tag, or <code>false</code> if it must not have the tag. For a list of available tags, call the :ref:`messages.listTags` method.",
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Whether all of the tag filters must apply, or any of them.",
|
||||
"enum": [
|
||||
"all",
|
||||
"any"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "QuickFilterTextDetail",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "String to match against the <var>recipients</var>, <var>sender</var>, <var>subject</var>, or <var>body</var>."
|
||||
},
|
||||
"recipients": {
|
||||
"type": "boolean",
|
||||
"description": "Shows messages where <var>text</var> matches the recipients.",
|
||||
"optional": true
|
||||
},
|
||||
"sender": {
|
||||
"type": "boolean",
|
||||
"description": "Shows messages where <var>text</var> matches the sender.",
|
||||
"optional": true
|
||||
},
|
||||
"subject": {
|
||||
"type": "boolean",
|
||||
"description": "Shows messages where <var>text</var> matches the subject.",
|
||||
"optional": true
|
||||
},
|
||||
"body": {
|
||||
"type": "boolean",
|
||||
"description": "Shows messages where <var>text</var> matches the message body.",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"name": "getAll",
|
||||
"type": "function",
|
||||
"description": "Returns an array of all mail tabs in all windows.",
|
||||
"async": true,
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "getCurrent",
|
||||
"type": "function",
|
||||
"description": "Returns the current mail tab in the most recent window, or throws an exception if the current tab is not a mail tab.",
|
||||
"async": true,
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "update",
|
||||
"type": "function",
|
||||
"description": "Modifies the properties of a mail tab. Properties that are not specified in <var>updateProperties</var> are not modified.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tabId",
|
||||
"type": "integer",
|
||||
"description": "Defaults to the selected tab of the current window.",
|
||||
"optional": true,
|
||||
"minimum": 1
|
||||
},
|
||||
{
|
||||
"name": "updateProperties",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"displayedFolder": {
|
||||
"type": "object",
|
||||
"description": "Sets the folder displayed in the tab. The extension must have an accounts permission to do this.",
|
||||
"optional": true,
|
||||
"properties": {
|
||||
"accountId": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"optional": true
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sortType": {
|
||||
"type": "string",
|
||||
"description": "Sorts the list of messages. <var>sortOrder</var> must also be given.",
|
||||
"optional": true,
|
||||
"enum": [
|
||||
"byNone",
|
||||
"byDate",
|
||||
"bySubject",
|
||||
"byAuthor",
|
||||
"byId",
|
||||
"byThread",
|
||||
"byPriority",
|
||||
"byStatus",
|
||||
"bySize",
|
||||
"byFlagged",
|
||||
"byUnread",
|
||||
"byRecipient",
|
||||
"byLocation",
|
||||
"byTags",
|
||||
"byJunkStatus",
|
||||
"byAttachments",
|
||||
"byAccount",
|
||||
"byCustom",
|
||||
"byReceived",
|
||||
"byCorrespondent"
|
||||
]
|
||||
},
|
||||
"sortOrder": {
|
||||
"type": "string",
|
||||
"description": "Sorts the list of messages. <var>sortType</var> must also be given.",
|
||||
"optional": true,
|
||||
"enum": [
|
||||
"none",
|
||||
"ascending",
|
||||
"descending"
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"type": "string",
|
||||
"description": "Sets the arrangement of the folder pane, message list pane, and message display pane. Note that setting this applies it to all mail tabs.",
|
||||
"optional": true,
|
||||
"enum": [
|
||||
"standard",
|
||||
"wide",
|
||||
"vertical"
|
||||
]
|
||||
},
|
||||
"folderPaneVisible": {
|
||||
"type": "boolean",
|
||||
"description": "Shows or hides the folder pane.",
|
||||
"optional": true
|
||||
},
|
||||
"messagePaneVisible": {
|
||||
"type": "boolean",
|
||||
"description": "Shows or hides the message display pane.",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getSelectedMessages",
|
||||
"type": "function",
|
||||
"description": "Lists the selected messages in the current folder. A messages permission is required to do this.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tabId",
|
||||
"type": "integer",
|
||||
"description": "Defaults to the selected tab of the current window.",
|
||||
"optional": true,
|
||||
"minimum": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "setQuickFilter",
|
||||
"type": "function",
|
||||
"description": "Sets the Quick Filter user interface based on the options specified.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tabId",
|
||||
"type": "integer",
|
||||
"description": "Defaults to the selected tab of the current window.",
|
||||
"optional": true,
|
||||
"minimum": 1
|
||||
},
|
||||
{
|
||||
"name": "properties",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"show": {
|
||||
"type": "boolean",
|
||||
"description": "Shows or hides the Quick Filter bar.",
|
||||
"optional": true
|
||||
},
|
||||
"unread": {
|
||||
"type": "boolean",
|
||||
"description": "Shows only unread messages.",
|
||||
"optional": true
|
||||
},
|
||||
"starred": {
|
||||
"type": "boolean",
|
||||
"description": "Shows only starred messages.",
|
||||
"optional": true
|
||||
},
|
||||
"contact": {
|
||||
"type": "boolean",
|
||||
"description": "Shows only messages from people in the address book.",
|
||||
"optional": true
|
||||
},
|
||||
"tags": {
|
||||
"optional": true,
|
||||
"choices": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"$ref": "QuickFilterTagsDetail"
|
||||
}
|
||||
],
|
||||
"description": "Shows only messages with tags on them."
|
||||
},
|
||||
"attachment": {
|
||||
"type": "boolean",
|
||||
"description": "Shows only messages with attachments.",
|
||||
"optional": true
|
||||
},
|
||||
"text": {
|
||||
"$ref": "QuickFilterTextDetail",
|
||||
"description": "Shows only messages matching the supplied text.",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onDisplayedFolderChanged",
|
||||
"type": "function",
|
||||
"description": "Fired when the displayed folder changes in any mail tab.",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "onSelectedMessagesChanged",
|
||||
"type": "function",
|
||||
"description": "Fired when the selected messages change in any mail tab.",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -38,7 +38,8 @@
|
|||
"favIconUrl": {"type": "string", "optional": true, "permissions": ["tabs"], "description": "The URL of the tab's favicon. This property is only present if the extension's manifest includes the <code>\"tabs\"</code> permission. It may also be an empty string if the tab is loading."},
|
||||
"status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."},
|
||||
"width": {"type": "integer", "optional": true, "description": "The width of the tab in pixels."},
|
||||
"height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."}
|
||||
"height": {"type": "integer", "optional": true, "description": "The height of the tab in pixels."},
|
||||
"isMail3Pane": {"type": "boolean", "optional": true, "description": "Whether the tab is a 3-pane tab."}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -226,6 +227,11 @@
|
|||
"type": "object",
|
||||
"name": "queryInfo",
|
||||
"properties": {
|
||||
"isMail3Pane": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
"description": "Whether the tab is a Thunderbird 3-pane tab."
|
||||
},
|
||||
"active": {
|
||||
"type": "boolean",
|
||||
"optional": true,
|
||||
|
|
|
@ -71,3 +71,7 @@ XPCOMUtils.defineLazyServiceGetter(MailServices, "junk",
|
|||
XPCOMUtils.defineLazyServiceGetter(MailServices, "newMailNotification",
|
||||
"@mozilla.org/newMailNotificationService;1",
|
||||
"mozINewMailNotificationService");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(MailServices, "folderLookup",
|
||||
"@mozilla.org/mail/folder-lookup;1",
|
||||
"nsIFolderLookupService");
|
||||
|
|
Загрузка…
Ссылка в новой задаче