Commit ba7439117c4a64cf7928c63d64fd58acd9898993
add tests for module deps, and mov emodules till it passes
mix irving committed on 1/19/2017, 9:18:40 AMParent: 3c201fb3cd2ad22f338850c91b72818022074849
Files changed
modules_basic/index.js | ||
---|---|---|
@@ -8,30 +8,29 @@ | ||
8 | 8 … | 'profile': require('./avatar/profile'), |
9 | 9 … | 'avatar': require('./avatar/avatar') |
10 | 10 … | }, |
11 | 11 … | 'compose': require('./compose'), |
12 … | + 'emoji': require('./emoji'), | |
12 | 13 … | 'feed': require('./feed'), |
13 | 14 … | 'follow': require('./follow'), |
14 | 15 … | 'invite': require('./invite'), |
15 | 16 … | 'like': require('./like'), |
16 | 17 … | 'markdown': require('./markdown'), |
17 | 18 … | 'message': { |
18 | 19 … | 'author': require('./message/author'), |
19 | 20 … | 'backlinks': require('./message/backlinks'), |
21 … | + 'confirm': require('./message/confirm'), | |
20 | 22 … | 'link': require('./message/link'), |
21 | 23 … | 'name': require('./message/name'), |
22 | 24 … | 'render': require('./message/render'), |
23 | 25 … | }, |
24 | - 'names': require('./names'), | |
25 | 26 … | 'post': require('./post'), |
26 | 27 … | 'private': require('./private'), |
27 | 28 … | 'pub': require('./pub'), |
28 | 29 … | 'public': require('./public'), |
29 | 30 … | 'relationships': require('./relationships'), |
30 | 31 … | 'reply': require('./reply'), |
31 | - 'search-box': require('./search-box'), | |
32 | 32 … | 'setup': require('./setup'), |
33 | - 'suggest-mentions': require('./suggest-mentions'), | |
34 | 33 … | 'thread': require('./thread'), |
35 | 34 … | 'timestamp': require('./timestamp') |
36 | 35 … | } |
37 | 36 … |
modules_basic/message/confirm.js | ||
---|---|---|
@@ -1,0 +1,73 @@ | ||
1 … | +var fs = require('fs') | |
2 … | +var lightbox = require('hyperlightbox') | |
3 … | +var h = require('../../h') | |
4 … | +var self_id = require('../../keys').id | |
5 … | +//publish or add | |
6 … | + | |
7 … | +exports.needs = { | |
8 … | + publish: 'first', | |
9 … | + message_render: 'first', | |
10 … | + avatar: 'first', | |
11 … | + message_meta: 'map' | |
12 … | +} | |
13 … | + | |
14 … | +exports.gives = { | |
15 … | + message_confirm: true, | |
16 … | + mcss: true | |
17 … | +} | |
18 … | + | |
19 … | +exports.create = function (api) { | |
20 … | + return { | |
21 … | + message_confirm, | |
22 … | + mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8') | |
23 … | + } | |
24 … | + | |
25 … | + function message_confirm (content, cb) { | |
26 … | + | |
27 … | + cb = cb || function () {} | |
28 … | + | |
29 … | + var lb = lightbox() | |
30 … | + document.body.appendChild(lb) | |
31 … | + | |
32 … | + var msg = { | |
33 … | + key: "DRAFT", | |
34 … | + value: { | |
35 … | + author: self_id, | |
36 … | + previous: null, | |
37 … | + sequence: null, | |
38 … | + timestamp: Date.now(), | |
39 … | + content: content | |
40 … | + } | |
41 … | + } | |
42 … | + | |
43 … | + var okay = h('button', { | |
44 … | + 'ev-click': () => { | |
45 … | + lb.remove() | |
46 … | + api.publish(content, cb) | |
47 … | + }}, | |
48 … | + 'okay' | |
49 … | + ) | |
50 … | + | |
51 … | + var cancel = h('button', { | |
52 … | + 'ev-click': () => { | |
53 … | + lb.remove() | |
54 … | + cb(null) | |
55 … | + }}, | |
56 … | + 'Cancel' | |
57 … | + ) | |
58 … | + | |
59 … | + okay.addEventListener('keydown', function (ev) { | |
60 … | + if(ev.keyCode === 27) cancel.click() //escape | |
61 … | + }) | |
62 … | + | |
63 … | + lb.show(h('MessageConfirm', [ | |
64 … | + h('header -preview_description', h('h1', 'Preview')), | |
65 … | + h('section -message_preview', api.message_render(msg)), | |
66 … | + h('section -actions', [okay, cancel]) | |
67 … | + ] | |
68 … | + )) | |
69 … | + | |
70 … | + okay.focus() | |
71 … | + } | |
72 … | +} | |
73 … | + |
modules_basic/message/confirm.mcss | ||
---|---|---|
@@ -1,0 +1,39 @@ | ||
1 … | +MessageConfirm { | |
2 … | + section { | |
3 … | + -preview_description { | |
4 … | + } | |
5 … | + | |
6 … | + -message_preview { | |
7 … | + background-color: white | |
8 … | + | |
9 … | + div { | |
10 … | + border: none | |
11 … | + | |
12 … | + header.author { | |
13 … | + div { | |
14 … | + section { | |
15 … | + -timestamp { | |
16 … | + display: none | |
17 … | + } | |
18 … | + } | |
19 … | + } | |
20 … | + } | |
21 … | + | |
22 … | + section.action { | |
23 … | + display: none | |
24 … | + } | |
25 … | + } | |
26 … | + } | |
27 … | + | |
28 … | + -actions { | |
29 … | + margin-top: 1rem | |
30 … | + display: flex | |
31 … | + justify-content: flex-end | |
32 … | + | |
33 … | + button { | |
34 … | + margin: 0 0 0 1rem | |
35 … | + } | |
36 … | + } | |
37 … | + } | |
38 … | +} | |
39 … | + |
modules_basic/emoji.js | ||
---|---|---|
@@ -1,0 +1,18 @@ | ||
1 … | +var emojis = require('emoji-named-characters') | |
2 … | +var emojiNames = Object.keys(emojis) | |
3 … | + | |
4 … | +exports.needs = { blob_url: 'first' } | |
5 … | +exports.gives = { emoji_names: true, emoji_url: true } | |
6 … | + | |
7 … | +exports.create = function (api) { | |
8 … | + return { | |
9 … | + emoji_names: function () { | |
10 … | + return emojiNames | |
11 … | + }, | |
12 … | + emoji_url: function (emoji) { | |
13 … | + return emoji in emojis && | |
14 … | + api.blob_url(emoji).replace(/\/blobs\/get/, '/img/emoji') + '.png' | |
15 … | + } | |
16 … | + } | |
17 … | +} | |
18 … | + |
modules_basic/index.test.js | ||
---|---|---|
@@ -1,0 +1,11 @@ | ||
1 … | +const test = require('tape') | |
2 … | +const combine = require('depject') | |
3 … | + | |
4 … | +const core = require('../modules_core') | |
5 … | +const basic = require('./') | |
6 … | + | |
7 … | +test('modules_basic has no outside deps', t => { | |
8 … | + t.ok(combine(basic, core)) | |
9 … | + t.end() | |
10 … | +}) | |
11 … | + |
modules_basic/names.js | ||
---|---|---|
@@ -1,179 +1,0 @@ | ||
1 | -var pull = require('pull-stream') | |
2 | -var many = require('pull-many') | |
3 | -var mfr = require('map-filter-reduce') | |
4 | - | |
5 | -function all(stream, cb) { | |
6 | - pull(stream, pull.collect(cb)) | |
7 | -} | |
8 | - | |
9 | -exports.needs = { | |
10 | - sbot_links2: 'first', | |
11 | - sbot_query: 'first' | |
12 | -} | |
13 | - | |
14 | -exports.gives = { | |
15 | - connection_status: true, | |
16 | - signifier: true, | |
17 | - signified: true, | |
18 | -} | |
19 | - | |
20 | -/* | |
21 | - filter(rel: ['mentions', prefix('@')]) | reduce(name: rel[1], value: count()) | |
22 | -*/ | |
23 | - | |
24 | -var filter = { | |
25 | - $filter: { | |
26 | - rel: ["mentions", {$prefix: "@"}] | |
27 | - } | |
28 | -} | |
29 | -var map = { | |
30 | - $map: { | |
31 | - name: ['rel', 1], | |
32 | - id: 'dest', | |
33 | - ts: 'ts', | |
34 | - } | |
35 | -} | |
36 | - | |
37 | -var reduce = { | |
38 | - $reduce: { | |
39 | - name: 'name', | |
40 | - id: 'id', | |
41 | - rank: {$count: true}, | |
42 | - ts: {$max: 'ts'} | |
43 | - } | |
44 | -} | |
45 | - | |
46 | -var filter2 = { | |
47 | - $filter: { | |
48 | - value: { | |
49 | - content: { | |
50 | - type: "about", | |
51 | - name: {"$prefix": ""}, | |
52 | - about: {"$prefix": ""} | |
53 | - } | |
54 | - } | |
55 | - } | |
56 | -} | |
57 | - | |
58 | -var map2 = { | |
59 | - $map: { | |
60 | - name: ["value", "content", "name"], | |
61 | - id: ['value', 'content', 'about'], | |
62 | - ts: "timestamp" | |
63 | - } | |
64 | -} | |
65 | - | |
66 | -//union with this query... | |
67 | - | |
68 | -var names = NAMES = [] | |
69 | -function update(name) { | |
70 | - var n = names.find(function (e) { | |
71 | - return e.id == name.id && e.name == e.name | |
72 | - }) | |
73 | - if(!n) { | |
74 | - name.rank = 1 | |
75 | - //this should be inserted at the right place... | |
76 | - names.push(name) | |
77 | - } | |
78 | - else | |
79 | - n.rank = n.rank += (name.rank || 1) | |
80 | -} | |
81 | - | |
82 | -var ready = false, waiting = [] | |
83 | - | |
84 | -var merge = { | |
85 | - $reduce: { | |
86 | - name: 'name', | |
87 | - id: 'id', | |
88 | - rank: {$sum: 'rank'}, | |
89 | - ts: {$max: 'ts'} | |
90 | - } | |
91 | -} | |
92 | - | |
93 | -function add_sigil(stream) { | |
94 | - return pull(stream, pull.map(function (e) { | |
95 | - if (e && e.id && e.name && e.id[0] !== e.name[0]) | |
96 | - e.name = e.id[0] + e.name | |
97 | - return e | |
98 | - }) | |
99 | - ) | |
100 | -} | |
101 | - | |
102 | -var queryNamedGitRepos = [ | |
103 | - {$filter: { | |
104 | - value: { | |
105 | - content: { | |
106 | - type: "git-repo", | |
107 | - name: {"$prefix": ""} | |
108 | - } | |
109 | - } | |
110 | - }}, | |
111 | - {$map: { | |
112 | - name: ["value", "content", "name"], | |
113 | - id: ['key'], | |
114 | - ts: "timestamp" | |
115 | - }}, | |
116 | - reduce | |
117 | -] | |
118 | -exports.create = function (api) { | |
119 | - | |
120 | - var exports = {} | |
121 | - exports.connection_status = function (err) { | |
122 | - if(!err) { | |
123 | - pull( | |
124 | - many([ | |
125 | - api.sbot_links2({query: [filter, map, reduce]}), | |
126 | - add_sigil(api.sbot_query({query: [filter2, map2, reduce]})), | |
127 | - add_sigil(api.sbot_query({query: queryNamedGitRepos})) | |
128 | - ]), | |
129 | - //reducing also ensures order by the lookup properties | |
130 | - //in this case: [name, id] | |
131 | - mfr.reduce(merge), | |
132 | - pull.collect(function (err, ary) { | |
133 | - if(!err) { | |
134 | - NAMES = names = ary | |
135 | - ready = true | |
136 | - while(waiting.length) waiting.shift()() | |
137 | - } | |
138 | - }) | |
139 | - ) | |
140 | - | |
141 | - pull(many([ | |
142 | - api.sbot_links2({query: [filter, map], old: false}), | |
143 | - add_sigil(api.sbot_query({query: [filter2, map2], old: false})), | |
144 | - add_sigil(api.sbot_query({query: queryNamedGitRepos, old: false})) | |
145 | - ]), | |
146 | - pull.drain(update)) | |
147 | - } | |
148 | - } | |
149 | - | |
150 | - function async(fn) { | |
151 | - return function (value, cb) { | |
152 | - function go () { cb(null, fn(value)) } | |
153 | - if(ready) go() | |
154 | - else waiting.push(go) | |
155 | - } | |
156 | - } | |
157 | - | |
158 | - function rank(ary) { | |
159 | - //sort by most used, or most recently used | |
160 | - return ary.sort(function (a, b) { return b.rank - a.rank || b.ts - a.ts }) | |
161 | - } | |
162 | - | |
163 | - //we are just iterating over the entire array. | |
164 | - //if this becomes a problem, maintain two arrays | |
165 | - //one of each sort order, but do not duplicate the objects. | |
166 | - //that should mean the space required is just 2x object references, | |
167 | - //not 2x objects, and we can use binary search to find matches. | |
168 | - | |
169 | - exports.signifier = async(function (id) { | |
170 | - return rank(names.filter(function (e) { return e.id == id})) | |
171 | - }) | |
172 | - | |
173 | - exports.signified = async(function (name) { | |
174 | - var rx = new RegExp('^'+name) | |
175 | - return rank(names.filter(function (e) { return rx.test(e.name) })) | |
176 | - }) | |
177 | - | |
178 | - return exports | |
179 | -} |
modules_basic/search-box.js | ||
---|---|---|
@@ -1,68 +1,0 @@ | ||
1 | -'use strict' | |
2 | -var cont = require('cont') | |
3 | -var h = require('hyperscript') | |
4 | -var suggest = require('suggest-box') | |
5 | - | |
6 | -exports.needs = { | |
7 | - sbot_query: 'first', sbot_links2: 'first', | |
8 | - suggest_search: 'map' //REWRITE | |
9 | -} | |
10 | - | |
11 | -exports.gives = 'search_box' | |
12 | - | |
13 | -exports.create = function (api) { | |
14 | - | |
15 | - return function (go) { | |
16 | - | |
17 | - var suggestBox | |
18 | - var search = h('input.searchprompt', { | |
19 | - type: 'search', | |
20 | - placeholder: 'Commands', | |
21 | - onkeydown: function (ev) { | |
22 | - switch (ev.keyCode) { | |
23 | - case 13: // enter | |
24 | - if (suggestBox && suggestBox.active) { | |
25 | - suggestBox.complete() | |
26 | - ev.stopPropagation() | |
27 | - } | |
28 | - if (go(search.value.trim(), !ev.ctrlKey)) | |
29 | - search.blur() | |
30 | - return | |
31 | - case 27: // escape | |
32 | - ev.preventDefault() | |
33 | - search.blur() | |
34 | - return | |
35 | - } | |
36 | - } | |
37 | - }) | |
38 | - | |
39 | - search.activate = function (sigil, ev) { | |
40 | - search.focus() | |
41 | - ev.preventDefault() | |
42 | - if (search.value[0] === sigil) { | |
43 | - search.selectionStart = 1 | |
44 | - search.selectionEnd = search.value.length | |
45 | - } else { | |
46 | - search.value = sigil | |
47 | - } | |
48 | - } | |
49 | - | |
50 | - // delay until the element has a parent | |
51 | - setTimeout(function () { | |
52 | - suggestBox = suggest(search, function (word, cb) { | |
53 | - cont.para(api.suggest_search(word)) | |
54 | - (function (err, ary) { | |
55 | - if(err) return cb(err) | |
56 | - | |
57 | - cb(null, ary.filter(Boolean).reduce(function (a, b) { | |
58 | - return a.concat(b) | |
59 | - }, [])) | |
60 | - }) | |
61 | - }, {}) | |
62 | - }, 10) | |
63 | - | |
64 | - return search | |
65 | - } | |
66 | - | |
67 | -} | |
68 | - |
modules_basic/suggest-mentions.js | ||
---|---|---|
@@ -1,63 +1,0 @@ | ||
1 | - | |
2 | -exports.needs = { | |
3 | - sbot_links2: 'first', | |
4 | - blob_url: 'first', | |
5 | - signified: 'first', | |
6 | - builtin_tabs: 'map' | |
7 | -} | |
8 | - | |
9 | -exports.gives = { | |
10 | - suggest_mentions: true, | |
11 | - suggest_search: true | |
12 | -} | |
13 | - | |
14 | -exports.create = function (api) { | |
15 | - | |
16 | - return { | |
17 | - suggest_mentions: function (word) { | |
18 | - return function (cb) { | |
19 | - if(!/^[%&@]\w/.test(word)) return cb() | |
20 | - | |
21 | - api.signified(word, function (err, names) { | |
22 | - if(err) cb(err) | |
23 | - else cb(null, names.map(function (e) { | |
24 | - return { | |
25 | - title: e.name + ': ' + e.id.substring(0,10)+' ('+e.rank+')', | |
26 | - value: '['+e.name+']('+e.id+')', | |
27 | - rank: e.rank, | |
28 | - //TODO: avatar images... | |
29 | - } | |
30 | - })) | |
31 | - }) | |
32 | - } | |
33 | - }, | |
34 | - | |
35 | - suggest_search: function (query) { | |
36 | - return function (cb) { | |
37 | - if(/^[@%]\w/.test(query)) { | |
38 | - api.signified(query, function (_, names) { | |
39 | - cb(null, names.map(function (e) { | |
40 | - return { | |
41 | - title: e.name + ':'+e.id.substring(0, 10), | |
42 | - value: e.id, | |
43 | - subtitle: e.rank, | |
44 | - rank: e.rank | |
45 | - } | |
46 | - })) | |
47 | - }) | |
48 | - | |
49 | - } else if(/^\//.test(query)) { | |
50 | - var tabs = [].concat.apply([], api.builtin_tabs()) | |
51 | - cb(null, tabs.filter(function (name) { | |
52 | - return name.substr(0, query.length) === query | |
53 | - }).map(function (name) { | |
54 | - return { | |
55 | - title: name, | |
56 | - value: name, | |
57 | - } | |
58 | - })) | |
59 | - } else cb() | |
60 | - } | |
61 | - } | |
62 | - } | |
63 | -} |
modules_core/index.js | ||
---|---|---|
@@ -4,15 +4,15 @@ | ||
4 | 4 … | 'crypto': require('./crypto'), |
5 | 5 … | 'external-confirm': require('./external-confirm'), |
6 | 6 … | 'file-input': require('./file-input'), |
7 | 7 … | 'menu': require('./menu'), |
8 | - 'message': { | |
9 | - 'confirm': require('./message/confirm') | |
10 | - }, | |
11 | - 'tabs': require('./tabs'), | |
12 | - 'sbot': require('./sbot'), | |
8 … | + 'names': require('./names'), | |
9 … | + 'tabs': require('./tabs'), | |
10 … | + 'sbot': require('./sbot'), | |
11 … | + 'search-box': require('./search-box'), | |
13 | 12 … | 'style': { |
14 | 13 … | 'styles': require('./style/styles'), |
15 | 14 … | 'mixins': require('./style/mixins') |
16 | - } | |
15 … | + }, | |
16 … | + 'suggest-mentions': require('./suggest-mentions') | |
17 | 17 … | } |
18 | 18 … |
modules_core/menu.js | ||
---|---|---|
@@ -1,23 +1,28 @@ | ||
1 | -var h = require('hyperscript') | |
1 … | +const h = require('hyperscript') | |
2 | 2 … | |
3 | 3 … | module.exports = { |
4 | - needs: {menu_items: 'map'}, | |
5 | - gives: {connection_status: true, menu: true}, | |
4 … | + needs: { | |
5 … | + menu_items: 'map' | |
6 … | + }, | |
7 … | + gives: { | |
8 … | + connection_status: true, | |
9 … | + menu: true, | |
10 … | + menu_items: true | |
11 … | + }, | |
6 | 12 … | create: function (api) { |
13 … | + const { menu_items } = api | |
7 | 14 … | |
8 | - var menu_items = api.menu_items | |
9 | - | |
10 | 15 … | var status = h('div.status.error') //start off disconnected |
11 | 16 … | var list = h('div.menu.column', {style: 'display: none;'}) |
12 | 17 … | |
13 | - var menu = h('div.column', status, list , { | |
14 | - onmouseover: function (e) { | |
15 | - list.style.display = 'flex' | |
16 | - }, onmouseout: function () { | |
17 | - list.style.display = 'none' | |
18 | - } | |
19 | - }) | |
18 … | + var menu = h('div.column', { | |
19 … | + onmouseover: () => list.style.display = 'flex', | |
20 … | + onmouseout: () => list.style.display = 'none' | |
21 … | + }, [ | |
22 … | + status, | |
23 … | + list | |
24 … | + ]) | |
20 | 25 … | |
21 | 26 … | setTimeout(function () { |
22 | 27 … | menu_items().forEach(function (el) { |
23 | 28 … | if(el) |
@@ -25,15 +30,14 @@ | ||
25 | 30 … | }) |
26 | 31 … | }, 0) |
27 | 32 … | |
28 | 33 … | return { |
29 | - connection_status: function (err) { | |
34 … | + connection_status: (err) => { | |
30 | 35 … | if(err) status.classList.add('error') |
31 | 36 … | else status.classList.remove('error') |
32 | 37 … | }, |
33 | - menu: function () { | |
34 | - return menu | |
35 | - } | |
38 … | + menu: () => menu, | |
39 … | + menu_items: () => null | |
36 | 40 … | } |
37 | 41 … | } |
38 | 42 … | } |
39 | 43 … |
modules_core/sbot.js | ||
---|---|---|
@@ -59,8 +59,14 @@ | ||
59 | 59 … | var opts = createConfig() |
60 | 60 … | var sbot = null |
61 | 61 … | var connection_status = [] |
62 | 62 … | |
63 … | + var rec = { | |
64 … | + sync: () => {}, | |
65 … | + async: () => {}, | |
66 … | + source: () => {}, | |
67 … | + } | |
68 … | + | |
63 | 69 … | var rec = Reconnect(function (isConn) { |
64 | 70 … | function notify (value) { |
65 | 71 … | isConn(value); api.connection_status(value) //.forEach(function (fn) { fn(value) }) |
66 | 72 … | } |
modules_core/index.test.js | ||
---|---|---|
@@ -1,0 +1,10 @@ | ||
1 … | +const test = require('tape') | |
2 … | +const combine = require('depject') | |
3 … | + | |
4 … | +const core = require('./') | |
5 … | + | |
6 … | +test('modules_core has no outside deps', t => { | |
7 … | + t.ok(combine(core)) | |
8 … | + t.end() | |
9 … | +}) | |
10 … | + |
modules_core/message/confirm.js | ||
---|---|---|
@@ -1,73 +1,0 @@ | ||
1 | -var fs = require('fs') | |
2 | -var lightbox = require('hyperlightbox') | |
3 | -var h = require('../../h') | |
4 | -var self_id = require('../../keys').id | |
5 | -//publish or add | |
6 | - | |
7 | -exports.needs = { | |
8 | - publish: 'first', | |
9 | - message_render: 'first', | |
10 | - avatar: 'first', | |
11 | - message_meta: 'map' | |
12 | -} | |
13 | - | |
14 | -exports.gives = { | |
15 | - message_confirm: true, | |
16 | - mcss: true | |
17 | -} | |
18 | - | |
19 | -exports.create = function (api) { | |
20 | - return { | |
21 | - message_confirm, | |
22 | - mcss: () => fs.readFileSync(__filename.replace(/js$/, 'mcss'), 'utf8') | |
23 | - } | |
24 | - | |
25 | - function message_confirm (content, cb) { | |
26 | - | |
27 | - cb = cb || function () {} | |
28 | - | |
29 | - var lb = lightbox() | |
30 | - document.body.appendChild(lb) | |
31 | - | |
32 | - var msg = { | |
33 | - key: "DRAFT", | |
34 | - value: { | |
35 | - author: self_id, | |
36 | - previous: null, | |
37 | - sequence: null, | |
38 | - timestamp: Date.now(), | |
39 | - content: content | |
40 | - } | |
41 | - } | |
42 | - | |
43 | - var okay = h('button', { | |
44 | - 'ev-click': () => { | |
45 | - lb.remove() | |
46 | - api.publish(content, cb) | |
47 | - }}, | |
48 | - 'okay' | |
49 | - ) | |
50 | - | |
51 | - var cancel = h('button', { | |
52 | - 'ev-click': () => { | |
53 | - lb.remove() | |
54 | - cb(null) | |
55 | - }}, | |
56 | - 'Cancel' | |
57 | - ) | |
58 | - | |
59 | - okay.addEventListener('keydown', function (ev) { | |
60 | - if(ev.keyCode === 27) cancel.click() //escape | |
61 | - }) | |
62 | - | |
63 | - lb.show(h('MessageConfirm', [ | |
64 | - h('header -preview_description', h('h1', 'Preview')), | |
65 | - h('section -message_preview', api.message_render(msg)), | |
66 | - h('section -actions', [okay, cancel]) | |
67 | - ] | |
68 | - )) | |
69 | - | |
70 | - okay.focus() | |
71 | - } | |
72 | -} | |
73 | - |
modules_core/message/confirm.mcss | ||
---|---|---|
@@ -1,39 +1,0 @@ | ||
1 | -MessageConfirm { | |
2 | - section { | |
3 | - -preview_description { | |
4 | - } | |
5 | - | |
6 | - -message_preview { | |
7 | - background-color: white | |
8 | - | |
9 | - div { | |
10 | - border: none | |
11 | - | |
12 | - header.author { | |
13 | - div { | |
14 | - section { | |
15 | - -timestamp { | |
16 | - display: none | |
17 | - } | |
18 | - } | |
19 | - } | |
20 | - } | |
21 | - | |
22 | - section.action { | |
23 | - display: none | |
24 | - } | |
25 | - } | |
26 | - } | |
27 | - | |
28 | - -actions { | |
29 | - margin-top: 1rem | |
30 | - display: flex | |
31 | - justify-content: flex-end | |
32 | - | |
33 | - button { | |
34 | - margin: 0 0 0 1rem | |
35 | - } | |
36 | - } | |
37 | - } | |
38 | -} | |
39 | - |
modules_core/names.js | ||
---|---|---|
@@ -1,0 +1,179 @@ | ||
1 … | +var pull = require('pull-stream') | |
2 … | +var many = require('pull-many') | |
3 … | +var mfr = require('map-filter-reduce') | |
4 … | + | |
5 … | +function all(stream, cb) { | |
6 … | + pull(stream, pull.collect(cb)) | |
7 … | +} | |
8 … | + | |
9 … | +exports.needs = { | |
10 … | + sbot_links2: 'first', | |
11 … | + sbot_query: 'first' | |
12 … | +} | |
13 … | + | |
14 … | +exports.gives = { | |
15 … | + connection_status: true, | |
16 … | + signifier: true, | |
17 … | + signified: true, | |
18 … | +} | |
19 … | + | |
20 … | +/* | |
21 … | + filter(rel: ['mentions', prefix('@')]) | reduce(name: rel[1], value: count()) | |
22 … | +*/ | |
23 … | + | |
24 … | +var filter = { | |
25 … | + $filter: { | |
26 … | + rel: ["mentions", {$prefix: "@"}] | |
27 … | + } | |
28 … | +} | |
29 … | +var map = { | |
30 … | + $map: { | |
31 … | + name: ['rel', 1], | |
32 … | + id: 'dest', | |
33 … | + ts: 'ts', | |
34 … | + } | |
35 … | +} | |
36 … | + | |
37 … | +var reduce = { | |
38 … | + $reduce: { | |
39 … | + name: 'name', | |
40 … | + id: 'id', | |
41 … | + rank: {$count: true}, | |
42 … | + ts: {$max: 'ts'} | |
43 … | + } | |
44 … | +} | |
45 … | + | |
46 … | +var filter2 = { | |
47 … | + $filter: { | |
48 … | + value: { | |
49 … | + content: { | |
50 … | + type: "about", | |
51 … | + name: {"$prefix": ""}, | |
52 … | + about: {"$prefix": ""} | |
53 … | + } | |
54 … | + } | |
55 … | + } | |
56 … | +} | |
57 … | + | |
58 … | +var map2 = { | |
59 … | + $map: { | |
60 … | + name: ["value", "content", "name"], | |
61 … | + id: ['value', 'content', 'about'], | |
62 … | + ts: "timestamp" | |
63 … | + } | |
64 … | +} | |
65 … | + | |
66 … | +//union with this query... | |
67 … | + | |
68 … | +var names = NAMES = [] | |
69 … | +function update(name) { | |
70 … | + var n = names.find(function (e) { | |
71 … | + return e.id == name.id && e.name == e.name | |
72 … | + }) | |
73 … | + if(!n) { | |
74 … | + name.rank = 1 | |
75 … | + //this should be inserted at the right place... | |
76 … | + names.push(name) | |
77 … | + } | |
78 … | + else | |
79 … | + n.rank = n.rank += (name.rank || 1) | |
80 … | +} | |
81 … | + | |
82 … | +var ready = false, waiting = [] | |
83 … | + | |
84 … | +var merge = { | |
85 … | + $reduce: { | |
86 … | + name: 'name', | |
87 … | + id: 'id', | |
88 … | + rank: {$sum: 'rank'}, | |
89 … | + ts: {$max: 'ts'} | |
90 … | + } | |
91 … | +} | |
92 … | + | |
93 … | +function add_sigil(stream) { | |
94 … | + return pull(stream, pull.map(function (e) { | |
95 … | + if (e && e.id && e.name && e.id[0] !== e.name[0]) | |
96 … | + e.name = e.id[0] + e.name | |
97 … | + return e | |
98 … | + }) | |
99 … | + ) | |
100 … | +} | |
101 … | + | |
102 … | +var queryNamedGitRepos = [ | |
103 … | + {$filter: { | |
104 … | + value: { | |
105 … | + content: { | |
106 … | + type: "git-repo", | |
107 … | + name: {"$prefix": ""} | |
108 … | + } | |
109 … | + } | |
110 … | + }}, | |
111 … | + {$map: { | |
112 … | + name: ["value", "content", "name"], | |
113 … | + id: ['key'], | |
114 … | + ts: "timestamp" | |
115 … | + }}, | |
116 … | + reduce | |
117 … | +] | |
118 … | +exports.create = function (api) { | |
119 … | + | |
120 … | + var exports = {} | |
121 … | + exports.connection_status = function (err) { | |
122 … | + if(!err) { | |
123 … | + pull( | |
124 … | + many([ | |
125 … | + api.sbot_links2({query: [filter, map, reduce]}), | |
126 … | + add_sigil(api.sbot_query({query: [filter2, map2, reduce]})), | |
127 … | + add_sigil(api.sbot_query({query: queryNamedGitRepos})) | |
128 … | + ]), | |
129 … | + //reducing also ensures order by the lookup properties | |
130 … | + //in this case: [name, id] | |
131 … | + mfr.reduce(merge), | |
132 … | + pull.collect(function (err, ary) { | |
133 … | + if(!err) { | |
134 … | + NAMES = names = ary | |
135 … | + ready = true | |
136 … | + while(waiting.length) waiting.shift()() | |
137 … | + } | |
138 … | + }) | |
139 … | + ) | |
140 … | + | |
141 … | + pull(many([ | |
142 … | + api.sbot_links2({query: [filter, map], old: false}), | |
143 … | + add_sigil(api.sbot_query({query: [filter2, map2], old: false})), | |
144 … | + add_sigil(api.sbot_query({query: queryNamedGitRepos, old: false})) | |
145 … | + ]), | |
146 … | + pull.drain(update)) | |
147 … | + } | |
148 … | + } | |
149 … | + | |
150 … | + function async(fn) { | |
151 … | + return function (value, cb) { | |
152 … | + function go () { cb(null, fn(value)) } | |
153 … | + if(ready) go() | |
154 … | + else waiting.push(go) | |
155 … | + } | |
156 … | + } | |
157 … | + | |
158 … | + function rank(ary) { | |
159 … | + //sort by most used, or most recently used | |
160 … | + return ary.sort(function (a, b) { return b.rank - a.rank || b.ts - a.ts }) | |
161 … | + } | |
162 … | + | |
163 … | + //we are just iterating over the entire array. | |
164 … | + //if this becomes a problem, maintain two arrays | |
165 … | + //one of each sort order, but do not duplicate the objects. | |
166 … | + //that should mean the space required is just 2x object references, | |
167 … | + //not 2x objects, and we can use binary search to find matches. | |
168 … | + | |
169 … | + exports.signifier = async(function (id) { | |
170 … | + return rank(names.filter(function (e) { return e.id == id})) | |
171 … | + }) | |
172 … | + | |
173 … | + exports.signified = async(function (name) { | |
174 … | + var rx = new RegExp('^'+name) | |
175 … | + return rank(names.filter(function (e) { return rx.test(e.name) })) | |
176 … | + }) | |
177 … | + | |
178 … | + return exports | |
179 … | +} |
modules_core/search-box.js | ||
---|---|---|
@@ -1,0 +1,68 @@ | ||
1 … | +'use strict' | |
2 … | +var cont = require('cont') | |
3 … | +var h = require('hyperscript') | |
4 … | +var suggest = require('suggest-box') | |
5 … | + | |
6 … | +exports.needs = { | |
7 … | + sbot_query: 'first', sbot_links2: 'first', | |
8 … | + suggest_search: 'map' //REWRITE | |
9 … | +} | |
10 … | + | |
11 … | +exports.gives = 'search_box' | |
12 … | + | |
13 … | +exports.create = function (api) { | |
14 … | + | |
15 … | + return function (go) { | |
16 … | + | |
17 … | + var suggestBox | |
18 … | + var search = h('input.searchprompt', { | |
19 … | + type: 'search', | |
20 … | + placeholder: 'Commands', | |
21 … | + onkeydown: function (ev) { | |
22 … | + switch (ev.keyCode) { | |
23 … | + case 13: // enter | |
24 … | + if (suggestBox && suggestBox.active) { | |
25 … | + suggestBox.complete() | |
26 … | + ev.stopPropagation() | |
27 … | + } | |
28 … | + if (go(search.value.trim(), !ev.ctrlKey)) | |
29 … | + search.blur() | |
30 … | + return | |
31 … | + case 27: // escape | |
32 … | + ev.preventDefault() | |
33 … | + search.blur() | |
34 … | + return | |
35 … | + } | |
36 … | + } | |
37 … | + }) | |
38 … | + | |
39 … | + search.activate = function (sigil, ev) { | |
40 … | + search.focus() | |
41 … | + ev.preventDefault() | |
42 … | + if (search.value[0] === sigil) { | |
43 … | + search.selectionStart = 1 | |
44 … | + search.selectionEnd = search.value.length | |
45 … | + } else { | |
46 … | + search.value = sigil | |
47 … | + } | |
48 … | + } | |
49 … | + | |
50 … | + // delay until the element has a parent | |
51 … | + setTimeout(function () { | |
52 … | + suggestBox = suggest(search, function (word, cb) { | |
53 … | + cont.para(api.suggest_search(word)) | |
54 … | + (function (err, ary) { | |
55 … | + if(err) return cb(err) | |
56 … | + | |
57 … | + cb(null, ary.filter(Boolean).reduce(function (a, b) { | |
58 … | + return a.concat(b) | |
59 … | + }, [])) | |
60 … | + }) | |
61 … | + }, {}) | |
62 … | + }, 10) | |
63 … | + | |
64 … | + return search | |
65 … | + } | |
66 … | + | |
67 … | +} | |
68 … | + |
modules_core/suggest-mentions.js | ||
---|---|---|
@@ -1,0 +1,68 @@ | ||
1 … | + | |
2 … | +exports.needs = { | |
3 … | + sbot_links2: 'first', | |
4 … | + blob_url: 'first', | |
5 … | + signified: 'first', | |
6 … | + builtin_tabs: 'map' | |
7 … | +} | |
8 … | + | |
9 … | +exports.gives = { | |
10 … | + suggest_mentions: true, | |
11 … | + suggest_search: true, | |
12 … | + builtin_tabs: true | |
13 … | +} | |
14 … | + | |
15 … | +exports.create = function (api) { | |
16 … | + | |
17 … | + return { | |
18 … | + suggest_mentions, | |
19 … | + suggest_search, | |
20 … | + builtin_tabs: () => null | |
21 … | + } | |
22 … | + | |
23 … | + function suggest_mentions (word) { | |
24 … | + return function (cb) { | |
25 … | + if(!/^[%&@]\w/.test(word)) return cb() | |
26 … | + | |
27 … | + api.signified(word, function (err, names) { | |
28 … | + if(err) cb(err) | |
29 … | + else cb(null, names.map(function (e) { | |
30 … | + return { | |
31 … | + title: e.name + ': ' + e.id.substring(0,10)+' ('+e.rank+')', | |
32 … | + value: '['+e.name+']('+e.id+')', | |
33 … | + rank: e.rank, | |
34 … | + //TODO: avatar images... | |
35 … | + } | |
36 … | + })) | |
37 … | + }) | |
38 … | + } | |
39 … | + } | |
40 … | + | |
41 … | + function suggest_search (query) { | |
42 … | + return function (cb) { | |
43 … | + if(/^[@%]\w/.test(query)) { | |
44 … | + api.signified(query, function (_, names) { | |
45 … | + cb(null, names.map(function (e) { | |
46 … | + return { | |
47 … | + title: e.name + ':'+e.id.substring(0, 10), | |
48 … | + value: e.id, | |
49 … | + subtitle: e.rank, | |
50 … | + rank: e.rank | |
51 … | + } | |
52 … | + })) | |
53 … | + }) | |
54 … | + | |
55 … | + } else if(/^\//.test(query)) { | |
56 … | + var tabs = [].concat.apply([], api.builtin_tabs()) | |
57 … | + cb(null, tabs.filter(function (name) { | |
58 … | + return name.substr(0, query.length) === query | |
59 … | + }).map(function (name) { | |
60 … | + return { | |
61 … | + title: name, | |
62 … | + value: name, | |
63 … | + } | |
64 … | + })) | |
65 … | + } else cb() | |
66 … | + } | |
67 … | + } | |
68 … | +} |
modules_extra/index.js | ||
---|---|---|
@@ -1,9 +1,8 @@ | ||
1 | 1 … | module.exports = { |
2 | 2 … | // 'audio-mp3': require('./audio-mp3'), |
3 | 3 … | 'blob': require('./blob'), |
4 | 4 … | 'channel': require('./channel'), |
5 | - 'emoji': require('./emoji'), | |
6 | 5 … | 'suggest-emoji': require('./suggest-emoji'), |
7 | 6 … | 'dns': require('./dns'), |
8 | 7 … | 'git': require('./git'), |
9 | 8 … | 'git-ssb': require('./git-ssb'), |
modules_extra/emoji.js | ||
---|---|---|
@@ -1,18 +1,0 @@ | ||
1 | -var emojis = require('emoji-named-characters') | |
2 | -var emojiNames = Object.keys(emojis) | |
3 | - | |
4 | -exports.needs = { blob_url: 'first' } | |
5 | -exports.gives = { emoji_names: true, emoji_url: true } | |
6 | - | |
7 | -exports.create = function (api) { | |
8 | - return { | |
9 | - emoji_names: function () { | |
10 | - return emojiNames | |
11 | - }, | |
12 | - emoji_url: function (emoji) { | |
13 | - return emoji in emojis && | |
14 | - api.blob_url(emoji).replace(/\/blobs\/get/, '/img/emoji') + '.png' | |
15 | - } | |
16 | - } | |
17 | -} | |
18 | - |
modules_extra/index.test.js | ||
---|---|---|
@@ -1,0 +1,20 @@ | ||
1 … | +const test = require('tape') | |
2 … | +const jsdom = require('jsdom') | |
3 … | +const combine = require('depject') | |
4 … | + | |
5 … | +var window = {} | |
6 … | + | |
7 … | +const core = require('../modules_core') | |
8 … | +const basic = require('../modules_basic') | |
9 … | +const extra = require('./') | |
10 … | + | |
11 … | +// jsdom.env('<body></body>', (err, window) => { | |
12 … | + | |
13 … | + test('modules_extra has no outside deps', t => { | |
14 … | + t.ok(combine(extra, basic, core)) | |
15 … | + t.end() | |
16 … | + // window.close() | |
17 … | + }) | |
18 … | +// }) | |
19 … | + | |
20 … | + |
package.json | ||
---|---|---|
@@ -6,14 +6,22 @@ | ||
6 | 6 … | "repository": { |
7 | 7 … | "type": "git", |
8 | 8 … | "url": "git://github.com/dominictarr/patchbay.git" |
9 | 9 … | }, |
10 … | + "scripts": { | |
11 … | + "lite": "mkdir -p build && browserify index.js | indexhtmlify --title patchbay > build/index.html", | |
12 … | + "start": "electro index.js", | |
13 … | + "bundle": "mkdir -p build && browselectrify index.js > build/bundle.js", | |
14 … | + "rebuild": "npm rebuild --runtime=electron --target=$(electron -v) --abi=$(electron --abi) --disturl=https://atom.io/download/atom-shell", | |
15 … | + "graph": "node index.js | dot -Tsvg > graph.svg", | |
16 … | + "test": "browserify modules_*/index.test.js | tape-run" | |
17 … | + }, | |
10 | 18 … | "dependencies": { |
11 | 19 … | "@mmckegg/mutant": "^3.12.0", |
12 | 20 … | "brfs": "^1.4.3", |
13 | 21 … | "cont": "^1.0.3", |
14 | 22 … | "dataurl-": "^0.1.0", |
15 | - "depject": "^3.1.0", | |
23 … | + "depject": "^3.1.4", | |
16 | 24 … | "es2040": "^1.2.4", |
17 | 25 … | "hjson": "^2.0.3", |
18 | 26 … | "human-time": "0.0.1", |
19 | 27 … | "hypercombo": "0.1.0", |
@@ -64,23 +72,17 @@ | ||
64 | 72 … | "devDependencies": { |
65 | 73 … | "browselectrify": "^1.0.1", |
66 | 74 … | "electro": "^2.0.3", |
67 | 75 … | "electron": "^1.4.10", |
68 | - "indexhtmlify": "^1.3.1" | |
76 … | + "indexhtmlify": "^1.3.1", | |
77 … | + "tape": "^4.6.3", | |
78 … | + "tape-run": "^2.1.5" | |
69 | 79 … | }, |
70 | 80 … | "browserify": { |
71 | 81 … | "transform": [ |
72 | 82 … | "brfs", |
73 | 83 … | "es2040" |
74 | 84 … | ] |
75 | 85 … | }, |
76 | - "scripts": { | |
77 | - "lite": "mkdir -p build && browserify index.js | indexhtmlify --title patchbay > build/index.html", | |
78 | - "start": "electro index.js", | |
79 | - "bundle": "mkdir -p build && browselectrify index.js > build/bundle.js", | |
80 | - "rebuild": "npm rebuild --runtime=electron --target=$(electron -v) --abi=$(electron --abi) --disturl=https://atom.io/download/atom-shell", | |
81 | - "graph": "node index.js | dot -Tsvg > graph.svg", | |
82 | - "test": "set -e; for t in test/*.js; do node $t; done" | |
83 | - }, | |
84 | 86 … | "author": "Dominic Tarr <dominic.tarr@gmail.com> (http://dominictarr.com)", |
85 | 87 … | "license": "MIT" |
86 | 88 … | } |
Built with git-ssb-web