elm-pages-v3-beta/examples/docs/public/elm-oembed.js
2021-05-18 10:44:30 -07:00

150 lines
4.4 KiB
JavaScript

export function setup() {
customElements.define(
"oembed-element",
class extends HTMLElement {
connectedCallback() {
let shadow = this.attachShadow({ mode: "closed" });
const urlAttr = this.getAttribute("url");
if (urlAttr) {
renderOembed(shadow, urlAttr, {
maxwidth: this.getAttribute("maxwidth"),
maxheight: this.getAttribute("maxheight"),
});
} else {
const discoverUrl = this.getAttribute("discover-url");
if (discoverUrl) {
getDiscoverUrl(discoverUrl, function (discoveredUrl) {
if (discoveredUrl) {
renderOembed(shadow, discoveredUrl, null);
}
});
}
}
}
}
);
/**
*
* @param {ShadowRoot} shadow
* @param {string} urlToEmbed
* @param {{maxwidth: string?; maxheight: string?}?} options
*/
function renderOembed(shadow, urlToEmbed, options) {
let apiUrlBuilder = new URL(
`https://cors-anywhere.herokuapp.com/${urlToEmbed}`
);
if (options && options.maxwidth) {
apiUrlBuilder.searchParams.set("maxwidth", options.maxwidth);
}
if (options && options.maxheight) {
apiUrlBuilder.searchParams.set("maxheight", options.maxheight);
}
const apiUrl = apiUrlBuilder.toString();
httpGetAsync(apiUrl, (rawResponse) => {
const response = JSON.parse(rawResponse);
switch (response.type) {
case "rich":
tryRenderingHtml(shadow, response);
break;
case "video":
tryRenderingHtml(shadow, response);
break;
case "photo":
let img = document.createElement("img");
img.setAttribute("src", response.url);
if (options) {
img.setAttribute(
"style",
`max-width: ${options.maxwidth}px; max-height: ${options.maxheight}px;`
);
}
shadow.appendChild(img);
break;
default:
break;
}
});
}
/**
* @param {{
height: ?number;
width: ?number;
html: any;
}} response
* @param {ShadowRoot} shadow
*/
function tryRenderingHtml(shadow, response) {
if (response && typeof response.html) {
let iframe = createIframe(response);
shadow.appendChild(iframe);
setTimeout(() => {
let refetchedIframe = shadow.querySelector("iframe");
if (refetchedIframe && !response.height) {
refetchedIframe.setAttribute(
"height",
// @ts-ignore
(iframe.contentWindow.document.body.scrollHeight + 10).toString()
);
}
if (refetchedIframe && !response.width) {
refetchedIframe.setAttribute(
"width",
// @ts-ignore
(iframe.contentWindow.document.body.scrollWidth + 10).toString()
);
}
}, 1000);
}
}
/**
* @param {{ height: number?; width: number?; html: string; }} response
* @returns {HTMLIFrameElement}
*/
function createIframe(response) {
let iframe = document.createElement("iframe");
iframe.setAttribute("border", "0");
iframe.setAttribute("frameborder", "0");
iframe.setAttribute("height", ((response.height || 500) + 20).toString());
iframe.setAttribute("width", ((response.width || 500) + 20).toString());
iframe.setAttribute("style", "max-width: 100%;");
iframe.srcdoc = response.html;
return iframe;
}
/**
* @param {string} url
* @param {{ (discoveredUrl: string?): void;}} callback
*/
function getDiscoverUrl(url, callback) {
let apiUrl = new URL(
`https://cors-anywhere.herokuapp.com/${url}`
).toString();
httpGetAsync(apiUrl, function (response) {
let dom = document.createElement("html");
dom.innerHTML = response;
/** @type {HTMLLinkElement | null} */ const oembedTag = dom.querySelector(
'link[type="application/json+oembed"]'
);
callback(oembedTag && oembedTag.href);
});
}
/**
* @param {string} theUrl
* @param {{ (rawResponse: string): void }} callback
*/
function httpGetAsync(theUrl, callback) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(xmlHttp.responseText);
};
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
}
}