| /**
 * LocalStorage.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */
/**
 * This class will simulate LocalStorage on IE 7 and return the native version on modern browsers.
 * Storage is done using userData on IE 7 and a special serialization format. The format is designed
 * to be as small as possible by making sure that the keys and values doesn't need to be encoded. This
 * makes it possible to store for example HTML data.
 *
 * Storage format for userData:
 * <base 32 key length>,<key string>,<base 32 value length>,<value>,...
 *
 * For example this data key1=value1,key2=value2 would be:
 * 4,key1,6,value1,4,key2,6,value2
 *
 * @class tinymce.util.LocalStorage
 * @static
 * @version 4.0
 * @example
 * tinymce.util.LocalStorage.setItem('key', 'value');
 * var value = tinymce.util.LocalStorage.getItem('key');
 */
define(
  'tinymce.core.util.LocalStorage',
  [
    'global!document',
    'global!window'
  ],
  function (document, window) {
    var LocalStorage, storageElm, items, keys, userDataKey, hasOldIEDataSupport;
    // Check for native support
    try {
      if (window.localStorage) {
        return window.localStorage;
      }
    } catch (ex) {
      // Ignore
    }
    userDataKey = "tinymce";
    storageElm = document.documentElement;
    hasOldIEDataSupport = !!storageElm.addBehavior;
    if (hasOldIEDataSupport) {
      storageElm.addBehavior('#default#userData');
    }
    /**
     * Gets the keys names and updates LocalStorage.length property. Since IE7 doesn't have any getters/setters.
     */
    var updateKeys = function () {
      keys = [];
      for (var key in items) {
        keys.push(key);
      }
      LocalStorage.length = keys.length;
    };
    /**
     * Loads the userData string and parses it into the items structure.
     */
    var load = function () {
      var key, data, value, pos = 0;
      items = {};
      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
      if (!hasOldIEDataSupport) {
        return;
      }
      var next = function (end) {
        var value, nextPos;
        nextPos = end !== undefined ? pos + end : data.indexOf(',', pos);
        if (nextPos === -1 || nextPos > data.length) {
          return null;
        }
        value = data.substring(pos, nextPos);
        pos = nextPos + 1;
        return value;
      };
      storageElm.load(userDataKey);
      data = storageElm.getAttribute(userDataKey) || '';
      do {
        var offset = next();
        if (offset === null) {
          break;
        }
        key = next(parseInt(offset, 32) || 0);
        if (key !== null) {
          offset = next();
          if (offset === null) {
            break;
          }
          value = next(parseInt(offset, 32) || 0);
          if (key) {
            items[key] = value;
          }
        }
      } while (key !== null);
      updateKeys();
    };
    /**
     * Saves the items structure into a the userData format.
     */
    var save = function () {
      var value, data = '';
      // localStorage can be disabled on WebKit/Gecko so make a dummy storage
      if (!hasOldIEDataSupport) {
        return;
      }
      for (var key in items) {
        value = items[key];
        data += (data ? ',' : '') + key.length.toString(32) + ',' + key + ',' + value.length.toString(32) + ',' + value;
      }
      storageElm.setAttribute(userDataKey, data);
      try {
        storageElm.save(userDataKey);
      } catch (ex) {
        // Ignore disk full
      }
      updateKeys();
    };
    LocalStorage = {
      /**
       * Length of the number of items in storage.
       *
       * @property length
       * @type Number
       * @return {Number} Number of items in storage.
       */
      //length:0,
      /**
       * Returns the key name by index.
       *
       * @method key
       * @param {Number} index Index of key to return.
       * @return {String} Key value or null if it wasn't found.
       */
      key: function (index) {
        return keys[index];
      },
      /**
       * Returns the value if the specified key or null if it wasn't found.
       *
       * @method getItem
       * @param {String} key Key of item to retrieve.
       * @return {String} Value of the specified item or null if it wasn't found.
       */
      getItem: function (key) {
        return key in items ? items[key] : null;
      },
      /**
       * Sets the value of the specified item by it's key.
       *
       * @method setItem
       * @param {String} key Key of the item to set.
       * @param {String} value Value of the item to set.
       */
      setItem: function (key, value) {
        items[key] = "" + value;
        save();
      },
      /**
       * Removes the specified item by key.
       *
       * @method removeItem
       * @param {String} key Key of item to remove.
       */
      removeItem: function (key) {
        delete items[key];
        save();
      },
      /**
       * Removes all items.
       *
       * @method clear
       */
      clear: function () {
        items = {};
        save();
      }
    };
    load();
    return LocalStorage;
  }
);
 |