mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-01-06 21:04:12 +01:00
Add gu, gU. Fix some editor issues and annoyances. Better undo support. Don't push TEXT_EDIT mode multiple times with noinsertmode set. Update NEWS.
This commit is contained in:
@@ -46,8 +46,28 @@ var Editor = Module("editor", {
|
|||||||
this.selection.focusOffset);
|
this.selection.focusOffset);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get selectionRange() {
|
||||||
|
if (!this.selection.rangeCount) {
|
||||||
|
let range = RangeFind.nodeContents(this.editor.rootElement.ownerDocument);
|
||||||
|
range.collapse(true);
|
||||||
|
this.selectionRange = range;
|
||||||
|
}
|
||||||
|
return this.selection.getRangeAt(0);
|
||||||
|
},
|
||||||
|
set selectionRange(range) {
|
||||||
|
this.selection.removeAllRanges();
|
||||||
|
if (range != null)
|
||||||
|
this.selection.addRange(range);
|
||||||
|
},
|
||||||
|
|
||||||
get selectedText() String(this.selection),
|
get selectedText() String(this.selection),
|
||||||
|
|
||||||
|
get preserveSelection() this.editor && !this.editor.shouldTxnSetSelection,
|
||||||
|
set preserveSelection(val) {
|
||||||
|
if (this.editor)
|
||||||
|
this.editor.setShouldTxnSetSelection(!val);
|
||||||
|
},
|
||||||
|
|
||||||
pasteClipboard: function (clipboard, toStart) {
|
pasteClipboard: function (clipboard, toStart) {
|
||||||
let elem = this.element;
|
let elem = this.element;
|
||||||
|
|
||||||
@@ -69,7 +89,7 @@ var Editor = Module("editor", {
|
|||||||
elem.value = value;
|
elem.value = value;
|
||||||
|
|
||||||
if (/^(search|text)$/.test(elem.type))
|
if (/^(search|text)$/.test(elem.type))
|
||||||
DOM(elem).rootElement.firstChild.textContent = value;
|
DOM(elem).editor.rootElement.firstChild.textContent = value;
|
||||||
|
|
||||||
elem.selectionStart = Math.min(start + (toStart ? 0 : text.length), elem.value.length);
|
elem.selectionStart = Math.min(start + (toStart ? 0 : text.length), elem.value.length);
|
||||||
elem.selectionEnd = elem.selectionStart;
|
elem.selectionEnd = elem.selectionStart;
|
||||||
@@ -118,6 +138,51 @@ var Editor = Module("editor", {
|
|||||||
this.selection[select ? "extend" : "collapse"](node, pos);
|
this.selection[select ? "extend" : "collapse"](node, pos);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
mungeRange: function mungeRange(range, munger, selectEnd) {
|
||||||
|
let { editor } = this;
|
||||||
|
editor.beginPlaceHolderTransaction(null);
|
||||||
|
|
||||||
|
let [container, offset] = ["startContainer", "startOffset"];
|
||||||
|
if (selectEnd)
|
||||||
|
[container, offset] = ["endContainer", "endOffset"];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// :(
|
||||||
|
let idx = range[offset];
|
||||||
|
let parent = range[container].parentNode;
|
||||||
|
let parentIdx = Array.indexOf(parent.childNodes,
|
||||||
|
range[container]);
|
||||||
|
|
||||||
|
for (let node in Editor.TextsIterator(range)) {
|
||||||
|
let text = node.textContent;
|
||||||
|
let start = 0, end = text.length;
|
||||||
|
if (node == range.startContainer)
|
||||||
|
start = range.startOffset;
|
||||||
|
if (node == range.endContainer)
|
||||||
|
end = range.endOffset;
|
||||||
|
|
||||||
|
if (start != 0 || end != text.length)
|
||||||
|
text = text.slice(0, start)
|
||||||
|
+ munger(text.slice(start, end))
|
||||||
|
+ text.slice(end);
|
||||||
|
else
|
||||||
|
text = munger(text);
|
||||||
|
|
||||||
|
if (editor instanceof Ci.nsIPlaintextEditor) {
|
||||||
|
this.selectionRange = RangeFind.nodeContents(node);
|
||||||
|
editor.insertText(text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
node.textContent = text;
|
||||||
|
}
|
||||||
|
this.selection.collapse(parent.childNodes[parentIdx], idx);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
editor.endPlaceHolderTransaction();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
findChar: function (key, count, backward) {
|
findChar: function (key, count, backward) {
|
||||||
|
|
||||||
util.assert(DOM(this.element).isInput);
|
util.assert(DOM(this.element).isInput);
|
||||||
@@ -322,35 +387,58 @@ var Editor = Module("editor", {
|
|||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
TextsIterator: Class("TextsIterator", {
|
TextsIterator: Class("TextsIterator", {
|
||||||
init: function init(root, context) {
|
init: function init(range, context, after) {
|
||||||
this.context = context;
|
this.after = after;
|
||||||
this.root = root;
|
this.start = context || range[after ? "endContainer" : "startContainer"];
|
||||||
|
if (after)
|
||||||
|
this.context = this.start;
|
||||||
|
this.range = range;
|
||||||
|
},
|
||||||
|
|
||||||
|
__iterator__: function __iterator__() {
|
||||||
|
while (this.nextNode())
|
||||||
|
yield this.context;
|
||||||
},
|
},
|
||||||
|
|
||||||
prevNode: function prevNode() {
|
prevNode: function prevNode() {
|
||||||
if (this.context == this.root)
|
if (!this.context)
|
||||||
return null;
|
return this.context = this.start;
|
||||||
|
|
||||||
|
var node = this.context;
|
||||||
|
if (!this.after)
|
||||||
|
node = node.previousSibling;
|
||||||
|
|
||||||
var node = this.context.previousSibling;
|
|
||||||
if (!node)
|
if (!node)
|
||||||
node = this.context.parentNode;
|
node = this.context.parentNode;
|
||||||
else
|
else
|
||||||
while (node.lastChild)
|
while (node.lastChild)
|
||||||
node = node.lastChild;
|
node = node.lastChild;
|
||||||
|
|
||||||
|
if (!node || !RangeFind.containsNode(this.range, node, true))
|
||||||
|
return null;
|
||||||
|
this.after = false;
|
||||||
return this.context = node;
|
return this.context = node;
|
||||||
},
|
},
|
||||||
|
|
||||||
nextNode: function nextNode() {
|
nextNode: function nextNode() {
|
||||||
var node = this.context.firstChild;
|
if (!this.context)
|
||||||
|
return this.context = this.start;
|
||||||
|
|
||||||
|
if (!this.after)
|
||||||
|
var node = this.context.firstChild;
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
node = this.context;
|
node = this.context;
|
||||||
while (node != this.root && !node.nextSibling)
|
while (node.parentNode && node != this.range.endContainer
|
||||||
|
&& !node.nextSibling)
|
||||||
node = node.parentNode;
|
node = node.parentNode;
|
||||||
|
|
||||||
node = node.nextSibling;
|
node = node.nextSibling;
|
||||||
}
|
}
|
||||||
if (node == this.root || node == null)
|
|
||||||
|
if (!node || !RangeFind.containsNode(this.range, node, true))
|
||||||
return null;
|
return null;
|
||||||
|
this.after = false;
|
||||||
return this.context = node;
|
return this.context = node;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -379,9 +467,12 @@ var Editor = Module("editor", {
|
|||||||
function advance(positive) {
|
function advance(positive) {
|
||||||
while (true) {
|
while (true) {
|
||||||
while (idx == text.length && (node = iterator.getNext())) {
|
while (idx == text.length && (node = iterator.getNext())) {
|
||||||
|
if (node == iterator.start)
|
||||||
|
idx = range.endOffset;
|
||||||
|
|
||||||
offset = text.length;
|
offset = text.length;
|
||||||
text += node.textContent;
|
text += node.textContent;
|
||||||
range.setEnd(node, 0);
|
range.setEnd(node, idx - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx >= text.length || re.test(text[idx]) != positive)
|
if (idx >= text.length || re.test(text[idx]) != positive)
|
||||||
@@ -393,9 +484,13 @@ var Editor = Module("editor", {
|
|||||||
while (true) {
|
while (true) {
|
||||||
while (idx == 0 && (node = iterator.getPrev())) {
|
while (idx == 0 && (node = iterator.getPrev())) {
|
||||||
let str = node.textContent;
|
let str = node.textContent;
|
||||||
idx += str.length;
|
if (node == iterator.start)
|
||||||
|
idx = range.endOffset;
|
||||||
|
else
|
||||||
|
idx = str.length;
|
||||||
|
|
||||||
text = str + text;
|
text = str + text;
|
||||||
range.setStart(node, str.length);
|
range.setStart(node, idx);
|
||||||
}
|
}
|
||||||
if (idx == 0 || re.test(text[idx - 1]) != positive)
|
if (idx == 0 || re.test(text[idx - 1]) != positive)
|
||||||
break;
|
break;
|
||||||
@@ -403,19 +498,22 @@ var Editor = Module("editor", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!root)
|
||||||
|
for (root = range.startContainer;
|
||||||
|
root.parentNode instanceof Element && !DOM(root).isEditable;
|
||||||
|
root = root.parentNode)
|
||||||
|
;
|
||||||
|
if (root instanceof Ci.nsIDOMNSEditableElement)
|
||||||
|
root = root.editor;
|
||||||
|
if (root instanceof Ci.nsIEditor)
|
||||||
|
root = root.rootElement;
|
||||||
|
|
||||||
let node = range[forward ? "endContainer" : "startContainer"];
|
let node = range[forward ? "endContainer" : "startContainer"];
|
||||||
let iterator = Editor.TextsIterator(root || node.ownerDocument.documentElement,
|
let iterator = Editor.TextsIterator(RangeFind.nodeContents(root),
|
||||||
node);
|
node, !forward);
|
||||||
|
|
||||||
if (!(node instanceof Ci.nsIDOMText)) {
|
let text = "";
|
||||||
node = iterator[forward ? "getNext" : "getPrev"]();
|
let idx = 0;
|
||||||
dactyl.assert(node);
|
|
||||||
range[forward ? "setEnd" : "setStart"](node, forward ? 0 : node.textContent.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let text = range[forward ? "endContainer" : "startContainer"].textContent;
|
|
||||||
let idx = range[forward ? "endOffset" : "startOffset"];
|
|
||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
if (forward) {
|
if (forward) {
|
||||||
@@ -621,9 +719,21 @@ var Editor = Module("editor", {
|
|||||||
addBeginInsertModeMap(["C"], ["cmd_deleteToEndOfLine"], "Delete from the cursor to the end of the line and start insert");
|
addBeginInsertModeMap(["C"], ["cmd_deleteToEndOfLine"], "Delete from the cursor to the end of the line and start insert");
|
||||||
|
|
||||||
function addMotionMap(key, desc, select, cmd, mode) {
|
function addMotionMap(key, desc, select, cmd, mode) {
|
||||||
mappings.add([modes.TEXT_EDIT], [key],
|
function doTxn(range, editor) {
|
||||||
|
try {
|
||||||
|
editor.editor.beginTransaction();
|
||||||
|
cmd(editor, range, editor.editor);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
editor.editor.endTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mappings.add([modes.TEXT_EDIT], key,
|
||||||
desc,
|
desc,
|
||||||
function ({ count, motion }) {
|
function ({ count, motion }) {
|
||||||
|
let start = editor.selectionRange.cloneRange();
|
||||||
|
|
||||||
modes.push(modes.OPERATOR, null, {
|
modes.push(modes.OPERATOR, null, {
|
||||||
count: count,
|
count: count,
|
||||||
|
|
||||||
@@ -631,17 +741,9 @@ var Editor = Module("editor", {
|
|||||||
if (stack.push || stack.fromEscape)
|
if (stack.push || stack.fromEscape)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try {
|
let range = RangeFind.union(start, editor.selectionRange);
|
||||||
editor_.beginTransaction();
|
editor.selectionRange = select ? range : start;
|
||||||
|
doTxn(range, editor);
|
||||||
let range = RangeFind.union(start, sel.getRangeAt(0));
|
|
||||||
sel.removeAllRanges();
|
|
||||||
sel.addRange(select ? range : start);
|
|
||||||
cmd(editor_, range);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
editor_.endTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
modes.delay(function () {
|
modes.delay(function () {
|
||||||
if (mode)
|
if (mode)
|
||||||
@@ -649,17 +751,31 @@ var Editor = Module("editor", {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let editor_ = editor.editor;
|
|
||||||
let sel = editor.selection;
|
|
||||||
let start = sel.getRangeAt(0).cloneRange();
|
|
||||||
},
|
},
|
||||||
{ count: true, type: "motion" });
|
{ count: true, type: "motion" });
|
||||||
|
|
||||||
|
mappings.add([modes.VISUAL], key,
|
||||||
|
desc,
|
||||||
|
function ({ count, motion }) {
|
||||||
|
dactyl.assert(editor.isTextEdit);
|
||||||
|
doTxn(editor.selectionRange, editor);
|
||||||
|
},
|
||||||
|
{ count: true, type: "motion" });
|
||||||
}
|
}
|
||||||
|
|
||||||
addMotionMap("d", "Delete motion", true, function (editor) { editor.cut(); });
|
addMotionMap(["d", "x"], "Delete text", true, function (editor) { editor.editor.cut(); });
|
||||||
addMotionMap("c", "Change motion", true, function (editor) { editor.cut(); }, modes.INSERT);
|
addMotionMap(["c"], "Change text", true, function (editor) { editor.editor.cut(); }, modes.INSERT);
|
||||||
addMotionMap("y", "Yank motion", false, function (editor, range) { dactyl.clipboardWrite(DOM.stringify(range)) });
|
addMotionMap(["y"], "Yank text", false, function (editor, range) { dactyl.clipboardWrite(DOM.stringify(range)) });
|
||||||
|
|
||||||
|
addMotionMap(["gu"], "Lowercase text", false,
|
||||||
|
function (editor, range) {
|
||||||
|
editor.mungeRange(range, String.toLocaleLowerCase);
|
||||||
|
});
|
||||||
|
|
||||||
|
addMotionMap(["gU"], "Uppercase text", false,
|
||||||
|
function (editor, range) {
|
||||||
|
editor.mungeRange(range, String.toLocaleUpperCase);
|
||||||
|
});
|
||||||
|
|
||||||
let bind = function bind(names, description, action, params)
|
let bind = function bind(names, description, action, params)
|
||||||
mappings.add([modes.INPUT], names, description,
|
mappings.add([modes.INPUT], names, description,
|
||||||
@@ -811,31 +927,13 @@ var Editor = Module("editor", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.VISUAL],
|
mappings.add([modes.VISUAL],
|
||||||
["c", "s"], "Change selected text",
|
["s"], "Change selected text",
|
||||||
function () {
|
function () {
|
||||||
dactyl.assert(editor.isTextEdit);
|
dactyl.assert(editor.isTextEdit);
|
||||||
editor.executeCommand("cmd_cut");
|
editor.executeCommand("cmd_cut");
|
||||||
modes.push(modes.INSERT);
|
modes.push(modes.INSERT);
|
||||||
});
|
});
|
||||||
|
|
||||||
mappings.add([modes.VISUAL],
|
|
||||||
["d", "x"], "Delete selected text",
|
|
||||||
function () {
|
|
||||||
dactyl.assert(editor.isTextEdit);
|
|
||||||
editor.executeCommand("cmd_cut");
|
|
||||||
});
|
|
||||||
|
|
||||||
mappings.add([modes.VISUAL],
|
|
||||||
["y"], "Yank selected text",
|
|
||||||
function () {
|
|
||||||
if (editor.isTextEdit) {
|
|
||||||
editor.executeCommand("cmd_copy");
|
|
||||||
modes.pop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
dactyl.clipboardWrite(buffer.currentWord, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
bind(["p"], "Paste clipboard contents",
|
bind(["p"], "Paste clipboard contents",
|
||||||
function ({ count }) {
|
function ({ count }) {
|
||||||
dactyl.assert(!editor.isCaret);
|
dactyl.assert(!editor.isCaret);
|
||||||
@@ -894,19 +992,6 @@ var Editor = Module("editor", {
|
|||||||
},
|
},
|
||||||
{ arg: true, count: true, type: "operator" });
|
{ arg: true, count: true, type: "operator" });
|
||||||
|
|
||||||
function mungeRange(range, munger) {
|
|
||||||
let text = munger(range);
|
|
||||||
let { startOffset, endOffset } = range;
|
|
||||||
let root = range.startContainer.parentNode;
|
|
||||||
|
|
||||||
range.deleteContents();
|
|
||||||
range.insertNode(range.startContainer.ownerDocument
|
|
||||||
.createTextNode(text));
|
|
||||||
root.normalize();
|
|
||||||
range.setStart(root.firstChild, startOffset);
|
|
||||||
range.setEnd(root.firstChild, endOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// text edit and visual mode
|
// text edit and visual mode
|
||||||
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
mappings.add([modes.TEXT_EDIT, modes.VISUAL],
|
||||||
["~"], "Switch case of the character under the cursor and move the cursor to the right",
|
["~"], "Switch case of the character under the cursor and move the cursor to the right",
|
||||||
@@ -917,21 +1002,14 @@ var Editor = Module("editor", {
|
|||||||
return c == lc ? c.toLocaleUpperCase() : lc;
|
return c == lc ? c.toLocaleUpperCase() : lc;
|
||||||
});
|
});
|
||||||
|
|
||||||
var range = editor.selection.getRangeAt(0);
|
var range = editor.selectionRange;
|
||||||
// Ugh. TODO: Utility.
|
|
||||||
if (!(range.startContainer instanceof Ci.nsIDOMText)) {
|
|
||||||
range = RangeFind.nodeContants(node.startContainer);
|
|
||||||
range.collapse(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (range.collapsed) {
|
if (range.collapsed) {
|
||||||
count = count || 1;
|
count = count || 1;
|
||||||
|
|
||||||
range.setEnd(range.startContainer,
|
range.setEnd(range.startContainer,
|
||||||
range.startOffset + count);
|
range.startOffset + count);
|
||||||
}
|
}
|
||||||
mungeRange(range, munger);
|
editor.mungeRange(range, munger, count != null);
|
||||||
editor.selection.collapse(range.startContainer, range.endOffset);
|
|
||||||
|
|
||||||
modes.pop(modes.TEXT_EDIT);
|
modes.pop(modes.TEXT_EDIT);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -867,7 +867,7 @@ var Events = Module("events", {
|
|||||||
if (!haveInput)
|
if (!haveInput)
|
||||||
if (options["insertmode"])
|
if (options["insertmode"])
|
||||||
modes.push(modes.INSERT);
|
modes.push(modes.INSERT);
|
||||||
else {
|
else if (!isinstance(modes.main, [modes.TEXT_EDIT, modes.VISUAL])) {
|
||||||
modes.push(modes.TEXT_EDIT);
|
modes.push(modes.TEXT_EDIT);
|
||||||
if (elem.selectionEnd - elem.selectionStart > 0)
|
if (elem.selectionEnd - elem.selectionStart > 0)
|
||||||
modes.push(modes.VISUAL);
|
modes.push(modes.VISUAL);
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
indexIter: function (private_) {
|
indexIter: function indexIter(private_) {
|
||||||
let idx = this.range.index;
|
let idx = this.range.index;
|
||||||
if (this.backward)
|
if (this.backward)
|
||||||
var groups = [util.range(idx + 1, 0, -1), util.range(this.ranges.length, idx, -1)];
|
var groups = [util.range(idx + 1, 0, -1), util.range(this.ranges.length, idx, -1)];
|
||||||
@@ -494,7 +494,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
iter: function (word) {
|
iter: function iter(word) {
|
||||||
let saved = ["lastRange", "lastString", "range", "regexp"].map(function (s) [s, this[s]], this);
|
let saved = ["lastRange", "lastString", "range", "regexp"].map(function (s) [s, this[s]], this);
|
||||||
let res;
|
let res;
|
||||||
try {
|
try {
|
||||||
@@ -525,7 +525,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
makeFrameList: function (win) {
|
makeFrameList: function makeFrameList(win) {
|
||||||
const self = this;
|
const self = this;
|
||||||
win = win.top;
|
win = win.top;
|
||||||
let frames = [];
|
let frames = [];
|
||||||
@@ -581,7 +581,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
return frames;
|
return frames;
|
||||||
},
|
},
|
||||||
|
|
||||||
reset: function () {
|
reset: function reset() {
|
||||||
this.ranges = this.makeFrameList(this.content);
|
this.ranges = this.makeFrameList(this.content);
|
||||||
|
|
||||||
this.startRange = this.selectedRange;
|
this.startRange = this.selectedRange;
|
||||||
@@ -594,7 +594,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
this.found = false;
|
this.found = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
find: function (pattern, reverse, private_) {
|
find: function find(pattern, reverse, private_) {
|
||||||
if (!private_ && this.lastRange && !RangeFind.equal(this.selectedRange, this.lastRange))
|
if (!private_ && this.lastRange && !RangeFind.equal(this.selectedRange, this.lastRange))
|
||||||
this.reset();
|
this.reset();
|
||||||
|
|
||||||
@@ -685,18 +685,18 @@ var RangeFind = Class("RangeFind", {
|
|||||||
get stale() this._stale || this.baseDocument.get() != this.content.document,
|
get stale() this._stale || this.baseDocument.get() != this.content.document,
|
||||||
set stale(val) this._stale = val,
|
set stale(val) this._stale = val,
|
||||||
|
|
||||||
addListeners: function () {
|
addListeners: function addListeners() {
|
||||||
for (let range in array.iterValues(this.ranges))
|
for (let range in array.iterValues(this.ranges))
|
||||||
range.window.addEventListener("unload", this.closure.onUnload, true);
|
range.window.addEventListener("unload", this.closure.onUnload, true);
|
||||||
},
|
},
|
||||||
purgeListeners: function () {
|
purgeListeners: function purgeListeners() {
|
||||||
for (let range in array.iterValues(this.ranges))
|
for (let range in array.iterValues(this.ranges))
|
||||||
try {
|
try {
|
||||||
range.window.removeEventListener("unload", this.closure.onUnload, true);
|
range.window.removeEventListener("unload", this.closure.onUnload, true);
|
||||||
}
|
}
|
||||||
catch (e if e.result === Cr.NS_ERROR_FAILURE) {}
|
catch (e if e.result === Cr.NS_ERROR_FAILURE) {}
|
||||||
},
|
},
|
||||||
onUnload: function (event) {
|
onUnload: function onUnload(event) {
|
||||||
this.purgeListeners();
|
this.purgeListeners();
|
||||||
if (this.highlighted)
|
if (this.highlighted)
|
||||||
this.highlight(true);
|
this.highlight(true);
|
||||||
@@ -704,7 +704,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
Range: Class("RangeFind.Range", {
|
Range: Class("RangeFind.Range", {
|
||||||
init: function (range, index) {
|
init: function init(range, index) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
|
||||||
this.range = range;
|
this.range = range;
|
||||||
@@ -720,7 +720,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
|
|
||||||
intersects: function (range) RangeFind.intersects(this.range, range),
|
intersects: function (range) RangeFind.intersects(this.range, range),
|
||||||
|
|
||||||
save: function () {
|
save: function save() {
|
||||||
this.scroll = Point(this.window.pageXOffset, this.window.pageYOffset);
|
this.scroll = Point(this.window.pageXOffset, this.window.pageYOffset);
|
||||||
|
|
||||||
this.initialSelection = null;
|
this.initialSelection = null;
|
||||||
@@ -728,11 +728,11 @@ var RangeFind = Class("RangeFind", {
|
|||||||
this.initialSelection = this.selection.getRangeAt(0);
|
this.initialSelection = this.selection.getRangeAt(0);
|
||||||
},
|
},
|
||||||
|
|
||||||
descroll: function () {
|
descroll: function descroll() {
|
||||||
this.window.scrollTo(this.scroll.x, this.scroll.y);
|
this.window.scrollTo(this.scroll.x, this.scroll.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
deselect: function () {
|
deselect: function deselect() {
|
||||||
if (this.selection) {
|
if (this.selection) {
|
||||||
this.selection.removeAllRanges();
|
this.selection.removeAllRanges();
|
||||||
if (this.initialSelection)
|
if (this.initialSelection)
|
||||||
@@ -752,17 +752,19 @@ var RangeFind = Class("RangeFind", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
contains: function (range, r) {
|
contains: function contains(range, r, quiet) {
|
||||||
try {
|
try {
|
||||||
return range.compareBoundaryPoints(range.START_TO_END, r) >= 0 &&
|
return range.compareBoundaryPoints(range.START_TO_END, r) >= 0 &&
|
||||||
range.compareBoundaryPoints(range.END_TO_START, r) <= 0;
|
range.compareBoundaryPoints(range.END_TO_START, r) <= 0;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
util.reportError(e, true);
|
if (e.result != Cr.NS_ERROR_DOM_WRONG_DOCUMENT_ERR && !quiet)
|
||||||
|
util.reportError(e, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
intersects: function (range, r) {
|
containsNode: function containsNode(range, n, quiet) n.ownerDocument && this.contains(range, RangeFind.nodeRange(n), quiet),
|
||||||
|
intersects: function intersects(range, r) {
|
||||||
try {
|
try {
|
||||||
return r.compareBoundaryPoints(range.START_TO_END, range) >= 0 &&
|
return r.compareBoundaryPoints(range.START_TO_END, range) >= 0 &&
|
||||||
r.compareBoundaryPoints(range.END_TO_START, range) <= 0;
|
r.compareBoundaryPoints(range.END_TO_START, range) <= 0;
|
||||||
@@ -772,12 +774,12 @@ var RangeFind = Class("RangeFind", {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
endpoint: function (range, before) {
|
endpoint: function endpoint(range, before) {
|
||||||
range = range.cloneRange();
|
range = range.cloneRange();
|
||||||
range.collapse(before);
|
range.collapse(before);
|
||||||
return range;
|
return range;
|
||||||
},
|
},
|
||||||
equal: function (r1, r2) {
|
equal: function equal(r1, r2) {
|
||||||
try {
|
try {
|
||||||
return !r1.compareBoundaryPoints(r1.START_TO_START, r2) && !r1.compareBoundaryPoints(r1.END_TO_END, r2);
|
return !r1.compareBoundaryPoints(r1.START_TO_START, r2) && !r1.compareBoundaryPoints(r1.END_TO_END, r2);
|
||||||
}
|
}
|
||||||
@@ -785,7 +787,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nodeContents: function (node) {
|
nodeContents: function nodeContents(node) {
|
||||||
let range = node.ownerDocument.createRange();
|
let range = node.ownerDocument.createRange();
|
||||||
try {
|
try {
|
||||||
range.selectNodeContents(node);
|
range.selectNodeContents(node);
|
||||||
@@ -793,7 +795,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
catch (e) {}
|
catch (e) {}
|
||||||
return range;
|
return range;
|
||||||
},
|
},
|
||||||
nodeRange: function (node) {
|
nodeRange: function nodeRange(node) {
|
||||||
let range = node.ownerDocument.createRange();
|
let range = node.ownerDocument.createRange();
|
||||||
try {
|
try {
|
||||||
range.selectNode(node);
|
range.selectNode(node);
|
||||||
@@ -801,7 +803,7 @@ var RangeFind = Class("RangeFind", {
|
|||||||
catch (e) {}
|
catch (e) {}
|
||||||
return range;
|
return range;
|
||||||
},
|
},
|
||||||
sameDocument: function (r1, r2) {
|
sameDocument: function sameDocument(r1, r2) {
|
||||||
if (!(r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument))
|
if (!(r1 && r2 && r1.endContainer.ownerDocument == r2.endContainer.ownerDocument))
|
||||||
return false;
|
return false;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -30,17 +30,44 @@
|
|||||||
everywhere from command-line and message history to option
|
everywhere from command-line and message history to option
|
||||||
values and cookies. [b1]
|
values and cookies. [b1]
|
||||||
• New and much more powerful incremental search implementation.
|
• New and much more powerful incremental search implementation.
|
||||||
Improvements over the standard Firefox find include: [b1]
|
Improvements over the standard Firefox find include:
|
||||||
- Starts at the cursor position in the currently selected
|
- Starts at the cursor position in the currently selected
|
||||||
frame, unlike Firefox, which always starts at the start of
|
frame, unlike Firefox, which always starts at the start of
|
||||||
the first frame.
|
the first frame. [b1]
|
||||||
- Returns the cursor and viewport to their original position
|
- Returns the cursor and viewport to their original position
|
||||||
on cancel.
|
on cancel. [b1]
|
||||||
- Backtracks to the first successful match after pressing
|
- Backtracks to the first successful match after pressing
|
||||||
backspace.
|
backspace. [b1]
|
||||||
- Supports reverse incremental search.
|
- Supports reverse incremental search. [b1]
|
||||||
- Input boxes are not focused when matches are highlighted.
|
- Input boxes are not focused when matches are highlighted. [b1]
|
||||||
- Crude regular expression search is supported. [b8]
|
- Crude regular expression search is supported. [b8]
|
||||||
|
- New searches now start within the current viewport where possible. [b8]
|
||||||
|
• Text editing improvements, including:
|
||||||
|
- Added t_gu and t_gU. [b8]
|
||||||
|
- Added operator modes and proper first class motion maps. [b8]
|
||||||
|
- Improved undo support for most mappings. [b8]
|
||||||
|
• General completion improvements
|
||||||
|
- Greatly improved completion rendering performance, especially
|
||||||
|
while scrolling. [b8]
|
||||||
|
- Added c_<C-f>, c_<C-b>, c_<C-Tab>, and c_<C-S-Tab> for scrolling
|
||||||
|
the completion list in increments larger than one line. [b8]
|
||||||
|
- Improved handling of asynchronous completions, including: [b8]
|
||||||
|
+ Pressing <Return> after tabbing past the end of already received
|
||||||
|
completions will execute the command after the desired result has
|
||||||
|
arrived.
|
||||||
|
+ Tabbing past the end of available completions more reliably selects
|
||||||
|
the desired completion when it is available.
|
||||||
|
+ Late arriving completion results no longer interfere with typing.
|
||||||
|
+ It is now possible to skip past the end of incomplete completion
|
||||||
|
groups via the c_<C-f> and c_<C-Tab> keys.
|
||||||
|
- JavaScript completion improvements, including: [b2]
|
||||||
|
+ The prototype of the function whose arguments are currently
|
||||||
|
being typed is displayed during completion.
|
||||||
|
+ Non-enumerable global properties are now completed for the
|
||||||
|
global object, including XMLHttpRequest and encodeURI.
|
||||||
|
- The concept of completion contexts is now exposed to the user
|
||||||
|
(see :contexts), allowing for powerful and fine-grained
|
||||||
|
completion system customization. [b1]
|
||||||
• Ex command parsing improvements, including:
|
• Ex command parsing improvements, including:
|
||||||
- Multiple Ex commands may now be separated by | [b1]
|
- Multiple Ex commands may now be separated by | [b1]
|
||||||
- Commands can continue over multiple lines in RC files by
|
- Commands can continue over multiple lines in RC files by
|
||||||
@@ -61,15 +88,6 @@
|
|||||||
- Added ;a and ;S modes for creating bookmarks and search keywords. [b4][b3]
|
- Added ;a and ;S modes for creating bookmarks and search keywords. [b4][b3]
|
||||||
- Added 'hintkeys' option. [b2]
|
- Added 'hintkeys' option. [b2]
|
||||||
- Added "transliterated" option to 'hintmatching'. [b1]
|
- Added "transliterated" option to 'hintmatching'. [b1]
|
||||||
• General completion improvements
|
|
||||||
- JavaScript completion improvements, including: [b2]
|
|
||||||
+ The prototype of the function whose arguments are currently
|
|
||||||
being typed is displayed during completion.
|
|
||||||
+ Non-enumerable global properties are now completed for the
|
|
||||||
global object, including XMLHttpRequest and encodeURI.
|
|
||||||
- The concept of completion contexts is now exposed to the user
|
|
||||||
(see :contexts), allowing for powerful and fine-grained
|
|
||||||
completion system customization. [b1]
|
|
||||||
• The external editor can now be configured to open to a given
|
• The external editor can now be configured to open to a given
|
||||||
line number and column, used for opening source links and
|
line number and column, used for opening source links and
|
||||||
editing input fields with i_<C-i>. See :h 'editor'. [b4]
|
editing input fields with i_<C-i>. See :h 'editor'. [b4]
|
||||||
|
|||||||
Reference in New Issue
Block a user