. * --------------------------------------------------------------------- */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /** * Ajax Class **/ class Ajax { /** * Create modal window * After display it using $name.dialog("open"); * * @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']) */ static function createModalWindow($name, $url, $options = []) { $param = ['width' => 800, 'height' => 400, 'modal' => true, 'container' => '', 'title' => '', 'extraparams' => [], 'display' => true, 'js_modal_fields' => '']; if (count($options)) { foreach ($options as $key => $val) { if (isset($param[$key])) { $param[$key] = $val; } } } $out = "\n"; if ($param['display']) { echo $out; } else { return $out; } } /** * Create a side slide panel * * @param string $name name of the js object * @param array $options Possible options: * - title Title to display * - position position (either left or right - defaults to right) * - display display or get string? (default true) * - icon Path to aditional icon * - icon_url Link for aditional icon * - icon_txt Alternative text and title for aditional icon_ * * @return void|string (see $options['display']) */ static function createSlidePanel($name, $options = []) { global $CFG_GLPI; $param = [ 'title' => '', 'position' => 'right', 'url' => '', 'display' => true, 'icon' => false, 'icon_url' => false, 'icon_txt' => false ]; if (count($options)) { foreach ($options as $key => $val) { if (isset($param[$key])) { $param[$key] = $val; } } } $out = ""; if ($param['display']) { echo $out; } else { return $out; } } /** * Create fixed modal window * After display it using $name.dialog("open"); * * @since 0.84 * * @param string $name name of the js object * @param array $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']) */ static function createFixedModalWindow($name, $options = []) { $param = ['width' => 800, 'height' => 400, 'modal' => true, 'container' => '', 'title' => '', 'display' => true]; if (count($options)) { foreach ($options as $key => $val) { if (isset($param[$key])) { $param[$key] = $val; } } } $out = ""; if ($param['display']) { echo $out; } else { return $out; } } /** * Create modal window in Iframe * After display it using Html::jsGetElementbyID($domid).dialog("open"); * * @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']) */ static function createIframeModalWindow($domid, $url, $options = []) { $param = ['width' => 1050, 'height' => 500, 'modal' => true, 'title' => '', 'display' => true, 'reloadonclose' => false]; if (count($options)) { foreach ($options as $key => $val) { if (isset($param[$key])) { $param[$key] = $val; } } } $url .= (strstr($url, '?') ?'&' : '?').'_in_modal=1'; $out = "
"; $out .= "
"; $out .= ""; 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 */ static function createTabs( $tabdiv_id = 'tabspanel', $tabdivcontent_id = 'tabcontent', $tabs = [], $type = '', $ID = 0, $orientation = 'vertical', $options = [] ) { global $CFG_GLPI; // TODO need to clean params !! $active_tabs = Session::getActiveTab($type); $mainclass = ''; if (isset($options['main_class'])) { $mainclass = " {$options['main_class']}"; } $rand = mt_rand(); if (count($tabs) > 0) { echo "
"; if (CommonGLPI::isLayoutWithMain() && !CommonGLPI::isLayoutExcludedPage()) { $orientation = 'horizontal'; } echo ""; echo "
"; $js = " $(function(){ forceReload$rand = false; $('#tabs$rand').tabs({ active: $selected_tab, // Loading indicator beforeLoad: function (event, ui) { if ($(ui.panel).html() && !forceReload$rand) { event.preventDefault(); } else { forceReload$rand = false; var _loader = $('
" . addslashes(__('Loading...')) . "
'); ui.panel.html(_loader); ui.jqXHR.always(function() { $('#loadingtabs').remove(); }); ui.jqXHR.fail(function(e) { console.log(e); if (e.statusText != 'abort') { ui.panel.html( '

" . addslashes(__('An error occured loading contents!')) . "

" . addslashes(__('Please check GLPI logs or contact your administrator.')) . "
" . addslashes(__('or')) . " " . addslashes(__('try to reload')) . "

' ); } }); } var tabs = ui.tab.parent().children(); if (tabs.length > 1) { var newIndex = tabs.index(ui.tab); $.get( '".$CFG_GLPI['root_doc']."/ajax/updatecurrenttab.php', { itemtype: '".addslashes($type)."', id: '$ID', tab: newIndex } ); } }, load: function(event) { var _url = window.location.href; //get the anchor var _parts = _url.split('#'); if (_parts.length > 1) { var _anchor = _parts[1]; //get the top offset of the target anchor if ($('#' + _anchor).length) { var target_offset = $('#' + _anchor).offset(); var target_top = target_offset.top; //goto that anchor by setting the body scroll top to anchor top $('html, body').animate({scrollTop:target_top}, 2000, 'easeOutQuad'); } } }, ajaxOptions: {type: 'POST'} });"; if ($orientation=='vertical') { $js .= "$('#tabs$rand').tabs().addClass( 'ui-tabs-vertical ui-helper-clearfix' );"; } if (CommonGLPI::isLayoutWithMain() && !CommonGLPI::isLayoutExcludedPage()) { $js .= "$('#tabs$rand').scrollabletabs();"; } else { $js .= "$('#tabs$rand').removeClass( 'ui-corner-top' ).addClass( 'ui-corner-left' );"; } $js .= '});'; $js .= "// force reload global function function reloadTab(add) { forceReload$rand = true; var current_index = $('#tabs$rand').tabs('option','active'); // remove scroll event bind, select2 bind it on parent with scrollbars (the tab currently) // as the select2 disapear with this tab reload, remove the event to prevent issues (infinite scroll to top) $('#tabs$rand .ui-tabs-panel[aria-hidden=false]').unbind('scroll'); // Save tab var currenthref = $('#tabs$rand ul>li a').eq(current_index).attr('href'); $('#tabs$rand ul>li a').eq(current_index).attr('href',currenthref+'&'+add); $('#tabs$rand').tabs( 'load' , current_index); // Restore tab $('#tabs$rand ul>li a').eq(current_index).attr('href',currenthref); };"; 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) */ static function updateItemOnEvent($toobserve, $toupdate, $url, $parameters = [], $events = ["change"], $minsize = -1, $buffertime = -1, $forceloadfor = [], $display = true) { $output = ""; 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) */ 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) */ 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) */ 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) */ 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) */ 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) */ static function updateItem($toupdate, $url, $parameters = [], $toobserve = "", $display = true) { $output = ""; if ($display) { echo $output; } else { return $output; } } }