diff --git a/static/css/main.css b/static/css/main.css
index b4a783f..bf68f18 100644
--- a/static/css/main.css
+++ b/static/css/main.css
@@ -13,6 +13,11 @@ html {
*:after {
box-sizing: inherit;
}
+*,
+*:focus,
+*:hover {
+ outline: none;
+}
[onClick] {
cursor: pointer;
}
@@ -413,6 +418,7 @@ header .menu {
cursor: pointer;
}
#checklist .checklist-item {
+ transform: translate(0, 0);
display: grid;
grid-template-columns: repeat(3, min-content);
grid-gap: 0 8px;
@@ -778,6 +784,24 @@ header .menu {
#schedule-events .header {
font-weight: bold;
}
+#input-text {
+ border: 1px solid #000 !important;
+ padding: 16px;
+ width: 300px;
+}
+#input-text .label {
+ margin-bottom: 4px;
+}
+#input-text input[type=text] {
+ width: 100%;
+ padding: 4px;
+}
+#input-text .buttons {
+ display: grid;
+ grid-template-columns: 1fr 64px 64px;
+ grid-gap: 8px;
+ margin-top: 8px;
+}
@media only screen and (max-width: 932px) {
#app.node {
grid-template-areas: "header" "crumbs" "child-nodes" "name" "content" "checklist" "schedule" "files" "blank";
diff --git a/static/js/checklist.mjs b/static/js/checklist.mjs
index 1e639a8..b84cd8b 100644
--- a/static/js/checklist.mjs
+++ b/static/js/checklist.mjs
@@ -110,10 +110,11 @@ export class Checklist extends Component {
this.groupElements = {}
this.state = {
confirmDeletion: true,
+ continueAddingItems: true,
}
window._checklist = this
}//}}}
- render({ ui, groups }, { confirmDeletion }) {//{{{
+ render({ ui, groups }, { confirmDeletion, continueAddingItems }) {//{{{
this.groupElements = {}
if (groups.length == 0 && !ui.node.value.ShowChecklist.value)
return
@@ -136,6 +137,10 @@ export class Checklist extends Component {
this.setState({ confirmDeletion: !confirmDeletion })} />
+
+ this.setState({ continueAddingItems: !continueAddingItems })} />
+
+
`
}
@@ -194,10 +199,62 @@ export class Checklist extends Component {
}//}}}
}
+class InputElement extends Component {
+ render({ placeholder, label }) {//{{{
+ return html`
+
+ `
+ }//}}}
+ componentDidMount() {//{{{
+ const dlg = document.getElementById('input-text')
+ const input = document.getElementById('input-text-el')
+ dlg.showModal()
+ dlg.addEventListener("keydown", evt => this.keyhandler(evt))
+ input.addEventListener("keydown", evt => this.keyhandler(evt))
+ input.focus()
+ }//}}}
+ ok() {//{{{
+ const input = document.getElementById('input-text-el')
+ this.props.callback(true, input.value)
+ }//}}}
+ cancel() {//{{{
+ this.props.callback(false)
+ }//}}}
+ keyhandler(evt) {//{{{
+ let handled = true
+ switch (evt.key) {
+ case 'Enter':
+ this.ok()
+ break;
+
+ case 'Escape':
+ this.cancel()
+ break;
+ default:
+ handled = false
+ }
+ if (handled) {
+ evt.stopPropagation()
+ evt.preventDefault()
+ }
+ }//}}}
+}
+
class ChecklistGroupElement extends Component {
constructor() {//{{{
super()
this.label = createRef()
+ this.addingItem = signal(false)
}//}}}
render({ ui, group }) {//{{{
let items = ({ ui, group }) =>
@@ -206,30 +263,42 @@ class ChecklistGroupElement extends Component {
.map(item => html`<${ChecklistItemElement} key="item-${item.ID}" ui=${ui} group=${this} item=${item} />`)
let label = () => html` this.editLabel()}>${group.Label}
`
+ let addItem = () => {
+ if (this.addingItem.value)
+ return html`<${InputElement} label="New item" callback=${(ok, val) => this.addItem(ok, val)} />`
+ }
return html`
+ <${addItem} />
☰
this.delete()} />
<${label} />
-
this.addItem()} />
+
this.addingItem.value = true} />
<${items} ui=${ui} group=${group} />
`
}//}}}
- addItem() {//{{{
- let label = prompt("Create a new item")
- if (label === null)
+ addItem(ok, label) {//{{{
+ if (!ok) {
+ this.addingItem.value = false
return
+ }
+
label = label.trim()
- if (label == '')
+ if (label == '') {
+ this.addingItem.value = false
return
+ }
this.props.group.addItem(label, () => {
this.forceUpdate()
})
+
+ if (!this.props.ui.state.continueAddingItems)
+ this.addingItem.value = false
}//}}}
editLabel() {//{{{
let label = prompt('Edit label', this.props.group.Label)
@@ -299,7 +368,7 @@ class ChecklistItemElement extends Component {
`
}//}}}
componentDidMount() {//{{{
- this.base.addEventListener('dragstart', () => this.dragStart())
+ this.base.addEventListener('dragstart', evt => this.dragStart(evt))
this.base.addEventListener('dragend', () => this.dragEnd())
this.base.addEventListener('dragenter', evt => this.dragEnter(evt))
}//}}}
@@ -353,10 +422,13 @@ class ChecklistItemElement extends Component {
setDragTarget(state) {//{{{
this.setState({ dragTarget: state })
}//}}}
- dragStart() {//{{{
+ dragStart(evt) {//{{{
// Shouldn't be needed, but in case the previous drag was bungled up, we reset.
this.props.ui.dragReset()
this.props.ui.dragItemSource = this
+
+ const img = new Image();
+ evt.dataTransfer.setDragImage(img, 10, 10);
}//}}}
dragEnter(evt) {//{{{
evt.preventDefault()
@@ -393,7 +465,7 @@ class ChecklistItemElement extends Component {
this.props.ui.groupElements[fromGroup.ID].current.forceUpdate()
this.props.ui.groupElements[toGroup.ID].current.forceUpdate()
- from.move(to, ()=>console.log('ok'))
+ from.move(to, () => {})
}//}}}
}
diff --git a/static/less/main.less b/static/less/main.less
index ed13f38..649a896 100644
--- a/static/less/main.less
+++ b/static/less/main.less
@@ -8,6 +8,10 @@ html {
box-sizing: inherit;
}
+*,*:focus,*:hover{
+ outline:none;
+}
+
[onClick] {
cursor: pointer;
}
@@ -476,6 +480,7 @@ header {
}
.checklist-item {
+ transform: translate(0, 0);
display: grid;
grid-template-columns: repeat(3, min-content);
grid-gap: 0 8px;
@@ -905,6 +910,28 @@ header {
}
}
+#input-text {
+ border: 1px solid #000 !important;
+ padding: 16px;
+ width: 300px;
+
+ .label {
+ margin-bottom: 4px;
+ }
+
+ input[type=text] {
+ width: 100%;
+ padding: 4px;
+ }
+
+ .buttons {
+ display: grid;
+ grid-template-columns: 1fr 64px 64px;
+ grid-gap: 8px;
+ margin-top: 8px;
+ }
+}
+
@media only screen and (max-width: 932px) {
#app.node {
.layout-crumbs();