Skip to content
This repository was archived by the owner on Jul 12, 2023. It is now read-only.

Commit 2afc3f7

Browse files
committed
create/update requests and stuff
1 parent 4195365 commit 2afc3f7

File tree

5 files changed

+99
-23
lines changed

5 files changed

+99
-23
lines changed

devserver.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@ polka()
2020
Look, the post source is **different**! This is a *demo*, so the micropub endpoint is fake :)`
2121
}
2222
],
23+
url: [`https://${req.headers.host}/fake/post`],
2324
},
2425
}))
2526
})
27+
.post('/fake-micropub', (req, res) => {
28+
res.setHeader('Location', req.headers.referer || `http://${req.headers.host}`)
29+
res.statusCode = 201
30+
res.end()
31+
})
2632
.listen(3003)
2733
.then(_ => console.log('Running on localhost:3003'))

src/micro-panel-editor-entry.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { sharedStyles, icons, iconCode } from './util.js'
55
import produce from 'immer'
66

77
export default class MicroPanelEditorEntry extends LitElement {
8-
static get properties () { return { entry: Object } }
8+
static get properties () { return { entry: Object, setEntry: Function } }
99

1010
_render ({ entry }) {
1111
return html`
@@ -57,17 +57,17 @@ export default class MicroPanelEditorEntry extends LitElement {
5757
<header class="bar">
5858
<label>${propname}</label>
5959
<button on-click=${_ =>
60-
this.entry = produce(entry, draft => { delete draft.properties[propname] })
60+
this._modify(entry, draft => delete draft.properties[propname])
6161
} title="Delete this property" class="icon-button">${iconCode(icons.minus)}</button>
6262
<button on-click=${_ =>
63-
this.entry = produce(entry, draft => { draft.properties[propname].push('') })
63+
this._modify(entry, draft => draft.properties[propname].push(''))
6464
} title="Add new value to this property" class="icon-button">${iconCode(icons.plus)}</button>
6565
</header>
6666
${entry.properties[propname].map((propval, idx) => html`
6767
<div class="input-row">
6868
${this._rowEditor(entry, propname, propval, idx)}
6969
<button on-click=${_ =>
70-
this.entry = produce(entry, draft => { draft.properties[propname].splice(idx, 1) })
70+
this._modify(entry, draft => draft.properties[propname].splice(idx, 1))
7171
} title="Delete this value" class="icon-button">${iconCode(icons.minus)}</button>
7272
</div>
7373
`)}
@@ -85,7 +85,7 @@ export default class MicroPanelEditorEntry extends LitElement {
8585
if (typeof propval === 'string') {
8686
return html`
8787
<input type="text" value=${propval} on-change=${e =>
88-
this.entry = produce(entry, draft => { draft.properties[propname][idx] = e.target.value })
88+
this._modify(entry, draft => draft.properties[propname][idx] = e.target.value)
8989
}/>
9090
`
9191
}
@@ -95,13 +95,13 @@ export default class MicroPanelEditorEntry extends LitElement {
9595
if ('html' in propval) {
9696
return html`
9797
<code-flask language="markup" value=${propval.html} on-value-changed=${e =>
98-
this.entry = produce(entry, draft => { draft.properties[propname][idx].html = e.target.value })
98+
this._modify(entry, draft => draft.properties[propname][idx].html = e.target.value)
9999
}></code-flask>
100100
`
101101
} else if ('markdown' in propval) {
102102
return html`
103103
<code-flask language="markdown" value=${propval.markdown} on-value-changed=${e =>
104-
this.entry = produce(entry, draft => { draft.properties[propname][idx].markdown = e.target.value })
104+
this._modify(entry, draft => draft.properties[propname][idx].markdown = e.target.value)
105105
}></code-flask>
106106
`
107107
}
@@ -113,12 +113,16 @@ export default class MicroPanelEditorEntry extends LitElement {
113113
}
114114
const inp = this.shadowRoot.getElementById('new-prop-inp')
115115
const propName = inp.value
116-
this.entry = produce(entry, draft => {
117-
propName.length > 0 && !(propName in draft.properties) && (draft.properties[propName] = [''])
118-
})
116+
this._modify(entry, draft =>
117+
propName.length > 0 && !(propName in draft.properties) && (draft.properties[propName] = ['']))
119118
inp.value = ''
120119
}
121120

121+
_modify (entry, fn) {
122+
// NOTE: propagating the entry property assignment up to the top component
123+
// NOTE: eat return value here to avoid returning assignment results
124+
this.setEntry(produce(entry, draft => { fn(draft) }))
125+
}
122126
}
123127

124128
customElements.define('micro-panel-editor-entry', MicroPanelEditorEntry)

src/micro-panel-editor.js

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ function micropubPost(endpoint, obj) {
2424
}
2525

2626
export default class MicroPanelEditor extends LitElement {
27-
static get properties () { return { micropub: String, entry: Object } }
27+
static get properties () {
28+
return {
29+
micropub: String, entry: Object, entryIsModified: Boolean, requestInFlight: Boolean,
30+
}
31+
}
2832

29-
_render ({ micropub, entry }) {
33+
_render ({ micropub, entry, entryIsModified }) {
3034
return html`
3135
${sharedStyles}
3236
<style>
@@ -49,28 +53,39 @@ export default class MicroPanelEditor extends LitElement {
4953
</style>
5054
5155
<header class="bar header-bar inverted">
52-
<button on-click=${_ => this.hidden = true} class="icon-button">${iconCode(icons.close)}</button>
56+
<button on-click=${_ => this.close()} class="icon-button">${iconCode(icons.close)}</button>
57+
<slot name="title"><h1>micro-panel editor</h1></slot>
58+
${this.entryIsNew ? html`
59+
<button on-click=${_ => this.createEntry()} disabled?=${!entryIsModified}>Create</button>
60+
` : html`
61+
<button on-click=${_ => this.updateEntry()} disabled?=${!entryIsModified}>Save</button>
62+
`}
5363
</header>
5464
55-
<micro-panel-editor-entry id="root-editor" entry=${entry}></micro-panel-editor-entry>
65+
<micro-panel-editor-entry id="root-editor" entry=${entry}
66+
setEntry=${entry => {
67+
this.entry = entry
68+
this.entryIsModified = true
69+
}}></micro-panel-editor-entry>
5670
5771
`
5872
}
5973

60-
async editEntry (url) {
74+
close () {
6175
if (this.entryIsModified && !confirm('Abandon current modified entry?')) {
6276
return
6377
}
78+
this.hidden = true
79+
}
80+
81+
async editEntry (url) {
6482
this.entry = await (await micropubGet(this.micropub, `q=source&url=${encodeURIComponent(url)}`)).json()
6583
this.entryIsNew = false
6684
this.entryIsModified = false
6785
this.hidden = false
6886
}
6987

7088
newEntry (properties = { name: ['New post'], content: [''] }) {
71-
if (this.entryIsModified && !confirm('Abandon current modified entry?')) {
72-
return
73-
}
7489
this.entry = {
7590
type: ['h-entry'],
7691
properties,
@@ -80,6 +95,46 @@ export default class MicroPanelEditor extends LitElement {
8095
this.hidden = false
8196
}
8297

98+
createEntry () {
99+
this._post({
100+
type: this.entry.type,
101+
properties: this.entry.properties,
102+
})
103+
}
104+
105+
updateEntry () {
106+
const url = ((this.entry.properties || {}).url || [null])[0]
107+
if (!url) {
108+
return alert('Somehow, an entry with no URL! I have no idea how to save that.')
109+
}
110+
this._post({
111+
'action': 'update',
112+
url,
113+
replace: this.entry.properties,
114+
// TODO 'delete': entry['x-micro-panel-deleted-properties'] || [],;w
115+
})
116+
}
117+
118+
async _post (data) {
119+
this.requestInFlight = true
120+
let resp
121+
try {
122+
resp = await micropubPost(this.micropub, data)
123+
} catch (e) {
124+
alert(`Couldn't save the entry! Got error: ${e}`)
125+
return
126+
} finally {
127+
this.requestInFlight = false
128+
}
129+
if (resp.status >= 300) {
130+
alert(`Couldn't save the entry! Got status: ${resp.status}`)
131+
return
132+
}
133+
this.entryIsModified = false
134+
this.close()
135+
location.href = resp.headers.get('Location')
136+
}
137+
83138
}
84139

