mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-29 10: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