diff --git a/ts/adaptors/HTMLAdaptor.ts b/ts/adaptors/HTMLAdaptor.ts index 97b2b05c3..565c213ae 100644 --- a/ts/adaptors/HTMLAdaptor.ts +++ b/ts/adaptors/HTMLAdaptor.ts @@ -74,6 +74,7 @@ export interface MinHTMLElement { /* tslint:disable:jsdoc-require */ getElementsByTagName(name: string): N[] | HTMLCollectionOf; getElementsByTagNameNS(ns: string, name: string): N[] | HTMLCollectionOf; + contains(child: N | T): boolean; appendChild(child: N | T): N | T | Node; removeChild(child: N | T): N | T | Node; replaceChild(nnode: N | T, onode: N | T): N | T | Node; @@ -254,6 +255,13 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { return containers; } + /** + * @override + */ + public contains(container: N, node: N | T) { + return container.contains(node); + } + /** * @override */ diff --git a/ts/adaptors/liteAdaptor.ts b/ts/adaptors/liteAdaptor.ts index 9fa7bc594..0332027fe 100644 --- a/ts/adaptors/liteAdaptor.ts +++ b/ts/adaptors/liteAdaptor.ts @@ -235,6 +235,16 @@ export class LiteAdaptor extends AbstractDOMAdaptor= 0) { onode.parent.children[i] = nnode; + nnode.parent = onode.parent; + onode.parent = null; } return onode; } diff --git a/ts/components/startup.ts b/ts/components/startup.ts index 79a9d82b8..a9b2699ba 100644 --- a/ts/components/startup.ts +++ b/ts/components/startup.ts @@ -327,19 +327,26 @@ export namespace Startup { * TypeseClear() clears all the MathItems from the document. */ export function makeTypesetMethods() { - MathJax.typeset = (elements: any = null) => { + MathJax.typeset = (elements: any[] = null) => { document.options.elements = elements; document.reset(); document.render(); }; - MathJax.typesetPromise = (elements: any = null) => { + MathJax.typesetPromise = (elements: any[] = null) => { document.options.elements = elements; document.reset(); return mathjax.handleRetriesFor(() => { document.render(); }); }; - MathJax.typesetClear = () => document.clear(); + MathJax.typesetClear = (elements: any[] = null) => { + if (elements) { + document.reset(); + document.clearMathItemsWithin(elements); + } else { + document.clear(); + } + }; } /** diff --git a/ts/core/DOMAdaptor.ts b/ts/core/DOMAdaptor.ts index 6ad61d77a..09eac9d97 100644 --- a/ts/core/DOMAdaptor.ts +++ b/ts/core/DOMAdaptor.ts @@ -114,6 +114,15 @@ export interface DOMAdaptor { */ getElements(nodes: (string | N | N[])[], document: D): N[]; + /** + * Determine if a container node contains a given node is somewhere in its DOM tree + * + * @param {N} container The container to search + * @param {N|T} node The node to look for + * @return {boolean} True if the node is in the container's DOM tree + */ + contains(container: N, node: N | T): boolean; + /** * @param {N|T} node The HTML node whose parent is to be obtained * @return {N} The parent node of the given one @@ -431,6 +440,11 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public abstract getElements(nodes: (string | N | N[])[], document: D): N[]; + /** + * @override + */ + public abstract contains(container: N, node: N | T): boolean; + /** * @override */ diff --git a/ts/core/MathDocument.ts b/ts/core/MathDocument.ts index d9e882b5e..da5a88a30 100644 --- a/ts/core/MathDocument.ts +++ b/ts/core/MathDocument.ts @@ -230,6 +230,15 @@ export class RenderList extends PrioritizedList> { } +/*****************************************************************/ +/** + * The ways of specifying a container (a selector string, an actual node, + * or an array of those (e.g., the result of document.getElementsByTagName()) + * + * @template N The HTMLElement node class + */ +export type ContainerList = string | N | (string | N | N[])[]; + /*****************************************************************/ /** * The MathDocument interface @@ -428,6 +437,24 @@ export interface MathDocument { */ concat(list: MathList): MathDocument; + /** + * Clear the typeset MathItems that are within the given container + * from the document's MathList. (E.g., when the content of the + * container has been updated and you want to remove the + * associated MathItems) + * + * @param {ContainerList} elements The container DOM elements whose math items are to be removed + */ + clearMathItemsWithin(containers: ContainerList): void; + + /** + * Get the typeset MathItems that are within a given container. + * + * @param {ContainerList} elements The container DOM elements whose math items are to be found + * @return {MathItem[]} The list of MathItems within that container + */ + getMathItemsWithin(elements: ContainerList): MathItem[]; + } /*****************************************************************/ @@ -857,6 +884,35 @@ export abstract class AbstractMathDocument implements MathDocument) { + this.math.remove(...this.getMathItemsWithin(containers)); + } + + /** + * @override + */ + public getMathItemsWithin(elements: ContainerList) { + if (!Array.isArray(elements)) { + elements = [elements]; + } + const adaptor = this.adaptor; + const items = [] as MathItem[]; + const containers = adaptor.getElements(elements, this.document); + ITEMS: + for (const item of this.math) { + for (const container of containers) { + if (item.start.node && adaptor.contains(container, item.start.node)) { + items.push(item); + continue ITEMS; + } + } + } + return items; + } + } /** diff --git a/ts/util/LinkedList.ts b/ts/util/LinkedList.ts index c5600887d..856e84256 100644 --- a/ts/util/LinkedList.ts +++ b/ts/util/LinkedList.ts @@ -26,7 +26,7 @@ * A symbol used to mark the special node used to indicate * the start and end of the list. */ -const END = Symbol(); +export const END = Symbol(); /** * Shorthand type for the functions used to sort the data items @@ -190,6 +190,28 @@ export class LinkedList { return item.data as DataClass; } + /** + * Remove items from the list + * + * @param {DataClass[]} items The items to remove + */ + public remove(...items: DataClass[]) { + const map = new Map(); + for (const item of items) { + map.set(item, true); + } + let item = this.list.next; + while (item.data !== END) { + const next = item.next; + if (map.has(item.data as DataClass)) { + item.prev.next = item.next; + item.next.prev = item.prev; + item.next = item.prev = null; + } + item = next; + } + } + /** * Empty the list *