Skip to content

Commit b056eff

Browse files
committed
Merged in ux-plus-2023_02_x-UXP-114 (pull request DSpace#1383)
Fix issue with markdown preview
2 parents d361579 + e905c12 commit b056eff

26 files changed

Lines changed: 356 additions & 202 deletions
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Injectable } from '@angular/core';
2+
import { Observable, ReplaySubject, Subject } from 'rxjs';
3+
import { environment } from 'src/environments/environment';
4+
import { MathJaxConfig, MathService } from './math.service';
5+
6+
@Injectable({
7+
providedIn: 'root'
8+
})
9+
export class ClientMathService extends MathService {
10+
11+
protected isReady$: Subject<boolean>;
12+
13+
protected mathJaxOptions = {
14+
tex: {
15+
inlineMath: [['$', '$'], ['\\(', '\\)']]
16+
},
17+
svg: {
18+
fontCache: 'global'
19+
},
20+
startup: {
21+
typeset: false
22+
}
23+
};
24+
25+
protected mathJax: MathJaxConfig = {
26+
source: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js',
27+
id: 'MathJaxScript'
28+
};
29+
protected mathJaxFallback: MathJaxConfig = {
30+
source: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-chtml.min.js',
31+
id: 'MathJaxBackupScript'
32+
};
33+
34+
constructor() {
35+
super();
36+
37+
this.isReady$ = new ReplaySubject<boolean>();
38+
39+
void this.registerMathJaxAsync(this.mathJax)
40+
.then(() => this.isReady$.next(true))
41+
.catch(_ => {
42+
void this.registerMathJaxAsync(this.mathJaxFallback)
43+
.then(() => this.isReady$.next(true));
44+
});
45+
}
46+
47+
protected async registerMathJaxAsync(config: MathJaxConfig): Promise<any> {
48+
if (environment.markdown.mathjax) {
49+
return new Promise<void>((resolve, reject) => {
50+
51+
const optionsScript: HTMLScriptElement = document.createElement('script');
52+
optionsScript.type = 'text/javascript';
53+
optionsScript.text = `MathJax = ${JSON.stringify(this.mathJaxOptions)};`;
54+
document.head.appendChild(optionsScript);
55+
56+
const script: HTMLScriptElement = document.createElement('script');
57+
script.id = config.id;
58+
script.type = 'text/javascript';
59+
script.src = config.source;
60+
script.crossOrigin = 'anonymous';
61+
script.async = true;
62+
script.onload = () => resolve();
63+
script.onerror = error => reject(error);
64+
document.head.appendChild(script);
65+
});
66+
}
67+
return Promise.resolve();
68+
}
69+
70+
ready(): Observable<boolean> {
71+
return this.isReady$;
72+
}
73+
74+
render(element: HTMLElement) {
75+
if (environment.markdown.mathjax) {
76+
(window as any).MathJax.typesetPromise([element]);
77+
}
78+
}
79+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { TestBed } from '@angular/core/testing';
2+
import { Observable, of } from 'rxjs';
3+
import { MathService, MathJaxConfig } from './math.service';
4+
5+
export class MockMathService extends MathService {
6+
protected mathJaxOptions: any = {};
7+
protected mathJax: MathJaxConfig = { source: '', id: '' };
8+
protected mathJaxFallback: MathJaxConfig = { source: '', id: '' };
9+
10+
protected registerMathJaxAsync(config: MathJaxConfig): Promise<any> {
11+
return Promise.resolve();
12+
}
13+
14+
ready(): Observable<boolean> {
15+
return of(true);
16+
}
17+
18+
render(element: HTMLElement): void {
19+
return;
20+
}
21+
}
22+
23+
describe('MathService', () => {
24+
let service: MockMathService;
25+
26+
beforeEach(() => {
27+
TestBed.configureTestingModule({});
28+
service = new MockMathService();
29+
spyOn(service, 'render');
30+
});
31+
32+
it('should be created', () => {
33+
expect(service).toBeTruthy();
34+
});
35+
36+
it('should be ready', (done) => {
37+
service.ready().subscribe(isReady => {
38+
expect(isReady).toBe(true);
39+
done();
40+
});
41+
});
42+
43+
it('should render', () => {
44+
service.render(document.createElement('div'));
45+
expect(service.render).toHaveBeenCalled();
46+
});
47+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Observable } from 'rxjs';
2+
3+
export interface MathJaxConfig {
4+
source: string;
5+
id: string;
6+
}
7+
8+
export abstract class MathService {
9+
protected abstract mathJaxOptions: any;
10+
protected abstract mathJax: MathJaxConfig;
11+
protected abstract mathJaxFallback: MathJaxConfig;
12+
13+
protected abstract registerMathJaxAsync(config: MathJaxConfig): Promise<any>;
14+
abstract ready(): Observable<boolean>;
15+
abstract render(element: HTMLElement): void;
16+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Injectable } from '@angular/core';
2+
import { Observable, ReplaySubject, Subject } from 'rxjs';
3+
import { MathJaxConfig, MathService } from './math.service';
4+
5+
@Injectable({
6+
providedIn: 'root'
7+
})
8+
export class ServerMathService extends MathService {
9+
10+
protected signal: Subject<boolean>;
11+
12+
protected mathJaxOptions = {};
13+
14+
protected mathJax: MathJaxConfig = {
15+
source: '',
16+
id: ''
17+
};
18+
protected mathJaxFallback: MathJaxConfig = {
19+
source: '',
20+
id: ''
21+
};
22+
23+
constructor() {
24+
super();
25+
26+
this.signal = new ReplaySubject<boolean>();
27+
this.signal.next(true);
28+
}
29+
30+
protected async registerMathJaxAsync(config: MathJaxConfig): Promise<any> {
31+
return Promise.resolve();
32+
}
33+
34+
ready(): Observable<boolean> {
35+
return this.signal;
36+
}
37+
38+
render(element: HTMLElement) {
39+
return;
40+
}
41+
}

src/app/item-page/field-components/metadata-values/metadata-values.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<!-- Render value as markdown -->
1414
<ng-template #markdown let-value="value">
15-
<span class="dont-break-out" [innerHTML]="value | dsMarkdown | async">
15+
<span class="dont-break-out" [dsMarkdown]="value">
1616
</span>
1717
</ng-template>
1818

src/app/item-page/field-components/metadata-values/metadata-values.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class MetadataValuesComponent implements OnChanges {
3737
@Input() label: string;
3838

3939
/**
40-
* Whether the {@link MarkdownPipe} should be used to render these metadata values.
40+
* Whether the {@link MarkdownDirective} should be used to render these metadata values.
4141
* This will only have effect if {@link MarkdownConfig#enabled} is true.
4242
* Mathjax will only be rendered if {@link MarkdownConfig#mathjax} is true.
4343
*/

src/app/item-page/item-page.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import {
6262
ThemedFullFileSectionComponent
6363
} from './full/field-components/file-section/themed-full-file-section.component';
6464
import { UnpaywallVersionsComponent } from './unpaywall-versions/unpaywall-versions.component';
65+
import { MarkdownViewerModule } from '../shared/markdown-viewer/markdown-viewer.module';
6566

6667

6768
const ENTRY_COMPONENTS = [
@@ -126,6 +127,7 @@ const DECLARATIONS = [
126127
CrisItemPageModule,
127128
ContextMenuModule.withEntryComponents(),
128129
MiradorViewerModule,
130+
MarkdownViewerModule,
129131
],
130132
declarations: [
131133
...DECLARATIONS,

src/app/item-page/simple/field-components/specific-field/abstract/item-page-abstract-field.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export class ItemPageAbstractFieldComponent extends ItemPageFieldComponent {
3737
label = 'item.page.abstract';
3838

3939
/**
40-
* Use the {@link MarkdownPipe} to render dc.description.abstract values
40+
* Use the {@link MarkdownDirective} to render dc.description.abstract values
4141
*/
4242
enableMarkdown = true;
4343
}

src/app/item-page/simple/field-components/specific-field/generic/generic-item-page-field.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class GenericItemPageFieldComponent extends ItemPageFieldComponent {
3636
@Input() label: string;
3737

3838
/**
39-
* Whether the {@link MarkdownPipe} should be used to render this metadata.
39+
* Whether the {@link MarkdownDirective} should be used to render this metadata.
4040
*/
4141
@Input() enableMarkdown = false;
4242

src/app/item-page/simple/field-components/specific-field/item-page-field.component.spec.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ import { MetadataMap, MetadataValue } from '../../../../core/shared/metadata.mod
99
import { createSuccessfulRemoteDataObject$ } from '../../../../shared/remote-data.utils';
1010
import { createPaginatedList } from '../../../../shared/testing/utils.test';
1111
import { environment } from '../../../../../environments/environment';
12-
import { MarkdownPipe } from '../../../../shared/utils/markdown.pipe';
1312
import { SharedModule } from '../../../../shared/shared.module';
1413
import { APP_CONFIG } from '../../../../../config/app-config.interface';
1514
import { By } from '@angular/platform-browser';
1615
import { BrowseDefinitionDataService } from '../../../../core/browse/browse-definition-data.service';
1716
import { BrowseDefinitionDataServiceStub } from '../../../../shared/testing/browse-definition-data-service.stub';
1817
import { RouterTestingModule } from '@angular/router/testing';
18+
import { MarkdownDirective } from '../../../../shared/utils/markdown.directive';
19+
import { MathService } from '../../../../core/shared/math.service';
1920

2021
let comp: ItemPageFieldComponent;
2122
let fixture: ComponentFixture<ItemPageFieldComponent>;
@@ -51,14 +52,15 @@ describe('ItemPageFieldComponent', () => {
5152
],
5253
providers: [
5354
{ provide: APP_CONFIG, useValue: appConfig },
54-
{ provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub }
55+
{ provide: BrowseDefinitionDataService, useValue: BrowseDefinitionDataServiceStub },
56+
{ provide: MathService, useValue: {} }
5557
],
5658
declarations: [ItemPageFieldComponent, MetadataValuesComponent],
5759
schemas: [NO_ERRORS_SCHEMA]
5860
}).overrideComponent(ItemPageFieldComponent, {
5961
set: { changeDetection: ChangeDetectionStrategy.Default }
6062
}).compileComponents();
61-
markdownSpy = spyOn(MarkdownPipe.prototype, 'transform');
63+
markdownSpy = spyOn(MarkdownDirective.prototype, 'render');
6264
fixture = TestBed.createComponent(ItemPageFieldComponent);
6365
comp = fixture.componentInstance;
6466
comp.item = mockItemWithMetadataFieldsAndValue(mockFields, mockValue);

0 commit comments

Comments
 (0)