Files
DocumentServer-v-9.2.0/sdkjs/common/GlobalLoaders.js
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

680 lines
24 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
"use strict";
(function(window, document){
// Import
var g_fontApplication = AscFonts.g_fontApplication;
var ImageLoadStatus = AscFonts.ImageLoadStatus;
var CImage = AscFonts.CImage;
function CGlobalFontLoader()
{
// сначала хотел писать "вытеснение" из этого мапа.
// но тогда нужно хранить base64 строки. Это не круто. По памяти - даже
// выигрыш будет. Не особо то шрифты жмутся lzw или deflate
// поэтому лучше из памяти будем удалять base64 строки
this.fonts_streams = [];
// теперь вся информация о всех возможных шрифтах. Они во всех редакторах должны быть одни и те же
this.fontFilesPath = "../../../../fonts/";
this.fontFiles = AscFonts.g_font_files;
this.fontInfos = AscFonts.g_font_infos;
this.map_font_index = AscFonts.g_map_font_index;
// динамическая подгрузка шрифтов
this.ThemeLoader = null;
this.Api = null;
this.fonts_loading = [];
this.bIsLoadDocumentFirst = false;
// информация для загрузки по одному шрифту
this.currentInfoLoaded = null;
this.loadFontCallBack = null;
this.loadFontCallBackArgs = null;
// при переоткрытиях файла - заменить на LoadDocumentFonts2
this.IsLoadDocumentFonts2 = false;
this.check_loaded_timer_id = -1;
this.endLoadingCallback = null;
// Счетчик загрузки шрифтов через метод LoadFonts
this.loadFontsCounter = 0;
this.perfStart = 0;
this.put_Api = function(api)
{
this.Api = api;
};
// добавляем шрифт в список для загрузки
this.AddLoadFonts = function(name, need_styles)
{
var fontinfo = g_fontApplication.GetFontInfo(name);
this.fonts_loading[this.fonts_loading.length] = fontinfo;
this.fonts_loading[this.fonts_loading.length - 1].NeedStyles = (need_styles === undefined) ? 0x0F : need_styles;
return fontinfo;
};
this.AddLoadFontsNotPick = function(info, need_styles)
{
this.fonts_loading[this.fonts_loading.length] = info;
this.fonts_loading[this.fonts_loading.length - 1].NeedStyles = (need_styles === undefined) ? 0x0F : need_styles;
};
// проверить все fontinfo из fonts_loading на нужность загрузки, и вернуть есть ли хоть один заново запущенный
this.CheckFontsNeedLoadingLoad = function()
{
let fonts = this.fonts_loading;
let isNeed = false;
for (let i = 0, len = fonts.length; i < len; i++)
{
if (true === fonts[i].CheckFontLoadStyles(this))
isNeed = true;
}
return isNeed;
};
// нужно ли грузить хоть один из списка (без запуска загрузки)
this.CheckFontsNeedLoading = function(fonts)
{
for (let i in fonts)
{
let info = g_fontApplication.GetFontInfo(fonts[i].name);
if (true === info.CheckFontLoadStylesNoLoad(this))
return true;
}
return false;
};
this.isWorking = function()
{
return (this.check_loaded_timer_id !== -1) ? true : false;
};
this.LoadDocumentFonts = function(fonts)
{
if (this.IsLoadDocumentFonts2)
return this.LoadDocumentFonts2(fonts);
let gui_fonts = [];
let gui_count = 0;
for (let i = 0; i < this.fontInfos.length; i++)
{
let info = this.fontInfos[i];
if (info.Name !== "ASCW3")
gui_fonts[gui_count++] = new AscFonts.CFont(info.Name, "", info.Thumbnail);
}
// сначала заполняем массив this.fonts_loading объекстами fontinfo
for (let i in fonts)
{
this.AddLoadFonts(fonts[i].name, fonts[i].NeedStyles);
}
this.Api.sync_InitEditorFonts(gui_fonts);
// но только если редактор!!!
if (this.Api.IsNeedDefaultFonts())
{
// теперь добавим шрифты, без которых редактор как без рук (спецсимволы + дефолтовые стили документа)
this.AddLoadFonts("Arial", 0x0F);
this.AddLoadFonts("Symbol", 0x0F);
this.AddLoadFonts("Wingdings", 0x0F);
this.AddLoadFonts("Courier New", 0x0F);
this.AddLoadFonts("Times New Roman", 0x0F);
}
this.Api.asyncFontsDocumentStartLoaded();
this.bIsLoadDocumentFirst = true;
this.CheckFontsNeedLoadingLoad();
this._LoadFonts();
};
this.LoadDocumentFonts2 = function(fonts, blockType, callback)
{
if (this.isWorking())
{
// такого быть не должно
return;
}
this.endLoadingCallback = (undefined !== callback) ? callback : null;
this.BlockOperationType = blockType;
// сначала заполняем массив this.fonts_loading объекстами fontinfo
for (var i in fonts)
this.AddLoadFonts(fonts[i].name, 0x0F);
if (null == this.ThemeLoader)
this.Api.asyncFontsDocumentStartLoaded(this.BlockOperationType);
else
this.ThemeLoader.asyncFontsStartLoaded();
this.CheckFontsNeedLoadingLoad();
this._LoadFonts();
};
this._LoadFonts = function()
{
if (this.bIsLoadDocumentFirst === true && 0 === this.perfStart && this.fonts_loading.length > 0)
this.perfStart = performance.now();
if (0 === this.fonts_loading.length)
{
if (this.perfStart > 0)
{
let perfEnd = performance.now();
AscCommon.sendClientLog("debug", AscCommon.getClientInfoString("onLoadFonts", perfEnd - this.perfStart), this.Api);
this.perfStart = 0;
}
if (null != this.endLoadingCallback)
{
this.endLoadingCallback.call(this.Api);
this.endLoadingCallback = null;
}
else if (null == this.ThemeLoader)
this.Api.asyncFontsDocumentEndLoaded(this.BlockOperationType);
else
this.ThemeLoader.asyncFontsEndLoaded();
this.BlockOperationType = undefined;
this.bIsLoadDocumentFirst = false;
return;
}
if (this.fonts_loading[0].CheckFontLoadStyles(this))
{
let _t = this;
this.check_loaded_timer_id = setTimeout(function(){
_t.check_loaded_list();
}, 50);
}
else
{
if (this.bIsLoadDocumentFirst === true)
{
this.Api.OpenDocumentProgress.CurrentFont++;
this.Api.SendOpenProgress();
}
this.fonts_loading.shift();
this._LoadFonts();
}
};
this.check_loaded_list = function()
{
this.check_loaded_timer_id = -1;
if (0 === this.fonts_loading.length)
{
// значит асинхронно удалилось
this._LoadFonts();
return;
}
let current = this.fonts_loading[0];
let isNeed = current.CheckFontLoadStyles(this);
if (true === isNeed)
{
let _t = this;
this.check_loaded_timer_id = setTimeout(function(){
_t.check_loaded_list();
}, 50);
}
else
{
if (this.bIsLoadDocumentFirst === true)
{
this.Api.OpenDocumentProgress.CurrentFont++;
this.Api.SendOpenProgress();
}
this.fonts_loading.shift();
this._LoadFonts();
}
};
// одиночная загрузка шрифта
this.LoadFont = function(fontinfo, loadFontCallBack, loadFontCallBackArgs)
{
this.currentInfoLoaded = fontinfo;
this.currentInfoLoaded.NeedStyles = 15; // все стили
let isNeed = this.currentInfoLoaded.CheckFontLoadStyles(this);
if ( undefined === loadFontCallBack )
{
this.loadFontCallBack = this.Api.asyncFontEndLoaded;
this.loadFontCallBackArgs = this.currentInfoLoaded;
}
else
{
this.loadFontCallBack = loadFontCallBack;
this.loadFontCallBackArgs = loadFontCallBackArgs;
}
if (isNeed)
{
this.Api.asyncFontStartLoaded();
let _t = this;
setTimeout(function() {
_t.check_loaded();
}, 20);
return true;
}
else
{
this.currentInfoLoaded = null;
return false;
}
};
this.check_loaded = function()
{
if (!this.currentInfoLoaded)
return;
let isNeed = this.currentInfoLoaded.CheckFontLoadStyles(this);
if (isNeed)
{
let _t = this;
setTimeout(function() {
_t.check_loaded();
}, 50);
}
else
{
this.loadFontCallBack.call( this.Api, this.loadFontCallBackArgs );
this.currentInfoLoaded = null;
}
};
// используется только в тестовом примере (предзагрузка в кэш браузера)
this.LoadFontsFromServer = function(fonts)
{
let count = fonts.length;
for (let i = 0; i < count; i++)
{
let info = g_fontApplication.GetFontInfo(fonts[i]);
info && info.LoadFontsFromServer(this);
}
};
this.isFontLoadInProgress = function()
{
return (this.isWorking() || this.loadFontsCounter > 0);
};
this.LoadFonts = function(fonts, callback)
{
++this.loadFontsCounter;
let fontMap = {}
if (fonts && Array.isArray(fonts))
{
for (let i = 0; i < fonts.length; ++i)
{
let name = fonts[i];
fontMap[name] = AscFonts.g_fontApplication.GetFontInfo(name);
fontMap[name].NeedStyles = 15;
}
}
else
{
for (let name in fonts)
{
fontMap[name] = AscFonts.g_fontApplication.GetFontInfo(name);
fontMap[name].NeedStyles = 15;
}
}
let globalLoader = this;
let checkLoaded = function()
{
let needLoad = 0;
for (let name in fontMap)
{
if (!fontMap[name].CheckFontLoadStyles(globalLoader))
delete fontMap[name];
else
++needLoad;
}
if (needLoad)
return setTimeout(checkLoaded, 50);
if (callback)
callback();
--globalLoader.loadFontsCounter;
};
checkLoaded();
}
}
function CGlobalImageLoader()
{
this.map_image_index = {};
// loading
this.Api = null;
this.ThemeLoader = null;
this.bIsLoadDocumentFirst = false;
this.bIsAsyncLoadDocumentImages = false;
this.isBlockchainSupport = false;
var oThis = this;
if (window["AscDesktopEditor"] &&
window["AscDesktopEditor"]["IsLocalFile"] &&
window["AscDesktopEditor"]["isBlockchainSupport"])
{
this.isBlockchainSupport = (window["AscDesktopEditor"]["isBlockchainSupport"]() && !window["AscDesktopEditor"]["IsLocalFile"]());
if (this.isBlockchainSupport)
{
Image.prototype.preload_crypto = function(_url)
{
window["crypto_images_map"] = window["crypto_images_map"] || {};
if (!window["crypto_images_map"][_url])
window["crypto_images_map"][_url] = [];
window["crypto_images_map"][_url].push(this);
window["AscDesktopEditor"]["PreloadCryptoImage"](_url, AscCommon.g_oDocumentUrls.getLocal(_url));
oThis.Api.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.LoadImage);
};
Image.prototype["onload_crypto"] = function(_src, _crypto_data)
{
if (_crypto_data && AscCommon.EncryptionWorker && AscCommon.EncryptionWorker.isCryptoImages())
{
AscCommon.EncryptionWorker.decryptImage(_src, this, _crypto_data);
return;
}
this.crossOrigin = "";
this.src = _src;
oThis.Api.sync_EndAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.LoadImage);
};
}
}
this.put_Api = function(api)
{
this.Api = api;
if (this.Api.IsAsyncOpenDocumentImages !== undefined)
{
this.bIsAsyncLoadDocumentImages = this.Api.IsAsyncOpenDocumentImages();
if (this.bIsAsyncLoadDocumentImages)
{
if (undefined === this.Api.asyncImageEndLoadedBackground)
this.bIsAsyncLoadDocumentImages = false;
}
}
};
this.loadImageByUrl = function(image, url, isDisableCrypto)
{
if (this.isBlockchainSupport && (true !== isDisableCrypto))
image.preload_crypto(url);
else
image.src = url;
};
this.LoadDocumentImages = function (images, isCheckExists, syncImages) {
if (isCheckExists) {
for (let i = images.length - 1; i >= 0; i--) {
let id = AscCommon.getFullImageSrc2(images[i]);
if (this.map_image_index[id] && (this.map_image_index[id].Status === ImageLoadStatus.Complete)) {
images.splice(i, 1);
}
}
if (0 === images.length)
return;
}
// сначала заполним массив
const oRequiredSyncImages = {};
const arrImagesLoading = [];
for (let id in images) {
const sFullImageSrc = AscCommon.getFullImageSrc2(images[id]);
arrImagesLoading.push(sFullImageSrc);
if (syncImages && syncImages[images[id]]) {
oRequiredSyncImages[sFullImageSrc] = true;
}
}
if (syncImages) {
for (let id in syncImages) {
const sFullImageSrc = AscCommon.getFullImageSrc2(id);
if (!oRequiredSyncImages[sFullImageSrc]) {
arrImagesLoading.push(sFullImageSrc);
oRequiredSyncImages[sFullImageSrc] = true;
}
}
}
if (this.ThemeLoader == null)
this.Api.asyncImagesDocumentStartLoaded(arrImagesLoading);
else
this.ThemeLoader.asyncImagesStartLoaded(arrImagesLoading);
if (!this.bIsAsyncLoadDocumentImages) {
this._LoadImages(arrImagesLoading);
} else {
this._LoadImagesAsync(arrImagesLoading, oRequiredSyncImages);
}
};
this._LoadImages = function (arrImages) {
let fOnEachImageLoadCallback;
if (oThis.bIsLoadDocumentFirst === true) {
fOnEachImageLoadCallback = function () {
oThis.Api.OpenDocumentProgress.CurrentImage++;
oThis.Api.SendOpenProgress();
};
}
this.LoadImagesWithCallback(arrImages, function () {
if (oThis.ThemeLoader == null)
oThis.Api.asyncImagesDocumentEndLoaded();
else
oThis.ThemeLoader.asyncImagesEndLoaded();
}, [], false, fOnEachImageLoadCallback);
};
this._LoadImagesAsync = function (arrImages, oRequiredSyncImages) {
const arrAsyncImages = [];
const arrSyncImages = [];
for (let i = 0; i < arrImages.length; i += 1) {
if (oRequiredSyncImages[arrImages[i]]) {
arrSyncImages.push(arrImages[i]);
} else {
arrAsyncImages.push(arrImages[i]);
}
}
let fOnEachImageLoadCallback;
if (oThis.bIsLoadDocumentFirst === true) {
fOnEachImageLoadCallback = function () {
oThis.Api.OpenDocumentProgress.CurrentImage++;
oThis.Api.SendOpenProgress();
};
}
this.LoadImagesWithCallback(arrSyncImages, function () {
for (let i = 0; i < arrAsyncImages.length; i += 1) {
oThis.LoadImageAsync(arrAsyncImages[i]);
}
if (oThis.ThemeLoader == null)
oThis.Api.asyncImagesDocumentEndLoaded();
else
oThis.ThemeLoader.asyncImagesEndLoaded();
}, [], false, fOnEachImageLoadCallback);
};
this.LoadImage = function(src, type)
{
var image = this.map_image_index[src];
if (undefined != image)
return image;
this.Api.asyncImageStartLoaded();
var oImage = new CImage(src);
// просто прокидываем параметр
oImage.Type = type;
oImage.Image = new Image();
oImage.Status = ImageLoadStatus.Loading;
oThis.map_image_index[oImage.src] = oImage;
oImage.Image.onload = function() {
oImage.Status = ImageLoadStatus.Complete;
oThis.Api.asyncImageEndLoaded(oImage);
};
oImage.Image.onerror = function() {
oImage.Image = null;
oImage.Status = ImageLoadStatus.Complete;
oThis.Api.asyncImageEndLoaded(oImage);
};
AscCommon.backoffOnErrorImg(oImage.Image, function(img) {
// Remove crossOrigin on retry to maximize display success
img.crossOrigin = null;
oThis.loadImageByUrl(img, img.src);
});
// Enable CORS for cross-origin images to allow canvas manipulation
oImage.Image.crossOrigin = 'anonymous';
this.loadImageByUrl(oImage.Image, oImage.src);
return null;
};
this.LoadImageAsync = function(imgSrc)
{
var oImage = new CImage(imgSrc);
oImage.Status = ImageLoadStatus.Loading;
oImage.Image = new Image();
oThis.map_image_index[oImage.src] = oImage;
oImage.Image.onload = function() {
oImage.Status = ImageLoadStatus.Complete;
oThis.Api.asyncImageEndLoadedBackground(oImage);
};
oImage.Image.onerror = function() {
oImage.Status = ImageLoadStatus.Complete;
oImage.Image = null;
oThis.Api.asyncImageEndLoadedBackground(oImage);
};
AscCommon.backoffOnErrorImg(oImage.Image, function(img) {
// Remove crossOrigin on retry to maximize display success
img.crossOrigin = null;
oThis.loadImageByUrl(img, img.src);
});
// Enable CORS for cross-origin images to allow canvas manipulation
oImage.Image.crossOrigin = 'anonymous';
oThis.loadImageByUrl(oImage.Image, oImage.src);
};
this.LoadImagesWithCallback = function(arr, loadImageCallBack, loadImageCallBackArgs, isDisableCrypto, onEachImageLoadCallback)
{
let arrAsync = [];
for (let i = 0; i < arr.length; i++)
{
if (this.map_image_index[arr[i]] && (this.map_image_index[arr[i]].Status === ImageLoadStatus.Complete))
continue;
arrAsync.push(arr[i]);
}
if (arrAsync.length == 0)
{
loadImageCallBack.call(this.Api, loadImageCallBackArgs);
return;
}
let asyncImageCounter = arrAsync.length;
const callback = loadImageCallBack.bind(this.Api, loadImageCallBackArgs);
for (let i = 0; i < arrAsync.length; i++)
{
var oImage = new CImage(arrAsync[i]);
oImage.Image = new Image();
oImage.Image.parentImage = oImage;
oImage.Status = ImageLoadStatus.Loading;
this.map_image_index[oImage.src] = oImage;
oImage.Image.onload = function ()
{
this.parentImage.Status = ImageLoadStatus.Complete;
asyncImageCounter--;
onEachImageLoadCallback && onEachImageLoadCallback();
if (asyncImageCounter === 0)
callback();
};
oImage.Image.onerror = function ()
{
this.parentImage.Image = null;
this.parentImage.Status = ImageLoadStatus.Complete;
asyncImageCounter--;
onEachImageLoadCallback && onEachImageLoadCallback();
if (asyncImageCounter === 0)
callback();
};
AscCommon.backoffOnErrorImg(oImage.Image, function(img) {
// Remove crossOrigin on retry to maximize display success
img.crossOrigin = null;
oThis.loadImageByUrl(img, img.src);
});
// Enable CORS for cross-origin images to allow canvas manipulation
oImage.Image.crossOrigin = 'anonymous';
this.loadImageByUrl(oImage.Image, oImage.src, isDisableCrypto);
}
};
}
//---------------------------------------------------------export---------------------------------------------------
window['AscCommon'] = window['AscCommon'] || {};
window['AscCommon'].CGlobalFontLoader = CGlobalFontLoader;
window['AscCommon'].g_font_loader = new CGlobalFontLoader();
window['AscCommon'].g_image_loader = new CGlobalImageLoader();
})(window, window.document);