Current File : /home/escuelai/public_html/it/src/Ajax.php |
<?php
/**
* ---------------------------------------------------------------------
*
* GLPI - Gestionnaire Libre de Parc Informatique
*
* http://glpi-project.org
*
* @copyright 2015-2022 Teclib' and contributors.
* @copyright 2003-2014 by the INDEPNET Development Team.
* @licence https://www.gnu.org/licenses/gpl-3.0.html
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* ---------------------------------------------------------------------
*/
use Glpi\Application\View\TemplateRenderer;
/**
* Ajax Class
**/
class Ajax
{
/**
* Create modal window
* After display it using data-bs-toggle and data-bs-target attributes
*
* @since 0.84
*
* @param string $name name of the js object
* @param string $url URL to display in modal
* @param string[] $options Possible options:
* - width (default 800)
* - height (default 400)
* - modal is a modal window? (default true)
* - container specify a html element to render (default empty to html.body)
* - title window title (default empty)
* - display display or get string? (default true)
*
* @return void|string (see $options['display'])
*/
public static function createModalWindow($name, $url, $options = [])
{
$param = [
'width' => 800,
'height' => 400,
'modal' => true,
'modal_class' => "modal-lg",
'container' => '',
'title' => '',
'extraparams' => [],
'display' => true,
'js_modal_fields' => ''
];
if (count($options)) {
foreach ($options as $key => $val) {
if (isset($param[$key])) {
$param[$key] = $val;
}
}
}
$html = TemplateRenderer::getInstance()->render(
'components/modal.html.twig',
[
'title' => $param['title'],
'modal_class' => $param['modal_class'],
]
);
$out = "<script type='text/javascript'>\n";
$out .= "var {$name};\n";
$out .= "$(function() {\n";
if (!empty($param['container'])) {
$out .= " var el = $('#" . Html::cleanId($param['container']) . "');\n";
$out .= " el.addClass('modal');\n";
} else {
$out .= " var el = $('<div class=\"modal\"></div>');";
$out .= " $('body').append(el);\n";
}
$out .= " el.html(" . json_encode($html) . ");\n";
$out .= " {$name} = new bootstrap.Modal(el.get(0), {show: false});\n";
$out .= " el.on(\n";
$out .= " 'show.bs.modal',\n";
$out .= " function(evt) {\n";
$out .= " var fields = ";
if (is_array($param['extraparams']) && count($param['extraparams'])) {
$out .= json_encode($param['extraparams'], JSON_FORCE_OBJECT);
} else {
$out .= '{}';
}
$out .= ";\n";
if (!empty($param['js_modal_fields'])) {
$out .= $param['js_modal_fields'] . "\n";
}
$out .= " el.find('.modal-body').load('$url', fields);\n";
$out .= " }\n";
$out .= " );\n";
$out .= "});\n";
$out .= "</script>\n";
if ($param['display']) {
echo $out;
} else {
return $out;
}
}
/**
* Create modal window in Iframe
* After display it using data-bs-toggle and data-bs-target attributes
*
* @since 0.85
*
* @param string $domid DOM ID of the js object
* @param string $url URL to display in modal
* @param array $options Possible options:
* - width (default 800)
* - height (default 400)
* - modal is a modal window? (default true)
* - title window title (default empty)
* - display display or get string? (default true)
* - reloadonclose reload main page on close? (default false)
*
* @return void|string (see $options['display'])
*/
public static function createIframeModalWindow($domid, $url, $options = [])
{
$param = [
'width' => 1050,
'height' => 500,
'modal' => true,
'title' => '',
'display' => true,
'dialog_class' => 'modal-lg',
'autoopen' => false,
'reloadonclose' => false
];
if (count($options)) {
foreach ($options as $key => $val) {
if (isset($param[$key])) {
$param[$key] = $val;
}
}
}
$url .= (strstr($url, '?') ? '&' : '?') . '_in_modal=1';
$rand = mt_rand();
$html = <<<HTML
<div id="$domid" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog {$param['dialog_class']}">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
<h3>{$param['title']}</h3>
</div>
<div class="modal-body">
<iframe id='iframe$domid' class="iframe hidden"
width="100%" height="400" frameborder="0">
</iframe>
</div>
</div>
</div>
</div>
HTML;
$reloadonclose = $param['reloadonclose'] ? "true" : "false";
$autoopen = $param['autoopen'] ? "true" : "false";
$js = <<<JAVASCRIPT
$(function() {
myModalEl{$rand} = document.getElementById('{$domid}');
myModal{$rand} = new bootstrap.Modal(myModalEl{$rand});
// move modal to body
$(myModalEl{$rand}).appendTo($("body"));
myModalEl{$rand}.addEventListener('show.bs.modal', function () {
$('#iframe{$domid}').attr('src','{$url}').removeClass('hidden');
});
myModalEl{$rand}.addEventListener('hide.bs.modal', function () {
if ({$reloadonclose}) {
window.location.reload()
}
});
if ({$autoopen}) {
myModal{$rand}.show();
}
document.getElementById('iframe$domid').onload = function() {
if ({$param['height']} !== 'undefined') {
var h = {$param['height']};
} else {
var h = $('#iframe{$domid}').contents().height();
}
if ({$param['width']} !== 'undefined') {
var w = {$param['width']};
} else {
var w = $('#iframe{$domid}').contents().width();
}
$('#iframe{$domid}')
.height(h);
if (w >= 700) {
$('#{$domid} .modal-dialog').addClass('modal-xl');
} else if (w >= 500) {
$('#{$domid} .modal-dialog').addClass('modal-lg');
} else if (w <= 300) {
$('#{$domid} .modal-dialog').addClass('modal-sm');
}
// reajust height to content
myModal{$rand}.handleUpdate()
};
});
JAVASCRIPT;
$out = "<script type='text/javascript'>$js</script>" . trim($html);
if ($param['display']) {
echo $out;
} else {
return $out;
}
}
/**
* Create Ajax Tabs apply to 'tabspanel' div. Content is displayed in 'tabcontent'
*
* @param string $tabdiv_id ID of the div containing the tabs (default 'tabspanel')
* @param string $tabdivcontent_id ID of the div containing the content loaded by tabs (default 'tabcontent')
* @param array $tabs Tabs to create : tabs is array('key' => array('title'=> 'x',
* tabs is array('key' => array('title'=> 'x',
* url => 'url_toload',
* params => 'url_params')...
* @param string $type itemtype for active tab
* @param integer $ID ID of element for active tab (default 0)
* @param string $orientation orientation of tabs (default vertical may also be horizontal)
* @param array $options Display options
*
* @return void
*/
public static function createTabs(
$tabdiv_id = 'tabspanel',
$tabdivcontent_id = 'tabcontent',
$tabs = [],
$type = '',
$ID = 0,
$orientation = 'vertical',
$options = []
) {
global $CFG_GLPI;
if (count($tabs) === 0) {
return;
}
$active_tab = Session::getActiveTab($type);
// Compute tabs ids.
$active_id = null;
foreach ($tabs as $key => $val) {
$id = sprintf('tab-%s-%s', str_replace('$', '_', $key), mt_rand());
$tabs[$key]['id'] = $id;
if ($key == $active_tab || $active_id === null) {
$active_id = $id;
}
}
$active_id = str_replace('\\', '_', $active_id);
// Display tabs
if (count($tabs) > 0) {
if (count($tabs) == 1) {
$orientation = "horizontal";
}
$flex_container = "flex-column flex-md-row";
$flex_tab = "flex-row flex-md-column d-none d-md-block";
$border = "border-start-0";
$navitemml = "ms-0";
$navlinkp = "pe-1";
$nav_width = "style='min-width: 200px'";
if ($orientation == "horizontal") {
$flex_container = "flex-column";
$flex_tab = "flex-row d-none d-md-flex";
$border = "";
$navitemml = "";
$navlinkp = "";
$nav_width = "";
}
echo "<div class='d-flex card-tabs $flex_container $orientation'>";
echo "<ul class='nav nav-tabs $flex_tab' id='$tabdiv_id' $nav_width role='tablist'>";
$html_tabs = "";
$html_sele = "";
$i = 0;
// Hide tabs if only one single tab on item creation form
$display_class = "";
if (
is_a($type, CommonDBTM::class, true)
&& count($tabs) == 1
) {
$display_class = "d-none";
}
foreach ($tabs as $val) {
$target = str_replace('\\', '_', $val['id']);
$html_tabs .= "<li class='nav-item $navitemml'>
<a class='nav-link justify-content-between $navlinkp $display_class' data-bs-toggle='tab' title='" . strip_tags($val['title']) . "' ";
$html_tabs .= " href='" . $val['url'] . (isset($val['params']) ? '?' . $val['params'] : '') . "' data-bs-target='#{$target}'>";
$html_tabs .= $val['title'] . "</a></li>";
$html_sele .= "<option value='$i' " . ($active_id == $target ? "selected" : "") . ">
{$val['title']}
</option>";
$i++;
}
echo $html_tabs;
echo "</ul>";
echo "<select class='form-select border-2 border-secondary rounded-0 rounded-top d-md-none mb-2' id='$tabdiv_id-select'>$html_sele</select>";
echo "<div class='tab-content p-2 flex-grow-1 card $border' style='min-height: 150px'>";
foreach ($tabs as $val) {
$id = str_replace('\\', '_', $val['id']);
echo "<div class='tab-pane fade' role='tabpanel' id='{$id}'></div>";
}
echo "</div>"; // .tab-content
echo "</div>"; // .container-fluid
$js = "
var loadTabContents = function (tablink, force_reload = false) {
var url = tablink.attr('href');
var target = tablink.attr('data-bs-target');
var index = tablink.closest('.nav-item').index();
const updateCurrentTab = () => {
$.get(
'{$CFG_GLPI['root_doc']}/ajax/updatecurrenttab.php',
{
itemtype: '" . addslashes($type) . "',
id: '$ID',
tab: index,
}
);
}
if ($(target).html() && !force_reload) {
updateCurrentTab();
return;
}
$(target).html('<i class=\"fas fa-3x fa-spinner fa-pulse position-absolute m-5 start-50\"></i>');
$.get(url, function(data) {
$(target).html(data);
$(target).closest('main').trigger('glpi.tab.loaded');
updateCurrentTab();
});
};
var reloadTab = function (add) {
var active_link = $('main #tabspanel .nav-item .nav-link.active');
// Update href and load tab contents
var currenthref = active_link.attr('href');
active_link.attr('href', currenthref + '&' + add);
loadTabContents(active_link, true);
// Restore href
active_link.attr('href', currenthref);
};
$(function() {
$('a[data-bs-toggle=\"tab\"]').on('shown.bs.tab', function(e) {
e.preventDefault();
loadTabContents($(this));
});
// load initial tab
$('a[data-bs-target=\"#{$active_id}\"]').tab('show');
// select events in responsive mode
$('#$tabdiv_id-select').on('change', function (e) {
$('#$tabdiv_id li a').eq($(this).val()).tab('show');
});
});
";
echo Html::scriptBlock($js);
}
}
/**
* Javascript code for update an item when another item changed
*
* @param string $toobserve id (or array of id) of the select to observe
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param array $events of the observed events (default 'change')
* @param integer $minsize minimum size of data to update content (default -1)
* @param integer $buffertime minimum time to wait before reload (default -1)
* @param array $forceloadfor of content which must force update content
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItemOnEvent(
$toobserve,
$toupdate,
$url,
$parameters = [],
$events = ["change"],
$minsize = -1,
$buffertime = -1,
$forceloadfor = [],
$display = true
) {
$output = "<script type='text/javascript'>";
$output .= "$(function() {";
$output .= self::updateItemOnEventJsCode(
$toobserve,
$toupdate,
$url,
$parameters,
$events,
$minsize,
$buffertime,
$forceloadfor,
false
);
$output .= "});</script>";
if ($display) {
echo $output;
} else {
return $output;
}
}
/**
* Javascript code for update an item when a select item changed
*
* @param string $toobserve id of the select to observe
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItemOnSelectEvent(
$toobserve,
$toupdate,
$url,
$parameters = [],
$display = true
) {
return self::updateItemOnEvent(
$toobserve,
$toupdate,
$url,
$parameters,
["change"],
-1,
-1,
[],
$display
);
}
/**
* Javascript code for update an item when a Input text item changed
*
* @param string $toobserve id of the Input text to observe
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param integer $minsize minimum size of data to update content (default -1)
* @param integer $buffertime minimum time to wait before reload (default -1)
* @param array $forceloadfor of content which must force update content
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItemOnInputTextEvent(
$toobserve,
$toupdate,
$url,
$parameters = [],
$minsize = -1,
$buffertime = -1,
$forceloadfor = [],
$display = true
) {
if (count($forceloadfor) == 0) {
$forceloadfor = ['*'];
}
// Need to define min size for text search
if ($minsize < 0) {
$minsize = 0;
}
if ($buffertime < 0) {
$buffertime = 0;
}
return self::updateItemOnEvent(
$toobserve,
$toupdate,
$url,
$parameters,
["dblclick", "keyup"],
$minsize,
$buffertime,
$forceloadfor,
$display
);
}
/**
* Javascript code for update an item when another item changed (Javascript code only)
*
* @param string $toobserve id (or array of id) of the select to observe
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param array $events of the observed events (default 'change')
* @param integer $minsize minimum size of data to update content (default -1)
* @param integer $buffertime minimum time to wait before reload (default -1)
* @param array $forceloadfor of content which must force update content
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItemOnEventJsCode(
$toobserve,
$toupdate,
$url,
$parameters = [],
$events = ["change"],
$minsize = -1,
$buffertime = -1,
$forceloadfor = [],
$display = true
) {
if (is_array($toobserve)) {
$zones = $toobserve;
} else {
$zones = [$toobserve];
}
$output = '';
foreach ($zones as $zone) {
foreach ($events as $event) {
if ($buffertime > 0) {
$output .= "var last$zone$event = 0;";
}
$output .= Html::jsGetElementbyID(Html::cleanId($zone)) . ".on(
'$event',
function(event) {";
// TODO manage buffer time !!?
// if ($buffertime > 0) {
// $output.= "var elapsed = new Date().getTime() - last$zone$event;
// last$zone$event = new Date().getTime();
// if (elapsed < $buffertime) {
// return;
// }";
// }
$condition = '';
if ($minsize >= 0) {
$condition = Html::jsGetElementbyID(Html::cleanId($zone)) . ".val().length >= $minsize ";
}
if (count($forceloadfor)) {
foreach ($forceloadfor as $value) {
if (!empty($condition)) {
$condition .= " || ";
}
$condition .= Html::jsGetElementbyID(Html::cleanId($zone)) . ".val() == '$value'";
}
}
if (!empty($condition)) {
$output .= "if ($condition) {";
}
$output .= self::updateItemJsCode($toupdate, $url, $parameters, $toobserve, false);
if (!empty($condition)) {
$output .= "}";
}
$output .= "}";
$output .= ");\n";
}
}
if ($display) {
echo $output;
} else {
return $output;
}
}
/**
* Javascript code for update an item (Javascript code only)
*
* @param array $options Options :
* - toupdate : array / Update a specific item on select change on dropdown
* (need value_fieldname, to_update,
* url (@see Ajax::updateItemOnSelectEvent for information)
* and may have moreparams)
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function commonDropdownUpdateItem($options, $display = true)
{
$field = '';
$output = '';
// Old scheme
if (
isset($options["update_item"])
&& (is_array($options["update_item"]) || (strlen($options["update_item"]) > 0))
) {
$field = "update_item";
}
// New scheme
if (
isset($options["toupdate"])
&& (is_array($options["toupdate"]) || (strlen($options["toupdate"]) > 0))
) {
$field = "toupdate";
}
if (!empty($field)) {
$datas = $options[$field];
if (is_array($datas) && count($datas)) {
// Put it in array
if (isset($datas['to_update'])) {
$datas = [$datas];
}
foreach ($datas as $data) {
$paramsupdate = [];
if (isset($data['value_fieldname'])) {
$paramsupdate = [$data['value_fieldname'] => '__VALUE__'];
}
if (
isset($data["moreparams"])
&& is_array($data["moreparams"])
&& count($data["moreparams"])
) {
foreach ($data["moreparams"] as $key => $val) {
$paramsupdate[$key] = $val;
}
}
$output .= self::updateItemOnSelectEvent(
"dropdown_" . $options["name"] . $options["rand"],
$data['to_update'],
$data['url'],
$paramsupdate,
$display
);
}
}
}
if ($display) {
echo $output;
} else {
return $output;
}
}
/**
* Javascript code for update an item (Javascript code only)
*
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param string|array $toobserve id of another item used to get value in case of __VALUE__ used or array of id to get value in case of __VALUE#__ used (default '')
* or
* array of id to get value in case of __VALUE#__ used (default '')
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItemJsCode(
$toupdate,
$url,
$parameters = [],
$toobserve = "",
$display = true
) {
$out = Html::jsGetElementbyID($toupdate) . ".load('$url'\n";
if (count($parameters)) {
$out .= ",{";
$first = true;
foreach ($parameters as $key => $val) {
// prevent xss attacks
if (!preg_match('/^[a-zA-Z_$][0-9a-zA-Z_$]*$/', $key)) {
continue;
}
if ($first) {
$first = false;
} else {
$out .= ",";
}
$out .= $key . ":";
$regs = [];
if (!is_array($val) && preg_match('/^__VALUE(\d+)__$/', $val, $regs)) {
$out .= Html::jsGetElementbyID(Html::cleanId($toobserve[$regs[1]])) . ".val()";
} else if (!is_array($val) && $val === "__VALUE__") {
$out .= Html::jsGetElementbyID(Html::cleanId($toobserve)) . ".val()";
} else {
$out .= json_encode($val);
}
}
$out .= "}\n";
}
$out .= ")\n";
if ($display) {
echo $out;
} else {
return $out;
}
}
/**
* Javascript code for update an item
*
* @param string $toupdate id of the item to update
* @param string $url Url to get datas to update the item
* @param array $parameters of parameters to send to ajax URL
* @param string $toobserve id of another item used to get value in case of __VALUE__ used
* (default '')
* @param boolean $display display or get string (default true)
*
* @return void|string (see $display)
*/
public static function updateItem($toupdate, $url, $parameters = [], $toobserve = "", $display = true)
{
$output = "<script type='text/javascript'>";
$output .= "$(function() {";
$output .= self::updateItemJsCode($toupdate, $url, $parameters, $toobserve, false);
$output .= "});</script>";
if ($display) {
echo $output;
} else {
return $output;
}
}
}