waves/public/assets/g/mario/References/ItemsHoldr-0.2.1.ts
2025-04-09 17:11:14 -05:00

1398 lines
44 KiB
TypeScript

declare module ItemsHoldr {
/**
* A mapping of ItemValue values to triggered callbacks.
*/
export interface ITriggers {
[i: string]: Function;
[i: number]: Function;
}
/**
* A container of default values to pass to IItemValues, keyed by the
* IItemValue keys.m
*/
export interface IItemValueDefaults {
[i: string]: IItemValueSettings;
}
/**
* Settings to initialize a new instance of the IItemValue interface.
*/
export interface IItemValueSettings {
/**
* An initial value to store.
*/
value?: any;
/**
* A default initial value to store, if value isn't provided.
*/
valueDefault?: any;
/**
* Whether the value should be stored in the IItemHoldr's localStorage.
*/
storeLocally?: boolean;
/**
* A mapping of values to callbacks that should be triggered when value
* is equal to them.
*/
triggers?: ITriggers;
/**
* Whether an Element should be created and synced to the value.
*/
hasElement?: boolean;
/**
* An Element tag to use in creating the element, if hasElement is true.
*/
elementTag?: string;
/**
* A minimum value for the value to equal, if value is a number.
*/
minimum?: number;
/**
* A callback to call when the value reaches the minimum value.
*/
onMinimum?: Function;
/**
* A maximum value for the value to equal, if value is a number.
*/
maximum?: number;
/**
* A callback to call when the value reaches the maximum value.
*/
onMaximum?: Function;
/**
* A maximum number to modulo the value against, if value is a number.
*/
modularity?: number;
/**
* A callback to call when the value reaches modularity.
*/
onModular?: Function;
/**
* A Function to transform the value when it's being set.
*/
transformGet?: Function;
/**
* A Function to transform the value when it's being retrieved.
*/
transformSet?: Function;
}
/**
* Storage container for a single IItemsHoldr value. The value may have triggers
* assigned to value, modularity, and other triggers, as well as an HTML element.
*/
export interface IItemValue {
/**
* The container IItemsHoldr governing usage of this ItemsValue.
*/
ItemsHolder: IItemsHoldr;
/**
* The unique key identifying this ItemValue in the ItemsHoldr.
*/
key: string;
/**
* A default initial value to store, if value isn't provided.
*/
valueDefault: any;
/**
* Whether the value should be stored in the ItemHoldr's localStorage.
*/
storeLocally: boolean;
/**
* A mapping of values to callbacks that should be triggered when value
* is equal to them.
*/
triggers: ITriggers;
/**
* An HTML element whose second child's textContent is always set to that of the element.
*/
element: HTMLElement;
/**
* Whether an Element should be created and synced to the value.
*/
hasElement: boolean;
/**
* An Element tag to use in creating the element, if hasElement is true.
*/
elementTag: string;
/**
* A maximum value for the value to equal, if value is a number.
*/
maximum: number;
/**
* A callback to call when the value reaches the maximum value.
*/
onMaximum: Function;
/**
* A minimum value for the value to equal, if value is a number.
*/
minimum: number;
/**
* A callback to call when the value reaches the minimum value.
*/
onMinimum: Function;
/**
* A maximum number to modulo the value against, if value is a number.
*/
modularity: number;
/**
* A callback to call when the value reaches modularity.
*/
onModular: Function;
/**
* A Function to transform the value when it's being set.
*/
transformGet?: Function;
/**
* A Function to transform the value when it's being retrieved.
*/
transformSet?: Function;
/**
* @returns The value being stored, with a transformGet applied if one exists.
*/
getValue(): any;
/**
* Sets the value being stored, with a is a transformSet applied if one exists.
* Any attached triggers to the new value will be called.
*
* @param value The desired value to now store.
*/
setValue(value: any): void;
/**
* General update Function to be run whenever the internal value is changed.
* It runs all the trigger, modular, etc. checks, updates the HTML element
* if there is one, and updates localStorage if needed.
*/
update(): void;
/**
* Stores a ItemValue's value in localStorage under the prefix plus its key.
*
* @param overrideAutoSave Whether the policy on saving should be ignored
* so saving happens regardless. By default, false.
*/
updateLocalStorage(overrideAutoSave?: boolean): void;
}
/**
* Settings to initialize a new instance of the IItemsHoldr interface.
*/
export interface IItemsHoldrSettings {
/**
* Initial settings for IItemValues to store.
*/
values?: IItemValueDefaults;
/**
* Whether new items are allowed to be added (by default, true).
*/
allowNewItems?: boolean;
/**
* Whether values should be saved immediately upon being set.
*/
autoSave?: boolean;
/**
* Arguments to pass to triggered callback Functions.
*/
callbackArgs?: any[];
/**
* A localStorage object to use instead of the global localStorage.
*/
localStorage?: any;
/**
* A prefix to add before IItemsValue keys
*/
prefix?: string;
/**
* Default attributes for IItemValues.
*/
defaults?: IItemValueDefaults;
/**
* Any hardcoded changes to element content.
*/
displayChanges?: { [i: string]: string };
/**
* Whether an HTML container should be created to house the IItemValue elements.
*/
doMakeContainer?: boolean;
/**
* Arguments to pass to create the container, if not the default div and className.
*/
containersArguments?: [string, any][];
}
/**
* A versatile container to store and manipulate values in localStorage, and
* optionally keep an updated HTML container showing these values.
*/
export interface IItemsHoldr {
/**
* @returns The values contained within, keyed by their keys.
*/
getValues(): { [i: string]: IItemValue };
/**
* @returns Default attributes for values.
*/
getDefaults(): IItemValueDefaults;
/**
* @returns A reference to localStorage or a replacment object.
*/
getLocalStorage(): Storage;
/**
* @returns Whether this should save changes to localStorage automatically.
*/
getAutoSave(): boolean;
/**
* @returns The prefix to store thigns under in localStorage.
*/
getPrefix(): string;
/**
* @returns The container HTML element, if it exists.
*/
getContainer(): HTMLElement;
/**
* @returns createElement arguments for HTML containers, outside-to-inside.
*/
getContainersArguments(): [string, any][];
/**
* @returns Any hard-coded changes to element content.
*/
getDisplayChanges(): { [i: string]: string };
/**
* @returns Arguments to be passed to triggered event callbacks.
*/
getCallbackArgs(): any[];
/**
* @returns String keys for each of the stored IItemValues.
*/
getKeys(): string[];
/**
* @param key The key for a known value.
* @returns The known value of a key, assuming that key exists.
*/
getItem(key: string): any;
/**
* @param key The key for a known value.
* @returns The settings for that particular key.
*/
getObject(key: string): any;
/**
* @param key The key for a potentially known value.
* @returns Whether there is a value under that key.
*/
hasKey(key: string): boolean;
/**
* @returns A mapping of key names to the actual values of all objects being stored.
*/
exportItems(): any;
/**
* Adds a new key & value pair to by linking to a newly created ItemValue.
*
* @param key The key to reference by new ItemValue by.
* @param settings The settings for the new ItemValue.
* @returns The newly created ItemValue.
*/
addItem(key: string, settings: any): IItemValue;
/**
* Clears a value from the listing, and removes its element from the
* container (if they both exist).
*
* @param key The key of the element to remove.
*/
removeItem(key: string): void;
/**
* Completely clears all values from the ItemsHoldr, removing their
* elements from the container (if they both exist) as well.
*/
clear(): void;
/**
* Sets the value for the ItemValue under the given key, then updates the ItemValue
* (including the ItemValue's element and localStorage, if needed).
*
* @param key The key of the ItemValue.
* @param value The new value for the ItemValue.
*/
setItem(key: string, value: any): void;
/**
* Increases the value for the ItemValue under the given key, via addition for
* Numbers or concatenation for Strings.
*
* @param key The key of the ItemValue.
* @param amount The amount to increase by (by default, 1).
*/
increase(key: string, amount?: number | string): void;
/**
* Increases the value for the ItemValue under the given key, via addition for
* Numbers or concatenation for Strings.
*
* @param key The key of the ItemValue.
* @param amount The amount to increase by (by default, 1).
*/
decrease(key: string, amount?: number): void;
/**
* Toggles whether a value is true or false.
*
* @param key The key of the ItemValue.
*/
toggle(key: string): void;
/**
* Ensures a key exists in values. If it doesn't, and new values are
* allowed, it creates it; otherwise, it throws an Error.
*
* @param key
*/
checkExistence(key: string): void;
/**
* Manually saves an item's value to localStorage, ignoring the autoSave flag.
*
* @param key The key of the item to save.
*/
saveItem(key: string): void;
/**
* Manually saves all values to localStorage, ignoring the autoSave flag.
*/
saveAll(): void;
/**
* Hides the container Element by setting its visibility to hidden.
*/
hideContainer(): void;
/**
* Shows the container Element by setting its visibility to visible.
*/
displayContainer(): void;
/**
* Creates the container Element, which contains a child for each ItemValue that
* specifies hasElement to be true.
*
* @param containers An Array representing the Element to be created and the
* children between it and the contained ItemValues.
* Each contained Object has a String tag name as its
* first member, followed by any number of Objects to apply
* via createElement.
* @returns A newly created Element that can be used as a container.
*/
makeContainer(containers: [string, any][]): HTMLElement;
/**
* @returns Whether displayChanges has an entry for a particular value.
*/
hasDisplayChange(value: string): boolean;
/**
* @returns The displayChanges entry for a particular value.
*/
getDisplayChange(value: string): string;
/**
* Creates a new HTMLElement of the given type. For each Object given as
* arguments after, each member is proliferated onto the element.
*
* @param tag The type of the HTMLElement (by default, "div").
* @param args Any number of Objects to be proliferated onto the
* new HTMLElement.
* @returns A newly created HTMLElement of the given tag.
*/
createElement(tag?: string, ...args: any[]): HTMLElement;
/**
* Proliferates all members of the donor to the recipient recursively, as
* a deep copy.
*
* @param recipient An object receiving the donor's members.
* @param donor An object whose members are copied to recipient.
* @param noOverride If recipient properties may be overriden (by
* default, false).
* @returns The recipient, which should have the donor proliferated onto it.
*/
proliferate(recipient: any, donor: any, noOverride?: boolean): any;
/**
* Identical to proliferate, but tailored for HTML elements because many
* element attributes don't play nicely with JavaScript Array standards.
* Looking at you, HTMLCollection!
*
* @param recipient An HTMLElement receiving the donor's members.
* @param donor An object whose members are copied to recipient.
* @param noOverride If recipient properties may be overriden (by
* default, false).
* @returns The recipient, which should have the donor proliferated onto it.
*/
proliferateElement(recipient: any, donor: any, noOverride?: boolean): any;
}
}
module ItemsHoldr {
"use strict";
/**
* Storage container for a single ItemsHoldr value. The value may have triggers
* assigned to value, modularity, and other triggers, as well as an HTML element.
*/
export class ItemValue implements IItemValue {
/**
* The container ItemsHoldr governing usage of this ItemsValue.
*/
ItemsHolder: ItemsHoldr;
/**
* The unique key identifying this ItemValue in the ItemsHoldr.
*/
key: string;
/**
* A default initial value to store, if value isn't provided.
*/
valueDefault: any;
/**
* Whether the value should be stored in the ItemHoldr's localStorage.
*/
storeLocally: boolean;
/**
* A mapping of values to callbacks that should be triggered when value
* is equal to them.
*/
triggers: ITriggers;
/**
* An HTML element whose second child's textContent is always set to that of the element.
*/
element: HTMLElement;
/**
* Whether an Element should be created and synced to the value.
*/
hasElement: boolean;
/**
* An Element tag to use in creating the element, if hasElement is true.
*/
elementTag: string;
/**
* A minimum value for the value to equal, if value is a number.
*/
minimum: number;
/**
* A callback to call when the value reaches the minimum value.
*/
onMinimum: Function;
/**
* A maximum value for the value to equal, if value is a number.
*/
maximum: number;
/**
* A callback to call when the value reaches the maximum value.
*/
onMaximum: Function;
/**
* A maximum number to modulo the value against, if value is a number.
*/
modularity: number;
/**
* A callback to call when the value reaches modularity.
*/
onModular: Function;
/**
* A Function to transform the value when it's being set.
*/
transformGet: Function;
/**
* A Function to transform the value when it's being retrieved.
*/
transformSet: Function;
/**
* The value being stored.
*/
private value: any;
/**
* Creates a new ItemValue with the given key and settings. Defaults are given
* to the value via proliferate before the settings.
*
* @constructor
* @param ItemsHolder The container for this value.
* @param key The key to reference this new ItemValue by.
* @param settings Any optional custom settings.
*/
constructor(ItemsHolder: ItemsHoldr, key: string, settings: any = {}) {
this.ItemsHolder = ItemsHolder;
ItemsHolder.proliferate(this, ItemsHolder.getDefaults());
ItemsHolder.proliferate(this, settings);
this.key = key;
if (!this.hasOwnProperty("value")) {
this.value = this.valueDefault;
}
if (this.hasElement) {
this.element = ItemsHolder.createElement(this.elementTag || "div", {
className: ItemsHolder.getPrefix() + "_value " + key
});
this.element.appendChild(ItemsHolder.createElement("div", {
"textContent": key
}));
this.element.appendChild(ItemsHolder.createElement("div", {
"textContent": this.value
}));
}
if (this.storeLocally) {
// If there exists an old version of this property, get it
if (ItemsHolder.getLocalStorage().hasOwnProperty(ItemsHolder.getPrefix() + key)) {
this.value = this.retrieveLocalStorage();
} else {
// Otherwise save the new version to memory
this.updateLocalStorage();
}
}
}
/**
* @returns The value being stored, with a transformGet applied if one exists.
*/
getValue(): any {
if (this.transformGet) {
return this.transformGet(this.value);
}
return this.value;
}
/**
* Sets the value being stored, with a is a transformSet applied if one exists.
* Any attached triggers to the new value will be called.
*
* @param value The desired value to now store.
*/
setValue(value: any): void {
if (this.transformSet) {
this.value = this.transformSet(value);
} else {
this.value = value;
}
this.update();
}
/**
* General update Function to be run whenever the internal value is changed.
* It runs all the trigger, modular, etc. checks, updates the HTML element
* if there is one, and updates localStorage if needed.
*/
update(): void {
// Mins and maxes must be obeyed before any other considerations
if (this.hasOwnProperty("minimum") && Number(this.value) <= Number(this.minimum)) {
this.value = this.minimum;
if (this.onMinimum) {
this.onMinimum.apply(this, this.ItemsHolder.getCallbackArgs());
}
} else if (this.hasOwnProperty("maximum") && Number(this.value) <= Number(this.maximum)) {
this.value = this.maximum;
if (this.onMaximum) {
this.onMaximum.apply(this, this.ItemsHolder.getCallbackArgs());
}
}
if (this.modularity) {
this.checkModularity();
}
if (this.triggers) {
this.checkTriggers();
}
if (this.hasElement) {
this.updateElement();
}
if (this.storeLocally) {
this.updateLocalStorage();
}
}
/**
* Stores a ItemValue's value in localStorage under the prefix plus its key.
*
* @param {Boolean} [overrideAutoSave] Whether the policy on saving should
* be ignored (so saving happens
* regardless). By default, false.
*/
updateLocalStorage(overrideAutoSave?: boolean): void {
if (overrideAutoSave || this.ItemsHolder.getAutoSave()) {
this.ItemsHolder.getLocalStorage()[this.ItemsHolder.getPrefix() + this.key] = JSON.stringify(this.value);
}
}
/**
* Checks if the current value should trigger a callback, and if so calls it.
*/
private checkTriggers(): void {
if (this.triggers.hasOwnProperty(this.value)) {
this.triggers[this.value].apply(this, this.ItemsHolder.getCallbackArgs());
}
}
/**
* Checks if the current value is greater than the modularity (assuming
* modular is a non-zero Numbers), and if so, continuously reduces value and
* calls this.onModular.
*/
private checkModularity(): void {
if (this.value.constructor !== Number || !this.modularity) {
return;
}
while (this.value >= this.modularity) {
this.value = Math.max(0, this.value - this.modularity);
if (this.onModular) {
this.onModular.apply(this, this.ItemsHolder.getCallbackArgs());
}
}
}
/**
* Updates the ItemValue's element's second child to be the ItemValue's value.
*/
private updateElement(): void {
if (this.ItemsHolder.hasDisplayChange(this.value)) {
this.element.children[1].textContent = this.ItemsHolder.getDisplayChange(this.value);
} else {
this.element.children[1].textContent = this.value;
}
}
/**
* Retrieves a ItemValue's value from localStorage, making sure not to try to
* JSON.parse an undefined or null value.
*
* @returns {Mixed}
*/
private retrieveLocalStorage(): void {
var value: any = localStorage.getItem(this.ItemsHolder.getPrefix() + this.key);
if (value === "undefined") {
return undefined;
}
if (value.constructor !== String) {
return value;
}
return JSON.parse(value);
}
}
/**
* A versatile container to store and manipulate values in localStorage, and
* optionally keep an updated HTML container showing these values.
*/
export class ItemsHoldr implements IItemsHoldr {
/**
* The ItemValues being stored, keyed by name.
*/
private items: { [i: string]: ItemValue };
/**
* A listing of all the String keys for the stored items.
*/
private itemKeys: string[];
/**
* Default attributes for ItemValues.
*/
private defaults: IItemValueDefaults;
/**
* A reference to localStorage or a replacement object.
*/
private localStorage: Storage;
/**
* A prefix to store things under in localStorage.
*/
private prefix: string;
/**
* Whether new items are allowed to be created using setItem.
*/
private allowNewItems: boolean;
/**
* Whether this should save changes to localStorage automatically.
*/
private autoSave: boolean;
/**
* A container element containing children for each value's element.
*/
private container: HTMLElement;
/**
* An Array of elements as createElement arguments, outside-to-inside.
*/
private containersArguments: [string, any][];
/**
* Any hardcoded changes to element content, such as "INF" for Infinity.
*/
private displayChanges: { [i: string]: string };
/**
* Arguments to be passed to triggered callback Functions.
*/
private callbackArgs: any[];
/**
* Initializes a new instance of the ItemsHoldr class.
*
* @param settings Any optional custom settings.
*/
constructor(settings: IItemsHoldrSettings = {}) {
var key: string;
this.prefix = settings.prefix || "";
this.autoSave = settings.autoSave;
this.callbackArgs = settings.callbackArgs || [];
this.allowNewItems = settings.allowNewItems === undefined
? true : settings.allowNewItems;
if (settings.localStorage) {
this.localStorage = settings.localStorage;
} else if (typeof localStorage === "undefined") {
this.localStorage = this.createPlaceholderStorage();
} else {
this.localStorage = localStorage;
}
this.defaults = settings.defaults || {};
this.displayChanges = settings.displayChanges || {};
this.items = {};
if (settings.values) {
this.itemKeys = Object.keys(settings.values);
for (key in settings.values) {
if (settings.values.hasOwnProperty(key)) {
this.addItem(key, settings.values[key]);
}
}
} else {
this.itemKeys = [];
}
if (settings.doMakeContainer) {
this.containersArguments = settings.containersArguments || [
["div", {
"className": this.prefix + "_container"
}]
];
this.container = this.makeContainer(settings.containersArguments);
}
}
/* Simple gets
*/
/**
*
*/
key(index: number): string {
return this.itemKeys[index];
}
/**
* @returns The values contained within, keyed by their keys.
*/
getValues(): { [i: string]: IItemValue } {
return this.items;
}
/**
* @returns {Mixed} Default attributes for values.
*/
getDefaults(): any {
return this.defaults;
}
/**
* @returns A reference to localStorage or a replacment object.
*/
getLocalStorage(): Storage {
return this.localStorage;
}
/**
* @returns Whether this should save changes to localStorage automatically.
*/
getAutoSave(): boolean {
return this.autoSave;
}
/**
* @returns The prefix to store thigns under in localStorage.
*/
getPrefix(): string {
return this.prefix;
}
/**
* @returns The container HTML element, if it exists.
*/
getContainer(): HTMLElement {
return this.container;
}
/**
* @returns createElement arguments for HTML containers, outside-to-inside.
*/
getContainersArguments(): [string, any][] {
return this.containersArguments;
}
/**
* @returns Any hard-coded changes to element content.
*/
getDisplayChanges(): { [i: string]: string } {
return this.displayChanges;
}
/**
* @returns Arguments to be passed to triggered event callbacks.
*/
getCallbackArgs(): any[] {
return this.callbackArgs;
}
/* Retrieval
*/
/**
* @returns String keys for each of the stored ItemValues.
*/
getKeys(): string[] {
return Object.keys(this.items);
}
/**
* @param key The key for a known value.
* @returns The known value of a key, assuming that key exists.
*/
getItem(key: string): any {
this.checkExistence(key);
return this.items[key].getValue();
}
/**
* @param key The key for a known value.
* @returns The settings for that particular key.
*/
getObject(key: string): any {
return this.items[key];
}
/**
* @param key The key for a potentially known value.
* @returns Whether there is a value under that key.
*/
hasKey(key: string): boolean {
return this.items.hasOwnProperty(key);
}
/**
* @returns A mapping of key names to the actual values of all objects being stored.
*/
exportItems(): any {
var output: any = {},
i: string;
for (i in this.items) {
if (this.items.hasOwnProperty(i)) {
output[i] = this.items[i].getValue();
}
}
return output;
}
/* ItemValues
*/
/**
* Adds a new key & value pair to by linking to a newly created ItemValue.
*
* @param key The key to reference by new ItemValue by.
* @param settings The settings for the new ItemValue.
* @returns The newly created ItemValue.
*/
addItem(key: string, settings: any = {}): ItemValue {
this.items[key] = new ItemValue(this, key, settings);
this.itemKeys.push(key);
return this.items[key];
}
/**
* Clears a value from the listing, and removes its element from the
* container (if they both exist).
*
* @param key The key of the element to remove.
*/
removeItem(key: string): void {
if (!this.items.hasOwnProperty(key)) {
return;
}
if (this.container && this.items[key].hasElement) {
this.container.removeChild(this.items[key].element);
}
this.itemKeys.splice(this.itemKeys.indexOf(key), 1);
delete this.items[key];
}
/**
* Completely clears all values from the ItemsHoldr, removing their
* elements from the container (if they both exist) as well.
*/
clear(): void {
var i: string;
if (this.container) {
for (i in this.items) {
if (this.items[i].hasElement) {
this.container.removeChild(this.items[i].element);
}
}
}
this.items = {};
this.itemKeys = [];
}
/**
* Sets the value for the ItemValue under the given key, then updates the ItemValue
* (including the ItemValue's element and localStorage, if needed).
*
* @param key The key of the ItemValue.
* @param value The new value for the ItemValue.
*/
setItem(key: string, value: any): void {
this.checkExistence(key);
this.items[key].setValue(value);
}
/**
* Increases the value for the ItemValue under the given key, via addition for
* Numbers or concatenation for Strings.
*
* @param key The key of the ItemValue.
* @param amount The amount to increase by (by default, 1).
*/
increase(key: string, amount: number | string = 1): void {
this.checkExistence(key);
var value: any = this.items[key].getValue();
value += amount;
this.items[key].setValue(value);
}
/**
* Increases the value for the ItemValue under the given key, via addition for
* Numbers or concatenation for Strings.
*
* @param key The key of the ItemValue.
* @param amount The amount to increase by (by default, 1).
*/
decrease(key: string, amount: number = 1): void {
this.checkExistence(key);
var value: any = this.items[key].getValue();
value -= amount;
this.items[key].setValue(value);
}
/**
* Toggles whether a value is true or false.
*
* @param key The key of the ItemValue.
*/
toggle(key: string): void {
this.checkExistence(key);
var value: any = this.items[key].getValue();
value = value ? false : true;
this.items[key].setValue(value);
}
/**
* Ensures a key exists in values. If it doesn't, and new values are
* allowed, it creates it; otherwise, it throws an Error.
*
* @param key
*/
checkExistence(key: string): void {
if (!this.items.hasOwnProperty(key)) {
if (this.allowNewItems) {
this.addItem(key);
} else {
throw new Error("Unknown key given to ItemsHoldr: '" + key + "'.");
}
}
}
/**
* Manually saves an item's value to localStorage, ignoring the autoSave flag.
*
* @param key The key of the item to save.
*/
saveItem(key: string): void {
if (!this.items.hasOwnProperty(key)) {
throw new Error("Unknown key given to ItemsHoldr: '" + key + "'.");
}
this.items[key].updateLocalStorage(true);
}
/**
* Manually saves all values to localStorage, ignoring the autoSave flag.
*/
saveAll(): void {
var key: string;
for (key in this.items) {
if (this.items.hasOwnProperty(key)) {
this.items[key].updateLocalStorage(true);
}
}
}
/* HTML helpers
*/
/**
* Hides the container Element by setting its visibility to hidden.
*/
hideContainer(): void {
this.container.style.visibility = "hidden";
}
/**
* Shows the container Element by setting its visibility to visible.
*/
displayContainer(): void {
this.container.style.visibility = "visible";
}
/**
* Creates the container Element, which contains a child for each ItemValue that
* specifies hasElement to be true.
*
* @param containers An Array representing the Element to be created and the
* children between it and the contained ItemValues.
* Each contained Object has a String tag name as its
* first member, followed by any number of Objects to apply
* via createElement.
* @returns A newly created Element that can be used as a container.
*/
makeContainer(containers: [string, any][]): HTMLElement {
var output: HTMLElement = this.createElement.apply(this, containers[0]),
current: HTMLElement = output,
child: HTMLElement,
key: string,
i: number;
for (i = 1; i < containers.length; ++i) {
child = this.createElement.apply(this, containers[i]);
current.appendChild(child);
current = child;
}
for (key in this.items) {
if (this.items[key].hasElement) {
child.appendChild(this.items[key].element);
}
}
return output;
}
/**
* @returns Whether displayChanges has an entry for a particular value.
*/
hasDisplayChange(value: string): boolean {
return this.displayChanges.hasOwnProperty(value);
}
/**
* @returns The displayChanges entry for a particular value.
*/
getDisplayChange(value: string): string {
return this.displayChanges[value];
}
/* Utilities
*/
/**
* Creates a new HTMLElement of the given type. For each Object given as
* arguments after, each member is proliferated onto the element.
*
* @param tag The type of the HTMLElement (by default, "div").
* @param args Any number of Objects to be proliferated onto the
* new HTMLElement.
* @returns A newly created HTMLElement of the given tag.
*/
createElement(tag: string = "div", ...args: any[]): HTMLElement {
var element: HTMLElement = document.createElement(tag),
i: number;
// For each provided object, add those settings to the element
for (i = 0; i < args.length; i += 1) {
this.proliferateElement(element, args[i]);
}
return element;
}
/**
* Proliferates all members of the donor to the recipient recursively, as
* a deep copy.
*
* @param recipient An object receiving the donor's members.
* @param donor An object whose members are copied to recipient.
* @param noOverride If recipient properties may be overriden (by
* default, false).
* @returns The recipient, which should have the donor proliferated onto it.
*/
proliferate(recipient: any, donor: any, noOverride?: boolean): any {
var setting: any,
i: string;
// For each attribute of the donor:
for (i in donor) {
if (donor.hasOwnProperty(i)) {
// If noOverride, don't override already existing properties
if (noOverride && recipient.hasOwnProperty(i)) {
continue;
}
// If it's an object, recurse on a new version of it
setting = donor[i];
if (typeof setting === "object") {
if (!recipient.hasOwnProperty(i)) {
recipient[i] = new setting.constructor();
}
this.proliferate(recipient[i], setting, noOverride);
} else {
// Regular primitives are easy to copy otherwise
recipient[i] = setting;
}
}
}
return recipient;
}
/**
* Identical to proliferate, but tailored for HTML elements because many
* element attributes don't play nicely with JavaScript Array standards.
* Looking at you, HTMLCollection!
*
* @param recipient An HTMLElement receiving the donor's members.
* @param donor An object whose members are copied to recipient.
* @param noOverride If recipient properties may be overriden (by
* default, false).
* @returns The recipient, which should have the donor proliferated onto it.
*/
proliferateElement(recipient: any, donor: any, noOverride?: boolean): HTMLElement {
var setting: any,
i: string,
j: number;
// For each attribute of the donor:
for (i in donor) {
if (donor.hasOwnProperty(i)) {
// If noOverride, don't override already existing properties
if (noOverride && recipient.hasOwnProperty(i)) {
continue;
}
setting = donor[i];
// Special cases for HTML elements
switch (i) {
// Children: just append all of them directly
case "children":
if (typeof (setting) !== "undefined") {
for (j = 0; j < setting.length; j += 1) {
recipient.appendChild(setting[j]);
}
}
break;
// Style: proliferate (instead of making a new Object)
case "style":
this.proliferate(recipient[i], setting);
break;
// By default, use the normal proliferate logic
default:
// If it's an object, recurse on a new version of it
if (typeof setting === "object") {
if (!recipient.hasOwnProperty(i)) {
recipient[i] = new setting.constructor();
}
this.proliferate(recipient[i], setting, noOverride);
} else {
// Regular primitives are easy to copy otherwise
recipient[i] = setting;
}
break;
}
}
}
return recipient;
}
/**
* Creates an Object that can be used to create a new LocalStorage
* replacement, if the JavaScript environment doesn't have one.
*
* @returns {Object}
*/
private createPlaceholderStorage(): Storage {
var i: string,
output: any = {
"keys": [],
"getItem": function (key: string): any {
return this.localStorage[key];
},
"setItem": function (key: string, value: string): void {
this.localStorage[key] = value;
},
"clear": function (): void {
for (i in this) {
if (this.hasOwnProperty(i)) {
delete this[i];
}
}
},
"removeItem": function (key: string): void {
delete this[key];
},
"key": function (index: number): string {
return this.keys[index];
}
};
Object.defineProperties(output, {
"length": {
"get": function (): number {
return output.keys.length;
}
},
"remainingSpace": {
"get": function (): number {
return 9001; // Is there a way to calculate this?
}
}
});
return output;
}
}
}