mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 08:33:11 +00:00
feat: assessments module
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, Input, TemplateRef} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
import {DataListContext} from '../list/data-list.component';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@@ -28,4 +29,6 @@ export class DataDetailContentComponent {
|
||||
* TODO
|
||||
*/
|
||||
@Input() item: SCThings;
|
||||
|
||||
@Input() contentTemplateRef?: TemplateRef<DataListContext<SCThings>>;
|
||||
}
|
||||
|
||||
@@ -1,86 +1,99 @@
|
||||
<stapps-title-card [item]="item"> </stapps-title-card>
|
||||
<div [ngSwitch]="item.type">
|
||||
<stapps-article-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'article'"
|
||||
></stapps-article-detail-content>
|
||||
<stapps-catalog-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'catalog'"
|
||||
></stapps-catalog-detail-content>
|
||||
<stapps-date-series-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'date series'"
|
||||
></stapps-date-series-detail-content>
|
||||
<stapps-dish-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'dish'"
|
||||
></stapps-dish-detail-content>
|
||||
<stapps-event-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'academic event'"
|
||||
></stapps-event-detail-content>
|
||||
<stapps-event-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'sport course'"
|
||||
></stapps-event-detail-content>
|
||||
<stapps-favorite-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'favorite'"
|
||||
></stapps-favorite-detail-content>
|
||||
<stapps-message-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'message'"
|
||||
></stapps-message-detail-content>
|
||||
<stapps-person-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'person'"
|
||||
></stapps-person-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'building'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'floor'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'point of interest'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'room'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-semester-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'semester'"
|
||||
></stapps-semester-detail-content>
|
||||
<stapps-video-detail-content
|
||||
[item]="item"
|
||||
*ngSwitchCase="'video'"
|
||||
></stapps-video-detail-content>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<ion-item class="ion-text-wrap" lines="inset">
|
||||
<ion-thumbnail slot="start" class="ion-margin-end">
|
||||
<ion-icon color="medium" [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="ion-text-wrap">
|
||||
<h2 class="name">{{ item.name }}</h2>
|
||||
<ion-note>{{ item.type }}</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'description' | propertyNameTranslate: item | titlecase"
|
||||
[content]="'description' | thingTranslate: item"
|
||||
></stapps-simple-card>
|
||||
</ng-container>
|
||||
</div>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
contentTemplateRef || defaultContent;
|
||||
context: {$implicit: item}
|
||||
"
|
||||
>
|
||||
</ng-container>
|
||||
<stapps-origin-detail [origin]="item.origin"></stapps-origin-detail>
|
||||
|
||||
<ng-template #defaultContent>
|
||||
<div [ngSwitch]="item.type">
|
||||
<stapps-article-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'article'"
|
||||
></stapps-article-detail-content>
|
||||
<stapps-catalog-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'catalog'"
|
||||
></stapps-catalog-detail-content>
|
||||
<stapps-date-series-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'date series'"
|
||||
></stapps-date-series-detail-content>
|
||||
<stapps-dish-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'dish'"
|
||||
></stapps-dish-detail-content>
|
||||
<stapps-event-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'academic event'"
|
||||
></stapps-event-detail-content>
|
||||
<stapps-event-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'sport course'"
|
||||
></stapps-event-detail-content>
|
||||
<stapps-favorite-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'favorite'"
|
||||
></stapps-favorite-detail-content>
|
||||
<stapps-message-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'message'"
|
||||
></stapps-message-detail-content>
|
||||
<stapps-person-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'person'"
|
||||
></stapps-person-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'building'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'floor'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'point of interest'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-place-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'room'"
|
||||
></stapps-place-detail-content>
|
||||
<stapps-semester-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'semester'"
|
||||
></stapps-semester-detail-content>
|
||||
<stapps-video-detail-content
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="'video'"
|
||||
></stapps-video-detail-content>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<ion-item class="ion-text-wrap" lines="inset">
|
||||
<ion-thumbnail slot="start" class="ion-margin-end">
|
||||
<ion-icon
|
||||
color="medium"
|
||||
[attr.name]="item.type | dataIcon"
|
||||
></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="ion-text-wrap">
|
||||
<h2 class="name">{{ item.name }}</h2>
|
||||
<ion-note>{{ item.type }}</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="$any('description' | propertyNameTranslate: item) | titlecase"
|
||||
[content]="'description' | thingTranslate: item"
|
||||
></stapps-simple-card>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion,@typescript-eslint/no-explicit-any */
|
||||
import {CUSTOM_ELEMENTS_SCHEMA, DebugElement} from '@angular/core';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {ActivatedRoute, RouterModule} from '@angular/router';
|
||||
@@ -118,9 +119,10 @@ describe('DataDetailComponent', () => {
|
||||
});
|
||||
|
||||
it('should get a data item', () => {
|
||||
comp.getItem(sampleThing.uid);
|
||||
comp.getItem(sampleThing.uid, false);
|
||||
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -128,6 +130,7 @@ describe('DataDetailComponent', () => {
|
||||
comp.ionViewWillEnter();
|
||||
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -135,6 +138,7 @@ describe('DataDetailComponent', () => {
|
||||
await comp.refresh(refresher);
|
||||
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(
|
||||
sampleThing.uid,
|
||||
true,
|
||||
);
|
||||
expect(refresher.complete).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2018, 2019 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component} from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
import {IonRefresher} from '@ionic/angular';
|
||||
import {IonRefresher, ViewWillEnter} from '@ionic/angular';
|
||||
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||
import {
|
||||
SCLanguageCode,
|
||||
@@ -26,6 +33,13 @@ import {DataProvider, DataScope} from '../data.provider';
|
||||
import {FavoritesService} from '../../favorites/favorites.service';
|
||||
import {take} from 'rxjs/operators';
|
||||
import {Network} from '@capacitor/network';
|
||||
import {DataListContext} from '../list/data-list.component';
|
||||
|
||||
export interface ExternalDataLoadEvent {
|
||||
uid: SCUuid;
|
||||
forceReload: boolean;
|
||||
resolve: (item: SCThings | null | undefined) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Component to display an SCThing detailed
|
||||
@@ -35,7 +49,7 @@ import {Network} from '@capacitor/network';
|
||||
styleUrls: ['data-detail.scss'],
|
||||
templateUrl: 'data-detail.html',
|
||||
})
|
||||
export class DataDetailComponent {
|
||||
export class DataDetailComponent implements ViewWillEnter {
|
||||
/**
|
||||
* The associated item
|
||||
*
|
||||
@@ -53,6 +67,25 @@ export class DataDetailComponent {
|
||||
*/
|
||||
isDisconnected: Promise<boolean>;
|
||||
|
||||
@ContentChild(TemplateRef) contentTemplateRef: TemplateRef<
|
||||
DataListContext<SCThings>
|
||||
>;
|
||||
|
||||
@Input() externalData = false;
|
||||
|
||||
/**
|
||||
* This is kind of a stupid situation where we would
|
||||
* like to use the default header in overriding elements
|
||||
* such as the assessment detail page, however the ionic
|
||||
* back button will not work if the header is in a subcomponent
|
||||
* which then means we have to copy and paste the header from
|
||||
* here into the overriding component.
|
||||
*/
|
||||
@Input() defaultHeader = true;
|
||||
|
||||
@Output() loadItem: EventEmitter<ExternalDataLoadEvent> =
|
||||
new EventEmitter<ExternalDataLoadEvent>();
|
||||
|
||||
/**
|
||||
* Type guard for SCSavableThing
|
||||
*/
|
||||
@@ -90,11 +123,22 @@ export class DataDetailComponent {
|
||||
* Provides data item with given UID
|
||||
*
|
||||
* @param uid Unique identifier of a thing
|
||||
* @param forceReload Indicating whether cached data should be ignored
|
||||
*/
|
||||
async getItem(uid: SCUuid) {
|
||||
async getItem(uid: SCUuid, forceReload: boolean) {
|
||||
try {
|
||||
const item = await this.dataProvider.get(uid, DataScope.Remote);
|
||||
this.item = DataDetailComponent.isSCSavableThing(item) ? item.data : item;
|
||||
const item = await (this.externalData
|
||||
? new Promise<SCThings | null | undefined>(resolve =>
|
||||
this.loadItem.emit({uid, forceReload, resolve}),
|
||||
)
|
||||
: this.dataProvider.get(uid, DataScope.Remote));
|
||||
|
||||
this.item = !item
|
||||
? // eslint-disable-next-line unicorn/no-null
|
||||
null
|
||||
: DataDetailComponent.isSCSavableThing(item)
|
||||
? item.data
|
||||
: item;
|
||||
} catch {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
this.item = null;
|
||||
@@ -106,7 +150,7 @@ export class DataDetailComponent {
|
||||
*/
|
||||
async ionViewWillEnter() {
|
||||
const uid = this.route.snapshot.paramMap.get('uid') || '';
|
||||
await this.getItem(uid ?? '');
|
||||
await this.getItem(uid ?? '', false);
|
||||
// fallback to the saved item (from favorites)
|
||||
if (this.item === null) {
|
||||
this.favoritesService
|
||||
@@ -126,7 +170,7 @@ export class DataDetailComponent {
|
||||
* @param refresher Refresher component that triggers the update
|
||||
*/
|
||||
async refresh(refresher: IonRefresher) {
|
||||
await this.getItem(this.route.snapshot.paramMap.get('uid') ?? '');
|
||||
await this.getItem(this.route.snapshot.paramMap.get('uid') ?? '', true);
|
||||
await refresher.complete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<ion-header>
|
||||
<ion-header *ngIf="defaultHeader">
|
||||
<ion-toolbar color="primary">
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
@@ -8,11 +8,12 @@
|
||||
<ion-buttons slot="primary">
|
||||
<stapps-favorite-button
|
||||
*ngIf="item"
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
></stapps-favorite-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ng-content select="[header]"></ng-content>
|
||||
<ion-content class="ion-no-padding">
|
||||
<ion-refresher slot="fixed" (ionRefresh)="refresh($event.target)">
|
||||
<ion-refresher-content
|
||||
@@ -44,7 +45,10 @@
|
||||
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<stapps-data-detail-content [item]="item"></stapps-data-detail-content>
|
||||
<stapps-data-detail-content
|
||||
[item]="item"
|
||||
[contentTemplateRef]="contentTemplateRef"
|
||||
></stapps-data-detail-content>
|
||||
</ng-container>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {Component, ContentChild, Input, TemplateRef} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
import {DataRoutingService} from '../data-routing.service';
|
||||
import {DataListContext} from './data-list.component';
|
||||
|
||||
/**
|
||||
* Shows data items in lists such es search result
|
||||
@@ -35,6 +36,12 @@ export class DataListItemComponent {
|
||||
*/
|
||||
@Input() item: SCThings;
|
||||
|
||||
@Input() favoriteButton = true;
|
||||
|
||||
@ContentChild(TemplateRef) contentTemplateRef: TemplateRef<
|
||||
DataListContext<SCThings>
|
||||
>;
|
||||
|
||||
constructor(private readonly dataRoutingService: DataRoutingService) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,66 +8,83 @@
|
||||
<ion-thumbnail slot="start" *ngIf="!hideThumbnail" class="ion-margin-end">
|
||||
<ion-icon color="medium" [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ng-container *ngIf="contentTemplateRef; else defaultContent">
|
||||
<ion-label class="ion-text-wrap" [ngSwitch]="true">
|
||||
<div>
|
||||
<ng-container
|
||||
*ngTemplateOutlet="contentTemplateRef; context: {$implicit: item}"
|
||||
></ng-container>
|
||||
</div>
|
||||
</ion-label>
|
||||
</ng-container>
|
||||
|
||||
<stapps-favorite-button
|
||||
*ngIf="favoriteButton"
|
||||
[item]="$any(item)"
|
||||
></stapps-favorite-button>
|
||||
</ion-item>
|
||||
|
||||
<ng-template #defaultContent>
|
||||
<ion-label class="ion-text-wrap" [ngSwitch]="true">
|
||||
<div>
|
||||
<stapps-catalog-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'catalog'"
|
||||
></stapps-catalog-list-item>
|
||||
<stapps-date-series-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'date series'"
|
||||
></stapps-date-series-list-item>
|
||||
<stapps-dish-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'dish'"
|
||||
></stapps-dish-list-item>
|
||||
<stapps-event-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'academic event'"
|
||||
></stapps-event-list-item>
|
||||
<stapps-event-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'sport course'"
|
||||
></stapps-event-list-item>
|
||||
<stapps-favorite-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'favorite'"
|
||||
></stapps-favorite-list-item>
|
||||
<stapps-message-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'message'"
|
||||
></stapps-message-list-item>
|
||||
<stapps-organization-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'organization'"
|
||||
></stapps-organization-list-item>
|
||||
<stapps-person-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'person'"
|
||||
></stapps-person-list-item>
|
||||
<stapps-place-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'building'"
|
||||
></stapps-place-list-item>
|
||||
<stapps-place-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'floor'"
|
||||
></stapps-place-list-item>
|
||||
<stapps-place-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'point of interest'"
|
||||
></stapps-place-list-item>
|
||||
<stapps-place-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'room'"
|
||||
></stapps-place-list-item>
|
||||
<stapps-semester-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'semester'"
|
||||
></stapps-semester-list-item>
|
||||
<stapps-video-list-item
|
||||
[item]="item"
|
||||
[item]="$any(item)"
|
||||
*ngSwitchCase="item.type === 'video'"
|
||||
></stapps-video-list-item>
|
||||
<div *ngSwitchDefault>
|
||||
@@ -87,5 +104,4 @@
|
||||
></stapps-action-chip-list>
|
||||
</div>
|
||||
</ion-label>
|
||||
<stapps-favorite-button [item]="item"></stapps-favorite-button>
|
||||
</ion-item>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {CdkVirtualScrollViewport} from '@angular/cdk/scrolling';
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
@@ -23,11 +24,16 @@ import {
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
import {BehaviorSubject, Observable, Subscription} from 'rxjs';
|
||||
|
||||
export interface DataListContext<T> {
|
||||
$implicit: T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the list of items
|
||||
*/
|
||||
@@ -47,6 +53,10 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
|
||||
*/
|
||||
@Input() items?: SCThings[];
|
||||
|
||||
@ContentChild(TemplateRef) listItemTemplateRef: TemplateRef<
|
||||
DataListContext<SCThings>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Stream of SCThings for virtual scroll to consume
|
||||
*/
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
(scrolledIndexChange)="scrolled($event)"
|
||||
[style.display]="items && items.length ? 'block' : 'none'"
|
||||
>
|
||||
<ng-content select="[header]"></ng-content>
|
||||
<ion-list>
|
||||
<stapps-data-list-item
|
||||
*cdkVirtualFor="let item of items; trackBy: identifyItem"
|
||||
[item]="item"
|
||||
[hideThumbnail]="singleType"
|
||||
></stapps-data-list-item>
|
||||
<ng-container *cdkVirtualFor="let item of items; trackBy: identifyItem">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
listItemTemplateRef || defaultListItem;
|
||||
context: {$implicit: item}
|
||||
"
|
||||
></ng-container>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</ng-container>
|
||||
@@ -28,3 +32,10 @@
|
||||
*ngFor="let skeleton of [].constructor(skeletonItems)"
|
||||
></stapps-skeleton-list-item>
|
||||
</ion-list>
|
||||
|
||||
<ng-template let-item #defaultListItem>
|
||||
<stapps-data-list-item
|
||||
[item]="item"
|
||||
[hideThumbnail]="singleType"
|
||||
></stapps-data-list-item>
|
||||
</ng-template>
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ContentChild,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
TemplateRef,
|
||||
} from '@angular/core';
|
||||
import {SCThings} from '@openstapps/core';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {Router} from '@angular/router';
|
||||
import {DataRoutingService} from '../data-routing.service';
|
||||
import {DataListContext} from './data-list.component';
|
||||
|
||||
/**
|
||||
* Shows the list of items
|
||||
@@ -30,18 +38,24 @@ export class SimpleDataListComponent implements OnInit, OnDestroy {
|
||||
/**
|
||||
* All SCThings to display
|
||||
*/
|
||||
@Input() items?: SCThings[];
|
||||
@Input() items?: Promise<SCThings[] | undefined>;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the list is to display SCThings of a single type
|
||||
*/
|
||||
@Input() singleType = false;
|
||||
|
||||
@Input() autoRouting = true;
|
||||
|
||||
/**
|
||||
* List header
|
||||
*/
|
||||
@Input() listHeader?: string;
|
||||
|
||||
@ContentChild(TemplateRef) listItemTemplateRef: TemplateRef<
|
||||
DataListContext<SCThings>
|
||||
>;
|
||||
|
||||
/**
|
||||
* Items that display the skeleton list
|
||||
*/
|
||||
@@ -58,6 +72,7 @@ export class SimpleDataListComponent implements OnInit, OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.autoRouting) return;
|
||||
this.subscriptions.push(
|
||||
this.dataRoutingService.itemSelectListener().subscribe(item => {
|
||||
void this.router.navigate(['data-detail', item.uid]);
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<ng-container *ngIf="items | async as items; else loading">
|
||||
<ion-list>
|
||||
<ng-container *ngIf="!listHeader; else header"></ng-container>
|
||||
<stapps-data-list-item
|
||||
*ngFor="let item of items"
|
||||
[item]="item"
|
||||
[hideThumbnail]="singleType"
|
||||
></stapps-data-list-item>
|
||||
<ng-container *ngFor="let item of items">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="
|
||||
listItemTemplateRef || defaultListItem;
|
||||
context: {$implicit: item}
|
||||
"
|
||||
></ng-container>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
</ng-container>
|
||||
<ng-template #loading>
|
||||
@@ -26,3 +29,9 @@
|
||||
</ion-text>
|
||||
</ion-list-header>
|
||||
</ng-template>
|
||||
<ng-template let-item #defaultListItem>
|
||||
<stapps-data-list-item
|
||||
[item]="item"
|
||||
[hideThumbnail]="singleType"
|
||||
></stapps-data-list-item>
|
||||
</ng-template>
|
||||
|
||||
Reference in New Issue
Block a user