/**
* A <code><?xxe-remark?></code> indicator.
*/
class RemarkIndicator extends HTMLElement {
constructor() {
super();
let shadow = this.attachShadow({mode: "open"});
shadow.appendChild(RemarkIndicator.TEMPLATE.content.cloneNode(true));
this._pole = shadow.lastElementChild;
this._flag = this._pole.previousElementSibling;
this.addEventListener("dblclick", this.editRemark.bind(this));
this._docView = null;
this._info = null;
}
editRemark(event) {
event.preventDefault();
event.stopPropagation();
let view = NodeView.lookupView(this);
if (view === null) {
// Should not happen.
return;
}
this._docView.selectNode(view)
.then((selected) => {
if (selected) {
this._docView.executeCommand(EXECUTE_NORMAL,
"remark", null);
}
});
}
// -----------------------------------------------------------------------
// Custom element
// -----------------------------------------------------------------------
connectedCallback() {
this._docView = DOMUtil.lookupAncestorByTag(this, "xxe-document-view");
if (this._docView === null) {
// Should not happen.
return;
}
this._info = null;
let infoValue = this.getAttribute("info");
if (infoValue) {
try {
this._info = JSON.parse(infoValue);
} catch (error) {
console.error(`"${infoValue}", invalid "info" attribute`);
}
}
if (this._info === null) {
this._info = { "editor": "??", "bg": "#D3D3D3", "fg": "#808080",
"date": Date.now(), "text": "" };
}
if (this._info.text) {
let tooltip = RemarkIndicator.remarkHeader(this._info.editor,
this._info.date);
let text = this._info.text;
if (text.length > 200) {
text = text.substring(0, 199) + "\u2026";
}
tooltip += "\n" + text;
if (Array.isArray(this._info.replies)) {
const replyCount = this._info.replies.length;
if (replyCount > 0) {
tooltip += "\n\n+ " +
((replyCount === 1)?
`${replyCount} reply` : `${replyCount} replies`);
}
}
this.setAttribute("title", tooltip);
}
this._flag.textContent = RemarkIndicator.getInitials(this._info.editor);
this._flag.setAttribute("style",
`border-color: ${this._info.fg}; background-color: ${this._info.bg};`);
this._pole.setAttribute("style", `background-color: ${this._info.fg};`);
}
// -----------------------------------------------------------------------
// Utilities
// -----------------------------------------------------------------------
static getInitials(editor) {
if (!editor) {
return "??";
} else {
return editor.substring(0, Math.min(2, editor.length));
}
}
static remarkHeader(editor, date) {
let ago = null;
const delta = Date.now() - date;
if (delta >= 0) {
const s = Math.floor(delta / 1000);
const m = Math.floor(s / 60);
const h = Math.floor(m / 60);
const d = Math.floor(h / 24);
if (d >= 1) {
if (d < 15) {
ago = `${editor}, ${d}d ago:`;
}
} else {
if (h >= 1) {
ago = `${editor}, ${h}h ago:`;
} else {
if (m >= 1) {
ago = `${editor}, ${m}m ago:`;
} else {
if (s >= 1) {
ago = `${editor}, ${s}s ago:`;
} else {
ago = `${editor}, now:`;
}
}
}
}
}
if (ago !== null) {
return ago;
} else {
return `On ${(new Date(date)).toLocaleString()}, ${editor} wrote:`;
}
}
}
RemarkIndicator.TEMPLATE = document.createElement("template");
RemarkIndicator.TEMPLATE.innerHTML = `
<style>
:host {
display: inline-flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: sans-serif;
font-variant: normal;
font-size: smaller;
font-weight: bold;
font-style: normal;
text-decoration: none;
color: var(--xui-fg, black);
vertical-align: calc(0.2em + 2px + 0.8em + 0.25em); /*Extra 0.25em*/
}
.flag {
flex: none;
padding: 0.2em 0.4em;
border: 2px solid black;
border-radius: 0.4em;
}
.pole {
flex: none;
width: 2px;
height: 0.8em;
background-color: black;
}
</style><div class="flag"></div><div class="pole"></div>`;
window.customElements.define("xxe-remark-indicator", RemarkIndicator);