Source: overlays/annotations/configurationSection.mjs

/**
 * Implementation for the annotations / ConfigurationWidget integration package.
 * Public entry is `attachAnnotationToolkitConfigurationWidget` from `./index.mjs`.
 * Not a ViewerOverlayBase; builds a custom section via ConfigurationWidget.addSection only.
 */

import { makeFaIcon } from '../../utils/faIcon.mjs';
import {
    ANNOTATION_TOOLBAR_PERSIST_ID_FILE,
    ANNOTATION_TOOLBAR_PERSIST_ID_PENCIL,
} from '../configuration/configuration.mjs';

/**
 * Attach the "Annotations" block to a ConfigurationWidget (calls addSection).
 * Does not register with AnnotationToolkit.destroy(); use AnnotationToolkit#registerWithConfigurationWidget for that.
 *
 * @param {OSDPaperjsAnnotation.AnnotationToolkit} annotationToolkit
 * @param {OSDPaperjsAnnotation.ConfigurationWidget} configurationWidget
 * @returns {HTMLElement|null} Root element passed to addSection, or null if nothing was attached
 */
export function attachAnnotationToolkitConfigurationWidget(annotationToolkit, configurationWidget) {
    if (!annotationToolkit || !configurationWidget) return null;
    if (configurationWidget.viewer !== annotationToolkit.viewer) {
        console.warn('[osd-paperjs-annotation] attachAnnotationToolkitConfigurationWidget: configuration widget viewer does not match toolkit viewer.');
        return null;
    }
    const ui = annotationToolkit.annotationUI;
    if (!ui || typeof ui.getViewerToolbarButtons !== 'function') {
        console.warn('[osd-paperjs-annotation] attachAnnotationToolkitConfigurationWidget requires AnnotationToolkit.addAnnotationUI().');
        return null;
    }
    const { pencil, file } = ui.getViewerToolbarButtons();
    if (!pencil && !file) {
        console.warn('[osd-paperjs-annotation] attachAnnotationToolkitConfigurationWidget: no pencil or file toolbar button to configure.');
        return null;
    }

    const root = document.createElement('div');
    root.classList.add('annotation-toolkit-config-section');

    const list = document.createElement('div');
    list.classList.add('config-overlay-list');

    const headingRow = document.createElement('div');
    headingRow.classList.add('config-overlay-heading-row');
    const titleSpacer = document.createElement('span');
    titleSpacer.classList.add('config-heading-title');
    titleSpacer.setAttribute('aria-hidden', 'true');
    titleSpacer.innerHTML = '\u00a0';
    const colHeader = document.createElement('span');
    colHeader.classList.add('config-col-header');
    colHeader.title = 'Include a button directly in the viewer\'s toolbar';
    colHeader.textContent = 'Show Button';
    headingRow.appendChild(titleSpacer);
    headingRow.appendChild(colHeader);
    headingRow.appendChild(document.createElement('span'));
    list.appendChild(headingRow);

    if (pencil?.element) {
        list.appendChild(_makeOverlayStyleRow({
            labelText: 'Annotation interface',
            faIconClass: 'fa-pencil',
            osdButton: pencil,
            configurationWidget,
            kind: 'pencil',
            ui,
        }));
    }
    if (file?.element) {
        list.appendChild(_makeOverlayStyleRow({
            labelText: 'Save / load annotations',
            faIconClass: 'fa-save',
            osdButton: file,
            configurationWidget,
            kind: 'file',
            ui,
        }));
    }

    root.appendChild(list);
    configurationWidget.addSection('Annotations', root);
    return root;
}

/**
 * @param {Object} p
 * @param {string} p.labelText
 * @param {string} p.faIconClass
 * @param {{ element: HTMLElement }} p.osdButton
 * @param {OSDPaperjsAnnotation.ConfigurationWidget} p.configurationWidget
 * @param {'pencil'|'file'} p.kind
 * @param {Object} p.ui - AnnotationUI instance
 */
function _makeOverlayStyleRow(p) {
    const { labelText, faIconClass, osdButton, configurationWidget, kind, ui } = p;
    const row = document.createElement('div');
    row.classList.add('config-overlay-row');

    const iconEl = document.createElement('div');
    iconEl.classList.add('config-overlay-icon');
    iconEl.appendChild(makeFaIcon(faIconClass));

    const labelEl = document.createElement('div');
    labelEl.classList.add('config-overlay-label');
    labelEl.textContent = labelText;

    const toggle = document.createElement('label');
    toggle.classList.add('config-toggle');
    toggle.title = 'Include a button directly in the viewer\'s toolbar';
    const checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    const slider = document.createElement('span');
    slider.classList.add('config-toggle-slider');
    toggle.appendChild(checkbox);
    toggle.appendChild(slider);

    const el = osdButton.element;
    const computedDisplay = typeof getComputedStyle !== 'undefined'
        ? getComputedStyle(el).display
        : el.style.display;
    const showDisplay = el.style.display && el.style.display !== 'none'
        ? el.style.display
        : (computedDisplay && computedDisplay !== 'none' ? computedDisplay : 'inline-block');

    const persistId = kind === 'pencil' ? ANNOTATION_TOOLBAR_PERSIST_ID_PENCIL : ANNOTATION_TOOLBAR_PERSIST_ID_FILE;
    let appliedPersisted = false;
    if (configurationWidget.persistToolbarVisibilityEnabled()) {
        const persisted = configurationWidget.getPersistedToolbarVisibility(persistId);
        if (typeof persisted === 'boolean') {
            checkbox.checked = persisted;
            el.style.display = persisted ? showDisplay : 'none';
            appliedPersisted = true;
        }
    }
    if (!appliedPersisted) {
        checkbox.checked = computedDisplay !== 'none';
    }

    checkbox.addEventListener('change', () => {
        el.style.display = checkbox.checked ? showDisplay : 'none';
        if (configurationWidget.persistToolbarVisibilityEnabled()) {
            configurationWidget.setPersistedToolbarVisibility(persistId, checkbox.checked);
        }
    });

    const activateBtn = document.createElement('button');
    activateBtn.type = 'button';
    activateBtn.title = kind === 'pencil' ? 'Open or close annotation panels' : 'Open save and load dialog';

    if (kind === 'pencil') {
        const syncPencilLabel = () => {
            activateBtn.textContent = ui.areAnnotationPanelsVisible() ? 'Close' : 'Open';
        };
        syncPencilLabel();
        activateBtn.addEventListener('click', () => {
            ui.toggleAnnotationPanels();
            syncPencilLabel();
        });
    } else {
        activateBtn.textContent = 'Open';
        activateBtn.addEventListener('click', () => {
            ui.openFileDialog();
            configurationWidget.close();
        });
    }

    row.appendChild(iconEl);
    row.appendChild(labelEl);
    row.appendChild(toggle);
    row.appendChild(activateBtn);
    return row;
}