141 lines
4.6 KiB
TypeScript
141 lines
4.6 KiB
TypeScript
// (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 { DownloadStatus } from '@/core/constants';
|
|
import { CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site';
|
|
import { CoreFile } from '@services/file';
|
|
import { CoreFilepool } from '@services/filepool';
|
|
import { CoreSites } from '@services/sites';
|
|
import { CoreWS } from '@services/ws';
|
|
import { makeSingleton } from '@singletons';
|
|
import { CoreStyleHandler, CoreStylesService } from '@features/styles/services/styles';
|
|
import { CoreLogger } from '@singletons/logger';
|
|
import { CoreUtils } from '@services/utils/utils';
|
|
|
|
const COMPONENT = 'mmaRemoteStyles';
|
|
|
|
/**
|
|
* Service to handle remote themes.
|
|
* A remote theme is a CSS sheet stored in the site that allows customising the Mobile app.
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class AddonRemoteThemesHandlerService implements CoreStyleHandler {
|
|
|
|
protected logger: CoreLogger;
|
|
|
|
name = 'mobilecssurl';
|
|
priority = 1000;
|
|
|
|
constructor() {
|
|
this.logger = CoreLogger.getInstance('AddonRemoteThemes');
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
async isEnabled(siteId: string, config?: CoreSitePublicConfigResponse): Promise<boolean> {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @inheritDoc
|
|
*/
|
|
async getStyle(siteId: string, config?: CoreSitePublicConfigResponse): Promise<string> {
|
|
if (siteId === CoreStylesService.TMP_SITE_ID) {
|
|
if (!config) {
|
|
return '';
|
|
}
|
|
|
|
// Config received, it's a temp site.
|
|
return this.getRemoteStyles(config.mobilecssurl);
|
|
}
|
|
|
|
const site = await CoreSites.getSite(siteId);
|
|
const infos = site.getInfo();
|
|
|
|
if (!infos?.mobilecssurl) {
|
|
if (infos?.mobilecssurl === '') {
|
|
// CSS URL is empty. Delete downloaded files (if any).
|
|
CoreFilepool.removeFilesByComponent(siteId, COMPONENT, 1);
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
let fileUrl = infos.mobilecssurl;
|
|
|
|
if (CoreFile.isAvailable()) {
|
|
// The file system is available. Download the file and remove old CSS files if needed.
|
|
fileUrl = await this.downloadFileAndRemoveOld(siteId, fileUrl);
|
|
}
|
|
|
|
this.logger.debug('Loading styles from: ', fileUrl);
|
|
|
|
// Get the CSS content using HTTP because we will treat the styles before saving them in the file.
|
|
const style = await this.getRemoteStyles(fileUrl);
|
|
|
|
if (style != '') {
|
|
// Treat the CSS.
|
|
CoreUtils.ignoreErrors(
|
|
CoreFilepool.treatCSSCode(siteId, infos.mobilecssurl, style, COMPONENT, 1),
|
|
);
|
|
}
|
|
|
|
return style;
|
|
}
|
|
|
|
/**
|
|
* Get styles from the url.
|
|
*
|
|
* @param url Url to get the code from.
|
|
* @returns The styles.
|
|
*/
|
|
protected async getRemoteStyles(url?: string): Promise<string> {
|
|
if (!url) {
|
|
return '';
|
|
}
|
|
|
|
return CoreWS.getText(url);
|
|
}
|
|
|
|
/**
|
|
* Downloads a CSS file and remove old files if needed.
|
|
*
|
|
* @param siteId Site ID.
|
|
* @param url File URL.
|
|
* @returns Promise resolved when the file is downloaded.
|
|
*/
|
|
protected async downloadFileAndRemoveOld(siteId: string, url: string): Promise<string> {
|
|
|
|
try {
|
|
// Check if the file is downloaded.
|
|
const state = await CoreFilepool.getFileStateByUrl(siteId, url);
|
|
|
|
if (state === DownloadStatus.DOWNLOADABLE_NOT_DOWNLOADED) {
|
|
// File not downloaded, URL has changed or first time. Delete downloaded CSS files.
|
|
await CoreFilepool.removeFilesByComponent(siteId, COMPONENT, 1);
|
|
}
|
|
} catch {
|
|
// An error occurred while getting state (shouldn't happen). Don't delete downloaded file.
|
|
}
|
|
|
|
return CoreFilepool.downloadUrl(siteId, url, false, COMPONENT, 1);
|
|
}
|
|
|
|
}
|
|
|
|
export const AddonRemoteThemesHandler = makeSingleton(AddonRemoteThemesHandlerService);
|