Improve selection

This commit is contained in:
Florian Mounier
2014-02-21 16:44:46 +01:00
parent 1db6c4eb5c
commit 6d10994eb7
2 changed files with 269 additions and 5 deletions

View File

@@ -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()

View File

@@ -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();