UNPKG

@ckeditor/ckeditor5-minimap

Version:

Content minimap feature for CKEditor 5.

150 lines (149 loc) 5.54 kB
/** * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ /** * @module minimap/minimapview */ import { View } from 'ckeditor5/src/ui.js'; import { Rect } from 'ckeditor5/src/utils.js'; import MinimapIframeView from './minimapiframeview.js'; import MinimapPositionTrackerView from './minimappositiontrackerview.js'; /** * The main view of the minimap. It renders the original content but scaled down with a tracker element * visualizing the subset of the content visible to the user and allowing interactions (scrolling, dragging). * * @internal */ export default class MinimapView extends View { /** * An instance of the tracker view displayed over the minimap. */ _positionTrackerView; /** * The scale ratio of the minimap relative to the original editing DOM root with the content. */ _scaleRatio; /** * An instance of the iframe view that hosts the minimap. */ _minimapIframeView; /** * Creates an instance of the minimap view. */ constructor({ locale, scaleRatio, pageStyles, extraClasses, useSimplePreview, domRootClone }) { super(locale); const bind = this.bindTemplate; this._positionTrackerView = new MinimapPositionTrackerView(locale); this._positionTrackerView.delegate('drag').to(this); this._scaleRatio = scaleRatio; this._minimapIframeView = new MinimapIframeView(locale, { useSimplePreview, pageStyles, extraClasses, scaleRatio, domRootClone }); this.setTemplate({ tag: 'div', attributes: { class: [ 'ck', 'ck-minimap' ] }, children: [ this._positionTrackerView ], on: { click: bind.to(this._handleMinimapClick.bind(this)), wheel: bind.to(this._handleMinimapMouseWheel.bind(this)) } }); } /** * @inheritDoc */ destroy() { this._minimapIframeView.destroy(); super.destroy(); } /** * Returns the DOM {@link module:utils/dom/rect~Rect} height of the minimap. */ get height() { return new Rect(this.element).height; } /** * Returns the number of available space (pixels) the position tracker (visible subset of the content) can use to scroll vertically. */ get scrollHeight() { return Math.max(0, Math.min(this.height, this._minimapIframeView.height) - this._positionTrackerView.height); } /** * @inheritDoc */ render() { super.render(); this._minimapIframeView.render(); this.element.appendChild(this._minimapIframeView.element); } /** * Sets the new height of the minimap (in px) to respond to the changes in the original editing DOM root. * * **Note**:The provided value should be the `offsetHeight` of the original editing DOM root. */ setContentHeight(newHeight) { this._minimapIframeView.setHeight(newHeight * this._scaleRatio); } /** * Sets the minimap scroll progress. * * The minimap scroll progress is linked to the original editing DOM root and its scrollable container (ancestor). * Changing the progress will alter the vertical position of the minimap (and its position tracker) and give the user an accurate * overview of the visible document. * * **Note**: The value should be between 0 and 1. 0 when the DOM root has not been scrolled, 1 when the * scrolling has reached the end. */ setScrollProgress(newScrollProgress) { const iframeView = this._minimapIframeView; const positionTrackerView = this._positionTrackerView; // The scrolling should end when the bottom edge of the iframe touches the bottom edge of the minimap. if (iframeView.height < this.height) { iframeView.setTopOffset(0); positionTrackerView.setTopOffset((iframeView.height - positionTrackerView.height) * newScrollProgress); } else { const totalOffset = iframeView.height - this.height; iframeView.setTopOffset(-totalOffset * newScrollProgress); positionTrackerView.setTopOffset((this.height - positionTrackerView.height) * newScrollProgress); } positionTrackerView.setScrollProgress(Math.round(newScrollProgress * 100)); } /** * Sets the new height of the tracker (in px) to visualize the subset of the content visible to the user. */ setPositionTrackerHeight(trackerHeight) { this._positionTrackerView.setHeight(trackerHeight * this._scaleRatio); } /** * @param data DOM event data */ _handleMinimapClick(data) { const positionTrackerView = this._positionTrackerView; if (data.target === positionTrackerView.element) { return; } const trackerViewRect = new Rect(positionTrackerView.element); const diff = data.clientY - trackerViewRect.top - trackerViewRect.height / 2; const percentage = diff / this._minimapIframeView.height; this.fire('click', percentage); } /** * @param data DOM event data */ _handleMinimapMouseWheel(data) { this.fire('drag', data.deltaY * this._scaleRatio); } }