mirror of
https://github.com/flynx/pWiki.git
synced 2025-12-25 04:11:56 +00:00
Compare commits
No commits in common. "cb62d1e1c213414f8d4a50077350fde741d1c0fc" and "883e6994c34ad5320d57defa599251ef3b6dae52" have entirely different histories.
cb62d1e1c2
...
883e6994c3
@ -768,18 +768,16 @@ var Outline = {
|
|||||||
|
|
||||||
|
|
||||||
get header(){
|
get header(){
|
||||||
return this.dom?.querySelector('.header') },
|
return this.dom.querySelector('.header') },
|
||||||
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(){
|
get code(){
|
||||||
return this.dom?.querySelector('.code')?.value },
|
return this.dom.querySelector('.code')?.value },
|
||||||
set code(value){
|
set code(value){
|
||||||
if(value == null){
|
var c = this.dom.querySelector('.code')
|
||||||
return }
|
|
||||||
var c = this.dom?.querySelector('.code')
|
|
||||||
if(c){
|
if(c){
|
||||||
c.value = value } },
|
c.value = value } },
|
||||||
|
|
||||||
@ -1461,9 +1459,9 @@ var Outline = {
|
|||||||
parse: function(text){
|
parse: function(text){
|
||||||
var that = this
|
var that = this
|
||||||
text = text
|
text = text
|
||||||
.replace(/^[ \t]*\n/, '')
|
.replace(/^\s*\n/, '')
|
||||||
text = ('\n' + text)
|
text = ('\n' + text)
|
||||||
.split(/\n([ \t]*)(?:- |-\s*$)/gm)
|
.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=[]){
|
||||||
@ -1781,23 +1779,22 @@ var Outline = {
|
|||||||
this.Block('next')) } },
|
this.Block('next')) } },
|
||||||
Enter: function(evt){
|
Enter: function(evt){
|
||||||
var edited = this.get('edited')
|
var edited = this.get('edited')
|
||||||
|
// edit -> split text...
|
||||||
if(edited){
|
if(edited){
|
||||||
if(evt.ctrlKey
|
if(evt.ctrlKey
|
||||||
|| evt.shiftKey){
|
|| evt.shiftKey){
|
||||||
return }
|
return }
|
||||||
// split text...
|
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
var a = edited.selectionStart
|
var a = edited.selectionStart
|
||||||
var b = edited.selectionEnd
|
var b = edited.selectionEnd
|
||||||
var prev = edited.value.slice(0, a)
|
var prev = edited.value.slice(0, a)
|
||||||
var next = edited.value.slice(b)
|
var next = edited.value.slice(b)
|
||||||
edited.value = prev
|
edited.value = prev
|
||||||
this.Block({text: next}, 'next')
|
this.Block('next')
|
||||||
// focus next if not at position 0, otherwise keep focus...
|
edited = this.edit('next')
|
||||||
if(a != 0){
|
edited.value = next
|
||||||
edited = this.edit('next')
|
edited.selectionStart = 0
|
||||||
edited.selectionStart = 0
|
edited.selectionEnd = 0
|
||||||
edited.selectionEnd = 0 }
|
|
||||||
return }
|
return }
|
||||||
// view -> edit...
|
// view -> edit...
|
||||||
evt.preventDefault()
|
evt.preventDefault()
|
||||||
@ -2141,113 +2138,93 @@ var Outline = {
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Custom element...
|
// Custom element...
|
||||||
|
|
||||||
|
|
||||||
window.customElements.define('outline-editor',
|
window.customElements.define('outline-editor',
|
||||||
window.OutlineEditor =
|
window.OutlineEditor =
|
||||||
Object.assign(
|
Object.assign(
|
||||||
function(){
|
function(){
|
||||||
var obj = Reflect.construct(HTMLElement, [...arguments], OutlineEditor)
|
var obj = Reflect.construct(HTMLElement, [...arguments], OutlineEditor)
|
||||||
|
|
||||||
var shadow = obj.attachShadow({mode: 'open'})
|
obj.editor = {
|
||||||
|
__proto__: Outline,
|
||||||
var style = document.createElement('link');
|
|
||||||
style.setAttribute('rel', 'stylesheet');
|
|
||||||
style.setAttribute('href', 'editor.css');
|
|
||||||
|
|
||||||
// XXX it is not rational to have this...
|
|
||||||
var editor = obj.dom = 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')
|
|
||||||
|
|
||||||
editor.append(
|
|
||||||
style,
|
|
||||||
header,
|
|
||||||
outline)
|
|
||||||
shadow.append(editor)
|
|
||||||
|
|
||||||
obj.setup(editor)
|
|
||||||
|
|
||||||
return obj },
|
|
||||||
// constructor stuff...
|
|
||||||
{
|
|
||||||
observedAttributes: [
|
|
||||||
'value',
|
|
||||||
],
|
|
||||||
|
|
||||||
prototype: Object.assign(
|
|
||||||
{
|
|
||||||
__proto__: HTMLElement.prototype,
|
|
||||||
|
|
||||||
// XXX HACK these are copies from Outline, use
|
|
||||||
// object.mixin(...) instead...
|
|
||||||
get header(){
|
|
||||||
return this.dom?.querySelector('.header') },
|
|
||||||
set header(val){},
|
|
||||||
get outline(){
|
|
||||||
return this.dom?.querySelector('.outline') },
|
|
||||||
set outline(val){},
|
|
||||||
get toolbar(){
|
|
||||||
return this.dom?.querySelector('.toolbar') },
|
|
||||||
set toolbar(val){},
|
|
||||||
|
|
||||||
// XXX these are generic...
|
|
||||||
encode: function(text){
|
|
||||||
var span = document.createElement('span')
|
|
||||||
span.innerText = text
|
|
||||||
return span.innerHTML },
|
|
||||||
decode: function(text){
|
|
||||||
var span = document.createElement('span')
|
|
||||||
span.innerHTML = text
|
|
||||||
return span.innerText },
|
|
||||||
|
|
||||||
get code(){
|
get code(){
|
||||||
return this.hasAttribute('value') ?
|
return obj.hasAttribute('value') ?
|
||||||
this.getAttribute('value')
|
obj.getAttribute('value')
|
||||||
: this.decode(this.innerHTML) },
|
: (obj.children.length == 1
|
||||||
|
&& obj.children[0].nodeName == 'TEXTAREA') ?
|
||||||
|
obj.children[0].value
|
||||||
|
: obj.innerHTML },
|
||||||
set code(value){
|
set code(value){
|
||||||
if(value == null){
|
|
||||||
return }
|
|
||||||
// XXX this can break in conjunction with .attributeChangedCallback(..)
|
// XXX this can break in conjunction with .attributeChangedCallback(..)
|
||||||
if(this.hasAttribute('value')){
|
if(obj.hasAttribute('value')){
|
||||||
this.setAttribute('value', value)
|
obj.setAttribute('value', value)
|
||||||
|
} else if(obj.children.length == 1
|
||||||
|
&& obj.children[0].nodeName == 'TEXTAREA'){
|
||||||
|
obj.children[0].value = value
|
||||||
} else {
|
} else {
|
||||||
this.innerHTML = this.encode(value) } },
|
obj.innerHTML = value } },
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj },
|
||||||
|
{
|
||||||
|
// constructor stuff...
|
||||||
|
observedAttributes: [
|
||||||
|
'value',
|
||||||
|
],
|
||||||
|
|
||||||
|
// instance stuff...
|
||||||
|
prototype: {
|
||||||
|
__proto__: HTMLElement.prototype,
|
||||||
|
|
||||||
// XXX do we need this???
|
|
||||||
// ...rename .code -> .value ???
|
|
||||||
get value(){
|
get value(){
|
||||||
return this.code },
|
return this.getAttribute('value') },
|
||||||
set value(value){
|
set value(value){
|
||||||
this.code = value },
|
this.setAttribute('value', value) },
|
||||||
|
|
||||||
connectedCallback: function(){
|
connectedCallback: function(){
|
||||||
var that = this
|
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...
|
// load the data...
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
that.load(that.code) }, 0) },
|
that.editor.setup(editor) }, 0)
|
||||||
|
|
||||||
attributeChangedCallback(name, before, after){
|
editor.append(
|
||||||
|
style,
|
||||||
|
header,
|
||||||
|
outline)
|
||||||
|
shadow.append(editor) },
|
||||||
|
disconnectedCallback: function(){
|
||||||
|
},
|
||||||
|
adoptedCallback: function(){
|
||||||
|
},
|
||||||
|
attributeChangedCallback: function(name, oldvalue, newvalue){
|
||||||
if(name == 'value'){
|
if(name == 'value'){
|
||||||
if(before != after){
|
console.log('---', newvalue)
|
||||||
// XXX
|
//oldvalue != newvalue
|
||||||
console.log('---', before, '->', after)
|
// && this.editor.load(newvalue)
|
||||||
}
|
|
||||||
return }
|
return }
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
// XXX this will fail due to all the getters/setters -- use object.mixin(..)...
|
}))
|
||||||
Outline),
|
|
||||||
}))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -68,7 +68,6 @@ HTMLTextAreaElement.prototype.getTextGeometry = function(){
|
|||||||
padding: style.padding,
|
padding: style.padding,
|
||||||
|
|
||||||
boxSizing: style.boxSizing,
|
boxSizing: style.boxSizing,
|
||||||
//whiteSpace: 'pre-wrap',
|
|
||||||
|
|
||||||
outline: 'solid 1px red',
|
outline: 'solid 1px red',
|
||||||
|
|
||||||
|
|||||||
@ -48,16 +48,6 @@ var setup = function(){
|
|||||||
-
|
-
|
||||||
- ## Bugs:
|
- ## Bugs:
|
||||||
focused:: true
|
focused:: true
|
||||||
- BUG: focus at times seems to be biased a bit to the right -- the caret is placed to the right from where expected...
|
|
||||||
-
|
|
||||||
_this seems to only affect text with leading whitespace only, like this._
|
|
||||||
- BUG: undo: does not handle element splitting correctly...
|
|
||||||
- place cursor somewhere here, hit `Enter`, and then undo.
|
|
||||||
- _this will correctly restore the old node but will not remove the new one_
|
|
||||||
- need to:
|
|
||||||
- add undo to `.Block(..)`
|
|
||||||
- group `new` and `cange` into one undo action...
|
|
||||||
- _undo chaining? ...i.e. support nested arrays?_
|
|
||||||
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
|
- BUG: mobile browsers behave quite chaotically ignoring parts of the styling...
|
||||||
- FF:
|
- FF:
|
||||||
- zooming on edited field
|
- zooming on edited field
|
||||||
@ -66,31 +56,7 @@ var setup = function(){
|
|||||||
- side margins are a bit too large (account for toolbat to the right)
|
- side margins are a bit too large (account for toolbat to the right)
|
||||||
-
|
-
|
||||||
- ## ToDo:
|
- ## ToDo:
|
||||||
- trailing whitespace is ignored in `.view`... (BUG?)
|
- selection / multiple node selection (via shift+motion)
|
||||||
- this node has a second empty line
|
|
||||||
|
|
||||||
- there are several ways to deal with this:#
|
|
||||||
- remove trailing whitespace completely on refocus (a-la logseq)
|
|
||||||
- show whitespace in both modes
|
|
||||||
- keep current behavior
|
|
||||||
-
|
|
||||||
_BTW: leading whitespace is shown..._
|
|
||||||
- Q: should we select text without first focusing??
|
|
||||||
- _...logseq does not do this either_
|
|
||||||
- editor as a custom element / web component
|
|
||||||
- DONE data interface:
|
|
||||||
collapsed:: true
|
|
||||||
- the "natural" way to pass data is to use the same mechanism as `<textarea>` the problem is that we can't extend `HTMLTextAreaElement` as it can not have shadow dom (reject?)
|
|
||||||
- adding an explicit textarea element is an odd requirement (reject?)
|
|
||||||
- seems that the least bad way to go is to use the `value` attribute
|
|
||||||
- DONE API: directly mixin Outline?
|
|
||||||
- `.value` / `.code` should be both updated internally and also load new content when updated externally -- not yet sure how...
|
|
||||||
- events
|
|
||||||
- test nesting...
|
|
||||||
-
|
|
||||||
- selection
|
|
||||||
- multiple node selection (via shift+motion)
|
|
||||||
- touch/mouse (???)
|
|
||||||
- copy/paste nodes/trees
|
- copy/paste nodes/trees
|
||||||
- numbered lists: add counters to a depth of 6-7...
|
- numbered lists: add counters to a depth of 6-7...
|
||||||
- _or find a way to make them repeat..._
|
- _or find a way to make them repeat..._
|
||||||
@ -114,6 +80,7 @@ var setup = function(){
|
|||||||
- FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)`
|
- FF: figure out a way to draw expand/collapse bullets without the use of CSS' `:has(..)`
|
||||||
- table inline editing a-la code editing -- click cell and edit directly...
|
- table inline editing a-la code editing -- click cell and edit directly...
|
||||||
- a way to make a block monospace (???)
|
- a way to make a block monospace (???)
|
||||||
|
- editor as a custom element...
|
||||||
- Nerd fonts (option???)
|
- Nerd fonts (option???)
|
||||||
- smooth scrolling
|
- smooth scrolling
|
||||||
- _...this is more complicated than adding `behavior: "smooth"` to `.scrollIntoView(..)` as scrolling animation will get interrupted by next user input..._
|
- _...this is more complicated than adding `behavior: "smooth"` to `.scrollIntoView(..)` as scrolling animation will get interrupted by next user input..._
|
||||||
@ -144,9 +111,6 @@ var setup = function(){
|
|||||||
- empty item height is a bit off...
|
- empty item height is a bit off...
|
||||||
- search?
|
- search?
|
||||||
- _...not sure if search should be internal or external yet..._
|
- _...not sure if search should be internal or external yet..._
|
||||||
- DONE might be a good idea to focus the prev (empty) node if pressing `Enter` at 0 position
|
|
||||||
collapsed:: true
|
|
||||||
- <- place cursor here and press enter
|
|
||||||
- DONE make `---` block not show list bullets...
|
- DONE make `---` block not show list bullets...
|
||||||
- DONE: undo: checkboxes and DONE??
|
- DONE: undo: checkboxes and DONE??
|
||||||
collapsed:: true
|
collapsed:: true
|
||||||
@ -397,9 +361,6 @@ 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>
|
<hr>
|
||||||
|
|
||||||
<h1>Outline editor as web component</h1>
|
<h1>Outline editor as web component</h1>
|
||||||
@ -414,15 +375,16 @@ var setup = function(){
|
|||||||
<outline-editor>
|
<outline-editor>
|
||||||
<textarea>- ## code enclosed in `<textarea>` element
|
<textarea>- ## code enclosed in `<textarea>` element
|
||||||
- code is treated as-is
|
- code is treated as-is
|
||||||
- the only exception is the closing textarea tag</textarea></outline-editor>
|
- the only exception is the closing textarea tag</textarea>
|
||||||
|
</outline-editor>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<outline-editor>
|
<outline-editor>
|
||||||
- ## raw outline editor `<element>`
|
- ## raw outline editor element
|
||||||
- the children are not protected
|
- the children are not protected
|
||||||
- any html <elements> are going to be parsed by the browser</outline-editor>
|
- any html <elements> are going to be parsed by the browser
|
||||||
|
</outline-editor>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user