forked from cory/tildefriends
		
	Experimenting with ordering. Handful of small fixes.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3989 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
		| @@ -1 +1 @@ | ||||
| {"type":"tildefriends-app","files":{"app.js":"&rLwYqurncmnUyGeWY+FLEGS2EIJmqw2cutl1gyGiVSk=.sha256","index.md":"&082vPjenwI6mL2vXwQDVEFquyl2jW9t767sGuCFvVNA=.sha256","todo.md":"&+z52vxpbZs5+HoLnQoDNkYt4objcPwF7F1PIwvZ3E3k=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256","ssb.md":"&WMvYIpp4CMZACwXJlX8HMDplJ+XeJB04BYf8zasrL4g=.sha256"}} | ||||
| {"type":"tildefriends-app","files":{"app.js":"&rLwYqurncmnUyGeWY+FLEGS2EIJmqw2cutl1gyGiVSk=.sha256","index.md":"&082vPjenwI6mL2vXwQDVEFquyl2jW9t767sGuCFvVNA=.sha256","todo.md":"&vD0IhCaw1GGEZ7JJA5iL9tmp30VjT/aN/HNH5KDCYyY=.sha256","structure.md":"&T+CBfT9XP6ooKFvD1ZCI9hsutqsNIamfBxtAho0HtlU=.sha256","guide.md":"&SgnGL0+rjetY2o9A2+lVRbNvHIkqKwMnZr9gXWneIlc=.sha256","id_refactor.md":"&8yoYd14gX2Z3ppktVrPYf4qR78fuwAlvrtsWkSCkWUA=.sha256","ssb.md":"&WMvYIpp4CMZACwXJlX8HMDplJ+XeJB04BYf8zasrL4g=.sha256"}} | ||||
| @@ -23,6 +23,7 @@ | ||||
| - attribute blob wants to messages | ||||
| - editor without app iframe | ||||
| - jwt for session tokens | ||||
| - sequence_before_author -> flags | ||||
|  | ||||
| ## Maybe Done | ||||
| - linkify https://... | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| {"type":"tildefriends-app","files":{"app.js":"&XCpiJOtpMzQz5Zo+Hu9f3ppQON9PxFdV4XnS2Ae+Ye8=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&pg1gLK150HFai73TcmAe5E/dMpMqmbhyre/+/J4XmHo=.sha256","tf-app.js":"&JloBYWTWVuz5ibCXOv+tLdlr6BF266R/iZ/iOL19/pw=.sha256","tf-message.js":"&LZA/ehDrUQj4YBXKXjYKQfG7UCmdnWeor34QkfJYIpo=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&pqYLDE/13PyEt2ceeFqvnwZ8NqWfPfpDBt4vP8SeHbs=.sha256","tf-styles.js":"&Ab+SjsySJ74kwK3EQD/j72yXYJlFAhkJ5EqyJfYpJEk=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&ESt2vMG19sH5j6ungKua/ZuvIGslyuWyb3juXdOCecg=.sha256","tf-tab-news.js":"&ehXkzOR+kQmiTHRtu5GPDMwrB4a4Z9vVsTo4ldhdu/E=.sha256","tf-tab-connections.js":"&jSnF/5NmgqxRze1XQAEGOW5mPzOV1/8aCyrDRZu34IQ=.sha256","tf-news.js":"&C1dKe98kQOkClnAbGvcreC15IdlTrD9J4RFohspnsSE=.sha256"}} | ||||
| {"type":"tildefriends-app","files":{"app.js":"&XCpiJOtpMzQz5Zo+Hu9f3ppQON9PxFdV4XnS2Ae+Ye8=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&pg1gLK150HFai73TcmAe5E/dMpMqmbhyre/+/J4XmHo=.sha256","tf-app.js":"&9sl0mwHSJIXJ7WiNzdauqrtmld5rasBjCgqFtrDg/e0=.sha256","tf-message.js":"&6KQxhv7bilj+BEN1B9B0zI9cQ4M5WknNFCs5VJ1WNwM=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&pqYLDE/13PyEt2ceeFqvnwZ8NqWfPfpDBt4vP8SeHbs=.sha256","tf-styles.js":"&Ab+SjsySJ74kwK3EQD/j72yXYJlFAhkJ5EqyJfYpJEk=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&ESt2vMG19sH5j6ungKua/ZuvIGslyuWyb3juXdOCecg=.sha256","tf-tab-news.js":"&QkPSLHWMW9lfcc06rbzjdiuhNdPPV/LjJqixrOKfSac=.sha256","tf-tab-connections.js":"&jSnF/5NmgqxRze1XQAEGOW5mPzOV1/8aCyrDRZu34IQ=.sha256","tf-news.js":"&G4Ywinot74p6QUCbdAPda9HxOszieBM3WwY9jQ16LRU=.sha256"}} | ||||
| @@ -54,6 +54,8 @@ class TfElement extends LitElement { | ||||
| 		this.hash = hash || '#'; | ||||
| 		if (this.hash.startsWith('#q=')) { | ||||
| 			this.tab = 'search'; | ||||
| 		} else if (this.hash === '#connections') { | ||||
| 			this.tab = 'connections'; | ||||
| 		} else { | ||||
| 			this.tab = 'news'; | ||||
| 		} | ||||
| @@ -270,6 +272,15 @@ class TfElement extends LitElement { | ||||
| 		}, ...this.unread]; | ||||
| 	} | ||||
|  | ||||
| 	async set_tab(tab) { | ||||
| 		this.tab = tab; | ||||
| 		if (tab === 'news') { | ||||
| 			await tfrpc.rpc.setHash('#'); | ||||
| 		} else if (tab === 'connections') { | ||||
| 			await tfrpc.rpc.setHash('#connections'); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		let self = this; | ||||
|  | ||||
| @@ -289,9 +300,9 @@ class TfElement extends LitElement { | ||||
| 		`; | ||||
| 		let tabs = html` | ||||
| 			<div> | ||||
| 				<input type="button" value="News" ?disabled=${self.tab == 'news'} @click=${event => self.tab = 'news'}></input> | ||||
| 				<input type="button" value="Connections" ?disabled=${self.tab == 'connections'} @click=${event => self.tab = 'connections'}></input> | ||||
| 				<input type="button" value="Search" ?disabled=${self.tab == 'search'} @click=${event => self.tab = 'search'}></input> | ||||
| 				<input type="button" value="News" ?disabled=${self.tab == 'news'} @click=${() => self.set_tab('news')}></input> | ||||
| 				<input type="button" value="Connections" ?disabled=${self.tab == 'connections'} @click=${() => self.set_tab('connections')}></input> | ||||
| 				<input type="button" value="Search" ?disabled=${self.tab == 'search'} @click=${() => self.set_tab('search')}></input> | ||||
| 			</div> | ||||
| 		`; | ||||
| 		let contents = !this.loaded ? | ||||
|   | ||||
| @@ -43,11 +43,26 @@ class TfMessageElement extends LitElement { | ||||
| 				return expression; | ||||
| 			} | ||||
| 		} | ||||
| 		return html`<div>${(this.message.votes || []).map(vote => html`<span title="${this.users[vote.author]?.name ?? vote.author}">${normalize_expression(vote.content.vote.expression)}</span>`)}</div>`; | ||||
| 		return html`<div>${(this.message.votes || []).map( | ||||
| 			vote => html` | ||||
| 				<span title="${this.users[vote.author]?.name ?? vote.author} ${new Date(vote.timestamp)}"> | ||||
| 					${normalize_expression(vote.content.vote.expression)} | ||||
| 				</span> | ||||
| 			`)}</div>`; | ||||
| 	} | ||||
|  | ||||
| 	render_raw() { | ||||
| 		return html`<div style="white-space: pre-wrap">${JSON.stringify(this.message, null, 2)}</div>` | ||||
| 		let raw = { | ||||
| 			id: this.message?.id, | ||||
| 			previous: this.message?.previous, | ||||
| 			author: this.message?.author, | ||||
| 			sequence: this.message?.sequence, | ||||
| 			timestamp: this.message?.timestamp, | ||||
| 			hash: this.message?.hash, | ||||
| 			content: this.message?.content, | ||||
| 			signature: this.message?.signature, | ||||
| 		} | ||||
| 		return html`<div style="white-space: pre-wrap">${JSON.stringify(raw, null, 2)}</div>` | ||||
| 	} | ||||
|  | ||||
| 	vote(emoji) { | ||||
| @@ -101,6 +116,12 @@ class TfMessageElement extends LitElement { | ||||
| 		document.body.appendChild(div); | ||||
| 	} | ||||
|  | ||||
| 	body_click(event) { | ||||
| 		if (event.srcElement.tagName == 'IMG') { | ||||
| 			this.show_image(event.srcElement.src); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	render_mention(mention) { | ||||
| 		if (!mention?.link || typeof(mention.link) != 'string') { | ||||
| 			return html`<pre>${JSON.stringify(mention)}</pre>`; | ||||
| @@ -121,12 +142,15 @@ class TfMessageElement extends LitElement { | ||||
| 		} else if (mention.link?.startsWith('#')) { | ||||
| 			return html` <a href=${'#q=' + encodeURIComponent(mention.link)}>${mention.link}</a>`; | ||||
| 		} else { | ||||
| 			return html`<pre>${JSON.stringify(mention)}</pre>`; | ||||
| 			return html`<pre style="white-space: pre-wrap">${JSON.stringify(mention, null, 2)}</pre>`; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	render_mentions() { | ||||
| 		if (this.message?.content?.mentions?.length) { | ||||
| 		let mentions = this.message?.content?.mentions || []; | ||||
| 		let content = JSON.stringify(this.message?.content); | ||||
| 		mentions = mentions.filter(x => content.indexOf(x.link) === -1); | ||||
| 		if (mentions.length) { | ||||
| 			let self = this; | ||||
| 			return html` | ||||
| 				<fieldset style="background-color: rgba(0, 0, 0, 0.1); padding: 0.5em; border: 1px solid black"> | ||||
| @@ -163,71 +187,83 @@ class TfMessageElement extends LitElement { | ||||
| 						<tf-message .message=${x} whoami=${this.whoami} .users=${this.users}></tf-message> | ||||
| 					`)} | ||||
| 				</div>`; | ||||
| 		} else if (content.type == 'about') { | ||||
| 			return small_frame(html` | ||||
| 				<div style="font-weight: bold">Updated profile:</div> | ||||
| 				<pre style="white-space: pre-wrap">${JSON.stringify(content, null, 2)}</pre> | ||||
| 			`); | ||||
| 		} else if (content.type == 'contact') { | ||||
| 			return small_frame(html` | ||||
| 				<div> | ||||
| 					is now | ||||
| 					${ | ||||
| 						content.blocking === true ? 'blocking' : | ||||
| 						content.blocking === false ? 'unblocking' : | ||||
| 						content.following === true ? 'following' : | ||||
| 						content.following === false ? 'unfollowing' : | ||||
| 						'?' | ||||
| 					} | ||||
| 					<tf-user id=${this.message.content.contact} .users=${this.users}></tf-user> | ||||
| 				</div> | ||||
| 			`); | ||||
| 		} else if (content.type == 'post') { | ||||
| 			let reply = this.reply ? html` | ||||
| 				<tf-compose | ||||
| 					?enabled=${this.reply} | ||||
| 					whoami=${this.whoami} | ||||
| 					.users=${this.users} | ||||
| 					root=${this.message.content.root || this.message.id} | ||||
| 					branch=${this.message.id} | ||||
| 					@tf-discard=${() => this.reply = false}></tf-compose> | ||||
| 			` : html` | ||||
| 				<input type="button" value="Reply" @click=${this.show_reply}></input> | ||||
| 			`; | ||||
| 			let self = this; | ||||
| 			let body = this.raw ? | ||||
| 				this.render_raw() : | ||||
| 				unsafeHTML(tfutils.markdown(content.text)); | ||||
| 			return html` | ||||
| 				<style> | ||||
| 					code { | ||||
| 						white-space: pre-wrap; | ||||
| 						overflow-wrap: break-word; | ||||
| 					} | ||||
| 					img { | ||||
| 						max-width: 100%; | ||||
| 						height: auto; | ||||
| 					} | ||||
| 				</style> | ||||
| 				<div style="border: 1px solid black; background-color: rgba(255, 255, 255, 0.1); margin-top: 8px; padding: 16px"> | ||||
| 					<div style="display: flex; flex-direction: row"> | ||||
| 						<tf-user id=${this.message.author} .users=${this.users}></tf-user> | ||||
| 						<span style="flex: 1"></span> | ||||
| 						<span style="padding-right: 8px"><a target="_top" href=${'#' + self.message.id}>%</a> ${new Date(this.message.timestamp).toLocaleString()}</span> | ||||
| 						<span>${raw_button}</span> | ||||
| 					</div> | ||||
| 					<div>${body}</div> | ||||
| 					${this.render_mentions()} | ||||
| 					${this.render_votes()} | ||||
| 		} else if (typeof(content?.type === 'string')) { | ||||
| 			if (content.type == 'about') { | ||||
| 				return small_frame(html` | ||||
| 					<div style="font-weight: bold">Updated profile:</div> | ||||
| 					<pre style="white-space: pre-wrap">${JSON.stringify(content, null, 2)}</pre> | ||||
| 				`); | ||||
| 			} else if (content.type == 'contact') { | ||||
| 				return small_frame(html` | ||||
| 					<div> | ||||
| 						${reply} | ||||
| 						<input type="button" value="React" @click=${this.react}></input> | ||||
| 						is | ||||
| 						${ | ||||
| 							content.blocking === true ? 'blocking' : | ||||
| 							content.blocking === false ? 'no longer blocking' : | ||||
| 							content.following === true ? 'following' : | ||||
| 							content.following === false ? 'no longer following' : | ||||
| 							'?' | ||||
| 						} | ||||
| 						<tf-user id=${this.message.content.contact} .users=${this.users}></tf-user> | ||||
| 					</div> | ||||
| 					${(this.message.child_messages || []).map(x => html`<tf-message .message=${x} whoami=${this.whoami} .users=${this.users}></tf-message>`)} | ||||
| 				</div> | ||||
| 			`; | ||||
| 		} else if (typeof(this.message.content) == 'string') { | ||||
| 			return small_frame(html`<span>🔒</span>`); | ||||
| 				`); | ||||
| 			} else if (content.type == 'post') { | ||||
| 				let reply = this.reply ? html` | ||||
| 					<tf-compose | ||||
| 						?enabled=${this.reply} | ||||
| 						whoami=${this.whoami} | ||||
| 						.users=${this.users} | ||||
| 						root=${this.message.content.root || this.message.id} | ||||
| 						branch=${this.message.id} | ||||
| 						@tf-discard=${() => this.reply = false}></tf-compose> | ||||
| 				` : html` | ||||
| 					<input type="button" value="Reply" @click=${this.show_reply}></input> | ||||
| 				`; | ||||
| 				let self = this; | ||||
| 				let body = this.raw ? | ||||
| 					this.render_raw() : | ||||
| 					unsafeHTML(tfutils.markdown(content.text)); | ||||
| 				return html` | ||||
| 					<style> | ||||
| 						code { | ||||
| 							white-space: pre-wrap; | ||||
| 							overflow-wrap: break-word; | ||||
| 						} | ||||
| 						img { | ||||
| 							max-width: 100%; | ||||
| 							height: auto; | ||||
| 						} | ||||
| 					</style> | ||||
| 					<div style="border: 1px solid black; background-color: rgba(255, 255, 255, 0.1); margin-top: 8px; padding: 16px"> | ||||
| 						<div style="display: flex; flex-direction: row"> | ||||
| 							<tf-user id=${this.message.author} .users=${this.users}></tf-user> | ||||
| 							<span style="flex: 1"></span> | ||||
| 							<span style="padding-right: 8px"><a target="_top" href=${'#' + self.message.id}>%</a> ${new Date(this.message.timestamp).toLocaleString()}</span> | ||||
| 							<span>${raw_button}</span> | ||||
| 						</div> | ||||
| 						<div @click=${this.body_click}>${body}</div> | ||||
| 						${this.render_mentions()} | ||||
| 						${this.render_votes()} | ||||
| 						<div> | ||||
| 							${reply} | ||||
| 							<input type="button" value="React" @click=${this.react}></input> | ||||
| 						</div> | ||||
| 						${(this.message.child_messages || []).map(x => html`<tf-message .message=${x} whoami=${this.whoami} .users=${this.users}></tf-message>`)} | ||||
| 					</div> | ||||
| 				`; | ||||
| 			} else if (content.type === 'pub') { | ||||
| 				return small_frame(html` | ||||
| 				<span> | ||||
| 					<div> | ||||
| 						🍻 <tf-user .users=${this.users} id=${content.address.key}></tf-user> | ||||
| 					</div> | ||||
| 					<pre>${content.address.host}:${content.address.port}</pre> | ||||
| 				</span>`); | ||||
| 			} else if (typeof(this.message.content) == 'string') { | ||||
| 				return small_frame(html`<span>🔒</span>`); | ||||
| 			} else { | ||||
| 				return small_frame(html`<div><b>type</b>: ${content.type}</div>`); | ||||
| 			} | ||||
| 		} else { | ||||
| 			return small_frame(this.render_raw()); | ||||
| 		} | ||||
|   | ||||
| @@ -115,11 +115,22 @@ class TfNewsElement extends LitElement { | ||||
| 				]); | ||||
| 	} | ||||
|  | ||||
| 	update_latest_subtree_timestamp(messages) { | ||||
| 		let latest = 0; | ||||
| 		for (let message of messages || []) { | ||||
| 			if (message.latest_subtree_timestamp === undefined) { | ||||
| 				message.latest_subtree_timestamp = Math.max(message.timestamp, this.update_latest_subtree_timestamp(message.child_messages)); | ||||
| 			} | ||||
| 			latest = Math.max(latest, message.latest_subtree_timestamp); | ||||
| 		} | ||||
| 		return latest; | ||||
| 	} | ||||
|  | ||||
| 	finalize_messages(messages_by_id) { | ||||
| 		function recursive_sort(messages, top) { | ||||
| 			if (messages) { | ||||
| 				if (top) { | ||||
| 					messages.sort((a, b) => b.timestamp - a.timestamp); | ||||
| 					messages.sort((a, b) => b.latest_subtree_timestamp - a.latest_subtree_timestamp); | ||||
| 				} else { | ||||
| 					messages.sort((a, b) => a.timestamp - b.timestamp); | ||||
| 				} | ||||
| @@ -133,6 +144,7 @@ class TfNewsElement extends LitElement { | ||||
| 		} | ||||
|  | ||||
| 		let roots = Object.values(messages_by_id).filter(x => !x.parent_message); | ||||
| 		this.update_latest_subtree_timestamp(roots); | ||||
| 		return recursive_sort(roots, true); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -120,7 +120,7 @@ class TfTabNewsElement extends LitElement { | ||||
| 		} | ||||
| 		let counts = {}; | ||||
| 		for (let message of this.unread) { | ||||
| 			let type = 'unknown'; | ||||
| 			let type = 'private'; | ||||
| 			try { | ||||
| 				type = JSON.parse(message.content).type || type; | ||||
| 			} catch { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user