git ssb

10+

Matt McKegg / patchwork



Tree: 2dc6d16729374905e59e3bbe8cbef95670c5edb2

Files: 2dc6d16729374905e59e3bbe8cbef95670c5edb2 / modules / gathering / sheet / edit.js

6601 bytesRaw
1var nest = require('depnest')
2var extend = require('xtend')
3var Pickr = require('flatpickr')
4var spacetime = require('spacetime')
5
6var {Value, h, computed, when} = require('mutant')
7
8exports.gives = nest('gathering.sheet.edit')
9
10exports.needs = nest({
11 'sheet.display': 'first',
12 'message.sheet.preview': 'first',
13 'keys.sync.id': 'first',
14 'sbot.async.publish': 'first',
15 'about.obs.latestValue': 'first',
16 'blob.html.input': 'first',
17 'blob.sync.url': 'first',
18 'intl.sync.i18n': 'first'
19})
20
21exports.create = function (api) {
22 const i18n = api.intl.sync.i18n
23 return nest('gathering.sheet.edit', function (id) {
24 api.sheet.display(close => {
25 var current = id ? {
26 title: api.about.obs.latestValue(id, 'title'),
27 startDateTime: api.about.obs.latestValue(id, 'startDateTime'),
28 image: api.about.obs.latestValue(id, 'image'),
29 description: api.about.obs.latestValue(id, 'description')
30 } : {
31 title: Value(),
32 startDateTime: Value(),
33 image: Value(),
34 description: Value()
35 }
36
37 var publishing = Value(false)
38
39 var chosen = {
40 title: Value(current.title()),
41 startDateTime: Value(current.startDateTime()),
42 image: Value(current.image()),
43 description: Value(current.description())
44 }
45
46 var imageUrl = computed(chosen.image, (id) => id && api.blob.sync.url(id))
47
48 return {
49 content: h('div', {
50 style: {
51 padding: '20px',
52 'text-align': 'center'
53 }
54 }, [
55 h('h2', {
56 style: {
57 'font-weight': 'normal'
58 }
59 }, [id ? i18n('Edit Gathering') : i18n('Create Gathering')]),
60 h('GatheringEditor', [
61 h('input.title', {
62 placeholder: i18n('Choose a title'),
63 hooks: [ValueHook(chosen.title), FocusHook()]
64 }),
65 h('input.date', {
66 placeholder: i18n('Choose date and time'),
67 hooks: [
68 PickrHook(chosen.startDateTime)
69 ]
70 }),
71 h('ImageInput .banner', {
72 style: { 'background-image': computed(imageUrl, x => `url(${x})`) }
73 }, [
74 h('span', ['🖼 ', i18n('Choose Banner Image...')]),
75 api.blob.html.input(file => {
76 chosen.image.set(file)
77 }, {
78 accept: 'image/*'
79 })
80 ]),
81 h('textarea.description', {
82 placeholder: i18n('Describe the gathering (if you want)'),
83 hooks: [ValueHook(chosen.description)]
84 })
85 ])
86 ]),
87 footer: [
88 h('button -save', {
89 'ev-click': save,
90 'disabled': publishing
91 }, when(publishing, i18n('Publishing...'), i18n('Preview & Publish'))),
92 h('button -cancel', {
93 'ev-click': close
94 }, i18n('Cancel'))
95 ]
96 }
97
98 function ensureExists (cb) {
99 if (!id) {
100 api.sbot.async.publish({
101 type: 'gathering'
102 }, (err, msg) => {
103 if (err) return cb(err)
104 cb(null, msg.key)
105 })
106 } else {
107 cb(null, id)
108 }
109 }
110
111 function save () {
112 // no confirm
113 var update = {}
114
115 if (!compareImage(chosen.image(), current.image())) update.image = chosen.image()
116 if (!compareTime(chosen.startDateTime(), current.startDateTime())) update.startDateTime = chosen.startDateTime()
117 if (chosen.title() !== current.title()) update.title = chosen.title() || i18n('Untitled Gathering')
118 if (chosen.description() !== current.description()) update.description = chosen.description()
119
120 if (Object.keys(update).length) {
121 // gatherings consist of multiple messages (maybe none of them exist yet), so we need to
122 // construct the preview dialog manually, and override the about values
123 api.message.sheet.preview({
124 key: id,
125 previewAbout: update,
126 publicallyEditable: true,
127 value: {
128 author: api.keys.sync.id(),
129 content: {
130 type: 'gathering'
131 }
132 }
133 }, (err, confirmed) => {
134 if (err) throw err
135 if (confirmed) {
136 publish(update)
137 }
138 })
139 } else {
140 showDialog({
141 type: 'info',
142 title: i18n('Update Profile'),
143 buttons: [i18n('OK')],
144 message: i18n('Nothing to publish'),
145 detail: i18n('You have not made any changes.')
146 })
147 close()
148 }
149 }
150
151 function publish (update) {
152 publishing.set(true)
153 ensureExists((err, id) => {
154 if (err) throw err
155 api.sbot.async.publish(extend({
156 type: 'about',
157 about: id
158 }, update), (err) => {
159 if (err) {
160 publishing.set(false)
161 showDialog({
162 type: 'error',
163 title: i18n('Error'),
164 buttons: ['OK'],
165 message: i18n('An error occurred while attempting to publish gathering.'),
166 detail: err.message
167 })
168 } else {
169 close()
170 }
171 })
172 })
173 }
174 })
175 })
176}
177
178function compareTime (a, b) {
179 if (!a && !b) {
180 return true
181 } else if (!a || !b) {
182 return false
183 } else {
184 return a.epoch === b.epoch
185 }
186}
187
188function compareImage (a, b) {
189 a = isObject(a) ? a.link : a
190 b = isObject(b) ? b.link : b
191 return a === b
192}
193
194function isObject (value) {
195 return value && typeof value === 'object'
196}
197
198function FocusHook () {
199 return function (element) {
200 setTimeout(() => {
201 element.focus()
202 element.select()
203 }, 5)
204 }
205}
206
207function ValueHook (obs) {
208 return function (element) {
209 element.value = obs()
210 element.oninput = function () {
211 obs.set(element.value.trim())
212 }
213 }
214}
215
216function showDialog (opts) {
217 var electron = require('electron')
218 electron.remote.dialog.showMessageBox(electron.remote.getCurrentWindow(), opts)
219}
220
221function PickrHook (obs) {
222 return function (element) {
223 var picker = new Pickr(element, {
224 enableTime: true,
225 altInput: true,
226 dateFormat: 'U',
227 onChange: function (dates) {
228 obs.set(spacetime(parseInt(element.value, 10) * 1000))
229 }
230 })
231
232 var value = obs()
233 if (value) {
234 picker.setDate(value.epoch)
235 }
236 return () => picker.destroy()
237 }
238}
239

Built with git-ssb-web