diff options
Diffstat (limited to 'ext/fg/js/content-script-main.js')
-rw-r--r-- | ext/fg/js/content-script-main.js | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/ext/fg/js/content-script-main.js b/ext/fg/js/content-script-main.js new file mode 100644 index 00000000..57386b85 --- /dev/null +++ b/ext/fg/js/content-script-main.js @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2019-2020 Yomichan Authors + * + * 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 3 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, see <https://www.gnu.org/licenses/>. + */ + +/* global + * DOM + * FrameOffsetForwarder + * Frontend + * PopupFactory + * PopupProxy + * apiBroadcastTab + * apiForwardLogsToBackend + * apiFrameInformationGet + * apiOptionsGet + */ + +async function createIframePopupProxy(frameOffsetForwarder, setDisabled) { + const rootPopupInformationPromise = yomichan.getTemporaryListenerResult( + chrome.runtime.onMessage, + ({action, params}, {resolve}) => { + if (action === 'rootPopupInformation') { + resolve(params); + } + } + ); + apiBroadcastTab('rootPopupRequestInformationBroadcast'); + const {popupId, frameId: parentFrameId} = await rootPopupInformationPromise; + + const getFrameOffset = frameOffsetForwarder.getOffset.bind(frameOffsetForwarder); + + const popup = new PopupProxy(popupId, 0, null, parentFrameId, getFrameOffset, setDisabled); + await popup.prepare(); + + return popup; +} + +async function getOrCreatePopup(depth) { + const {frameId} = await apiFrameInformationGet(); + if (typeof frameId !== 'number') { + const error = new Error('Failed to get frameId'); + yomichan.logError(error); + throw error; + } + + const popupFactory = new PopupFactory(frameId); + await popupFactory.prepare(); + + const popup = popupFactory.getOrCreatePopup(null, null, depth); + + return popup; +} + +async function createPopupProxy(depth, id, parentFrameId) { + const popup = new PopupProxy(null, depth + 1, id, parentFrameId); + await popup.prepare(); + + return popup; +} + +(async () => { + apiForwardLogsToBackend(); + await yomichan.prepare(); + + const data = window.frontendInitializationData || {}; + const {id, depth=0, parentFrameId, url=window.location.href, proxy=false, isSearchPage=false} = data; + + const isIframe = !proxy && (window !== window.parent); + + const popups = { + iframe: null, + proxy: null, + normal: null + }; + + let frontend = null; + let frontendPreparePromise = null; + let frameOffsetForwarder = null; + + let iframePopupsInRootFrameAvailable = true; + + const disableIframePopupsInRootFrame = () => { + iframePopupsInRootFrameAvailable = false; + applyOptions(); + }; + + let urlUpdatedAt = 0; + let popupProxyUrlCached = url; + const getPopupProxyUrl = async () => { + const now = Date.now(); + if (popups.proxy !== null && now - urlUpdatedAt > 500) { + popupProxyUrlCached = await popups.proxy.getUrl(); + urlUpdatedAt = now; + } + return popupProxyUrlCached; + }; + + const applyOptions = async () => { + const optionsContext = { + depth: isSearchPage ? 0 : depth, + url: proxy ? await getPopupProxyUrl() : window.location.href + }; + const options = await apiOptionsGet(optionsContext); + + if (!proxy && frameOffsetForwarder === null) { + frameOffsetForwarder = new FrameOffsetForwarder(); + frameOffsetForwarder.start(); + } + + let popup; + if (isIframe && options.general.showIframePopupsInRootFrame && DOM.getFullscreenElement() === null && iframePopupsInRootFrameAvailable) { + popup = popups.iframe || await createIframePopupProxy(frameOffsetForwarder, disableIframePopupsInRootFrame); + popups.iframe = popup; + } else if (proxy) { + popup = popups.proxy || await createPopupProxy(depth, id, parentFrameId); + popups.proxy = popup; + } else { + popup = popups.normal || await getOrCreatePopup(depth); + popups.normal = popup; + } + + if (frontend === null) { + const getUrl = proxy ? getPopupProxyUrl : null; + frontend = new Frontend(popup, getUrl); + frontendPreparePromise = frontend.prepare(); + await frontendPreparePromise; + } else { + await frontendPreparePromise; + if (isSearchPage) { + const disabled = !options.scanning.enableOnSearchPage; + frontend.setDisabledOverride(disabled); + } + + if (isIframe) { + await frontend.setPopup(popup); + } + } + }; + + yomichan.on('optionsUpdated', applyOptions); + window.addEventListener('fullscreenchange', applyOptions, false); + + await applyOptions(); +})(); |