forked from CIT/Vmeda.Online
		
	MOBILE-3637 book: Implement book activity
This commit is contained in:
		
							parent
							
								
									5a15fca0a9
								
							
						
					
					
						commit
						c98fa810fa
					
				
							
								
								
									
										28
									
								
								src/addons/mod/book/book-lazy.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/addons/mod/book/book-lazy.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
// (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 { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: ':courseId/:cmdId',
 | 
			
		||||
        loadChildren: () => import('./pages/index/index.module').then( m => m.AddonModBookIndexPageModule),
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [RouterModule.forChild(routes)],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookLazyModule {}
 | 
			
		||||
							
								
								
									
										57
									
								
								src/addons/mod/book/book.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addons/mod/book/book.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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 { Routes } from '@angular/router';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
			
		||||
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
 | 
			
		||||
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
 | 
			
		||||
import { CoreTagAreaDelegate } from '@features/tag/services/tag-area-delegate';
 | 
			
		||||
import { AddonModBookComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModBookModuleHandler, AddonModBookModuleHandlerService } from './services/handlers/module';
 | 
			
		||||
import { AddonModBookIndexLinkHandler } from './services/handlers/index-link';
 | 
			
		||||
import { AddonModBookListLinkHandler } from './services/handlers/list-link';
 | 
			
		||||
import { AddonModBookPrefetchHandler } from './services/handlers/prefetch';
 | 
			
		||||
import { AddonModBookTagAreaHandler } from './services/handlers/tag-area';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: AddonModBookModuleHandlerService.PAGE_NAME,
 | 
			
		||||
        loadChildren: () => import('./book-lazy.module').then(m => m.AddonModBookLazyModule),
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreMainMenuTabRoutingModule.forChild(routes),
 | 
			
		||||
        AddonModBookComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        {
 | 
			
		||||
            provide: APP_INITIALIZER,
 | 
			
		||||
            multi: true,
 | 
			
		||||
            deps: [],
 | 
			
		||||
            useFactory: () => () => {
 | 
			
		||||
                CoreCourseModuleDelegate.instance.registerHandler(AddonModBookModuleHandler.instance);
 | 
			
		||||
                CoreContentLinksDelegate.instance.registerHandler(AddonModBookIndexLinkHandler.instance);
 | 
			
		||||
                CoreContentLinksDelegate.instance.registerHandler(AddonModBookListLinkHandler.instance);
 | 
			
		||||
                CoreCourseModulePrefetchDelegate.instance.registerHandler(AddonModBookPrefetchHandler.instance);
 | 
			
		||||
                CoreTagAreaDelegate.instance.registerHandler(AddonModBookTagAreaHandler.instance);
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookModule {}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/addons/mod/book/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/addons/mod/book/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
// (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 { FormsModule } from '@angular/forms';
 | 
			
		||||
import { IonicModule } from '@ionic/angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@features/course/components/components.module';
 | 
			
		||||
import { CoreTagComponentsModule } from '@features/tag/components/components.module';
 | 
			
		||||
 | 
			
		||||
import { AddonModBookIndexComponent } from './index/index';
 | 
			
		||||
import { AddonModBookTocComponent } from './toc/toc';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModBookIndexComponent,
 | 
			
		||||
        AddonModBookTocComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        FormsModule,
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
        CoreTagComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonModBookIndexComponent,
 | 
			
		||||
        AddonModBookTocComponent,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookComponentsModule {}
 | 
			
		||||
@ -0,0 +1,52 @@
 | 
			
		||||
<!-- Buttons to add to the header. -->
 | 
			
		||||
<core-navbar-buttons slot="end">
 | 
			
		||||
    <ion-button (click)="showToc()" [attr.aria-label]="'addon.mod_book.toc' | translate" aria-haspopup="true" *ngIf="loaded">
 | 
			
		||||
        <ion-icon name="fas-bookmark" slot="icon-only"></ion-icon>
 | 
			
		||||
    </ion-button>
 | 
			
		||||
    <core-context-menu>
 | 
			
		||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate"
 | 
			
		||||
            [href]="externalUrl" iconAction="fas-external-link-alt"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate"
 | 
			
		||||
            (action)="expandDescription()" iconAction="fas-arrow-right"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}"
 | 
			
		||||
            iconAction="far-newspaper" (action)="gotoBlog()"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)"
 | 
			
		||||
            [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)"
 | 
			
		||||
            [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}"
 | 
			
		||||
            iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
    </core-context-menu>
 | 
			
		||||
</core-navbar-buttons>
 | 
			
		||||
 | 
			
		||||
<!-- Content. -->
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
 | 
			
		||||
 | 
			
		||||
    <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"
 | 
			
		||||
        contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"></core-course-module-description>
 | 
			
		||||
 | 
			
		||||
    <ion-card class="core-warning-card" *ngIf="warning">
 | 
			
		||||
        <ion-icon name="fas-exclamation-triangle" slot="start"></ion-icon>
 | 
			
		||||
        <span [innerHTML]="warning"></span>
 | 
			
		||||
    </ion-card>
 | 
			
		||||
 | 
			
		||||
    <div class="ion-padding safe-padding-horizontal">
 | 
			
		||||
        <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id"
 | 
			
		||||
            [previousTitle]="previousNavBarTitle" [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle"
 | 
			
		||||
            (action)="changeChapter($event)">
 | 
			
		||||
        </core-navigation-bar>
 | 
			
		||||
 | 
			
		||||
        <core-format-text [component]="component" [componentId]="componentId" [text]="chapterContent" contextLevel="module"
 | 
			
		||||
            [contextInstanceId]="module?.id" [courseId]="courseId"></core-format-text>
 | 
			
		||||
        <div class="ion-margin-top" *ngIf="tagsEnabled && tags?.length > 0">
 | 
			
		||||
            <strong>{{ 'core.tag.tags' | translate }}: </strong>
 | 
			
		||||
            <core-tag-list [tags]="tags"></core-tag-list>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id"
 | 
			
		||||
            [previousTitle]="previousNavBarTitle" [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle"
 | 
			
		||||
            (action)="changeChapter($event)"></core-navigation-bar>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</core-loading>
 | 
			
		||||
							
								
								
									
										251
									
								
								src/addons/mod/book/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/addons/mod/book/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,251 @@
 | 
			
		||||
// (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, Optional, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { IonContent } from '@ionic/angular';
 | 
			
		||||
import {
 | 
			
		||||
    CoreCourseModuleMainResourceComponent, CoreCourseResourceDownloadResult,
 | 
			
		||||
} from '@features/course/classes/main-resource-component';
 | 
			
		||||
import {
 | 
			
		||||
    AddonModBookProvider,
 | 
			
		||||
    AddonModBookContentsMap,
 | 
			
		||||
    AddonModBookTocChapter,
 | 
			
		||||
    AddonModBookNavStyle,
 | 
			
		||||
    AddonModBook,
 | 
			
		||||
    AddonModBookBookWSData,
 | 
			
		||||
} from '../../services/book';
 | 
			
		||||
import { CoreTag, CoreTagItem } from '@features/tag/services/tag';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
 | 
			
		||||
import { ModalController, Translate } from '@singletons';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreCourse } from '@features/course/services/course';
 | 
			
		||||
import { AddonModBookTocComponent } from '../toc/toc';
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a book.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-mod-book-index',
 | 
			
		||||
    templateUrl: 'addon-mod-book-index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
    @Input() initialChapterId?: number; // The initial chapter ID to load.
 | 
			
		||||
 | 
			
		||||
    component = AddonModBookProvider.COMPONENT;
 | 
			
		||||
    chapterContent?: string;
 | 
			
		||||
    previousChapter?: AddonModBookTocChapter;
 | 
			
		||||
    nextChapter?: AddonModBookTocChapter;
 | 
			
		||||
    tagsEnabled = false;
 | 
			
		||||
    displayNavBar = true;
 | 
			
		||||
    previousNavBarTitle?: string;
 | 
			
		||||
    nextNavBarTitle?: string;
 | 
			
		||||
    warning = '';
 | 
			
		||||
    tags?: CoreTagItem[];
 | 
			
		||||
 | 
			
		||||
    protected chapters: AddonModBookTocChapter[] = [];
 | 
			
		||||
    protected currentChapter?: number;
 | 
			
		||||
    protected book?: AddonModBookBookWSData;
 | 
			
		||||
    protected displayTitlesInNavBar = false;
 | 
			
		||||
    protected contentsMap: AddonModBookContentsMap = {};
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected content?: IonContent,
 | 
			
		||||
        @Optional() courseContentsPage?: CoreCourseContentsPage,
 | 
			
		||||
    ) {
 | 
			
		||||
        super('AddonModBookIndexComponent', courseContentsPage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
 | 
			
		||||
        this.tagsEnabled = CoreTag.instance.areTagsAvailableInSite();
 | 
			
		||||
        this.loadContent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Show the TOC.
 | 
			
		||||
     */
 | 
			
		||||
    async showToc(): Promise<void> {
 | 
			
		||||
        // Create the toc modal.
 | 
			
		||||
        const modal = await ModalController.instance.create({
 | 
			
		||||
            component: AddonModBookTocComponent,
 | 
			
		||||
            componentProps: {
 | 
			
		||||
                moduleId: this.module!.id,
 | 
			
		||||
                chapters: this.chapters,
 | 
			
		||||
                selected: this.currentChapter,
 | 
			
		||||
                courseId: this.courseId,
 | 
			
		||||
                book: this.book,
 | 
			
		||||
            },
 | 
			
		||||
            cssClass: 'core-modal-lateral',
 | 
			
		||||
            showBackdrop: true,
 | 
			
		||||
            backdropDismiss: true,
 | 
			
		||||
            // @todo enterAnimation: 'core-modal-lateral-transition',
 | 
			
		||||
            // @todo leaveAnimation: 'core-modal-lateral-transition',
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        await modal.present();
 | 
			
		||||
 | 
			
		||||
        const result = await modal.onDidDismiss();
 | 
			
		||||
 | 
			
		||||
        if (result.data) {
 | 
			
		||||
            this.changeChapter(result.data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Change the current chapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapterId Chapter to load.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    changeChapter(chapterId: number): void {
 | 
			
		||||
        if (chapterId && chapterId != this.currentChapter) {
 | 
			
		||||
            this.loaded = false;
 | 
			
		||||
            this.refreshIcon = CoreConstants.ICON_LOADING;
 | 
			
		||||
            this.loadChapter(chapterId, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Perform the invalidate content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected invalidateContent(): Promise<void> {
 | 
			
		||||
        return AddonModBook.instance.invalidateContent(this.module!.id, this.courseId!);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Download book contents and load the current chapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param refresh Whether we're refreshing data.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async fetchContent(refresh = false): Promise<void> {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
        let downloadResult: CoreCourseResourceDownloadResult | undefined;
 | 
			
		||||
 | 
			
		||||
        // Try to get the book data. Ignore errors since this WS isn't available in some Moodle versions.
 | 
			
		||||
        promises.push(CoreUtils.instance.ignoreErrors(AddonModBook.instance.getBook(this.courseId!, this.module!.id))
 | 
			
		||||
            .then((book) => {
 | 
			
		||||
                if (!book) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.book = book;
 | 
			
		||||
                this.dataRetrieved.emit(book);
 | 
			
		||||
 | 
			
		||||
                this.description = book.intro;
 | 
			
		||||
                this.displayNavBar = book.navstyle != AddonModBookNavStyle.TOC_ONLY;
 | 
			
		||||
                this.displayTitlesInNavBar = book.navstyle == AddonModBookNavStyle.TEXT;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        // Get module status to determine if it needs to be downloaded.
 | 
			
		||||
        promises.push(this.downloadResourceIfNeeded(refresh).then((result) => {
 | 
			
		||||
            downloadResult = result;
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await Promise.all(promises);
 | 
			
		||||
 | 
			
		||||
            this.contentsMap = AddonModBook.instance.getContentsMap(this.module!.contents);
 | 
			
		||||
            this.chapters = AddonModBook.instance.getTocList(this.module!.contents);
 | 
			
		||||
 | 
			
		||||
            if (typeof this.currentChapter == 'undefined' && typeof this.initialChapterId != 'undefined' && this.chapters) {
 | 
			
		||||
                // Initial chapter set. Validate that the chapter exists.
 | 
			
		||||
                const chapter = this.chapters.find((chapter) => chapter.id == this.initialChapterId);
 | 
			
		||||
 | 
			
		||||
                if (chapter) {
 | 
			
		||||
                    this.currentChapter = this.initialChapterId;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (typeof this.currentChapter == 'undefined') {
 | 
			
		||||
                // Load the first chapter.
 | 
			
		||||
                this.currentChapter = AddonModBook.instance.getFirstChapter(this.chapters);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Show chapter.
 | 
			
		||||
            try {
 | 
			
		||||
                await this.loadChapter(this.currentChapter!, refresh);
 | 
			
		||||
 | 
			
		||||
                this.warning = downloadResult?.failed ? this.getErrorDownloadingSomeFilesMessage(downloadResult.error!) : '';
 | 
			
		||||
            } catch {
 | 
			
		||||
                // Ignore errors, they're handled inside the loadChapter function.
 | 
			
		||||
            }
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.fillContextMenu(refresh);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load a book chapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapterId Chapter to load.
 | 
			
		||||
     * @param logChapterId Whether chapter ID should be passed to the log view function.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async loadChapter(chapterId: number, logChapterId: boolean): Promise<void> {
 | 
			
		||||
        this.currentChapter = chapterId;
 | 
			
		||||
        this.content?.scrollToTop();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const content = await AddonModBook.instance.getChapterContent(this.contentsMap, chapterId, this.module!.id);
 | 
			
		||||
 | 
			
		||||
            this.tags = this.tagsEnabled ? this.contentsMap[this.currentChapter].tags : [];
 | 
			
		||||
 | 
			
		||||
            this.chapterContent = content;
 | 
			
		||||
            this.previousChapter = AddonModBook.instance.getPreviousChapter(this.chapters, chapterId);
 | 
			
		||||
            this.nextChapter = AddonModBook.instance.getNextChapter(this.chapters, chapterId);
 | 
			
		||||
 | 
			
		||||
            this.previousNavBarTitle = this.previousChapter && this.displayTitlesInNavBar
 | 
			
		||||
                ? Translate.instance.instant('addon.mod_book.navprevtitle', { $a: this.previousChapter.title })
 | 
			
		||||
                : '';
 | 
			
		||||
            this.nextNavBarTitle = this.nextChapter && this.displayTitlesInNavBar
 | 
			
		||||
                ? Translate.instance.instant('addon.mod_book.navnexttitle', { $a: this.nextChapter.title })
 | 
			
		||||
                : '';
 | 
			
		||||
 | 
			
		||||
            // Chapter loaded, log view. We don't return the promise because we don't want to block the user for this.
 | 
			
		||||
            await CoreUtils.instance.ignoreErrors(AddonModBook.instance.logView(
 | 
			
		||||
                this.module!.instance!,
 | 
			
		||||
                logChapterId ? chapterId : undefined,
 | 
			
		||||
                this.module!.name,
 | 
			
		||||
            ));
 | 
			
		||||
 | 
			
		||||
            // Module is completed when last chapter is viewed, so we only check completion if the last is reached.
 | 
			
		||||
            if (!this.nextChapter) {
 | 
			
		||||
                CoreCourse.instance.checkModuleCompletion(this.courseId!, this.module!.completiondata);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.instance.showErrorModalDefault(error, 'addon.mod_book.errorchapter', true);
 | 
			
		||||
 | 
			
		||||
            throw error;
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
            this.refreshIcon = CoreConstants.ICON_REFRESH;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/addons/mod/book/components/toc/toc.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/addons/mod/book/components/toc/toc.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>{{ 'addon.mod_book.toc' | translate }}</ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
            <ion-button (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
 | 
			
		||||
                <ion-icon name="fas-times" slot="icon-only"></ion-icon>
 | 
			
		||||
            </ion-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <nav>
 | 
			
		||||
        <ion-list>
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)"
 | 
			
		||||
                [class.core-nav-item-selected]="selected == chapter.id"
 | 
			
		||||
                [class.item-dimmed]="chapter.hidden">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <p [class.ion-padding-left]="addPadding && chapter.level == 1 ? true : null">
 | 
			
		||||
                        <span *ngIf="showNumbers" class="addon-mod-book-number">{{chapter.indexNumber}}</span>
 | 
			
		||||
                        <span *ngIf="showBullets" class="addon-mod-book-bullet">•</span>
 | 
			
		||||
                        <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="moduleId"
 | 
			
		||||
                            [courseId]="courseId">
 | 
			
		||||
                        </core-format-text>
 | 
			
		||||
                    </p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-list>
 | 
			
		||||
    </nav>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										5
									
								
								src/addons/mod/book/components/toc/toc.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/addons/mod/book/components/toc/toc.scss
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
.addon-mod-book-bullet {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    font-size: 1.5em;
 | 
			
		||||
    margin-right: 3px;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								src/addons/mod/book/components/toc/toc.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/addons/mod/book/components/toc/toc.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
// (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, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { ModalController } from '@singletons';
 | 
			
		||||
import { AddonModBookTocChapter, AddonModBookBookWSData, AddonModBookNumbering } from '../../services/book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Modal to display the TOC of a book.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-mod-book-toc',
 | 
			
		||||
    templateUrl: 'toc.html',
 | 
			
		||||
    styleUrls: ['toc.scss'],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookTocComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
    @Input() moduleId?: number;
 | 
			
		||||
    @Input() chapters: AddonModBookTocChapter[] = [];
 | 
			
		||||
    @Input() selected?: number;
 | 
			
		||||
    @Input() courseId?: number;
 | 
			
		||||
    showNumbers = true;
 | 
			
		||||
    addPadding = true;
 | 
			
		||||
    showBullets = false;
 | 
			
		||||
 | 
			
		||||
    @Input() protected book?: AddonModBookBookWSData;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component loaded.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        if (this.book) {
 | 
			
		||||
            this.showNumbers = this.book.numbering == AddonModBookNumbering.NUMBERS;
 | 
			
		||||
            this.showBullets = this.book.numbering == AddonModBookNumbering.BULLETS;
 | 
			
		||||
            this.addPadding = this.book.numbering != AddonModBookNumbering.NONE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Function called when a course is clicked.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id ID of the clicked chapter.
 | 
			
		||||
     */
 | 
			
		||||
    loadChapter(id: number): void {
 | 
			
		||||
        ModalController.instance.dismiss(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Close modal.
 | 
			
		||||
     */
 | 
			
		||||
    closeModal(): void {
 | 
			
		||||
        ModalController.instance.dismiss();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/addons/mod/book/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/addons/mod/book/lang.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
    "errorchapter": "Error reading chapter of book.",
 | 
			
		||||
    "modulenameplural": "Books",
 | 
			
		||||
    "navnexttitle": "Next: {{$a}}",
 | 
			
		||||
    "navprevtitle": "Previous: {{$a}}",
 | 
			
		||||
    "tagarea_book_chapters": "Book chapters",
 | 
			
		||||
    "toc": "Table of contents"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/addons/mod/book/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/addons/mod/book/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [attr.aria-label]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>
 | 
			
		||||
            <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">
 | 
			
		||||
            </core-format-text>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
            <!-- The buttons defined by the component will be added in here. -->
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!bookComponent?.loaded" (ionRefresh)="bookComponent?.doRefresh($event)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
 | 
			
		||||
    <addon-mod-book-index [module]="module" [courseId]="courseId" [initialChapterId]="chapterId"
 | 
			
		||||
        (dataRetrieved)="updateData($event)">
 | 
			
		||||
    </addon-mod-book-index>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										46
									
								
								src/addons/mod/book/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/mod/book/pages/index/index.module.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 { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { IonicModule } from '@ionic/angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { AddonModBookComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { AddonModBookIndexPage } from './index';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: AddonModBookIndexPage,
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        AddonModBookComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModBookIndexPage,
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [RouterModule],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookIndexPageModule {}
 | 
			
		||||
							
								
								
									
										57
									
								
								src/addons/mod/book/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/addons/mod/book/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
// (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, ViewChild } from '@angular/core';
 | 
			
		||||
import { CoreCourseWSModule } from '@features/course/services/course';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { AddonModBookIndexComponent } from '../../components/index/index';
 | 
			
		||||
import { AddonModBookBookWSData } from '../../services/book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays a book.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-addon-mod-book-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBookIndexPage implements OnInit {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(AddonModBookIndexComponent) bookComponent?: AddonModBookIndexComponent;
 | 
			
		||||
 | 
			
		||||
    title?: string;
 | 
			
		||||
    module?: CoreCourseWSModule;
 | 
			
		||||
    courseId?: number;
 | 
			
		||||
    chapterId?: number;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        this.module = CoreNavigator.instance.getRouteParam('module');
 | 
			
		||||
        this.courseId = CoreNavigator.instance.getRouteNumberParam('courseId');
 | 
			
		||||
        this.chapterId = CoreNavigator.instance.getRouteNumberParam('chapterId');
 | 
			
		||||
        this.title = this.module?.name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update some data based on the book instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param book Book instance.
 | 
			
		||||
     */
 | 
			
		||||
    updateData(book: AddonModBookBookWSData): void {
 | 
			
		||||
        this.title = book.name || this.title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										479
									
								
								src/addons/mod/book/services/book.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										479
									
								
								src/addons/mod/book/services/book.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,479 @@
 | 
			
		||||
// (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 { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
			
		||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
			
		||||
import { CoreTagItem } from '@features/tag/services/tag';
 | 
			
		||||
import { CoreWSExternalWarning, CoreWSExternalFile, CoreWS } from '@services/ws';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
			
		||||
import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreFilepool } from '@services/filepool';
 | 
			
		||||
import { CoreTextUtils } from '@services/utils/text';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreFile } from '@services/file';
 | 
			
		||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constants to define how the chapters and subchapters of a book should be displayed in that table of contents.
 | 
			
		||||
 */
 | 
			
		||||
export const enum AddonModBookNumbering {
 | 
			
		||||
    NONE = 0,
 | 
			
		||||
    NUMBERS = 1,
 | 
			
		||||
    BULLETS = 2,
 | 
			
		||||
    INDENTED = 3,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Constants to define the navigation style used within a book.
 | 
			
		||||
 */
 | 
			
		||||
export const enum AddonModBookNavStyle {
 | 
			
		||||
    TOC_ONLY = 0,
 | 
			
		||||
    IMAGE = 1,
 | 
			
		||||
    TEXT = 2,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'mmaModBook:';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service that provides some features for books.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookProvider {
 | 
			
		||||
 | 
			
		||||
    static readonly COMPONENT = 'mmaModBook';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a book by course module ID.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param cmId Course module ID.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved when the book is retrieved.
 | 
			
		||||
     */
 | 
			
		||||
    getBook(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModBookBookWSData> {
 | 
			
		||||
        return this.getBookByField(courseId, 'coursemodule', cmId, options);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a book with key=value. If more than one is found, only the first will be returned.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param key Name of the property to check.
 | 
			
		||||
     * @param value Value to search.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the book is retrieved.
 | 
			
		||||
     */
 | 
			
		||||
    protected async getBookByField(
 | 
			
		||||
        courseId: number,
 | 
			
		||||
        key: string,
 | 
			
		||||
        value: number,
 | 
			
		||||
        options: CoreSitesCommonWSOptions = {},
 | 
			
		||||
    ): Promise<AddonModBookBookWSData> {
 | 
			
		||||
 | 
			
		||||
        const site = await CoreSites.instance.getSite(options.siteId);
 | 
			
		||||
        const params: AddonModBookGetBooksByCoursesWSParams = {
 | 
			
		||||
            courseids: [courseId],
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            cacheKey: this.getBookDataCacheKey(courseId),
 | 
			
		||||
            updateFrequency: CoreSite.FREQUENCY_RARELY,
 | 
			
		||||
            component: AddonModBookProvider.COMPONENT,
 | 
			
		||||
            ...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const response: AddonModBookGetBooksByCoursesWSResponse = await site.read('mod_book_get_books_by_courses', params, preSets);
 | 
			
		||||
 | 
			
		||||
        // Search the book.
 | 
			
		||||
        const book = response.books.find((book) => book[key] == value);
 | 
			
		||||
        if (book) {
 | 
			
		||||
            return book;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new CoreWSError('Book not found');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for get book data WS calls.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @return Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getBookDataCacheKey(courseId: number): string {
 | 
			
		||||
        return ROOT_CACHE_KEY + 'book:' + courseId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a chapter contents.
 | 
			
		||||
     *
 | 
			
		||||
     * @param contentsMap Contents map returned by getContentsMap.
 | 
			
		||||
     * @param chapterId Chapter to retrieve.
 | 
			
		||||
     * @param moduleId The module ID.
 | 
			
		||||
     * @return Promise resolved with the contents.
 | 
			
		||||
     */
 | 
			
		||||
    async getChapterContent(contentsMap: AddonModBookContentsMap, chapterId: number, moduleId: number): Promise<string> {
 | 
			
		||||
 | 
			
		||||
        const indexUrl = contentsMap[chapterId] ? contentsMap[chapterId].indexUrl : undefined;
 | 
			
		||||
        if (!indexUrl) {
 | 
			
		||||
            // It shouldn't happen.
 | 
			
		||||
            throw new CoreWSError('Could not locate the index chapter.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!CoreFile.instance.isAvailable()) {
 | 
			
		||||
            // We return the live URL.
 | 
			
		||||
            return CoreSites.instance.getCurrentSite()!.checkAndFixPluginfileURL(indexUrl);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const siteId = CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        const url = await CoreFilepool.instance.downloadUrl(siteId, indexUrl, false, AddonModBookProvider.COMPONENT, moduleId);
 | 
			
		||||
 | 
			
		||||
        const content = await CoreWS.instance.getText(url);
 | 
			
		||||
 | 
			
		||||
        // Now that we have the content, we update the SRC to point back to the external resource.
 | 
			
		||||
        return CoreDomUtils.instance.restoreSourcesInHtml(content, contentsMap[chapterId].paths);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert an array of book contents into an object where contents are organized in chapters.
 | 
			
		||||
     * Each chapter has an indexUrl and the list of contents in that chapter.
 | 
			
		||||
     *
 | 
			
		||||
     * @param contents The module contents.
 | 
			
		||||
     * @return Contents map.
 | 
			
		||||
     */
 | 
			
		||||
    getContentsMap(contents: CoreCourseModuleContentFile[]): AddonModBookContentsMap {
 | 
			
		||||
        const map: AddonModBookContentsMap = {};
 | 
			
		||||
 | 
			
		||||
        if (!contents) {
 | 
			
		||||
            return map;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        contents.forEach((content) => {
 | 
			
		||||
            if (!this.isFileDownloadable(content)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Search the chapter number in the filepath.
 | 
			
		||||
            const matches = content.filepath.match(/\/(\d+)\//);
 | 
			
		||||
            if (!matches || !matches[1]) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            let key: string;
 | 
			
		||||
            const chapter: string = matches[1];
 | 
			
		||||
            const filepathIsChapter = content.filepath == '/' + chapter + '/';
 | 
			
		||||
 | 
			
		||||
            // Init the chapter if it's not defined yet.
 | 
			
		||||
            map[chapter] = map[chapter] || { paths: {} };
 | 
			
		||||
 | 
			
		||||
            if (content.filename == 'index.html' && filepathIsChapter) {
 | 
			
		||||
                // Index of the chapter, set indexUrl and tags of the chapter.
 | 
			
		||||
                map[chapter].indexUrl = content.fileurl;
 | 
			
		||||
                map[chapter].tags = content.tags;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (filepathIsChapter) {
 | 
			
		||||
                // It's a file in the root folder OR the WS isn't returning the filepath as it should (MDL-53671).
 | 
			
		||||
                // Try to get the path to the file from the URL.
 | 
			
		||||
                const split = content.fileurl.split('mod_book/chapter' + content.filepath);
 | 
			
		||||
                key = split[1] || content.filename; // Use filename if we couldn't find the path.
 | 
			
		||||
            } else {
 | 
			
		||||
                // Remove the chapter folder from the path and add the filename.
 | 
			
		||||
                key = content.filepath.replace('/' + chapter + '/', '') + content.filename;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            map[chapter].paths[CoreTextUtils.instance.decodeURIComponent(key)] = content.fileurl;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the first chapter of a book.
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapters The chapters list.
 | 
			
		||||
     * @return The chapter id.
 | 
			
		||||
     */
 | 
			
		||||
    getFirstChapter(chapters: AddonModBookTocChapter[]): number | undefined {
 | 
			
		||||
        if (!chapters || !chapters.length) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return chapters[0].id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the next chapter to the given one.
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapters The chapters list.
 | 
			
		||||
     * @param chapterId The current chapter.
 | 
			
		||||
     * @return The next chapter.
 | 
			
		||||
     */
 | 
			
		||||
    getNextChapter(chapters: AddonModBookTocChapter[], chapterId: number): AddonModBookTocChapter | undefined {
 | 
			
		||||
        const currentChapterIndex = chapters.findIndex((chapter) => chapter.id == chapterId);
 | 
			
		||||
 | 
			
		||||
        if (currentChapterIndex >= 0 && typeof chapters[currentChapterIndex + 1] != 'undefined') {
 | 
			
		||||
            return chapters[currentChapterIndex + 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the previous chapter to the given one.
 | 
			
		||||
     *
 | 
			
		||||
     * @param chapters The chapters list.
 | 
			
		||||
     * @param chapterId The current chapter.
 | 
			
		||||
     * @return The next chapter.
 | 
			
		||||
     */
 | 
			
		||||
    getPreviousChapter(chapters: AddonModBookTocChapter[], chapterId: number): AddonModBookTocChapter | undefined {
 | 
			
		||||
        const currentChapterIndex = chapters.findIndex((chapter) => chapter.id == chapterId);
 | 
			
		||||
 | 
			
		||||
        if (currentChapterIndex > 0) {
 | 
			
		||||
            return chapters[currentChapterIndex - 1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the book toc as an array.
 | 
			
		||||
     *
 | 
			
		||||
     * @param contents The module contents.
 | 
			
		||||
     * @return The toc.
 | 
			
		||||
     */
 | 
			
		||||
    getToc(contents: CoreCourseModuleContentFile[]): AddonModBookTocChapterParsed[] {
 | 
			
		||||
        if (!contents || !contents.length || typeof contents[0].content == 'undefined') {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return CoreTextUtils.instance.parseJSON(contents[0].content, []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the book toc as an array of chapters (not nested).
 | 
			
		||||
     *
 | 
			
		||||
     * @param contents The module contents.
 | 
			
		||||
     * @return The toc as a list.
 | 
			
		||||
     */
 | 
			
		||||
    getTocList(contents: CoreCourseModuleContentFile[]): AddonModBookTocChapter[] {
 | 
			
		||||
        // Convenience function to get chapter info.
 | 
			
		||||
        const getChapterInfo = (
 | 
			
		||||
            chapter: AddonModBookTocChapterParsed,
 | 
			
		||||
            chapterNumber: number,
 | 
			
		||||
            previousNumber: string = '',
 | 
			
		||||
        ): AddonModBookTocChapter => {
 | 
			
		||||
            const hidden = !!parseInt(chapter.hidden, 10);
 | 
			
		||||
 | 
			
		||||
            const fullChapterNumber = previousNumber + (hidden ? 'x.' : chapterNumber + '.');
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                id: parseInt(chapter.href.replace('/index.html', ''), 10),
 | 
			
		||||
                title: chapter.title,
 | 
			
		||||
                level: chapter.level,
 | 
			
		||||
                indexNumber: fullChapterNumber,
 | 
			
		||||
                hidden: hidden,
 | 
			
		||||
            };
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const chapters: AddonModBookTocChapter[] = [];
 | 
			
		||||
        const toc = this.getToc(contents);
 | 
			
		||||
 | 
			
		||||
        let chapterNumber = 1;
 | 
			
		||||
        toc.forEach((chapter) => {
 | 
			
		||||
            const tocChapter = getChapterInfo(chapter, chapterNumber);
 | 
			
		||||
 | 
			
		||||
            // Add the chapter to the list.
 | 
			
		||||
            chapters.push(tocChapter);
 | 
			
		||||
 | 
			
		||||
            if (chapter.subitems) {
 | 
			
		||||
                let subChapterNumber = 1;
 | 
			
		||||
                // Add all the subchapters to the list.
 | 
			
		||||
                chapter.subitems.forEach((subChapter) => {
 | 
			
		||||
                    chapters.push(getChapterInfo(subChapter, subChapterNumber, tocChapter.indexNumber));
 | 
			
		||||
                    subChapterNumber++;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            chapterNumber++;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return chapters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidates book data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    async invalidateBookData(courseId: number, siteId?: string): Promise<void> {
 | 
			
		||||
        const site = await CoreSites.instance.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        await site.invalidateWsCacheForKey(this.getBookDataCacheKey(courseId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate the prefetched content.
 | 
			
		||||
     *
 | 
			
		||||
     * @param moduleId The module ID.
 | 
			
		||||
     * @param courseId Course ID of the module.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateContent(moduleId: number, courseId: number, siteId?: string): Promise<void> {
 | 
			
		||||
        siteId = siteId || CoreSites.instance.getCurrentSiteId();
 | 
			
		||||
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(this.invalidateBookData(courseId, siteId));
 | 
			
		||||
        promises.push(CoreFilepool.instance.invalidateFilesByComponent(siteId, AddonModBookProvider.COMPONENT, moduleId));
 | 
			
		||||
        promises.push(CoreCourse.instance.invalidateModule(moduleId, siteId));
 | 
			
		||||
 | 
			
		||||
        return CoreUtils.instance.allPromises(promises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if a file is downloadable. The file param must have a 'type' attribute like in core_course_get_contents response.
 | 
			
		||||
     *
 | 
			
		||||
     * @param file File to check.
 | 
			
		||||
     * @return Whether it's downloadable.
 | 
			
		||||
     */
 | 
			
		||||
    isFileDownloadable(file: CoreCourseModuleContentFile): boolean {
 | 
			
		||||
        return file.type === 'file';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Return whether or not the plugin is enabled.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    async isPluginEnabled(siteId?: string): Promise<boolean> {
 | 
			
		||||
        const site = await CoreSites.instance.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        return site.canDownloadFiles();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Report a book as being viewed.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id Module ID.
 | 
			
		||||
     * @param chapterId Chapter ID.
 | 
			
		||||
     * @param name Name of the book.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the WS call is successful.
 | 
			
		||||
     */
 | 
			
		||||
    logView(id: number, chapterId?: number, name?: string, siteId?: string): Promise<void> {
 | 
			
		||||
        const params: AddonModBookViewBookWSParams = {
 | 
			
		||||
            bookid: id,
 | 
			
		||||
            chapterid: chapterId,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return CoreCourseLogHelper.instance.logSingle(
 | 
			
		||||
            'mod_book_view_book',
 | 
			
		||||
            params,
 | 
			
		||||
            AddonModBookProvider.COMPONENT,
 | 
			
		||||
            id,
 | 
			
		||||
            name,
 | 
			
		||||
            'book',
 | 
			
		||||
            { chapterid: chapterId },
 | 
			
		||||
            siteId,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonModBook extends makeSingleton(AddonModBookProvider) {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A book chapter inside the toc list.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBookTocChapter = {
 | 
			
		||||
    id: number; // ID to identify the chapter.
 | 
			
		||||
    title: string; // Chapter's title.
 | 
			
		||||
    level: number; // The chapter's level.
 | 
			
		||||
    hidden: boolean; // The chapter is hidden.
 | 
			
		||||
    indexNumber: string; // The chapter's number'.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A book chapter parsed from JSON.
 | 
			
		||||
 */
 | 
			
		||||
type AddonModBookTocChapterParsed = {
 | 
			
		||||
    title: string; // Chapter's title.
 | 
			
		||||
    level: number; // The chapter's level.
 | 
			
		||||
    hidden: string; // The chapter is hidden.
 | 
			
		||||
    href: string;
 | 
			
		||||
    subitems: AddonModBookTocChapterParsed[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Map of book contents. For each chapter it has its index URL and the list of paths of the files the chapter has. Each path
 | 
			
		||||
 * is identified by the relative path in the book, and the value is the URL of the file.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBookContentsMap = {
 | 
			
		||||
    [chapter: string]: {
 | 
			
		||||
        indexUrl?: string;
 | 
			
		||||
        paths: {[path: string]: string};
 | 
			
		||||
        tags?: CoreTagItem[];
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Book returned by mod_book_get_books_by_courses.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBookBookWSData = {
 | 
			
		||||
    id: number; // Book id.
 | 
			
		||||
    coursemodule: number; // Course module id.
 | 
			
		||||
    course: number; // Course id.
 | 
			
		||||
    name: string; // Book name.
 | 
			
		||||
    intro: string; // The Book intro.
 | 
			
		||||
    introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | 
			
		||||
    introfiles?: CoreWSExternalFile[]; // @since 3.2.
 | 
			
		||||
    numbering: number; // Book numbering configuration.
 | 
			
		||||
    navstyle: number; // Book navigation style configuration.
 | 
			
		||||
    customtitles: number; // Book custom titles type.
 | 
			
		||||
    revision?: number; // Book revision.
 | 
			
		||||
    timecreated?: number; // Time of creation.
 | 
			
		||||
    timemodified?: number; // Time of last modification.
 | 
			
		||||
    section?: number; // Course section id.
 | 
			
		||||
    visible?: boolean; // Visible.
 | 
			
		||||
    groupmode?: number; // Group mode.
 | 
			
		||||
    groupingid?: number; // Group id.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_book_get_books_by_courses WS.
 | 
			
		||||
 */
 | 
			
		||||
type AddonModBookGetBooksByCoursesWSParams = {
 | 
			
		||||
    courseids?: number[]; // Array of course ids.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by mod_book_get_books_by_courses WS.
 | 
			
		||||
 */
 | 
			
		||||
type AddonModBookGetBooksByCoursesWSResponse = {
 | 
			
		||||
    books: AddonModBookBookWSData[];
 | 
			
		||||
    warnings?: CoreWSExternalWarning[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_book_view_book WS.
 | 
			
		||||
 */
 | 
			
		||||
type AddonModBookViewBookWSParams = {
 | 
			
		||||
    bookid: number; // Book instance id.
 | 
			
		||||
    chapterid?: number; // Chapter id.
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										55
									
								
								src/addons/mod/book/services/handlers/index-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/addons/mod/book/services/handlers/index-link.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
// (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 { Params } from '@angular/router';
 | 
			
		||||
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonModBook } from '../book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to book.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookIndexLinkHandlerService extends CoreContentLinksModuleIndexHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBookLinkHandler';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonModBook', 'book', 'b');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the mod params necessary to open an activity.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  url      The URL to treat.
 | 
			
		||||
     * @param  params   The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
 | 
			
		||||
     * @return List of params to pass to navigateToModule / navigateToModuleByInstance.
 | 
			
		||||
     */
 | 
			
		||||
    getPageParams(url: string, params: Record<string, string>): Params {
 | 
			
		||||
        return params.chapterid ? { chapterId: parseInt(params.chapterid, 10) } : {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled for a certain site (site + user) and a URL.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the handler is enabled for the URL and site.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(siteId: string): Promise<boolean> {
 | 
			
		||||
        return AddonModBook.instance.isPluginEnabled(siteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonModBookIndexLinkHandler extends makeSingleton(AddonModBookIndexLinkHandlerService) {}
 | 
			
		||||
							
								
								
									
										44
									
								
								src/addons/mod/book/services/handlers/list-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/addons/mod/book/services/handlers/list-link.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
// (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 { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonModBook } from '../book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to book list page.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookListLinkHandlerService extends CoreContentLinksModuleListHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBookListLinkHandler';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonModBook', 'book');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled for a certain site (site + user) and a URL.
 | 
			
		||||
     * If not defined, defaults to true.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether the handler is enabled for the URL and site.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonModBook.instance.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonModBookListLinkHandler extends makeSingleton(AddonModBookListLinkHandlerService) {}
 | 
			
		||||
							
								
								
									
										94
									
								
								src/addons/mod/book/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/addons/mod/book/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
// (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, Type } from '@angular/core';
 | 
			
		||||
import { AddonModBookIndexComponent } from '../../components/index';
 | 
			
		||||
import { AddonModBook } from '../book';
 | 
			
		||||
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course';
 | 
			
		||||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreCourseModule } from '@features/course/services/course-helper';
 | 
			
		||||
import { CoreConstants } from '@/core/constants';
 | 
			
		||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support book modules.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookModuleHandlerService implements CoreCourseModuleHandler {
 | 
			
		||||
 | 
			
		||||
    static readonly PAGE_NAME = 'mod_book';
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBook';
 | 
			
		||||
    modName = 'book';
 | 
			
		||||
 | 
			
		||||
    supportedFeatures = {
 | 
			
		||||
        [CoreConstants.FEATURE_MOD_ARCHETYPE]: CoreConstants.MOD_ARCHETYPE_RESOURCE,
 | 
			
		||||
        [CoreConstants.FEATURE_GROUPS]: false,
 | 
			
		||||
        [CoreConstants.FEATURE_GROUPINGS]: false,
 | 
			
		||||
        [CoreConstants.FEATURE_MOD_INTRO]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false,
 | 
			
		||||
        [CoreConstants.FEATURE_GRADE_OUTCOMES]: false,
 | 
			
		||||
        [CoreConstants.FEATURE_BACKUP_MOODLE2]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonModBook.instance.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the data required to display the module in the course contents view.
 | 
			
		||||
     *
 | 
			
		||||
     * @param module The module object.
 | 
			
		||||
     * @param courseId The course ID.
 | 
			
		||||
     * @param sectionId The section ID.
 | 
			
		||||
     * @return Data to render the module.
 | 
			
		||||
     */
 | 
			
		||||
    getData(module: CoreCourseAnyModuleData): CoreCourseModuleHandlerData {
 | 
			
		||||
        return {
 | 
			
		||||
            icon: CoreCourse.instance.getModuleIconSrc(this.modName, 'modicon' in module ? module.modicon : undefined),
 | 
			
		||||
            title: module.name,
 | 
			
		||||
            class: 'addon-mod_book-handler',
 | 
			
		||||
            showDownloadButton: true,
 | 
			
		||||
            action(event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions): void {
 | 
			
		||||
                options = options || {};
 | 
			
		||||
                options.params = options.params || {};
 | 
			
		||||
                Object.assign(options.params, { module });
 | 
			
		||||
                const routeParams = '/' + courseId + '/' + module.id;
 | 
			
		||||
 | 
			
		||||
                CoreNavigator.instance.navigateToSitePath(AddonModBookModuleHandlerService.PAGE_NAME + routeParams, options);
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to render the module. This is needed to support singleactivity course format.
 | 
			
		||||
     * The component returned must implement CoreCourseModuleMainComponent.
 | 
			
		||||
     * It's recommended to return the class of the component, but you can also return an instance of the component.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    async getMainComponent(): Promise<Type<unknown> | undefined> {
 | 
			
		||||
        return AddonModBookIndexComponent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
export class AddonModBookModuleHandler extends makeSingleton(AddonModBookModuleHandlerService) {}
 | 
			
		||||
							
								
								
									
										86
									
								
								src/addons/mod/book/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/addons/mod/book/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,86 @@
 | 
			
		||||
// (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 { CoreCourseResourcePrefetchHandlerBase } from '@features/course/classes/resource-prefetch-handler';
 | 
			
		||||
import { CoreCourseAnyModuleData, CoreCourseWSModule } from '@features/course/services/course';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreWSExternalFile } from '@services/ws';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonModBook, AddonModBookProvider } from '../book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to prefetch books.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookPrefetchHandlerService extends CoreCourseResourcePrefetchHandlerBase {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBook';
 | 
			
		||||
    modName = 'book';
 | 
			
		||||
    component = AddonModBookProvider.COMPONENT;
 | 
			
		||||
    updatesNames = /^configuration$|^.*files$|^entries$/;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Download or prefetch the content.
 | 
			
		||||
     *
 | 
			
		||||
     * @param module The module object returned by WS.
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param prefetch True to prefetch, false to download right away.
 | 
			
		||||
     * @return Promise resolved when all content is downloaded. Data returned is not reliable.
 | 
			
		||||
     */
 | 
			
		||||
    async downloadOrPrefetch(module: CoreCourseWSModule, courseId: number, prefetch?: boolean): Promise<void> {
 | 
			
		||||
        const promises: Promise<unknown>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
 | 
			
		||||
        // Ignore errors since this WS isn't available in some Moodle versions.
 | 
			
		||||
        promises.push(CoreUtils.instance.ignoreErrors(AddonModBook.instance.getBook(courseId, module.id)));
 | 
			
		||||
        await Promise.all(promises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns module intro files.
 | 
			
		||||
     *
 | 
			
		||||
     * @param module The module object returned by WS.
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @return Promise resolved with list of intro files.
 | 
			
		||||
     */
 | 
			
		||||
    async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreWSExternalFile[]> {
 | 
			
		||||
        const book = await CoreUtils.instance.ignoreErrors(AddonModBook.instance.getBook(courseId, module.id));
 | 
			
		||||
 | 
			
		||||
        return this.getIntroFilesFromInstance(module, book);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate the prefetched content.
 | 
			
		||||
     *
 | 
			
		||||
     * @param moduleId The module ID.
 | 
			
		||||
     * @param courseId Course ID the module belongs to.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    async invalidateContent(moduleId: number, courseId: number): Promise<void> {
 | 
			
		||||
        await AddonModBook.instance.invalidateContent(moduleId, courseId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonModBook.instance.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonModBookPrefetchHandler extends makeSingleton(AddonModBookPrefetchHandlerService) {}
 | 
			
		||||
							
								
								
									
										79
									
								
								src/addons/mod/book/services/handlers/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/addons/mod/book/services/handlers/tag-area.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
// (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, Type } from '@angular/core';
 | 
			
		||||
import { CoreCourse } from '@features/course/services/course';
 | 
			
		||||
import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
 | 
			
		||||
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
 | 
			
		||||
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
 | 
			
		||||
import { CoreUrlUtils } from '@services/utils/url';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonModBook } from '../book';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support tags.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBookTagAreaHandlerService implements CoreTagAreaHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBookTagAreaHandler';
 | 
			
		||||
    type = 'mod_book/book_chapters';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonModBook.instance.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Parses the rendered content of a tag index and returns the items.
 | 
			
		||||
     *
 | 
			
		||||
     * @param content Rendered content.
 | 
			
		||||
     * @return Area items (or promise resolved with the items).
 | 
			
		||||
     */
 | 
			
		||||
    async parseContent(content: string): Promise<CoreTagFeedElement[]> {
 | 
			
		||||
        const items = CoreTagHelper.instance.parseFeedContent(content);
 | 
			
		||||
 | 
			
		||||
        // Find module ids of the returned books, they are needed by the link delegate.
 | 
			
		||||
        await Promise.all(items.map((item) => {
 | 
			
		||||
            const params = item.url ? CoreUrlUtils.instance.extractUrlParams(item.url) : {};
 | 
			
		||||
            if (params.b && !params.id) {
 | 
			
		||||
                const bookId = parseInt(params.b, 10);
 | 
			
		||||
 | 
			
		||||
                return CoreCourse.instance.getModuleBasicInfoByInstance(bookId, 'book').then((module) => {
 | 
			
		||||
                    item.url += '&id=' + module.id;
 | 
			
		||||
 | 
			
		||||
                    return;
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to use to display items.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The component (or promise resolved with component) to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getComponent(): Type<unknown> | Promise<Type<unknown>> {
 | 
			
		||||
        return CoreTagFeedComponent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AddonModBookTagAreaHandler extends makeSingleton(AddonModBookTagAreaHandlerService) {}
 | 
			
		||||
@ -14,11 +14,13 @@
 | 
			
		||||
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { AddonModBookModule } from './book/book.module';
 | 
			
		||||
import { AddonModLessonModule } from './lesson/lesson.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [],
 | 
			
		||||
    imports: [
 | 
			
		||||
        AddonModBookModule,
 | 
			
		||||
        AddonModLessonModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [],
 | 
			
		||||
 | 
			
		||||
@ -77,12 +77,18 @@ export class CoreConstants {
 | 
			
		||||
    static readonly OUTDATED = 'outdated';
 | 
			
		||||
    static readonly NOT_DOWNLOADABLE = 'notdownloadable';
 | 
			
		||||
 | 
			
		||||
    // Download / prefetch status icon. @todo
 | 
			
		||||
    static readonly DOWNLOADED_ICON = 'cloud-done';
 | 
			
		||||
    static readonly DOWNLOADING_ICON = 'spinner';
 | 
			
		||||
    static readonly NOT_DOWNLOADED_ICON = 'cloud-download';
 | 
			
		||||
    static readonly OUTDATED_ICON = 'fas-redo-alt';
 | 
			
		||||
    static readonly NOT_DOWNLOADABLE_ICON = '';
 | 
			
		||||
 | 
			
		||||
    // General download and sync icons.
 | 
			
		||||
    static readonly ICON_LOADING = 'spinner';
 | 
			
		||||
    static readonly ICON_REFRESH = 'fas-redo-alt';
 | 
			
		||||
    static readonly ICON_SYNC = 'fas-sync-alt';
 | 
			
		||||
 | 
			
		||||
    // Constants from Moodle's resourcelib.
 | 
			
		||||
    static readonly RESOURCELIB_DISPLAY_AUTO = 0; // Try the best way.
 | 
			
		||||
    static readonly RESOURCELIB_DISPLAY_EMBED = 1; // Display using object tag.
 | 
			
		||||
 | 
			
		||||
@ -58,7 +58,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
			
		||||
    // Data for context menu.
 | 
			
		||||
    externalUrl?: string; // External URL to open in browser.
 | 
			
		||||
    description?: string; // Module description.
 | 
			
		||||
    refreshIcon = 'spinner'; // Refresh icon, normally spinner or refresh.
 | 
			
		||||
    refreshIcon = CoreConstants.ICON_LOADING; // Refresh icon, normally spinner or refresh.
 | 
			
		||||
    prefetchStatusIcon?: string; // Used when calling fillContextMenu.
 | 
			
		||||
    prefetchStatus?: string; // Used when calling fillContextMenu.
 | 
			
		||||
    prefetchText?: string; // Used when calling fillContextMenu.
 | 
			
		||||
@ -132,14 +132,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.refreshIcon = 'spinner';
 | 
			
		||||
        this.refreshIcon = CoreConstants.ICON_LOADING;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreUtils.instance.ignoreErrors(this.invalidateContent());
 | 
			
		||||
 | 
			
		||||
            await this.loadContent(true);
 | 
			
		||||
        } finally  {
 | 
			
		||||
            this.refreshIcon = 'fas-redo';
 | 
			
		||||
            this.refreshIcon = CoreConstants.ICON_REFRESH;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -181,7 +181,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
 | 
			
		||||
            CoreDomUtils.instance.showErrorModalDefault(error, this.fetchContentDefaultError, true);
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
            this.refreshIcon = 'fas-redo';
 | 
			
		||||
            this.refreshIcon = CoreConstants.ICON_REFRESH;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -64,9 +64,9 @@ export class CoreH5PFramework {
 | 
			
		||||
        const db = await CoreSites.instance.getSiteDb(siteId);
 | 
			
		||||
 | 
			
		||||
        const whereAndParams = db.getInOrEqual(libraryIds);
 | 
			
		||||
        whereAndParams[0] = 'mainlibraryid ' + whereAndParams[0];
 | 
			
		||||
        whereAndParams.sql = 'mainlibraryid ' + whereAndParams.sql;
 | 
			
		||||
 | 
			
		||||
        await db.updateRecordsWhere(CONTENT_TABLE_NAME, { filtered: null }, whereAndParams[0], whereAndParams[1]);
 | 
			
		||||
        await db.updateRecordsWhere(CONTENT_TABLE_NAME, { filtered: null }, whereAndParams.sql, whereAndParams.params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -919,4 +919,3 @@ type LibraryDependency = {
 | 
			
		||||
type LibraryAddonDBData = Omit<CoreH5PLibraryAddonData, 'addTo'> & {
 | 
			
		||||
    addTo: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2196,15 +2196,16 @@ export class CoreFilepoolProvider {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const fileIds = items.map((item) => item.fileId);
 | 
			
		||||
 | 
			
		||||
        const whereAndParams = db.getInOrEqual(fileIds);
 | 
			
		||||
 | 
			
		||||
        whereAndParams[0] = 'fileId ' + whereAndParams[0];
 | 
			
		||||
        whereAndParams.sql = 'fileId ' + whereAndParams.sql;
 | 
			
		||||
 | 
			
		||||
        if (onlyUnknown) {
 | 
			
		||||
            whereAndParams[0] += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE + ')';
 | 
			
		||||
            whereAndParams.sql += ' AND (' + CoreFilepoolProvider.FILE_UPDATE_UNKNOWN_WHERE_CLAUSE + ')';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await db.updateRecordsWhere(FILES_TABLE_NAME, { stale: 1 }, whereAndParams[0], whereAndParams[1]);
 | 
			
		||||
        await db.updateRecordsWhere(FILES_TABLE_NAME, { stale: 1 }, whereAndParams.sql, whereAndParams.params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user