commit
9ff408d3b9
|
@ -176,6 +176,8 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
|||
* @inheritdoc
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
super.ngOnChanges(changes);
|
||||
|
||||
if (this.loaded && changes.block) {
|
||||
// Block was re-fetched, load content.
|
||||
this.reloadContent();
|
||||
|
|
|
@ -1089,11 +1089,11 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
|
|||
// Only show outcomes with info on it, outcomeid could be null if outcomes are disabled on site.
|
||||
gradeInfo.outcomes?.forEach((outcome) => {
|
||||
if (outcome.id == String(grade.outcomeid)) {
|
||||
outcome.selected = grade.gradeformatted;
|
||||
// Clean HTML tags, grade can contain an icon.
|
||||
outcome.selected = CoreTextUtils.cleanTags(grade.gradeformatted || '');
|
||||
outcome.modified = grade.gradedategraded;
|
||||
if (outcome.options) {
|
||||
outcome.selectedId =
|
||||
CoreGradesHelper.getGradeValueFromLabel(outcome.options, outcome.selected || '');
|
||||
outcome.selectedId = CoreGradesHelper.getGradeValueFromLabel(outcome.options, outcome.selected);
|
||||
this.originalGrades.outcomes[outcome.id] = outcome.selectedId;
|
||||
outcome.itemNumber = grade.itemnumber;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
<ion-item *ngIf="model[modelValueName]">
|
||||
<ion-label color="success">{{ 'core.answered' | translate }}</ion-label>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="expired" class="ion-text-wrap">
|
||||
<ion-item *ngIf="expired" class="ion-text-wrap core-input-error">
|
||||
<ion-label color="danger">{{ 'core.login.recaptchaexpired' | translate }}</ion-label>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="showRequiredError && !model[modelValueName] && !expired" class="ion-text-wrap core-input-error">
|
||||
<ion-label color="danger">{{ 'core.required' | translate }}</ion-label>
|
||||
</ion-item>
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,7 @@ export class CoreRecaptchaComponent implements OnInit {
|
|||
@Input() publicKey?: string; // The site public key.
|
||||
@Input() modelValueName = 'recaptcharesponse'; // Name of the model property where to store the response.
|
||||
@Input() siteUrl = ''; // The site URL. If not defined, current site.
|
||||
@Input() showRequiredError = false; // Whether to display the required error if recaptcha hasn't been answered.
|
||||
|
||||
expired = false;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { OnInit, Input, Component, Optional, Inject } from '@angular/core';
|
||||
import { OnInit, Input, Component, Optional, Inject, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
|
@ -30,7 +30,7 @@ import { CorePromisedValue } from '@classes/promised-value';
|
|||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export abstract class CoreBlockBaseComponent implements OnInit, ICoreBlockComponent, AsyncDirective {
|
||||
export abstract class CoreBlockBaseComponent implements OnInit, OnChanges, ICoreBlockComponent, AsyncDirective {
|
||||
|
||||
@Input() title!: string; // The block title.
|
||||
@Input() block!: CoreCourseBlock; // The block to render.
|
||||
|
@ -54,15 +54,31 @@ export abstract class CoreBlockBaseComponent implements OnInit, ICoreBlockCompon
|
|||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
if (this.block.configs && this.block.configs.length > 0) {
|
||||
this.block.configs.forEach((config) => {
|
||||
config.value = CoreTextUtils.parseJSON(config.value);
|
||||
});
|
||||
await this.loadContent();
|
||||
}
|
||||
|
||||
this.block.configsRecord = CoreUtils.arrayToObject(this.block.configs, 'name');
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes.block) {
|
||||
this.parseConfigs();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configs if needed.
|
||||
*/
|
||||
protected parseConfigs(): void {
|
||||
if (!this.block.configs?.length || this.block.configsRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.loadContent();
|
||||
this.block.configs.forEach((config) => {
|
||||
config.value = CoreTextUtils.parseJSON(config.value);
|
||||
});
|
||||
|
||||
this.block.configsRecord = CoreUtils.arrayToObject(this.block.configs, 'name');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -193,7 +193,6 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
|
||||
this.siteName = this.siteConfig.sitename;
|
||||
this.logoUrl = CoreLoginHelper.getLogoUrl(this.siteConfig);
|
||||
this.authInstructions = this.siteConfig.authinstructions || Translate.instant('core.login.loginsteps');
|
||||
this.showScanQR = await CoreLoginHelper.displayQRInCredentialsScreen(this.siteConfig.tool_mobile_qrcodetype);
|
||||
|
||||
const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig);
|
||||
|
@ -204,6 +203,8 @@ export class CoreLoginCredentialsPage implements OnInit, OnDestroy {
|
|||
!!this.supportConfig?.canContactSupport(),
|
||||
this.showForgottenPassword,
|
||||
);
|
||||
this.authInstructions = this.siteConfig.authinstructions ||
|
||||
(this.canSignup ? Translate.instant('core.login.loginsteps') : '');
|
||||
|
||||
if (!this.eventThrown && !this.viewLeft) {
|
||||
this.eventThrown = true;
|
||||
|
|
|
@ -21,13 +21,13 @@
|
|||
<div class="list-item-limited-width">
|
||||
|
||||
<!-- Site has an unsupported required field. -->
|
||||
<ion-list *ngIf="!allRequiredSupported">
|
||||
<ion-list *ngIf="!allRequiredSupported" class="ion-padding">
|
||||
<ion-item class="ion-text-wrap">
|
||||
<ion-label>
|
||||
{{ 'core.login.signuprequiredfieldnotsupported' | translate }}
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-button expand="block" class="ion-margin" [href]="signupUrl" core-link autoLogin="no" [showBrowserWarning]="false">
|
||||
<ion-button expand="block" [href]="signupUrl" core-link autoLogin="no" [showBrowserWarning]="false">
|
||||
{{ 'core.openinbrowser' | translate }}
|
||||
</ion-button>
|
||||
</ion-list>
|
||||
|
@ -62,9 +62,11 @@
|
|||
</ion-item>
|
||||
|
||||
<!-- Submit button. -->
|
||||
<ion-button expand="block" class="ion-margin" type="submit" [disabled]="!ageVerificationForm.valid">
|
||||
{{ 'core.proceed' | translate }}
|
||||
</ion-button>
|
||||
<div class="ion-padding">
|
||||
<ion-button expand="block" type="submit" [disabled]="!ageVerificationForm.valid">
|
||||
{{ 'core.proceed' | translate }}
|
||||
</ion-button>
|
||||
</div>
|
||||
|
||||
<ion-item class="ion-text-wrap">
|
||||
<ion-label>
|
||||
|
@ -186,7 +188,8 @@
|
|||
<h2><span [core-mark-required]="true">{{ 'core.login.security_question' | translate }}</span></h2>
|
||||
</ion-label>
|
||||
</ion-item-divider>
|
||||
<core-recaptcha [publicKey]="settings.recaptchapublickey" [model]="captcha" [siteUrl]="siteUrl"></core-recaptcha>
|
||||
<core-recaptcha [publicKey]="settings.recaptchapublickey" [model]="captcha" [siteUrl]="siteUrl"
|
||||
[showRequiredError]="formSubmitClicked"></core-recaptcha>
|
||||
</ng-container>
|
||||
|
||||
<!-- Site policy (if any). -->
|
||||
|
@ -213,10 +216,12 @@
|
|||
</ion-item>
|
||||
</ng-container>
|
||||
|
||||
<!-- Submit button. -->
|
||||
<ion-button expand="block" class="ion-margin" type="submit">{{ 'core.login.createaccount' | translate }}</ion-button>
|
||||
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
||||
<input type="submit" class="core-submit-hidden-enter" />
|
||||
<div class="ion-padding">
|
||||
<!-- Submit button. -->
|
||||
<ion-button expand="block" type="submit">{{ 'core.login.createaccount' | translate }}</ion-button>
|
||||
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
||||
<input type="submit" class="core-submit-hidden-enter" />
|
||||
</div>
|
||||
</form>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
@ -239,9 +244,11 @@
|
|||
<p *ngIf="supportEmail">{{ supportEmail }}</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-button *ngIf="!supportName && !supportEmail" expand="block" class="ion-margin" (click)="showContactOnSite()">
|
||||
{{ 'core.openinbrowser' | translate }}
|
||||
</ion-button>
|
||||
<div class="ion-padding">
|
||||
<ion-button *ngIf="!supportName && !supportEmail" expand="block" (click)="showContactOnSite()">
|
||||
{{ 'core.openinbrowser' | translate }}
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-list>
|
||||
</div>
|
||||
</ion-content>
|
||||
|
|
|
@ -60,6 +60,7 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
settingsLoaded = false;
|
||||
allRequiredSupported = true;
|
||||
signupUrl?: string;
|
||||
formSubmitClicked = false;
|
||||
captcha = {
|
||||
recaptcharesponse: '',
|
||||
};
|
||||
|
@ -265,6 +266,8 @@ export class CoreLoginEmailSignupPage implements OnInit {
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.formSubmitClicked = true;
|
||||
|
||||
if (!this.signupForm.valid || (this.settings?.recaptchapublickey && !this.captcha.recaptcharesponse)) {
|
||||
// Form not valid. Mark all controls as dirty to display errors.
|
||||
for (const name in this.signupForm.controls) {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 30 KiB |
|
@ -75,7 +75,7 @@
|
|||
</ion-label>
|
||||
<ion-toggle [(ngModel)]="debugDisplay" (ionChange)="debugDisplayChanged($event)" slot="end"></ion-toggle>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap" *ngIf="analyticsSupported">
|
||||
<ion-item class="ion-text-wrap" *ngIf="analyticsAvailable">
|
||||
<ion-label>
|
||||
<p class="item-heading">{{ 'core.settings.enableanalytics' | translate }}</p>
|
||||
<p>{{ 'core.settings.enableanalyticsdescription' | translate }}</p>
|
||||
|
|
|
@ -44,7 +44,7 @@ export class CoreSettingsGeneralPage {
|
|||
selectedZoomLevel = CoreZoomLevel.NONE;
|
||||
richTextEditor = true;
|
||||
debugDisplay = false;
|
||||
analyticsSupported = false;
|
||||
analyticsAvailable = false;
|
||||
analyticsEnabled = false;
|
||||
colorSchemes: CoreColorScheme[] = [];
|
||||
selectedScheme: CoreColorScheme = CoreColorScheme.LIGHT;
|
||||
|
@ -101,8 +101,8 @@ export class CoreSettingsGeneralPage {
|
|||
|
||||
this.debugDisplay = await CoreConfig.get(CoreConstants.SETTINGS_DEBUG_DISPLAY, false);
|
||||
|
||||
this.analyticsSupported = CoreAnalytics.hasHandlers();
|
||||
if (this.analyticsSupported) {
|
||||
this.analyticsAvailable = await CoreAnalytics.isAnalyticsAvailable();
|
||||
if (this.analyticsAvailable) {
|
||||
this.analyticsEnabled = await CoreConfig.get(CoreConstants.SETTINGS_ANALYTICS_ENABLED, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,29 @@ export class CoreAnalyticsService extends CoreDelegate<CoreAnalyticsHandler> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if analytics is available for the app/site.
|
||||
*
|
||||
* @returns True if available, false otherwise.
|
||||
*/
|
||||
async isAnalyticsAvailable(): Promise<boolean> {
|
||||
if (Object.keys(this.enabledHandlers).length > 0) {
|
||||
// There is an enabled handler, analytics is available.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if there is a handler that is enabled at app level (enabled handlers are only set when logged in).
|
||||
const enabledList = await Promise.all(Object.values(this.handlers).map(handler => {
|
||||
if (!handler.appLevelEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return handler.isEnabled();
|
||||
}));
|
||||
|
||||
return enabledList.includes(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an event for the current site.
|
||||
*
|
||||
|
@ -108,6 +131,11 @@ export const CoreAnalytics = makeSingleton(CoreAnalyticsService);
|
|||
*/
|
||||
export interface CoreAnalyticsHandler extends CoreDelegateHandler {
|
||||
|
||||
/**
|
||||
* If true it means that the handler is enabled or not for the whole app, it doesn't depend on the site.
|
||||
*/
|
||||
appLevelEnabled?: boolean;
|
||||
|
||||
/**
|
||||
* Log an event.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue