import {LitElement, html} from './lit-all.min.js'; import * as tfutils from './tf-utils.js'; import * as tfrpc from '/static/tfrpc.js'; import {styles} from './tf-styles.js'; import Tribute from './tribute.esm.js'; class TfComposeElement extends LitElement { static get properties() { return { whoami: {type: String}, users: {type: Object}, root: {type: String}, branch: {type: String}, mentions: {type: Object}, } } static styles = styles; constructor() { super(); this.users = {}; this.root = undefined; this.branch = undefined; this.mentions = {}; } changed(event) { let edit = this.renderRoot.getElementById('edit'); let preview = this.renderRoot.getElementById('preview'); let text = edit.value; /* Update mentions. */ for (let match of text.matchAll(/\[([^\[]+)]\(([@&%][^\)]+)/g)) { let name = match[1]; let link = match[2]; let balance = 0; let bracket_end = match.index + match[1].length + '[]'.length - 1; for (let i = bracket_end; i >= 0; i--) { if (text.charAt(i) == ']') { balance++; } else if (text.charAt(i) == '[') { balance--; } if (balance <= 0) { name = text.substring(i + 1, bracket_end); break; } } if (!this.mentions[link]) { this.mentions[link] = { link: link, } } this.mentions[link].name = name.startsWith('@') ? name.substring(1) : name; this.mentions = Object.assign({}, this.mentions); } preview.innerHTML = tfutils.markdown(text); } add_file(file) { let self = this; file.arrayBuffer().then(function(buffer) { let bin = Array.from(new Uint8Array(buffer)); return Promise.all([tfrpc.rpc.store_blob(bin), bin]); }).then(function([id, bin]) { self.mentions[id] = { link: id, name: file.name, type: file.type, size: bin.length, }; self.mentions = Object.assign({}, self.mentions); let edit = self.renderRoot.getElementById('edit'); edit.value += `\n![${file.name}](${id})`; self.changed(); }).catch(function(e) { alert(e.message); }); } paste(event) { let self = this; for(let item of event.clipboardData.items) { if (item.type?.startsWith('image/')) { let file = item.getAsFile(); if (!file) { continue; } self.add_file(file); break; } } } submit() { let self = this; let edit = this.renderRoot.getElementById('edit'); let message = { type: 'post', text: edit.value, }; if (this.root || this.branch) { message.root = this.root; message.branch = this.branch; } if (Object.values(this.mentions).length) { message.mentions = Object.values(this.mentions); } console.log('Would post:', message); tfrpc.rpc.appendMessage(this.whoami, message).then(function() { edit.value = ''; self.changed(); }).catch(function(error) { alert(error.message); }); } discard() { let edit = this.renderRoot.getElementById('edit'); edit.value = ''; this.changed(); this.dispatchEvent(new CustomEvent('tf-discard')); } attach() { let self = this; let edit = this.renderRoot.getElementById('edit'); let input = document.createElement('input'); input.type = 'file'; input.onchange = function(event) { let file = event.target.files[0]; self.add_file(file); }; input.click(); } firstUpdated() { let tribute = new Tribute({ values: Object.entries(this.users).map(x => ({key: x[1].name, value: x[0]})), selectTemplate: function(item) { return `[@${item.original.key}](${item.original.value})`; }, }); tribute.attach(this.renderRoot.getElementById('edit')); } remove_mention(id) { delete this.mentions[id]; this.mentions = Object.assign({}, this.mentions); } render_mention(mention) { let self = this; return html`
${JSON.stringify(mention, null, 2)}
self.remove_mention(mention.link)}>
`; } render() { let self = this; let result = html`
${Object.values(this.mentions).map(x => self.render_mention(x))} `; return result; } } customElements.define('tf-compose', TfComposeElement);