1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00
joplin/packages/app-mobile/components/NoteBodyViewer/bundledJs/utils/addPluginAssets.ts

77 lines
2.4 KiB
TypeScript
Raw Normal View History

import { RenderResultPluginAsset } from '@joplin/renderer/types';
type PluginAssetRecord = {
element: HTMLElement;
};
const pluginAssetsAdded_: Record<string, PluginAssetRecord> = {};
// Note that this function keeps track of what's been added so as not to
// add the same CSS files multiple times.
//
// Shared with app-desktop/gui-note-viewer.
//
// TODO: If possible, refactor such that this function is not duplicated.
const addPluginAssets = (assets: RenderResultPluginAsset[]) => {
if (!assets) return;
const pluginAssetsContainer = document.getElementById('joplin-container-pluginAssetsContainer');
const processedAssetIds = [];
for (let i = 0; i < assets.length; i++) {
const asset = assets[i];
// # and ? can be used in valid paths and shouldn't be treated as the start of a query or fragment
const encodedPath = asset.path
.replace(/#/g, '%23')
.replace(/\?/g, '%3F');
const assetId = asset.name ? asset.name : encodedPath;
processedAssetIds.push(assetId);
if (pluginAssetsAdded_[assetId]) continue;
let element = null;
if (asset.mime === 'application/javascript') {
element = document.createElement('script');
element.src = encodedPath;
pluginAssetsContainer.appendChild(element);
} else if (asset.mime === 'text/css') {
element = document.createElement('link');
element.rel = 'stylesheet';
element.href = encodedPath;
pluginAssetsContainer.appendChild(element);
}
pluginAssetsAdded_[assetId] = {
element,
};
}
// Once we have added the relevant assets, we also remove those that
// are no longer needed. It's necessary in particular for the CSS
// generated by noteStyle - if we don't remove it, we might end up
// with two or more stylesheet and that will create conflicts.
//
// It was happening for example when automatically switching from
// light to dark theme, and then back to light theme - in that case
// the viewer would remain dark because it would use the dark
// stylesheet that would still be in the DOM.
for (const [assetId, asset] of Object.entries(pluginAssetsAdded_)) {
if (!processedAssetIds.includes(assetId)) {
try {
asset.element.remove();
} catch (error) {
// We don't throw an exception but we log it since
// it shouldn't happen
console.warn('Tried to remove an asset but got an error', error);
}
pluginAssetsAdded_[assetId] = null;
}
}
};
export default addPluginAssets;