function initXopat(PLUGINS, MODULES, ENV, POST_DATA, PLUGINS_FOLDER, MODULES_FOLDER, VERSION, I18NCONFIG={}) {
const savedState = checkLocalState();
if (savedState) {
PLUGINS = savedState.PLUGINS;
MODULES = savedState.MODULES;
ENV = savedState.ENV;
POST_DATA = savedState.POST_DATA;
PLUGINS_FOLDER = savedState.PLUGINS_FOLDER;
MODULES_FOLDER = savedState.MODULES_FOLDER;
VERSION = savedState.VERSION;
I18NCONFIG = savedState.I18NCONFIG;
}
initXopatUI();
function localizeDom() {
jqueryI18next.init(i18next, $, {
tName: 't',
i18nName: 'i18n',
handleName: 'localize',
selectorAttr: 'data-i18n',
targetAttr: 'i18n-target',
optionsAttr: 'i18n-options',
useOptionsAttr: false,
parseDefaultValueFromContent: true
});
delete window.jqueryI18next;
delete window.i18next;
$('body').localize();
}
if (i18next.isInitialized) {
localizeDom();
} else {
I18NCONFIG.fallbackLng = 'en';
i18next.init(I18NCONFIG, (err, t) => {
if (err) throw err;
localizeDom();
});
}
POST_DATA = xOpatParseConfiguration(POST_DATA, $.i18n, ENV.serverStatus.supportsPost);
let CONFIG = POST_DATA.visualization;
if (!CONFIG) {
CONFIG = {
error: $.t('error.nothingToRender'),
description: $.t('error.noDetails'),
details: 'Initial configuration is not defined!'
};
}
if (!window.OpenSeadragon) {
CONFIG = {
error: $.t('error.nothingToRender'),
description: $.t('error.noDetails'),
details: 'Missing OpenSeadragon library!'
};
}
const defaultSetup = Object.freeze(ENV.setup);
const viewerSecureMode = ENV.client.secureMode && ENV.client.secureMode !== "false";
CONFIG.params = CONFIG.params || {};
CONFIG.params.bypassCookies = CONFIG.params.bypassCookies ?? defaultSetup.bypassCookies;
POST_DATA = POST_DATA || {};
const sessionName = CONFIG.params["sessionName"] || ENV.setup["sessionName"];
if (!XOpatStorage.Cookies.registered()) {
Cookies.withAttributes({
path: ENV.client.js_cookie_path,
domain: ENV.client.js_cookie_domain || ENV.client.domain,
expires: ENV.client.js_cookie_expire,
sameSite: ENV.client.js_cookie_same_site,
secure: typeof ENV.client.js_cookie_secure === "boolean" ? ENV.client.js_cookie_secure : undefined
});
Cookies.set("test", "test");
if (Cookies.get("test") === "test") {
XOpatStorage.Cookies.registerClass(class {
getItem(key) {
return Cookies.get(key) || null;
}
setItem(key, value) {
Cookies.set(key, value);
if (!Cookies.get(key)) {
console.warn("Cookie value too big to store!", key);
}
}
removeItem(key) {
Cookies.remove(key);
}
clear() {
const allCookies = Cookies.get();
for (let key in allCookies) {
Cookies.remove(key);
}
}
get length() {
return Object.keys(Cookies.get()).length;
}
key(index) {
const keys = Object.keys(Cookies.get());
return keys[index] || null;
}
});
} else {
console.warn("Cookie.js seems to be blocked.");
console.log("Cookies are implemented using local storage. This might be a security vulnerability!");
XOpatStorage.Cookies.registerInstance(localStorage);
}
Cookies.remove("test");
}
if (!XOpatStorage.Cache.registered()) {
XOpatStorage.Cache.registerInstance(localStorage);
}
const runLoader = initXOpatLoader(PLUGINS, MODULES, PLUGINS_FOLDER, MODULES_FOLDER, POST_DATA, VERSION);
window.APPLICATION_CONTEXT = {
config: {
get params() {
return CONFIG.params || {};
},
get defaultParams() {
return defaultSetup;
},
get data() {
return CONFIG.data || [];
},
get background() {
return CONFIG.background || [];
},
get visualizations() {
return CONFIG.visualizations || [];
},
get plugins() {
return CONFIG.plugins || {};
},
},
AppCache: {
get() {console.warn("AppCache used before initialization.")},
set() {console.warn("AppCache used before initialization.")},
},
AppCookies: {
get() {console.warn("AppCookies used before initialization.")},
set() {console.warn("AppCookies used before initialization.")},
},
get sessionName() {
const config = VIEWER.scalebar.getReferencedTiledImage()?.getBackgroundConfig() || {};
if (config["sessionName"]) return config["sessionName"];
if (sessionName) return sessionName;
return this.referencedId();
},
get secure() {
return viewerSecureMode;
},
get env() {
return ENV;
},
get url() {
const domain = this.env.client.domain;
if (!domain.endsWith("/")) return domain + "/" + this.env.client.path;
return domain + this.env.client.path;
},
get settingsMenuId() { return "app-settings"; },
get pluginsMenuId() { return "app-plugins"; },
layersAvailable: false,
getOption(name, defaultValue=undefined, cache=true) {
if (cache && this.AppCache) {
let cached = this.AppCache.get(name);
if (cached !== null && cached !== undefined) {
if (cached === "false") cached = false;
else if (cached === "true") cached = true;
return cached;
}
}
let value = this.config.params[name] !== undefined ? this.config.params[name] :
(defaultValue === undefined ? this.config.defaultParams[name] : defaultValue);
if (value === "false") value = false;
else if (value === "true") value = true;
return value;
},
setOption(name, value, cache=true) {
if (cache && this.AppCache) this.AppCache.set(name, value);
if (value === "false") value = false;
else if (value === "true") value = true;
this.config.params[name] = value;
},
setDirty() {
this.__cache.dirty = true;
},
pluginIds() {
return Object.keys(PLUGINS);
},
activePluginIds() {
const result = [];
for (let pid in PLUGINS) {
if (!PLUGINS.hasOwnProperty(pid)) continue;
const plugin = PLUGINS[pid];
if (!plugin.error && plugin.instance && (plugin.loaded || plugin.permaLoad)) {
result.push(pid);
}
}
return result;
},
referencedName(stripSuffix=false) {
if (CONFIG.background.length < 0) {
return undefined;
}
const bgConfig = VIEWER.scalebar.getReferencedTiledImage()?.getBackgroundConfig();
if (bgConfig) {
if (bgConfig.name) return bgConfig.name;
return UTILITIES.fileNameFromPath(CONFIG.data[bgConfig.dataReference], stripSuffix);
}
return undefined;
},
referencedId() {
if (CONFIG.background.length < 0) {
return "__anonymous__";
}
let config;
if (VIEWER.scalebar) {
VIEWER.scalebar.getReferencedTiledImage()?.getBackgroundConfig();
} else {
config = CONFIG.background[APPLICATION_CONTEXT.getOption('activeBackgroundIndex')]
|| CONFIG.background[0];
}
return config ? CONFIG.data[config.dataReference] : "__anonymous__";
},
_dangerouslyAccessConfig() {
return CONFIG;
},
_dangerouslyAccessPlugin(id) {
return PLUGINS[id];
},
__cache: {
dirty: false
}
};
if (!OpenSeadragon.supportsCanvas) {
window.location = `./src/error.php?title=${encodeURIComponent('Your browser is not supported.')}
&description=${encodeURIComponent('ERROR: The visualization requires canvasses in order to work.')}`;
}
const headers = $.extend({}, ENV.client.headers, CONFIG.params.headers);
window.VIEWER = OpenSeadragon({
id: "osd",
prefixUrl: ENV.openSeadragonPrefix + "images",
showNavigator: true,
maxZoomPixelRatio: 2,
zoomPerClick: 2,
zoomPerScroll: 1.7,
blendTime: 0,
animationTime: 0,
showNavigationControl: false,
navigatorId: "panel-navigator",
loadTilesWithAjax : true,
drawer: "canvas",
ajaxHeaders: headers,
splitHashDataForPost: true,
subPixelRoundingForTransparency:
navigator.userAgent.includes("Chrome") && navigator.vendor.includes("Google Inc") ?
OpenSeadragon.SUBPIXEL_ROUNDING_OCCURRENCES.NEVER :
OpenSeadragon.SUBPIXEL_ROUNDING_OCCURRENCES.ONLY_AT_REST,
debugMode: APPLICATION_CONTEXT.getOption("debugMode", false, false),
maxImageCacheCount: APPLICATION_CONTEXT.getOption("maxImageCacheCount", undefined, false)
});
VIEWER.gestureSettingsMouse.clickToZoom = false;
new OpenSeadragon.Tools(VIEWER);
VIEWER.addHandler('warn-user', e => {
if (e.preventDefault || !e.message) return;
Dialogs.show(e.message, Math.max(Math.min(50*e.message.length, 15000), 5000), Dialogs.MSG_WARN, false);
}, -Infinity);
VIEWER.addHandler('error-user', e => {
if (e.preventDefault || !e.message) return;
Dialogs.show(e.message, Math.max(Math.min(50*e.message.length, 15000), 5000), Dialogs.MSG_ERR, false);
}, -Infinity);
VIEWER.addHandler('plugin-failed', e => Dialogs.show(e.message, 6000, Dialogs.MSG_ERR));
VIEWER.addHandler('plugin-loaded', e => Dialogs.show($.t('messages.pluginLoadedNamed', {plugin: PLUGINS[e.id].name}), 2500, Dialogs.MSG_INFO));
let notified = false;
VIEWER.addHandler('add-item-failed', e => {
if (notified) return;
if (e.message && e.message.statusCode) {
let title;
switch (e.message.statusCode) {
case 401:
$("#tissue-title-content").html($.t('main.global.tissue'));
Dialogs.show($.t('error.slide.401'),
20000, Dialogs.MSG_ERR);
XOpatUser.instance().logout();
break;
case 403:
$("#tissue-title-content").html($.t('main.global.tissue'));
Dialogs.show($.t('error.slide.403'),
20000, Dialogs.MSG_ERR);
break;
case 404:
Dialogs.show($.t('error.slide.404'),
20000, Dialogs.MSG_ERR);
break;
default:
break;
}
notified = true;
} else {
console.error('Item failed to load and the event does not contain reliable information to notify user. Notification was bypassed.');
}
});
function updateBackgroundChanged(index) {
const tiledImage = VIEWER.world.getItemAt(index);
const imageData = tiledImage?.getBackgroundConfig() || {};
const title = $("#tissue-title-header").removeClass('error-container');
if (Number.isInteger(Number.parseInt(imageData?.dataReference))) {
const name = imageData.name || UTILITIES.fileNameFromPath(
APPLICATION_CONTEXT.config.data[imageData.dataReference]
);
title.find('#tissue-title-content').html(name);
title.attr('title', name);
USER_INTERFACE.toggleDemoPage(false);
} else if (tiledImage?.source instanceof OpenSeadragon.EmptyTileSource) {
const name = imageData.name || UTILITIES.fileNameFromPath(
APPLICATION_CONTEXT.config.data[APPLICATION_CONTEXT.getOption('activeBackgroundIndex')]
|| 'unknown'
);
title.addClass('error-container').find('#tissue-title-content').html($.t('main.navigator.faultyTissue', {slide: name}));
USER_INTERFACE.toggleDemoPage(true);
} else {
USER_INTERFACE.toggleDemoPage(false);
}
const hasMicrons = !!imageData.microns, hasDimMicrons = !!(imageData.micronsX && imageData.micronsY);
if (!hasMicrons || !hasDimMicrons) {
const sourceMeta = typeof tiledImage?.source?.getImageMetaAt === "function" && tiledImage.source.getImageMetaAt();
if (sourceMeta) {
if (!hasMicrons) imageData.microns = sourceMeta.microns;
if (!hasDimMicrons) {
imageData.micronsX = sourceMeta.micronsX;
imageData.micronsY = sourceMeta.micronsY;
}
}
}
if (!VIEWER.scalebar) {
UTILITIES.setImageMeasurements(imageData?.microns, imageData?.micronsX, imageData?.micronsY);
}
VIEWER.scalebar.linkReferenceTileSourceIndex(index);
}
window.UTILITIES.setImageMeasurements = function (microns, micronsX, micronsY) {
let ppm = microns, ppmX = micronsX, ppmY = micronsY,
lengthFormatter = OpenSeadragon.ScalebarSizeAndTextRenderer.METRIC_LENGTH;
if (ppmX && ppmY) {
ppm = undefined;
ppmX = 1e6 / ppmX;
ppmY = 1e6 / ppmY;
} else if (!ppm) {
lengthFormatter = OpenSeadragon.ScalebarSizeAndTextRenderer.METRIC_GENERIC.bind(null, "px");
ppm = 1;
} else ppm = 1e6 / ppm;
const magMicrons = microns || (micronsX + micronsY) / 2;
const values = [2.4, 2, 1.2, 4, 0.6, 10, 0.3, 20, 0.15, 40];
let index = 0, best = Infinity, mag;
if (magMicrons) {
while (index < values.length) {
const dev = Math.abs(magMicrons - values[index]);
if (dev < best && dev < values[index]) {
best = dev;
mag = values[index+1]
}
index += 2;
}
}
VIEWER.makeScalebar({
pixelsPerMeter: ppm,
pixelsPerMeterX: ppmX,
pixelsPerMeterY: ppmY,
sizeAndTextRenderer: lengthFormatter,
stayInsideImage: false,
location: OpenSeadragon.ScalebarLocation.BOTTOM_LEFT,
xOffset: 5,
yOffset: 10,
backgroundColor: "rgba(255, 255, 255, 0.5)",
fontSize: "small",
barThickness: 2,
destroy: !APPLICATION_CONTEXT.getOption("scaleBar", true, false),
magnification: mag
});
};
let preventedSwap = false;
window.UTILITIES.swapBackgroundImages = function(bgIndex) {
if (APPLICATION_CONTEXT.getOption("stackedBackground")) {
console.error("UTILITIES::swapBackgroundImages not supported in stackedBackground mode!");
return;
}
if (preventedSwap) {
Dialogs.show($.t('messages.stillLoadingSwap'), 5000, Dialogs.MSG_WARN);
return;
}
let activeBackground = APPLICATION_CONTEXT.getOption('activeBackgroundIndex', 0, false);
if (typeof activeBackground === "string") activeBackground = Number.parseInt(activeBackground);
if (activeBackground === bgIndex) return;
const image = APPLICATION_CONTEXT.config.background[bgIndex],
imagePath = APPLICATION_CONTEXT.config.data[image.dataReference],
sourceUrlMaker = new Function("path,data", "return " +
(image.protocol || APPLICATION_CONTEXT.env.client.image_group_protocol));
let prevImage = VIEWER.world.getItemAt(0);
let url = sourceUrlMaker(APPLICATION_CONTEXT.env.client.image_group_server, imagePath);
preventedSwap = true;
VIEWER.addTiledImage({
tileSource: url,
index: 0,
opacity: 1,
replace: true,
success: function(e) {
preventedSwap = false;
APPLICATION_CONTEXT.setOption('activeBackgroundIndex', bgIndex);
e.item.getBackgroundConfig = () => APPLICATION_CONTEXT.config.background[bgIndex];
updateBackgroundChanged(0);
let previousBackgroundSetup = APPLICATION_CONTEXT.config.background[activeBackground];
VIEWER.raiseEvent('background-image-swap', {
backgroundImageUrl: url,
prevBackgroundSetup: previousBackgroundSetup,
backgroundSetup: image,
previousTiledImage: prevImage,
tiledImage: e.item,
});
let container = document.getElementById('tissue-preview-container');
container.children[activeBackground].classList.remove('selected');
container.children[bgIndex].classList.add('selected');
},
error: function(e) {
preventedSwap = false;
console.error("Swap Images Failure", e);
let container = document.getElementById('tissue-preview-container');
Dialogs.show($.t('messages.swapImagesFail'), 5000, Dialogs.MSG_ERR);
container.children[bgIndex].classList.remove('selected');
container.children[activeBackground].classList.add('selected');
}
});
};
let reopenCounter = -1;
function handleSyntheticOpenEvent() {
reopenCounter += 1;
let confData = APPLICATION_CONTEXT.config.data,
confBackground = APPLICATION_CONTEXT.config.background;
if (APPLICATION_CONTEXT.getOption("stackedBackground")) {
let i = 0, selectedImageLayer = 0;
let imageOpts = [];
let largestWidth = -1,
imageNode = $("#image-layer-options");
if (imageNode) {
for (let idx = confBackground.length - 1; idx >= 0; idx-- ) {
const image = confBackground[idx],
worldItem = VIEWER.world.getItemAt(i),
configGetter = worldItem?.getBackgroundConfig,
referencedImage = configGetter && configGetter();
if (image == referencedImage) {
if (image.hasOwnProperty("lossless") && image.lossless) {
worldItem.source.fileFormat = "png";
}
let width = worldItem.getContentSize().x;
if (width > largestWidth) {
largestWidth = width;
selectedImageLayer = i;
}
imageOpts.push(`
<div class="h5 pl-3 py-1 position-relative d-flex"><input type="checkbox" checked class="form-control"
onchange="VIEWER.world.getItemAt(${i}).setOpacity(this.checked ? 1 : 0);" style="margin: 5px;">
<span class="pr-1" style="color: var(--color-text-tertiary)">${$.t('common.Image')}</span>
${image.name ? image.name : UTILITIES.fileNameFromPath(confData[image.dataReference])} <input type="range" class="flex-1 px-2" min="0"
max="1" value="${worldItem.getOpacity()}" step="0.1" onchange="VIEWER.world.getItemAt(${i}).setOpacity(Number.parseFloat(this.value));" style="width: 100%;"></div>`);
i++;
} else {
imageOpts.push(`
<div class="h5 pl-3 py-1 position-relative d-flex"><input type="checkbox" disabled class="form-control" style="margin: 5px;">
<span class="pr-1" style="color: var(--color-text-danger)">${$.t('common.Faulty')}</span>
${image.name ? image.name : UTILITIES.fileNameFromPath(confData[image.dataReference])} <input type="range" class="flex-1 px-2" min="0"
max="1" value="0" step="0.1" style="width: 100%;" disabled></div>`);
}
}
}
imageOpts.push(`<div class="inner-panel-content noselect" id="inner-panel-content-1">
<div>
<span id="images-pin" class="material-icons btn-pointer inline-arrow" onclick="USER_INTERFACE.MainMenu.clickHeader($(this), $(this).parents().eq(1).children().eq(1));" style="padding: 0;"> navigate_next </span>
<h3 class="d-inline-block btn-pointer" onclick="USER_INTERFACE.MainMenu.clickHeader($(this.previousElementSibling), $(this).parents().eq(1).children().eq(1));">Images</h3>
</div>
<div id="image-layer-options" class="inner-panel-hidden">`);
imageOpts = imageOpts.reverse();
imageOpts.push("</div></div>");
$("#panel-images").html(imageOpts.join("")).css('display', 'block');
$("#global-tissue-visibility").css("display", "none");
if (largestWidth === -1) {
VIEWER.addTiledImage({
tileSource : new OpenSeadragon.EmptyTileSource({height: 20000, width: 20000, tileSize: 512}),
index: 0,
opacity: $("#global-opacity input").val(),
replace: false,
success: (event) => {
event.item.getBackgroundConfig = () => {
return undefined;
}
handleSyntheticEventFinishWithValidData(0, 1);
}
});
} else {
handleSyntheticEventFinishWithValidData(selectedImageLayer, i);
}
return;
}
const activeIndex = APPLICATION_CONTEXT.getOption('activeBackgroundIndex', 0, false);
if (confBackground.length > 1) {
let html = "";
for (let idx = 0; idx < confBackground.length; idx++ ) {
const image = confBackground[idx],
imagePath = confData[image.dataReference];
if (APPLICATION_CONTEXT.secure) delete image.protocolPreview;
const eventArgs = {
server: APPLICATION_CONTEXT.env.client.image_group_server,
usesCustomProtocol: !!image.protocolPreview,
image: imagePath,
imagePreview: null,
};
VIEWER.tools.raiseAwaitEvent(VIEWER,'get-preview-url', eventArgs).then(() => {
let blobUrl;
if (!eventArgs.imagePreview) {
const previewUrlmaker = new Function("path,data", "return " +
(image.protocolPreview || APPLICATION_CONTEXT.env.client.image_group_preview));
eventArgs.imagePreview = previewUrlmaker(eventArgs.server, imagePath);
} else if (typeof eventArgs.imagePreview !== "string") {
blobUrl = eventArgs.imagePreview = URL.createObjectURL(eventArgs.imagePreview);
}
const img = new Image();
img.onload = () => {
let child = img;
if (img.width < img.height) {
child = document.createElement("canvas"),
context = child.getContext("2d");
child.width = img.height;
child.height = img.width;
context.setTransform(0,-1, 1,0, 0, child.width/2);
context.drawImage(img, 0, 0);
}
child.style.width = '180px';
$(`#tissue-preview-item-${idx}`).append(child);
if (blobUrl) URL.revokeObjectURL(blobUrl);
};
img.onerror = img.onabort = () => {
if (blobUrl) URL.revokeObjectURL(blobUrl);
};
img.src = eventArgs.imagePreview;
});
html += `
<div id="tissue-preview-item-${idx}" onclick="UTILITIES.swapBackgroundImages(${idx});"
class="${activeIndex == idx ? 'selected' : ''} pointer position-relative mx-2 my-2 color-bg-canvas overflow-hidden"
style="width: 180px; height: 90px; border-bottom: 1px solid var(--color-bg-backdrop); border-radius: 21px;">
<span class="tissue-label">${image.name ? image.name : UTILITIES.fileNameFromPath(confData[image.dataReference])}</span>
</div>`;
}
$("#panel-images").html(`<div id="tissue-preview-container">${html}</div>`);
} else {
$("#panel-images").html("").css('display', 'none');
}
if (confBackground.length > 0) {
$("#global-tissue-visibility").css("display", "initial");
const image = confBackground[activeIndex],
worldItem = VIEWER.world.getItemAt(0),
configGetter = worldItem?.getBackgroundConfig,
referencedImage = configGetter && configGetter();
if (image != referencedImage) {
const dimensions = worldItem?.getContentSize();
VIEWER.addTiledImage({
tileSource : new OpenSeadragon.EmptyTileSource({
height: dimensions?.y || 20000,
width: dimensions?.x || 20000,
tileSize: 512
}),
index: 0,
opacity: $("#global-opacity input").val(),
replace: false,
success: (event) => {
event.item.getBackgroundConfig = () => {
return undefined;
}
handleSyntheticEventFinishWithValidData(0, 1);
}
});
return;
} else {
if (image.hasOwnProperty("lossless") && image.lossless && worldItem) {
worldItem.source.fileFormat = "png";
}
}
handleSyntheticEventFinishWithValidData(0, 1);
} else {
VIEWER.addTiledImage({
tileSource : new OpenSeadragon.EmptyTileSource({height: 20000, width: 20000, tileSize: 512}),
index: 0,
opacity: $("#global-opacity input").val(),
replace: false,
success: (event) => {
event.item.getBackgroundConfig = () => {
return undefined;
}
handleSyntheticEventFinishWithValidData(0, 1);
}
});
}
}
function handleSyntheticEventFinishWithValidData(referenceImage, layerPosition) {
updateBackgroundChanged(referenceImage);
const eventOpts = {};
const seaGL = VIEWER.bridge;
if (APPLICATION_CONTEXT.config.visualizations.length > 0 && seaGL) {
const layerWorldItem = VIEWER.world.getItemAt(layerPosition);
const activeVis = seaGL.visualization();
if (layerWorldItem) {
UTILITIES.prepareTiledImage(layerPosition,
layerWorldItem, activeVis);
$("#panel-shaders").css('display', 'block');
seaGL.initAfterOpen();
} else {
Dialogs.show($.t('messages.visualizationDisabled', {name: activeVis.name}), 20000, Dialogs.MSG_ERR);
$("#panel-shaders").css('display', 'none');
APPLICATION_CONTEXT.disableVisualization();
eventOpts.error = $.t('messages.overlaysDisabled');
}
}
handleSyntheticEventFinish(eventOpts);
}
let loadTooLongTimeout = null;
function handleSyntheticEventFinish(opts={}) {
if (reopenCounter === 0) {
runLoader();
let focus = APPLICATION_CONTEXT.getOption("viewport");
if (focus && focus.hasOwnProperty("point") && focus.hasOwnProperty("zoomLevel")) {
window.VIEWER.viewport.panTo({x: Number.parseFloat(focus.point.x), y: Number.parseFloat(focus.point.y)}, true);
window.VIEWER.viewport.zoomTo(Number.parseFloat(focus.zoomLevel), null, true);
}
if (window.innerHeight < 630 || window.innerWidth < 900) {
if (window.innerWidth >= 900) {
$('#navigator-pin').click();
}
USER_INTERFACE.MainMenu.close();
}
window.onerror = null;
try {
if (window.opener && window.opener.VIEWER) {
VIEWER.tools.link( window.opener.VIEWER);
}
} catch (e) {
}
const firstTimeVisit = APPLICATION_CONTEXT.AppCookies.get("_shadersPin",
APPLICATION_CONTEXT.getOption("bypassCookies") ? false : null) === null;
if (!USER_INTERFACE.Errors.active && firstTimeVisit) {
setTimeout(() => {
USER_INTERFACE.Tutorials.show($.t('messages.pluginsWelcome'),
$.t('messages.pluginsWelcomeDescription', {tutorial: $.t('tutorials.basic.title')})
);
}, 2000);
}
}
if (USER_INTERFACE.Errors.active) {
$("#viewer-container").addClass("disabled");
}
opts.source = VIEWER.world.getItemAt(0)?.source;
opts.reopenCounter = reopenCounter;
VIEWER.raiseEvent('open', opts);
USER_INTERFACE.Loading.show(false);
if (loadTooLongTimeout) clearTimeout(loadTooLongTimeout);
APPLICATION_CONTEXT.setOption("bypassCacheLoadTime", false);
}
APPLICATION_CONTEXT.beginApplicationLifecycle = async function (data,
background,
visualizations=undefined) {
try {
initXopatLayers();
function loadPluginAwaits(pid, hasParams) {
return new Promise((resolve) => {
UTILITIES.loadPlugin(pid, resolve);
if (!hasParams) {
CONFIG.plugins[pid] = {};
}
});
}
const pluginKeys = APPLICATION_CONTEXT.AppCookies.get('_plugins', '').split(',') || [];
for (let pid in PLUGINS) {
const hasParams = CONFIG.plugins[pid];
const plugin = PLUGINS[pid];
if (
(plugin.loaded && !plugin.instance) ||
(!plugin.loaded && (hasParams || pluginKeys.includes(pid)))
) {
if (plugin.error) {
console.warn("Dynamic plugin loading skipped: ", pid, plugin.error);
} else {
await loadPluginAwaits(pid, hasParams);
}
}
}
USER_INTERFACE.AdvancedMenu._build();
USER_INTERFACE.MainMenu._sync();
await VIEWER.tools.raiseAwaitEvent(VIEWER,'before-first-open', {
data, background, visualizations, fromLocalStorage: !!CONFIG.__fromLocalStorage
}).catch(e =>
{
console.error(e);
}
);
this.openViewerWith(data, background, visualizations || []);
} catch (e) {
USER_INTERFACE.Loading.show(false);
USER_INTERFACE.Errors.show($.t('error.unknown'), `${$.t('error.reachUs')} <br><code>${e}</code>`, true);
console.error(e);
}
};
let _allowRecursionReload = true;
APPLICATION_CONTEXT.openViewerWith = function (
data,
background,
visualizations=[],
) {
USER_INTERFACE.Loading.show(true);
VIEWER.close();
const isSecureMode = APPLICATION_CONTEXT.secure;
let renderingWithWebGL = visualizations?.length > 0;
if (renderingWithWebGL) {
if (_allowRecursionReload && !window.WebGLModule) {
_allowRecursionReload = false;
UTILITIES.loadModules(() => APPLICATION_CONTEXT.openViewerWith(data, background, visualizations), "webgl");
return;
}
if (!window.WebGLModule) {
console.error("Recursion prevented: webgl module failed to load!");
Dialogs.show($.t('messages.overlaysLoadFail'), 8000, Dialogs.MSG_ERR);
renderingWithWebGL = false;
}
}
loadTooLongTimeout = setTimeout(() => Dialogs.show($.t('error.slide.pending'), 15000, Dialogs.MSG_WARN), 8000);
const config = APPLICATION_CONTEXT._dangerouslyAccessConfig();
config.data = data;
config.background = background;
config.visualizations = visualizations;
if (reopenCounter > 0) {
APPLICATION_CONTEXT.disableVisualization();
} else {
VIEWER.raiseEvent('before-canvas-reload');
}
const toOpen = [];
const opacity = Number.parseFloat($("global-opacity").val()) || 1;
let openedSources = 0;
const handleFinishOpenImageEvent = (item, url, index) => {
openedSources--;
if (item) {
VIEWER.raiseEvent('tiled-image-created', {item, url, index});
}
if (openedSources <= 0) handleSyntheticOpenEvent();
};
let imageOpenerCreator = (success, userArg=undefined) => {
return (toOpenLastBgIndex, source, toOpenIndex) => {
openedSources++;
window.VIEWER.addTiledImage({
tileSource: source,
opacity: opacity,
success: (event) => {
success({userArg, toOpenLastBgIndex, toOpenIndex, event});
handleFinishOpenImageEvent(event.item, source, toOpenIndex);
},
error: () => {
handleFinishOpenImageEvent();
}
});
}
};
let imageOpener;
if (APPLICATION_CONTEXT.getOption("stackedBackground")) {
for (let i = background.length-1; i >= 0; i--) {
const bg = background[i];
if (isSecureMode) delete bg.protocol;
const urlmaker = new Function("path,data", "return " + (bg.protocol || APPLICATION_CONTEXT.env.client.image_group_protocol));
toOpen.push(urlmaker(APPLICATION_CONTEXT.env.client.image_group_server, data[bg.dataReference]));
}
imageOpener = imageOpenerCreator(e => {
const index = e.toOpenLastBgIndex - e.toOpenIndex;
e.event.item.getBackgroundConfig = () => {
return APPLICATION_CONTEXT.config.background[index];
};
});
} else if (background.length > 0) {
const selectedIndex = APPLICATION_CONTEXT.getOption('activeBackgroundIndex', 0, false);
let selectedImage = background[selectedIndex];
if (isSecureMode) delete selectedImage.protocol;
const urlmaker = new Function("path,data", "return " + (selectedImage.protocol || APPLICATION_CONTEXT.env.client.image_group_protocol));
toOpen.push(urlmaker(APPLICATION_CONTEXT.env.client.image_group_server, data[selectedImage.dataReference]));
imageOpener = imageOpenerCreator(e => {
const index = e.userArg;
e.event.item.getBackgroundConfig = () => {
return APPLICATION_CONTEXT.config.background[index];
};
}, selectedIndex);
}
const openAll = (numOfVisLayersAtTheEnd) => {
if (toOpen.length < 1) {
handleFinishOpenImageEvent();
return;
}
let i = 0;
let lastValidBgIndex = toOpen.length - numOfVisLayersAtTheEnd - 1;
for (; i <= lastValidBgIndex; i++) imageOpener(lastValidBgIndex, toOpen[i], i);
const visOpener = imageOpenerCreator(()=>{});
for (; i < toOpen.length; i++) visOpener(toOpen.length - 1, toOpen[i], i);
}
if (renderingWithWebGL) {
try {
UTILITIES.testRendering();
} catch (e) {
console.error(e);
USER_INTERFACE.Errors.show($.t('error.renderTitle'), `${$.t('error.renderDesc')} <br><code>${e}</code>`, true);
}
APPLICATION_CONTEXT.prepareRendering();
renderingWithWebGL = APPLICATION_CONTEXT.layersAvailable;
}
if (renderingWithWebGL) {
APPLICATION_CONTEXT.prepareRendering();
let activeVisIndex = Number.parseInt(APPLICATION_CONTEXT.getOption("activeVisualizationIndex"));
if (!APPLICATION_CONTEXT.getOption("stackedBackground")) {
const activeBackgroundSetup = config.background[APPLICATION_CONTEXT.getOption('activeBackgroundIndex', 0, false)],
defaultIndex = Number.parseInt(activeBackgroundSetup?.goalIndex);
if (defaultIndex >= 0 && defaultIndex < config.visualizations.length) {
activeVisIndex = defaultIndex;
APPLICATION_CONTEXT.setOption("activeVisualizationIndex", activeVisIndex);
}
}
VIEWER.bridge.loadShaders(
activeVisIndex,
function() {
VIEWER.bridge.createUrlMaker(VIEWER.bridge.visualization(), isSecureMode);
let data = VIEWER.bridge.dataImageSources();
toOpen.push(VIEWER.bridge.urlMaker(APPLICATION_CONTEXT.env.client.data_group_server, data));
openAll(1);
}
);
} else {
openAll(0);
}
}
APPLICATION_CONTEXT.AppCache = new XOpatStorage.Cache({id: ""});
APPLICATION_CONTEXT.AppCookies = new XOpatStorage.Cookies({id: ""});
initXopatScripts();
function checkLocalState() {
const data = sessionStorage.getItem('__xopat_session__');
sessionStorage.setItem('__xopat_session__', undefined);
if (data) {
try {
return JSON.parse(data);
} catch (e) {
console.debug("Failed to restore session!", e);
}
}
return null;
}
window.UTILITIES.storePageState = function(includedPluginsList=undefined) {
try {
if (includedPluginsList) {
const pluginRefs = CONFIG.plugins;
CONFIG.plugins = {};
for (let plugin in includedPluginsList) {
const oldPluginRef = pluginRefs.plugins[plugin];
if (!pluginRefs.plugins[plugin]) {
CONFIG.plugins[plugin] = {};
} else {
CONFIG.plugins[plugin] = oldPluginRef;
}
}
}
POST_DATA.visualization = CONFIG;
const plugins = {...PLUGINS};
const modules = {...MODULES};
for (let id in plugins) {
delete plugins[id].instance;
}
for (let id in modules) {
delete modules[id].loaded;
}
sessionStorage.setItem('__xopat_session__', safeStringify({
PLUGINS: plugins, MODULES: modules,
ENV, POST_DATA, PLUGINS_FOLDER, MODULES_FOLDER, VERSION, I18NCONFIG
}));
return true;
} catch (e) {
console.error("Failed to store application state!", e);
}
return false;
}
function safeStringify(obj) {
const seenData = new WeakMap();
return JSON.stringify(obj, function(key, value) {
if (key.startsWith("_") || ["eventSource"].includes(key)) {
return undefined;
}
if (value && typeof value === 'object') {
if (seenData.has(value)) {
return undefined;
}
seenData.set(value, true);
}
return value;
});
}
if (CONFIG.error) {
USER_INTERFACE.Errors.show(CONFIG.error, `${CONFIG.description} <br><code>${CONFIG.details}</code>`,
true);
}
}