nehan-player
Version:
web component for paged media powered by nehan layout engine
211 lines • 9.68 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { layoutSettings, isMultiCol, isMultiRow, decGridCol, decGridRow, getElementLrPaddingSize, getElementBottomPaddingSize, getPlayerSize, getPlayerStyle, getPlayerHTML, getGridStyle } from './PlayerLayout';
import { Utils, WritingMode, PhysicalSize } from 'nehan';
import { NehanPagedMediaPlayer } from './NehanPagedMediaPlayer';
const THEME_CSS_ID = "theme-css";
const MIN_UPDATE_TIME = 200;
let responsivePlayers = {};
let globalConfig = {
cssFiles: [],
onFetchContent(src, content) { return content; },
onClickLeftPage(player) { player.gotoLeftPage(); },
onClickRightPage(player) { player.gotoRightPage(); },
};
function handleResize() {
Object.values(responsivePlayers).forEach((player) => player.refresh(true));
}
function genId() {
const time = new Date();
return `player-${time.getTime()}`;
}
const defaultAttrs = {
src: "",
theme: "",
width: "responsive",
height: 450,
fontSize: 16,
fontFamily: "",
lineHeight: 2,
layout: "1x1",
borderSize: 1,
writingMode: "horizontal-tb",
};
function truncateMinMax(value, min, max) {
return Math.max(min, Math.min(max, value));
}
export class NehanPlayer extends HTMLElement {
constructor() {
super();
this.src = "";
this.html = "";
this.$shadow = this.attachShadow({ mode: "open" });
const id = this.getAttribute("id");
if (!id) {
this.id = genId();
}
}
static initialize(userConfig) {
if (userConfig) {
globalConfig = Object.assign(Object.assign({}, globalConfig), userConfig);
}
customElements.define("nehan-player", NehanPlayer);
}
static get observedAttributes() {
return ["class"];
}
connectedCallback() {
this.render();
}
attributeChangedCallback(name, oldValue, newValue) {
return __awaiter(this, void 0, void 0, function* () {
if (name === "class" && this.classList.contains("update")) {
yield this.render();
this.classList.remove("update");
}
});
}
update(attrs) {
let isUpdated = false;
if (attrs.theme && Object.keys(attrs).length === 1) {
const $old = this.$shadow.getElementById(THEME_CSS_ID);
const $new = this.createCssLink(attrs.theme, true);
const $first = this.$shadow.firstElementChild;
if ($old) {
this.$shadow.replaceChild($new, $old);
}
else if ($first) {
this.$shadow.insertBefore($new, $first);
}
else {
this.$shadow.appendChild($new);
}
this.setAttribute("theme", attrs.theme);
return;
}
for (const [key, value] of Object.entries(attrs)) {
const attrName = Utils.String.camelToChain(key);
const old = this.getAttribute(attrName) || "";
if (value !== old) {
if (key === "width" && old === "responsive") {
delete responsivePlayers[this.id];
}
this.setAttribute(attrName, value);
isUpdated = true;
}
}
if (isUpdated) {
this.refresh(false);
}
}
createCssLink(href, theme = false) {
const link = document.createElement("link");
if (theme) {
link.id = THEME_CSS_ID;
}
link.setAttribute("rel", "stylesheet");
link.setAttribute("type", "text/css");
link.setAttribute("href", href);
return link;
}
refresh(throttle) {
const curTime = new Date().getTime();
if (throttle && this.lastUpdate && curTime - this.lastUpdate < MIN_UPDATE_TIME) {
return;
}
this.lastUpdate = curTime;
this.classList.add("update");
}
parseWidth() {
const width = this.getAttribute("width") || defaultAttrs.width;
if (!width) {
throw new Error("System Error: width can't be resolved!");
}
if (width === "responsive") {
if (this.parentElement) {
return this.parentElement.clientWidth;
}
return this.clientWidth;
}
return typeof width === "number" ? width : parseInt(width);
}
render() {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const src = this.getAttribute("src") || defaultAttrs.src;
const theme = this.getAttribute("theme") || defaultAttrs.theme;
const width = Math.max(this.parseWidth(), layoutSettings.minWidth);
const height = Math.max(parseInt(this.getAttribute("height") || String(defaultAttrs.height)), layoutSettings.minHeight);
let layout = (this.getAttribute("layout") || layoutSettings.defaultLayout);
if (isMultiCol(layout) && width < layoutSettings.minMultiColWidth) {
layout = decGridCol(layout);
}
if (isMultiRow(layout) && height < layoutSettings.minMultiRowHeight) {
layout = decGridRow(layout);
}
const lineHeight = truncateMinMax(parseFloat(this.getAttribute("line-height") || String(defaultAttrs.lineHeight)), 1.5, 2.0);
const fontSize = truncateMinMax(parseInt(this.getAttribute("font-size") || String(defaultAttrs.fontSize)), layoutSettings.minFontSize, layoutSettings.maxFontSize);
const fontFamily = this.getAttribute("font-family") || defaultAttrs.fontFamily || "";
const borderSize = Math.min(parseInt(this.getAttribute("border-size") || String(defaultAttrs.borderSize)), layoutSettings.maxBorderSize);
const writingModeValue = (this.getAttribute("writing-mode") || defaultAttrs.writingMode);
const writingMode = new WritingMode(writingModeValue);
const elementSize = new PhysicalSize({ width, height });
const lrPaddingSize = getElementLrPaddingSize(writingMode, layout, elementSize, fontSize, lineHeight, borderSize);
const bottomPaddingSize = getElementBottomPaddingSize(writingMode, layout, elementSize, fontSize, lineHeight, borderSize);
const playerSize = getPlayerSize(elementSize, fontSize, lrPaddingSize, bottomPaddingSize, borderSize);
this.$shadow.innerHTML = "";
const screenStyle = document.createElement("style");
const gridStyle = document.createElement("style");
screenStyle.textContent = getPlayerStyle(writingMode, playerSize, fontSize, lrPaddingSize, bottomPaddingSize, borderSize);
gridStyle.textContent = getGridStyle(layout, playerSize);
this.$shadow.appendChild(screenStyle);
this.$shadow.appendChild(gridStyle);
if (theme) {
const link = this.createCssLink(theme, true);
this.$shadow.appendChild(link);
}
const cssFiles = globalConfig.cssFiles || [];
cssFiles.forEach(href => {
const link = this.createCssLink(href, false);
this.$shadow.appendChild(link);
});
const cssText = globalConfig.cssText || "";
if (cssText) {
const style = document.createElement("style");
style.innerHTML = cssText;
this.$shadow.appendChild(style);
}
const template = document.createElement("template");
template.innerHTML = getPlayerHTML();
this.$shadow.appendChild(template.content.cloneNode(true));
const slotContent = ((_a = this.$shadow.host.querySelector("div[slot='content']")) === null || _a === void 0 ? void 0 : _a.innerHTML) || "";
if (slotContent !== "") {
this.html = globalConfig.onFetchContent ? globalConfig.onFetchContent("content.slot", slotContent) : slotContent;
}
else if (!src) {
this.html = "Can't resolve content. Neither 'content' slot or 'src' attribute is specified!";
}
else if (src !== this.src || !this.html) {
this.src = src;
this.html = yield fetch(this.src)
.then(response => response.ok ? response.text() : `Failed to load ${src}`)
.then(text => globalConfig.onFetchContent ? globalConfig.onFetchContent(src, text) : text);
}
const player = new NehanPagedMediaPlayer(globalConfig, this, this.$shadow, this.html, layout, writingMode, playerSize, fontSize, fontFamily);
if (this.getAttribute("width") === "responsive") {
if (Object.entries(responsivePlayers).length === 0) {
window.addEventListener("resize", handleResize);
}
responsivePlayers[this.id] = player;
}
});
}
}
//# sourceMappingURL=NehanPlayerElement.js.map