/* $Id: common.js $ */ /** @file * Common JavaScript functions */ /* * Copyright (C) 2012-2019 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ /********************************************************************************************************************************* * Global Variables * *********************************************************************************************************************************/ /** Same as WuiDispatcherBase.ksParamRedirectTo. */ var g_ksParamRedirectTo = 'RedirectTo'; /** * Checks if the given value is a decimal integer value. * * @returns true if it is, false if it's isn't. * @param sValue The value to inspect. */ function isInteger(sValue) { if (typeof sValue != 'undefined') { var intRegex = /^\d+$/; if (intRegex.test(sValue)) { return true; } } return false; } /** * Checks if @a oMemmber is present in aoArray. * * @returns true/false. * @param aoArray The array to check. * @param oMember The member to check for. */ function isMemberOfArray(aoArray, oMember) { var i; for (i = 0; i < aoArray.length; i++) if (aoArray[i] == oMember) return true; return false; } /** * Removes the element with the specified ID. */ function removeHtmlNode(sContainerId) { var oElement = document.getElementById(sContainerId); if (oElement) { oElement.parentNode.removeChild(oElement); } } /** * Sets the value of the element with id @a sInputId to the keys of aoItems * (comma separated). */ function setElementValueToKeyList(sInputId, aoItems) { var sKey; var oElement = document.getElementById(sInputId); oElement.value = ''; for (sKey in aoItems) { if (oElement.value.length > 0) { oElement.value += ','; } oElement.value += sKey; } } /** * Get the Window.devicePixelRatio in a safe way. * * @returns Floating point ratio. 1.0 means it's a 1:1 ratio. */ function getDevicePixelRatio() { var fpRatio = 1.0; if (window.devicePixelRatio) { fpRatio = window.devicePixelRatio; if (fpRatio < 0.5 || fpRatio > 10.0) fpRatio = 1.0; } return fpRatio; } /** * Tries to figure out the DPI of the device in the X direction. * * @returns DPI on success, null on failure. */ function getDeviceXDotsPerInch() { if (window.deviceXDPI && window.deviceXDPI > 48 && window.deviceXDPI < 2048) { return window.deviceXDPI; } else if (window.devicePixelRatio && window.devicePixelRatio >= 0.5 && window.devicePixelRatio <= 10.0) { cDotsPerInch = Math.round(96 * window.devicePixelRatio); } else { cDotsPerInch = null; } return cDotsPerInch; } /** * Gets the width of the given element (downscaled). * * Useful when using the element to figure the size of a image * or similar. * * @returns Number of pixels. null if oElement is bad. * @param oElement The element (not ID). */ function getElementWidth(oElement) { if (oElement && oElement.offsetWidth) return oElement.offsetWidth; return null; } /** By element ID version of getElementWidth. */ function getElementWidthById(sElementId) { return getElementWidth(document.getElementById(sElementId)); } /** * Gets the real unscaled width of the given element. * * Useful when using the element to figure the size of a image * or similar. * * @returns Number of screen pixels. null if oElement is bad. * @param oElement The element (not ID). */ function getUnscaledElementWidth(oElement) { if (oElement && oElement.offsetWidth) return Math.round(oElement.offsetWidth * getDevicePixelRatio()); return null; } /** By element ID version of getUnscaledElementWidth. */ function getUnscaledElementWidthById(sElementId) { return getUnscaledElementWidth(document.getElementById(sElementId)); } /** * Gets the part of the URL needed for a RedirectTo parameter. * * @returns URL string. */ function getCurrentBrowerUrlPartForRedirectTo() { var sWhere = window.location.href; var offTmp; var offPathKeep; /* Find the end of that URL 'path' component. */ var offPathEnd = sWhere.indexOf('?'); if (offPathEnd < 0) offPathEnd = sWhere.indexOf('#'); if (offPathEnd < 0) offPathEnd = sWhere.length; /* Go backwards from the end of the and find the start of the last component. */ offPathKeep = sWhere.lastIndexOf("/", offPathEnd); offTmp = sWhere.lastIndexOf(":", offPathEnd); if (offPathKeep < offTmp) offPathKeep = offTmp; offTmp = sWhere.lastIndexOf("\\", offPathEnd); if (offPathKeep < offTmp) offPathKeep = offTmp; return sWhere.substring(offPathKeep + 1); } /** * Adds the given sorting options to the URL and reloads. * * This will preserve previous sorting columns except for those * given in @a aiColumns. * * @param sParam Sorting parameter. * @param aiColumns Array of sorting columns. */ function ahrefActionSortByColumns(sParam, aiColumns) { var sWhere = window.location.href; var offHash = sWhere.indexOf('#'); if (offHash < 0) offHash = sWhere.length; var offQm = sWhere.indexOf('?'); if (offQm > offHash) offQm = -1; var sNew = ''; if (offQm > 0) sNew = sWhere.substring(0, offQm); sNew += '?' + sParam + '=' + aiColumns[0]; var i; for (i = 1; i < aiColumns.length; i++) sNew += '&' + sParam + '=' + aiColumns[i]; if (offQm >= 0 && offQm + 1 < offHash) { var sArgs = '&' + sWhere.substring(offQm + 1, offHash); var off = 0; while (off < sArgs.length) { var offMatch = sArgs.indexOf('&' + sParam + '=', off); if (offMatch >= 0) { if (off < offMatch) sNew += sArgs.substring(off, offMatch); var offValue = offMatch + 1 + sParam.length + 1; offEnd = sArgs.indexOf('&', offValue); if (offEnd < offValue) offEnd = sArgs.length; var iColumn = parseInt(sArgs.substring(offValue, offEnd)); if (!isMemberOfArray(aiColumns, iColumn) && !isMemberOfArray(aiColumns, -iColumn)) sNew += sArgs.substring(offMatch, offEnd); off = offEnd; } else { sNew += sArgs.substring(off); break; } } } if (offHash < sWhere.length) sNew = sWhere.substr(offHash); window.location.href = sNew; } /** * Sets the value of an input field element (give by ID). * * @returns Returns success indicator (true/false). * @param sFieldId The field ID (required for updating). * @param sValue The field value. */ function setInputFieldValue(sFieldId, sValue) { var oInputElement = document.getElementById(sFieldId); if (oInputElement) { oInputElement.value = sValue; return true; } return false; } /** * Adds a hidden input field to a form. * * @returns The new input field element. * @param oFormElement The form to append it to. * @param sName The field name. * @param sValue The field value. * @param sFieldId The field ID (optional). */ function addHiddenInputFieldToForm(oFormElement, sName, sValue, sFieldId) { var oNew = document.createElement('input'); oNew.type = 'hidden'; oNew.name = sName; oNew.value = sValue; if (sFieldId) oNew.id = sFieldId; oFormElement.appendChild(oNew); return oNew; } /** By element ID version of addHiddenInputFieldToForm. */ function addHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId) { return addHiddenInputFieldToForm(document.getElementById(sFormId), sName, sValue, sFieldId); } /** * Adds or updates a hidden input field to/on a form. * * @returns The new input field element. * @param sFormId The ID of the form to amend. * @param sName The field name. * @param sValue The field value. * @param sFieldId The field ID (required for updating). */ function addUpdateHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId) { var oInputElement = null; if (sFieldId) { oInputElement = document.getElementById(sFieldId); } if (oInputElement) { oInputElement.name = sName; oInputElement.value = sValue; } else { oInputElement = addHiddenInputFieldToFormById(sFormId, sName, sValue, sFieldId); } return oInputElement; } /** * Adds a width and a dpi input to the given form element if possible to * determine the values. * * This is normally employed in an onlick hook, but then you must specify IDs or * the browser may end up adding it several times. * * @param sFormId The ID of the form to amend. * @param sWidthSrcId The ID of the element to calculate the width * value from. * @param sWidthName The name of the width value. * @param sDpiName The name of the dpi value. */ function addDynamicGraphInputs(sFormId, sWidthSrcId, sWidthName, sDpiName) { var cx = getUnscaledElementWidthById(sWidthSrcId); var cDotsPerInch = getDeviceXDotsPerInch(); if (cx) { addUpdateHiddenInputFieldToFormById(sFormId, sWidthName, cx, sFormId + '-' + sWidthName + '-id'); } if (cDotsPerInch) { addUpdateHiddenInputFieldToFormById(sFormId, sDpiName, cDotsPerInch, sFormId + '-' + sDpiName + '-id'); } } /** * Adds the RedirecTo field with the current URL to the form. * * This is a 'onsubmit' action. * * @returns Returns success indicator (true/false). * @param oForm The form being submitted. */ function addRedirectToInputFieldWithCurrentUrl(oForm) { /* Constant used here is duplicated in WuiDispatcherBase.ksParamRedirectTo */ return addHiddenInputFieldToForm(oForm, 'RedirectTo', getCurrentBrowerUrlPartForRedirectTo(), null); } /** * Adds the RedirecTo parameter to the href of the given anchor. * * This is a 'onclick' action. * * @returns Returns success indicator (true/false). * @param oAnchor The anchor element being clicked on. */ function addRedirectToAnchorHref(oAnchor) { var sRedirectToParam = g_ksParamRedirectTo + '=' + encodeURIComponent(getCurrentBrowerUrlPartForRedirectTo()); var sHref = oAnchor.href; if (sHref.indexOf(sRedirectToParam) < 0) { var sHash; var offHash = sHref.indexOf('#'); if (offHash >= 0) sHash = sHref.substring(offHash); else { sHash = ''; offHash = sHref.length; } sHref = sHref.substring(0, offHash) if (sHref.indexOf('?') >= 0) sHref += '&'; else sHref += '?'; sHref += sRedirectToParam; sHref += sHash; oAnchor.href = sHref; } return true; } /** * Clears one input element. * * @param oInput The input to clear. */ function resetInput(oInput) { switch (oInput.type) { case 'checkbox': case 'radio': oInput.checked = false; break; case 'text': oInput.value = 0; break; } } /** * Clears a form. * * @param sIdForm The ID of the form */ function clearForm(sIdForm) { var oForm = document.getElementById(sIdForm); if (oForm) { var aoInputs = oForm.getElementsByTagName('INPUT'); var i; for (i = 0; i < aoInputs.length; i++) resetInput(aoInputs[i]) /* HTML5 allows inputs outside