MOBILE-2201 tag: Index page
This commit is contained in:
		
							parent
							
								
									353c6823db
								
							
						
					
					
						commit
						b2db3774e6
					
				| @ -1800,11 +1800,15 @@ | |||||||
|   "core.submit": "moodle", |   "core.submit": "moodle", | ||||||
|   "core.success": "moodle", |   "core.success": "moodle", | ||||||
|   "core.tablet": "local_moodlemobileapp", |   "core.tablet": "local_moodlemobileapp", | ||||||
|  |   "core.tag.errorareanotsupported": "local_moodlemobileapp", | ||||||
|  |   "core.tag.itemstaggedwith": "moodle", | ||||||
|  |   "core.tag.tag": "moodle", | ||||||
|   "core.tag.tagarea_course": "moodle", |   "core.tag.tagarea_course": "moodle", | ||||||
|   "core.tag.tagarea_course_modules": "moodle", |   "core.tag.tagarea_course_modules": "moodle", | ||||||
|   "core.tag.tagarea_post": "moodle", |   "core.tag.tagarea_post": "moodle", | ||||||
|   "core.tag.tagarea_user": "moodle", |   "core.tag.tagarea_user": "moodle", | ||||||
|   "core.tag.tags": "moodle", |   "core.tag.tags": "moodle", | ||||||
|  |   "core.tag.warningareasnotsupported": "local_moodlemobileapp", | ||||||
|   "core.teachers": "moodle", |   "core.teachers": "moodle", | ||||||
|   "core.thereisdatatosync": "local_moodlemobileapp", |   "core.thereisdatatosync": "local_moodlemobileapp", | ||||||
|   "core.thisdirection": "langconfig", |   "core.thisdirection": "langconfig", | ||||||
|  | |||||||
| @ -1800,11 +1800,15 @@ | |||||||
|     "core.submit": "Submit", |     "core.submit": "Submit", | ||||||
|     "core.success": "Success", |     "core.success": "Success", | ||||||
|     "core.tablet": "Tablet", |     "core.tablet": "Tablet", | ||||||
|  |     "core.tag.errorareanotsupported": "This tag area is not supported by the app.", | ||||||
|  |     "core.tag.itemstaggedwith": "{{$a.tagarea}} tagged with \"{{$a.tag}}\"", | ||||||
|  |     "core.tag.tag": "Tag", | ||||||
|     "core.tag.tagarea_course": "Courses", |     "core.tag.tagarea_course": "Courses", | ||||||
|     "core.tag.tagarea_course_modules": "Activities and resources", |     "core.tag.tagarea_course_modules": "Activities and resources", | ||||||
|     "core.tag.tagarea_post": "Blog posts", |     "core.tag.tagarea_post": "Blog posts", | ||||||
|     "core.tag.tagarea_user": "User interests", |     "core.tag.tagarea_user": "User interests", | ||||||
|     "core.tag.tags": "Tags", |     "core.tag.tags": "Tags", | ||||||
|  |     "core.tag.warningareasnotsupported": "Some of the tag areas are not displayed because they are not supported by the app.", | ||||||
|     "core.teachers": "Teachers", |     "core.teachers": "Teachers", | ||||||
|     "core.thereisdatatosync": "There are offline {{$a}} to be synchronised.", |     "core.thereisdatatosync": "There are offline {{$a}} to be synchronised.", | ||||||
|     "core.thisdirection": "ltr", |     "core.thisdirection": "ltr", | ||||||
|  | |||||||
| @ -1,7 +1,11 @@ | |||||||
| { | { | ||||||
|  |     "errorareanotsupported": "This tag area is not supported by the app.", | ||||||
|  |     "itemstaggedwith": "{{$a.tagarea}} tagged with \"{{$a.tag}}\"", | ||||||
|  |     "tag": "Tag", | ||||||
|     "tagarea_course": "Courses", |     "tagarea_course": "Courses", | ||||||
|     "tagarea_course_modules": "Activities and resources", |     "tagarea_course_modules": "Activities and resources", | ||||||
|     "tagarea_post": "Blog posts", |     "tagarea_post": "Blog posts", | ||||||
|     "tagarea_user": "User interests", |     "tagarea_user": "User interests", | ||||||
|     "tags": "Tags" |     "tags": "Tags", | ||||||
|  |     "warningareasnotsupported": "Some of the tag areas are not displayed because they are not supported by the app." | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								src/core/tag/pages/index-area/index-area.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/core/tag/pages/index-area/index-area.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | <ion-header> | ||||||
|  |     <ion-navbar core-back-button> | ||||||
|  |         <ion-title>{{ 'core.tag.itemstaggedwith' | translate: { $a: {tagarea: areaNameKey | translate, tag: tagName} } }}</ion-title> | ||||||
|  |     </ion-navbar> | ||||||
|  | </ion-header> | ||||||
|  | <ion-content> | ||||||
|  |     <ion-refresher [enabled]="loaded" (ionRefresh)="refreshData($event)"> | ||||||
|  |         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||||
|  |     </ion-refresher> | ||||||
|  |     <core-loading [hideUntil]="loaded"> | ||||||
|  |         <ng-container *ngIf="loaded"> | ||||||
|  |             <core-dynamic-component [component]="areaComponent" [data]="{items: items}"></core-dynamic-component> | ||||||
|  |         </ng-container> | ||||||
|  |         <core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"></core-infinite-loading> | ||||||
|  |     </core-loading> | ||||||
|  | </ion-content> | ||||||
							
								
								
									
										33
									
								
								src/core/tag/pages/index-area/index-area.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/tag/pages/index-area/index-area.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | // (C) Copyright 2015 Martin Dougiamas
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { NgModule } from '@angular/core'; | ||||||
|  | import { IonicPageModule } from 'ionic-angular'; | ||||||
|  | import { TranslateModule } from '@ngx-translate/core'; | ||||||
|  | import { CoreTagIndexAreaPage } from './index-area'; | ||||||
|  | import { CoreComponentsModule } from '@components/components.module'; | ||||||
|  | import { CoreDirectivesModule } from '@directives/directives.module'; | ||||||
|  | 
 | ||||||
|  | @NgModule({ | ||||||
|  |     declarations: [ | ||||||
|  |         CoreTagIndexAreaPage | ||||||
|  |     ], | ||||||
|  |     imports: [ | ||||||
|  |         CoreComponentsModule, | ||||||
|  |         CoreDirectivesModule, | ||||||
|  |         IonicPageModule.forChild(CoreTagIndexAreaPage), | ||||||
|  |         TranslateModule.forChild() | ||||||
|  |     ], | ||||||
|  | }) | ||||||
|  | export class CoreTagIndexAreaPageModule {} | ||||||
							
								
								
									
										150
									
								
								src/core/tag/pages/index-area/index-area.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/core/tag/pages/index-area/index-area.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | |||||||
|  | // (C) Copyright 2015 Martin Dougiamas
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { Component, Injector } from '@angular/core'; | ||||||
|  | import { TranslateService } from '@ngx-translate/core'; | ||||||
|  | import { IonicPage, NavParams } from 'ionic-angular'; | ||||||
|  | import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||||
|  | import { CoreTagProvider } from '@core/tag/providers/tag'; | ||||||
|  | import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Page that displays the tag index area. | ||||||
|  |  */ | ||||||
|  | @IonicPage({ segment: 'core-tag-index-area' }) | ||||||
|  | @Component({ | ||||||
|  |     selector: 'page-core-tag-index-area', | ||||||
|  |     templateUrl: 'index-area.html', | ||||||
|  | }) | ||||||
|  | export class CoreTagIndexAreaPage { | ||||||
|  |     tagId: number; | ||||||
|  |     tagName: string; | ||||||
|  |     collectionId: number; | ||||||
|  |     areaId: number; | ||||||
|  |     fromContextId: number; | ||||||
|  |     contextId: number; | ||||||
|  |     recursive: boolean; | ||||||
|  |     areaNameKey: string; | ||||||
|  |     loaded = false; | ||||||
|  |     componentName: string; | ||||||
|  |     itemType: string; | ||||||
|  |     items = []; | ||||||
|  |     nextPage = 0; | ||||||
|  |     canLoadMore = false; | ||||||
|  |     areaComponent: any; | ||||||
|  |     loadMoreError = false; | ||||||
|  | 
 | ||||||
|  |     constructor(navParams: NavParams, private injector: Injector, private translate: TranslateService, | ||||||
|  |             private tagProvider: CoreTagProvider, private domUtils: CoreDomUtilsProvider, | ||||||
|  |             private tagAreaDelegate: CoreTagAreaDelegate) { | ||||||
|  |         this.tagId = navParams.get('tagId'); | ||||||
|  |         this.tagName = navParams.get('tagName'); | ||||||
|  |         this.collectionId = navParams.get('collectionId'); | ||||||
|  |         this.areaId = navParams.get('areaId'); | ||||||
|  |         this.fromContextId = navParams.get('fromContextId'); | ||||||
|  |         this.contextId = navParams.get('contextId'); | ||||||
|  |         this.recursive = navParams.get('recursive'); | ||||||
|  |         this.areaNameKey = navParams.get('areaNameKey'); | ||||||
|  | 
 | ||||||
|  |         // Pass the the following parameters to avoid fetching the first page.
 | ||||||
|  |         this.componentName = navParams.get('componentName'); | ||||||
|  |         this.itemType = navParams.get('itemType'); | ||||||
|  |         this.items = navParams.get('items') || []; | ||||||
|  |         this.nextPage = navParams.get('nextPage') || 0; | ||||||
|  |         this.canLoadMore = !!navParams.get('canLoadMore'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * View loaded. | ||||||
|  |      */ | ||||||
|  |     ionViewDidLoad(): void { | ||||||
|  |         let promise: Promise<any>; | ||||||
|  |         if (!this.componentName || !this.itemType || !this.items.length || this.nextPage == 0) { | ||||||
|  |             promise = this.fetchData(true); | ||||||
|  |         } else { | ||||||
|  |             promise = Promise.resolve(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         promise.then(() => { | ||||||
|  |             return this.tagAreaDelegate.getComponent(this.componentName, this.itemType, this.injector).then((component) => { | ||||||
|  |                 this.areaComponent = component; | ||||||
|  |             }); | ||||||
|  |         }).finally(() => { | ||||||
|  |             this.loaded = true; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fetch next page of the tag index area. | ||||||
|  |      * | ||||||
|  |      * @param {boolean} [refresh=false] Whether to refresh the data or fetch a new page. | ||||||
|  |      * @return {Promise<any>} Resolved when done. | ||||||
|  |      */ | ||||||
|  |     fetchData(refresh: boolean = false): Promise<any> { | ||||||
|  |         this.loadMoreError = false; | ||||||
|  |         const page = refresh ? 0 : this.nextPage; | ||||||
|  | 
 | ||||||
|  |         return this.tagProvider.getTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId, | ||||||
|  |                 this.contextId, this.recursive, page).then((areas) => { | ||||||
|  |             const area = areas[0]; | ||||||
|  | 
 | ||||||
|  |             return this.tagAreaDelegate.parseContent(area.component, area.itemtype, area.content).then((items) => { | ||||||
|  |                 if (!items || !items.length) { | ||||||
|  |                     // Tag area not supported.
 | ||||||
|  |                     return Promise.reject(this.translate.instant('core.tag.errorareanotsupported')); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (page == 0) { | ||||||
|  |                     this.items = items; | ||||||
|  |                 } else { | ||||||
|  |                     this.items.push(...items); | ||||||
|  |                 } | ||||||
|  |                 this.componentName = area.component; | ||||||
|  |                 this.itemType = area.itemtype; | ||||||
|  |                 this.areaNameKey = this.tagAreaDelegate.getDisplayNameKey(area.component, area.itemtype); | ||||||
|  |                 this.canLoadMore = !!area.nextpageurl; | ||||||
|  |                 this.nextPage = page + 1; | ||||||
|  |             }); | ||||||
|  |         }).catch((error) => { | ||||||
|  |             this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
 | ||||||
|  |             this.domUtils.showErrorModalDefault(error, 'Error loading tag index'); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Load more items. | ||||||
|  |      * | ||||||
|  |      * @param {any} infiniteComplete Infinite scroll complete function. | ||||||
|  |      * @return {Promise<any>} Resolved when done. | ||||||
|  |      */ | ||||||
|  |     loadMore(infiniteComplete: any): Promise<any> { | ||||||
|  |         return this.fetchData().finally(() => { | ||||||
|  |             infiniteComplete(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Refresh data. | ||||||
|  |      * | ||||||
|  |      * @param {any} refresher Refresher. | ||||||
|  |      */ | ||||||
|  |     refreshData(refresher: any): void { | ||||||
|  |         this.tagProvider.invalidateTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId, | ||||||
|  |                 this.contextId, this.recursive).finally(() => { | ||||||
|  |             this.fetchData(true).finally(() => { | ||||||
|  |                 refresher.complete(); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/core/tag/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/core/tag/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | |||||||
|  | <ion-header> | ||||||
|  |     <ion-navbar core-back-button> | ||||||
|  |         <ion-title>{{ 'core.tag.tag' | translate }}: {{ tagName }}</ion-title> | ||||||
|  |     </ion-navbar> | ||||||
|  | </ion-header> | ||||||
|  | <core-split-view> | ||||||
|  |     <ion-content> | ||||||
|  |         <ion-refresher [enabled]="loaded" (ionRefresh)="refreshData($event)"> | ||||||
|  |             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||||
|  |         </ion-refresher> | ||||||
|  |         <core-loading [hideUntil]="loaded"> | ||||||
|  |             <ion-list> | ||||||
|  |                 <ion-item text-wrap *ngIf="hasUnsupportedAreas" class="core-warning-item"> | ||||||
|  |                     <ion-icon item-start name="warning" color="warning"></ion-icon> | ||||||
|  |                     {{ 'core.tag.warningareasnotsupported' | translate }} | ||||||
|  |                 </ion-item> | ||||||
|  |                 <a ion-item text-wrap *ngFor="let area of areas" [title]="area.nameKey | translate" (click)="openArea(area)" [class.core-split-item-selected]="area.id == selectedAreaId"> | ||||||
|  |                     <h2>{{ area.nameKey | translate }}</h2> | ||||||
|  |                     <ion-badge item-end *ngIf="area.badge">{{ area.badge }}</ion-badge> | ||||||
|  |                 </a> | ||||||
|  |             </ion-list> | ||||||
|  |         </core-loading> | ||||||
|  |     </ion-content> | ||||||
|  | </core-split-view> | ||||||
							
								
								
									
										33
									
								
								src/core/tag/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/core/tag/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | // (C) Copyright 2015 Martin Dougiamas
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { NgModule } from '@angular/core'; | ||||||
|  | import { IonicPageModule } from 'ionic-angular'; | ||||||
|  | import { TranslateModule } from '@ngx-translate/core'; | ||||||
|  | import { CoreTagIndexPage } from './index'; | ||||||
|  | import { CoreComponentsModule } from '@components/components.module'; | ||||||
|  | import { CoreDirectivesModule } from '@directives/directives.module'; | ||||||
|  | 
 | ||||||
|  | @NgModule({ | ||||||
|  |     declarations: [ | ||||||
|  |         CoreTagIndexPage | ||||||
|  |     ], | ||||||
|  |     imports: [ | ||||||
|  |         CoreComponentsModule, | ||||||
|  |         CoreDirectivesModule, | ||||||
|  |         IonicPageModule.forChild(CoreTagIndexPage), | ||||||
|  |         TranslateModule.forChild() | ||||||
|  |     ], | ||||||
|  | }) | ||||||
|  | export class CoreTagIndexPageModule {} | ||||||
							
								
								
									
										154
									
								
								src/core/tag/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/core/tag/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | |||||||
|  | // (C) Copyright 2015 Martin Dougiamas
 | ||||||
|  | //
 | ||||||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||||
|  | // you may not use this file except in compliance with the License.
 | ||||||
|  | // You may obtain a copy of the License at
 | ||||||
|  | //
 | ||||||
|  | //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||||
|  | //
 | ||||||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||||||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||||
|  | // See the License for the specific language governing permissions and
 | ||||||
|  | // limitations under the License.
 | ||||||
|  | 
 | ||||||
|  | import { Component, ViewChild } from '@angular/core'; | ||||||
|  | import { IonicPage, NavParams } from 'ionic-angular'; | ||||||
|  | import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||||
|  | import { CoreSplitViewComponent } from '@components/split-view/split-view'; | ||||||
|  | import { CoreTagProvider } from '@core/tag/providers/tag'; | ||||||
|  | import { CoreTagAreaDelegate } from '@core/tag/providers/area-delegate'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Page that displays the tag index. | ||||||
|  |  */ | ||||||
|  | @IonicPage({ segment: 'core-tag-index' }) | ||||||
|  | @Component({ | ||||||
|  |     selector: 'page-core-tag-index', | ||||||
|  |     templateUrl: 'index.html', | ||||||
|  | }) | ||||||
|  | export class CoreTagIndexPage { | ||||||
|  |     @ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent; | ||||||
|  | 
 | ||||||
|  |     tagId: number; | ||||||
|  |     tagName: string; | ||||||
|  |     collectionId: number; | ||||||
|  |     areaId: number; | ||||||
|  |     fromContextId: number; | ||||||
|  |     contextId: number; | ||||||
|  |     recursive: boolean; | ||||||
|  |     loaded = false; | ||||||
|  |     areas: Array<{ | ||||||
|  |         id: number, | ||||||
|  |         componentName: string, | ||||||
|  |         itemType: string, | ||||||
|  |         nameKey: string, | ||||||
|  |         items: any[], | ||||||
|  |         canLoadMore: boolean, | ||||||
|  |         badge: string | ||||||
|  |     }>; | ||||||
|  |     selectedAreaId: number; | ||||||
|  |     hasUnsupportedAreas = false; | ||||||
|  | 
 | ||||||
|  |     constructor(navParams: NavParams, private tagProvider: CoreTagProvider, private domUtils: CoreDomUtilsProvider, | ||||||
|  |             private tagAreaDelegate: CoreTagAreaDelegate) { | ||||||
|  |         this.tagId = navParams.get('tagId') || 0; | ||||||
|  |         this.tagName = navParams.get('tagName') || ''; | ||||||
|  |         this.collectionId = navParams.get('collectionId'); | ||||||
|  |         this.areaId = navParams.get('areaId') || 0; | ||||||
|  |         this.fromContextId = navParams.get('fromContextId') || 0; | ||||||
|  |         this.contextId = navParams.get('contextId') || 0; | ||||||
|  |         this.recursive = navParams.get('recursive') || true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * View loaded. | ||||||
|  |      */ | ||||||
|  |     ionViewDidLoad(): void { | ||||||
|  |         this.fetchData().then(() => { | ||||||
|  |             if (this.splitviewCtrl.isOn() && this.areas && this.areas.length > 0) { | ||||||
|  |                 const area = this.areas.find((area) => area.id == this.areaId); | ||||||
|  |                 this.openArea(area || this.areas[0]); | ||||||
|  |             } | ||||||
|  |         }).finally(() => { | ||||||
|  |             this.loaded = true; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fetch first page of tag index per area. | ||||||
|  |      * | ||||||
|  |      * @return {Promise<any>} Resolved when done. | ||||||
|  |      */ | ||||||
|  |     fetchData(): Promise<any> { | ||||||
|  |         return this.tagProvider.getTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId, | ||||||
|  |                 this.contextId, this.recursive, 0).then((areas) => { | ||||||
|  |             this.areas = []; | ||||||
|  |             this.hasUnsupportedAreas = false; | ||||||
|  | 
 | ||||||
|  |             return Promise.all(areas.map((area) => { | ||||||
|  |                 return this.tagAreaDelegate.parseContent(area.component, area.itemtype, area.content).then((items) => { | ||||||
|  |                     if (!items || !items.length) { | ||||||
|  |                         // Tag area not supported, skip.
 | ||||||
|  |                         this.hasUnsupportedAreas = true; | ||||||
|  | 
 | ||||||
|  |                         return null; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     return { | ||||||
|  |                         id: area.ta, | ||||||
|  |                         componentName: area.component, | ||||||
|  |                         itemType: area.itemtype, | ||||||
|  |                         nameKey: this.tagAreaDelegate.getDisplayNameKey(area.component, area.itemtype), | ||||||
|  |                         items, | ||||||
|  |                         canLoadMore: !!area.nextpageurl, | ||||||
|  |                         badge: items && items.length ? items.length + (area.nextpageurl ? '+' : '') : '', | ||||||
|  |                     }; | ||||||
|  |                 }); | ||||||
|  |             })).then((areas) => { | ||||||
|  |                 this.areas = areas.filter((area) => area != null); | ||||||
|  |             }); | ||||||
|  |         }).catch((error) => { | ||||||
|  |             this.domUtils.showErrorModalDefault(error, 'Error loading tag index'); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Refresh data. | ||||||
|  |      * | ||||||
|  |      * @param {any} refresher Refresher. | ||||||
|  |      */ | ||||||
|  |     refreshData(refresher: any): void { | ||||||
|  |         this.tagProvider.invalidateTagIndexPerArea(this.tagId, this.tagName, this.collectionId, this.areaId, this.fromContextId, | ||||||
|  |                 this.contextId, this.recursive).finally(() => { | ||||||
|  |             this.fetchData().finally(() => { | ||||||
|  |                 refresher.complete(); | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Navigate to an index area. | ||||||
|  |      * | ||||||
|  |      * @param {any} area Area. | ||||||
|  |      */ | ||||||
|  |     openArea(area: any): void { | ||||||
|  |         this.selectedAreaId = area.id; | ||||||
|  |         const params = { | ||||||
|  |             tagId: this.tagId, | ||||||
|  |             tagName: this.tagName, | ||||||
|  |             collectionId: this.collectionId, | ||||||
|  |             areaId: area.id, | ||||||
|  |             fromContextId: this.fromContextId, | ||||||
|  |             contextId: this.contextId, | ||||||
|  |             recursive: this.recursive, | ||||||
|  |             areaNameKey: area.nameKey, | ||||||
|  |             componentName: area.component, | ||||||
|  |             itemType: area.itemType, | ||||||
|  |             items: area.items.slice(), | ||||||
|  |             canLoadMore: area.canLoadMore, | ||||||
|  |             nextPage: 1 | ||||||
|  |         }; | ||||||
|  |         this.splitviewCtrl.push('CoreTagIndexAreaPage', params); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -13,8 +13,27 @@ | |||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
| import { Injectable } from '@angular/core'; | import { Injectable } from '@angular/core'; | ||||||
|  | import { TranslateService } from '@ngx-translate/core'; | ||||||
| import { CoreSitesProvider } from '@providers/sites'; | import { CoreSitesProvider } from '@providers/sites'; | ||||||
| import { CoreSite } from '@classes/site'; | import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Structure of a tag index returned by WS. | ||||||
|  |  */ | ||||||
|  | export interface CoreTagIndex { | ||||||
|  |     tagid: number; | ||||||
|  |     ta: number; | ||||||
|  |     component: string; | ||||||
|  |     itemtype: string; | ||||||
|  |     nextpageurl: string; | ||||||
|  |     prevpageurl: string; | ||||||
|  |     exclusiveurl: string; | ||||||
|  |     exclusivetext: string; | ||||||
|  |     title: string; | ||||||
|  |     content: string; | ||||||
|  |     hascontent: number; | ||||||
|  |     anchor: string; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Structure of a tag item returned by WS. |  * Structure of a tag item returned by WS. | ||||||
| @ -38,7 +57,9 @@ export interface CoreTagItem { | |||||||
| @Injectable() | @Injectable() | ||||||
| export class CoreTagProvider { | export class CoreTagProvider { | ||||||
| 
 | 
 | ||||||
|     constructor(private sitesProvider: CoreSitesProvider) {} |     protected ROOT_CACHE_KEY = 'CoreTag:'; | ||||||
|  | 
 | ||||||
|  |     constructor(private sitesProvider: CoreSitesProvider, private translate: TranslateService) {} | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Check whether tags are available in a certain site. |      * Check whether tags are available in a certain site. | ||||||
| @ -67,4 +88,96 @@ export class CoreTagProvider { | |||||||
|                 site.wsAvailable('core_tag_get_tag_collections') && |                 site.wsAvailable('core_tag_get_tag_collections') && | ||||||
|                 !site.isFeatureDisabled('NoDelegate_CoreTag'); |                 !site.isFeatureDisabled('NoDelegate_CoreTag'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fetch the tag index. | ||||||
|  |      * | ||||||
|  |      * @param {number} [id=0] Tag ID. | ||||||
|  |      * @param {string} [name=''] Tag name. | ||||||
|  |      * @param {number} [collectionId=0] Tag collection ID. | ||||||
|  |      * @param {number} [areaId=0] Tag area ID. | ||||||
|  |      * @param {number} [fromContextId=0] Context ID where the link was displayed. | ||||||
|  |      * @param {number} [contextId=0] Context ID where to search for items. | ||||||
|  |      * @param {boolean} [recursive=true] Search in the context and its children. | ||||||
|  |      * @param {number} [page=0] Page number. | ||||||
|  |      * @param {string} [siteId] Site ID. If not defined, current site. | ||||||
|  |      * @return {Promise<CoreTagIndex[]>} Promise resolved with the tag index per area. | ||||||
|  |      * @since 3.7 | ||||||
|  |      */ | ||||||
|  |     getTagIndexPerArea(id: number, name: string = '', collectionId: number = 0, areaId: number = 0, fromContextId: number = 0, | ||||||
|  |             contextId: number = 0, recursive: boolean = true, page: number = 0, siteId?: string): Promise<CoreTagIndex[]> { | ||||||
|  |         return this.sitesProvider.getSite(siteId).then((site) => { | ||||||
|  |             const params = { | ||||||
|  |                 tagindex: { | ||||||
|  |                     id: id, | ||||||
|  |                     tag: name, | ||||||
|  |                     tc: collectionId, | ||||||
|  |                     ta: areaId, | ||||||
|  |                     excl: true, | ||||||
|  |                     from: fromContextId, | ||||||
|  |                     ctx: contextId, | ||||||
|  |                     rec: recursive, | ||||||
|  |                     page: page | ||||||
|  |                 }, | ||||||
|  |             }; | ||||||
|  |             const preSets: CoreSiteWSPreSets = { | ||||||
|  |                 updateFrequency: CoreSite.FREQUENCY_OFTEN, | ||||||
|  |                 cacheKey: this.getTagIndexPerAreaKey(id, name, collectionId, areaId, fromContextId, contextId, recursive) | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             return site.read('core_tag_get_tagindex_per_area', params, preSets).catch((error) => { | ||||||
|  |                 // Workaround for WS not passing parameter to error string.
 | ||||||
|  |                 if (error && error.errorcode == 'notagsfound') { | ||||||
|  |                     error.message = this.translate.instant('core.tag.notagsfound', {$a: name || id || ''}); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return Promise.reject(error); | ||||||
|  |             }).then((response) => { | ||||||
|  |                 if (!response || !response.length) { | ||||||
|  |                     return Promise.reject(null); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 return response; | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Invalidate tag index. | ||||||
|  |      * | ||||||
|  |      * @param {number} [id=0] Tag ID. | ||||||
|  |      * @param {string} [name=''] Tag name. | ||||||
|  |      * @param {number} [collectionId=0] Tag collection ID. | ||||||
|  |      * @param {number} [areaId=0] Tag area ID. | ||||||
|  |      * @param {number} [fromContextId=0] Context ID where the link was displayed. | ||||||
|  |      * @param {number} [contextId=0] Context ID where to search for items. | ||||||
|  |      * @param {boolean} [recursive=true] Search in the context and its children. | ||||||
|  |      * @return {Promise<any>} Promise resolved when the data is invalidated. | ||||||
|  |      */ | ||||||
|  |     invalidateTagIndexPerArea(id: number, name: string = '', collectionId: number = 0, areaId: number = 0, | ||||||
|  |             fromContextId: number = 0, contextId: number = 0, recursive: boolean = true, siteId?: string): Promise<any> { | ||||||
|  |         return this.sitesProvider.getSite(siteId).then((site) => { | ||||||
|  |             const key = this.getTagIndexPerAreaKey(id, name, collectionId, areaId, fromContextId, contextId, recursive); | ||||||
|  | 
 | ||||||
|  |             return site.invalidateWsCacheForKey(key); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Get cache key for tag index. | ||||||
|  |      * | ||||||
|  |      * @param {number} id Tag ID. | ||||||
|  |      * @param {string} name Tag name. | ||||||
|  |      * @param {number} collectionId Tag collection ID. | ||||||
|  |      * @param {number} areaId Tag area ID. | ||||||
|  |      * @param {number} fromContextId Context ID where the link was displayed. | ||||||
|  |      * @param {number} contextId Context ID where to search for items. | ||||||
|  |      * @param {boolean} [recursive=true] Search in the context and its children. | ||||||
|  |      * @return {string} Cache key. | ||||||
|  |      */ | ||||||
|  |     protected getTagIndexPerAreaKey(id: number, name: string, collectionId: number, areaId: number,  fromContextId: number, | ||||||
|  |             contextId: number, recursive: boolean): string { | ||||||
|  |         return this.ROOT_CACHE_KEY + 'index:' + id + ':' + name + ':' + collectionId + ':' + areaId + ':' + fromContextId + ':' | ||||||
|  |             + contextId + ':' +  (recursive ? 1 : 0); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user