forked from CIT/Vmeda.Online
		
	MOBILE-3608 blocks: Starred and recent courses block
This commit is contained in:
		
							parent
							
								
									b2ecdf5224
								
							
						
					
					
						commit
						d0af70be5a
					
				@ -30,8 +30,10 @@ import { AddonBlockMyOverviewModule } from './block/myoverview/myoverview.module
 | 
			
		||||
import { AddonBlockNewsItemsModule } from './block/newsitems/newsitems.module';
 | 
			
		||||
import { AddonBlockOnlineUsersModule } from './block/onlineusers/onlineusers.module';
 | 
			
		||||
import { AddonBlockPrivateFilesModule } from './block/privatefiles/privatefiles.module';
 | 
			
		||||
import { AddonBlockRecentlyAccessedCoursesModule } from './block/recentlyaccessedcourses/recentlyaccessedcourses.module';
 | 
			
		||||
import { AddonBlockRssClientModule } from './block/rssclient/rssclient.module';
 | 
			
		||||
import { AddonBlockSelfCompletionModule } from './block/selfcompletion/selfcompletion.module';
 | 
			
		||||
import { AddonBlockStarredCoursesModule } from './block/starredcourses/starredcourses.module';
 | 
			
		||||
import { AddonBlockTagsModule } from './block/tags/tags.module';
 | 
			
		||||
import { AddonPrivateFilesModule } from './privatefiles/privatefiles.module';
 | 
			
		||||
import { AddonFilterModule } from './filter/filter.module';
 | 
			
		||||
@ -57,8 +59,10 @@ import { AddonUserProfileFieldModule } from './userprofilefield/userprofilefield
 | 
			
		||||
        AddonBlockNewsItemsModule,
 | 
			
		||||
        AddonBlockOnlineUsersModule,
 | 
			
		||||
        AddonBlockPrivateFilesModule,
 | 
			
		||||
        AddonBlockRecentlyAccessedCoursesModule,
 | 
			
		||||
        AddonBlockRssClientModule,
 | 
			
		||||
        AddonBlockSelfCompletionModule,
 | 
			
		||||
        AddonBlockStarredCoursesModule,
 | 
			
		||||
        AddonBlockTagsModule,
 | 
			
		||||
        AddonUserProfileFieldModule,
 | 
			
		||||
    ],
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 { CoreCoursesComponentsModule } from '@features/courses/components/components.module';
 | 
			
		||||
 | 
			
		||||
import { AddonBlockRecentlyAccessedCoursesComponent } from './recentlyaccessedcourses/recentlyaccessedcourses';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonBlockRecentlyAccessedCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCoursesComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonBlockRecentlyAccessedCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        AddonBlockRecentlyAccessedCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockRecentlyAccessedCoursesComponentsModule {}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
<ion-item-divider>
 | 
			
		||||
    <ion-label>
 | 
			
		||||
        <h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2>
 | 
			
		||||
        </ion-label>
 | 
			
		||||
    <div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end">
 | 
			
		||||
        <ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark" (click)="prefetchCourses()">
 | 
			
		||||
            <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only">
 | 
			
		||||
            </ion-icon>
 | 
			
		||||
        </ion-button>
 | 
			
		||||
        <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge">{{prefetchCoursesData.badge}}</ion-badge>
 | 
			
		||||
        <ion-spinner *ngIf="!prefetchCoursesData.icon || prefetchCoursesData.loading"></ion-spinner>
 | 
			
		||||
    </div>
 | 
			
		||||
</ion-item-divider>
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
 | 
			
		||||
    <core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_recentlyaccessedcourses.nocourses' | translate"></core-empty-box>
 | 
			
		||||
    <!-- List of courses. -->
 | 
			
		||||
     <div class="core-horizontal-scroll">
 | 
			
		||||
        <ng-container *ngFor="let course of courses">
 | 
			
		||||
            <core-courses-course-progress [course]="course" class="core-recentlyaccessedcourses" [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
</core-loading>
 | 
			
		||||
@ -0,0 +1,237 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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, OnInit, OnDestroy, Input, OnChanges, SimpleChange } from '@angular/core';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses';
 | 
			
		||||
import { CoreCoursesHelper, CoreEnrolledCourseDataWithOptions } from '@features/courses/services/courses-helper';
 | 
			
		||||
