mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-21 16:22:20 +02:00
Merge branch 'support/3.0' into saas/3.0
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
var iChartDefaultHeight = 200,
|
||||
iChartLegendHeight = 6 * {{ oUIBlock.iMaxNbCharsInLabel }},
|
||||
iChartTotalHeight = iChartDefaultHeight+iChartLegendHeight;
|
||||
$('#my_chart_{{ oUIBlock.sId }}').height(iChartTotalHeight+'px');
|
||||
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#my_chart_{{ oUIBlock.sId }}'),
|
||||
data: {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
// Calculate height of graph : 200px (minimum height for the chart) + 20*iNbLinesToAddForName for the legend
|
||||
var iChartDefaultHeight = 200,
|
||||
iChartLegendHeight = 20 * {{ oUIBlock.iNbLinesToAddForName }} ,
|
||||
iChartTotalHeight = (iChartDefaultHeight+iChartLegendHeight);
|
||||
$('#my_chart_{{ oUIBlock.sId }}').height(iChartTotalHeight+'px');
|
||||
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#my_chart_{{ oUIBlock.sId }}'),
|
||||
data: {
|
||||
@@ -9,7 +15,7 @@ var chart = c3.generate({
|
||||
names: {{ oUIBlock.sJSNames|raw }},
|
||||
onclick: function (d) {
|
||||
var aURLs = {{ oUIBlock.sJSURLs|raw }};
|
||||
window.location.href= aURLs[d.index];
|
||||
window.location.href = aURLs[d.index];
|
||||
},
|
||||
order: null
|
||||
},
|
||||
@@ -19,17 +25,19 @@ var chart = c3.generate({
|
||||
},
|
||||
tooltip: {
|
||||
format: {
|
||||
value: function (value) { return value; }
|
||||
value: function (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof(charts) === "undefined")
|
||||
if (typeof (charts) === "undefined")
|
||||
{
|
||||
charts = [];
|
||||
refreshChart = [];
|
||||
refreshChart = [];
|
||||
}
|
||||
var idxChart=charts.length;
|
||||
var idxChart = charts.length;
|
||||
charts.push(chart);
|
||||
var refreshChart{{ oUIBlock.sId|sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME')) }}=' $.post("{{ oUIBlock.sURLForRefresh|raw }}&refresh='+idxChart+'","", function (data) {'+
|
||||
'charts['+idxChart+'].unload();'+
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<span class="{{ oUIBlock.GetOriginDecorationClasses() }}"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if get_config_parameter('activity_panel.show_author_name_below_entries') %}
|
||||
{% if oUIBlock.ShowAuthorNameBelowEntries() %}
|
||||
<span class="ibo-activity-entry--author-name ibo-is-hidden" data-role="ibo-activity-entry--author-name">{{ oUIBlock.GetAuthorFriendlyname() }}</span>
|
||||
{% endif %}
|
||||
<span class="ibo-activity-entry--datetime" data-role="ibo-activity-entry--datetime"
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
data-object-id="{{ oUIBlock.GetObjectId() }}"
|
||||
data-attribute-code="{{ oUIBlock.GetAttCode() }}"
|
||||
data-attribute-label="{{ oUIBlock.GetAttLabel() }}"
|
||||
data-attribute-type="{{ oUIBlock.GetAttType() }}"
|
||||
data-input-type="{{ constant('cmdbAbstractObject::ENUM_INPUT_TYPE_HTML_EDITOR') }}"
|
||||
data-input-id="{{ oUIBlock.GetTextInput().GetId() }}"
|
||||
data-submit-mode="{{ oUIBlock.GetSubmitMode() }}"
|
||||
method="post">
|
||||
<div class="ibo-caselog-entry-form--actions">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
$('#{{ oUIBlock.GetId() }}').activity_panel({
|
||||
datetime_format: {{ oUIBlock.GetDateTimeFormatForJSWidget()|json_encode|raw }},
|
||||
datetimes_reformat_limit: {{ get_config_parameter('activity_panel.datetimes_reformat_limit') }},
|
||||
datetimes_reformat_limit: {{ oUIBlock.GetDatetimesReformatLimit() }},
|
||||
{% if oUIBlock.HasTransactionId() %}transaction_id: {{ oUIBlock.GetTransactionId()|var_export }},{% endif %}
|
||||
lock_enabled: {{ oUIBlock.IsLockEnabled()|var_export }},
|
||||
lock_watcher_period: {{ get_config_parameter('activity_panel.lock_watcher_period') }},
|
||||
lock_watcher_period: {{ oUIBlock.GetLockWatcherPeriod() }},
|
||||
lock_endpoint: {{ oUIBlock.GetLockEndpoint()|var_export|raw }},
|
||||
show_multiple_entries_submit_confirmation: {{ oUIBlock.GetShowMultipleEntriesSubmitConfirmation()|var_export }},
|
||||
save_state_endpoint: {{ oUIBlock.GetSaveStateEndpoint()|var_export|raw }},
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<label class="ibo-activity-panel--tab-toolbar-action" data-role="ibo-activity-panel--tab-toolbar-action"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Logs:Tooltip'|dict_s }}">
|
||||
<input type="checkbox" name="caselogs" data-role="ibo-activity-panel--filter" data-target-entry-types="caselog"
|
||||
{% if (aFilteredCaseLogsAttCodes is not defined) or (aFilteredCaseLogsAttCodes is empty) or (get_config_parameter('activity_panel.prefilter_only_current_log') == false) %}checked{% endif %}>
|
||||
{% if (aFilteredCaseLogsAttCodes is not defined) or (aFilteredCaseLogsAttCodes is empty) or (oUIBlock.GetPrefilterOnlyCurrentLog() == false) %}checked{% endif %}>
|
||||
{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Logs:Title'|dict_s }}
|
||||
{% if oUIBlock.GetCaseLogTabs()|length > 0 %}
|
||||
<a class="ibo-activity-panel--filter-options-toggler ibo-is-closed" href="#"
|
||||
@@ -43,7 +43,7 @@
|
||||
<input type="checkbox" name="caselog" value="{{ sCaseLogAttCode }}"
|
||||
class="ibo-activity-panel--filter-option-input"
|
||||
data-role="ibo-activity-panel--filter-option-input"
|
||||
{% if (aFilteredCaseLogsAttCodes is not defined) or (sCaseLogAttCode in aFilteredCaseLogsAttCodes) or (get_config_parameter('activity_panel.prefilter_only_current_log') == false) %}checked{% endif %}>
|
||||
{% if (aFilteredCaseLogsAttCodes is not defined) or (sCaseLogAttCode in aFilteredCaseLogsAttCodes) or (oUIBlock.GetPrefilterOnlyCurrentLog() == false) %}checked{% endif %}>
|
||||
{{ aCaseLogData['title'] }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
@@ -55,13 +55,13 @@
|
||||
<label class="ibo-activity-panel--tab-toolbar-action"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Transitions:Tooltip'|dict_s }}">
|
||||
<input type="checkbox" name="transitions" data-role="ibo-activity-panel--filter"
|
||||
data-target-entry-types="transition" {% if (bPrefilterStateChanges is defined and bPrefilterStateChanges == true) or (get_config_parameter('activity_panel.prefilter_state_changes_on_logs') == true) %}checked{% endif %}>
|
||||
data-target-entry-types="transition" {% if (bPrefilterStateChanges is defined and bPrefilterStateChanges == true) or (oUIBlock.GetPrefilterStateChangesOnLogs() == true) %}checked{% endif %}>
|
||||
{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Transitions:Title'|dict_s }}
|
||||
</label>
|
||||
{% endif %}
|
||||
<label class="ibo-activity-panel--tab-toolbar-action"
|
||||
data-tooltip-content="{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Edits:Tooltip'|dict_s }}">
|
||||
<input type="checkbox" name="edits" data-role="ibo-activity-panel--filter" data-target-entry-types="edits" {% if (bPrefilterEdits is defined and bPrefilterEdits == true) or (get_config_parameter('activity_panel.prefilter_edits_on_logs') == true) %}checked{% endif %}>
|
||||
<input type="checkbox" name="edits" data-role="ibo-activity-panel--filter" data-target-entry-types="edits" {% if (bPrefilterEdits is defined and bPrefilterEdits == true) or (oUIBlock.GetPrefilterEditsOnLogs() == true) %}checked{% endif %}>
|
||||
{{ 'UI:Layout:ActivityPanel:Tab:Toolbar:Filter:Edits:Title'|dict_s }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
$('#{{ oUIBlock.GetId() }}').navigation_menu({
|
||||
display_counts: {% if get_config_parameter('navigation_menu.show_menus_count') %} true {% else %} false {% endif %},
|
||||
display_counts: {% if oUIBlock.GetShowMenusCount() %} true {% else %} false {% endif %},
|
||||
org_id: '{{ oUIBlock.GetOrgId() }}'
|
||||
});
|
||||
|
||||
|
||||
@@ -35,55 +35,99 @@
|
||||
{% set sId = oLayout.GetId() | sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME')) %}
|
||||
{% block iboPageJsFiles %}
|
||||
<script type="text/javascript">
|
||||
window['{{ sPromiseId }}'] = new Promise(function (resolve, reject) {
|
||||
let fInlineOnDomReadyScript{{ sId }} = function () {
|
||||
{% for sJsInlineOnDomReady in aPage.aJsInlineOnDomReady %}
|
||||
{{ sJsInlineOnDomReady|raw }}
|
||||
window['{{ sPromiseId }}'] = new Promise(function (resolve, reject) {
|
||||
let fInlineOnDomReadyScript{{ sId }} = function () {
|
||||
{% for sJsInlineOnDomReady in aPage.aJsInlineOnDomReady %}
|
||||
{{ sJsInlineOnDomReady|raw }}
|
||||
{% endfor %}
|
||||
resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 use 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"},
|
||||
* ...
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
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 %}
|
||||
resolve();
|
||||
}
|
||||
|
||||
let aFilesToLoad{{ sId }} = [];
|
||||
let iCurrentIdx = 0;
|
||||
let iFilesToLoadCount = aJsFilesToLoad.length;
|
||||
if (iFilesToLoadCount > 0)
|
||||
{
|
||||
let fLoadScript{{ sId }} = function () {
|
||||
let sCurrentFileId = aJsFilesToLoad[iCurrentIdx]["id"];
|
||||
let sCurrentFileUrl = aJsFilesToLoad[iCurrentIdx]["url"];
|
||||
|
||||
{% for sJsFile in aPage.aJsFiles %}
|
||||
if ($.inArray('{{ sJsFile|raw }}', aListJsFiles) === -1)
|
||||
{
|
||||
aFilesToLoad{{ sId }}.push('{{ sJsFile|add_itop_version|raw }}');
|
||||
aListJsFiles.push("{{ sJsFile|raw }}");
|
||||
}
|
||||
{% endfor %}
|
||||
/** @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)()
|
||||
);
|
||||
}
|
||||
|
||||
let iCurrentIdx{{ sId }} = 0;
|
||||
let iFilesToLoadCount{{ sId }} = aFilesToLoad{{ sId }}.length;
|
||||
if (iFilesToLoadCount{{ sId }} > 0)
|
||||
{
|
||||
let fLoadScript{{ sId }} = function () {
|
||||
$.when(
|
||||
$.ajax({
|
||||
url: aFilesToLoad{{ sId }}[iCurrentIdx{{ sId }}],
|
||||
dataType: 'script',
|
||||
cache: true
|
||||
})
|
||||
)
|
||||
.then(function () {
|
||||
iCurrentIdx{{ sId }}++;
|
||||
if (iCurrentIdx{{ sId }} !== iFilesToLoadCount{{ sId }})
|
||||
{
|
||||
fLoadScript{{ sId }}();
|
||||
}
|
||||
else
|
||||
{
|
||||
fInlineOnDomReadyScript{{ sId }}();
|
||||
}
|
||||
});
|
||||
};
|
||||
fLoadScript{{ sId }}();
|
||||
}
|
||||
else
|
||||
{
|
||||
fInlineOnDomReadyScript{{ sId }}();
|
||||
}
|
||||
});
|
||||
// Only once file is loaded (by the request or another), proceed to next step
|
||||
oPromise.then(function () {
|
||||
iCurrentIdx++;
|
||||
if (iCurrentIdx !== iFilesToLoadCount)
|
||||
{
|
||||
fLoadScript{{ sId }}();
|
||||
}
|
||||
else
|
||||
{
|
||||
fInlineOnDomReadyScript{{ sId }}();
|
||||
}
|
||||
});
|
||||
};
|
||||
fLoadScript{{ sId }}();
|
||||
}
|
||||
else
|
||||
{
|
||||
fInlineOnDomReadyScript{{ sId }}();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% else %}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{# @copyright Copyright (C) 2010-2021 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
{% apply spaceless %}
|
||||
{{ render_block(oLayout, {aPage: aPage}) }}
|
||||
{% endapply %}
|
||||
@@ -64,14 +64,32 @@
|
||||
{{ render_block(oBlock, {aPage: aPage}) }}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
{% if aPage.aJsFiles is not empty %}
|
||||
<script type="text/javascript">
|
||||
var aListJsFiles = [];
|
||||
|
||||
<script type="text/javascript">
|
||||
{# JS files can either be loaded initially or requested by an XHR response #}
|
||||
{# - For the initial page, all files are loaded before running inline snippets #}
|
||||
{# - For XHR responses, we need to ensure that all required files are fully loaded before running inline snippets #}
|
||||
|
||||
/**
|
||||
* @var {Map} aLoadedJsFilesRegister
|
||||
* Register of all JS files loaded in this page, including the Promise corresponding to the loading state of each file.
|
||||
* A JS file MUST NOT be loaded more than once as it could compromise settings / plugins loaded after the first time.
|
||||
*/
|
||||
const aLoadedJsFilesRegister = new Map();
|
||||
/**
|
||||
* @var {Map} aLoadedJsFilesResolveCallbacks
|
||||
* Resolve callbacks of JS files registered in aLoadedJsFilesRegister. Used -mostly in \AjaxPage- to know when a file is done loading so the depending snippets can run
|
||||
*/
|
||||
const aLoadedJsFilesResolveCallbacks = new Map();
|
||||
{% for sJsFile in aPage.aJsFiles %}
|
||||
aListJsFiles.push("{{ sJsFile|raw }}");
|
||||
{% endfor %}
|
||||
</script>
|
||||
{% endif %}
|
||||
aLoadedJsFilesRegister.set("{{ sJsFile|raw }}", new Promise(function(resolve) {
|
||||
aLoadedJsFilesResolveCallbacks.set("{{ sJsFile|raw }}", resolve);
|
||||
// Resolve promise right away as these files are loaded immediately before any inline JS is executed
|
||||
aLoadedJsFilesResolveCallbacks.get("{{ sJsFile|raw }}")();
|
||||
}));
|
||||
{% endfor %}
|
||||
</script>
|
||||
|
||||
{% block iboPageJsFiles %}
|
||||
{% for sJsFile in aPage.aJsFiles %}
|
||||
<script type="text/javascript" src="{{ sJsFile|add_itop_version|raw }}"></script>
|
||||
|
||||
Reference in New Issue
Block a user