VisiOmatic web client

source

util/VUtil.js

/**
 #	This file part of:	VisiOmatic
 * @file Miscellaneous utilities

 * @copyright (c) 2014-2023 CNRS/IAP/CFHT/SorbonneU
 * @author Emmanuel Bertin <bertin@cfht.hawaii.edu>
 */
import {
	DomUtil,
	latLng
} from 'leaflet';

// Callback definitions
/**
 * Callback for Ajax queries.
 * @callback VUtil~queryCallback
 * @param {object} context
   Context (this).
 * @param {object} httpRequest
   XMLHttpRequest object.
 */

/**
 @namespace VUtil
 */
export const VUtil = {
	// Definitions for RegExp
	REG_PDEC: '(\\d+\\.\\d*)',
	REG_FLOAT: '([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?)',

	/**
	 * Do an AJAX query to a server.
	 * @param {string} url
	   Server URL.
	 * @param {string} purpose
	   Purpose of the query (for error messages).
	 * @param {VUtil~queryCallback} action
	   Callback function for successful queries.
	 * @param {object} context
	   Context (this).
	 * @param {number} timeout
	   Query timeout in seconds.
	 */
	requestURL: function (url, purpose, action, context, timeout) {
		var	httpRequest;

		if (window.XMLHttpRequest) { // Mozilla, Safari, ...
			httpRequest = new XMLHttpRequest();
		} else if (window.ActiveXObject) { // IE
			try {
				httpRequest = new ActiveXObject('Msxml2.XMLHTTP');
			}
			catch (e) {
				try {
					httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
				}
				catch (e) {}
			}
		}
		if (!httpRequest) {
			alert('Giving up: Cannot create an XMLHTTP instance for ' + purpose);
			return false;
		}
		if (timeout) {
			httpRequest.timeout = timeout * 1000;	// seconds -> milliseconds
			httpRequest.ontimeout = function () {
				alert('Time out while ' + purpose);
			};
		}
		httpRequest.open('GET', url);

		// Send Credentials
		if ((context) && (context.options.credentials)) {
			httpRequest.withCredentials = true;

		}

		// if request catalog need authenticate
		if ((context) && (context.options.authenticate === 'csrftoken')) {
			httpRequest.setRequestHeader('X-CSRFToken', this.getCookie('csrftoken'));
		}

		if ((action)) {
			httpRequest.onreadystatechange = function () {
				action(context, httpRequest);
			};
		}
		httpRequest.send();
	},

	/**
	 * Return a dictionary of keyword/value pairs from a URL string.
	 * @see {@link https://stevenbenner.com/2010/03/javascript-regex-trick-parse-a-query-string-into-an-object}
	 * @param {string} url
	   URL.
	 * @return {Object.<string, string>}
	   Dictionary of keyword/value pairs.
	 */
	parseURL: function (url) {
		const	dict = {};
		url.replace(
			new RegExp('([^?=&]+)(=([^&]*))?', 'g'),
			function ($0, $1, $2, $3) { dict[$1] = $3; }
		);
		return dict;
	},

	/**
	 * Return a URL with a new or updated keyword/value query string.
	 * @see {@link https://stackoverflow.com/a/5999118}
	 * @param {string} url
	   Input URL.
	 * @param {string} keyword
	   keyword.
	 * @param {number|string} value
	   value.
	 * @return {string}
	   Updated URL.
	 */
	updateURL: function (url, keyword, value) {
		const	re = new RegExp('([?&])' + keyword + '=.*?(&|$)', 'i'),
			separator = url.indexOf('?') !== -1 ? '&' : '?';

		return url.match(re) ? url.replace(re, '$1' + keyword + '=' + value +
			'$2') : url + separator + keyword + '=' + value;
	},

	/**
	 * Return the domain of a given URL.
	 * @see {@link https://stackoverflow.com/a/28054735}
	 * @param {string} url
	   Input URL.
	 * @return {string}
	   URL domain.
	 */
	checkDomain: function (url) {
		if (url.indexOf('//') === 0) {
			url = location.protocol + url;
		}
		return url.toLowerCase().replace(/([a-z])?:\/\//, '$1').split('/')[0];
	},

	/**
	 * Check if a given URL is external.
	 * @see {@link https://stackoverflow.com/a/28054735}
	 * @param {string} url
	   Input URL.
	 * @return {boolean}
	   `true` if the input URL is external, `false` otherwise.
	 */
	isExternal: function (url) {
		return ((url.indexOf(':') > -1 || url.indexOf('//') > -1) &&
			this.checkDomain(location.href) !== this.checkDomain(url));
	},

	/**
	 * Return the value of the cookie with the given name.
	 * @see {@link https://www.w3schools.com/js/js_cookies.asp}
	 * @param {string} cname
	   Cookie name.
	 * @return {string}
	   Cookie string.
	 */
	getCookie: function (cname) {
		const	name = cname + '=',
			ca = document.cookie.split(';');

		for (var i = 0; i < ca.length; i++) {
		    var c = ca[i];
			while (c.charAt(0) === ' ') {
				c = c.substring(1);
			}
			if (c.indexOf(name) === 0) {
				return c.substring(name.length, c.length);
			}
		}
		return '';
	},

	/**
	 * Copy the input string to the clipboard. 
	 * @see {@link https://stackoverflow.com/a/33928558}
	 * @param {string} text
	   Input string.
	 * @return {boolean}
	  `false` if copy failed.
	 */
	copyToClipboard: function (text) {
		if (document.queryCommandSupported &&
			document.queryCommandSupported('copy')) {
			const	textarea = document.createElement('textarea');
			textarea.textContent = text;
			// Prevent scrolling to bottom of page in MS Edge.
			textarea.style.position = 'fixed';
			document.body.appendChild(textarea);
			textarea.select();
			try {
				// Security exception may be thrown by some browsers.
				return document.execCommand('copy');
			} catch (ex) {
				console.warn('Copy to clipboard failed.', ex);
				return false;
			} finally {
				document.body.removeChild(textarea);
			}
		}
	},

	/**
	 * Add a short (<400ms) "flash" animation to an element.
	 * @param {object} elem
	   Element to be "flashed".
	 */
	flashElement: function (elem) {
		DomUtil.addClass(elem, 'leaflet-control-flash');
		setTimeout(function () {
			DomUtil.removeClass(elem, 'leaflet-control-flash');
		}, 400);

	},

	/**
	 * Read the value of a FITS header keyword.
	 * @param {string} keyword
	   Keyword.
	 * @param {string} str
	   Input string.
	 * @return {?string}
	   Keyword value string, or `null` if keyword could not be matched.
	 */
	readFITSKey: function (keyword, str) {
		const	key = keyword.trim().toUpperCase().substr(0, 8),
			nspace = 8 - key.length,
			keyreg = new RegExp(key + (nspace > 0 ? '\\ {' + nspace.toString() + '}' : '') +
			 '=\\ *(?:\'((?:\\ *[^\'\\ ]+)*)\\ *\'|([-+]?[0-9]*\\.?[0-9]+(?:[eE][-+]?[0-9]+)?))'),
			match = keyreg.exec(str);
		if (!match) {
			return null;
		} else if (match[1]) {
			return match[1];
		} else {
			return match[2];
		}
	}

};