1- import { forkJoin , Observable , BehaviorSubject } from "rxjs" ;
2- import { switchMap } from "rxjs/operators" ;
1+ import { forkJoin , Observable , BehaviorSubject , lastValueFrom } from "rxjs" ;
2+ import { map , switchMap } from "rxjs/operators" ;
33
44import { HttpClient } from "@angular/common/http" ;
5- import { Injectable } from "@angular/core" ;
5+ import { inject , Injectable } from "@angular/core" ;
66
77import { FileService } from "./file.service" ;
88
99@Injectable ( {
1010 providedIn : "root" ,
1111} )
1212export class B64Service {
13- JS_BUNDLE_URL = "assets/bundle.js" ;
14- FONTS_BUNDLE_URL = "assets/fonts.b64.css" ;
15- /**
16- * Creates an instance of B64Service, a service for B64 encoding assets.
17- * @param {HttpClient } http - The HttpClient service for making HTTP requests.
18- * @param {FileService } fileService - The FileService for handling file operations.
19- */
20- jsAndFontsBundle$ = new BehaviorSubject < [ string , string ] | null > ( null ) ;
21- constructor (
22- private http : HttpClient ,
23- private fileService : FileService ,
24- ) {
25- this . getBundle$ ( ) . subscribe ( ( bundle ) => {
26- this . jsAndFontsBundle$ . next ( [
27- this . indent ( bundle [ 0 ] , 6 ) , //apply the indentation to the js bundle
28- this . indent ( bundle [ 1 ] , 6 ) ,
29- ] ) ;
30- } ) ;
31- }
13+ private readonly JS_BUNDLE_URL = "assets/bundle.js" ;
14+ private readonly FONTS_BUNDLE_URL = "assets/fonts.b64.css" ;
15+ private http = inject ( HttpClient ) ;
16+ private fileService = inject ( FileService ) ;
17+ private cachedBundle : Promise < [ string , string ] > | null = null ;
18+
3219 getBundle$ ( ) : Observable < [ string , string ] > {
3320 return forkJoin ( [
3421 this . http
@@ -38,7 +25,19 @@ export class B64Service {
3825 this . http
3926 . get ( this . FONTS_BUNDLE_URL , { responseType : "blob" } )
4027 . pipe ( switchMap ( ( blob : Blob ) => this . fileService . readFile$ ( blob ) ) ) ,
41- ] ) ;
28+ ] ) . pipe (
29+ map ( ( bundle ) => [ this . indent ( bundle [ 0 ] , 6 ) , this . indent ( bundle [ 1 ] , 6 ) ] ) ,
30+ ) ;
31+ }
32+
33+ // A promise implementation of getBundle()$. Additionally, the promise is
34+ // cached and reused on subsequent bundle requests.
35+ getBundle ( ) : Promise < [ string , string ] > {
36+ if ( ! this . cachedBundle ) {
37+ this . cachedBundle = lastValueFrom ( this . getBundle$ ( ) ) ;
38+ }
39+
40+ return this . cachedBundle ;
4241 }
4342 utf8_to_b64 ( str : string ) {
4443 // See https://stackoverflow.com/questions/30106476/using-javascripts-atob-to-decode-base64-doesnt-properly-decode-utf-8-strings
@@ -59,24 +58,32 @@ export class B64Service {
5958 ) ;
6059 }
6160
62- xmlToB64 ( xml : Document ) {
61+ xmlToB64 ( xml : Document ) : string {
6362 return this . utf8_to_b64 (
6463 new XMLSerializer ( )
6564 . serializeToString ( xml )
6665 . replace ( "?><read" , "?>\n<read" ) ,
6766 ) ;
6867 }
6968
70- blobToB64 ( blob : any ) {
71- return new Promise ( ( resolve , _ ) => {
72- const reader = new FileReader ( ) ;
73- // @ts -ignore
74- reader . onloadend = ( ) => resolve ( reader . result ) ;
75- reader . readAsDataURL ( blob ) ;
76- } ) ;
69+ // rasToDataURL creates a data URL containing the contents of the RAS document.
70+ rasToDataURL ( xml : Document ) : Promise < string > {
71+ const xmlText = new XMLSerializer ( )
72+ . serializeToString ( xml )
73+ . replace ( "?><read" , "?>\n<read" ) ;
74+
75+ return this . fileService . readFileAsDataURL (
76+ xmlText ,
77+ "application/readalong+xml" ,
78+ ) ;
79+ }
80+
81+ // blobToDataURL encodes the blob to a data URL.
82+ blobToDataURL ( blob : Blob ) : Promise < string > {
83+ return this . fileService . readFileAsDataURL ( blob ) ;
7784 }
7885
79- indent ( str : string , level : number ) {
86+ private indent ( str : string , level : number ) {
8087 const indent = " " . repeat ( level ) ;
8188
8289 return str
0 commit comments