diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 7a2c363..4fdc9d0 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -22,6 +22,7 @@ import { CreateBlockComponent } from './components/modal/modals/create-block/cre
import { RemoveBlockComponent } from './components/modal/modals/remove-block/remove-block.component';
import { ToggleComponent } from './components/shared/toggle/toggle.component';
import { TasksComponent } from './components/pages/page/tower/tasks/tasks.component';
+import { ColorPipe } from './pipes/color.pipe';
@NgModule({
declarations: [
@@ -41,7 +42,8 @@ import { TasksComponent } from './components/pages/page/tower/tasks/tasks.compon
CreateBlockComponent,
RemoveBlockComponent,
ToggleComponent,
- TasksComponent
+ TasksComponent,
+ ColorPipe
],
imports: [BrowserModule, AppRoutingModule, FormsModule, BrowserAnimationsModule, DragDropModule],
providers: [],
diff --git a/src/app/components/modal/modals/create-block/create-block.component.html b/src/app/components/modal/modals/create-block/create-block.component.html
index ac8762f..cf5a62b 100644
--- a/src/app/components/modal/modals/create-block/create-block.component.html
+++ b/src/app/components/modal/modals/create-block/create-block.component.html
@@ -24,7 +24,7 @@
diff --git a/src/app/components/modal/modals/create-block/create-block.component.ts b/src/app/components/modal/modals/create-block/create-block.component.ts
index bbf3d84..5f9fed9 100644
--- a/src/app/components/modal/modals/create-block/create-block.component.ts
+++ b/src/app/components/modal/modals/create-block/create-block.component.ts
@@ -9,7 +9,7 @@ import { ModalService } from '../../../../services/modal.service';
export class CreateBlockComponent {
selected: string;
description: string = null;
- isDone: boolean;
+ isDone: boolean = !this.modalService.active.input.isTask;
constructor(public modalService: ModalService) {}
diff --git a/src/app/components/modal/modals/edit-block/edit-block.component.html b/src/app/components/modal/modals/edit-block/edit-block.component.html
index 265fb8f..8e967c6 100644
--- a/src/app/components/modal/modals/edit-block/edit-block.component.html
+++ b/src/app/components/modal/modals/edit-block/edit-block.component.html
@@ -8,7 +8,7 @@
You are trying to remove
- {{
+ {{
modalService.active.input.name ? modalService.active.input.name : 'an unnamed tower'
}}.
diff --git a/src/app/components/pages/page/tower/block/block.component.html b/src/app/components/pages/page/tower/block/block.component.html
index 8b984b3..59c0d82 100644
--- a/src/app/components/pages/page/tower/block/block.component.html
+++ b/src/app/components/pages/page/tower/block/block.component.html
@@ -1 +1 @@
-
+
diff --git a/src/app/components/pages/page/tower/block/block.component.ts b/src/app/components/pages/page/tower/block/block.component.ts
index 2aae178..b539ec1 100644
--- a/src/app/components/pages/page/tower/block/block.component.ts
+++ b/src/app/components/pages/page/tower/block/block.component.ts
@@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core';
import { Block } from '../../../../../model/block';
import { ModalService } from '../../../../../services/modal.service';
-import { Tower } from '../../../../../model/tower';
+import { ColoredBlock, Tower } from '../../../../../model/tower';
@Component({
selector: 'app-block',
@@ -9,7 +9,7 @@ import { Tower } from '../../../../../model/tower';
styleUrls: ['./block.component.scss']
})
export class BlockComponent {
- @Input() block: Block;
+ @Input() block: ColoredBlock;
@Input() tower: Tower;
constructor(private modalService: ModalService) {}
@@ -22,9 +22,12 @@ export class BlockComponent {
description: this.block.description,
isDone: this.block.isDone
});
- this.block.tag = selected;
- this.block.description = description;
- this.block.isDone = isDone;
+ console.log(description);
+ this.block.changeProperties({
+ tag: selected,
+ description,
+ isDone
+ });
} catch {
// pass
}
diff --git a/src/app/components/pages/page/tower/tasks/tasks.component.html b/src/app/components/pages/page/tower/tasks/tasks.component.html
index 7712a63..afe2543 100644
--- a/src/app/components/pages/page/tower/tasks/tasks.component.html
+++ b/src/app/components/pages/page/tower/tasks/tasks.component.html
@@ -6,8 +6,8 @@
{{ tasks.length == 0 ? '' : tasks.length == 1 ? 'task' : 'tasks' }}
-
diff --git a/src/app/components/pages/page/tower/tasks/tasks.component.ts b/src/app/components/pages/page/tower/tasks/tasks.component.ts
index 39b845f..17eb6e8 100644
--- a/src/app/components/pages/page/tower/tasks/tasks.component.ts
+++ b/src/app/components/pages/page/tower/tasks/tasks.component.ts
@@ -3,8 +3,8 @@ import { Block } from '../../../../../model/block';
import { Tower } from '../../../../../model/tower';
import { ModalService } from '../../../../../services/modal.service';
import { CancelService } from '../../../../../services/cancel.service';
-import { toHslString } from '../../../../../utils/color';
-import { IColor } from '../../../../../interfaces/persistance/color';
+import { IColor } from '../../../../../interfaces/color';
+import { IBlock } from '../../../../../interfaces/persistance/block';
@Component({
selector: 'app-tasks',
@@ -12,8 +12,6 @@ import { IColor } from '../../../../../interfaces/persistance/color';
styleUrls: ['./tasks.component.scss']
})
export class TasksComponent implements OnInit {
- readonly toHslString = toHslString;
-
@Input() tasks: Array
;
@Input() tower: Tower;
@@ -48,12 +46,16 @@ export class TasksComponent implements OnInit {
isDone: block.isDone
});
- block.tag = selected;
- block.description = description;
+ const change: Partial = {
+ tag: selected,
+ description,
+ isDone
+ };
if (!block.isDone && isDone) {
- block.created = new Date();
+ change.created = new Date();
}
- block.isDone = isDone;
+
+ block.changeProperties(change);
} catch {
// pass
}
diff --git a/src/app/components/pages/page/tower/tower.component.html b/src/app/components/pages/page/tower/tower.component.html
index 1a6f196..de6bcaf 100644
--- a/src/app/components/pages/page/tower/tower.component.html
+++ b/src/app/components/pages/page/tower/tower.component.html
@@ -18,7 +18,7 @@
id="tower-name"
type="text"
placeholder="name…"
- [(ngModel)]="tower.name"
- [ngStyle]="{ color: toHslString(tower?.baseColor) }"
+ [(ngModel)]="towerName"
+ [ngStyle]="{ color: tower?.baseColor | color }"
/>
diff --git a/src/app/components/pages/page/tower/tower.component.ts b/src/app/components/pages/page/tower/tower.component.ts
index c3400ce..0f463c2 100644
--- a/src/app/components/pages/page/tower/tower.component.ts
+++ b/src/app/components/pages/page/tower/tower.component.ts
@@ -1,9 +1,6 @@
import { Component, Input } from '@angular/core';
-import { Tower } from '../../../../model/tower';
+import { ColoredBlock, Tower } from '../../../../model/tower';
import { ModalService } from '../../../../services/modal.service';
-import { Block } from '../../../../model/block';
-import { IColor } from '../../../../interfaces/persistance/color';
-import { toHslString } from '../../../../utils/color';
@Component({
selector: 'app-tower',
@@ -11,7 +8,13 @@ import { toHslString } from '../../../../utils/color';
styleUrls: ['./tower.component.scss']
})
export class TowerComponent {
- readonly toHslString = toHslString;
+ get towerName(): string {
+ return this.tower.name;
+ }
+
+ set towerName(value: string) {
+ this.tower.changeName(value);
+ }
@Input() set dateRange(value: { from: Date; to: Date }) {
if (this.dateRange !== undefined && this.dateRange.from === value.from && this.dateRange.to === value.to) {
@@ -26,13 +29,13 @@ export class TowerComponent {
public constructor(private modalService: ModalService) {}
- get drawableBlocks(): Array {
+ get drawableBlocks(): Array {
return this.tower.coloredBlocks.filter(
block => this.dateRange.from <= block.created && block.created <= this.dateRange.to && block.isDone
);
}
- get tasks(): Array {
+ get tasks(): Array {
return this.tower.coloredBlocks.filter(
block => this.dateRange.from <= block.created && block.created <= this.dateRange.to && !block.isDone
);
diff --git a/src/app/interfaces/color.ts b/src/app/interfaces/color.ts
new file mode 100644
index 0000000..a414a2a
--- /dev/null
+++ b/src/app/interfaces/color.ts
@@ -0,0 +1,5 @@
+export interface IColor {
+ h: number;
+ s: number;
+ l: number;
+}
diff --git a/src/app/interfaces/persistance/block.ts b/src/app/interfaces/persistance/block.ts
index 75be455..5021ea3 100644
--- a/src/app/interfaces/persistance/block.ts
+++ b/src/app/interfaces/persistance/block.ts
@@ -1,7 +1,4 @@
-import { Typed } from './typed';
-
-export interface IBlock extends Typed {
- type: 'Block';
+export interface IBlock {
created: Date;
tag: string;
isDone: boolean;
diff --git a/src/app/interfaces/persistance/color.ts b/src/app/interfaces/persistance/color.ts
deleted file mode 100644
index 1a49186..0000000
--- a/src/app/interfaces/persistance/color.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Typed } from './typed';
-
-export interface IColor extends Typed {
- type: 'Color';
- h: number;
- s: number;
- l: number;
-}
diff --git a/src/app/interfaces/persistance/page.ts b/src/app/interfaces/persistance/page.ts
index ba8ed10..43dd10a 100644
--- a/src/app/interfaces/persistance/page.ts
+++ b/src/app/interfaces/persistance/page.ts
@@ -1,8 +1,6 @@
import { ITower } from './tower';
-import { Typed } from './typed';
-export interface IPage extends Typed {
- type: 'Page';
+export interface IPage {
name: string;
towers: ITower[];
diff --git a/src/app/interfaces/persistance/tower.ts b/src/app/interfaces/persistance/tower.ts
index 352a674..4776161 100644
--- a/src/app/interfaces/persistance/tower.ts
+++ b/src/app/interfaces/persistance/tower.ts
@@ -1,9 +1,7 @@
import { IBlock } from './block';
-import { IColor } from './color';
-import { Typed } from './typed';
+import { IColor } from '../color';
-export interface ITower extends Typed {
- type: 'Tower';
+export interface ITower {
name: string;
blocks: IBlock[];
baseColor: IColor;
diff --git a/src/app/interfaces/persistance/typed.ts b/src/app/interfaces/persistance/typed.ts
deleted file mode 100644
index 7d34e2e..0000000
--- a/src/app/interfaces/persistance/typed.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export interface Typed {
- type: string;
-}
diff --git a/src/app/interfaces/vector.ts b/src/app/interfaces/vector.ts
deleted file mode 100644
index 332d2bf..0000000
--- a/src/app/interfaces/vector.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export interface Vector {
- x: number;
- y: number;
-}
diff --git a/src/app/model/block.ts b/src/app/model/block.ts
index 06fd0f0..cf75711 100644
--- a/src/app/model/block.ts
+++ b/src/app/model/block.ts
@@ -1,20 +1,30 @@
import { Serializable } from './serializable';
import { IBlock } from '../interfaces/persistance/block';
-import { Node } from '../storage/node';
+import { Node } from '../store/node';
export class Block extends Serializable implements IBlock {
constructor(parent: Node, props: IBlock) {
super(parent, props);
+ this.onAfterClone();
+ }
+ protected onAfterClone(): void {
if (this.created.constructor.name !== 'Date') {
this.created = new Date(this.created);
}
+
+ // TODO: remove.
+ if (this.isDone === null || this.isDone === undefined) {
+ this.isDone = false;
+ }
+ }
+
+ changeProperties(values: Partial) {
+ this.changeKeys(values);
}
- // Only here to prevent ts warnings.
- type: 'Block';
created: Date;
isDone: boolean;
- description: string;
- tag: string;
+ readonly description: string;
+ readonly tag: string;
}
diff --git a/src/app/model/page.ts b/src/app/model/page.ts
index dd9424d..bad43c3 100644
--- a/src/app/model/page.ts
+++ b/src/app/model/page.ts
@@ -1,21 +1,19 @@
import { Serializable } from './serializable';
import { IPage } from '../interfaces/persistance/page';
import { Tower } from './tower';
-import { Node } from '../storage/node';
+import { Node } from '../store/node';
export class Page extends Serializable implements IPage {
constructor(parent: Node, props: IPage) {
super(parent, props);
}
- // Only here to prevent ts warnings.
- name: string;
+ readonly name: string;
get towers(): Array {
return this.children as Array;
}
- type: 'Page';
- userData: {
+ readonly userData: {
hideCreateTowerButton: boolean;
defaultDateRange: {
from: Date;
@@ -38,10 +36,14 @@ export class Page extends Serializable implements IPage {
return;
}
- this.map(page => {
- const tower = page.towers[previousIndex];
- page.towers.splice(previousIndex, 1);
- page.towers.splice(currentIndex, 0, tower);
+ const towers = [...this.towers];
+ const tower = towers[previousIndex];
+ towers.splice(previousIndex, 1);
+ towers.splice(currentIndex, 0, tower);
+
+ this.changeValue({
+ oldValue: this.towers,
+ newValue: towers
});
}
@@ -52,10 +54,9 @@ export class Page extends Serializable implements IPage {
} while (30 <= hue && hue <= 200);
new Tower(this, {
- type: 'Tower',
name,
blocks: [],
- baseColor: { h: hue, s: 100, l: 50, type: 'Color' }
+ baseColor: { h: hue, s: 100, l: 50 }
});
}
diff --git a/src/app/model/serializable.ts b/src/app/model/serializable.ts
index 36f1967..41f0e2b 100644
--- a/src/app/model/serializable.ts
+++ b/src/app/model/serializable.ts
@@ -1,8 +1,7 @@
-import { Cloneable } from '../storage/cloneable';
-import { Node } from '../storage/node';
+import { Cloneable } from '../store/cloneable';
+import { Node } from '../store/node';
export class Serializable extends Cloneable {
- type: string;
private static propertyList: any = {};
static childrenMap: {
[type: string]: {
@@ -11,7 +10,11 @@ export class Serializable extends Cloneable {
};
};
- constructor(parent: Node, properties: any) {
+ protected onAfterClone(): void {
+ // pass
+ }
+
+ protected constructor(parent: Node, properties: any) {
super(parent);
const type = this.constructor.name;
diff --git a/src/app/model/tower.ts b/src/app/model/tower.ts
index 90c1323..e0d7a24 100644
--- a/src/app/model/tower.ts
+++ b/src/app/model/tower.ts
@@ -3,44 +3,39 @@ import { lighten } from '../utils/color';
import { Block } from './block';
import { Serializable } from './serializable';
import { hash } from '../utils/hash';
-import { Node } from '../storage/node';
-import { IColor } from '../interfaces/persistance/color';
+import { Node } from '../store/node';
+import { IColor } from '../interfaces/color';
+
+export type ColoredBlock = Block & { color: IColor };
export class Tower extends Serializable implements ITower {
- constructor(parent: Node, props: ITower) {
- super(parent, props);
-
- this.blocks.sort((a, b) => a.created.getTime() - b.created.getTime());
- this.calculateTagList();
- }
-
tags: string[];
-
- // Only here to prevent ts warnings.
name: string;
- type: 'Tower';
+
get blocks(): Array {
return this.children as Array;
}
- baseColor: IColor;
- get coloredBlocks(): Array {
- return this.children.map(b => {
- const coloredBlock = b as Block & { color: IColor };
+ coloredBlocks: Array;
+
+ readonly baseColor: IColor;
+
+ constructor(parent: Node, props: ITower) {
+ super(parent, props);
+ this.onAfterClone();
+ }
+
+ protected onAfterClone(): void {
+ this.blocks.sort((a, b) => {
+ return a.created.getTime() - b.created.getTime();
+ });
+
+ this.coloredBlocks = this.blocks.map(b => {
+ const coloredBlock = b as ColoredBlock;
coloredBlock.color = lighten((hash(coloredBlock.tag) - 0.5) * 50, this.baseColor);
return coloredBlock;
});
- }
- addBlock(props: { tag: string; description: string; isDone: boolean }) {
- new Block(this, {
- created: new Date(),
- ...props,
- type: 'Block'
- });
- }
-
- private calculateTagList() {
this.tags = [];
for (const block of this.blocks) {
if (!this.tags.includes(block.tag)) {
@@ -48,4 +43,17 @@ export class Tower extends Serializable implements ITower {
}
}
}
+
+ addBlock(props: { tag: string; description: string; isDone: boolean }) {
+ new Block(this, {
+ created: new Date(),
+ ...props
+ });
+ }
+
+ changeName(newName: string) {
+ // For optimization purposes.
+ this.name = newName;
+ this.mutatedUpdate();
+ }
}
diff --git a/src/app/pipes/color.pipe.ts b/src/app/pipes/color.pipe.ts
new file mode 100644
index 0000000..d68241f
--- /dev/null
+++ b/src/app/pipes/color.pipe.ts
@@ -0,0 +1,12 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { IColor } from '../interfaces/color';
+import { toHslString } from '../utils/color';
+
+@Pipe({
+ name: 'color'
+})
+export class ColorPipe implements PipeTransform {
+ transform(color: IColor, args?: any): string {
+ return toHslString(color);
+ }
+}
diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts
index 95ce3cf..e939076 100644
--- a/src/app/services/data.service.ts
+++ b/src/app/services/data.service.ts
@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { StoreService } from './store.service';
import { Page } from '../model/page';
-import { Root } from '../storage/root';
+import { Root } from '../store/root';
import { Serializable } from '../model/serializable';
import { Tower } from '../model/tower';
import { Block } from '../model/block';
@@ -47,15 +47,22 @@ export class DataService extends Root {
this.children$.subscribe(value => {
this.log();
this._safeChildren.next(value);
- this.storeService.scheduleSave(this.pages);
+ this.save(0);
});
}
+ mutatedUpdate() {
+ this.save(2500);
+ }
+
+ save(timeout: number) {
+ this.storeService.scheduleSave(this.pages, timeout);
+ }
+
addPage(name: string) {
new Page(this, {
name,
userData: {},
- type: 'Page',
towers: []
});
}
diff --git a/src/app/services/store.service.ts b/src/app/services/store.service.ts
index 8b677dc..2a029a8 100644
--- a/src/app/services/store.service.ts
+++ b/src/app/services/store.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { Page } from '../model/page';
import { IPage } from '../interfaces/persistance/page';
-const LOCAL_STORAGE_KEY = 'life-towers.data.v.3';
+const LOCAL_STORAGE_KEY = 'life-towers.data.v.2';
@Injectable({
providedIn: 'root'
@@ -15,84 +15,77 @@ export class StoreService {
{
name: 'Work & life',
userData: {},
- type: 'Page',
towers: [
{
name: 'work',
- baseColor: { h: 0, s: 100, l: 50, type: 'Color' },
- type: 'Tower',
+ baseColor: { h: 0, s: 100, l: 50 },
blocks: [
{
created: new Date(2015, 2, 13),
tag: 'a',
description: 'done it',
- isDone: true,
- type: 'Block'
+ isDone: true
},
{
created: new Date(2016, 2, 15),
tag: 'go to school',
description: 'done it',
- type: 'Block'
+ isDone: false
},
{
created: new Date(2017, 2, 15),
tag: 'go to work',
- isDone: true,
- type: 'Block'
+ isDone: true
},
{
created: new Date(2018, 2, 13),
tag: 'go to work',
description: 'done it',
- isDone: true,
- type: 'Block'
+ isDone: true
},
{
created: new Date(2019, 3, 13),
tag: 'go to work',
- type: 'Block'
+ isDone: false
},
{
created: new Date(2020, 2, 15),
tag: 'go to school',
description: 'done it',
- isDone: true,
- type: 'Block'
+ isDone: true
},
{
created: new Date(2021, 2, 15),
tag: 'go to school',
- type: 'Block'
+ isDone: false
}
]
},
{
- baseColor: { h: 180, s: 100, l: 50, type: 'Color' },
+ baseColor: { h: 180, s: 100, l: 50 },
name: 'life',
- type: 'Tower',
blocks: [
{
created: new Date(2019, 3, 13),
tag: 'go home',
description: 'done it',
- type: 'Block'
+ isDone: false
},
{
created: new Date(2019, 4, 13),
tag: 'go home',
- type: 'Block'
+ isDone: false
},
{
created: new Date(2019, 4, 15),
tag: 'go to work',
description: 'done it',
- type: 'Block'
+ isDone: false
},
{
created: new Date(2019, 4, 15, 14),
tag: 'go to work',
- type: 'Block'
+ isDone: false
}
]
}
@@ -105,14 +98,14 @@ export class StoreService {
this.storedData = JSON.parse(localStorageData ? localStorageData : this.mockData) as T;
}
- scheduleSave(data: T) {
+ scheduleSave(data: T, timeout: number) {
this.dataToSave = data;
if (!this.saveScheduled) {
this.saveScheduled = true;
setTimeout(() => {
this.saveScheduled = false;
this.save(this.dataToSave).catch();
- }, 0);
+ }, timeout);
}
}
diff --git a/src/app/storage/cloneable.ts b/src/app/store/cloneable.ts
similarity index 56%
rename from src/app/storage/cloneable.ts
rename to src/app/store/cloneable.ts
index 767b5f0..317e279 100644
--- a/src/app/storage/cloneable.ts
+++ b/src/app/store/cloneable.ts
@@ -1,11 +1,13 @@
import { InnerNode } from './inner-node';
import { Node } from './node';
-export class Cloneable extends InnerNode {
- constructor(parent: Node) {
+export abstract class Cloneable extends InnerNode {
+ protected constructor(parent: Node) {
super(parent);
}
+ protected abstract onAfterClone(): void;
+
protected cloneWithMap(map: (node: this) => void): this {
const insides = Object.getOwnPropertyDescriptors(this);
@@ -20,8 +22,8 @@ export class Cloneable extends InnerNode {
return value.bind(proxy);
}
return value;
- } else if (this.hasOwnProperty(prop)) {
- const value = this[prop];
+ } else if (target.prototype.hasOwnProperty(prop)) {
+ const value = target.prototype[prop];
if (typeof value === 'function') {
return value.bind(proxy);
}
@@ -34,28 +36,44 @@ export class Cloneable extends InnerNode {
});
map(insidesProxy);
- (insidesProxy.__target__).id.value = Node.id++;
- (insidesProxy.__target__).copyCount.value++;
- Node.sumCopyCount++;
-
- return Object.create(Object.getPrototypeOf(this), insidesProxy.__target__);
+ return this.cloneFromInsides(insidesProxy.__target__);
}
- protected cloneWithAdd({ value, propertyName }: { value: any; propertyName: string }): this {
+ protected cloneWithAdd({ propertyName, value }: { value: any; propertyName: string }): this {
+ if (this[propertyName] === value) {
+ return this;
+ }
+
const insides = Object.getOwnPropertyDescriptors(this);
insides[propertyName].value = value;
- insides.id.value = Node.id++;
- insides.copyCount.value++;
- Node.sumCopyCount++;
+ return this.cloneFromInsides(insides);
+ }
- return Object.create(Object.getPrototypeOf(this), insides);
+ protected cloneWithChangedKeys(props: { [propertyName: string]: any }): this {
+ const insides = Object.getOwnPropertyDescriptors(this);
+
+ for (let key in props) {
+ if (props.hasOwnProperty(key)) {
+ if (insides.hasOwnProperty(key)) {
+ insides[key].value = props[key];
+ } else {
+ // @ts-ignore
+ insides[key] = {
+ value: props[key]
+ };
+ }
+ }
+ }
+
+ return this.cloneFromInsides(insides);
}
protected cloneWithModify({ oldValue, newValue }: { oldValue: any; newValue: any }): this {
+ if (oldValue === newValue) {
+ return this;
+ }
+
const insides = Object.getOwnPropertyDescriptors(this);
- insides.id.value = Node.id++;
- insides.copyCount.value++;
- Node.sumCopyCount++;
let wasMatch = false;
for (let name in insides) {
@@ -69,6 +87,16 @@ export class Cloneable extends InnerNode {
throw new TypeError(`Object has no property with value: ${oldValue.toString()}`);
}
- return Object.create(Object.getPrototypeOf(this), insides);
+ return this.cloneFromInsides(insides);
+ }
+
+ private cloneFromInsides(insides): this {
+ insides.id.value = Node.id++;
+ insides.copyCount.value++;
+ Node.sumCopyCount++;
+
+ const clone = Object.create(Object.getPrototypeOf(this), insides);
+ clone.onAfterClone();
+ return clone;
}
}
diff --git a/src/app/storage/inner-node.ts b/src/app/store/inner-node.ts
similarity index 67%
rename from src/app/storage/inner-node.ts
rename to src/app/store/inner-node.ts
index 06425d6..655ca69 100644
--- a/src/app/storage/inner-node.ts
+++ b/src/app/store/inner-node.ts
@@ -1,4 +1,5 @@
import { Node } from './node';
+import { observableToBeFn } from 'rxjs/internal/testing/TestScheduler';
export abstract class InnerNode extends Node {
parent: Node;
@@ -17,21 +18,31 @@ export abstract class InnerNode extends Node {
protected constructor(parent: Node) {
super();
- parent.addChild({
- value: this
- });
+ new Promise(r => r()).then(() =>
+ parent.addChild({
+ value: this
+ })
+ );
+ }
+
+ mutatedUpdate() {
+ this.parent.mutatedUpdate();
}
map(map: (a: this) => void) {
return this.update((self: this) => this.cloneWithMap.call(self, map));
}
- changeKey(update: { propertyName: string; value: any }): this {
- return this.update((self: this) => this.cloneWithAdd.call(self, update));
+ changeKey({ propertyName, value }: { propertyName: string; value: any }): this {
+ return this.update((self: this) => this.cloneWithAdd.call(self, { propertyName, value }));
}
- changeValue(update: { oldValue: any; newValue: any }): this {
- return this.update((self: this) => this.cloneWithModify.call(self, update));
+ changeKeys(props: { [propertyName: string]: any }): this {
+ return this.update((self: this) => this.cloneWithChangedKeys.call(self, props));
+ }
+
+ changeValue({ oldValue, newValue }: { oldValue: any; newValue: any }): this {
+ return this.update((self: this) => this.cloneWithModify.call(self, { oldValue, newValue }));
}
addChild(update: { value: InnerNode }) {
@@ -44,6 +55,7 @@ export abstract class InnerNode extends Node {
protected abstract cloneWithMap(map: (a: this) => void): this;
protected abstract cloneWithAdd(update: { value: any; propertyName: string }): this;
+ protected abstract cloneWithChangedKeys(props: { [propertyName: string]: any }): this;
protected abstract cloneWithModify(update: { oldValue: any; newValue: any }): this;
private update(cloneMethod: (self: this) => this): this {
@@ -52,6 +64,10 @@ export abstract class InnerNode extends Node {
}
const clone = cloneMethod(this);
+ if (clone === this) {
+ return this;
+ }
+
for (let child of clone.children) {
child.parent = clone;
}
diff --git a/src/app/storage/node.ts b/src/app/store/node.ts
similarity index 93%
rename from src/app/storage/node.ts
rename to src/app/store/node.ts
index 81e29f6..c9d1384 100644
--- a/src/app/storage/node.ts
+++ b/src/app/store/node.ts
@@ -14,6 +14,8 @@ export abstract class Node {
Node.sumCopyCount++;
}
+ abstract mutatedUpdate(): void;
+
addChild(update: { value: InnerNode }) {
this.changeValue({
oldValue: this.children,
@@ -22,6 +24,10 @@ export abstract class Node {
}
changeChild({ oldValue, newValue }: { oldValue: InnerNode; newValue: InnerNode }) {
+ if (oldValue === newValue) {
+ return;
+ }
+
this.changeValue({
oldValue: this.children,
newValue: this.children.map(c => (c === oldValue ? newValue : c))
diff --git a/src/app/storage/root.ts b/src/app/store/root.ts
similarity index 96%
rename from src/app/storage/root.ts
rename to src/app/store/root.ts
index 1cbeed9..54c62e8 100644
--- a/src/app/storage/root.ts
+++ b/src/app/store/root.ts
@@ -15,6 +15,10 @@ export class Root extends Node {
this._children.next(value);
}
+ mutatedUpdate() {
+ // pass
+ }
+
changeValue({ oldValue, newValue }: { oldValue: any; newValue: any }) {
if (this.children !== oldValue) {
throw new TypeError('Only children can be changed.');
diff --git a/src/app/utils/color.ts b/src/app/utils/color.ts
index 7d7eb85..3e15f5e 100644
--- a/src/app/utils/color.ts
+++ b/src/app/utils/color.ts
@@ -1,4 +1,4 @@
-import { IColor } from '../interfaces/persistance/color';
+import { IColor } from '../interfaces/color';
export const lighten = (by: number, { h, s, l }: IColor): IColor => {
let newL = l + by;
@@ -8,7 +8,7 @@ export const lighten = (by: number, { h, s, l }: IColor): IColor => {
newL = 0;
}
- return { h, s, l: newL, type: 'Color' };
+ return { h, s, l: newL };
};
export const toHslString = ({ h, s, l }: IColor): string => {