commit
07f661e5ab
|
@ -29,7 +29,7 @@
|
|||
<ion-item class="ion-text-wrap" *ngIf="activityInstructions">
|
||||
<ion-label>
|
||||
<core-format-text [text]="activityInstructions" [component]="component" [componentId]="moduleId" contextLevel="module"
|
||||
[contextInstanceId]="moduleId" [courseId]="courseId" [maxHeight]="120">
|
||||
[contextInstanceId]="moduleId" [courseId]="courseId">
|
||||
</core-format-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
|
|
|
@ -19,10 +19,6 @@ import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
|
|||
*/
|
||||
export class CoreAjaxError extends CoreSiteError {
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0. AJAX endpoint should always be available in supported Moodle versions.
|
||||
*/
|
||||
available = 1;
|
||||
status?: number;
|
||||
|
||||
constructor(messageOrOptions: string | CoreSiteErrorOptions, available?: number, status?: number) {
|
||||
|
|
|
@ -1634,38 +1634,6 @@ export class CoreSite {
|
|||
return CoreUrlUtils.addParamsToUrl(CorePath.concatenatePaths(this.siteUrl, path), params, anchor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the local_mobile plugin is installed in the Moodle site.
|
||||
*
|
||||
* @returns Promise resolved when the check is done.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
async checkLocalMobilePlugin(): Promise<LocalMobileResponse> {
|
||||
// Not used anymore.
|
||||
return { code: 0, coreSupported: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if local_mobile has been installed in Moodle.
|
||||
*
|
||||
* @returns Whether the App is able to use local_mobile plugin for this site.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
checkIfAppUsesLocalMobile(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if local_mobile has been installed in Moodle but the app is not using it.
|
||||
*
|
||||
* @returns Promise resolved it local_mobile was added, rejected otherwise.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async checkIfLocalMobileInstalledAndNotUsed(): Promise<void> {
|
||||
throw new CoreError('Deprecated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a URL belongs to this site.
|
||||
*
|
||||
|
@ -2666,33 +2634,6 @@ export type CoreSiteWSPreSets = {
|
|||
updateInBackground?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Response of checking local_mobile status.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
export type LocalMobileResponse = {
|
||||
/**
|
||||
* Code to identify the authentication method to use.
|
||||
*/
|
||||
code: number;
|
||||
|
||||
/**
|
||||
* Name of the service to use.
|
||||
*/
|
||||
service?: string;
|
||||
|
||||
/**
|
||||
* Code of the warning message.
|
||||
*/
|
||||
warning?: string;
|
||||
|
||||
/**
|
||||
* Whether core SSO is supported.
|
||||
*/
|
||||
coreSupported?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Info of a request waiting in the queue.
|
||||
*/
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, Input, Output, OnInit, OnDestroy, EventEmitter, OnChanges, SimpleChange } from '@angular/core';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreContextMenuComponent } from '../context-menu/context-menu';
|
||||
|
||||
/**
|
||||
|
@ -58,11 +57,6 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
|
|||
@Output() onClosed?: EventEmitter<() => void>; // Will emit an event when the popover is closed because the item was clicked.
|
||||
@Output() toggleChange = new EventEmitter<boolean>();// Will emit an event when toggle changes to enable 2-way data binding.
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
@Input() iconDescription?: string;
|
||||
|
||||
protected hasAction = false;
|
||||
protected destroyed = false;
|
||||
|
||||
|
@ -92,12 +86,6 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange
|
|||
if (!this.destroyed) {
|
||||
this.ctxtMenu.addItem(this);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (this.iconDescription !== undefined) {
|
||||
CoreLogger.getInstance('CoreContextMenuItemComponent')
|
||||
.warn('iconDescription Input is deprecated and should not be used');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,10 +35,6 @@ export class CoreDownloadRefreshComponent {
|
|||
@Input() statusTranslatable?: string; // Download status translatable string.
|
||||
@Input() enabled = false; // Whether the download is enabled.
|
||||
@Input() loading = true; // Force loading status when is not downloading.
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
@Input() size = ''; // Size of the buttons.
|
||||
@Input() canTrustDownload = false; // If false, refresh will be shown if downloaded.
|
||||
@Output() action: EventEmitter<boolean>; // Will emit an event when the item clicked.
|
||||
|
||||
|
|
|
@ -35,11 +35,6 @@ export class CoreEmptyBoxComponent {
|
|||
@Input() image?: string; // Image source. If an icon is provided, image won't be used.
|
||||
@Input() flipIconRtl = false; // Whether to flip the icon in RTL. Defaults to false.
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
@Input() inline = false;
|
||||
|
||||
@HostBinding('class.dimmed')
|
||||
get isDimmed(): boolean {
|
||||
return this.dimmed;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
import { Component, Input, OnInit, OnChanges, SimpleChange, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
|
||||
|
||||
import { CoreEventLoadingChangedData, CoreEvents } from '@singletons/events';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreAnimations } from '@components/animations';
|
||||
import { Translate } from '@singletons';
|
||||
|
@ -153,13 +152,6 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
|
|||
this.lastScrollPosition = this.getScrollPosition();
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
|
||||
// Event has been deprecated since app 4.0.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
CoreEvents.trigger(CoreEvents.CORE_LOADING_CHANGED, <CoreEventLoadingChangedData> {
|
||||
loaded,
|
||||
uniqueId: this.uniqueId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -78,10 +78,6 @@ export class CoreConstants {
|
|||
// WS constants.
|
||||
static readonly WS_TIMEOUT = 30000; // Timeout when not in WiFi.
|
||||
static readonly WS_TIMEOUT_WIFI = 30000; // Timeout when in WiFi.
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
static readonly WS_PREFIX = 'local_mobile_';
|
||||
|
||||
// Login constants.
|
||||
/**
|
||||
|
|
|
@ -90,21 +90,6 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
|
|||
@Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
|
||||
@Input() disabled?: boolean; // If disabled, autoplay elements will be disabled.
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
@Input() fullOnClick?: boolean | string;
|
||||
/**
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
@Input() fullTitle?: string;
|
||||
/**
|
||||
* Max height in pixels to render the content box. It should be 50 at least to make sense.
|
||||
*
|
||||
* @deprecated since 4.0 Use collapsible-item directive instead.
|
||||
*/
|
||||
@Input() maxHeight?: number;
|
||||
|
||||
@Output() afterRender: EventEmitter<void>; // Called when the data is rendered.
|
||||
@Output() onClick: EventEmitter<void> = new EventEmitter(); // Called when clicked.
|
||||
|
||||
|
@ -380,15 +365,6 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec
|
|||
|
||||
await CoreUtils.nextTick();
|
||||
|
||||
// Use collapsible-item directive instead.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (this.maxHeight && !this.collapsible) {
|
||||
this.collapsible = new CoreCollapsibleItemDirective(new ElementRef(this.element));
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
this.collapsible.height = this.maxHeight;
|
||||
this.collapsible.ngOnInit();
|
||||
}
|
||||
|
||||
// Add magnifying glasses to images.
|
||||
this.addMagnifyingGlasses();
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { CoreContentLinksHandlerBase } from './base-handler';
|
||||
import { Params } from '@angular/router';
|
||||
import { CoreContentLinksAction } from '../services/contentlinks-delegate';
|
||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||
import { CoreNavigationOptions } from '@services/navigator';
|
||||
|
@ -52,20 +51,6 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
|
|||
this.featureName = 'CoreCourseModuleDelegate_' + addon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mod params necessary to open an activity.
|
||||
*
|
||||
* @param url The URL to treat.
|
||||
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
|
||||
* @param courseId Course ID related to the URL. Optional but recommended.
|
||||
* @returns List of params to pass to navigateToModule / navigateToModuleByInstance.
|
||||
* @deprecated since 4.0. Not used anymore.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
getPageParams(url: string, params: Record<string, string>, courseId?: number): Params {
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the navigation options to open the module.
|
||||
*
|
||||
|
@ -97,19 +82,6 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
|
|||
): CoreContentLinksAction[] | Promise<CoreContentLinksAction[]> {
|
||||
|
||||
courseId = Number(courseId || params.courseid || params.cid);
|
||||
const getModNavOptions = (siteId: string): CoreNavigationOptions => {
|
||||
let modNavOptions = this.getModNavOptions(url, params, siteId, courseId);
|
||||
if (!modNavOptions) {
|
||||
// Use the old function, currently deprecated.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const pageParams = this.getPageParams(url, params, courseId);
|
||||
if (pageParams && Object.keys(pageParams).length > 0) {
|
||||
modNavOptions = { params: pageParams };
|
||||
}
|
||||
}
|
||||
|
||||
return modNavOptions;
|
||||
};
|
||||
|
||||
if (this.instanceIdParam && params[this.instanceIdParam] !== undefined) {
|
||||
const instanceId = parseInt(params[this.instanceIdParam], 10);
|
||||
|
@ -122,7 +94,7 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
|
|||
{
|
||||
courseId,
|
||||
useModNameToGetModule: this.useModNameToGetModule,
|
||||
modNavOptions: getModNavOptions(siteId),
|
||||
modNavOptions: this.getModNavOptions(url, params, siteId, courseId),
|
||||
siteId,
|
||||
},
|
||||
);
|
||||
|
@ -137,7 +109,7 @@ export class CoreContentLinksModuleIndexHandler extends CoreContentLinksHandlerB
|
|||
{
|
||||
courseId,
|
||||
modName: this.useModNameToGetModule ? this.modName : undefined,
|
||||
modNavOptions: getModNavOptions(siteId),
|
||||
modNavOptions: this.getModNavOptions(url, params, siteId, courseId),
|
||||
siteId,
|
||||
},
|
||||
);
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, HostBinding, Input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component to display the description of a module.
|
||||
|
@ -47,4 +47,8 @@ export class CoreCourseModuleDescriptionComponent {
|
|||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters.
|
||||
|
||||
@HostBinding('class.deprecated') get isDeprecated(): boolean {
|
||||
return true;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -148,14 +148,6 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
|||
|
||||
this.modNavOptions = CoreNavigator.getRouteParam<CoreNavigationOptions>('modNavOptions');
|
||||
this.openModule = CoreNavigator.getRouteBooleanParam('openModule') ?? true; // If false, just scroll to module.
|
||||
if (!this.modNavOptions) {
|
||||
// Fallback to old way of passing params. @deprecated since 4.0.
|
||||
const modParams = CoreNavigator.getRouteParam<Params>('modParams');
|
||||
if (modParams) {
|
||||
this.modNavOptions = { params: modParams };
|
||||
}
|
||||
}
|
||||
|
||||
this.currentPagePath = CoreNavigator.getCurrentPath();
|
||||
this.contentsTab.page = CorePath.concatenatePaths(this.currentPagePath, this.contentsTab.page);
|
||||
this.contentsTab.pageParams = {
|
||||
|
|
|
@ -42,7 +42,6 @@ import {
|
|||
CoreEnrolledCourseData,
|
||||
} from '@features/courses/services/courses';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
||||
import { CoreCourseOffline } from './course-offline';
|
||||
import {
|
||||
CoreCourseOptionsDelegate,
|
||||
|
@ -258,22 +257,6 @@ export class CoreCourseHelperProvider {
|
|||
return section.uservisible !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate completion data of a module.
|
||||
*
|
||||
* @param module Module.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
calculateModuleCompletionData(module: CoreCourseModuleData): void {
|
||||
if (!module.completiondata || !module.completion) {
|
||||
return;
|
||||
}
|
||||
|
||||
module.completiondata.courseId = module.course;
|
||||
module.completiondata.tracking = module.completion;
|
||||
module.completiondata.cmid = module.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the status of a section.
|
||||
*
|
||||
|
@ -312,8 +295,6 @@ export class CoreCourseHelperProvider {
|
|||
}
|
||||
|
||||
sectionWithStatus.downloadStatus = result.status;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
sectionWithStatus.canCheckUpdates = true;
|
||||
|
||||
// Set this section data.
|
||||
if (result.status !== CoreConstants.DOWNLOADING) {
|
||||
|
@ -375,8 +356,6 @@ export class CoreCourseHelperProvider {
|
|||
if (allSectionsSection) {
|
||||
// Set "All sections" data.
|
||||
allSectionsSection.downloadStatus = allSectionsStatus;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
allSectionsSection.canCheckUpdates = true;
|
||||
allSectionsSection.isDownloading = allSectionsStatus === CoreConstants.DOWNLOADING;
|
||||
}
|
||||
|
||||
|
@ -514,32 +493,6 @@ export class CoreCourseHelperProvider {
|
|||
return CoreUtils.allPromises(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation dialog and then remove a module files.
|
||||
*
|
||||
* @param module Module to remove the files.
|
||||
* @param courseId Course ID the module belongs to.
|
||||
* @returns Promise resolved when done.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async confirmAndRemoveFiles(module: CoreCourseModuleData, courseId: number): Promise<void> {
|
||||
let modal: CoreIonLoadingElement | undefined;
|
||||
|
||||
try {
|
||||
await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: module.name });
|
||||
|
||||
modal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
await this.removeModuleStoredData(module, courseId);
|
||||
} catch (error) {
|
||||
if (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
}
|
||||
} finally {
|
||||
modal?.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the size to download a section and show a confirm modal if needed.
|
||||
*
|
||||
|
@ -1358,31 +1311,6 @@ export class CoreCourseHelperProvider {
|
|||
return CoreConstants.ICON_DOWNLOADING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the course ID from a module instance ID, showing an error message if it can't be retrieved.
|
||||
*
|
||||
* @param instanceId Instance ID.
|
||||
* @param moduleName Name of the module. E.g. 'glossary'.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @returns Promise resolved with the module's course ID.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async getModuleCourseIdByInstance(instanceId: number, moduleName: string, siteId?: string): Promise<number> {
|
||||
try {
|
||||
const cm = await CoreCourse.getModuleBasicInfoByInstance(
|
||||
instanceId,
|
||||
moduleName,
|
||||
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
|
||||
);
|
||||
|
||||
return cm.course;
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true);
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get prefetch info for a module.
|
||||
*
|
||||
|
@ -1805,8 +1733,6 @@ export class CoreCourseHelperProvider {
|
|||
|
||||
// Set "All sections" data.
|
||||
section.downloadStatus = allSectionsStatus;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
section.canCheckUpdates = true;
|
||||
section.isDownloading = allSectionsStatus === CoreConstants.DOWNLOADING;
|
||||
} finally {
|
||||
section.isDownloading = false;
|
||||
|
@ -2120,10 +2046,6 @@ export type CoreCourseSection = CoreCourseWSSection & {
|
|||
*/
|
||||
export type CoreCourseSectionWithStatus = CoreCourseSection & {
|
||||
downloadStatus?: string; // Section status.
|
||||
/**
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
canCheckUpdates?: boolean; // Whether can check updates.
|
||||
isDownloading?: boolean; // Whether section is being downloaded.
|
||||
total?: number; // Total of modules being downloaded.
|
||||
count?: number; // Number of downloaded modules.
|
||||
|
@ -2141,13 +2063,6 @@ export type CoreCourseModuleData = Omit<CoreCourseGetContentsWSModule, 'completi
|
|||
section: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Module with calculated data.
|
||||
*
|
||||
* @deprecated since 4.0. Use CoreCourseModuleData instead.
|
||||
*/
|
||||
export type CoreCourseModule = CoreCourseModuleData;
|
||||
|
||||
/**
|
||||
* Module completion with calculated data.
|
||||
*/
|
||||
|
|
|
@ -110,36 +110,6 @@ export class CoreCourseProvider {
|
|||
static readonly ACCESS_DEFAULT = 'courses_access_default';
|
||||
static readonly ALL_COURSES_CLEARED = -1;
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE instead.
|
||||
*/
|
||||
static readonly COMPLETION_TRACKING_NONE = 0;
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_MANUAL instead.
|
||||
*/
|
||||
static readonly COMPLETION_TRACKING_MANUAL = 1;
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_AUTOMATIC instead.
|
||||
*/
|
||||
static readonly COMPLETION_TRACKING_AUTOMATIC = 2;
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_INCOMPLETE instead.
|
||||
*/
|
||||
static readonly COMPLETION_INCOMPLETE = 0;
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE instead.
|
||||
*/
|
||||
static readonly COMPLETION_COMPLETE = 1;
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_PASS instead.
|
||||
*/
|
||||
static readonly COMPLETION_COMPLETE_PASS = 2;
|
||||
/**
|
||||
* @deprecated since 4.0, use CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE_FAIL instead.
|
||||
*/
|
||||
static readonly COMPLETION_COMPLETE_FAIL = 3;
|
||||
|
||||
static readonly COMPONENT = 'CoreCourse';
|
||||
|
||||
readonly CORE_MODULES = [
|
||||
|
@ -863,24 +833,6 @@ export class CoreCourseProvider {
|
|||
return path + moduleName + '.svg';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the section ID a module belongs to.
|
||||
*
|
||||
* @param moduleId The module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @returns Promise resolved with the section ID.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async getModuleSectionId(moduleId: number, siteId?: string): Promise<number> {
|
||||
// Try to get the section using getModuleBasicInfo.
|
||||
const module = await CoreCourse.getModuleBasicInfo(
|
||||
moduleId,
|
||||
{ siteId, readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE },
|
||||
);
|
||||
|
||||
return module.section;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a specific section.
|
||||
*
|
||||
|
@ -1829,15 +1781,6 @@ type CoreCourseGetCourseModuleWSResponse = {
|
|||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Course module data returned by the WS with course added.
|
||||
*
|
||||
* @deprecated since 4.0. Use CoreCourseModuleData instead.
|
||||
*/
|
||||
export type CoreCourseWSModule = CoreCourseGetContentsWSModule & {
|
||||
course: number; // The course id.
|
||||
};
|
||||
|
||||
/**
|
||||
* Module completion data.
|
||||
*/
|
||||
|
|
|
@ -57,24 +57,6 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler {
|
|||
*/
|
||||
displayBlocks?(course: CoreCourseAnyCourseData): boolean;
|
||||
|
||||
/**
|
||||
* Whether the option to enable section/module download should be displayed.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @returns Whether the option to enable section/module download should be displayed.
|
||||
* @deprecated since 4.0 Not used anymore because prefetch has been moved to storage manager.
|
||||
*/
|
||||
displayEnableDownload?(course: CoreCourseAnyCourseData): boolean;
|
||||
|
||||
/**
|
||||
* Whether the default course index should be displayed. Defaults to true.
|
||||
*
|
||||
* @param course The course to check.
|
||||
* @returns Whether the default course index should be displayed.
|
||||
* @deprecated since 4.0. Please use displayCourseIndex instead.
|
||||
*/
|
||||
displaySectionSelector?(course: CoreCourseAnyCourseData): boolean;
|
||||
|
||||
/**
|
||||
* Whether the default section selector should be displayed. Defaults to true.
|
||||
*
|
||||
|
|
|
@ -77,16 +77,6 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
|
|||
}, CoreSites.getCurrentSiteId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current site can check updates using core_course_check_updates.
|
||||
*
|
||||
* @returns True if can check updates, false otherwise.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
canCheckUpdates(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain module can use core_course_check_updates.
|
||||
*
|
||||
|
@ -705,8 +695,7 @@ export class CoreCourseModulePrefetchDelegateService extends CoreDelegate<CoreCo
|
|||
await Promise.all(modules.map(async (module) => {
|
||||
const handler = this.getPrefetchHandlerFor(module.modname);
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (!handler || (onlyToDisplay && handler.skipListStatus)) {
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1364,14 +1353,6 @@ export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler {
|
|||
*/
|
||||
updatesNames?: RegExp;
|
||||
|
||||
/**
|
||||
* If true, this module will be treated as not downloadable when determining the status of a list of modules. The module will
|
||||
* still be downloaded when downloading the section/course, it only affects whether the button should be displayed.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
skipListStatus?: boolean;
|
||||
|
||||
/**
|
||||
* Get the download size of a module.
|
||||
*
|
||||
|
|
|
@ -1,60 +1,3 @@
|
|||
<ion-card [attr.course-color]="course.color ? null : course.colorNumber">
|
||||
<div (click)="openCourse()" class="core-course-thumb" [class.core-course-color-img]="course.courseimage"
|
||||
[style.background-color]="course.color">
|
||||
<img *ngIf="course.courseimage" [src]="course.courseimage" core-external-content alt="" />
|
||||
</div>
|
||||
<ion-item button (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" class="core-course-header"
|
||||
[class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" detail="false">
|
||||
<ion-label class="ion-text-wrap core-course-title"
|
||||
[class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)"
|
||||
[class.core-course-with-spinner]="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner">
|
||||
<p *ngIf="course.categoryname || (course.displayname && course.shortname && course.fullname != course.displayname)"
|
||||
class="core-course-additional-info">
|
||||
<span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span>
|
||||
<span *ngIf="course.categoryname" class="core-course-category">
|
||||
<core-format-text [text]="course.categoryname"></core-format-text>
|
||||
</span>
|
||||
<span *ngIf="course.categoryname && course.displayname && course.shortname && course.fullname != course.displayname"
|
||||
class="core-course-category"> | </span>
|
||||
<span *ngIf="course.displayname && course.shortname && course.fullname != course.displayname" class="core-course-shortname">
|
||||
<core-format-text [text]="course.shortname" contextLevel="course" [contextInstanceId]="course.id">
|
||||
</core-format-text>
|
||||
</span>
|
||||
</p>
|
||||
<p class="item-heading">
|
||||
<ion-icon name="fas-star" *ngIf="isFavourite" [attr.aria-label]="'core.courses.favourite' | translate">
|
||||
</ion-icon>
|
||||
<span class="sr-only" *ngIf="isFavourite">{{ 'core.courses.aria:favourite' | translate }}</span>
|
||||
<span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span>
|
||||
<core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
|
||||
<div class="core-button-spinner" *ngIf="downloadCourseEnabled && !courseOptionMenuEnabled && showDownload" slot="end">
|
||||
<core-download-refresh [status]="prefetchCourseData.status" [enabled]="downloadCourseEnabled"
|
||||
[statusTranslatable]="prefetchCourseData.statusTranslatable" [canTrustDownload]="false"
|
||||
[loading]="prefetchCourseData.loading" (action)="prefetchCourse()"></core-download-refresh>
|
||||
</div>
|
||||
|
||||
<div class="core-button-spinner" *ngIf="courseOptionMenuEnabled" slot="end">
|
||||
<!-- Download course spinner. -->
|
||||
<ion-spinner *ngIf="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner"
|
||||
[attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||
|
||||
<!-- Downloaded icon. -->
|
||||
<ion-icon *ngIf="downloadCourseEnabled && prefetchCourseData.downloadSucceeded && !showSpinner" class="core-icon-downloaded"
|
||||
name="fam-cloud-done" color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon>
|
||||
|
||||
<!-- Options menu. -->
|
||||
<ion-button fill="clear" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner"
|
||||
[attr.aria-label]="('core.displayoptions' | translate)">
|
||||
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="showAll && progress >= 0 && completionUserTracked !== false" class="core-course-progress">
|
||||
<ion-label>
|
||||
<core-progress-bar [progress]="progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
<core-courses-course-list-item [course]="course" class="core-course-progress" [showDownload]="showDownload"
|
||||
[layout]="showAll ? 'card' : 'summarycard'">
|
||||
</core-courses-course-list-item>
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
@import "~theme/globals";
|
||||
|
||||
:host {
|
||||
ion-card {
|
||||
--vertical-margin: 12px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
height: calc(100% - var(--vertical-margin) - var(--vertical-margin));
|
||||
margin-top: var(--vertical-margin);
|
||||
margin-bottom: var(--vertical-margin);
|
||||
|
||||
@for $i from 0 to length($core-course-image-background) {
|
||||
&[course-color="#{$i}"] .core-course-thumb {
|
||||
background: var(--core-course-color-#{$i});
|
||||
}
|
||||
}
|
||||
|
||||
.core-course-thumb {
|
||||
padding-top: 40%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
-webkit-transition: all 50ms ease-in-out;
|
||||
transition: all 50ms ease-in-out;
|
||||
|
||||
&.core-course-color-img {
|
||||
background: var(--ion-item-background);
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
|
||||
// Fill geopaterns
|
||||
&[src$=".svg"] {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-hide-thumb-on-cards) {
|
||||
.core-course-thumb {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-thumb-on-cards-background) {
|
||||
.core-course-thumb {
|
||||
background: $core-course-thumb-on-cards-background !important;
|
||||
}
|
||||
}
|
||||
|
||||
.core-course-additional-info {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.core-course-header {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.core-course-only-title {
|
||||
&::part(native) {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.core-course-title {
|
||||
margin: 12px 0;
|
||||
flex-grow: 1;
|
||||
|
||||
.item-heading ion-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--core-star-color);
|
||||
}
|
||||
}
|
||||
|
||||
.core-button-spinner {
|
||||
margin: 0;
|
||||
}
|
||||
.core-button-spinner ion-spinner {
|
||||
vertical-align: top; // the better option for most scenarios
|
||||
vertical-align: -webkit-baseline-middle; // the best for those that support it
|
||||
}
|
||||
|
||||
.core-button-spinner .core-icon-downloaded {
|
||||
font-size: 28.8px;
|
||||
margin-top: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.item-button[icon-only] {
|
||||
min-width: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-hide-progress-on-cards) {
|
||||
.core-course-progress {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Common styles.
|
||||
:host-context(.core-horizontal-scroll) {
|
||||
@include horizontal_scroll_item(80%, 250px, 300px);
|
||||
|
||||
ion-card {
|
||||
.core-course-thumb {
|
||||
padding-top: 30%;
|
||||
}
|
||||
|
||||
.core-course-header {
|
||||
.core-course-title {
|
||||
margin: 7px 0;
|
||||
|
||||
.item-heading ion-icon {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
&.core-course-with-buttons {
|
||||
max-width: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
.core-button-spinner {
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
|
||||
ion-spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
.item-button[icon-only] {
|
||||
min-width: 40px;
|
||||
width: 40px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,21 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges } from '@angular/core';
|
||||
import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreCourses, CoreCoursesProvider } from '@features/courses/services/courses';
|
||||
import { CoreCourse, CoreCourseProvider } from '@features/course/services/course';
|
||||
import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import {
|
||||
CoreCourseAnyCourseDataWithExtraInfoAndOptions,
|
||||
CoreEnrolledCourseDataWithExtraInfoAndOptions,
|
||||
} from '../../services/courses-helper';
|
||||
import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu';
|
||||
import { CoreUser } from '@features/user/services/user';
|
||||
import { Component, HostBinding, Input } from '@angular/core';
|
||||
import { CoreCourseListItem } from '@features/courses/services/courses';
|
||||
|
||||
/**
|
||||
* This component is meant to display a course for a list of courses with progress.
|
||||
|
@ -41,296 +28,15 @@ import { CoreUser } from '@features/user/services/user';
|
|||
@Component({
|
||||
selector: 'core-courses-course-progress',
|
||||
templateUrl: 'core-courses-course-progress.html',
|
||||
styleUrls: ['course-progress.scss'],
|
||||
})
|
||||
export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy, OnChanges {
|
||||
export class CoreCoursesCourseProgressComponent {
|
||||
|
||||
// The course to render.
|
||||
@Input() course!: CoreCourseAnyCourseDataWithExtraInfoAndOptions;
|
||||
@Input() course!: CoreCourseListItem; // The course to render.
|
||||
@Input() showAll = false; // If true, will show all actions, options, star and progress.
|
||||
@Input() showDownload = true; // If true, will show download button. Only works if the options menu is not shown.
|
||||
|
||||
prefetchCourseData: CorePrefetchStatusInfo = {
|
||||
icon: '',
|
||||
statusTranslatable: 'core.loading',
|
||||
status: '',
|
||||
loading: true,
|
||||
@HostBinding('class.deprecated') get isDeprecated(): boolean {
|
||||
return true;
|
||||
};
|
||||
|
||||
showSpinner = false;
|
||||
downloadCourseEnabled = false;
|
||||
courseOptionMenuEnabled = false;
|
||||
isFavourite = false;
|
||||
progress = -1;
|
||||
completionUserTracked: boolean | undefined = false;
|
||||
|
||||
protected courseStatus = CoreConstants.NOT_DOWNLOADED;
|
||||
protected isDestroyed = false;
|
||||
protected courseStatusObserver?: CoreEventObserver;
|
||||
protected siteUpdatedObserver?: CoreEventObserver;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
|
||||
if (this.downloadCourseEnabled) {
|
||||
this.initPrefetchCourse();
|
||||
}
|
||||
|
||||
// This field is only available from 3.6 onwards.
|
||||
this.courseOptionMenuEnabled = this.showAll && 'isfavourite' in this.course &&
|
||||
this.course.isfavourite !== undefined;
|
||||
|
||||
// Refresh the enabled flag if site is updated.
|
||||
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
||||
const wasEnabled = this.downloadCourseEnabled;
|
||||
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
|
||||
if (!wasEnabled && this.downloadCourseEnabled) {
|
||||
// Download course is enabled now, initialize it.
|
||||
this.initPrefetchCourse();
|
||||
}
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnChanges(): void {
|
||||
this.isFavourite = 'isfavourite' in this.course && !!this.course.isfavourite;
|
||||
this.progress = 'progress' in this.course ? this.course.progress || -1 : -1;
|
||||
this.completionUserTracked = 'completionusertracked' in this.course && this.course.completionusertracked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize prefetch course.
|
||||
*/
|
||||
async initPrefetchCourse(): Promise<void> {
|
||||
if (this.courseStatusObserver !== undefined) {
|
||||
// Already initialized.
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for status change in course.
|
||||
this.courseStatusObserver = CoreEvents.on(CoreEvents.COURSE_STATUS_CHANGED, (data: CoreEventCourseStatusChanged) => {
|
||||
if (data.courseId == this.course.id || data.courseId == CoreCourseProvider.ALL_COURSES_CLEARED) {
|
||||
this.updateCourseStatus(data.status);
|
||||
}
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
// Determine course prefetch icon.
|
||||
const status = await CoreCourse.getCourseStatus(this.course.id);
|
||||
|
||||
this.updateCourseStatus(status);
|
||||
|
||||
if (this.prefetchCourseData.loading) {
|
||||
// Course is being downloaded. Get the download promise.
|
||||
const promise = CoreCourseHelper.getCourseDownloadPromise(this.course.id);
|
||||
if (promise) {
|
||||
// There is a download promise. If it fails, show an error.
|
||||
promise.catch((error) => {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No download, this probably means that the app was closed while downloading. Set previous status.
|
||||
CoreCourse.setCoursePreviousStatus(this.course.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a course.
|
||||
*/
|
||||
openCourse(): void {
|
||||
CoreCourseHelper.openCourse(this.course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch the course.
|
||||
*
|
||||
* @param e Click event.
|
||||
*/
|
||||
async prefetchCourse(e?: Event): Promise<void> {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
try {
|
||||
await CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course);
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the course.
|
||||
*/
|
||||
async deleteCourse(): Promise<void> {
|
||||
try {
|
||||
await CoreDomUtils.showDeleteConfirm(
|
||||
'addon.storagemanager.confirmdeletedatafrom',
|
||||
{ name: this.course.displayname || this.course.fullname },
|
||||
);
|
||||
} catch (error) {
|
||||
if (!CoreDomUtils.isCanceledError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const modal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
try {
|
||||
await CoreCourseHelper.deleteCourseFiles(this.course.id);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, Translate.instant('core.errordeletefile'));
|
||||
} finally {
|
||||
modal.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the course status icon and title.
|
||||
*
|
||||
* @param status Status to show.
|
||||
*/
|
||||
protected updateCourseStatus(status: string): void {
|
||||
const statusData = CoreCourseHelper.getCoursePrefetchStatusInfo(status);
|
||||
|
||||
this.courseStatus = status;
|
||||
this.prefetchCourseData.status = statusData.status;
|
||||
this.prefetchCourseData.icon = statusData.icon;
|
||||
this.prefetchCourseData.statusTranslatable = statusData.statusTranslatable;
|
||||
this.prefetchCourseData.loading = statusData.loading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the context menu.
|
||||
*
|
||||
* @param e Click Event.
|
||||
*/
|
||||
async showCourseOptionsMenu(e: Event): Promise<void> {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const popoverData = await CoreDomUtils.openPopover<string>({
|
||||
component: CoreCoursesCourseOptionsMenuComponent,
|
||||
componentProps: {
|
||||
course: this.course,
|
||||
prefetch: this.prefetchCourseData,
|
||||
},
|
||||
event: e,
|
||||
});
|
||||
|
||||
switch (popoverData) {
|
||||
case 'download':
|
||||
if (!this.prefetchCourseData.loading) {
|
||||
this.prefetchCourse(e);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
if (this.courseStatus == CoreConstants.DOWNLOADED || this.courseStatus == CoreConstants.OUTDATED) {
|
||||
this.deleteCourse();
|
||||
}
|
||||
break;
|
||||
case 'hide':
|
||||
this.setCourseHidden(true);
|
||||
break;
|
||||
case 'show':
|
||||
this.setCourseHidden(false);
|
||||
break;
|
||||
case 'favourite':
|
||||
this.setCourseFavourite(true);
|
||||
break;
|
||||
case 'unfavourite':
|
||||
this.setCourseFavourite(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide/Unhide the course from the course list.
|
||||
*
|
||||
* @param hide True to hide and false to show.
|
||||
*/
|
||||
protected async setCourseHidden(hide: boolean): Promise<void> {
|
||||
this.showSpinner = true;
|
||||
|
||||
// We should use null to unset the preference.
|
||||
try {
|
||||
await CoreUser.updateUserPreference(
|
||||
'block_myoverview_hidden_course_' + this.course.id,
|
||||
hide ? '1' : undefined,
|
||||
);
|
||||
|
||||
(<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).hidden = hide;
|
||||
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
|
||||
courseId: this.course.id,
|
||||
course: this.course,
|
||||
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
|
||||
state: CoreCoursesProvider.STATE_HIDDEN,
|
||||
value: hide,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error changing course visibility.');
|
||||
}
|
||||
} finally {
|
||||
this.showSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Favourite/Unfavourite the course from the course list.
|
||||
*
|
||||
* @param favourite True to favourite and false to unfavourite.
|
||||
*/
|
||||
protected async setCourseFavourite(favourite: boolean): Promise<void> {
|
||||
this.showSpinner = true;
|
||||
|
||||
try {
|
||||
await CoreCourses.setFavouriteCourse(this.course.id, favourite);
|
||||
|
||||
(<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).isfavourite = favourite;
|
||||
this.isFavourite = favourite;
|
||||
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
|
||||
courseId: this.course.id,
|
||||
course: this.course,
|
||||
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
|
||||
state: CoreCoursesProvider.STATE_FAVOURITE,
|
||||
value: favourite,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error changing course favourite attribute.');
|
||||
}
|
||||
} finally {
|
||||
this.showSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
|
||||
this.siteUpdatedObserver?.off();
|
||||
this.courseStatusObserver?.off();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -70,16 +70,6 @@ export class CoreCoursesProvider {
|
|||
protected userCoursesIds?: Set<number>;
|
||||
protected downloadOptionsEnabled = false;
|
||||
|
||||
/**
|
||||
* Whether current site supports getting course options.
|
||||
*
|
||||
* @returns Whether current site supports getting course options.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
canGetAdminAndNavOptions(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get categories. They can be filtered by id.
|
||||
*
|
||||
|
@ -602,26 +592,6 @@ export class CoreCoursesProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if get courses by field WS is available in a certain site.
|
||||
*
|
||||
* @returns Whether get courses by field is available.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
isGetCoursesByFieldAvailable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if get courses by field WS is available in a certain site, by site ID.
|
||||
*
|
||||
* @returns Promise resolved with boolean: whether get courses by field is available.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async isGetCoursesByFieldAvailableInSite(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the navigation and administration options for the given courses.
|
||||
*
|
||||
|
@ -1462,7 +1432,7 @@ export type CoreCourseGetCoursesData = CoreEnrolledCourseBasicData & {
|
|||
/**
|
||||
* Number of weeks/topics.
|
||||
*
|
||||
* @deprecated use courseformatoptions. This attribute is deprecated in moodle since 2.4 but still present.
|
||||
* @deprecatedonmoodle since 2.4. Use courseformatoptions. This attribute is deprecated in moodle since 2.4 but still present.
|
||||
*/
|
||||
numsections?: number;
|
||||
maxbytes?: number; // Largest size of file that can be uploaded into the course.
|
||||
|
@ -1470,7 +1440,7 @@ export type CoreCourseGetCoursesData = CoreEnrolledCourseBasicData & {
|
|||
/**
|
||||
* How the hidden sections in the course are displayed to students.
|
||||
*
|
||||
* @deprecated use courseformatoptions. This attribute is deprecated in moodle since 2.4 but still present.
|
||||
* @deprecatedonmoodle since 2.4. Use courseformatoptions. This attribute is deprecated in moodle since 2.4 but still present.
|
||||
*/
|
||||
hiddensections?: number;
|
||||
groupmode?: number; // No group, separate, visible.
|
||||
|
|
|
@ -60,26 +60,6 @@ export class CoreFilterProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not WS get available in context is available.
|
||||
*
|
||||
* @returns Promise resolved with true if ws is available, false otherwise.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async canGetAvailableInContext(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not WS get available in context is available in a certain site.
|
||||
*
|
||||
* @returns Promise resolved with true if ws is available, false otherwise.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
canGetAvailableInContextInSite(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can get the available filters: the WS is available and the feature isn't disabled.
|
||||
*
|
||||
|
|
|
@ -60,49 +60,6 @@ export class CoreGradesHelperProvider {
|
|||
this.logger = CoreLogger.getInstance('CoreGradesHelperProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a row from the grades table te be rendered in a page.
|
||||
*
|
||||
* @param tableRow JSON object representing row of grades table data.
|
||||
* @returns Formatted row object.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
protected async formatGradeRow(tableRow: CoreGradesTableRow): Promise<CoreGradesFormattedRow> {
|
||||
const row: CoreGradesFormattedRow = {
|
||||
rowclass: '',
|
||||
};
|
||||
for (const name in tableRow) {
|
||||
const column: CoreGradesTableColumn = tableRow[name];
|
||||
|
||||
if (column.content === undefined || column.content === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let content = String(column.content);
|
||||
|
||||
if (name == 'itemname') {
|
||||
await this.setRowIconAndType(row, content);
|
||||
|
||||
row.link = this.getModuleLink(content);
|
||||
row.rowclass += column.class.indexOf('hidden') >= 0 ? ' hidden' : '';
|
||||
row.rowclass += column.class.indexOf('dimmed_text') >= 0 ? ' dimmed_text' : '';
|
||||
|
||||
content = content.replace(/<\/span>/gi, '\n');
|
||||
content = CoreTextUtils.cleanTags(content);
|
||||
} else {
|
||||
content = CoreTextUtils.replaceNewLines(content, '<br>');
|
||||
}
|
||||
|
||||
if (content == ' ') {
|
||||
content = '';
|
||||
}
|
||||
|
||||
row[name] = content.trim();
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a row from the grades table to be rendered in one table.
|
||||
*
|
||||
|
@ -353,34 +310,6 @@ export class CoreGradesHelperProvider {
|
|||
return someCoursesAreMissing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an specific grade item.
|
||||
*
|
||||
* @param courseId ID of the course to get the grades from.
|
||||
* @param gradeId Grade ID.
|
||||
* @param userId ID of the user to get the grades from. If not defined use site's current user.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @returns Promise to be resolved when the grades are retrieved.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async getGradeItem(
|
||||
courseId: number,
|
||||
gradeId: number,
|
||||
userId?: number,
|
||||
siteId?: string,
|
||||
ignoreCache: boolean = false,
|
||||
): Promise<CoreGradesFormattedRow | null> {
|
||||
const grades = await CoreGrades.getCourseGradesTable(courseId, userId, siteId, ignoreCache);
|
||||
|
||||
if (!grades) {
|
||||
throw new CoreError('Couldn\'t get grade item');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return this.getGradesTableRow(grades, gradeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the label of the selected grade.
|
||||
*
|
||||
|
@ -460,65 +389,6 @@ export class CoreGradesHelperProvider {
|
|||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a row from the grades table.
|
||||
*
|
||||
* @param table JSON object representing a table with data.
|
||||
* @param gradeId Grade Object identifier.
|
||||
* @returns Formatted HTML table.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async getGradesTableRow(table: CoreGradesTable, gradeId: number): Promise<CoreGradesFormattedRow | null> {
|
||||
if (table.tabledata) {
|
||||
const selectedRow = table.tabledata.find(
|
||||
(row) =>
|
||||
row.itemname &&
|
||||
row.itemname.id &&
|
||||
row.itemname.id.substring(0, 3) == 'row' &&
|
||||
parseInt(row.itemname.id.split('_')[1], 10) == gradeId,
|
||||
);
|
||||
|
||||
if (selectedRow) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return await this.formatGradeRow(selectedRow);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rows related to a module from the grades table.
|
||||
*
|
||||
* @param table JSON object representing a table with data.
|
||||
* @param moduleId Grade Object identifier.
|
||||
* @returns Formatted HTML table.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async getModuleGradesTableRows(table: CoreGradesTable, moduleId: number): Promise<CoreGradesFormattedRow[]> {
|
||||
if (!table.tabledata) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Find href containing "/mod/xxx/xxx.php".
|
||||
const regex = /href="([^"]*\/mod\/[^"|^/]*\/[^"|^.]*\.php[^"]*)/;
|
||||
|
||||
return Promise.all(table.tabledata.filter((row) => {
|
||||
if (row.itemname && row.itemname.content) {
|
||||
const matches = row.itemname.content.match(regex);
|
||||
|
||||
if (matches && matches.length) {
|
||||
const hrefParams = CoreUrlUtils.extractUrlParams(matches[1]);
|
||||
|
||||
return hrefParams && parseInt(hrefParams.id) === moduleId;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
}).map((row) => this.formatGradeRow(row)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get module grades to display.
|
||||
*
|
||||
|
|
|
@ -342,16 +342,6 @@ export class CoreGradesProvider {
|
|||
return !(course && course.showgrades !== undefined && !course.showgrades);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not WS Grade Items is available.
|
||||
*
|
||||
* @returns True if ws is available, false otherwise.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async isGradeItemsAvailable(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log Course grades view in Moodle.
|
||||
*
|
||||
|
|
|
@ -44,16 +44,6 @@ export class CoreRatingProvider {
|
|||
static readonly AGGREGATE_CHANGED_EVENT = 'core_rating_aggregate_changed';
|
||||
static readonly RATING_SAVED_EVENT = 'core_rating_rating_saved';
|
||||
|
||||
/**
|
||||
* Returns whether the web serivce to add ratings is available.
|
||||
*
|
||||
* @returns If WS is available.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
isAddRatingWSAvailable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a rating to an item.
|
||||
*
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { CoreSite, CoreSiteConfig } from '@classes/site';
|
||||
import { CoreCourse, CoreCourseWSSection } from '@features/course/services/course';
|
||||
|
@ -89,14 +89,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
|
|||
|
||||
const module = CoreNavigator.getRouteParam<CoreCourseModuleData>('module');
|
||||
if (module) {
|
||||
let modNavOptions = CoreNavigator.getRouteParam<CoreNavigationOptions>('modNavOptions');
|
||||
if (!modNavOptions) {
|
||||
// Fallback to old way of passing params. @deprecated since 4.0.
|
||||
const modParams = CoreNavigator.getRouteParam<Params>('modParams');
|
||||
if (modParams) {
|
||||
modNavOptions = { params: modParams };
|
||||
}
|
||||
}
|
||||
const modNavOptions = CoreNavigator.getRouteParam<CoreNavigationOptions>('modNavOptions');
|
||||
CoreCourseHelper.openModule(module, this.siteHomeId, { modNavOptions });
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,7 @@ export class CoreSitePluginsCourseFormatHandler extends CoreSitePluginsBaseHandl
|
|||
*/
|
||||
displayCourseIndex(): boolean {
|
||||
// Use displaysectionselector while is not completely deprecated.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return this.handlerSchema.displaycourseindex ?? this.handlerSchema.displaysectionselector ?? true;
|
||||
return this.handlerSchema.displaycourseindex ?? true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, OnChanges, Input, ViewChild, Output, EventEmitter, HostBinding } from '@angular/core';
|
||||
import { Component, OnChanges, Input, ViewChild, HostBinding } from '@angular/core';
|
||||
import { IonRefresher } from '@ionic/angular';
|
||||
|
||||
import { CoreCourseFormatComponent } from '@features/course/components/course-format/course-format';
|
||||
import { CoreCourseModuleCompletionData, CoreCourseSection } from '@features/course/services/course-helper';
|
||||
import { CoreCourseSection } from '@features/course/services/course-helper';
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreSitePlugins, CoreSitePluginsContent } from '@features/siteplugins/services/siteplugins';
|
||||
|
@ -37,12 +37,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges {
|
|||
@Input() initialSectionId?: number; // The section to load first (by ID).
|
||||
@Input() initialSectionNumber?: number; // The section to load first (by number).
|
||||
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
|
||||
/**
|
||||
* Notify when any module completion changes.
|
||||
*
|
||||
* @deprecated since 4.0. Use CoreEvents instead.
|
||||
*/
|
||||
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>();
|
||||
|
||||
// Special input, allows access to the parent instance properties and methods.
|
||||
// Please notice that all the other inputs/outputs are also accessible through this instance, so they could be removed.
|
||||
|
@ -87,8 +81,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges {
|
|||
initialSectionId: this.initialSectionId,
|
||||
initialSectionNumber: this.initialSectionNumber,
|
||||
moduleId: this.moduleId,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
completionChanged: this.completionChanged,
|
||||
coreCourseFormatComponent: this.coreCourseFormatComponent,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { Component, OnInit, OnDestroy, Input, ViewChild, HostBinding } from '@angular/core';
|
||||
import { CoreIonLoadingElement } from '@classes/ion-loading';
|
||||
|
||||
import { CoreSiteWSPreSets } from '@classes/site';
|
||||
import {
|
||||
|
@ -22,12 +20,11 @@ import {
|
|||
CoreCourseModuleSummaryComponent,
|
||||
} from '@features/course/components/module-summary/module-summary';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||
import { CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||
import {
|
||||
CoreCourseModuleDelegate,
|
||||
CoreCourseModuleMainComponent,
|
||||
} from '@features/course/services/module-delegate';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
|
||||
import {
|
||||
CoreSitePlugins,
|
||||
CoreSitePluginsContent,
|
||||
|
@ -61,31 +58,6 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
|||
preSets?: CoreSiteWSPreSets;
|
||||
description?: string;
|
||||
|
||||
/**
|
||||
* @deprecated since 4.0, use module.url instead.
|
||||
*/
|
||||
externalUrl?: string;
|
||||
/**
|
||||
* @deprecated since 4.0. It won't be populated anymore.
|
||||
*/
|
||||
refreshIcon = CoreConstants.ICON_REFRESH;
|
||||
/**
|
||||
* @deprecated since 4.0. It won't be populated anymore.
|
||||
*/
|
||||
prefetchStatus?: string;
|
||||
/**
|
||||
* @deprecated since 4.0. It won't be populated anymore.
|
||||
*/
|
||||
prefetchStatusIcon?: string;
|
||||
/**
|
||||
* @deprecated since 4.0. It won't be populated anymore.
|
||||
*/
|
||||
prefetchText?: string;
|
||||
/**
|
||||
* @deprecated since 4.0. It won't be populated anymore.
|
||||
*/
|
||||
size?: string;
|
||||
|
||||
collapsibleFooterAppearOnBottom = true;
|
||||
|
||||
displayOpenInBrowser = true;
|
||||
|
@ -142,8 +114,6 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
|||
|
||||
// Get the data for the context menu.
|
||||
this.description = this.module.description;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
this.externalUrl = this.module.url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,15 +148,6 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the description.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
expandDescription(): void {
|
||||
this.openModuleSummary();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a module summary page.
|
||||
*/
|
||||
|
@ -221,50 +182,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
|||
}
|
||||
|
||||
/**
|
||||
* Prefetch the module.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async prefetch(): Promise<void> {
|
||||
try {
|
||||
// We need to call getDownloadSize, the package might have been updated.
|
||||
const size = await CoreCourseModulePrefetchDelegate.getModuleDownloadSize(this.module, this.courseId, true);
|
||||
|
||||
await CoreDomUtils.confirmDownloadSize(size);
|
||||
|
||||
await CoreCourseModulePrefetchDelegate.prefetchModule(this.module, this.courseId, true);
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm and remove downloaded files.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async removeFiles(): Promise<void> {
|
||||
let modal: CoreIonLoadingElement | undefined;
|
||||
|
||||
try {
|
||||
await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: this.module.name });
|
||||
|
||||
modal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
await CoreCourseHelper.removeModuleStoredData(this.module, this.courseId);
|
||||
} catch (error) {
|
||||
if (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
}
|
||||
} finally {
|
||||
modal?.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
|
|
|
@ -391,16 +391,6 @@ export class CoreSitePluginsProvider {
|
|||
await site.invalidateWsCacheForKey(this.getContentCacheKey(component, callback, args || {}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the get content WS is available.
|
||||
*
|
||||
* @returns If get content WS is available.
|
||||
* @deprecated since 4.0
|
||||
*/
|
||||
isGetContentAvailable(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a handler is enabled for a certain course.
|
||||
*
|
||||
|
@ -904,10 +894,6 @@ export type CoreSitePluginsCourseModuleHandlerData = CoreSitePluginsHandlerCommo
|
|||
export type CoreSitePluginsCourseFormatHandlerData = CoreSitePluginsHandlerCommonData & {
|
||||
canviewallsections?: boolean;
|
||||
displayenabledownload?: boolean;
|
||||
/**
|
||||
* @deprecated since 4.0. Use displaycourseindex instead.
|
||||
*/
|
||||
displaysectionselector?: boolean;
|
||||
displaycourseindex?: boolean;
|
||||
};
|
||||
|
||||
|
|
|
@ -109,26 +109,6 @@ export class CoreUserProvider {
|
|||
return !!site?.wsAvailable('core_enrol_search_users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WS to update profile picture is available in site.
|
||||
*
|
||||
* @returns Promise resolved with boolean: whether it's available.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
async canUpdatePicture(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WS to search participants is available in site.
|
||||
*
|
||||
* @returns Whether it's available.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
canUpdatePictureInSite(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the given user profile picture.
|
||||
*
|
||||
|
|
|
@ -411,63 +411,6 @@ export class CoreSitesProvider {
|
|||
return new CoreLoginError(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a site exists.
|
||||
*
|
||||
* @param siteUrl URL of the site to check.
|
||||
* @returns A promise to be resolved if the site exists.
|
||||
* @deprecated since 4.0. Now the app calls uses tool_mobile_get_public_config to check if site exists.
|
||||
*/
|
||||
async siteExists(siteUrl: string): Promise<void> {
|
||||
let data: CoreSitesLoginTokenResponse;
|
||||
|
||||
// Use a valid path first.
|
||||
siteUrl = CoreUrlUtils.removeUrlParams(siteUrl);
|
||||
|
||||
try {
|
||||
const lang = await CoreLang.getCurrentLanguage(CoreLangFormat.LMS);
|
||||
|
||||
data = await Http.post(`${siteUrl}/login/token.php?lang=${lang}`, { appsitecheck: 1 })
|
||||
.pipe(timeout(CoreWS.getRequestTimeout()))
|
||||
.toPromise();
|
||||
} catch (error) {
|
||||
throw this.createCannotConnectLoginError(null, {
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: 'sitecheckfailed',
|
||||
errorDetails: CoreDomUtils.getErrorMessage(error) ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
if (data === null) {
|
||||
// Cannot connect.
|
||||
throw this.createCannotConnectLoginError(null, {
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
errorcode: 'appsitecheckfailed',
|
||||
errorDetails: 'A request to /login/token.php with appsitecheck=1 returned an empty response',
|
||||
});
|
||||
}
|
||||
|
||||
if (data.errorcode && (data.errorcode == 'enablewsdescription' || data.errorcode == 'requirecorrectaccess')) {
|
||||
throw this.createCannotConnectLoginError(siteUrl, {
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
critical: data.errorcode == 'enablewsdescription',
|
||||
errorcode: data.errorcode,
|
||||
errorDetails: data.error,
|
||||
});
|
||||
}
|
||||
|
||||
if (data.error && data.error == 'Web services must be enabled in Advanced features.') {
|
||||
throw this.createCannotConnectLoginError(siteUrl, {
|
||||
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
|
||||
critical: true,
|
||||
errorcode: 'enablewsdescription',
|
||||
errorDetails: data.error,
|
||||
});
|
||||
}
|
||||
|
||||
// Other errors are not being checked because invalid login will be always raised and we cannot differ them.
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a user token from the server.
|
||||
*
|
||||
|
@ -702,16 +645,6 @@ export class CoreSitesProvider {
|
|||
return <string> Md5.hashAsciiStr(siteUrl + username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for determine which service we should use (default or extended plugin).
|
||||
*
|
||||
* @returns The service shortname.
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
determineService(): string {
|
||||
return CoreConstants.CONFIG.wsservice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit a site link.
|
||||
*
|
||||
|
@ -2184,13 +2117,6 @@ export type CoreSiteCheckResponse = {
|
|||
*/
|
||||
service: string;
|
||||
|
||||
/**
|
||||
* Code of the warning message to show to the user.
|
||||
*
|
||||
* @deprecated since 4.0.
|
||||
*/
|
||||
warning?: string;
|
||||
|
||||
/**
|
||||
* Site public config (if available).
|
||||
*/
|
||||
|
|
|
@ -49,8 +49,6 @@ import { CoreSites } from '@services/sites';
|
|||
import { NavigationStart } from '@angular/router';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||
import { CoreUserSupport } from '@features/user/services/support';
|
||||
|
@ -99,20 +97,6 @@ export class CoreDomUtilsProvider {
|
|||
this.debugDisplay = debugDisplay != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to element.closest(). If the browser doesn't support element.closest, it will
|
||||
* traverse the parents to achieve the same functionality.
|
||||
* Returns the closest ancestor of the current element (or the current element itself) which matches the selector.
|
||||
*
|
||||
* @param element DOM Element.
|
||||
* @param selector Selector to search.
|
||||
* @returns Closest ancestor.
|
||||
* @deprecated since 4.0. Not needed anymore since it's supported on both Android and iOS. Use closest instead.
|
||||
*/
|
||||
closest(element: Element | undefined | null, selector: string): Element | null {
|
||||
return element?.closest(selector) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the download size is higher than a certain threshold shows a confirm dialog.
|
||||
*
|
||||
|
@ -396,91 +380,6 @@ export class CoreDomUtilsProvider {
|
|||
return this.convertToElement(html).children[0].getAttribute(attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns height of an element.
|
||||
*
|
||||
* @param element DOM element to measure.
|
||||
* @param usePadding Whether to use padding to calculate the measure.
|
||||
* @param useMargin Whether to use margin to calculate the measure.
|
||||
* @param useBorder Whether to use borders to calculate the measure.
|
||||
* @param innerMeasure If inner measure is needed: padding, margin or borders will be substracted.
|
||||
* @returns Height in pixels.
|
||||
* @deprecated since 4.0 Use getBoundingClientRect.height instead.
|
||||
*/
|
||||
getElementHeight(
|
||||
element: HTMLElement,
|
||||
usePadding?: boolean,
|
||||
useMargin?: boolean,
|
||||
useBorder?: boolean,
|
||||
innerMeasure?: boolean,
|
||||
): number {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return this.getElementMeasure(element, false, usePadding, useMargin, useBorder, innerMeasure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns height or width of an element.
|
||||
*
|
||||
* @param element DOM element to measure.
|
||||
* @param getWidth Whether to get width or height.
|
||||
* @param usePadding Whether to use padding to calculate the measure.
|
||||
* @param useMargin Whether to use margin to calculate the measure.
|
||||
* @param useBorder Whether to use borders to calculate the measure.
|
||||
* @param innerMeasure If inner measure is needed: padding, margin or borders will be substracted.
|
||||
* @returns Measure in pixels.
|
||||
* @deprecated since 4.0. Use getBoundingClientRect.height or width instead.
|
||||
*/
|
||||
getElementMeasure(
|
||||
element: HTMLElement,
|
||||
getWidth?: boolean,
|
||||
usePadding?: boolean,
|
||||
useMargin?: boolean,
|
||||
useBorder?: boolean,
|
||||
innerMeasure?: boolean,
|
||||
): number {
|
||||
const offsetMeasure = getWidth ? 'offsetWidth' : 'offsetHeight';
|
||||
const measureName = getWidth ? 'width' : 'height';
|
||||
const clientMeasure = getWidth ? 'clientWidth' : 'clientHeight';
|
||||
const priorSide = getWidth ? 'Left' : 'Top';
|
||||
const afterSide = getWidth ? 'Right' : 'Bottom';
|
||||
let measure = element[offsetMeasure] || element[measureName] || element[clientMeasure] || 0;
|
||||
|
||||
// Measure not correctly taken.
|
||||
if (measure <= 0) {
|
||||
const style = getComputedStyle(element);
|
||||
if (style?.display == '') {
|
||||
element.style.display = 'inline-block';
|
||||
measure = element[offsetMeasure] || element[measureName] || element[clientMeasure] || 0;
|
||||
element.style.display = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (usePadding || useMargin || useBorder) {
|
||||
const computedStyle = getComputedStyle(element);
|
||||
let surround = 0;
|
||||
|
||||
if (usePadding) {
|
||||
surround += this.getComputedStyleMeasure(computedStyle, 'padding' + priorSide) +
|
||||
this.getComputedStyleMeasure(computedStyle, 'padding' + afterSide);
|
||||
}
|
||||
if (useMargin) {
|
||||
surround += this.getComputedStyleMeasure(computedStyle, 'margin' + priorSide) +
|
||||
this.getComputedStyleMeasure(computedStyle, 'margin' + afterSide);
|
||||
}
|
||||
if (useBorder) {
|
||||
surround += this.getComputedStyleMeasure(computedStyle, 'border' + priorSide + 'Width') +
|
||||
this.getComputedStyleMeasure(computedStyle, 'border' + afterSide + 'Width');
|
||||
}
|
||||
if (innerMeasure) {
|
||||
measure = measure > surround ? measure - surround : 0;
|
||||
} else {
|
||||
measure += surround;
|
||||
}
|
||||
}
|
||||
|
||||
return measure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the computed style measure or 0 if not found or NaN.
|
||||
*
|
||||
|
@ -492,62 +391,6 @@ export class CoreDomUtilsProvider {
|
|||
return parseInt(style[measure], 10) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns width of an element.
|
||||
*
|
||||
* @param element DOM element to measure.
|
||||
* @param usePadding Whether to use padding to calculate the measure.
|
||||
* @param useMargin Whether to use margin to calculate the measure.
|
||||
* @param useBorder Whether to use borders to calculate the measure.
|
||||
* @param innerMeasure If inner measure is needed: padding, margin or borders will be substracted.
|
||||
* @returns Width in pixels.
|
||||
* @deprecated since 4.0. Use getBoundingClientRect.width instead.
|
||||
*/
|
||||
getElementWidth(
|
||||
element: HTMLElement,
|
||||
usePadding?: boolean,
|
||||
useMargin?: boolean,
|
||||
useBorder?: boolean,
|
||||
innerMeasure?: boolean,
|
||||
): number {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return this.getElementMeasure(element, true, usePadding, useMargin, useBorder, innerMeasure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the position of a element relative to another element.
|
||||
*
|
||||
* @param element Element to search in.
|
||||
* @param selector Selector to find the element to gets the position.
|
||||
* @param positionParentClass Parent Class where to stop calculating the position. Default inner-scroll.
|
||||
* @returns positionLeft, positionTop of the element relative to.
|
||||
* @deprecated since 4.0. Use CoreDom.getRelativeElementPosition instead.
|
||||
*/
|
||||
getElementXY(element: HTMLElement, selector?: string, positionParentClass = 'inner-scroll'): [number, number] | null {
|
||||
if (selector) {
|
||||
const foundElement = element.querySelector<HTMLElement>(selector);
|
||||
if (!foundElement) {
|
||||
// Element not found.
|
||||
return null;
|
||||
}
|
||||
|
||||
element = foundElement;
|
||||
}
|
||||
|
||||
const parent = element.closest<HTMLElement>(`.${positionParentClass}`);
|
||||
if (!parent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const position = CoreDom.getRelativeElementPosition(element, parent);
|
||||
|
||||
// Calculate the top and left positions.
|
||||
return [
|
||||
Math.ceil(position.x),
|
||||
Math.ceil(position.y),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a message, it deduce if it's a network error.
|
||||
*
|
||||
|
@ -639,19 +482,6 @@ export class CoreDomUtilsProvider {
|
|||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve component/directive instance.
|
||||
* Please use this function only if you cannot retrieve the instance using parent/child methods: ViewChild (or similar)
|
||||
* or Angular's injection.
|
||||
*
|
||||
* @param element The root element of the component/directive.
|
||||
* @returns The instance, undefined if not found.
|
||||
* @deprecated since 4.0. Use CoreDirectivesRegistry instead.
|
||||
*/
|
||||
getInstanceByElement<T = unknown>(element: Element): T | undefined {
|
||||
return CoreDirectivesRegistry.resolve<T>(element) ?? undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an error is an error caused because the user canceled a showConfirm.
|
||||
*
|
||||
|
@ -672,36 +502,6 @@ export class CoreDomUtilsProvider {
|
|||
return error instanceof CoreSilentError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait an element to exists using the findFunction.
|
||||
*
|
||||
* @param findFunction The function used to find the element.
|
||||
* @param retries Number of retries before giving up.
|
||||
* @param retryAfter Milliseconds to wait before retrying if the element wasn't found.
|
||||
* @returns Resolved if found, rejected if too many tries.
|
||||
* @deprecated since 4.0. Use CoreDom.waitToBeInsideElement instead.
|
||||
*/
|
||||
async waitElementToExist(
|
||||
findFunction: () => HTMLElement | null,
|
||||
retries: number = 100,
|
||||
retryAfter: number = 100,
|
||||
): Promise<HTMLElement> {
|
||||
const element = findFunction();
|
||||
|
||||
if (!element && retries === 0) {
|
||||
throw Error('Element not found');
|
||||
}
|
||||
|
||||
if (!element) {
|
||||
await CoreUtils.wait(retryAfter);
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return this.waitElementToExist(findFunction, retries - 1);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle bootstrap tooltips in a certain element.
|
||||
*
|
||||
|
@ -853,28 +653,6 @@ export class CoreDomUtilsProvider {
|
|||
return element.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a component/directive instance using the DOM Element.
|
||||
*
|
||||
* @param element The root element of the component/directive.
|
||||
* @deprecated since 4.0. It's no longer necessary to remove instances.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
removeInstanceByElement(element: Element): void {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a component/directive instance using the ID.
|
||||
*
|
||||
* @param id The ID to remove.
|
||||
* @deprecated since 4.0. It's no longer necessary to remove instances.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
removeInstanceById(id: string): void {
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for certain classes in an element contents and replace them with the specified new values.
|
||||
*
|
||||
|
@ -998,67 +776,6 @@ export class CoreDomUtilsProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to a certain element.
|
||||
*
|
||||
* @param content Not used anymore.
|
||||
* @param element The element to scroll to.
|
||||
* @param scrollParentClass Not used anymore.
|
||||
* @param duration Duration of the scroll animation in milliseconds.
|
||||
* @returns True if the element is found, false otherwise.
|
||||
* @deprecated since 4.0. Use CoreDom.scrollToElement instead.
|
||||
*/
|
||||
scrollToElement(content: IonContent, element: HTMLElement, scrollParentClass?: string, duration?: number): boolean {
|
||||
CoreDom.scrollToElement(element, undefined, { duration });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to a certain element using a selector to find it.
|
||||
*
|
||||
* @param container The element that contains the element that must be scrolled.
|
||||
* @param content Not used anymore.
|
||||
* @param selector Selector to find the element to scroll to.
|
||||
* @param scrollParentClass Not used anymore.
|
||||
* @param duration Duration of the scroll animation in milliseconds.
|
||||
* @returns True if the element is found, false otherwise.
|
||||
* @deprecated since 4.0. Use CoreDom.scrollToElement instead.
|
||||
*/
|
||||
scrollToElementBySelector(
|
||||
container: HTMLElement | null,
|
||||
content: unknown | null,
|
||||
selector: string,
|
||||
scrollParentClass?: string,
|
||||
duration?: number,
|
||||
): boolean {
|
||||
if (!container || !content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CoreDom.scrollToElement(container, selector, { duration });
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an input with error (core-input-error directive) and scrolls to it if found.
|
||||
*
|
||||
* @param container The element that contains the element that must be scrolled.
|
||||
* @returns True if the element is found, false otherwise.
|
||||
* @deprecated since 4.0. Use CoreDom.scrollToInputError instead.
|
||||
*/
|
||||
scrollToInputError(container: HTMLElement | null): boolean {
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CoreDom.scrollToInputError(container);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether debug messages should be displayed.
|
||||
*
|
||||
|
@ -1669,17 +1386,6 @@ export class CoreDomUtilsProvider {
|
|||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a component/directive instance.
|
||||
*
|
||||
* @param element The root element of the component/directive.
|
||||
* @param instance The instance to store.
|
||||
* @deprecated since 4.0. Use CoreDirectivesRegistry instead.
|
||||
*/
|
||||
storeInstanceByElement(element: Element, instance: unknown): void {
|
||||
CoreDirectivesRegistry.register(element, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an element supports input via keyboard.
|
||||
*
|
||||
|
|
|
@ -298,18 +298,6 @@ export class CoreTextUtilsProvider {
|
|||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two paths, adding a slash between them if needed.
|
||||
*
|
||||
* @param leftPath Left path.
|
||||
* @param rightPath Right path.
|
||||
* @returns Concatenated path.
|
||||
* @deprecated since 4.0. Use CorePath instead.
|
||||
*/
|
||||
concatenatePaths(leftPath: string, rightPath: string): string {
|
||||
return CorePath.concatenatePaths(leftPath, rightPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert some HTML as text into an HTMLElement. This HTML is put inside a div or a body.
|
||||
* This function is the same as in DomUtils, but we cannot use that one because of circular dependencies.
|
||||
|
|
|
@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import moment, { LongDateFormatKey } from 'moment-timezone';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
|
||||
/*
|
||||
* "Utils" service with helper functions for date and time.
|
||||
|
@ -155,52 +154,6 @@ export class CoreTimeUtilsProvider {
|
|||
return fixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns years, months, days, hours, minutes and seconds in a human readable format.
|
||||
*
|
||||
* @param seconds A number of seconds
|
||||
* @param precision Number of elements to have in precision.
|
||||
* @returns Seconds in a human readable format.
|
||||
* @deprecated since 4.0. Use CoreTime.formatTime instead.
|
||||
*/
|
||||
formatTime(seconds: number, precision = 2): string {
|
||||
return CoreTime.formatTime(seconds, precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a number of seconds into a short human readable format: minutes and seconds, in fromat: 3' 27''.
|
||||
*
|
||||
* @param duration Seconds
|
||||
* @returns Short human readable text.
|
||||
* @deprecated since 4.0. Use CoreTime.formatTimeShort instead.
|
||||
*/
|
||||
formatTimeShort(duration: number): string {
|
||||
return CoreTime.formatTimeShort(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hours, minutes and seconds in a human readable format.
|
||||
*
|
||||
* @param duration Duration in seconds
|
||||
* @param precision Number of elements to have in precision. 0 or undefined to full precission.
|
||||
* @returns Duration in a human readable format.
|
||||
* @deprecated since 4.0. Use CoreTime.formatTime instead.
|
||||
*/
|
||||
formatDuration(duration: number, precision?: number): string {
|
||||
return CoreTime.formatTime(duration, precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns duration in a short human readable format: minutes and seconds, in fromat: 3' 27''.
|
||||
*
|
||||
* @param duration Duration in seconds
|
||||
* @returns Duration in a short human readable format.
|
||||
* @deprecated since 4.0. Use CoreTime.formatTimeShort instead.
|
||||
*/
|
||||
formatDurationShort(duration: number): string {
|
||||
return CoreTime.formatTimeShort(duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current timestamp in a "readable" format: YYYYMMDDHHmmSS.
|
||||
*
|
||||
|
|
|
@ -39,8 +39,6 @@ export interface CoreEventsData {
|
|||
[CoreEvents.SITE_ADDED]: CoreEventSiteAddedData;
|
||||
[CoreEvents.SITE_DELETED]: CoreSite;
|
||||
[CoreEvents.SESSION_EXPIRED]: CoreEventSessionExpiredData;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
[CoreEvents.CORE_LOADING_CHANGED]: CoreEventLoadingChangedData;
|
||||
[CoreEvents.COURSE_STATUS_CHANGED]: CoreEventCourseStatusChanged;
|
||||
[CoreEvents.PACKAGE_STATUS_CHANGED]: CoreEventPackageStatusChanged;
|
||||
[CoreEvents.USER_DELETED]: CoreEventUserDeletedData;
|
||||
|
@ -104,10 +102,6 @@ export class CoreEvents {
|
|||
static readonly APP_LAUNCHED_URL = 'app_launched_url'; // App opened with a certain URL (custom URL scheme).
|
||||
static readonly FILE_SHARED = 'file_shared';
|
||||
static readonly KEYBOARD_CHANGE = 'keyboard_change';
|
||||
/**
|
||||
* @deprecated since 4.0. Use CoreDirectivesRegistry promises instead.
|
||||
*/
|
||||
static readonly CORE_LOADING_CHANGED = 'core_loading_changed';
|
||||
static readonly ORIENTATION_CHANGE = 'orientation_change';
|
||||
static readonly SEND_ON_ENTER_CHANGED = 'send_on_enter_changed';
|
||||
static readonly SELECT_COURSE_TAB = 'select_course_tab';
|
||||
|
|
Loading…
Reference in New Issue