import {LitElement, html, unsafeHTML} from './lit-all.min.js'; import * as tfrpc from '/static/tfrpc.js'; import {styles} from './tf-styles.js'; class TfTabSearchElement extends LitElement { static get properties() { return { drafts: {type: Object}, whoami: {type: String}, users: {type: Object}, following: {type: Array}, query: {type: String}, expanded: {type: Object}, messages: {type: Array}, results: {type: Array}, error: {type: Object}, }; } static styles = styles; constructor() { super(); let self = this; this.whoami = null; this.users = {}; this.following = []; this.expanded = {}; this.drafts = {}; tfrpc.rpc.localStorageGet('drafts').then(function (d) { self.drafts = JSON.parse(d || '{}'); }); } async search(query) { console.log('Searching...', this.whoami, query); let search = this.renderRoot.getElementById('search'); if (search) { search.value = query; search.focus(); search.select(); } await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query)); this.error = undefined; this.results = []; this.messages = []; if (query.startsWith('sql:')) { this.messages = []; try { this.results = await tfrpc.rpc.query( query.substring('sql:'.length), [] ); } catch (e) { this.results = []; this.error = e; } } else { let results = await tfrpc.rpc.query( ` SELECT messages.id, messages.previous, messages.author, messages.sequence, messages.timestamp, messages.hash, json(messages.content) AS content, messages.signature FROM messages_fts(?) JOIN messages ON messages.rowid = messages_fts.rowid JOIN json_each(?) AS following ON messages.author = following.value ORDER BY timestamp DESC limit 100 `, ['"' + query.replace('"', '""') + '"', JSON.stringify(this.following)] ); console.log('Done.'); search = this.renderRoot.getElementById('search'); if (search) { search.value = query; search.focus(); search.select(); } this.messages = results; } } search_keydown(event) { if (event.keyCode == 13) { this.query = this.renderRoot.getElementById('search').value; } } on_expand(event) { if (event.detail.expanded) { let expand = {}; expand[event.detail.id] = true; this.expanded = Object.assign({}, this.expanded, expand); } else { delete this.expanded[event.detail.id]; this.expanded = Object.assign({}, this.expanded); } } draft(event) { let id = event.detail.id || ''; let previous = this.drafts[id]; if (event.detail.draft !== undefined) { this.drafts[id] = event.detail.draft; } else { delete this.drafts[id]; } this.drafts = Object.assign({}, this.drafts); tfrpc.rpc.localStorageSet('drafts', JSON.stringify(this.drafts)); } render_results() { if (this.error) { return html`

${this.error.message}

${this.error.stack}
`; } else if (this.messages?.length) { return html``; } else if (this.results?.length) { let keys = Object.keys(this.results[0]).sort(); return html` ${keys.map((key) => html``)} ${this.results.map( (row) => html` ${keys.map((key) => html``)} ` )}
${key}
${row[key]}
`; } else { return html`
No results.
`; } } render() { if (this.query !== this.last_query) { this.last_query = this.query; this.search(this.query); } let self = this; return html`
${this.render_results()}
`; } } customElements.define('tf-tab-search', TfTabSearchElement);