kopia lustrzana https://github.com/OpenDroneMap/WebODM
194 wiersze
5.6 KiB
JavaScript
194 wiersze
5.6 KiB
JavaScript
import React from 'react';
|
|
import './css/Console.scss';
|
|
import './vendor/google-code-prettify/prettify';
|
|
import './vendor/google-code-prettify/prettify.css';
|
|
import update from 'immutability-helper';
|
|
import Utils from './classes/Utils';
|
|
import $ from 'jquery';
|
|
|
|
class Console extends React.Component {
|
|
constructor(props){
|
|
super();
|
|
|
|
this.state = {
|
|
lines: []
|
|
};
|
|
|
|
if (typeof props.children === "string"){
|
|
this.state.lines = props.children.split('\n');
|
|
if (props.onAddLines) props.onAddLines(this.state.lines);
|
|
}
|
|
|
|
this.autoscroll = props.autoscroll === true;
|
|
|
|
this.setRef = this.setRef.bind(this);
|
|
this.handleMouseOver = this.handleMouseOver.bind(this);
|
|
this.handleMouseOut = this.handleMouseOut.bind(this);
|
|
this.downloadTxt = this.downloadTxt.bind(this);
|
|
this.copyTxt = this.copyTxt.bind(this);
|
|
}
|
|
|
|
componentDidMount(){
|
|
this.checkAutoscroll();
|
|
this.setupDynamicSource();
|
|
}
|
|
|
|
setupDynamicSource(){
|
|
if (this.props.source !== undefined){
|
|
const updateFromSource = () => {
|
|
let sourceUrl = typeof this.props.source === 'function' ?
|
|
this.props.source(this.state.lines.length) :
|
|
this.props.source;
|
|
|
|
// Fetch
|
|
this.sourceRequest = $.get(sourceUrl, text => {
|
|
if (text !== ""){
|
|
let lines = text.split("\n");
|
|
this.addLines(lines);
|
|
}
|
|
})
|
|
.always((_, textStatus) => {
|
|
if (textStatus !== "abort" && this.props.refreshInterval !== undefined){
|
|
this.sourceTimeout = setTimeout(updateFromSource, this.props.refreshInterval);
|
|
}
|
|
this.checkAutoscroll();
|
|
});
|
|
};
|
|
|
|
updateFromSource();
|
|
}
|
|
}
|
|
|
|
clear(){
|
|
this.tearDownDynamicSource();
|
|
this.setState({lines: []});
|
|
this.setupDynamicSource();
|
|
}
|
|
|
|
downloadTxt(filename="console.txt"){
|
|
console.log(filename);
|
|
function saveAs(uri, filename) {
|
|
let link = document.createElement('a');
|
|
if (typeof link.download === 'string') {
|
|
link.href = uri;
|
|
link.download = filename;
|
|
|
|
//Firefox requires the link to be in the body
|
|
document.body.appendChild(link);
|
|
|
|
//simulate click
|
|
link.click();
|
|
|
|
//remove the link when done
|
|
document.body.removeChild(link);
|
|
} else {
|
|
window.open(uri);
|
|
}
|
|
}
|
|
|
|
saveAs("data:application/octet-stream," + encodeURIComponent(this.state.lines.join("\r\n")), filename);
|
|
}
|
|
|
|
copyTxt(){
|
|
const el = document.createElement('textarea');
|
|
el.value = this.state.lines.join("\r\n");
|
|
document.body.appendChild(el);
|
|
el.select();
|
|
document.execCommand('copy');
|
|
document.body.removeChild(el);
|
|
console.log("Output copied to clipboard");
|
|
}
|
|
|
|
tearDownDynamicSource(){
|
|
if (this.sourceTimeout) clearTimeout(this.sourceTimeout);
|
|
if (this.sourceRequest) this.sourceRequest.abort();
|
|
}
|
|
|
|
componentWillUnmount(){
|
|
this.tearDownDynamicSource();
|
|
}
|
|
|
|
setRef(domNode){
|
|
if (domNode != null){
|
|
this.$console = $(domNode);
|
|
}
|
|
}
|
|
|
|
handleMouseOver(){
|
|
this.autoscroll = false;
|
|
}
|
|
|
|
handleMouseOut(){
|
|
this.autoscroll = this.props.autoscroll === true;
|
|
}
|
|
|
|
checkAutoscroll(){
|
|
if (this.$console && this.autoscroll){
|
|
this.$console.scrollTop(this.$console[0].scrollHeight - this.$console.height());
|
|
}
|
|
}
|
|
|
|
addLines(lines){
|
|
if (!Array.isArray(lines)) lines = [lines];
|
|
this.setState(update(this.state, {
|
|
lines: {$push: lines}
|
|
}));
|
|
this.checkAutoscroll();
|
|
if (this.props.onAddLines) this.props.onAddLines(lines);
|
|
}
|
|
|
|
render() {
|
|
const prettyLine = (line) => {
|
|
return {__html: prettyPrintOne(Utils.escapeHtml(line), this.props.lang, this.props.lines)};
|
|
}
|
|
let i = 0;
|
|
|
|
let lines = this.state.lines;
|
|
if (this.props.maximumLines && lines.length > this.props.maximumLines){
|
|
lines = lines.slice(-this.props.maximumLines);
|
|
lines.unshift(`... output truncated at ${this.props.maximumLines} lines ...`);
|
|
}
|
|
|
|
const items = [
|
|
<pre key="console" className={`console prettyprint
|
|
${this.props.lang ? `lang-${this.props.lang}` : ""}
|
|
${this.props.lines ? "linenums" : ""}
|
|
${this.props.className || ""}`}
|
|
style={{height: (this.props.height ? this.props.height : "auto")}}
|
|
onMouseOver={this.handleMouseOver}
|
|
onMouseOut={this.handleMouseOut}
|
|
ref={this.setRef}
|
|
>{lines.map(line => {
|
|
if (this.props.lang) return (<div key={i++} dangerouslySetInnerHTML={prettyLine(line)}></div>);
|
|
else return line + "\n";
|
|
})}
|
|
{"\n"}
|
|
</pre>];
|
|
|
|
if (this.props.showConsoleButtons){
|
|
items.push(<div key="buttons" className="console-buttons">
|
|
<a href="javascript:void(0);" onClick={() => this.downloadTxt()} className="btn btn-sm btn-primary" title="Download To File">
|
|
<i className="fa fa-download"></i>
|
|
</a>
|
|
<a href="javascript:void(0);" onClick={this.copyTxt} className="btn btn-sm btn-primary" title="Copy To Clipboard">
|
|
<i className="fa fa-clipboard"></i>
|
|
</a>
|
|
</div>);
|
|
}
|
|
|
|
return items;
|
|
}
|
|
}
|
|
|
|
$(function(){
|
|
$("[data-console]").each(function(){
|
|
window.ReactDOM.render(<Console
|
|
lang={$(this).data("console-lang")}
|
|
height={$(this).data("console-height")}
|
|
autoscroll={typeof $(this).attr("autoscroll") !== 'undefined' && $(this).attr("autoscroll") !== false}
|
|
>{$(this).text()}</Console>, $(this).get(0));
|
|
});
|
|
});
|
|
|
|
export default Console;
|