| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | import {LitElement, html, unsafeHTML} from './lit-all.min.js'; | 
					
						
							|  |  |  | import * as tfrpc from '/static/tfrpc.js'; | 
					
						
							| 
									
										
										
										
											2025-10-22 19:39:20 -04:00
										 |  |  | import {styles, generate_theme} from './tf-styles.js'; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TfTabSearchElement extends LitElement { | 
					
						
							|  |  |  | 	static get properties() { | 
					
						
							|  |  |  | 		return { | 
					
						
							| 
									
										
										
										
											2024-09-11 20:25:55 -04:00
										 |  |  | 			drafts: {type: Object}, | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 			whoami: {type: String}, | 
					
						
							|  |  |  | 			users: {type: Object}, | 
					
						
							|  |  |  | 			following: {type: Array}, | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 			query: {type: String}, | 
					
						
							| 
									
										
										
										
											2023-06-14 16:39:08 +00:00
										 |  |  | 			expanded: {type: Object}, | 
					
						
							| 
									
										
										
										
											2025-10-22 18:21:22 -04:00
										 |  |  | 			messages: {type: Array}, | 
					
						
							|  |  |  | 			results: {type: Array}, | 
					
						
							|  |  |  | 			error: {type: Object}, | 
					
						
							| 
									
										
										
										
											2023-03-29 22:02:12 +00:00
										 |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static styles = styles; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 		let self = this; | 
					
						
							|  |  |  | 		this.whoami = null; | 
					
						
							|  |  |  | 		this.users = {}; | 
					
						
							|  |  |  | 		this.following = []; | 
					
						
							| 
									
										
										
										
											2023-06-14 16:39:08 +00:00
										 |  |  | 		this.expanded = {}; | 
					
						
							| 
									
										
										
										
											2024-09-11 20:25:55 -04:00
										 |  |  | 		this.drafts = {}; | 
					
						
							|  |  |  | 		tfrpc.rpc.localStorageGet('drafts').then(function (d) { | 
					
						
							|  |  |  | 			self.drafts = JSON.parse(d || '{}'); | 
					
						
							|  |  |  | 		}); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 	async search(query) { | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		console.log('Searching...', this.whoami, query); | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 		let search = this.renderRoot.getElementById('search'); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		if (search) { | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 			search.value = query; | 
					
						
							|  |  |  | 			search.focus(); | 
					
						
							|  |  |  | 			search.select(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		await tfrpc.rpc.setHash('#q=' + encodeURIComponent(query)); | 
					
						
							| 
									
										
										
										
											2025-10-22 18:21:22 -04:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	search_keydown(event) { | 
					
						
							|  |  |  | 		if (event.keyCode == 13) { | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 			this.query = this.renderRoot.getElementById('search').value; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-14 16:39:08 +00:00
										 |  |  | 	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); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-11 20:25:55 -04:00
										 |  |  | 	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)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-10-22 18:21:22 -04:00
										 |  |  | 	render_results() { | 
					
						
							|  |  |  | 		if (this.error) { | 
					
						
							|  |  |  | 			return html`<h2 style="color: red">${this.error.message}</h2>
 | 
					
						
							|  |  |  | 				<pre style="color: red">${this.error.stack}</pre>`; | 
					
						
							|  |  |  | 		} else if (this.messages?.length) { | 
					
						
							|  |  |  | 			return html`<tf-news
 | 
					
						
							|  |  |  | 				id="news" | 
					
						
							|  |  |  | 				whoami=${this.whoami} | 
					
						
							|  |  |  | 				.messages=${this.messages} | 
					
						
							|  |  |  | 				.users=${this.users} | 
					
						
							|  |  |  | 				.expanded=${this.expanded} | 
					
						
							|  |  |  | 				.drafts=${this.drafts} | 
					
						
							|  |  |  | 				@tf-expand=${this.on_expand} | 
					
						
							|  |  |  | 				@tf-draft=${this.draft} | 
					
						
							|  |  |  | 			></tf-news>`; | 
					
						
							|  |  |  | 		} else if (this.results?.length) { | 
					
						
							|  |  |  | 			let keys = Object.keys(this.results[0]).sort(); | 
					
						
							|  |  |  | 			return html`<table style="width: 100%; max-width: 100%">
 | 
					
						
							|  |  |  | 				<tr> | 
					
						
							|  |  |  | 					${keys.map((key) => html`<th>${key}</th>`)} | 
					
						
							|  |  |  | 				</tr> | 
					
						
							|  |  |  | 				${this.results.map( | 
					
						
							|  |  |  | 					(row) => | 
					
						
							|  |  |  | 						html`<tr>
 | 
					
						
							|  |  |  | 							${keys.map((key) => html`<td>${row[key]}</td>`)} | 
					
						
							|  |  |  | 						</tr>` | 
					
						
							|  |  |  | 				)} | 
					
						
							|  |  |  | 			</table>`; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return html`<div>No results.</div>`; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	render() { | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 		if (this.query !== this.last_query) { | 
					
						
							| 
									
										
										
										
											2023-06-14 16:39:08 +00:00
										 |  |  | 			this.last_query = this.query; | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 			this.search(this.query); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		let self = this; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		return html`
 | 
					
						
							| 
									
										
										
										
											2025-10-22 19:39:20 -04:00
										 |  |  | 			<style>${generate_theme()}</style> | 
					
						
							| 
									
										
										
										
											2025-10-22 18:21:22 -04:00
										 |  |  | 			<div class="w3-padding"> | 
					
						
							|  |  |  | 				<div style="display: flex; flex-direction: row; gap: 4px"> | 
					
						
							|  |  |  | 					<input type="text" class="w3-input w3-theme-d1" id="search" value=${this.query} style="flex: 1" @keydown=${this.search_keydown}></input> | 
					
						
							|  |  |  | 					<button class="w3-button w3-theme-d1" @click=${(event) => self.search(self.renderRoot.getElementById('search').value)}>Search</button> | 
					
						
							|  |  |  | 				</div> | 
					
						
							|  |  |  | 				${this.render_results()} | 
					
						
							| 
									
										
										
										
											2022-09-15 00:16:37 +00:00
										 |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		`;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | customElements.define('tf-tab-search', TfTabSearchElement); |