Files
iTop/templates/pages/backoffice/ajaxpage/layout.html.twig
2025-09-03 10:37:26 +02:00

214 lines
9.8 KiB
Twig

{# @copyright Copyright (C) 2010-2024 Combodo SAS #}
{# @license http://opensource.org/licenses/AGPL-3.0 #}
{% apply spaceless %}
{% set sId = oLayout.GetId() | sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME')) %}
{% set bHasOnInitOrOnDomReadyScripts = aPage.aJsInlineOnInit is not empty or aPage.aJsInlineOnDomReady is not empty %}
{% if bEscapeContent %}
{{ render_block(oLayout, {aPage: aPage})|escape }}
{% else %}
{{ render_block(oLayout, {aPage: aPage}) }}
{% endif %}
{% block iboPageJsInlineEarly %}
{% for sJsInline in aPage.aJsInlineEarly %}
{# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
<script type="text/javascript">
{{ sJsInline|raw }}
</script>
{% endfor %}
{% endblock %}
{% block iboPageJsInlineLive %}
{% for sJsInline in aPage.aJsInlineLive %}
{# We put each scripts in a dedicated script tag to prevent massive failure if 1 script is broken (eg. missing semi-colon or non closed multi-line comment) #}
<script type="text/javascript">
{{ sJsInline|raw }}
</script>
{% endfor %}
{% endblock %}
{% if bHasOnInitOrOnDomReadyScripts %}
<script type="text/javascript">
let fOnJsFilesLoaded{{ sId }} = function (fResolve) {
{% for sJsInline in aPage.aJsInlineOnInit %}
{{ sJsInline|raw }}
{% endfor %}
{% for sJsInline in aPage.aJsInlineOnDomReady %}
{{ sJsInline|raw }}
{% endfor %}
fResolve();
}
</script>
{% endif %}
{% set sPromiseId = aPage.sPromiseId %}
{% if aPage.aJsFiles is not empty %}
{% block iboPageJsFiles %}
<script type="text/javascript">
{% if bHasOnInitOrOnDomReadyScripts == false %}
// Define a dummy empty callback if there's no script to execute
let fOnJsFilesLoaded{{ sId }} = function (fResolve) {
fResolve();
}
{% endif %}
window['{{ sPromiseId }}'] = new Promise(function (fAllJsFilesResolve, fAllJsFilesReject) {
/**
* @type {Array} aJsFilesToLoad Files required by the current AjaxPage
*
* For each file:
* - "id": Used as an identifier to check if file is already being handled
* - "url" is the URL that will be used for loading. It should include any relevant query args, including the cache buster
*
* ```
* [
* {"id": "https://itop/js/foo.js", "url": "https://itop/js/foo.js?cache_buster=123},
* {"id": "https://itop/js/bar.js", "url": "https://itop/js/bar.js?a=b&cache_buster=123"},
* ...
* ]
* ```
*/
// If these constants aren't defined by the main page, define them (global) ourselves
if (typeof aLoadedJsFilesRegister === "undefined") {
Object.defineProperty(window, "aLoadedJsFilesRegister", {
value: new Map(),
writable: false,
configurable: false,
enumerable: true
});
}
if (typeof aLoadedJsFilesResolveCallbacks === "undefined") {
Object.defineProperty(window, "aLoadedJsFilesResolveCallbacks", {
value: new Map(),
writable: false,
configurable: false,
enumerable: true
});
}
let aJsFilesToLoad = [];
/**
* @type {Array} aJsFilesToLoadByOtherRequests Files required by the current AjaxPage but that are already being handled by another request (done or ongoing)
*/
let aJsFilesToLoadByOtherRequests = [];
{% for sJsFile in aPage.aJsFiles %}
aJsFilesToLoad.push({
"id": "{{ sJsFile|raw }}",
"url": "{{ sJsFile|add_itop_version|raw }}"
});
// If file is already present in the register (see it declaration in WebPage TWIG template), let its original requester load it
if (aLoadedJsFilesRegister.has("{{ sJsFile|raw }}") === true) {
aJsFilesToLoadByOtherRequests.push("{{ sJsFile|raw }}");
}
// Otherwise add it to register and initialize corresponding promise
else {
aLoadedJsFilesRegister.set("{{ sJsFile|raw }}", new Promise(function(fJsFileResolve) {
aLoadedJsFilesResolveCallbacks.set("{{ sJsFile|raw }}", fJsFileResolve);
}));
}
{% endfor %}
let iCurrentIdx = 0;
let iFilesToLoadCount = aJsFilesToLoad.length;
if (iFilesToLoadCount > 0)
{
let fLoadScript{{ sId }} = function () {
let sCurrentFileId = aJsFilesToLoad[iCurrentIdx]["id"];
let sCurrentFileUrl = aJsFilesToLoad[iCurrentIdx]["url"];
/** @type {Promise} oPromise Promise to use once file is loaded */
let oPromise = null;
// If file is handled by another request, retrieve the existing promise
if ($.inArray(sCurrentFileId, aJsFilesToLoadByOtherRequests) !== -1) {
oPromise = aLoadedJsFilesRegister.get(sCurrentFileId)
}
// Otherwise create its own promise to load it
else {
oPromise = $.when(
$.ajax({
url: sCurrentFileUrl,
dataType: 'script',
cache: true
}),
aLoadedJsFilesResolveCallbacks.get(sCurrentFileId)()
);
}
// Only once file is loaded (by the request or another), proceed to next step
oPromise.then(function () {
iCurrentIdx++;
if (iCurrentIdx !== iFilesToLoadCount)
{
fLoadScript{{ sId }}();
}
else
{
fOnJsFilesLoaded{{ sId }}(fAllJsFilesResolve);
}
});
};
fLoadScript{{ sId }}();
}
else
{
fOnJsFilesLoaded{{ sId }}(fAllJsFilesResolve);
}
});
</script>
{% endblock %}
{% else %}
{% if bHasOnInitOrOnDomReadyScripts %}
{% block iboPageJsInlineOnDomReady %}
<script type="text/javascript">
window['{{ sPromiseId }}'] = new Promise(function (fNoJsFileResolve, fNoJsFileReject) {
fOnJsFilesLoaded{{ sId }}(fNoJsFileResolve);
});
</script>
{% endblock %}
{% endif %}
{% endif %}
{% if aDeferredBlocks is not empty %}
{% for oBlock in aDeferredBlocks %}
{{ render_block(oBlock, {aPage: aPage})|raw }}
{% endfor %}
{% endif %}
{% if sDeferredContent %}
<script type="text/javascript">
$('body').append('{{ sDeferredContent|raw }}');
</script>
{% endif %}
{% block iboPageCssFiles %}
{% if aPage.aCssFiles is not empty %}
<script type="text/javascript">
// If this constant isn't defined by the main page, define it (global) ourselves
if (typeof aLoadedCssFilesRegister === "undefined") {
Object.defineProperty(window, "aLoadedCssFilesRegister", {
value: new Map(),
writable: false,
configurable: false,
enumerable: true
});
}
{% for aCssFileData in aPage.aCssFiles %}
// Only if file is NOT already present in the register (see it declaration in WebPage TWIG template), add it to the page and register
if (aLoadedCssFilesRegister.has("{{ aCssFileData['link']|raw }}") === false) {
$('<link href="{{ aCssFileData['link'] }}" rel="stylesheet">').appendTo('head');
aLoadedCssFilesRegister.set("{{ aCssFileData['link']|raw }}", true);
}
{% endfor %}
</script>
{% endif %}
{% endblock %}
{{ aPage.sCapturedOutput|raw }}
{% endapply %}