| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | import {LitElement, html, unsafeHTML} from './lit-all.min.js'; | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | import * as tfrpc from '/static/tfrpc.js'; | 
					
						
							| 
									
										
										
										
											2023-11-16 01:33:00 +00:00
										 |  |  | import * as commonmark from './commonmark.min.js'; | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class TfWikiDocElement extends LitElement { | 
					
						
							|  |  |  | 	static get properties() { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			whoami: {type: String}, | 
					
						
							| 
									
										
										
										
											2023-12-06 17:48:44 +00:00
										 |  |  | 			wiki: {type: Object}, | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 			value: {type: Object}, | 
					
						
							|  |  |  | 			blob: {type: String}, | 
					
						
							|  |  |  | 			blob_original: {type: String}, | 
					
						
							| 
									
										
										
										
											2023-11-01 22:21:42 +00:00
										 |  |  | 			blob_for_value: {type: String}, | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 			is_editing: {type: Boolean}, | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	constructor() { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 	markdown(md) { | 
					
						
							| 
									
										
										
										
											2024-11-12 20:43:03 -05:00
										 |  |  | 		let reader = new commonmark.Parser(); | 
					
						
							|  |  |  | 		let writer = new commonmark.HtmlRenderer({safe: true}); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 		let parsed = reader.parse(md || ''); | 
					
						
							| 
									
										
										
										
											2023-11-14 17:38:48 +00:00
										 |  |  | 		let walker = parsed.walker(); | 
					
						
							|  |  |  | 		let event; | 
					
						
							|  |  |  | 		while ((event = walker.next())) { | 
					
						
							|  |  |  | 			let node = event.node; | 
					
						
							|  |  |  | 			if (event.entering) { | 
					
						
							| 
									
										
										
										
											2024-01-28 23:54:28 +00:00
										 |  |  | 				if (node.destination?.startsWith('&')) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					node.destination = | 
					
						
							|  |  |  | 						'/' + | 
					
						
							|  |  |  | 						node.destination + | 
					
						
							|  |  |  | 						'/view?filename=' + | 
					
						
							|  |  |  | 						node.firstChild?.literal; | 
					
						
							| 
									
										
										
										
											2024-01-28 23:54:28 +00:00
										 |  |  | 				} else if (node.type === 'link') { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					if ( | 
					
						
							|  |  |  | 						node.destination.indexOf(':') == -1 && | 
					
						
							|  |  |  | 						node.destination.indexOf('/') == -1 | 
					
						
							|  |  |  | 					) { | 
					
						
							| 
									
										
										
										
											2023-11-14 17:38:48 +00:00
										 |  |  | 						node.destination = `#${this.wiki?.name}/${node.destination}`; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 		return writer.render(parsed); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 19:35:41 +00:00
										 |  |  | 	title(md) { | 
					
						
							|  |  |  | 		let lines = (md || '').split('\n'); | 
					
						
							|  |  |  | 		for (let line of lines) { | 
					
						
							|  |  |  | 			let m = line.match(/#+ (.*)/); | 
					
						
							|  |  |  | 			if (m) { | 
					
						
							|  |  |  | 				return m[1]; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 	summary(md) { | 
					
						
							|  |  |  | 		let lines = (md || '').split('\n'); | 
					
						
							|  |  |  | 		let result = []; | 
					
						
							|  |  |  | 		let have_content = false; | 
					
						
							|  |  |  | 		for (let line of lines) { | 
					
						
							|  |  |  | 			if (have_content && !line.trim().length) { | 
					
						
							|  |  |  | 				return result.join('\n'); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!line.startsWith('#') && line.trim().length) { | 
					
						
							|  |  |  | 				have_content = true; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-12-09 19:35:41 +00:00
										 |  |  | 			if (!line.startsWith('#')) { | 
					
						
							|  |  |  | 				result.push(line); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return result.join('\n'); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	thumbnail(md) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		let m = md | 
					
						
							|  |  |  | 			? md.match(/\!\[image:[^\]]+\]\((\&.{44}\.sha256)\).*/) | 
					
						
							|  |  |  | 			: undefined; | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 		return m ? m[1] : undefined; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 	async load_blob() { | 
					
						
							| 
									
										
										
										
											2023-11-08 01:58:02 +00:00
										 |  |  | 		let blob = await tfrpc.rpc.get_blob(this.value?.blob); | 
					
						
							| 
									
										
										
										
											2024-02-25 15:37:13 -05:00
										 |  |  | 		if (!blob) { | 
					
						
							|  |  |  | 			console.warn( | 
					
						
							|  |  |  | 				"no blob found, we're going to assume the document is empty (load_blob())" | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2024-02-22 18:11:13 +01:00
										 |  |  | 		} else if (blob.endsWith('.box')) { | 
					
						
							| 
									
										
										
										
											2023-11-08 01:58:02 +00:00
										 |  |  | 			let d = await tfrpc.rpc.try_decrypt(this.whoami, blob); | 
					
						
							|  |  |  | 			if (d) { | 
					
						
							|  |  |  | 				blob = d; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.blob = blob; | 
					
						
							|  |  |  | 		this.blob_original = blob; | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	on_edit(event) { | 
					
						
							|  |  |  | 		this.blob = event.srcElement.value; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 	on_discard(event) { | 
					
						
							|  |  |  | 		this.blob = this.blob_original; | 
					
						
							|  |  |  | 		this.is_editing = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 	async append_message(draft) { | 
					
						
							| 
									
										
										
										
											2023-11-08 01:58:02 +00:00
										 |  |  | 		let blob = this.blob; | 
					
						
							| 
									
										
										
										
											2023-12-04 17:50:13 +00:00
										 |  |  | 		if (draft || this.value?.private) { | 
					
						
							| 
									
										
										
										
											2023-12-06 17:48:44 +00:00
										 |  |  | 			blob = await tfrpc.rpc.encrypt(this.whoami, this.wiki.editors, blob); | 
					
						
							| 
									
										
										
										
											2023-11-08 01:58:02 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		let id = await tfrpc.rpc.store_blob(blob); | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 		let message = { | 
					
						
							|  |  |  | 			type: 'wiki-doc', | 
					
						
							|  |  |  | 			key: this.value.id, | 
					
						
							|  |  |  | 			parent: this.value.parent, | 
					
						
							|  |  |  | 			blob: id, | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			mentions: this.blob.match(/(&.{44}.sha256)/g)?.map((x) => ({link: x})), | 
					
						
							| 
									
										
										
										
											2023-12-04 17:50:13 +00:00
										 |  |  | 			private: this.value?.private, | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 		if (draft) { | 
					
						
							|  |  |  | 			message.recps = this.value.editors; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			message = await tfrpc.rpc.encrypt( | 
					
						
							|  |  |  | 				this.whoami, | 
					
						
							|  |  |  | 				this.value.editors, | 
					
						
							|  |  |  | 				JSON.stringify(message) | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		await tfrpc.rpc.appendMessage(this.whoami, message); | 
					
						
							| 
									
										
										
										
											2023-11-02 00:45:20 +00:00
										 |  |  | 		this.is_editing = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 	async on_save_draft() { | 
					
						
							|  |  |  | 		return this.append_message(true); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 	async on_publish() { | 
					
						
							| 
									
										
										
										
											2023-11-05 23:25:55 +00:00
										 |  |  | 		return this.append_message(false); | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-09 19:13:06 +00:00
										 |  |  | 	async on_blog_publish() { | 
					
						
							|  |  |  | 		let blob = this.blob; | 
					
						
							|  |  |  | 		let id = await tfrpc.rpc.store_blob(blob); | 
					
						
							|  |  |  | 		let message = { | 
					
						
							|  |  |  | 			type: 'blog', | 
					
						
							|  |  |  | 			key: this.value.id, | 
					
						
							|  |  |  | 			parent: this.value.parent, | 
					
						
							| 
									
										
										
										
											2023-12-09 19:35:41 +00:00
										 |  |  | 			title: this.title(blob), | 
					
						
							| 
									
										
										
										
											2023-12-09 19:13:06 +00:00
										 |  |  | 			summary: this.summary(blob), | 
					
						
							|  |  |  | 			thumbnail: this.thumbnail(blob), | 
					
						
							|  |  |  | 			blog: id, | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			mentions: this.blob.match(/(&.{44}.sha256)/g)?.map((x) => ({link: x})), | 
					
						
							| 
									
										
										
										
											2023-12-09 19:13:06 +00:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 		await tfrpc.rpc.appendMessage(this.whoami, message); | 
					
						
							|  |  |  | 		this.is_editing = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 	convert_to_format(buffer, type, mime_type) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		return new Promise(function (resolve, reject) { | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			let img = new Image(); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			img.onload = function () { | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 				let canvas = document.createElement('canvas'); | 
					
						
							|  |  |  | 				let width_scale = Math.min(img.width, 1024) / img.width; | 
					
						
							|  |  |  | 				let height_scale = Math.min(img.height, 1024) / img.height; | 
					
						
							|  |  |  | 				let scale = Math.min(width_scale, height_scale); | 
					
						
							|  |  |  | 				canvas.width = img.width * scale; | 
					
						
							|  |  |  | 				canvas.height = img.height * scale; | 
					
						
							|  |  |  | 				let context = canvas.getContext('2d'); | 
					
						
							|  |  |  | 				context.drawImage(img, 0, 0, canvas.width, canvas.height); | 
					
						
							|  |  |  | 				let data_url = canvas.toDataURL(mime_type); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 				let result = atob(data_url.split(',')[1]) | 
					
						
							|  |  |  | 					.split('') | 
					
						
							|  |  |  | 					.map((x) => x.charCodeAt(0)); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 				resolve(result); | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			img.onerror = function (event) { | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 				reject(new Error('Failed to load image.')); | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 			let raw = Array.from(new Uint8Array(buffer)) | 
					
						
							|  |  |  | 				.map((b) => String.fromCharCode(b)) | 
					
						
							|  |  |  | 				.join(''); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			let original = `data:${type};base64,${btoa(raw)}`; | 
					
						
							|  |  |  | 			img.src = original; | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 	humanSize(value) { | 
					
						
							|  |  |  | 		let units = ['B', 'kB', 'MB', 'GB']; | 
					
						
							|  |  |  | 		let i = 0; | 
					
						
							|  |  |  | 		while (i < units.length - 1 && value >= 1024) { | 
					
						
							|  |  |  | 			value /= 1024; | 
					
						
							|  |  |  | 			i++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return `${Math.round(value * 10) / 10} ${units[i]}`; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 	async add_file(editor, file) { | 
					
						
							|  |  |  | 		try { | 
					
						
							|  |  |  | 			let self = this; | 
					
						
							|  |  |  | 			let buffer = await file.arrayBuffer(); | 
					
						
							|  |  |  | 			let type = file.type; | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 			let insert; | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			if (type.startsWith('image/')) { | 
					
						
							|  |  |  | 				let best_buffer; | 
					
						
							|  |  |  | 				let best_type; | 
					
						
							|  |  |  | 				for (let format of ['image/png', 'image/jpeg', 'image/webp']) { | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 					let test_buffer = await self.convert_to_format( | 
					
						
							|  |  |  | 						buffer, | 
					
						
							|  |  |  | 						file.type, | 
					
						
							|  |  |  | 						format | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 					if (!best_buffer || test_buffer.length < best_buffer.length) { | 
					
						
							|  |  |  | 						best_buffer = test_buffer; | 
					
						
							|  |  |  | 						best_type = format; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				buffer = best_buffer; | 
					
						
							|  |  |  | 				type = best_type; | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 				let id = await tfrpc.rpc.store_blob(buffer); | 
					
						
							|  |  |  | 				let name = type.split('/')[0] + ':' + file.name; | 
					
						
							|  |  |  | 				insert = `\n`; | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				buffer = Array.from(new Uint8Array(buffer)); | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 				let id = await tfrpc.rpc.store_blob(buffer); | 
					
						
							|  |  |  | 				let name = file.name; | 
					
						
							|  |  |  | 				insert = `\n[${name}](${id}) (${this.humanSize(buffer.length)})`; | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 			document.execCommand('insertText', false, insert); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			self.on_edit({srcElement: editor}); | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | 		} catch (e) { | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			alert(e?.message); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	paste(event) { | 
					
						
							|  |  |  | 		let self = this; | 
					
						
							|  |  |  | 		for (let item of event.clipboardData.items) { | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 			let file = item.getAsFile(); | 
					
						
							|  |  |  | 			if (file) { | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 				self.add_file(event.srcElement, file); | 
					
						
							| 
									
										
										
										
											2024-01-24 02:58:53 +00:00
										 |  |  | 				event.preventDefault(); | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 	render() { | 
					
						
							| 
									
										
										
										
											2023-11-01 22:21:42 +00:00
										 |  |  | 		let value = JSON.stringify(this.value); | 
					
						
							|  |  |  | 		if (this.blob_for_value != value) { | 
					
						
							|  |  |  | 			this.blob_for_value = value; | 
					
						
							|  |  |  | 			this.blob = undefined; | 
					
						
							|  |  |  | 			this.blob_original = undefined; | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 			this.load_blob(); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 		let self = this; | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 		let thumbnail_ref = this.thumbnail(this.blob); | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 		return html`
 | 
					
						
							| 
									
										
										
										
											2024-02-22 16:11:49 +01:00
										 |  |  | 			<link rel="stylesheet" href="tildefriends.css"/> | 
					
						
							| 
									
										
										
										
											2024-01-03 23:24:24 +00:00
										 |  |  | 			<style> | 
					
						
							|  |  |  | 				a:link { color: #268bd2 } | 
					
						
							|  |  |  | 				a:visited { color: #6c71c4 } | 
					
						
							|  |  |  | 				a:hover { color: #859900 } | 
					
						
							|  |  |  | 				a:active { color: #2aa198 } | 
					
						
							| 
									
										
										
										
											2024-02-22 18:11:13 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				#editor-text-area { | 
					
						
							|  |  |  | 					background-color: #00000040; | 
					
						
							|  |  |  | 					color: white; | 
					
						
							|  |  |  | 					style="flex: 1 1; | 
					
						
							|  |  |  | 					min-height: 10em; | 
					
						
							|  |  |  | 					font-size: larger; | 
					
						
							| 
									
										
										
										
											2024-02-25 15:37:13 -05:00
										 |  |  | 					${this.value?.private ? 'border: 4px solid #800' : ''} | 
					
						
							| 
									
										
										
										
											2024-01-03 23:24:24 +00:00
										 |  |  | 			</style> | 
					
						
							| 
									
										
										
										
											2024-02-22 13:03:21 +01:00
										 |  |  | 			<div class="inline-flex-row"> | 
					
						
							| 
									
										
										
										
											2024-02-25 15:37:13 -05:00
										 |  |  | 				<button ?disabled=${!this.whoami || this.is_editing} @click=${() => (self.is_editing = true)}>Edit</button> | 
					
						
							| 
									
										
										
										
											2023-11-02 00:45:20 +00:00
										 |  |  | 				<button ?disabled=${this.blob == this.blob_original} @click=${this.on_save_draft}>Save Draft</button> | 
					
						
							| 
									
										
										
										
											2023-11-02 01:19:14 +00:00
										 |  |  | 				<button ?disabled=${this.blob == this.blob_original && !this.value?.draft} @click=${this.on_publish}>Publish</button> | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 				<button ?disabled=${!this.is_editing} @click=${this.on_discard}>Discard</button> | 
					
						
							| 
									
										
										
										
											2024-02-25 15:37:13 -05:00
										 |  |  | 				<button ?disabled=${!this.is_editing} @click=${() => (self.value = Object.assign({}, self.value, {private: !self.value.private}))}>${this.value?.private ? 'Make Public' : 'Make Private'}</button> | 
					
						
							| 
									
										
										
										
											2023-12-09 19:13:06 +00:00
										 |  |  | 				<button ?disabled=${!this.is_editing} @click=${this.on_blog_publish}>Publish Blog</button> | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2023-12-06 17:48:44 +00:00
										 |  |  | 			<div ?hidden=${!this.value?.private} style="color: #800">🔒 document is private</div> | 
					
						
							| 
									
										
										
										
											2024-02-22 18:11:13 +01:00
										 |  |  | 			<div class="flex-column" ${this.value?.private ? 'border-top: 4px solid #800' : ''}"> | 
					
						
							| 
									
										
										
										
											2023-11-01 23:39:34 +00:00
										 |  |  | 				<textarea | 
					
						
							| 
									
										
										
										
											2024-02-22 22:34:11 +01:00
										 |  |  | 					rows="25" | 
					
						
							| 
									
										
										
										
											2023-11-02 00:29:07 +00:00
										 |  |  | 					?hidden=${!this.is_editing} | 
					
						
							| 
									
										
										
										
											2024-02-22 18:11:13 +01:00
										 |  |  | 					id="editor-text-area" | 
					
						
							| 
									
										
										
										
											2023-12-03 18:03:42 +00:00
										 |  |  | 					@input=${this.on_edit} | 
					
						
							|  |  |  | 					@paste=${this.paste} | 
					
						
							|  |  |  | 					.value=${this.blob ?? ''}></textarea> | 
					
						
							| 
									
										
										
										
											2024-02-22 22:34:11 +01:00
										 |  |  | 				<div style="flex: 1 1; margin-top: 16px"> | 
					
						
							| 
									
										
										
										
											2024-02-22 18:11:13 +01:00
										 |  |  | 					<div ?hidden=${!this.is_editing} class="box"> | 
					
						
							|  |  |  | 						Summary | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 						<img ?hidden=${!thumbnail_ref} style="max-width: 128px; max-height: 128px; float: right" src="/${thumbnail_ref}/view"> | 
					
						
							| 
									
										
										
										
											2023-12-09 19:35:41 +00:00
										 |  |  | 						<h1 ?hidden=${!this.title(this.blob)}>${unsafeHTML(this.markdown(this.title(this.blob)))}</h1> | 
					
						
							| 
									
										
										
										
											2023-12-09 18:35:42 +00:00
										 |  |  | 						${unsafeHTML(this.markdown(this.summary(this.blob)))} | 
					
						
							|  |  |  | 					</div> | 
					
						
							|  |  |  | 					${unsafeHTML(this.markdown(this.blob))} | 
					
						
							|  |  |  | 				</div> | 
					
						
							| 
									
										
										
										
											2023-11-01 23:39:34 +00:00
										 |  |  | 			</div> | 
					
						
							| 
									
										
										
										
											2023-10-30 00:22:30 +00:00
										 |  |  | 		`;
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 11:09:34 -05:00
										 |  |  | customElements.define('tf-wiki-doc', TfWikiDocElement); |