Frontend initialization refactor (#610)
* Create member functions for ignoreElements and ignorePoint * Create addFullscreenChangeEventListener utility * Move popup creation management into Frontend * Move getUrl implementation * Remove old setup * Remove try/catch block * Error wrap * Add prepare call to TextScanner * Update depth when popup changes * Refactor how Frontend gets PopupFactory and frameId * Update popup preview to work * Update popup preview frame to use the frontend's popup * Update how nested popups are set up * Error wrap * Update how popups are set up on the search page * Error wrap * Error unwrap * Add missing prepare * Remove use of frontendInitializationData * Catch and log errors
This commit is contained in:
parent
244ab31bb2
commit
f2991fb9ee
@ -18,42 +18,16 @@
|
|||||||
/* global
|
/* global
|
||||||
* DisplaySearch
|
* DisplaySearch
|
||||||
* api
|
* api
|
||||||
* dynamicLoader
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function injectSearchFrontend() {
|
|
||||||
await dynamicLoader.loadScripts([
|
|
||||||
'/mixed/js/text-scanner.js',
|
|
||||||
'/fg/js/frame-offset-forwarder.js',
|
|
||||||
'/fg/js/popup.js',
|
|
||||||
'/fg/js/popup-factory.js',
|
|
||||||
'/fg/js/frontend.js',
|
|
||||||
'/fg/js/content-script-main.js'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
try {
|
||||||
api.forwardLogsToBackend();
|
api.forwardLogsToBackend();
|
||||||
await yomichan.prepare();
|
await yomichan.prepare();
|
||||||
|
|
||||||
const displaySearch = new DisplaySearch();
|
const displaySearch = new DisplaySearch();
|
||||||
await displaySearch.prepare();
|
await displaySearch.prepare();
|
||||||
|
} catch (e) {
|
||||||
let optionsApplied = false;
|
yomichan.logError(e);
|
||||||
|
}
|
||||||
const applyOptions = async () => {
|
|
||||||
const optionsContext = {depth: 0, url: window.location.href};
|
|
||||||
const options = await api.optionsGet(optionsContext);
|
|
||||||
if (!options.scanning.enableOnSearchPage || optionsApplied) { return; }
|
|
||||||
|
|
||||||
optionsApplied = true;
|
|
||||||
yomichan.off('optionsUpdated', applyOptions);
|
|
||||||
|
|
||||||
window.frontendInitializationData = {depth: 1, proxy: false, isSearchPage: true};
|
|
||||||
await injectSearchFrontend();
|
|
||||||
};
|
|
||||||
|
|
||||||
yomichan.on('optionsUpdated', applyOptions);
|
|
||||||
|
|
||||||
await applyOptions();
|
|
||||||
})();
|
})();
|
||||||
|
@ -42,6 +42,7 @@ class QueryParser {
|
|||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
await this._queryParserGenerator.prepare();
|
await this._queryParserGenerator.prepare();
|
||||||
|
this._textScanner.prepare();
|
||||||
this._queryParser.addEventListener('click', this._onClick.bind(this));
|
this._queryParser.addEventListener('click', this._onClick.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,11 @@
|
|||||||
* ClipboardMonitor
|
* ClipboardMonitor
|
||||||
* DOM
|
* DOM
|
||||||
* Display
|
* Display
|
||||||
|
* Frontend
|
||||||
|
* PopupFactory
|
||||||
* QueryParser
|
* QueryParser
|
||||||
* api
|
* api
|
||||||
|
* dynamicLoader
|
||||||
* wanakana
|
* wanakana
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -73,7 +76,6 @@ class DisplaySearch extends Display {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
try {
|
|
||||||
await super.prepare();
|
await super.prepare();
|
||||||
await this.updateOptions();
|
await this.updateOptions();
|
||||||
yomichan.on('optionsUpdated', () => this.updateOptions());
|
yomichan.on('optionsUpdated', () => this.updateOptions());
|
||||||
@ -114,10 +116,9 @@ class DisplaySearch extends Display {
|
|||||||
|
|
||||||
this.updateSearchButton();
|
this.updateSearchButton();
|
||||||
|
|
||||||
|
await this._prepareNestedPopups();
|
||||||
|
|
||||||
this._isPrepared = true;
|
this._isPrepared = true;
|
||||||
} catch (e) {
|
|
||||||
this.onError(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onError(error) {
|
onError(error) {
|
||||||
@ -401,4 +402,53 @@ class DisplaySearch extends Display {
|
|||||||
document.title = `${text} - Yomichan Search`;
|
document.title = `${text} - Yomichan Search`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _prepareNestedPopups() {
|
||||||
|
let complete = false;
|
||||||
|
|
||||||
|
const onOptionsUpdated = async () => {
|
||||||
|
const optionsContext = this.getOptionsContext();
|
||||||
|
const options = await api.optionsGet(optionsContext);
|
||||||
|
if (!options.scanning.enableOnSearchPage || complete) { return; }
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
yomichan.off('optionsUpdated', onOptionsUpdated);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this._setupNestedPopups();
|
||||||
|
} catch (e) {
|
||||||
|
yomichan.logError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
yomichan.on('optionsUpdated', onOptionsUpdated);
|
||||||
|
|
||||||
|
await onOptionsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _setupNestedPopups() {
|
||||||
|
await dynamicLoader.loadScripts([
|
||||||
|
'/mixed/js/text-scanner.js',
|
||||||
|
'/fg/js/frame-offset-forwarder.js',
|
||||||
|
'/fg/js/popup.js',
|
||||||
|
'/fg/js/popup-factory.js',
|
||||||
|
'/fg/js/frontend.js'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const {frameId} = await api.frameInformationGet();
|
||||||
|
|
||||||
|
const popupFactory = new PopupFactory(frameId);
|
||||||
|
await popupFactory.prepare();
|
||||||
|
|
||||||
|
const frontend = new Frontend(
|
||||||
|
frameId,
|
||||||
|
popupFactory,
|
||||||
|
{
|
||||||
|
depth: 1,
|
||||||
|
proxy: false,
|
||||||
|
isSearchPage: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await frontend.prepare();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* global
|
/* global
|
||||||
|
* PopupFactory
|
||||||
* PopupPreviewFrame
|
* PopupPreviewFrame
|
||||||
* api
|
* api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
try {
|
||||||
api.forwardLogsToBackend();
|
api.forwardLogsToBackend();
|
||||||
const preview = new PopupPreviewFrame();
|
|
||||||
|
const {frameId} = await api.frameInformationGet();
|
||||||
|
|
||||||
|
const popupFactory = new PopupFactory(frameId);
|
||||||
|
await popupFactory.prepare();
|
||||||
|
|
||||||
|
const preview = new PopupPreviewFrame(frameId, popupFactory);
|
||||||
await preview.prepare();
|
await preview.prepare();
|
||||||
|
} catch (e) {
|
||||||
|
yomichan.logError(e);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -18,17 +18,17 @@
|
|||||||
/* global
|
/* global
|
||||||
* Frontend
|
* Frontend
|
||||||
* Popup
|
* Popup
|
||||||
* PopupFactory
|
|
||||||
* TextSourceRange
|
* TextSourceRange
|
||||||
* api
|
* api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PopupPreviewFrame {
|
class PopupPreviewFrame {
|
||||||
constructor() {
|
constructor(frameId, popupFactory) {
|
||||||
|
this._frameId = frameId;
|
||||||
|
this._popupFactory = popupFactory;
|
||||||
this._frontend = null;
|
this._frontend = null;
|
||||||
this._frontendGetOptionsContextOld = null;
|
this._frontendGetOptionsContextOld = null;
|
||||||
this._apiOptionsGetOld = null;
|
this._apiOptionsGetOld = null;
|
||||||
this._popup = null;
|
|
||||||
this._popupSetCustomOuterCssOld = null;
|
this._popupSetCustomOuterCssOld = null;
|
||||||
this._popupShown = false;
|
this._popupShown = false;
|
||||||
this._themeChangeTimeout = null;
|
this._themeChangeTimeout = null;
|
||||||
@ -55,24 +55,25 @@ class PopupPreviewFrame {
|
|||||||
api.optionsGet = this._apiOptionsGet.bind(this);
|
api.optionsGet = this._apiOptionsGet.bind(this);
|
||||||
|
|
||||||
// Overwrite frontend
|
// Overwrite frontend
|
||||||
const {frameId} = await api.frameInformationGet();
|
this._frontend = new Frontend(
|
||||||
|
this._frameId,
|
||||||
const popupFactory = new PopupFactory(frameId);
|
this._popupFactory,
|
||||||
await popupFactory.prepare();
|
{
|
||||||
|
allowRootFramePopupProxy: false
|
||||||
this._popup = popupFactory.getOrCreatePopup();
|
}
|
||||||
this._popup.setChildrenSupported(false);
|
);
|
||||||
|
|
||||||
this._popupSetCustomOuterCssOld = this._popup.setCustomOuterCss.bind(this._popup);
|
|
||||||
this._popup.setCustomOuterCss = this._popupSetCustomOuterCss.bind(this);
|
|
||||||
|
|
||||||
this._frontend = new Frontend(this._popup);
|
|
||||||
this._frontendGetOptionsContextOld = this._frontend.getOptionsContext.bind(this._frontend);
|
this._frontendGetOptionsContextOld = this._frontend.getOptionsContext.bind(this._frontend);
|
||||||
this._frontend.getOptionsContext = this._getOptionsContext.bind(this);
|
this._frontend.getOptionsContext = this._getOptionsContext.bind(this);
|
||||||
await this._frontend.prepare();
|
await this._frontend.prepare();
|
||||||
this._frontend.setDisabledOverride(true);
|
this._frontend.setDisabledOverride(true);
|
||||||
this._frontend.canClearSelection = false;
|
this._frontend.canClearSelection = false;
|
||||||
|
|
||||||
|
const popup = this._frontend.popup;
|
||||||
|
popup.setChildrenSupported(false);
|
||||||
|
|
||||||
|
this._popupSetCustomOuterCssOld = popup.setCustomOuterCss.bind(popup);
|
||||||
|
popup.setCustomOuterCss = this._popupSetCustomOuterCss.bind(this);
|
||||||
|
|
||||||
// Update search
|
// Update search
|
||||||
this._updateSearch();
|
this._updateSearch();
|
||||||
}
|
}
|
||||||
@ -132,7 +133,9 @@ class PopupPreviewFrame {
|
|||||||
}
|
}
|
||||||
this._themeChangeTimeout = setTimeout(() => {
|
this._themeChangeTimeout = setTimeout(() => {
|
||||||
this._themeChangeTimeout = null;
|
this._themeChangeTimeout = null;
|
||||||
this._popup.updateTheme();
|
const popup = this._frontend.popup;
|
||||||
|
if (popup === null) { return; }
|
||||||
|
popup.updateTheme();
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,12 +157,16 @@ class PopupPreviewFrame {
|
|||||||
|
|
||||||
_setCustomCss({css}) {
|
_setCustomCss({css}) {
|
||||||
if (this._frontend === null) { return; }
|
if (this._frontend === null) { return; }
|
||||||
this._popup.setCustomCss(css);
|
const popup = this._frontend.popup;
|
||||||
|
if (popup === null) { return; }
|
||||||
|
popup.setCustomCss(css);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setCustomOuterCss({css}) {
|
_setCustomOuterCss({css}) {
|
||||||
if (this._frontend === null) { return; }
|
if (this._frontend === null) { return; }
|
||||||
this._popup.setCustomOuterCss(css, false);
|
const popup = this._frontend.popup;
|
||||||
|
if (popup === null) { return; }
|
||||||
|
popup.setCustomOuterCss(css, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updateOptionsContext({optionsContext}) {
|
async _updateOptionsContext({optionsContext}) {
|
||||||
@ -188,7 +195,8 @@ class PopupPreviewFrame {
|
|||||||
this._textSource = source;
|
this._textSource = source;
|
||||||
await this._frontend.showContentCompleted();
|
await this._frontend.showContentCompleted();
|
||||||
|
|
||||||
if (this._popup.isVisibleSync()) {
|
const popup = this._frontend.popup;
|
||||||
|
if (popup !== null && popup.isVisibleSync()) {
|
||||||
this._popupShown = true;
|
this._popupShown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@
|
|||||||
<script src="/fg/js/source.js"></script>
|
<script src="/fg/js/source.js"></script>
|
||||||
<script src="/fg/js/popup-factory.js"></script>
|
<script src="/fg/js/popup-factory.js"></script>
|
||||||
<script src="/fg/js/frontend.js"></script>
|
<script src="/fg/js/frontend.js"></script>
|
||||||
|
<script src="/fg/js/frame-offset-forwarder.js"></script>
|
||||||
<script src="/bg/js/settings/popup-preview-frame.js"></script>
|
<script src="/bg/js/settings/popup-preview-frame.js"></script>
|
||||||
|
|
||||||
<script src="/bg/js/settings/popup-preview-frame-main.js"></script>
|
<script src="/bg/js/settings/popup-preview-frame-main.js"></script>
|
||||||
|
@ -16,147 +16,31 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* global
|
/* global
|
||||||
* DOM
|
|
||||||
* FrameOffsetForwarder
|
|
||||||
* Frontend
|
* Frontend
|
||||||
* PopupFactory
|
* PopupFactory
|
||||||
* PopupProxy
|
|
||||||
* api
|
* api
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function createPopupFactory() {
|
(async () => {
|
||||||
|
try {
|
||||||
|
api.forwardLogsToBackend();
|
||||||
|
await yomichan.prepare();
|
||||||
|
|
||||||
const {frameId} = await api.frameInformationGet();
|
const {frameId} = await api.frameInformationGet();
|
||||||
if (typeof frameId !== 'number') {
|
if (typeof frameId !== 'number') {
|
||||||
const error = new Error('Failed to get frameId');
|
throw new Error('Failed to get frameId');
|
||||||
yomichan.logError(error);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const popupFactory = new PopupFactory(frameId);
|
const popupFactory = new PopupFactory(frameId);
|
||||||
await popupFactory.prepare();
|
await popupFactory.prepare();
|
||||||
return popupFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createIframePopupProxy(frameOffsetForwarder, setDisabled) {
|
const frontend = new Frontend(
|
||||||
const rootPopupInformationPromise = yomichan.getTemporaryListenerResult(
|
frameId,
|
||||||
chrome.runtime.onMessage,
|
popupFactory,
|
||||||
({action, params}, {resolve}) => {
|
{}
|
||||||
if (action === 'rootPopupInformation') {
|
|
||||||
resolve(params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
api.broadcastTab('rootPopupRequestInformationBroadcast');
|
await frontend.prepare();
|
||||||
const {popupId, frameId: parentFrameId} = await rootPopupInformationPromise;
|
} catch (e) {
|
||||||
|
yomichan.logError(e);
|
||||||
const popup = new PopupProxy(popupId, 0, null, parentFrameId, frameOffsetForwarder);
|
|
||||||
popup.on('offsetNotFound', setDisabled);
|
|
||||||
await popup.prepare();
|
|
||||||
|
|
||||||
return popup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getOrCreatePopup(depth, popupFactory) {
|
|
||||||
return popupFactory.getOrCreatePopup(null, null, depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createPopupProxy(depth, id, parentFrameId) {
|
|
||||||
const popup = new PopupProxy(null, depth + 1, id, parentFrameId);
|
|
||||||
await popup.prepare();
|
|
||||||
|
|
||||||
return popup;
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
api.forwardLogsToBackend();
|
|
||||||
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 popupFactoryPromise = 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 api.optionsGet(optionsContext);
|
|
||||||
|
|
||||||
if (!proxy && frameOffsetForwarder === null) {
|
|
||||||
frameOffsetForwarder = new FrameOffsetForwarder();
|
|
||||||
frameOffsetForwarder.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
if (!popup) {
|
|
||||||
if (popupFactoryPromise === null) {
|
|
||||||
popupFactoryPromise = createPopupFactory();
|
|
||||||
}
|
|
||||||
const popupFactory = await popupFactoryPromise;
|
|
||||||
const popupNormal = await getOrCreatePopup(depth, popupFactory);
|
|
||||||
popups.normal = popupNormal;
|
|
||||||
popup = popupNormal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
})();
|
})();
|
||||||
|
@ -18,42 +18,15 @@
|
|||||||
/* global
|
/* global
|
||||||
* DisplayFloat
|
* DisplayFloat
|
||||||
* api
|
* api
|
||||||
* dynamicLoader
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
async function injectPopupNested() {
|
|
||||||
await dynamicLoader.loadScripts([
|
|
||||||
'/mixed/js/text-scanner.js',
|
|
||||||
'/fg/js/popup.js',
|
|
||||||
'/fg/js/popup-proxy.js',
|
|
||||||
'/fg/js/frontend.js',
|
|
||||||
'/fg/js/content-script-main.js'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function popupNestedInitialize(id, depth, parentFrameId, url) {
|
|
||||||
let optionsApplied = false;
|
|
||||||
|
|
||||||
const applyOptions = async () => {
|
|
||||||
const optionsContext = {depth, url};
|
|
||||||
const options = await api.optionsGet(optionsContext);
|
|
||||||
const maxPopupDepthExceeded = !(typeof depth === 'number' && depth < options.scanning.popupNestingMaxDepth);
|
|
||||||
if (maxPopupDepthExceeded || optionsApplied) { return; }
|
|
||||||
|
|
||||||
optionsApplied = true;
|
|
||||||
yomichan.off('optionsUpdated', applyOptions);
|
|
||||||
|
|
||||||
window.frontendInitializationData = {id, depth, parentFrameId, url, proxy: true};
|
|
||||||
await injectPopupNested();
|
|
||||||
};
|
|
||||||
|
|
||||||
yomichan.on('optionsUpdated', applyOptions);
|
|
||||||
|
|
||||||
await applyOptions();
|
|
||||||
}
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
try {
|
||||||
api.forwardLogsToBackend();
|
api.forwardLogsToBackend();
|
||||||
|
|
||||||
const display = new DisplayFloat();
|
const display = new DisplayFloat();
|
||||||
await display.prepare();
|
await display.prepare();
|
||||||
|
} catch (e) {
|
||||||
|
yomichan.logError(e);
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
/* global
|
/* global
|
||||||
* Display
|
* Display
|
||||||
|
* Frontend
|
||||||
|
* PopupFactory
|
||||||
* api
|
* api
|
||||||
* popupNestedInitialize
|
* dynamicLoader
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class DisplayFloat extends Display {
|
class DisplayFloat extends Display {
|
||||||
@ -30,7 +32,7 @@ class DisplayFloat extends Display {
|
|||||||
this._token = null;
|
this._token = null;
|
||||||
|
|
||||||
this._orphaned = false;
|
this._orphaned = false;
|
||||||
this._initializedNestedPopups = false;
|
this._nestedPopupsPrepared = false;
|
||||||
|
|
||||||
this._onKeyDownHandlers = new Map([
|
this._onKeyDownHandlers = new Map([
|
||||||
['C', (e) => {
|
['C', (e) => {
|
||||||
@ -183,10 +185,10 @@ class DisplayFloat extends Display {
|
|||||||
|
|
||||||
await this.updateOptions();
|
await this.updateOptions();
|
||||||
|
|
||||||
if (childrenSupported && !this._initializedNestedPopups) {
|
if (childrenSupported && !this._nestedPopupsPrepared) {
|
||||||
const {depth, url} = optionsContext;
|
const {depth, url} = optionsContext;
|
||||||
popupNestedInitialize(popupId, depth, frameId, url);
|
this._prepareNestedPopups(popupId, depth, frameId, url);
|
||||||
this._initializedNestedPopups = true;
|
this._nestedPopupsPrepared = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setContentScale(scale);
|
this.setContentScale(scale);
|
||||||
@ -201,4 +203,57 @@ class DisplayFloat extends Display {
|
|||||||
this._secret === message.secret
|
this._secret === message.secret
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _prepareNestedPopups(id, depth, parentFrameId, url) {
|
||||||
|
let complete = false;
|
||||||
|
|
||||||
|
const onOptionsUpdated = async () => {
|
||||||
|
const optionsContext = this.optionsContext;
|
||||||
|
const options = await api.optionsGet(optionsContext);
|
||||||
|
const maxPopupDepthExceeded = !(typeof depth === 'number' && depth < options.scanning.popupNestingMaxDepth);
|
||||||
|
if (maxPopupDepthExceeded || complete) { return; }
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
yomichan.off('optionsUpdated', onOptionsUpdated);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this._setupNestedPopups(id, depth, parentFrameId, url);
|
||||||
|
} catch (e) {
|
||||||
|
yomichan.logError(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
yomichan.on('optionsUpdated', onOptionsUpdated);
|
||||||
|
|
||||||
|
await onOptionsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _setupNestedPopups(id, depth, parentFrameId, url) {
|
||||||
|
await dynamicLoader.loadScripts([
|
||||||
|
'/mixed/js/text-scanner.js',
|
||||||
|
'/fg/js/popup.js',
|
||||||
|
'/fg/js/popup-proxy.js',
|
||||||
|
'/fg/js/popup-factory.js',
|
||||||
|
'/fg/js/frame-offset-forwarder.js',
|
||||||
|
'/fg/js/frontend.js'
|
||||||
|
]);
|
||||||
|
|
||||||
|
const {frameId} = await api.frameInformationGet();
|
||||||
|
|
||||||
|
const popupFactory = new PopupFactory(frameId);
|
||||||
|
await popupFactory.prepare();
|
||||||
|
|
||||||
|
const frontend = new Frontend(
|
||||||
|
frameId,
|
||||||
|
popupFactory,
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
depth,
|
||||||
|
parentFrameId,
|
||||||
|
url,
|
||||||
|
proxy: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await frontend.prepare();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,16 +16,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* global
|
/* global
|
||||||
|
* DOM
|
||||||
|
* FrameOffsetForwarder
|
||||||
|
* PopupProxy
|
||||||
* TextScanner
|
* TextScanner
|
||||||
* api
|
* api
|
||||||
* docSentenceExtract
|
* docSentenceExtract
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Frontend {
|
class Frontend {
|
||||||
constructor(popup, getUrl=null) {
|
constructor(frameId, popupFactory, frontendInitializationData) {
|
||||||
this._id = yomichan.generateId(16);
|
this._id = yomichan.generateId(16);
|
||||||
this._popup = popup;
|
this._popup = null;
|
||||||
this._getUrl = getUrl;
|
|
||||||
this._disabledOverride = false;
|
this._disabledOverride = false;
|
||||||
this._options = null;
|
this._options = null;
|
||||||
this._pageZoomFactor = 1.0;
|
this._pageZoomFactor = 1.0;
|
||||||
@ -37,11 +39,31 @@ class Frontend {
|
|||||||
this._optionsUpdatePending = false;
|
this._optionsUpdatePending = false;
|
||||||
this._textScanner = new TextScanner({
|
this._textScanner = new TextScanner({
|
||||||
node: window,
|
node: window,
|
||||||
ignoreElements: () => this._popup.isProxy() ? [] : [this._popup.getFrame()],
|
ignoreElements: this._ignoreElements.bind(this),
|
||||||
ignorePoint: (x, y) => this._popup.containsPoint(x, y),
|
ignorePoint: this._ignorePoint.bind(this),
|
||||||
search: this._search.bind(this)
|
search: this._search.bind(this)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
depth=0,
|
||||||
|
id: proxyPopupId,
|
||||||
|
parentFrameId,
|
||||||
|
proxy: useProxyPopup=false,
|
||||||
|
isSearchPage=false,
|
||||||
|
allowRootFramePopupProxy=true
|
||||||
|
} = frontendInitializationData;
|
||||||
|
this._proxyPopupId = proxyPopupId;
|
||||||
|
this._parentFrameId = parentFrameId;
|
||||||
|
this._useProxyPopup = useProxyPopup;
|
||||||
|
this._isSearchPage = isSearchPage;
|
||||||
|
this._depth = depth;
|
||||||
|
this._frameId = frameId;
|
||||||
|
this._frameOffsetForwarder = new FrameOffsetForwarder();
|
||||||
|
this._popupFactory = popupFactory;
|
||||||
|
this._allowRootFramePopupProxy = allowRootFramePopupProxy;
|
||||||
|
this._popupCache = new Map();
|
||||||
|
this._updatePopupToken = null;
|
||||||
|
|
||||||
this._windowMessageHandlers = new Map([
|
this._windowMessageHandlers = new Map([
|
||||||
['popupClose', this._onMessagePopupClose.bind(this)],
|
['popupClose', this._onMessagePopupClose.bind(this)],
|
||||||
['selectionCopy', this._onMessageSelectionCopy.bind()]
|
['selectionCopy', this._onMessageSelectionCopy.bind()]
|
||||||
@ -62,8 +84,13 @@ class Frontend {
|
|||||||
this._textScanner.canClearSelection = value;
|
this._textScanner.canClearSelection = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get popup() {
|
||||||
|
return this._popup;
|
||||||
|
}
|
||||||
|
|
||||||
async prepare() {
|
async prepare() {
|
||||||
try {
|
this._frameOffsetForwarder.prepare();
|
||||||
|
|
||||||
await this.updateOptions();
|
await this.updateOptions();
|
||||||
try {
|
try {
|
||||||
const {zoomFactor} = await api.getZoom();
|
const {zoomFactor} = await api.getZoom();
|
||||||
@ -72,7 +99,10 @@ class Frontend {
|
|||||||
// Ignore exceptions which may occur due to being on an unsupported page (e.g. about:blank)
|
// Ignore exceptions which may occur due to being on an unsupported page (e.g. about:blank)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._textScanner.prepare();
|
||||||
|
|
||||||
window.addEventListener('resize', this._onResize.bind(this), false);
|
window.addEventListener('resize', this._onResize.bind(this), false);
|
||||||
|
DOM.addFullscreenChangeEventListener(this._updatePopup.bind(this));
|
||||||
|
|
||||||
const visualViewport = window.visualViewport;
|
const visualViewport = window.visualViewport;
|
||||||
if (visualViewport !== null && typeof visualViewport === 'object') {
|
if (visualViewport !== null && typeof visualViewport === 'object') {
|
||||||
@ -88,17 +118,12 @@ class Frontend {
|
|||||||
this._textScanner.on('clearSelection', this._onClearSelection.bind(this));
|
this._textScanner.on('clearSelection', this._onClearSelection.bind(this));
|
||||||
this._textScanner.on('activeModifiersChanged', this._onActiveModifiersChanged.bind(this));
|
this._textScanner.on('activeModifiersChanged', this._onActiveModifiersChanged.bind(this));
|
||||||
|
|
||||||
|
api.crossFrame.registerHandlers([
|
||||||
|
['getUrl', {async: false, handler: this._onApiGetUrl.bind(this)}]
|
||||||
|
]);
|
||||||
|
|
||||||
this._updateContentScale();
|
this._updateContentScale();
|
||||||
this._broadcastRootPopupInformation();
|
this._broadcastRootPopupInformation();
|
||||||
} catch (e) {
|
|
||||||
yomichan.logError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async setPopup(popup) {
|
|
||||||
this._textScanner.clearSelection(true);
|
|
||||||
this._popup = popup;
|
|
||||||
await popup.setOptionsContext(await this.getOptionsContext(), this._id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDisabledOverride(disabled) {
|
setDisabledOverride(disabled) {
|
||||||
@ -112,8 +137,16 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getOptionsContext() {
|
async getOptionsContext() {
|
||||||
const url = this._getUrl !== null ? await this._getUrl() : window.location.href;
|
let url = window.location.href;
|
||||||
const depth = this._popup.depth;
|
if (this._useProxyPopup) {
|
||||||
|
try {
|
||||||
|
url = await api.crossFrame.invoke(this._parentFrameId, 'getUrl', {});
|
||||||
|
} catch (e) {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const depth = this._depth;
|
||||||
const modifierKeys = [...this._activeModifiers];
|
const modifierKeys = [...this._activeModifiers];
|
||||||
return {depth, url, modifierKeys};
|
return {depth, url, modifierKeys};
|
||||||
}
|
}
|
||||||
@ -121,6 +154,9 @@ class Frontend {
|
|||||||
async updateOptions() {
|
async updateOptions() {
|
||||||
const optionsContext = await this.getOptionsContext();
|
const optionsContext = await this.getOptionsContext();
|
||||||
this._options = await api.optionsGet(optionsContext);
|
this._options = await api.optionsGet(optionsContext);
|
||||||
|
|
||||||
|
await this._updatePopup();
|
||||||
|
|
||||||
this._textScanner.setOptions(this._options);
|
this._textScanner.setOptions(this._options);
|
||||||
this._updateTextScannerEnabled();
|
this._updateTextScannerEnabled();
|
||||||
|
|
||||||
@ -130,8 +166,6 @@ class Frontend {
|
|||||||
}
|
}
|
||||||
this._textScanner.ignoreNodes = ignoreNodes.join(',');
|
this._textScanner.ignoreNodes = ignoreNodes.join(',');
|
||||||
|
|
||||||
await this._popup.setOptionsContext(optionsContext, this._id);
|
|
||||||
|
|
||||||
this._updateContentScale();
|
this._updateContentScale();
|
||||||
|
|
||||||
const textSourceCurrent = this._textScanner.getCurrentTextSource();
|
const textSourceCurrent = this._textScanner.getCurrentTextSource();
|
||||||
@ -167,6 +201,12 @@ class Frontend {
|
|||||||
this._broadcastDocumentInformation(uniqueId);
|
this._broadcastDocumentInformation(uniqueId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API message handlers
|
||||||
|
|
||||||
|
_onApiGetUrl() {
|
||||||
|
return window.location.href;
|
||||||
|
}
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_onResize() {
|
_onResize() {
|
||||||
@ -223,6 +263,95 @@ class Frontend {
|
|||||||
await this.updateOptions();
|
await this.updateOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _updatePopup() {
|
||||||
|
const showIframePopupsInRootFrame = this._options.general.showIframePopupsInRootFrame;
|
||||||
|
const isIframe = !this._useProxyPopup && (window !== window.parent);
|
||||||
|
|
||||||
|
let popupPromise;
|
||||||
|
if (
|
||||||
|
isIframe &&
|
||||||
|
showIframePopupsInRootFrame &&
|
||||||
|
DOM.getFullscreenElement() === null &&
|
||||||
|
this._allowRootFramePopupProxy
|
||||||
|
) {
|
||||||
|
popupPromise = this._popupCache.get('iframe');
|
||||||
|
if (typeof popupPromise === 'undefined') {
|
||||||
|
popupPromise = this._getIframeProxyPopup();
|
||||||
|
this._popupCache.set('iframe', popupPromise);
|
||||||
|
}
|
||||||
|
} else if (this._useProxyPopup) {
|
||||||
|
popupPromise = this._popupCache.get('proxy');
|
||||||
|
if (typeof popupPromise === 'undefined') {
|
||||||
|
popupPromise = this._getProxyPopup();
|
||||||
|
this._popupCache.set('proxy', popupPromise);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
popupPromise = this._popupCache.get('default');
|
||||||
|
if (typeof popupPromise === 'undefined') {
|
||||||
|
popupPromise = this._getDefaultPopup();
|
||||||
|
this._popupCache.set('default', popupPromise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The token below is used as a unique identifier to ensure that a new _updatePopup call
|
||||||
|
// hasn't been started during the await.
|
||||||
|
const token = {};
|
||||||
|
this._updatePopupToken = token;
|
||||||
|
const popup = await popupPromise;
|
||||||
|
const optionsContext = await this.getOptionsContext();
|
||||||
|
if (this._updatePopupToken !== token) { return; }
|
||||||
|
await popup.setOptionsContext(optionsContext, this._id);
|
||||||
|
if (this._updatePopupToken !== token) { return; }
|
||||||
|
|
||||||
|
if (this._isSearchPage) {
|
||||||
|
this.setDisabledOverride(!this._options.scanning.enableOnSearchPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._textScanner.clearSelection(true);
|
||||||
|
this._popup = popup;
|
||||||
|
this._depth = popup.depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getDefaultPopup() {
|
||||||
|
return this._popupFactory.getOrCreatePopup(null, null, this._depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getProxyPopup() {
|
||||||
|
const popup = new PopupProxy(null, this._depth + 1, this._proxyPopupId, this._parentFrameId);
|
||||||
|
await popup.prepare();
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getIframeProxyPopup() {
|
||||||
|
const rootPopupInformationPromise = yomichan.getTemporaryListenerResult(
|
||||||
|
chrome.runtime.onMessage,
|
||||||
|
({action, params}, {resolve}) => {
|
||||||
|
if (action === 'rootPopupInformation') {
|
||||||
|
resolve(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
api.broadcastTab('rootPopupRequestInformationBroadcast');
|
||||||
|
const {popupId, frameId: parentFrameId} = await rootPopupInformationPromise;
|
||||||
|
|
||||||
|
const popup = new PopupProxy(popupId, 0, null, parentFrameId, this._frameOffsetForwarder);
|
||||||
|
popup.on('offsetNotFound', () => {
|
||||||
|
this._allowRootFramePopupProxy = false;
|
||||||
|
this._updatePopup();
|
||||||
|
});
|
||||||
|
await popup.prepare();
|
||||||
|
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ignoreElements() {
|
||||||
|
return this._popup === null || this._popup.isProxy() ? [] : [this._popup.getFrame()];
|
||||||
|
}
|
||||||
|
|
||||||
|
_ignorePoint(x, y) {
|
||||||
|
return this._popup !== null && this._popup.containsPoint(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
async _search(textSource, cause) {
|
async _search(textSource, cause) {
|
||||||
await this._updatePendingOptions();
|
await this._updatePendingOptions();
|
||||||
|
|
||||||
@ -318,7 +447,7 @@ class Frontend {
|
|||||||
_updateTextScannerEnabled() {
|
_updateTextScannerEnabled() {
|
||||||
const enabled = (
|
const enabled = (
|
||||||
this._options.general.enable &&
|
this._options.general.enable &&
|
||||||
this._popup.depth <= this._options.scanning.popupNestingMaxDepth &&
|
this._depth <= this._options.scanning.popupNestingMaxDepth &&
|
||||||
!this._disabledOverride
|
!this._disabledOverride
|
||||||
);
|
);
|
||||||
this._enabledEventListeners.removeAllEventListeners();
|
this._enabledEventListeners.removeAllEventListeners();
|
||||||
@ -342,27 +471,41 @@ class Frontend {
|
|||||||
if (contentScale === this._contentScale) { return; }
|
if (contentScale === this._contentScale) { return; }
|
||||||
|
|
||||||
this._contentScale = contentScale;
|
this._contentScale = contentScale;
|
||||||
|
if (this._popup !== null) {
|
||||||
this._popup.setContentScale(this._contentScale);
|
this._popup.setContentScale(this._contentScale);
|
||||||
|
}
|
||||||
this._updatePopupPosition();
|
this._updatePopupPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
async _updatePopupPosition() {
|
async _updatePopupPosition() {
|
||||||
const textSource = this._textScanner.getCurrentTextSource();
|
const textSource = this._textScanner.getCurrentTextSource();
|
||||||
if (textSource !== null && await this._popup.isVisible()) {
|
if (
|
||||||
|
textSource !== null &&
|
||||||
|
this._popup !== null &&
|
||||||
|
await this._popup.isVisible()
|
||||||
|
) {
|
||||||
this._showPopupContent(textSource, await this.getOptionsContext());
|
this._showPopupContent(textSource, await this.getOptionsContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcastRootPopupInformation() {
|
_broadcastRootPopupInformation() {
|
||||||
if (!this._popup.isProxy() && this._popup.depth === 0 && this._popup.frameId === 0) {
|
if (
|
||||||
api.broadcastTab('rootPopupInformation', {popupId: this._popup.id, frameId: this._popup.frameId});
|
this._popup !== null &&
|
||||||
|
!this._popup.isProxy() &&
|
||||||
|
this._depth === 0 &&
|
||||||
|
this._frameId === 0
|
||||||
|
) {
|
||||||
|
api.broadcastTab('rootPopupInformation', {
|
||||||
|
popupId: this._popup.id,
|
||||||
|
frameId: this._frameId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_broadcastDocumentInformation(uniqueId) {
|
_broadcastDocumentInformation(uniqueId) {
|
||||||
api.broadcastTab('documentInformationBroadcast', {
|
api.broadcastTab('documentInformationBroadcast', {
|
||||||
uniqueId,
|
uniqueId,
|
||||||
frameId: this._popup.frameId,
|
frameId: this._frameId,
|
||||||
title: document.title
|
title: document.title
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,7 @@ class PopupFactory {
|
|||||||
['showContent', {async: true, handler: this._onApiShowContent.bind(this)}],
|
['showContent', {async: true, handler: this._onApiShowContent.bind(this)}],
|
||||||
['setCustomCss', {async: false, handler: this._onApiSetCustomCss.bind(this)}],
|
['setCustomCss', {async: false, handler: this._onApiSetCustomCss.bind(this)}],
|
||||||
['clearAutoPlayTimer', {async: false, handler: this._onApiClearAutoPlayTimer.bind(this)}],
|
['clearAutoPlayTimer', {async: false, handler: this._onApiClearAutoPlayTimer.bind(this)}],
|
||||||
['setContentScale', {async: false, handler: this._onApiSetContentScale.bind(this)}],
|
['setContentScale', {async: false, handler: this._onApiSetContentScale.bind(this)}]
|
||||||
['getUrl', {async: false, handler: this._onApiGetUrl.bind(this)}]
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,10 +146,6 @@ class PopupFactory {
|
|||||||
return popup.setContentScale(scale);
|
return popup.setContentScale(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onApiGetUrl() {
|
|
||||||
return window.location.href;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
|
|
||||||
_getPopup(id) {
|
_getPopup(id) {
|
||||||
|
@ -104,10 +104,6 @@ class PopupProxy extends EventDispatcher {
|
|||||||
this._invoke('setContentScale', {id: this._id, scale});
|
this._invoke('setContentScale', {id: this._id, scale});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUrl() {
|
|
||||||
return await this._invoke('getUrl', {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
_invoke(action, params={}) {
|
_invoke(action, params={}) {
|
||||||
|
@ -415,16 +415,7 @@ class Popup {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullscreenEvents = [
|
DOM.addFullscreenChangeEventListener(this._onFullscreenChanged.bind(this), this._fullscreenEventListeners);
|
||||||
'fullscreenchange',
|
|
||||||
'MSFullscreenChange',
|
|
||||||
'mozfullscreenchange',
|
|
||||||
'webkitfullscreenchange'
|
|
||||||
];
|
|
||||||
const onFullscreenChanged = this._onFullscreenChanged.bind(this);
|
|
||||||
for (const eventName of fullscreenEvents) {
|
|
||||||
this._fullscreenEventListeners.addEventListener(document, eventName, onFullscreenChanged, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onFullscreenChanged() {
|
_onFullscreenChanged() {
|
||||||
|
@ -77,6 +77,24 @@ class DOM {
|
|||||||
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
|
return (typeof key === 'string' ? (key.length === 1 ? key.toUpperCase() : key) : '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static addFullscreenChangeEventListener(onFullscreenChanged, eventListenerCollection=null) {
|
||||||
|
const target = document;
|
||||||
|
const options = false;
|
||||||
|
const fullscreenEventNames = [
|
||||||
|
'fullscreenchange',
|
||||||
|
'MSFullscreenChange',
|
||||||
|
'mozfullscreenchange',
|
||||||
|
'webkitfullscreenchange'
|
||||||
|
];
|
||||||
|
for (const eventName of fullscreenEventNames) {
|
||||||
|
if (eventListenerCollection === null) {
|
||||||
|
target.addEventListener(eventName, onFullscreenChanged, options);
|
||||||
|
} else {
|
||||||
|
eventListenerCollection.addEventListener(target, eventName, onFullscreenChanged, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static getFullscreenElement() {
|
static getFullscreenElement() {
|
||||||
return (
|
return (
|
||||||
document.fullscreenElement ||
|
document.fullscreenElement ||
|
||||||
|
@ -28,6 +28,7 @@ class TextScanner extends EventDispatcher {
|
|||||||
this._ignorePoint = ignorePoint;
|
this._ignorePoint = ignorePoint;
|
||||||
this._search = search;
|
this._search = search;
|
||||||
|
|
||||||
|
this._isPrepared = false;
|
||||||
this._ignoreNodes = null;
|
this._ignoreNodes = null;
|
||||||
|
|
||||||
this._causeCurrent = null;
|
this._causeCurrent = null;
|
||||||
@ -69,10 +70,15 @@ class TextScanner extends EventDispatcher {
|
|||||||
return this._causeCurrent;
|
return this._causeCurrent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepare() {
|
||||||
|
this._isPrepared = true;
|
||||||
|
this.setEnabled(this._enabled);
|
||||||
|
}
|
||||||
|
|
||||||
setEnabled(enabled) {
|
setEnabled(enabled) {
|
||||||
this._eventListeners.removeAllEventListeners();
|
this._eventListeners.removeAllEventListeners();
|
||||||
this._enabled = enabled;
|
this._enabled = enabled;
|
||||||
if (this._enabled) {
|
if (this._enabled && this._isPrepared) {
|
||||||
this._hookEvents();
|
this._hookEvents();
|
||||||
} else {
|
} else {
|
||||||
this.clearSelection(true);
|
this.clearSelection(true);
|
||||||
|
Loading…
Reference in New Issue
Block a user