git ssb

3+

arj / patchbook



Tree: 1d5d3beb765e9f7bb08097a0896eb8ea83eeccca

Files: 1d5d3beb765e9f7bb08097a0896eb8ea83eeccca / book / html / layout / detail.js

6298 bytesRaw
1const nest = require('depnest')
2const { h, when, computed, Value } = require('mutant')
3const addSuggest = require('suggest-box')
4
5exports.needs = nest({
6 'book.obs.book': 'first',
7 'about.html.image': 'first',
8 'about.obs.name': 'first',
9 'keys.sync.id': 'first',
10 'emoji.async.suggest': 'first',
11 'message.html': {
12 markdown: 'first'
13 },
14 'book.html': {
15 title: 'first',
16 authors: 'first',
17 series: 'first',
18 description: 'first',
19 images: 'first',
20 simpleEmoji: 'first'
21 }
22})
23
24exports.gives = nest('book.html.layout')
25
26exports.create = (api) => {
27 return nest('book.html.layout', bookLayout)
28
29 function ratingEdit(isEditing, value) {
30 return when(isEditing,
31 h('input', {
32 'ev-input': e => value.set(e.target.value),
33 value,
34 placeholder: 'your rating'
35 }),
36 h('span.text', { innerHTML: computed(value, api.book.html.simpleEmoji) })
37 )
38 }
39
40 function ratingTypeEdit(isEditing, value) {
41 let getEmojiSuggestions = api.emoji.async.suggest()
42
43 let ratingTypeInput = h('input', {'ev-input': e => value.set(e.target.value),
44 value: value, placeholder: 'rating type' })
45
46 let suggestWrapper = h('span.ratingType', ratingTypeInput)
47
48 addSuggest(ratingTypeInput, (inputText, cb) => {
49 if (inputText[0] === ':') {
50 cb(null, getEmojiSuggestions(inputText.slice(1)))
51 }
52 }, {cls: 'PatchSuggest'})
53
54 ratingTypeInput.addEventListener('suggestselect', ev => {
55 value.set(ev.detail.value)
56 })
57
58 return when(isEditing, suggestWrapper,
59 h('span.text', { innerHTML: computed(value, api.book.html.simpleEmoji) }))
60 }
61
62 function simpleEdit(isEditing, name, value) {
63 const classList = computed([value, isEditing], (v, e) => {
64 return v || e
65 ? '-expanded'
66 : '-contracted'
67 })
68
69 return h('div', { classList }, [
70 h('span', name + ':'),
71 when(isEditing,
72 h('input', {'ev-input': e => value.set(e.target.value), value }),
73 h('span', value)
74 )
75 ])
76 }
77
78 function textEdit(isEditing, name, value) {
79 const classList = computed([value, isEditing], (v, e) => {
80 return v || e
81 ? '-expanded'
82 : '-contracted'
83 })
84
85 return h('div', { classList }, [
86 h('div', name + ':'),
87 when(isEditing,
88 h('textarea', {'ev-input': e => value.set(e.target.value), value }),
89 computed(value, api.message.html.markdown)
90 )
91 ])
92 }
93
94 function saveSubjective(obs, isEditingSubjective) {
95 obs.updateSubjective()
96 isEditingSubjective.set(false)
97 }
98
99 function handleSubjective(user, i, obs) {
100 let originalSubjective = {}
101 let isEditingSubjective = Value(false)
102 let subjective = obs.subjective.get(user)
103 let isMe = Value(api.keys.sync.id() == user)
104 let isOwnEditingSubj = computed([isEditingSubjective, isMe],
105 (e, me) => { return e && me })
106 let showRating = computed([subjective.rating, isEditingSubjective, isMe],
107 (v, e, me) => { return v || (e && me) })
108
109 function editRatingClick() {
110 if (isEditingSubjective()) { // cancel
111 if (obs.subjective.has(api.keys.sync.id())) {
112 let subj = obs.subjective.get(api.keys.sync.id())
113 Object.keys(originalSubjective).forEach((v) => {
114 subj[v].set(originalSubjective[v])
115 })
116 }
117 } else {
118 if (obs.subjective.has(api.keys.sync.id()))
119 originalSubjective = JSON.parse(JSON.stringify(obs.subjective.get(api.keys.sync.id())()))
120 }
121
122 isEditingSubjective.set(!isEditingSubjective())
123 }
124
125 return [
126 h('section',
127 [api.about.html.image(user),
128 h('span.text', [api.about.obs.name(user), when(showRating, ' rated ')]),
129 ratingEdit(isOwnEditingSubj, subjective.rating),
130 ratingTypeEdit(isOwnEditingSubj, subjective.ratingType)]),
131 simpleEdit(isOwnEditingSubj, 'Shelve', subjective.shelve),
132 simpleEdit(isOwnEditingSubj, 'Genre', subjective.genre),
133 textEdit(isOwnEditingSubj, 'Review', subjective.review),
134 h('section.actions',
135 when(isMe, [
136 h('button.subjective', { 'ev-click': editRatingClick },
137 when(isEditingSubjective, 'Cancel', 'Edit my rating')),
138 when(isEditingSubjective,
139 h('button', { 'ev-click': () => saveSubjective(obs, isEditingSubjective) },
140 'Update rating'))
141 ]))
142 ]
143 }
144
145 function bookLayout(msg, opts) {
146 const { layout, obs, isEditing, isCard } = opts
147
148 if (layout !== undefined && layout !== 'detail') return
149
150 const { title, authors, description,
151 series, seriesNo, images } = api.book.html
152
153 let originalBook = {}
154 let reviews = []
155
156 function editClick() {
157 if (isEditing()) { // cancel
158 Object.keys(originalBook).forEach((v) => {
159 obs[v].set(originalBook[v])
160 })
161 } else
162 originalBook = JSON.parse(JSON.stringify(obs()))
163
164 isEditing.set(!isEditing())
165 }
166
167 return [h('Message -book-detail', [
168 title({ title: obs.title, msg, isEditing, onUpdate: obs.title.set }),
169 series({ series: obs.series, seriesNo: obs.seriesNo, msg, isEditing,
170 onUpdate: obs.series.set, onUpdateNo: obs.seriesNo.set }),
171 authors({authors: obs.authors, isEditing, onUpdate: obs.authors.set}),
172 h('section.content', [
173 images({images: obs.images, isEditing, onUpdate: obs.images.add }),
174 h('section.description',
175 description({description: obs.description, isEditing, onUpdate: obs.description.set})),
176 ]),
177 h('section.actions', [
178 h('button.edit', { 'ev-click': editClick },
179 when(isEditing, 'Cancel', 'Edit book')),
180 when(isEditing, h('button', {'ev-click': () => saveBook(obs)}, 'Update book'))
181 ]),
182 h('section.subjective', [
183 computed(obs.subjective, subjectives => {
184 let i = 0;
185 Object.keys(subjectives).forEach(user => {
186 if (i++ < reviews.length) return
187 reviews.push(handleSubjective(user, i, obs))
188 })
189
190 return reviews
191 })
192 ])
193 ])]
194
195 function saveBook(obs) {
196 obs.amend()
197
198 isEditing.set(false)
199 }
200 }
201}
202

Built with git-ssb-web