MOBILE-3814 format-text: Use a general loader solution on format-text
parent
fb3a01a55c
commit
e03ef0d26e
|
@ -90,8 +90,8 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
|
||||
protected element: HTMLElement;
|
||||
protected emptyText = '';
|
||||
protected contentSpan: HTMLElement;
|
||||
protected domPromise?: CoreCancellablePromise<void>;
|
||||
protected domPromises: CoreCancellablePromise<void>[] = [];
|
||||
protected domElementPromise?: CoreCancellablePromise<void>;
|
||||
|
||||
constructor(
|
||||
element: ElementRef,
|
||||
|
@ -101,18 +101,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
CoreComponentsRegistry.register(element.nativeElement, this);
|
||||
|
||||
this.element = element.nativeElement;
|
||||
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.element.classList.add('core-loading'); // Hide contents until they're treated.
|
||||
|
||||
this.emptyText = this.hideIfEmpty ? '' : ' ';
|
||||
this.contentSpan.innerHTML = this.emptyText;
|
||||
this.element.innerHTML = this.emptyText;
|
||||
|
||||
this.afterRender = new EventEmitter<void>();
|
||||
|
||||
|
@ -134,14 +126,15 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.domPromise?.cancel();
|
||||
this.domElementPromise?.cancel();
|
||||
this.domPromises.forEach((promise) => { promise.cancel();});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ready(): Promise<void> {
|
||||
if (!this.element.classList.contains('core-format-text-loading')) {
|
||||
if (!this.element.classList.contains('core-loading')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -229,7 +222,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
* Add magnifying glass icons to view adapted images at full size.
|
||||
*/
|
||||
async addMagnifyingGlasses(): Promise<void> {
|
||||
const imgs = Array.from(this.contentSpan.querySelectorAll('.core-adapted-img-container > img'));
|
||||
const imgs = Array.from(this.element.querySelectorAll('.core-adapted-img-container > img'));
|
||||
if (!imgs.length) {
|
||||
return;
|
||||
}
|
||||
|
@ -311,7 +304,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
*/
|
||||
protected async finishRender(): Promise<void> {
|
||||
// Show the element again.
|
||||
this.element.classList.remove('core-format-text-loading');
|
||||
this.element.classList.remove('core-loading');
|
||||
|
||||
await CoreUtils.nextTick();
|
||||
|
||||
|
@ -324,7 +317,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
*/
|
||||
protected async formatAndRenderContents(): Promise<void> {
|
||||
if (!this.text) {
|
||||
this.contentSpan.innerHTML = this.emptyText; // Remove current contents.
|
||||
this.element.innerHTML = this.emptyText; // Remove current contents.
|
||||
|
||||
await this.finishRender();
|
||||
|
||||
|
@ -342,10 +335,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
// Disable media adapt to correctly calculate the height.
|
||||
this.element.classList.add('core-disable-media-adapt');
|
||||
|
||||
this.contentSpan.innerHTML = ''; // Remove current contents.
|
||||
this.element.innerHTML = ''; // Remove current contents.
|
||||
|
||||
// Move the children to the current element to be able to calculate the height.
|
||||
CoreDomUtils.moveChildren(result.div, this.contentSpan);
|
||||
CoreDomUtils.moveChildren(result.div, this.element);
|
||||
|
||||
await CoreUtils.nextTick();
|
||||
|
||||
|
@ -362,7 +355,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
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.
|
||||
CoreFilterDelegate.handleHtml(
|
||||
this.contentSpan,
|
||||
this.element,
|
||||
result.filters,
|
||||
this.viewContainerRef,
|
||||
result.options,
|
||||
|
@ -557,9 +550,10 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
* @return The width of the element in pixels.
|
||||
*/
|
||||
protected async getElementWidth(): Promise<number> {
|
||||
this.domPromise = CoreDomUtils.waitToBeInDOM(this.element);
|
||||
|
||||
await this.domPromise;
|
||||
if (!this.domElementPromise) {
|
||||
this.domElementPromise = CoreDomUtils.waitToBeInDOM(this.element);
|
||||
}
|
||||
await this.domElementPromise;
|
||||
|
||||
let width = this.element.getBoundingClientRect().width;
|
||||
if (!width) {
|
||||
|
@ -709,12 +703,15 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
newUrl += `&h=${privacyHash}`;
|
||||
}
|
||||
|
||||
const domPromise = CoreDomUtils.waitToBeInDOM(iframe);
|
||||
this.domPromises.push(domPromise);
|
||||
|
||||
await domPromise;
|
||||
|
||||
// Width and height are mandatory, we need to calculate them.
|
||||
let width: string | number;
|
||||
let height: string | number;
|
||||
|
||||
await CoreDomUtils.waitToBeInDOM(iframe, 5000);
|
||||
|
||||
if (iframe.width) {
|
||||
width = iframe.width;
|
||||
} else {
|
||||
|
|
|
@ -58,7 +58,7 @@ describe('CoreFormatTextDirective', () => {
|
|||
);
|
||||
|
||||
// Assert
|
||||
const text = fixture.nativeElement.querySelector('core-format-text .core-format-text-content');
|
||||
const text = fixture.nativeElement.querySelector('core-format-text');
|
||||
expect(text).not.toBeNull();
|
||||
expect(text.innerHTML).toEqual(sentence);
|
||||
});
|
||||
|
|
|
@ -5,59 +5,25 @@
|
|||
core-format-text {
|
||||
--core-format-text-background: var(--background, var(--ion-item-background));
|
||||
--core-format-text-viewer-icon-background: rgba(255, 255, 255, .5);
|
||||
--core-format-text-loader-shine: 251,251,251;
|
||||
}
|
||||
|
||||
body.dark core-format-text {
|
||||
--core-format-text-viewer-icon-background: rgba(0, 0, 0, .5);
|
||||
--core-format-text-loader-shine: 90,90,90;
|
||||
}
|
||||
|
||||
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;
|
||||
display: block;
|
||||
border-radius: var(--small-radius);
|
||||
|
||||
.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-format-text-content {
|
||||
opacity: 1;
|
||||
@include core-transition(opacity, 200ms);
|
||||
|
||||
display: contents;
|
||||
user-select: text;
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
|
||||
@include core-transition(background-color color, 200ms);
|
||||
&.core-loading {
|
||||
width: 100%;
|
||||
&:empty:before {
|
||||
content: 'E'; // Set a minimum empty text to have a minimum height of one line.
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsible-item {
|
||||
|
@ -66,16 +32,11 @@ core-format-text {
|
|||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
|
||||
.core-format-text-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.collapsible-enabled {
|
||||
.core-format-text-content {
|
||||
display: block;
|
||||
max-height: none;
|
||||
}
|
||||
&.collapsible-collapsed .core-format-text-content {
|
||||
|
||||
&.collapsible-collapsed {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +58,7 @@ core-format-text {
|
|||
}
|
||||
&.collapsible-item.inline {
|
||||
display: inline-block;
|
||||
&.collapsible-enabled .core-format-text-content {
|
||||
&.collapsible-enabled {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +102,7 @@ core-format-text {
|
|||
}
|
||||
|
||||
// Disable clicks in links inside MathJax equations.
|
||||
.core-format-text-content .filter_mathjaxloader_equation .MathJax_Preview a {
|
||||
.filter_mathjaxloader_equation .MathJax_Preview a {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
@ -243,7 +204,7 @@ core-format-text {
|
|||
|
||||
}
|
||||
|
||||
core-format-text .core-format-text-content,
|
||||
core-format-text,
|
||||
core-rich-text-editor .core-rte-editor {
|
||||
@include core-headings();
|
||||
|
||||
|
@ -657,14 +618,10 @@ core-rich-text-editor .core-rte-editor {
|
|||
|
||||
// h1 is too big and ugly, reduce size when loading.
|
||||
ion-header.ios h1 core-format-text {
|
||||
&.core-format-text-loading {
|
||||
&.core-loading {
|
||||
max-height: 30px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
&.core-format-text-content {
|
||||
display: block;
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
body.dark core-format-text select,
|
||||
|
|
|
@ -120,15 +120,15 @@ body {
|
|||
}
|
||||
|
||||
// Correctly inherit ion-text-wrap onto labels.
|
||||
.item ion-label core-format-text .core-format-text-content > *,
|
||||
.fake-ion-item core-format-text .core-format-text-content > * {
|
||||
.item ion-label core-format-text > *,
|
||||
.fake-ion-item core-format-text > * {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.item.ion-text-wrap > ion-label core-format-text .core-format-text-content > *,
|
||||
.fake-ion-item.ion-text-wrap core-format-text .core-format-text-content > * {
|
||||
.item.ion-text-wrap > ion-label core-format-text > *,
|
||||
.fake-ion-item.ion-text-wrap core-format-text > * {
|
||||
white-space: normal;
|
||||
overflow: inherit;
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ ion-button.button-solid {
|
|||
--box-shadow: none;
|
||||
}
|
||||
|
||||
ion-button core-format-text .core-format-text-content {
|
||||
ion-button core-format-text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -350,7 +350,7 @@ ion-button > * {
|
|||
|
||||
ion-button.ion-text-wrap {
|
||||
white-space: normal;
|
||||
core-format-text .core-format-text-content {
|
||||
core-format-text {
|
||||
white-space: normal;
|
||||
display: contents;
|
||||
}
|
||||
|
@ -1516,3 +1516,36 @@ ion-header.no-title {
|
|||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Loader animation.
|
||||
.core-loading {
|
||||
position: relative;
|
||||
background-color: var(--loader-background-color);
|
||||
color: transparent; // Hide contents.
|
||||
overflow: hidden;
|
||||
display: var(--loader-display);
|
||||
border-radius: var(--loader-radius);
|
||||
@include core-transition(all, 200ms);
|
||||
min-height: 8px;
|
||||
min-width: 50px;
|
||||
|
||||
// Hide contents.
|
||||
> * {
|
||||
opacity: 0;
|
||||
@include core-transition(opacity, 200ms);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -45%;
|
||||
height: 100%;
|
||||
width: 45%;
|
||||
background-image: linear-gradient(to left, rgba(var(--loader-shine), .05), rgba(var(--loader-shine), .3), rgba(var(--loader-shine), .6), rgba(var(--loader-shine), .3), rgba(var(--loader-shine), .05));
|
||||
animation: loading 1s infinite;
|
||||
display: block;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
|
||||
--contrast-background: var(--gray-900);
|
||||
|
||||
--loader-shine: 90, 90, 90;
|
||||
|
||||
--drop-shadow-color: 0, 0, 0, 1;
|
||||
--drop-shadow-top: 0px 2px 5px rgba(var(--drop-shadow-color));
|
||||
--drop-shadow-bottom: 0px -2px 5px rgba(var(--drop-shadow-color));
|
||||
|
|
|
@ -85,6 +85,11 @@
|
|||
|
||||
--contrast-background: white;
|
||||
|
||||
--loader-background-color: rgba(0, 0, 0, .1);
|
||||
--loader-shine: 251, 251, 251;
|
||||
--loader-radius: var(--small-radius);
|
||||
--loader-display: block;
|
||||
|
||||
--drop-shadow-color: 0, 0, 0, 0.5;
|
||||
--drop-shadow-top: 0px 2px 5px rgba(var(--drop-shadow-color));
|
||||
--drop-shadow-bottom: 0px -2px 5px rgba(var(--drop-shadow-color));
|
||||
|
|
Loading…
Reference in New Issue