mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-06-10 06:14:39 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0287946d9 | ||
|
|
fbd71d55ef | ||
|
|
0ac8437387 | ||
|
|
866b56b682 | ||
|
|
4d87059872 | ||
|
|
5bbe456496 | ||
|
|
5b9cc257a8 | ||
|
|
34b6287e0c | ||
|
|
41ee5fb843 | ||
|
|
cfda54a724 | ||
|
|
033169ab08 | ||
|
|
920c435b00 | ||
|
|
27e6aa8a5d | ||
|
|
92633f52ce |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ sass/scss
|
||||
build/
|
||||
.cache/
|
||||
.env*
|
||||
.pytest_cache
|
||||
|
||||
2
.isort.cfg
Normal file
2
.isort.cfg
Normal file
@@ -0,0 +1,2 @@
|
||||
[settings]
|
||||
multi_line_output=4
|
||||
@@ -1,3 +1,8 @@
|
||||
3.2.2
|
||||
=====
|
||||
|
||||
* Fix unescaping entities when linkifying
|
||||
|
||||
3.2.1
|
||||
=====
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ RUN apt-get update \
|
||||
libssl-dev \
|
||||
python-dev \
|
||||
python-setuptools \
|
||||
&& sudo easy_install pip \
|
||||
&& sudo pip install --upgrade setuptools \
|
||||
&& apt-get clean \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
__title__ = "butterfly"
|
||||
__version__ = "3.2.1"
|
||||
__version__ = "3.2.3"
|
||||
|
||||
__summary__ = "A sleek web based terminal emulator"
|
||||
__uri__ = "https://github.com/paradoxxxzero/butterfly"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
from contextlib import contextmanager
|
||||
|
||||
import termios
|
||||
from butterfly.utils import ansi_colors as colors # noqa: F401
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ def geolocation():
|
||||
rv = sys.stdin.read(1)
|
||||
if rv != 'R':
|
||||
loc += rv
|
||||
except:
|
||||
except Exception:
|
||||
return
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
||||
|
||||
@@ -30,6 +30,7 @@ import tornado.options
|
||||
import tornado.process
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
|
||||
from butterfly import Route, url, utils
|
||||
from butterfly.terminal import Terminal
|
||||
|
||||
|
||||
@@ -93,5 +93,20 @@ body
|
||||
padding: .5em
|
||||
font-size: .75em
|
||||
|
||||
#input-view
|
||||
position: fixed
|
||||
z-index: 100
|
||||
padding: 0
|
||||
margin: 0
|
||||
text-decoration: underline
|
||||
|
||||
#input-helper
|
||||
position: fixed
|
||||
z-index: -100
|
||||
opacity: 0
|
||||
white-space: nowrap
|
||||
overflow: hidden
|
||||
resize: none
|
||||
|
||||
.terminal
|
||||
outline: none
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var Popup, Selection, _set_theme_href, _theme, alt, cancel, clean_ansi, copy, ctrl, first, histSize, linkify, maybePack, nextLeaf, packSize, popup, previousLeaf, selection, setAlarm, tid, virtualInput, walk,
|
||||
var Popup, Selection, _set_theme_href, _theme, alt, cancel, clean_ansi, copy, ctrl, escape, histSize, linkify, maybePack, nextLeaf, packSize, popup, previousLeaf, selection, setAlarm, tags, tid, walk,
|
||||
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; };
|
||||
|
||||
clean_ansi = function(data) {
|
||||
@@ -121,13 +121,14 @@
|
||||
});
|
||||
|
||||
addEventListener('copy', copy = function(e) {
|
||||
var data, end, j, len1, line, ref, sel;
|
||||
var data, end, j, len, line, ref, sel;
|
||||
document.getElementsByTagName('body')[0].contentEditable = false;
|
||||
butterfly.bell("copied");
|
||||
e.clipboardData.clearData();
|
||||
sel = getSelection().toString().replace(/\u00A0/g, ' ').replace(/\u2007/g, ' ');
|
||||
data = '';
|
||||
ref = sel.split('\n');
|
||||
for (j = 0, len1 = ref.length; j < len1; j++) {
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
line = ref[j];
|
||||
if (line.slice(-1) === '\u23CE') {
|
||||
end = '';
|
||||
@@ -143,6 +144,7 @@
|
||||
|
||||
addEventListener('paste', function(e) {
|
||||
var data, send, size;
|
||||
document.getElementsByTagName('body')[0].contentEditable = false;
|
||||
butterfly.bell("pasted");
|
||||
data = e.clipboardData.getData('text/plain');
|
||||
data = data.replace(/\r\n/g, '\n').replace(/\n/g, '\r');
|
||||
@@ -183,10 +185,10 @@
|
||||
});
|
||||
|
||||
walk = function(node, callback) {
|
||||
var child, j, len1, ref, results;
|
||||
var child, j, len, ref, results;
|
||||
ref = node.childNodes;
|
||||
results = [];
|
||||
for (j = 0, len1 = ref.length; j < len1; j++) {
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
child = ref[j];
|
||||
callback.call(child);
|
||||
results.push(walk(child, callback));
|
||||
@@ -202,12 +204,25 @@
|
||||
return text.replace(urlPattern, '<a href="$&">$&</a>').replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>').replace(emailAddressPattern, '<a href="mailto:$&">$&</a>');
|
||||
};
|
||||
|
||||
tags = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>'
|
||||
};
|
||||
|
||||
escape = function(s) {
|
||||
return s.replace(/[&<>]/g, function(tag) {
|
||||
return tags[tag] || tag;
|
||||
});
|
||||
};
|
||||
|
||||
Terminal.on('change', function(line) {
|
||||
return walk(line, function() {
|
||||
var linkified, newNode;
|
||||
var linkified, newNode, val;
|
||||
if (this.nodeType === 3) {
|
||||
linkified = linkify(this.nodeValue);
|
||||
if (linkified !== this.nodeValue) {
|
||||
val = this.nodeValue;
|
||||
linkified = linkify(escape(val));
|
||||
if (linkified !== val) {
|
||||
newNode = document.createElement('span');
|
||||
newNode.innerHTML = linkified;
|
||||
this.parentElement.replaceChild(newNode, this);
|
||||
@@ -217,6 +232,46 @@
|
||||
});
|
||||
});
|
||||
|
||||
ctrl = false;
|
||||
|
||||
alt = false;
|
||||
|
||||
addEventListener('touchstart', function(e) {
|
||||
if (e.touches.length === 2) {
|
||||
return ctrl = true;
|
||||
} else if (e.touches.length === 3) {
|
||||
ctrl = false;
|
||||
return alt = true;
|
||||
} else if (e.touches.length === 4) {
|
||||
ctrl = true;
|
||||
return alt = true;
|
||||
}
|
||||
});
|
||||
|
||||
window.mobileKeydown = function(e) {
|
||||
var _altKey, _ctrlKey, _keyCode;
|
||||
if (ctrl || alt) {
|
||||
_ctrlKey = ctrl;
|
||||
_altKey = alt;
|
||||
_keyCode = e.keyCode;
|
||||
if (e.keyCode >= 97 && e.keyCode <= 122) {
|
||||
_keyCode -= 32;
|
||||
}
|
||||
e = new KeyboardEvent('keydown', {
|
||||
ctrlKey: _ctrlKey,
|
||||
altKey: _altKey,
|
||||
keyCode: _keyCode
|
||||
});
|
||||
ctrl = alt = false;
|
||||
setTimeout(function() {
|
||||
return window.dispatchEvent(e);
|
||||
}, 0);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (!(e.altKey && e.keyCode === 79)) {
|
||||
return true;
|
||||
@@ -276,9 +331,6 @@
|
||||
Popup.prototype.open = function(html) {
|
||||
this.el.innerHTML = html;
|
||||
this.el.classList.remove('hidden');
|
||||
if (typeof InstallTrigger !== "undefined") {
|
||||
document.body.contentEditable = 'false';
|
||||
}
|
||||
addEventListener('click', this.bound_click_maybe_close);
|
||||
return addEventListener('keydown', this.bound_key_maybe_close);
|
||||
};
|
||||
@@ -286,9 +338,6 @@
|
||||
Popup.prototype.close = function() {
|
||||
removeEventListener('click', this.bound_click_maybe_close);
|
||||
removeEventListener('keydown', this.bound_key_maybe_close);
|
||||
if (typeof InstallTrigger !== "undefined") {
|
||||
document.body.contentEditable = 'true';
|
||||
}
|
||||
this.el.classList.add('hidden');
|
||||
return this.el.innerHTML = '';
|
||||
};
|
||||
@@ -652,7 +701,7 @@
|
||||
}
|
||||
oReq = new XMLHttpRequest();
|
||||
oReq.addEventListener('load', function() {
|
||||
var j, len1, out, ref, response, session;
|
||||
var j, len, out, ref, response, session;
|
||||
response = JSON.parse(this.responseText);
|
||||
out = '<div>';
|
||||
out += '<h2>Session list</h2>';
|
||||
@@ -661,7 +710,7 @@
|
||||
} else {
|
||||
out += '<ul>';
|
||||
ref = response.sessions;
|
||||
for (j = 0, len1 = ref.length; j < len1; j++) {
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
session = ref[j];
|
||||
out += "<li><a href=\"/session/" + session + "\">" + session + "</a></li>";
|
||||
}
|
||||
@@ -716,7 +765,7 @@
|
||||
}
|
||||
oReq = new XMLHttpRequest();
|
||||
oReq.addEventListener('load', function() {
|
||||
var builtin_themes, inner, j, k, len1, len2, option, response, theme, theme_list, themes, url;
|
||||
var builtin_themes, inner, j, k, len, len1, option, response, theme, theme_list, themes, url;
|
||||
response = JSON.parse(this.responseText);
|
||||
builtin_themes = response.builtin_themes;
|
||||
themes = response.themes;
|
||||
@@ -733,7 +782,7 @@
|
||||
option("/static/main.css", 'default');
|
||||
if (themes.length) {
|
||||
inner += '<optgroup label="Local themes">';
|
||||
for (j = 0, len1 = themes.length; j < len1; j++) {
|
||||
for (j = 0, len = themes.length; j < len; j++) {
|
||||
theme = themes[j];
|
||||
url = "/theme/" + theme + "/style.css";
|
||||
option(url, theme);
|
||||
@@ -741,7 +790,7 @@
|
||||
inner += '</optgroup>';
|
||||
}
|
||||
inner += '<optgroup label="Built-in themes">';
|
||||
for (k = 0, len2 = builtin_themes.length; k < len2; k++) {
|
||||
for (k = 0, len1 = builtin_themes.length; k < len1; k++) {
|
||||
theme = builtin_themes[k];
|
||||
url = "/theme/" + theme + "/style.css";
|
||||
option(url, theme.slice('built-in-'.length));
|
||||
@@ -759,74 +808,6 @@
|
||||
return cancel(e);
|
||||
});
|
||||
|
||||
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
|
||||
ctrl = false;
|
||||
alt = false;
|
||||
first = true;
|
||||
virtualInput = document.createElement('input');
|
||||
virtualInput.type = 'password';
|
||||
virtualInput.style.position = 'fixed';
|
||||
virtualInput.style.top = 0;
|
||||
virtualInput.style.left = 0;
|
||||
virtualInput.style.border = 'none';
|
||||
virtualInput.style.outline = 'none';
|
||||
virtualInput.style.opacity = 0;
|
||||
virtualInput.value = '0';
|
||||
document.body.appendChild(virtualInput);
|
||||
virtualInput.addEventListener('blur', function() {
|
||||
return setTimeout(((function(_this) {
|
||||
return function() {
|
||||
return _this.focus();
|
||||
};
|
||||
})(this)), 10);
|
||||
});
|
||||
addEventListener('click', function() {
|
||||
return virtualInput.focus();
|
||||
});
|
||||
addEventListener('touchstart', function(e) {
|
||||
if (e.touches.length === 2) {
|
||||
return ctrl = true;
|
||||
} else if (e.touches.length === 3) {
|
||||
ctrl = false;
|
||||
return alt = true;
|
||||
} else if (e.touches.length === 4) {
|
||||
ctrl = true;
|
||||
return alt = true;
|
||||
}
|
||||
});
|
||||
virtualInput.addEventListener('keydown', function(e) {
|
||||
butterfly.keyDown(e);
|
||||
return true;
|
||||
});
|
||||
virtualInput.addEventListener('input', function(e) {
|
||||
var len;
|
||||
len = this.value.length;
|
||||
if (len === 0) {
|
||||
e.keyCode = 8;
|
||||
butterfly.keyDown(e);
|
||||
this.value = '0';
|
||||
return true;
|
||||
}
|
||||
e.keyCode = this.value.charAt(1).charCodeAt(0);
|
||||
if ((ctrl || alt) && !first) {
|
||||
e.keyCode = this.value.charAt(1).charCodeAt(0);
|
||||
e.ctrlKey = ctrl;
|
||||
e.altKey = alt;
|
||||
if (e.keyCode >= 97 && e.keyCode <= 122) {
|
||||
e.keyCode -= 32;
|
||||
}
|
||||
butterfly.keyDown(e);
|
||||
this.value = '0';
|
||||
ctrl = alt = false;
|
||||
return true;
|
||||
}
|
||||
butterfly.keyPress(e);
|
||||
first = false;
|
||||
this.value = '0';
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
}).call(this);
|
||||
|
||||
//# sourceMappingURL=ext.js.map
|
||||
|
||||
4
butterfly/static/ext.min.js
vendored
4
butterfly/static/ext.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -2861,6 +2861,19 @@ body {
|
||||
display: block;
|
||||
padding: .5em;
|
||||
font-size: .75em; }
|
||||
body #input-view {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-decoration: underline; }
|
||||
body #input-helper {
|
||||
position: fixed;
|
||||
z-index: -100;
|
||||
opacity: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none; }
|
||||
|
||||
.terminal {
|
||||
outline: none; }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var $, State, Terminal, cancel, cols, openTs, quit, rows, s, ws,
|
||||
var $, State, Terminal, cancel, cols, isMobile, openTs, quit, rows, s, ws,
|
||||
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; };
|
||||
|
||||
cols = rows = null;
|
||||
@@ -131,6 +131,10 @@
|
||||
return false;
|
||||
};
|
||||
|
||||
isMobile = function() {
|
||||
return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||
};
|
||||
|
||||
s = 0;
|
||||
|
||||
State = {
|
||||
@@ -170,10 +174,14 @@
|
||||
this.body = this.document.getElementsByTagName('body')[0];
|
||||
this.term = this.document.getElementById('term');
|
||||
this.forceWidth = this.body.getAttribute('data-force-unicode-width') === 'yes';
|
||||
this.inputHelper = this.document.getElementById('input-helper');
|
||||
this.inputView = this.document.getElementById('input-view');
|
||||
this.body.className = 'terminal focus';
|
||||
this.body.style.outline = 'none';
|
||||
this.body.setAttribute('tabindex', 0);
|
||||
this.body.setAttribute('spellcheck', 'false');
|
||||
this.inputHelper.setAttribute('tabindex', 0);
|
||||
this.inputHelper.setAttribute('spellcheck', 'false');
|
||||
div = this.document.createElement('div');
|
||||
div.className = 'line';
|
||||
this.term.appendChild(div);
|
||||
@@ -185,11 +193,28 @@
|
||||
this.termName = 'xterm';
|
||||
this.cursorBlink = true;
|
||||
this.cursorState = 0;
|
||||
this.inComposition = false;
|
||||
this.compositionText = "";
|
||||
this.resetVars();
|
||||
this.focus();
|
||||
this.startBlink();
|
||||
this.inputHelper.addEventListener('compositionstart', this.compositionStart.bind(this));
|
||||
this.inputHelper.addEventListener('compositionupdate', this.compositionUpdate.bind(this));
|
||||
this.inputHelper.addEventListener('compositionend', this.compositionEnd.bind(this));
|
||||
addEventListener('keydown', this.keyDown.bind(this));
|
||||
addEventListener('keypress', this.keyPress.bind(this));
|
||||
addEventListener('keyup', (function(_this) {
|
||||
return function() {
|
||||
return _this.inputHelper.focus();
|
||||
};
|
||||
})(this));
|
||||
if (isMobile()) {
|
||||
addEventListener('click', (function(_this) {
|
||||
return function() {
|
||||
return _this.inputHelper.focus();
|
||||
};
|
||||
})(this));
|
||||
}
|
||||
addEventListener('focus', this.focus.bind(this));
|
||||
addEventListener('blur', this.blur.bind(this));
|
||||
addEventListener('resize', (function(_this) {
|
||||
@@ -202,9 +227,6 @@
|
||||
return _this.nativeScrollTo();
|
||||
};
|
||||
})(this), true);
|
||||
if (typeof InstallTrigger !== "undefined") {
|
||||
this.body.contentEditable = 'true';
|
||||
}
|
||||
this.initmouse();
|
||||
addEventListener('load', (function(_this) {
|
||||
return function() {
|
||||
@@ -248,7 +270,8 @@
|
||||
invisible: a.invisible,
|
||||
italic: a.italic,
|
||||
faint: a.faint,
|
||||
crossed: a.crossed
|
||||
crossed: a.crossed,
|
||||
placeholder: false
|
||||
};
|
||||
};
|
||||
|
||||
@@ -256,12 +279,18 @@
|
||||
return a.bg === b.bg && a.fg === b.fg && a.bold === b.bold && a.underline === b.underline && a.blink === b.blink && a.inverse === b.inverse && a.invisible === b.invisible && a.italic === b.italic && a.faint === b.faint && a.crossed === b.crossed;
|
||||
};
|
||||
|
||||
Terminal.prototype.putChar = function(c) {
|
||||
Terminal.prototype.putChar = function(c, placeholder) {
|
||||
var newChar;
|
||||
if (placeholder == null) {
|
||||
placeholder = false;
|
||||
}
|
||||
newChar = this.cloneAttr(this.curAttr, c);
|
||||
newChar.placeholder = placeholder;
|
||||
if (this.insertMode) {
|
||||
this.screen[this.y + this.shift].chars.splice(this.x, 0, this.cloneAttr(this.curAttr, c));
|
||||
this.screen[this.y + this.shift].chars.splice(this.x, 0, newChar);
|
||||
this.screen[this.y + this.shift].chars.pop();
|
||||
} else {
|
||||
this.screen[this.y + this.shift].chars[this.x] = this.cloneAttr(this.curAttr, c);
|
||||
this.screen[this.y + this.shift].chars[this.x] = newChar;
|
||||
}
|
||||
return this.screen[this.y + this.shift].dirty = true;
|
||||
};
|
||||
@@ -297,7 +326,8 @@
|
||||
invisible: false,
|
||||
italic: false,
|
||||
faint: false,
|
||||
crossed: false
|
||||
crossed: false,
|
||||
placeholder: false
|
||||
};
|
||||
this.curAttr = this.cloneAttr(this.defAttr);
|
||||
this.params = [];
|
||||
@@ -342,6 +372,7 @@
|
||||
this.showCursor();
|
||||
this.body.classList.add('focus');
|
||||
this.body.classList.remove('blur');
|
||||
this.inputHelper.focus();
|
||||
this.resize();
|
||||
return this.scrollLock = old_sl;
|
||||
};
|
||||
@@ -581,8 +612,15 @@
|
||||
return [classes, styles];
|
||||
};
|
||||
|
||||
Terminal.prototype.isCJK = function(ch) {
|
||||
return ("\u4e00" <= ch && ch <= "\u9fff") || ("\u3040" <= ch && ch <= "\u30ff") || ("\u31f0" <= ch && ch <= "\u31ff") || ("\u3190" <= ch && ch <= "\u319f") || ("\u3301" <= ch && ch <= "\u3356") || ("\uac00" <= ch && ch <= "\ud7ff") || ("\u3000" <= ch && ch <= "\u303f") || ("\uff00" <= ch && ch <= "\uff60") || ("\uffe0" <= ch && ch <= "\uffe6");
|
||||
};
|
||||
|
||||
Terminal.prototype.charToDom = function(data, attr, cursor) {
|
||||
var ch, char, classes, ref, styles;
|
||||
if (data.placeholder) {
|
||||
return;
|
||||
}
|
||||
if (data.html) {
|
||||
return data.html;
|
||||
}
|
||||
@@ -621,12 +659,12 @@
|
||||
default:
|
||||
if (ch <= " ") {
|
||||
char += " ";
|
||||
} else if (!this.forceWidth) {
|
||||
} else if (!(this.forceWidth || this.isCJK(ch))) {
|
||||
char += ch;
|
||||
} else {
|
||||
if (ch <= "~") {
|
||||
char += ch;
|
||||
} else if (("\uff00" < ch && ch < "\uffef")) {
|
||||
} else if (this.isCJK(ch)) {
|
||||
char += "<span style=\"display: inline-block; width: " + (2 * this.charSize.width) + "px\">" + ch + "</span>";
|
||||
} else {
|
||||
char += "<span style=\"display: inline-block; width: " + this.charSize.width + "px\">" + ch + "</span>";
|
||||
@@ -733,6 +771,7 @@
|
||||
dom = this.screenToDom(force);
|
||||
this.writeDom(dom);
|
||||
this.nativeScrollTo();
|
||||
this.updateInputViews();
|
||||
return this.emit('refresh');
|
||||
};
|
||||
|
||||
@@ -912,12 +951,8 @@
|
||||
}
|
||||
this.putChar(ch);
|
||||
this.x++;
|
||||
if (this.forceWidth && ("\uff00" < ch && ch < "\uffef")) {
|
||||
if (this.cols < 2 || this.x >= this.cols) {
|
||||
this.putChar(" ");
|
||||
break;
|
||||
}
|
||||
this.putChar(" ");
|
||||
if (this.isCJK(ch)) {
|
||||
this.putChar(" ", true);
|
||||
this.x++;
|
||||
}
|
||||
}
|
||||
@@ -1409,11 +1444,93 @@
|
||||
return this.write(data + "\r\n");
|
||||
};
|
||||
|
||||
Terminal.prototype.updateInputViews = function() {
|
||||
var cursorPos;
|
||||
cursorPos = this.cursor.getBoundingClientRect();
|
||||
this.inputView.style['left'] = cursorPos.left + "px";
|
||||
this.inputView.style['top'] = cursorPos.top + "px";
|
||||
this.inputHelper.style['left'] = cursorPos.left + "px";
|
||||
this.inputHelper.style['top'] = cursorPos.top + "px";
|
||||
return this.inputHelper.value = "";
|
||||
};
|
||||
|
||||
Terminal.prototype.compositionStart = function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.updateInputViews();
|
||||
this.inputView.className = "";
|
||||
this.inputView.innerText = "";
|
||||
this.cursor.style['visibility'] = "hidden";
|
||||
this.inComposition = true;
|
||||
this.compositionText = "";
|
||||
return false;
|
||||
};
|
||||
|
||||
Terminal.prototype.compositionUpdate = function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.compositionText = ev.data;
|
||||
this.inputView.innerText = this.compositionText;
|
||||
return false;
|
||||
};
|
||||
|
||||
Terminal.prototype.compositionEnd = function(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
this.finishComposition();
|
||||
return false;
|
||||
};
|
||||
|
||||
Terminal.prototype.finishComposition = function() {
|
||||
this.inComposition = false;
|
||||
this.showCursor();
|
||||
this.inputHelper.value = "";
|
||||
this.inputView.className = "hidden";
|
||||
this.send(this.compositionText);
|
||||
this.compositionText = "";
|
||||
return this.inputHelper.focus();
|
||||
};
|
||||
|
||||
Terminal.prototype.keyDown = function(ev) {
|
||||
var key, ref;
|
||||
if (this.inComposition) {
|
||||
if (ev.keyCode === 229) {
|
||||
return false;
|
||||
} else if (ev.keyCode === 16 || ev.keyCode === 17 || ev.keyCode === 18) {
|
||||
return false;
|
||||
}
|
||||
this.finishComposition();
|
||||
}
|
||||
if (ev.keyCode === 229) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
setTimeout((function(_this) {
|
||||
return function() {
|
||||
var char, e, val;
|
||||
if (!(_this.inComposition || _this.inputHelper.value.length > 1)) {
|
||||
val = _this.inputHelper.value;
|
||||
_this.inputHelper.value = "";
|
||||
char = val.toUpperCase().charCodeAt(0);
|
||||
if ((65 <= char && char <= 90)) {
|
||||
e = new KeyboardEvent('keydown', {
|
||||
keyCode: char
|
||||
});
|
||||
if (window.mobileKeydown(e)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return _this.send(val);
|
||||
}
|
||||
};
|
||||
})(this), 0);
|
||||
return false;
|
||||
}
|
||||
if (ev.keyCode > 15 && ev.keyCode < 19) {
|
||||
return true;
|
||||
}
|
||||
if (window.mobileKeydown(ev)) {
|
||||
return true;
|
||||
}
|
||||
if (ev.keyCode === 19) {
|
||||
this.body.classList.add('stopped');
|
||||
this.out('\x03');
|
||||
@@ -1424,6 +1541,7 @@
|
||||
return true;
|
||||
}
|
||||
if ((ev.shiftKey && ev.ctrlKey) && ((ref = ev.keyCode) === 67 || ref === 86)) {
|
||||
this.body.contentEditable = true;
|
||||
return true;
|
||||
}
|
||||
if (ev.altKey && ev.keyCode === 90 && !this.skipNextKey) {
|
||||
|
||||
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
@@ -18,6 +18,10 @@
|
||||
data-force-unicode-width="{{ 'yes' if options.force_unicode_width else 'no' }}"
|
||||
data-root-path="{{ options.uri_root_path }}"
|
||||
data-session-token={{ session }}>
|
||||
<textarea id="input-helper">
|
||||
</textarea>
|
||||
<div id="input-view" class="hidden">
|
||||
</div>
|
||||
<div id="popup" class="hidden">
|
||||
</div>
|
||||
<script src="{{ static_url('html-sanitizer.js') }}"></script>
|
||||
|
||||
@@ -24,6 +24,7 @@ import signal
|
||||
import string
|
||||
import struct
|
||||
import sys
|
||||
import termios
|
||||
from logging import getLogger
|
||||
|
||||
import tornado.ioloop
|
||||
@@ -32,7 +33,6 @@ import tornado.process
|
||||
import tornado.web
|
||||
import tornado.websocket
|
||||
|
||||
import termios
|
||||
from butterfly import __version__, utils
|
||||
|
||||
log = getLogger('butterfly')
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
addEventListener 'copy', copy = (e) ->
|
||||
document.getElementsByTagName('body')[0].contentEditable = false
|
||||
butterfly.bell "copied"
|
||||
e.clipboardData.clearData()
|
||||
sel = getSelection().toString().replace(
|
||||
@@ -35,6 +36,7 @@ addEventListener 'copy', copy = (e) ->
|
||||
|
||||
|
||||
addEventListener 'paste', (e) ->
|
||||
document.getElementsByTagName('body')[0].contentEditable = false
|
||||
butterfly.bell "pasted"
|
||||
data = e.clipboardData.getData 'text/plain'
|
||||
data = data.replace(/\r\n/g, '\n').replace(/\n/g, '\r')
|
||||
|
||||
@@ -14,11 +14,19 @@ linkify = (text) ->
|
||||
.replace(pseudoUrlPattern, '$1<a href="http://$2">$2</a>')
|
||||
.replace(emailAddressPattern, '<a href="mailto:$&">$&</a>')
|
||||
|
||||
tags =
|
||||
'&': '&'
|
||||
'<': '<'
|
||||
'>': '>'
|
||||
|
||||
escape = (s) -> s.replace(/[&<>]/g, (tag) -> tags[tag] or tag)
|
||||
|
||||
Terminal.on 'change', (line) ->
|
||||
walk line, ->
|
||||
if @nodeType is 3
|
||||
linkified = linkify @nodeValue
|
||||
if linkified isnt @nodeValue
|
||||
val = @nodeValue
|
||||
linkified = linkify escape(val)
|
||||
if linkified isnt val
|
||||
newNode = document.createElement('span')
|
||||
newNode.innerHTML = linkified
|
||||
@parentElement.replaceChild newNode, @
|
||||
|
||||
52
coffees/ext/mobile.coffee
Normal file
52
coffees/ext/mobile.coffee
Normal file
@@ -0,0 +1,52 @@
|
||||
# *-* coding: utf-8 *-*
|
||||
# This file is part of butterfly
|
||||
#
|
||||
# butterfly Copyright(C) 2015-2017 Florian Mounier
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# 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/>.
|
||||
|
||||
ctrl = false
|
||||
alt = false
|
||||
|
||||
addEventListener 'touchstart', (e) ->
|
||||
if e.touches.length == 2
|
||||
ctrl = true
|
||||
else if e.touches.length == 3
|
||||
ctrl = false
|
||||
alt = true
|
||||
else if e.touches.length == 4
|
||||
ctrl = true
|
||||
alt = true
|
||||
|
||||
# Dispatch a new event if the current event need to
|
||||
# be modified with ctrlKey and altKey from touch events
|
||||
# If so, this function will return true and dispatch the new event.
|
||||
# The caller should return immediately upon receiving true.
|
||||
window.mobileKeydown = (e) ->
|
||||
if ctrl or alt
|
||||
_ctrlKey = ctrl
|
||||
_altKey = alt
|
||||
_keyCode = e.keyCode
|
||||
if e.keyCode >= 97 && e.keyCode <= 122
|
||||
_keyCode -= 32
|
||||
e = new KeyboardEvent 'keydown',
|
||||
ctrlKey: _ctrlKey,
|
||||
altKey: _altKey,
|
||||
keyCode: _keyCode
|
||||
ctrl = alt = false
|
||||
setTimeout ->
|
||||
window.dispatchEvent e
|
||||
, 0
|
||||
return true
|
||||
else
|
||||
return false
|
||||
@@ -9,10 +9,6 @@ class Popup
|
||||
@el.innerHTML = html
|
||||
@el.classList.remove 'hidden'
|
||||
|
||||
# ff glorious hack
|
||||
if typeof InstallTrigger isnt "undefined"
|
||||
document.body.contentEditable = 'false'
|
||||
|
||||
addEventListener 'click', @bound_click_maybe_close
|
||||
addEventListener 'keydown', @bound_key_maybe_close
|
||||
|
||||
@@ -20,10 +16,6 @@ class Popup
|
||||
removeEventListener 'click', @bound_click_maybe_close
|
||||
removeEventListener 'keydown', @bound_key_maybe_close
|
||||
|
||||
# ff glorious hack
|
||||
if typeof InstallTrigger isnt "undefined"
|
||||
document.body.contentEditable = 'true'
|
||||
|
||||
@el.classList.add 'hidden'
|
||||
@el.innerHTML = ''
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# *-* coding: utf-8 *-*
|
||||
# This file is part of butterfly
|
||||
#
|
||||
# butterfly Copyright(C) 2015-2017 Florian Mounier
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# 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/>.
|
||||
|
||||
|
||||
if /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
|
||||
.test navigator.userAgent
|
||||
ctrl = false
|
||||
alt = false
|
||||
first = true
|
||||
virtualInput = document.createElement 'input'
|
||||
virtualInput.type = 'password'
|
||||
virtualInput.style.position = 'fixed'
|
||||
virtualInput.style.top = 0
|
||||
virtualInput.style.left = 0
|
||||
virtualInput.style.border = 'none'
|
||||
virtualInput.style.outline = 'none'
|
||||
virtualInput.style.opacity = 0
|
||||
virtualInput.value = '0'
|
||||
document.body.appendChild virtualInput
|
||||
|
||||
virtualInput.addEventListener 'blur', ->
|
||||
setTimeout((=> @focus()), 10)
|
||||
|
||||
addEventListener 'click', ->
|
||||
virtualInput.focus()
|
||||
|
||||
addEventListener 'touchstart', (e) ->
|
||||
if e.touches.length == 2
|
||||
ctrl = true
|
||||
else if e.touches.length == 3
|
||||
ctrl = false
|
||||
alt = true
|
||||
else if e.touches.length == 4
|
||||
ctrl = true
|
||||
alt = true
|
||||
|
||||
virtualInput.addEventListener 'keydown', (e) ->
|
||||
butterfly.keyDown(e)
|
||||
return true
|
||||
|
||||
virtualInput.addEventListener 'input', (e) ->
|
||||
len = @value.length
|
||||
|
||||
if len == 0
|
||||
e.keyCode = 8
|
||||
butterfly.keyDown e
|
||||
@value = '0'
|
||||
return true
|
||||
|
||||
e.keyCode = @value.charAt(1).charCodeAt(0)
|
||||
|
||||
if (ctrl or alt) and not first
|
||||
e.keyCode = @value.charAt(1).charCodeAt(0)
|
||||
e.ctrlKey = ctrl
|
||||
e.altKey = alt
|
||||
if e.keyCode >= 97 && e.keyCode <= 122
|
||||
e.keyCode -= 32
|
||||
butterfly.keyDown e
|
||||
@value = '0'
|
||||
ctrl = alt = false
|
||||
return true
|
||||
|
||||
butterfly.keyPress e
|
||||
first = false
|
||||
@value = '0'
|
||||
true
|
||||
@@ -34,6 +34,9 @@ cancel = (ev) ->
|
||||
ev.cancelBubble = true
|
||||
false
|
||||
|
||||
isMobile = ->
|
||||
/iPhone|iPad|iPod|Android/i.test navigator.userAgent
|
||||
|
||||
s = 0
|
||||
State =
|
||||
normal: s++
|
||||
@@ -67,11 +70,23 @@ class Terminal
|
||||
@forceWidth = @body.getAttribute(
|
||||
'data-force-unicode-width') is 'yes'
|
||||
|
||||
# A hidden textarea to capture all input events
|
||||
# This allows the body to receive IME composition events
|
||||
# without being `contentEditable`, which will mess up
|
||||
# the layout
|
||||
@inputHelper = @document.getElementById('input-helper')
|
||||
|
||||
# A simple div to take place of the IME input preview
|
||||
# which is now hidden due to the textarea
|
||||
@inputView = @document.getElementById('input-view')
|
||||
|
||||
# Main terminal element
|
||||
@body.className = 'terminal focus'
|
||||
@body.style.outline = 'none'
|
||||
@body.setAttribute 'tabindex', 0
|
||||
@body.setAttribute 'spellcheck', 'false'
|
||||
@inputHelper.setAttribute 'tabindex', 0
|
||||
@inputHelper.setAttribute 'spellcheck', 'false'
|
||||
|
||||
# Adding one line to compute char size
|
||||
div = @document.createElement('div')
|
||||
@@ -87,14 +102,29 @@ class Terminal
|
||||
@termName = 'xterm'
|
||||
@cursorBlink = true
|
||||
@cursorState = 0
|
||||
@inComposition = false
|
||||
@compositionText = ""
|
||||
|
||||
@resetVars()
|
||||
|
||||
@focus()
|
||||
|
||||
@startBlink()
|
||||
# IME Events should be registered to the textarea
|
||||
# The textarea helps guiding the IME to pop up
|
||||
# at the correct position
|
||||
@inputHelper.addEventListener 'compositionstart',
|
||||
@compositionStart.bind(@)
|
||||
@inputHelper.addEventListener 'compositionupdate',
|
||||
@compositionUpdate.bind(@)
|
||||
@inputHelper.addEventListener 'compositionend',
|
||||
@compositionEnd.bind(@)
|
||||
addEventListener 'keydown', @keyDown.bind(@)
|
||||
addEventListener 'keypress', @keyPress.bind(@)
|
||||
# Always focus on the inputHelper textarea
|
||||
addEventListener 'keyup', => @inputHelper.focus()
|
||||
if isMobile()
|
||||
addEventListener 'click', => @inputHelper.focus()
|
||||
addEventListener 'focus', @focus.bind(@)
|
||||
addEventListener 'blur', @blur.bind(@)
|
||||
addEventListener 'resize', => @resize()
|
||||
@@ -102,10 +132,6 @@ class Terminal
|
||||
@nativeScrollTo()
|
||||
, true
|
||||
|
||||
# # Horrible Firefox paste workaround
|
||||
if typeof InstallTrigger isnt "undefined"
|
||||
@body.contentEditable = 'true'
|
||||
|
||||
@initmouse()
|
||||
addEventListener 'load', => @resize()
|
||||
@emit 'load'
|
||||
@@ -131,6 +157,7 @@ class Terminal
|
||||
italic: a.italic
|
||||
faint: a.faint
|
||||
crossed: a.crossed
|
||||
placeholder: false
|
||||
|
||||
equalAttr: (a, b) ->
|
||||
# Not testing char
|
||||
@@ -140,12 +167,14 @@ class Terminal
|
||||
a.italic is b.italic and a.faint is b.faint and
|
||||
a.crossed is b.crossed)
|
||||
|
||||
putChar: (c) ->
|
||||
putChar: (c, placeholder = false) ->
|
||||
newChar = @cloneAttr @curAttr, c
|
||||
newChar.placeholder = placeholder
|
||||
if @insertMode
|
||||
@screen[@y + @shift].chars.splice(@x, 0, @cloneAttr @curAttr, c)
|
||||
@screen[@y + @shift].chars.splice(@x, 0, newChar)
|
||||
@screen[@y + @shift].chars.pop()
|
||||
else
|
||||
@screen[@y + @shift].chars[@x] = @cloneAttr @curAttr, c
|
||||
@screen[@y + @shift].chars[@x] = newChar
|
||||
|
||||
@screen[@y + @shift].dirty = true
|
||||
|
||||
@@ -187,6 +216,7 @@ class Terminal
|
||||
italic: false
|
||||
faint: false
|
||||
crossed: false
|
||||
placeholder: false
|
||||
|
||||
@curAttr = @cloneAttr @defAttr
|
||||
@params = []
|
||||
@@ -222,6 +252,7 @@ class Terminal
|
||||
@showCursor()
|
||||
@body.classList.add('focus')
|
||||
@body.classList.remove('blur')
|
||||
@inputHelper.focus() # Always focus on the textarea
|
||||
@resize()
|
||||
|
||||
@scrollLock = old_sl
|
||||
@@ -450,7 +481,21 @@ class Terminal
|
||||
|
||||
[classes, styles]
|
||||
|
||||
# Fullwidth (CJK) character ranges
|
||||
isCJK: (ch) ->
|
||||
"\u4e00" <= ch <= "\u9fff" or # CJK Unified Ideographs
|
||||
"\u3040" <= ch <= "\u30ff" or # Japanese Hiragana and Katakana
|
||||
"\u31f0" <= ch <= "\u31ff" or # Japanese Katakana Phonetic Extensions
|
||||
"\u3190" <= ch <= "\u319f" or # Japanese Kanbun symbols
|
||||
"\u3301" <= ch <= "\u3356" or # Japanese compound characters Kumimoji (組文字)
|
||||
"\uac00" <= ch <= "\ud7ff" or # Hangul precomposed syllables
|
||||
"\u3000" <= ch <= "\u303f" or # CJK Punctuations and Symbols
|
||||
"\uff00" <= ch <= "\uff60" or # Fullwidth forms
|
||||
"\uffe0" <= ch <= "\uffe6" # Fullwidth forms
|
||||
|
||||
charToDom: (data, attr, cursor) ->
|
||||
# Just do not render if we see any placeholder characters
|
||||
return if data.placeholder
|
||||
return data.html if data.html
|
||||
attr = attr or @cloneAttr @defAttr
|
||||
ch = data.ch
|
||||
@@ -478,12 +523,13 @@ class Terminal
|
||||
else
|
||||
if ch <= " "
|
||||
char += " "
|
||||
else unless @forceWidth
|
||||
# CJK characters should always be forced to be fullwidth
|
||||
else unless @forceWidth or @isCJK ch
|
||||
char += ch
|
||||
else
|
||||
if ch <= "~" # Ascii chars
|
||||
char += ch
|
||||
else if "\uff00" < ch < "\uffef"
|
||||
else if @isCJK ch # CJK always fullwidth
|
||||
char += "<span style=\"display: inline-block; width: #{
|
||||
2 * @charSize.width}px\">#{ch}</span>"
|
||||
else
|
||||
@@ -544,6 +590,7 @@ class Terminal
|
||||
dom = @screenToDom(force)
|
||||
@writeDom dom
|
||||
@nativeScrollTo()
|
||||
@updateInputViews()
|
||||
@emit 'refresh'
|
||||
|
||||
_cursorBlink: ->
|
||||
@@ -692,12 +739,15 @@ class Terminal
|
||||
@x = 0
|
||||
@putChar ch
|
||||
@x++
|
||||
if @forceWidth and "\uff00" < ch < "\uffef"
|
||||
if @cols < 2 or @x >= @cols
|
||||
@putChar " "
|
||||
break
|
||||
|
||||
@putChar " "
|
||||
if @isCJK ch
|
||||
# Add a dummy, placeholder character
|
||||
# for double-width, CJK characters
|
||||
# In order to fix counting of characters
|
||||
# when calculating for remaining cols
|
||||
# They are always considered to be
|
||||
# @forceWidth because otherwise they
|
||||
# do not render properly at all
|
||||
@putChar " ", true
|
||||
@x++
|
||||
|
||||
when State.escaped
|
||||
@@ -1251,11 +1301,96 @@ class Terminal
|
||||
writeln: (data) ->
|
||||
@write "#{data}\r\n"
|
||||
|
||||
updateInputViews: ->
|
||||
# Re-position the textarea and the preview box
|
||||
# to the current position of the cursor
|
||||
cursorPos = @cursor.getBoundingClientRect()
|
||||
@inputView.style['left'] = cursorPos.left + "px"
|
||||
@inputView.style['top'] = cursorPos.top + "px"
|
||||
@inputHelper.style['left'] = cursorPos.left + "px"
|
||||
@inputHelper.style['top'] = cursorPos.top + "px"
|
||||
# Clear the textarea as often as possible
|
||||
@inputHelper.value = ""
|
||||
|
||||
compositionStart: (ev) ->
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
@updateInputViews()
|
||||
|
||||
# Show the preview box
|
||||
@inputView.className = ""
|
||||
@inputView.innerText = ""
|
||||
|
||||
# Hide the blinking cursor
|
||||
@cursor.style['visibility'] = "hidden"
|
||||
|
||||
@inComposition = true
|
||||
@compositionText = ""
|
||||
return false
|
||||
|
||||
compositionUpdate: (ev) ->
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
# Update the composition text
|
||||
@compositionText = ev.data
|
||||
@inputView.innerText = @compositionText
|
||||
return false
|
||||
|
||||
compositionEnd: (ev) ->
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
@finishComposition()
|
||||
return false
|
||||
|
||||
finishComposition: ->
|
||||
@inComposition = false
|
||||
@showCursor()
|
||||
@inputHelper.value = ""
|
||||
@inputView.className = "hidden"
|
||||
@send @compositionText
|
||||
@compositionText = ""
|
||||
# Force focus on the inputHelper
|
||||
@inputHelper.focus()
|
||||
|
||||
keyDown: (ev) ->
|
||||
if @inComposition
|
||||
# Continue IME composition if the character is
|
||||
# composition key or modifier key
|
||||
if ev.keyCode is 229
|
||||
return false
|
||||
else if ev.keyCode is 16 || ev.keyCode is 17 || ev.keyCode is 18
|
||||
return false
|
||||
# Otherwise, if we receive a keyDown, abort the composition
|
||||
@finishComposition()
|
||||
|
||||
if ev.keyCode is 229
|
||||
ev.preventDefault()
|
||||
ev.stopPropagation()
|
||||
# If the composition key is sent while IME not active
|
||||
# it means that some character have been input while IME
|
||||
# enabled, i.e. punctuations
|
||||
# in which case we just fetch it from the text area
|
||||
setTimeout =>
|
||||
unless @inComposition || @inputHelper.value.length > 1
|
||||
val = @inputHelper.value
|
||||
@inputHelper.value = "" # Clear the value immediately
|
||||
char = val.toUpperCase().charCodeAt(0)
|
||||
if 65 <= char <= 90
|
||||
# If the character sent here is a letter
|
||||
# allow it to be overridden on mobile
|
||||
# Combinations like "Ctrl+C" won't work without this
|
||||
# on Chrome for Android
|
||||
e = new KeyboardEvent 'keydown', keyCode: char
|
||||
return if window.mobileKeydown e
|
||||
@send val
|
||||
, 0
|
||||
return false
|
||||
|
||||
# Key Resources:
|
||||
# https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent
|
||||
# Don't handle modifiers alone
|
||||
return true if ev.keyCode > 15 and ev.keyCode < 19
|
||||
return true if window.mobileKeydown ev
|
||||
|
||||
if ev.keyCode is 19 # Pause break
|
||||
@body.classList.add 'stopped'
|
||||
@@ -1268,7 +1403,11 @@ class Terminal
|
||||
return true if (ev.shiftKey or ev.ctrlKey) and ev.keyCode is 45
|
||||
|
||||
# Let the ctrl+shift+c, ctrl+shift+v go through to handle native copy paste
|
||||
return true if (ev.shiftKey and ev.ctrlKey) and ev.keyCode in [67, 86]
|
||||
if (ev.shiftKey and ev.ctrlKey) and ev.keyCode in [67, 86]
|
||||
# Make the content temporarily ediatble, to allow the paste event
|
||||
# to propagate (this does not work for the textarea if not set like this)
|
||||
@body.contentEditable = true
|
||||
return true
|
||||
|
||||
# Alt-z works as an escape to relay the following keys to the browser.
|
||||
# usefull to trigger browser shortcuts, i.e.: Alt+Z F5 to reload
|
||||
|
||||
@@ -20,6 +20,6 @@
|
||||
"grunt-contrib-cssmin": "^1.0.1",
|
||||
"grunt-contrib-uglify": "^1.0.1",
|
||||
"grunt-contrib-watch": "^1.0.0",
|
||||
"grunt-sass": "^1.2.0"
|
||||
"grunt-sass": "^2.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
201
yarn.lock
201
yarn.lock
@@ -179,6 +179,10 @@ camelcase@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
|
||||
|
||||
caseless@~0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
@@ -283,6 +287,10 @@ commander@2.8.x:
|
||||
dependencies:
|
||||
graceful-readlink ">= 1.0.0"
|
||||
|
||||
commander@^2.9.0:
|
||||
version "2.15.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -478,6 +486,16 @@ gaze@^1.0.0:
|
||||
dependencies:
|
||||
globule "^1.0.0"
|
||||
|
||||
generate-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
|
||||
|
||||
generate-object-property@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
|
||||
dependencies:
|
||||
is-property "^1.0.0"
|
||||
|
||||
get-caller-file@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
|
||||
@@ -496,6 +514,16 @@ getpass@^0.1.1:
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
glob@^6.0.4:
|
||||
version "6.0.4"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
|
||||
dependencies:
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "2 || 3"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.0.0, glob@^7.0.3, glob@^7.0.6, glob@~7.1.1:
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
|
||||
@@ -629,12 +657,12 @@ grunt-legacy-util@~1.0.0:
|
||||
underscore.string "~3.2.3"
|
||||
which "~1.2.1"
|
||||
|
||||
grunt-sass@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/grunt-sass/-/grunt-sass-1.2.1.tgz#fb87b6caac46fb32d45177fd2e4b6ff7468c1919"
|
||||
grunt-sass@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/grunt-sass/-/grunt-sass-2.1.0.tgz#b7ba1d85ef4c2d9b7d8195fe65f664ac7554efa1"
|
||||
dependencies:
|
||||
each-async "^1.0.0"
|
||||
node-sass "^3.7.0"
|
||||
node-sass "^4.7.2"
|
||||
object-assign "^4.0.1"
|
||||
|
||||
grunt@^1.0.1:
|
||||
@@ -669,6 +697,15 @@ har-schema@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e"
|
||||
|
||||
har-validator@~2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d"
|
||||
dependencies:
|
||||
chalk "^1.1.1"
|
||||
commander "^2.9.0"
|
||||
is-my-json-valid "^2.12.4"
|
||||
pinkie-promise "^2.0.0"
|
||||
|
||||
har-validator@~4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a"
|
||||
@@ -758,7 +795,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
|
||||
inherits@2, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
@@ -792,6 +829,24 @@ is-fullwidth-code-point@^1.0.0:
|
||||
dependencies:
|
||||
number-is-nan "^1.0.0"
|
||||
|
||||
is-my-ip-valid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
|
||||
|
||||
is-my-json-valid@^2.12.4:
|
||||
version "2.17.2"
|
||||
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c"
|
||||
dependencies:
|
||||
generate-function "^2.0.0"
|
||||
generate-object-property "^1.1.0"
|
||||
is-my-ip-valid "^1.0.0"
|
||||
jsonpointer "^4.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
is-property@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
@@ -851,6 +906,10 @@ jsonify@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
|
||||
jsonpointer@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918"
|
||||
@@ -898,6 +957,10 @@ lodash.clonedeep@^4.3.2:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
|
||||
lodash.mergewith@^4.6.0:
|
||||
version "4.6.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||
|
||||
lodash@^3.10.1, lodash@~3.10.1:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||
@@ -998,9 +1061,9 @@ ms@0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
|
||||
|
||||
nan@^2.3.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
|
||||
nan@^2.10.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
|
||||
|
||||
node-gyp@^3.3.1:
|
||||
version "3.6.1"
|
||||
@@ -1020,9 +1083,9 @@ node-gyp@^3.3.1:
|
||||
tar "^2.0.0"
|
||||
which "1"
|
||||
|
||||
node-sass@^3.7.0:
|
||||
version "3.13.1"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-3.13.1.tgz#7240fbbff2396304b4223527ed3020589c004fc2"
|
||||
node-sass@^4.7.2:
|
||||
version "4.9.0"
|
||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.0.tgz#d1b8aa855d98ed684d6848db929a20771cc2ae52"
|
||||
dependencies:
|
||||
async-foreach "^0.1.3"
|
||||
chalk "^1.1.1"
|
||||
@@ -1033,13 +1096,16 @@ node-sass@^3.7.0:
|
||||
in-publish "^2.0.0"
|
||||
lodash.assign "^4.2.0"
|
||||
lodash.clonedeep "^4.3.2"
|
||||
lodash.mergewith "^4.6.0"
|
||||
meow "^3.7.0"
|
||||
mkdirp "^0.5.1"
|
||||
nan "^2.3.2"
|
||||
nan "^2.10.0"
|
||||
node-gyp "^3.3.1"
|
||||
npmlog "^4.0.0"
|
||||
request "^2.61.0"
|
||||
sass-graph "^2.1.1"
|
||||
request "~2.79.0"
|
||||
sass-graph "^2.2.4"
|
||||
stdout-stream "^1.4.0"
|
||||
"true-case-path" "^1.0.2"
|
||||
|
||||
"nopt@2 || 3", nopt@~3.0.6:
|
||||
version "3.0.6"
|
||||
@@ -1182,6 +1248,10 @@ process-nextick-args@~1.0.6:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
|
||||
|
||||
process-nextick-args@~2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
|
||||
|
||||
pseudomap@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
@@ -1198,6 +1268,10 @@ qs@~5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9"
|
||||
|
||||
qs@~6.3.0:
|
||||
version "6.3.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c"
|
||||
|
||||
qs@~6.4.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
||||
@@ -1225,6 +1299,18 @@ read-pkg@^1.0.0:
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^1.0.0"
|
||||
|
||||
readable-stream@^2.0.1:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.3"
|
||||
isarray "~1.0.0"
|
||||
process-nextick-args "~2.0.0"
|
||||
safe-buffer "~5.1.1"
|
||||
string_decoder "~1.1.1"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@^2.0.6, readable-stream@^2.2.2:
|
||||
version "2.2.9"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8"
|
||||
@@ -1254,7 +1340,7 @@ repeating@^2.0.0:
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request@2, request@^2.61.0:
|
||||
request@2:
|
||||
version "2.81.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||
dependencies:
|
||||
@@ -1281,6 +1367,31 @@ request@2, request@^2.61.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.0.0"
|
||||
|
||||
request@~2.79.0:
|
||||
version "2.79.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
|
||||
dependencies:
|
||||
aws-sign2 "~0.6.0"
|
||||
aws4 "^1.2.1"
|
||||
caseless "~0.11.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.0"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.1.1"
|
||||
har-validator "~2.0.6"
|
||||
hawk "~3.1.3"
|
||||
http-signature "~1.1.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.7"
|
||||
oauth-sign "~0.8.1"
|
||||
qs "~6.3.0"
|
||||
stringstream "~0.0.4"
|
||||
tough-cookie "~2.3.0"
|
||||
tunnel-agent "~0.4.1"
|
||||
uuid "^3.0.0"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
@@ -1311,18 +1422,22 @@ safe-buffer@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
|
||||
|
||||
sass-graph@^2.1.1:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.2.tgz#f4d6c95b546ea2a09d14176d0fc1a07ee2b48354"
|
||||
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
|
||||
sass-graph@^2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
|
||||
dependencies:
|
||||
glob "^7.0.0"
|
||||
lodash "^4.0.0"
|
||||
scss-tokenizer "^0.2.1"
|
||||
yargs "^6.6.0"
|
||||
scss-tokenizer "^0.2.3"
|
||||
yargs "^7.0.0"
|
||||
|
||||
scss-tokenizer@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.1.tgz#07c0cc577bb7ab4d08fd900185adbf4bc844141d"
|
||||
scss-tokenizer@^0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
|
||||
dependencies:
|
||||
js-base64 "^2.1.8"
|
||||
source-map "^0.4.2"
|
||||
@@ -1396,6 +1511,12 @@ statuses@1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
|
||||
|
||||
stdout-stream@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b"
|
||||
dependencies:
|
||||
readable-stream "^2.0.1"
|
||||
|
||||
string-width@^1.0.1, string-width@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
@@ -1410,6 +1531,12 @@ string_decoder@~1.0.0:
|
||||
dependencies:
|
||||
buffer-shims "~1.0.0"
|
||||
|
||||
string_decoder@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
|
||||
dependencies:
|
||||
safe-buffer "~5.1.0"
|
||||
|
||||
stringstream@~0.0.4:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
|
||||
@@ -1483,12 +1610,22 @@ trim-newlines@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
|
||||
|
||||
"true-case-path@^1.0.2":
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.2.tgz#7ec91130924766c7f573be3020c34f8fdfd00d62"
|
||||
dependencies:
|
||||
glob "^6.0.4"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tunnel-agent@~0.4.1:
|
||||
version "0.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
@@ -1599,6 +1736,10 @@ wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
xtend@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||
|
||||
y18n@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
|
||||
@@ -1607,15 +1748,15 @@ yallist@^2.0.0:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
|
||||
yargs-parser@^4.2.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
|
||||
yargs-parser@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
|
||||
yargs@^6.6.0:
|
||||
version "6.6.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
|
||||
yargs@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
|
||||
dependencies:
|
||||
camelcase "^3.0.0"
|
||||
cliui "^3.2.0"
|
||||
@@ -1629,7 +1770,7 @@ yargs@^6.6.0:
|
||||
string-width "^1.0.2"
|
||||
which-module "^1.0.0"
|
||||
y18n "^3.2.1"
|
||||
yargs-parser "^4.2.0"
|
||||
yargs-parser "^5.0.0"
|
||||
|
||||
yargs@~3.10.0:
|
||||
version "3.10.0"
|
||||
|
||||
Reference in New Issue
Block a user