mirror of
https://github.com/ihhub/fheroes2.git
synced 2026-10-12 02:16:11 +00:00
151 lines
5.5 KiB
JavaScript
151 lines
5.5 KiB
JavaScript
/***************************************************************************
|
|
* fheroes2: https://github.com/ihhub/fheroes2 *
|
|
* Copyright (C) 2025 *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
|
|
// Constants
|
|
const LINK_ICON = '🔗';
|
|
const COPIED_ICON = ' - Copied';
|
|
const ERROR_ICON = '❌';
|
|
const RESET_DELAY = 2000;
|
|
const HEADING_SELECTORS = 'h2, h3, h4, h5, h6';
|
|
|
|
// Class to handle heading copy functionality
|
|
class HeadingCopyManager
|
|
{
|
|
constructor( contentElement )
|
|
{
|
|
this.content = contentElement;
|
|
this.accessibility = new AccessibilityManager();
|
|
|
|
// Apply to all headings
|
|
this.content.querySelectorAll( HEADING_SELECTORS ).forEach( heading => this.createHeadingLink( heading ) );
|
|
}
|
|
|
|
// Creates a unique ID for a heading based on its text content
|
|
// Parameters:
|
|
// text - The heading text
|
|
// Returns: A unique ID
|
|
generateHeadingId( text )
|
|
{
|
|
return text.toLowerCase().replace( /[^a-z0-9]+/g, '-' );
|
|
}
|
|
|
|
// Creates a link icon element with proper accessibility attributes
|
|
// Returns: The icon element
|
|
createIconElement()
|
|
{
|
|
const icon = this.accessibility.createAccessibleSpan( { text : LINK_ICON, ariaLabel : 'Copy link to heading', className : 'heading-anchor' } );
|
|
return icon;
|
|
}
|
|
|
|
// Updates the icon appearance based on the copy result
|
|
// Parameters:
|
|
// icon - The icon element
|
|
// success - Whether the copy was successful
|
|
// headingText - The text of the heading
|
|
updateIconState( icon, success, headingText )
|
|
{
|
|
this.accessibility.updateElementState( {
|
|
element : icon,
|
|
success : success,
|
|
successMessage : `Link to ${headingText} copied to clipboard`,
|
|
errorMessage : `Failed to copy link to ${headingText}`,
|
|
successText : COPIED_ICON,
|
|
errorText : ERROR_ICON,
|
|
defaultText : LINK_ICON,
|
|
resetDelay : RESET_DELAY,
|
|
isHtml : true // Use innerHTML for the heading icon
|
|
} );
|
|
}
|
|
|
|
// Handles the copy functionality for a heading
|
|
// Parameters:
|
|
// e - The event object
|
|
// heading - The heading element
|
|
// icon - The icon element
|
|
handleCopy( e, heading, icon )
|
|
{
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
const url = new URL( window.location.href );
|
|
url.hash = heading.id;
|
|
|
|
try {
|
|
navigator.clipboard.writeText( url.toString() )
|
|
.then( () => {
|
|
this.updateIconState( icon, true, heading.textContent );
|
|
|
|
// Update URL without scrolling
|
|
history.pushState( null, null, `#${heading.id}` );
|
|
} )
|
|
.catch( err => {
|
|
console.error( 'Failed to copy:', err );
|
|
this.updateIconState( icon, false, heading.textContent );
|
|
} );
|
|
}
|
|
catch ( err ) {
|
|
console.error( 'Failed to copy:', err );
|
|
this.updateIconState( icon, false, heading.textContent );
|
|
}
|
|
}
|
|
|
|
// Sets up event listeners for a heading icon
|
|
// Parameters:
|
|
// icon - The icon element
|
|
// heading - The heading element
|
|
setupEventListeners( icon, heading )
|
|
{
|
|
// Add click event handler
|
|
icon.addEventListener( 'click', ( e ) => this.handleCopy( e, heading, icon ) );
|
|
|
|
// Add keyboard event handler
|
|
this.accessibility.setupKeyboardEvents( icon, ( e ) => this.handleCopy( e, heading, icon ) );
|
|
}
|
|
|
|
// Creates a heading link with proper accessibility attributes
|
|
// Parameters:
|
|
// heading - The heading element
|
|
createHeadingLink( heading )
|
|
{
|
|
// Generate ID if needed
|
|
if ( !heading.id ) {
|
|
heading.id = this.generateHeadingId( heading.textContent );
|
|
}
|
|
|
|
// Create icon element
|
|
const icon = this.createIconElement();
|
|
|
|
// Add icon to the heading
|
|
heading.appendChild( icon );
|
|
|
|
// Set up event listeners
|
|
this.setupEventListeners( icon, heading );
|
|
}
|
|
}
|
|
|
|
// Initialize when the DOM is fully loaded
|
|
document.addEventListener( 'DOMContentLoaded', () => {
|
|
const content = document.querySelector( '#main_content' );
|
|
if ( content ) {
|
|
// Initialize the heading copy manager
|
|
new HeadingCopyManager( content );
|
|
}
|
|
} );
|