mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-05-26 07:08:08 +00:00
Scroll lock
This commit is contained in:
@@ -19,7 +19,7 @@ $fg: #fff !default
|
||||
$shadow: 6px !default
|
||||
$shadow-alpha: .5 !default
|
||||
|
||||
.terminal
|
||||
body
|
||||
text-shadow: 0 0 $shadow rgba($fg, $shadow-alpha)
|
||||
transition: 200ms
|
||||
transform-origin: bottom
|
||||
@@ -68,3 +68,10 @@ $shadow-alpha: .5 !default
|
||||
&.stopped
|
||||
-webkit-filter: brightness(50%)
|
||||
filter: brightness(50%)
|
||||
|
||||
&.locked
|
||||
&::-webkit-scrollbar-thumb
|
||||
background: rgba(red, .7)
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover
|
||||
background: rgba(red, .8)
|
||||
|
||||
@@ -25,14 +25,14 @@ body
|
||||
overflow-x: hidden
|
||||
overflow-y: scroll
|
||||
|
||||
::-webkit-scrollbar
|
||||
&::-webkit-scrollbar
|
||||
background: $bg
|
||||
width: .75em
|
||||
|
||||
::-webkit-scrollbar-thumb
|
||||
&::-webkit-scrollbar-thumb
|
||||
background: rgba($fg, .1)
|
||||
|
||||
::-webkit-scrollbar-thumb:hover
|
||||
&::-webkit-scrollbar-thumb:hover
|
||||
background: rgba($fg, .15)
|
||||
|
||||
.terminal
|
||||
|
||||
2
butterfly/static/ext.min.js
vendored
2
butterfly/static/ext.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -76,26 +76,26 @@ body {
|
||||
/* GNU General Public License for more details. */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
.terminal {
|
||||
body {
|
||||
text-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
|
||||
transition: 200ms;
|
||||
transform-origin: bottom; }
|
||||
.terminal.bell {
|
||||
body.bell {
|
||||
-webkit-filter: blur(2px);
|
||||
filter: blur(2px); }
|
||||
.terminal.skip {
|
||||
body.skip {
|
||||
-webkit-filter: sepia(1);
|
||||
filter: sepia(1); }
|
||||
.terminal.selection {
|
||||
body.selection {
|
||||
-webkit-filter: saturate(2);
|
||||
filter: saturate(2); }
|
||||
.terminal.alarm {
|
||||
body.alarm {
|
||||
-webkit-filter: hue-rotate(150deg);
|
||||
filter: hue-rotate(150deg); }
|
||||
.terminal.dead {
|
||||
body.dead {
|
||||
-webkit-filter: grayscale(1);
|
||||
filter: grayscale(1); }
|
||||
.terminal.dead:after {
|
||||
body.dead:after {
|
||||
content: "CLOSED";
|
||||
font-size: 15em;
|
||||
display: flex;
|
||||
@@ -109,13 +109,17 @@ body {
|
||||
transform: rotate(-45deg);
|
||||
opacity: .2;
|
||||
font-weight: 900; }
|
||||
.terminal.copied {
|
||||
body.copied {
|
||||
transform: scale(1.05); }
|
||||
.terminal.pasted {
|
||||
body.pasted {
|
||||
transform: scale(.95); }
|
||||
.terminal.stopped {
|
||||
body.stopped {
|
||||
-webkit-filter: brightness(50%);
|
||||
filter: brightness(50%); }
|
||||
body.locked::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 0, 0, 0.7); }
|
||||
body.locked::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 0, 0, 0.8); }
|
||||
|
||||
/* *-* coding: utf-8 *-* */
|
||||
/* This file is part of butterfly */
|
||||
@@ -3026,15 +3030,12 @@ body {
|
||||
white-space: nowrap;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll; }
|
||||
|
||||
::-webkit-scrollbar {
|
||||
body::-webkit-scrollbar {
|
||||
background: #110f13;
|
||||
width: .75em; }
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
body::-webkit-scrollbar-thumb {
|
||||
background: rgba(244, 234, 213, 0.1); }
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
body::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(244, 234, 213, 0.15); }
|
||||
|
||||
.terminal {
|
||||
|
||||
@@ -150,21 +150,19 @@
|
||||
this.body = this.document.getElementsByTagName('body')[0];
|
||||
this.html_escapes_enabled = this.body.getAttribute('data-allow-html') === 'yes';
|
||||
this.force_width = this.body.getAttribute('data-force-unicode-width') === 'yes';
|
||||
this.element = this.document.createElement('div');
|
||||
this.element.className = 'terminal focus';
|
||||
this.element.style.outline = 'none';
|
||||
this.element.setAttribute('tabindex', 0);
|
||||
this.element.setAttribute('spellcheck', 'false');
|
||||
this.parent.insertBefore(this.element, this.parent.firstChild);
|
||||
this.body.className = 'terminal focus';
|
||||
this.body.style.outline = 'none';
|
||||
this.body.setAttribute('tabindex', 0);
|
||||
this.body.setAttribute('spellcheck', 'false');
|
||||
div = this.document.createElement('div');
|
||||
div.className = 'line';
|
||||
this.element.appendChild(div);
|
||||
this.body.appendChild(div);
|
||||
this.children = [div];
|
||||
this.compute_char_size();
|
||||
this.cols = Math.floor(this.element.clientWidth / this.char_size.width);
|
||||
this.cols = Math.floor(this.body.clientWidth / this.char_size.width);
|
||||
this.rows = Math.floor(window.innerHeight / this.char_size.height);
|
||||
px = window.innerHeight % this.char_size.height;
|
||||
this.element.style['padding-bottom'] = px + "px";
|
||||
this.body.style['padding-bottom'] = px + "px";
|
||||
this.scrollback = 1000000;
|
||||
this.buff_size = 100000;
|
||||
this.visualBell = 100;
|
||||
@@ -222,6 +220,7 @@
|
||||
this.queue = '';
|
||||
this.scrollTop = 0;
|
||||
this.scrollBottom = this.rows - 1;
|
||||
this.scrollLock = false;
|
||||
this.applicationKeypad = false;
|
||||
this.applicationCursor = false;
|
||||
this.originMode = false;
|
||||
@@ -279,8 +278,8 @@
|
||||
this.send('\x1b[I');
|
||||
}
|
||||
this.showCursor();
|
||||
this.element.classList.add('focus');
|
||||
return this.element.classList.remove('blur');
|
||||
this.body.classList.add('focus');
|
||||
return this.body.classList.remove('blur');
|
||||
};
|
||||
|
||||
Terminal.prototype.blur = function() {
|
||||
@@ -290,8 +289,8 @@
|
||||
if (this.sendFocus) {
|
||||
this.send('\x1b[O');
|
||||
}
|
||||
this.element.classList.add('blur');
|
||||
return this.element.classList.remove('focus');
|
||||
this.body.classList.add('blur');
|
||||
return this.body.classList.remove('focus');
|
||||
};
|
||||
|
||||
Terminal.prototype.initmouse = function() {
|
||||
@@ -404,7 +403,7 @@
|
||||
var h, w, x, y;
|
||||
x = ev.pageX;
|
||||
y = ev.pageY - window.scrollY;
|
||||
w = _this.element.clientWidth;
|
||||
w = _this.body.clientWidth;
|
||||
h = window.innerHeight;
|
||||
x = Math.ceil((x / w) * _this.cols);
|
||||
y = Math.ceil((y / h) * _this.rows);
|
||||
@@ -479,7 +478,7 @@
|
||||
if (force == null) {
|
||||
force = false;
|
||||
}
|
||||
ref = this.element.querySelectorAll(".cursor");
|
||||
ref = this.body.querySelectorAll(".cursor");
|
||||
for (k = 0, len = ref.length; k < len; k++) {
|
||||
cursor = ref[k];
|
||||
cursor.parentNode.replaceChild(this.document.createTextNode(cursor.textContent), cursor);
|
||||
@@ -608,7 +607,7 @@
|
||||
group = this.document.createElement('div');
|
||||
group.className = 'group';
|
||||
group.innerHTML = new_out;
|
||||
this.element.appendChild(group);
|
||||
this.body.appendChild(group);
|
||||
this.screen = this.screen.slice(-this.rows);
|
||||
this.shift = 0;
|
||||
lines = document.querySelectorAll('.line');
|
||||
@@ -627,13 +626,15 @@
|
||||
}
|
||||
this.children = Array.prototype.slice.call(lines, -this.rows);
|
||||
}
|
||||
if (!this.scrollLock) {
|
||||
return this.native_scroll_to();
|
||||
}
|
||||
};
|
||||
|
||||
Terminal.prototype._cursorBlink = function() {
|
||||
var cursor;
|
||||
this.cursorState ^= 1;
|
||||
cursor = this.element.querySelector(".cursor");
|
||||
cursor = this.body.querySelector(".cursor");
|
||||
if (!cursor) {
|
||||
return;
|
||||
}
|
||||
@@ -1269,12 +1270,12 @@
|
||||
}
|
||||
if (ev.altKey && ev.keyCode === 90 && !this.skipNextKey) {
|
||||
this.skipNextKey = true;
|
||||
this.element.classList.add('skip');
|
||||
this.body.classList.add('skip');
|
||||
return cancel(ev);
|
||||
}
|
||||
if (this.skipNextKey) {
|
||||
this.skipNextKey = false;
|
||||
this.element.classList.remove('skip');
|
||||
this.body.classList.remove('skip');
|
||||
return true;
|
||||
}
|
||||
switch (ev.keyCode) {
|
||||
@@ -1409,6 +1410,14 @@
|
||||
case 123:
|
||||
key = "\x1b[24~";
|
||||
break;
|
||||
case 145:
|
||||
this.scrollLock = !this.scrollLock;
|
||||
if (this.scrollLock) {
|
||||
this.body.classList.add('locked');
|
||||
} else {
|
||||
this.body.classList.remove('locked');
|
||||
}
|
||||
return cancel(ev);
|
||||
default:
|
||||
if (ev.ctrlKey) {
|
||||
if (ev.keyCode >= 65 && ev.keyCode <= 90) {
|
||||
@@ -1421,7 +1430,7 @@
|
||||
clearTimeout(id);
|
||||
}
|
||||
}
|
||||
this.element.classList.add('stopped');
|
||||
this.body.classList.add('stopped');
|
||||
this.stop = true;
|
||||
} else if (this.stop) {
|
||||
return true;
|
||||
@@ -1524,10 +1533,10 @@
|
||||
if (!this.visualBell) {
|
||||
return;
|
||||
}
|
||||
this.element.classList.add(cls);
|
||||
this.body.classList.add(cls);
|
||||
return this.t_bell = setTimeout(((function(_this) {
|
||||
return function() {
|
||||
return _this.element.classList.remove(cls);
|
||||
return _this.body.classList.remove(cls);
|
||||
};
|
||||
})(this)), this.visualBell);
|
||||
};
|
||||
@@ -1543,10 +1552,10 @@
|
||||
old_cols = this.cols;
|
||||
old_rows = this.rows;
|
||||
this.compute_char_size();
|
||||
this.cols = x || Math.floor(this.element.clientWidth / this.char_size.width);
|
||||
this.cols = x || Math.floor(this.body.clientWidth / this.char_size.width);
|
||||
this.rows = y || Math.floor(window.innerHeight / this.char_size.height);
|
||||
px = window.innerHeight % this.char_size.height;
|
||||
this.element.style['padding-bottom'] = px + "px";
|
||||
this.body.style['padding-bottom'] = px + "px";
|
||||
if ((!x && !y) && old_cols === this.cols && old_rows === this.rows) {
|
||||
return;
|
||||
}
|
||||
@@ -1569,7 +1578,7 @@
|
||||
this.setupStops(old_cols);
|
||||
j = old_rows;
|
||||
if (j < this.rows) {
|
||||
el = this.element;
|
||||
el = this.body;
|
||||
while (j++ < this.rows) {
|
||||
if (this.screen.length < this.rows) {
|
||||
this.screen.push([this.blank_line(), true]);
|
||||
@@ -2202,7 +2211,7 @@
|
||||
this.vt200Mouse = params === 1000;
|
||||
this.normalMouse = params > 1000;
|
||||
this.mouseEvents = true;
|
||||
return this.element.style.cursor = 'pointer';
|
||||
return this.body.style.cursor = 'pointer';
|
||||
case 1004:
|
||||
return this.sendFocus = true;
|
||||
case 1005:
|
||||
@@ -2278,7 +2287,7 @@
|
||||
this.vt200Mouse = false;
|
||||
this.normalMouse = false;
|
||||
this.mouseEvents = false;
|
||||
return this.element.style.cursor = "";
|
||||
return this.body.style.cursor = "";
|
||||
case 1004:
|
||||
return this.sendFocus = false;
|
||||
case 1005:
|
||||
|
||||
6
butterfly/static/main.min.js
vendored
6
butterfly/static/main.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -56,25 +56,22 @@ class Terminal
|
||||
'data-force-unicode-width') is 'yes'
|
||||
|
||||
# Main terminal element
|
||||
@element = @document.createElement('div')
|
||||
@element.className = 'terminal focus'
|
||||
@element.style.outline = 'none'
|
||||
@element.setAttribute 'tabindex', 0
|
||||
@element.setAttribute 'spellcheck', 'false'
|
||||
|
||||
@parent.insertBefore @element, @parent.firstChild
|
||||
@body.className = 'terminal focus'
|
||||
@body.style.outline = 'none'
|
||||
@body.setAttribute 'tabindex', 0
|
||||
@body.setAttribute 'spellcheck', 'false'
|
||||
|
||||
# Adding one line to compute char size
|
||||
div = @document.createElement('div')
|
||||
div.className = 'line'
|
||||
@element.appendChild(div)
|
||||
@body.appendChild(div)
|
||||
@children = [div]
|
||||
|
||||
@compute_char_size()
|
||||
@cols = Math.floor(@element.clientWidth / @char_size.width)
|
||||
@cols = Math.floor(@body.clientWidth / @char_size.width)
|
||||
@rows = Math.floor(window.innerHeight / @char_size.height)
|
||||
px = window.innerHeight % @char_size.height
|
||||
@element.style['padding-bottom'] = "#{px}px"
|
||||
@body.style['padding-bottom'] = "#{px}px"
|
||||
|
||||
@scrollback = 1000000
|
||||
@buff_size = 100000
|
||||
@@ -130,6 +127,7 @@ class Terminal
|
||||
|
||||
@scrollTop = 0
|
||||
@scrollBottom = @rows - 1
|
||||
@scrollLock = false
|
||||
|
||||
# modes
|
||||
@applicationKeypad = false
|
||||
@@ -183,16 +181,16 @@ class Terminal
|
||||
focus: ->
|
||||
@send('\x1b[I') if @sendFocus
|
||||
@showCursor()
|
||||
@element.classList.add('focus')
|
||||
@element.classList.remove('blur')
|
||||
@body.classList.add('focus')
|
||||
@body.classList.remove('blur')
|
||||
|
||||
blur: ->
|
||||
@cursorState = 1
|
||||
@screen[@y + @shift][1] = true
|
||||
@refresh()
|
||||
@send('\x1b[O') if @sendFocus
|
||||
@element.classList.add('blur')
|
||||
@element.classList.remove('focus')
|
||||
@body.classList.add('blur')
|
||||
@body.classList.remove('focus')
|
||||
|
||||
# XTerm mouse events
|
||||
# http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
|
||||
@@ -327,7 +325,7 @@ class Terminal
|
||||
y = ev.pageY - window.scrollY
|
||||
|
||||
# convert to cols/rows
|
||||
w = @element.clientWidth
|
||||
w = @body.clientWidth
|
||||
h = window.innerHeight
|
||||
x = Math.ceil((x / w) * @cols)
|
||||
y = Math.ceil((y / h) * @rows)
|
||||
@@ -378,7 +376,7 @@ class Terminal
|
||||
cancel ev
|
||||
|
||||
refresh: (force=false) ->
|
||||
for cursor in @element.querySelectorAll(".cursor")
|
||||
for cursor in @body.querySelectorAll(".cursor")
|
||||
cursor.parentNode.replaceChild(
|
||||
@document.createTextNode(cursor.textContent), cursor)
|
||||
new_out = ''
|
||||
@@ -486,7 +484,7 @@ class Terminal
|
||||
group = @document.createElement('div')
|
||||
group.className = 'group'
|
||||
group.innerHTML = new_out
|
||||
@element.appendChild group
|
||||
@body.appendChild group
|
||||
@screen = @screen.slice(-@rows)
|
||||
@shift = 0
|
||||
|
||||
@@ -501,11 +499,11 @@ class Terminal
|
||||
@children = Array.prototype.slice.call(
|
||||
lines, -@rows)
|
||||
|
||||
@native_scroll_to()
|
||||
@native_scroll_to() unless @scrollLock
|
||||
|
||||
_cursorBlink: ->
|
||||
@cursorState ^= 1
|
||||
cursor = @element.querySelector(".cursor")
|
||||
cursor = @body.querySelector(".cursor")
|
||||
return unless cursor
|
||||
if cursor.classList.contains("reverse-video")
|
||||
cursor.classList.remove "reverse-video"
|
||||
@@ -1186,12 +1184,12 @@ class Terminal
|
||||
# May be redundant with keyPrefix
|
||||
if ev.altKey and ev.keyCode is 90 and not @skipNextKey
|
||||
@skipNextKey = true
|
||||
@element.classList.add('skip')
|
||||
@body.classList.add('skip')
|
||||
return cancel(ev)
|
||||
|
||||
if @skipNextKey
|
||||
@skipNextKey = false
|
||||
@element.classList.remove('skip')
|
||||
@body.classList.remove('skip')
|
||||
return true
|
||||
|
||||
switch ev.keyCode
|
||||
@@ -1341,6 +1339,15 @@ class Terminal
|
||||
when 123
|
||||
key = "\x1b[24~"
|
||||
|
||||
# Scroll lock
|
||||
when 145
|
||||
@scrollLock = ! @scrollLock
|
||||
if @scrollLock
|
||||
@body.classList.add 'locked'
|
||||
else
|
||||
@body.classList.remove 'locked'
|
||||
return cancel(ev)
|
||||
|
||||
else
|
||||
# a-z and space
|
||||
if ev.ctrlKey
|
||||
@@ -1351,7 +1358,7 @@ class Terminal
|
||||
id = (setTimeout ->)
|
||||
(clearTimeout id if id not in [
|
||||
@t_bell, @t_queue, @t_blink]) while id--
|
||||
@element.classList.add 'stopped'
|
||||
@body.classList.add 'stopped'
|
||||
@stop = true
|
||||
else if @stop
|
||||
return true
|
||||
@@ -1447,19 +1454,19 @@ class Terminal
|
||||
|
||||
bell: (cls="bell")->
|
||||
return unless @visualBell
|
||||
@element.classList.add cls
|
||||
@body.classList.add cls
|
||||
@t_bell = setTimeout (=>
|
||||
@element.classList.remove cls
|
||||
@body.classList.remove cls
|
||||
), @visualBell
|
||||
|
||||
resize: (x=null, y=null) ->
|
||||
old_cols = @cols
|
||||
old_rows = @rows
|
||||
@compute_char_size()
|
||||
@cols = x or Math.floor(@element.clientWidth / @char_size.width)
|
||||
@cols = x or Math.floor(@body.clientWidth / @char_size.width)
|
||||
@rows = y or Math.floor(window.innerHeight / @char_size.height)
|
||||
px = window.innerHeight % @char_size.height
|
||||
@element.style['padding-bottom'] = "#{px}px"
|
||||
@body.style['padding-bottom'] = "#{px}px"
|
||||
|
||||
if (not x and not y) and old_cols == @cols and old_rows == @rows
|
||||
return
|
||||
@@ -1482,7 +1489,7 @@ class Terminal
|
||||
# resize rows
|
||||
j = old_rows
|
||||
if j < @rows
|
||||
el = @element
|
||||
el = @body
|
||||
while j++ < @rows
|
||||
@screen.push [@blank_line(), true] if @screen.length < @rows
|
||||
if @children.length < @rows
|
||||
@@ -2229,7 +2236,7 @@ class Terminal
|
||||
@vt200Mouse = params is 1000
|
||||
@normalMouse = params > 1000
|
||||
@mouseEvents = true
|
||||
@element.style.cursor = 'pointer'
|
||||
@body.style.cursor = 'pointer'
|
||||
when 1004 # send focusin/focusout events
|
||||
# focusin: ^[[I
|
||||
# focusout: ^[[O
|
||||
@@ -2383,7 +2390,7 @@ class Terminal
|
||||
@vt200Mouse = false
|
||||
@normalMouse = false
|
||||
@mouseEvents = false
|
||||
@element.style.cursor = ""
|
||||
@body.style.cursor = ""
|
||||
when 1004 # send focusin/focusout events
|
||||
@sendFocus = false
|
||||
when 1005 # utf8 ext mode mouse
|
||||
|
||||
Reference in New Issue
Block a user