MediaWiki:Gadget-copyTable.js: Difference between revisions
Appearance
Content deleted Content added
No edit summary |
No edit summary |
||
| Line 1: | Line 1: | ||
/** |
/** |
||
* Gadget: CopyTable |
* Gadget: CopyTable |
||
* Discreet copy icon at the |
* Discreet copy icon at the top-right of every wikitable. |
||
* Copies content as TSV for pasting into Excel / Sheets. |
* Copies content as TSV for pasting into Excel / Sheets. |
||
*/ |
*/ |
||
| Line 34: | Line 34: | ||
} |
} |
||
mw.hook( 'wikipage.content' ).add( function ( $content ) { |
mw.hook( 'wikipage.content' ).add( function ( $content ) { |
||
$content.find( 'table.wikitable' ).not( '.copy-table-added' ).each( function () { |
$content.find( 'table.wikitable' ).not( '.copy-table-added' ).each( function () { |
||
var $table = $( this ).addClass( 'copy-table-added' ); |
var $table = $( this ).addClass( 'copy-table-added' ); |
||
var $btn = $( '<button>' ) |
var $btn = $( '<button>' ) |
||
.addClass( 'copy-table-btn' ) |
.addClass( 'copy-table-btn' ) |
||
.attr( 'title', 'Copy table' ) |
.attr( 'title', 'Copy table' ) |
||
.html( COPY_ICON ) |
.html( COPY_ICON ) |
||
.on( 'click', function () { |
.on( 'click', function () { |
||
var tsv = tableToTSV( $table[ 0 ] ); |
var tsv = tableToTSV( $table[ 0 ] ); |
||
navigator.clipboard.writeText( tsv ).then( function () { |
navigator.clipboard.writeText( tsv ).then( function () { |
||
$btn.html( CHECK_ICON ).addClass( 'copy-table-btn--ok' ); |
$btn.html( CHECK_ICON ).addClass( 'copy-table-btn--ok' ); |
||
setTimeout( function () { |
setTimeout( function () { |
||
$btn.html( COPY_ICON ).removeClass( 'copy-table-btn--ok' ); |
$btn.html( COPY_ICON ).removeClass( 'copy-table-btn--ok' ); |
||
}, 2000 ); |
}, 2000 ); |
||
| ⚫ | |||
} ); |
} ); |
||
| ⚫ | |||
// Two boxes: an inner .copy-table-scroll that scrolls horizontally, and a |
|||
// non-scrolling .copy-table-wrapper that anchors the pinned button. The |
|||
// |
// button is a SIBLING of the scroller (inside the wrapper), so it stays at |
||
// the visible top-right while the table scrolls underneath. If the table is |
|||
| ⚫ | |||
// already inside a scroll box, reuse that box as the scroller. |
|||
| ⚫ | |||
| ⚫ | |||
var $scroller; |
|||
| ⚫ | |||
| ⚫ | |||
$target.parent().append( $btn ); // button is now a sibling of the scroller |
|||
$scroller = $parent; |
|||
} else { |
|||
$table.wrap( '<div class="copy-table-scroll">' ); |
|||
$scroller = $table.parent(); |
|||
} |
|||
| ⚫ | |||
$scroller.parent().append( $btn ); |
|||
} ); |
|||
} ); |
} ); |
||
} ); |
|||
}() ); |
}() ); |
||
Latest revision as of 00:24, 11 June 2026
/**
* Gadget: CopyTable
* Discreet copy icon at the top-right of every wikitable.
* Copies content as TSV for pasting into Excel / Sheets.
*/
( function () {
'use strict';
// Standard two-rectangle "copy" icon
var COPY_ICON = '<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"/>'
+ '<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>'
+ '</svg>';
// Checkmark shown after copy
var CHECK_ICON = '<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">'
+ '<polyline points="20 6 9 17 4 12"/>'
+ '</svg>';
function tableToTSV( table ) {
var lines = [];
$( table ).find( 'tr' ).each( function () {
var cells = [];
$( this ).find( 'th, td' ).each( function () {
cells.push( $( this ).text().trim().replace( /[\t\n\r]+/g, ' ' ) );
} );
lines.push( cells.join( '\t' ) );
} );
return lines.join( '\n' );
}
mw.hook( 'wikipage.content' ).add( function ( $content ) {
$content.find( 'table.wikitable' ).not( '.copy-table-added' ).each( function () {
var $table = $( this ).addClass( 'copy-table-added' );
var $btn = $( '<button>' )
.addClass( 'copy-table-btn' )
.attr( 'title', 'Copy table' )
.html( COPY_ICON )
.on( 'click', function () {
var tsv = tableToTSV( $table[ 0 ] );
navigator.clipboard.writeText( tsv ).then( function () {
$btn.html( CHECK_ICON ).addClass( 'copy-table-btn--ok' );
setTimeout( function () {
$btn.html( COPY_ICON ).removeClass( 'copy-table-btn--ok' );
}, 2000 );
} );
} );
// Two boxes: an inner .copy-table-scroll that scrolls horizontally, and a
// non-scrolling .copy-table-wrapper that anchors the pinned button. The
// button is a SIBLING of the scroller (inside the wrapper), so it stays at
// the visible top-right while the table scrolls underneath. If the table is
// already inside a scroll box, reuse that box as the scroller.
var $parent = $table.parent();
var $scroller;
if ( /auto|scroll/.test( $parent.css( 'overflow-x' ) ) ) {
$scroller = $parent;
} else {
$table.wrap( '<div class="copy-table-scroll">' );
$scroller = $table.parent();
}
$scroller.wrap( '<div class="copy-table-wrapper">' );
$scroller.parent().append( $btn );
} );
} );
}() );