Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)
at lambda-fork/main 89 lines 3.1 kB view raw
1/* 2 * Copyright (C) 2023-2025 Yomitan Authors 3 * Copyright (C) 2020-2022 Yomichan Authors 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19import {FrameAncestryHandler} from './frame-ancestry-handler.js'; 20 21export class FrameOffsetForwarder { 22 /** 23 * @param {import('../comm/cross-frame-api.js').CrossFrameAPI} crossFrameApi 24 */ 25 constructor(crossFrameApi) { 26 /** @type {import('../comm/cross-frame-api.js').CrossFrameAPI} */ 27 this._crossFrameApi = crossFrameApi; 28 /** @type {FrameAncestryHandler} */ 29 this._frameAncestryHandler = new FrameAncestryHandler(crossFrameApi); 30 } 31 32 /** 33 * @returns {void} 34 */ 35 prepare() { 36 this._frameAncestryHandler.prepare(); 37 this._crossFrameApi.registerHandlers([ 38 ['frameOffsetForwarderGetChildFrameRect', this._onMessageGetChildFrameRect.bind(this)], 39 ]); 40 } 41 42 /** 43 * @returns {Promise<?[x: number, y: number]>} 44 */ 45 async getOffset() { 46 if (this._frameAncestryHandler.isRootFrame()) { 47 return [0, 0]; 48 } 49 50 const {frameId} = this._crossFrameApi; 51 if (frameId === null) { return null; } 52 53 try { 54 const ancestorFrameIds = await this._frameAncestryHandler.getFrameAncestryInfo(); 55 56 let childFrameId = frameId; 57 /** @type {Promise<?import('frame-offset-forwarder').ChildFrameRect>[]} */ 58 const promises = []; 59 for (const ancestorFrameId of ancestorFrameIds) { 60 promises.push(this._crossFrameApi.invoke(ancestorFrameId, 'frameOffsetForwarderGetChildFrameRect', {frameId: childFrameId})); 61 childFrameId = ancestorFrameId; 62 } 63 64 const results = await Promise.all(promises); 65 66 let x = 0; 67 let y = 0; 68 for (const result of results) { 69 if (result === null) { return null; } 70 x += result.x; 71 y += result.y; 72 } 73 return [x, y]; 74 } catch (e) { 75 return null; 76 } 77 } 78 79 // Private 80 81 /** @type {import('cross-frame-api').ApiHandler<'frameOffsetForwarderGetChildFrameRect'>} */ 82 _onMessageGetChildFrameRect({frameId}) { 83 const frameElement = this._frameAncestryHandler.getChildFrameElement(frameId); 84 if (frameElement === null) { return null; } 85 86 const {left, top, width, height} = frameElement.getBoundingClientRect(); 87 return {x: left, y: top, width, height}; 88 } 89}