Merge pull request #2220 from crazyserver/MOBILE-3213

Mobile 3213
main
Juan Leyva 2019-12-18 12:45:40 +01:00 committed by GitHub
commit 62ce8a3536
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 125 additions and 45 deletions

View File

@ -1,6 +1,6 @@
<ion-item-divider>
<h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2>
<div *ngIf="downloadEnabled && courses && courses.length > 1" class="core-button-spinner" item-end>
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" item-end>
<button *ngIf="prefetchCoursesData.icon && prefetchCoursesData.icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<core-icon [name]="prefetchCoursesData.icon"></core-icon>
</button>
@ -13,7 +13,7 @@
<!-- List of courses. -->
<div class="core-horizontal-scroll">
<ng-container *ngFor="let course of courses">
<core-courses-course-progress [course]="course" class="core-recentlyaccessedcourses" [showDownload]="downloadEnabled"></core-courses-course-progress>
<core-courses-course-progress [course]="course" class="core-recentlyaccessedcourses" [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
</ng-container>
</div>
</core-loading>

View File

@ -37,10 +37,13 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
icon: '',
badge: ''
};
downloadCourseEnabled: boolean;
downloadCoursesEnabled: boolean;
protected prefetchIconsInitialized = false;
protected isDestroyed;
protected coursesObserver;
protected updateSiteObserver;
protected courseIds = [];
protected fetchContentDefaultError = 'Error getting recent courses data.';
@ -58,6 +61,17 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
*/
ngOnInit(): void {
// Refresh the enabled flags if enabled.
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
// Refresh the enabled flags if site is updated.
this.updateSiteObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
}, this.sitesProvider.getCurrentSiteId());
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.refreshContent();
}, this.sitesProvider.getCurrentSiteId());
@ -154,5 +168,6 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
ngOnDestroy(): void {
this.isDestroyed = true;
this.coursesObserver && this.coursesObserver.off();
this.updateSiteObserver && this.updateSiteObserver.off();
}
}

View File

@ -1,6 +1,6 @@
<ion-item-divider>
<h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2>
<div *ngIf="downloadEnabled && courses && courses.length > 1" class="core-button-spinner" item-end>
<div *ngIf="downloadCoursesEnabled && downloadEnabled && courses && courses.length > 1" class="core-button-spinner" item-end>
<button *ngIf="prefetchCoursesData.icon && prefetchCoursesData.icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
<core-icon [name]="prefetchCoursesData.icon"></core-icon>
</button>
@ -13,7 +13,7 @@
<!-- List of courses. -->
<div class="core-horizontal-scroll">
<ng-container *ngFor="let course of courses">
<core-courses-course-progress [course]="course" class="core-block_starredcourses" [showDownload]="downloadEnabled"></core-courses-course-progress>
<core-courses-course-progress [course]="course" class="core-block_starredcourses" [showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-progress>
</ng-container>
</div>
</core-loading>

View File

@ -37,10 +37,13 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
icon: '',
badge: ''
};
downloadCourseEnabled: boolean;
downloadCoursesEnabled: boolean;
protected prefetchIconsInitialized = false;
protected isDestroyed;
protected coursesObserver;
protected updateSiteObserver;
protected courseIds = [];
protected fetchContentDefaultError = 'Error getting starred courses data.';
@ -58,6 +61,17 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
*/
ngOnInit(): void {
// Refresh the enabled flags if enabled.
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
// Refresh the enabled flags if site is updated.
this.updateSiteObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
this.downloadCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
}, this.sitesProvider.getCurrentSiteId());
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.refreshContent();
}, this.sitesProvider.getCurrentSiteId());
@ -154,5 +168,6 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
ngOnDestroy(): void {
this.isDestroyed = true;
this.coursesObserver && this.coursesObserver.off();
this.updateSiteObserver && this.updateSiteObserver.off();
}
}

View File

@ -14,3 +14,32 @@ ion-app.app-root addon-block-timeline-events {
pointer-events: auto;
}
}
ion-app.app-root core-courses-course-progress addon-block-timeline-events {
@include media-breakpoint-up(md) {
.hidden-tablet {
display: block !important;
opacity: 1 !important;
&.button[disabled] {
opacity: .4 !important;
}
}
.hidden-phone {
display: none !important;
opacity: 0 !important;
}
}
@include media-breakpoint-up(lg) {
.hidden-tablet {
display: none !important;
opacity: 0 !important;
}
.hidden-phone {
display: block !important;
opacity: 1 !important;
&.button[disabled] {
opacity: .4 !important;
}
}
}
}

