commit
01eaffa3de
|
@ -20,7 +20,9 @@
|
||||||
"addon.block_myoverview.nocoursesinprogress": "block_myoverview",
|
"addon.block_myoverview.nocoursesinprogress": "block_myoverview",
|
||||||
"addon.block_myoverview.nocoursespast": "block_myoverview",
|
"addon.block_myoverview.nocoursespast": "block_myoverview",
|
||||||
"addon.block_myoverview.past": "block_myoverview",
|
"addon.block_myoverview.past": "block_myoverview",
|
||||||
|
"addon.block_myoverview.pluginname": "block_myoverview",
|
||||||
"addon.block_myoverview.title": "block_myoverview",
|
"addon.block_myoverview.title": "block_myoverview",
|
||||||
|
"addon.block_recentcourses.nocourses": "moodle",
|
||||||
"addon.block_sitemainmenu.pluginname": "block_site_main_menu",
|
"addon.block_sitemainmenu.pluginname": "block_site_main_menu",
|
||||||
"addon.block_timeline.duedate": "block_timeline",
|
"addon.block_timeline.duedate": "block_timeline",
|
||||||
"addon.block_timeline.next30days": "block_timeline",
|
"addon.block_timeline.next30days": "block_timeline",
|
||||||
|
@ -30,6 +32,7 @@
|
||||||
"addon.block_timeline.nocoursesinprogress": "block_timeline",
|
"addon.block_timeline.nocoursesinprogress": "block_timeline",
|
||||||
"addon.block_timeline.noevents": "block_timeline",
|
"addon.block_timeline.noevents": "block_timeline",
|
||||||
"addon.block_timeline.overdue": "block_timeline",
|
"addon.block_timeline.overdue": "block_timeline",
|
||||||
|
"addon.block_timeline.pluginname": "block_timeline",
|
||||||
"addon.block_timeline.sortbycourses": "block_timeline",
|
"addon.block_timeline.sortbycourses": "block_timeline",
|
||||||
"addon.block_timeline.sortbydates": "block_timeline",
|
"addon.block_timeline.sortbydates": "block_timeline",
|
||||||
"addon.calendar.calendar": "calendar",
|
"addon.calendar.calendar": "calendar",
|
||||||
|
@ -1192,7 +1195,6 @@
|
||||||
"core.courses.searchcoursesadvice": "local_moodlemobileapp",
|
"core.courses.searchcoursesadvice": "local_moodlemobileapp",
|
||||||
"core.courses.selfenrolment": "local_moodlemobileapp",
|
"core.courses.selfenrolment": "local_moodlemobileapp",
|
||||||
"core.courses.sendpaymentbutton": "enrol_paypal",
|
"core.courses.sendpaymentbutton": "enrol_paypal",
|
||||||
"core.courses.timeline": "block_dashboard",
|
|
||||||
"core.courses.totalcoursesearchresults": "local_moodlemobileapp",
|
"core.courses.totalcoursesearchresults": "local_moodlemobileapp",
|
||||||
"core.currentdevice": "local_moodlemobileapp",
|
"core.currentdevice": "local_moodlemobileapp",
|
||||||
"core.datastoredoffline": "local_moodlemobileapp",
|
"core.datastoredoffline": "local_moodlemobileapp",
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
<ion-item-divider color="light">
|
||||||
|
<h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2>
|
||||||
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
<a ion-item text-wrap *ngFor="let entry of entries" class="item-media" detail-none [navPush]="'CoreCourseListModTypePage'" [navParams]="{title: entry.name, courseId: instanceId, modName: entry.modName}">
|
<a ion-item text-wrap *ngFor="let entry of entries" class="item-media" detail-none [navPush]="'CoreCourseListModTypePage'" [navParams]="{title: entry.name, courseId: instanceId, modName: entry.modName}">
|
||||||
<img item-start [src]="entry.icon" alt="" role="presentation" class="core-module-icon">
|
<img item-start [src]="entry.icon" alt="" role="presentation" class="core-module-icon">
|
||||||
|
|
|
@ -13,28 +13,20 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { CoreBlockHandler, CoreBlockHandlerData } from '@core/block/providers/delegate';
|
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||||
import { AddonBlockActivityModulesComponent } from '../components/activitymodules/activitymodules';
|
import { AddonBlockActivityModulesComponent } from '../components/activitymodules/activitymodules';
|
||||||
|
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Course nav handler.
|
* Block handler.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonBlockActivityModulesHandler implements CoreBlockHandler {
|
export class AddonBlockActivityModulesHandler extends CoreBlockBaseHandler {
|
||||||
name = 'AddonBlockActivityModulesHandler';
|
name = 'AddonBlockActivityModules';
|
||||||
blockName = 'activity_modules';
|
blockName = 'activity_modules';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Nothing to do.
|
super();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the handler is enabled on a site level.
|
|
||||||
*
|
|
||||||
* @return {boolean} Whether or not the handler is enabled on a site level.
|
|
||||||
*/
|
|
||||||
isEnabled(): boolean | Promise<boolean> {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
// (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 { CoreCoursesComponentsModule } from '@core/courses/components/components.module';
|
||||||
|
import { AddonBlockMyOverviewComponent } from './myoverview/myoverview';
|
||||||
|
import { CoreComponentsModule } from '@components/components.module';
|
||||||
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
|
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonBlockMyOverviewComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreComponentsModule,
|
||||||
|
CoreDirectivesModule,
|
||||||
|
CoreCoursesComponentsModule,
|
||||||
|
CoreCourseComponentsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AddonBlockMyOverviewComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AddonBlockMyOverviewComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonBlockMyOverviewComponentsModule {}
|
|
@ -1,10 +1,13 @@
|
||||||
<!-- Buttons to add to the header. -->
|
<!-- Buttons to add to the header. -->
|
||||||
<core-navbar-buttons end>
|
<core-navbar-buttons end>
|
||||||
<button [hidden]="!showFilterSwitchButton()" ion-button icon-only [attr.aria-label]="'core.courses.filtermycourses' | translate" (click)="switchFilter()">
|
<button [hidden]="!loaded || !showFilterSwitchButton()" ion-button icon-only [attr.aria-label]="'core.courses.filtermycourses' | translate" (click)="switchFilter()">
|
||||||
<ion-icon name="funnel"></ion-icon>
|
<ion-icon name="funnel"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
|
|
||||||
|
<ion-item-divider color="light">
|
||||||
|
<h2>{{ 'addon.block_myoverview.pluginname' | translate }}</h2>
|
||||||
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
<div padding ion-row justify-content-end [hidden]="showFilter">
|
<div padding ion-row justify-content-end [hidden]="showFilter">
|
||||||
<!-- "Time" selector. -->
|
<!-- "Time" selector. -->
|
|
@ -2,11 +2,12 @@
|
||||||
"all": "All",
|
"all": "All",
|
||||||
"future": "Future",
|
"future": "Future",
|
||||||
"inprogress": "In progress",
|
"inprogress": "In progress",
|
||||||
"past": "Past",
|
"lastaccessed": "Last accessed",
|
||||||
"morecourses": "More courses",
|
"morecourses": "More courses",
|
||||||
"nocoursesfuture": "No future courses",
|
"nocoursesfuture": "No future courses",
|
||||||
"nocoursesinprogress": "No in progress courses",
|
"nocoursesinprogress": "No in progress courses",
|
||||||
"nocoursespast": "No past courses",
|
"nocoursespast": "No past courses",
|
||||||
"lastaccessed": "Last accessed",
|
"past": "Past",
|
||||||
|
"pluginname": "Course Overview",
|
||||||
"title": "Title"
|
"title": "Title"
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,22 +15,26 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { IonicModule } from 'ionic-angular';
|
import { IonicModule } from 'ionic-angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { CoreComponentsModule } from '@components/components.module';
|
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||||
import { CoreCoursesComponentsModule } from '@core/courses/components/components.module';
|
import { AddonBlockMyOverviewComponentsModule } from './components/components.module';
|
||||||
import { AddonBlockMyOverviewComponent } from './component/myoverview';
|
import { AddonBlockMyOverviewHandler } from './providers/block-handler';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AddonBlockMyOverviewComponent
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule,
|
IonicModule,
|
||||||
CoreComponentsModule,
|
AddonBlockMyOverviewComponentsModule,
|
||||||
CoreCoursesComponentsModule,
|
|
||||||
TranslateModule.forChild()
|
TranslateModule.forChild()
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AddonBlockMyOverviewComponent
|
],
|
||||||
|
providers: [
|
||||||
|
AddonBlockMyOverviewHandler
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AddonBlockMyOverviewModule {}
|
export class AddonBlockMyOverviewModule {
|
||||||
|
constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockMyOverviewHandler) {
|
||||||
|
blockDelegate.registerHandler(blockHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
// (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 { Injectable, Injector } from '@angular/core';
|
||||||
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||||
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
|
import { AddonBlockMyOverviewComponent } from '../components/myoverview/myoverview';
|
||||||
|
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block handler.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonBlockMyOverviewHandler extends CoreBlockBaseHandler {
|
||||||
|
name = 'AddonBlockMyOverview';
|
||||||
|
blockName = 'myoverview';
|
||||||
|
|
||||||
|
constructor(private coursesProvider: CoreCoursesProvider, private sitesProvider: CoreSitesProvider) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handler is enabled on a site level.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether or not the handler is enabled on a site level.
|
||||||
|
*/
|
||||||
|
isEnabled(): boolean | Promise<boolean> {
|
||||||
|
return this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.6') ||
|
||||||
|
!this.coursesProvider.isMyCoursesDisabledInSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data needed to render the block.
|
||||||
|
*
|
||||||
|
* @param {Injector} injector Injector.
|
||||||
|
* @param {any} block The block to render.
|
||||||
|
* @param {string} contextLevel The context where the block will be used.
|
||||||
|
* @param {number} instanceId The instance ID associated with the context level.
|
||||||
|
* @return {CoreBlockHandlerData|Promise<CoreBlockHandlerData>} Data or promise resolved with the data.
|
||||||
|
*/
|
||||||
|
getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number)
|
||||||
|
: CoreBlockHandlerData | Promise<CoreBlockHandlerData> {
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: 'addon.block_myoverview.pluginname',
|
||||||
|
class: 'addon-block-myoverview',
|
||||||
|
component: AddonBlockMyOverviewComponent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
<ion-item-divider color="light">
|
||||||
|
<h2>{{ 'addon.block_sitemainmenu.pluginname' | translate }}</h2>
|
||||||
|
</ion-item-divider>
|
||||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
<ion-item text-wrap *ngIf="block.summary">
|
<ion-item text-wrap *ngIf="block.summary">
|
||||||
<core-format-text [text]="block.summary"></core-format-text>
|
<core-format-text [text]="block.summary"></core-format-text>
|
||||||
|
|
|
@ -13,28 +13,20 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { CoreBlockHandler, CoreBlockHandlerData } from '@core/block/providers/delegate';
|
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||||
import { AddonBlockSiteMainMenuComponent } from '../components/sitemainmenu/sitemainmenu';
|
import { AddonBlockSiteMainMenuComponent } from '../components/sitemainmenu/sitemainmenu';
|
||||||
|
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Course nav handler.
|
* Block handler.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonBlockSiteMainMenuHandler implements CoreBlockHandler {
|
export class AddonBlockSiteMainMenuHandler extends CoreBlockBaseHandler {
|
||||||
name = 'AddonBlockSiteMainMenuHandler';
|
name = 'AddonBlockSiteMainMenu';
|
||||||
blockName = 'site_main_menu';
|
blockName = 'site_main_menu';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Nothing to do.
|
super();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the handler is enabled on a site level.
|
|
||||||
*
|
|
||||||
* @return {boolean} Whether or not the handler is enabled on a site level.
|
|
||||||
*/
|
|
||||||
isEnabled(): boolean | Promise<boolean> {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
// (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 { CoreCoursesComponentsModule } from '@core/courses/components/components.module';
|
||||||
|
import { AddonBlockTimelineComponent } from './timeline/timeline';
|
||||||
|
import { AddonBlockTimelineEventsComponent } from './events/events';
|
||||||
|
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
AddonBlockTimelineComponent,
|
||||||
|
AddonBlockTimelineEventsComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
IonicModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
|
CoreComponentsModule,
|
||||||
|
CoreDirectivesModule,
|
||||||
|
CorePipesModule,
|
||||||
|
CoreCoursesComponentsModule,
|
||||||
|
CoreCourseComponentsModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
AddonBlockTimelineComponent,
|
||||||
|
AddonBlockTimelineEventsComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
AddonBlockTimelineComponent,
|
||||||
|
AddonBlockTimelineEventsComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class AddonBlockTimelineComponentsModule {}
|
|
@ -1,34 +1,39 @@
|
||||||
<div padding [hidden]="!loaded" ion-row>
|
<ion-item-divider color="light">
|
||||||
<ion-col>
|
<h2>{{ 'addon.block_timeline.pluginname' | translate }}</h2>
|
||||||
<ion-select text-start [(ngModel)]="filter" (ngModelChange)="switchFilter()" interface="popover" class="core-button-select">
|
</ion-item-divider>
|
||||||
<ion-option value="all">{{ 'core.all' | translate }}</ion-option>
|
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||||
<ion-option value="overdue">{{ 'addon.block_timeline.overdue' | translate }}</ion-option>
|
<div padding ion-row>
|
||||||
<ion-option disabled value="disabled">{{ 'addon.block_timeline.duedate' | translate }}</ion-option>
|
<ion-col>
|
||||||
<ion-option value="next7days">{{ 'addon.block_timeline.next7days' | translate }}</ion-option>
|
<ion-select text-start [(ngModel)]="filter" (ngModelChange)="switchFilter()" interface="popover" class="core-button-select">
|
||||||
<ion-option value="next30days">{{ 'addon.block_timeline.next30days' | translate }}</ion-option>
|
<ion-option value="all">{{ 'core.all' | translate }}</ion-option>
|
||||||
<ion-option value="next3months">{{ 'addon.block_timeline.next3months' | translate }}</ion-option>
|
<ion-option value="overdue">{{ 'addon.block_timeline.overdue' | translate }}</ion-option>
|
||||||
<ion-option value="next6months">{{ 'addon.block_timeline.next6months' | translate }}</ion-option>
|
<ion-option disabled value="disabled">{{ 'addon.block_timeline.duedate' | translate }}</ion-option>
|
||||||
</ion-select>
|
<ion-option value="next7days">{{ 'addon.block_timeline.next7days' | translate }}</ion-option>
|
||||||
</ion-col>
|
<ion-option value="next30days">{{ 'addon.block_timeline.next30days' | translate }}</ion-option>
|
||||||
<ion-col>
|
<ion-option value="next3months">{{ 'addon.block_timeline.next3months' | translate }}</ion-option>
|
||||||
<ion-select text-start [(ngModel)]="sort" (ngModelChange)="switchSort()" interface="popover" class="core-button-select">
|
<ion-option value="next6months">{{ 'addon.block_timeline.next6months' | translate }}</ion-option>
|
||||||
<ion-option value="sortbydates">{{ 'addon.block_timeline.sortbydates' | translate }}</ion-option>
|
</ion-select>
|
||||||
<ion-option value="sortbycourses">{{ 'addon.block_timeline.sortbycourses' | translate }}</ion-option>
|
</ion-col>
|
||||||
</ion-select>
|
<ion-col>
|
||||||
</ion-col>
|
<ion-select text-start [(ngModel)]="sort" (ngModelChange)="switchSort()" interface="popover" class="core-button-select">
|
||||||
</div>
|
<ion-option value="sortbydates">{{ 'addon.block_timeline.sortbydates' | translate }}</ion-option>
|
||||||
<core-loading [hideUntil]="loaded && timeline.loaded" [hidden]="sort != 'sortbydates'" class="core-loading-center">
|
<ion-option value="sortbycourses">{{ 'addon.block_timeline.sortbycourses' | translate }}</ion-option>
|
||||||
<addon-block-timeline-events [events]="timeline.events" showCourse="true" [canLoadMore]="timeline.canLoadMore" (loadMore)="loadMoreTimeline()" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events>
|
</ion-select>
|
||||||
</core-loading>
|
</ion-col>
|
||||||
<core-loading [hideUntil]="loaded && timelineCourses.loaded" [hidden]="sort != 'sortbycourses'" class="core-loading-center">
|
</div>
|
||||||
<ion-grid no-padding>
|
<core-loading [hideUntil]="timeline.loaded" [hidden]="sort != 'sortbydates'" class="core-loading-center">
|
||||||
<ion-row no-padding>
|
<addon-block-timeline-events [events]="timeline.events" showCourse="true" [canLoadMore]="timeline.canLoadMore" (loadMore)="loadMoreTimeline()" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events>
|
||||||
<ion-col *ngFor="let course of timelineCourses.courses" no-padding col-12 col-md-6>
|
</core-loading>
|
||||||
<core-courses-course-progress [course]="course">
|
<core-loading [hideUntil]="timelineCourses.loaded" [hidden]="sort != 'sortbycourses'" class="core-loading-center">
|
||||||
<addon-block-timeline-events [events]="course.events" [canLoadMore]="course.canLoadMore" (loadMore)="loadMoreCourse(course)" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events>
|
<ion-grid no-padding>
|
||||||
</core-courses-course-progress>
|
<ion-row no-padding>
|
||||||
</ion-col>
|
<ion-col *ngFor="let course of timelineCourses.courses" no-padding col-12 col-md-6>
|
||||||
</ion-row>
|
<core-courses-course-progress [course]="course">
|
||||||
</ion-grid>
|
<addon-block-timeline-events [events]="course.events" [canLoadMore]="course.canLoadMore" (loadMore)="loadMoreCourse(course)" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events>
|
||||||
<core-empty-box *ngIf="timelineCourses.courses.length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_timeline.nocoursesinprogress' | translate"></core-empty-box>
|
</core-courses-course-progress>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
<core-empty-box *ngIf="timelineCourses.courses.length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_timeline.nocoursesinprogress' | translate"></core-empty-box>
|
||||||
|
</core-loading>
|
||||||
</core-loading>
|
</core-loading>
|
|
@ -7,6 +7,7 @@
|
||||||
"nocoursesinprogress": "No in progress courses",
|
"nocoursesinprogress": "No in progress courses",
|
||||||
"noevents": "No upcoming activities due",
|
"noevents": "No upcoming activities due",
|
||||||
"overdue": "Overdue",
|
"overdue": "Overdue",
|
||||||
|
"pluginname": "Timeline",
|
||||||
"sortbycourses": "Sort by courses",
|
"sortbycourses": "Sort by courses",
|
||||||
"sortbydates": "Sort by dates"
|
"sortbydates": "Sort by dates"
|
||||||
}
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
// (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 { Injectable, Injector } from '@angular/core';
|
||||||
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
import { CoreBlockHandlerData } from '@core/block/providers/delegate';
|
||||||
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
|
import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/timeline';
|
||||||
|
import { AddonBlockTimelineComponent } from '../components/timeline/timeline';
|
||||||
|
import { CoreBlockBaseHandler } from '@core/block/classes/base-block-handler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block handler.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class AddonBlockTimelineHandler extends CoreBlockBaseHandler {
|
||||||
|
name = 'AddonBlockTimeline';
|
||||||
|
blockName = 'timeline';
|
||||||
|
|
||||||
|
constructor(private timelineProvider: AddonBlockTimelineProvider, private coursesProvider: CoreCoursesProvider,
|
||||||
|
private sitesProvider: CoreSitesProvider) {
|
||||||
|
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the handler is enabled on a site level.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether or not the handler is enabled on a site level.
|
||||||
|
*/
|
||||||
|
isEnabled(): boolean | Promise<boolean> {
|
||||||
|
return this.timelineProvider.isAvailable() && (this.sitesProvider.getCurrentSite().isVersionGreaterEqualThan('3.6') ||
|
||||||
|
!this.coursesProvider.isMyCoursesDisabledInSite());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data needed to render the block.
|
||||||
|
*
|
||||||
|
* @param {Injector} injector Injector.
|
||||||
|
* @param {any} block The block to render.
|
||||||
|
* @param {string} contextLevel The context where the block will be used.
|
||||||
|
* @param {number} instanceId The instance ID associated with the context level.
|
||||||
|
* @return {CoreBlockHandlerData|Promise<CoreBlockHandlerData>} Data or promise resolved with the data.
|
||||||
|
*/
|
||||||
|
getDisplayData?(injector: Injector, block: any, contextLevel: string, instanceId: number)
|
||||||
|
: CoreBlockHandlerData | Promise<CoreBlockHandlerData> {
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: 'addon.block_timeline.pluginname',
|
||||||
|
class: 'addon-block-timeline',
|
||||||
|
component: AddonBlockTimelineComponent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,33 +15,28 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { IonicModule } from 'ionic-angular';
|
import { IonicModule } from 'ionic-angular';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { CoreComponentsModule } from '@components/components.module';
|
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
import { AddonBlockTimelineComponentsModule } from './components/components.module';
|
||||||
import { CorePipesModule } from '@pipes/pipes.module';
|
|
||||||
import { CoreCoursesComponentsModule } from '@core/courses/components/components.module';
|
|
||||||
import { AddonBlockTimelineComponent } from './components/timeline/timeline';
|
|
||||||
import { AddonBlockTimelineEventsComponent } from './components/events/events';
|
|
||||||
import { AddonBlockTimelineProvider } from './providers/timeline';
|
import { AddonBlockTimelineProvider } from './providers/timeline';
|
||||||
|
import { AddonBlockTimelineHandler } from './providers/block-handler';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AddonBlockTimelineComponent,
|
|
||||||
AddonBlockTimelineEventsComponent
|
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
IonicModule,
|
IonicModule,
|
||||||
CoreComponentsModule,
|
AddonBlockTimelineComponentsModule,
|
||||||
CoreDirectivesModule,
|
|
||||||
CorePipesModule,
|
|
||||||
CoreCoursesComponentsModule,
|
|
||||||
TranslateModule.forChild()
|
TranslateModule.forChild()
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AddonBlockTimelineComponent,
|
|
||||||
AddonBlockTimelineEventsComponent
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AddonBlockTimelineProvider
|
AddonBlockTimelineProvider,
|
||||||
|
AddonBlockTimelineHandler
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class AddonBlockTimelineModule {}
|
export class AddonBlockTimelineModule {
|
||||||
|
constructor(blockDelegate: CoreBlockDelegate, blockHandler: AddonBlockTimelineHandler) {
|
||||||
|
blockDelegate.registerHandler(blockHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<core-loading [hideUntil]="filesLoaded" *ngIf="showPrivateFiles || showSiteFiles">
|
<core-loading [hideUntil]="filesLoaded" *ngIf="showPrivateFiles || showSiteFiles">
|
||||||
<!-- Allow selecting the files to see: private or site. -->
|
<!-- Allow selecting the files to see: private or site. -->
|
||||||
<div padding *ngIf="showPrivateFiles && showSiteFiles && !path">
|
<div padding *ngIf="showPrivateFiles && showSiteFiles && !path">
|
||||||
<ion-select [(ngModel)]="root" (ngModelChange)="rootChanged()" interface="popover">
|
<ion-select [(ngModel)]="root" (ngModelChange)="rootChanged()" interface="popover" class="core-button-select">
|
||||||
<ion-option value="my">{{ 'addon.files.privatefiles' | translate }}</ion-option>
|
<ion-option value="my">{{ 'addon.files.privatefiles' | translate }}</ion-option>
|
||||||
<ion-option value="site">{{ 'addon.files.sitefiles' | translate }}</ion-option>
|
<ion-option value="site">{{ 'addon.files.sitefiles' | translate }}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
|
|
|
@ -63,7 +63,7 @@ ion-app.app-root page-addon-messages-discussion {
|
||||||
min-height: initial;
|
min-height: initial;
|
||||||
line-height: initial;
|
line-height: initial;
|
||||||
@include margin(0, 0, 0, 10px);
|
@include margin(0, 0, 0, 10px);
|
||||||
height: auto;
|
height: 1.6em !important;
|
||||||
-webkit-align-self: flex-end;
|
-webkit-align-self: flex-end;
|
||||||
-ms-flex-item-align: end;
|
-ms-flex-item-align: end;
|
||||||
align-self: flex-end;
|
align-self: flex-end;
|
||||||
|
|
|
@ -738,6 +738,19 @@ ion-app.app-root {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.core-#{$color-name}-selected-item {
|
||||||
|
@include border-start(5px, solid, $color-base);
|
||||||
|
&.item-md {
|
||||||
|
@include padding(null, null, null, $item-md-padding-start - 5px);
|
||||||
|
}
|
||||||
|
&.item-ios {
|
||||||
|
@include padding(null, null, null, $item-ios-padding-start - 5px);
|
||||||
|
}
|
||||||
|
&.item-wp {
|
||||||
|
@include padding(null, null, null, $item-wp-padding-start - 5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.core-#{$color-name}-circle {
|
.core-#{$color-name}-circle {
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
"addon.block_myoverview.nocoursesinprogress": "No in progress courses",
|
"addon.block_myoverview.nocoursesinprogress": "No in progress courses",
|
||||||
"addon.block_myoverview.nocoursespast": "No past courses",
|
"addon.block_myoverview.nocoursespast": "No past courses",
|
||||||
"addon.block_myoverview.past": "Past",
|
"addon.block_myoverview.past": "Past",
|
||||||
|
"addon.block_myoverview.pluginname": "Course Overview",
|
||||||
"addon.block_myoverview.title": "Title",
|
"addon.block_myoverview.title": "Title",
|
||||||
"addon.block_sitemainmenu.pluginname": "Main menu",
|
"addon.block_sitemainmenu.pluginname": "Main menu",
|
||||||
"addon.block_timeline.duedate": "Due date",
|
"addon.block_timeline.duedate": "Due date",
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
"addon.block_timeline.nocoursesinprogress": "No in progress courses",
|
"addon.block_timeline.nocoursesinprogress": "No in progress courses",
|
||||||
"addon.block_timeline.noevents": "No upcoming activities due",
|
"addon.block_timeline.noevents": "No upcoming activities due",
|
||||||
"addon.block_timeline.overdue": "Overdue",
|
"addon.block_timeline.overdue": "Overdue",
|
||||||
|
"addon.block_timeline.pluginname": "Timeline",
|
||||||
"addon.block_timeline.sortbycourses": "Sort by courses",
|
"addon.block_timeline.sortbycourses": "Sort by courses",
|
||||||
"addon.block_timeline.sortbydates": "Sort by dates",
|
"addon.block_timeline.sortbydates": "Sort by dates",
|
||||||
"addon.calendar.calendar": "Calendar",
|
"addon.calendar.calendar": "Calendar",
|
||||||
|
@ -1192,7 +1194,6 @@
|
||||||
"core.courses.searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
"core.courses.searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
||||||
"core.courses.selfenrolment": "Self enrolment",
|
"core.courses.selfenrolment": "Self enrolment",
|
||||||
"core.courses.sendpaymentbutton": "Send payment via PayPal",
|
"core.courses.sendpaymentbutton": "Send payment via PayPal",
|
||||||
"core.courses.timeline": "Timeline",
|
|
||||||
"core.courses.totalcoursesearchresults": "Total courses: {{$a}}",
|
"core.courses.totalcoursesearchresults": "Total courses: {{$a}}",
|
||||||
"core.currentdevice": "Current device",
|
"core.currentdevice": "Current device",
|
||||||
"core.datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
"core.datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
||||||
|
|
|
@ -287,6 +287,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
|
||||||
this.slideChanged();
|
this.slideChanged();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
this.calculateTabBarHeight();
|
||||||
this.slides.update();
|
this.slides.update();
|
||||||
this.slides.resize();
|
this.slides.resize();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
<!-- Only render the block if it's supported. -->
|
<!-- Only render the block if it's supported. -->
|
||||||
<div *ngIf="loaded && componentClass" class="{{class}}">
|
<div *ngIf="loaded && componentClass" class="{{class}}">
|
||||||
<ion-item-divider color="light" *ngIf="title">{{ title | translate }}</ion-item-divider>
|
|
||||||
|
|
||||||
<core-dynamic-component [component]="componentClass" [data]="data"></core-dynamic-component>
|
<core-dynamic-component [component]="componentClass" [data]="data"></core-dynamic-component>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { CoreBlockBaseHandler } from '../classes/base-block-handler';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreBlockDefaultHandler extends CoreBlockBaseHandler {
|
export class CoreBlockDefaultHandler extends CoreBlockBaseHandler {
|
||||||
name = 'CoreBlockDefault';
|
name = 'CoreBlockDefault';
|
||||||
type = 'default';
|
blockName = 'default';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
|
@ -80,6 +80,8 @@ export class CoreBlockDelegate extends CoreDelegate {
|
||||||
|
|
||||||
protected handlerNameProperty = 'blockName';
|
protected handlerNameProperty = 'blockName';
|
||||||
|
|
||||||
|
protected featurePrefix = 'CoreBlockDelegate_';
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
|
constructor(logger: CoreLoggerProvider, sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider,
|
||||||
protected defaultHandler: CoreBlockDefaultHandler) {
|
protected defaultHandler: CoreBlockDefaultHandler) {
|
||||||
super('CoreBlockDelegate', logger, sitesProvider, eventsProvider);
|
super('CoreBlockDelegate', logger, sitesProvider, eventsProvider);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ng-container *ngFor="let section of sections">
|
<ng-container *ngFor="let section of sections">
|
||||||
<a ion-item *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" text-wrap (click)="selectSection(section)" [class.core-primary-item]="selected.id == section.id" [class.item-dimmed]="section.visible === 0 || section.uservisible === false" detail-none>
|
<a ion-item *ngIf="!section.hiddenbynumsections && section.id != stealthModulesSectionId" text-wrap (click)="selectSection(section)" [class.core-primary-selected-item]="selected.id == section.id" [class.item-dimmed]="section.visible === 0 || section.uservisible === false" detail-none>
|
||||||
<core-icon name="fa-folder" item-start></core-icon>
|
<core-icon name="fa-folder" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="section.formattedName || section.name"></core-format-text></h2>
|
<h2><core-format-text [text]="section.formattedName || section.name"></core-format-text></h2>
|
||||||
<ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible !== false">{{ 'core.course.hiddenfromstudents' | translate }}</ion-badge>
|
<ion-badge color="secondary" *ngIf="section.visible === 0 && section.uservisible !== false">{{ 'core.course.hiddenfromstudents' | translate }}</ion-badge>
|
||||||
|
|
|
@ -28,6 +28,5 @@
|
||||||
"searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
"searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
||||||
"selfenrolment": "Self enrolment",
|
"selfenrolment": "Self enrolment",
|
||||||
"sendpaymentbutton": "Send payment via PayPal",
|
"sendpaymentbutton": "Send payment via PayPal",
|
||||||
"timeline": "Timeline",
|
|
||||||
"totalcoursesearchresults": "Total courses: {{$a}}"
|
"totalcoursesearchresults": "Total courses: {{$a}}"
|
||||||
}
|
}
|
|
@ -23,26 +23,23 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</core-tab>
|
</core-tab>
|
||||||
|
|
||||||
<!-- Courses tab. -->
|
<!-- Dashboard tab. -->
|
||||||
<core-tab [show]="coursesEnabled" [title]="'core.courses.courses' | translate">
|
<core-tab [show]="dashboardEnabled" [title]="'core.courses.mymoodle' | translate">
|
||||||
<ng-template>
|
<ng-template>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-refresher [enabled]="!!blockMyOverview && blockMyOverview.loaded" (ionRefresh)="blockMyOverview.doRefresh($event)">
|
<ion-refresher [enabled]="dashboardLoaded" (ionRefresh)="refreshDashboard($event)">
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<addon-block-myoverview></addon-block-myoverview>
|
<core-loading [hideUntil]="dashboardLoaded" class="core-loading-center">
|
||||||
</ion-content>
|
<ion-list>
|
||||||
</ng-template>
|
<!-- Dashboard blocks. -->
|
||||||
</core-tab>
|
<ng-container *ngFor="let block of blocks">
|
||||||
|
<core-block [block]="block" contextLevel="user" [instanceId]="userId"></core-block>
|
||||||
|
</ng-container>
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
<!-- Timeline tab. -->
|
<core-empty-box *ngIf="blocks.length == 0" icon="qr-scanner" [message]="'core.course.nocontentavailable' | translate"></core-empty-box>
|
||||||
<core-tab [show]="timelineEnabled" [title]="'core.courses.timeline' | translate">
|
</core-loading>
|
||||||
<ng-template>
|
|
||||||
<ion-content>
|
|
||||||
<ion-refresher [enabled]="!!blockTimeline && blockTimeline.loaded" (ionRefresh)="blockTimeline.doRefresh($event)">
|
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
|
||||||
</ion-refresher>
|
|
||||||
<addon-block-timeline></addon-block-timeline>
|
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</core-tab>
|
</core-tab>
|
||||||
|
|
|
@ -19,9 +19,8 @@ import { CoreCoursesDashboardPage } from './dashboard';
|
||||||
import { CoreComponentsModule } from '@components/components.module';
|
import { CoreComponentsModule } from '@components/components.module';
|
||||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
import { CoreCoursesComponentsModule } from '../../components/components.module';
|
import { CoreCoursesComponentsModule } from '../../components/components.module';
|
||||||
import { AddonBlockMyOverviewModule } from '@addon/block/myoverview/myoverview.module';
|
|
||||||
import { AddonBlockTimelineModule } from '@addon/block/timeline/timeline.module';
|
|
||||||
import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/components.module';
|
import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/components.module';
|
||||||
|
import { CoreBlockComponentsModule } from '@core/block/components/components.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -32,8 +31,7 @@ import { CoreSiteHomeComponentsModule } from '@core/sitehome/components/componen
|
||||||
CoreDirectivesModule,
|
CoreDirectivesModule,
|
||||||
CoreCoursesComponentsModule,
|
CoreCoursesComponentsModule,
|
||||||
CoreSiteHomeComponentsModule,
|
CoreSiteHomeComponentsModule,
|
||||||
AddonBlockMyOverviewModule,
|
CoreBlockComponentsModule,
|
||||||
AddonBlockTimelineModule,
|
|
||||||
IonicPageModule.forChild(CoreCoursesDashboardPage),
|
IonicPageModule.forChild(CoreCoursesDashboardPage),
|
||||||
TranslateModule.forChild()
|
TranslateModule.forChild()
|
||||||
],
|
],
|
||||||
|
|
|
@ -12,17 +12,18 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnDestroy, ViewChild } from '@angular/core';
|
import { Component, OnDestroy, ViewChild, ViewChildren, QueryList } from '@angular/core';
|
||||||
import { IonicPage, NavController } from 'ionic-angular';
|
import { IonicPage, NavController } from 'ionic-angular';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreCoursesProvider } from '../../providers/courses';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
|
|
||||||
import { AddonBlockMyOverviewComponent } from '@addon/block/myoverview/component/myoverview';
|
|
||||||
import { AddonBlockTimelineComponent } from '@addon/block/timeline/components/timeline/timeline';
|
|
||||||
import { CoreTabsComponent } from '@components/tabs/tabs';
|
import { CoreTabsComponent } from '@components/tabs/tabs';
|
||||||
|
import { CoreBlockDelegate } from '@core/block/providers/delegate';
|
||||||
|
import { CoreBlockComponent } from '@core/block/components/block/block';
|
||||||
|
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
|
||||||
import { CoreSiteHomeIndexComponent } from '@core/sitehome/components/index/index';
|
import { CoreSiteHomeIndexComponent } from '@core/sitehome/components/index/index';
|
||||||
import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/timeline';
|
import { CoreCoursesProvider } from '../../providers/courses';
|
||||||
|
import { CoreCoursesDashboardProvider } from '../../providers/dashboard';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the dashboard.
|
* Page that displays the dashboard.
|
||||||
|
@ -35,25 +36,26 @@ import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/time
|
||||||
export class CoreCoursesDashboardPage implements OnDestroy {
|
export class CoreCoursesDashboardPage implements OnDestroy {
|
||||||
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
|
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
|
||||||
@ViewChild(CoreSiteHomeIndexComponent) siteHomeComponent: CoreSiteHomeIndexComponent;
|
@ViewChild(CoreSiteHomeIndexComponent) siteHomeComponent: CoreSiteHomeIndexComponent;
|
||||||
@ViewChild(AddonBlockMyOverviewComponent) blockMyOverview: AddonBlockMyOverviewComponent;
|
@ViewChildren(CoreBlockComponent) blocksComponents: QueryList<CoreBlockComponent>;
|
||||||
@ViewChild(AddonBlockTimelineComponent) blockTimeline: AddonBlockTimelineComponent;
|
|
||||||
|
|
||||||
firstSelectedTab: number;
|
firstSelectedTab: number;
|
||||||
siteHomeEnabled = false;
|
siteHomeEnabled = false;
|
||||||
timelineEnabled = false;
|
|
||||||
coursesEnabled = false;
|
|
||||||
tabsReady = false;
|
tabsReady = false;
|
||||||
searchEnabled: boolean;
|
searchEnabled: boolean;
|
||||||
tabs = [];
|
tabs = [];
|
||||||
siteName: string;
|
siteName: string;
|
||||||
|
blocks: any[];
|
||||||
|
dashboardEnabled = false;
|
||||||
|
userId: number;
|
||||||
|
dashboardLoaded = false;
|
||||||
|
|
||||||
protected isDestroyed;
|
protected isDestroyed;
|
||||||
protected updateSiteObserver;
|
protected updateSiteObserver;
|
||||||
protected courseIds = '';
|
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
|
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
|
||||||
private sitesProvider: CoreSitesProvider, private siteHomeProvider: CoreSiteHomeProvider,
|
private sitesProvider: CoreSitesProvider, private siteHomeProvider: CoreSiteHomeProvider,
|
||||||
private eventsProvider: CoreEventsProvider, private timelineProvider: AddonBlockTimelineProvider) {
|
private eventsProvider: CoreEventsProvider, private dashboardProvider: CoreCoursesDashboardProvider,
|
||||||
|
private domUtils: CoreDomUtilsProvider, private blockDelegate: CoreBlockDelegate) {
|
||||||
this.loadSiteName();
|
this.loadSiteName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,25 +73,21 @@ export class CoreCoursesDashboardPage implements OnDestroy {
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
// Decide which tab to load first.
|
|
||||||
promises.push(this.siteHomeProvider.isAvailable().then((enabled) => {
|
promises.push(this.siteHomeProvider.isAvailable().then((enabled) => {
|
||||||
this.siteHomeEnabled = enabled;
|
this.siteHomeEnabled = enabled;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
promises.push(this.timelineProvider.isAvailable().then((enabled) => {
|
promises.push(this.loadDashboardContent());
|
||||||
this.timelineEnabled = enabled;
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.coursesEnabled = !this.coursesProvider.isMyCoursesDisabledInSite();
|
|
||||||
|
|
||||||
|
// Decide which tab to load first.
|
||||||
Promise.all(promises).finally(() => {
|
Promise.all(promises).finally(() => {
|
||||||
if (this.siteHomeEnabled && (this.coursesEnabled || this.timelineEnabled)) {
|
if (this.siteHomeEnabled && this.dashboardEnabled) {
|
||||||
const site = this.sitesProvider.getCurrentSite(),
|
const site = this.sitesProvider.getCurrentSite(),
|
||||||
displaySiteHome = site.getInfo() && site.getInfo().userhomepage === 0;
|
displaySiteHome = site.getInfo() && site.getInfo().userhomepage === 0;
|
||||||
|
|
||||||
this.firstSelectedTab = displaySiteHome ? 0 : 1;
|
this.firstSelectedTab = displaySiteHome ? 0 : 1;
|
||||||
} else {
|
} else {
|
||||||
this.firstSelectedTab = this.siteHomeEnabled ? 1 : 0;
|
this.firstSelectedTab = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabsReady = true;
|
this.tabsReady = true;
|
||||||
|
@ -124,6 +122,72 @@ export class CoreCoursesDashboardPage implements OnDestroy {
|
||||||
this.siteName = this.sitesProvider.getCurrentSite().getInfo().sitename;
|
this.siteName = this.sitesProvider.getCurrentSite().getInfo().sitename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function to fetch the dashboard data.
|
||||||
|
*
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
protected loadDashboardContent(): Promise<any> {
|
||||||
|
return this.dashboardProvider.isAvailable().then((enabled) => {
|
||||||
|
if (enabled) {
|
||||||
|
this.userId = this.sitesProvider.getCurrentSiteUserId();
|
||||||
|
|
||||||
|
return this.dashboardProvider.getDashboardBlocks().then((blocks) => {
|
||||||
|
this.blocks = blocks;
|
||||||
|
}).catch((error) => {
|
||||||
|
this.domUtils.showErrorModal(error);
|
||||||
|
|
||||||
|
// Cannot get the blocks, just show dashboard if needed.
|
||||||
|
this.loadFallbackBlocks();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not enabled, check separated tabs.
|
||||||
|
this.loadFallbackBlocks();
|
||||||
|
}).finally(() => {
|
||||||
|
this.dashboardEnabled = this.blockDelegate.hasSupportedBlock(this.blocks);
|
||||||
|
this.dashboardLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh the dashboard data.
|
||||||
|
*
|
||||||
|
* @param {any} refresher Refresher.
|
||||||
|
*/
|
||||||
|
refreshDashboard(refresher: any): void {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
promises.push(this.dashboardProvider.invalidateDashboardBlocks());
|
||||||
|
|
||||||
|
// Invalidate the blocks.
|
||||||
|
this.blocksComponents.forEach((blockComponent) => {
|
||||||
|
promises.push(blockComponent.invalidate().catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
Promise.all(promises).finally(() => {
|
||||||
|
this.loadDashboardContent().finally(() => {
|
||||||
|
refresher.complete();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load fallback blocks to shown before 3.6 when dashboard blocks are not supported.
|
||||||
|
*/
|
||||||
|
protected loadFallbackBlocks(): void {
|
||||||
|
this.blocks = [
|
||||||
|
{
|
||||||
|
name: 'myoverview'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'timeline'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being destroyed.
|
* Component being destroyed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,8 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreCoursesProvider } from './courses';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/timeline';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features regarding course overview.
|
* Service that provides some features regarding course overview.
|
||||||
|
@ -22,30 +21,69 @@ import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/time
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreCoursesDashboardProvider {
|
export class CoreCoursesDashboardProvider {
|
||||||
|
|
||||||
constructor(private coursesProvider: CoreCoursesProvider, private timelineProvider: AddonBlockTimelineProvider) { }
|
constructor(private sitesProvider: CoreSitesProvider) { }
|
||||||
|
|
||||||
|
protected ROOT_CACHE_KEY = 'CoreCoursesDashboard:';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not My Overview is available for a certain site.
|
* Get cache key for dashboard blocks WS calls.
|
||||||
|
*
|
||||||
|
* @param {number} [userId] User ID. Default, 0 means current user.
|
||||||
|
* @return {string} Cache key.
|
||||||
|
*/
|
||||||
|
protected getDashboardBlocksCacheKey(userId: number = 0): string {
|
||||||
|
return this.ROOT_CACHE_KEY + 'blocks:' + userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get dashboard blocks.
|
||||||
|
*
|
||||||
|
* @param {number} [userId] User ID. Default, current user.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any[]>} Promise resolved with the list of blocks.
|
||||||
|
* @since 3.6
|
||||||
|
*/
|
||||||
|
getDashboardBlocks(userId?: number, siteId?: string): Promise<any[]> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
const params = {
|
||||||
|
},
|
||||||
|
preSets = {
|
||||||
|
cacheKey: this.getDashboardBlocksCacheKey(userId)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (userId) {
|
||||||
|
params['userid'] = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return site.read('core_block_get_dashboard_blocks', params, preSets).then((result) => {
|
||||||
|
return result.blocks || [];
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidates dashboard blocks WS call.
|
||||||
|
*
|
||||||
|
* @param {number} [userId] User ID. Default, current user.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||||
|
*/
|
||||||
|
invalidateDashboardBlocks(userId?: number, siteId?: string): Promise<any> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
return site.invalidateWsCacheForKey(this.getDashboardBlocksCacheKey(userId));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not block based Dashboard is available for a certain site.
|
||||||
*
|
*
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @return {Promise<boolean>} Promise resolved with true if available, resolved with false or rejected otherwise.
|
* @return {Promise<boolean>} Promise resolved with true if available, resolved with false or rejected otherwise.
|
||||||
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
isAvailable(siteId?: string): Promise<boolean> {
|
isAvailable(siteId?: string): Promise<boolean> {
|
||||||
return this.timelineProvider.isAvailable(siteId);
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
}
|
return site.wsAvailable('core_block_get_dashboard_blocks');
|
||||||
|
});
|
||||||
/**
|
|
||||||
* Check if My Overview is available and not disabled.
|
|
||||||
*
|
|
||||||
* @return {Promise<boolean>} Promise resolved with true if enabled, resolved with false otherwise.
|
|
||||||
*/
|
|
||||||
isEnabled(): Promise<boolean> {
|
|
||||||
if (!this.coursesProvider.isMyCoursesDisabledInSite()) {
|
|
||||||
return this.isAvailable().catch(() => {
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { CoreCoursesProvider } from './courses';
|
||||||
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
|
import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@core/mainmenu/providers/delegate';
|
||||||
import { CoreCoursesDashboardProvider } from '../providers/dashboard';
|
import { CoreCoursesDashboardProvider } from '../providers/dashboard';
|
||||||
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
|
import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
|
||||||
|
import { AddonBlockTimelineProvider } from '@addon/block/timeline/providers/timeline';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to add Dashboard into main menu.
|
* Handler to add Dashboard into main menu.
|
||||||
|
@ -27,7 +28,7 @@ export class CoreDashboardMainMenuHandler implements CoreMainMenuHandler {
|
||||||
priority = 1100;
|
priority = 1100;
|
||||||
|
|
||||||
constructor(private coursesProvider: CoreCoursesProvider, private dashboardProvider: CoreCoursesDashboardProvider,
|
constructor(private coursesProvider: CoreCoursesProvider, private dashboardProvider: CoreCoursesDashboardProvider,
|
||||||
private siteHomeProvider: CoreSiteHomeProvider) { }
|
private siteHomeProvider: CoreSiteHomeProvider, private timelineProvider: AddonBlockTimelineProvider) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the handler is enabled on a site level.
|
* Check if the handler is enabled on a site level.
|
||||||
|
@ -35,20 +36,27 @@ export class CoreDashboardMainMenuHandler implements CoreMainMenuHandler {
|
||||||
* @return {boolean | Promise<boolean>} Whether or not the handler is enabled on a site level.
|
* @return {boolean | Promise<boolean>} Whether or not the handler is enabled on a site level.
|
||||||
*/
|
*/
|
||||||
isEnabled(): boolean | Promise<boolean> {
|
isEnabled(): boolean | Promise<boolean> {
|
||||||
// Check if my overview is enabled.
|
// Check if 3.6 dashboard is enabled.
|
||||||
return this.dashboardProvider.isEnabled().then((enabled) => {
|
return this.dashboardProvider.isAvailable().then((enabled) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.siteHomeProvider.isAvailable().then((enabled) => {
|
// Check if my overview is enabled.
|
||||||
// Show in case siteHome is enabled.
|
return this.timelineProvider.isAvailable().then((enabled) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// My overview not enabled, check if my courses is enabled.
|
return this.siteHomeProvider.isAvailable().then((enabled) => {
|
||||||
return !this.coursesProvider.isMyCoursesDisabledInSite();
|
// Show in case siteHome is enabled.
|
||||||
|
if (enabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// My overview not enabled, check if my courses is enabled.
|
||||||
|
return !this.coursesProvider.isMyCoursesDisabledInSite();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="usageLoaded">
|
<core-loading [hideUntil]="usageLoaded">
|
||||||
<ion-item *ngFor="let site of sites" [class.core-primary-item]="site.id == currentSiteId">
|
<ion-item *ngFor="let site of sites" [class.core-primary-selected-item]="site.id == currentSiteId">
|
||||||
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
||||||
<p>{{ site.fullName }}</p>
|
<p>{{ site.fullName }}</p>
|
||||||
<p item-end>{{ site.spaceUsage | coreBytesToSize }}</p>
|
<p item-end>{{ site.spaceUsage | coreBytesToSize }}</p>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<ion-item-divider color="light">
|
<ion-item-divider color="light">
|
||||||
<p>{{ 'core.settings.sites' | translate }}</p>
|
<p>{{ 'core.settings.sites' | translate }}</p>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ion-item *ngFor="let site of sites" [class.core-primary-item]="site.id == currentSiteId" text-wrap>
|
<ion-item *ngFor="let site of sites" [class.core-primary-selected-item]="site.id == currentSiteId" text-wrap>
|
||||||
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
<h2><core-format-text [text]="site.siteName"></core-format-text></h2>
|
||||||
<p>{{ site.fullName }}</p>
|
<p>{{ site.fullName }}</p>
|
||||||
<p>{{ site.siteUrl }}</p>
|
<p>{{ site.siteUrl }}</p>
|
||||||
|
|
Loading…
Reference in New Issue