diff --git a/Donators b/Donators index 5f579784..517856f2 100644 --- a/Donators +++ b/Donators @@ -2,6 +2,7 @@ Note: If you don't wish to appear on this list when making a donation, please tell me. 2008: +* Daniel Schaffrath * Sam Griffin * Ivan Pantuyev * Spike Spiegal diff --git a/Makefile b/Makefile index e2f7cdd1..8f4f9a18 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ #### configuration -VERSION = 0.6pre +VERSION = 1.0pre NAME = vimperator include Makefile.common diff --git a/content/editor.js b/content/editor.js index e43875f4..97866402 100644 --- a/content/editor.js +++ b/content/editor.js @@ -265,7 +265,7 @@ liberator.Editor = function () //{{{ [""], "Insert clipboard/selection", function () { liberator.editor.pasteClipboard(); }); - liberator.mappings.add([liberator.modes.INSERT, liberator.modes.TEXTAREA], + liberator.mappings.add([liberator.modes.INSERT, liberator.modes.TEXTAREA, liberator.modes.COMPOSE], [""], "Edit text field with an external editor", function () { liberator.editor.editWithExternalEditor(); }); @@ -719,15 +719,27 @@ liberator.Editor = function () //{{{ return -1; }, + // TODO: clean up with 2 functions for textboxes and currentEditor? editWithExternalEditor: function () { - var textBox = document.commandDispatcher.focusedElement; + var textBox = null; + if (!(liberator.config.isComposeWindow)) + textBox = document.commandDispatcher.focusedElement; + + var text = ""; + if (textBox) + text = textBox.value; + else if (typeof GetCurrentEditor == "function") // Thunderbird composer + text = GetCurrentEditor().outputToString("text/plain", 2); + else + return false; + var editor = liberator.options["editor"]; var args = editor.split(" "); if (args.length < 1) { liberator.echoerr("no editor specified"); - return; + return false; } try @@ -737,29 +749,35 @@ liberator.Editor = function () //{{{ catch (e) { liberator.echoerr("Could not create temporary file: " + e.message); - return; + return false; } try { - liberator.io.writeFile(tmpfile, textBox.value); + liberator.io.writeFile(tmpfile, text); } catch (e) { liberator.echoerr("Could not write to temporary file " + tmpfile.path + ": " + e.message); - return; + return false; } var prog = args.shift(); args.push(tmpfile.path) - textBox.setAttribute("readonly", "true"); - var oldBg = textBox.style.backgroundColor; - var tmpBg = "yellow"; - textBox.style.backgroundColor = "#bbbbbb"; + if (textBox) + { + textBox.setAttribute("readonly", "true"); + var oldBg = textBox.style.backgroundColor; + var tmpBg = "yellow"; + textBox.style.backgroundColor = "#bbbbbb"; + } + var newThread = Components.classes["@mozilla.org/thread-manager;1"].getService().newThread(0); // TODO: save return value in v:shell_error liberator.callFunctionInThread(newThread, liberator.io.run, [prog, args, true]); - textBox.removeAttribute("readonly"); + + if (textBox) + textBox.removeAttribute("readonly"); // if (v:shell_error != 0) @@ -772,7 +790,22 @@ liberator.Editor = function () //{{{ try { var val = liberator.io.readFile(tmpfile); - textBox.value = val; + if (textBox) + textBox.value = val; + else + { + //document.getElementById("content-frame").contentDocument.designMode = "on"; + var editor = GetCurrentEditor(); + var wholeDocRange = editor.document.createRange(); + var rootNode = editor.rootElement.QueryInterface(Components.interfaces.nsIDOMNode); + wholeDocRange.selectNodeContents(rootNode); + editor.selection.addRange(wholeDocRange); + editor.selection.deleteFromDocument(); + editor.insertText(val); + //setTimeout(function() { + // document.getElementById("content-frame").contentDocument.designMode = "off"; + //}, 100); + } } catch (e) { @@ -782,19 +815,23 @@ liberator.Editor = function () //{{{ // } // blink the textbox after returning - TODO: could use setInterval - var timeout = 100; - textBox.style.backgroundColor = tmpBg; - setTimeout(function () { - textBox.style.backgroundColor = oldBg; + if (textBox) + { + var timeout = 100; + textBox.style.backgroundColor = tmpBg; setTimeout(function () { - textBox.style.backgroundColor = tmpBg; + textBox.style.backgroundColor = oldBg; setTimeout(function () { - textBox.style.backgroundColor = oldBg; + textBox.style.backgroundColor = tmpBg; + setTimeout(function () { + textBox.style.backgroundColor = oldBg; + }, timeout); }, timeout); }, timeout); - }, timeout); + } tmpfile.remove(false); + return true; }, // Abbreviations {{{ diff --git a/content/events.js b/content/events.js index 28dd973d..2a499345 100644 --- a/content/events.js +++ b/content/events.js @@ -233,49 +233,52 @@ liberator.Events = function () //{{{ var currentMacro = ""; var lastMacro = ""; - // any tab related events - var tabcontainer = getBrowser().mTabContainer; - if (tabcontainer) // not every VIM-like extension has a tab container + try // not every extension has a getBrowser() method { - tabcontainer.addEventListener("TabMove", function (event) + var tabcontainer = getBrowser().mTabContainer; + if (tabcontainer) // not every VIM-like extension has a tab container { - liberator.statusline.updateTabCount(); - liberator.buffer.updateBufferList(); - }, false); - tabcontainer.addEventListener("TabOpen", function (event) + tabcontainer.addEventListener("TabMove", function (event) + { + liberator.statusline.updateTabCount(); + liberator.buffer.updateBufferList(); + }, false); + tabcontainer.addEventListener("TabOpen", function (event) + { + liberator.statusline.updateTabCount(); + liberator.buffer.updateBufferList(); + }, false); + tabcontainer.addEventListener("TabClose", function (event) + { + liberator.statusline.updateTabCount(); + liberator.buffer.updateBufferList(); + }, false); + tabcontainer.addEventListener("TabSelect", function (event) + { + // TODO: is all of that necessary? + liberator.modes.reset(); + liberator.commandline.clear(); + liberator.modes.show(); + liberator.statusline.updateTabCount(); + liberator.buffer.updateBufferList(); + liberator.tabs.updateSelectionHistory(); + + setTimeout(function () { liberator.focusContent(true); }, 10); // just make sure, that no widget has focus + }, false); + } + + // this adds an event which is is called on each page load, even if the + // page is loaded in a background tab + getBrowser().addEventListener("load", onPageLoad, true); + + // called when the active document is scrolled + getBrowser().addEventListener("scroll", function (event) { - liberator.statusline.updateTabCount(); - liberator.buffer.updateBufferList(); - }, false); - tabcontainer.addEventListener("TabClose", function (event) - { - liberator.statusline.updateTabCount(); - liberator.buffer.updateBufferList(); - }, false); - tabcontainer.addEventListener("TabSelect", function (event) - { - // TODO: is all of that necessary? - liberator.modes.reset(); - liberator.commandline.clear(); + liberator.statusline.updateBufferPosition(); liberator.modes.show(); - liberator.statusline.updateTabCount(); - liberator.buffer.updateBufferList(); - liberator.tabs.updateSelectionHistory(); - - setTimeout(function () { liberator.focusContent(true); }, 10); // just make sure, that no widget has focus - }, false); + }, null); } - - // this adds an event which is is called on each page load, even if the - // page is loaded in a background tab - getBrowser().addEventListener("load", onPageLoad, true); - - // called when the active document is scrolled - getBrowser().addEventListener("scroll", function (event) - { - liberator.statusline.updateBufferPosition(); - liberator.modes.show(); - }, null); + catch (e) { } // getBrowser().addEventListener("submit", function (event) // { @@ -430,7 +433,7 @@ liberator.Events = function () //{{{ var title = liberator.buffer.title; //update history - if (liberator.history) + if (url && liberator.history) liberator.history.add(url, title); liberator.buffer.updateBufferList(); @@ -531,7 +534,7 @@ liberator.Events = function () //{{{ function () { liberator.events.onEscape(); }); // add the ":" mapping in all but insert mode mappings - liberator.mappings.add([liberator.modes.NORMAL, liberator.modes.VISUAL, liberator.modes.HINTS, liberator.modes.MESSAGE, liberator.modes.CARET, liberator.modes.TEXTAREA], + liberator.mappings.add([liberator.modes.NORMAL, liberator.modes.VISUAL, liberator.modes.HINTS, liberator.modes.MESSAGE, liberator.modes.COMPOSE, liberator.modes.CARET, liberator.modes.TEXTAREA], [":"], "Enter command line mode", function () { liberator.commandline.open(":", "", liberator.modes.EX); }); @@ -950,7 +953,15 @@ liberator.Events = function () //{{{ if ((win && win.document && win.document instanceof HTMLDocument) || elem instanceof HTMLAnchorElement) { - if (liberator.mode != liberator.modes.MESSAGE) + if (liberator.config.isComposeWindow) + { + dump("Compose editor got focus\n"); + liberator.modes.set(liberator.modes.INSERT, liberator.modes.TEXTAREA); + //setTimeout(function(){liberator.editor.editWithExternalEditor();}, 100); + win.blur(); + //liberator.editor.editWithExternalEditor(); + } + else if (liberator.mode != liberator.modes.MESSAGE) liberator.mode = liberator.modes.MESSAGE; return; } @@ -1092,7 +1103,7 @@ liberator.Events = function () //{{{ var stop = true; // set to false if we should NOT consume this event but let also firefox handle it var win = document.commandDispatcher.focusedWindow; - if (win && win.document.designMode == "on") + if (win && win.document.designMode == "on" && !liberator.config.isComposeWindow) return false; // menus have their own command handlers @@ -1468,7 +1479,11 @@ liberator.Events = function () //{{{ .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIXULWindow) .XULBrowserWindow = window.XULBrowserWindow; - getBrowser().addProgressListener(eventManager.progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL); + try + { + getBrowser().addProgressListener(eventManager.progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL); + } + catch(e) { } eventManager.prefObserver.register(); diff --git a/content/io.js b/content/io.js index af5bfb49..419e4f85 100644 --- a/content/io.js +++ b/content/io.js @@ -338,15 +338,17 @@ liberator.IO = function () //{{{ { var file = Components.classes["@mozilla.org/file/local;1"]. createInstance(Components.interfaces.nsILocalFile); + + var tmpname = liberator.config.name.toLowerCase() + ".tmp" if (WINDOWS) { var dir = environmentService.get("TMP") || environmentService.get("TEMP") || "C:\\"; - file.initWithPath(dir + "\\vimperator.tmp"); + file.initWithPath(dir + "\\" + tmpname); } else { var dir = environmentService.get("TMP") || environmentService.get("TEMP") || "/tmp/"; - file.initWithPath(dir + "/vimperator.tmp"); + file.initWithPath(dir + "/" + tmpname); } file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600); diff --git a/content/liberator.js b/content/liberator.js index 3a706ca5..fe8d9784 100644 --- a/content/liberator.js +++ b/content/liberator.js @@ -501,16 +501,25 @@ const liberator = (function () //{{{ { var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]. getService(Components.interfaces.nsIWindowWatcher); - if (window == ww.activeWindow && document.commandDispatcher.focusedElement && clearFocusedElement) document.commandDispatcher.focusedElement.blur(); // TODO: make more generic - if (liberator.has("mail") && clearFocusedElement && gDBView) - gDBView.selection.select(gDBView.selection.currentIndex); + try + { + if (liberator.has("mail") && clearFocusedElement && !liberator.config.isComposeWindow) + { + var i = gDBView.selection.currentIndex; + if (i == -1 && gDBView.rowCount >= 0) + i = 0; - var elem = liberator.config.mainWidget || content; - if (elem != document.commandDispatcher.focusedElement) + gDBView.selection.select(i); + } + } + catch (e) { } + + var elem = liberator.config.mainWidget || window.content; + if (elem && (elem != document.commandDispatcher.focusedElement)) elem.focus(); }, @@ -797,7 +806,7 @@ const liberator = (function () //{{{ // optional modules if (liberator.has("bookmarks")) { log("bookmarks"); liberator.bookmarks = liberator.Bookmarks(); } if (liberator.has("history")) { log("history"); liberator.history = liberator.History(); } - if (liberator.has("mail")) { log("mail"); liberator.mail = liberator.Mail(); } + if (liberator.has("mail") && liberator.Mail) { log("mail"); liberator.mail = liberator.Mail(); } if (liberator.has("tabs")) { log("tabs"); liberator.tabs = liberator.Tabs(); } if (liberator.has("marks")) { log("marks"); liberator.marks = liberator.Marks(); } if (liberator.has("quickmarks")) { log("quickmarks"); liberator.quickmarks = liberator.QuickMarks(); } @@ -888,16 +897,17 @@ const liberator = (function () //{{{ }, 0); liberator.statusline.update(); - liberator.log("Vimperator fully initialized", 1); + liberator.log(liberator.config.name + " fully initialized", 1); }, shutdown: function () { // save our preferences liberator.commandline.destroy(); - liberator.quickmarks.destroy(); liberator.options.destroy(); liberator.events.destroy(); + if (liberator.has("quickmarks")) + liberator.quickmarks.destroy(); window.dump("All liberator modules destroyed\n"); }, diff --git a/content/mail.js b/content/mail.js index af01ac94..56660e0d 100644 --- a/content/mail.js +++ b/content/mail.js @@ -193,6 +193,11 @@ liberator.Mail = function () "Inspect (focus) message", function () { content.focus(); }); + liberator.mappings.add(modes, [""], + "Scroll message or select next unread one", + function () { return true; }, + { flags: liberator.Mappings.flags.ALLOW_EVENT_ROUTING }); + liberator.mappings.add(modes, ["x"], "Select thread", function () { gDBView.ExpandAndSelectThreadByIndex(GetThreadTree().currentIndex, false) }); diff --git a/content/modes.js b/content/modes.js index d4e48884..25ab05cf 100644 --- a/content/modes.js +++ b/content/modes.js @@ -79,6 +79,8 @@ liberator.modes = (function () //{{{ return "-- TEXTAREA" + ext; case liberator.modes.MESSAGE: return "-- MESSAGE" + ext; + case liberator.modes.COMPOSE: + return "-- COMPOSE" + ext; case liberator.modes.CUSTOM: return "-- " + liberator.plugins.mode + ext; default: // NORMAL mode @@ -162,7 +164,8 @@ liberator.modes = (function () //{{{ CARET: 1 << 5, // text cursor is visible TEXTAREA: 1 << 6, // text cursor is in a HTMLTextAreaElement MESSAGE: 1 << 7, // for now only used in Muttator when the message has focus - CUSTOM: 1 << 8, + COMPOSE: 1 << 8, + CUSTOM: 1 << 9, // extended modes, can include multiple modes, and even main modes EX: 1 << 10, INPUT_MULTILINE: 1 << 11, @@ -189,7 +192,7 @@ liberator.modes = (function () //{{{ get all() { return [this.NONE, this.NORMAL, this.INSERT, this.VISUAL, this.HINTS, this.COMMAND_LINE, this.CARET, - this.TEXTAREA, this.MESSAGE, this.CUSTOM]; }, + this.TEXTAREA, this.MESSAGE, this.COMPOSE, this.CUSTOM]; }, // show the current mode string in the command line show: function () @@ -245,7 +248,11 @@ liberator.modes = (function () //{{{ // keeps recording state reset: function (silent) { - this.set(liberator.modes.NORMAL, liberator.modes.NONE, silent); + //if (window.wintype == "msgcompose") + if (liberator.config.isComposeWindow) + this.set(liberator.modes.COMPOSE, liberator.modes.NONE, silent); + else + this.set(liberator.modes.NORMAL, liberator.modes.NONE, silent); }, remove: function (mode) diff --git a/content/muttator.js b/content/muttator.js index f3e91924..86c68432 100644 --- a/content/muttator.js +++ b/content/muttator.js @@ -36,8 +36,13 @@ liberator.config = { guioptions: { m: ["mail-toolbar-menubar2"], T: ["mail-bar2"], f: ["folderPaneBox", "folderpane_splitter"], F: ["folderPaneHeader"] }, get browserModes() { return [liberator.modes.MESSAGE]; }, - get mainWidget() { return GetThreadTree(); }, // focusContent() focuses this widget - mainWindowID: "messengerWindow", // used for :set titlestring + get mainWidget() { // focusContent() focuses this widget + return this.isComposeWindow ? + document.getElementById("content-frame") : + GetThreadTree(); + }, + get mainWindowID() { return this.isComposeWindow ? "msgcomposeWindow" : "messengerWindow"; }, + isComposeWindow: false, dialogs: [ /*["about", "About Firefox", @@ -88,8 +93,33 @@ liberator.config = { ["o"], "Open a message", function () { liberator.commandline.open(":", "open ", liberator.modes.EX); }); + liberator.mappings.add([liberator.modes.COMPOSE], + ["e"], "Edit message", + function () { liberator.editor.editWithExternalEditor(); }); + // don't wait too long when selecting new messages - GetThreadTree()._selectDelay = 300; // TODO: make configurable + // GetThreadTree()._selectDelay = 300; // TODO: make configurable + this.isComposeWindow = window.wintype == "msgcompose"; + + if (this.isComposeWindow) + { + /*setTimeout(function() { + document.getElementById("content-frame").contentDocument.designMode = "off"; + document.getElementById("content-frame").focus(); + }, 500);*/ + //document.getElementById("content-frame").contentWindow.addEventListener("load", function() { + /*window.addEventListener("load", function() { + alert("load"); + if (! liberator.editor.editWithExternalEditor()) + liberator.echoerr("Editing with external editor failed. Be sure to :set editor correctly"); + }, true); + document.getElementById("content-frame").contentDocument.addEventListener("load", function() { + alert("load1"); + }, true);*/ + /*document.getElementById("content-frame").addEventListener("DOMContentLoaded", function() { + alert("load2"); + }, true);*/ + } } } diff --git a/content/muttator.xul b/content/muttator.xul index 1ffb93cf..f041c1be 100644 --- a/content/muttator.xul +++ b/content/muttator.xul @@ -63,11 +63,11 @@ the terms of any one of the MPL, the GPL or the LGPL. + oncommandupdate="if (typeof liberator.events != 'undefined') liberator.events.onFocusChange(event);"/> + oncommandupdate="if (typeof liberator.events != 'undefined') liberator.events.onSelectionChange(event);"/> diff --git a/content/muttatorcompose.xul b/content/muttatorcompose.xul new file mode 100644 index 00000000..18591179 --- /dev/null +++ b/content/muttatorcompose.xul @@ -0,0 +1,140 @@ + + + + + + + + + +