import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
 | 
			
		||||
import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate';
 | 
			
		||||
import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion';
 | 
			
		||||
import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to render a recent courses block.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-block-recentlyaccessedcourses',
 | 
			
		||||
    templateUrl: 'addon-block-recentlyaccessedcourses.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @Input() downloadEnabled = false;
 | 
			
		||||
 | 
			
		||||
    courses: CoreEnrolledCourseDataWithOptions [] = [];
 | 
			
		||||
    prefetchCoursesData: CorePrefetchStatusInfo = {
 | 
			
		||||
        icon: '',
 | 
			
		||||
        statusTranslatable: 'core.loading',
 | 
			
		||||
        status: '',
 | 
			
		||||
        loading: true,
 | 
			
		||||
        badge: '',
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    downloadCourseEnabled = false;
 | 
			
		||||
    downloadCoursesEnabled = false;
 | 
			
		||||
 | 
			
		||||
    protected prefetchIconsInitialized = false;
 | 
			
		||||
    protected isDestroyed = false;
 | 
			
		||||
    protected coursesObserver?: CoreEventObserver;
 | 
			
		||||
    protected updateSiteObserver?: CoreEventObserver;
 | 
			
		||||
    protected courseIds = [];
 | 
			
		||||
    protected fetchContentDefaultError = 'Error getting recent courses data.';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonBlockRecentlyAccessedCoursesComponent');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
 | 
			
		||||
        // Refresh the enabled flags if enabled.
 | 
			
		||||
        this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
 | 
			
		||||
        this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
 | 
			
		||||
            this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
 | 
			
		||||
            this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
        }, CoreSites.instance.getCurrentSiteId());
 | 
			
		||||
 | 
			
		||||
        this.coursesObserver = CoreEvents.on(
 | 
			
		||||
            CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
 | 
			
		||||
            (data: CoreCoursesMyCoursesUpdatedEventData) => {
 | 
			
		||||
 | 
			
		||||
                if (this.shouldRefreshOnUpdatedEvent(data)) {
 | 
			
		||||
                    this.refreshCourseList();
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            CoreSites.instance.getCurrentSiteId(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detect changes on input properties.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnChanges(changes: {[name: string]: SimpleChange}): void {
 | 
			
		||||
        if (changes.downloadEnabled && !changes.downloadEnabled.previousValue && this.downloadEnabled && this.loaded) {
 | 
			
		||||
            // Download all courses is enabled now, initialize it.
 | 
			
		||||
            this.initPrefetchCoursesIcons();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Perform the invalidate content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async invalidateContent(): Promise<void> {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourses.instance.invalidateUserCourses().finally(() =>
 | 
			
		||||
            // Invalidate course completion data.
 | 
			
		||||
            CoreUtils.instance.allPromises(this.courseIds.map((courseId) =>
 | 
			
		||||
                AddonCourseCompletion.instance.invalidateCourseCompletion(courseId)))));
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourseOptionsDelegate.instance.clearAndInvalidateCoursesOptions());
 | 
			
		||||
        if (this.courseIds.length > 0) {
 | 
			
		||||
            promises.push(CoreCourses.instance.invalidateCoursesByField('ids', this.courseIds.join(',')));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreUtils.instance.allPromises(promises).finally(() => {
 | 
			
		||||
            this.prefetchIconsInitialized = false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the courses for recent courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async fetchContent(): Promise<void> {
 | 
			
		||||
        const showCategories = this.block.configsRecord && this.block.configsRecord.displaycategories &&
 | 
			
		||||
            this.block.configsRecord.displaycategories.value == '1';
 | 
			
		||||
 | 
			
		||||
        this.courses = await CoreCoursesHelper.instance.getUserCoursesWithOptions('lastaccess', 10, undefined, showCategories);
 | 
			
		||||
        this.initPrefetchCoursesIcons();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the list of courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async refreshCourseList(): Promise<void> {
 | 
			
		||||
        CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreCourses.instance.invalidateUserCourses();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await this.loadContent(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the prefetch icon for selected courses.
 | 
			
		||||
     */
 | 
			
		||||
    protected async initPrefetchCoursesIcons(): Promise<void> {
 | 
			
		||||
        if (this.prefetchIconsInitialized || !this.downloadEnabled) {
 | 
			
		||||
            // Already initialized.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.prefetchIconsInitialized = true;
 | 
			
		||||
 | 
			
		||||
        this.prefetchCoursesData = await CoreCourseHelper.instance.initPrefetchCoursesIcons(this.courses, this.prefetchCoursesData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether list should be refreshed based on a EVENT_MY_COURSES_UPDATED event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param data Event data.
 | 
			
		||||
     * @return Whether to refresh.
 | 
			
		||||
     */
 | 
			
		||||
    protected shouldRefreshOnUpdatedEvent(data: CoreCoursesMyCoursesUpdatedEventData): boolean {
 | 
			
		||||
        if (data.action == CoreCoursesProvider.ACTION_ENROL) {
 | 
			
		||||
            // Always update if user enrolled in a course.
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data.action == CoreCoursesProvider.ACTION_VIEW && data.courseId != CoreSites.instance.getCurrentSiteHomeId() &&
 | 
			
		||||
                this.courses[0] && data.courseId != this.courses[0].id) {
 | 
			
		||||
            // Update list if user viewed a course that isn't the most recent one and isn't site home.
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data.action == CoreCoursesProvider.ACTION_STATE_CHANGED && data.state == CoreCoursesProvider.STATE_FAVOURITE &&
 | 
			
		||||
                data.courseId && this.hasCourse(data.courseId)) {
 | 
			
		||||
            // Update list if a visible course is now favourite or unfavourite.
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a certain course is in the list of courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID to search.
 | 
			
		||||
     * @return Whether it's in the list.
 | 
			
		||||
     */
 | 
			
		||||
    protected hasCourse(courseId: number): boolean {
 | 
			
		||||
        if (!this.courses) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return !!this.courses.find((course) => course.id == courseId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prefetch all the shown courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async prefetchCourses(): Promise<void> {
 | 
			
		||||
        const initialIcon = this.prefetchCoursesData.icon;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            return CoreCourseHelper.instance.prefetchCourses(this.courses, this.prefetchCoursesData);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (!this.isDestroyed) {
 | 
			
		||||
                CoreDomUtils.instance.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
 | 
			
		||||
                this.prefetchCoursesData.icon = initialIcon;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being destroyed.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.isDestroyed = true;
 | 
			
		||||
        this.coursesObserver?.off();
 | 
			
		||||
        this.updateSiteObserver?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								src/addons/block/recentlyaccessedcourses/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/addons/block/recentlyaccessedcourses/lang.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
    "nocourses": "No recent courses",
 | 
			
		||||
    "pluginname": "Recently accessed courses"
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
			
		||||
import { IonicModule } from '@ionic/angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreBlockDelegate } from '@features/block/services/block-delegate';
 | 
			
		||||
import { AddonBlockRecentlyAccessedCoursesComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonBlockRecentlyAccessedCoursesHandler } from './services/block-handler';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        AddonBlockRecentlyAccessedCoursesComponentsModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        {
 | 
			
		||||
            provide: APP_INITIALIZER,
 | 
			
		||||
            multi: true,
 | 
			
		||||
            useValue: () => {
 | 
			
		||||
                CoreBlockDelegate.instance.registerHandler(AddonBlockRecentlyAccessedCoursesHandler.instance);
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockRecentlyAccessedCoursesModule {}
 | 
			
		||||
@ -0,0 +1,46 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 } from '@angular/core';
 | 
			
		||||
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
 | 
			
		||||
import { AddonBlockRecentlyAccessedCoursesComponent } from '../components/recentlyaccessedcourses/recentlyaccessedcourses';
 | 
			
		||||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Block handler.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonBlockRecentlyAccessedCoursesHandlerService extends CoreBlockBaseHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonBlockRecentlyAccessedCourses';
 | 
			
		||||
    blockName = 'recentlyaccessedcourses';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the data needed to render the block.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Data or promise resolved with the data.
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(): CoreBlockHandlerData {
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            title: 'addon.block_recentlyaccessedcourses.pluginname',
 | 
			
		||||
            class: 'addon-block-recentlyaccessedcourses',
 | 
			
		||||
            component: AddonBlockRecentlyAccessedCoursesComponent,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonBlockRecentlyAccessedCoursesHandler extends makeSingleton(AddonBlockRecentlyAccessedCoursesHandlerService) {}
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 { CoreCoursesComponentsModule } from '@features/courses/components/components.module';
 | 
			
		||||
 | 
			
		||||
import { AddonBlockStarredCoursesComponent } from './starredcourses/starredcourses';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonBlockStarredCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCoursesComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonBlockStarredCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        AddonBlockStarredCoursesComponent,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockStarredCoursesComponentsModule {}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
<ion-item-divider sticky="true">
 | 
			
		||||
    <ion-label>
 | 
			
		||||
        <h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2>
 | 
			
		||||
    </ion-label>
 | 
			
		||||
    <div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" slot="end">
 | 
			
		||||
        <ion-button *ngIf="prefetchCoursesData.icon && !prefetchCoursesData.loading" fill="clear" color="dark" (click)="prefetchCourses()">
 | 
			
		||||
            <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only">
 | 
			
		||||
            </ion-icon>
 | 
			
		||||
        </ion-button>
 | 
			
		||||
        <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge">{{prefetchCoursesData.badge}}</ion-badge>
 | 
			
		||||
        <ion-spinner *ngIf="!prefetchCoursesData.icon || prefetchCoursesData.loading"></ion-spinner>
 | 
			
		||||
    </div>
 | 
			
		||||
</ion-item-divider>
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="core-loading-center safe-area-page">
 | 
			
		||||
    <core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" [message]="'addon.block_starredcourses.nocourses' | translate"></core-empty-box>
 | 
			
		||||
    <!-- List of courses. -->
 | 
			
		||||
    <div class="core-horizontal-scroll">
 | 
			
		||||
        <ng-container *ngFor="let course of courses">
 | 
			
		||||
            <core-courses-course-progress [course]="course" class="core-block_starredcourses" [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
    </div>
 | 
			
		||||
</core-loading>
 | 
			
		||||
@ -0,0 +1,217 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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, OnInit, OnDestroy, Input, OnChanges, SimpleChange } from '@angular/core';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses';
 | 
			
		||||
import { CoreCoursesHelper, CoreEnrolledCourseDataWithOptions } from '@features/courses/services/courses-helper';
 | 
			
		||||
import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
 | 
			
		||||
import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate';
 | 
			
		||||
import { AddonCourseCompletion } from '@/addons/coursecompletion/services/coursecompletion';
 | 
			
		||||
import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component to render a starred courses block.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-block-starredcourses',
 | 
			
		||||
    templateUrl: 'addon-block-starredcourses.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @Input() downloadEnabled = false;
 | 
			
		||||
 | 
			
		||||
    courses: CoreEnrolledCourseDataWithOptions [] = [];
 | 
			
		||||
    prefetchCoursesData: CorePrefetchStatusInfo = {
 | 
			
		||||
        icon: '',
 | 
			
		||||
        statusTranslatable: 'core.loading',
 | 
			
		||||
        status: '',
 | 
			
		||||
        loading: true,
 | 
			
		||||
        badge: '',
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    downloadCourseEnabled = false;
 | 
			
		||||
    downloadCoursesEnabled = false;
 | 
			
		||||
 | 
			
		||||
    protected prefetchIconsInitialized = false;
 | 
			
		||||
    protected isDestroyed = false;
 | 
			
		||||
    protected coursesObserver?: CoreEventObserver;
 | 
			
		||||
    protected updateSiteObserver?: CoreEventObserver;
 | 
			
		||||
    protected courseIds: number[] = [];
 | 
			
		||||
    protected fetchContentDefaultError = 'Error getting starred courses data.';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonBlockStarredCoursesComponent');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        // Refresh the enabled flags if enabled.
 | 
			
		||||
        this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
 | 
			
		||||
        this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
        // Refresh the enabled flags if site is updated.
 | 
			
		||||
        this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
 | 
			
		||||
            this.downloadCourseEnabled = !CoreCourses.instance.isDownloadCourseDisabledInSite();
 | 
			
		||||
            this.downloadCoursesEnabled = !CoreCourses.instance.isDownloadCoursesDisabledInSite();
 | 
			
		||||
 | 
			
		||||
        }, CoreSites.instance.getCurrentSiteId());
 | 
			
		||||
 | 
			
		||||
        this.coursesObserver = CoreEvents.on(
 | 
			
		||||
            CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
 | 
			
		||||
            (data: CoreCoursesMyCoursesUpdatedEventData) => {
 | 
			
		||||
 | 
			
		||||
                if (this.shouldRefreshOnUpdatedEvent(data)) {
 | 
			
		||||
                    this.refreshCourseList();
 | 
			
		||||
                }
 | 
			
		||||
                this.refreshContent();
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            CoreSites.instance.getCurrentSiteId(),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Detect changes on input properties.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnChanges(changes: {[name: string]: SimpleChange}): void {
 | 
			
		||||
        if (changes.downloadEnabled && !changes.downloadEnabled.previousValue && this.downloadEnabled && this.loaded) {
 | 
			
		||||
            // Download all courses is enabled now, initialize it.
 | 
			
		||||
            this.initPrefetchCoursesIcons();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Perform the invalidate content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async invalidateContent(): Promise<void> {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourses.instance.invalidateUserCourses().finally(() =>
 | 
			
		||||
            // Invalidate course completion data.
 | 
			
		||||
            CoreUtils.instance.allPromises(this.courseIds.map((courseId) =>
 | 
			
		||||
                AddonCourseCompletion.instance.invalidateCourseCompletion(courseId)))));
 | 
			
		||||
 | 
			
		||||
        promises.push(CoreCourseOptionsDelegate.instance.clearAndInvalidateCoursesOptions());
 | 
			
		||||
        if (this.courseIds.length > 0) {
 | 
			
		||||
            promises.push(CoreCourses.instance.invalidateCoursesByField('ids', this.courseIds.join(',')));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await CoreUtils.instance.allPromises(promises).finally(() => {
 | 
			
		||||
            this.prefetchIconsInitialized = false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch the courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async fetchContent(): Promise<void> {
 | 
			
		||||
        const showCategories = this.block.configsRecord && this.block.configsRecord.displaycategories &&
 | 
			
		||||
            this.block.configsRecord.displaycategories.value == '1';
 | 
			
		||||
 | 
			
		||||
        this.courses = await CoreCoursesHelper.instance.getUserCoursesWithOptions('timemodified', 0, 'isfavourite', showCategories);
 | 
			
		||||
        this.initPrefetchCoursesIcons();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Refresh the list of courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async refreshCourseList(): Promise<void> {
 | 
			
		||||
        CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreCourses.instance.invalidateUserCourses();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await this.loadContent(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether list should be refreshed based on a EVENT_MY_COURSES_UPDATED event.
 | 
			
		||||
     *
 | 
			
		||||
     * @param data Event data.
 | 
			
		||||
     * @return Whether to refresh.
 | 
			
		||||
     */
 | 
			
		||||
    protected shouldRefreshOnUpdatedEvent(data: CoreCoursesMyCoursesUpdatedEventData): boolean {
 | 
			
		||||
        if (data.action == CoreCoursesProvider.ACTION_ENROL) {
 | 
			
		||||
            // Always update if user enrolled in a course.
 | 
			
		||||
            // New courses shouldn't be favourite by default, but just in case.
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data.action == CoreCoursesProvider.ACTION_STATE_CHANGED && data.state == CoreCoursesProvider.STATE_FAVOURITE) {
 | 
			
		||||
            // Update list when making a course favourite or not.
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Initialize the prefetch icon for selected courses.
 | 
			
		||||
     */
 | 
			
		||||
    protected async initPrefetchCoursesIcons(): Promise<void> {
 | 
			
		||||
        if (this.prefetchIconsInitialized || !this.downloadEnabled) {
 | 
			
		||||
            // Already initialized.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.prefetchIconsInitialized = true;
 | 
			
		||||
 | 
			
		||||
        this.prefetchCoursesData = await CoreCourseHelper.instance.initPrefetchCoursesIcons(this.courses, this.prefetchCoursesData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Prefetch all the shown courses.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async prefetchCourses(): Promise<void> {
 | 
			
		||||
        const initialIcon = this.prefetchCoursesData.icon;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            return CoreCourseHelper.instance.prefetchCourses(this.courses, this.prefetchCoursesData);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            if (!this.isDestroyed) {
 | 
			
		||||
                CoreDomUtils.instance.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
 | 
			
		||||
                this.prefetchCoursesData.icon = initialIcon;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being destroyed.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.isDestroyed = true;
 | 
			
		||||
        this.coursesObserver?.off();
 | 
			
		||||
        this.updateSiteObserver?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										4
									
								
								src/addons/block/starredcourses/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/addons/block/starredcourses/lang.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
    "nocourses": "No starred courses",
 | 
			
		||||
    "pluginname": "Starred courses"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								src/addons/block/starredcourses/services/block-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/block/starredcourses/services/block-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 } from '@angular/core';
 | 
			
		||||
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
 | 
			
		||||
import { AddonBlockStarredCoursesComponent } from '../components/starredcourses/starredcourses';
 | 
			
		||||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Block handler.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonBlockStarredCoursesHandlerService extends CoreBlockBaseHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonBlockStarredCourses';
 | 
			
		||||
    blockName = 'starredcourses';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the data needed to render the block.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Data or promise resolved with the data.
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(): CoreBlockHandlerData {
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            title: 'addon.starredcourses.pluginname',
 | 
			
		||||
            class: 'addon-block-starredcourses',
 | 
			
		||||
            component: AddonBlockStarredCoursesComponent,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonBlockStarredCoursesHandler extends makeSingleton(AddonBlockStarredCoursesHandlerService) {}
 | 
			
		||||
							
								
								
									
										38
									
								
								src/addons/block/starredcourses/starredcourses.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/addons/block/starredcourses/starredcourses.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// 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 { APP_INITIALIZER, NgModule } from '@angular/core';
 | 
			
		||||
import { IonicModule } from '@ionic/angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreBlockDelegate } from '@features/block/services/block-delegate';
 | 
			
		||||
import { AddonBlockStarredCoursesComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonBlockStarredCoursesHandler } from './services/block-handler';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        AddonBlockStarredCoursesComponentsModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        {
 | 
			
		||||
            provide: APP_INITIALIZER,
 | 
			
		||||
            multi: true,
 | 
			
		||||
            useValue: () => {
 | 
			
		||||
                CoreBlockDelegate.instance.registerHandler(AddonBlockStarredCoursesHandler.instance);
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonBlockStarredCoursesModule {}
 | 
			
		||||
@ -109,27 +109,34 @@
 | 
			
		||||
 | 
			
		||||
// @todo
 | 
			
		||||
:host-context(.core-horizontal-scroll) {
 | 
			
		||||
    /*@include horizontal_scroll_item(80%, 250px, 300px);*/
 | 
			
		||||
    flex: 0 0 80%;
 | 
			
		||||
    min-width: 250px;
 | 
			
		||||
    max-width: 300px;
 | 
			
		||||
    align-self: stretch;
 | 
			
		||||
    display: block;
 | 
			
		||||
 | 
			
		||||
    [text-wrap] .label {
 | 
			
		||||
        h2, p {
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            text-overflow: ellipsis;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ion-card {
 | 
			
		||||
        .core-course-thumb {
 | 
			
		||||
            padding-top: 30%;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .core-course-link {
 | 
			
		||||
            /*@include padding(4px, 0px, 4px, 8px);*/
 | 
			
		||||
            .core-course-additional-info {
 | 
			
		||||
                font-size: 1.2rem;
 | 
			
		||||
            }
 | 
			
		||||
        .core-course-header {
 | 
			
		||||
            padding-top: 4px;
 | 
			
		||||
            padding-bottom: 4px;
 | 
			
		||||
 | 
			
		||||
            .core-course-title {
 | 
			
		||||
                margin: 3px 0;
 | 
			
		||||
 | 
			
		||||
                h2 {
 | 
			
		||||
                    font-size: 1.5rem;
 | 
			
		||||
                    ion-icon {
 | 
			
		||||
                        margin-right: 2px;
 | 
			
		||||
                    }
 | 
			
		||||
                h2 ion-icon {
 | 
			
		||||
                    margin-right: 2px;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                &.core-course-with-buttons {
 | 
			
		||||
@ -148,7 +155,6 @@
 | 
			
		||||
            .item-button[icon-only] {
 | 
			
		||||
                min-width: 40px;
 | 
			
		||||
                width: 40px;
 | 
			
		||||
                font-size: 1.5rem;
 | 
			
		||||
                padding: 8px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -277,3 +277,11 @@ ion-select.core-button-select,
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    text-decoration: underline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Horizontal scrolling elements
 | 
			
		||||
.core-horizontal-scroll {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-flow: nowrap;
 | 
			
		||||
    overflow-x: scroll;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user