mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2025-12-23 09:08:37 +01:00
Resurrect my range finder, Part II: Make things works sensibly with frames.
This commit is contained in:
@@ -115,11 +115,11 @@ function isobject(obj) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isarray(obj) {
|
function isarray(obj) {
|
||||||
return Object.prototype.toString(obj) == "[object Array]";
|
return Object.prototype.toString.call(obj) == "[object Array]";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isgenerator(val) {
|
function isgenerator(val) {
|
||||||
return Object.prototype.toString(obj) == "[object Generator]";
|
return Object.prototype.toString.call(val) == "[object Generator]";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isstring(val) {
|
function isstring(val) {
|
||||||
@@ -212,9 +212,11 @@ function Class() {
|
|||||||
constructor: Constructor,
|
constructor: Constructor,
|
||||||
get closure() {
|
get closure() {
|
||||||
delete this.closure;
|
delete this.closure;
|
||||||
const self = this;
|
function closure(fn) function () fn.apply(self, arguments);
|
||||||
return this.closure = dict([k for (k in this) if (!self.__lookupGetter__(k) && callable(self[k]))].map(
|
for (let k in this)
|
||||||
function (k) [k, function () self[k].apply(self, arguments)]));
|
if (!this.__lookupGetter__(k) && callable(this[k]))
|
||||||
|
closure[k] = closure(self[k]);
|
||||||
|
return this.closure = closure;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var res = self.init.apply(self, arguments);
|
var res = self.init.apply(self, arguments);
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ const Events = Module("events", {
|
|||||||
*/
|
*/
|
||||||
toString: function (event) {
|
toString: function (event) {
|
||||||
if (!event)
|
if (!event)
|
||||||
return "[object Mappings]";
|
return "[instance events]";
|
||||||
|
|
||||||
if (event.liberatorString)
|
if (event.liberatorString)
|
||||||
return event.liberatorString;
|
return event.liberatorString;
|
||||||
|
|||||||
@@ -479,13 +479,15 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
},
|
},
|
||||||
|
|
||||||
find: function (str, backwards) {
|
find: function (str, backwards) {
|
||||||
|
try {
|
||||||
let caseSensitive = false;
|
let caseSensitive = false;
|
||||||
this.rangeFind = RangeFind(caseSensitive, backwards);
|
this.rangeFind = RangeFind(caseSensitive, backwards);
|
||||||
|
|
||||||
if (!this.rangeFind.search(searchString))
|
if (!this.rangeFind.search(str))
|
||||||
setTimeout(function () { liberator.echoerr("E486: Pattern not found: " + searchPattern); }, 0);
|
setTimeout(function () { liberator.echoerr("E486: Pattern not found: " + str); }, 0);
|
||||||
|
|
||||||
return this.rangeFind.found;
|
return this.rangeFind.found;
|
||||||
|
} catch(e) { liberator.reportError(e) }
|
||||||
},
|
},
|
||||||
|
|
||||||
findAgain: function (reverse) {
|
findAgain: function (reverse) {
|
||||||
@@ -513,8 +515,10 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
// Called when the user types a key in the search dialog. Triggers a find attempt if 'incsearch' is set
|
// Called when the user types a key in the search dialog. Triggers a find attempt if 'incsearch' is set
|
||||||
onKeyPress: function (command) {
|
onKeyPress: function (command) {
|
||||||
|
try {
|
||||||
if (options["incsearch"] && this.rangeFind)
|
if (options["incsearch"] && this.rangeFind)
|
||||||
this.rangeFind.search(command);
|
this.rangeFind.search(command);
|
||||||
|
} catch(e) { liberator.reportError(e); }
|
||||||
},
|
},
|
||||||
|
|
||||||
onSubmit: function (command) {
|
onSubmit: function (command) {
|
||||||
@@ -622,28 +626,18 @@ const RangeFinder = Module("rangefinder", {
|
|||||||
|
|
||||||
const RangeFind = Class("RangeFind", {
|
const RangeFind = Class("RangeFind", {
|
||||||
init: function (matchCase, backward) {
|
init: function (matchCase, backward) {
|
||||||
this.finder = Components.classes["@mozilla.org/embedcomp/rangefind;1"]
|
this.finder = services.create("find");
|
||||||
.createInstance()
|
|
||||||
.QueryInterface(Components.interfaces.nsIFind);
|
|
||||||
this.finder.caseSensitive = matchCase;
|
this.finder.caseSensitive = matchCase;
|
||||||
this.matchCase = matchCase;
|
this.matchCase = matchCase;
|
||||||
this._backward = backward;
|
this._backward = backward;
|
||||||
this.sel = buffer.selectionController;
|
|
||||||
this.win = content;
|
|
||||||
this.doc = content.document;
|
|
||||||
|
|
||||||
this.pageRange = this.doc.createRange();
|
this.ranges = this.makeFrameList(content);
|
||||||
this.pageRange.setStartBefore(this.doc.body);
|
this.range = { document: (tabs.localStore.focusedFrame || content).document };
|
||||||
this.pageRange.setEndAfter(this.doc.body);
|
|
||||||
this.pageStart = this.pageRange.cloneRange();
|
|
||||||
this.pageEnd = this.pageRange.cloneRange();
|
|
||||||
this.pageStart.collapse(true);
|
|
||||||
this.pageEnd.collapse(false);
|
|
||||||
|
|
||||||
this.start = Point(this.win.pageXOffset, this.win.pageYOffset);
|
this.startRange = (this.selection.rangeCount ? this.selection.getRangeAt(0) : this.ranges[0].range).cloneRange();
|
||||||
this.selection = this.sel.getSelection(this.sel.SELECTION_NORMAL);
|
this.startRange.collapse(!backward);
|
||||||
this.startRange = this.selection.rangeCount ? this.selection.getRangeAt(0) : this.pageStart;
|
this.range = this.findRange(this.startRange);
|
||||||
this.startRange.collapse(true);
|
this.ranges.first = this.range;
|
||||||
|
|
||||||
this.lastString = "";
|
this.lastString = "";
|
||||||
this.lastRange = null;
|
this.lastRange = null;
|
||||||
@@ -651,9 +645,76 @@ const RangeFind = Class("RangeFind", {
|
|||||||
this.found = false;
|
this.found = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get docShell() {
|
||||||
|
for (let shell in iter(getBrowser().docShell.getDocShellEnumerator(Ci.nsIDocShellTreeItem.typeAll, Ci.nsIDocShell.ENUMERATE_FORWARDS)))
|
||||||
|
if (shell.QueryInterface(nsIWebNavigation).document == this.range.document)
|
||||||
|
return shell;
|
||||||
|
},
|
||||||
|
get selectionController() this.docShell
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsISelectionDisplay)
|
||||||
|
.QueryInterface(Ci.nsISelectionController),
|
||||||
|
get selection() this.selectionController.getSelection(Ci.nsISelectionController.SELECTION_NORMAL),
|
||||||
|
|
||||||
|
sameDocument: function (r1, r2) r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument,
|
||||||
|
|
||||||
|
compareRanges: function (r1, r2)
|
||||||
|
this.backward ? r1.compareBoundaryPoints(Range.END_TO_START, r2)
|
||||||
|
: -r1.compareBoundaryPoints(Range.START_TO_END, r2),
|
||||||
|
|
||||||
|
findRange: function (range) {
|
||||||
|
let doc = range.startContainer.ownerDocument;
|
||||||
|
let win = doc.defaultView;
|
||||||
|
let ranges = this.ranges.filter(function (r)
|
||||||
|
r.window == win &&
|
||||||
|
r.range.compareBoundaryPoints(Range.START_TO_END, range) >= 0 &&
|
||||||
|
r.range.compareBoundaryPoints(Range.END_TO_START, range) <= 0);
|
||||||
|
|
||||||
|
if (this.backward)
|
||||||
|
return ranges[ranges.length - 1];
|
||||||
|
return ranges[0];
|
||||||
|
},
|
||||||
|
|
||||||
|
makeFrameList: function (win) {
|
||||||
|
win = win.top;
|
||||||
|
let frames = [];
|
||||||
|
|
||||||
|
function endpoint(range, before) {
|
||||||
|
range = range.cloneRange();
|
||||||
|
range.collapse(before);
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
function pushRange(start, end, win) {
|
||||||
|
let scroll = Point(win.pageXOffset, win.pageYOffset);
|
||||||
|
let range = win.document.createRange();
|
||||||
|
range.setStart(start.startContainer, start.startOffset);
|
||||||
|
range.setEnd(end.startContainer, end.startOffset);
|
||||||
|
frames.push({ range: range, index: frames.length, window: win, document: win.document, scroll: scroll });
|
||||||
|
}
|
||||||
|
function rec(win) {
|
||||||
|
let doc = win.document;
|
||||||
|
let pageRange = doc.createRange();
|
||||||
|
pageRange.setStartBefore(doc.body || doc.documentElement.lastChild);
|
||||||
|
pageRange.setEndAfter(doc.body || doc.documentElement.lastChild);
|
||||||
|
let pageStart = endpoint(pageRange, true);
|
||||||
|
let pageEnd = endpoint(pageRange, false);
|
||||||
|
|
||||||
|
for (let frame in util.Array.itervalues(win.frames)) {
|
||||||
|
let range = doc.createRange();
|
||||||
|
range.selectNode(frame.frameElement);
|
||||||
|
pushRange(pageStart, endpoint(range, true), win);
|
||||||
|
pageStart = endpoint(range, false);
|
||||||
|
rec(frame);
|
||||||
|
}
|
||||||
|
pushRange(pageStart, pageEnd, win);
|
||||||
|
}
|
||||||
|
rec(win);
|
||||||
|
return frames;
|
||||||
|
},
|
||||||
|
|
||||||
// This doesn't work yet.
|
// This doesn't work yet.
|
||||||
resetCaret: function () {
|
resetCaret: function () {
|
||||||
let equal = function (r1, r2) !r1.compareToRange(Range.START_TO_START, r2) && !r1.compareToRange(Range.END_TO_END, r2);
|
let equal = function (r1, r2) !r1.compareBoundaryPoints(Range.START_TO_START, r2) && !r1.compareBoundaryPoints(Range.END_TO_END, r2);
|
||||||
letselection = this.win.getSelection();
|
letselection = this.win.getSelection();
|
||||||
if (selection.rangeCount == 0)
|
if (selection.rangeCount == 0)
|
||||||
selection.addRange(this.pageStart);
|
selection.addRange(this.pageStart);
|
||||||
@@ -696,48 +757,67 @@ const RangeFind = Class("RangeFind", {
|
|||||||
if (!this.matchCase)
|
if (!this.matchCase)
|
||||||
word = word.toLowerCase();
|
word = word.toLowerCase();
|
||||||
|
|
||||||
|
if (!again && (word == "" || word.indexOf(this.lastString) != 0 || this.backward)) {
|
||||||
|
this.unhighlight();
|
||||||
|
if (word == "")
|
||||||
|
this.deScroll(this.range);
|
||||||
|
this.lastRange = this.startRange;
|
||||||
|
this.range = this.ranges.first;
|
||||||
|
}
|
||||||
|
|
||||||
if (word == "")
|
if (word == "")
|
||||||
var range = this.startRange;
|
var range = this.startRange;
|
||||||
else {
|
else {
|
||||||
if (this.lastRange) {
|
function indices() {
|
||||||
if (again)
|
let idx = this.range.index;
|
||||||
this.lastRange.collapse(this.backward);
|
for (let i in this.backward ? util.range(idx + 1, -1, -1) : util.range(idx, this.ranges.length))
|
||||||
else if (word.indexOf(this.lastString) != 0 || this.backward)
|
yield i;
|
||||||
this.lastRange = null;
|
this.wrapped = true;
|
||||||
else
|
for (let i in this.backward ? util.range(this.ranges.length, idx, -1) : util.range(0, idx))
|
||||||
this.lastRange.collapse(true);
|
yield i;
|
||||||
}
|
}
|
||||||
|
for (let i in indices.call(this)) {
|
||||||
|
this.range = this.ranges[i];
|
||||||
|
let start = this.sameDocument(this.lastRange, this.range.range) ?
|
||||||
|
this.lastRange : this.range.range;
|
||||||
|
|
||||||
var range = this.finder.Find(word, this.pageRange,
|
var range = this.finder.Find(word, this.range.range, start, this.range.range);
|
||||||
this.lastRange || this.startRange,
|
if (range && this.compareRanges(range, this.range.range) <= 0)
|
||||||
this.pageEnd);
|
break;
|
||||||
|
this.deScroll(this.range);
|
||||||
|
this.unhighlight();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastString = word;
|
this.lastString = word;
|
||||||
if (range == null) {
|
if (range == null) {
|
||||||
if (this.wrapped) {
|
|
||||||
this.cancel();
|
this.cancel();
|
||||||
this.found = false;
|
this.found = false;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
this.wrapped = true;
|
|
||||||
this.lastRange = this.backward ? this.pageEnd : this.pageStart;
|
|
||||||
return this.search(again ? null : word, reverse);
|
|
||||||
}
|
|
||||||
this.wrapped = false;
|
this.wrapped = false;
|
||||||
this.selection.removeAllRanges();
|
this.selection.removeAllRanges();
|
||||||
this.selection.addRange(range);
|
this.selection.addRange(range);
|
||||||
this.sel.scrollSelectionIntoView(this.sel.SELECTION_NORMAL, 0, false);
|
this.selectionController.scrollSelectionIntoView(this.selectionController.SELECTION_NORMAL, 0, false);
|
||||||
this.lastRange = range.cloneRange();
|
this.lastRange = range.cloneRange();
|
||||||
this.found = true;
|
this.found = true;
|
||||||
return range;
|
return range;
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function () {
|
cancel: function () {
|
||||||
this.selection.removeAllRanges();
|
if (false) // Later.
|
||||||
this.selection.addRange(this.startRange);
|
this.selection.addRange(this.startRange);
|
||||||
this.win.scrollTo(this.start.x, this.start.y);
|
this.unhighlight();
|
||||||
|
this.deScroll(this.range);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
unhighlight: function () {
|
||||||
|
this.selection.removeAllRanges();
|
||||||
|
},
|
||||||
|
|
||||||
|
deScroll: function (range) {
|
||||||
|
range.window.scrollTo(range.scroll.x, range.scroll.y);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Stolen from toolkit.jar in Firefox, for the time being. The private
|
/* Stolen from toolkit.jar in Firefox, for the time being. The private
|
||||||
|
|||||||
Reference in New Issue
Block a user