Common.Utils

Classes for your scripts

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/389765/1090053/CommonUtils.js

  1. // ==UserScript==
  2. // @name Common.Utils
  3. // @description Classes for your scripts
  4. // @author Anton Shevchuk
  5. // @license MIT License
  6. // @version 0.0.7
  7. // @match *://*/*
  8. // @grant none
  9. // @namespace https://greasyfork.org/users/227648
  10. // ==/UserScript==
  11.  
  12. /**
  13. * Object with wrapper with getters and setters
  14. */
  15. class Container {
  16. constructor() {
  17. this.container = {};
  18. }
  19. /**
  20. * @param {String[]} keys
  21. * @param {String} value
  22. */
  23. set(keys, value) {
  24. this._set(this.container, keys, value);
  25. }
  26. _set(elements, keys, value) {
  27. let key = keys.shift();
  28. if (typeof elements[key] === 'undefined') {
  29. elements[key] = {};
  30. }
  31. if (keys.length === 0) {
  32. elements[key] = value;
  33. } else {
  34. this._set(elements[key], keys, value);
  35. }
  36. }
  37. /**
  38. * @param {String} keys
  39. * @return {null|*}
  40. */
  41. get(...keys) {
  42. if (keys.length === 0) {
  43. return this.container
  44. }
  45. if (this.has(...keys)) {
  46. return this._get(this.container, ...keys);
  47. } else {
  48. return null;
  49. }
  50. }
  51. _get(elements, ...keys) {
  52. let key = keys.shift();
  53. if (typeof elements[key] === 'undefined') {
  54. return null;
  55. }
  56. if (keys.length === 0) {
  57. return elements[key];
  58. } else {
  59. return this._get(elements[key], ...keys);
  60. }
  61. }
  62. /**
  63. * @param {String} keys
  64. * @return {boolean}
  65. */
  66. has(...keys) {
  67. return this._has(this.container, ...keys);
  68. }
  69. _has(elements, ...keys) {
  70. let key = keys.shift();
  71. if (typeof elements[key] === 'undefined') {
  72. return false;
  73. }
  74. if (keys.length === 0) {
  75. return true;
  76. } else {
  77. return this._has(elements[key], ...keys);
  78. }
  79. }
  80. }
  81.  
  82. /**
  83. * Simple cache object with getters and setters
  84. */
  85. class SimpleCache extends Container {
  86. /**
  87. * @param {String} key
  88. * @param {*} value
  89. */
  90. set(key, value) {
  91. super.set([key], value);
  92. }
  93. }
  94.  
  95. /**
  96. * Settings object with localStorage as storage
  97. */
  98. class Settings extends Container {
  99. constructor(uid, def = {}) {
  100. super();
  101. this.uid = uid;
  102. this.default = def;
  103. this.load();
  104. }
  105. load() {
  106. let settings = localStorage.getItem(this.uid);
  107. if (settings) {
  108. settings = JSON.parse(settings);
  109. this.container = Tools.mergeDeep({}, this.default, settings);
  110. } else {
  111. this.container = this.default;
  112. }
  113. }
  114. /**
  115. * With jQuery:
  116. * $(window).on('beforeunload', () => SettingsInstance.save() );
  117. */
  118. save() {
  119. localStorage.setItem(this.uid, JSON.stringify(this.container));
  120. }
  121. }
  122.  
  123. /**
  124. * Static functions
  125. */
  126. class Tools {
  127. /**
  128. * Simple object check
  129. * @param {Object} item
  130. * @returns {Boolean}
  131. */
  132. static isObject(item) {
  133. return (item && typeof item === 'object' && !Array.isArray(item));
  134. }
  135.  
  136. /**
  137. * Deep merge objects
  138. * @param {Object} target
  139. * @param {Array} sources
  140. */
  141. static mergeDeep(target, ...sources) {
  142. if (!sources.length) return target;
  143. const source = sources.shift();
  144.  
  145. if (Tools.isObject(target) && Tools.isObject(source)) {
  146. for (const key in source) {
  147. if (Tools.isObject(source[key])) {
  148. if (!target[key]) Object.assign(target, { [key]: {} });
  149. Tools.mergeDeep(target[key], source[key]);
  150. } else {
  151. Object.assign(target, { [key]: source[key] });
  152. }
  153. }
  154. }
  155. return Tools.mergeDeep(target, ...sources);
  156. }
  157. }