git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 741ac0a148c2a18f2bc5d54ad7582e7c82430d2b

Files: 741ac0a148c2a18f2bc5d54ad7582e7c82430d2b / modules / sheet / editTags.js

5134 bytesRaw
1const nest = require('depnest')
2const { h, Value, Struct, map, computed } = require('mutant')
3const MutantArray = require('mutant/Array')
4const concat = require('lodash/concat')
5const filter = require('lodash/filter')
6const zip = require('lodash/zip')
7const forEach = require('lodash/forEach')
8const addSuggest = require('suggest-box')
9
10exports.gives = nest('sheet.editTags')
11
12exports.needs = nest({
13 'about.obs.valueFrom': 'first',
14 'keys.sync.id': 'first',
15 'sheet.display': 'first',
16 'tag': {
17 'async': {
18 'apply': 'first',
19 'create': 'first',
20 'name': 'first'
21 },
22 'html': {
23 'tag': 'first'
24 },
25 'obs': {
26 'messageTags': 'first',
27 'allTags': 'first'
28 }
29 }
30})
31
32exports.create = function(api) {
33 return nest({ 'sheet.editTags': editTags })
34
35 function editTags({ msgId }, cb) {
36 cb = cb || function() {}
37 api.sheet.display(function (close) {
38 const tagsToCreate = MutantArray([])
39 const tagsToApply = MutantArray([])
40 const tagsToRemove = MutantArray([])
41 const tagsInput = Value('')
42
43 const myId = api.keys.sync.id()
44 const messageTags = map(
45 api.tag.obs.messageTags(msgId),
46 tagId => Struct({
47 tagId: Value(tagId),
48 tagName: api.about.obs.valueFrom(tagId, 'name', myId)
49 })
50 )
51 const filteredMessages = computed(
52 [ messageTags, tagsToRemove ],
53 (tags, removedIds) => filter(tags, tag => !removedIds.includes(tag.tagId))
54 )
55
56 const messageTagsView = map(
57 filteredMessages,
58 tag => computed(tag, t => api.tag.html.tag(t, () => tagsToRemove.push(t.tagId)))
59 )
60 const tagsToApplyView = map(
61 tagsToApply,
62 tag => api.tag.html.tag(tag, () => tagsToApply.delete(tag))
63 )
64 const tagsToCreateView = map(
65 tagsToCreate,
66 tag => api.tag.html.tag({ tagName: tag, tagId: 'new' }, () => tagsToCreate.delete(tag))
67 )
68 const stagedTags = computed(
69 [messageTagsView, tagsToApplyView, tagsToCreateView],
70 (a, b, c) => h('StagedTags', concat(a, [b, c]))
71 )
72
73 const input = h('input.tags', {
74 placeholder: 'Add tags here',
75 'ev-keyup': onInput,
76 value: tagsInput()
77 })
78
79 input.addEventListener('suggestselect', onSuggestSelect)
80
81 return {
82 content: [
83 stagedTags,
84 h('EditTags', input)
85 ],
86 footer: [
87 h('button.save', {
88 'ev-click': () => {
89 onSave()
90 close()
91 }
92 },
93 'Save'
94 ),
95 h('button.cancel', {
96 'ev-click': () => close()
97 },
98 'Cancel'
99 )
100 ],
101 mounted: () => {
102 input.focus()
103 addSuggest(input, (inputText, cb) => {
104 cb(null, getTagSuggestions(inputText))
105 }, { cls: 'ConfirmSuggest' })
106 }
107 }
108
109 function publish () {
110 close()
111 onSave()
112 }
113
114 function onInput(e) {
115 const input = e.target.value;
116 if (!input.endsWith(",")) {
117 tagsInput.set(input)
118 return
119 }
120 const tag = input.substring(0, input.length - 1)
121 tagsToCreate.push(tag)
122 e.target.value = ""
123 }
124
125 function onSuggestSelect(e) {
126 e.target.value = ""
127 const { value, tagId } = e.detail
128 const index = tagsToRemove().indexOf(tagId)
129 if (index >= 0) {
130 tagsToRemove.deleteAt(index)
131 } else {
132 tagsToApply.push({ tagId, tagName: value })
133 }
134 }
135
136 function getTagSuggestions(word) {
137 const suggestions = map(
138 api.tag.obs.allTags(),
139 tagId => {
140 const tagName = api.about.obs.valueFrom(tagId, 'name', myId)()
141 return {
142 title: tagName,
143 value: tagName,
144 tagId
145 }
146 }
147 )()
148 const appliedTagIds = map(filteredMessages, tag => tag.tagId)
149 const applyTagIds = map(tagsToApply, tag => tag.tagId)
150 const stagedTagIds = computed([ appliedTagIds, applyTagIds ], (a, b) => concat(a, b))()
151 const filteredSuggestions = filter(suggestions, tag => !stagedTagIds.includes(tag.tagId))
152 filteredSuggestions.push({ title: "Press , to create a new tag" })
153 return filteredSuggestions
154 }
155
156 function onSave() {
157 // tagsToCreate
158 forEach(
159 tagsToCreate(),
160 tag => {
161 api.tag.async.create(null, (err, msg) => {
162 if (err) return
163 api.tag.async.name({ tag: msg.key, name: tag }, cb)
164 api.tag.async.apply({ tagged: true, message: msgId, tag: msg.key }, cb)
165 })
166 }
167 )
168
169 // tagsToApply
170 forEach(
171 tagsToApply(),
172 tag => api.tag.async.apply({ tagged: true, message: msgId, tag: tag.tagId }, cb)
173 )
174
175 // tagsToRemove
176 forEach(
177 tagsToRemove(),
178 tagId => api.tag.async.apply({ tagged: false, message: msgId, tag: tagId }, cb)
179 )
180 }
181 })
182 }
183}

Built with git-ssb-web