Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Some refactoring (created a JSM).

  • Loading branch information...
commit ff09854e6686edddef7b47bf298245d5153542e7 1 parent b0fd7ea
Jonathan Protzenko authored
8 TODO
View
@@ -1,10 +1,9 @@
# vim:ft=none
-#28 Display the custom buttons [open in new tab, mark all read, (un|)fold all]
- ONLY if we are viewing a thread, not a conversation.
+
#9 Add an option to mark a thread as read when it is displayed
b) Improve it by only marking a message as read when it is scrolled into view
#12 Extension does not work with newsgroups (throws an exception) (see bug
- 478167).
+ 478167) --> temporary workaround + check other types of non-mail accounts
#29 Encoding issues (Chinese not ok, Czech not ok either)
#30 Add "reply - reply to all - ..." and other links at the bottom of the
message, see http://www.flickr.com/photos/davidascher/3095078638/
@@ -13,6 +12,9 @@
b) Steal code from message display (jsmimeemitter.js sees the HTML go by, find
a way to catch it with a GlodaMimeMsg)
c) Adapt "- hide quoted text -" code
+
+#31 Create a real @media(print) stylesheet to print a whole conversation
+#32 Detect hotmail-style quoted parts (optional)
#7 SLOW: make everything asynchronous. Start filling in messages for the first
query, then launch the extended query that fetches more messages, and then
asynchronously insert those in the right place as they arrive (i.e.
2  chrome.manifest
View
@@ -1,6 +1,8 @@
content gconversation content/
skin gconversation classic/1.0 skin/
+resource gconversation modules/
overlay chrome://messenger/content/messenger.xul chrome://gconversation/content/overlay.xul
#style chrome://messenger/content/multimessageview.xhtml chrome://gconversation/skin/mmv.css
override chrome://messenger/content/multimessageview.xhtml chrome://gconversation/content/multimessageview.xhtml
+
locale gconversation en-US locale/en-US/
20 content/multimessageview.xhtml
View
@@ -63,8 +63,8 @@
<link rel="stylesheet" media="screen" type="text/css"
href="chrome://gconversation/skin/mmv.css"/>
<title>&window.title;</title>
- <script type="application/x-javascript" src="chrome://messenger/content/jquery.js" />
- <script type="application/x-javascript;version=1.8"><![CDATA[
+ <script type="application/javascript" src="chrome://messenger/content/jquery.js" />
+ <script type="application/javascript;version=1.8"><![CDATA[
Components.utils.import("resource://app/modules/errUtils.js");
const Ci = Components.interfaces;
const Cc = Components.classes;
@@ -145,6 +145,14 @@
function foldAll(event) {
$(".msgarrow[src=chrome://gconversation/skin/up.png]").click();
}
+
+ function disableExtraButtons() {
+ [x.setAttribute("disabled", "true") for each ([,x] in Iterator(document.getElementsByClassName("extra-button")))];
+ }
+
+ function enableExtraButtons() {
+ [x.setAttribute("disabled", "false") for each ([,x] in Iterator(document.getElementsByClassName("extra-button")))];
+ }
]]>
</script>
</head>
@@ -156,19 +164,19 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<hbox id="buttonhbox" align="start">
<button id="open_in_new_tab"
- class="button msgHeaderView-button"
+ class="button msgHeaderView-button extra-button"
label="&button.open_in_new_tab;"
onclick="if (event.button == 0) window.top.gconversation.on_load_thread_tab();"/>
<button id="mark_as_read"
- class="button msgHeaderView-button"
+ class="button msgHeaderView-button extra-button"
label="&button.mark_all_read;"
onclick="if (event.button == 0) window.top.DefaultController.doCommand('cmd_markThreadAsRead');"/>
<button id="unfold_all"
- class="button msgHeaderView-button"
+ class="button msgHeaderView-button extra-button"
onclick="if (event.button == 0) unfoldAll();"
label="&button.unfold_all;" />
<button id="fold_all"
- class="button msgHeaderView-button"
+ class="button msgHeaderView-button extra-button"
onclick="if (event.button == 0) foldAll();"
label="&button.fold_all;" />
<button id="archive"
11 content/overlay.xul
View
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://gconversation/skin/overlay.css" type="text/css" ?>
<?xml-stylesheet href="chrome://gconversation/skin/msg.css" type="text/css" ?>
-<!--<!DOCTYPE window SYSTEM "chrome://tbsortfolders/locale/main.dtd">-->
+<!DOCTYPE window SYSTEM "chrome://messenger/locale/messenger.dtd">
<overlay id="messengerWindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<stringbundleset id="stringbundleset">
<stringbundle id="gconv-string-bundle" src="chrome://gconversation/locale/main.properties"/>
@@ -29,8 +29,15 @@
oncommand="gconversation.on_load_thread();"
>
<menupopup>
- <menuitem label="Open thread in new tab" oncommand="gconversation.on_load_thread_tab();" />
+ <menuitem label="Open thread in new tab"
+ oncommand="gconversation.on_load_thread_tab();"
+ insertAfter="mailContext" />
</menupopup>
</toolbarbutton>
</toolbarpalette>
+ <popupset id="mainPopupSet">
+ <popup id="gConvMenu">
+ <menuitem label="&printButton.label;" oncommand="gconversation.print()" />
+ </popup>
+ </popupset>
</overlay>
121 content/selectionsummaries.js
View
@@ -29,11 +29,12 @@ var gconversation = {
document.addEventListener("load", function () {
const Ci = Components.interfaces;
const Cc = Components.classes;
+ const Cu = Components.utils;
+ Components.utils.import("resource://gconversation/MailUtils.jsm");
+
/* Various magic values */
- const nsMsgViewIndex_None = 0xffffffff;
- /* from mailnews/base/public/nsMsgFolderFlags.idl */
- const nsMsgFolderFlags_SentMail = 0x00000200;
- const nsMsgFolderFlags_Archive = 0x00004000;
+ const nsMsgViewIndex_None = 0xffffffff;
+
const prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService).getBranch("gconversation.");
const txttohtmlconv = Cc["@mozilla.org/txttohtmlconv;1"].createInstance(Ci.mozITXTToHTMLConv);
const stringBundle = document.getElementById("gconv-string-bundle");
@@ -72,65 +73,6 @@ document.addEventListener("load", function () {
};
myPrefObserver.register();
- /* Do a "old-style" retrieval of a message's body given its nsIMsgDBHdr. This
- * is useful when MsgHdrToMimeMessage fails. */
- function getMessageBody(aMessageHeader, aStripHtml) {
- let messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
- let listener = Cc["@mozilla.org/network/sync-stream-listener;1"].createInstance(Ci.nsISyncStreamListener);
- let uri = aMessageHeader.folder.getUriForMsg(aMessageHeader);
- messenger.messageServiceFromURI(uri).streamMessage(uri, listener, null, null, false, "");
- let folder = aMessageHeader.folder;
- /*
- * AUTF8String getMsgTextFromStream(in nsIInputStream aStream, in ACString aCharset,
- in unsigned long aBytesToRead, in unsigned long aMaxOutputLen,
- in boolean aCompressQuotes, in boolean aStripHTMLTags,
- out ACString aContentType);
- */
- return folder.getMsgTextFromStream(listener.inputStream, aMessageHeader.Charset, 65536, 32768, false, aStripHtml, { });
- }
-
- /* In the case of GMail accounts, several messages with the same Message-Id
- * header will be returned when we search for all message related to the
- * conversation we will display. We have multiple alternatives to choose from,
- * so prefer :
- * - the message that's in the current folder
- * - the message that's in the "Sent" folder (GMail sent messages also appear
- * in "All Mail")
- * - the message that's not in the Archives
- */
- function selectRightMessage(similar) {
- let msgHdr;
- /* NB: this will return false for the "Inbox" Smart Folder for instance */
- for each (let m in similar) {
- if (gDBView.msgFolder && m.folderMessage.folder.URI == gDBView.msgFolder.URI) {
- dump("Found a corresponding message in the current folder\n");
- msgHdr = m;
- break;
- }
- }
- if (!msgHdr) {
- for each (let m in similar) {
- if (m.folderMessage.folder.getFlag(nsMsgFolderFlags_SentMail)) {
- dump("Found a corresponding message in the sent folder\n");
- msgHdr = m;
- break;
- }
- }
- }
- if (!msgHdr) {
- for each (let m in similar) {
- if (!m.folderMessage.folder.getFlag(nsMsgFolderFlags_Archive)) {
- dump("Found a corresponding message that's not in an Archive folder\n");
- msgHdr = m;
- break;
- }
- }
- }
- if (!msgHdr)
- msgHdr = similar[0];
- return msgHdr;
- }
-
/* We override the usual ThreadSummary class to provide our own. Our own
* displays full messages, plus other extra features */
ThreadSummary = function (messages) {
@@ -196,7 +138,7 @@ document.addEventListener("load", function () {
break;
}
- let msgHdr = selectRightMessage(this._msgHdrs[i]).folderMessage;
+ let msgHdr = selectRightMessage(this._msgHdrs[i], gDBView.msgFolder).folderMessage;
let msg_classes = "message ";
if (!msgHdr.isRead)
@@ -371,8 +313,9 @@ document.addEventListener("load", function () {
let body = getMessageBody(msgHdr, true);
let snippet = body.substring(0, SNIPPET_LENGTH-3)+"...";
fillSnippetAndMsg(snippet, body);
- dump("Got an \"offline message\"");
+ dump("Got an \"offline message\"\n");
} catch (e) {
+ Application.console.log("Error fetching the message: "+e);
/* Ok, that failed too... */
fullMsgNode.textContent = "...";
snippetMsgNode.textContent = "...";
@@ -456,26 +399,6 @@ document.addEventListener("load", function () {
}
}
- /* Remove messages with the same Message-Id header from a collection.
- * Return an object with, for each message in selectedMessages, the duplicates
- * that have been found. */
- function removeDuplicates(items) {
- //let info = function (hdr) hdr.mime2DecodedAuthor+" ["+hdr.mime2DecodedSubject+"]";
- let similar = {};
- let orderedIds = [];
- for (let i = 0; i < items.length; ++i) {
- let item = items[i];
- let id = item.headerMessageID;
- if (!similar[id]) {
- similar[id] = [item];
- orderedIds.push(id);
- } else {
- similar[id].push(item);
- }
- }
- return [similar[id] for each (id in orderedIds)];
- }
-
/* The summarizeThread function overwrites the default one, searches for more
* messages, and passes them to our instance of ThreadSummary. This design is
* more convenient as it follows Thunderbird's more closely, which allows me
@@ -486,6 +409,7 @@ document.addEventListener("load", function () {
dump("No selected messages\n");
return false;
}
+ document.getElementById('multimessage').contentWindow.enableExtraButtons();
pullConversation(
aSelectedMessages,
@@ -499,6 +423,24 @@ document.addEventListener("load", function () {
return true;
};
+ /* We must catch the call to summarizeMultipleSelection to hide the buttons in
+ * multimessageview.xhtml */
+ /* XXX figure out why I can't do let old = ... and then summarize... = old(); */
+ summarizeMultipleSelection = function (aSelectedMessages) {
+ if (aSelectedMessages.length == 0)
+ return;
+ try {
+ gSummary = new MultiMessageSummary(aSelectedMessages);
+ gSummary.init();
+ } catch (e) {
+ dump("Exception in summarizeMultipleSelection" + e + "\n");
+ Components.utils.reportError(e);
+ throw(e);
+ }
+
+ document.getElementById('multimessage').contentWindow.disableExtraButtons();
+ };
+
/* Register event handlers through the global variable */
gconversation.on_load_thread = function() {
if (summarizeThread(gFolderDisplay.selectedMessages))
@@ -523,4 +465,13 @@ document.addEventListener("load", function () {
);
};
+ /* Register "print" functionnality */
+ gconversation.print = function () {
+ document.getElementById("multimessage").contentWindow.print();
+ };
+
+ /* We need to attach our custom context menu to multimessage, that's simpler
+ * than using an overlay. */
+ document.getElementById("multimessage").setAttribute("context", "gConvMenu");
+
}, true);
BIN  icon.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3  install.rdf
View
@@ -22,8 +22,7 @@
<em:name>GMail Conversation View</em:name>
<em:description>Display your own emails in thread summaries.</em:description>
<em:optionsURL>chrome://gconversation/content/options.xul</em:optionsURL>
-
-
+ <em:iconURL>chrome://gconversation/content/icon.png</em:iconURL>
<em:creator>Jonathan Protzenko</em:creator>
</Description>
0  locale/en-US/menu.dtd
View
No changes.
88 modules/MailUtils.jsm
View
@@ -0,0 +1,88 @@
+var EXPORTED_SYMBOLS = ['getMessageBody', 'selectRightMessage',
+ 'removeDuplicates']
+
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cu = Components.utils;
+/* from mailnews/base/public/nsMsgFolderFlags.idl */
+const nsMsgFolderFlags_SentMail = 0x00000200;
+const nsMsgFolderFlags_Archive = 0x00004000;
+
+/* Do a "old-style" retrieval of a message's body given its nsIMsgDBHdr. This
+ * is useful when MsgHdrToMimeMessage fails. */
+function getMessageBody(aMessageHeader, aStripHtml) {
+ let messenger = Cc["@mozilla.org/messenger;1"].createInstance(Ci.nsIMessenger);
+ let listener = Cc["@mozilla.org/network/sync-stream-listener;1"].createInstance(Ci.nsISyncStreamListener);
+ let uri = aMessageHeader.folder.getUriForMsg(aMessageHeader);
+ messenger.messageServiceFromURI(uri).streamMessage(uri, listener, null, null, false, "");
+ let folder = aMessageHeader.folder;
+ /*
+ * AUTF8String getMsgTextFromStream(in nsIInputStream aStream, in ACString aCharset,
+ in unsigned long aBytesToRead, in unsigned long aMaxOutputLen,
+ in boolean aCompressQuotes, in boolean aStripHTMLTags,
+ out ACString aContentType);
+ */
+ return folder.getMsgTextFromStream(listener.inputStream, aMessageHeader.Charset, 65536, 32768, false, aStripHtml, { });
+}
+
+/* In the case of GMail accounts, several messages with the same Message-Id
+ * header will be returned when we search for all message related to the
+ * conversation we will display. We have multiple alternatives to choose from,
+ * so prefer :
+ * - the message that's in the current folder
+ * - the message that's in the "Sent" folder (GMail sent messages also appear
+ * in "All Mail")
+ * - the message that's not in the Archives
+ */
+function selectRightMessage(similar, currentFolder) {
+ let msgHdr;
+ /* NB: this won't find anything for the "Inbox" Smart Folder for instance */
+ for each (let m in similar) {
+ if (currentFolder && m.folderMessage.folder.URI == currentFolder.URI) {
+ dump("Found a corresponding message in the current folder\n");
+ msgHdr = m;
+ break;
+ }
+ }
+ if (!msgHdr) {
+ for each (let m in similar) {
+ if (m.folderMessage.folder.getFlag(nsMsgFolderFlags_SentMail)) {
+ dump("Found a corresponding message in the sent folder\n");
+ msgHdr = m;
+ break;
+ }
+ }
+ }
+ if (!msgHdr) {
+ for each (let m in similar) {
+ if (!m.folderMessage.folder.getFlag(nsMsgFolderFlags_Archive)) {
+ dump("Found a corresponding message that's not in an Archive folder\n");
+ msgHdr = m;
+ break;
+ }
+ }
+ }
+ if (!msgHdr)
+ msgHdr = similar[0];
+ return msgHdr;
+}
+
+/* Remove messages with the same Message-Id header from a collection.
+ * Return an object with, for each message in selectedMessages, the duplicates
+ * that have been found. */
+function removeDuplicates(items) {
+ //let info = function (hdr) hdr.mime2DecodedAuthor+" ["+hdr.mime2DecodedSubject+"]";
+ let similar = {};
+ let orderedIds = [];
+ for (let i = 0; i < items.length; ++i) {
+ let item = items[i];
+ let id = item.headerMessageID;
+ if (!similar[id]) {
+ similar[id] = [item];
+ orderedIds.push(id);
+ } else {
+ similar[id].push(item);
+ }
+ }
+ return [similar[id] for each (id in orderedIds)];
+}
BIN  skin/up.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Please sign in to comment.
Something went wrong with that request. Please try again.