/** * --------------------------------------------------------------------- * GLPI - Gestionnaire Libre de Parc Informatique * Copyright (C) 2015-2020 Teclib' and contributors. * * http://glpi-project.org * * based on GLPI - Gestionnaire Libre de Parc Informatique * Copyright (C) 2003-2014 by the INDEPNET Development Team. * * --------------------------------------------------------------------- * * LICENSE * * This file is part of GLPI. * * GLPI 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 2 of the License, or * (at your option) any later version. * * GLPI 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 GLPI. If not, see . * --------------------------------------------------------------------- */ /* global L */ var timeoutglobalvar; if (typeof(String.prototype.normalize) !== 'function') { $.ajax({ type: "GET", url: CFG_GLPI.root_doc + "/public/lib/unorm.js", dataType: "script", cache: true }); } /** * modifier la propriete display d'un element * * @param objet * @param statut **/ function setdisplay(objet, statut) { var e = objet; if (e.style.display != statut) { e.style.display = statut; } return true; } /** * @param id **/ function cleandisplay(id) { var e = document.getElementById(id); if (e) { setdisplay(e,'block'); } } /** * @param id **/ function cleanhide(id) { var e = document.getElementById(id); if (e) { setdisplay(e,'none'); } } /** * masquer le menu actif par timeout * * @param idMenu **/ function afterView(idMenu) { setdisplay(idMenu,'none'); } /** * @param id * @param idMenu **/ function menuAff(id, idMenu) { var m = document.getElementById(idMenu); var item = m.getElementsByTagName('li'); var ssmenu = null; for (var i=0; i lastScrollTop && st > navbarHeight) { // Scroll Down $('#header').removeClass('nav-down').addClass('nav-up'); } else { // Scroll Up if (st + $(window).height() < $(document).height()) { $('#header').removeClass('nav-up').addClass('nav-down'); } } lastScrollTop = st; }; } var langSwitch = function(elt) { var _url = elt.attr('href').replace(/front\/preference.+/, 'ajax/switchlang.php'); $.ajax({ url: _url, type: 'GET', success: function(html) { $('#language_link') .html(html); $('#debugajax').remove(); } }); }; $(function() { if ($('html').hasClass('loginpage')) { return; } $('#menu.fullmenu li').on('mouseover', function() { var _id = $(this).data('id'); menuAff('menu' + _id, 'menu'); }); $("body").delegate('td','mouseover mouseleave', function(e) { var col = $(this).closest('tr').children().index($(this)); var tr = $(this).closest('tr'); if (!$(this).closest('tr').hasClass('noHover')) { if (e.type == 'mouseover') { tr.addClass("rowHover"); // If rowspan if (tr.has('td[rowspan]').length === 0) { tr.prevAll('tr:has(td[rowspan]):first').find('td[rowspan]').addClass("rowHover"); } $(this).closest('table').find('tr:not(.noHover) th:nth-child('+(col+1)+')').addClass("headHover"); } else { tr.removeClass("rowHover"); // remove rowspan tr.removeClass("rowHover").prevAll('tr:has(td[rowspan]):first').find('td[rowspan]').removeClass("rowHover"); $(this).closest('table').find('tr:not(.noHover) th:nth-child('+(col+1)+')').removeClass("headHover"); } } }); // prevent jquery ui dialog to keep focus $.ui.dialog.prototype._focusTabbable = function() {}; //quick lang switch $('#language_link > a').on('click', function(event) { event.preventDefault(); langSwitch($(this)); }); // ctrl+enter in form textareas (without tinymce) $(document).on('keydown', '#page form textarea', function(event) { if (event.ctrlKey && event.keyCode == 13) { submitparentForm($(this)); } }); // permits to have html in dialogs title $.widget("ui.dialog", $.extend({}, $.ui.dialog.prototype, { _title: function(title) { if (!this.options.title ) { title.html(" "); } else { title.html(this.options.title); } } })); }); /** * Trigger submit event for a parent form of passed input dom element * * @param Object input the dom or jquery object of input * @return bool */ var submitparentForm = function(input) { // find parent form var form = $(input).closest('form'); // find submit button(s) var submit = form.find('[type=submit]').filter('[name=add], [name=update]'); // trigger if only one submit button if (submit.length == 1) { return (submit.trigger('click') !== false); } return false; }; /** * Determines if data from drop is an image. * * @param {Blob} file The file * @return {boolean} True if image, False otherwise. */ var isImage = function(file) { var validimagetypes = ["image/gif", "image/jpeg","image/jpg", "image/png"]; if ($.inArray(file.type, validimagetypes) < 0) { return false; } else { return true; } }; /** * Return a png url reprensenting an extension * * @param {String} ext the extension * @return {string} an image html tag */ var getExtIcon = function(ext) { var url = CFG_GLPI.root_doc+'/pics/icones/'+ext+'-dist.png'; if (!urlExists(url)) { url = CFG_GLPI.root_doc+'/pics/icones/defaut-dist.png'; } return ''; }; /** * Check for existence of an url * * @param {String} url * @return {Bool} */ var urlExists = function(url) { var exist = false; $.ajax({ 'type': 'HEAD', 'url': url, 'async': false, 'success': function() { exist = true; } }); return exist; }; /** * Format a size to the last possible unit (o, Kio, Mio, etc) * * @param {integer} size * @return {string} The formated size */ var getSize = function (size) { var bytes = ['o', 'Kio', 'Mio', 'Gio', 'Tio']; var lastval = ''; bytes.some(function(val) { if (size > 1024) { size = size / 1024; } else { lastval = val; return true; } }); return Math.round(size * 100, 2) / 100 + lastval; }; /** * Convert a integer index into an excel like alpha index (A, B, ..., AA, AB, ...) * @since 9.3 * @param integer index the numeric index * @return string excel like string index */ var getBijectiveIndex = function(index) { var bij_str = ""; while (parseInt(index) > 0) { index--; bij_str = String.fromCharCode("A".charCodeAt(0) + ( index % 26)) + bij_str; index /= 26; } return bij_str; }; /** * Stop propagation and navigation default for the specified event */ var stopEvent = function(event) { event.preventDefault(); event.stopPropagation(); }; /** * Back to top implementation */ if ($('#backtotop').length) { var scrollTrigger = 100, // px backToTop = function () { var scrollTop = $(window).scrollTop(); if (scrollTop > scrollTrigger) { $('#backtotop').show('slow'); $('#see_debug').addClass('wbttop'); } else { $('#backtotop').hide(); $('#see_debug').removeClass('wbttop'); } }; backToTop(); $(window).on('scroll', function () { backToTop(); }); $('#backtotop').on('click', function (e) { e.preventDefault(); $('html,body').animate({ scrollTop: 0 }, 700); }); } /** * Returns element height, including margins */ function _eltRealSize(_elt) { var _s = 0; _s += _elt.outerHeight(); _s += parseFloat(_elt.css('margin-top').replace('px', '')); _s += parseFloat(_elt.css('margin-bottom').replace('px', '')); _s += parseFloat(_elt.css('padding-top').replace('px', '')); _s += parseFloat(_elt.css('padding-bottom').replace('px', '')); return _s; } var initMap = function(parent_elt, map_id, height) { // default parameters map_id = (typeof map_id !== 'undefined') ? map_id : 'map'; height = (typeof height !== 'undefined') ? height : '200px'; if (height == 'full') { //full height map var wheight = $(window).height(); var _oSize = 0; $('#header_top, #c_menu, #c_ssmenu2, #footer, .search_page').each(function(){ _oSize += _eltRealSize($(this)); }); _oSize += parseFloat($('#page').css('padding-top').replace('px', '')); _oSize += parseFloat($('#page').css('padding-bottom').replace('px', '')); _oSize += parseFloat($('#page').css('margin-top').replace('px', '')); _oSize += parseFloat($('#page').css('margin-bottom').replace('px', '')); var newHeight = Math.floor(wheight - _oSize); var minHeight = 300; if ( newHeight < minHeight ) { newHeight = minHeight; } height = newHeight + 'px'; } //add map, set a default arbitrary location parent_elt.append($('
')); var map = L.map(map_id, {fullscreenControl: true}).setView([43.6112422, 3.8767337], 6); //setup tiles and © messages L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); return map; }; var showMapForLocation = function(elt) { var _id = $(elt).data('fid'); var _items_id = $('#' + _id).val(); if (_items_id == 0) { return; } var _dialog = $('
'); _dialog.appendTo('body').dialog({ close: function() { $(this).dialog('destroy').remove(); } }); //add map, set a default arbitrary location var map_elt = initMap($('#location_map_dialog'), 'location_map'); map_elt.spin(true); $.ajax({ dataType: 'json', method: 'POST', url: CFG_GLPI.root_doc + '/ajax/getMapPoint.php', data: { itemtype: 'Location', items_id: $('#' + _id).val() } }).done(function(data) { if (data.success === false) { _dialog.dialog('close'); $('
' + data.message + '
').dialog({ close: function() { $(this).dialog('destroy').remove(); } }); } else { var _markers = []; var _marker = L.marker([data.lat, data.lng]); _markers.push(_marker); var _group = L.featureGroup(_markers).addTo(map_elt); map_elt.fitBounds( _group.getBounds(), { padding: [50, 50], maxZoom: 10 } ); } }).always(function() { //hide spinner map_elt.spin(false); }); }; var query = {}; function markMatch (text, term) { // Find where the match is var match = text.toUpperCase().indexOf(term.toUpperCase()); var _result = $(''); // If there is no match, move on if (match < 0) { _result.append(escapeMarkupText(text)); return _result.html(); } // Put in whatever text is before the match _result.html(escapeMarkupText(text.substring(0, match))); // Mark the match var _match = $(''); _match.html(escapeMarkupText(text.substring(match, match + term.length))); // Append the matching text _result.append(_match); // Put in whatever is after the match _result.append(escapeMarkupText(text.substring(match + term.length))); return _result.html(); } /** * Function that renders select2 results. */ var templateResult = function(result) { var _elt = $(''); _elt.attr('title', result.title); if (typeof query.term !== 'undefined' && typeof result.rendered_text !== 'undefined') { _elt.html(result.rendered_text); } else { if (!result.text) { return null; } var text = result.text; if (!result.id) { // If result has no id, then it is used as an optgroup and is not used for matches _elt.html(escapeMarkupText(text)); return _elt; } var _term = query.term || ''; var markup = markMatch(text, _term); if (result.level) { var a=''; var i=result.level; while (i>1) { a = a+'   '; i=i-1; } _elt.html(a+'»'+markup); } else { _elt.html(markup); } } return _elt; }; // delay function who reinit timer on each call var typewatch = (function(){ var timer = 0; return function(callback, ms){ clearTimeout (timer); timer = setTimeout(callback, ms); }; })(); /** * Function that renders select2 selections. */ var templateSelection = function (selection) { if (!("element" in selection)) { return selection.text; } // Data generated by ajax containing 'selection_text' if (Object.prototype.hasOwnProperty.call(selection, 'selection_text')) { return selection.selection_text; } // Data generated with optgroups if (selection.element.parentElement.nodeName == 'OPTGROUP') { return selection.element.parentElement.getAttribute('label') + ' - ' + selection.text; } // Default text return selection.text; }; /** * Returns given text without is diacritical marks. * * @param {string} text * * @return {string} */ var getTextWithoutDiacriticalMarks = function (text) { // Normalizing to NFD Unicode normal form decomposes combined graphemes // into the combination of simple ones. The "è" becomes "e + ̀`". text = text.normalize('NFD'); // The U+0300 -> U+036F range corresponds to diacritical chars. // They are removed to keep only chars without their diacritical mark. return text.replace(/[\u0300-\u036f]/g, ''); }; /** * Escape markup in text to prevent XSS. * * @param {string} text * * @return {string} */ var escapeMarkupText = function (text) { if (text.indexOf('>') !== -1 || text.indexOf('<') !== -1) { // escape text, if it contains chevrons (can already be escaped prior to this point :/) text = jQuery.fn.select2.defaults.defaults.escapeMarkup(text); } return text; }; /** * Updates an accessible progress bar title and foreground width. * @since 9.5.0 * @param progressid ID of the progress bar * @return void */ function updateProgress(progressid) { var progress = $("progress#progress"+progressid).first(); $("div[data-progressid='"+progressid+"']").each(function(i, item) { var j_item = $(item); var fg = j_item.find(".progress-fg").first(); var calcWidth = (progress.attr('value') / progress.attr('max')) * 100; fg.width(calcWidth+'%'); if (j_item.data('append-percent') === 1) { var new_title = (j_item.prop('title').replace(new RegExp("\\d*%$"), progress.attr('value')+'%')).trim(); progress.prop('title', new_title); j_item.prop('title', new_title); } }); } /** * Normalize altfield value of a MultiDatePicker instance. * * @param input_id id of the date input field * @param date_format dateFormat option used in MultiDatePicker instance * (i.e. 'dd-mm-yy', 'mm-dd-yy' or 'yy-mm-dd') * * @return void */ function normalizeMultiDateAltField(input_id, date_format) { var dates = $(input_id).val().split(', '); var alt_dates = []; for (var i = 0; i < dates.length; i++) { var date_obj = $.datepicker.parseDate(date_format, dates[i]); alt_dates.push($.datepicker.formatDate('yy-mm-dd', date_obj)); } $(input_id).val(alt_dates.join(', ')); } /** * Get RGB object from an hexadecimal color code * * @param {*} hex * @returns {Object} {r, g, b} */ function hexToRgb(hex) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } /** * Get luminance for a color * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef * * @param {Array} rgb [r, g, b] array * @returns {Number} */ function luminance(rgb) { var a = rgb.map(function (v) { v /= 255; return v <= 0.03928 ? v / 12.92 : Math.pow( (v + 0.055) / 1.055, 2.4 ); }); return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; } /** * Get contrast ratio between two colors * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef * * @param {Array} rgb1 [r, g, b] array * @param {Array} rgb2 [r, g, b] array * @returns {Number} */ function contrast(rgb1, rgb2) { return (luminance(rgb1) + 0.05) / (luminance(rgb2) + 0.05); } // fullscreen api function GoInFullscreen(element) { if (element.requestFullscreen) { element.requestFullscreen(); } else if (element.mozRequestFullScreen) { element.mozRequestFullScreen(); } else if (element.webkitRequestFullscreen) { element.webkitRequestFullscreen(); } else if (element.msRequestFullscreen) { element.msRequestFullscreen(); } } function GoOutFullscreen() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } } function getUuidV4() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } /** Track input changes and warn the user of unsaved changes if they try to navigate away */ window.glpiUnsavedFormChanges = false; $(document).ready(function() { // Forms must have the data-track-changes attribute set to true. // Form fields may have their data-track-changes attribute set to empty (false) to override the tracking on that input. $(document).on('input', 'form[data-track-changes="true"] input:not([data-track-changes=""]),' + 'form[data-track-changes="true"] textarea:not([data-track-changes="false"])', function() { window.glpiUnsavedFormChanges = true; }); $(document).on('change', 'form[data-track-changes="true"] select:not([data-track-changes=""])', function() { window.glpiUnsavedFormChanges = true; }); $(window).on('beforeunload', function(e) { if (window.glpiUnsavedFormChanges) { e.preventDefault(); // All supported browsers will show a localized message return ''; } }); $(document).on('submit', 'form', function() { window.glpiUnsavedFormChanges = false; }); }); function onTinyMCEChange(e) { var editor = $(e.target)[0]; if ($(editor.targetElm).data('trackChanges') !== false) { if ($(editor.formElement).data('trackChanges') === true) { window.glpiUnsavedFormChanges = true; } } } function relativeDate(str) { var s = ( +new Date() - Date.parse(str) ) / 1e3, m = s / 60, h = m / 60, d = h / 24, y = d / 365.242199, tmp; return (tmp = Math.round(s)) === 1 ? __('just now') : m < 1.01 ? '%s seconds ago'.replace('%s', tmp) : (tmp = Math.round(m)) === 1 ? __('a minute ago') : h < 1.01 ? '%s minutes ago'.replace('%s', tmp) : (tmp = Math.round(h)) === 1 ? __('an hour ago') : d < 1.01 ? '%s hours ago'.replace('%s', tmp) : (tmp = Math.round(d)) === 1 ? __('yesterday') : y < 1.01 ? '%s days ago'.replace('%s', tmp) : (tmp = Math.round(y)) === 1 ? __('a year ago') : '%s years ago'.replace('%s', tmp); }