|
@@ -33,8 +33,14 @@ class Console extends Tab {
|
|
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
|
|
- const filtersGroup = document.createElement( 'div' );
|
|
|
|
|
- filtersGroup.className = 'console-filters-group';
|
|
|
|
|
|
|
+ const copyButton = document.createElement( 'button' );
|
|
|
|
|
+ copyButton.className = 'console-copy-button';
|
|
|
|
|
+ copyButton.title = 'Copy all';
|
|
|
|
|
+ copyButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>';
|
|
|
|
|
+ copyButton.addEventListener( 'click', () => this.copyAll( copyButton ) );
|
|
|
|
|
+
|
|
|
|
|
+ const buttonsGroup = document.createElement( 'div' );
|
|
|
|
|
+ buttonsGroup.className = 'console-buttons-group';
|
|
|
|
|
|
|
|
Object.keys( this.filters ).forEach( type => {
|
|
Object.keys( this.filters ).forEach( type => {
|
|
|
|
|
|
|
@@ -53,11 +59,11 @@ class Console extends Tab {
|
|
|
label.appendChild( checkbox );
|
|
label.appendChild( checkbox );
|
|
|
label.appendChild( checkmark );
|
|
label.appendChild( checkmark );
|
|
|
label.append( type.charAt( 0 ).toUpperCase() + type.slice( 1 ) );
|
|
label.append( type.charAt( 0 ).toUpperCase() + type.slice( 1 ) );
|
|
|
- filtersGroup.appendChild( label );
|
|
|
|
|
|
|
+ buttonsGroup.appendChild( label );
|
|
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
|
|
- filtersGroup.addEventListener( 'change', ( e ) => {
|
|
|
|
|
|
|
+ buttonsGroup.addEventListener( 'change', ( e ) => {
|
|
|
|
|
|
|
|
const type = e.target.dataset.type;
|
|
const type = e.target.dataset.type;
|
|
|
if ( type in this.filters ) {
|
|
if ( type in this.filters ) {
|
|
@@ -69,8 +75,10 @@ class Console extends Tab {
|
|
|
|
|
|
|
|
} );
|
|
} );
|
|
|
|
|
|
|
|
|
|
+ buttonsGroup.appendChild( copyButton );
|
|
|
|
|
+
|
|
|
header.appendChild( filterInput );
|
|
header.appendChild( filterInput );
|
|
|
- header.appendChild( filtersGroup );
|
|
|
|
|
|
|
+ header.appendChild( buttonsGroup );
|
|
|
this.content.appendChild( header );
|
|
this.content.appendChild( header );
|
|
|
|
|
|
|
|
}
|
|
}
|
|
@@ -92,6 +100,32 @@ class Console extends Tab {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ copyAll( button ) {
|
|
|
|
|
+
|
|
|
|
|
+ const win = this.logContainer.ownerDocument.defaultView;
|
|
|
|
|
+ const selection = win.getSelection();
|
|
|
|
|
+ const selectedText = selection.toString();
|
|
|
|
|
+ const textInConsole = selectedText && this.logContainer.contains( selection.anchorNode );
|
|
|
|
|
+
|
|
|
|
|
+ let text;
|
|
|
|
|
+ if ( textInConsole ) {
|
|
|
|
|
+
|
|
|
|
|
+ text = selectedText;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ const messages = this.logContainer.querySelectorAll( '.log-message:not(.hidden)' );
|
|
|
|
|
+ text = Array.from( messages ).map( msg => msg.dataset.rawText ).join( '\n' );
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ navigator.clipboard.writeText( text );
|
|
|
|
|
+
|
|
|
|
|
+ button.classList.add( 'copied' );
|
|
|
|
|
+ setTimeout( () => button.classList.remove( 'copied' ), 350 );
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
_getIcon( type, subType ) {
|
|
_getIcon( type, subType ) {
|
|
|
|
|
|
|
|
let icon;
|
|
let icon;
|