Storage.js

  1. /* global platypus, window */
  2. import DataMap from './DataMap.js';
  3. import {UserData} from 'springroll';
  4. /**
  5. * This class is used to create the Platypus storage system accessible at `platypus.storage`. It uses Springroll UserData if available, with a fallback to local storage if not.
  6. *
  7. * @memberof platypus
  8. * @class Storage
  9. * @param {*} springroll
  10. * @param {*} options
  11. * @return {Data} Returns the new Storage object.
  12. */
  13. class Storage {
  14. constructor (springroll, options) {
  15. const
  16. gameId = options.name,
  17. storageKey = gameId + '-data',
  18. unconnectedData = window.localStorage.getItem(storageKey),
  19. keys = options.storageKeys || null,
  20. handleData = (resp) => {
  21. const
  22. data = resp && resp.data ? resp.data : resp;
  23. if (data) {
  24. for (const key in data) {
  25. if (data.hasOwnProperty(key)) {
  26. if (this.map.has(key)) {
  27. this.map.set(key, data[key]);
  28. } else {
  29. this.addKey(key, data[key]);
  30. }
  31. }
  32. }
  33. }
  34. };
  35. this.map = DataMap.setUp();
  36. /**
  37. * The storage key being used to store data.
  38. *
  39. * @property storageKey
  40. * @type String
  41. * @default options.name+'-data'
  42. */
  43. this.storageKey = storageKey;
  44. /**
  45. * Whether Springroll is connected to a hosting page.
  46. *
  47. * @property connected
  48. * @type Boolean
  49. * @default false
  50. */
  51. this.connected = false;
  52. if (keys) {
  53. for (let i = 0; i < keys.length; i++) {
  54. this.addKey(keys[i], null);
  55. }
  56. }
  57. try { // May throw if data is not parseable. If so, we'll just ignore it.
  58. handleData(JSON.parse(unconnectedData));
  59. } catch (e) {}
  60. springroll.container.on('connected', () => {
  61. this.connected = true;
  62. UserData.read(this.storageKey).then(handleData).catch((e) => {
  63. platypus.debug.warn('Storage: connected but received an error', e);
  64. });
  65. });
  66. }
  67. /**
  68. * Adds a storage key to the game's storage.
  69. *
  70. * @param {String} key The key to add.
  71. * @param {*} value The data to store at this defined key.
  72. */
  73. addKey (key, value) {
  74. this.map.set(key, value);
  75. Object.defineProperty(this, key, {
  76. get: function () {
  77. return this.map.get(key);
  78. },
  79. set: function (value) {
  80. this.map.set(key, value);
  81. this.save();
  82. },
  83. enumerable: true
  84. });
  85. }
  86. /**
  87. * Gets a value from storage for the provided storage key.
  88. *
  89. * @param {String} key The key for the data to return
  90. * @return {*}
  91. */
  92. get (key) {
  93. if (!this.map.has(key)) {
  94. this.addKey(key, null);
  95. }
  96. return this[key];
  97. }
  98. /**
  99. * Takes the current game storage and saves it to local storage or Springroll UserData
  100. *
  101. */
  102. save () {
  103. const save = this.map.toJSON();
  104. if (this.connected) {
  105. UserData.write(this.storageKey, save).catch((e) => {
  106. platypus.debug.warn('Storage: tried to save but received an error', e);
  107. });
  108. } else {
  109. window.localStorage.setItem(this.storageKey, JSON.stringify(save));
  110. }
  111. }
  112. /**
  113. * Updates a storage key's data. Creates the key if it does not exist.
  114. *
  115. * @param {String} key The key to update.
  116. * @param {*} value The data to store at this key.
  117. */
  118. set (key, value) {
  119. if (!this.map.has(key)) {
  120. this.addKey(key, value);
  121. this.save();
  122. } else {
  123. this[key] = value;
  124. }
  125. }
  126. };
  127. export default Storage;