Files: f5dde01a771f059ca6c79e815d0d184dbc80523e / app / html / thread-card.js
3046 bytesRaw
1 | var h = require('mutant/h') |
2 | const last = require('lodash/last') |
3 | |
4 | exports.gives = { |
5 | app: {html: {threadCard: true}} |
6 | } |
7 | |
8 | exports.needs = { |
9 | keys: {sync: {id: 'first'}}, |
10 | history: {sync: {push: 'first'}}, |
11 | about: { |
12 | obs: {name: 'first'}, |
13 | html: {image: 'first'}, |
14 | }, |
15 | message: {html: {markdown: 'first'}}, |
16 | translations: {sync: {strings: 'first'}}, |
17 | } |
18 | |
19 | function isString (s) { |
20 | return 'string' === typeof s |
21 | } |
22 | |
23 | function firstLine (text) { |
24 | if(text.length < 80 && !~text.indexOf('\n')) return text |
25 | |
26 | var line = '' |
27 | var lineNumber = 0 |
28 | while (line.length === 0) { |
29 | const rawLine = text.split('\n')[lineNumber] |
30 | line = trimLeadingMentions(rawLine) |
31 | |
32 | lineNumber++ |
33 | } |
34 | |
35 | var sample = line.substring(0, 80) |
36 | if (hasBrokenLink(sample)) |
37 | sample = sample + line.substring(81).match(/[^\)]*\)/)[0] |
38 | |
39 | return sample |
40 | |
41 | function trimLeadingMentions (str) { |
42 | return str.replace(/^(\s*\[@[^\)]+\)\s*)*/, '') |
43 | // deletes any number of pattern " [@...) " from start of line |
44 | } |
45 | |
46 | function hasBrokenLink (str) { |
47 | return /\[[^\]]*\]\([^\)]*$/.test(str) |
48 | // matches "[name](start_of_link" |
49 | } |
50 | } |
51 | |
52 | exports.create = function (api) { |
53 | |
54 | //render the icon for a thread. |
55 | //it would be more depjecty to split this |
56 | //into two methods, one in a private plugin |
57 | //one in a channel plugin |
58 | function threadIcon (msg) { |
59 | if(msg.value.private) { |
60 | const myId = api.keys.sync.id() |
61 | |
62 | return msg.value.content.recps |
63 | .map(link => isString(link) ? link : link.link) |
64 | .filter(link => link !== myId) |
65 | .map(api.about.html.image) |
66 | } |
67 | else if(msg.value.content.channel) |
68 | return '#'+msg.value.content.channel |
69 | } |
70 | |
71 | |
72 | // REFACTOR: move this to a template? |
73 | function buildRecipientNames (thread) { |
74 | const myId = api.keys.sync.id() |
75 | |
76 | return thread.value.content.recps |
77 | .map(link => isString(link) ? link : link.link) |
78 | .filter(link => link !== myId) |
79 | .map(api.about.obs.name) |
80 | } |
81 | |
82 | function link(location) { |
83 | return {'ev-click': () => api.history.sync.push(location)} |
84 | } |
85 | |
86 | function subject (msg) { |
87 | const { subject, text } = msg.value.content |
88 | if(!(subject||text)) debugger |
89 | return api.message.html.markdown(firstLine(subject|| text)) |
90 | } |
91 | |
92 | return {app: {html: {threadCard: function (_, thread, opts = {}) { |
93 | var strings = api.translations.sync.strings() |
94 | |
95 | if(!thread.value) return |
96 | if(!thread.value.content.text) return |
97 | |
98 | const subjectEl = h('div.subject', [ |
99 | opts.nameRecipients |
100 | ? h('div.recps', buildRecipientNames(thread).map(recp => h('div.recp', recp))) |
101 | : null, |
102 | subject(thread) |
103 | ]) |
104 | |
105 | const lastReply = thread.replies && last(thread.replies) |
106 | const replyEl = lastReply |
107 | ? h('div.reply', [ |
108 | h('div.replySymbol', strings.replySymbol), |
109 | subject(lastReply) |
110 | ]) |
111 | : null |
112 | |
113 | return h('div.thread', link(thread), [ |
114 | //h('div.context', context), |
115 | h('div.context', threadIcon(thread)), |
116 | h('div.content', [ |
117 | subjectEl, |
118 | replyEl |
119 | ]) |
120 | ]) |
121 | }}}} |
122 | } |
123 | |
124 | |
125 |
Built with git-ssb-web