| 
									
										
										
										
											2025-01-11 14:09:42 -05:00
										 |  |  | import {LitElement, html, unsafeHTML, repeat, until} from './lit-all.min.js'; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 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 TfNewsElement extends LitElement { | 
					
						
							|  |  |  | 	static get properties() { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			whoami: {type: String}, | 
					
						
							|  |  |  | 			users: {type: Object}, | 
					
						
							|  |  |  | 			messages: {type: Array}, | 
					
						
							|  |  |  | 			following: {type: Array}, | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  | 			drafts: {type: Object}, | 
					
						
							| 
									
										
										
										
											2023-01-25 00:56:10 +00:00
										 |  |  | 			expanded: {type: Object}, | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  | 			channel: {type: String}, | 
					
						
							|  |  |  | 			channel_unread: {type: Number}, | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  | 			recent_reactions: {type: Array}, | 
					
						
							| 
									
										
										
										
											2025-06-11 19:22:21 -04:00
										 |  |  | 			hash: {type: String}, | 
					
						
							| 
									
										
										
										
											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.messages = []; | 
					
						
							|  |  |  | 		this.following = []; | 
					
						
							| 
									
										
										
										
											2023-01-21 00:16:18 +00:00
										 |  |  | 		this.drafts = {}; | 
					
						
							| 
									
										
										
										
											2023-01-25 00:56:10 +00:00
										 |  |  | 		this.expanded = {}; | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  | 		this.channel_unread = -1; | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  | 		this.recent_reactions = []; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-07 23:37:06 +00:00
										 |  |  | 	process_messages(messages) { | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		let self = this; | 
					
						
							| 
									
										
										
										
											2022-12-07 23:37:06 +00:00
										 |  |  | 		let messages_by_id = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		console.log('processing', messages.length, 'messages'); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-18 12:43:25 -05:00
										 |  |  | 		function ensure_message(id, rowid) { | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 			let found = messages_by_id[id]; | 
					
						
							|  |  |  | 			if (found) { | 
					
						
							|  |  |  | 				return found; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				let added = { | 
					
						
							| 
									
										
										
										
											2024-12-18 12:43:25 -05:00
										 |  |  | 					rowid: rowid, | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 					id: id, | 
					
						
							|  |  |  | 					placeholder: true, | 
					
						
							|  |  |  | 					content: '"placeholder"', | 
					
						
							|  |  |  | 					parent_message: undefined, | 
					
						
							|  |  |  | 					child_messages: [], | 
					
						
							|  |  |  | 					votes: [], | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 				messages_by_id[id] = added; | 
					
						
							|  |  |  | 				return added; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		function link_message(message) { | 
					
						
							|  |  |  | 			if (message.content.type === 'vote') { | 
					
						
							| 
									
										
										
										
											2024-12-18 12:43:25 -05:00
										 |  |  | 				let parent = ensure_message(message.content.vote.link, message.rowid); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 				if (!parent.votes) { | 
					
						
							|  |  |  | 					parent.votes = []; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				parent.votes.push(message); | 
					
						
							|  |  |  | 				message.parent_message = message.content.vote.link; | 
					
						
							|  |  |  | 			} else if (message.content.type == 'post') { | 
					
						
							|  |  |  | 				if (message.content.root) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					if (typeof message.content.root === 'string') { | 
					
						
							| 
									
										
										
										
											2024-12-18 12:43:25 -05:00
										 |  |  | 						let m = ensure_message(message.content.root, message.rowid); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 						if (!m.child_messages) { | 
					
						
							|  |  |  | 							m.child_messages = []; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						m.child_messages.push(message); | 
					
						
							|  |  |  | 						message.parent_message = message.content.root; | 
					
						
							|  |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2024-12-18 12:43:25 -05:00
										 |  |  | 						let m = ensure_message(message.content.root[0], message.rowid); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 						if (!m.child_messages) { | 
					
						
							|  |  |  | 							m.child_messages = []; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						m.child_messages.push(message); | 
					
						
							|  |  |  | 						message.parent_message = message.content.root[0]; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-01 00:43:54 +00:00
										 |  |  | 		for (let message of messages) { | 
					
						
							| 
									
										
										
										
											2023-01-26 02:08:14 +00:00
										 |  |  | 			message.votes = []; | 
					
						
							| 
									
										
										
										
											2022-12-01 00:43:54 +00:00
										 |  |  | 			message.parent_message = undefined; | 
					
						
							|  |  |  | 			message.child_messages = undefined; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		for (let message of messages) { | 
					
						
							|  |  |  | 			try { | 
					
						
							|  |  |  | 				message.content = JSON.parse(message.content); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			} catch {} | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 			if (!messages_by_id[message.id]) { | 
					
						
							|  |  |  | 				messages_by_id[message.id] = message; | 
					
						
							|  |  |  | 				link_message(message); | 
					
						
							|  |  |  | 			} else if (messages_by_id[message.id].placeholder) { | 
					
						
							|  |  |  | 				let placeholder = messages_by_id[message.id]; | 
					
						
							|  |  |  | 				messages_by_id[message.id] = message; | 
					
						
							|  |  |  | 				message.parent_message = placeholder.parent_message; | 
					
						
							|  |  |  | 				message.child_messages = placeholder.child_messages; | 
					
						
							|  |  |  | 				message.votes = placeholder.votes; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				if ( | 
					
						
							|  |  |  | 					placeholder.parent_message && | 
					
						
							|  |  |  | 					messages_by_id[placeholder.parent_message] | 
					
						
							|  |  |  | 				) { | 
					
						
							|  |  |  | 					let children = | 
					
						
							|  |  |  | 						messages_by_id[placeholder.parent_message].child_messages; | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 					children.splice(children.indexOf(placeholder), 1); | 
					
						
							|  |  |  | 					children.push(message); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				link_message(message); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return messages_by_id; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-25 12:33:54 +00:00
										 |  |  | 	update_latest_subtree_timestamp(messages) { | 
					
						
							|  |  |  | 		let latest = 0; | 
					
						
							|  |  |  | 		for (let message of messages || []) { | 
					
						
							|  |  |  | 			if (message.latest_subtree_timestamp === undefined) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				message.latest_subtree_timestamp = Math.max( | 
					
						
							|  |  |  | 					message.timestamp ?? 0, | 
					
						
							|  |  |  | 					this.update_latest_subtree_timestamp(message.child_messages) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2022-09-25 12:33:54 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			latest = Math.max(latest, message.latest_subtree_timestamp); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return latest; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	finalize_messages(messages_by_id) { | 
					
						
							|  |  |  | 		function recursive_sort(messages, top) { | 
					
						
							|  |  |  | 			if (messages) { | 
					
						
							|  |  |  | 				if (top) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					messages.sort( | 
					
						
							|  |  |  | 						(a, b) => b.latest_subtree_timestamp - a.latest_subtree_timestamp | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					messages.sort((a, b) => a.timestamp - b.timestamp); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				for (let message of messages) { | 
					
						
							|  |  |  | 					recursive_sort(message.child_messages, false); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				return messages.map((x) => Object.assign({}, x)); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				return {}; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		let roots = Object.values(messages_by_id).filter((x) => !x.parent_message); | 
					
						
							| 
									
										
										
										
											2022-09-25 12:33:54 +00:00
										 |  |  | 		this.update_latest_subtree_timestamp(roots); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		return recursive_sort(roots, true); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 	group_messages(messages) { | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 		let result = []; | 
					
						
							|  |  |  | 		let group = []; | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 		let type = undefined; | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 		for (let message of messages) { | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 			if ( | 
					
						
							|  |  |  | 				message?.content?.type === 'contact' || | 
					
						
							|  |  |  | 				message?.content?.type === 'channel' | 
					
						
							|  |  |  | 			) { | 
					
						
							|  |  |  | 				if (type && message.content.type !== type) { | 
					
						
							|  |  |  | 					if (group.length == 1) { | 
					
						
							|  |  |  | 						result.push(group[0]); | 
					
						
							|  |  |  | 						group = []; | 
					
						
							|  |  |  | 					} else if (group.length > 1) { | 
					
						
							|  |  |  | 						result.push({ | 
					
						
							|  |  |  | 							rowid: Math.max(...group.map((x) => x.rowid)), | 
					
						
							|  |  |  | 							type: `${type}_group`, | 
					
						
							|  |  |  | 							messages: group, | 
					
						
							|  |  |  | 						}); | 
					
						
							|  |  |  | 						group = []; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				type = message.content.type; | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 				group.push(message); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2025-05-31 15:17:07 -04:00
										 |  |  | 				if (group.length == 1) { | 
					
						
							|  |  |  | 					result.push(group[0]); | 
					
						
							|  |  |  | 					group = []; | 
					
						
							|  |  |  | 				} else if (group.length > 1) { | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 					result.push({ | 
					
						
							| 
									
										
										
										
											2024-12-11 20:35:32 -05:00
										 |  |  | 						rowid: Math.max(...group.map((x) => x.rowid)), | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 						type: `${type}_group`, | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 						messages: group, | 
					
						
							|  |  |  | 					}); | 
					
						
							|  |  |  | 					group = []; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				result.push(message); | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 				type = undefined; | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-05-31 15:17:07 -04:00
										 |  |  | 		if (group.length == 1) { | 
					
						
							|  |  |  | 			result.push(group[0]); | 
					
						
							|  |  |  | 			group = []; | 
					
						
							|  |  |  | 		} else if (group.length > 1) { | 
					
						
							| 
									
										
										
										
											2024-12-07 14:08:53 -05:00
										 |  |  | 			result.push({ | 
					
						
							| 
									
										
										
										
											2024-12-11 20:35:32 -05:00
										 |  |  | 				rowid: Math.max(...group.map((x) => x.rowid)), | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 				type: `${type}_group`, | 
					
						
							| 
									
										
										
										
											2024-12-07 14:08:53 -05:00
										 |  |  | 				messages: group, | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-03-19 23:31:08 +00:00
										 |  |  | 		return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 19:22:21 -04:00
										 |  |  | 	unread_allowed() { | 
					
						
							|  |  |  | 		return !this.hash?.startsWith('#%') && !this.hash?.startsWith('#@'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-23 01:29:54 +00:00
										 |  |  | 	load_and_render(messages) { | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		let messages_by_id = this.process_messages(messages); | 
					
						
							| 
									
										
										
										
											2025-09-27 16:16:06 -04:00
										 |  |  | 		let final_messages = this.group_messages( | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			this.finalize_messages(messages_by_id) | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2024-12-01 12:56:31 -05:00
										 |  |  | 		let unread_rowid = -1; | 
					
						
							| 
									
										
										
										
											2025-06-11 20:12:23 -04:00
										 |  |  | 		if (this.unread_allowed()) { | 
					
						
							| 
									
										
										
										
											2025-06-11 19:22:21 -04:00
										 |  |  | 			for (let message of final_messages) { | 
					
						
							|  |  |  | 				if (message.rowid >= this.channel_unread) { | 
					
						
							|  |  |  | 					unread_rowid = message.rowid; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-12-01 12:56:31 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		return html`
 | 
					
						
							| 
									
										
										
										
											2025-10-22 19:39:20 -04:00
										 |  |  | 			<style> | 
					
						
							|  |  |  | 				${generate_theme()} | 
					
						
							|  |  |  | 			</style> | 
					
						
							| 
									
										
										
										
											2024-11-30 15:05:14 -05:00
										 |  |  | 			<div> | 
					
						
							| 
									
										
										
										
											2025-01-11 14:09:42 -05:00
										 |  |  | 				${repeat( | 
					
						
							|  |  |  | 					final_messages, | 
					
						
							|  |  |  | 					(x) => x.id, | 
					
						
							| 
									
										
										
										
											2024-12-23 11:08:27 -05:00
										 |  |  | 					(x) => html`
 | 
					
						
							|  |  |  | 						<tf-message | 
					
						
							|  |  |  | 							.message=${x} | 
					
						
							|  |  |  | 							whoami=${this.whoami} | 
					
						
							|  |  |  | 							.users=${this.users} | 
					
						
							|  |  |  | 							.drafts=${this.drafts} | 
					
						
							|  |  |  | 							.expanded=${this.expanded} | 
					
						
							|  |  |  | 							collapsed="true" | 
					
						
							|  |  |  | 							channel=${this.channel} | 
					
						
							|  |  |  | 							channel_unread=${this.channel_unread} | 
					
						
							| 
									
										
										
										
											2025-04-29 20:48:47 -04:00
										 |  |  | 							.recent_reactions=${this.recent_reactions} | 
					
						
							| 
									
										
										
										
											2024-12-23 11:08:27 -05:00
										 |  |  | 						></tf-message> | 
					
						
							| 
									
										
										
										
											2024-12-26 19:36:04 -05:00
										 |  |  | 						${x.rowid == unread_rowid | 
					
						
							| 
									
										
										
										
											2024-12-23 11:08:27 -05:00
										 |  |  | 							? html`<div style="display: flex; flex-direction: row">
 | 
					
						
							|  |  |  | 									<div | 
					
						
							|  |  |  | 										style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px" | 
					
						
							|  |  |  | 									></div> | 
					
						
							| 
									
										
										
										
											2025-07-02 18:19:34 -04:00
										 |  |  | 									<button | 
					
						
							|  |  |  | 										style="color: #f00; padding: 8px" | 
					
						
							|  |  |  | 										class="w3-button" | 
					
						
							|  |  |  | 										@click=${() => | 
					
						
							|  |  |  | 											this.dispatchEvent( | 
					
						
							|  |  |  | 												new Event('mark_all_read', { | 
					
						
							|  |  |  | 													bubbles: true, | 
					
						
							|  |  |  | 													composed: true, | 
					
						
							|  |  |  | 												}) | 
					
						
							|  |  |  | 											)} | 
					
						
							|  |  |  | 									> | 
					
						
							|  |  |  | 										unread | 
					
						
							|  |  |  | 									</button> | 
					
						
							| 
									
										
										
										
											2024-12-23 11:08:27 -05:00
										 |  |  | 									<div | 
					
						
							|  |  |  | 										style="border-bottom: 1px solid #f00; flex: 1; align-self: center; height: 1px" | 
					
						
							|  |  |  | 									></div> | 
					
						
							|  |  |  | 								</div>` | 
					
						
							|  |  |  | 							: undefined} | 
					
						
							|  |  |  | 					`
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				)} | 
					
						
							| 
									
										
										
										
											2022-10-05 02:11:46 +00:00
										 |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 		`;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	render() { | 
					
						
							| 
									
										
										
										
											2023-02-23 01:29:54 +00:00
										 |  |  | 		return this.load_and_render(this.messages || []); | 
					
						
							| 
									
										
										
										
											2022-09-11 17:42:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | customElements.define('tf-news', TfNewsElement); |