Source: src/utils/store.js

/**
 * This class provides a convenience wrapper around basic local storage support testing, saving and retrieving. 
 * <br>- Values are expected to be strings, return values will always be strings.
 * <br>- If local storage is not supported the data will be saved for the life of the `store` instance as a fallback.
 * <br>- See {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API}
 * @module store
 */

/**
 * Will be added as a prefix to local storage variables.
 * <br>- Use `store.setPrefix()` to set this variable before app initialises.
 * @type {string}
 * @readonly
 * @private
 */
let prefix = 'stm';
const STORAGE_ENABLED = true;

if(!STORAGE_ENABLED){
  console.log('WARNING: Local Storage is disabled');
}

let sessionData = {}; // Fallback just for this session

let _enabled = null;

/**
 * Will be true if local storage is supported / enabled on the current device.
 * @returns {boolean} enabled
 * @readonly
 */
export function isEnabled(){
  if (_enabled === true || _enabled === false){
    return _enabled;
  }
  _enabled = _localStorageAvailable(); // Retrieve device capability and save.
  return _enabled;
}

/**
 * Disable using storage even if supported.
 * <br>- To be called before `storymode.createApp()`.
 */
export function disable(){
  _enabled = false;
}


/**
 * Override the default storage prefix.
 * <br>- To be called before `storymode.createApp()`.
 * @param {string} prefix - Will be added as a prefix to local storage variables.
 */
export function setPrefix(_prefix){
  prefix = _prefix;
}

/**
 * Save a value in local storage.
 * @param {string} key - The storage key.
 * @param {string} val - The string value to set.
 * @returns {boolean} success - If false then data was saved to the `store` instance until the page is reloaded.
 */
export function save(key, val){  
  key = prefix + '.' + key;
  if (!isEnabled()){    
    sessionData[key] = val;
    return false;
  }
  localStorage.setItem(key, val);    
  return true;
}

/**
 * Retrieve a value from local storage.
 * @param {string} key - The storage key.
 * @returns {string|null} value - If data for the key is not found then will return null.
 */
export function load(key){
  key = prefix + '.' + key;
  if (!isEnabled()){    
    if (typeof sessionData[key] !== 'undefined'){
      return sessionData[key];
    }    
    return null;
  }  
  let data = localStorage.getItem(key);
  return data ? data : null;
}

/**
 * Removes a key from local storage.
 * @param {string} key - The storage key.
 */
export function remove(key){
  if (!isEnabled()){
    if (typeof sessionData[key] !== 'undefined'){
      sessionData[key] = null;
      delete sessionData[key];
    }
    return;
  }
  key = prefix + '.' + key;
  localStorage.removeItem(key);
}

/**
 * Removes all storage data from the store instance.
 */
export function removeAll(){
  if (!isEnabled()){
    sessionData = {}
    return null;
  }
  localStorage.clear();
}

/**
 * Check if the device supports local storage.
 * @private
 */
function _localStorageAvailable() {
    if (!STORAGE_ENABLED){
      return false;
    }
    let storage;    
    try {
        storage = window['localStorage'];
        let x = '__storage_test__';
        storage.setItem(x, x);
        storage.removeItem(x);
        return true;
    }
    catch(e) {
        return e instanceof DOMException && (
            // everything except Firefox
            e.code === 22 ||
            // Firefox
            e.code === 1014 ||
            // test name field too, because code might not be present
            // everything except Firefox
            e.name === 'QuotaExceededError' ||
            // Firefox
            e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
            // acknowledge QuotaExceededError only if there's something already stored
            (storage && storage.length !== 0);
    }
}