mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-31 11:00:08 +00:00 
			
		
		
		
	started experimenting with web component...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									d04a6ee538
								
							
						
					
					
						commit
						883e6994c3
					
				| @ -769,13 +769,18 @@ var Outline = { | |||||||
| 
 | 
 | ||||||
| 	get header(){ | 	get header(){ | ||||||
| 		return this.dom.querySelector('.header') }, | 		return this.dom.querySelector('.header') }, | ||||||
| 	get code(){ |  | ||||||
| 		return this.dom.querySelector('.code') }, |  | ||||||
| 	get outline(){ | 	get outline(){ | ||||||
| 		return this.dom.querySelector('.outline') }, | 		return this.dom.querySelector('.outline') }, | ||||||
| 	get toolbar(){ | 	get toolbar(){ | ||||||
| 		return this.dom.querySelector('.toolbar') }, | 		return this.dom.querySelector('.toolbar') }, | ||||||
| 
 | 
 | ||||||
|  | 	get code(){ | ||||||
|  | 		return this.dom.querySelector('.code')?.value }, | ||||||
|  | 	set code(value){ | ||||||
|  | 		var c = this.dom.querySelector('.code') | ||||||
|  | 		if(c){ | ||||||
|  | 			c.value = value } }, | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	path: function(node='focused', mode='index'){ | 	path: function(node='focused', mode='index'){ | ||||||
| 		if(['index', 'text', 'node', 'data'].includes(node)){ | 		if(['index', 'text', 'node', 'data'].includes(node)){ | ||||||
| @ -1026,14 +1031,15 @@ var Outline = { | |||||||
| 
 | 
 | ||||||
| 		var parsed = {} | 		var parsed = {} | ||||||
| 		if('text' in data){ | 		if('text' in data){ | ||||||
| 			var text = node.querySelector('textarea') | 			var text = node.querySelector('.code') | ||||||
| 			var html = node.querySelector('span') | 			var html = node.querySelector('.view') | ||||||
| 			if(this.__code2html__){ | 			if(this.__code2html__){ | ||||||
| 				// NOTE: we are ignoring the .collapsed attr here 
 | 				// NOTE: we are ignoring the .collapsed attr here 
 | ||||||
| 				parsed = this.__code2html__(data.text, {...data}) | 				parsed = this.__code2html__(data.text, {...data}) | ||||||
| 				html.innerHTML = parsed.text | 				html.innerHTML = parsed.text | ||||||
| 				// heading...
 | 				// heading...
 | ||||||
| 				node.classList.remove(...this.__styles) | 				this.__styles != null | ||||||
|  | 					&& node.classList.remove(...this.__styles) | ||||||
| 				parsed.style | 				parsed.style | ||||||
| 					&& node.classList.add(...parsed.style) | 					&& node.classList.add(...parsed.style) | ||||||
| 				delete parsed.style | 				delete parsed.style | ||||||
| @ -1201,6 +1207,7 @@ var Outline = { | |||||||
| 		return node }, | 		return node }, | ||||||
| 
 | 
 | ||||||
| 	// crop...
 | 	// crop...
 | ||||||
|  | 	// XXX the header links are not component-compatible...
 | ||||||
| 	crop: function(node='focused'){ | 	crop: function(node='focused'){ | ||||||
| 		this.dom.classList.add('crop') | 		this.dom.classList.add('crop') | ||||||
| 		for(var block of [...this.outline.querySelectorAll('[cropped]')]){ | 		for(var block of [...this.outline.querySelectorAll('[cropped]')]){ | ||||||
| @ -1212,7 +1219,9 @@ var Outline = { | |||||||
| 				+ this.path(...arguments, 'text') | 				+ this.path(...arguments, 'text') | ||||||
| 					.slice(0, -1) | 					.slice(0, -1) | ||||||
| 					.map(function(s, i, {length}){ | 					.map(function(s, i, {length}){ | ||||||
| 						return `<span class="path-item" onclick="editor.uncrop(${ length-i })">${s}</span> ` }) | 						return `<span class="path-item" onclick="editor.uncrop(${ length-i })">${ | ||||||
|  | 							plugin.encode(s) | ||||||
|  | 						}</span> ` }) | ||||||
| 					.join(' / ') | 					.join(' / ') | ||||||
| 		return this }, | 		return this }, | ||||||
| 	uncrop: function(count=1){ | 	uncrop: function(count=1){ | ||||||
| @ -1563,20 +1572,20 @@ var Outline = { | |||||||
| 			.clear() | 			.clear() | ||||||
| 			.outline | 			.outline | ||||||
| 				.append(...level(data)) | 				.append(...level(data)) | ||||||
| 		/* XXX do we actually need this??? |  | ||||||
| 		// update sizes of all the textareas (transparent)...
 | 		// update sizes of all the textareas (transparent)...
 | ||||||
|  | 		// NOTE: this is needed to make initial clicking into multi-line 
 | ||||||
|  | 		// 		blocks place the cursor into the clicked location.
 | ||||||
|  | 		// 		...this is done by expanding the textarea to the element 
 | ||||||
|  | 		// 		size and enabling it to intercept clicks correctly...
 | ||||||
| 		setTimeout(function(){ | 		setTimeout(function(){ | ||||||
| 			for(var e of [...that.outline.querySelectorAll('textarea')]){ | 			for(var e of [...that.outline.querySelectorAll('textarea')]){ | ||||||
| 				e.updateSize() } }, 0) | 				e.updateSize() } }, 0) | ||||||
| 		//*/
 |  | ||||||
| 		// restore focus...
 | 		// restore focus...
 | ||||||
| 		this.focus() | 		this.focus() | ||||||
| 		return this }, | 		return this }, | ||||||
| 
 | 
 | ||||||
| 	sync: function(){ | 	sync: function(){ | ||||||
| 		var code = this.code | 		this.code = this.text() | ||||||
| 		if(code){ |  | ||||||
| 			code.value = this.text() } |  | ||||||
| 		return this }, | 		return this }, | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -2109,7 +2118,7 @@ var Outline = { | |||||||
| 		var code = this.code | 		var code = this.code | ||||||
| 		if(code){ | 		if(code){ | ||||||
| 			var t = Date.now() | 			var t = Date.now() | ||||||
| 			this.load(code.value | 			this.load(code | ||||||
| 				.replace(/</g, '<') | 				.replace(/</g, '<') | ||||||
| 				.replace(/>/g, '>'))  | 				.replace(/>/g, '>'))  | ||||||
| 			console.log(`Parse: ${Date.now() - t}ms`) } | 			console.log(`Parse: ${Date.now() - t}ms`) } | ||||||
| @ -2126,5 +2135,99 @@ var Outline = { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
|  | // Custom element...
 | ||||||
|  | 
 | ||||||
|  | window.customElements.define('outline-editor', | ||||||
|  | window.OutlineEditor =  | ||||||
|  | 	Object.assign( | ||||||
|  | 		function(){ | ||||||
|  | 			var obj = Reflect.construct(HTMLElement, [...arguments], OutlineEditor) | ||||||
|  | 
 | ||||||
|  | 			obj.editor = { | ||||||
|  | 				__proto__: Outline, | ||||||
|  | 
 | ||||||
|  | 				get code(){ | ||||||
|  | 					return obj.hasAttribute('value') ? | ||||||
|  | 							obj.getAttribute('value') | ||||||
|  | 						: (obj.children.length == 1  | ||||||
|  | 								&& obj.children[0].nodeName == 'TEXTAREA') ? | ||||||
|  | 							obj.children[0].value | ||||||
|  | 						: obj.innerHTML }, | ||||||
|  | 				set code(value){ | ||||||
|  | 					// XXX this can break in conjunction with .attributeChangedCallback(..)
 | ||||||
|  | 					if(obj.hasAttribute('value')){ | ||||||
|  | 						obj.setAttribute('value', value) | ||||||
|  | 					} else if(obj.children.length == 1  | ||||||
|  | 							&& obj.children[0].nodeName == 'TEXTAREA'){ | ||||||
|  | 						obj.children[0].value = value | ||||||
|  | 					} else { | ||||||
|  | 						obj.innerHTML = value } }, | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			return obj },  | ||||||
|  | 		{ | ||||||
|  | 			// constructor stuff...
 | ||||||
|  | 			observedAttributes: [ | ||||||
|  | 				'value', | ||||||
|  | 			], | ||||||
|  | 
 | ||||||
|  | 			// instance stuff...
 | ||||||
|  | 			prototype: { | ||||||
|  | 				__proto__: HTMLElement.prototype, | ||||||
|  | 
 | ||||||
|  | 				get value(){ | ||||||
|  | 					return this.getAttribute('value') }, | ||||||
|  | 				set value(value){ | ||||||
|  | 					this.setAttribute('value', value) }, | ||||||
|  | 
 | ||||||
|  | 				connectedCallback: function(){ | ||||||
|  | 					var that = this | ||||||
|  | 					var shadow = this.attachShadow({mode: 'open'}) | ||||||
|  | 
 | ||||||
|  | 					var style = document.createElement('link'); | ||||||
|  | 					style.setAttribute('rel', 'stylesheet'); | ||||||
|  | 					style.setAttribute('href', 'editor.css'); | ||||||
|  | 
 | ||||||
|  | 					// XXX it is not rational to have this...
 | ||||||
|  | 					var editor = document.createElement('div') | ||||||
|  | 					editor.classList.add('editor') | ||||||
|  | 
 | ||||||
|  | 					var header = document.createElement('div') | ||||||
|  | 					header.classList.add('header') | ||||||
|  | 
 | ||||||
|  | 					var outline = document.createElement('div') | ||||||
|  | 					outline.classList.add('outline') | ||||||
|  | 					outline.setAttribute('tabindex', '0') | ||||||
|  | 
 | ||||||
|  | 					//var toolbar = document.createElement('div')
 | ||||||
|  | 					//toolbar.classList.add('toolbar')
 | ||||||
|  | 
 | ||||||
|  | 					// load the data...
 | ||||||
|  | 					setTimeout(function(){ | ||||||
|  | 						that.editor.setup(editor) }, 0) | ||||||
|  | 
 | ||||||
|  | 					editor.append( | ||||||
|  | 						style, | ||||||
|  | 						header, | ||||||
|  | 						outline) | ||||||
|  | 					shadow.append(editor) }, | ||||||
|  | 				disconnectedCallback: function(){ | ||||||
|  | 				}, | ||||||
|  | 				adoptedCallback: function(){ | ||||||
|  | 				}, | ||||||
|  | 				attributeChangedCallback: function(name, oldvalue, newvalue){ | ||||||
|  | 					if(name == 'value'){ | ||||||
|  | 						console.log('---', newvalue) | ||||||
|  | 						//oldvalue != newvalue
 | ||||||
|  | 						//	&& this.editor.load(newvalue) 
 | ||||||
|  | 						return } | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		})) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /********************************************************************** | /********************************************************************** | ||||||
| * vim:set ts=4 sw=4 :                                                */ | * vim:set ts=4 sw=4 :                                                */ | ||||||
|  | |||||||
| @ -354,7 +354,6 @@ var setup = function(){ | |||||||
| 		<button onclick="editor.toggleCollapse()?.focus()">˅˄</button> | 		<button onclick="editor.toggleCollapse()?.focus()">˅˄</button> | ||||||
| 		<button onclick="editor.remove()">×</button> | 		<button onclick="editor.remove()">×</button> | ||||||
| 	</div--> | 	</div--> | ||||||
| 	<span class="__textarea"></span> |  | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <hr> | <hr> | ||||||
| @ -362,6 +361,32 @@ var setup = function(){ | |||||||
| <button onclick="editor.dom.classList.toggle('show-click-zones')">show/hide click zones</button> | <button onclick="editor.dom.classList.toggle('show-click-zones')">show/hide click zones</button> | ||||||
| <button onclick="editor.dom.classList.toggle('block-offsets')">show/hide block offsets</button> | <button onclick="editor.dom.classList.toggle('block-offsets')">show/hide block offsets</button> | ||||||
| 
 | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <h1>Outline editor as web component</h1> | ||||||
|  | 
 | ||||||
|  | <outline-editor value=" | ||||||
|  | - ## code as part of an attribute | ||||||
|  | 	- as long as "quotes" are sanitized in the html, this is the safest"> | ||||||
|  | </outline-editor> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <outline-editor> | ||||||
|  | <textarea>- ## code enclosed in `<textarea>` element | ||||||
|  | 	- code is treated as-is | ||||||
|  | 	- the only exception is the closing textarea tag</textarea> | ||||||
|  | </outline-editor> | ||||||
|  | 
 | ||||||
|  | <hr> | ||||||
|  | 
 | ||||||
|  | <outline-editor> | ||||||
|  | - ## raw outline editor element | ||||||
|  | 	- the children are not protected | ||||||
|  | 	- any html <elements> are going to be parsed by the browser | ||||||
|  | </outline-editor> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user