Merge pull request #2982 from crazyserver/MOBILE-3899
MOBILE-3899 mainmenu: Hide main menu on navigation level > 1main
commit
72a9f498ef
|
@ -1439,8 +1439,6 @@
|
||||||
"core.completion-alt-manual-y-override": "completion",
|
"core.completion-alt-manual-y-override": "completion",
|
||||||
"core.confirmcanceledit": "local_moodlemobileapp",
|
"core.confirmcanceledit": "local_moodlemobileapp",
|
||||||
"core.confirmdeletefile": "repository",
|
"core.confirmdeletefile": "repository",
|
||||||
"core.confirmgotabroot": "local_moodlemobileapp",
|
|
||||||
"core.confirmgotabrootdefault": "local_moodlemobileapp",
|
|
||||||
"core.confirmleaveunknownchanges": "local_moodlemobileapp",
|
"core.confirmleaveunknownchanges": "local_moodlemobileapp",
|
||||||
"core.confirmloss": "local_moodlemobileapp",
|
"core.confirmloss": "local_moodlemobileapp",
|
||||||
"core.confirmopeninbrowser": "local_moodlemobileapp",
|
"core.confirmopeninbrowser": "local_moodlemobileapp",
|
||||||
|
|
|
@ -46,7 +46,6 @@ import {
|
||||||
import { CoreFileHelper } from '@services/file-helper';
|
import { CoreFileHelper } from '@services/file-helper';
|
||||||
import { AddonModH5PActivityModuleHandlerService } from '../../services/handlers/module';
|
import { AddonModH5PActivityModuleHandlerService } from '../../services/handlers/module';
|
||||||
import { CoreMainMenuPage } from '@features/mainmenu/pages/menu/menu';
|
import { CoreMainMenuPage } from '@features/mainmenu/pages/menu/menu';
|
||||||
import { Platform } from '@singletons';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays an H5P activity entry page.
|
* Component that displays an H5P activity entry page.
|
||||||
|
@ -81,13 +80,11 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
||||||
isOpeningPage = false;
|
isOpeningPage = false;
|
||||||
canViewAllAttempts = false;
|
canViewAllAttempts = false;
|
||||||
|
|
||||||
protected listeningResize = false;
|
|
||||||
protected fetchContentDefaultError = 'addon.mod_h5pactivity.errorgetactivity';
|
protected fetchContentDefaultError = 'addon.mod_h5pactivity.errorgetactivity';
|
||||||
protected syncEventName = AddonModH5PActivitySyncProvider.AUTO_SYNCED;
|
protected syncEventName = AddonModH5PActivitySyncProvider.AUTO_SYNCED;
|
||||||
protected site: CoreSite;
|
protected site: CoreSite;
|
||||||
protected observer?: CoreEventObserver;
|
protected observer?: CoreEventObserver;
|
||||||
protected messageListenerFunction: (event: MessageEvent) => Promise<void>;
|
protected messageListenerFunction: (event: MessageEvent) => Promise<void>;
|
||||||
protected resizeFunction: () => void;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected mainMenuPage: CoreMainMenuPage,
|
protected mainMenuPage: CoreMainMenuPage,
|
||||||
|
@ -102,7 +99,6 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
||||||
// Listen for messages from the iframe.
|
// Listen for messages from the iframe.
|
||||||
this.messageListenerFunction = this.onIframeMessage.bind(this);
|
this.messageListenerFunction = this.onIframeMessage.bind(this);
|
||||||
window.addEventListener('message', this.messageListenerFunction);
|
window.addEventListener('message', this.messageListenerFunction);
|
||||||
this.resizeFunction = this.contentResized.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -375,8 +371,6 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
||||||
AddonModH5PActivity.logView(this.h5pActivity!.id, this.h5pActivity!.name, this.siteId);
|
AddonModH5PActivity.logView(this.h5pActivity!.id, this.h5pActivity!.name, this.siteId);
|
||||||
|
|
||||||
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
|
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||||
|
|
||||||
this.setResizeListener();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -506,45 +500,6 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the resize listener if needed.
|
|
||||||
*/
|
|
||||||
setResizeListener(): void {
|
|
||||||
if (!this.playing || this.listeningResize) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.listeningResize = true;
|
|
||||||
window.addEventListener('resize', this.contentResized.bind(this));
|
|
||||||
this.contentResized();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On content resize, change visibility of the main menu: show on portrait and hide on landscape.
|
|
||||||
*/
|
|
||||||
contentResized(): void {
|
|
||||||
this.mainMenuPage.changeVisibility(Platform.isPortrait());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
ionViewDidEnter(): void {
|
|
||||||
this.setResizeListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
ionViewWillLeave(): void {
|
|
||||||
this.mainMenuPage.changeVisibility(true);
|
|
||||||
|
|
||||||
if (this.listeningResize) {
|
|
||||||
this.listeningResize = false;
|
|
||||||
window.removeEventListener('resize', this.resizeFunction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component destroyed.
|
* Component destroyed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
<!-- Question text first. -->
|
<!-- Question text first. -->
|
||||||
<ion-item class="ion-text-wrap">
|
<ion-item class="ion-text-wrap">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p><core-format-text [component]="component" [componentId]="componentId" [text]="multiQuestion.text"
|
<p>
|
||||||
|
<core-format-text [component]="component" [componentId]="componentId" [text]="multiQuestion.text"
|
||||||
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
||||||
</core-format-text></p>
|
</core-format-text>
|
||||||
|
</p>
|
||||||
<p *ngIf="multiQuestion.prompt">{{ multiQuestion.prompt }}</p>
|
<p *ngIf="multiQuestion.prompt">{{ multiQuestion.prompt }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -12,7 +14,8 @@
|
||||||
<!-- Checkbox for multiple choice. -->
|
<!-- Checkbox for multiple choice. -->
|
||||||
<ng-container *ngIf="multiQuestion.multi">
|
<ng-container *ngIf="multiQuestion.multi">
|
||||||
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
|
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
|
||||||
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")' class="flex">
|
<ion-label [color]='(option.isCorrect === 1 ? "success": "") + (option.isCorrect === 0 ? "danger": "")'
|
||||||
|
[class]="option.class">
|
||||||
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
|
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
|
||||||
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
|
@ -38,9 +41,10 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Radio buttons for single choice. -->
|
<!-- Radio buttons for single choice. -->
|
||||||
<ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel" [name]="multiQuestion.optionsName">
|
<ion-radio-group *ngIf="!multiQuestion.multi" [(ngModel)]="multiQuestion.singleChoiceModel"
|
||||||
|
[name]="multiQuestion.optionsName">
|
||||||
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
|
<ion-item class="ion-text-wrap answer" *ngFor="let option of multiQuestion.options">
|
||||||
<ion-label class="flex">
|
<ion-label [class]="option.class">
|
||||||
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
|
<core-format-text [component]="component" [componentId]="componentId" [text]="option.text"
|
||||||
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
[contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" [courseId]="courseId">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
|
|
|
@ -6,7 +6,11 @@
|
||||||
padding: 0 .7em;
|
padding: 0 .7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
.answer {
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-flex {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,6 +297,9 @@ export class AppComponent implements OnInit, AfterViewInit {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isOnline = CoreApp.isOnline();
|
||||||
|
document.body.classList.toggle('core-offline', !isOnline);
|
||||||
|
|
||||||
// Set StatusBar properties.
|
// Set StatusBar properties.
|
||||||
CoreApp.setStatusBarColor();
|
CoreApp.setStatusBarColor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
protected tabsElement?: HTMLElement; // The tabs parent element. It's the element that will be "scrolled" to hide tabs.
|
protected tabsElement?: HTMLElement; // The tabs parent element. It's the element that will be "scrolled" to hide tabs.
|
||||||
protected tabBarElement?: HTMLIonTabBarElement; // The top tab bar element.
|
protected tabBarElement?: HTMLIonTabBarElement; // The top tab bar element.
|
||||||
protected tabsShown = true;
|
protected tabsShown = true;
|
||||||
protected resizeFunction?: EventListenerOrEventListenerObject;
|
protected resizeFunction: EventListenerOrEventListenerObject;
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected isCurrentView = true;
|
protected isCurrentView = true;
|
||||||
protected shouldSlideToInitial = false; // Whether we need to slide to the initial slide because it's out of view.
|
protected shouldSlideToInitial = false; // Whether we need to slide to the initial slide because it's out of view.
|
||||||
|
@ -97,6 +97,8 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
protected element: ElementRef,
|
protected element: ElementRef,
|
||||||
) {
|
) {
|
||||||
this.backButtonFunction = this.backButtonClicked.bind(this);
|
this.backButtonFunction = this.backButtonClicked.bind(this);
|
||||||
|
this.resizeFunction = this.windowResized.bind(this);
|
||||||
|
|
||||||
this.tabAction = new CoreTabsRoleTab(this);
|
this.tabAction = new CoreTabsRoleTab(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +132,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
await this.initializeTabs();
|
await this.initializeTabs();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resizeFunction = this.windowResized.bind(this);
|
window.addEventListener('resize', this.resizeFunction);
|
||||||
|
|
||||||
window.addEventListener('resize', this.resizeFunction!);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,17 +162,17 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
||||||
|
|
||||||
if (showTabs) {
|
if (showTabs) {
|
||||||
// Smooth translation.
|
// Smooth translation.
|
||||||
this.tabBarElement!.classList.remove('tabs-hidden');
|
this.tabBarElement.classList.remove('tabs-hidden');
|
||||||
if (scroll === 0) {
|
if (scroll === 0) {
|
||||||
this.tabBarElement!.style.height = '';
|
this.tabBarElement.style.height = '';
|
||||||
this.previousLastScroll = this.lastScroll;
|
this.previousLastScroll = this.lastScroll;
|
||||||
this.lastScroll = 0;
|
this.lastScroll = 0;
|
||||||
} else if (scroll !== undefined) {
|
} else if (scroll !== undefined) {
|
||||||
this.tabBarElement!.style.height = (this.tabBarHeight - scroll) + 'px';
|
this.tabBarElement.style.height = (this.tabBarHeight - scroll) + 'px';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.tabBarElement!.classList.add('tabs-hidden');
|
this.tabBarElement.classList.add('tabs-hidden');
|
||||||
this.tabBarElement!.style.height = '';
|
this.tabBarElement.style.height = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabsShown = showTabs;
|
this.tabsShown = showTabs;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<div *ngIf="!loading" [@coreShowHideAnimation]>
|
<div *ngIf="!loading" @coreShowHideAnimation>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Spinner. -->
|
<!-- Spinner. -->
|
||||||
<ion-spinner *ngIf="loading" [@coreShowHideAnimation] [attr.aria-label]="loadingLabel | translate"></ion-spinner>
|
<ion-spinner *ngIf="loading" @coreShowHideAnimation [attr.aria-label]="loadingLabel | translate"></ion-spinner>
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
<ng-container *ngIf="enabled && !loading">
|
<ng-container *ngIf="enabled && !loading">
|
||||||
<!-- Download button. -->
|
<!-- Download button. -->
|
||||||
<ion-button *ngIf="status == statusNotDownloaded" fill="clear" (click)="download($event, false)" color="dark"
|
<ion-button *ngIf="status == statusNotDownloaded" fill="clear" (click)="download($event, false)" color="dark" @coreShowHideAnimation
|
||||||
[@coreShowHideAnimation] [attr.aria-label]="(statusTranslatable || 'core.download') | translate" [size]="size">
|
[attr.aria-label]="(statusTranslatable || 'core.download') | translate" [size]="size">
|
||||||
<ion-icon slot="icon-only" name="cloud-download" aria-hidden="true"></ion-icon>
|
<ion-icon slot="icon-only" name="cloud-download" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- Refresh button. -->
|
<!-- Refresh button. -->
|
||||||
<ion-button *ngIf="status == statusOutdated || (status == statusDownloaded && !canTrustDownload)" fill="clear"
|
<ion-button *ngIf="status == statusOutdated || (status == statusDownloaded && !canTrustDownload)" fill="clear"
|
||||||
(click)="download($event, true)" color="dark" [@coreShowHideAnimation]
|
(click)="download($event, true)" color="dark" @coreShowHideAnimation
|
||||||
[attr.aria-label]="(statusTranslatable || 'core.refresh') | translate" [size]="size">
|
[attr.aria-label]="(statusTranslatable || 'core.refresh') | translate" [size]="size">
|
||||||
<ion-icon slot="icon-only" name="fas-redo-alt" aria-hidden="true"></ion-icon>
|
<ion-icon slot="icon-only" name="fas-redo-alt" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- Downloaded status icon. -->
|
<!-- Downloaded status icon. -->
|
||||||
<ion-icon *ngIf="status == statusDownloaded && canTrustDownload" class="core-icon-downloaded ion-padding-horizontal"
|
<ion-icon *ngIf="status == statusDownloaded && canTrustDownload" class="core-icon-downloaded ion-padding-horizontal" color="success"
|
||||||
color="success" name="cloud-done" [attr.aria-label]="(statusTranslatable || 'core.downloaded') | translate"
|
name="cloud-done" [attr.aria-label]="(statusTranslatable || 'core.downloaded') | translate" role="status"></ion-icon>
|
||||||
role="status"></ion-icon>
|
|
||||||
|
|
||||||
<ion-spinner *ngIf="status === statusDownloading" [@coreShowHideAnimation]
|
<ion-spinner *ngIf="status === statusDownloading" @coreShowHideAnimation
|
||||||
[attr.aria-label]="(statusTranslatable || 'core.downloading') | translate"></ion-spinner>
|
[attr.aria-label]="(statusTranslatable || 'core.downloading') | translate"></ion-spinner>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Spinner. -->
|
<!-- Spinner. -->
|
||||||
<ion-spinner *ngIf="loading" [@coreShowHideAnimation] [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
<ion-spinner *ngIf="loading" @coreShowHideAnimation [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="core-loading-container" *ngIf="!hideUntil" role="status" [@coreShowHideAnimation]>
|
<div class="core-loading-container" *ngIf="!hideUntil" role="status" @coreShowHideAnimation>
|
||||||
<ion-spinner color="primary" aria-hidden="true"></ion-spinner>
|
<ion-spinner color="primary" aria-hidden="true"></ion-spinner>
|
||||||
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
|
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="!hideUntil" [@coreShowHideAnimation]
|
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="!hideUntil" @coreShowHideAnimation
|
||||||
[class.opacity-hide]="!hideUntil">
|
[class.opacity-hide]="!hideUntil">
|
||||||
<ng-content *ngIf="loaded">
|
<ng-content *ngIf="loaded">
|
||||||
</ng-content>
|
</ng-content>
|
||||||
|
|
|
@ -63,7 +63,7 @@ export class CoreH5PIframeComponent implements OnChanges, OnDestroy {
|
||||||
) {
|
) {
|
||||||
|
|
||||||
this.logger = CoreLogger.getInstance('CoreH5PIframeComponent');
|
this.logger = CoreLogger.getInstance('CoreH5PIframeComponent');
|
||||||
this.site = CoreSites.getCurrentSite()!;
|
this.site = CoreSites.getRequiredCurrentSite();
|
||||||
this.siteId = this.site.getId();
|
this.siteId = this.site.getId();
|
||||||
this.siteCanDownload = this.site.canDownloadFiles() && !CoreH5P.isOfflineDisabledInSite();
|
this.siteCanDownload = this.site.canDownloadFiles() && !CoreH5P.isOfflineDisabledInSite();
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,12 @@
|
||||||
<ion-tabs #mainTabs [hidden]="!showTabs" [class]="'placement-' + tabsPlacement" [class.tabshidden]="hidden"
|
<ion-tabs #mainTabs [hidden]="!showTabs" [class]="'placement-' + tabsPlacement"
|
||||||
(ionTabsDidChange)="tabChanged($event)">
|
[class.tabshidden]="!isMainScreen && tabsPlacement == 'bottom'" (ionTabsDidChange)="tabChanged($event)">
|
||||||
<ion-tab-bar slot="bottom" [hidden]="hidden" class="mainmenu-tabs">
|
<ion-tab-bar slot="bottom" class="mainmenu-tabs"
|
||||||
|
[@menuShowHideAnimation]="tabsPlacement == 'side' ? '' : (isMainScreen ? 'visible' : 'hidden')">
|
||||||
<ion-spinner *ngIf="!loaded" [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
<ion-spinner *ngIf="!loaded" [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||||
|
|
||||||
<ion-tab-button
|
<ion-tab-button *ngFor="let tab of tabs" (keydown)="tabAction.keyDown($event)" (keyup)="tabAction.keyUp(tab.page, $event)"
|
||||||
*ngFor="let tab of tabs"
|
[hidden]="!loaded && tab.hide" [tab]="tab.page" [disabled]="tab.hide" layout="label-hide" class="{{tab.class}}"
|
||||||
(click)="tabClicked($event, tab.page)"
|
[selected]="tab.page === selectedTab" [tabindex]="selectedTab == tab.page ? 0 : -1" [attr.aria-controls]="tab.id">
|
||||||
(keydown)="tabAction.keyDown($event)"
|
|
||||||
(keyup)="tabAction.keyUp(tab.page, $event)"
|
|
||||||
[hidden]="!loaded && tab.hide"
|
|
||||||
[tab]="tab.page"
|
|
||||||
[disabled]="tab.hide"
|
|
||||||
layout="label-hide"
|
|
||||||
class="{{tab.class}}"
|
|
||||||
[selected]="tab.page === selectedTab"
|
|
||||||
[tabindex]="selectedTab == tab.page ? 0 : -1"
|
|
||||||
[attr.aria-controls]="tab.id"
|
|
||||||
>
|
|
||||||
<ion-icon [name]="tab.icon" aria-hidden="true"></ion-icon>
|
<ion-icon [name]="tab.icon" aria-hidden="true"></ion-icon>
|
||||||
<ion-label aria-hidden="true">{{ tab.title | translate }}</ion-label>
|
<ion-label aria-hidden="true">{{ tab.title | translate }}</ion-label>
|
||||||
<ion-badge *ngIf="tab.badge" aria-hidden="true">{{ tab.badge }}</ion-badge>
|
<ion-badge *ngIf="tab.badge" aria-hidden="true">{{ tab.badge }}</ion-badge>
|
||||||
|
@ -26,16 +16,8 @@
|
||||||
</span>
|
</span>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
|
|
||||||
<ion-tab-button
|
<ion-tab-button (keydown)="tabAction.keyDown($event)" (keyup)="tabAction.keyUp(morePageName, $event)" [hidden]="!loaded"
|
||||||
(click)="tabClicked($event, morePageName)"
|
[tab]="morePageName" layout="label-hide" [tabindex]="selectedTab == morePageName ? 0 : -1" [attr.aria-controls]="morePageName">
|
||||||
(keydown)="tabAction.keyDown($event)"
|
|
||||||
(keyup)="tabAction.keyUp(morePageName, $event)"
|
|
||||||
[hidden]="!loaded"
|
|
||||||
[tab]="morePageName"
|
|
||||||
layout="label-hide"
|
|
||||||
[tabindex]="selectedTab == morePageName ? 0 : -1"
|
|
||||||
[attr.aria-controls]="morePageName"
|
|
||||||
>
|
|
||||||
<ion-icon name="fas-bars" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-bars" aria-hidden="true"></ion-icon>
|
||||||
<ion-label aria-hidden="true">{{ 'core.more' | translate }}</ion-label>
|
<ion-label aria-hidden="true">{{ 'core.more' | translate }}</ion-label>
|
||||||
<span class="sr-only">{{ 'core.more' | translate }}</span>
|
<span class="sr-only">{{ 'core.more' | translate }}</span>
|
||||||
|
|
|
@ -9,9 +9,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@if ($core-always-show-main-menu) {
|
@if ($core-always-show-main-menu) {
|
||||||
ion-tab-bar[hidden] {
|
ion-tabs.placement-bottom ion-tab-bar {
|
||||||
display: flex !important;
|
height: var(--menutabbar-size) !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
transform: translateY(0) !important;
|
||||||
}
|
}
|
||||||
|
} @else {
|
||||||
|
ion-tabs.tabshidden.placement-bottom ion-tab-bar {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
ion-tab-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-tab-button ion-icon {
|
ion-tab-button ion-icon {
|
||||||
|
@ -56,12 +67,15 @@
|
||||||
@include border-end(var(--border));
|
@include border-end(var(--border));
|
||||||
box-shadow: 3px 0 3px rgba(var(--drop-shadow));
|
box-shadow: 3px 0 3px rgba(var(--drop-shadow));
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
@include padding(var(--ion-safe-area-top), 0px, var(--ion-safe-area-bottom), var(--ion-safe-area-left));
|
@include padding(var(--ion-safe-area-top), 0px, var(--ion-safe-area-bottom), var(--ion-safe-area-left));
|
||||||
|
|
||||||
ion-tab-button {
|
ion-tab-button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
min-height: var(--menutabbar-size);
|
||||||
|
flex: 0;
|
||||||
|
|
||||||
ion-badge {
|
ion-badge {
|
||||||
top: calc(50% - 20px);
|
top: calc(50% - 20px);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
|
||||||
import { IonTabs } from '@ionic/angular';
|
import { IonTabs } from '@ionic/angular';
|
||||||
import { BackButtonEvent } from '@ionic/core';
|
import { BackButtonEvent } from '@ionic/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
@ -22,11 +21,13 @@ import { CoreApp } from '@services/app';
|
||||||
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
import { CoreEvents, CoreEventObserver } from '@singletons/events';
|
||||||
import { CoreMainMenu, CoreMainMenuProvider } from '../../services/mainmenu';
|
import { CoreMainMenu, CoreMainMenuProvider } from '../../services/mainmenu';
|
||||||
import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from '../../services/mainmenu-delegate';
|
import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from '../../services/mainmenu-delegate';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { Router } from '@singletons';
|
||||||
import { Translate } from '@singletons';
|
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from '@classes/aria-role-tab';
|
import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from '@classes/aria-role-tab';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { filter } from 'rxjs/operators';
|
||||||
|
import { NavigationEnd } from '@angular/router';
|
||||||
|
import { trigger, state, style, transition, animate } from '@angular/animations';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the main menu of the app.
|
* Page that displays the main menu of the app.
|
||||||
|
@ -34,6 +35,25 @@ import { CoreNavigator } from '@services/navigator';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'page-core-mainmenu',
|
selector: 'page-core-mainmenu',
|
||||||
templateUrl: 'menu.html',
|
templateUrl: 'menu.html',
|
||||||
|
animations: [
|
||||||
|
trigger('menuShowHideAnimation', [
|
||||||
|
state('hidden', style({
|
||||||
|
height: 0,
|
||||||
|
visibility: 'hidden',
|
||||||
|
transform: 'translateY(100%)',
|
||||||
|
})),
|
||||||
|
state('visible', style({
|
||||||
|
visibility: 'visible',
|
||||||
|
})),
|
||||||
|
transition('visible => hidden', [
|
||||||
|
style({ transform: 'translateY(0)' }),
|
||||||
|
animate('500ms ease-in-out', style({ transform: 'translateY(100%)' })),
|
||||||
|
]),
|
||||||
|
transition('hidden => visible', [
|
||||||
|
style({ transform: 'translateY(100%)', visibility: 'visible', height: '*' }),
|
||||||
|
animate('500ms ease-in-out', style({ transform: 'translateY(0)' })),
|
||||||
|
]),
|
||||||
|
])],
|
||||||
styleUrls: ['menu.scss'],
|
styleUrls: ['menu.scss'],
|
||||||
})
|
})
|
||||||
export class CoreMainMenuPage implements OnInit, OnDestroy {
|
export class CoreMainMenuPage implements OnInit, OnDestroy {
|
||||||
|
@ -43,11 +63,12 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
showTabs = false;
|
showTabs = false;
|
||||||
tabsPlacement: 'bottom' | 'side' = 'bottom';
|
tabsPlacement: 'bottom' | 'side' = 'bottom';
|
||||||
hidden = false;
|
|
||||||
morePageName = CoreMainMenuProvider.MORE_PAGE_NAME;
|
morePageName = CoreMainMenuProvider.MORE_PAGE_NAME;
|
||||||
selectedTab?: string;
|
selectedTab?: string;
|
||||||
|
isMainScreen = false;
|
||||||
|
|
||||||
protected subscription?: Subscription;
|
protected subscription?: Subscription;
|
||||||
|
protected navSubscription?: Subscription;
|
||||||
protected keyboardObserver?: CoreEventObserver;
|
protected keyboardObserver?: CoreEventObserver;
|
||||||
protected resizeFunction: () => void;
|
protected resizeFunction: () => void;
|
||||||
protected backButtonFunction: (event: BackButtonEvent) => void;
|
protected backButtonFunction: (event: BackButtonEvent) => void;
|
||||||
|
@ -58,21 +79,27 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
tabAction: CoreMainMenuRoleTab;
|
tabAction: CoreMainMenuRoleTab;
|
||||||
|
|
||||||
constructor(
|
constructor() {
|
||||||
protected route: ActivatedRoute,
|
|
||||||
protected changeDetector: ChangeDetectorRef,
|
|
||||||
) {
|
|
||||||
this.resizeFunction = this.initHandlers.bind(this);
|
this.resizeFunction = this.initHandlers.bind(this);
|
||||||
this.backButtonFunction = this.backButtonClicked.bind(this);
|
this.backButtonFunction = this.backButtonClicked.bind(this);
|
||||||
this.tabAction = new CoreMainMenuRoleTab(this);
|
this.tabAction = new CoreMainMenuRoleTab(this);
|
||||||
|
|
||||||
|
// Listen navigation events to show or hide tabs.
|
||||||
|
this.navSubscription = Router.events
|
||||||
|
.pipe(filter(event => event instanceof NavigationEnd))
|
||||||
|
.subscribe(async () => {
|
||||||
|
this.isMainScreen = !this.mainTabs?.outlet.canGoBack();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the component.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
async ngOnInit(): Promise<void> {
|
||||||
this.showTabs = true;
|
this.showTabs = true;
|
||||||
|
|
||||||
|
this.isMainScreen = !this.mainTabs?.outlet.canGoBack();
|
||||||
|
|
||||||
this.subscription = CoreMainMenuDelegate.getHandlersObservable().subscribe((handlers) => {
|
this.subscription = CoreMainMenuDelegate.getHandlersObservable().subscribe((handlers) => {
|
||||||
// Remove the handlers that should only appear in the More menu.
|
// Remove the handlers that should only appear in the More menu.
|
||||||
this.allHandlers = handlers.filter((handler) => !handler.onlyInMore);
|
this.allHandlers = handlers.filter((handler) => !handler.onlyInMore);
|
||||||
|
@ -134,78 +161,16 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change tabs visibility to show/hide them from the view.
|
* @inheritdoc
|
||||||
*
|
|
||||||
* @param visible If show or hide the tabs.
|
|
||||||
*/
|
|
||||||
changeVisibility(visible: boolean): void {
|
|
||||||
if (this.hidden == visible) {
|
|
||||||
// Change needed.
|
|
||||||
this.hidden = !visible;
|
|
||||||
|
|
||||||
/* setTimeout(() => {
|
|
||||||
this.viewCtrl.getContent().resize();
|
|
||||||
});*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Page destroyed.
|
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subscription?.unsubscribe();
|
this.subscription?.unsubscribe();
|
||||||
|
this.navSubscription?.unsubscribe();
|
||||||
window.removeEventListener('resize', this.resizeFunction);
|
window.removeEventListener('resize', this.resizeFunction);
|
||||||
document.removeEventListener('ionBackButton', this.backButtonFunction);
|
document.removeEventListener('ionBackButton', this.backButtonFunction);
|
||||||
this.keyboardObserver?.off();
|
this.keyboardObserver?.off();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tab clicked.
|
|
||||||
*
|
|
||||||
* @param e Event.
|
|
||||||
* @param page Page of the tab.
|
|
||||||
*/
|
|
||||||
async tabClicked(e: Event, page: string): Promise<void> {
|
|
||||||
if (this.mainTabs?.getSelected() != page) {
|
|
||||||
// Just change the tab.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
|
|
||||||
// Current tab was clicked. Check if user is already at root level.
|
|
||||||
const isMainMenuRoot = await this.currentRouteIsMainMenuRoot();
|
|
||||||
if (isMainMenuRoot) {
|
|
||||||
return; // Already at root level, nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maybe the route isn't defined as it should. Check if the current path is the tab one.
|
|
||||||
const currentPath = CoreNavigator.getCurrentPath();
|
|
||||||
if (currentPath == `/main/${page}`) {
|
|
||||||
return; // Already at root level, nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ask the user if he wants to go back to the root page of the tab.
|
|
||||||
try {
|
|
||||||
const tab = this.tabs.find((tab) => tab.page == page);
|
|
||||||
|
|
||||||
if (tab?.title) {
|
|
||||||
await CoreDomUtils.showConfirm(Translate.instant('core.confirmgotabroot', {
|
|
||||||
name: Translate.instant(tab.title),
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
await CoreDomUtils.showConfirm(Translate.instant('core.confirmgotabrootdefault'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// User confirmed, go to root.
|
|
||||||
this.mainTabs?.select(page);
|
|
||||||
} catch {
|
|
||||||
// User canceled.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selected tab has changed.
|
* Selected tab has changed.
|
||||||
*
|
*
|
||||||
|
@ -274,13 +239,6 @@ export class CoreMainMenuPage implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
class CoreMainMenuRoleTab extends CoreAriaRoleTab<CoreMainMenuPage> {
|
class CoreMainMenuRoleTab extends CoreAriaRoleTab<CoreMainMenuPage> {
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
selectTab(tabId: string, e: Event): void {
|
|
||||||
this.componentInstance.tabClicked(e, tabId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -97,6 +97,7 @@ export class CoreQuestionBaseComponent {
|
||||||
const radioEl = radios[i];
|
const radioEl = radios[i];
|
||||||
const option: AddonModQuizQuestionRadioOption = {
|
const option: AddonModQuizQuestionRadioOption = {
|
||||||
id: radioEl.id,
|
id: radioEl.id,
|
||||||
|
class: '',
|
||||||
name: radioEl.name,
|
name: radioEl.name,
|
||||||
value: radioEl.value,
|
value: radioEl.value,
|
||||||
checked: radioEl.checked,
|
checked: radioEl.checked,
|
||||||
|
@ -621,6 +622,7 @@ export class CoreQuestionBaseComponent {
|
||||||
const element = options[i];
|
const element = options[i];
|
||||||
const option: AddonModQuizQuestionRadioOption = {
|
const option: AddonModQuizQuestionRadioOption = {
|
||||||
id: element.id,
|
id: element.id,
|
||||||
|
class: '',
|
||||||
name: element.name,
|
name: element.name,
|
||||||
value: element.value,
|
value: element.value,
|
||||||
checked: element.checked,
|
checked: element.checked,
|
||||||
|
@ -643,6 +645,7 @@ export class CoreQuestionBaseComponent {
|
||||||
// Not found, use the old format.
|
// Not found, use the old format.
|
||||||
label = questionEl.querySelector('label[for="' + option.id + '"]');
|
label = questionEl.querySelector('label[for="' + option.id + '"]');
|
||||||
}
|
}
|
||||||
|
option.class = label?.className || option.class;
|
||||||
|
|
||||||
// Check that we were able to successfully extract options required data.
|
// Check that we were able to successfully extract options required data.
|
||||||
if (!label || option.name === undefined || option.value === undefined) {
|
if (!label || option.name === undefined || option.value === undefined) {
|
||||||
|
@ -736,6 +739,7 @@ export type AddonModQuizQuestionSelectOption = {
|
||||||
export type AddonModQuizQuestionRadioOption = {
|
export type AddonModQuizQuestionRadioOption = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
class: string;
|
||||||
value: string;
|
value: string;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item *ngFor="let site of sites" [attr.aria-current]="site.id == currentSiteId ? 'page' : 'false'">
|
<ion-item *ngFor="let site of sites" [class.item-current]="site.id == currentSiteId">
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<p class="item-heading">
|
<p class="item-heading">
|
||||||
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<h2>{{ 'core.settings.sites' | translate }}</h2>
|
<h2>{{ 'core.settings.sites' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<ion-item *ngFor="let site of sites" [attr.aria-current]="site.id == currentSiteId ? 'page' : 'false'" class="ion-text-wrap">
|
<ion-item *ngFor="let site of sites" [class.item-current]="site.id == currentSiteId" class="ion-text-wrap">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">
|
<p class="item-heading">
|
||||||
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
<core-format-text [text]="site.siteName" clean="true" [siteId]="site.id"></core-format-text>
|
||||||
|
@ -40,8 +40,8 @@
|
||||||
<p>{{ site.siteUrl }}</p>
|
<p>{{ site.siteUrl }}</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end">
|
<core-button-with-spinner [loading]="isSynchronizing(site.id)" slot="end">
|
||||||
<ion-button fill="clear" (click)="synchronize(site.id)"
|
<ion-button fill="clear" (click)="synchronize(site.id)" [title]="site.siteName"
|
||||||
[title]="site.siteName" [attr.aria-label]="'core.settings.synchronizenow' | translate">
|
[attr.aria-label]="'core.settings.synchronizenow' | translate">
|
||||||
<ion-icon name="fas-sync-alt" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-sync-alt" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</core-button-with-spinner>
|
</core-button-with-spinner>
|
||||||
|
|
|
@ -47,8 +47,6 @@
|
||||||
"completion-alt-manual-y-override": "Completed: {{$a.modname}} (set by {{$a.overrideuser}}). Select to mark as not complete.",
|
"completion-alt-manual-y-override": "Completed: {{$a.modname}} (set by {{$a.overrideuser}}). Select to mark as not complete.",
|
||||||
"confirmcanceledit": "Are you sure you want to leave this page? All changes will be lost.",
|
"confirmcanceledit": "Are you sure you want to leave this page? All changes will be lost.",
|
||||||
"confirmdeletefile": "Are you sure you want to delete this file?",
|
"confirmdeletefile": "Are you sure you want to delete this file?",
|
||||||
"confirmgotabroot": "Are you sure you want to go back to {{name}}?",
|
|
||||||
"confirmgotabrootdefault": "Are you sure you want to go to the initial page of the current tab?",
|
|
||||||
"confirmleaveunknownchanges": "Are you sure you want to leave this page? If you have unsaved changes they will be lost.",
|
"confirmleaveunknownchanges": "Are you sure you want to leave this page? If you have unsaved changes they will be lost.",
|
||||||
"confirmloss": "Are you sure? All changes will be lost.",
|
"confirmloss": "Are you sure? All changes will be lost.",
|
||||||
"confirmopeninbrowser": "Do you want to open it in a web browser?",
|
"confirmopeninbrowser": "Do you want to open it in a web browser?",
|
||||||
|
|
|
@ -254,7 +254,7 @@ export class CoreTextUtilsProvider {
|
||||||
// First, we use a regexpr.
|
// First, we use a regexpr.
|
||||||
text = text.replace(/(<([^>]+)>)/ig, '');
|
text = text.replace(/(<([^>]+)>)/ig, '');
|
||||||
// Then, we rely on the browser. We need to wrap the text to be sure is HTML.
|
// Then, we rely on the browser. We need to wrap the text to be sure is HTML.
|
||||||
text = this.convertToElement(text).textContent!;
|
text = this.convertToElement(text).textContent || '';
|
||||||
// Recover or remove new lines.
|
// Recover or remove new lines.
|
||||||
text = this.replaceNewLines(text, singleLine ? ' ' : '<br>');
|
text = this.replaceNewLines(text, singleLine ? ' ' : '<br>');
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ export class CoreTextUtilsProvider {
|
||||||
*/
|
*/
|
||||||
decodeHTMLEntities(text: string): string {
|
decodeHTMLEntities(text: string): string {
|
||||||
if (text) {
|
if (text) {
|
||||||
text = this.convertToElement(text).textContent!;
|
text = this.convertToElement(text).textContent || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
|
|
|
@ -295,19 +295,19 @@ export class CoreTimeUtilsProvider {
|
||||||
* @return Readable date.
|
* @return Readable date.
|
||||||
*/
|
*/
|
||||||
userDate(timestamp: number, format?: string, convert: boolean = true, fixDay: boolean = true, fixHour: boolean = true): string {
|
userDate(timestamp: number, format?: string, convert: boolean = true, fixDay: boolean = true, fixHour: boolean = true): string {
|
||||||
format = Translate.instant(format ? format : 'core.strftimedaydatetime');
|
format = Translate.instant(format ? format : 'core.strftimedaydatetime') as string;
|
||||||
|
|
||||||
if (fixDay) {
|
if (fixDay) {
|
||||||
format = format!.replace(/%d/g, '%e');
|
format = format.replace(/%d/g, '%e');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fixHour) {
|
if (fixHour) {
|
||||||
format = format!.replace('%I', '%l');
|
format = format.replace('%I', '%l');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format could be in PHP format, convert it to moment.
|
// Format could be in PHP format, convert it to moment.
|
||||||
if (convert) {
|
if (convert) {
|
||||||
format = this.convertPHPToMoment(format!);
|
format = this.convertPHPToMoment(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
return moment(timestamp).format(format);
|
return moment(timestamp).format(format);
|
||||||
|
|
|
@ -64,7 +64,12 @@ export class CoreColors {
|
||||||
document.body.appendChild(d);
|
document.body.appendChild(d);
|
||||||
|
|
||||||
// Color in RGB .
|
// Color in RGB .
|
||||||
const rgba = getComputedStyle(d).color.match(/\d+/g)!.map((a) => parseInt(a, 10));
|
const matches = getComputedStyle(d).color.match(/\d+/g) || [];
|
||||||
|
if (matches.length == 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgba = matches.map((a) => parseInt(a, 10));
|
||||||
|
|
||||||
const hex = [0,1,2].map(
|
const hex = [0,1,2].map(
|
||||||
(idx) => this.componentToHex(rgba[idx]),
|
(idx) => this.componentToHex(rgba[idx]),
|
||||||
|
@ -72,7 +77,7 @@ export class CoreColors {
|
||||||
|
|
||||||
document.body.removeChild(d);
|
document.body.removeChild(d);
|
||||||
|
|
||||||
return '#'+hex;
|
return '#' + hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -201,14 +201,6 @@ core-format-text {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Erase if core-format-text display is contents again.
|
|
||||||
.flex > core-format-text {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.core-course-title > p.item-heading > core-format-text {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loading {
|
@keyframes loading {
|
||||||
0% {
|
0% {
|
||||||
left: -45%;
|
left: -45%;
|
||||||
|
@ -327,6 +319,10 @@ core-rich-text-editor .core-rte-editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub, sup {
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
position: initial !important;
|
position: initial !important;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue