commit
						9ba630c02a
					
				
							
								
								
									
										2
									
								
								.github/workflows/testing.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/testing.yml
									
									
									
									
										vendored
									
									
								
							| @ -14,8 +14,8 @@ jobs: | ||||
|       with: | ||||
|         node-version: '12.x' | ||||
|     - run: npm ci | ||||
|     - run: result=$(find src -type f -iname '*.html' -exec sh -c 'cat {} | tr "\n" " " | grep -Eo "class=\"[^\"]+\"[^>]+class=\"" ' \; | wc -l); test $result -eq 0 | ||||
|     - run: npm run lint | ||||
|     - run: npx tslint -c ionic-migration.json -p tsconfig.json | ||||
|     - run: npm run test:ci | ||||
|     - run: npm run build:prod | ||||
|     - run: result=$(find src -type f -iname '*.html' -exec sh -c 'cat {} | tr "\n" " " | grep -Eo "class=\"[^\"]+\"[^>]+class=\"" ' \; | wc -l); test $result -eq 0 | ||||
|  | ||||
| @ -376,13 +376,13 @@ export class AddonModBookProvider { | ||||
|      * @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> { | ||||
|     async logView(id: number, chapterId?: number, name?: string, siteId?: string): Promise<void> { | ||||
|         const params: AddonModBookViewBookWSParams = { | ||||
|             bookid: id, | ||||
|             chapterid: chapterId, | ||||
|         }; | ||||
| 
 | ||||
|         return CoreCourseLogHelper.instance.logSingle( | ||||
|         await CoreCourseLogHelper.instance.logSingle( | ||||
|             'mod_book_view_book', | ||||
|             params, | ||||
|             AddonModBookProvider.COMPONENT, | ||||
|  | ||||
| @ -16,12 +16,14 @@ import { NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { AddonModBookModule } from './book/book.module'; | ||||
| import { AddonModLessonModule } from './lesson/lesson.module'; | ||||
| import { AddonModPageModule } from './page/page.module'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [], | ||||
|     imports: [ | ||||
|         AddonModBookModule, | ||||
|         AddonModLessonModule, | ||||
|         AddonModPageModule, | ||||
|     ], | ||||
|     providers: [], | ||||
|     exports: [], | ||||
|  | ||||
							
								
								
									
										42
									
								
								src/addons/mod/page/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/addons/mod/page/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| // (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 { AddonModPageIndexComponent } from './index/index'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|         AddonModPageIndexComponent, | ||||
|     ], | ||||
|     imports: [ | ||||
|         CommonModule, | ||||
|         IonicModule, | ||||
|         TranslateModule.forChild(), | ||||
|         FormsModule, | ||||
|         CoreSharedModule, | ||||
|         CoreCourseComponentsModule, | ||||
|     ], | ||||
|     exports: [ | ||||
|         AddonModPageIndexComponent, | ||||
|     ], | ||||
| }) | ||||
| export class AddonModPageComponentsModule {} | ||||
| @ -0,0 +1,47 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <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 safe-area-page"> | ||||
| 
 | ||||
|     <core-course-module-description *ngIf="displayDescription" [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"> | ||||
|         <core-format-text [component]="component" [componentId]="componentId" [text]="contents" contextLevel="module" | ||||
|             [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|         </core-format-text> | ||||
| 
 | ||||
|         <p class="ion-padding-bottom addon-mod_page-timemodified" *ngIf="displayTimemodified && timemodified"> | ||||
|             {{ 'core.lastmodified' | translate}}: {{ timemodified! * 1000 | coreFormatDate }} | ||||
|         </p> | ||||
|     </div> | ||||
| 
 | ||||
| </core-loading> | ||||
							
								
								
									
										8
									
								
								src/addons/mod/page/components/index/index.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/addons/mod/page/components/index/index.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| /* Solves iframe height */ | ||||
| .core-loading-content > div[padding] { | ||||
|     height: 100%; | ||||
| } | ||||
| 
 | ||||
| core-format-text > .no-overflow { | ||||
|     display: inline; | ||||
| } | ||||
							
								
								
									
										150
									
								
								src/addons/mod/page/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/addons/mod/page/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | ||||
| // (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, Optional } from '@angular/core'; | ||||
| import { | ||||
|     CoreCourseModuleMainResourceComponent, | ||||
| } from '@features/course/classes/main-resource-component'; | ||||
| import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; | ||||
| import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { AddonModPageProvider, AddonModPagePage, AddonModPage } from '../../services/page'; | ||||
| import { AddonModPageHelper } from '../../services/page-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that displays a page. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'addon-mod-page-index', | ||||
|     templateUrl: 'addon-mod-page-index.html', | ||||
|     styleUrls: ['index.scss'], | ||||
| }) | ||||
| export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit { | ||||
| 
 | ||||
|     component = AddonModPageProvider.COMPONENT; | ||||
|     canGetPage = false; | ||||
|     contents?: string; | ||||
|     displayDescription = true; | ||||
|     displayTimemodified = true; | ||||
|     timemodified?: number; | ||||
|     page?: CoreCourseWSModule | AddonModPagePage; | ||||
|     warning?: string; | ||||
| 
 | ||||
|     protected fetchContentDefaultError = 'addon.mod_page.errorwhileloadingthepage'; | ||||
| 
 | ||||
|     constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) { | ||||
|         super('AddonModPageIndexComponent', courseContentsPage); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     async ngOnInit(): Promise<void> { | ||||
|         super.ngOnInit(); | ||||
| 
 | ||||
|         this.canGetPage = AddonModPage.instance.isGetPageWSAvailable(); | ||||
| 
 | ||||
|         await this.loadContent(); | ||||
| 
 | ||||
|         try { | ||||
|             await AddonModPage.instance.logView(this.module!.instance!, this.module!.name); | ||||
|             CoreCourse.instance.checkModuleCompletion(this.courseId!, this.module!.completiondata); | ||||
|         } catch { | ||||
|             // Ignore errors.
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Perform the invalidate content function. | ||||
|      * | ||||
|      * @return Resolved when done. | ||||
|      */ | ||||
|     protected async invalidateContent(): Promise<void> { | ||||
|         await AddonModPage.instance.invalidateContent(this.module!.id, this.courseId!); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Download page contents. | ||||
|      * | ||||
|      * @param refresh Whether we're refreshing data. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async fetchContent(refresh?: boolean): Promise<void> { | ||||
|         // Download the resource if it needs to be downloaded.
 | ||||
|         try { | ||||
|             const downloadResult = await this.downloadResourceIfNeeded(refresh); | ||||
| 
 | ||||
|             const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|             let getPagePromise: Promise<CoreCourseWSModule | AddonModPagePage>; | ||||
| 
 | ||||
|             // Get the module to get the latest title and description. Data should've been updated in download.
 | ||||
|             if (this.canGetPage) { | ||||
|                 getPagePromise = AddonModPage.instance.getPageData(this.courseId!, this.module!.id); | ||||
|             } else { | ||||
|                 getPagePromise = CoreCourse.instance.getModule(this.module!.id, this.courseId!); | ||||
|             } | ||||
| 
 | ||||
|             promises.push(getPagePromise.then((page) => { | ||||
|                 if (!page) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 this.description = 'intro' in page ? page.intro : page.description; | ||||
|                 this.dataRetrieved.emit(page); | ||||
| 
 | ||||
|                 if (!this.canGetPage) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 this.page = page; | ||||
| 
 | ||||
|                 // Check if description and timemodified should be displayed.
 | ||||
|                 if ('displayoptions' in this.page) { | ||||
|                     const options: Record<string, string | boolean> = | ||||
|                         CoreTextUtils.instance.unserialize(this.page.displayoptions) || {}; | ||||
| 
 | ||||
|                     this.displayDescription = typeof options.printintro == 'undefined' || | ||||
|                             CoreUtils.instance.isTrueOrOne(options.printintro); | ||||
|                     this.displayTimemodified = typeof options.printlastmodified == 'undefined' || | ||||
|                             CoreUtils.instance.isTrueOrOne(options.printlastmodified); | ||||
|                 } else { | ||||
|                     this.displayDescription = true; | ||||
|                     this.displayTimemodified = true; | ||||
|                 } | ||||
| 
 | ||||
|                 this.timemodified = 'timemodified' in this.page ? this.page.timemodified : undefined; | ||||
| 
 | ||||
|                 return; | ||||
|             }).catch(() => { | ||||
|                 // Ignore errors.
 | ||||
|             })); | ||||
| 
 | ||||
|             // Get the page HTML.
 | ||||
|             promises.push(AddonModPageHelper.instance.getPageHtml(this.module!.contents, this.module!.id).then((content) => { | ||||
| 
 | ||||
|                 this.contents = content; | ||||
|                 this.warning = downloadResult?.failed ? this.getErrorDownloadingSomeFilesMessage(downloadResult.error!) : ''; | ||||
| 
 | ||||
|                 return; | ||||
|             })); | ||||
| 
 | ||||
|             await Promise.all(promises); | ||||
|         } finally { | ||||
|             this.fillContextMenu(refresh); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/addons/mod/page/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/addons/mod/page/lang.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| { | ||||
|     "errorwhileloadingthepage": "Error while loading the page content.", | ||||
|     "modulenameplural": "Pages" | ||||
| } | ||||
							
								
								
									
										28
									
								
								src/addons/mod/page/page-lazy.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/addons/mod/page/page-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.AddonModPageIndexPageModule), | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [RouterModule.forChild(routes)], | ||||
| }) | ||||
| export class AddonModPageLazyModule {} | ||||
							
								
								
									
										56
									
								
								src/addons/mod/page/page.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/addons/mod/page/page.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | ||||
| // (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 { CorePluginFileDelegate } from '@services/plugin-file-delegate'; | ||||
| import { AddonModPageComponentsModule } from './components/components.module'; | ||||
| import { AddonModPageIndexLinkHandler } from './services/handlers/index-link'; | ||||
| import { AddonModPageListLinkHandler } from './services/handlers/list-link'; | ||||
| import { AddonModPageModuleHandler, AddonModPageModuleHandlerService } from './services/handlers/module'; | ||||
| import { AddonModPagePluginFileHandler } from './services/handlers/pluginfile'; | ||||
| import { AddonModPagePrefetchHandler } from './services/handlers/prefetch'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
|     { | ||||
|         path: AddonModPageModuleHandlerService.PAGE_NAME, | ||||
|         loadChildren: () => import('./page-lazy.module').then(m => m.AddonModPageLazyModule), | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [ | ||||
|         CoreMainMenuTabRoutingModule.forChild(routes), | ||||
|         AddonModPageComponentsModule, | ||||
|     ], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreCourseModuleDelegate.instance.registerHandler(AddonModPageModuleHandler.instance); | ||||
|                 CoreContentLinksDelegate.instance.registerHandler(AddonModPageIndexLinkHandler.instance); | ||||
|                 CoreContentLinksDelegate.instance.registerHandler(AddonModPageListLinkHandler.instance); | ||||
|                 CoreCourseModulePrefetchDelegate.instance.registerHandler(AddonModPagePrefetchHandler.instance); | ||||
|                 CorePluginFileDelegate.instance.registerHandler(AddonModPagePluginFileHandler.instance); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class AddonModPageModule {} | ||||
							
								
								
									
										22
									
								
								src/addons/mod/page/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/addons/mod/page/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <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]="!pageComponent?.loaded" (ionRefresh)="pageComponent?.doRefresh($event)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-page-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-page-index> | ||||
| </ion-content> | ||||
							
								
								
									
										46
									
								
								src/addons/mod/page/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/addons/mod/page/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 { AddonModPageComponentsModule } from '../../components/components.module'; | ||||
| import { AddonModPageIndexPage } from './index'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
|     { | ||||
|         path: '', | ||||
|         component: AddonModPageIndexPage, | ||||
|     }, | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     imports: [ | ||||
|         RouterModule.forChild(routes), | ||||
|         CommonModule, | ||||
|         IonicModule, | ||||
|         TranslateModule.forChild(), | ||||
|         CoreSharedModule, | ||||
|         AddonModPageComponentsModule, | ||||
|     ], | ||||
|     declarations: [ | ||||
|         AddonModPageIndexPage, | ||||
|     ], | ||||
|     exports: [RouterModule], | ||||
| }) | ||||
| export class AddonModPageIndexPageModule {} | ||||
							
								
								
									
										54
									
								
								src/addons/mod/page/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/addons/mod/page/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| // (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 { AddonModPageIndexComponent } from '../../components/index/index'; | ||||
| import { AddonModPagePage } from '../../services/page'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays a page. | ||||
|  */ | ||||
| @Component({ | ||||
|     selector: 'page-addon-mod-page-index', | ||||
|     templateUrl: 'index.html', | ||||
| }) | ||||
| export class AddonModPageIndexPage implements OnInit { | ||||
| 
 | ||||
|     @ViewChild(AddonModPageIndexComponent) pageComponent?: AddonModPageIndexComponent; | ||||
| 
 | ||||
|     title?: string; | ||||
|     module?: CoreCourseWSModule; | ||||
|     courseId?: number; | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.module = CoreNavigator.instance.getRouteParam('module'); | ||||
|         this.courseId = CoreNavigator.instance.getRouteNumberParam('courseId'); | ||||
|         this.title = this.module?.name; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Update some data based on the page instance. | ||||
|      * | ||||
|      * @param page Page instance. | ||||
|      */ | ||||
|     updateData(page: CoreCourseWSModule | AddonModPagePage): void { | ||||
|         this.title = 'name' in page ? page.name : this.title; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										44
									
								
								src/addons/mod/page/services/handlers/index-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/addons/mod/page/services/handlers/index-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 { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { AddonModPage } from '../page'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to treat links to page resource. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPageIndexLinkHandlerService extends CoreContentLinksModuleIndexHandler { | ||||
| 
 | ||||
|     name = 'AddonModPageLinkHandler'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super('AddonModPage', 'page', 'p'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the handler is enabled for a certain site (site + user) and a URL. | ||||
|      * | ||||
|      * @param siteId The site ID. | ||||
|      * @return Whether the handler is enabled for the URL and site. | ||||
|      */ | ||||
|     isEnabled(siteId: string): Promise<boolean> { | ||||
|         return AddonModPage.instance.isPluginEnabled(siteId); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModPageIndexLinkHandler extends makeSingleton(AddonModPageIndexLinkHandlerService) {} | ||||
							
								
								
									
										44
									
								
								src/addons/mod/page/services/handlers/list-link.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/addons/mod/page/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 { AddonModPage } from '../page'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to treat links to page list page. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPageListLinkHandlerService extends CoreContentLinksModuleListHandler { | ||||
| 
 | ||||
|     name = 'AddonModPageListLinkHandler'; | ||||
| 
 | ||||
|     constructor() { | ||||
|         super('AddonModPage', 'page'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the handler is enabled on a site level. | ||||
|      * | ||||
|      * @param siteId The site ID. | ||||
|      * @return Whether or not the handler is enabled on a site level. | ||||
|      */ | ||||
|     isEnabled(siteId: string): Promise<boolean> { | ||||
|         return AddonModPage.instance.isPluginEnabled(siteId); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModPageListLinkHandler extends makeSingleton(AddonModPageListLinkHandlerService) {} | ||||
							
								
								
									
										93
									
								
								src/addons/mod/page/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/addons/mod/page/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,93 @@ | ||||
| // (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 { AddonModPage } from '../page'; | ||||
| import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; | ||||
| import { CoreConstants } from '@/core/constants'; | ||||
| import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course'; | ||||
| import { CoreCourseModule } from '@features/course/services/course-helper'; | ||||
| import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; | ||||
| import { AddonModPageIndexComponent } from '../../components/index'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to support page modules. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPageModuleHandlerService implements CoreCourseModuleHandler { | ||||
| 
 | ||||
|     static readonly PAGE_NAME = 'mod_page'; | ||||
| 
 | ||||
|     name = 'AddonModPage'; | ||||
|     modName = 'page'; | ||||
| 
 | ||||
|     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 AddonModPage.instance.isPluginEnabled(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the data required to display the module in the course contents view. | ||||
|      * | ||||
|      * @param module The module object. | ||||
|      * @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_page-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(AddonModPageModuleHandlerService.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. | ||||
|      * | ||||
|      * @param course The course object. | ||||
|      * @param module The module object. | ||||
|      * @return The component to use, undefined if not found. | ||||
|      */ | ||||
|     async getMainComponent(): Promise<Type<unknown> | undefined> { | ||||
|         return AddonModPageIndexComponent; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class AddonModPageModuleHandler extends makeSingleton(AddonModPageModuleHandlerService) {} | ||||
							
								
								
									
										63
									
								
								src/addons/mod/page/services/handlers/pluginfile.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/addons/mod/page/services/handlers/pluginfile.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| // (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 { CorePluginFileHandler } from '@services/plugin-file-delegate'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to treat links to page. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPagePluginFileHandlerService implements CorePluginFileHandler { | ||||
| 
 | ||||
|     name = 'AddonModPagePluginFileHandler'; | ||||
|     component = 'mod_page'; | ||||
| 
 | ||||
|     /** | ||||
|      * Return the RegExp to match the revision on pluginfile URLs. | ||||
|      * | ||||
|      * @param args Arguments of the pluginfile URL defining component and filearea at least. | ||||
|      * @return RegExp to match the revision on pluginfile URLs. | ||||
|      */ | ||||
|     getComponentRevisionRegExp(args: string[]): RegExp | undefined { | ||||
|         // Check filearea.
 | ||||
|         if (args[2] == 'content') { | ||||
|             // Component + Filearea + Revision
 | ||||
|             return new RegExp('/mod_page/content/([0-9]+)/'); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Should return the string to remove the revision on pluginfile url. | ||||
|      * | ||||
|      * @return String to remove the revision on pluginfile url. | ||||
|      */ | ||||
|     getComponentRevisionReplace(): string { | ||||
|         // Component + Filearea + Revision
 | ||||
|         return '/mod_page/content/0/'; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Whether or not the handler is enabled on a site level. | ||||
|      * | ||||
|      * @return Whether or not the handler is enabled on a site level. | ||||
|      */ | ||||
|     async isEnabled(): Promise<boolean> { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModPagePluginFileHandler extends makeSingleton(AddonModPagePluginFileHandlerService) {} | ||||
							
								
								
									
										90
									
								
								src/addons/mod/page/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/addons/mod/page/services/handlers/prefetch.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| // (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 { CoreCourse, CoreCourseAnyModuleData, CoreCourseWSModule } from '@features/course/services/course'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { AddonModPage, AddonModPageProvider } from '../page'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch pages. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPagePrefetchHandlerService extends CoreCourseResourcePrefetchHandlerBase { | ||||
| 
 | ||||
|     name = 'AddonModPage'; | ||||
|     modName = 'page'; | ||||
|     component = AddonModPageProvider.COMPONENT; | ||||
|     updatesNames = /^configuration$|^.*files$/; | ||||
| 
 | ||||
|     /** | ||||
|      * 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)); | ||||
| 
 | ||||
|         if (AddonModPage.instance.isGetPageWSAvailable()) { | ||||
|             promises.push(AddonModPage.instance.getPageData(courseId, module.id)); | ||||
|         } | ||||
| 
 | ||||
|         await Promise.all(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 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 AddonModPage.instance.invalidateContent(moduleId, courseId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidate WS calls needed to determine module status. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @return Promise resolved when invalidated. | ||||
|      */ | ||||
|     async invalidateModule(module: CoreCourseAnyModuleData, courseId: number): Promise<void> { | ||||
|         const promises: Promise<unknown>[] = []; | ||||
| 
 | ||||
|         promises.push(AddonModPage.instance.invalidatePageData(courseId)); | ||||
|         promises.push(CoreCourse.instance.invalidateModule(module.id)); | ||||
| 
 | ||||
|         await CoreUtils.instance.allPromises(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 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 AddonModPage.instance.isPluginEnabled(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class AddonModPagePrefetchHandler extends makeSingleton(AddonModPagePrefetchHandlerService) {} | ||||
							
								
								
									
										105
									
								
								src/addons/mod/page/services/page-helper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/addons/mod/page/services/page-helper.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| // (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 { AddonModPageProvider } from './page'; | ||||
| import { CoreError } from '@classes/errors/error'; | ||||
| import { CoreTextUtils } from '@services/utils/text'; | ||||
| import { CoreFile } from '@services/file'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreFilepool } from '@services/filepool'; | ||||
| import { CoreWS } from '@services/ws'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreCourseModuleContentFile } from '@features/course/services/course'; | ||||
| 
 | ||||
| /** | ||||
|  * Service that provides some features for page. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPageHelperProvider { | ||||
| 
 | ||||
|     /** | ||||
|      * Gets the page HTML. | ||||
|      * | ||||
|      * @param contents The module contents. | ||||
|      * @param moduleId The module ID. | ||||
|      * @return The HTML of the page. | ||||
|      */ | ||||
|     async getPageHtml(contents: CoreCourseModuleContentFile[], moduleId: number): Promise<string> { | ||||
|         let indexUrl: string | undefined; | ||||
|         const paths: Record<string, string> = {}; | ||||
| 
 | ||||
|         // Extract the information about paths from the module contents.
 | ||||
|         contents.forEach((content) => { | ||||
|             const url = content.fileurl; | ||||
| 
 | ||||
|             if (this.isMainPage(content)) { | ||||
|                 // This seems to be the most reliable way to spot the index page.
 | ||||
|                 indexUrl = url; | ||||
|             } else { | ||||
|                 let key = content.filename; | ||||
|                 if (content.filepath !== '/') { | ||||
|                     // Add the folders without the leading slash.
 | ||||
|                     key = content.filepath.substr(1) + key; | ||||
|                 } | ||||
|                 paths[CoreTextUtils.instance.decodeURIComponent(key)] = url; | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         // Promise handling when we are in a browser.
 | ||||
|         if (!indexUrl) { | ||||
|             // If ever that happens.
 | ||||
|             throw new CoreError('Could not locate the index page'); | ||||
|         } | ||||
| 
 | ||||
|         let url: string; | ||||
|         if (CoreFile.instance.isAvailable()) { | ||||
|             // The file system is available.
 | ||||
|             url = await CoreFilepool.instance.downloadUrl( | ||||
|                 CoreSites.instance.getCurrentSiteId(), | ||||
|                 indexUrl, | ||||
|                 false, | ||||
|                 AddonModPageProvider.COMPONENT, | ||||
|                 moduleId, | ||||
|             ); | ||||
|         } else { | ||||
|             // We return the live URL.
 | ||||
|             url = await CoreSites.instance.getCurrentSite()?.checkAndFixPluginfileURL(indexUrl) || ''; | ||||
|         } | ||||
| 
 | ||||
|         const content = await CoreWS.instance.getText(url); | ||||
| 
 | ||||
|         // Now that we have the content, we update the SRC to point back to the external resource.
 | ||||
|         // That will be caught by core-format-text.
 | ||||
|         return CoreDomUtils.instance.restoreSourcesInHtml(content, paths); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether the file is the main page of the module. | ||||
|      * | ||||
|      * @param file An object returned from WS containing file info. | ||||
|      * @return Whether the file is the main page or not. | ||||
|      */ | ||||
|     protected isMainPage(file: CoreCourseModuleContentFile): boolean { | ||||
|         const filename = file.filename || ''; | ||||
|         const fileurl = file.fileurl || ''; | ||||
|         const url = '/mod_page/content/index.html'; | ||||
|         const encodedUrl = encodeURIComponent(url); | ||||
| 
 | ||||
|         return (filename === 'index.html' && (fileurl.indexOf(url) > 0 || fileurl.indexOf(encodedUrl) > 0 )); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| export class AddonModPageHelper extends makeSingleton(AddonModPageHelperProvider) {} | ||||
							
								
								
									
										225
									
								
								src/addons/mod/page/services/page.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										225
									
								
								src/addons/mod/page/services/page.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,225 @@ | ||||
| // (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 { CoreSitesCommonWSOptions, CoreSites } from '@services/sites'; | ||||
| import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; | ||||
| import { CoreWSExternalWarning, CoreWSExternalFile } from '@services/ws'; | ||||
| import { makeSingleton } from '@singletons'; | ||||
| import { CoreFilepool } from '@services/filepool'; | ||||
| import { CoreCourse } from '@features/course/services/course'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreCourseLogHelper } from '@features/course/services/log-helper'; | ||||
| import { CoreWSError } from '@classes/errors/wserror'; | ||||
| 
 | ||||
| const ROOT_CACHE_KEY = 'mmaModPage:'; | ||||
| 
 | ||||
| /** | ||||
|  * Service that provides some features for page. | ||||
|  */ | ||||
| @Injectable({ providedIn: 'root' }) | ||||
| export class AddonModPageProvider { | ||||
| 
 | ||||
|     static readonly COMPONENT = 'mmaModPage'; | ||||
| 
 | ||||
|     /** | ||||
|      * Get a page by course module ID. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param cmId Course module ID. | ||||
|      * @param options Other options. | ||||
|      * @return Promise resolved when the page is retrieved. | ||||
|      */ | ||||
|     getPageData(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModPagePage> { | ||||
|         return this.getPageByKey(courseId, 'coursemodule', cmId, options); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get a page. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param key Name of the property to check. | ||||
|      * @param value Value to search. | ||||
|      * @param options Other options. | ||||
|      * @return Promise resolved when the page is retrieved. | ||||
|      */ | ||||
|     protected async getPageByKey( | ||||
|         courseId: number, | ||||
|         key: string, | ||||
|         value: number, | ||||
|         options: CoreSitesCommonWSOptions = {}, | ||||
|     ): Promise<AddonModPagePage> { | ||||
|         const site = await CoreSites.instance.getSite(options.siteId); | ||||
| 
 | ||||
|         const params: AddonModPageGetPagesByCoursesWSParams = { | ||||
|             courseids: [courseId], | ||||
|         }; | ||||
|         const preSets: CoreSiteWSPreSets = { | ||||
|             cacheKey: this.getPageCacheKey(courseId), | ||||
|             updateFrequency: CoreSite.FREQUENCY_RARELY, | ||||
|             component: AddonModPageProvider.COMPONENT, | ||||
|             ...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), | ||||
|         }; | ||||
| 
 | ||||
|         const response = await site.read<AddonModPageGetPagesByCoursesWSResponse>('mod_page_get_pages_by_courses', params, preSets); | ||||
| 
 | ||||
|         const currentPage = response.pages.find((page) => page[key] == value); | ||||
|         if (currentPage) { | ||||
|             return currentPage; | ||||
|         } | ||||
| 
 | ||||
|         throw new CoreWSError('Page not found'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get cache key for page data WS calls. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getPageCacheKey(courseId: number): string { | ||||
|         return ROOT_CACHE_KEY + 'page:' + 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. | ||||
|      */ | ||||
|     invalidateContent(moduleId: number, courseId: number, siteId?: string): Promise<void> { | ||||
|         siteId = siteId || CoreSites.instance.getCurrentSiteId(); | ||||
| 
 | ||||
|         const promises: Promise<void>[] = []; | ||||
| 
 | ||||
|         promises.push(this.invalidatePageData(courseId, siteId)); | ||||
|         promises.push(CoreFilepool.instance.invalidateFilesByComponent(siteId, AddonModPageProvider.COMPONENT, moduleId)); | ||||
|         promises.push(CoreCourse.instance.invalidateModule(moduleId, siteId)); | ||||
| 
 | ||||
|         return CoreUtils.instance.allPromises(promises); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates page data. | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     async invalidatePageData(courseId: number, siteId?: string): Promise<void> { | ||||
|         const site = await CoreSites.instance.getSite(siteId); | ||||
| 
 | ||||
|         await site.invalidateWsCacheForKey(this.getPageCacheKey(courseId)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not getPage WS available or not. | ||||
|      * | ||||
|      * @return If WS is avalaible. | ||||
|      * @since 3.3 | ||||
|      */ | ||||
|     isGetPageWSAvailable(): boolean { | ||||
|         return CoreSites.instance.wsAvailableInCurrentSite('mod_page_get_pages_by_courses'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 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 page as being viewed. | ||||
|      * | ||||
|      * @param pageid Module ID. | ||||
|      * @param name Name of the page. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when the WS call is successful. | ||||
|      */ | ||||
|     logView(pageid: number, name?: string, siteId?: string): Promise<void> { | ||||
|         const params: AddonModPageViewPageWSParams = { | ||||
|             pageid, | ||||
|         }; | ||||
| 
 | ||||
|         return CoreCourseLogHelper.instance.logSingle( | ||||
|             'mod_page_view_page', | ||||
|             params, | ||||
|             AddonModPageProvider.COMPONENT, | ||||
|             pageid, | ||||
|             name, | ||||
|             'page', | ||||
|             {}, | ||||
|             siteId, | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export class AddonModPage extends makeSingleton(AddonModPageProvider) {} | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * Page returned by mod_page_get_pages_by_courses. | ||||
|  */ | ||||
| export type AddonModPagePage = { | ||||
|     id: number; // Module id.
 | ||||
|     coursemodule: number; // Course module id.
 | ||||
|     course: number; // Course id.
 | ||||
|     name: string; // Page name.
 | ||||
|     intro: string; // Summary.
 | ||||
|     introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | ||||
|     introfiles: CoreWSExternalFile[]; | ||||
|     content: string; // Page content.
 | ||||
|     contentformat: number; // Content format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | ||||
|     contentfiles: CoreWSExternalFile[]; | ||||
|     legacyfiles: number; // Legacy files flag.
 | ||||
|     legacyfileslast: number; // Legacy files last control flag.
 | ||||
|     display: number; // How to display the page.
 | ||||
|     displayoptions: string; // Display options (width, height).
 | ||||
|     revision: number; // Incremented when after each file changes, to avoid cache.
 | ||||
|     timemodified: number; // Last time the page was modified.
 | ||||
|     section: number; // Course section id.
 | ||||
|     visible: number; // Module visibility.
 | ||||
|     groupmode: number; // Group mode.
 | ||||
|     groupingid: number; // Grouping id.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Result of WS mod_page_get_pages_by_courses. | ||||
|  */ | ||||
| type AddonModPageGetPagesByCoursesWSResponse = { | ||||
|     pages: AddonModPagePage[]; | ||||
|     warnings?: CoreWSExternalWarning[]; | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Params of mod_page_view_page WS. | ||||
|  */ | ||||
| type AddonModPageViewPageWSParams = { | ||||
|     pageid: number; // Page instance id.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Params of mod_page_get_pages_by_courses WS. | ||||
|  */ | ||||
| type AddonModPageGetPagesByCoursesWSParams = { | ||||
|     courseids?: number[]; // Array of course ids.
 | ||||
| }; | ||||
| @ -310,7 +310,7 @@ export interface CorePluginFileHandler extends CoreDelegateHandler { | ||||
|      * @param args Arguments of the pluginfile URL defining component and filearea at least. | ||||
|      * @return RegExp to match the revision on pluginfile URLs. | ||||
|      */ | ||||
|     getComponentRevisionRegExp?(args: string[]): RegExp; | ||||
|     getComponentRevisionRegExp?(args: string[]): RegExp | undefined; | ||||
| 
 | ||||
|     /** | ||||
|      * Should return the string to remove the revision on pluginfile url. | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user