UNPKG

@openui5/sap.ui.core

Version:

OpenUI5 Core Library sap.ui.core

298 lines (274 loc) 9.88 kB
/*! * OpenUI5 * (c) Copyright 2026 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ /* * IMPORTANT: This is a private module, its API must not be used and is subject to change. * Code other than the OpenUI5 libraries must not introduce dependencies to this module. */ sap.ui.define(["sap/base/assert"], function (assert) { "use strict"; /** * Default prefix to be used for a storage instance when no other prefix is provided * at construction time. * * @private */ var STATE_STORAGE_KEY_PREFIX = "state.key_"; /** * @class A Storage API for JavaScript. * * <b>Note:</b> The Web Storage API stores the data on the client. Therefore, you must not use * this API for confidential information. * * Provides a unified interface and methods to store data on the client using the * Web Storage API or a custom implementation. By default, data can be persisted inside * localStorage or sessionStorage. * * A typical intended usage of this API is the storage of a string representing the state of * a control. In this case, the data is stored in the browser session, and the methods to be * used are {@link #put} and {@link #get}. The method {@link #remove} can be used to delete * the previously saved state. * * The <code>Storage</code> class allows a simple scoping by prefixing the keys of all * <code>put/get/remove</code> operations with a fixed prefix given when constructing a * storage instance. By choosing unique prefixes, different instances can write/read/delete * data to the same underlying storage implementation without interfering with each other. * * For the sake of completeness, the method {@link #clear} is available. However, it does not * honor the scoping and therefore should only be called when a global erasing of data is * required. If only keys with certain prefix should be deleted, the method {@link #removeAll} * should be used. * * Besides creating an own storage instance, callers can use the static methods of the * <code>Storage</code> class to access a default session storage instance. All calls will use * the same scope (same prefix). * * @example * <pre> * // Default Storage * sap.ui.require(["sap/ui/util/Storage"], function(Storage) { * Storage.get("stored_data"); * }); * </pre> * * @example * <pre> * // Storage Instance * sap.ui.require(["sap/ui/util/Storage"], function(Storage) { * var oMyStorage = new Storage(Storage.Type.session, "my_prefix"); * oMyStorage.put("stored_data", "{ state: 'active' }"); * oMyStorage.get("stored_data"); * }); * </pre> * * @since 1.58 * @alias module:sap/ui/util/Storage * @param {module:sap/ui/util/Storage.Type | Storage} [vStorage=module:sap/ui/util/Storage.Type.session] * The type of native storage implementation that this <code>Storage</code> instance should * use internally. Alternatively, this can be a custom implementation of the * {@link https://developer.mozilla.org/en-US/docs/Web/API/Storage Storage Web API). * @param {string} [sStorageKeyPrefix='state.key_'] * The scope prefix to be used by this storage instance * @public * @borrows module:sap/ui/util/Storage#isSupported as isSupported * @borrows module:sap/ui/util/Storage#put as put * @borrows module:sap/ui/util/Storage#get as get * @borrows module:sap/ui/util/Storage#remove as remove * @borrows module:sap/ui/util/Storage#removeAll as removeAll * @borrows module:sap/ui/util/Storage#clear as clear * @borrows module:sap/ui/util/Storage#getType as getType */ var Storage = function (vStorage, sStorageKeyPrefix) { var sType = "unknown", sPrefix = (sStorageKeyPrefix || STATE_STORAGE_KEY_PREFIX) + "-", oStorageImpl; if (!vStorage || typeof (vStorage) === "string") { sType = vStorage || Storage.Type.session; try { oStorageImpl = window[sType + "Storage"]; // Test for QUOTA_EXCEEDED_ERR (Happens e.g. in mobile Safari when private browsing active) if (oStorageImpl) { var sTestKey = sPrefix + "___sapui5TEST___"; oStorageImpl.setItem(sTestKey, "1"); oStorageImpl.removeItem(sTestKey); } } catch (e) { oStorageImpl = null; } } else if (typeof (vStorage) === "object") { sType = vStorage.getType ? vStorage.getType() : "unknown"; oStorageImpl = vStorage; } /** * Helper function for function execution ignoring errors and checking for support. * * @param {function} fnToExecute * @returns {boolean} */ var hasExecuted = function (fnToExecute) { try { if (this.isSupported()) { fnToExecute(); return true; } } catch (e) { return false; } return false; }.bind(this); /** * Returns whether the given storage is supported. * * @returns {boolean} true if storage is supported, false otherwise (e.g. due to browser security settings) * @public */ this.isSupported = function () { //Possibility to define for custom storage return typeof (oStorageImpl.isSupported) == "function" ? oStorageImpl.isSupported() : true; }; /** * Stores the given value under the given key in the storage or updates the value * if the key already exists. * * This method supports the same types of values as <code>JSON.stringify</code>. * * @param {string} sKey * Key to store the given value under; will be prefixed with the prefix given when * constructing this <code>Storage</code> * @param {any} vValue * Value to store/update under the given key * @returns {boolean} * Whether the data was successfully stored * * @public */ this.put = function (sKey, vValue) { //precondition: non-empty sKey and available storage feature assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string"); return hasExecuted(function () { oStorageImpl.setItem(sPrefix + sKey, JSON.stringify(vValue)); }); }; /** * Retrieves the value for the given key or <code>null</code> if the key does not exist * in this storage. * * The returned value will be of a type that <code>JSON.parse</code> could return, too. * * @param {string} sKey * Key to retrieve the value for; will be prefixed with the prefix given when * constructing this <code>Storage</code> * @returns {any} * The key's value or <code>null</code> if the key does not exist in the storage. * @public */ this.get = function (sKey) { //precondition: non-empty sKey and available storage feature assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string"); var oData; hasExecuted(function () { oData = JSON.parse(oStorageImpl.getItem(sPrefix + sKey)); }); return oData !== undefined ? oData : null; }; /** * Removes the key and its value from storage, if the key exists. * * @param {string} sKey * Key to remove; will be prefixed with the prefix given when constructing this * <code>Storage</code> * @returns {boolean} * Whether the deletion succeeded; if the key didn't exists, the method also * reports a success * @public */ this.remove = function (sKey) { // precondition: non-empty sKey and available storage feature assert(typeof sKey === "string" && sKey.length > 0, "key must be a non-empty string"); return hasExecuted(function () { oStorageImpl.removeItem(sPrefix + sKey); }); }; /** * Removes all key/value pairs form the storage where the key starts with the given * <code>sKeyPrefix</code>. * * @param {string} [sKeyPrefix=""] * Key prefix for the keys/values to delete; will be additionally prefixed with the * prefix given when constructing this <code>Storage</code> * @returns {boolean} * Whether the deletion was successful; if no key matches the prefix, this is also * a success * @public */ this.removeAll = function (sKeyPrefix) { return hasExecuted(function () { var p = sPrefix + (sKeyPrefix || ""), keysToRemove = [], key, i; // first determine keys that should be removed for (i = 0; i < oStorageImpl.length; i++) { key = oStorageImpl.key(i); if (key && key.startsWith(p)) { keysToRemove.push(key); } } // then remove them (to avoid concurrent modification while looping over the keys) for (i = 0; i < keysToRemove.length; i++) { oStorageImpl.removeItem(keysToRemove[i]); } }); }; /** * Clears the whole storage (Independent of the current Storage instance!). * * <b>CAUTION</b> This method should be called only in very particular situations, * when a global erasing of data is required. Given that the method deletes * the data saved under any key, it should not be called when managing data * for specific controls. * * @returns {boolean} * Whether clearing the storage was successful * @public */ this.clear = function () { return hasExecuted(function () { oStorageImpl.clear(); }); }; /** * Returns the type of this storage. * * @returns {module:sap/ui/util/Storage.Type | string} * Type of this storage or "unknown" when the Storage was created with an * unknown type or implementation * @public */ this.getType = function () { return sType; }; }; /** * Enumeration of the storage types supported by {@link module:sap/ui/util/Storage}. * * @enum {string} * @public * @version 1.147.0 */ Storage.Type = { /** * Indicates usage of the browser's localStorage feature * @public */ local: "local", /** * Indicates usage of the browser's sessionStorage feature * @public */ session: "session" }; Object.assign(Storage, new Storage()); return Storage; });