mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-21 22:58:01 +01:00
383 lines
12 KiB
JavaScript
383 lines
12 KiB
JavaScript
/***** BEGIN LICENSE BLOCK ***** {{{
|
|
Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
The contents of this file are subject to the Mozilla Public License Version
|
|
1.1 (the "License"); you may not use this file except in compliance with
|
|
the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
for the specific language governing rights and limitations under the
|
|
License.
|
|
|
|
(c) 2006-2007: Martin Stubenschrott <stubenschrott@gmx.net>
|
|
|
|
Alternatively, the contents of this file may be used under the terms of
|
|
either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
in which case the provisions of the GPL or the LGPL are applicable instead
|
|
of those above. If you wish to allow use of your version of this file only
|
|
under the terms of either the GPL or the LGPL, and not to allow others to
|
|
use your version of this file under the terms of the MPL, indicate your
|
|
decision by deleting the provisions above and replace them with the notice
|
|
and other provisions required by the GPL or the LGPL. If you do not delete
|
|
the provisions above, a recipient may use your version of this file under
|
|
the terms of any one of the MPL, the GPL or the LGPL.
|
|
}}} ***** END LICENSE BLOCK *****/
|
|
|
|
function Buffer() //{{{
|
|
{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////// PRIVATE SECTION /////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////{{{
|
|
|
|
var zoom_manager = ZoomManager.prototype.getInstance();
|
|
const ZOOM_INTERVAL = 25;
|
|
|
|
// initialize the zoom levels
|
|
zoom_manager.zoomFactors = [zoom_manager.MIN];
|
|
for (var i = ZOOM_INTERVAL; i <= zoom_manager.MAX; i += ZOOM_INTERVAL)
|
|
zoom_manager.zoomFactors.push(i);
|
|
|
|
function setZoom(value)
|
|
{
|
|
try
|
|
{
|
|
zoom_manager.textZoom = value;
|
|
vimperator.echo("Text zoom: " + zoom_manager.textZoom + "%");
|
|
// TODO: shouldn't this just recalculate hint coords, rather than
|
|
// unsuccessfully attempt to reshow hints? i.e. isn't it just relying
|
|
// on the recalculation side effect? -- djk
|
|
// NOTE: we could really do with a zoom event...
|
|
vimperator.hints.reshowHints();
|
|
}
|
|
catch (e) // Components.results.NS_ERROR_INVALID_ARG
|
|
{
|
|
vimperator.echoerr("Zoom value out of range (" + zoom_manager.MIN + "-" + zoom_manager.MAX + ")");
|
|
}
|
|
}
|
|
|
|
// NOTE: this is only needed as there's currently no way to specify a
|
|
// multiplier when calling ZM.reduce()/ZM.enlarge(). TODO: see if we can
|
|
// get this added to ZoomManager
|
|
function bumpZoomLevel(steps)
|
|
{
|
|
var adjusted_zoom = zoom_manager.snap(zoom_manager.textZoom);
|
|
var current = zoom_manager.indexOf(adjusted_zoom);
|
|
var next = current + steps;
|
|
|
|
var start = 0, end = zoom_manager.zoomFactors.length - 1;
|
|
|
|
if ((current == start && steps < 0) || (current == end && steps > 0))
|
|
{
|
|
vimperator.beep();
|
|
return;
|
|
}
|
|
|
|
if (next < start)
|
|
next = start;
|
|
else if (next > end)
|
|
next = end;
|
|
|
|
setZoom(zoom_manager.zoomFactors[next]);
|
|
}
|
|
|
|
function checkScrollYBounds(win, direction)
|
|
{
|
|
// NOTE: it's possible to have scrollY > scrollMaxY - FF bug?
|
|
if (direction > 0 && win.scrollY >= win.scrollMaxY || direction < 0 && win.scrollY == 0)
|
|
vimperator.beep();
|
|
}
|
|
|
|
// both values are given in percent, -1 means no change
|
|
function scrollToPercentiles(horizontal, vertical)
|
|
{
|
|
var win = document.commandDispatcher.focusedWindow;
|
|
var h, v;
|
|
|
|
if (horizontal < 0)
|
|
h = win.scrollX;
|
|
else
|
|
h = win.scrollMaxX / 100 * horizontal;
|
|
|
|
if (vertical < 0)
|
|
v = win.scrollY;
|
|
else
|
|
v = win.scrollMaxY / 100 * vertical;
|
|
|
|
win.scrollTo(h, v);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////}}}
|
|
////////////////////// PUBLIC SECTION //////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////{{{
|
|
|
|
this.__defineGetter__("URL", function()
|
|
{
|
|
return window.content.document.URL;
|
|
});
|
|
|
|
this.__defineGetter__("pageHeight", function()
|
|
{
|
|
return getBrowser().mPanelContainer.boxObject.height; // FIXME: best way to do this?
|
|
});
|
|
|
|
this.__defineGetter__("textZoom", function()
|
|
{
|
|
return zoom_manager.textZoom;
|
|
});
|
|
|
|
this.__defineSetter__("textZoom", function(value)
|
|
{
|
|
setZoom(value);
|
|
});
|
|
|
|
this.__defineGetter__("title", function()
|
|
{
|
|
return window.content.document.title;
|
|
});
|
|
|
|
// returns an XPathResult object
|
|
this.evaluateXPath = function(expression, doc, ordered)
|
|
{
|
|
if (!doc)
|
|
doc = window.content.document;
|
|
|
|
var result = doc.evaluate(expression, doc,
|
|
function lookupNamespaceURI(prefix) {
|
|
switch (prefix) {
|
|
case 'xhtml':
|
|
return 'http://www.w3.org/1999/xhtml';
|
|
default:
|
|
return null;
|
|
}
|
|
},
|
|
ordered ? XPathResult.ORDERED_NODE_SNAPSHOT_TYPE : XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
|
null
|
|
);
|
|
|
|
return result;
|
|
}
|
|
|
|
// TODO: move to v.buffers.list()
|
|
this.list = function(fullmode)
|
|
{
|
|
if (fullmode)
|
|
{
|
|
// toggle the special buffer previw window
|
|
if (vimperator.bufferwindow.visible())
|
|
{
|
|
vimperator.bufferwindow.hide();
|
|
}
|
|
else
|
|
{
|
|
var items = vimperator.completion.get_buffer_completions("");
|
|
vimperator.bufferwindow.show(items);
|
|
vimperator.bufferwindow.selectItem(getBrowser().mTabContainer.selectedIndex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// TODO: move this to vimperator.buffers.get()
|
|
var items = vimperator.completion.get_buffer_completions("");
|
|
var number, indicator, title, url;
|
|
|
|
var list = "<table>"
|
|
for (var i = 0; i < items.length; i++)
|
|
{
|
|
if (i == vimperator.tabs.index())
|
|
indicator = " <span style=\"color: blue\">%</span> ";
|
|
else if (i == vimperator.tabs.index(vimperator.tabs.alternate))
|
|
indicator = " <span style=\"color: blue\">#</span> ";
|
|
else
|
|
indicator = " ";
|
|
|
|
[number, title] = items[i][0].split(/:\s+/, 2);
|
|
url = items[i][1];
|
|
|
|
list += "<tr><td align=\"right\"> " + number + "</td><td>" + indicator + "</td><td>" + title + "</td><td><span style=\"color: green\">" + url + "</span></td></tr>";
|
|
}
|
|
list += "</table>";
|
|
|
|
vimperator.commandline.echo(list, true);
|
|
}
|
|
}
|
|
|
|
this.scrollBottom = function()
|
|
{
|
|
scrollToPercentiles(-1, 100);
|
|
}
|
|
|
|
this.scrollColumns = function(cols)
|
|
{
|
|
var win = window.document.commandDispatcher.focusedWindow;
|
|
const COL_WIDTH = 20;
|
|
|
|
if (cols > 0 && win.scrollX >= win.scrollMaxX || cols < 0 && win.scrollX == 0)
|
|
vimperator.beep();
|
|
|
|
win.scrollBy(COL_WIDTH * cols, 0);
|
|
}
|
|
|
|
this.scrollEnd = function()
|
|
{
|
|
scrollToPercentiles(100, -1);
|
|
}
|
|
|
|
this.scrollLines = function(lines)
|
|
{
|
|
var win = window.document.commandDispatcher.focusedWindow;
|
|
checkScrollYBounds(win, lines);
|
|
win.scrollByLines(lines);
|
|
}
|
|
|
|
this.scrollPages = function(pages)
|
|
{
|
|
var win = window.document.commandDispatcher.focusedWindow;
|
|
checkScrollYBounds(win, pages);
|
|
win.scrollByPages(pages);
|
|
}
|
|
|
|
this.scrollToPercentile = function(percentage)
|
|
{
|
|
scrollToPercentiles(-1, percentage);
|
|
}
|
|
|
|
this.scrollStart = function()
|
|
{
|
|
scrollToPercentiles(0, -1);
|
|
}
|
|
|
|
this.scrollTop = function()
|
|
{
|
|
scrollToPercentiles(-1, 0);
|
|
}
|
|
|
|
// TODO: allow callback for filtering out unwanted frames? User defined?
|
|
this.shiftFrameFocus = function(count, forward)
|
|
{
|
|
try
|
|
{
|
|
var frames = [];
|
|
|
|
// find all frames - depth-first search
|
|
(function(frame)
|
|
{
|
|
if (frame.document.body.localName.toLowerCase() == "body")
|
|
frames.push(frame);
|
|
for (var i = 0; i < frame.frames.length; i++)
|
|
arguments.callee(frame.frames[i])
|
|
})(window.content);
|
|
|
|
if (frames.length == 0) // currently top is always included
|
|
return;
|
|
|
|
// remove all unfocusable frames
|
|
// TODO: find a better way to do this
|
|
var start = document.commandDispatcher.focusedWindow;
|
|
frames = frames.filter(function(frame) {
|
|
frame.focus();
|
|
if (document.commandDispatcher.focusedWindow == frame)
|
|
return frame;
|
|
});
|
|
start.focus();
|
|
|
|
// find the currently focused frame index
|
|
// TODO: If the window is a frameset then the first _frame_ should be
|
|
// focused. Since this is not the current FF behaviour,
|
|
// we initalize current to -1 so the first call takes us to the
|
|
// first frame.
|
|
var current = -1;
|
|
for (var i = 0; i < frames.length; i++)
|
|
{
|
|
if (frames[i] == document.commandDispatcher.focusedWindow)
|
|
{
|
|
var current = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// calculate the next frame to focus
|
|
var next = current;
|
|
if (forward)
|
|
{
|
|
if (count > 1)
|
|
next = current + count;
|
|
else
|
|
next++;
|
|
|
|
if (next > frames.length - 1)
|
|
{
|
|
if (current == frames.length - 1)
|
|
vimperator.beep(); // still allow the frame indicator to be activated
|
|
|
|
next = frames.length - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (count > 1)
|
|
next = current - count;
|
|
else
|
|
next--;
|
|
|
|
if (next < 0)
|
|
{
|
|
if (current == 0)
|
|
vimperator.beep(); // still allow the frame indicator to be activated
|
|
|
|
next = 0;
|
|
}
|
|
}
|
|
|
|
// focus next frame and scroll into view
|
|
frames[next].focus();
|
|
if (frames[next] != window.content)
|
|
frames[next].frameElement.scrollIntoView(false);
|
|
|
|
// add the frame indicator
|
|
var doc = frames[next].document;
|
|
var indicator = doc.createElement("div");
|
|
indicator.id = "vimperator-frame-indicator";
|
|
// NOTE: need to set a high z-index - it's a crapshoot!
|
|
var style = "background-color: red; opacity: 0.5; z-index: 999;" +
|
|
"position: fixed; top: 0; bottom: 0; left: 0; right: 0;";
|
|
indicator.setAttribute("style", style);
|
|
doc.body.appendChild(indicator);
|
|
|
|
// remove the frame indicator
|
|
setTimeout(function() { doc.body.removeChild(indicator); }, 500);
|
|
}
|
|
catch (e)
|
|
{
|
|
// FIXME: fail silently here for now
|
|
//vimperator.log(e);
|
|
}
|
|
}
|
|
|
|
// updates the buffer preview in place only if list is visible
|
|
this.updateBufferList = function()
|
|
{
|
|
if (!vimperator.bufferwindow.visible())
|
|
return false;
|
|
|
|
var items = vimperator.completion.get_buffer_completions("");
|
|
vimperator.bufferwindow.show(items);
|
|
vimperator.bufferwindow.selectItem(getBrowser().mTabContainer.selectedIndex);
|
|
}
|
|
|
|
this.zoomIn = function(steps)
|
|
{
|
|
bumpZoomLevel(steps);
|
|
}
|
|
|
|
this.zoomOut = function(steps)
|
|
{
|
|
bumpZoomLevel(-steps);
|
|
}
|
|
//}}}
|
|
} //}}}
|
|
|
|
// vim: set fdm=marker sw=4 ts=4 et:
|