85140
customElements.define('micro-panel-editor', MicroPanelEditor)

src/micro-panel-toolbar.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default class MicroPanelToolbar extends LitElement {
1414
</style>
1515
1616
<header class="bar header-bar inverted">
17+
<slot name="title"><h1>micro-panel</h1></slot>
1718
<button on-click=${_ => mpe().newEntry()}>${iconCode(icons.leadPencil)} New post</button>
1819
</header>
1920
`

src/util.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ export const sharedStyles = html`
4242
background: var(--accent);
4343
color: var(--neutral);
4444
}
45+
button[disabled] {
46+
opacity: 0.5;
47+
}
4548
4649
.icon, .icon-button {
4750
vertical-align: middle;
@@ -75,15 +78,22 @@ export const sharedStyles = html`
7578
.bar label, .bar h1 {
7679
flex: 1;
7780
}
78-
.bar button {
79-
margin: 0 0.2rem;
81+
.bar > * {
82+
margin: 0 0.4rem;
8083
}
81-
.bar button:first-child {
84+
.bar > *:first-child {
8285
margin-left: 0;
8386
}
84-
.bar button:last-child {
87+
.bar > * + * {
8588
margin-right: 0;
8689
}
90+
.bar h1 {
91+
margin: 0;
92+
font-size: 1.1rem;
93+
}
94+
.bar button {
95+
font-size: 1rem;
96+
}
8797
</style>
8898
`
8999

@@ -111,7 +121,7 @@ export const icons = {
111121
}
112122

113123
export function iconCode (icon, title = null) {
114-
return html`<svg class="icon" width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden$=${title ? 'false' : 'true'} title$=${title || ''}>
124+
return html`<svg class="icon" width="24" height="24" viewBox="0 0 24 24" role="img" aria-hidden?=${title} title$=${title || ''}>
115125
${icon}
116126
${title ? html`<title>${title}</title>` : ''}
117127
</svg>`

0 commit comments

Comments
 (0)