refactor of open. potential fix for ipad.

This commit is contained in:
Christopher Jeffrey
2013-08-14 00:29:57 -05:00
parent 349daf25bf
commit cd956bca1d
+82 -30
View File
@@ -180,7 +180,7 @@ function Terminal(options) {
// this.context = options.context || window; // this.context = options.context || window;
// this.document = options.document || document; // this.document = options.document || document;
this.parent = options.body || options.parent this.parent = options.body || options.parent
|| (document ? document.body : null); || (document ? document.getElementsByTagName('body')[0] : null);
this.cols = options.cols || options.geometry[0]; this.cols = options.cols || options.geometry[0];
this.rows = options.rows || options.geometry[1]; this.rows = options.rows || options.geometry[1];
@@ -458,8 +458,12 @@ Terminal.prototype.initGlobal = function() {
Terminal.bindKeys(document); Terminal.bindKeys(document);
if (this.isIpad) {
Terminal.fixIpad(document);
}
if (this.useStyle) { if (this.useStyle) {
Terminal.insertStyle(document, this); Terminal.insertStyle(document, this.colors[256], this.colors[257]);
} }
}; };
@@ -468,17 +472,17 @@ Terminal.prototype.initGlobal = function() {
*/ */
Terminal.bindKeys = function(document) { Terminal.bindKeys = function(document) {
// We could put an "if (Terminal.focus)" check // We should only need to check `target === body` below,
// here, but it shouldn't be necessary. // but we can check everything for good measure.
on(document, 'keydown', function(ev) { on(document, 'keydown', function(ev) {
if (!Terminal.focus) return; if (!Terminal.focus) return;
var target = ev.target || ev.srcElement; var target = ev.target || ev.srcElement;
// Should just be body, but we can if (!target) return;
// check everything for good measure.
if (target === Terminal.focus.element if (target === Terminal.focus.element
|| target === Terminal.focus.context || target === Terminal.focus.context
|| target === Terminal.focus.document || target === Terminal.focus.document
|| target === Terminal.focus.document.body || target === Terminal.focus.body
|| target === Terminal._textarea
|| target === Terminal.focus.parent) { || target === Terminal.focus.parent) {
return Terminal.focus.keyDown(ev); return Terminal.focus.keyDown(ev);
} }
@@ -487,12 +491,12 @@ Terminal.bindKeys = function(document) {
on(document, 'keypress', function(ev) { on(document, 'keypress', function(ev) {
if (!Terminal.focus) return; if (!Terminal.focus) return;
var target = ev.target || ev.srcElement; var target = ev.target || ev.srcElement;
// Should just be body, but we can if (!target) return;
// check everything for good measure.
if (target === Terminal.focus.element if (target === Terminal.focus.element
|| target === Terminal.focus.context || target === Terminal.focus.context
|| target === Terminal.focus.document || target === Terminal.focus.document
|| target === Terminal.focus.document.body || target === Terminal.focus.body
|| target === Terminal._textarea
|| target === Terminal.focus.parent) { || target === Terminal.focus.parent) {
return Terminal.focus.keyPress(ev); return Terminal.focus.keyPress(ev);
} }
@@ -514,12 +518,35 @@ Terminal.bindKeys = function(document) {
}); });
}; };
/**
* Fix iPad - no idea if this works
*/
Terminal.fixIpad = function(document) {
var textarea = document.createElement('textarea');
textarea.style.position = 'absolute';
textarea.style.left = '-32000px';
textarea.style.top = '-32000px';
textarea.style.opacity = '0';
textarea.style.backgroundColor = 'transparent';
textarea.style.borderStyle = 'none';
textarea.style.outlineStyle = 'none';
document.getElementsByTagName('body')[0].appendChild(textarea);
Terminal._textarea = textarea;
setTimeout(function() {
textarea.focus();
}, 1000);
};
/** /**
* Insert a default style * Insert a default style
*/ */
Terminal.insertStyle = function(document, term) { Terminal.insertStyle = function(document, bg, fg) {
var style = document.getElementById('termjs-style'); var style = document.getElementById('term-style');
if (style) return; if (style) return;
var head = document.getElementsByTagName('head')[0]; var head = document.getElementsByTagName('head')[0];
@@ -532,16 +559,16 @@ Terminal.insertStyle = function(document, term) {
style.innerHTML = '' style.innerHTML = ''
+ '.terminal {\n' + '.terminal {\n'
+ ' float: left;\n' + ' float: left;\n'
+ ' border: ' + term.colors[256] + ' solid 5px;\n' + ' border: ' + bg + ' solid 5px;\n'
+ ' font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;\n' + ' font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;\n'
+ ' font-size: 11px;\n' + ' font-size: 11px;\n'
+ ' color: ' + term.colors[257] + ';\n' + ' color: ' + fg + ';\n'
+ ' background: ' + term.colors[256] + ';\n' + ' background: ' + bg + ';\n'
+ '}\n' + '}\n'
+ '\n' + '\n'
+ '.terminal-cursor {\n' + '.terminal-cursor {\n'
+ ' color: ' + term.colors[256] + ';\n' + ' color: ' + bg + ';\n'
+ ' background: ' + term.colors[257] + ';\n' + ' background: ' + fg + ';\n'
+ '}\n'; + '}\n';
head.insertBefore(style, head.firstChild); head.insertBefore(style, head.firstChild);
@@ -562,36 +589,58 @@ Terminal.prototype.open = function(parent) {
throw new Error('Terminal requires a parent element.'); throw new Error('Terminal requires a parent element.');
} }
// Grab global elements.
this.context = this.parent.ownerDocument.defaultView; this.context = this.parent.ownerDocument.defaultView;
this.document = this.parent.ownerDocument; this.document = this.parent.ownerDocument;
this.body = this.document.getElementsByTagName('body')[0];
// Parse user-agent strings.
if (this.context.navigator && this.context.navigator.userAgent) {
this.isMac = !!~this.context.navigator.userAgent.indexOf('Mac');
this.isIpad = !!~this.context.navigator.userAgent.indexOf('iPad');
this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
}
// Create our main terminal element.
this.element = this.document.createElement('div'); this.element = this.document.createElement('div');
this.element.className = 'terminal'; this.element.className = 'terminal';
this.element.style.outline = 'none'; this.element.style.outline = 'none';
this.element.setAttribute('tabindex', 0); this.element.setAttribute('tabindex', 0);
this.element.style.backgroundColor = this.colors[256];
this.element.style.color = this.colors[257];
// Create the lines for our terminal.
this.children = []; this.children = [];
for (; i < this.rows; i++) { for (; i < this.rows; i++) {
div = this.document.createElement('div'); div = this.document.createElement('div');
this.element.appendChild(div); this.element.appendChild(div);
this.children.push(div); this.children.push(div);
} }
this.parent.appendChild(this.element); this.parent.appendChild(this.element);
// Draw the screen.
this.refresh(0, this.rows - 1); this.refresh(0, this.rows - 1);
// Initialize global actions that
// need to be taken on the document.
this.initGlobal(); this.initGlobal();
// Ensure there is a Terminal.focus.
this.focus(); this.focus();
// Start blinking the cursor.
this.startBlink(); this.startBlink();
// Bind to DOM events related
// to focus and paste behavior.
on(this.element, 'focus', function() { on(this.element, 'focus', function() {
self.focus(); self.focus();
if (Terminal._textarea) {
Terminal._textarea.focus();
}
}); });
// This causes slightly funky behavior.
// on(this.element, 'blur', function() { // on(this.element, 'blur', function() {
// self.blur(); // self.blur();
// }); // });
@@ -600,6 +649,7 @@ Terminal.prototype.open = function(parent) {
self.focus(); self.focus();
}); });
// Clickable paste workaround, using contentEditable.
// This probably shouldn't work, // This probably shouldn't work,
// ... but it does. Firefox's paste // ... but it does. Firefox's paste
// event seems to only work for textareas? // event seems to only work for textareas?
@@ -623,6 +673,8 @@ Terminal.prototype.open = function(parent) {
}, 1); }, 1);
}, true); }, true);
// This seems to work well for ctrl-V and middle-click,
// even without the contentEditable workaround.
on(this.element, 'paste', function(ev) { on(this.element, 'paste', function(ev) {
if (ev.clipboardData) { if (ev.clipboardData) {
self.send(ev.clipboardData.getData('text/plain')); self.send(ev.clipboardData.getData('text/plain'));
@@ -634,6 +686,8 @@ Terminal.prototype.open = function(parent) {
return cancel(ev); return cancel(ev);
}); });
// Listen for mouse events and translate
// them into terminal mouse protocols.
this.bindMouse(); this.bindMouse();
// Figure out whether boldness affects // Figure out whether boldness affects
@@ -642,16 +696,13 @@ Terminal.prototype.open = function(parent) {
Terminal.brokenBold = isBoldBroken(this.document); Terminal.brokenBold = isBoldBroken(this.document);
} }
// sync default bg/fg colors
this.element.style.backgroundColor = this.colors[256];
this.element.style.color = this.colors[257];
if (this.context.navigator && this.context.navigator.userAgent) {
this.isMac = !!~this.context.navigator.userAgent.indexOf('Mac');
this.isMSIE = !!~this.context.navigator.userAgent.indexOf('MSIE');
}
// this.emit('open'); // this.emit('open');
// This can be useful for pasting,
// as well as the iPad fix.
setTimeout(function() {
self.element.focus();
}, 100);
}; };
// XTerm mouse events // XTerm mouse events
@@ -4515,13 +4566,14 @@ function inherits(child, parent) {
// if bold is broken, we can't // if bold is broken, we can't
// use it in the terminal. // use it in the terminal.
function isBoldBroken(document) { function isBoldBroken(document) {
var body = document.getElementsByTagName('body')[0];
var el = document.createElement('span'); var el = document.createElement('span');
el.innerHTML = 'hello world'; el.innerHTML = 'hello world';
document.body.appendChild(el); body.appendChild(el);
var w1 = el.scrollWidth; var w1 = el.scrollWidth;
el.style.fontWeight = 'bold'; el.style.fontWeight = 'bold';
var w2 = el.scrollWidth; var w2 = el.scrollWidth;
document.body.removeChild(el); body.removeChild(el);
return w1 !== w2; return w1 !== w2;
} }