|
import {action, createAtom, IAtom} from 'mobx'; |
|
|
|
/** |
|
* Class wrapper for a single cookie entry |
|
* emitting to and reading from a cookie storage. |
|
*/ |
|
export class Cookie<T> { |
|
private atom: IAtom; |
|
|
|
constructor ( |
|
public readonly name: string, |
|
public readonly options: CookieOptions = {}, |
|
private storage: ICookieMap |
|
) { |
|
this.atom = createAtom('cookie-' + name); |
|
} |
|
|
|
@action |
|
set (value: T) { |
|
if (value === undefined) { |
|
this.remove(); |
|
} else { |
|
this.storage.set(this.name, JSON.stringify(value), this.options); |
|
this.atom.reportChanged(); |
|
} |
|
} |
|
|
|
get (): T { |
|
this.atom.reportObserved(); |
|
const raw = this.storage.get(this.name); |
|
return raw && JSON.parse(raw); |
|
} |
|
|
|
@action |
|
remove () { |
|
this.storage.delete(this.name); |
|
this.atom.reportChanged(); |
|
} |
|
} |
|
|
|
/** |
|
* Standard cookie options |
|
*/ |
|
export type CookieOptions = Partial<{ |
|
expires: number, |
|
path: string, |
|
domain: string, |
|
secure: boolean |
|
}>; |
|
|
|
/** |
|
* The implementation of this interface should write to |
|
* the environments cookie storage,ie. document.cookie. |
|
*/ |
|
export interface ICookieMap { |
|
set (name: string, value: string, options: CookieOptions): void; |
|
get (name: string): string; |
|
delete (name: string): void; |
|
} |
|
|
|
const decoratorCookies = new Map<string, Cookie<any>>(); |
|
|
|
/** |
|
* Property decorator for automatically binding a property to a cookie of the same name |
|
*/ |
|
export function cookie (defaultValue?: any, options?: CookieOptions) { |
|
return function bake <T extends {map: ICookieMap}, V> ( |
|
targetClass: T, |
|
propertyKey: keyof T |
|
): void { |
|
function pull (targetInstance: T) { |
|
let cookie: Cookie<V> = decoratorCookies.get(propertyKey); |
|
if (!cookie) { |
|
cookie = new Cookie<V>(propertyKey, options, targetInstance.map); |
|
if (defaultValue !== undefined && cookie.get() === undefined) { |
|
cookie.set(defaultValue); |
|
} |
|
decoratorCookies.set(propertyKey, cookie); |
|
} |
|
return cookie; |
|
} |
|
|
|
Object.defineProperty(targetClass, propertyKey, { |
|
get: function () { // tslint:disable-line |
|
return pull(this).get(); |
|
}, |
|
set: function (value: V) { // tslint:disable-line |
|
pull(this).set(value); |
|
} |
|
}); |
|
}; |
|
} |