diff --git a/src/NeonCore.ts b/src/NeonCore.ts index aafda7125..d7502f8c2 100644 --- a/src/NeonCore.ts +++ b/src/NeonCore.ts @@ -330,6 +330,10 @@ class NeonCore { } return new Promise((resolve): void => { promise.then(entry => { + // delete unnecessary SVG object reference; + // otherwise, this is not garbage collected! + entry.svg = null; + const currentMEI = entry.mei; const message: VerovioMessage = { id: uuidv4(), @@ -398,7 +402,7 @@ class NeonCore { const svg = this.parser.parseFromString( svgText, 'image/svg+xml' - ).documentElement as unknown as SVGSVGElement; + ).documentElement as HTMLElement & SVGSVGElement; this.neonCache.set(pageURI, { mei: mei, svg: svg, diff --git a/src/NeonView.ts b/src/NeonView.ts index 34b816988..a6ac9d056 100644 --- a/src/NeonView.ts +++ b/src/NeonView.ts @@ -3,9 +3,17 @@ import NeonCore from './NeonCore'; import { parseManifest } from './utils/NeonManifest'; import { prepareEditMode } from './utils/EditControls'; import setBody from './utils/template/Template'; -import * as Types from './Types'; -import * as Interfaces from './Interfaces'; import { ModalWindow } from './utils/ModalWindow'; +import { NeonManifest, EditorAction, Attributes } from './Types'; +import { + InfoInterface, + ModalWindowInterface, + NeonViewParams, + NeumeEditInterface, + TextEditInterface, + TextViewInterface, + ViewInterface +} from './Interfaces'; /** @@ -14,31 +22,31 @@ import { ModalWindow } from './utils/ModalWindow'; */ class NeonView { /** The manifest describing what to load and where to find it. */ - manifest: Types.NeonManifest; + manifest: NeonManifest; /** Module that displays rendered MEI. */ - view: Interfaces.ViewInterface; + view: ViewInterface; /** Name of the document loaded. */ name: string; /** Module that handles managing resources, rendering SVGs. */ core: NeonCore; /** Module that provides additional information on musical elements. */ - info: Interfaces.InfoInterface; + info: InfoInterface; /** Module that allows editing of musical elements. */ - NeumeEdit: Interfaces.NeumeEditInterface; + NeumeEdit: NeumeEditInterface; /** Module that allows viewing of syllable text. */ - textView: Interfaces.TextViewInterface; + textView: TextViewInterface; /** Module that allows editing of syllable text. */ - TextEdit: Interfaces.TextEditInterface; + TextEdit: TextEditInterface; /** Module that controls state and content of Neon modal windows */ - modal: Interfaces.ModalWindowInterface; + modal: ModalWindowInterface; - params: Interfaces.NeonViewParams; + params: NeonViewParams; /** * Constructor for NeonView. Sets mode and passes constructors. */ - constructor (params: Interfaces.NeonViewParams) { + constructor (params: NeonViewParams) { if (!parseManifest(params.manifest)) { console.error('Unable to parse the manifest'); } @@ -50,7 +58,7 @@ class NeonView { /** * Set up Neon for any provided editing modules. */ - setupEdit(params: Interfaces.NeonViewParams): void { + setupEdit(params: NeonViewParams): void { if (params.NeumeEdit !== undefined || (params.TextEdit !== undefined && params.TextView !== undefined)) { // Set up display for edit button prepareEditMode(this); @@ -135,7 +143,7 @@ class NeonView { * @param action - The editor toolkit action object. * @param pageURI - The URI of the page to perform the action on */ - edit (action: Types.EditorAction, pageURI: string): Promise { + edit (action: EditorAction, pageURI: string): Promise { return this.core.edit(action, pageURI); } @@ -144,7 +152,7 @@ class NeonView { * @param elementId - The unique ID of the musical element. * @param pageURI - The URI of the page the element is found on. */ - getElementAttr (elementID: string, pageURI: string): Promise { + getElementAttr (elementID: string, pageURI: string): Promise { return this.core.getElementAttr(elementID, pageURI); } diff --git a/src/SingleView/SingleView.ts b/src/SingleView/SingleView.ts index 13aa3f835..448f0bd50 100644 --- a/src/SingleView/SingleView.ts +++ b/src/SingleView/SingleView.ts @@ -15,7 +15,7 @@ class SingleView implements ViewInterface { private updateCallbacks: Array<() => void>; private group: SVGSVGElement; private bg: SVGImageElement; - private mei: SVGSVGElement; + private svg: SVGSVGElement; zoomHandler: ZoomHandler; private displayPanel: DisplayPanel; readonly pageURI: string; @@ -55,12 +55,13 @@ class SingleView implements ViewInterface { reader.readAsDataURL(blob); }); - this.mei = document.createElementNS('http://www.w3.org/svg', 'svg') as SVGSVGElement; - this.mei.id = 'mei_output'; - this.mei.classList.add('neon-container', 'active-page'); + // It is better named svg, to avoid confusion with the actual MEI file. + this.svg = document.createElementNS('http://www.w3.org/svg', 'svg') as SVGSVGElement; + this.svg.id = 'mei_output'; + this.svg.classList.add('neon-container', 'active-page'); this.group.appendChild(this.bg); - this.group.appendChild(this.mei); + this.group.appendChild(this.svg); this.container.appendChild(this.group); this.zoomHandler = new ZoomHandler(); @@ -79,12 +80,12 @@ class SingleView implements ViewInterface { * @param svg - New rendered SVG to use. */ updateSVG (svg: SVGSVGElement): void { - this.group.replaceChild(svg, this.mei); - this.mei = svg; - this.mei.id = 'mei_output'; - this.mei.classList.add('neon-container', 'active-page'); - const height = parseInt(this.mei.getAttribute('height')); - const width = parseInt(this.mei.getAttribute('width')); + this.group.replaceChild(svg, this.svg); + this.svg = svg; + this.svg.id = 'mei_output'; + this.svg.classList.add('neon-container', 'active-page'); + const height = parseInt(this.svg.getAttribute('height')); + const width = parseInt(this.svg.getAttribute('width')); this.bg.setAttribute('height', height.toString()); this.bg.setAttribute('width', width.toString()); @@ -208,4 +209,4 @@ class SingleView implements ViewInterface { } } -export { SingleView as default }; \ No newline at end of file +export { SingleView as default };