forked from EVOgeek/Vmeda.Online
		
	MOBILE-2235 h5p: Display download button in H5P placeholder
This commit is contained in:
		
							parent
							
								
									690544afbf
								
							
						
					
					
						commit
						9b637fc496
					
				| @ -1,4 +1,4 @@ | ||||
| <div [class.core-loading-container]="loading"> | ||||
| <div [class.core-loading-container]="loading" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}"> | ||||
|     <iframe #iframe [hidden]="loading" class="core-iframe" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl"></iframe> | ||||
|     <span class="core-loading-spinner"> | ||||
|         <ion-spinner *ngIf="loading"></ion-spinner> | ||||
|  | ||||
| @ -1,7 +1,4 @@ | ||||
| ion-app.app-root core-iframe { | ||||
|     > div { | ||||
|         height: 100%; | ||||
|     } | ||||
|     iframe { | ||||
|         border: 0; | ||||
|         display: block; | ||||
|  | ||||
| @ -30,6 +30,7 @@ import { CORE_COURSES_PROVIDERS } from '@core/courses/courses.module'; | ||||
| import { CORE_FILEUPLOADER_PROVIDERS } from '@core/fileuploader/fileuploader.module'; | ||||
| import { CORE_FILTER_PROVIDERS } from '@core/filter/filter.module'; | ||||
| import { CORE_GRADES_PROVIDERS } from '@core/grades/grades.module'; | ||||
| import { CORE_H5P_PROVIDERS } from '@core/h5p/h5p.module'; | ||||
| import { CORE_LOGIN_PROVIDERS } from '@core/login/login.module'; | ||||
| import { CORE_MAINMENU_PROVIDERS } from '@core/mainmenu/mainmenu.module'; | ||||
| import { CORE_QUESTION_PROVIDERS } from '@core/question/question.module'; | ||||
| @ -236,7 +237,7 @@ export class CoreCompileProvider { | ||||
|                 .concat(ADDON_MOD_SURVEY_PROVIDERS).concat(ADDON_MOD_URL_PROVIDERS).concat(ADDON_MOD_WIKI_PROVIDERS) | ||||
|                 .concat(ADDON_MOD_WORKSHOP_PROVIDERS).concat(ADDON_NOTES_PROVIDERS).concat(ADDON_NOTIFICATIONS_PROVIDERS) | ||||
|                 .concat(CORE_PUSHNOTIFICATIONS_PROVIDERS).concat(ADDON_REMOTETHEMES_PROVIDERS).concat(CORE_BLOCK_PROVIDERS) | ||||
|                 .concat(CORE_FILTER_PROVIDERS); | ||||
|                 .concat(CORE_FILTER_PROVIDERS).concat(CORE_H5P_PROVIDERS); | ||||
| 
 | ||||
|         // We cannot inject anything to this constructor. Use the Injector to inject all the providers into the instance.
 | ||||
|         for (const i in providers) { | ||||
|  | ||||
| @ -402,7 +402,7 @@ export type CoreFilterFilter = { | ||||
|  */ | ||||
| export type CoreFilterGetAvailableInContextResult = { | ||||
|     filters: CoreFilterFilter[]; // Available filters.
 | ||||
|     warning: CoreWSExternalWarning[]; // List of warnings.
 | ||||
|     warnings: CoreWSExternalWarning[]; // List of warnings.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -1,9 +1,14 @@ | ||||
| <div *ngIf="!showPackage" class="core-h5p-placeholder"> | ||||
|     <button *ngIf="!loading" class="core-h5p-placeholder-play-button" ion-button icon-only clear color="dark" (click)="play($event)"> | ||||
|     <button *ngIf="!loading && !errorMessage" class="core-h5p-placeholder-play-button" ion-button icon-only clear (click)="play($event)"> | ||||
|         <core-icon name="fa-play-circle"></core-icon> | ||||
|     </button> | ||||
| 
 | ||||
|     <ion-spinner *ngIf="loading" class="core-h5p-placeholder-spinner"></ion-spinner> | ||||
|     <ion-spinner *ngIf="loading && !errorMessage" class="core-h5p-placeholder-spinner"></ion-spinner> | ||||
| 
 | ||||
|     <div *ngIf="errorMessage" class="core-h5p-placeholder-error">{{ errorMessage }}</div> | ||||
| 
 | ||||
|     <div class="core-h5p-placeholder-download-container"> | ||||
|         <core-download-refresh [status]="state" [enabled]="canDownload" [loading]="calculating" [canTrustDownload]="true" (action)="download()"></core-download-refresh> | ||||
|     </div> | ||||
| </div> | ||||
| <core-iframe *ngIf="showPackage" [src]="src"></core-iframe> | ||||
| <core-iframe *ngIf="showPackage" [src]="playerSrc" iframeHeight="230px"></core-iframe> | ||||
|  | ||||
| @ -1,23 +1,56 @@ | ||||
| // H5P variables. | ||||
| $core-h5p-placeholder-bg-color: $gray !default; | ||||
| $core-h5p-placeholder-text-color: $text-color !default; | ||||
| 
 | ||||
| ion-app.app-root core-h5p-player { | ||||
|     .core-h5p-placeholder { | ||||
|         position: relative; | ||||
|         width: 100%; | ||||
|         height: 230px; | ||||
|         background: url('../assets/img/icons/h5p.svg') center top 25px / 100px auto no-repeat $core-h5p-placeholder-bg-color; | ||||
|         color: $core-h5p-placeholder-text-color; | ||||
| 
 | ||||
|         .core-h5p-placeholder-play-button { | ||||
|         .icon { | ||||
|             color: $core-h5p-placeholder-text-color; | ||||
|         } | ||||
| 
 | ||||
|         .core-h5p-placeholder-play-button, .core-h5p-placeholder-spinner { | ||||
|             position: absolute; | ||||
|             top: 50%; | ||||
|             left: 50%; | ||||
|             transform: translate(-50%, -50%); | ||||
|         } | ||||
| 
 | ||||
|         .core-h5p-placeholder-play-button { | ||||
|             font-size: 30px; | ||||
|             min-height: 50px; | ||||
|         } | ||||
| 
 | ||||
|         .core-h5p-placeholder-download-container { | ||||
|             position: absolute; | ||||
|             right: 10px; | ||||
|             font-size: 1.8em; | ||||
|             top: 0; | ||||
|             right: 0; | ||||
| 
 | ||||
|             ion-spinner { | ||||
|                 margin-right: 0.75em; | ||||
|             } | ||||
| 
 | ||||
|             core-download-refresh > ion-icon { | ||||
|                 margin: 0.4rem 0.2rem; | ||||
|                 padding: 0 0.5em; | ||||
|                 line-height: .67; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         .core-h5p-placeholder-error { | ||||
|             position: absolute; | ||||
|             width: 100%; | ||||
|             text-align: center; | ||||
|             top: 50%; | ||||
|         } | ||||
| 
 | ||||
|         ion-spinner circle { | ||||
|             stroke: $core-h5p-placeholder-text-color; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -12,8 +12,12 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, ElementRef } from '@angular/core'; | ||||
| import { Component, Input, ElementRef, OnInit, SimpleChange } from '@angular/core'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| import { CoreUrlUtilsProvider } from '@providers/utils/url'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreH5PProvider } from '@core/h5p/providers/h5p'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to render an H5P package. | ||||
| @ -22,17 +26,39 @@ import { CoreSitesProvider } from '@providers/sites'; | ||||
|     selector: 'core-h5p-player', | ||||
|     templateUrl: 'core-h5p-player.html' | ||||
| }) | ||||
| export class CoreH5PPlayerComponent { | ||||
| export class CoreH5PPlayerComponent implements OnInit { | ||||
|     @Input() src: string; // The URL of the player to display the H5P package.
 | ||||
| 
 | ||||
|     playerSrc: string; | ||||
|     showPackage = false; | ||||
|     loading = false; | ||||
|     status: string; | ||||
|     canDownload: boolean; | ||||
|     calculating = true; | ||||
|     errorMessage: string; | ||||
| 
 | ||||
|     constructor(public elementRef: ElementRef, | ||||
|             protected sitesProvider: CoreSitesProvider) { | ||||
|             protected sitesProvider: CoreSitesProvider, | ||||
|             protected urlUtils: CoreUrlUtilsProvider, | ||||
|             protected utils: CoreUtilsProvider, | ||||
|             protected textUtils: CoreTextUtilsProvider, | ||||
|             protected h5pProvider: CoreH5PProvider) { } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.checkCanDownload(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Detect changes on input properties. | ||||
|      */ | ||||
|     ngOnChanges(changes: {[name: string]: SimpleChange}): void { | ||||
|         // If it's already playing and the src changes, don't change the player src, the user could lose data.
 | ||||
|         if (changes.src && !this.showPackage) { | ||||
|             this.checkCanDownload(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -46,11 +72,57 @@ export class CoreH5PPlayerComponent { | ||||
| 
 | ||||
|         this.loading = true; | ||||
| 
 | ||||
|         // @TODO: Check if package is downloaded and use the local player if so.
 | ||||
| 
 | ||||
|         // Get auto-login URL so the user is automatically authenticated.
 | ||||
|         this.sitesProvider.getCurrentSite().getAutoLoginUrl(this.src, false).then((url) => { | ||||
|             this.src = url; | ||||
|             this.playerSrc = url; | ||||
|             this.loading = false; | ||||
|             this.showPackage = true; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Download the package. | ||||
|      */ | ||||
|     download(): void { | ||||
|         // @TODO: Implement package download.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the package can be downloaded. | ||||
|      */ | ||||
|     protected checkCanDownload(): void { | ||||
|         if (this.src && this.h5pProvider.canGetTrustedH5PFileInSite()) { | ||||
|             const params = this.urlUtils.extractUrlParams(this.src); | ||||
| 
 | ||||
|             // @todo: Check if H5P offline is disabled in the site.
 | ||||
| 
 | ||||
|             // Now check if the package can be played.
 | ||||
|             this.calculating = true; | ||||
| 
 | ||||
|             const options = { | ||||
|                 frame: this.utils.isTrueOrOne(params.frame), | ||||
|                 export: this.utils.isTrueOrOne(params.export), | ||||
|                 embed: this.utils.isTrueOrOne(params.embed), | ||||
|                 copyright: this.utils.isTrueOrOne(params.copyright), | ||||
|             }; | ||||
| 
 | ||||
|             this.h5pProvider.getTrustedH5PFile(params.url, options).then((file) => { | ||||
|                 this.canDownload = true; | ||||
|                 this.errorMessage = undefined; | ||||
|             }).catch((error) => { | ||||
|                 this.canDownload = false; | ||||
|                 this.errorMessage = this.textUtils.getErrorMessageFromError(error); | ||||
|             }).finally(() => { | ||||
|                 this.calculating = false; | ||||
|             }); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.calculating = false; | ||||
|         this.canDownload = false; | ||||
|         this.errorMessage = undefined; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -14,6 +14,12 @@ | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { CoreH5PComponentsModule } from './components/components.module'; | ||||
| import { CoreH5PProvider } from './providers/h5p'; | ||||
| 
 | ||||
| // List of providers (without handlers).
 | ||||
| export const CORE_H5P_PROVIDERS: any[] = [ | ||||
|     CoreH5PProvider | ||||
| ]; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [], | ||||
| @ -21,6 +27,7 @@ import { CoreH5PComponentsModule } from './components/components.module'; | ||||
|         CoreH5PComponentsModule | ||||
|     ], | ||||
|     providers: [ | ||||
|         CoreH5PProvider | ||||
|     ], | ||||
|     exports: [] | ||||
| }) | ||||
|  | ||||
							
								
								
									
										169
									
								
								src/core/h5p/providers/h5p.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/core/h5p/providers/h5p.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | ||||
| // (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 { CoreLoggerProvider } from '@providers/logger'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; | ||||
| import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws'; | ||||
| 
 | ||||
| /** | ||||
|  * Service to provide H5P functionalities. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class CoreH5PProvider { | ||||
| 
 | ||||
|     protected ROOT_CACHE_KEY = 'mmH5P:'; | ||||
| 
 | ||||
|     protected logger; | ||||
| 
 | ||||
|     constructor(logger: CoreLoggerProvider, | ||||
|             private sitesProvider: CoreSitesProvider) { | ||||
| 
 | ||||
|         this.logger = logger.getInstance('CoreFilterProvider'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not WS to get trusted H5P file is available. | ||||
|      * | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with true if ws is available, false otherwise. | ||||
|      * @since 3.8 | ||||
|      */ | ||||
|     canGetTrustedH5PFile(siteId?: string): Promise<boolean> { | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
|             return this.canGetTrustedH5PFileInSite(site); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether or not WS to get trusted H5P file is available in a certain site. | ||||
|      * | ||||
|      * @param site Site. If not defined, current site. | ||||
|      * @return Promise resolved with true if ws is available, false otherwise. | ||||
|      * @since 3.4 | ||||
|      */ | ||||
|     canGetTrustedH5PFileInSite(site?: CoreSite): boolean { | ||||
|         site = site || this.sitesProvider.getCurrentSite(); | ||||
| 
 | ||||
|         return site.wsAvailable('core_h5p_get_trusted_h5p_file'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get a trusted H5P file. | ||||
|      * | ||||
|      * @param url The file URL. | ||||
|      * @param options Options. | ||||
|      * @param ignoreCache Whether to ignore cache.. | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved with the file data. | ||||
|      */ | ||||
|     getTrustedH5PFile(url: string, options: CoreH5PGetTrustedFileOptions, ignoreCache?: boolean, siteId?: string) | ||||
|             : Promise<CoreWSExternalFile> { | ||||
| 
 | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
| 
 | ||||
|             const data = { | ||||
|                     url: url, | ||||
|                     frame: options.frame ? 1 : 0, | ||||
|                     export: options.export ? 1 : 0, | ||||
|                     embed: options.embed ? 1 : 0, | ||||
|                     copyright: options.copyright ? 1 : 0, | ||||
|                 }, | ||||
|                 preSets: CoreSiteWSPreSets = { | ||||
|                     cacheKey: this.getTrustedH5PFileCacheKey(url), | ||||
|                     updateFrequency: CoreSite.FREQUENCY_RARELY | ||||
|                 }; | ||||
| 
 | ||||
|             if (ignoreCache) { | ||||
|                 preSets.getFromCache = false; | ||||
|                 preSets.emergencyCache = false; | ||||
|             } | ||||
| 
 | ||||
|             return site.read('core_h5p_get_trusted_h5p_file', data, preSets).then((result: CoreH5PGetTrustedH5PFileResult): any => { | ||||
|                 if (result.warnings && result.warnings.length) { | ||||
|                     return Promise.reject(result.warnings[0]); | ||||
|                 } | ||||
| 
 | ||||
|                 if (result.files && result.files.length) { | ||||
|                     return result.files[0]; | ||||
|                 } | ||||
| 
 | ||||
|                 return Promise.reject(null); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get cache key for trusted H5P file WS calls. | ||||
|      * | ||||
|      * @param url The file URL. | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getTrustedH5PFileCacheKey(url: string): string { | ||||
|         return this.getTrustedH5PFilePrefixCacheKey() + url; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get prefixed cache key for trusted H5P file WS calls. | ||||
|      * | ||||
|      * @return Cache key. | ||||
|      */ | ||||
|     protected getTrustedH5PFilePrefixCacheKey(): string { | ||||
|         return this.ROOT_CACHE_KEY + 'trustedH5PFile:'; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates all trusted H5P file WS calls. | ||||
|      * | ||||
|      * @param siteId Site ID (empty for current site). | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     invalidateAllGetTrustedH5PFile(siteId?: string): Promise<any> { | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
|             return site.invalidateWsCacheForKeyStartingWith(this.getTrustedH5PFilePrefixCacheKey()); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidates get trusted H5P file WS call. | ||||
|      * | ||||
|      * @param url The URL of the file. | ||||
|      * @param siteId Site ID (empty for current site). | ||||
|      * @return Promise resolved when the data is invalidated. | ||||
|      */ | ||||
|     invalidateAvailableInContexts(url: string, siteId?: string): Promise<any> { | ||||
|         return this.sitesProvider.getSite(siteId).then((site) => { | ||||
|             return site.invalidateWsCacheForKey(this.getTrustedH5PFileCacheKey(url)); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Options for core_h5p_get_trusted_h5p_file. | ||||
|  */ | ||||
| export type CoreH5PGetTrustedFileOptions = { | ||||
|     frame?: boolean; // Whether to show the bar options below the content.
 | ||||
|     export?: boolean; // Whether to allow to download the package.
 | ||||
|     embed?: boolean; // Whether to allow to copy the code to your site.
 | ||||
|     copyright?: boolean; // The copyright option.
 | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Result of core_h5p_get_trusted_h5p_file. | ||||
|  */ | ||||
| export type CoreH5PGetTrustedH5PFileResult = { | ||||
|     files: CoreWSExternalFile[]; // Files.
 | ||||
|     warnings: CoreWSExternalWarning[]; // List of warnings.
 | ||||
| }; | ||||
| @ -369,9 +369,6 @@ $core-question-state-incorrect-color: $red-light !default; | ||||
| $core-dd-question-selected-shadow: 2px 2px 4px $gray-dark !default; | ||||
| $core-dd-question-colors: $white, $blue-light, #DCDCDC, #D8BFD8, #87CEFA, #DAA520, #FFD700, #F0E68C !default; | ||||
| 
 | ||||
| // H5P variables. | ||||
| $core-h5p-placeholder-bg-color: $gray-dark !default; | ||||
| 
 | ||||
| // Mixins | ||||
| // ------------------------- | ||||
| @mixin core-transition($where: all, $time: 500ms) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user