diff --git a/common/content/buffer.js b/common/content/buffer.js
index 8912ad0a..25c8cfed 100644
--- a/common/content/buffer.js
+++ b/common/content/buffer.js
@@ -352,6 +352,12 @@ var Buffer = Module("buffer", {
return elem.scrollTop * 100 / (elem.scrollHeight - elem.clientHeight);
},
+ /**
+ * @property {{ x: number, y: number }} The buffer's current scroll position
+ * as reported by {@link Buffer.getScrollPosition}.
+ */
+ get scrollPosition() Buffer.getScrollPosition(this.findScrollable(0, false)),
+
/**
* Adds a new section to the page information output.
*
@@ -705,6 +711,14 @@ var Buffer = Module("buffer", {
scrollToPercent: function scrollToPercent(horizontal, vertical)
Buffer.scrollToPercent(this.findScrollable(0, vertical == null), horizontal, vertical),
+ /**
+ * Scrolls the currently active element to the given horizontal and
+ * vertical positions. See {@link Buffer.scrollToPosition} for
+ * parameters.
+ */
+ scrollToPosition: function scrollToPosition(horizontal, vertical)
+ Buffer.scrollToPosition(this.findScrollable(0, vertical == null), horizontal, vertical),
+
_scrollByScrollSize: function _scrollByScrollSize(count, direction) {
if (count > 0)
options["scroll"] = count;
@@ -1248,6 +1262,7 @@ var Buffer = Module("buffer", {
// Temporary hack. Should be done better.
if (elem.ownerDocument == buffer.focusedFrame.document)
marks.add("'");
+
if (left != null)
elem.scrollLeft = left;
if (top != null)
@@ -1301,7 +1316,7 @@ var Buffer = Module("buffer", {
* given direction.
*/
scrollVertical: function scrollVertical(elem, increment, number) {
- let fontSize = parseInt(util.computedStyle(elem).fontSize);
+ let fontSize = parseInt(util.computedStyle(elem).lineHeight);
if (increment == "lines")
increment = fontSize;
else if (increment == "pages")
@@ -1337,6 +1352,50 @@ var Buffer = Module("buffer", {
: (elem.scrollHeight - elem.clientHeight) * (vertical / 100));
},
+ /**
+ * Scrolls the currently active element to the given horizontal and
+ * vertical position.
+ *
+ * @param {Element} elem The element to scroll.
+ * @param {number|null} horizontal The possibly fractional
+ * line ordinal to scroll to.
+ * @param {number|null} vertical The possibly fractional
+ * column ordinal to scroll to.
+ */
+ scrollToPosition: function scrollToPosition(elem, horizontal, vertical) {
+ let style = util.computedStyle(elem);
+ Buffer.scrollTo(elem,
+ horizontal == null ? null :
+ horizontal == 0 ? 0 : this._exWidth(elem) * horizontal,
+ vertical == null ? null : parseFloat(style.lineHeight) * vertical);
+ },
+
+ /**
+ * Returns the current scroll position as understood by
+ * {@link #scrollToPosition}.
+ *
+ * @param {Element} elem The element to scroll.
+ */
+ getScrollPosition: function getPosition(elem) {
+ let style = util.computedStyle(elem);
+ return {
+ x: elem.scrollLeft && elem.scrollLeft / this._exWidth(elem),
+ y: elem.scrollTop / parseFloat(style.lineHeight)
+ }
+ },
+
+ _exWidth: function _exWidth(elem) {
+ let div = elem.appendChild(
+ util.xmlToDom(,
+ elem.ownerDocument));
+ try {
+ return parseFloat(util.computedStyle(div).width);
+ }
+ finally {
+ div.parentNode.removeChild(div);
+ }
+ },
+
openUploadPrompt: function openUploadPrompt(elem) {
io.CommandFileMode(_("buffer.prompt.uploadFile") + " ", {
onSubmit: function onSubmit(path) {
@@ -2010,12 +2069,12 @@ var Buffer = Module("buffer", {
options.add(["nextpattern"],
"Patterns to use when guessing the next page in a document sequence",
- "regexplist", UTF8("'\\bnext\\b',^>$,^(>>|»)$,^(>|»),(>|»)$,'\\bmore\\b'"),
+ "regexplist", UTF8(/'\bnext\b',^>$,^(>>|»)$,^(>|»),(>|»)$,'\bmore\b'/.source),
{ regexpFlags: "i" });
options.add(["previouspattern"],
"Patterns to use when guessing the previous page in a document sequence",
- "regexplist", UTF8("'\\bprev|previous\\b',^<$,^(<<|«)$,^(<|«),(<|«)$"),
+ "regexplist", UTF8(/'\bprev|previous\b',^<$,^(<<|«)$,^(<|«),(<|«)$/.source),
{ regexpFlags: "i" });
options.add(["pageinfo", "pa"],
diff --git a/common/content/marks.js b/common/content/marks.js
index 8e563283..5af61cc9 100644
--- a/common/content/marks.js
+++ b/common/content/marks.js
@@ -48,16 +48,16 @@ var Marks = Module("marks", {
let win = buffer.focusedFrame;
let doc = win.document;
- let position = { x: buffer.scrollXPercent / 100, y: buffer.scrollYPercent / 100 };
+ let position = buffer.scrollPosition;
if (Marks.isURLMark(mark)) {
- let res = this._urlMarks.set(mark, { location: doc.documentURI, position: position, tab: Cu.getWeakReference(tabs.getTab()), timestamp: Date.now()*1000 });
+ let res = this._urlMarks.set(mark, { location: doc.documentURI, offset: position, tab: Cu.getWeakReference(tabs.getTab()), timestamp: Date.now()*1000 });
if (!silent)
dactyl.log(_("mark.addURL", Marks.markToString(mark, res)), 5);
}
else if (Marks.isLocalMark(mark)) {
let marks = this._localMarks.get(doc.documentURI, {});
- marks[mark] = { location: doc.documentURI, position: position, timestamp: Date.now()*1000 };
+ marks[mark] = { location: doc.documentURI, offset: position, timestamp: Date.now()*1000 };
this._localMarks.changed();
if (!silent)
dactyl.log(_("mark.addLocal", Marks.markToString(mark, marks[mark])), 5);
@@ -116,7 +116,7 @@ var Marks = Module("marks", {
let doc = tab.linkedBrowser.contentDocument;
if (doc.documentURI == mark.location) {
dactyl.log(_("mark.jumpingToURL", Marks.markToString(char, mark)), 5);
- buffer.scrollToPercent(mark.position.x * 100, mark.position.y * 100);
+ this._scrollTo(mark);
}
else {
this._pendingJumps.push(mark);
@@ -147,13 +147,20 @@ var Marks = Module("marks", {
dactyl.assert(mark, _("mark.unset", char));
dactyl.log(_("mark.jumpingToLocal", Marks.markToString(char, mark)), 5);
- buffer.scrollToPercent(mark.position.x * 100, mark.position.y * 100);
+ this._scrollTo(mark);
}
else
dactyl.echoerr(_("mark.invalid"));
},
+ _scrollTo: function _scrollTo(mark) {
+ if (mark.position)
+ buffer.scrollToPercent(mark.position.x * 100, mark.position.y * 100);
+ else if (mark.offset)
+ buffer.scrollToPosition(mark.offset.x, mark.offset.y);
+ },
+
/**
* List all marks matching *filter*.
*
@@ -174,18 +181,20 @@ var Marks = Module("marks", {
template.tabular(
["Mark", "HPos", "VPos", "File"],
["", "text-align: right", "text-align: right", "color: green"],
- ([mark[0],
- Math.round(mark[1].position.x * 100) + "%",
- Math.round(mark[1].position.y * 100) + "%",
- mark[1].location]
- for ([, mark] in Iterator(marks)))));
+ ([name,
+ mark.position ? Math.round(mark.position.x * 100) + "%"
+ : Math.round(mark.offset.x),
+ mark.position ? Math.round(mark.position.y * 100) + "%"
+ : Math.round(mark.offset.y),
+ mark.location]
+ for ([, [name, mark]] in Iterator(marks)))));
},
_onPageLoad: function _onPageLoad(event) {
let win = event.originalTarget.defaultView;
for (let [i, mark] in Iterator(this._pendingJumps)) {
if (win && win.location.href == mark.location) {
- buffer.scrollToPercent(mark.position.x * 100, mark.position.y * 100);
+ this._scrollTo(mark);
this._pendingJumps.splice(i, 1);
return;
}
@@ -194,10 +203,18 @@ var Marks = Module("marks", {
}, {
markToString: function markToString(name, mark) {
let tab = mark.tab && mark.tab.get();
- return name + ", " + mark.location +
- ", (" + Math.round(mark.position.x * 100) +
- "%, " + Math.round(mark.position.y * 100) + "%)" +
- (tab ? ", tab: " + tabs.index(tab) : "");
+ if (mark.position)
+ return [name, mark.location,
+ "(" + Math.round(mark.position.x * 100) + "%",
+ Math.round(mark.position.y * 100) + "%)",
+ (tab && "tab: " + tabs.index(tab))
+ ].filter(util.identity).join(", ");
+
+ return [name, mark.location,
+ "(" + Math.round(mark.offset.x * 100),
+ Math.round(mark.offset.y * 100) + ")",
+ (tab && "tab: " + tabs.index(tab))
+ ].filter(util.identity).join(", ");
},
isLocalMark: function isLocalMark(mark) /^[a-z`']$/.test(mark),
diff --git a/pentadactyl/NEWS b/pentadactyl/NEWS
index 7c32c645..db357ee8 100644
--- a/pentadactyl/NEWS
+++ b/pentadactyl/NEWS
@@ -71,6 +71,7 @@
editing input fields with i_. See :h 'editor'. [b4]
• Improved [macro-string] support, including automatic elision
of optional elements, and array subscripts. [b4][b7]
+ • Marks are now stored as line and column ordinals rather than percentages. [b8]
• Mapping changes:
- It's now possible to map keys in many more modes, including
Hint, Multi-line Output, and Menu. [b4]