View File

@ -29,6 +29,7 @@ import { CoreSyncBaseProvider } from '@classes/base-sync';
import { AddonModAssignProvider, AddonModAssignAssign } from './assign';
import { AddonModAssignOfflineProvider } from './assign-offline';
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
/**
* Data returned by an assign sync.
@ -55,13 +56,22 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
protected componentTranslate: string;
constructor(loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider,
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
private courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
private assignProvider: AddonModAssignProvider, private assignOfflineProvider: AddonModAssignOfflineProvider,
private utils: CoreUtilsProvider, private submissionDelegate: AddonModAssignSubmissionDelegate,
private gradesHelper: CoreGradesHelperProvider, timeUtils: CoreTimeUtilsProvider,
private logHelper: CoreCourseLogHelperProvider) {
constructor(loggerProvider: CoreLoggerProvider,
sitesProvider: CoreSitesProvider,
appProvider: CoreAppProvider,
syncProvider: CoreSyncProvider,
textUtils: CoreTextUtilsProvider,
translate: TranslateService,
timeUtils: CoreTimeUtilsProvider,
protected courseProvider: CoreCourseProvider,
protected eventsProvider: CoreEventsProvider,
protected assignProvider: AddonModAssignProvider,
protected assignOfflineProvider: AddonModAssignOfflineProvider,
protected utils: CoreUtilsProvider,
protected submissionDelegate: AddonModAssignSubmissionDelegate,
protected feedbackDelegate: AddonModAssignFeedbackDelegate,
protected gradesHelper: CoreGradesHelperProvider,
protected logHelper: CoreCourseLogHelperProvider) {
super('AddonModAssignSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
timeUtils);
@ -403,9 +413,19 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
return this.assignProvider.submitGradingFormOnline(assign.id, userId, offlineData.grade, offlineData.attemptnumber,
offlineData.addattempt, offlineData.workflowstate, offlineData.applytoall, offlineData.outcomes,
offlineData.plugindata, siteId).then(() => {
// Grades sent.
// Discard grades drafts.
const promises = [];
if (status.feedback && status.feedback.plugins) {
status.feedback.plugins.forEach((plugin) => {
promises.push(this.feedbackDelegate.discardPluginFeedbackData(assign.id, userId, plugin, siteId));
});
}
// Grades sent, update cached data. No need to block the user for this.
this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
// Update cached data.
promises.push(this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId));
return Promise.all(promises);
}).catch((error) => {
if (error && this.utils.isWebServiceError(error)) {
// The WebService has thrown an error, this means it cannot be submitted. Discard the offline data.

View File

@ -286,6 +286,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
let entriesHTML = this.dataHelper.getTemplate(this.data, 'listtemplateheader', this.fieldsArray);
console.error(entriesHTML);
// Get first entry from the whole list.
if (!this.search.searching || !this.firstEntry) {
this.firstEntry = this.entries[0].id;
@ -305,7 +306,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
});
entriesHTML += this.dataHelper.getTemplate(this.data, 'listtemplatefooter', this.fieldsArray);
this.entriesRendered = entriesHTML;
this.entriesRendered = this.domUtils.fixHtml(entriesHTML);
console.error(entriesHTML);
// Pass the input data to the component.
this.jsData = {

View File

@ -3,6 +3,7 @@
white-space: normal;
word-break: break-word;
padding: $content-padding;
@include safe-area-padding-horizontal($content-padding !important, $content-padding !important);
background-color: $white;
border-top-width: 1px;
border-bottom-width: 1px;
@ -31,6 +32,18 @@
@extend .col;
min-height: auto;
}
// Do not let block elements to define widths or heights.
address, article, aside, blockquote, canvas, dd, div, dl, dt, fieldset, figcaption, figure, footer, form, h1, h2, h3, h4, h5, h6,
header, hr, li, main, nav, noscript, ol, p, pre, section, table, tfoot, ul, video {
width: auto !important;
height: auto !important;
min-width: auto !important;
min-height: auto !important;
// Avoid having one entry over another.
max-height: none !important;
}
}
page-addon-mod-data-search,

View File

@ -599,8 +599,10 @@ export class AddonModDataHelperProvider {
getTemplate(data: any, type: string, fields: any[]): string {
let template = data[type] || this.getDefaultTemplate(type, fields);
// Try to fix syntax errors so the template can be parsed by Angular.
template = this.domUtils.fixHtml(template);
if (type != 'listtemplateheader' && type != 'listtemplatefooter') {
// Try to fix syntax errors so the template can be parsed by Angular.
template = this.domUtils.fixHtml(template);
}
// Add core-link directive to links.
template = template.replace(/<a ([^>]*href="[^>]*)>/ig, (match, attributes) => {

View File

@ -154,6 +154,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
promises.push(this.workshopProvider.invalidateReviewerAssesmentsData(this.workshop.id));
}
promises.push(this.workshopProvider.invalidateGradesData(this.workshop.id));
promises.push(this.workshopProvider.invalidateWorkshopWSData(this.workshop.id));
}
return Promise.all(promises);

View File

@ -9,7 +9,7 @@
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshAssessment($event)">
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshAssessment($event)" *ngIf="!evaluating">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded">

View File

@ -9,9 +9,6 @@
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshSubmission($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded">
<form ion-list [formGroup]="editForm" *ngIf="workshop">
<ion-item text-wrap>

View File

@ -274,26 +274,6 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy {
return false;
}
/**
* Pull to refresh.
*
* @param refresher Refresher.
*/
refreshSubmission(refresher: any): void {
if (this.loaded) {
const promises = [];
promises.push(this.workshopProvider.invalidateSubmissionData(this.workshopId, this.submission.id));
promises.push(this.workshopProvider.invalidateSubmissionsData(this.workshopId));
Promise.all(promises).finally(() => {
return this.fetchSubmissionData();
}).finally(() => {
refresher.complete();
});
}
}
/**
* Save the submission.
*/

