mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-30 08:59:39 +00:00
Improve selection
This commit is contained in:
@@ -14,10 +14,126 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
selection = null
|
||||
|
||||
# get_line_range = (y) ->
|
||||
# first_node = term.children[y].firstChild
|
||||
# last_node = term.children[y].lastChild
|
||||
|
||||
# range = document.createRange()
|
||||
# range.setStart first_node, 0
|
||||
# range.setEnd last_node, last_node.length
|
||||
# range
|
||||
class Selection
|
||||
constructor: ->
|
||||
@reset()
|
||||
|
||||
reset: ->
|
||||
@selection = getSelection()
|
||||
fake_range = document.createRange()
|
||||
fake_range.setStart(@selection.anchorNode, @selection.anchorOffset)
|
||||
fake_range.setEnd(@selection.focusNode, @selection.focusOffset)
|
||||
@start =
|
||||
node: @selection.anchorNode
|
||||
off: @selection.anchorOffset
|
||||
@end =
|
||||
node: @selection.focusNode
|
||||
off: @selection.focusOffset
|
||||
|
||||
if fake_range.collapsed
|
||||
[@start, @end] = [@end, @start]
|
||||
|
||||
clear: ->
|
||||
@selection.removeAllRanges()
|
||||
|
||||
text: ->
|
||||
@selection.toString()
|
||||
|
||||
up: ->
|
||||
@go -1
|
||||
|
||||
down: ->
|
||||
@go +1
|
||||
|
||||
go: (n) ->
|
||||
index = term.children.indexOf @get_selected_line()
|
||||
|
||||
if 0 <= index + n < term.children.length
|
||||
@clear()
|
||||
@selection.addRange get_line_range(index + n)
|
||||
|
||||
get_selected_line: ->
|
||||
node = @start.node
|
||||
while not node.classList or 'line' not in node.classList
|
||||
node = node.parentNode
|
||||
node
|
||||
|
||||
|
||||
nextLeaf = (node) ->
|
||||
next = node.nextSibling
|
||||
if not next
|
||||
next = node.parentNode.nextSibling
|
||||
if not next
|
||||
next = node.parentNode.parentNode.nextSibling.firstChild
|
||||
next
|
||||
|
||||
find_node_offset = (line, backward=false) ->
|
||||
step = if backward then -1 else 1
|
||||
|
||||
for node in line.childNodes by step
|
||||
if node.nodeType != node.TEXT_NODE
|
||||
node = node.firstChild
|
||||
for c, offset in node.textContent by step
|
||||
if not c.match /\s/
|
||||
return [node, offset + if backward then 1 else 0]
|
||||
return [line.firstChild, 0]
|
||||
|
||||
get_line_range = (y) ->
|
||||
line = term.children[y]
|
||||
range = document.createRange()
|
||||
range.setStart.apply range, find_node_offset(line)
|
||||
range.setEnd.apply range, find_node_offset(line, true)
|
||||
range
|
||||
|
||||
|
||||
sel_to_line = (y) ->
|
||||
selection = getSelection()
|
||||
selection.removeAllRanges()
|
||||
selection.addRange get_line_range(y)
|
||||
|
||||
|
||||
document.addEventListener 'keydown', (e) ->
|
||||
if selection
|
||||
selection.reset()
|
||||
if not e.ctrlKey and e.shiftKey and 37 <= e.keyCode <= 40
|
||||
return true
|
||||
if e.shiftKey and e.ctrlKey
|
||||
if e.keyCode == 38
|
||||
selection.up()
|
||||
return cancel e
|
||||
else if e.keyCode == 40
|
||||
selection.down()
|
||||
return cancel e
|
||||
|
||||
else if e.keyCode == 13
|
||||
term.handler selection.text()
|
||||
selection.clear()
|
||||
selection = null
|
||||
else
|
||||
selection.clear()
|
||||
selection = null
|
||||
return true
|
||||
return cancel e
|
||||
|
||||
# Start selection mode with shift up
|
||||
if not selection and e.ctrlKey and e.shiftKey and e.keyCode == 38
|
||||
sel_to_line term.y - 1
|
||||
selection = new Selection()
|
||||
return cancel e
|
||||
|
||||
document.addEventListener 'dblclick', (e) ->
|
||||
return if e.ctrlKey or e.altkey
|
||||
sel = window.getSelection()
|
||||
sel = getSelection()
|
||||
return if sel.isCollapsed or sel.toString().match /\s/
|
||||
|
||||
range = document.createRange()
|
||||
@@ -26,8 +142,8 @@ document.addEventListener 'dblclick', (e) ->
|
||||
if range.collapsed
|
||||
sel.removeAllRanges()
|
||||
new_range = document.createRange()
|
||||
new_range.setEnd(sel.anchorNode, sel.anchorOffset)
|
||||
new_range.setStart(sel.focusNode, sel.focusOffset)
|
||||
new_range.setEnd(sel.anchorNode, sel.anchorOffset)
|
||||
sel.addRange(new_range)
|
||||
range.detach()
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Generated by CoffeeScript 1.6.3
|
||||
var $, State, Terminal, alt, bench, cancel, cbench, cols, ctl, ctrl, first, quit, rows, s, send, term, virtual_input, ws, ws_url,
|
||||
var $, Selection, State, Terminal, alt, bench, cancel, cbench, cols, ctl, ctrl, find_node_offset, first, get_line_range, nextLeaf, quit, rows, s, sel_to_line, selection, send, term, virtual_input, ws, ws_url,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
|
||||
__slice = [].slice;
|
||||
|
||||
cancel = function(ev) {
|
||||
@@ -2411,12 +2412,159 @@ Terminal = (function() {
|
||||
|
||||
})();
|
||||
|
||||
selection = null;
|
||||
|
||||
Selection = (function() {
|
||||
function Selection() {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
Selection.prototype.reset = function() {
|
||||
var fake_range, _ref;
|
||||
this.selection = getSelection();
|
||||
fake_range = document.createRange();
|
||||
fake_range.setStart(this.selection.anchorNode, this.selection.anchorOffset);
|
||||
fake_range.setEnd(this.selection.focusNode, this.selection.focusOffset);
|
||||
this.start = {
|
||||
node: this.selection.anchorNode,
|
||||
off: this.selection.anchorOffset
|
||||
};
|
||||
this.end = {
|
||||
node: this.selection.focusNode,
|
||||
off: this.selection.focusOffset
|
||||
};
|
||||
if (fake_range.collapsed) {
|
||||
return _ref = [this.end, this.start], this.start = _ref[0], this.end = _ref[1], _ref;
|
||||
}
|
||||
};
|
||||
|
||||
Selection.prototype.clear = function() {
|
||||
return this.selection.removeAllRanges();
|
||||
};
|
||||
|
||||
Selection.prototype.text = function() {
|
||||
return this.selection.toString();
|
||||
};
|
||||
|
||||
Selection.prototype.up = function() {
|
||||
return this.go(-1);
|
||||
};
|
||||
|
||||
Selection.prototype.down = function() {
|
||||
return this.go(+1);
|
||||
};
|
||||
|
||||
Selection.prototype.go = function(n) {
|
||||
var index, _ref;
|
||||
index = term.children.indexOf(this.get_selected_line());
|
||||
if ((0 <= (_ref = index + n) && _ref < term.children.length)) {
|
||||
this.clear();
|
||||
return this.selection.addRange(get_line_range(index + n));
|
||||
}
|
||||
};
|
||||
|
||||
Selection.prototype.get_selected_line = function() {
|
||||
var node;
|
||||
node = this.start.node;
|
||||
while (!node.classList || __indexOf.call(node.classList, 'line') < 0) {
|
||||
node = node.parentNode;
|
||||
}
|
||||
return node;
|
||||
};
|
||||
|
||||
return Selection;
|
||||
|
||||
})();
|
||||
|
||||
nextLeaf = function(node) {
|
||||
var next;
|
||||
next = node.nextSibling;
|
||||
if (!next) {
|
||||
next = node.parentNode.nextSibling;
|
||||
}
|
||||
if (!next) {
|
||||
next = node.parentNode.parentNode.nextSibling.firstChild;
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
find_node_offset = function(line, backward) {
|
||||
var c, node, offset, step, _i, _j, _len, _len1, _ref, _ref1;
|
||||
if (backward == null) {
|
||||
backward = false;
|
||||
}
|
||||
step = backward ? -1 : 1;
|
||||
_ref = line.childNodes;
|
||||
for ((step > 0 ? (_i = 0, _len = _ref.length) : _i = _ref.length - 1); step > 0 ? _i < _len : _i >= 0; _i += step) {
|
||||
node = _ref[_i];
|
||||
if (node.nodeType !== node.TEXT_NODE) {
|
||||
node = node.firstChild;
|
||||
}
|
||||
_ref1 = node.textContent;
|
||||
for ((step > 0 ? (offset = _j = 0, _len1 = _ref1.length) : offset = _j = _ref1.length - 1); step > 0 ? _j < _len1 : _j >= 0; offset = _j += step) {
|
||||
c = _ref1[offset];
|
||||
if (!c.match(/\s/)) {
|
||||
return [node, offset + (backward ? 1 : 0)];
|
||||
}
|
||||
}
|
||||
}
|
||||
return [line.firstChild, 0];
|
||||
};
|
||||
|
||||
get_line_range = function(y) {
|
||||
var line, range;
|
||||
line = term.children[y];
|
||||
range = document.createRange();
|
||||
range.setStart.apply(range, find_node_offset(line));
|
||||
range.setEnd.apply(range, find_node_offset(line, true));
|
||||
return range;
|
||||
};
|
||||
|
||||
sel_to_line = function(y) {
|
||||
selection = getSelection();
|
||||
selection.removeAllRanges();
|
||||
return selection.addRange(get_line_range(y));
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
var _ref;
|
||||
if (selection) {
|
||||
selection.reset();
|
||||
if (!e.ctrlKey && e.shiftKey && (37 <= (_ref = e.keyCode) && _ref <= 40)) {
|
||||
return true;
|
||||
}
|
||||
if (e.shiftKey && e.ctrlKey) {
|
||||
if (e.keyCode === 38) {
|
||||
selection.up();
|
||||
return cancel(e);
|
||||
} else if (e.keyCode === 40) {
|
||||
selection.down();
|
||||
return cancel(e);
|
||||
}
|
||||
} else if (e.keyCode === 13) {
|
||||
term.handler(selection.text());
|
||||
selection.clear();
|
||||
selection = null;
|
||||
} else {
|
||||
selection.clear();
|
||||
selection = null;
|
||||
return true;
|
||||
}
|
||||
return cancel(e);
|
||||
}
|
||||
if (!selection && e.ctrlKey && e.shiftKey && e.keyCode === 38) {
|
||||
sel_to_line(term.y - 1);
|
||||
selection = new Selection();
|
||||
return cancel(e);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('dblclick', function(e) {
|
||||
var anchorNode, anchorOffset, new_range, range, sel;
|
||||
if (e.ctrlKey || e.altkey) {
|
||||
return;
|
||||
}
|
||||
sel = window.getSelection();
|
||||
sel = getSelection();
|
||||
if (sel.isCollapsed || sel.toString().match(/\s/)) {
|
||||
return;
|
||||
}
|
||||
@@ -2426,8 +2574,8 @@ document.addEventListener('dblclick', function(e) {
|
||||
if (range.collapsed) {
|
||||
sel.removeAllRanges();
|
||||
new_range = document.createRange();
|
||||
new_range.setEnd(sel.anchorNode, sel.anchorOffset);
|
||||
new_range.setStart(sel.focusNode, sel.focusOffset);
|
||||
new_range.setEnd(sel.anchorNode, sel.anchorOffset);
|
||||
sel.addRange(new_range);
|
||||
}
|
||||
range.detach();
|
||||
|
||||
Reference in New Issue
Block a user