diff --git a/src/domTree.js b/src/domTree.js index 6a143eaf..7335f595 100644 --- a/src/domTree.js +++ b/src/domTree.js @@ -53,24 +53,16 @@ export type SvgChildNode = pathNode | lineNode; export type CssStyle = {[name: string]: string}; -/** - * This node represents a span node, with a className, a list of children, and - * an inline style. It also contains information about its height, depth, and - * maxFontSize. - * - * Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan - * otherwise. This typesafety is important when HTML builders access a span's - * children. - */ -class span implements HtmlDomNode { - classes: string[]; +export class HtmlDomContainer + implements HtmlDomNode { children: ChildType[]; + attributes: {[string]: string}; + classes: string[]; height: number; depth: number; width: ?number; maxFontSize: number; style: CssStyle; - attributes: {[string]: string}; constructor( classes?: string[], @@ -80,11 +72,11 @@ class span implements HtmlDomNode { ) { this.classes = classes || []; this.children = children || []; + this.attributes = {}; this.height = 0; this.depth = 0; this.maxFontSize = 0; this.style = Object.assign({}, style); - this.attributes = {}; if (options) { if (options.style.isTight()) { this.classes.push("mtight"); @@ -97,9 +89,9 @@ class span implements HtmlDomNode { } /** - * Sets an arbitrary attribute on the span. Warning: use this wisely. Not all - * browsers support attributes the same, and having too many custom attributes - * is probably bad. + * Sets an arbitrary attribute on the node. Warning: use this wisely. Not + * all browsers support attributes the same, and having too many custom + * attributes is probably bad. */ setAttribute(attribute: string, value: string) { this.attributes[attribute] = value; @@ -109,190 +101,57 @@ class span implements HtmlDomNode { return utils.contains(this.classes, className); } + /** + * Try to combine with given sibling. Returns true if the sibling has + * been successfully merged into this node, and false otherwise. + * Default behavior fails (returns false). + */ tryCombine(sibling: HtmlDomNode): boolean { return false; } + tagName(): string { + throw new Error("use of generic HtmlDomContainer tagName"); + } + /** - * Convert the span into an HTML node + * Convert into an HTML node */ - toNode(): HTMLSpanElement { - const span = document.createElement("span"); + toNode(): HTMLElement { + const node = document.createElement(this.tagName()); // Apply the class - span.className = createClass(this.classes); + node.className = createClass(this.classes); // Apply inline styles for (const style in this.style) { if (Object.prototype.hasOwnProperty.call(this.style, style)) { - // $FlowFixMe Flow doesn't seem to understand span.style's type. - span.style[style] = this.style[style]; + // $FlowFixMe Flow doesn't seem to understand node.style's type. + node.style[style] = this.style[style]; } } // Apply attributes for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - span.setAttribute(attr, this.attributes[attr]); + if (this.attributes.hasOwnProperty(attr)) { + node.setAttribute(attr, this.attributes[attr]); } } // Append the children, also as HTML nodes for (let i = 0; i < this.children.length; i++) { - span.appendChild(this.children[i].toNode()); + node.appendChild(this.children[i].toNode()); } - return span; + return node; } /** - * Convert the span into an HTML markup string + * Convert into an HTML markup string */ toMarkup(): string { - let markup = ") element with a hyperlink, a list of classes, - * a list of children, and an inline style. It also contains information about its - * height, depth, and maxFontSize. - */ -class anchor implements HtmlDomNode { - href: string; - classes: string[]; - children: HtmlDomNode[]; - height: number; - depth: number; - maxFontSize: number; - style: CssStyle; - attributes: {[string]: string}; - - constructor( - href: string, - classes: string[], - children: HtmlDomNode[], - options: Options, - ) { - this.href = href; - this.classes = classes; - this.children = children; - this.height = 0; - this.depth = 0; - this.maxFontSize = 0; - this.style = {}; - this.attributes = {}; - if (options.style.isTight()) { - this.classes.push("mtight"); - } - const color = options.getColor(); - if (color) { - this.style.color = color; - } - } - - /** - * Sets an arbitrary attribute on the anchor. Warning: use this wisely. Not all - * browsers support attributes the same, and having too many custom attributes - * is probably bad. - */ - setAttribute(attribute: string, value: string) { - this.attributes[attribute] = value; - } - - hasClass(className: string): boolean { - return utils.contains(this.classes, className); - } - - tryCombine(sibling: HtmlDomNode): boolean { - return false; - } - - /** - * Convert the anchor into an HTML node - */ - toNode(): HTMLAnchorElement { - const a = document.createElement("a"); - - // Apply the href - a.setAttribute('href', this.href); - - // Apply the class - if (this.classes.length) { - a.className = createClass(this.classes); - } - - // Apply inline styles - for (const style in this.style) { - if (Object.prototype.hasOwnProperty.call(this.style, style)) { - // $FlowFixMe Flow doesn't seem to understand a.style's type. - a.style[style] = this.style[style]; - } - } - - // Apply attributes - for (const attr in this.attributes) { - if (Object.prototype.hasOwnProperty.call(this.attributes, attr)) { - a.setAttribute(attr, this.attributes[attr]); - } - } - - // Append the children, also as HTML nodes - for (let i = 0; i < this.children.length; i++) { - a.appendChild(this.children[i].toNode()); - } - - return a; - } - - /** - * Convert the a into an HTML markup string - */ - toMarkup(): string { - let markup = "`; return markup; } } +/** + * This node represents a span node, with a className, a list of children, and + * an inline style. It also contains information about its height, depth, and + * maxFontSize. + * + * Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan + * otherwise. This typesafety is important when HTML builders access a span's + * children. + */ +class span extends HtmlDomContainer { + constructor( + classes?: string[], + children?: ChildType[], + options?: Options, + style?: CssStyle, + ) { + super(classes, children, options, style); + } + + tagName() { + return "span"; + } +} + +/** + * This node represents an anchor () element with a hyperlink, a list of classes, + * a list of children, and an inline style. It also contains information about its + * height, depth, and maxFontSize. + */ +class anchor extends HtmlDomContainer { + href: string; + + constructor( + href: string, + classes: string[], + children: HtmlDomNode[], + options: Options, + ) { + super(classes, children, options); + this.setAttribute('href', href); + } + + tagName() { + return "a"; + } +} + /** * This node represents a document fragment, which contains elements, but when * placed into the DOM doesn't have any representation itself. Thus, it only