MOBILE-2235 h5p: Handle display options

main
Dani Palou 2019-11-26 08:49:59 +01:00
parent ad716ce07e
commit 5903975e8c
4 changed files with 124 additions and 32 deletions

View File

@ -0,0 +1,35 @@
// (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.
/**
* Handle display options included in the URL and put them in the H5PIntegration object if it exists.
*/
if (window.H5PIntegration && window.H5PIntegration.contents && location.search) {
var contentData = window.H5PIntegration.contents[Object.keys(window.H5PIntegration.contents)[0]];
if (contentData) {
contentData.displayOptions = contentData.displayOptions || {};
var search = location.search.replace(/^\?/, ''),
split = search.split('&');
split.forEach(function(param) {
var nameAndValue = param.split('=');
if (nameAndValue.length == 2) {
contentData.displayOptions[nameAndValue[0]] = nameAndValue[1] === '1' || nameAndValue[1] === 'true';
}
});
}
}

View File

@ -105,7 +105,7 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
if (this.canDownload && (this.state == CoreConstants.DOWNLOADED || this.state == CoreConstants.OUTDATED)) {
// Package is downloaded, use the local URL.
promise = this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.siteId).catch(() => {
promise = this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.urlParams, this.siteId).catch(() => {
// Index file doesn't exist, probably deleted because a lib was updated. Try to create it again.
return this.filepoolProvider.getInternalUrlByUrl(this.siteId, this.urlParams.url).then((path) => {
@ -114,7 +114,7 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
return this.h5pProvider.extractH5PFile(this.urlParams.url, file, this.siteId);
}).then(() => {
// File treated. Try to get the index file URL again.
return this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.siteId);
return this.h5pProvider.getContentIndexFileUrl(this.urlParams.url, this.urlParams, this.siteId);
});
}).catch((error) => {
// Still failing. Delete the H5P package?

View File

@ -100,7 +100,7 @@ export class CoreH5PProvider {
notNull: true
},
{
name: 'displayoptions',
name: 'displayoptions', // Not used right now, but we keep the field to be consistent with Moodle web.
type: 'INTEGER'
},
{
@ -494,10 +494,7 @@ export class CoreH5PProvider {
return this.sitesProvider.getSite(siteId).then((site) => {
const disable = typeof content.disable != 'undefined' && content.disable != null ?
content.disable : CoreH5PProvider.DISABLE_NONE,
displayOptions = this.getDisplayOptionsForView(disable, id),
contentId = this.getContentId(id),
const contentId = this.getContentId(id),
basePath = this.fileProvider.getBasePathInstant(),
contentUrl = this.textUtils.concatenatePaths(basePath, this.getContentFolderPath(content.folderName, site.getId()));
@ -506,10 +503,10 @@ export class CoreH5PProvider {
library: this.libraryToString(content.library),
fullScreen: content.library.fullscreen,
exportUrl: '', // We'll never display the download button, so we don't need the exportUrl.
embedCode: this.getEmbedCode(site.getURL(), h5pUrl, displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED]),
embedCode: this.getEmbedCode(site.getURL(), h5pUrl, true),
resizeCode: this.getResizeCode(),
title: content.slug,
displayOptions: displayOptions,
displayOptions: {},
url: this.getEmbedUrl(site.getURL(), h5pUrl),
contentUrl: contentUrl,
metadata: content.metadata,
@ -537,6 +534,10 @@ export class CoreH5PProvider {
html += '<script type="text/javascript">var H5PIntegration = ' +
JSON.stringify(result.settings).replace(/\//g, '\\/') + '</script>';
// Add our own script to handle the display options.
html += '<script type="text/javascript" src="' +
this.textUtils.concatenatePaths(this.getCoreH5PPath(), 'moodle/js/displayoptions.js') + '"></script>';
html += '</head><body>';
// Include the required JS at the beginning of the body, like Moodle web does.
@ -1218,17 +1219,26 @@ export class CoreH5PProvider {
* Get the content index file.
*
* @param fileUrl URL of the H5P package.
* @param urlParams URL params.
* @param siteId The site ID. If not defined, current site.
* @return Promise resolved with the file URL if exists, rejected otherwise.
*/
getContentIndexFileUrl(fileUrl: string, siteId?: string): Promise<string> {
getContentIndexFileUrl(fileUrl: string, urlParams?: {[name: string]: string}, siteId?: string): Promise<string> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.getContentFolderNameByUrl(fileUrl, siteId).then((folderName) => {
return this.fileProvider.getFile(this.getContentIndexPath(folderName, siteId));
}).then((file) => {
return file.toURL();
}).then((url) => {
// Add display options to the URL.
return this.getContentDataByUrl(fileUrl, siteId).then((data) => {
const options = this.validateDisplayOptions(this.getDisplayOptionsFromUrlParams(urlParams), data.id);
return this.urlUtils.addParamsToUrl(url, options, undefined, true);
});
});
}
/**
@ -1486,25 +1496,31 @@ export class CoreH5PProvider {
* @return Display options as object.
*/
getDisplayOptionsForView(disable: number, id: number): CoreH5PDisplayOptions {
const displayOptions = this.getDisplayOptionsAsObject(disable);
return this.validateDisplayOptions(this.getDisplayOptionsAsObject(disable), id);
}
if (this.getOption(CoreH5PProvider.DISPLAY_OPTION_FRAME, true) == false) {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_FRAME] = false;
} else {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD] = this.setDisplayOptionOverrides(
CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD, CoreH5PPermission.DOWNLOAD_H5P, id,
displayOptions[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD]);
/**
* Get display options from a URL params.
*
* @param params URL params.
* @return Display options as object.
*/
getDisplayOptionsFromUrlParams(params: {[name: string]: string}): CoreH5PDisplayOptions {
const displayOptions: CoreH5PDisplayOptions = {};
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED] = this.setDisplayOptionOverrides(
CoreH5PProvider.DISPLAY_OPTION_EMBED, CoreH5PPermission.EMBED_H5P, id,
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED]);
if (this.getOption(CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT, true) == false) {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT] = false;
}
if (!params) {
return displayOptions;
}
displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPY] = this.hasPermission(CoreH5PPermission.COPY_H5P, id);
displayOptions[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD] =
this.utils.isTrueOrOne(params[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD]);
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED] =
this.utils.isTrueOrOne(params[CoreH5PProvider.DISPLAY_OPTION_EMBED]);
displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT] =
this.utils.isTrueOrOne(params[CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT]);
displayOptions[CoreH5PProvider.DISPLAY_OPTION_FRAME] = displayOptions[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD] ||
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED] || displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT];
displayOptions[CoreH5PProvider.DISPLAY_OPTION_ABOUT] = !!this.getOption(CoreH5PProvider.DISPLAY_OPTION_ABOUT, true);
return displayOptions;
}
@ -1734,7 +1750,7 @@ export class CoreH5PProvider {
*/
getOption(name: string, defaultValue: any = false): any {
// For now, all them are disabled by default, so only will be rendered when defined in the displayoptions DB field.
return 2; // CONTROLLED_BY_AUTHOR_DEFAULT_OFF.
return CoreH5PDisplayOptionBehaviour.CONTROLLED_BY_AUTHOR_DEFAULT_OFF; // CONTROLLED_BY_AUTHOR_DEFAULT_OFF.
}
/**
@ -1845,7 +1861,8 @@ export class CoreH5PProvider {
* @return Whether the user has permission to execute an action.
*/
hasPermission(permission: number, id: number): boolean {
return true;
// H5P capabilities have not been introduced.
return null;
}
/**
@ -1967,7 +1984,7 @@ export class CoreH5PProvider {
params: contentData.jsoncontent,
// The embedtype will be always set to 'iframe' to prevent conflicts with JS and CSS.
embedType: 'iframe',
disable: contentData.displayoptions,
disable: null,
folderName: contentData.foldername,
title: libData.title,
slug: this.h5pUtils.slugify(libData.title) + '-' + contentData.id,
@ -2193,7 +2210,7 @@ export class CoreH5PProvider {
const data: any = {
jsoncontent: content.params,
displayoptions: content.disable,
displayoptions: null,
mainlibraryid: content.library.libraryId,
timemodified: Date.now(),
filtered: null,
@ -2563,6 +2580,40 @@ export class CoreH5PProvider {
return db.updateRecords(this.CONTENT_TABLE, data, {id: id});
});
}
/**
* Validate display options, updating them if needed.
*
* @param displayOptions The display options to validate.
* @param id Package ID.
*/
validateDisplayOptions(displayOptions: CoreH5PDisplayOptions, id: number): CoreH5PDisplayOptions {
// Never allow downloading in the app.
displayOptions[CoreH5PProvider.DISPLAY_OPTION_DOWNLOAD] = false;
// Embed - force setting it if always on or always off. In web, this is done when storing in DB.
const embed = this.getOption(CoreH5PProvider.DISPLAY_OPTION_EMBED, CoreH5PDisplayOptionBehaviour.ALWAYS_SHOW);
if (embed == CoreH5PDisplayOptionBehaviour.ALWAYS_SHOW || embed == CoreH5PDisplayOptionBehaviour.NEVER_SHOW) {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED] = (embed == CoreH5PDisplayOptionBehaviour.ALWAYS_SHOW);
}
if (this.getOption(CoreH5PProvider.DISPLAY_OPTION_FRAME, true) == false) {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_FRAME] = false;
} else {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED] = this.setDisplayOptionOverrides(
CoreH5PProvider.DISPLAY_OPTION_EMBED, CoreH5PPermission.EMBED_H5P, id,
displayOptions[CoreH5PProvider.DISPLAY_OPTION_EMBED]);
if (this.getOption(CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT, true) == false) {
displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPYRIGHT] = false;
}
}
displayOptions[CoreH5PProvider.DISPLAY_OPTION_COPY] = this.hasPermission(CoreH5PPermission.COPY_H5P, id);
return displayOptions;
}
}
/**
@ -2633,7 +2684,7 @@ export type CoreH5PContentDBData = {
id: number; // The id of the content.
jsoncontent: string; // The content in json format.
mainlibraryid: number; // The library we first instantiate for this node.
displayoptions: number; // H5P Button display options.
displayoptions: number; // H5P Button display options. Not used right now.
foldername: string; // Name of the folder that contains the contents.
fileurl: string; // The online URL of the H5P package.
filtered: string; // Filtered version of json_content.

View File

@ -50,13 +50,19 @@ export class CoreUrlUtilsProvider {
* @param url URL to add the params to.
* @param params Object with the params to add.
* @param anchor Anchor text if needed.
* @param boolToNumber Whether to convert bools to 1 or 0.
* @return URL with params.
*/
addParamsToUrl(url: string, params?: {[key: string]: any}, anchor?: string): string {
addParamsToUrl(url: string, params?: {[key: string]: any}, anchor?: string, boolToNumber?: boolean): string {
let separator = url.indexOf('?') != -1 ? '&' : '?';
for (const key in params) {
const value = params[key];
let value = params[key];
if (boolToNumber && typeof value == 'boolean') {
// Convert booleans to 1 or 0.
value = value ? 1 : 0;
}
// Ignore objects.
if (typeof value != 'object') {