Skip to content

Commit

Permalink
safeSetStyle / safeSetAttribute helpers globalised
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Mrowetz committed Jun 6, 2017
1 parent aca9814 commit a5ebd5b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 36 deletions.
51 changes: 50 additions & 1 deletion src/ts/helpers/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,56 @@ export function getLastItemOfNodeList<T extends Node>(list: NodeListOf<T>) {
return list.item(list.length - 1);
}

// /** Calls `fn` with each element of `els` */
/** Calls `fn` with each element of `els` */
export function forEachNodeList<T extends Node>(els: NodeListOf<T>, fn: (el: T, index: number) => any) {
Array.prototype.forEach.call(els, fn);
}

interface StringOrNumberMap { [key: string]: string | number; }

/** Sets a CSS style property, but only if property exists on `el` */
export function safeSetStyle(el: HTMLElement | SVGElement, property: string, value: string) {
if (property in el.style) {
el.style[property] = value;
} else {
console.warn(new Error(`Trying to set non-existing style ` +
`${property} = ${value} on a <${el.tagName.toLowerCase()}>.`));
}
}

/** Sets an attribute, but only if `name` exists on `el` */
export function safeSetAttribute(el: HTMLElement | SVGElement, name: string, value: string) {
if (!(name in el)) {
console.warn(new Error(`Trying to set non-existing attribute ` +
`${name} = ${value} on a <${el.tagName.toLowerCase()}>.`));
}
el.setAttributeNS(null, name, value);
}

/** Sets multiple CSS style properties, but only if property exists on `el` */
export function safeSetStyles(el: HTMLElement | SVGElement, css: StringOrNumberMap) {
Object.keys(css).forEach((property) => {
safeSetStyle(el, property, css[property].toString());
});
}

/** Sets attributes, but only if they exist on `el` */
export function safeSetAttributes(el: HTMLElement | SVGElement, attributes: StringOrNumberMap) {
Object.keys(attributes).forEach((name) => {
safeSetAttribute(el, name, attributes[name].toString());
});
}

export function makeHtmlEl() {
const html = document.createElement("html");
html.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://www.w3.org/2000/xmlns/");
return html;
}

export function makeBodyEl(css: StringOrNumberMap = {}, innerHTML = "") {
const body = document.createElement("body");
body.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
safeSetStyles(body, css);
body.innerHTML = innerHTML;
return body;
}
38 changes: 7 additions & 31 deletions src/ts/helpers/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SVG Helpers
*/

import { addClass } from "./dom";
import { addClass, safeSetAttributes, safeSetStyles } from "./dom";

export interface StringToStringOrNumberMap { [key: string]: string | number; }
export type DomAttributeMap = StringToStringOrNumberMap;
Expand All @@ -11,33 +11,10 @@ export type CssStyleMap = StringToStringOrNumberMap;
/** Namespace for SVG Elements */
const svgNamespaceUri = "http://www.w3.org/2000/svg";

function entries(obj: StringToStringOrNumberMap): Array<[string, string]> {
const entries: Array<[string, string]> = [];
for (const k of Object.keys(obj)) {
entries.push([k, String((obj[k]))]);
}
return entries;
}

function safeSetAttribute(el: SVGElement, key: string, s: string) {
if (!(key in el)) {
console.warn(new Error(`Trying to set non-existing attribute ${key} = ${s} on a <${el.tagName.toLowerCase()}>.`));
}
el.setAttributeNS(null, key, s);
}

interface StylableSVGElement extends SVGElement {
readonly style: CSSStyleDeclaration;
}

function safeSetStyle(el: StylableSVGElement, key: string, s: string) {
if (key in el.style) {
el.style[key] = s;
} else {
console.warn(new Error(`Trying to set non-existing style ${key} = ${s} on a <${el.tagName.toLowerCase()}>.`));
}
}

interface SvgElementOptions {
attributes?: DomAttributeMap;
css?: CssStyleMap;
Expand All @@ -58,9 +35,8 @@ function newElement<T extends StylableSVGElement>(tagName: string, {
if (text) {
element.textContent = text;
}
entries(css).forEach(([key, value]) => safeSetStyle(element, key, value));
entries(attributes).forEach(([key, value]) => safeSetAttribute(element, key, value));

safeSetStyles(element, css);
safeSetAttributes(element, attributes);
return element;
}

Expand All @@ -77,22 +53,22 @@ export function newClipPath(id: string): SVGClipPathElement {
return newElement<SVGClipPathElement>("clipPath", { attributes });
}

export function newForeignObject(attributes: DomAttributeMap) {
return newElement<SVGForeignObjectElement>("foreignObject", { attributes });
export function newForeignObject(attributes: DomAttributeMap, className = "", css: CssStyleMap = {}) {
return newElement<SVGForeignObjectElement>("foreignObject", { attributes, className, css });
}

export function newA(className: string): SVGAElement {
return newElement<SVGAElement>("a", { className });
}

export function newRect(attributes: DomAttributeMap,
className: string = "",
className = "",
css: CssStyleMap = {}) {
return newElement<SVGRectElement>("rect", { attributes, className, css });
}

export function newLine(attributes: DomAttributeMap,
className: string = "") {
className = "") {
return newElement<SVGLineElement>("line", { className, attributes });
}

Expand Down
7 changes: 3 additions & 4 deletions src/ts/waterfall/details-overlay/html-details-body.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { makeBodyEl, makeHtmlEl } from "../../helpers/dom";
import { escapeHtml, sanitizeUrlForLink } from "../../helpers/parse";
import { WaterfallEntry } from "../../typing/waterfall";

Expand All @@ -11,10 +12,8 @@ import { WaterfallEntry } from "../../typing/waterfall";
*/
export function createDetailsBody(requestID: number, detailsHeight: number, entry: WaterfallEntry) {

const html = document.createElement("html") as HTMLHtmlElement;
const body = document.createElement("body");
body.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
html.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://www.w3.org/2000/xmlns/");
const html = makeHtmlEl();
const body = makeBodyEl();

const tabMenu = entry.tabs.map((t) => {
return `<li><button class="tab-button">${t.title}</button></li>`;
Expand Down

0 comments on commit a5ebd5b

Please sign in to comment.