MOBILE-2342 glossary: Implement index and mode-picker components
parent
507fd96d5c
commit
c2da659be3
|
@ -0,0 +1,51 @@
|
|||
// (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 { CommonModule } from '@angular/common';
|
||||
import { IonicModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
|
||||
import { AddonModGlossaryIndexComponent } from './index/index';
|
||||
import { AddonModGlossaryModePickerPopoverComponent } from './mode-picker/mode-picker';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModGlossaryIndexComponent,
|
||||
AddonModGlossaryModePickerPopoverComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
TranslateModule.forChild(),
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
CoreCourseComponentsModule
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
exports: [
|
||||
AddonModGlossaryIndexComponent,
|
||||
AddonModGlossaryModePickerPopoverComponent
|
||||
],
|
||||
entryComponents: [
|
||||
AddonModGlossaryIndexComponent,
|
||||
AddonModGlossaryModePickerPopoverComponent
|
||||
]
|
||||
})
|
||||
export class AddonModGlossaryComponentsModule {}
|
|
@ -0,0 +1,64 @@
|
|||
<!-- Buttons to add to the header. -->
|
||||
<core-navbar-buttons end>
|
||||
<button *ngIf="glossary" ion-button icon-only (click)="openModePicker($event)" [attr.aria-label]="'addon.mod_glossary.browsemode' | translate">
|
||||
<ion-icon name="funnel"></ion-icon>
|
||||
</button>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="650" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="canAdd" [priority]="600" [content]="'addon.mod_glossary.addentry' | translate" (action)="openNewEntry()" iconAction="add"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="size" [iconDescription]="'cube'" (action)="removeFiles()" [iconAction]="'trash'"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
<!-- Content. -->
|
||||
<core-split-view>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="loaded" (ionRefresh)="doRefresh($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description>
|
||||
|
||||
<!-- Glossary entries found to be synchronized -->
|
||||
<ion-card class="core-warning-card" icon-start *ngIf="hasOffline">
|
||||
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: moduleName} }}
|
||||
</ion-card>
|
||||
|
||||
<core-search-box *ngIf="viewMode == 'search'" (onSubmit)="search($event)" [placeholder]="'addon.mod_glossary.searchquery' | translate" [autoFocus]="true" [lengthCheck]="2" [showClear]="false"></core-search-box>
|
||||
|
||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
|
||||
<ion-list *ngIf="viewMode != 'search' && offlineEntries.length > 0">
|
||||
<ion-item-divider color="light">
|
||||
{{ 'addon.mod_glossary.entriestobesynced' | translate }}
|
||||
</ion-item-divider>
|
||||
<ion-item *ngFor="let entry of offlineEntries" (click)="openNewEntry(entry)">
|
||||
<p>{{entry.concept}}</p>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
|
||||
<ion-list *ngIf="entries.length > 0">
|
||||
<ng-container *ngFor="let entry of entries; let index = index">
|
||||
|
||||
<ion-item-divider color="light" *ngIf="showDivider(entry, entries[index - 1])">
|
||||
{{getDivider(entry)}}
|
||||
</ion-item-divider>
|
||||
|
||||
<ion-item (click)="openEntry(entry.id)" [class.core-split-item-selected]="entry.id == selectedEntry">
|
||||
<p>{{entry.concept}}</p>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
|
||||
<core-empty-box *ngIf="!entries.length && !offlineEntries.length" icon="list" [message]="'addon.mod_glossary.noentriesfound' | translate"></core-empty-box>
|
||||
|
||||
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(loadMoreEntries())">
|
||||
<ion-infinite-scroll-content></ion-infinite-scroll-content>
|
||||
</ion-infinite-scroll>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
</core-split-view>
|
|
@ -0,0 +1,400 @@
|
|||
// (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, ViewChild } from '@angular/core';
|
||||
import { Content, PopoverController } from 'ionic-angular';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
||||
import { AddonModGlossaryProvider } from '../../providers/glossary';
|
||||
import { AddonModGlossaryOfflineProvider } from '../../providers/offline';
|
||||
import { AddonModGlossarySyncProvider } from '../../providers/sync';
|
||||
import { AddonModGlossaryModePickerPopoverComponent } from '../mode-picker/mode-picker';
|
||||
|
||||
type FetchMode = 'author_all' | 'cat_all' | 'newest_first' | 'recently_updated' | 'search' | 'letter_all';
|
||||
|
||||
/**
|
||||
* Component that displays a glossary entry page.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-glossary-index',
|
||||
templateUrl: 'index.html',
|
||||
})
|
||||
export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivityComponent {
|
||||
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
||||
@ViewChild(Content) content: Content;
|
||||
|
||||
component = AddonModGlossaryProvider.COMPONENT;
|
||||
moduleName = 'glossary';
|
||||
|
||||
fetchMode: FetchMode;
|
||||
viewMode: string;
|
||||
isSearch = false;
|
||||
entries = [];
|
||||
offlineEntries = [];
|
||||
canAdd = false;
|
||||
canLoadMore = false;
|
||||
loadingMessage = this.translate.instant('core.loading');
|
||||
selectedEntry: number;
|
||||
|
||||
protected syncEventName = AddonModGlossarySyncProvider.AUTO_SYNCED;
|
||||
protected glossary: any;
|
||||
protected fetchFunction: Function;
|
||||
protected fetchInvalidate: Function;
|
||||
protected fetchArguments: any[];
|
||||
protected showDivider: (entry: any, previous?: any) => boolean;
|
||||
protected getDivider: (entry: any) => string;
|
||||
protected addEntryObserver: any;
|
||||
|
||||
constructor(injector: Injector,
|
||||
private popoverCtrl: PopoverController,
|
||||
private glossaryProvider: AddonModGlossaryProvider,
|
||||
private glossaryOffline: AddonModGlossaryOfflineProvider,
|
||||
private glossarySync: AddonModGlossarySyncProvider) {
|
||||
super(injector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
super.ngOnInit();
|
||||
|
||||
// When an entry is added, we reload the data.
|
||||
this.addEntryObserver = this.eventsProvider.on(AddonModGlossaryProvider.ADD_ENTRY_EVENT, this.eventReceived.bind(this));
|
||||
|
||||
this.loadContent(false, true).then(() => {
|
||||
if (!this.glossary) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.splitviewCtrl.isOn()) {
|
||||
// Load the first entry.
|
||||
if (this.entries.length > 0) {
|
||||
this.openEntry(this.entries[0].id);
|
||||
}
|
||||
}
|
||||
|
||||
this.glossaryProvider.logView(this.glossary.id, this.viewMode).then(() => {
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
}).catch((error) => {
|
||||
// Ignore errors.
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the component contents.
|
||||
*
|
||||
* @param {boolean} [refresh=false] Whether we're refreshing data.
|
||||
* @param {boolean} [sync=false] If the refresh needs syncing.
|
||||
* @param {boolean} [showErrors=false] Wether to show errors to the user or hide them.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
|
||||
return this.glossaryProvider.getGlossary(this.courseId, this.module.id).then((glossary) => {
|
||||
this.glossary = glossary;
|
||||
|
||||
this.description = glossary.intro || this.description;
|
||||
this.canAdd = (this.glossaryProvider.isPluginEnabledForEditing() && glossary.canaddentry) || false;
|
||||
|
||||
if (!this.fetchMode) {
|
||||
this.switchMode('letter_all');
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize the glossary.
|
||||
return this.syncActivity(showErrors);
|
||||
}
|
||||
}).then(() => {
|
||||
|
||||
return this.fetchEntries().then(() => {
|
||||
// Check if there are responses stored in offline.
|
||||
return this.glossaryOffline.getGlossaryNewEntries(this.glossary.id).then((offlineEntries) => {
|
||||
offlineEntries.sort((a, b) => a.concept.localeCompare(b.fullname));
|
||||
this.hasOffline = !!offlineEntries.length;
|
||||
this.offlineEntries = offlineEntries || [];
|
||||
});
|
||||
});
|
||||
}).then(() => {
|
||||
// All data obtained, now fill the context menu.
|
||||
this.fillContextMenu(refresh);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to fetch entries.
|
||||
*
|
||||
* @param {boolean} [append=false] True if fetched entries are appended to exsiting ones.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected fetchEntries(append: boolean = false): Promise<any> {
|
||||
if (!this.fetchFunction || !this.fetchArguments) {
|
||||
// This happens in search mode with an empty query.
|
||||
return Promise.resolve({entries: [], count: 0});
|
||||
}
|
||||
|
||||
const limitFrom = append ? this.entries.length : 0;
|
||||
const limitNum = AddonModGlossaryProvider.LIMIT_ENTRIES;
|
||||
|
||||
return this.glossaryProvider.fetchEntries(this.fetchFunction, this.fetchArguments, limitFrom, limitNum).then((result) => {
|
||||
if (append) {
|
||||
Array.prototype.push.apply(this.entries, result.entries);
|
||||
} else {
|
||||
this.entries = result.entries;
|
||||
}
|
||||
this.canLoadMore = this.entries.length < result.count;
|
||||
}).catch((error) => {
|
||||
this.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
* @return {Promise<any>} Resolved when done.
|
||||
*/
|
||||
protected invalidateContent(): Promise<any> {
|
||||
const promises = [];
|
||||
|
||||
if (this.fetchInvalidate && this.fetchArguments) {
|
||||
promises.push(this.fetchInvalidate.apply(this.glossaryProvider, this.fetchArguments));
|
||||
}
|
||||
|
||||
promises.push(this.glossaryProvider.invalidateCourseGlossaries(this.courseId));
|
||||
|
||||
if (this.glossary && this.glossary.id) {
|
||||
promises.push(this.glossaryProvider.invalidateCategories(this.glossary.id));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the sync of the activity.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected sync(): Promise<boolean> {
|
||||
return this.glossarySync.syncGlossaryEntries(this.glossary.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if sync has succeed from result sync data.
|
||||
*
|
||||
* @param {any} result Data returned on the sync function.
|
||||
* @return {boolean} Whether it succeed or not.
|
||||
*/
|
||||
protected hasSyncSucceed(result: any): boolean {
|
||||
return result.updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares sync event data with current data to check if refresh content is needed.
|
||||
*
|
||||
* @param {any} syncEventData Data receiven on sync observer.
|
||||
* @return {boolean} True if refresh is needed, false otherwise.
|
||||
*/
|
||||
protected isRefreshSyncNeeded(syncEventData: any): boolean {
|
||||
return this.glossary && syncEventData.glossaryId == this.glossary.id &&
|
||||
syncEventData.userId == this.sitesProvider.getCurrentSiteUserId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change fetch mode.
|
||||
*
|
||||
* @param {FetchMode} mode New mode.
|
||||
*/
|
||||
protected switchMode(mode: FetchMode): void {
|
||||
this.fetchMode = mode;
|
||||
|
||||
switch (mode) {
|
||||
case 'author_all':
|
||||
// Browse by author.
|
||||
this.viewMode = 'author';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesByAuthor;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesByAuthor;
|
||||
this.fetchArguments = [this.glossary.id, 'ALL', 'LASTNAME', 'ASC'];
|
||||
this.getDivider = (entry: any): string => entry.userfullname;
|
||||
this.showDivider = (entry: any, previous?: any): boolean => {
|
||||
return previous === 'undefined' || entry.userid != previous.userid;
|
||||
};
|
||||
break;
|
||||
case 'cat_all':
|
||||
// Browse by category.
|
||||
this.viewMode = 'cat';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesByCategory;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesByCategory;
|
||||
this.fetchArguments = [this.glossary.id, AddonModGlossaryProvider.SHOW_ALL_CATERGORIES];
|
||||
this.getDivider = (entry: any): string => entry.categoryname;
|
||||
this.showDivider = (entry?: any, previous?: any): boolean => {
|
||||
return !previous || this.getDivider(entry) != this.getDivider(previous);
|
||||
};
|
||||
break;
|
||||
case 'newest_first':
|
||||
// Newest first.
|
||||
this.viewMode = 'date';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesByDate;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesByDate;
|
||||
this.fetchArguments = [this.glossary.id, 'CREATION', 'DESC'];
|
||||
this.getDivider = null;
|
||||
this.showDivider = (): boolean => false;
|
||||
break;
|
||||
case 'recently_updated':
|
||||
// Recently updated.
|
||||
this.viewMode = 'date';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesByDate;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesByDate;
|
||||
this.fetchArguments = [this.glossary.id, 'UPDATE', 'DESC'];
|
||||
this.getDivider = null;
|
||||
this.showDivider = (): boolean => false;
|
||||
break;
|
||||
case 'search':
|
||||
// Search for entries.
|
||||
this.viewMode = 'search';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesBySearch;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesBySearch;
|
||||
this.fetchArguments = null; // Dynamically set later.
|
||||
this.getDivider = null;
|
||||
this.showDivider = (): boolean => false;
|
||||
break;
|
||||
case 'letter_all':
|
||||
default:
|
||||
// Consider it is 'letter_all'.
|
||||
this.viewMode = 'letter';
|
||||
this.fetchMode = 'letter_all';
|
||||
this.fetchFunction = this.glossaryProvider.getEntriesByLetter;
|
||||
this.fetchInvalidate = this.glossaryProvider.invalidateEntriesByLetter;
|
||||
this.fetchArguments = [this.glossary.id, 'ALL'];
|
||||
this.getDivider = (entry: any): string => entry.concept.substr(0, 1).toUpperCase();
|
||||
this.showDivider = (entry?: any, previous?: any): boolean => {
|
||||
return !previous || this.getDivider(entry) != this.getDivider(previous);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to load more forum discussions.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
loadMoreEntries(): Promise<any> {
|
||||
return this.fetchEntries(true).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentries', true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the mode picker menu.
|
||||
*
|
||||
* @param {MouseEvent} event Event.
|
||||
*/
|
||||
openModePicker(event: MouseEvent): void {
|
||||
const popover = this.popoverCtrl.create(AddonModGlossaryModePickerPopoverComponent, {
|
||||
glossary: this.glossary,
|
||||
selectedMode: this.fetchMode
|
||||
});
|
||||
|
||||
popover.onDidDismiss((newMode: FetchMode) => {
|
||||
if (newMode === this.fetchMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadingMessage = this.translate.instant('core.loading');
|
||||
this.content.scrollToTop();
|
||||
this.switchMode(newMode);
|
||||
|
||||
if (this.fetchMode === 'search') {
|
||||
// If it's not an instant search, then we reset the values.
|
||||
this.entries = [];
|
||||
this.canLoadMore = false;
|
||||
} else {
|
||||
this.loaded = false;
|
||||
this.loadContent();
|
||||
}
|
||||
});
|
||||
|
||||
popover.present({
|
||||
ev: event
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an entry.
|
||||
*
|
||||
* @param {number} entryId Entry id.
|
||||
*/
|
||||
openEntry(entryId: number): void {
|
||||
const params = {
|
||||
courseId: this.courseId,
|
||||
entryId: entryId,
|
||||
};
|
||||
this.splitviewCtrl.push('AddonModGlossaryEntryPage', params);
|
||||
this.selectedEntry = entryId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens new entry editor.
|
||||
*
|
||||
* @param {any} [entry] Offline entry to edit.
|
||||
*/
|
||||
openNewEntry(entry?: any): void {
|
||||
const params = {
|
||||
courseId: this.courseId,
|
||||
module: this.module,
|
||||
glossary: this.glossary,
|
||||
entry: entry,
|
||||
};
|
||||
this.splitviewCtrl.getMasterNav().push('AddonModGlossaryEditPage', params);
|
||||
this.selectedEntry = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search entries.
|
||||
*
|
||||
* @param {string} query Text entered on the search box.
|
||||
*/
|
||||
search(query: string): void {
|
||||
this.loadingMessage = this.translate.instant('core.searching');
|
||||
this.fetchArguments = [this.glossary.id, query, 1, 'CONCEPT', 'ASC'];
|
||||
this.loaded = false;
|
||||
this.loadContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when we receive an event of new entry.
|
||||
*
|
||||
* @param {any} data Event data.
|
||||
*/
|
||||
protected eventReceived(data: any): void {
|
||||
if (this.glossary && this.glossary.id === data.glossaryId) {
|
||||
this.loaded = false;
|
||||
this.loadContent();
|
||||
|
||||
// Check completion since it could be configured to complete once the user adds a new discussion or replies.
|
||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
|
||||
this.addEntryObserver && this.addEntryObserver.off();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<ion-list radio-group [(ngModel)]="selectedMode">
|
||||
<ion-item text-wrap *ngFor="let mode of modes" >
|
||||
<ion-label>{{mode.langkey | translate}}</ion-label>
|
||||
<ion-radio [value]="mode.key" (ionSelect)="modePicked($event, mode.key)" ></ion-radio>
|
||||
</ion-item>
|
||||
</ion-list>
|
|
@ -0,0 +1,69 @@
|
|||
// (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 } from '@angular/core';
|
||||
import { NavParams, ViewController } from 'ionic-angular';
|
||||
|
||||
/**
|
||||
* Component to display the mode picker.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'addon-mod-glossary-mode-picker-popover',
|
||||
templateUrl: 'mode-picker.html'
|
||||
})
|
||||
export class AddonModGlossaryModePickerPopoverComponent {
|
||||
modes = [];
|
||||
selectedMode: string;
|
||||
|
||||
constructor(navParams: NavParams, private viewCtrl: ViewController) {
|
||||
this.selectedMode = navParams.get('selectedMode');
|
||||
const glossary = navParams.get('glossary');
|
||||
|
||||
// Preparing browse modes.
|
||||
this.modes = [
|
||||
{key: 'search', langkey: 'addon.mod_glossary.bysearch'}
|
||||
];
|
||||
glossary.browsemodes.forEach((mode) => {
|
||||
switch (mode) {
|
||||
case 'letter' :
|
||||
this.modes.push({key: 'letter_all', langkey: 'addon.mod_glossary.byalphabet'});
|
||||
break;
|
||||
case 'cat' :
|
||||
this.modes.push({key: 'cat_all', langkey: 'addon.mod_glossary.bycategory'});
|
||||
break;
|
||||
case 'date' :
|
||||
this.modes.push({key: 'newest_first', langkey: 'addon.mod_glossary.bynewestfirst'});
|
||||
this.modes.push({key: 'recently_updated', langkey: 'addon.mod_glossary.byrecentlyupdated'});
|
||||
break;
|
||||
case 'author' :
|
||||
this.modes.push({key: 'author_all', langkey: 'addon.mod_glossary.byauthor'});
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when a mode is clicked.
|
||||
*
|
||||
* @param {Event} event Click event.
|
||||
* @param {string} key Clicked mode key.
|
||||
* @return {boolean} Return true if success, false if error.
|
||||
*/
|
||||
modePicked(event: Event, key: string): boolean {
|
||||
this.viewCtrl.dismiss(key);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -15,15 +15,21 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { AddonModGlossaryProvider } from './providers/glossary';
|
||||
import { AddonModGlossaryOfflineProvider } from './providers/offline';
|
||||
import { AddonModGlossaryHelperProvider } from './providers/helper';
|
||||
import { AddonModGlossarySyncProvider } from './providers/sync';
|
||||
import { AddonModGlossaryComponentsModule } from './components/components.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
],
|
||||
imports: [
|
||||
AddonModGlossaryComponentsModule,
|
||||
],
|
||||
providers: [
|
||||
AddonModGlossaryProvider,
|
||||
AddonModGlossaryOfflineProvider,
|
||||
AddonModGlossaryHelperProvider,
|
||||
AddonModGlossarySyncProvider,
|
||||
]
|
||||
})
|
||||
export class AddonModGlossaryModule {
|
||||
|
|
Loading…
Reference in New Issue