Merge pull request #2810 from crazyserver/MOBILE-3320

Mobile 3320
main
Dani Palou 2021-06-04 16:52:24 +02:00 committed by GitHub
commit 9f0de18eaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 181 additions and 98 deletions

View File

@ -5,7 +5,7 @@
</core-horizontal-scroll-controls> </core-horizontal-scroll-controls>
</div> </div>
</ion-item-divider> </ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page margin"> <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page">
<div <div
[id]="scrollElementId" [id]="scrollElementId"
[hidden]="!items || items.length === 0" [hidden]="!items || items.length === 0"

View File

@ -8,4 +8,7 @@
.core-course-module-handler { .core-course-module-handler {
--inner-border-width: 0; --inner-border-width: 0;
} }
core-loading {
--loading-inline-min-height: 102px;
}
} }

View File

@ -53,7 +53,7 @@
</ion-item> </ion-item>
</ion-card> </ion-card>
<core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar" inline="true" <core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar"
[message]="'addon.calendar.noevents' | translate"> [message]="'addon.calendar.noevents' | translate">
</core-empty-box> </core-empty-box>

View File

@ -96,7 +96,7 @@
<core-user-avatar slot="start" [user]="members[message.useridfrom]" [linkProfile]="false" <core-user-avatar slot="start" [user]="members[message.useridfrom]" [linkProfile]="false"
aria-hidden="true"> aria-hidden="true">
</core-user-avatar> </core-user-avatar>
{{ members[message.useridfrom].fullname }} <div>{{ members[message.useridfrom].fullname }}</div>
</div> </div>
<div *ngIf="!message.showUserData" class="sr-only"> <div *ngIf="!message.showUserData" class="sr-only">
{{ message.useridfrom == currentUserId {{ message.useridfrom == currentUserId

View File

@ -8,7 +8,6 @@
<h2>{{ user!.fullname }}</h2> <h2>{{ user!.fullname }}</h2>
<ng-container *ngTemplateOutlet="submissionStatus"></ng-container> <ng-container *ngTemplateOutlet="submissionStatus"></ng-container>
</ion-label> </ion-label>
<ng-container *ngTemplateOutlet="submissionStatusBadges"></ng-container>
</ion-item> </ion-item>
<!-- Status of the submission if user is blinded. --> <!-- Status of the submission if user is blinded. -->
@ -17,7 +16,6 @@
<h2>{{ 'addon.mod_assign.hiddenuser' | translate }} {{blindId}}</h2> <h2>{{ 'addon.mod_assign.hiddenuser' | translate }} {{blindId}}</h2>
<ng-container *ngTemplateOutlet="submissionStatus"></ng-container> <ng-container *ngTemplateOutlet="submissionStatus"></ng-container>
</ion-label> </ion-label>
<ng-container *ngTemplateOutlet="submissionStatusBadges"></ng-container>
</ion-item> </ion-item>
<!-- Status of the submission in the rest of cases. --> <!-- Status of the submission in the rest of cases. -->
@ -26,7 +24,6 @@
<h2>{{ 'addon.mod_assign.submissionstatus' | translate }}</h2> <h2>{{ 'addon.mod_assign.submissionstatus' | translate }}</h2>
<ng-container *ngTemplateOutlet="submissionStatus"></ng-container> <ng-container *ngTemplateOutlet="submissionStatus"></ng-container>
</ion-label> </ion-label>
<ng-container *ngTemplateOutlet="submissionStatusBadges"></ng-container>
</ion-item> </ion-item>
<!-- Tabs: see the submission or grade it. --> <!-- Tabs: see the submission or grade it. -->
@ -385,12 +382,12 @@
{{ 'addon.mod_assign.defaultteam' | translate }} {{ 'addon.mod_assign.defaultteam' | translate }}
</p> </p>
</ng-container> </ng-container>
</ng-template> <p>
<ng-template #submissionStatusBadges> <ion-badge *ngIf="statusTranslated" [color]="statusColor">
<ion-badge slot="end" *ngIf="statusTranslated" [color]="statusColor">
{{ statusTranslated }} {{ statusTranslated }}
</ion-badge> </ion-badge>
<ion-badge slot="end" *ngIf="gradingStatusTranslationId" [color]="gradingColor"> <ion-badge class="ion-margin-start" *ngIf="gradingStatusTranslationId" [color]="gradingColor">
{{ gradingStatusTranslationId | translate }} {{ gradingStatusTranslationId | translate }}
</ion-badge> </ion-badge>
</p>
</ng-template> </ng-template>

View File

@ -43,10 +43,10 @@
</ion-card> </ion-card>
<ng-container *ngIf="chat"> <ng-container *ngIf="chat">
<ion-button class="ion-margin" expand="block" color="primary" (click)="enterChat()"> <ion-button class="ion-margin ion-text-wrap" expand="block" color="primary" (click)="enterChat()">
{{ 'addon.mod_chat.enterchat' | translate }} {{ 'addon.mod_chat.enterchat' | translate }}
</ion-button> </ion-button>
<ion-button class="ion-margin" expand="block" color="light" *ngIf="sessionsAvailable" (click)="viewSessions()"> <ion-button class="ion-margin ion-text-wrap" expand="block" color="light" *ngIf="sessionsAvailable" (click)="viewSessions()">
{{ 'addon.mod_chat.viewreport' | translate }} {{ 'addon.mod_chat.viewreport' | translate }}
</ion-button> </ion-button>
</ng-container> </ng-container>

View File

@ -10,11 +10,13 @@
<core-context-menu-item *ngIf="blog" <core-context-menu-item *ngIf="blog"
[priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'far-newspaper'" (action)="gotoBlog()"> [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'far-newspaper'" (action)="gotoBlog()">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline" <core-context-menu-item
*ngIf="discussions.onlineLoaded && discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline"
[priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" [iconAction]="refreshIcon" [closeOnClick]="false" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" [iconAction]="refreshIcon" [closeOnClick]="false"
(action)="doRefresh(null, $event)"> (action)="doRefresh(null, $event)">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item *ngIf="discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline" <core-context-menu-item
*ngIf="discussions.onlineLoaded && discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline"
[priority]="600" [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false" [priority]="600" [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false"
(action)="doRefresh(null, $event, true)"> (action)="doRefresh(null, $event, true)">
</core-context-menu-item> </core-context-menu-item>
@ -37,11 +39,11 @@
<!-- Content. --> <!-- Content. -->
<core-split-view> <core-split-view>
<ion-refresher slot="fixed" [disabled]="!discussions.loaded" (ionRefresh)="doRefresh($event.target)"> <ion-refresher slot="fixed" [disabled]="!discussions.onlineLoaded || !discussions.loaded" (ionRefresh)="doRefresh($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="discussions.loaded"> <core-loading [hideUntil]="discussions.onlineLoaded && discussions.loaded">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
(completionChanged)="onCompletionChange()"> (completionChanged)="onCompletionChange()">

View File

@ -49,7 +49,7 @@
[autoFocus]="true" [lengthCheck]="2" (onClear)="toggleSearch()" searchArea="AddonModGlossary-{{module.id}}"> [autoFocus]="true" [lengthCheck]="2" (onClear)="toggleSearch()" searchArea="AddonModGlossary-{{module.id}}">
</core-search-box> </core-search-box>
<core-loading [hideUntil]="entries.loaded"> <core-loading [hideUntil]="loaded">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true"
(completionChanged)="onCompletionChange()"> (completionChanged)="onCompletionChange()">

View File

@ -47,12 +47,8 @@ export class AddonModGlossaryEditLinkHandlerService extends CoreContentLinksHand
const module = await CoreCourse.getModuleBasicInfo(cmId, siteId); const module = await CoreCourse.getModuleBasicInfo(cmId, siteId);
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
AddonModGlossaryModuleHandlerService.PAGE_NAME + '/edit/0', AddonModGlossaryModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/edit/0`,
{ {
params: {
cmId: module.id,
courseId: module.course,
},
siteId, siteId,
}, },
); );

View File

@ -52,12 +52,8 @@ export class AddonModGlossaryEntryLinkHandlerService extends CoreContentLinksHan
); );
await CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
AddonModGlossaryModuleHandlerService.PAGE_NAME + `/entry/${entryId}`, AddonModGlossaryModuleHandlerService.PAGE_NAME + `/${module.course}/${module.id}/entry/${entryId}`,
{ {
params: {
cmId: module.id,
courseId: module.course,
},
siteId, siteId,
}, },
); );

View File

@ -144,15 +144,36 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
this.tabBarHeight = this.tabBarElement.offsetHeight; this.tabBarHeight = this.tabBarElement.offsetHeight;
if (this.tabsShown) { this.applyScroll(this.tabsShown, this.lastScroll);
// Smooth translation.
this.tabBarElement.style.top = - this.lastScroll + 'px';
this.tabBarElement.style.height = 'calc(100% + ' + scroll + 'px';
} else {
this.tabBarElement.classList.add('tabs-hidden');
this.tabBarElement.style.top = '0';
this.tabBarElement.style.height = '';
} }
/**
* Apply scroll to hiding tabs.
*
* @param showTabs Show or completely hide tabs.
* @param scroll Scroll position.
*/
protected applyScroll(showTabs: boolean, scroll?: number): void {
if (!this.tabBarElement || !this.tabBarHeight) {
return;
}
if (showTabs) {
// Smooth translation.
this.tabBarElement!.classList.remove('tabs-hidden');
if (scroll === 0) {
this.tabBarElement!.style.height = '';
this.lastScroll = 0;
} else if (scroll !== undefined) {
this.tabBarElement!.style.height = (this.tabBarHeight - scroll) + 'px';
}
} else {
this.tabBarElement!.classList.add('tabs-hidden');
this.tabBarElement!.style.height = '';
}
this.tabsShown = showTabs;
} }
/** /**
@ -478,11 +499,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
if (scrollTop <= 0) { if (scrollTop <= 0) {
// Ensure tabbar is shown. // Ensure tabbar is shown.
this.tabsElement.style.top = '0'; this.applyScroll(true, 0);
this.tabsElement.style.height = '';
this.tabBarElement.classList.remove('tabs-hidden');
this.tabsShown = true;
this.lastScroll = 0;
return; return;
} }
@ -493,22 +510,17 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
} }
if (this.tabsShown && scrollTop > this.tabBarHeight) { if (this.tabsShown && scrollTop > this.tabBarHeight) {
this.tabsShown = false;
// Hide tabs. // Hide tabs.
this.tabBarElement.classList.add('tabs-hidden'); this.applyScroll(false);
this.tabsElement.style.top = '0';
this.tabsElement.style.height = '';
} else if (!this.tabsShown && scrollTop <= this.tabBarHeight) { } else if (!this.tabsShown && scrollTop <= this.tabBarHeight) {
this.tabsShown = true; this.applyScroll(true);
this.tabBarElement.classList.remove('tabs-hidden');
} }
if (this.tabsShown && scrollElement.scrollHeight > scrollElement.clientHeight + (this.tabBarHeight - scrollTop)) { if (this.tabsShown && scrollElement.scrollHeight > scrollElement.clientHeight + (this.tabBarHeight - scrollTop)) {
// Smooth translation. // Smooth translation.
this.tabsElement.style.top = - scrollTop + 'px'; this.applyScroll(true, scrollTop);
this.tabsElement.style.height = 'calc(100% + ' + scrollTop + 'px';
} }
// Use lastScroll after moving the tabs to avoid flickering. // Use lastScroll after moving the tabs to avoid flickering.
this.lastScroll = scrollTop; this.lastScroll = scrollTop;
} }

View File

@ -13,7 +13,6 @@
--color: var(--core-combobox-color); --color: var(--core-combobox-color);
--color-activated: var(--core-combobox-color); --color-activated: var(--core-combobox-color);
--border-color: var(--core-combobox-border-color); --border-color: var(--core-combobox-border-color);
--border-width: 0 0 var(--core-combobox-border-width) 0;
--border-style: solid; --border-style: solid;
--color-focused: currentcolor; --color-focused: currentcolor;
--color-hover: currentcolor; --color-hover: currentcolor;
@ -53,9 +52,7 @@ ion-button {
} }
ion-select { ion-select {
border-color: var(--border-color); border-bottom: var(--core-combobox-border-width) var(--border-style) var(--border-color);
border-width: var(--border-width);
border-style: var(--border-style);
&::part(icon) { &::part(icon) {
margin: var(--icon-margin); margin: var(--icon-margin);
@ -84,6 +81,8 @@ ion-select {
ion-button { ion-button {
--border-radius: 0; --border-radius: 0;
--border-width: 0 0 var(--core-combobox-border-width) 0;
flex: 1; flex: 1;
min-height: 45px; min-height: 45px;

View File

@ -2,21 +2,24 @@
:host { :host {
--loading-background: var(--ion-background-color); --loading-background: var(--ion-background-color);
--loading-background-inline: var(--ion-background-color-rgb);
--loading-spinner: var(--ion-color-primary); --loading-spinner: var(--ion-color-primary);
--loading-text-color: var(--ion-text-color); --loading-text-color: var(--ion-text-color);
--loading-inline-margin: 0; --loading-inline-margin: 0;
--loading-inline-min-height: 28px; --loading-inline-min-height: 28px;
--internal-loading-inline-min-height: var(--loading-inline-min-height);
position: static; position: static;
color: var(--loading-text-color); color: var(--loading-text-color);
@include core-transition(all, 200ms);
&.margin { &.margin {
--loading-inline-margin: 10px; --loading-inline-margin: 10px;
--internal-loading-inline-min-height: calc(var(--loading-inline-min-height) + var(--loading-inline-margin) + var(--loading-inline-margin));
} }
&.core-loading-loaded { &.core-loading-loaded {
--loading-inline-margin: 0; --internal-loading-inline-min-height: 0;
--loading-inline-min-height: 0;
} }
ion-spinner { ion-spinner {
@ -27,17 +30,17 @@
.core-loading-container { .core-loading-container {
position: absolute; position: absolute;
@include position(0, 0, 0, 0); @include position(0, 0, 0, 0);
display: flex;
height: 100%; height: 100%;
width: 100%; width: 100%;
justify-content: center;
align-items: center;
flex-direction: column;
z-index: 3; z-index: 3;
margin: 0; margin: 0;
padding: 0; padding: 0;
background-color: var(--loading-background); background-color: var(--loading-background);
@include core-transition(all, 200ms); @include core-transition(all, 200ms);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
} }
.core-loading-message { .core-loading-message {
@ -54,15 +57,14 @@
&.core-loading-loaded { &.core-loading-loaded {
position: unset; position: unset;
display: contents;
} }
&.core-loading-inline { &.core-loading-inline {
--loading-background: transparent; --loading-background: rgba(var(--loading-background-inline), 0.5);
position: relative; position: relative;
display: block; display: block;
min-height: var(--loading-inline-min-height); min-height: var(--internal-loading-inline-min-height);
margin-top: var(--loading-inline-margin);
margin-bottom: var(--loading-inline-margin);
.core-loading-message { .core-loading-message {
@include margin(0, 0, 0, 10px); @include margin(0, 0, 0, 10px);

View File

@ -22,6 +22,8 @@
-webkit-filter: drop-shadow(0px 3px 3px rgba(var(--drop-shadow))); -webkit-filter: drop-shadow(0px 3px 3px rgba(var(--drop-shadow)));
filter: drop-shadow(0px 3px 3px rgba(var(--drop-shadow))); filter: drop-shadow(0px 3px 3px rgba(var(--drop-shadow)));
border: 0; border: 0;
display: flex;
align-items: flex-end;
ion-row { ion-row {
width: 100%; width: 100%;

View File

@ -72,6 +72,7 @@ export class CoreFormatTextDirective implements OnChanges {
@Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the text for some reason. @Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the text for some reason.
@Input() captureLinks?: boolean; // Whether links should tried to be opened inside the app. Defaults to true. @Input() captureLinks?: boolean; // Whether links should tried to be opened inside the app. Defaults to true.
@Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser. @Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser.
@Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty.
/** /**
* Max height in pixels to render the content box. It should be 50 at least to make sense. * Max height in pixels to render the content box. It should be 50 at least to make sense.
@ -86,6 +87,8 @@ export class CoreFormatTextDirective implements OnChanges {
protected element: HTMLElement; protected element: HTMLElement;
protected showMoreDisplayed = false; protected showMoreDisplayed = false;
protected loadingChangedListener?: CoreEventObserver; protected loadingChangedListener?: CoreEventObserver;
protected emptyText = '';
protected contentSpan: HTMLElement;
constructor( constructor(
element: ElementRef, element: ElementRef,
@ -93,9 +96,20 @@ export class CoreFormatTextDirective implements OnChanges {
protected viewContainerRef: ViewContainerRef, protected viewContainerRef: ViewContainerRef,
protected sanitizer: DomSanitizer, protected sanitizer: DomSanitizer,
) { ) {
this.element = element.nativeElement; this.element = element.nativeElement;
this.element.classList.add('opacity-hide'); // Hide contents until they're treated. this.element.classList.add('core-format-text-loading'); // Hide contents until they're treated.
const placeholder = document.createElement('span');
placeholder.classList.add('core-format-text-loader');
this.element.appendChild(placeholder);
this.contentSpan = document.createElement('span');
this.contentSpan.classList.add('core-format-text-content');
this.element.appendChild(this.contentSpan);
this.emptyText = this.hideIfEmpty ? '' : '&nbsp;';
this.contentSpan.innerHTML = this.emptyText;
this.afterRender = new EventEmitter<void>(); this.afterRender = new EventEmitter<void>();
this.element.addEventListener('click', this.elementClicked.bind(this)); this.element.addEventListener('click', this.elementClicked.bind(this));
@ -183,7 +197,7 @@ export class CoreFormatTextDirective implements OnChanges {
* Add magnifying glass icons to view adapted images at full size. * Add magnifying glass icons to view adapted images at full size.
*/ */
addMagnifyingGlasses(): void { addMagnifyingGlasses(): void {
const imgs = Array.from(this.element.querySelectorAll('.core-adapted-img-container > img')); const imgs = Array.from(this.contentSpan.querySelectorAll('.core-adapted-img-container > img'));
if (!imgs.length) { if (!imgs.length) {
return; return;
} }
@ -339,7 +353,7 @@ export class CoreFormatTextDirective implements OnChanges {
*/ */
protected finishRender(): void { protected finishRender(): void {
// Show the element again. // Show the element again.
this.element.classList.remove('opacity-hide'); this.element.classList.remove('core-format-text-loading');
// Emit the afterRender output. // Emit the afterRender output.
this.afterRender.emit(); this.afterRender.emit();
} }
@ -349,7 +363,7 @@ export class CoreFormatTextDirective implements OnChanges {
*/ */
protected async formatAndRenderContents(): Promise<void> { protected async formatAndRenderContents(): Promise<void> {
if (!this.text) { if (!this.text) {
this.element.innerHTML = ''; // Remove current contents. this.contentSpan.innerHTML = this.emptyText; // Remove current contents.
this.finishRender(); this.finishRender();
return; return;
@ -370,12 +384,12 @@ export class CoreFormatTextDirective implements OnChanges {
// Disable media adapt to correctly calculate the height. // Disable media adapt to correctly calculate the height.
this.element.classList.add('core-disable-media-adapt'); this.element.classList.add('core-disable-media-adapt');
this.element.innerHTML = ''; // Remove current contents. this.contentSpan.innerHTML = ''; // Remove current contents.
if (this.maxHeight && result.div.innerHTML != '' && if (this.maxHeight && result.div.innerHTML != '' &&
(this.fullOnClick || (window.innerWidth < 576 || window.innerHeight < 576))) { // Don't collapse in big screens. (this.fullOnClick || (window.innerWidth < 576 || window.innerHeight < 576))) { // Don't collapse in big screens.
// Move the children to the current element to be able to calculate the height. // Move the children to the current element to be able to calculate the height.
CoreDomUtils.moveChildren(result.div, this.element); CoreDomUtils.moveChildren(result.div, this.contentSpan);
// Calculate the height now. // Calculate the height now.
this.calculateHeight(); this.calculateHeight();
@ -396,7 +410,7 @@ export class CoreFormatTextDirective implements OnChanges {
}); });
} }
} else { } else {
CoreDomUtils.moveChildren(result.div, this.element); CoreDomUtils.moveChildren(result.div, this.contentSpan);
// Add magnifying glasses to images. // Add magnifying glasses to images.
this.addMagnifyingGlasses(); this.addMagnifyingGlasses();
@ -405,7 +419,7 @@ export class CoreFormatTextDirective implements OnChanges {
if (result.options.filter) { if (result.options.filter) {
// Let filters handle HTML. We do it here because we don't want them to block the render of the text. // Let filters handle HTML. We do it here because we don't want them to block the render of the text.
CoreFilterDelegate.handleHtml( CoreFilterDelegate.handleHtml(
this.element, this.contentSpan,
result.filters, result.filters,
this.viewContainerRef, this.viewContainerRef,
result.options, result.options,

View File

@ -66,7 +66,7 @@ describe('CoreFormatTextDirective', () => {
); );
// Assert // Assert
const text = fixture.nativeElement.querySelector('core-format-text'); const text = fixture.nativeElement.querySelector('core-format-text .core-format-text-content');
expect(text).not.toBeNull(); expect(text).not.toBeNull();
expect(text.innerHTML).toEqual(sentence); expect(text.innerHTML).toEqual(sentence);
}); });

View File

@ -142,7 +142,10 @@
</ion-item-divider> </ion-item-divider>
<ion-item class="ion-text-wrap" *ngIf="section.summary"> <ion-item class="ion-text-wrap" *ngIf="section.summary">
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course?.id"></core-format-text> <ion-label>
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course?.id">
</core-format-text>
</ion-label>
</ion-item> </ion-item>
<ng-container *ngFor="let module of section.modules"> <ng-container *ngFor="let module of section.modules">

View File

@ -9,6 +9,7 @@
clip: rect(0, 0, 0, 0); clip: rect(0, 0, 0, 0);
white-space: nowrap; white-space: nowrap;
border: 0; border: 0;
display: block !important;
} }
.sr-only-focusable:active, .sr-only-focusable:focus { .sr-only-focusable:active, .sr-only-focusable:focus {

View File

@ -2,22 +2,70 @@
/** Styles of elements inside the directive should be placed in format-text.scss */ /** Styles of elements inside the directive should be placed in format-text.scss */
@import "~theme/globals"; @import "~theme/globals";
:root { core-format-text {
--background: var(--background, #{$ion-item-background}); --core-format-text-background: var(--background, #{$ion-item-background});
--background-gradient-rgb: var(--background-rgb, #{color-to-rgb-list($ion-item-background)}); --core-format-text-background-gradient-rgb: var(--background-rgb, #{color-to-rgb-list($ion-item-background)});
--viewer-icon-background: rgba(255, 255, 255, .5); --core-format-text-viewer-icon-background: rgba(255, 255, 255, .5);
--core-format-text-loader-shine: 251,251,251;
} }
:root body.dark { body.dark core-format-text {
--background: var(--background, #{$ion-item-background-dark}); --core-format-text-background: var(--background, #{$ion-item-background-dark});
--background-gradient-rgb: var(--background-rgb, #{color-to-rgb-list($ion-item-background-dark)}); --core-format-text-background-gradient-rgb: var(--background-rgb, #{color-to-rgb-list($ion-item-background-dark)});
--viewer-icon-background: rgba(0, 0, 0, .5); --core-format-text-viewer-icon-background: rgba(0, 0, 0, .5);
--core-format-text-loader-shine: 90,90,90;
} }
core-format-text { core-format-text {
display: contents;
.core-format-text-loader {
opacity: 0;
@include core-transition(opacity, 200ms);
display: contents;
}
&.core-format-text-loading {
position: relative;
width: 100%;
height: 100%;
opacity: 1;
background-color: rgba(0,0,0,.1);
overflow: hidden;
border-radius: 5px;
display: block;
.core-format-text-loader {
position: absolute;
left: -45%;
height: 100%;
width: 45%;
background-image: -webkit-linear-gradient(to left, rgba(var(--core-format-text-loader-shine), .05), rgba(var(--core-format-text-loader-shine), .3), rgba(var(--core-format-text-loader-shine), .6), rgba(var(--core-format-text-loader-shine), .3), rgba(var(--core-format-text-loader-shine), .05));
background-image: linear-gradient(to left, rgba(var(--core-format-text-loader-shine), .05), rgba(var(--core-format-text-loader-shine), .3), rgba(var(--core-format-text-loader-shine), .6), rgba(var(--core-format-text-loader-shine), .3), rgba(var(--core-format-text-loader-shine), .05));
animation: loading 1s infinite;
opacity: 1;
display: inline;
}
.core-format-text-content {
opacity: 0;
display: inline;
}
.core-show-more {
display: none !important;
}
}
.core-format-text-content {
opacity: 1;
@include core-transition(opacity, 200ms);
display: contents;
user-select: text; user-select: text;
word-break: break-word; word-break: break-word;
word-wrap: break-word; word-wrap: break-word;
}
&[maxHeight], &[maxHeight],
&[ng-reflect-max-height] { &[ng-reflect-max-height] {
@ -57,7 +105,7 @@ core-format-text {
position: absolute; position: absolute;
@include position(null, 0, 0, null); @include position(null, 0, 0, null);
z-index: 7; z-index: 7;
background-color: var(--background); background-color: var(--core-format-text-background);
color: var(--text-color); color: var(--text-color);
@include padding(null, null, null, 10px); @include padding(null, null, null, 10px);
margin: 0; margin: 0;
@ -68,10 +116,8 @@ core-format-text {
height: 100%; height: 100%;
position: absolute; position: absolute;
@include position(null, 0, 0, 0); @include position(null, 0, 0, 0);
background: -moz-linear-gradient(top, rgba(var(--background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--background-gradient-rgb), 1) calc(100% - 15px)); background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 15px));
background: -webkit-gradient(left top, left bottom, color-stop(calc(100% - 50px), rgba(var(--background-gradient-rgb), 0)), color-stop(calc(100% - 15px), rgba(var(--background-gradient-rgb), 1))); background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 15px));
background: -webkit-linear-gradient(top, rgba(var(--background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--background-gradient-rgb), 1) calc(100% - 15px));
background: linear-gradient(to bottom, rgba(var(--background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--background-gradient-rgb), 1) calc(100% - 15px));
z-index: 6; z-index: 6;
} }
} }
@ -115,15 +161,15 @@ core-format-text {
.core-adapted-img-container { .core-adapted-img-container {
position: relative; position: relative;
display: inline-block; display: inline-block;
width: 100%; max-width: 100%;
} }
.core-image-viewer-icon { .core-image-viewer-icon {
position: absolute; position: absolute;
@include position(null, 10px, 10px, null); @include position(null, 10px, 10px, null);
color: var(--black); color: var(--ion-text-color);
border-radius: 5px; border-radius: 5px;
background-color: var(--viewer-icon-background); background-color: var(--core-format-text-viewer-icon-background);
display: flex; display: flex;
width: var(--a11y-min-target-size); width: var(--a11y-min-target-size);
@ -141,3 +187,13 @@ core-format-text {
} }
} }
} }
@keyframes loading {
0% {
left: -45%;
}
100% {
left: 100%;
}
}

View File

@ -685,7 +685,7 @@ audio.core-media-adapt-width {
} }
// Make links clickable when inside radio or checkbox items. Style part. // Make links clickable when inside radio or checkbox items. Style part.
@media (any-hover: hover) { @media (hover: hover) {
ion-item.item-multiple-inputs:hover::part(native) { ion-item.item-multiple-inputs:hover::part(native) {
color: var(--color-hover); color: var(--color-hover);