N°3786 - Fix lock removal when leaving an object details page in edition

The main problem was WebPage::$a_scripts are now printed after the DOM when the mechanism actually prints some JS to redirect to another page immediately.
As there are a LOT of calls to WebPage::add_script(), we kept it to ensure the compatibility; and we add a new WebPage::add_early_script() for JS snippets that explicitly need to be execute before the DOM interpretation.
This commit is contained in:
Molkobain
2021-07-20 09:35:54 +02:00
parent d0813f6607
commit 957cb87b8d
6 changed files with 72 additions and 8 deletions

View File

@@ -202,8 +202,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$sParams .= $sName.'='.urlencode($value).'&'; // Always add a trailing &
}
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/'.$oObj->GetUIPage().'?'.$sParams.'class='.get_class($oObj).'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink().'&a=1';
$oPage->add_script(
<<<EOF
$oPage->add_early_script(<<<JS
if (!sessionStorage.getItem('$sSessionStorageKey'))
{
sessionStorage.setItem('$sSessionStorageKey', 1);
@@ -213,7 +212,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
sessionStorage.removeItem('$sSessionStorageKey');
}
EOF
JS
);
$oObj->Reload();

View File

@@ -115,11 +115,10 @@ function OnUnload(sTransactionId, sObjClass, iObjKey, sToken)
// IMPORTANT: the ajax request MUST BE synchronous to be executed in this context
$.ajax({
url: GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
async: true,
async: false,
method: 'POST',
data: {operation: 'on_form_cancel', transaction_id: sTransactionId, obj_class: sObjClass, obj_key: iObjKey, token: sToken }
});
CombodoGlobalToolbox.Pause(1000);
}
}

View File

@@ -74,7 +74,13 @@ class WebPage implements Page
protected $s_title;
protected $s_content;
protected $s_deferred_content;
/** @var array Scripts to be put in the page's header */
/**
* @var array Scripts to be put in the page's header, therefore executed first, BEFORE the DOM interpretation.
* /!\ Keep in mind that no external JS files (eg. jQuery) will be loaded yet.
* @since 3.0.0
*/
protected $a_early_scripts;
/** @var array Scripts to be executed immediately without waiting for the DOM to be ready */
protected $a_scripts;
/** @var array Scripts to be executed when the DOM is ready (typical JQuery use), right before "ready scripts" */
protected $a_init_scripts;
@@ -127,6 +133,7 @@ class WebPage implements Page
$this->s_title = $s_title;
$this->s_content = "";
$this->s_deferred_content = '';
$this->InitializeEarlyScripts();
$this->InitializeScripts();
$this->InitializeInitScripts();
$this->InitializeReadyScripts();
@@ -433,6 +440,45 @@ class WebPage implements Page
/**
* Empty all base JS in the page's header
*
* @uses \WebPage::$a_a_early_scripts
* @return void
* @since 3.0.0
*/
protected function EmptyEarlyScripts(): void
{
$this->a_early_scripts = [];
}
/**
* Initialize base JS in the page's header
*
* @uses \WebPage::$a_scripts
* @return void
* @since 3.0.0
*/
protected function InitializeEarlyScripts(): void
{
$this->EmptyEarlyScripts();
}
/**
* Add some Javascript to the header of the page, therefore executed first, BEFORE the DOM interpretation.
* /!\ Keep in mind that no external JS files (eg. jQuery) will be loaded yet.
*
* @uses \WebPage::$a_a_early_scripts
* @param string $s_script
* @since 3.0.0
*/
public function add_early_script($s_script)
{
if (!empty(trim($s_script))) {
$this->a_early_scripts[] = $s_script;
}
}
/**
* Empty all base JS
*
* @uses \WebPage::$a_scripts
* @return void
* @since 3.0.0
@@ -443,7 +489,7 @@ class WebPage implements Page
}
/**
* Initialize base JS in the page's header
* Initialize base JS
*
* @uses \WebPage::$a_scripts
* @return void
@@ -455,7 +501,7 @@ class WebPage implements Page
}
/**
* Add some Javascript to the header of the page
* Add some Javascript to be executed immediately without waiting for the DOM to be ready
*
* @uses \WebPage::$a_scripts
* @param string $s_script
@@ -1123,6 +1169,7 @@ JS;
],
'aCssFiles' => $this->a_linked_stylesheets,
'aCssInline' => $this->a_styles,
'aJsInlineEarly' => $this->a_early_scripts,
'aJsFiles' => $this->a_linked_scripts,
'aJsInlineLive' => $this->a_scripts,
'aJsInlineOnDomReady' => $this->GetReadyScripts(),

View File

@@ -861,6 +861,7 @@ HTML;
[
'aCssFiles' => $this->a_linked_stylesheets,
'aCssInline' => $this->a_styles,
'aJsInlineEarly' => $this->a_early_scripts,
'aJsFiles' => $this->a_linked_scripts,
'aJsInlineOnInit' => $this->a_init_scripts,
'aJsInlineOnDomReady' => $this->GetReadyScripts(),

View File

@@ -7,6 +7,15 @@
{{ 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) #}

View File

@@ -35,6 +35,15 @@
</style>
{% endfor %}
{% endblock %}
{% 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 %}
</head>
<body data-gui-type="backoffice">
{% block iboPageBodyHtml %}