diff --git a/src/app/build/shop.component.ts b/src/app/build/shop.component.ts deleted file mode 100644 index bc13421..0000000 --- a/src/app/build/shop.component.ts +++ /dev/null @@ -1,144 +0,0 @@ -import {Pipe, PipeTransform, Component, Output, EventEmitter, Inject} from 'angular2/core'; -import {NgFor, NgClass} from 'angular2/common'; - -import {DDragonDirective} from '../misc/ddragon.directive'; -import {LoadingComponent} from '../misc/loading.component'; -import {ErrorComponent} from '../misc/error.component'; -import {ToIterablePipe} from '../misc/to-iterable.pipe'; - -import {LolApiService} from '../misc/lolapi.service'; - -@Pipe({ - name: 'translate' -}) - -class TranslatePipe implements PipeTransform { - translator: Object = - { - 'GOLDPER': 'Gold income', - 'TRINKET': 'Trinkets', - 'SPELLBLOCK': 'Magic resist', - 'HEALTHREGEN': 'Health regen', - 'CRITICALSTRIKE': 'Critical strike', - 'SPELLDAMAGE': 'Ability power', - 'COOLDOWNREDUCTION': 'Cooldown reduction', - 'MANAREGEN': 'Mana regen', - 'NONBOOTSMOVEMENT': 'Other', - 'ARMORPENETRATION': 'Armor penetration', - 'AURA': 'Area Of Effect', - 'MAGICPENETRATION': 'Magic penetration', - 'ONHIT': 'On hit effect', - 'SPELLVAMP': 'Spell vamp', - 'UNCATEGORIZED': 'Other' - }; - - transform(value: string, args: any[]) { - if (!value) { - return false; - } else if (this.translator[value]) { - return this.translator[value]; - } - return this.capitalize(value.toLowerCase()); - } - - private capitalize(value: string) { - return value.charAt(0).toUpperCase() + value.slice(1); - } -} - -@Component({ - selector: 'shop', - providers: [LolApiService], - directives: [NgFor, NgClass, DDragonDirective, LoadingComponent, ErrorComponent], - pipes: [TranslatePipe], - template: ` -
- -
-

{{category.header | translate}}

-
- -
-
-
- -
-
- -
-

{{item.name}}

-
- -

{{item.gold.total}}

-
-
-
- - -
-
` -}) - -export class ShopComponent { - @Output() itemPicked: EventEmitter = new EventEmitter(); - - private items: Object; - private loading: boolean = true; - private error: boolean = false; - - constructor(private lolApi: LolApiService) { - this.getData(); - } - - getData() { - this.loading = true; - this.error = false; - - this.lolApi.getItems() - .subscribe( - res => { - this.items = this.alterData(res); - }, - error => { this.error = true; this.loading = false; }, - () => this.loading = false - ); - } - - alterData(newItems: Object): Object { - var alteredItems = { data: null, tree: null }; - var pipe = new ToIterablePipe(); - alteredItems.data = pipe.transform(newItems['data']).filter(this.filter).sort(this.sort); - alteredItems.tree = this.removeSortIndex(pipe.transform(newItems['tree'])); - return alteredItems; - - } - - sort(objA, objB) { - return objA.gold.total > objB.gold.total ? 1 : -1; - } - - filter(obj) { - //TODO: currently fixed: SummonersRiftNew && no specific champions && no hide from all - return obj.maps[11] && !obj.requiredChampion && !obj.hideFromAll; - } - - removeSortIndex(tree: Object) { - for (var category in tree) { - tree[category].tags.splice(tree[category].tags.indexOf('_SORTINDEX'), 1); - } - - return tree; - } -} diff --git a/src/app/build/shop/champion.pipe.spec.ts b/src/app/build/shop/champion.pipe.spec.ts new file mode 100644 index 0000000..bf7dd59 --- /dev/null +++ b/src/app/build/shop/champion.pipe.spec.ts @@ -0,0 +1,39 @@ +import {it, inject, beforeEach, beforeEachProviders} from 'angular2/testing'; + +import {ChampionPipe} from './champion.pipe'; + + +describe('Shop ChampionPipe', () => { + beforeEachProviders(() => [ + ChampionPipe + ]); + + let items = []; + let item1 = {}; + let item2 = {}; + let item3 = {}; + + beforeEach(() => { + item1 = { + id: 1, + requiredChampion: 5 + }; + item2 = { + id: 2, + requiredChampion: 3 + }; + item3 = { + id: 3 + }; + items = [item1, item2, item3]; + }); + + it('should filter', inject([ChampionPipe], (pipe) => { + expect(pipe.transform(items, [3])).toHaveEqualContent([item2, item3]); + })); + + it('should not filter null', inject([ChampionPipe], (pipe) => { + expect(pipe.transform(null, [3])).toBe(null); + expect(pipe.transform(items, [null])).toBe(items); + })); +}); diff --git a/src/app/build/shop/champion.pipe.ts b/src/app/build/shop/champion.pipe.ts new file mode 100644 index 0000000..c17aab5 --- /dev/null +++ b/src/app/build/shop/champion.pipe.ts @@ -0,0 +1,20 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'champion', + pure: false +}) + +export class ChampionPipe implements PipeTransform { + transform(items: Array, [champion]) { + if (!items || !champion) { + return items; + } + return items.filter((item) => { + if (!item.requiredChampion) { + return true; + } + return item.requiredChampion === champion; + }); + } +} diff --git a/src/app/build/shop/hide.pipe.spec.ts b/src/app/build/shop/hide.pipe.spec.ts new file mode 100644 index 0000000..b4a55f4 --- /dev/null +++ b/src/app/build/shop/hide.pipe.spec.ts @@ -0,0 +1,38 @@ +import {it, inject, beforeEach, beforeEachProviders} from 'angular2/testing'; + +import {HidePipe} from './hide.pipe'; + + +describe('Shop HidePipe', () => { + beforeEachProviders(() => [ + HidePipe + ]); + + let items = []; + let item1 = {}; + let item2 = {}; + let item3 = {}; + + beforeEach(() => { + item1 = { + id: 1, + hideFromAll: true + }; + item2 = { + id: 2, + hideFromAll: false + }; + item3 = { + id: 3 + }; + items = [item1, item2, item3]; + }); + + it('should filter', inject([HidePipe], (pipe) => { + expect(pipe.transform(items)).toHaveEqualContent([item2, item3]); + })); + + it('should not filter null', inject([HidePipe], (pipe) => { + expect(pipe.transform(null)).toBe(null); + })); +}); diff --git a/src/app/build/shop/hide.pipe.ts b/src/app/build/shop/hide.pipe.ts new file mode 100644 index 0000000..305c89d --- /dev/null +++ b/src/app/build/shop/hide.pipe.ts @@ -0,0 +1,17 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'hide', + pure: false +}) + +export class HidePipe implements PipeTransform { + transform(items: Array) { + if (!items) { + return items; + } + return items.filter((item) => { + return !item.hideFromAll; + }); + } +} diff --git a/src/app/build/shop/map.pipe.spec.ts b/src/app/build/shop/map.pipe.spec.ts new file mode 100644 index 0000000..bd71462 --- /dev/null +++ b/src/app/build/shop/map.pipe.spec.ts @@ -0,0 +1,45 @@ +import {it, inject, beforeEach, beforeEachProviders} from 'angular2/testing'; + +import {MapPipe} from './map.pipe'; + + +describe('Shop MapPipe', () => { + beforeEachProviders(() => [ + MapPipe + ]); + + let items = []; + let item1 = {}; + let item2 = {}; + let item3 = {}; + let item4 = {}; + + beforeEach(() => { + item1 = { + id: 1, + maps: {1: true} + }; + item2 = { + id: 2, + maps: {1: true, 2: true} + }; + item3 = { + id: 3, + maps: {1: false} + }; + item4 = { + id: 4 + }; + items = [item1, item2, item3, item4]; + }); + + it('should filter', inject([MapPipe], (pipe) => { + expect(pipe.transform(items, [2])).toHaveEqualContent([item2]); + expect(pipe.transform(items, [1])).toHaveEqualContent([item1, item2]); + })); + + it('should not filter null', inject([MapPipe], (pipe) => { + expect(pipe.transform(null, [1])).toBe(null); + expect(pipe.transform(items, [null])).toBe(items); + })); +}); diff --git a/src/app/build/shop/map.pipe.ts b/src/app/build/shop/map.pipe.ts new file mode 100644 index 0000000..05f2323 --- /dev/null +++ b/src/app/build/shop/map.pipe.ts @@ -0,0 +1,20 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'map', + pure: false +}) + +export class MapPipe implements PipeTransform { + transform(items: Array, [map]) { + if (!items || !map) { + return items; + } + return items.filter((item) => { + if (!item.maps || item.maps.length <= 0) { + return false; + } + return item.maps[map]; + }); + } +} diff --git a/src/app/build/shop/shop.component.spec.ts b/src/app/build/shop/shop.component.spec.ts new file mode 100644 index 0000000..99c0178 --- /dev/null +++ b/src/app/build/shop/shop.component.spec.ts @@ -0,0 +1,106 @@ +import {provide} from 'angular2/core'; +import {BaseRequestOptions, Http, Response, ResponseOptions} from 'angular2/http'; +import {RouteParams} from 'angular2/router'; +import {RootRouter} from 'angular2/src/router/router'; + +import {it, inject, injectAsync, beforeEachProviders} from 'angular2/testing'; +import {MockBackend, MockConnection} from 'angular2/http/testing'; + +import {LolApiService} from '../../misc/lolapi.service'; +import {ShopComponent} from './shop.component'; + +class MockEvent { + public target: any; +} + +describe('ShopComponent', () => { + beforeEachProviders(() => [ + provide(RouteParams, { useValue: new RouteParams({ region: 'euw' }) }), + BaseRequestOptions, + MockBackend, + provide(Http, { + useFactory: function(backend, defaultOptions) { + return new Http(backend, defaultOptions); + }, + deps: [MockBackend, BaseRequestOptions] + }), + provide(Event, { useValue: new MockEvent() }), + + LolApiService, + ShopComponent + ]); + + + + it('should call getData() on contruct', inject([LolApiService], (service) => { + spyOn(ShopComponent.prototype, 'getData'); + expect(ShopComponent.prototype.getData).not.toHaveBeenCalled(); + let component = new ShopComponent(service); + expect(ShopComponent.prototype.getData).toHaveBeenCalled(); + })); + + + it('should get items', injectAsync([MockBackend, ShopComponent, LolApiService], (mockBackend, component, service) => { + let mockResponse = new Response(new ResponseOptions({ status: 200, body: [{}] })); + mockBackend.connections.subscribe( + (connection: MockConnection) => { + connection.mockRespond(mockResponse); + }); + + expect(component.items).not.toBeDefined(); + component.getData(); + return service.getItems().toPromise().then(() => { + expect(component.items).toBeDefined(); + }); + })); + + it('should not get items', injectAsync([MockBackend, ShopComponent, LolApiService], (mockBackend, component, service) => { + mockBackend.connections.subscribe( + (connection: MockConnection) => { + connection.mockError(); + }); + + expect(component.items).not.toBeDefined(); + component.getData(); + return service.getItems().toPromise().catch(() => { + expect(component.items).not.toBeDefined(); + }); + })); + + + it('should add tags', inject([ShopComponent, Event], (component, event) => { + expect(component.tags).not.toContain('HEALTH'); + event.target = { checked: true, value: 'HEALTH' }; + component.tagChanged(event); + expect(component.tags).toContain('HEALTH'); + })); + + it('should not add tags on null event', inject([ShopComponent, Event], (component, event) => { + component.tags = null; + expect(component.tags).toBe(null); + component.tagChanged(null); + expect(component.tags).toBe(null); + event.target = null; + component.tagChanged(event); + expect(component.tags).toBe(null); + })); + + it('should add multiple tags', inject([ShopComponent, Event], (component, event) => { + expect(component.tags).not.toContain('HEALTH'); + event.target = { checked: true, value: 'HEALTH' }; + component.tagChanged(event); + expect(component.tags).toContain('HEALTH'); + expect(component.tags).not.toContain('ARMOR'); + event.target = { checked: true, value: 'ARMOR' }; + component.tagChanged(event); + expect(component.tags).toContain('HEALTH'); + expect(component.tags).toContain('ARMOR'); + })); + + it('should remove tags', inject([ShopComponent, Event], (component, event) => { + component.tags = ['HEALTH']; + event.target = { checked: false, value: 'HEALTH' }; + component.tagChanged(event); + expect(component.tags).not.toContain('HEALTH'); + })); +}); diff --git a/src/app/build/shop/shop.component.ts b/src/app/build/shop/shop.component.ts new file mode 100644 index 0000000..89756c3 --- /dev/null +++ b/src/app/build/shop/shop.component.ts @@ -0,0 +1,103 @@ +import {Component, Output, EventEmitter, Inject} from 'angular2/core'; +import {NgFor, NgIf, NgClass} from 'angular2/common'; + +import {DDragonDirective} from '../../misc/ddragon.directive'; +import {LoadingComponent} from '../../misc/loading.component'; +import {ErrorComponent} from '../../misc/error.component'; + +import {ToIterablePipe} from '../../misc/to-iterable.pipe'; +import {TranslatePipe} from './translate.pipe'; +import {CapitalizePipe} from '../../misc/capitalize.pipe'; +import {MapPipe} from './map.pipe'; +import {ChampionPipe} from './champion.pipe'; +import {HidePipe} from './hide.pipe'; +import {SortPipe} from './sort.pipe'; +import {TagsPipe} from './tags.pipe'; + +import {LolApiService} from '../../misc/lolapi.service'; + +@Component({ + selector: 'shop', + providers: [LolApiService], + directives: [NgFor, NgIf, NgClass, DDragonDirective, LoadingComponent, ErrorComponent], + pipes: [TranslatePipe, CapitalizePipe, ToIterablePipe, MapPipe, ChampionPipe, HidePipe, SortPipe, TagsPipe], + template: ` +
+ +
+

{{category.header | translate | capitalize}}

+
+ +
+
+
+ +
+
+ +
+

{{item.name}}

+
+ +

{{item.gold.total}}

+
+
+
+ + +
+
` +}) + +export class ShopComponent { + @Output() itemPicked: EventEmitter = new EventEmitter(); + + private items: Object; + private loading: boolean = true; + private error: boolean = false; + + private tags: Array = []; + + constructor(private lolApi: LolApiService) { + this.getData(); + } + + getData() { + this.loading = true; + this.error = false; + + this.lolApi.getItems() + .subscribe( + res => { this.items = res; }, + error => { this.error = true; this.loading = false; }, + () => this.loading = false + ); + } + + private tagChanged(event: Event) { + if (!event || !event.target) { + return; + } + var input = event.target; + if (input['checked']) { + this.tags.push(input['value']); + } else { + var index: number = this.tags.indexOf(input['value']); + if (index > -1) { + this.tags.splice(index, 1); + } + } + } +} diff --git a/src/app/build/shop/sort.pipe.spec.ts b/src/app/build/shop/sort.pipe.spec.ts new file mode 100644 index 0000000..84dd625 --- /dev/null +++ b/src/app/build/shop/sort.pipe.spec.ts @@ -0,0 +1,39 @@ +import {it, inject, beforeEach, beforeEachProviders} from 'angular2/testing'; + +import {SortPipe} from './sort.pipe'; + + +describe('Shop SortPipe', () => { + beforeEachProviders(() => [ + SortPipe + ]); + + let items = []; + let item1 = {}; + let item2 = {}; + let item3 = {}; + + beforeEach(() => { + item1 = { + id: 1, + gold: { total: 3 } + }; + item2 = { + id: 2, + gold: { total: 0 } + }; + item3 = { + id: 3, + gold: { total: 1 } + }; + items = [item1, item2, item3]; + }); + + it('should sort', inject([SortPipe], (pipe) => { + expect(pipe.transform(items)).toHaveEqualContent([item2, item3, item1]); + })); + + it('should not sort null', inject([SortPipe], (pipe) => { + expect(pipe.transform(null)).toBe(null); + })); +}); diff --git a/src/app/build/shop/sort.pipe.ts b/src/app/build/shop/sort.pipe.ts new file mode 100644 index 0000000..8e7c521 --- /dev/null +++ b/src/app/build/shop/sort.pipe.ts @@ -0,0 +1,16 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'sort' +}) + +export class SortPipe implements PipeTransform { + transform(items: Array) { + if (!items) { + return items; + } + return items.sort((a: any, b: any) => { + return a.gold.total > b.gold.total ? 1 : -1; + }); + } +} diff --git a/src/app/build/shop/tags.pipe.spec.ts b/src/app/build/shop/tags.pipe.spec.ts new file mode 100644 index 0000000..2a606ca --- /dev/null +++ b/src/app/build/shop/tags.pipe.spec.ts @@ -0,0 +1,47 @@ +import {it, inject, beforeEach, beforeEachProviders} from 'angular2/testing'; + +import {TagsPipe} from './tags.pipe'; + + +describe('Shop TagsPipe', () => { + beforeEachProviders(() => [ + TagsPipe + ]); + + let items = []; + let item1 = {}; + let item2 = {}; + let item3 = {}; + + beforeEach(() => { + item1 = { + id: 1, + tags: [ + 'CooldownReduction', + 'Health' + ] + }; + item2 = { + id: 2, + tags: [ + 'Armor', + 'Health' + ] + }; + item3 = { + id: 3 + }; + items = [item1, item2, item3]; + }); + + it('should filter', inject([TagsPipe], (pipe) => { + let tags = ['Armor']; + expect(pipe.transform(items, [tags])).toHaveEqualContent([item2]); + })); + + it('should not filter null', inject([TagsPipe], (pipe) => { + let tags = ['Armor']; + expect(pipe.transform(null, [tags])).toBe(null); + expect(pipe.transform(items, [null])).toBe(items); + })); +}); diff --git a/src/app/build/shop/tags.pipe.ts b/src/app/build/shop/tags.pipe.ts new file mode 100644 index 0000000..3ecc864 --- /dev/null +++ b/src/app/build/shop/tags.pipe.ts @@ -0,0 +1,28 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'tags', + pure: false +}) + +export class TagsPipe implements PipeTransform { + transform(items: Array, [tags]) { + if (!items || !tags) { + return items; + } + return items.filter((item) => { + if (!item['tags']) { + return false; + } + if (tags && tags.length > 0) { + for (var tag in tags) { + item['tags'] = item['tags'].map(tag => tag.toLowerCase()); + if (item['tags'].indexOf(tags[tag].toLowerCase()) === -1) { + return false; + } + } + } + return true; + }); + } +} diff --git a/src/app/build/shop/translate.pipe.spec.ts b/src/app/build/shop/translate.pipe.spec.ts new file mode 100644 index 0000000..458665e --- /dev/null +++ b/src/app/build/shop/translate.pipe.spec.ts @@ -0,0 +1,20 @@ +import {it, inject, beforeEachProviders} from 'angular2/testing'; + +import {TranslatePipe} from './translate.pipe'; + + +describe('Shop TranslatePipe', () => { + beforeEachProviders(() => [ + TranslatePipe + ]); + + + it('should translate', inject([TranslatePipe], (pipe) => { + expect(pipe.transform('AURA')).toBe('Area Of Effect'); + })); + + it('should not translate', inject([TranslatePipe], (pipe) => { + expect(pipe.transform(null)).toBe(null); + expect(pipe.transform('Test')).toBe('Test'); + })); +}); diff --git a/src/app/build/shop/translate.pipe.ts b/src/app/build/shop/translate.pipe.ts new file mode 100644 index 0000000..77900fd --- /dev/null +++ b/src/app/build/shop/translate.pipe.ts @@ -0,0 +1,33 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'translate' +}) + +export class TranslatePipe implements PipeTransform { + translator: Object = + { + GOLDPER: 'Gold income', + TRINKET: 'Trinkets', + SPELLBLOCK: 'Magic resist', + HEALTHREGEN: 'Health regen', + CRITICALSTRIKE: 'Critical strike', + SPELLDAMAGE: 'Ability power', + COOLDOWNREDUCTION: 'Cooldown reduction', + MANAREGEN: 'Mana regen', + NONBOOTSMOVEMENT: 'Other', + ARMORPENETRATION: 'Armor penetration', + AURA: 'Area Of Effect', + MAGICPENETRATION: 'Magic penetration', + ONHIT: 'On hit effect', + SPELLVAMP: 'Spell vamp', + UNCATEGORIZED: 'Other' + }; + + transform(value: string, args: any[]) { + if (this.translator[value]) { + return this.translator[value]; + } + return value; + } +} diff --git a/src/app/misc/capitalize.pipe.spec.ts b/src/app/misc/capitalize.pipe.spec.ts new file mode 100644 index 0000000..cb76c1d --- /dev/null +++ b/src/app/misc/capitalize.pipe.spec.ts @@ -0,0 +1,17 @@ +import {it, inject, beforeEachProviders} from 'angular2/testing'; + +import {CapitalizePipe} from './capitalize.pipe'; + + +describe('CapitalizePipe', () => { + beforeEachProviders(() => [ + CapitalizePipe + ]); + + + it('should capitalize', inject([CapitalizePipe], (pipe) => { + expect(pipe.transform('test')).toBe('Test'); + expect(pipe.transform('Test')).toBe('Test'); + expect(pipe.transform('tEST')).toBe('Test'); + })); +}); diff --git a/src/app/misc/capitalize.pipe.ts b/src/app/misc/capitalize.pipe.ts new file mode 100644 index 0000000..1e3bedf --- /dev/null +++ b/src/app/misc/capitalize.pipe.ts @@ -0,0 +1,12 @@ +import {Pipe, PipeTransform} from 'angular2/core'; + +@Pipe({ + name: 'capitalize' +}) + +export class CapitalizePipe implements PipeTransform { + transform(value: string) { + value = value.toLowerCase(); + return value.charAt(0).toUpperCase() + value.slice(1); + } +} diff --git a/src/app/routes/build.component.ts b/src/app/routes/build.component.ts index 1eb813d..5d4beb8 100644 --- a/src/app/routes/build.component.ts +++ b/src/app/routes/build.component.ts @@ -1,6 +1,6 @@ import {Component, ViewEncapsulation} from 'angular2/core'; -import {ShopComponent} from '../build/shop.component'; +import {ShopComponent} from '../build/shop/shop.component'; import {ChampionComponent} from '../build/champion.component'; @Component({