mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-10-31 11:00:08 +00:00 
			
		
		
		
	lots of fixes + started major refactoring...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									53ad572369
								
							
						
					
					
						commit
						4690bc0770
					
				| @ -54,13 +54,23 @@ | |||||||
| 	display: block; | 	display: block; | ||||||
| 	position: relative; | 	position: relative; | ||||||
| 
 | 
 | ||||||
| 	/* XXX do a better calculation... */ |  | ||||||
| 	width: calc(100% - var(--button-size) - var(--outline-padding) * 2); | 	width: calc(100% - var(--button-size) - var(--outline-padding) * 2); | ||||||
| 
 | 
 | ||||||
| 	padding-left: var(--outline-padding); | 	padding: 1em var(--outline-padding); | ||||||
| 	padding-right: var(--outline-padding); | 	padding-bottom: 1.2em | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* virtual empty block... */ | ||||||
|  | .editor .outline:empty:after { | ||||||
|  | 	content: "Empty"; | ||||||
|  | 	display: block; | ||||||
|  | 	font-style: italic; | ||||||
|  | 	color: rgba(0,0,0,0.2); | ||||||
|  | } | ||||||
|  | .editor .outline:empty:hover:after { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| .editor .outline .block { | .editor .outline .block { | ||||||
| 	position: relative; | 	position: relative; | ||||||
| 	outline: none; | 	outline: none; | ||||||
| @ -110,6 +120,7 @@ | |||||||
| 	pointer-events: none; | 	pointer-events: none; | ||||||
| } | } | ||||||
| /* block hover... */ | /* block hover... */ | ||||||
|  | .editor .outline:empty:hover:after, | ||||||
| .editor .outline .block:hover>.view { | .editor .outline .block:hover>.view { | ||||||
| 	background: linear-gradient( | 	background: linear-gradient( | ||||||
| 		90deg,  | 		90deg,  | ||||||
| @ -127,6 +138,7 @@ | |||||||
| } | } | ||||||
| /* clickable things in view */ | /* clickable things in view */ | ||||||
| .editor .outline .block>.view a, | .editor .outline .block>.view a, | ||||||
|  | .editor .outline .block>.view pre, | ||||||
| .editor .outline .block>.view input { | .editor .outline .block>.view input { | ||||||
| 	pointer-events: auto; | 	pointer-events: auto; | ||||||
| } | } | ||||||
| @ -138,7 +150,7 @@ editor .outline .block:focus { | |||||||
| 	outline: none; | 	outline: none; | ||||||
| } | } | ||||||
| .editor .outline .block:focus>.text { | .editor .outline .block:focus>.text { | ||||||
| 	background: rgba(0,0,0,0.1); | 	background: rgba(0,0,0,0.07); | ||||||
| } | } | ||||||
| .editor .outline .block.focused:not(:focus)>.text { | .editor .outline .block.focused:not(:focus)>.text { | ||||||
| 	background: rgba(0,0,0,0.01); | 	background: rgba(0,0,0,0.01); | ||||||
| @ -464,11 +476,13 @@ editor .outline .block:focus { | |||||||
| 	font-family: monospace; | 	font-family: monospace; | ||||||
| 	background: rgba(0,0,0,0.07); | 	background: rgba(0,0,0,0.07); | ||||||
| 	border-radius: 0.2em; | 	border-radius: 0.2em; | ||||||
|  | 	outline: none; | ||||||
| } | } | ||||||
| .editor .outline .block>.view pre>code { | .editor .outline .block>.view pre>code { | ||||||
| 	display: block; | 	display: block; | ||||||
| 	padding: 0.6em 0.6em; | 	padding: 0.6em 0.6em; | ||||||
| 	padding-bottom: 0.8em; | 	padding-bottom: 0.8em; | ||||||
|  | 	outline: none; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,6 +25,56 @@ var atLine = function(elem, index){ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | var codeBlock = { | ||||||
|  | 	// can be used in:
 | ||||||
|  | 	// 		<string>.replace(codeBlock.pattern, codeBlock.handler)
 | ||||||
|  | 	// or:
 | ||||||
|  | 	// 		codeBlock
 | ||||||
|  | 	pattern: /(?<!\\)```(.*\s*\n)((\n|.)*?)\h*(?<!\\)```/g, | ||||||
|  | 	handler: function(_, language, code){ | ||||||
|  | 		var quote = this?.quote  | ||||||
|  | 			|| codeBlock.quote | ||||||
|  | 		language = language.trim() | ||||||
|  | 		language = language ? | ||||||
|  | 			'language-'+language | ||||||
|  | 			: language | ||||||
|  | 		return `<pre>` | ||||||
|  | 				+`<code contenteditable="true" class="${language}">${  | ||||||
|  | 					quote ? | ||||||
|  | 						quote(code) | ||||||
|  | 						: code | ||||||
|  | 				}</code>` | ||||||
|  | 			+`</pre>` }, | ||||||
|  | 
 | ||||||
|  | 	quote: function(text){ | ||||||
|  | 		return text | ||||||
|  | 			.replace(/(?<!\\)&/g, '&') | ||||||
|  | 			.replace(/(?<!\\)</g, '<') | ||||||
|  | 			.replace(/(?<!\\)>/g, '>') | ||||||
|  | 			.replace(/\\(?!`)/g, '\\\\') }, | ||||||
|  | 
 | ||||||
|  | 	map: function(text, func){ | ||||||
|  | 		return text.replace(this.pattern, func) }, | ||||||
|  | 
 | ||||||
|  | 	replace: function(text, index, updated){ | ||||||
|  | 		return this.map(text,  | ||||||
|  | 			function(match, language, code){ | ||||||
|  | 				return index-- != 0 ? | ||||||
|  | 					match | ||||||
|  | 					: ('```'+language | ||||||
|  | 						+ (typeof(updated) == 'function' ? | ||||||
|  | 							updated(code) | ||||||
|  | 							: updated) | ||||||
|  | 						+'```') }) }, | ||||||
|  | 
 | ||||||
|  | 	toHTML: function(text){ | ||||||
|  | 		return this.map(text, this.handler) }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| //---------------------------------------------------------------------
 | //---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // XXX experiment with a concatinative model...
 | // XXX experiment with a concatinative model...
 | ||||||
| @ -101,12 +151,13 @@ var Outline = { | |||||||
| 		// groups defaulting to .focused as base...
 | 		// groups defaulting to .focused as base...
 | ||||||
| 		if(['parent', 'next', 'prev', 'children', 'siblings'].includes(node)){ | 		if(['parent', 'next', 'prev', 'children', 'siblings'].includes(node)){ | ||||||
| 			return this.get('focused', node) } | 			return this.get('focused', node) } | ||||||
| 
 |  | ||||||
| 		// helpers...
 | 		// helpers...
 | ||||||
| 		var parent = function(node){ | 		var parent = function(node){ | ||||||
| 			return node === outline ? | 			return node === outline ? | ||||||
| 				node | 					outline | ||||||
| 				: node?.parentElement?.parentElement } | 				: node.parentElement === outline ? | ||||||
|  | 					outline | ||||||
|  | 				: node.parentElement.parentElement } | ||||||
| 		var children = function(node){ | 		var children = function(node){ | ||||||
| 			return node === outline ? | 			return node === outline ? | ||||||
| 				[...node.children] | 				[...node.children] | ||||||
| @ -337,11 +388,6 @@ var Outline = { | |||||||
| 				.replace(/\\(?!`)/g, '\\\\') } | 				.replace(/\\(?!`)/g, '\\\\') } | ||||||
| 		var quote = function(_, code){ | 		var quote = function(_, code){ | ||||||
| 			return `<code>${quoteText(code)}</code>` } | 			return `<code>${quoteText(code)}</code>` } | ||||||
| 		var pre = function(_, language, code){ |  | ||||||
| 			language = language ? |  | ||||||
| 				'language-'+language |  | ||||||
| 				: language |  | ||||||
| 			return `<pre><code class="${language}">${ quoteText(code) }</code></pre>` } |  | ||||||
| 		var table = function(_, body){ | 		var table = function(_, body){ | ||||||
| 			return `<table><tr><td>${ | 			return `<table><tr><td>${ | ||||||
| 				body | 				body | ||||||
| @ -349,78 +395,123 @@ var Outline = { | |||||||
| 					.replace(/\s*\|\s*/gm, '</td><td>') | 					.replace(/\s*\|\s*/gm, '</td><td>') | ||||||
| 			}</td></td></table>` } | 			}</td></td></table>` } | ||||||
| 
 | 
 | ||||||
| 		elem.text = code  | 		var preParse = function(text){ | ||||||
| 			// hidden attributes...
 | 			return text  | ||||||
| 			// XXX make this generic...
 | 				// hidden attributes...
 | ||||||
| 			// collapsed...
 | 				// XXX make this generic...
 | ||||||
| 			.replace(/(\n|^)\s*collapsed::\s*(.*)\s*(\n|$)/,  | 				// collapsed...
 | ||||||
| 				function(_, value){ | 				.replace(/(\n|^)\s*collapsed::\s*(.*)\s*(\n|$)/,  | ||||||
| 					elem.collapsed = value.trim() == 'true' | 					function(_, value){ | ||||||
| 					return '' }) | 						elem.collapsed = value.trim() == 'true' | ||||||
| 			// id...
 | 						return '' }) | ||||||
| 			.replace(/(\n|^)\s*id::\s*(.*)\s*(\n|$)/,  | 				// id...
 | ||||||
| 				function(_, value){ | 				.replace(/(\n|^)\s*id::\s*(.*)\s*(\n|$)/,  | ||||||
| 					elem.id = value.trim() | 					function(_, value){ | ||||||
| 					return '' }) | 						elem.id = value.trim() | ||||||
| 			// markdown...
 | 						return '' }) } | ||||||
| 			// style: headings...
 | 		var blockParse = function(text){ | ||||||
| 			.replace(/^(?<!\\)######\s+(.*)$/m, style('heading-6')) | 			return text  | ||||||
| 			.replace(/^(?<!\\)#####\s+(.*)$/m, style('heading-5')) | 				// markdown...
 | ||||||
| 			.replace(/^(?<!\\)####\s+(.*)$/m, style('heading-4')) | 				// style: headings...
 | ||||||
| 			.replace(/^(?<!\\)###\s+(.*)$/m, style('heading-3')) | 				.replace(/^(?<!\\)######\s+(.*)$/m, style('heading-6')) | ||||||
| 			.replace(/^(?<!\\)##\s+(.*)$/m, style('heading-2')) | 				.replace(/^(?<!\\)#####\s+(.*)$/m, style('heading-5')) | ||||||
| 			.replace(/^(?<!\\)#\s+(.*)$/m, style('heading-1')) | 				.replace(/^(?<!\\)####\s+(.*)$/m, style('heading-4')) | ||||||
| 			// style: list...
 | 				.replace(/^(?<!\\)###\s+(.*)$/m, style('heading-3')) | ||||||
| 			//.replace(/^(?<!\\)[-\*]\s+(.*)$/m, style('list-item'))
 | 				.replace(/^(?<!\\)##\s+(.*)$/m, style('heading-2')) | ||||||
| 			.replace(/^\s*(.*)(?<!\\):\s*$/m, style('list')) | 				.replace(/^(?<!\\)#\s+(.*)$/m, style('heading-1')) | ||||||
| 			.replace(/^\s*(.*)(?<!\\)#\s*$/m, style('numbered-list')) | 				// style: list...
 | ||||||
| 			// style: misc...
 | 				//.replace(/^(?<!\\)[-\*]\s+(.*)$/m, style('list-item'))
 | ||||||
| 			.replace(/^\s*(?<!\\)>\s+(.*)$/m, style('quote')) | 				.replace(/^\s*(.*)(?<!\\):\s*$/m, style('list')) | ||||||
| 			.replace(/^\s*(?<!\\)((\/\/|;)\s+.*)$/m, style('comment')) | 				.replace(/^\s*(.*)(?<!\\)#\s*$/m, style('numbered-list')) | ||||||
| 			.replace(/^\s*(?<!\\)NOTE:?\s*(.*)$/m, style('NOTE')) | 
 | ||||||
| 			.replace(/^\s*(?<!\\)XXX\s+(.*)$/m, style('XXX')) | 				// style: misc...
 | ||||||
| 			.replace(/^(.*)\s*(?<!\\)XXX$/m, style('XXX')) | 				.replace(/^\s*(?<!\\)>\s+(.*)$/m, style('quote')) | ||||||
| 			.replace(/(\s*)(?<!\\)(ASAP|BUG|FIX|HACK|STUB|WARNING|CAUTION)(\s*)/gm,  | 				.replace(/^\s*(?<!\\)((\/\/|;)\s+.*)$/m, style('comment')) | ||||||
| 				'$1<span class="highlight $2">$2</span>$3') | 				.replace(/^\s*(?<!\\)NOTE:?\s*(.*)$/m, style('NOTE')) | ||||||
| 			// elements...
 | 				.replace(/^\s*(?<!\\)XXX\s+(.*)$/m, style('XXX')) | ||||||
| 			.replace(/(\n|^)(?<!\\)---*\h*(\n|$)/m, '$1<hr>') | 				.replace(/^(.*)\s*(?<!\\)XXX$/m, style('XXX')) } | ||||||
| 			// ToDo...
 | 		var quoteParse = function(text){ | ||||||
| 			// NOTE: these are separate as we need to align block text 
 | 			return text | ||||||
| 			// 		to leading chekbox...
 | 				.replace(codeBlock.pattern, codeBlock.handler) | ||||||
| 			.replace(/^\s*(?<!\\)\[[_ ]\]\s*/m,  | 				.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote) } | ||||||
| 				style('todo', '<input type="checkbox">')) | 		var inlineParse = function(text){ | ||||||
| 			.replace(/^\s*(?<!\\)\[[Xx]\]\s*/m,  | 			return text  | ||||||
| 				style('todo', '<input type="checkbox" checked>')) | 				.replace(/(\s*)(?<!\\)(FEATURE:|Q:|Question:|Note:)(\s*)/gm,  | ||||||
| 			// inline checkboxes...
 | 					'$1<b class="$2">$2</b>$3') | ||||||
| 			.replace(/\s*(?<!\\)\[[_ ]\]\s*/gm,  | 				.replace(/(\s*)(?<!\\)(ASAP|BUG|FIX|HACK|STUB|WARNING|CAUTION)(\s*)/gm,  | ||||||
| 				style('check', '<input type="checkbox">')) | 					'$1<span class="highlight $2">$2</span>$3') | ||||||
| 			.replace(/\s*(?<!\\)\[[Xx]\]\s*/gm,  | 				// elements...
 | ||||||
| 				style('check', '<input type="checkbox" checked>')) | 				.replace(/(\n|^)(?<!\\)---*\h*(\n|$)/m, '$1<hr>') | ||||||
| 			// tables...
 | 				// ToDo...
 | ||||||
| 			.replace(/^\s*(?<!\\)\|\s*((.|\n)*)\s*\|\s*$/, table) | 				// NOTE: these are separate as we need to align block text 
 | ||||||
| 			// basic styling...
 | 				// 		to leading chekbox...
 | ||||||
| 			// XXX revise...
 | 				.replace(/^\s*(?<!\\)\[[_ ]\]\s*/m,  | ||||||
| 			.replace(/(?<!\\)\*(?=[^\s*])(([^*]|\\\*)*[^\s*])(?<!\\)\*/gm, '<b>$1</b>') | 					style('todo', '<input type="checkbox">')) | ||||||
| 			.replace(/(?<!\\)~(?=[^\s~])(([^~]|\\~)*[^\s~])(?<!\\)~/gm, '<s>$1</s>') | 				.replace(/^\s*(?<!\\)\[[Xx]\]\s*/m,  | ||||||
| 			.replace(/(?<!\\)_(?=[^\s_])(([^_]|\\_)*[^\s_])(?<!\\)_/gm, '<i>$1</i>')  | 					style('todo', '<input type="checkbox" checked>')) | ||||||
| 		    // code/quoting...
 | 				// inline checkboxes...
 | ||||||
| 			.replace(/(?<!\\)```(.*)\s*\n((\n|.)*)\h*(?<!\\)```\s*/g, pre)  | 				.replace(/\s*(?<!\\)\[[_ ]\]\s*/gm,  | ||||||
| 			.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote)  | 					style('check', '<input type="checkbox">')) | ||||||
| 			// XXX support "\==" in mark...
 | 				.replace(/\s*(?<!\\)\[[Xx]\]\s*/gm,  | ||||||
| 			.replace(/(?<!\\)==(?=[^\s])(.*[^\s])(?<!\\)==/gm, '<mark>$1</mark>')  | 					style('check', '<input type="checkbox" checked>')) | ||||||
| 			// links...
 | 				// tables...
 | ||||||
| 			.replace(/(?<!\\)\[([^\]]*)\]\(([^)]*)\)/g, '<a href="$2">$1</a>') | 				.replace(/^\s*(?<!\\)\|\s*((.|\n)*)\s*\|\s*$/, table) | ||||||
| 			.replace(/((?:https?:|ftps?:)[^\s]*)(\s*)/g, '<a href="$1">$1</a>$2') | 				// basic styling...
 | ||||||
| 			// characters...
 | 				// XXX revise...
 | ||||||
| 			// XXX use ligatures for these???
 | 				.replace(/(?<!\\)\*(?=[^\s*])(([^*]|\\\*)*[^\s*])(?<!\\)\*/gm, '<b>$1</b>') | ||||||
| 			.replace(/(?<!\\)\(i\)/gm, '🛈')  | 				.replace(/(?<!\\)~(?=[^\s~])(([^~]|\\~)*[^\s~])(?<!\\)~/gm, '<s>$1</s>') | ||||||
| 			.replace(/(?<!\\)\(c\)/gm, '©')  | 				.replace(/(?<!\\)_(?=[^\s_])(([^_]|\\_)*[^\s_])(?<!\\)_/gm, '<i>$1</i>')  | ||||||
| 			.replace(/(?<!\\)\/!\\/gm, '⚠')  | 				// code/quoting...
 | ||||||
| 			.replace(/(?<!\\)---(?!-)/gm, '—')  | 				//.replace(/(?<!\\)`(?=[^\s])(([^`]|\\`)*[^\s])(?<!\\)`/gm, quote) 
 | ||||||
| 			.replace(/(?<!\\)--(?!-)/gm, '–')  | 				// XXX support "\==" in mark...
 | ||||||
| 			// quoting...
 | 				.replace(/(?<!\\)==(?=[^\s])(.*[^\s])(?<!\\)==/gm, '<mark>$1</mark>')  | ||||||
| 			// NOTE: this must be last...
 | 				// links...
 | ||||||
| 			.replace(/(?<!\\)\\(.)/gm, '$1')  | 				.replace(/(?<!\\)\[([^\]]*)\]\(([^)]*)\)/g, '<a href="$2">$1</a>') | ||||||
|  | 				.replace(/((?:https?:|ftps?:)[^\s]*)(\s*)/g, '<a href="$1">$1</a>$2') | ||||||
|  | 				// characters...
 | ||||||
|  | 				// XXX use ligatures for these???
 | ||||||
|  | 				.replace(/(?<!\\)\(i\)/gm, '🛈')  | ||||||
|  | 				.replace(/(?<!\\)\(c\)/gm, '©')  | ||||||
|  | 				.replace(/(?<!\\)\/!\\/gm, '⚠')  | ||||||
|  | 				.replace(/(?<!\\)---(?!-)/gm, '—')  | ||||||
|  | 				.replace(/(?<!\\)--(?!-)/gm, '–') } | ||||||
|  | 		var postParse = function(text){ | ||||||
|  | 			return text | ||||||
|  | 				// quoting...
 | ||||||
|  | 				// NOTE: this must be last...
 | ||||||
|  | 				.replace(/(?<!\\)\\(.)/gm, '$1') } | ||||||
|  | 
 | ||||||
|  | 		var parse = function(text){ | ||||||
|  | 			// split text into parsable and non-parsable sections...
 | ||||||
|  | 			// split fomat:
 | ||||||
|  | 			// 	[ text <match> <type> <body>, ... ]
 | ||||||
|  | 			var pattern = /(<(pre|code)(?:|\s[^>]*)>((?:\n|.)*)<\/\2>)/g | ||||||
|  | 			var sections =  | ||||||
|  | 				quoteParse( | ||||||
|  | 						blockParse( | ||||||
|  | 							preParse(text | ||||||
|  | 								.replace(/\x00/g, '')))) | ||||||
|  | 					.split(pattern) | ||||||
|  | 			// sort out the sections...
 | ||||||
|  | 			var parsable = []  | ||||||
|  | 			var quoted = [] | ||||||
|  | 			while(sections.length > 0){ | ||||||
|  | 				var [section, match] = sections.splice(0, 4) | ||||||
|  | 				parsable.push(section) | ||||||
|  | 				quoted.push(match) } | ||||||
|  | 			// parse only the parsable sections...
 | ||||||
|  | 			return postParse( | ||||||
|  | 				inlineParse( | ||||||
|  | 						parsable | ||||||
|  | 							.join('\x00')) | ||||||
|  | 					.split(/\x00/g) | ||||||
|  | 					.map(function(section){ | ||||||
|  | 						return [section, quoted.shift() ?? '']	}) | ||||||
|  | 					.flat() | ||||||
|  | 					.join('')) } | ||||||
|  | 
 | ||||||
|  | 		elem.text = parse(code) | ||||||
|  | 
 | ||||||
| 		return elem }, | 		return elem }, | ||||||
| 	// XXX essentially here we need to remove service stuff like some 
 | 	// XXX essentially here we need to remove service stuff like some 
 | ||||||
| 	// 		attributes (collapsed, id, ...)...
 | 	// 		attributes (collapsed, id, ...)...
 | ||||||
| @ -482,7 +573,7 @@ var Outline = { | |||||||
| 		text = text | 		text = text | ||||||
| 			.replace(/^\s*\n/, '') | 			.replace(/^\s*\n/, '') | ||||||
| 		text = ('\n' + text) | 		text = ('\n' + text) | ||||||
| 			.split(/\n(\s*)- /g) | 			.split(/\n(\s*)(?:- |-\s*$)/gm) | ||||||
| 			.slice(1) | 			.slice(1) | ||||||
| 		var tab = ' '.repeat(this.tab_size || 8) | 		var tab = ' '.repeat(this.tab_size || 8) | ||||||
| 		var level = function(lst, prev_sep=undefined, parent=[]){ | 		var level = function(lst, prev_sep=undefined, parent=[]){ | ||||||
| @ -747,6 +838,15 @@ var Outline = { | |||||||
| 				if(elem.classList.contains('children')){ | 				if(elem.classList.contains('children')){ | ||||||
| 					return } | 					return } | ||||||
| 
 | 
 | ||||||
|  | 				// empty outline -> create new eleemnt...
 | ||||||
|  | 				if(elem.classList.contains('outline') | ||||||
|  | 						&& elem.children.length == 0){ | ||||||
|  | 					// create new eleemnt and edit it...
 | ||||||
|  | 					var block = that.Block() | ||||||
|  | 					that.outline.append(block) | ||||||
|  | 					that.edit(block) | ||||||
|  | 					return } | ||||||
|  | 
 | ||||||
| 				// expand/collapse
 | 				// expand/collapse
 | ||||||
| 				if(elem.classList.contains('view') | 				if(elem.classList.contains('view') | ||||||
| 						&& elem.parentElement.getAttribute('tabindex')){ | 						&& elem.parentElement.getAttribute('tabindex')){ | ||||||
| @ -783,10 +883,14 @@ var Outline = { | |||||||
| 							to | 							to | ||||||
| 							: m } | 							: m } | ||||||
| 					text.value = text.value.replace(/\[[Xx_]\]/g, toggle) } }) | 					text.value = text.value.replace(/\[[Xx_]\]/g, toggle) } }) | ||||||
| 		// heboard handling...
 | 		// keyboard handling...
 | ||||||
| 		outline.addEventListener('keydown',  | 		outline.addEventListener('keydown',  | ||||||
| 			function(evt){ | 			function(evt){ | ||||||
| 				var elem = evt.target | 				var elem = evt.target | ||||||
|  | 				// code editing...
 | ||||||
|  | 				if(elem.nodeName == 'CODE'  | ||||||
|  | 						&& elem.getAttribute('contenteditable') == 'true'){ | ||||||
|  | 					return } | ||||||
| 				// update element state...
 | 				// update element state...
 | ||||||
| 				if(elem.nodeName == 'TEXTAREA'){ | 				if(elem.nodeName == 'TEXTAREA'){ | ||||||
| 					setTimeout(function(){ | 					setTimeout(function(){ | ||||||
| @ -795,6 +899,28 @@ var Outline = { | |||||||
| 				// handle keyboard...
 | 				// handle keyboard...
 | ||||||
| 				evt.key in that.keyboard  | 				evt.key in that.keyboard  | ||||||
| 					&& that.keyboard[evt.key].call(that, evt) }) | 					&& that.keyboard[evt.key].call(that, evt) }) | ||||||
|  | 		// update code block...
 | ||||||
|  | 		outline.addEventListener('keyup',  | ||||||
|  | 			function(evt){ | ||||||
|  | 				var elem = evt.target | ||||||
|  | 				// editable code...
 | ||||||
|  | 				if(elem.nodeName == 'CODE'  | ||||||
|  | 						&& elem.getAttribute('contenteditable') == 'true'){ | ||||||
|  | 					// XXX should we clear the syntax???
 | ||||||
|  | 					// XXX do this only if things changed...
 | ||||||
|  | 					delete elem.dataset.highlighted | ||||||
|  | 
 | ||||||
|  | 					var block = that.get(elem) | ||||||
|  | 					var code = block.querySelector('.code') | ||||||
|  | 
 | ||||||
|  | 					var update = elem.innerText | ||||||
|  | 					var i = [...block | ||||||
|  | 							.querySelectorAll('.view code[contenteditable=true]')] | ||||||
|  | 						.indexOf(elem) | ||||||
|  | 					// update element content...
 | ||||||
|  | 					code.value = codeBlock.replace(code.value, i, update) | ||||||
|  | 
 | ||||||
|  | 					return } }) | ||||||
| 		// toggle view/code of nodes...
 | 		// toggle view/code of nodes...
 | ||||||
| 		outline.addEventListener('focusin',  | 		outline.addEventListener('focusin',  | ||||||
| 			function(evt){ | 			function(evt){ | ||||||
| @ -829,7 +955,8 @@ var Outline = { | |||||||
| 				 | 				 | ||||||
| 				// XXX do a plugin...
 | 				// XXX do a plugin...
 | ||||||
| 				window.hljs | 				window.hljs | ||||||
| 					&& hljs.highlightAll() }) | 					&& hljs.highlightAll()  | ||||||
|  | 			}) | ||||||
| 		// update .code...
 | 		// update .code...
 | ||||||
| 		var update_code_timeout | 		var update_code_timeout | ||||||
| 		outline.addEventListener('change',  | 		outline.addEventListener('change',  | ||||||
| @ -870,6 +997,10 @@ var Outline = { | |||||||
| 				.replace(/>/g, '>'))  | 				.replace(/>/g, '>'))  | ||||||
| 			console.log(`Parse: ${Date.now() - t}ms`)} | 			console.log(`Parse: ${Date.now() - t}ms`)} | ||||||
| 
 | 
 | ||||||
|  | 		// XXX do a plugin...
 | ||||||
|  | 		window.hljs | ||||||
|  | 			&& hljs.highlightAll()  | ||||||
|  | 		 | ||||||
| 		return this }, | 		return this }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -26,11 +26,7 @@ var setup = function(){ | |||||||
| 	window.editor = { | 	window.editor = { | ||||||
| 		__proto__: Outline, | 		__proto__: Outline, | ||||||
| 	}.setup( | 	}.setup( | ||||||
| 		document.querySelector('.editor'))  | 		document.querySelector('.editor')) } | ||||||
| 
 |  | ||||||
| 	// XXX make this a plugin... |  | ||||||
| 	window.hljs |  | ||||||
| 		&& hljs.highlightAll() } |  | ||||||
| 
 | 
 | ||||||
| </script> | </script> | ||||||
| </head> | </head> | ||||||
| @ -56,19 +52,41 @@ var setup = function(){ | |||||||
|         an we'll not get here... |         an we'll not get here... | ||||||
|   - |   - | ||||||
| - ## ToDo: | - ## ToDo: | ||||||
|   - ASAP: editor: bksapce/del at start/end of a block should join it with prev/next |   - ASAP: editor: backsapce/del at start/end of a block should join it with prev/next | ||||||
|   - ASAP: editor: pressing enter in text edit mode should split text into two blocks |   - ASAP: editor: pressing enter in text edit mode should split text into two blocks | ||||||
|   - ASAP: editor: shifting nodes up/down |   - ASAP: editor: shifting nodes up/down | ||||||
|   - ASAP: use \\t for indent... |  | ||||||
|   - ASAP: scroll into view is bad... |   - ASAP: scroll into view is bad... | ||||||
|   - on item click, place the cursor where it was clicked before the code expanded... |   - ASAP: need to reach checkboxes via keyboard | ||||||
|   - ~editor: semi-live update styles~ |   - FEATURE: "percentage complete" in parent blocks with todo's nested | ||||||
|   - need to reach checkboxes via keyboard |     - _...use `[%]` (preferred), `%%`, or something similar..._ | ||||||
|   - persistent empty first/last node (a button to create a new node) |   - FEATURE: read-only mode | ||||||
|   - add completion percentage to blocks with todo's nested |   - FEATURE: `collapse-children:: true` block option -- when loading collapse all immediate children | ||||||
|     - _...use `[%]`, `%%`, or something similar..._ |   - FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)` | ||||||
|   - read-only mode |   - Code blocks and bullets: | ||||||
|   - should bulets be on the same level as nodes or offset?? |     - ``` | ||||||
|  |       code | ||||||
|  |       ``` | ||||||
|  |     - _bullet should be either in the middle of the block or at the first line of code (preferred)..._ | ||||||
|  |   - custom element... | ||||||
|  |   - Nerd fonts (option???) | ||||||
|  |   - multiple node selection | ||||||
|  |   - copy/paste nodes/trees | ||||||
|  |   - undo  | ||||||
|  |     collapsed:: true | ||||||
|  |     - delete node | ||||||
|  |     - indent/deindent | ||||||
|  |     - edit node | ||||||
|  |   - Q: can we get the caret line in a textarea??? | ||||||
|  |     - _...this will fix a lot of issues with moving between blocks in edit mode..._ | ||||||
|  |   - Q: do we use \\t for indent? (option???) | ||||||
|  |   - Q: can we place the cursor on item click where it was clicked before before the code expanded? | ||||||
|  |     collapsed:: true | ||||||
|  |     - for example | ||||||
|  |       - #### Click in this line and see where the cursor goes | ||||||
|  |     - _not sure how..._ | ||||||
|  |   - Q: persistent empty first/last node (a button to create a new node)? | ||||||
|  |   - Q: should bullets be on the same level as nodes or offset?? | ||||||
|  |     collapsed:: true | ||||||
|     - A) justified to bullet: |     - A) justified to bullet: | ||||||
|          * list item |          * list item | ||||||
|          * list item |          * list item | ||||||
| @ -78,8 +96,10 @@ var setup = function(){ | |||||||
|          * list item |          * list item | ||||||
|            block text |            block text | ||||||
|     - NOTE: this is only a problem if making list-items manually -- disable??? |     - NOTE: this is only a problem if making list-items manually -- disable??? | ||||||
|   - FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)` |   - ~Q: can we edit code in a code block directly? (a-la Logseq)~ | ||||||
|   - Nerd fonts (options?) |   - empty item height is a bit off... | ||||||
|  |   - ~`.editor .outline:empty` view and behavior...~ | ||||||
|  |   - ~editor: semi-live update styles~ | ||||||
|   - ~do a better expand/collapse icons~ |   - ~do a better expand/collapse icons~ | ||||||
|   - ~loading from DOM -- fill textarea~ |   - ~loading from DOM -- fill textarea~ | ||||||
|   - ~focus management~ |   - ~focus management~ | ||||||
| @ -89,17 +109,29 @@ var setup = function(){ | |||||||
|   - ~shift subtree up/down~ |   - ~shift subtree up/down~ | ||||||
|   - ~create node~ |   - ~create node~ | ||||||
|   - ~edit node~ |   - ~edit node~ | ||||||
|   - multiple node selection |  | ||||||
|   - copy/paste nodes/trees |  | ||||||
|   - undo  |  | ||||||
|     collapsed:: true |  | ||||||
|     - delete node |  | ||||||
|     - indent/deindent |  | ||||||
|     - edit node |  | ||||||
|   - empty item height is a bit off... |  | ||||||
|   - ~serialize/deserialize~ |   - ~serialize/deserialize~ | ||||||
|   - ~add optional text styling to nodes~ |   - ~add optional text styling to nodes~ | ||||||
|   -  |   -  | ||||||
|  | - ## Refactoring: | ||||||
|  |   - Item parser (`.__code2html__(..)`) | ||||||
|  |     - split out | ||||||
|  |     - define api | ||||||
|  |     - define a way to extend/stack parsers | ||||||
|  |       _...add wikiwords, ..._ | ||||||
|  |   - Format parser/generator | ||||||
|  |     - split out | ||||||
|  |     - define api | ||||||
|  |     - experiment with clean markdown as format | ||||||
|  |   - CSS | ||||||
|  |     - separate out theming | ||||||
|  |     - separate out settings | ||||||
|  |   - Actions -- move user actions (code in `.keyboard`) into methods | ||||||
|  |   - Move to `keyboard.js` | ||||||
|  |   - Plugin architecture | ||||||
|  |     - Q: do we need `features.js` and/or `actions.js` | ||||||
|  |   - Q: do we need a concatenative API?? | ||||||
|  | 	- `<block>.get() -> <block>` | ||||||
|  |   - | ||||||
| - ## TEST | - ## TEST | ||||||
|   - ### Formatting: |   - ### Formatting: | ||||||
|     - Styles |     - Styles | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user