MOBILE-3819 core: Remove code specific for Moodle 3.1-3.4
parent
d944cb1978
commit
68e57c0f17
|
@ -39,7 +39,7 @@ export class AddonBadgesProvider {
|
|||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.canUseAdvancedFeature('enablebadges') && site.wsAvailable('core_course_get_user_navigation_options');
|
||||
return site.canUseAdvancedFeature('enablebadges');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +194,7 @@ export type AddonBadgesUserBadge = {
|
|||
targetframework?: string; // Target framework.
|
||||
targetcode?: string; // Target code.
|
||||
}[];
|
||||
competencies?: { // @deprecated from 3.7. @since 3.6. In 3.7 it was renamed to alignment.
|
||||
competencies?: { // @deprecatedonmoodle from 3.7. @since 3.6. In 3.7 it was renamed to alignment.
|
||||
id?: number; // Alignment id.
|
||||
badgeid?: number; // Badge id.
|
||||
targetname?: string; // Target name.
|
||||
|
|
|
@ -16,10 +16,10 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
|
||||
import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-title-block/only-title-block';
|
||||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
|
||||
import { AddonCalendar } from '@/addons/calendar/services/calendar';
|
||||
import { CoreCourseBlock } from '@features/course/services/course';
|
||||
import { Params } from '@angular/router';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonCalendarMainMenuHandlerService } from '@addons/calendar/services/handlers/mainmenu';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
|
@ -45,7 +45,7 @@ export class AddonBlockCalendarMonthHandlerService extends CoreBlockBaseHandler
|
|||
title: 'addon.block_calendarmonth.pluginname',
|
||||
class: 'addon-block-calendar-month',
|
||||
component: CoreBlockOnlyTitleComponent,
|
||||
link: AddonCalendar.getMainCalendarPagePath(),
|
||||
link: AddonCalendarMainMenuHandlerService.PAGE_NAME,
|
||||
linkParams: linkParams,
|
||||
navOptions: {
|
||||
preferCurrentTab: false,
|
||||
|
|
|
@ -16,10 +16,10 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
|
||||
import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-title-block/only-title-block';
|
||||
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
|
||||
import { AddonCalendar } from '@/addons/calendar/services/calendar';
|
||||
import { CoreCourseBlock } from '@features/course/services/course';
|
||||
import { Params } from '@angular/router';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonCalendarMainMenuHandlerService } from '@addons/calendar/services/handlers/mainmenu';
|
||||
|
||||
/**
|
||||
* Block handler.
|
||||
|
@ -46,7 +46,7 @@ export class AddonBlockCalendarUpcomingHandlerService extends CoreBlockBaseHandl
|
|||
title: 'addon.block_calendarupcoming.pluginname',
|
||||
class: 'addon-block-calendar-upcoming',
|
||||
component: CoreBlockOnlyTitleComponent,
|
||||
link: AddonCalendar.getMainCalendarPagePath(),
|
||||
link: AddonCalendarMainMenuHandlerService.PAGE_NAME,
|
||||
linkParams: linkParams,
|
||||
navOptions: {
|
||||
preferCurrentTab: false,
|
||||
|
|
|
@ -248,13 +248,8 @@ export class AddonBlockTimelineProvider {
|
|||
async isAvailable(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
// First check if dashboard is disabled.
|
||||
if (CoreCoursesDashboard.isDisabledInSite(site)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return site.wsAvailable('core_calendar_get_action_events_by_courses') &&
|
||||
site.wsAvailable('core_calendar_get_action_events_by_timesort');
|
||||
// Check if dashboard is disabled.
|
||||
return !CoreCoursesDashboard.isDisabledInSite(site);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,11 +40,12 @@ export class AddonBlogProvider {
|
|||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if enabled, resolved with false or rejected otherwise.
|
||||
* @since 3.6
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('core_blog_get_entries') &&site.canUseAdvancedFeature('enableblogs');
|
||||
return site.wsAvailable('core_blog_get_entries') && site.canUseAdvancedFeature('enableblogs');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,13 +38,6 @@ function buildRoutes(injector: Injector): Routes {
|
|||
},
|
||||
loadChildren: () => import('@/addons/calendar/pages/index/index.module').then(m => m.AddonCalendarIndexPageModule),
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
data: {
|
||||
mainMenuTabRoot: AddonCalendarMainMenuHandlerService.PAGE_NAME,
|
||||
},
|
||||
loadChildren: () => import('@/addons/calendar/pages/list/list.module').then(m => m.AddonCalendarListPageModule),
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
loadChildren: () =>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<core-context-menu-item [hidden]="!canEdit || !event || !event.canedit || event.deleted" [priority]="300"
|
||||
[content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!canDelete || !event || !event.candelete || event.deleted" [priority]="200"
|
||||
<core-context-menu-item [hidden]="!event || !event.candelete || event.deleted" [priority]="200"
|
||||
[content]="'core.delete' | translate" (action)="deleteEvent()"
|
||||
iconAction="fas-trash"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!event || !event.deleted" [priority]="200" [content]="'core.restore' | translate"
|
||||
|
|
|
@ -17,16 +17,12 @@ import { IonRefresher } from '@ionic/angular';
|
|||
import { AlertOptions } from '@ionic/core';
|
||||
import {
|
||||
AddonCalendar,
|
||||
AddonCalendarEvent,
|
||||
AddonCalendarEventBase,
|
||||
AddonCalendarEventToDisplay,
|
||||
AddonCalendarGetEventsEvent,
|
||||
AddonCalendarProvider,
|
||||
} from '../../services/calendar';
|
||||
import { AddonCalendarHelper } from '../../services/calendar-helper';
|
||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||
import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync';
|
||||
import { CoreCourses } from '@features/courses/services/courses';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
|
@ -82,7 +78,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
defaultTime = 0;
|
||||
reminders: AddonCalendarReminderDBRecord[] = [];
|
||||
canEdit = false;
|
||||
canDelete = false;
|
||||
hasOffline = false;
|
||||
isOnline = false;
|
||||
syncIcon = CoreConstants.ICON_LOADING; // Sync icon.
|
||||
|
@ -99,9 +94,8 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||
this.isSplitViewOn = this.svComponent?.outletActivated;
|
||||
|
||||
// Check if site supports editing and deleting. No need to check allowed types, event.canedit already does it.
|
||||
// Check if site supports editing. No need to check allowed types, event.canedit already does it.
|
||||
this.canEdit = AddonCalendar.canEditEventsInSite();
|
||||
this.canDelete = AddonCalendar.canDeleteEventsInSite();
|
||||
|
||||
// Listen for event edited. If current event is edited, reload the data.
|
||||
this.editEventObserver = CoreEvents.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
|
||||
|
@ -168,8 +162,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
async fetchEvent(sync = false, showErrors = false): Promise<void> {
|
||||
const currentSite = CoreSites.getCurrentSite();
|
||||
const canGetById = AddonCalendar.isGetEventByIdAvailableInSite();
|
||||
let deleted = false;
|
||||
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
|
@ -209,13 +201,8 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
try {
|
||||
let event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent;
|
||||
// Get the event data.
|
||||
if (canGetById) {
|
||||
event = await AddonCalendar.getEventById(this.eventId);
|
||||
} else {
|
||||
event = await AddonCalendar.getEvent(this.eventId);
|
||||
}
|
||||
const event = await AddonCalendar.getEventById(this.eventId);
|
||||
this.event = AddonCalendarHelper.formatEventData(event);
|
||||
|
||||
try {
|
||||
|
@ -254,9 +241,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Get the module URL.
|
||||
if (canGetById) {
|
||||
this.moduleUrl = this.event!.url || '';
|
||||
}
|
||||
this.moduleUrl = this.event!.url || '';
|
||||
}
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
@ -264,24 +249,10 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
const courseId = this.event.courseid;
|
||||
if (courseId != this.siteHomeId) {
|
||||
// If the event belongs to a course, get the course name and the URL to view it.
|
||||
if (canGetById && this.event.course) {
|
||||
if (this.event.course) {
|
||||
this.courseId = this.event.course.id;
|
||||
this.courseName = this.event.course.fullname;
|
||||
this.courseUrl = this.event.course.viewurl;
|
||||
} else if (!canGetById && this.event.courseid ) {
|
||||
// Retrieve the course.
|
||||
promises.push(CoreCourses.getUserCourse(this.event.courseid, true).then((course) => {
|
||||
this.courseId = course.id;
|
||||
this.courseName = course.fullname;
|
||||
this.courseUrl = currentSite ? CoreTextUtils.concatenatePaths(
|
||||
currentSite.siteUrl,
|
||||
'/course/view.php?id=' + this.courseId,
|
||||
) : '';
|
||||
|
||||
return;
|
||||
}).catch(() => {
|
||||
// Error getting course, just don't show the course name.
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,7 +270,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
|
|||
}));
|
||||
}
|
||||
|
||||
if (canGetById && this.event.iscategoryevent && this.event.category) {
|
||||
if (this.event.iscategoryevent && this.event.category) {
|
||||
this.categoryPath = this.event.category.nestedname;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<h1>{{ 'addon.calendar.calendarevents' | translate }}</h1>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button fill="clear" (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
|
||||
<ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600"
|
||||
[content]="'core.settings.settings' | translate" (action)="openSettings()" iconAction="fas-cogs">
|
||||
</core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!eventsLoaded || !hasOffline || !isOnline" [priority]="400"
|
||||
[content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)"
|
||||
[iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed" [disabled]="!eventsLoaded" (ionRefresh)="doRefresh($event.target)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="eventsLoaded">
|
||||
<!-- There is data to be synchronized -->
|
||||
<ion-card class="core-warning-card" *ngIf="hasOffline">
|
||||
<ion-item>
|
||||
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
|
||||
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
|
||||
<core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar"
|
||||
[message]="'addon.calendar.noevents' | translate">
|
||||
</core-empty-box>
|
||||
|
||||
<ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin">
|
||||
<ng-container *ngFor="let event of filteredEvents">
|
||||
<ion-item-divider *ngIf="event.showDate">
|
||||
<ion-label><p class="item-heading">{{ event.timestart * 1000 | coreFormatDate: "strftimedayshort" }}</p></ion-label>
|
||||
</ion-item-divider>
|
||||
<ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)"
|
||||
[attr.aria-current]="event.id == eventId ? 'page' : 'false'"
|
||||
[ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button detail="true">
|
||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt=""
|
||||
role="presentation">
|
||||
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"
|
||||
aria-hidden="true">
|
||||
</ion-icon>
|
||||
<ion-label>
|
||||
<p class="item-heading">
|
||||
<!-- Add the icon title so accessibility tools read it. -->
|
||||
<span class="sr-only">
|
||||
{{ 'addon.calendar.type' + event.formattedType | translate }}
|
||||
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
|
||||
</span>
|
||||
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
|
||||
[contextInstanceId]="event.contextInstanceId">
|
||||
</core-format-text>
|
||||
</p>
|
||||
<p>
|
||||
{{ event.timestart * 1000 | coreFormatDate: "strftimetime" }}
|
||||
<span *ngIf="event.timeduration && event.endsSameDay">
|
||||
- {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimetime" }}
|
||||
</span>
|
||||
<span *ngIf="event.timeduration && !event.endsSameDay">
|
||||
- {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimedatetimeshort" }}
|
||||
</span>
|
||||
</p>
|
||||
</ion-label>
|
||||
<ion-note *ngIf="event.offline && !event.deleted" slot="end">
|
||||
<ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
|
||||
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
|
||||
</ion-note>
|
||||
<ion-note *ngIf="event.deleted" slot="end">
|
||||
<ion-icon name="fas-trash" aria-hidden="true"></ion-icon>
|
||||
<span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span>
|
||||
</ion-note>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
|
||||
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreEvents($event)" [error]="loadMoreError">
|
||||
</core-infinite-loading>
|
||||
</core-loading>
|
||||
|
||||
<!-- Create a calendar event. -->
|
||||
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate">
|
||||
<ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
|
||||
<ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
|
||||
<span class="sr-only">{{ 'addon.calendar.newevent' | translate }}</span>
|
||||
</ion-fab-button>
|
||||
</ion-fab>
|
||||
</ion-content>
|
|
@ -1,60 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { AddonCalendarEventRoute, AddonCalendarEditRoute } from '@addons/calendar/calendar-lazy.module';
|
||||
import { conditionalRoutes } from '@/app/app-routing.module';
|
||||
import { CoreScreen } from '@services/screen';
|
||||
|
||||
import { CoreSharedModule } from '@/core/shared.module';
|
||||
|
||||
import { AddonCalendarListPage } from './list.page';
|
||||
|
||||
const splitviewRoutes = [AddonCalendarEditRoute, AddonCalendarEventRoute];
|
||||
|
||||
const mobileRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AddonCalendarListPage,
|
||||
},
|
||||
...splitviewRoutes,
|
||||
];
|
||||
|
||||
const tabletRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AddonCalendarListPage,
|
||||
children: [
|
||||
...splitviewRoutes,
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const routes: Routes = [
|
||||
...conditionalRoutes(mobileRoutes, () => CoreScreen.isMobile),
|
||||
...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet),
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CoreSharedModule,
|
||||
],
|
||||
declarations: [
|
||||
AddonCalendarListPage,
|
||||
],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class AddonCalendarListPageModule {}
|
|
@ -1,643 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild, OnDestroy, OnInit } from '@angular/core';
|
||||
import { IonContent, IonRefresher } from '@ionic/angular';
|
||||
import {
|
||||
AddonCalendarProvider,
|
||||
AddonCalendar,
|
||||
AddonCalendarEventToDisplay,
|
||||
} from '../../services/calendar';
|
||||
import { AddonCalendarOffline } from '../../services/calendar-offline';
|
||||
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
|
||||
import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync';
|
||||
import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreLocalNotifications } from '@services/local-notifications';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreApp } from '@services/app';
|
||||
import moment from 'moment';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
|
||||
import { Params } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { Network, NgZone } from '@singletons';
|
||||
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
||||
/**
|
||||
* Page that displays the list of calendar events.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'page-addon-calendar-list',
|
||||
templateUrl: 'list.html',
|
||||
styleUrls: ['../../calendar-common.scss', 'list.scss'],
|
||||
})
|
||||
export class AddonCalendarListPage implements OnInit, OnDestroy {
|
||||
|
||||
@ViewChild(IonContent) content?: IonContent;
|
||||
|
||||
protected initialTime = 0;
|
||||
protected daysLoaded = 0;
|
||||
protected emptyEventsTimes = 0; // Variable to identify consecutive calls returning 0 events.
|
||||
protected categoriesRetrieved = false;
|
||||
protected getCategories = false;
|
||||
protected categories: { [id: number]: CoreCategoryData } = {};
|
||||
protected siteHomeId: number;
|
||||
protected currentSiteId: string;
|
||||
protected onlineEvents: AddonCalendarEventToDisplay[] = [];
|
||||
protected offlineEvents: AddonCalendarEventToDisplay[] = [];
|
||||
protected deletedEvents: number [] = [];
|
||||
|
||||
// Observers.
|
||||
protected obsDefaultTimeChange?: CoreEventObserver;
|
||||
protected newEventObserver: CoreEventObserver;
|
||||
protected discardedObserver: CoreEventObserver;
|
||||
protected editEventObserver: CoreEventObserver;
|
||||
protected deleteEventObserver: CoreEventObserver;
|
||||
protected undeleteEventObserver: CoreEventObserver;
|
||||
protected syncObserver: CoreEventObserver;
|
||||
protected manualSyncObserver: CoreEventObserver;
|
||||
protected filterChangedObserver: CoreEventObserver;
|
||||
protected onlineObserver: Subscription;
|
||||
|
||||
eventId?: number; // Selected EventId on list
|
||||
courses: Partial<CoreEnrolledCourseData>[] = [];
|
||||
eventsLoaded = false;
|
||||
events: AddonCalendarEventToDisplay[] = []; // Events (both online and offline).
|
||||
notificationsEnabled = false;
|
||||
filteredEvents: AddonCalendarEventToDisplay[] = [];
|
||||
canLoadMore = false;
|
||||
loadMoreError = false;
|
||||
canCreate = false;
|
||||
hasOffline = false;
|
||||
isOnline = false;
|
||||
syncIcon = CoreConstants.ICON_LOADING;
|
||||
filter: AddonCalendarFilter = {
|
||||
filtered: false,
|
||||
courseId: undefined,
|
||||
categoryId: undefined,
|
||||
course: true,
|
||||
group: true,
|
||||
site: true,
|
||||
user: true,
|
||||
category: true,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
|
||||
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
|
||||
this.notificationsEnabled = CoreLocalNotifications.isAvailable();
|
||||
this.currentSiteId = CoreSites.getCurrentSiteId();
|
||||
|
||||
if (this.notificationsEnabled) {
|
||||
// Re-schedule events if default time changes.
|
||||
this.obsDefaultTimeChange = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
|
||||
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
|
||||
}, this.currentSiteId);
|
||||
}
|
||||
|
||||
// Listen for events added. When an event is added, reload the data.
|
||||
this.newEventObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
|
||||
if (data && data.eventId) {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents(true, false);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Listen for new event discarded event. When it does, reload the data.
|
||||
this.discardedObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents(true, false);
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Listen for events edited. When an event is edited, reload the data.
|
||||
this.editEventObserver = CoreEvents.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
|
||||
if (data && data.eventId) {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents(true, false);
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh data if calendar events are synchronized automatically.
|
||||
this.syncObserver = CoreEvents.on(AddonCalendarSyncProvider.AUTO_SYNCED, () => {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents();
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Refresh data if calendar events are synchronized manually but not by this page.
|
||||
this.manualSyncObserver = CoreEvents.on(AddonCalendarSyncProvider.MANUAL_SYNCED, (data) => {
|
||||
if (data && data.source != 'list') {
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents();
|
||||
}
|
||||
}, this.currentSiteId);
|
||||
|
||||
// Update the list when an event is deleted.
|
||||
this.deleteEventObserver = CoreEvents.on(
|
||||
AddonCalendarProvider.DELETED_EVENT_EVENT,
|
||||
(data) => {
|
||||
if (data && !data.sent) {
|
||||
// Event was deleted in offline. Just mark it as deleted, no need to refresh.
|
||||
this.markAsDeleted(data.eventId, true);
|
||||
this.deletedEvents.push(data.eventId);
|
||||
this.hasOffline = true;
|
||||
} else {
|
||||
// Event deleted, refresh the view.
|
||||
this.eventsLoaded = false;
|
||||
this.refreshEvents();
|
||||
}
|
||||
},
|
||||
this.currentSiteId,
|
||||
);
|
||||
|
||||
// Listen for events "undeleted" (offline).
|
||||
this.undeleteEventObserver = CoreEvents.on(
|
||||
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
|
||||
(data) => {
|
||||
if (!data || !data.eventId) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark it as undeleted, no need to refresh.
|
||||
this.markAsDeleted(data.eventId, false);
|
||||
|
||||
// Remove it from the list of deleted events if it's there.
|
||||
const index = this.deletedEvents.indexOf(data.eventId);
|
||||
if (index != -1) {
|
||||
this.deletedEvents.splice(index, 1);
|
||||
}
|
||||
|
||||
this.hasOffline = !!this.offlineEvents.length || !!this.deletedEvents.length;
|
||||
},
|
||||
this.currentSiteId,
|
||||
);
|
||||
|
||||
this.filterChangedObserver =
|
||||
CoreEvents.on(AddonCalendarProvider.FILTER_CHANGED_EVENT, async (data) => {
|
||||
this.filter = data;
|
||||
|
||||
// Course viewed has changed, check if the user can create events for this course calendar.
|
||||
this.canCreate = await AddonCalendarHelper.canEditEvents(this.filter.courseId);
|
||||
|
||||
this.filterEvents();
|
||||
|
||||
this.content?.scrollToTop();
|
||||
});
|
||||
|
||||
// Refresh online status when changes.
|
||||
this.onlineObserver = Network.onChange().subscribe(() => {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
NgZone.run(() => {
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* View loaded.
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.filter.courseId = CoreNavigator.getRouteNumberParam('courseId');
|
||||
this.syncIcon = CoreConstants.ICON_LOADING;
|
||||
|
||||
await this.fetchData(false, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all the data required for the view.
|
||||
*
|
||||
* @param refresh Empty events array first.
|
||||
* @param sync Whether it should try to synchronize offline events.
|
||||
* @param showErrors Whether to show sync errors to the user.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async fetchData(refresh = false, sync = false, showErrors = false): Promise<void> {
|
||||
this.initialTime = CoreTimeUtils.timestamp();
|
||||
this.daysLoaded = 0;
|
||||
this.emptyEventsTimes = 0;
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
|
||||
if (sync) {
|
||||
// Try to synchronize offline events.
|
||||
try {
|
||||
const result = await AddonCalendarSync.syncEvents();
|
||||
if (result.warnings && result.warnings.length) {
|
||||
CoreDomUtils.showErrorModal(result.warnings[0]);
|
||||
}
|
||||
|
||||
if (result.updated) {
|
||||
// Trigger a manual sync event.
|
||||
result.source = 'list';
|
||||
|
||||
CoreEvents.trigger(
|
||||
AddonCalendarSyncProvider.MANUAL_SYNCED,
|
||||
result,
|
||||
this.currentSiteId,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
if (showErrors) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
this.hasOffline = false;
|
||||
|
||||
promises.push(AddonCalendarHelper.canEditEvents(this.filter.courseId).then((canEdit) => {
|
||||
this.canCreate = canEdit;
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
// Load courses for the popover.
|
||||
promises.push(CoreCoursesHelper.getCoursesForPopover(this.filter.courseId).then((result) => {
|
||||
this.courses = result.courses;
|
||||
|
||||
return this.fetchEvents(refresh);
|
||||
}));
|
||||
|
||||
// Get offline events.
|
||||
promises.push(AddonCalendarOffline.getAllEditedEvents().then((offlineEvents) => {
|
||||
this.hasOffline = this.hasOffline || !!offlineEvents.length;
|
||||
|
||||
// Format data and sort by timestart.
|
||||
const events: AddonCalendarEventToDisplay[] = offlineEvents.map((event) =>
|
||||
AddonCalendarHelper.formatOfflineEventData(event));
|
||||
|
||||
this.offlineEvents = AddonCalendarHelper.sortEvents(events);
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
// Get events deleted in offline.
|
||||
promises.push(AddonCalendarOffline.getAllDeletedEventsIds().then((ids) => {
|
||||
this.hasOffline = this.hasOffline || !!ids.length;
|
||||
this.deletedEvents = ids;
|
||||
|
||||
return;
|
||||
}));
|
||||
|
||||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
|
||||
}
|
||||
|
||||
this.eventsLoaded = true;
|
||||
this.syncIcon = CoreConstants.ICON_SYNC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the events and updates the view.
|
||||
*
|
||||
* @param refresh Empty events array first.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async fetchEvents(refresh = false): Promise<void> {
|
||||
this.loadMoreError = false;
|
||||
|
||||
try {
|
||||
const onlineEventsTemp =
|
||||
await AddonCalendar.getEventsList(this.initialTime, this.daysLoaded, AddonCalendarProvider.DAYS_INTERVAL);
|
||||
|
||||
if (onlineEventsTemp.length === 0) {
|
||||
this.emptyEventsTimes++;
|
||||
if (this.emptyEventsTimes > 5) { // Stop execution if we retrieve empty list 6 consecutive times.
|
||||
this.canLoadMore = false;
|
||||
if (refresh) {
|
||||
this.onlineEvents = [];
|
||||
this.filteredEvents = [];
|
||||
this.events = this.offlineEvents;
|
||||
}
|
||||
} else {
|
||||
// No events returned, load next events.
|
||||
this.daysLoaded += AddonCalendarProvider.DAYS_INTERVAL;
|
||||
|
||||
return this.fetchEvents();
|
||||
}
|
||||
} else {
|
||||
const onlineEvents = onlineEventsTemp.map((event) => AddonCalendarHelper.formatEventData(event));
|
||||
|
||||
// Get the merged events of this period.
|
||||
const events = this.mergeEvents(onlineEvents);
|
||||
|
||||
this.getCategories = this.shouldLoadCategories(onlineEvents);
|
||||
|
||||
if (refresh) {
|
||||
this.onlineEvents = onlineEvents;
|
||||
this.events = events;
|
||||
} else {
|
||||
// Filter events with same ID. Repeated events are returned once per WS call, show them only once.
|
||||
this.onlineEvents = CoreUtils.mergeArraysWithoutDuplicates(this.onlineEvents, onlineEvents, 'id');
|
||||
this.events = CoreUtils.mergeArraysWithoutDuplicates(this.events, events, 'id');
|
||||
}
|
||||
this.filterEvents();
|
||||
|
||||
// Calculate which evemts need to display the date.
|
||||
this.filteredEvents.forEach((event, index) => {
|
||||
event.showDate = this.showDate(event, this.filteredEvents[index - 1]);
|
||||
event.endsSameDay = this.endsSameDay(event);
|
||||
});
|
||||
this.canLoadMore = true;
|
||||
|
||||
// Schedule notifications for the events retrieved (might have new events).
|
||||
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
|
||||
|
||||
this.daysLoaded += AddonCalendarProvider.DAYS_INTERVAL;
|
||||
}
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
|
||||
this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
|
||||
}
|
||||
|
||||
// Success retrieving events. Get categories if needed.
|
||||
if (this.getCategories) {
|
||||
this.getCategories = false;
|
||||
|
||||
return this.loadCategories();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to load more events.
|
||||
*
|
||||
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
loadMoreEvents(infiniteComplete?: () => void ): void {
|
||||
this.fetchEvents().finally(() => {
|
||||
infiniteComplete && infiniteComplete();
|
||||
});
|
||||
}
|
||||
|
||||
protected filterEvents(): void {
|
||||
this.filteredEvents = AddonCalendarHelper.getFilteredEvents(this.events, this.filter, this.categories);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the current state should load categories or not.
|
||||
*
|
||||
* @param events Events to parse.
|
||||
* @return True if categories should be loaded.
|
||||
*/
|
||||
protected shouldLoadCategories(events: AddonCalendarEventToDisplay[]): boolean {
|
||||
if (this.categoriesRetrieved || this.getCategories) {
|
||||
// Use previous value
|
||||
return this.getCategories;
|
||||
}
|
||||
|
||||
// Categories not loaded yet. We should get them if there's any category event.
|
||||
const found = events.some((event) => typeof event.categoryid != 'undefined' && event.categoryid > 0);
|
||||
|
||||
return found || this.getCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load categories to be able to filter events.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async loadCategories(): Promise<void> {
|
||||
try {
|
||||
const cats = await CoreCourses.getCategories(0, true);
|
||||
this.categoriesRetrieved = true;
|
||||
this.categories = {};
|
||||
// Index categories by ID.
|
||||
cats.forEach((category) => {
|
||||
this.categories[category.id] = category;
|
||||
});
|
||||
} catch {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge a period of online events with the offline events of that period.
|
||||
*
|
||||
* @param onlineEvents Online events.
|
||||
* @return Merged events.
|
||||
*/
|
||||
protected mergeEvents(onlineEvents: AddonCalendarEventToDisplay[]): AddonCalendarEventToDisplay[] {
|
||||
if (!this.offlineEvents.length && !this.deletedEvents.length) {
|
||||
// No offline events, nothing to merge.
|
||||
return onlineEvents;
|
||||
}
|
||||
|
||||
const start = this.initialTime + (CoreConstants.SECONDS_DAY * this.daysLoaded);
|
||||
const end = start + (CoreConstants.SECONDS_DAY * AddonCalendarProvider.DAYS_INTERVAL) - 1;
|
||||
let result = onlineEvents;
|
||||
|
||||
if (this.deletedEvents.length) {
|
||||
// Mark as deleted the events that were deleted in offline.
|
||||
result.forEach((event) => {
|
||||
event.deleted = this.deletedEvents.indexOf(event.id) != -1;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.offlineEvents.length) {
|
||||
// Remove the online events that were modified in offline.
|
||||
result = result.filter((event) => {
|
||||
const offlineEvent = this.offlineEvents.find((ev) => ev.id == event.id);
|
||||
|
||||
return !offlineEvent;
|
||||
});
|
||||
}
|
||||
|
||||
// Now get the offline events that belong to this period.
|
||||
const periodOfflineEvents = this.offlineEvents.filter((event) => {
|
||||
if (this.daysLoaded == 0 && event.timestart < start) {
|
||||
// Display offline events that are previous to current time to allow editing them.
|
||||
return true;
|
||||
}
|
||||
|
||||
return (event.timestart >= start || event.timestart + event.timeduration >= start) && event.timestart <= end;
|
||||
});
|
||||
|
||||
// Merge both arrays and sort them.
|
||||
result = result.concat(periodOfflineEvents);
|
||||
|
||||
return AddonCalendarHelper.sortEvents(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the data.
|
||||
*
|
||||
* @param refresher Refresher.
|
||||
* @param done Function to call when done.
|
||||
* @param showErrors Whether to show sync errors to the user.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async doRefresh(refresher?: IonRefresher, done?: () => void, showErrors?: boolean): Promise<void> {
|
||||
if (!this.eventsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.refreshEvents(true, showErrors).finally(() => {
|
||||
refresher?.complete();
|
||||
done && done();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the events.
|
||||
*
|
||||
* @param sync Whether it should try to synchronize offline events.
|
||||
* @param showErrors Whether to show sync errors to the user.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async refreshEvents(sync?: boolean, showErrors?: boolean): Promise<void> {
|
||||
this.syncIcon = CoreConstants.ICON_LOADING;
|
||||
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
promises.push(AddonCalendar.invalidateEventsList());
|
||||
promises.push(AddonCalendar.invalidateAllowedEventTypes());
|
||||
|
||||
if (this.categoriesRetrieved) {
|
||||
promises.push(CoreCourses.invalidateCategories(0, true));
|
||||
this.categoriesRetrieved = false;
|
||||
}
|
||||
|
||||
await Promise.all(promises).finally(() => this.fetchData(true, sync, showErrors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check date should be shown on event list for the current event.
|
||||
* If date has changed from previous to current event it should be shown.
|
||||
*
|
||||
* @param event Current event where to show the date.
|
||||
* @param prevEvent Previous event where to compare the date with.
|
||||
* @return If date has changed and should be shown.
|
||||
*/
|
||||
protected showDate(event: AddonCalendarEventToDisplay, prevEvent?: AddonCalendarEventToDisplay): boolean {
|
||||
if (!prevEvent) {
|
||||
// First event, show it.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if day has changed.
|
||||
return !moment(event.timestart * 1000).isSame(prevEvent.timestart * 1000, 'day');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event ends the same date or not.
|
||||
*
|
||||
* @param event Event info.
|
||||
* @return If date has changed and should be shown.
|
||||
*/
|
||||
protected endsSameDay(event: AddonCalendarEventToDisplay): boolean {
|
||||
if (!event.timeduration) {
|
||||
// No duration.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if day has changed.
|
||||
return moment(event.timestart * 1000).isSame((event.timestart + event.timeduration) * 1000, 'day');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the context menu.
|
||||
*
|
||||
* @param event Event.
|
||||
*/
|
||||
async openFilter(event: MouseEvent): Promise<void> {
|
||||
await CoreDomUtils.openPopover({
|
||||
component: AddonCalendarFilterPopoverComponent,
|
||||
componentProps: {
|
||||
courses: this.courses,
|
||||
filter: this.filter,
|
||||
},
|
||||
event,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Open page to create/edit an event.
|
||||
*
|
||||
* @param eventId Event ID to edit.
|
||||
*/
|
||||
openEdit(eventId?: number): void {
|
||||
this.eventId = undefined;
|
||||
eventId = eventId || 0;
|
||||
|
||||
const params: Params = {};
|
||||
|
||||
if (this.filter.courseId) {
|
||||
params.courseId = this.filter.courseId;
|
||||
}
|
||||
|
||||
CoreNavigator.navigateToSitePath(`calendar/edit/${eventId}`, { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* Open calendar events settings.
|
||||
*/
|
||||
openSettings(): void {
|
||||
CoreNavigator.navigateToSitePath('/calendar/settings');
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a particular event.
|
||||
*
|
||||
* @param eventId Event to load.
|
||||
*/
|
||||
gotoEvent(eventId: number): void {
|
||||
this.eventId = eventId;
|
||||
|
||||
if (eventId <= 0) {
|
||||
// It's an offline event, go to the edit page.
|
||||
this.openEdit(eventId);
|
||||
} else {
|
||||
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an event and mark it as deleted.
|
||||
*
|
||||
* @param eventId Event ID.
|
||||
* @param deleted Whether to mark it as deleted or not.
|
||||
*/
|
||||
protected markAsDeleted(eventId: number, deleted: boolean): void {
|
||||
const event = this.onlineEvents.find((event) => event.id == eventId);
|
||||
|
||||
if (event) {
|
||||
event.deleted = deleted;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.obsDefaultTimeChange?.off();
|
||||
this.newEventObserver?.off();
|
||||
this.discardedObserver?.off();
|
||||
this.editEventObserver?.off();
|
||||
this.deleteEventObserver?.off();
|
||||
this.undeleteEventObserver?.off();
|
||||
this.syncObserver?.off();
|
||||
this.manualSyncObserver?.off();
|
||||
this.filterChangedObserver?.off();
|
||||
this.onlineObserver?.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
:host {
|
||||
ion-note {
|
||||
max-width: 30%;
|
||||
}
|
||||
}
|
|
@ -125,36 +125,6 @@ export class AddonCalendarProvider {
|
|||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Check if a certain site allows deleting events.
|
||||
*
|
||||
* @param siteId Site Id. If not defined, use current site.
|
||||
* @return Promise resolved with true if can delete.
|
||||
* @since 3.3
|
||||
*/
|
||||
async canDeleteEvents(siteId?: string): Promise<boolean> {
|
||||
try {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return this.canDeleteEventsInSite(site);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain site allows deleting events.
|
||||
*
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @return Whether events can be deleted.
|
||||
* @since 3.3
|
||||
*/
|
||||
canDeleteEventsInSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!site?.wsAvailable('core_calendar_delete_calendar_events');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain site allows creating and editing events.
|
||||
*
|
||||
|
@ -186,67 +156,6 @@ export class AddonCalendarProvider {
|
|||
return !!site?.isVersionGreaterEqualThan('3.7.1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain site allows viewing events in monthly view.
|
||||
*
|
||||
* @param siteId Site Id. If not defined, use current site.
|
||||
* @return Promise resolved with true if monthly view is supported.
|
||||
* @since 3.4
|
||||
*/
|
||||
async canViewMonth(siteId?: string): Promise<boolean> {
|
||||
try {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return this.canViewMonthInSite(site);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a certain site allows viewing events in monthly view.
|
||||
*
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @return Whether monthly view is supported.
|
||||
* @since 3.4
|
||||
*/
|
||||
canViewMonthInSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!site?.wsAvailable('core_calendar_get_calendar_monthly_view');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the site main calendar page path.
|
||||
*
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @return Main calendar page path of the site.
|
||||
*/
|
||||
getMainCalendarPagePath(site?: CoreSite): string {
|
||||
return AddonCalendarMainMenuHandlerService.PAGE_NAME + (this.canViewMonthInSite(site) ? '' : '/list');
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired events from local DB.
|
||||
*
|
||||
* @param siteId ID of the site the event belongs to. If not defined, use current site.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async cleanExpiredEvents(siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
if (this.canViewMonthInSite(site)) {
|
||||
// Site supports monthly view, don't clean expired events because user can see past events.
|
||||
return;
|
||||
}
|
||||
const events = await site.getDb().getRecordsSelect<AddonCalendarEventDBRecord>(
|
||||
EVENTS_TABLE,
|
||||
'timestart + timeduration < ?',
|
||||
[CoreTimeUtils.timestamp()],
|
||||
);
|
||||
|
||||
await Promise.all(events.map((event) => this.deleteLocalEvent(event.id!, siteId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an event.
|
||||
*
|
||||
|
@ -367,12 +276,8 @@ export class AddonCalendarProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
// Check which page we should load.
|
||||
const site = await CoreSites.getSite(notification.siteId);
|
||||
const pageName = this.getMainCalendarPagePath(site);
|
||||
|
||||
CoreNavigator.navigateToSitePath(
|
||||
pageName,
|
||||
AddonCalendarMainMenuHandlerService.PAGE_NAME,
|
||||
{
|
||||
siteId: notification.siteId,
|
||||
preferCurrentTab: false,
|
||||
|
@ -695,7 +600,6 @@ export class AddonCalendarProvider {
|
|||
* @param id Event ID.
|
||||
* @param siteId ID of the site. If not defined, use current site.
|
||||
* @return Promise resolved when the event data is retrieved.
|
||||
* @since 3.4
|
||||
*/
|
||||
async getEventById(id: number, siteId?: string): Promise<AddonCalendarEvent> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
@ -742,10 +646,6 @@ export class AddonCalendarProvider {
|
|||
const record: AddonCalendarGetEventsEvent | AddonCalendarEvent | AddonCalendarEventDBRecord =
|
||||
await site.getDb().getRecord(EVENTS_TABLE, { id: id });
|
||||
|
||||
if (!this.isGetEventByIdAvailableInSite(site)) {
|
||||
return record as AddonCalendarGetEventsEvent;
|
||||
}
|
||||
|
||||
const eventConverted = record as AddonCalendarEvent;
|
||||
const originalEvent = record as AddonCalendarGetEventsEvent;
|
||||
const recordAsRecord = record as AddonCalendarEventDBRecord;
|
||||
|
@ -994,10 +894,6 @@ export class AddonCalendarProvider {
|
|||
};
|
||||
const response: AddonCalendarGetCalendarEventsWSResponse =
|
||||
await site.read('core_calendar_get_calendar_events', params, preSets);
|
||||
if (!this.canViewMonthInSite(site)) {
|
||||
// Store events only in 3.1-3.3. In 3.4+ we'll use the new WS that return more info.
|
||||
this.storeEventsInLocalDB(response.events, siteId);
|
||||
}
|
||||
|
||||
return response.events;
|
||||
}
|
||||
|
@ -1059,12 +955,8 @@ export class AddonCalendarProvider {
|
|||
const params: AddonCalendarGetCalendarMonthlyViewWSParams = {
|
||||
year: year,
|
||||
month: month,
|
||||
mini: true, // Set mini to 1 to prevent returning the course selector HTML.
|
||||
};
|
||||
// This parameter requires Moodle 3.5.
|
||||
if (site.isVersionGreaterEqualThan('3.5')) {
|
||||
// Set mini to 1 to prevent returning the course selector HTML.
|
||||
params.mini = true;
|
||||
}
|
||||
if (courseId) {
|
||||
params.courseid = courseId;
|
||||
}
|
||||
|
@ -1406,36 +1298,6 @@ export class AddonCalendarProvider {
|
|||
return this.isCalendarDisabledInSite(site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the get event by ID WS is available.
|
||||
*
|
||||
* @param siteId Site Id. If not defined, use current site.
|
||||
* @return Promise resolved with true if available.
|
||||
* @since 3.4
|
||||
*/
|
||||
async isGetEventByIdAvailable(siteId?: string): Promise<boolean> {
|
||||
try {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return this.isGetEventByIdAvailableInSite(site);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the get event by ID WS is available in a certain site.
|
||||
*
|
||||
* @param site Site. If not defined, use current site.
|
||||
* @return Whether it's available.
|
||||
* @since 3.4
|
||||
*/
|
||||
isGetEventByIdAvailableInSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!site?.wsAvailable('core_calendar_get_calendar_event_by_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next events for all the sites and schedules their notifications.
|
||||
* If an event notification time is 0, cancel its scheduled notification (if any).
|
||||
|
@ -1450,7 +1312,7 @@ export class AddonCalendarProvider {
|
|||
|
||||
const siteIds = await CoreSites.getSitesIds();
|
||||
|
||||
const promises = siteIds.map((siteId: string) => this.cleanExpiredEvents(siteId).then(async() => {
|
||||
const promises = siteIds.map((siteId: string) => async () => {
|
||||
if (notificationsEnabled) {
|
||||
// Check if calendar is disabled for the site.
|
||||
const disabled = await this.isDisabled(siteId);
|
||||
|
@ -1462,7 +1324,7 @@ export class AddonCalendarProvider {
|
|||
}
|
||||
|
||||
return;
|
||||
}));
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
@ -1995,7 +1857,7 @@ export type AddonCalendarMonth = {
|
|||
date: CoreWSDate;
|
||||
periodname: string; // Periodname.
|
||||
includenavigation: boolean; // Includenavigation.
|
||||
initialeventsloaded: boolean; // @since 3.5. Initialeventsloaded.
|
||||
initialeventsloaded: boolean; // Initialeventsloaded.
|
||||
previousperiod: CoreWSDate;
|
||||
previousperiodlink: string; // Previousperiodlink.
|
||||
previousperiodname: string; // Previousperiodname.
|
||||
|
@ -2151,7 +2013,7 @@ export type AddonCalendarGetEventsEvent = {
|
|||
description?: string; // Description.
|
||||
format: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
courseid: number; // Course id.
|
||||
categoryid?: number; // @since 3.4. Category id (only for category events).
|
||||
categoryid?: number; // Category id (only for category events).
|
||||
groupid: number; // Group id.
|
||||
userid: number; // User id.
|
||||
repeatid: number; // Repeat id.
|
||||
|
|
|
@ -46,7 +46,7 @@ export class AddonCalendarMainMenuHandlerService implements CoreMainMenuHandler
|
|||
return {
|
||||
icon: 'far-calendar',
|
||||
title: 'addon.calendar.calendar',
|
||||
page: AddonCalendar.getMainCalendarPagePath(),
|
||||
page: AddonCalendarMainMenuHandlerService.PAGE_NAME,
|
||||
class: 'addon-calendar-handler',
|
||||
};
|
||||
}
|
||||
|
|
|
@ -111,13 +111,9 @@ export class AddonCalendarViewLinkHandlerService extends CoreContentLinksHandler
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonCalendar.isDisabled(siteId).then((disabled) => {
|
||||
if (disabled) {
|
||||
return false;
|
||||
}
|
||||
const disabled = await AddonCalendar.isDisabled(siteId);
|
||||
|
||||
return AddonCalendar.canViewMonth(siteId);
|
||||
});
|
||||
return !disabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -125,17 +125,6 @@ export class AddonMessageOutputAirnotifierProvider {
|
|||
return site.invalidateWsCacheForKey(this.getUserDevicesCacheKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the plugin is enabled for the current site.
|
||||
*
|
||||
* @return True if enabled, false otherwise.
|
||||
* @since 3.2
|
||||
*/
|
||||
isEnabled(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('message_airnotifier_enable_device') &&
|
||||
CoreSites.wsAvailableInCurrentSite('message_airnotifier_get_user_devices');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonMessageOutputAirnotifier = makeSingleton(AddonMessageOutputAirnotifierProvider);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { AddonMessageOutputHandler, AddonMessageOutputHandlerData } from '@addons/messageoutput/services/messageoutput-delegate';
|
||||
import { AddonMessageOutputAirnotifierProvider } from '../airnotifier';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
|
@ -29,15 +28,13 @@ export class AddonMessageOutputAirnotifierHandlerService implements AddonMessage
|
|||
name = 'AddonMessageOutputAirnotifier';
|
||||
processorName = 'airnotifier';
|
||||
|
||||
constructor(private airnotifierProvider: AddonMessageOutputAirnotifierProvider) {}
|
||||
|
||||
/**
|
||||
* Whether or not the module is enabled for the site.
|
||||
*
|
||||
* @return True if enabled, false otherwise.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return this.airnotifierProvider.isEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,12 +27,12 @@ export const AddonMessagesDiscussionRoute: Route = {
|
|||
function buildRoutes(injector: Injector): Routes {
|
||||
return [
|
||||
{
|
||||
path: 'index', // 3.5 or lower.
|
||||
path: 'index', // 3.5.
|
||||
loadChildren: () =>
|
||||
import('./pages/discussions-35/discussions.module').then(m => m.AddonMessagesDiscussions35PageModule),
|
||||
},
|
||||
{
|
||||
path: 'contacts-35', // 3.5 or lower.
|
||||
path: 'contacts-35', // 3.5.
|
||||
loadChildren: () => import('./pages/contacts-35/contacts.module').then(m => m.AddonMessagesContacts35PageModule),
|
||||
},
|
||||
{
|
||||
|
|
|
@ -747,58 +747,37 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
*/
|
||||
protected async markMessagesAsRead(forceMark: boolean): Promise<void> {
|
||||
let readChanged = false;
|
||||
let messageUnreadFound = false;
|
||||
|
||||
if (AddonMessages.isMarkAllMessagesReadEnabled()) {
|
||||
let messageUnreadFound = false;
|
||||
|
||||
// Mark all messages at a time if there is any unread message.
|
||||
if (forceMark) {
|
||||
messageUnreadFound = true;
|
||||
} else if (this.groupMessagingEnabled) {
|
||||
messageUnreadFound = !!((this.conversation?.unreadcount && this.conversation?.unreadcount > 0) &&
|
||||
(this.conversationId && this.conversationId > 0));
|
||||
} else {
|
||||
// If an unread message is found, mark all messages as read.
|
||||
messageUnreadFound = this.messages.some((message) =>
|
||||
message.useridfrom != this.currentUserId && ('read' in message && !message.read));
|
||||
}
|
||||
|
||||
if (messageUnreadFound) {
|
||||
this.setUnreadLabelPosition();
|
||||
|
||||
if (this.groupMessagingEnabled) {
|
||||
await AddonMessages.markAllConversationMessagesRead(this.conversationId!);
|
||||
} else {
|
||||
await AddonMessages.markAllMessagesRead(this.userId);
|
||||
|
||||
// Mark all messages as read.
|
||||
this.messages.forEach((message) => {
|
||||
if ('read' in message) {
|
||||
message.read = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
readChanged = true;
|
||||
}
|
||||
// Mark all messages at a time if there is any unread message.
|
||||
if (forceMark) {
|
||||
messageUnreadFound = true;
|
||||
} else if (this.groupMessagingEnabled) {
|
||||
messageUnreadFound = !!((this.conversation?.unreadcount && this.conversation?.unreadcount > 0) &&
|
||||
(this.conversationId && this.conversationId > 0));
|
||||
} else {
|
||||
// If an unread message is found, mark all messages as read.
|
||||
messageUnreadFound = this.messages.some((message) =>
|
||||
message.useridfrom != this.currentUserId && ('read' in message && !message.read));
|
||||
}
|
||||
|
||||
if (messageUnreadFound) {
|
||||
this.setUnreadLabelPosition();
|
||||
const promises: Promise<void>[] = [];
|
||||
|
||||
// Mark each message as read one by one.
|
||||
this.messages.forEach((message) => {
|
||||
// If the message is unread, call AddonMessages.markMessageRead.
|
||||
if (message.useridfrom != this.currentUserId && 'read' in message && !message.read) {
|
||||
promises.push(AddonMessages.markMessageRead(message.id).then(() => {
|
||||
readChanged = true;
|
||||
if (this.groupMessagingEnabled) {
|
||||
await AddonMessages.markAllConversationMessagesRead(this.conversationId!);
|
||||
} else {
|
||||
await AddonMessages.markAllMessagesRead(this.userId);
|
||||
|
||||
// Mark all messages as read.
|
||||
this.messages.forEach((message) => {
|
||||
if ('read' in message) {
|
||||
message.read = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
readChanged = true;
|
||||
}
|
||||
|
||||
if (readChanged) {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
|
||||
<core-search-box *ngIf="search.enabled" (onSubmit)="searchMessage($event)" (onClear)="clearSearch()"
|
||||
<core-search-box (onSubmit)="searchMessage($event)" (onClear)="clearSearch()"
|
||||
[placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
|
||||
[disabled]="!loaded" searchArea="AddonMessagesDiscussions" [autoFocus]="false"></core-search-box>
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
|
|||
discussionUserId?: number;
|
||||
|
||||
search = {
|
||||
enabled: false,
|
||||
showResults: false,
|
||||
results: <AddonMessagesMessageAreaContact[]> [],
|
||||
loading: '',
|
||||
|
@ -179,7 +178,6 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
|
|||
*/
|
||||
protected async fetchData(): Promise<void> {
|
||||
this.loadingMessage = this.loadingMessages;
|
||||
this.search.enabled = AddonMessages.isSearchMessagesEnabled();
|
||||
|
||||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ export class AddonMessagesMainMenuHandlerService implements CoreMainMenuHandler,
|
|||
title: 'addon.messages.messages',
|
||||
page: AddonMessagesMainMenuHandlerService.PAGE_NAME,
|
||||
class: 'addon-messages-handler',
|
||||
showBadge: true, // Do not check isMessageCountEnabled because we'll use fallback it not enabled.
|
||||
showBadge: true,
|
||||
badge: '',
|
||||
badgeA11yText: 'addon.messages.unreadconversations',
|
||||
loading: true,
|
||||
|
@ -199,8 +199,7 @@ export class AddonMessagesMainMenuHandlerService implements CoreMainMenuHandler,
|
|||
* @return True if is a sync process, false otherwise.
|
||||
*/
|
||||
isSync(): boolean {
|
||||
// This is done to use only wifi if using the fallback function.
|
||||
return !AddonMessages.isMessageCountEnabled() && !AddonMessages.isGroupMessagingEnabled();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,9 +34,7 @@ export class AddonMessagesSettingsHandlerService implements CoreSettingsHandler
|
|||
* @return Whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
const messagingEnabled = await AddonMessages.isPluginEnabled();
|
||||
|
||||
return messagingEnabled && AddonMessages.isMessagePreferencesEnabled();
|
||||
return await AddonMessages.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1567,9 +1567,8 @@ export class AddonMessagesProvider {
|
|||
self: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_SELF] || 0,
|
||||
};
|
||||
|
||||
} else if (this.isMessageCountEnabled()) {
|
||||
// @since 3.2
|
||||
const params: { useridto: number } = {
|
||||
} else {
|
||||
const params: AddonMessageGetUnreadConversationsCountWSParams = {
|
||||
useridto: site.getUserId(),
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
|
@ -1577,37 +1576,11 @@ export class AddonMessagesProvider {
|
|||
typeExpected: 'number',
|
||||
};
|
||||
|
||||
const count: number = await site.read('core_message_get_unread_conversations_count', params, preSets);
|
||||
const count = await site.read<number>('core_message_get_unread_conversations_count', params, preSets);
|
||||
|
||||
counts = { favourites: 0, individual: count, group: 0, self: 0 };
|
||||
} else {
|
||||
// Fallback call.
|
||||
const params: AddonMessagesGetMessagesWSParams = {
|
||||
read: false,
|
||||
limitfrom: 0,
|
||||
limitnum: AddonMessagesProvider.LIMIT_MESSAGES + 1,
|
||||
useridto: site.getUserId(),
|
||||
useridfrom: 0,
|
||||
};
|
||||
|
||||
const response = await this.getMessages(params, {}, siteId);
|
||||
|
||||
// Count the discussions by filtering same senders.
|
||||
const discussions = {};
|
||||
response.messages.forEach((message) => {
|
||||
discussions[message.useridto] = 1;
|
||||
});
|
||||
|
||||
const count = Object.keys(discussions).length;
|
||||
|
||||
counts = {
|
||||
favourites: 0,
|
||||
individual: count,
|
||||
group: 0,
|
||||
self: 0,
|
||||
orMore: count > AddonMessagesProvider.LIMIT_MESSAGES,
|
||||
};
|
||||
}
|
||||
|
||||
// Notify the new counts so all views are updated.
|
||||
CoreEvents.trigger(AddonMessagesProvider.UNREAD_CONVERSATION_COUNTS_EVENT, counts, site.id);
|
||||
|
||||
|
@ -1936,8 +1909,7 @@ export class AddonMessagesProvider {
|
|||
// @since 3.6
|
||||
return site.invalidateWsCacheForKey(this.getCacheKeyForUnreadConversationCounts());
|
||||
|
||||
} else if (this.isMessageCountEnabled()) {
|
||||
// @since 3.2
|
||||
} else {
|
||||
return site.invalidateWsCacheForKey(this.getCacheKeyForMessageCount(site.getUserId()));
|
||||
}
|
||||
}
|
||||
|
@ -2016,37 +1988,6 @@ export class AddonMessagesProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can mark all messages as read.
|
||||
*
|
||||
* @return If related WS is available on current site.
|
||||
* @since 3.2
|
||||
*/
|
||||
isMarkAllMessagesReadEnabled(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('core_message_mark_all_conversation_messages_as_read') ||
|
||||
CoreSites.wsAvailableInCurrentSite('core_message_mark_all_messages_as_read');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can count unread messages.
|
||||
*
|
||||
* @return True if enabled, false otherwise.
|
||||
* @since 3.2
|
||||
*/
|
||||
isMessageCountEnabled(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('core_message_get_unread_conversations_count');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the message preferences are enabled for the current site.
|
||||
*
|
||||
* @return True if enabled, false otherwise.
|
||||
* @since 3.2
|
||||
*/
|
||||
isMessagePreferencesEnabled(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('core_message_get_user_message_preferences');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not messaging is enabled for a certain site.
|
||||
*
|
||||
|
@ -2105,15 +2046,6 @@ export class AddonMessagesProvider {
|
|||
return site.canUseAdvancedFeature('messaging');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can search messages.
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
isSearchMessagesEnabled(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('core_message_data_for_messagearea_search_messages');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not self conversation is supported in a certain site.
|
||||
*
|
||||
|
@ -3691,6 +3623,13 @@ type AddonMessagesSetFavouriteConversationsWSParams = {
|
|||
conversations: number[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Params of core_message_get_unread_conversations_count WS.
|
||||
*/
|
||||
type AddonMessageGetUnreadConversationsCountWSParams = {
|
||||
useridto: number; // The user id who received the message, 0 for any user.
|
||||
};
|
||||
|
||||
/**
|
||||
* Data sent by UNREAD_CONVERSATION_COUNTS_EVENT event.
|
||||
*/
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
<h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2>
|
||||
<h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2>
|
||||
</ion-label>
|
||||
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
|
||||
<ion-badge slot="end" color="primary">
|
||||
<span aria-hidden="true">{{ summary.participantcount }}</span>
|
||||
<span class="sr-only" *ngIf="!assign.teamsubmission">
|
||||
{{ 'addon.mod_assign.numberofparticipantscountdescription' | translate:{count: summary.participantcount} }}
|
||||
|
@ -109,12 +109,12 @@
|
|||
|
||||
<!-- Summary of submissions with draft status. -->
|
||||
<ion-item class="ion-text-wrap" *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled"
|
||||
[class.hide-detail]="showNumbers && !summary.submissiondraftscount"
|
||||
[class.hide-detail]="!summary.submissiondraftscount"
|
||||
detail="true"
|
||||
[button]="!showNumbers || summary.submissiondraftscount"
|
||||
[button]="summary.submissiondraftscount"
|
||||
(click)="goToSubmissionList(submissionStatusDraft, !!summary.submissiondraftscount)">
|
||||
<ion-label><h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2></ion-label>
|
||||
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
|
||||
<ion-badge slot="end" color="primary">
|
||||
<span aria-hidden="true">{{ summary.submissiondraftscount }}</span>
|
||||
<span class="sr-only">
|
||||
{{ 'addon.mod_assign.numberofdraftsubmissionscountdescription' | translate:
|
||||
|
@ -125,12 +125,12 @@
|
|||
|
||||
<!-- Summary of submissions with submitted status. -->
|
||||
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled"
|
||||
[class.hide-detail]="showNumbers && !summary.submissionssubmittedcount"
|
||||
[class.hide-detail]="!summary.submissionssubmittedcount"
|
||||
detail="true"
|
||||
[button]="!showNumbers || summary.submissionssubmittedcount"
|
||||
[button]="summary.submissionssubmittedcount"
|
||||
(click)="goToSubmissionList(submissionStatusSubmitted, !!summary.submissionssubmittedcount)">
|
||||
<ion-label><h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2></ion-label>
|
||||
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
|
||||
<ion-badge slot="end" color="primary">
|
||||
<span aria-hidden="true">{{ summary.submissionssubmittedcount }}</span>
|
||||
<span class="sr-only">
|
||||
{{ 'addon.mod_assign.numberofsubmittedassignmentscountdescription' | translate:
|
||||
|
@ -140,7 +140,7 @@
|
|||
</ion-item>
|
||||
|
||||
<!-- Summary of submissions that need grading. -->
|
||||
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers"
|
||||
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission"
|
||||
[class.hide-detail]="!needsGradingAvailable"
|
||||
detail="true"
|
||||
[button]="needsGradingAvailable"
|
||||
|
|
|
@ -63,7 +63,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
canViewOwnSubmission = false; // Whether the user can view their own submission.
|
||||
timeRemaining?: string; // Message about time remaining to submit.
|
||||
lateSubmissions?: string; // Message about late submissions.
|
||||
showNumbers = true; // Whether to show number of submissions with each status.
|
||||
summary?: AddonModAssignSubmissionGradingSummary; // The grading summary.
|
||||
needsGradingAvailable = false; // Whether we can see the submissions that need grading.
|
||||
|
||||
|
@ -235,8 +234,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
|
||||
// Check if groupmode is enabled to avoid showing wrong numbers.
|
||||
this.groupInfo = await CoreGroups.getActivityGroupInfo(this.assign.cmid, false);
|
||||
this.showNumbers = (this.groupInfo.groups && this.groupInfo.groups.length == 0) ||
|
||||
this.currentSite!.isVersionGreaterEqualThan('3.5');
|
||||
|
||||
await this.setGroup(CoreGroups.validateGroupId(this.group, this.groupInfo));
|
||||
|
||||
|
@ -296,9 +293,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
}
|
||||
}
|
||||
|
||||
this.needsGradingAvailable =
|
||||
(submissionStatus.gradingsummary?.submissionsneedgradingcount || 0) > 0 &&
|
||||
this.currentSite!.isVersionGreaterEqualThan('3.2');
|
||||
this.needsGradingAvailable = (submissionStatus.gradingsummary?.submissionsneedgradingcount || 0) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -308,7 +303,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
* @param hasSubmissions If the status has any submission.
|
||||
*/
|
||||
goToSubmissionList(status?: string, hasSubmissions = false): void {
|
||||
if (typeof status != 'undefined' && !hasSubmissions && this.showNumbers) {
|
||||
if (typeof status != 'undefined' && !hasSubmissions) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -649,7 +649,6 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|||
this.gradeInfo = await CoreCourse.getModuleBasicGradeInfo(this.moduleId);
|
||||
|
||||
if (!this.gradeInfo) {
|
||||
// It won't get gradeinfo on 3.1.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -966,7 +965,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|||
}
|
||||
|
||||
// Treat outcomes.
|
||||
if (this.gradeInfo.outcomes && AddonModAssign.isOutcomesEditEnabled()) {
|
||||
if (this.gradeInfo.outcomes) {
|
||||
this.gradeInfo.outcomes.forEach((outcome) => {
|
||||
if (outcome.scale) {
|
||||
outcome.options =
|
||||
|
@ -981,8 +980,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|||
}
|
||||
|
||||
// Get grade items.
|
||||
const grades = <CoreGradesFormattedItem[]>
|
||||
await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId);
|
||||
const grades = await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId);
|
||||
|
||||
const outcomes: AddonModAssignGradeOutcome[] = [];
|
||||
|
||||
|
@ -1091,16 +1089,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|||
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit
|
||||
) {
|
||||
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit.forEach((member) => {
|
||||
if (this.blindMarking) {
|
||||
// Users not blinded! (Moodle < 3.1.1, 3.2).
|
||||
promises.push(AddonModAssign.getAssignmentUserMappings(this.assign!.id, member, {
|
||||
cmId: this.moduleId,
|
||||
}).then((blindId) => {
|
||||
this.membersToSubmitBlind.push(blindId);
|
||||
|
||||
return;
|
||||
}));
|
||||
} else {
|
||||
if (!this.blindMarking) {
|
||||
promises.push(CoreUser.getProfile(member, this.courseId).then((profile) => {
|
||||
this.membersToSubmit.push(profile);
|
||||
|
||||
|
|
|
@ -72,13 +72,6 @@
|
|||
</ion-label>
|
||||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
<ion-card class="ion-text-wrap core-warning-card" *ngIf="!haveAllParticipants">
|
||||
<ion-item>
|
||||
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
|
||||
<ion-label>{{ 'addon.mod_assign.notallparticipantsareshown' | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
</core-split-view>
|
||||
|
|
|
@ -55,7 +55,6 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
|
|||
assign?: AddonModAssignAssign; // Assignment.
|
||||
submissions: AddonModAssignSubmissionListManager; // List of submissions
|
||||
loaded = false; // Whether data has been loaded.
|
||||
haveAllParticipants = true; // Whether all participants have been loaded.
|
||||
groupId = 0; // Group ID to show.
|
||||
courseId!: number; // Course ID the assignment belongs to.
|
||||
moduleId!: number; // Module ID the submission belongs to.
|
||||
|
@ -202,16 +201,6 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
|
|||
async setGroup(groupId: number): Promise<void> {
|
||||
this.groupId = groupId;
|
||||
|
||||
this.haveAllParticipants = true;
|
||||
|
||||
if (!CoreSites.getCurrentSite()?.wsAvailable('mod_assign_list_participants')) {
|
||||
// Submissions are not displayed in Moodle 3.1 without the local plugin, see MOBILE-2968.
|
||||
this.haveAllParticipants = false;
|
||||
this.submissions.resetItems();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch submissions and grades.
|
||||
const submissions =
|
||||
await AddonModAssignHelper.getSubmissionsUserData(
|
||||
|
|
|
@ -398,13 +398,9 @@ export class AddonModAssignHelperProvider {
|
|||
groupId?: number,
|
||||
options: CoreSitesCommonWSOptions = {},
|
||||
): Promise<AddonModAssignSubmissionFormatted[]> {
|
||||
// Create new options including all existing ones.
|
||||
const modOptions: CoreCourseCommonModWSOptions = { cmId: assign.cmid, ...options };
|
||||
|
||||
const parts = await this.getParticipants(assign, groupId, options);
|
||||
|
||||
const blind = assign.blindmarking && !assign.revealidentities;
|
||||
const promises: Promise<void>[] = [];
|
||||
const result: AddonModAssignSubmissionFormatted[] = [];
|
||||
const participants: {[id: number]: AddonModAssignParticipant} = CoreUtils.arrayToObject(parts, 'id');
|
||||
|
||||
|
@ -434,31 +430,12 @@ export class AddonModAssignHelperProvider {
|
|||
submission.groupname = participant.groupname;
|
||||
}
|
||||
|
||||
let promise = Promise.resolve();
|
||||
if (submission.userid && submission.userid > 0 && blind) {
|
||||
// Blind but not blinded! (Moodle < 3.1.1, 3.2).
|
||||
delete submission.userid;
|
||||
|
||||
promise = AddonModAssign.getAssignmentUserMappings(assign.id, submission.submitid, modOptions)
|
||||
.then((blindId) => {
|
||||
submission.blindid = blindId;
|
||||
|
||||
return;
|
||||
});
|
||||
// Add to the list.
|
||||
if (submission.userfullname || submission.blindid) {
|
||||
result.push(submission);
|
||||
}
|
||||
|
||||
promises.push(promise.then(() => {
|
||||
// Add to the list.
|
||||
if (submission.userfullname || submission.blindid) {
|
||||
result.push(submission);
|
||||
}
|
||||
|
||||
return;
|
||||
}));
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
// Create a submission for each participant left in the list (the participants already treated were removed).
|
||||
CoreUtils.objectToArray(participants).forEach((participant: AddonModAssignParticipant) => {
|
||||
const submission = this.createEmptySubmission();
|
||||
|
|
|
@ -37,7 +37,7 @@ import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
import { CoreGradesFormattedItem, CoreGradesFormattedRow, CoreGradesHelper } from '@features/grades/services/grades-helper';
|
||||
import { CoreGradesFormattedItem, CoreGradesHelper } from '@features/grades/services/grades-helper';
|
||||
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
|
||||
import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
|
||||
|
||||
|
@ -457,21 +457,20 @@ export class AddonModAssignSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
}
|
||||
|
||||
// If grade has been modified from gradebook, do not use offline.
|
||||
const grades: CoreGradesFormattedItem[] | CoreGradesFormattedRow[] =
|
||||
await CoreGradesHelper.getGradeModuleItems(courseId, assign.cmid, userId, undefined, siteId, true);
|
||||
const grades = await CoreGradesHelper.getGradeModuleItems(courseId, assign.cmid, userId, undefined, siteId, true);
|
||||
|
||||
const gradeInfo = await CoreCourse.getModuleBasicGradeInfo(assign.cmid, siteId);
|
||||
|
||||
// Override offline grade and outcomes based on the gradebook data.
|
||||
grades.forEach((grade: CoreGradesFormattedItem | CoreGradesFormattedRow) => {
|
||||
if ('gradedategraded' in grade && (grade.gradedategraded || 0) >= offlineData.timemodified) {
|
||||
grades.forEach((grade: CoreGradesFormattedItem) => {
|
||||
if ((grade.gradedategraded || 0) >= offlineData.timemodified) {
|
||||
if (!grade.outcomeid && !grade.scaleid) {
|
||||
if (gradeInfo && gradeInfo.scale) {
|
||||
offlineData.grade = this.getSelectedScaleId(gradeInfo.scale, grade.grade || '');
|
||||
} else {
|
||||
offlineData.grade = parseFloat(grade.grade || '');
|
||||
}
|
||||
} else if (gradeInfo && grade.outcomeid && AddonModAssign.isOutcomesEditEnabled() && gradeInfo.outcomes) {
|
||||
} else if (gradeInfo && grade.outcomeid && gradeInfo.outcomes) {
|
||||
gradeInfo.outcomes.forEach((outcome, index) => {
|
||||
if (outcome.scale && grade.itemnumber == index) {
|
||||
offlineData.outcomes[grade.itemnumber] = this.getSelectedScaleId(
|
||||
|
|
|
@ -90,8 +90,6 @@ export class AddonModAssignProvider {
|
|||
static readonly SUBMITTED_FOR_GRADING_EVENT = 'addon_mod_assign_submitted_for_grading';
|
||||
static readonly GRADED_EVENT = 'addon_mod_assign_graded';
|
||||
|
||||
protected gradingOfflineEnabled: {[siteId: string]: boolean} = {};
|
||||
|
||||
/**
|
||||
* Check if the user can submit in offline. This should only be used if submissionStatus.lastattempt.cansubmit cannot
|
||||
* be used (offline usage).
|
||||
|
@ -151,7 +149,7 @@ export class AddonModAssignProvider {
|
|||
|
||||
return {
|
||||
isBlind: !userId ? false : !!isBlind,
|
||||
groupId: site.isVersionGreaterEqualThan('3.5') ? groupId || 0 : 0,
|
||||
groupId: groupId || 0,
|
||||
userId: userId || site.getUserId(),
|
||||
};
|
||||
}
|
||||
|
@ -662,10 +660,6 @@ export class AddonModAssignProvider {
|
|||
groupId = groupId || 0;
|
||||
|
||||
const site = await CoreSites.getSite(options.siteId);
|
||||
if (!site.wsAvailable('mod_assign_list_participants')) {
|
||||
// Silently fail if is not available. (needs Moodle version >= 3.2)
|
||||
throw new CoreError('mod_assign_list_participants WS is only available 3.2 onwards');
|
||||
}
|
||||
|
||||
const params: AddonModAssignListParticipantsWSParams = {
|
||||
assignid: assignId,
|
||||
|
@ -836,47 +830,6 @@ export class AddonModAssignProvider {
|
|||
await site.invalidateWsCacheForKeyStartingWith(this.listParticipantsPrefixCacheKey(assignId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to check if grading offline is enabled.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with boolean: whether grading offline is enabled.
|
||||
*/
|
||||
protected async isGradingOfflineEnabled(siteId?: string): Promise<boolean> {
|
||||
siteId = siteId || CoreSites.getCurrentSiteId();
|
||||
|
||||
if (typeof this.gradingOfflineEnabled[siteId] != 'undefined') {
|
||||
return this.gradingOfflineEnabled[siteId];
|
||||
}
|
||||
|
||||
this.gradingOfflineEnabled[siteId] = await CoreGrades.isGradeItemsAvailable(siteId);
|
||||
|
||||
return this.gradingOfflineEnabled[siteId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Outcomes only can be edited if mod_assign_submit_grading_form is available.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if outcomes edit is enabled, rejected or resolved with false otherwise.
|
||||
* @since 3.2
|
||||
*/
|
||||
async isOutcomesEditEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('mod_assign_submit_grading_form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if assignments plugin is enabled in a certain site.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Whether the plugin is enabled.
|
||||
*/
|
||||
isPluginEnabled(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a submission is open. This function is based on Moodle's submissions_open.
|
||||
*
|
||||
|
@ -1261,25 +1214,6 @@ export class AddonModAssignProvider {
|
|||
return false;
|
||||
};
|
||||
|
||||
// Grading offline is only allowed if WS of grade items is enabled to avoid inconsistency.
|
||||
const enabled = await this.isGradingOfflineEnabled(siteId);
|
||||
if (!enabled) {
|
||||
await this.submitGradingFormOnline(
|
||||
assignId,
|
||||
userId,
|
||||
grade,
|
||||
attemptNumber,
|
||||
addAttempt,
|
||||
workflowState,
|
||||
applyToAll,
|
||||
outcomes,
|
||||
pluginData,
|
||||
siteId,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CoreApp.isOnline()) {
|
||||
// App is offline, store the action.
|
||||
return storeOffline();
|
||||
|
@ -1345,58 +1279,35 @@ export class AddonModAssignProvider {
|
|||
const site = await CoreSites.getSite(siteId);
|
||||
userId = userId || site.getUserId();
|
||||
|
||||
if (site.wsAvailable('mod_assign_submit_grading_form')) {
|
||||
// WS available @since 3.2.
|
||||
const jsonData = {
|
||||
grade,
|
||||
attemptnumber: attemptNumber,
|
||||
addattempt: addAttempt ? 1 : 0,
|
||||
workflowstate: workflowState,
|
||||
applytoall: applyToAll ? 1 : 0,
|
||||
};
|
||||
|
||||
const jsonData = {
|
||||
grade,
|
||||
attemptnumber: attemptNumber,
|
||||
addattempt: addAttempt ? 1 : 0,
|
||||
workflowstate: workflowState,
|
||||
applytoall: applyToAll ? 1 : 0,
|
||||
};
|
||||
|
||||
for (const index in outcomes) {
|
||||
jsonData['outcome_' + index + '[' + userId + ']'] = outcomes[index];
|
||||
}
|
||||
|
||||
for (const index in pluginData) {
|
||||
jsonData[index] = pluginData[index];
|
||||
}
|
||||
|
||||
const serialized = CoreInterceptor.serialize(jsonData, true);
|
||||
const params: AddonModAssignSubmitGradingFormWSParams = {
|
||||
assignmentid: assignId,
|
||||
userid: userId,
|
||||
jsonformdata: JSON.stringify(serialized),
|
||||
};
|
||||
|
||||
const warnings = await site.write<CoreWSExternalWarning[]>('mod_assign_submit_grading_form', params);
|
||||
|
||||
if (warnings.length) {
|
||||
// The WebService returned warnings, reject.
|
||||
throw new CoreWSError(warnings[0]);
|
||||
}
|
||||
|
||||
return;
|
||||
for (const index in outcomes) {
|
||||
jsonData['outcome_' + index + '[' + userId + ']'] = outcomes[index];
|
||||
}
|
||||
|
||||
// WS not available, fallback to save_grade.
|
||||
const params: AddonModAssignSaveGradeWSParams = {
|
||||
for (const index in pluginData) {
|
||||
jsonData[index] = pluginData[index];
|
||||
}
|
||||
|
||||
const serialized = CoreInterceptor.serialize(jsonData, true);
|
||||
const params: AddonModAssignSubmitGradingFormWSParams = {
|
||||
assignmentid: assignId,
|
||||
userid: userId,
|
||||
grade: grade,
|
||||
attemptnumber: attemptNumber,
|
||||
addattempt: addAttempt,
|
||||
workflowstate: workflowState,
|
||||
applytoall: applyToAll,
|
||||
plugindata: pluginData,
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
responseExpected: false,
|
||||
jsonformdata: JSON.stringify(serialized),
|
||||
};
|
||||
|
||||
await site.write('mod_assign_save_grade', params, preSets);
|
||||
const warnings = await site.write<CoreWSExternalWarning[]>('mod_assign_submit_grading_form', params);
|
||||
|
||||
if (warnings.length) {
|
||||
// The WebService returned warnings, reject.
|
||||
throw new CoreWSError(warnings[0]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1431,7 +1342,7 @@ export type AddonModAssignAssign = {
|
|||
timemodified: number; // Last time assignment was modified.
|
||||
completionsubmit: number; // If enabled, set activity as complete following submission.
|
||||
cutoffdate: number; // Date after which submission is not accepted without an extension.
|
||||
gradingduedate?: number; // @since 3.3. The expected date for marking the submissions.
|
||||
gradingduedate?: number; // The expected date for marking the submissions.
|
||||
teamsubmission: number; // If enabled, students submit as a team.
|
||||
requireallteammemberssubmit: number; // If enabled, all team members must submit.
|
||||
teamsubmissiongroupingid: number; // The grouping id for the team submission groups.
|
||||
|
@ -1443,13 +1354,13 @@ export type AddonModAssignAssign = {
|
|||
markingworkflow: number; // Enable marking workflow.
|
||||
markingallocation: number; // Enable marking allocation.
|
||||
requiresubmissionstatement: number; // Student must accept submission statement.
|
||||
preventsubmissionnotingroup?: number; // @since 3.2. Prevent submission not in group.
|
||||
submissionstatement?: string; // @since 3.2. Submission statement formatted.
|
||||
submissionstatementformat?: number; // @since 3.2. Submissionstatement format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
preventsubmissionnotingroup?: number; // Prevent submission not in group.
|
||||
submissionstatement?: string; // Submission statement formatted.
|
||||
submissionstatementformat?: number; // Submissionstatement format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
configs: AddonModAssignConfig[]; // Configuration settings.
|
||||
intro?: string; // Assignment intro, not allways returned because it deppends on the activity configuration.
|
||||
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
introattachments?: CoreWSExternalFile[];
|
||||
};
|
||||
|
||||
|
@ -1494,7 +1405,7 @@ export type AddonModAssignSubmission = {
|
|||
assignment?: number; // Assignment id.
|
||||
latest?: number; // Latest attempt.
|
||||
plugins?: AddonModAssignPlugin[]; // Plugins.
|
||||
gradingstatus?: string; // @since 3.2. Grading status.
|
||||
gradingstatus?: string; // Grading status.
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1539,7 +1450,7 @@ export type AddonModAssignSubmissionAttempt = {
|
|||
locked: boolean; // Whether new submissions are locked.
|
||||
graded: boolean; // Whether the submission is graded.
|
||||
canedit: boolean; // Whether the user can edit the current submission.
|
||||
caneditowner?: boolean; // @since 3.2. Whether the owner of the submission can edit it.
|
||||
caneditowner?: boolean; // Whether the owner of the submission can edit it.
|
||||
cansubmit: boolean; // Whether the user can submit.
|
||||
extensionduedate: number; // Extension due date.
|
||||
blindmarking: boolean; // Whether blind marking is enabled.
|
||||
|
@ -1610,7 +1521,7 @@ export type AddonModAssignParticipant = {
|
|||
interests?: string; // User interests (separated by commas).
|
||||
firstaccess?: number; // First access to the site (0 if never).
|
||||
lastaccess?: number; // Last access to the site (0 if never).
|
||||
suspended?: boolean; // @since 3.2. Suspend user account, either false to enable user login or true to disable it.
|
||||
suspended?: boolean; // Suspend user account, either false to enable user login or true to disable it.
|
||||
description?: string; // User profile description.
|
||||
descriptionformat?: number; // Int format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
city?: string; // Home city of the user.
|
||||
|
@ -1647,7 +1558,7 @@ export type AddonModAssignParticipant = {
|
|||
}[];
|
||||
submitted: boolean; // Have they submitted their assignment.
|
||||
requiregrading: boolean; // Is their submission waiting for grading.
|
||||
grantedextension?: boolean; // @since 3.3. Have they been granted an extension.
|
||||
grantedextension?: boolean; // Have they been granted an extension.
|
||||
groupid?: number; // For group assignments this is the group id.
|
||||
groupname?: string; // For group assignments this is the group name.
|
||||
};
|
||||
|
@ -1815,45 +1726,6 @@ type AddonModAssignSubmitGradingFormWSParams = {
|
|||
jsonformdata: string; // The data from the grading form, encoded as a json array.
|
||||
};
|
||||
|
||||
/**
|
||||
* Params of mod_assign_save_grade WS.
|
||||
*/
|
||||
type AddonModAssignSaveGradeWSParams = {
|
||||
assignmentid: number; // The assignment id to operate on.
|
||||
userid: number; // The student id to operate on.
|
||||
grade: number; // The new grade for this user. Ignored if advanced grading used.
|
||||
attemptnumber: number; // The attempt number (-1 means latest attempt).
|
||||
addattempt: boolean; // Allow another attempt if the attempt reopen method is manual.
|
||||
workflowstate: string; // The next marking workflow state.
|
||||
applytoall: boolean; // If true, this grade will be applied to all members of the group (for group assignments).
|
||||
plugindata?: AddonModAssignSavePluginData; // Plugin data.
|
||||
advancedgradingdata?: {
|
||||
guide?: {
|
||||
criteria: {
|
||||
criterionid: number; // Criterion id.
|
||||
fillings?: { // Filling.
|
||||
criterionid: number; // Criterion id.
|
||||
levelid?: number; // Level id.
|
||||
remark?: string; // Remark.
|
||||
remarkformat?: number; // Remark format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
score: number; // Maximum score.
|
||||
}[];
|
||||
}[];
|
||||
}; // Items.
|
||||
rubric?: {
|
||||
criteria: {
|
||||
criterionid: number; // Criterion id.
|
||||
fillings?: { // Filling.
|
||||
criterionid: number; // Criterion id.
|
||||
levelid?: number; // Level id.
|
||||
remark?: string; // Remark.
|
||||
remarkformat?: number; // Remark format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
}[];
|
||||
}[];
|
||||
}; // Items.
|
||||
}; // Advanced grading data.
|
||||
};
|
||||
|
||||
/**
|
||||
* Assignment grade outcomes.
|
||||
*/
|
||||
|
|
|
@ -20,7 +20,6 @@ import { makeSingleton } from '@singletons';
|
|||
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course';
|
||||
import { CoreCourseModule } from '@features/course/services/course-helper';
|
||||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||
import { AddonModAssign } from '../assign';
|
||||
|
||||
/**
|
||||
* Handler to support assign modules.
|
||||
|
@ -54,7 +53,7 @@ export class AddonModAssignModuleHandlerService implements CoreCourseModuleHandl
|
|||
* @return Whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonModAssign.isPluginEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -202,15 +202,6 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
|
|||
return CoreCourse.invalidateModule(module.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonModAssign.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
@ -391,10 +382,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
|
|||
// Participiants already fetched, we don't need to ignore cache now.
|
||||
const participants = await AddonModAssignHelper.getParticipants(assign, group.id, { siteId });
|
||||
|
||||
// Fail silently (Moodle < 3.2).
|
||||
await CoreUtils.ignoreErrors(
|
||||
CoreUser.prefetchUserAvatars(participants, 'profileimageurl', siteId),
|
||||
);
|
||||
await CoreUser.prefetchUserAvatars(participants, 'profileimageurl', siteId);
|
||||
|
||||
return;
|
||||
}));
|
||||
|
|
|
@ -16,7 +16,6 @@ import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin }
|
|||
import { AddonModAssignSubmissionHandler } from '@addons/mod/assign/services/submission-delegate';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreComments } from '@features/comments/services/comments';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModAssignSubmissionCommentsComponent } from '../component/comments';
|
||||
|
||||
|
@ -87,18 +86,14 @@ export class AddonModAssignSubmissionCommentsHandlerService implements AddonModA
|
|||
plugin: AddonModAssignPlugin,
|
||||
siteId?: string,
|
||||
): Promise<void> {
|
||||
|
||||
// Fail silently (Moodle < 3.1.1, 3.2)
|
||||
await CoreUtils.ignoreErrors(
|
||||
CoreComments.getComments(
|
||||
'module',
|
||||
assign.cmid,
|
||||
'assignsubmission_comments',
|
||||
submission.id,
|
||||
'submission_comments',
|
||||
0,
|
||||
siteId,
|
||||
),
|
||||
await CoreComments.getComments(
|
||||
'module',
|
||||
assign.cmid,
|
||||
'assignsubmission_comments',
|
||||
submission.id,
|
||||
'submission_comments',
|
||||
0,
|
||||
siteId,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import { AddonModAssignSubmissionHandler } from '@addons/mod/assign/services/sub
|
|||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreFileHelper } from '@services/file-helper';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
|
@ -224,11 +223,7 @@ export class AddonModAssignSubmissionOnlineTextHandlerService implements AddonMo
|
|||
* @return Whether or not the handler is enabled for edit on a site level.
|
||||
*/
|
||||
isEnabledForEdit(): boolean {
|
||||
// There's a bug in Moodle 3.1.0 that doesn't allow submitting HTML, so we'll disable this plugin in that case.
|
||||
// Bug was fixed in 3.1.1 minor release and in 3.2.
|
||||
const currentSite = CoreSites.getCurrentSite();
|
||||
|
||||
return !!currentSite?.isVersionGreaterEqualThan('3.1.1') || !!currentSite?.checkIfAppUsesLocalMobile();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -441,7 +441,7 @@ export type AddonModBookBookWSData = {
|
|||
name: string; // Book name.
|
||||
intro: string; // The Book intro.
|
||||
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
numbering: number; // Book numbering configuration.
|
||||
navstyle: number; // Book navigation style configuration.
|
||||
customtitles: number; // Book custom titles type.
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<ion-button class="ion-margin ion-text-wrap" expand="block" color="primary" (click)="enterChat()">
|
||||
{{ 'addon.mod_chat.enterchat' | translate }}
|
||||
</ion-button>
|
||||
<ion-button class="ion-margin ion-text-wrap" expand="block" color="light" *ngIf="sessionsAvailable" (click)="viewSessions()">
|
||||
<ion-button class="ion-margin ion-text-wrap" expand="block" color="light" (click)="viewSessions()">
|
||||
{{ 'addon.mod_chat.viewreport' | translate }}
|
||||
</ion-button>
|
||||
</ng-container>
|
||||
|
|
|
@ -34,7 +34,6 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
component = AddonModChatProvider.COMPONENT;
|
||||
moduleName = 'chat';
|
||||
chat?: AddonModChatChat;
|
||||
sessionsAvailable = false;
|
||||
chatInfo?: {
|
||||
date: string;
|
||||
fromnow: string;
|
||||
|
@ -89,8 +88,6 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
}
|
||||
|
||||
this.dataRetrieved.emit(this.chat);
|
||||
|
||||
this.sessionsAvailable = await AddonModChat.areSessionsAvailable();
|
||||
} finally {
|
||||
this.fillContextMenu(refresh);
|
||||
}
|
||||
|
|
|
@ -217,19 +217,6 @@ export class AddonModChatProvider {
|
|||
return site.read('mod_chat_get_chat_users', params, preSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether WS for passed sessions are available.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with a boolean.
|
||||
* @since 3.5
|
||||
*/
|
||||
async areSessionsAvailable(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('mod_chat_get_sessions') && site.wsAvailable('mod_chat_get_session_messages');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat sessions.
|
||||
*
|
||||
|
@ -238,7 +225,6 @@ export class AddonModChatProvider {
|
|||
* @param showAll Whether to include incomplete sessions or not.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of sessions.
|
||||
* @since 3.5
|
||||
*/
|
||||
async getSessions(
|
||||
chatId: number,
|
||||
|
@ -275,7 +261,6 @@ export class AddonModChatProvider {
|
|||
* @param groupId Group ID, 0 means that the function will determine the user group.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of messages.
|
||||
* @since 3.5
|
||||
*/
|
||||
async getSessionMessages(
|
||||
chatId: number,
|
||||
|
@ -461,7 +446,7 @@ export type AddonModChatChat = {
|
|||
name: string; // Chat name.
|
||||
intro: string; // The Chat intro.
|
||||
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
chatmethod?: string; // Chat method (sockets, ajax, header_js).
|
||||
keepdays?: number; // Keep days.
|
||||
studentlogs?: number; // Student logs visible to everyone.
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/
|
|||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModChatIndexComponent } from '../../components/index';
|
||||
import { AddonModChat } from '../chat';
|
||||
|
||||
/**
|
||||
* Handler to support chat modules.
|
||||
|
@ -59,6 +58,7 @@ export class AddonModChatModuleHandlerService implements CoreCourseModuleHandler
|
|||
icon: CoreCourse.getModuleIconSrc(this.modName, 'modicon' in module ? module.modicon : undefined),
|
||||
title: module.name,
|
||||
class: 'addon-mod_chat-handler',
|
||||
showDownloadButton: true,
|
||||
action(event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions): void {
|
||||
options = options || {};
|
||||
options.params = options.params || {};
|
||||
|
@ -69,20 +69,9 @@ export class AddonModChatModuleHandlerService implements CoreCourseModuleHandler
|
|||
},
|
||||
};
|
||||
|
||||
this.checkDownloadButton(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether download button should be displayed.
|
||||
*
|
||||
* @param data Handler data.
|
||||
*/
|
||||
protected async checkDownloadButton(data: CoreCourseModuleHandlerData): Promise<void> {
|
||||
data.showDownloadButton = await AddonModChat.areSessionsAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -32,13 +32,6 @@ export class AddonModChatPrefetchHandlerService extends CoreCourseActivityPrefet
|
|||
modName = 'chat';
|
||||
component = AddonModChatProvider.COMPONENT;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonModChat.areSessionsAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -484,7 +484,7 @@ export type AddonModChoiceChoice = {
|
|||
name: string; // Choice name.
|
||||
intro: string; // The choice intro.
|
||||
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
publish?: boolean; // If choice is published.
|
||||
showresults?: number; // 0 never, 1 after answer, 2 after close, 3 always.
|
||||
display?: number; // Display mode (vertical, horizontal).
|
||||
|
|
|
@ -950,19 +950,6 @@ export class AddonModDataProvider {
|
|||
await site.invalidateWsCacheForKey(this.getEntryCacheKey(dataId, entryId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the database WS are available.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
|
||||
* @since 3.3
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('mod_data_get_data_access_information');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the database as being viewed.
|
||||
*
|
||||
|
|
|
@ -17,7 +17,6 @@ import { Params } from '@angular/router';
|
|||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
import { AddonModDataHelper } from '../data-helper';
|
||||
|
||||
/**
|
||||
|
@ -56,7 +55,7 @@ export class AddonModDataApproveLinkHandlerService extends CoreContentLinksHandl
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import { Params } from '@angular/router';
|
|||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
import { AddonModDataHelper } from '../data-helper';
|
||||
|
||||
/**
|
||||
|
@ -54,7 +53,7 @@ export class AddonModDataDeleteLinkHandlerService extends CoreContentLinksHandle
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
import { AddonModDataModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -72,7 +71,7 @@ export class AddonModDataEditLinkHandlerService extends CoreContentLinksHandlerB
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
|
||||
/**
|
||||
* Handler to treat links to data.
|
||||
|
@ -29,12 +28,5 @@ export class AddonModDataIndexLinkHandlerService extends CoreContentLinksModuleI
|
|||
super('AddonModData', 'data', 'd');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(siteId: string): Promise<boolean> {
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataIndexLinkHandler = makeSingleton(AddonModDataIndexLinkHandlerService);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
|
||||
/**
|
||||
* Handler to treat links to data list page.
|
||||
|
@ -29,12 +28,5 @@ export class AddonModDataListLinkHandlerService extends CoreContentLinksModuleLi
|
|||
super('AddonModData', 'data');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(siteId?: string): Promise<boolean> {
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModDataListLinkHandler = makeSingleton(AddonModDataListLinkHandlerService);
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/
|
|||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModDataIndexComponent } from '../../components/index';
|
||||
import { AddonModData } from '../data';
|
||||
|
||||
/**
|
||||
* Handler to support data modules.
|
||||
|
@ -50,8 +49,8 @@ export class AddonModDataModuleHandlerService implements CoreCourseModuleHandler
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModData.isPluginEnabled();
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -203,13 +203,6 @@ export class AddonModDataPrefetchHandlerService extends CoreCourseActivityPrefet
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonModData.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
import { AddonModDataModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -87,7 +86,7 @@ export class AddonModDataShowLinkHandlerService extends CoreContentLinksHandlerB
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModData.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
|
|||
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
|
||||
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModData } from '../data';
|
||||
|
||||
/**
|
||||
* Handler to support tags.
|
||||
|
@ -32,7 +31,7 @@ export class AddonModDataTagAreaHandlerService implements CoreTagAreaHandler {
|
|||
* @inheritdoc
|
||||
*/
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return AddonModData.isPluginEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1089,20 +1089,6 @@ export class AddonModFeedbackProvider {
|
|||
return CoreUtils.promiseWorks(site.read('mod_feedback_get_last_completed', params, preSets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the feedback WS are available.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
|
||||
* @since 3.3
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('mod_feedback_get_feedbacks_by_courses') &&
|
||||
site.wsAvailable('mod_feedback_get_feedback_access_information');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the feedback as being viewed.
|
||||
*
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -84,7 +83,7 @@ export class AddonModFeedbackAnalysisLinkHandlerService extends CoreContentLinks
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -72,7 +71,7 @@ export class AddonModFeedbackCompleteLinkHandlerService extends CoreContentLinks
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
|
||||
/**
|
||||
* Handler to treat links to feedback.
|
||||
|
@ -29,19 +28,6 @@ export class AddonModFeedbackIndexLinkHandlerService extends CoreContentLinksMod
|
|||
super('AddonModFeedback', 'feedback');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @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.
|
||||
* @return Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModFeedback.isPluginEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonModFeedbackIndexLinkHandler = makeSingleton(AddonModFeedbackIndexLinkHandlerService);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
|
||||
/**
|
||||
* Handler to treat links to feedback list page.
|
||||
|
@ -29,13 +28,6 @@ export class AddonModFeedbackListLinkHandlerService extends CoreContentLinksModu
|
|||
super('AddonModFeedback', 'feedback');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModFeedback.isPluginEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonModFeedbackListLinkHandler = makeSingleton(AddonModFeedbackListLinkHandlerService);
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourseModule } from '@features/course/services/course-helper';
|
|||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
|
||||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackIndexComponent } from '../../components/index';
|
||||
|
||||
/**
|
||||
|
@ -48,8 +47,8 @@ export class AddonModFeedbackModuleHandlerService implements CoreCourseModuleHan
|
|||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModFeedback.isPluginEnabled();
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,13 +110,6 @@ export class AddonModFeedbackPrefetchHandlerService extends CoreCourseActivityPr
|
|||
return accessData.isopen;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModFeedback.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -72,7 +71,7 @@ export class AddonModFeedbackPrintLinkHandlerService extends CoreContentLinksHan
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifi
|
|||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackHelper } from '../feedback-helper';
|
||||
|
||||
/**
|
||||
|
@ -39,7 +38,7 @@ export class AddonModFeedbackPushClickHandlerService implements CorePushNotifica
|
|||
if (CoreUtils.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'mod_feedback' &&
|
||||
(notification.name == 'submission' || notification.name == 'message')) {
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(notification.site);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
|
||||
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackHelper } from '../feedback-helper';
|
||||
|
||||
/**
|
||||
|
@ -50,7 +49,7 @@ export class AddonModFeedbackShowEntriesLinkHandlerService extends CoreContentLi
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFeedback } from '../feedback';
|
||||
import { AddonModFeedbackModuleHandlerService } from './module';
|
||||
/**
|
||||
* Content links handler for feedback show non respondents.
|
||||
|
@ -67,7 +66,7 @@ export class AddonModFeedbackShowNonRespondentsLinkHandlerService extends CoreCo
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModFeedback.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import { Params } from '@angular/router';
|
|||
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
|
||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { Md5 } from 'ts-md5';
|
||||
import { AddonModFolder, AddonModFolderFolder, AddonModFolderProvider } from '../../services/folder';
|
||||
|
@ -41,7 +40,6 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
|
|||
@Input() subfolder?: AddonModFolderFolderFormattedData; // Subfolder to show.
|
||||
|
||||
component = AddonModFolderProvider.COMPONENT;
|
||||
canGetFolder = false;
|
||||
contents?: AddonModFolderFolderFormattedData;
|
||||
|
||||
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
|
||||
|
@ -54,8 +52,6 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
|
|||
async ngOnInit(): Promise<void> {
|
||||
super.ngOnInit();
|
||||
|
||||
this.canGetFolder = AddonModFolder.isGetFolderWSAvailable();
|
||||
|
||||
if (this.subfolder) {
|
||||
this.description = this.folderInstance ? this.folderInstance.intro : this.module.description;
|
||||
this.contents = this.subfolder;
|
||||
|
@ -98,18 +94,8 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
|
|||
*/
|
||||
protected async fetchContent(refresh = false): Promise<void> {
|
||||
try {
|
||||
if (this.canGetFolder) {
|
||||
this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
|
||||
await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
|
||||
} else {
|
||||
const module = await CoreCourse.getModule(this.module.id, this.courseId);
|
||||
|
||||
if (!module.contents.length && this.module.contents.length && !CoreApp.isOnline()) {
|
||||
// The contents might be empty due to a cached data. Use the old ones.
|
||||
module.contents = this.module.contents;
|
||||
}
|
||||
this.module = module;
|
||||
}
|
||||
this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
|
||||
await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
|
||||
|
||||
this.dataRetrieved.emit(this.folderInstance || this.module);
|
||||
|
||||
|
|
|
@ -122,16 +122,6 @@ export class AddonModFolderProvider {
|
|||
await site.invalidateWsCacheForKey(this.getFolderCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not getFolder WS available or not.
|
||||
*
|
||||
* @return If WS is available.
|
||||
* @since 3.3
|
||||
*/
|
||||
isGetFolderWSAvailable(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('mod_folder_get_folders_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a folder as being viewed.
|
||||
*
|
||||
|
|
|
@ -35,10 +35,7 @@ export class AddonModFolderPrefetchHandlerService extends CoreCourseResourcePref
|
|||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
|
||||
|
||||
if (AddonModFolder.isGetFolderWSAvailable()) {
|
||||
promises.push(AddonModFolder.getFolder(courseId, module.id));
|
||||
}
|
||||
promises.push(AddonModFolder.getFolder(courseId, module.id));
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
|
|
@ -359,12 +359,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
|
|||
* @return Promise resolved with the list of groups.
|
||||
*/
|
||||
protected addAllParticipantsOption(groups: CoreGroup[], check: boolean): Promise<CoreGroup[]> {
|
||||
if (!AddonModForum.isAllParticipantsFixed()) {
|
||||
// All participants has a bug, don't add it.
|
||||
return Promise.resolve(groups);
|
||||
}
|
||||
|
||||
let promise;
|
||||
let promise: Promise<boolean>;
|
||||
|
||||
if (check) {
|
||||
// We need to check if the user can add a discussion to all participants.
|
||||
|
|
|
@ -308,15 +308,6 @@ export class AddonModForumProvider {
|
|||
return index >= 0 ? posts.splice(index, 1).pop() : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* There was a bug adding new discussions to All Participants (see MDL-57962). Check if it's fixed.
|
||||
*
|
||||
* @return True if fixed, false otherwise.
|
||||
*/
|
||||
isAllParticipantsFixed(): boolean {
|
||||
return !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan(['3.1.5', '3.2.2']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not getDiscussionPost WS available or not.
|
||||
*
|
||||
|
|
|
@ -162,7 +162,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
|
|||
this.glossary = await AddonModGlossary.getGlossary(this.courseId, this.module.id);
|
||||
|
||||
this.description = this.glossary.intro || this.description;
|
||||
this.canAdd = (AddonModGlossary.isPluginEnabledForEditing() && !!this.glossary.canaddentry) || false;
|
||||
this.canAdd = !!this.glossary.canaddentry || false;
|
||||
|
||||
this.dataRetrieved.emit(this.glossary);
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import { CoreRatingInfo } from '@features/rating/services/rating';
|
|||
import { CoreTagItem } from '@features/tag/services/tag';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
|
@ -964,11 +963,6 @@ export class AddonModGlossaryProvider {
|
|||
});
|
||||
}
|
||||
|
||||
// Workaround for bug MDL-57737.
|
||||
if (!site.isVersionGreaterEqualThan('3.2.2')) {
|
||||
params.definition = CoreTextUtils.cleanTags(params.definition);
|
||||
}
|
||||
|
||||
const response = await site.write<AddonModGlossaryAddEntryWSResponse>('mod_glossary_add_entry', params);
|
||||
|
||||
return response.entryid;
|
||||
|
@ -1007,16 +1001,6 @@ export class AddonModGlossaryProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled for editing in the current site. Plugin is enabled if the glossary WS are
|
||||
* available.
|
||||
*
|
||||
* @return Whether the glossary editing is available or not.
|
||||
*/
|
||||
isPluginEnabledForEditing(): boolean {
|
||||
return !!CoreSites.getCurrentSite()?.wsAvailable('mod_glossary_add_entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a glossary as being viewed.
|
||||
*
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/c
|
|||
import { CoreCourses } from '@features/courses/services/courses';
|
||||
import { CoreUser } from '@features/user/services/user';
|
||||
import { CoreFilepool } from '@services/filepool';
|
||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
@ -73,16 +73,12 @@ export class AddonModGlossaryPrefetchHandlerService extends CoreCourseActivityPr
|
|||
): CoreWSFile[] {
|
||||
let files = this.getIntroFilesFromInstance(module, glossary);
|
||||
|
||||
const getInlineFiles = CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.2');
|
||||
|
||||
// Get entries files.
|
||||
entries.forEach((entry) => {
|
||||
files = files.concat(entry.attachments || []);
|
||||
|
||||
if (getInlineFiles && entry.definitioninlinefiles && entry.definitioninlinefiles.length) {
|
||||
if (entry.definitioninlinefiles && entry.definitioninlinefiles.length) {
|
||||
files = files.concat(entry.definitioninlinefiles);
|
||||
} else if (entry.definition && !getInlineFiles) {
|
||||
files = files.concat(CoreFilepool.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -744,6 +744,7 @@ export class AddonModH5PActivityProvider {
|
|||
* Delete launcher.
|
||||
*
|
||||
* @return Promise resolved when the launcher file is deleted.
|
||||
* @since 3.9
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
@ -788,7 +789,7 @@ export class AddonModH5PActivityProvider {
|
|||
const site = await CoreSites.getSite(options.siteId);
|
||||
|
||||
if (!site.wsAvailable('mod_h5pactivity_log_report_viewed')) {
|
||||
// Site doesn't support the WS, stop.
|
||||
// Site doesn't support the WS, stop. Added in Moodle 3.11.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreSitesReadingStrategy } from '@services/sites';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreWSFile } from '@services/ws';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModLabel, AddonModLabelLabel, AddonModLabelProvider } from '../label';
|
||||
import { AddonModLabel, AddonModLabelProvider } from '../label';
|
||||
|
||||
/**
|
||||
* Handler to prefetch labels.
|
||||
|
@ -37,13 +37,9 @@ export class AddonModLabelPrefetchHandlerService extends CoreCourseResourcePrefe
|
|||
* @inheritdoc
|
||||
*/
|
||||
async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number, ignoreCache?: boolean): Promise<CoreWSFile[]> {
|
||||
let label: AddonModLabelLabel | undefined;
|
||||
|
||||
if (AddonModLabel.isGetLabelAvailableForSite()) {
|
||||
label = await AddonModLabel.getLabel(courseId, module.id, {
|
||||
readingStrategy: ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined,
|
||||
});
|
||||
}
|
||||
const label = await AddonModLabel.getLabel(courseId, module.id, {
|
||||
readingStrategy: ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined,
|
||||
});
|
||||
|
||||
return this.getIntroFilesFromInstance(module, label);
|
||||
}
|
||||
|
|
|
@ -136,32 +136,6 @@ export class AddonModLabelProvider {
|
|||
await CoreUtils.allPromises(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site has the WS to get label data.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with boolean: whether it's available.
|
||||
* @since 3.3
|
||||
*/
|
||||
async isGetLabelAvailable(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return site.wsAvailable('mod_label_get_labels_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site has the WS to get label data.
|
||||
*
|
||||
* @param site Site. If not defined, current site.
|
||||
* @return Whether it's available.
|
||||
* @since 3.3
|
||||
*/
|
||||
isGetLabelAvailableForSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!site?.wsAvailable('mod_label_get_labels_by_courses');
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModLabel = makeSingleton(AddonModLabelProvider);
|
||||
|
||||
|
|
|
@ -82,21 +82,6 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @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.
|
||||
* @return Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
|
||||
return AddonModLesson.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonModLessonGradeLinkHandler = makeSingleton(AddonModLessonGradeLinkHandlerService);
|
||||
|
|
|
@ -66,21 +66,6 @@ export class AddonModLessonIndexLinkHandlerService extends CoreContentLinksModul
|
|||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled for a certain site (site + user) and a URL.
|
||||
* If not defined, defaults to true.
|
||||
*
|
||||
* @param siteId The site ID.
|
||||
* @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.
|
||||
* @return Whether the handler is enabled for the URL and site.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
|
||||
return AddonModLesson.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a lesson module (index page) with a fixed password.
|
||||
*
|
||||
|
|
|
@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModLesson } from '../lesson';
|
||||
|
||||
/**
|
||||
* Handler to treat links to lesson list page.
|
||||
|
@ -30,16 +29,6 @@ export class AddonModLessonListLinkHandlerService extends CoreContentLinksModule
|
|||
super('AddonModLesson', 'lesson');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled on a site level.
|
||||
*
|
||||
* @return Promise resolved with boolean: whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
|
||||
return AddonModLesson.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const AddonModLessonListLinkHandler = makeSingleton(AddonModLessonListLinkHandlerService);
|
||||
|
|
|
@ -18,7 +18,6 @@ import { CoreConstants } from '@/core/constants';
|
|||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
|
||||
import { CoreCourse, CoreCourseAnyModuleData, CoreCourseWSModule } from '@features/course/services/course';
|
||||
import { CoreCourseModule } from '@features/course/services/course-helper';
|
||||
import { AddonModLesson } from '../lesson';
|
||||
import { AddonModLessonIndexComponent } from '../../components/index';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
|
||||
|
@ -52,8 +51,8 @@ export class AddonModLessonModuleHandlerService implements CoreCourseModuleHandl
|
|||
*
|
||||
* @return Promise resolved with boolean: whether or not the handler is enabled on a site level.
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModLesson.isPluginEnabled();
|
||||
async isEnabled(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -221,15 +221,6 @@ export class AddonModLessonPrefetchHandlerService extends CoreCourseActivityPref
|
|||
(accessInfo.preventaccessreasons.length == 1 && AddonModLesson.isPasswordProtected(accessInfo));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return Promise resolved with a boolean indicating if the handler is enabled.
|
||||
*/
|
||||
isEnabled(): Promise<boolean> {
|
||||
return AddonModLesson.isPluginEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModLesson } from '../lesson';
|
||||
import { AddonModLessonModuleHandlerService } from './module';
|
||||
|
||||
/**
|
||||
|
@ -81,7 +80,7 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
|
|||
return false;
|
||||
}
|
||||
|
||||
return AddonModLesson.isPluginEnabled(siteId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2710,19 +2710,6 @@ export class AddonModLessonProvider {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the lesson WS are available.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
|
||||
*/
|
||||
async isPluginEnabled(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
// All WS were introduced at the same time so checking one is enough.
|
||||
return site.wsAvailable('mod_lesson_get_lesson_access_information');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a page is a question page or a content page.
|
||||
*
|
||||
|
|
|
@ -331,7 +331,7 @@ export type AddonModLtiLti = {
|
|||
name: string; // LTI name.
|
||||
intro?: string; // The LTI intro.
|
||||
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
timecreated?: number; // Time of creation.
|
||||
timemodified?: number; // Time of last modification.
|
||||
typeid?: number; // Type id.
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Component, OnInit, Optional } from '@angular/core';
|
||||
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
|
||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
||||
import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AddonModPageProvider, AddonModPagePage, AddonModPage } from '../../services/page';
|
||||
|
@ -32,12 +32,11 @@ import { AddonModPageHelper } from '../../services/page-helper';
|
|||
export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit {
|
||||
|
||||
component = AddonModPageProvider.COMPONENT;
|
||||
canGetPage = false;
|
||||
contents?: string;
|
||||
displayDescription = true;
|
||||
displayTimemodified = true;
|
||||
timemodified?: number;
|
||||
page?: CoreCourseWSModule | AddonModPagePage;
|
||||
page?: AddonModPagePage;
|
||||
warning?: string;
|
||||
|
||||
protected fetchContentDefaultError = 'addon.mod_page.errorwhileloadingthepage';
|
||||
|
@ -52,8 +51,6 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
|
|||
async ngOnInit(): Promise<void> {
|
||||
super.ngOnInit();
|
||||
|
||||
this.canGetPage = AddonModPage.isGetPageWSAvailable();
|
||||
|
||||
await this.loadContent();
|
||||
|
||||
try {
|
||||
|
@ -103,21 +100,13 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
|
|||
*/
|
||||
protected async loadPageData(): Promise<void> {
|
||||
// Get latest title, description and some extra data. Data should've been updated in download.
|
||||
const page = this.canGetPage ?
|
||||
await AddonModPage.getPageData(this.courseId, this.module.id) :
|
||||
await CoreCourse.getModule(this.module.id, this.courseId);
|
||||
this.page = await AddonModPage.getPageData(this.courseId, this.module.id);
|
||||
|
||||
this.description = 'intro' in page ? page.intro : page.description;
|
||||
this.dataRetrieved.emit(page);
|
||||
|
||||
if (!this.canGetPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.page = page;
|
||||
this.description = this.page.intro;
|
||||
this.dataRetrieved.emit(this.page);
|
||||
|
||||
// Check if description and timemodified should be displayed.
|
||||
if ('displayoptions' in this.page) {
|
||||
if (this.page.displayoptions) {
|
||||
const options: Record<string, string | boolean> =
|
||||
CoreTextUtils.unserialize(this.page.displayoptions) || {};
|
||||
|
||||
|
|
|
@ -42,10 +42,7 @@ export class AddonModPagePrefetchHandlerService extends CoreCourseResourcePrefet
|
|||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
|
||||
|
||||
if (AddonModPage.isGetPageWSAvailable()) {
|
||||
promises.push(AddonModPage.getPageData(courseId, module.id));
|
||||
}
|
||||
promises.push(AddonModPage.getPageData(courseId, module.id));
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
|
|
@ -124,16 +124,6 @@ export class AddonModPageProvider {
|
|||
await site.invalidateWsCacheForKey(this.getPageCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not getPage WS available or not.
|
||||
*
|
||||
* @return If WS is available.
|
||||
* @since 3.3
|
||||
*/
|
||||
isGetPageWSAvailable(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('mod_page_get_pages_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled.
|
||||
*
|
||||
|
|
|
@ -18,7 +18,6 @@ import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
|
|||
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
|
||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { IonContent } from '@ionic/angular';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
|
@ -154,7 +153,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
// If the site doesn't support check updates, always prefetch it because we cannot tell if there's something new.
|
||||
const isDownloaded = this.currentStatus == CoreConstants.DOWNLOADED;
|
||||
|
||||
if (isDownloaded && CoreCourseModulePrefetchDelegate.canCheckUpdates()) {
|
||||
if (isDownloaded) {
|
||||
// Already downloaded, open it.
|
||||
return this.openQuiz();
|
||||
}
|
||||
|
@ -168,7 +167,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
// Success downloading, open quiz.
|
||||
this.openQuiz();
|
||||
} catch (error) {
|
||||
if (this.hasOffline || (isDownloaded && !CoreCourseModulePrefetchDelegate.canCheckUpdates())) {
|
||||
if (this.hasOffline) {
|
||||
// Error downloading but there is something offline, allow continuing it.
|
||||
// If the site doesn't support check updates, continue too because we cannot tell if there's something new.
|
||||
this.openQuiz();
|
||||
|
@ -647,9 +646,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
|
||||
if (data) {
|
||||
this.gradebookData = {
|
||||
grade: 'graderaw' in data && data.graderaw !== undefined && data.graderaw !== null ?
|
||||
data.graderaw :
|
||||
(data.grade !== undefined && data.grade !== null ? Number(data.grade) : undefined),
|
||||
grade: data.graderaw ?? (data.grade !== undefined && data.grade !== null ? Number(data.grade) : undefined),
|
||||
feedback: data.feedback,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -111,7 +111,6 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
|
|||
attempts: AddonModQuizAttemptWSData[],
|
||||
siteId?: string,
|
||||
): Promise<CoreWSFile[]> {
|
||||
const getInlineFiles = CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.2');
|
||||
let files: CoreWSFile[] = [];
|
||||
|
||||
await Promise.all(attempts.map(async (attempt) => {
|
||||
|
@ -131,12 +130,8 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
|
|||
siteId,
|
||||
});
|
||||
|
||||
if (getInlineFiles && feedback.feedbackinlinefiles?.length) {
|
||||
if (feedback.feedbackinlinefiles?.length) {
|
||||
files = files.concat(feedback.feedbackinlinefiles);
|
||||
} else if (feedback.feedbacktext && !getInlineFiles) {
|
||||
files = files.concat(
|
||||
CoreFilepool.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext),
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -526,7 +521,7 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
|
|||
try {
|
||||
const gradebookData = await AddonModQuiz.getGradeFromGradebook(quiz.course, quiz.coursemodule, true, siteId);
|
||||
|
||||
if (gradebookData && 'graderaw' in gradebookData && gradebookData.graderaw !== undefined) {
|
||||
if (gradebookData && gradebookData.graderaw !== undefined) {
|
||||
await AddonModQuiz.getFeedbackForGrade(quiz.id, gradebookData.graderaw, modOptions);
|
||||
}
|
||||
} catch {
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreWSError } from '@classes/errors/wserror';
|
|||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
|
||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
||||
import { CoreGradesFormattedItem, CoreGradesFormattedRow, CoreGradesHelper } from '@features/grades/services/grades-helper';
|
||||
import { CoreGradesFormattedItem, CoreGradesHelper } from '@features/grades/services/grades-helper';
|
||||
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
|
||||
import {
|
||||
CoreQuestion,
|
||||
|
@ -647,7 +647,7 @@ export class AddonModQuizProvider {
|
|||
ignoreCache?: boolean,
|
||||
siteId?: string,
|
||||
userId?: number,
|
||||
): Promise<CoreGradesFormattedItem | CoreGradesFormattedRow | undefined> {
|
||||
): Promise<CoreGradesFormattedItem | undefined> {
|
||||
|
||||
const items = await CoreGradesHelper.getGradeModuleItems(
|
||||
courseId,
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
|
|||
import { CoreError } from '@classes/errors/error';
|
||||
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
|
||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
|
||||
import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreFileHelper } from '@services/file-helper';
|
||||
|
@ -30,7 +30,6 @@ import {
|
|||
AddonModResource,
|
||||
AddonModResourceCustomData,
|
||||
AddonModResourceProvider,
|
||||
AddonModResourceResource,
|
||||
} from '../../services/resource';
|
||||
import { AddonModResourceHelper } from '../../services/resource-helper';
|
||||
|
||||
|
@ -45,7 +44,6 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
|
||||
component = AddonModResourceProvider.COMPONENT;
|
||||
|
||||
canGetResource = false;
|
||||
mode = '';
|
||||
src = '';
|
||||
contentText = '';
|
||||
|
@ -69,7 +67,6 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
async ngOnInit(): Promise<void> {
|
||||
super.ngOnInit();
|
||||
|
||||
this.canGetResource = AddonModResource.isGetResourceWSAvailable();
|
||||
this.isIOS = CoreApp.isIOS();
|
||||
this.isOnline = CoreApp.isOnline();
|
||||
|
||||
|
@ -110,26 +107,17 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
|
|||
throw new CoreError(Translate.instant('core.filenotfound'));
|
||||
}
|
||||
|
||||
let resource: AddonModResourceResource | CoreCourseWSModule | undefined;
|
||||
let options: AddonModResourceCustomData = {};
|
||||
let hasCalledDownloadResource = false;
|
||||
|
||||
// Get the resource instance to get the latest name/description and to know if it's embedded.
|
||||
if (this.canGetResource) {
|
||||
resource = await AddonModResource.getResourceData(this.courseId, this.module.id);
|
||||
this.description = resource.intro || '';
|
||||
options = resource.displayoptions ? CoreTextUtils.unserialize(resource.displayoptions) : {};
|
||||
} else {
|
||||
resource = await CoreCourse.getModule(this.module.id, this.courseId);
|
||||
this.description = resource.description || '';
|
||||
options = resource.customdata ? CoreTextUtils.unserialize(CoreTextUtils.parseJSON(resource.customdata)) : {};
|
||||
}
|
||||
const resource = await AddonModResource.getResourceData(this.courseId, this.module.id);
|
||||
this.description = resource.intro || '';
|
||||
const options: AddonModResourceCustomData =
|
||||
resource.displayoptions ? CoreTextUtils.unserialize(resource.displayoptions) : {};
|
||||
|
||||
try {
|
||||
if (resource) {
|
||||
this.displayDescription = typeof options.printintro == 'undefined' || !!options.printintro;
|
||||
this.dataRetrieved.emit(resource);
|
||||
}
|
||||
this.displayDescription = typeof options.printintro == 'undefined' || !!options.printintro;
|
||||
this.dataRetrieved.emit(resource);
|
||||
|
||||
if (AddonModResourceHelper.isDisplayedInIframe(this.module)) {
|
||||
hasCalledDownloadResource = true;
|
||||
|
|
|
@ -156,7 +156,7 @@ export class AddonModResourceModuleHandlerService implements CoreCourseModuleHan
|
|||
|
||||
if ('customdata' in module && typeof module.customdata != 'undefined') {
|
||||
options = CoreTextUtils.unserialize(CoreTextUtils.parseJSON(module.customdata));
|
||||
} else if (AddonModResource.isGetResourceWSAvailable()) {
|
||||
} else {
|
||||
// Get the resource data.
|
||||
promises.push(AddonModResource.getResourceData(courseId, module.id).then((info) => {
|
||||
infoFiles = info.contentfiles;
|
||||
|
|
|
@ -67,10 +67,7 @@ export class AddonModResourcePrefetchHandlerService extends CoreCourseResourcePr
|
|||
const promises: Promise<unknown>[] = [];
|
||||
|
||||
promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath));
|
||||
|
||||
if (AddonModResource.isGetResourceWSAvailable()) {
|
||||
promises.push(AddonModResource.getResourceData(courseId, module.id));
|
||||
}
|
||||
promises.push(AddonModResource.getResourceData(courseId, module.id));
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
|
|
@ -130,16 +130,6 @@ export class AddonModResourceProvider {
|
|||
await site.invalidateWsCacheForKey(this.getResourceCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not getResource WS available or not.
|
||||
*
|
||||
* @return If WS is abalaible.
|
||||
* @since 3.3
|
||||
*/
|
||||
isGetResourceWSAvailable(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('mod_resource_get_resources_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the plugin is enabled.
|
||||
*
|
||||
|
|
|
@ -1612,11 +1612,6 @@ export class AddonModScormProvider {
|
|||
};
|
||||
const wsFunction = 'mod_scorm_insert_scorm_tracks';
|
||||
|
||||
// Check if the method is available, use a prefixed version if possible.
|
||||
if (!currentSite.wsAvailable(wsFunction, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = CoreWS.syncCall<AddonModScormInsertScormTracksWSResponse>(wsFunction, params, preSets);
|
||||
|
||||
|
|
|
@ -322,7 +322,7 @@ export type AddonModSurveySurvey = {
|
|||
name: string; // Survey name.
|
||||
intro?: string; // The Survey intro.
|
||||
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
||||
introfiles?: CoreWSExternalFile[];
|
||||
template?: number; // Survey type.
|
||||
days?: number; // Days.
|
||||
questions?: string; // Question ids.
|
||||
|
|
|
@ -36,7 +36,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
|
|||
|
||||
component = AddonModUrlProvider.COMPONENT;
|
||||
|
||||
canGetUrl = false;
|
||||
url?: string;
|
||||
name?: string;
|
||||
shouldEmbed = false;
|
||||
|
@ -58,8 +57,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
|
|||
async ngOnInit(): Promise<void> {
|
||||
super.ngOnInit();
|
||||
|
||||
this.canGetUrl = AddonModUrl.isGetUrlWSAvailable();
|
||||
|
||||
await this.loadContent();
|
||||
|
||||
if ((this.shouldIframe ||
|
||||
|
@ -86,9 +83,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
|
|||
*/
|
||||
protected async fetchContent(refresh = false): Promise<void> {
|
||||
try {
|
||||
if (!this.canGetUrl) {
|
||||
throw null;
|
||||
}
|
||||
// Fetch the module data.
|
||||
const url = await AddonModUrl.getUrl(this.courseId, this.module.id);
|
||||
|
||||
|
@ -110,7 +104,7 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
|
|||
await this.calculateDisplayOptions(url);
|
||||
|
||||
} catch {
|
||||
// Fallback in case is not prefetched or not available.
|
||||
// Fallback in case is not prefetched.
|
||||
const mod =
|
||||
await CoreCourse.getModule(this.module.id, this.courseId, undefined, false, false, undefined, 'url');
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
|
|||
if (canHandle) {
|
||||
// URL handled by the app, open it directly.
|
||||
return true;
|
||||
} else if (AddonModUrl.isGetUrlWSAvailable()) {
|
||||
} else {
|
||||
// Not handled by the app, check the display type.
|
||||
const url = await CoreUtils.ignoreErrors(AddonModUrl.getUrl(courseId, module.id));
|
||||
const displayType = AddonModUrl.getFinalDisplayType(url);
|
||||
|
@ -183,8 +183,6 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
|
|||
return displayType == CoreConstants.RESOURCELIB_DISPLAY_OPEN ||
|
||||
displayType == CoreConstants.RESOURCELIB_DISPLAY_POPUP;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -206,16 +206,6 @@ export class AddonModUrlProvider {
|
|||
await site.invalidateWsCacheForKey(this.getUrlCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not getUrl WS available or not.
|
||||
*
|
||||
* @return If WS is abalaible.
|
||||
* @since 3.3
|
||||
*/
|
||||
isGetUrlWSAvailable(): boolean {
|
||||
return CoreSites.wsAvailableInCurrentSite('mod_url_get_urls_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the url as being viewed.
|
||||
*
|
||||
|
|
|
@ -178,9 +178,7 @@ export class AddonModWikiProvider {
|
|||
if (section) {
|
||||
params.section = section;
|
||||
}
|
||||
|
||||
// This parameter requires Moodle 3.2. It saves network usage.
|
||||
if (lockOnly && site.isVersionGreaterEqualThan('3.2')) {
|
||||
if (lockOnly) {
|
||||
params.lockonly = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModWorkshopProvider, AddonModWorkshop } from '../workshop';
|
||||
import { AddonModWorkshopProvider } from '../workshop';
|
||||
/**
|
||||
* Handler to treat links to workshop.
|
||||
*/
|
||||
|
@ -28,12 +28,5 @@ export class AddonModWorkshopIndexLinkHandlerService extends CoreContentLinksMod
|
|||
super(AddonModWorkshopProvider.COMPONENT, 'workshop', 'w');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
isEnabled(siteId: string): Promise<boolean> {
|
||||
return AddonModWorkshop.isPluginEnabled(siteId);
|
||||
}
|
||||
|
||||
}
|
||||
export const AddonModWorkshopIndexLinkHandler = makeSingleton(AddonModWorkshopIndexLinkHandlerService);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue