|
import observable from '@/helpers/observable' |
|
|
|
let instance = null |
|
|
|
class Store { |
|
#modules = null |
|
|
|
#observers = {} |
|
|
|
#observersMap = {} |
|
|
|
#listeners = {} |
|
|
|
/** |
|
* @return {null} |
|
*/ |
|
constructor () { |
|
if (!instance) { |
|
instance = this |
|
} |
|
|
|
this.#modules = {} |
|
|
|
return instance |
|
} |
|
|
|
get state () { |
|
return this.#modules |
|
} |
|
|
|
getModule (key) { |
|
if (!this.#modules[key]) { |
|
console.error(`Cannot get state for key ${key}`) |
|
return |
|
} |
|
|
|
return this.#modules[key] |
|
} |
|
|
|
registerModule ({ key, data }) { |
|
if (this.#modules[key]) { |
|
console.warn(`Cannot register state module ${key}. Module already exist`) |
|
return |
|
} |
|
|
|
this.#listeners[key] = () => { |
|
this.runObservers(key) |
|
} |
|
|
|
this.#modules[key] = observable( |
|
{ |
|
target: { |
|
data: { |
|
...data |
|
}, |
|
get: (id) => this.#modules[key].data[id] || null |
|
}, |
|
listener: this.#listeners[key] |
|
}) |
|
} |
|
|
|
deleteModule ({ key }) { |
|
if (this.#modules[key]) delete this.#modules[key] |
|
if (this.#listeners[key]) delete this.#listeners[key] |
|
} |
|
|
|
/* State Methods */ |
|
commit ({ key, data }) { |
|
if (!this.#modules[key]) { |
|
console.warn(`No Store module register for this key: ${key}`) |
|
return |
|
} |
|
|
|
this.#modules[key].data = { |
|
...this.#modules[key].data, |
|
...data |
|
} |
|
} |
|
|
|
clean (key) { |
|
this.#modules[key] = {} |
|
} |
|
|
|
delete (key) { |
|
if (this.#modules[key]) { |
|
delete this.#modules[key] |
|
} |
|
} |
|
|
|
/* Observable Methods */ |
|
runObservers (key) { |
|
console.log('runObservers', key) |
|
if (!this.#observers[key]) return |
|
Object.values(this.#observers[key]) |
|
.forEach(observer => { |
|
if (typeof observer === 'function') { |
|
observer() |
|
} |
|
}) |
|
} |
|
|
|
/** |
|
* Add a callback on state update |
|
* @param callback |
|
*/ |
|
observe ({ key, handler }) { |
|
if (!this.#observers[key]) { |
|
this.#observers[key] = {} |
|
} |
|
|
|
if (!handler || typeof handler !== 'function') { |
|
console.error('State observe callback must be a function') |
|
return |
|
} |
|
|
|
const id = Date.now() |
|
this.#observers[key] = { |
|
...this.#observers[key], |
|
[id]: handler |
|
} |
|
|
|
this.#observersMap[id] = [key] |
|
return id |
|
} |
|
|
|
/** |
|
* Remove callback on state update by id |
|
* @param id |
|
*/ |
|
unObserve (id) { |
|
if (!id) { |
|
console.error('State unObserve method needs an id') |
|
return |
|
} |
|
|
|
if (this.#observersMap[id] && this.#observers[this.#observersMap[id]]) { |
|
const key = this.#observersMap[id] |
|
console.log('deleteObserver', id) |
|
delete this.#observers[key][id] |
|
|
|
if (Object.values(this.#observers[key]).length === 0) { |
|
delete this.#observers[key] |
|
} |
|
} |
|
|
|
return null |
|
} |
|
} |
|
|
|
const state = new Store() |
|
|
|
export default state |