diff --git a/README.md b/README.md index b682c88..89e189b 100644 --- a/README.md +++ b/README.md @@ -14,15 +14,34 @@ $ npm i @parcility/kennel Kennel was written to be as easy to interact with as possible. -`render(depiction: any, options?: Parital): Promise` +`render(depiction: any, options?: Partial): Promise` > Render a depiction to either a HTMLElement or a string. > > `depiction`: An object that stores the native depiction's contents. > > `options`: The settings used for rendering. + > `options.ssr`: Output a string instead of a DOM element. +> > `options.defaultTintColor`: The css color used for the tint. +> +> `options.backgroundColor`: The css color used for the background. +> +> `options.ignoredViewNames`: An array of view class names to ignore/not render. +> +> `options.linkForm`: Link to a webpage to render `form-` links. +> +> +> `options.linkHeaderless`: Link to a webpage to render `depiction-` links. +> +> `options.proxyIframeUrl`: The specific proxy url to use for iframe only. +> +> `options.proxyImageUrl`: The specific proxy url to use for image only. +> +> `options.proxyVideoUrl`: The specific proxy url to use for video only. +> +> `options.proxyUrl`: The default proxy url to use for iframe, image or video. `hydrate(target?: ParentNode): void` diff --git a/index.html b/index.html index 8756798..8d01f36 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@ @media screen and (prefers-color-scheme: dark) { body { color: #fff; - background-color: #000; + background-color: #111; } } @@ -25,7 +25,12 @@ async function renderDepiction([name, depictionImport]) { const { default: depiction } = await depictionImport(); - let [dom, ssr] = await Promise.all([render(depiction), render(depiction, { ssr: true })]); + let [dom, ssr, proxy, ignoredViewNames] = await Promise.all([ + render(depiction), + render(depiction, { ssr: true }), + render(depiction, { proxyImageUrl: "https://api.ios-repo-updates.com/image.php?url=" }), + render(depiction, { ignoredViewNames: ["DepictionHeaderView", "DepictionImageView", "DepictionSeparatorView", "DepictionVideoView", "DepictionWebView"] }) + ]); const details = document.createElement("div"); const content = document.createElement("div"); const summary = document.createElement("h3"); @@ -52,7 +57,27 @@ ssrContent.innerHTML = ssr; ssrDetails.append(ssrSummary, ssrContent); - content.append(domDetails, ssrDetails); + // add proxy el + const proxyDetails = document.createElement("details"); + const proxySummary = document.createElement("summary"); + proxySummary.innerHTML = "Proxy"; + const proxyContent = document.createElement("div"); + proxyContent.style.maxWidth = "32rem"; + proxyContent.style.margin = "auto"; + proxyContent.appendChild(proxy); + proxyDetails.append(proxySummary, proxyContent); + + // add ignoredViewNames el + const ignoredViewNamesDetails = document.createElement("details"); + const ignoredViewNamesSummary = document.createElement("summary"); + ignoredViewNamesSummary.innerHTML = "Ignored view names"; + const ignoredViewNamesContent = document.createElement("div"); + ignoredViewNamesContent.style.maxWidth = "32rem"; + ignoredViewNamesContent.style.margin = "auto"; + ignoredViewNamesContent.appendChild(ignoredViewNames); + ignoredViewNamesDetails.append(ignoredViewNamesSummary, ignoredViewNamesContent); + + content.append(domDetails, ssrDetails, proxyDetails, ignoredViewNamesDetails); details.appendChild(content); // add to body diff --git a/lib/index.scss b/lib/index.scss index 7792c12..9b1d175 100644 --- a/lib/index.scss +++ b/lib/index.scss @@ -37,6 +37,7 @@ & > * { flex: 1; + flex-shrink: 1; } } } @@ -97,7 +98,7 @@ span { background: linear-gradient( to right, - #ff8a00 var(--kennel-rating-progress), + rgba(121, 121, 121, 1) var(--kennel-rating-progress), rgba(121, 121, 121, 0.15) var(--kennel-rating-progress) ); background-clip: text; @@ -108,7 +109,7 @@ .nd-review { padding: 1rem 1rem; - background-color: rgba(121, 121, 121, 0.05); + background-color: rgba(121, 121, 121, 0.1); margin-bottom: 1rem; border-radius: 0.5rem; @@ -139,20 +140,19 @@ .nd-button { box-sizing: border-box; - margin: 0.5rem 0; - display: block; - text-decoration: none; + margin: 0.5rem; - & > p { - margin: 0; + & > a { + display: block; + text-decoration: none; } - &.nd-button-link { + & > .nd-button-link { color: var(--kennel-tint-color); margin: 0; } - &.nd-button-not-link { + & > .nd-button-not-link { box-sizing: border-box; text-align: center; display: block; @@ -160,11 +160,13 @@ -webkit-appearance: none; -moz-appearance: none; padding: 0.5rem 1rem; - margin: 0.5rem 0.5rem; font: inherit; border-radius: 0.5rem; appearance: none; width: 100%; + & > span { + margin: 0 0.5rem; + } } } @@ -242,10 +244,13 @@ cursor: pointer; grid-area: tab; text-align: center; - padding: 0.5rem 1rem; + padding: 0 1rem; + } + & > input + label > span { + padding: 0.5rem 0; } - & > input:checked + label { + & > input:checked + label > span { color: var(--kennel-tint-color); border-bottom: solid 1px; } @@ -293,7 +298,7 @@ & > * { margin-right: 1rem; scroll-snap-align: center; - flex-shrink: 0; + flex-shrink: 1; border-radius: var(--screenshot-item-radius); width: var(--screenshot-item-width); height: var(--screenshot-item-height); @@ -304,4 +309,55 @@ } } } + .nd-featured-banners { + overflow: auto hidden; + white-space: nowrap; + margin: 0.5rem; + + & > .nd-banner-item:first-child { + margin-left: 0; + } + + & > .nd-banner-item { + color: #fff; + display: inline-block; + margin: 0 0.25rem; + position: relative; + overflow: hidden; + height: var(--banner-item-height); + width: var(--banner-item-width); + border-radius: var(--banner-item-radius); + + & > img { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%) scale(1.1); + height: 100%; + width: 100%; + object-fit: cover; + } + + & > span { + display: block; + position: absolute; + bottom: 0; + right: 0; + left: 0; + top: 0; + width: 100%; + height: 100%; + line-height: 900%; + padding: 0.75rem; + font-size: 1.5rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + + &.nd-banner-shadow { + text-shadow: 0 0 1.5rem #000, 0 0 1.5rem #000, 0 0 1.5rem #000; + } + } + } + } } diff --git a/lib/index.ts b/lib/index.ts index aeea122..9759150 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -1,14 +1,9 @@ /// import "./index.scss"; -import { createElement, renderElement, setStyles } from "./renderable"; -import { constructView, constructViews, defaultIfNotType, KennelError, makeViews } from "./util"; +import { RenderOptions, createElement, renderElement, setStyles } from "./renderable"; +import { constructView, constructViews, defaultIfNotType, undefIfNotType, KennelError, makeViews } from "./util"; import { DepictionBaseView, mountable } from "./views"; -interface RenderOptions { - ssr: boolean; - defaultTintColor: string; -} - export async function render, U extends T["ssr"] extends true ? string : HTMLElement>( depiction: any, options?: T @@ -16,26 +11,34 @@ export async function render, U extends T["ssr" let tintColor = defaultIfNotType(depiction["tintColor"], "color", options?.defaultTintColor as string) as | string | undefined; + let backgroundColor = undefIfNotType(depiction["backgroundColor"], "color") as + | string + | undefined; // process the depiction let processed: DepictionBaseView[] | undefined; if (Array.isArray(depiction.tabs)) { depiction.className = "DepictionTabView"; - let view = constructView(depiction); + let view = constructView(depiction, options); if (view) { processed = [view]; } } else if (Array.isArray(depiction.views)) { - processed = constructViews(depiction.views); + processed = constructViews(depiction.views, options); } if (!processed) throw new KennelError("Unable to process depiction. No child was found."); // build an element to render let el = createElement("form", { class: "nd-root" }); + let styleOptions: any = {}; if (tintColor) { - setStyles(el, { - "--kennel-tint-color": tintColor, - }); + styleOptions["--kennel-tint-color"] = tintColor; + } + if (backgroundColor) { + styleOptions["background-color"] = backgroundColor; + } + if (Object.keys(styleOptions).length > 0) { + setStyles(el, styleOptions); } el.children = await makeViews(processed); diff --git a/lib/markdown.css b/lib/markdown.css index e3ab26b..b6b7f5a 100644 --- a/lib/markdown.css +++ b/lib/markdown.css @@ -73,4 +73,5 @@ code { a { color: var(--kennel-tint-color); + text-decoration: none; } diff --git a/lib/renderable.ts b/lib/renderable.ts index 66b060c..012b5d5 100644 --- a/lib/renderable.ts +++ b/lib/renderable.ts @@ -1,6 +1,19 @@ import createDOMPurify, { DOMPurifyI } from "dompurify"; import { escapeHTML } from "./util"; +export interface RenderOptions { + ssr: boolean; + defaultTintColor: string; + backgroundColor: string; + ignoredViewNames: any[]; + linkForm: string; + linkHeaderless: string; + proxyUrl: string; + proxyIframeUrl: string; + proxyImageUrl: string; + proxyVideoUrl: string; +} + const PURIFY_OPTIONS: createDOMPurify.Config = { RETURN_DOM_FRAGMENT: false, RETURN_DOM: false, diff --git a/lib/util/index.ts b/lib/util/index.ts index 6825cbc..10403c6 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -1,4 +1,4 @@ -import { RenderableElement, setStyles } from "../renderable"; +import { RenderOptions, RenderableElement, setStyles } from "../renderable"; import { DepictionBaseView, views } from "../views"; import { isValidColor } from "./colors"; import { isValidHttpUrl, isValidHttpUrlExtended } from "./urls"; @@ -41,22 +41,19 @@ export function fontWeightParse(fontWeight: string): string { } } -export function buttonLinkHandler(el: RenderableElement, url: string, label?: string) { - let link = url; +export function buttonLinkHandler(url: string, label?: string, options?: Partial): [string, string] { // javascript: links should do nothing. const jsXssIndex = url.indexOf("javascript:"); if (jsXssIndex !== -1) { - link = url.substring(0, jsXssIndex) + encodeURIComponent(url.substring(jsXssIndex)); + url = url.substring(0, jsXssIndex) + encodeURIComponent(url.substring(jsXssIndex)); // depiction- links should link to a depiction. Use Parcility's API for this. } else if (url.indexOf("depiction-") == 0) { - url = url.substring(10); if (!label) label = "Depiction"; - link = `https://api.parcility.co/render/headerless?url=${encodeURIComponent(url)}&name=${label}`; + url = (options?.linkHeaderless ?? 'https://api.parcility.co/render/headerless?url=') + `${encodeURIComponent(url.substring(10))}&name=${label}`; } else if (url.indexOf("form-") == 0) { - url = url.substring(5); - link = `https://api.parcility.co/render/form?url=${encodeURIComponent(url)}`; + url = (options?.linkForm ?? 'https://api.parcility.co/render/form?url=') + `${encodeURIComponent(url.substring(5))}&name=${label}`; } - el.attributes.href = link; + return [url, (label ?? "")]; } // Alignment @@ -107,18 +104,24 @@ export function applyAlignmentMargin(el: RenderableElement, alignment: Alignment // Processing -export function constructView(view: any): DepictionBaseView | undefined { +export function constructView( + view: any, + options?: Partial +): DepictionBaseView | undefined { let v = views.get(view.class); try { - if (v) return new v(view); + if (v && (!options || !options.ignoredViewNames || !options.ignoredViewNames.includes(view.class))) return new v(view, options); } catch (error) { console.error(error); } return undefined; } -export function constructViews(views: any[]): DepictionBaseView[] { - return views.map(constructView).filter(Boolean) as DepictionBaseView[]; +export function constructViews ( + views: any[], + options?: Partial +): DepictionBaseView[] { + return views.map((view) => constructView(view, options)).filter(Boolean) as DepictionBaseView[]; } export async function makeView(view: DepictionBaseView): Promise { diff --git a/lib/util/urls.ts b/lib/util/urls.ts index e821db5..c26c2ef 100644 --- a/lib/util/urls.ts +++ b/lib/util/urls.ts @@ -1,23 +1,23 @@ export function isValidHttpUrl(string: string): boolean { - let url; - try { - url = new URL(string); - } catch (_) { - return false; - } - return url.protocol === "http:" || url.protocol === "https:"; + let url; + try { + url = new URL(string); + } catch (_) { + return false; + } + return url.protocol === "http:" || url.protocol === "https:"; } export function isValidHttpUrlExtended(string: string): boolean { - if(isValidHttpUrl(string)) { - return true; - } - let url; - try { - url = new URL(string); - } catch (_) { - return false; - } - return url.protocol == "depiction-http:" || url.protocol == "depiction-https:" || - url.protocol == "form-http:" || url.protocol == "form-https:"; + if(isValidHttpUrl(string)) { + return true; + } + let url; + try { + url = new URL(string); + } catch (_) { + return false; + } + return url.protocol == "depiction-http:" || url.protocol == "depiction-https:" || + url.protocol == "form-http:" || url.protocol == "form-https:"; } \ No newline at end of file diff --git a/lib/views/auto_stack.ts b/lib/views/auto_stack.ts index ecbc8c7..fcddac4 100644 --- a/lib/views/auto_stack.ts +++ b/lib/views/auto_stack.ts @@ -1,4 +1,4 @@ -import { createElement, RenderableElement, setStyles } from "../renderable"; +import { RenderOptions, createElement, RenderableElement, setStyles } from "../renderable"; import { constructView, guardIfNotType, makeViews, undefIfNotType } from "../util"; import DepictionBaseView from "./base"; @@ -9,15 +9,18 @@ export default class DepictionAutoStackView extends DepictionBaseView { backgroundColor?: string; static viewName = "DepictionAutoStackView"; - constructor(depiction: any) { - super(depiction); + constructor( + depiction: any, + options?: Partial + ) { + super(depiction, options); let views = guardIfNotType(depiction["views"], "array"); this.horizontalSpacing = guardIfNotType(depiction["horizontalSpacing"], "number"); for (let view of views) { guardIfNotType(view["class"], "string"); guardIfNotType(view["preferredWidth"], "number"); - let v = constructView(view); + let v = constructView(view, options); if (!v) throw new Error("Invalid view"); this.views.push(v); } diff --git a/lib/views/base.ts b/lib/views/base.ts index 30a24e7..0aa0256 100644 --- a/lib/views/base.ts +++ b/lib/views/base.ts @@ -1,13 +1,16 @@ -import { RenderableElement } from "../renderable"; -import { undefIfNotType } from "../util"; +import { RenderOptions, RenderableElement } from "../renderable"; +import { defaultIfNotType, undefIfNotType } from "../util"; export default abstract class DepictionBaseView { tintColor?: string; static viewName = "DepictionBaseView"; - constructor(depiction: any) { + constructor( + depiction: any, + options?: Partial + ) { if (depiction) { - this.tintColor = undefIfNotType(depiction["tintColor"], "color"); + this.tintColor = undefIfNotType(defaultIfNotType(depiction["tintColor"], "color", options?.defaultTintColor as string), "color"); } } diff --git a/lib/views/button.ts b/lib/views/button.ts index 0f6adef..8da9b71 100644 --- a/lib/views/button.ts +++ b/lib/views/button.ts @@ -1,4 +1,4 @@ -import { createElement, RenderableElement, setClassList, setStyles } from "../renderable"; +import { RenderOptions, createElement, RenderableElement, setClassList, setStyles } from "../renderable"; import { buttonLinkHandler, constructView, defaultIfNotType, guardIfNotType, makeView, undefIfNotType } from "../util"; import DepictionBaseView from "./base"; @@ -11,37 +11,41 @@ export default class DepictionButtonView extends DepictionBaseView { openExternal: boolean; static viewName = "DepictionButtonView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); this.isLink = defaultIfNotType(dictionary["isLink"], "boolean", false); this.yPadding = defaultIfNotType(dictionary["yPadding"], "number", 0); + let text = undefIfNotType(dictionary["text"], "string"); let action = undefIfNotType(dictionary["action"], "urlExtended"); if(typeof action !== "string") { this.action = guardIfNotType(dictionary["backupAction"], "urlExtended"); } else { this.action = action; } + [this.action, text] = buttonLinkHandler(this.action, text, options); + this.openExternal = defaultIfNotType(dictionary["openExternal"], "boolean", false); let dict = dictionary["view"]; if (typeof dict === "object") { - this.children = constructView(dict); + this.children = constructView(dict, options); } - if (!this.children) { - let text = dictionary["text"]; - if (typeof text === "string") { - this.text = text; - } + if (!this.children && text.length > 0) { + this.text = text; } } async make(): Promise { + let div = createElement("div"); + setClassList(div, ["nd-button"]); let el = createElement("a"); - setClassList(el, ["nd-button", this.isLink ? "nd-button-link" : "nd-button-not-link"]); + setClassList(el, [this.isLink ? "nd-button-link" : "nd-button-not-link"]); let styles: any = {}; if (this.tintColor) styles["--kennel-tint-color"] = this.tintColor; - buttonLinkHandler(el, this.action, this.text); if (this.isLink) { styles.color = "var(--kennel-tint-color)"; } else { @@ -49,6 +53,7 @@ export default class DepictionButtonView extends DepictionBaseView { styles["color"] = "white"; } + el.attributes.href = this.action; if (this.openExternal) { el.attributes.target = "_blank"; } @@ -59,9 +64,10 @@ export default class DepictionButtonView extends DepictionBaseView { child.attributes.pointerEvents = "none"; el.children = [child]; } else if (this.text) { - el.children = [this.text]; + el.children = [createElement("span", {}, [this.text])]; } setStyles(el, styles); - return el; + div.children = [el]; + return div; } } diff --git a/lib/views/featured-banners.ts b/lib/views/featured-banners.ts new file mode 100644 index 0000000..9c130ee --- /dev/null +++ b/lib/views/featured-banners.ts @@ -0,0 +1,83 @@ +import { RenderOptions, createElement, setClassList, setStyles } from "../renderable"; +import { guardIfNotType, undefIfNotType, parseSize, defaultIfNotType } from "../util"; +import DepictionBaseView from "./base"; + +interface FeaturedBanner { + url: string; + title?: string; + package?: string; + hideShadow: boolean; +} + +export default class FeaturedBannersView extends DepictionBaseView { + itemHeight: number; + itemWidth: number; + itemBorderRadius: number; + banners: FeaturedBanner[]; + static viewName = "FeaturedBannersView"; + + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); + let rawItemSize = guardIfNotType(dictionary["itemSize"], "string"); + [this.itemWidth, this.itemHeight] = parseSize(rawItemSize); + + this.itemBorderRadius = guardIfNotType(dictionary["itemCornerRadius"], "number"); + + this.banners = guardIfNotType(dictionary["banners"], "array") + .map((banner) => this.parseBanner(banner, options)) + .filter(Boolean) as FeaturedBanner[]; + } + + parseBanner( + dictionary: any, + options?: Partial + ): FeaturedBanner | undefined { + let url = guardIfNotType(dictionary["url"], "url"); + if (options?.proxyImageUrl || options?.proxyUrl) { + url = (options?.proxyImageUrl ?? options?.proxyUrl) + encodeURIComponent(url); + } + let title = defaultIfNotType(dictionary["title"], "string", ""); + let pack = undefIfNotType(dictionary["package"], "string"); + let hideShadow = defaultIfNotType(dictionary["hideShadow"], "boolean", false); + return { + url: url, + title: title, + package: pack, + hideShadow: hideShadow + }; + } + + async make() { + const el = createElement("div", { class: "nd-featured-banners" }); + setStyles(el, { + "--banner-item-width": `${this.itemWidth}px`, + "--banner-item-height": `${this.itemHeight}px`, + "--banner-item-radius": `${this.itemBorderRadius}px`, + }); + for (let banner of this.banners) { + let linkEl = createElement("a", { + class: "nd-banner-item", + href: (banner.package ? `cydia://${banner.package}` : banner.url) + }) + el.children.push(linkEl); + + let bannerEl = createElement("img", { + src: banner.url, + alt: (banner.title ?? "") + }); + linkEl.children.push(bannerEl); + + if (banner.title) { + let titleEl = createElement("span", {}, [banner.title]); + if (!banner.hideShadow) { + setClassList(titleEl, ["nd-banner-shadow"]); + } + linkEl.children.push(titleEl); + } + } + return el; + } +} diff --git a/lib/views/header.ts b/lib/views/header.ts index 0e618bc..568e06f 100644 --- a/lib/views/header.ts +++ b/lib/views/header.ts @@ -1,4 +1,4 @@ -import { createElement, setClassList, setStyles } from "../renderable"; +import { RenderOptions, createElement, setClassList, setStyles } from "../renderable"; import { defaultIfNotType, textAlignment } from "../util"; import DepictionBaseView from "./base"; @@ -11,8 +11,11 @@ export default class DepictionHeaderView extends DepictionBaseView { alignment: string; static viewName = "DepictionHeaderView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); if (typeof dictionary["title"] === "string") { this.title = dictionary.title; } diff --git a/lib/views/image.ts b/lib/views/image.ts index 18740b1..2bf7f97 100644 --- a/lib/views/image.ts +++ b/lib/views/image.ts @@ -1,4 +1,4 @@ -import { createElement, RenderableElement, setStyles } from "../renderable"; +import { RenderOptions, createElement, RenderableElement, setStyles } from "../renderable"; import { Alignment, applyAlignmentMargin, defaultIfNotType, getAlignment, guardIfNotType, KennelError } from "../util"; import DepictionBaseView from "./base"; @@ -11,12 +11,19 @@ export default class DepictionImageView extends DepictionBaseView { borderRadius: number; static viewName = "DepictionImageView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); this.url = guardIfNotType(dictionary["URL"], "url"); this.width = defaultIfNotType(dictionary["width"], "number", 0); this.height = defaultIfNotType(dictionary["height"], "number", 0); + if(options?.proxyImageUrl || options?.proxyUrl) { + this.url = (options?.proxyImageUrl ?? options?.proxyUrl) + encodeURIComponent(this.url); + } + if (this.width === 0 || this.height === 0) throw new KennelError("Invalid image size"); this.borderRadius = guardIfNotType(dictionary["cornerRadius"], "number"); diff --git a/lib/views/index.ts b/lib/views/index.ts index 51858f5..53931b0 100644 --- a/lib/views/index.ts +++ b/lib/views/index.ts @@ -1,7 +1,9 @@ export type { default as DepictionBaseView } from "./base"; +import { RenderOptions } from "../renderable"; import AutoStackView from "./auto_stack"; import ButtonView from "./button"; +import FeaturedBannersView from "./featured-banners" import HeaderView from "./header"; import ImageView from "./image"; import LabelView from "./label"; @@ -24,7 +26,10 @@ import WebView from "./web"; import DepictionBaseView from "./base"; export type DepictionViewConstructor = { - new (dictionary: any): T; + new ( + dictionary: any, + options?: Partial + ): T; viewName: string; hydrate?(el: HTMLElement): void; }; @@ -50,6 +55,7 @@ export const views = new Map>([ ["DepictionTableTextView", TableTextView], ["DepictionVideoView", VideoView], ["DepictionWebView", WebView], + ["FeaturedBannersView", FeaturedBannersView], ]); export const mountable = new Map>( diff --git a/lib/views/label.ts b/lib/views/label.ts index e716791..1fc2171 100644 --- a/lib/views/label.ts +++ b/lib/views/label.ts @@ -1,4 +1,4 @@ -import { createElement, RenderableElement, setStyles } from "../renderable"; +import { RenderOptions, createElement, RenderableElement, setStyles } from "../renderable"; import { defaultIfNotType, fontWeightParse, parseSize, textAlignment, undefIfNotType } from "../util"; import DepictionBaseView from "./base"; @@ -13,8 +13,11 @@ export default class DepictionLabelView extends DepictionBaseView { fontSize: number; static viewName = "DepictionLabelView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); if (typeof dictionary["text"] === "string") { this.text = dictionary.text; } diff --git a/lib/views/layer.ts b/lib/views/layer.ts index c54bd60..1711ea9 100644 --- a/lib/views/layer.ts +++ b/lib/views/layer.ts @@ -1,4 +1,4 @@ -import { createElement } from "../renderable"; +import { RenderOptions, createElement } from "../renderable"; import { constructViews, guardIfNotType, makeViews } from "../util"; import DepictionBaseView from "./base"; @@ -6,10 +6,13 @@ export default class DepictionLayerView extends DepictionBaseView { views: DepictionBaseView[]; static viewName = "DepictionLayerView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); let rawViews = guardIfNotType(dictionary["views"], "array"); - this.views = constructViews(rawViews); + this.views = constructViews(rawViews, options); } async make() { diff --git a/lib/views/markdown.ts b/lib/views/markdown.ts index c50d624..5ff0ccf 100644 --- a/lib/views/markdown.ts +++ b/lib/views/markdown.ts @@ -1,6 +1,6 @@ import { marked } from "marked"; import markdownStyles from "../markdown.css?raw"; -import { createElement, createRawNode, createShadowedElement, renderElementString, setStyles } from "../renderable"; +import { RenderOptions, createElement, createRawNode, createShadowedElement, renderElementString, setStyles } from "../renderable"; import { defaultIfNotType, escapeHTML, guardIfNotType, makeView } from "../util"; import DepictionBaseView from "./base"; import DepictionSeparatorView from "./separator"; @@ -21,8 +21,11 @@ export default class DepictionMarkdownView extends DepictionBaseView { useRawFormat: boolean; static viewName = "DepictionMarkdownView"; - constructor(dictionary: any) { - super(dictionary); + constructor( + dictionary: any, + options?: Partial + ) { + super(dictionary, options); let md = guardIfNotType(dictionary["markdown"], "string"); this.useMargins = defaultIfNotType(dictionary["useMargins"], "boolean", true); this.useSpacing = defaultIfNotType(dictionary["useSpacing"], "boolean", true); @@ -33,7 +36,7 @@ export default class DepictionMarkdownView extends DepictionBaseView { let xssWarn = `

[Warning: This depiction may be trying to maliciously run code in your browser.]


`; rendered = rendered.replace( /
/gi, - await renderElementString(await makeView(new DepictionSeparatorView(undefined))) + await renderElementString(await makeView(new DepictionSeparatorView(undefined, undefined))) ); if ( rendered.toLowerCase().indexOf("