diff --git a/content/buffers.js b/content/buffers.js index 2ce7624f..102f364a 100644 --- a/content/buffers.js +++ b/content/buffers.js @@ -283,13 +283,6 @@ vimperator.Buffer = function () //{{{ return window.content.document.title; }, - // quick function to get elements inside the document reliably - // argument "args" is something like: @id='myid' or @type='text' (don't forget the quoted around myid) - element: function (args, index) - { - return vimperator.buffer.evaluateXPath("//*[" + (args || "") + "]").snapshotItem(index || 0) - }, - // returns an XPathResult object evaluateXPath: function (expression, doc, elem, asIterator) { @@ -316,14 +309,33 @@ vimperator.Buffer = function () //{{{ return result; }, + // quick function to get elements inside the document reliably + // argument "args" is something like: @id='myid' or @type='text' (don't forget the quoted around myid) + getElement: function (args, index) + { + return vimperator.buffer.evaluateXPath("//*[" + (args || "") + "]").snapshotItem(index || 0) + }, + // artificially "clicks" a link in order to open it - followLink: function (elem, where, offsetX, offsetY) + followLink: function (elem, where) { var doc = window.content.document; var view = window.document.defaultView; - //var view = doc.defaultView; - offsetX = offsetX || 1; - offsetY = offsetY || 1; + var offsetX = 1; + var offsetY = 1; + + var localName = elem.localName.toLowerCase(); + if (localName == "frame" || localName == "iframe") // broken? + { + elem.contentWindow.focus(); + return false; + } + else if (localName == "area") // for imagemap + { + var coords = elem.getAttribute("coords").split(","); + offsetX = Number(coords[0]) + 1; + offsetY = Number(coords[1]) + 1; + } var newTab = false, newWindow = false; switch (where) @@ -339,15 +351,80 @@ vimperator.Buffer = function () //{{{ vimperator.log("Invalid where argument for followLink()"); } + elem.focus(); + var evt = doc.createEvent("MouseEvents"); evt.initMouseEvent("mousedown", true, true, view, 1, offsetX, offsetY, 0, 0, /*ctrl*/ newTab, /*event.altKey*/0, /*event.shiftKey*/ newWindow, /*event.metaKey*/ newTab, 0, null); elem.dispatchEvent(evt); - - //var evt = doc.createEvent("MouseEvents"); evt.initMouseEvent("click", true, true, view, 1, offsetX, offsetY, 0, 0, /*ctrl*/ newTab, /*event.altKey*/0, /*event.shiftKey*/ newWindow, /*event.metaKey*/ newTab, 0, null); elem.dispatchEvent(evt); }, + // more advanced than a simple elem.focus() as it also works for iframes + // and image maps + // TODO: merge with followLink()? + focusElement: function (elem) + { + var doc = window.content.document; + var elemTagName = elem.localName.toLowerCase(); + if (elemTagName == "frame" || elemTagName == "iframe") + { + elem.contentWindow.focus(); + return false; + } + else + { + elem.focus(); + } + + var evt = doc.createEvent("MouseEvents"); + var x = 0; + var y = 0; + // for imagemap + if (elemTagName == "area") + { + var coords = elem.getAttribute("coords").split(","); + x = Number(coords[0]); + y = Number(coords[1]); + } + + evt.initMouseEvent("mouseover", true, true, doc.defaultView, 1, x, y, 0, 0, 0, 0, 0, 0, 0, null); + elem.dispatchEvent(evt); + }, + + yankElementText: function (elem) + { + var text = elem.textContent || ""; + vimperator.copyToClipboard(text); + vimperator.echo("Yanked " + text, vimperator.commandline.FORCE_SINGLELINE); + }, + + yankElementLocation: function (elem) + { + var loc = elem.href || ""; + vimperator.copyToClipboard(loc); + vimperator.echo("Yanked " + loc, vimperator.commandline.FORCE_SINGLELINE); + }, + + saveLink: function (elem, skipPrompt) + { + var doc = elem.ownerDocument; + var url = makeURLAbsolute(elem.baseURI, elem.href); + var text = elem.textContent; + + try + { + urlSecurityCheck(url, doc.nodePrincipal); + // we always want to save that link relative to the current working directory + vimperator.options.setFirefoxPref("browser.download.lastDir", vimperator.io.getCurrentDirectory()); + saveURL(url, text, null, true, skipPrompt, makeURI(url, doc.characterSet)); + } + catch (e) + { + vimperator.echoerr(e); + } + }, + // in contrast to vim, returns the selection if one is made, // otherwise tries to guess the current word unter the text cursor // NOTE: might change the selection @@ -668,7 +745,14 @@ vimperator.Buffer = function () //{{{ bumpZoomLevel(-steps, fullZoom); }, - pageInfo: function (verbose) + // similar to pageInfo + // TODO: print more useful information, just like the DOM inspector + showElementInfo: function (elem) + { + vimperator.echo("Element:
" + vimperator.objectToString(elem), vimperator.commandline.FORCE_MULTILINE); + }, + + showPageInfo: function (verbose) { const feedTypes = { "application/rss+xml": "RSS", diff --git a/content/commands.js b/content/commands.js index ee57c333..68a30e88 100644 --- a/content/commands.js +++ b/content/commands.js @@ -722,14 +722,14 @@ vimperator.Commands = function () //{{{ case "pagesource": BrowserViewSourceOfDocument(content.document); break; case "places": PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); break; case "preferences": openPreferences(); break; - // XXX what are onEnter.. and onExit...? + // XXX what are onEnter.. and onExit...? case "printpreview": PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); break; case "print": PrintUtils.print(); break; case "printsetup": PrintUtils.showPageSetup(); break; case "saveframe": saveFrameDocument(); break; case "savepage": saveDocument(window.content.document); break; case "searchengines": openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); break; - // TODO add viewPartialSource('selection'); ... + // TODO add viewPartialSource('selection'); ... case "": vimperator.echoerr("E474: Invalid argument"); break; default: vimperator.echoerr("Dialog '" + args + "' not available"); } @@ -1745,7 +1745,7 @@ vimperator.Commands = function () //{{{ } )); commandManager.add(new vimperator.Command(["pa[geinfo]"], - function () { vimperator.buffer.pageInfo(true); }, + function () { vimperator.buffer.showPageInfo(true); }, { shortHelp: "Show various page information", help: "See :help 'pageinfo' for available options" @@ -1883,11 +1883,24 @@ vimperator.Commands = function () //{{{ } )); commandManager.add(new vimperator.Command(["sav[eas]", "w[rite]"], - function () { saveDocument(window.content.document); }, + function (args, special) + { + var file = vimperator.io.getFile(args || ""); + // we always want to save that link relative to the current working directory + vimperator.options.setFirefoxPref("browser.download.lastDir", vimperator.io.getCurrentDirectory()); + //if (args) + //{ + // saveURL(vimperator.buffer.URL, args, null, true, special, // special == skipPrompt + // makeURI(vimperator.buffer.URL, content.document.characterSet)); + //} + //else + saveDocument(window.content.document, special); + }, { shortHelp: "Save current web page to disk", help: "Opens the original Firefox \"Save page as...\" dialog.
" + - "There, you can save the current web page to disk with various options." + "There, you can save the current web page to disk with various options. " + + "Use ! to save the file with a default filename to the current working directory, skipping the Save as... prompt" } )); commandManager.add(new vimperator.Command(["se[t]"], diff --git a/content/help.js b/content/help.js index c546aa53..f5869830 100644 --- a/content/help.js +++ b/content/help.js @@ -301,7 +301,7 @@ vimperator.Help = function(section) { vimperator.open("chrome://vimperator/locale/" + file); setTimeout(function() { - var elem = vimperator.buffer.element('@class="tag" and text()="' + tag + '"'); + var elem = vimperator.buffer.getElement('@class="tag" and text()="' + tag + '"'); if (elem) window.content.scrollTo(0, elem.getBoundingClientRect().top - 10); // 10px context }, 100); diff --git a/content/hints.js b/content/hints.js index 329f5c01..0b23a22a 100644 --- a/content/hints.js +++ b/content/hints.js @@ -74,93 +74,6 @@ vimperator.Hints = function () //{{{ (hintNumber > 0 ? " <" + hintNumber + ">" : "")); } - // this function 'click' an element, which also works - // for javascript links - function openHint(elem, where) - { - var x = 1, y = 1; - var elemTagName = elem.localName.toLowerCase(); - elem.focus(); - if (elemTagName == "frame" || elemTagName == "iframe") - return false; - - // for imagemap - if (elemTagName == "area") - { - var coords = elem.getAttribute("coords").split(","); - x = Number(coords[0]) + 1; - y = Number(coords[1]) + 1; - } - - vimperator.buffer.followLink(elem, where, x, y); - return true; - } - - function focusHint(elem) - { - var doc = window.content.document; - var elemTagName = elem.localName.toLowerCase(); - if (elemTagName == "frame" || elemTagName == "iframe") - { - elem.contentWindow.focus(); - return false; - } - else - { - elem.focus(); - } - - var evt = doc.createEvent("MouseEvents"); - var x = 0; - var y = 0; - // for imagemap - if (elemTagName == "area") - { - var coords = elem.getAttribute("coords").split(","); - x = Number(coords[0]); - y = Number(coords[1]); - } - - evt.initMouseEvent("mouseover", true, true, doc.defaultView, 1, x, y, 0, 0, 0, 0, 0, 0, 0, null); - elem.dispatchEvent(evt); - } - - // TODO: print more useful information, just like the DOM inspector - function printHint(elem) - { - vimperator.echo("Element:
" + vimperator.objectToString(elem), vimperator.commandline.FORCE_MULTILINE); - } - - function yankHint(elem, text) - { - if (text) - var loc = elem.textContent || ""; - else - var loc = elem.href || ""; - - vimperator.copyToClipboard(loc); - // TODO: echoed text disappears immediately - vimperator.echo("Yanked " + loc, vimperator.commandline.FORCE_SINGLELINE); - } - - // TODO: should use the 'cwd', does it? - function saveHint(elem, skipPrompt) - { - var doc = elem.ownerDocument; - var url = makeURLAbsolute(elem.baseURI, elem.href); - var text = elem.textContent; - - try - { - urlSecurityCheck(url, doc.nodePrincipal); - saveURL(url, text, null, true, skipPrompt, makeURI(url, doc.characterSet)); - } - catch (e) - { - vimperator.echoerr(e); - } - } - function generate(win) { var startDate = Date.now(); @@ -232,7 +145,7 @@ vimperator.Hints = function () //{{{ for (var i = 0; i < win.frames.length; i++) generate(win.frames[i]); - vimperator.log("hints.generate() completed after: " + (Date.now() - startDate) + "ms"); + vimperator.log("hints.generate() completed after: " + (Date.now() - startDate) + "ms for " + hints.length + " hints."); return true; } @@ -427,20 +340,20 @@ vimperator.Hints = function () //{{{ switch (submode) { // TODO: move/rename those helper functions to a better place - case ";": focusHint(elem); break; - case "?": printHint(elem); break; - case "a": saveHint(elem, false); break; - case "s": saveHint(elem, true); break; - case "o": openHint(elem, vimperator.CURRENT_TAB); break; + case ";": vimperator.buffer.focusElement(elem); break; + case "?": vimperator.buffer.showElementInfo(elem); break; + case "a": vimperator.buffer.saveLink(elem, false); break; + case "s": vimperator.buffer.saveLink(elem, true); break; + case "o": vimperator.buffer.followLink(elem, vimperator.CURRENT_TAB); break; case "O": vimperator.commandline.open(":", "open " + loc, vimperator.modes.EX); break; - case "t": openHint(elem, vimperator.NEW_TAB); break; + case "t": vimperator.buffer.followLink(elem, vimperator.NEW_TAB); break; case "T": vimperator.commandline.open(":", "tabopen " + loc, vimperator.modes.EX); break; case "v": vimperator.commands.viewsource(loc); break; case "V": vimperator.commands.viewsource(loc, true); break; - case "w": openHint(elem, vimperator.NEW_WINDOW); break; + case "w": vimperator.buffer.followLink(elem, vimperator.NEW_WINDOW); break; case "W": vimperator.commandline.open(":", "winopen " + loc, vimperator.modes.EX); break; - case "y": yankHint(elem, false); break; - case "Y": yankHint(elem, true); break; + case "y": vimperator.buffer.yankElementLocation(elem); break; + case "Y": vimperator.buffer.yankElementText(elem); break; default: vimperator.echoerr("INTERNAL ERROR: unknown submode: " + submode); } diff --git a/content/io.js b/content/io.js index 64a9a014..5bfbccb7 100644 --- a/content/io.js +++ b/content/io.js @@ -54,6 +54,11 @@ vimperator.IO = function () //{{{ MODE_SYNC: 0x40, MODE_EXCL: 0x80, + get directorySeperator() + { + return WINDOWS ? "\\" : "/"; + }, + expandPath: function (path) { // TODO: proper pathname separator translation like Vim diff --git a/content/mappings.js b/content/mappings.js index cc14cd22..b4f61c77 100644 --- a/content/mappings.js +++ b/content/mappings.js @@ -1099,7 +1099,7 @@ vimperator.Mappings = function () //{{{ // page info addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], [""], - function (count) { vimperator.buffer.pageInfo(false); }, + function (count) { vimperator.buffer.showPageInfo(false); }, { shortHelp: "Print the current file name", help: "Also shows some additional file information like file size or the last modified date. " + @@ -1108,7 +1108,7 @@ vimperator.Mappings = function () //{{{ } )); addDefaultMap(new vimperator.Map([vimperator.modes.NORMAL], ["g"], - function (count) { vimperator.buffer.pageInfo(true); }, + function (count) { vimperator.buffer.showPageInfo(true); }, { shortHelp: "Print file information", help: "Same as :pa[geinfo]."