View File

@ -12,7 +12,7 @@
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshSubmission($event)">
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshSubmission($event)" *ngIf="!((assessmentId && access.assessingallowed) || canAddFeedback)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="loaded">

View File

@ -373,6 +373,10 @@ export class AddonModWorkshopSubmissionPage implements OnInit, OnDestroy {
promises.push(this.workshopProvider.invalidateAssessmentData(this.workshopId, this.assessmentId));
}
if (this.assessmentUserId) {
promises.push(this.workshopProvider.invalidateReviewerAssesmentsData(this.workshopId, this.assessmentId));
}
return Promise.all(promises).finally(() => {
this.eventsProvider.trigger(AddonModWorkshopProvider.ASSESSMENT_INVALIDATED, this.siteId);

View File

@ -68,7 +68,7 @@ export class AddonModWorkshopHelperProvider {
const task = this.getTask(tasks, taskCode);
if (task) {
return task.completed;
return !!task.completed;
}
// Task not found, assume true.

View File

@ -33,9 +33,9 @@ export class AddonModWorkshopProvider {
static PHASE_ASSESSMENT = 30;
static PHASE_EVALUATION = 40;
static PHASE_CLOSED = 50;
static EXAMPLES_VOLUNTARY: 0;
static EXAMPLES_BEFORE_SUBMISSION: 1;
static EXAMPLES_BEFORE_ASSESSMENT: 2;
static EXAMPLES_VOLUNTARY = 0;
static EXAMPLES_BEFORE_SUBMISSION = 1;
static EXAMPLES_BEFORE_ASSESSMENT = 2;
static SUBMISSION_TYPE_DISABLED = 0;
static SUBMISSION_TYPE_AVAILABLE = 1;
static SUBMISSION_TYPE_REQUIRED = 2;

View File

@ -25,6 +25,7 @@ ion-app.app-root .ion-page {
color: $core-dark-link-color;
}
.core-tabs-bar,
.core-tabs-bar *,
.core-tabs-bar .tab-slide,
.ion-page,

View File

@ -474,6 +474,7 @@ $core-dd-question-colors: $white, $blue-light, #DCDCDC, #D8BFD8, #87CEFA, #DAA52
}
@mixin safe-area-position($top: null, $end: null, $bottom: null, $start: null) {
@include position-horizontal($start, $end);
@include safe-position-horizontal($start, $end);
top: $top;
bottom: $bottom;