Eugene Pankov 0ea346a6ae wip
2017-04-11 02:22:48 +02:00

92 lines
2.8 KiB
TypeScript

import { Inject, Injectable } from '@angular/core'
import { TerminalDecorator, TerminalTabComponent } from 'terminus-terminal'
import { LinkHandler } from './api'
@Injectable()
export class LinkHighlighterDecorator extends TerminalDecorator {
constructor (@Inject(LinkHandler) private handlers: LinkHandler[]) {
super()
}
attach (terminal: TerminalTabComponent): void {
terminal.contentUpdated$
.debounceTime(1000)
.subscribe(() => {
this.insertLinks(terminal.hterm.screen_)
})
}
insertLinks (screen) {
if ('#text' === screen.cursorNode_.nodeName) {
// replace text node to element
const cursorNode = document.createElement('span');
cursorNode.textContent = screen.cursorNode_.textContent;
screen.cursorRowNode_.replaceChild(cursorNode, screen.cursorNode_);
screen.cursorNode_ = cursorNode;
}
const traverse = (parentNode: Node) => {
Array.from(parentNode.childNodes).forEach((node) => {
if (node.nodeName == '#text') {
parentNode.replaceChild(this.urlizeNode(node), node)
} else if (node.nodeName != 'A') {
traverse(node)
}
})
}
screen.rowsArray.forEach((x) => traverse(x))
}
urlizeNode (node) {
let matches = []
this.handlers.forEach((handler) => {
let regex = new RegExp(handler.regex, 'gi')
let match
while (match = regex.exec(node.textContent)) {
let uri = handler.convert(match[0])
if (!handler.verify(uri)) {
continue;
}
matches.push({
start: regex.lastIndex - match[0].length,
end: regex.lastIndex,
text: match[0],
uri,
handler
})
}
})
if (matches.length == 0) {
return node
}
matches.sort((a, b) => a.start < b.start ? -1 : 1)
let span = document.createElement('span')
let position = 0
matches.forEach((match) => {
if (match.start < position) {
return
}
if (match.start > position) {
span.appendChild(document.createTextNode(node.textContent.slice(position, match.start)))
}
let a = document.createElement('a')
a.textContent = match.text
a.addEventListener('click', () => {
match.handler.handle(match.uri)
})
span.appendChild(a)
position = match.end
})
span.appendChild(document.createTextNode(node.textContent.slice(position)))
return span
}
}