git ssb

16+

Dominic / patchbay



Commit 8cf292c13507a00dd6f025dfa662409737ba7dea

rewrite using depject/v2

Dominic Tarr committed on 12/3/2016, 6:00:37 PM
Parent: 86745d2ae3eb9733681d16c4e9cfabeeef30b588

Files changed

basic.jschanged
modules_basic/about.jschanged
modules_basic/avatar-edit.jschanged
modules_basic/avatar-image.jschanged
modules_basic/avatar-link.jschanged
modules_basic/avatar-name.jschanged
modules_basic/avatar-profile.jschanged
modules_basic/avatar.jschanged
modules_basic/compose.jschanged
modules_basic/feed.jschanged
modules_basic/follow.jschanged
modules_basic/index.jschanged
modules_basic/invite.jschanged
modules_basic/like.jschanged
modules_basic/markdown.jschanged
modules_basic/message-link.jschanged
modules_basic/message-name.jschanged
modules_basic/message.jschanged
modules_basic/names.jschanged
modules_basic/post.jschanged
modules_basic/private.jschanged
modules_basic/pub.jschanged
modules_basic/public.jschanged
modules_basic/relationships.jschanged
modules_basic/search-box.jschanged
modules_basic/setup.jschanged
modules_basic/suggest-mentions.jschanged
modules_basic/thread.jschanged
modules_basic/timestamp.jschanged
modules_basic/suggest.jsdeleted
modules_core/app.jschanged
modules_core/blob-url.jschanged
modules_core/crypto.jschanged
modules_core/file-input.jschanged
modules_core/index.jschanged
modules_core/menu.jschanged
modules_core/message-confirm.jschanged
modules_core/sbot.jschanged
modules_core/tabs.jschanged
basic.jsView
@@ -1,6 +1,6 @@
11 require('depject')(
22 require('./modules_core'),
33 require('./modules_basic')
4-).plugs.app[0]()
4 +).app[0]()
55
66
modules_basic/about.jsView
@@ -8,33 +8,41 @@
88 function asLink (ln) {
99 return 'string' === typeof ln ? ln : ln.link
1010 }
1111
12-var blob_url = require('../plugs').first(exports.blob_url = [])
12 +//var blob_url = require('../plugs').first(exports.blob_url = [])
1313
14-exports.message_content = function (msg) {
15- if(msg.value.content.type !== 'about') return
14 +exports.needs = {
15 + blob_url: 'first'
16 +}
1617
17- if(!msg.value.content.image && !msg.value.content.name)
18- return
18 +exports.gives = 'message_content'
1919
20- var about = msg.value.content
21- var id = msg.value.content.about
22- return h('p',
23- about.about === msg.value.author
24- ? h('span', 'self-identifies ')
25- : h('span', 'identifies ', idLink(id)),
26- ' as ',
27- h('a', {href:"#"+about.about},
28- about.name || null,
29- about.image
30- ? h('img.avatar--fullsize', {src: blob_url(about.image)})
31- : null
20 +exports.create = function (api) {
21 +
22 + return function (msg) {
23 + if(msg.value.content.type !== 'about') return
24 +
25 + if(!msg.value.content.image && !msg.value.content.name)
26 + return
27 +
28 + var about = msg.value.content
29 + var id = msg.value.content.about
30 + return h('p',
31 + about.about === msg.value.author
32 + ? h('span', 'self-identifies ')
33 + : h('span', 'identifies ', idLink(id)),
34 + ' as ',
35 + h('a', {href:"#"+about.about},
36 + about.name || null,
37 + about.image
38 + ? h('img.avatar--fullsize', {src: api.blob_url(about.image)})
39 + : null
40 + )
3241 )
33- )
3442
43 + }
44 +
3545 }
3646
3747
3848
39-
40-
modules_basic/avatar-edit.jsView
@@ -1,4 +1,5 @@
1 +'use strict'
12 var dataurl = require('dataurl-')
23 var hyperfile = require('hyperfile')
34 var hypercrop = require('hypercrop')
45 var hyperlightbox = require('hyperlightbox')
@@ -9,13 +10,14 @@
910 var ref = require('ssb-ref')
1011 var visualize = require('visualize-buffer')
1112 var self_id = require('../keys').id
1213
13-var confirm = plugs.first(exports.message_confirm = [])
14-var sbot_blobs_add = plugs.first(exports.sbot_blobs_add = [])
15-var blob_url = plugs.first(exports.blob_url = [])
16-var sbot_links = plugs.first(exports.sbot_links = [])
17-var avatar_name = plugs.first(exports.avatar_name = [])
14 +//var confirm = plugs.first(exports.message_confirm = [])
15 +//var sbot_blobs_add = plugs.first(exports.sbot_blobs_add = [])
16 +//var blob_url = plugs.first(exports.blob_url = [])
17 +//var sbot_links = plugs.first(exports.sbot_links = [])
18 +//var avatar_name = plugs.first(exports.avatar_name = [])
19 +//
1820
1921 function crop (d, cb) {
2022 var data
2123 var canvas = hypercrop(h('img', {src: d}))
@@ -33,109 +35,118 @@
3335 )
3436 )
3537 }
3638
37-exports.avatar_edit = function (id) {
39 +exports.needs = {
40 + message_confirm: 'first',
41 + sbot_blobs_add: 'first',
42 + blob_url: 'first',
43 + sbot_links: 'first',
44 + avatar_name: 'first'
45 +}
3846
39- var img = visualize(new Buffer(id.substring(1), 'base64'), 256)
40- img.classList.add('avatar--large')
47 +exports.gives = 'avatar_edit'
4148
42- var lb = hyperlightbox()
43- var name_input = h('input', {placeholder: 'rename'})
44- var name = avatar_name(id)
45- var selected = null, selected_data = null
49 +exports.create = function (api) {
50 + return function (id) {
4651
47- getAvatar({links: sbot_links}, self_id, id, function (err, avatar) {
48- if (err) return console.error(err)
49- //don't show user has already selected an avatar.
50- if(selected) return
51- if(ref.isBlob(avatar.image))
52- img.src = blob_url(avatar.image)
53- })
52 + var img = visualize(new Buffer(id.substring(1), 'base64'), 256)
53 + img.classList.add('avatar--large')
5454
55- var also_pictured = h('div.profile__alsopicturedas.wrap')
55 + var lb = hyperlightbox()
56 + var name_input = h('input', {placeholder: 'rename'})
57 + var name = api.avatar_name(id)
58 + var selected = null, selected_data = null
5659
57- pull(
58- sbot_links({dest: id, rel: 'about', values: true}),
59- pull.map(function (e) {
60- return e.value.content.image
61- }),
62- pull.filter(function (e) {
63- return e && 'string' == typeof e.link
64- }),
65- pull.unique('link'),
66- pull.drain(function (image) {
67- also_pictured.appendChild(
68- h('a', {href:'#', onclick: function (ev) {
69- ev.stopPropagation()
70- ev.preventDefault()
71- selected = image
72- img.src = blob_url(image.link || image)
73- }},
74- h('img.avatar--thumbnail', {src: blob_url(image)})
75- )
76- )
60 + getAvatar({links: api.sbot_links}, self_id, id, function (err, avatar) {
61 + if (err) return console.error(err)
62 + //don't show user has already selected an avatar.
63 + if(selected) return
64 + if(ref.isBlob(avatar.image))
65 + img.src = api.blob_url(avatar.image)
7766 })
78- )
7967
80- return h('div.row.profile',
81- lb,
82- img,
83- h('div.column.profile__info',
84- h('strong', name),
85- name_input,
68 + var also_pictured = h('div.profile__alsopicturedas.wrap')
8669
87- hyperfile.asDataURL(function (data) {
88- var el = crop(data, function (err, data) {
89- if(data) {
90- img.src = data
91- var _data = dataurl.parse(data)
92- pull(
93- pull.once(_data.data),
94- sbot_blobs_add(function (err, hash) {
95- //TODO. Alerts are EVIL.
96- //I use them only in a moment of weakness.
70 + pull(
71 + api.sbot_links({dest: id, rel: 'about', values: true}),
72 + pull.map(function (e) {
73 + return e.value.content.image
74 + }),
75 + pull.filter(function (e) {
76 + return e && 'string' == typeof e.link
77 + }),
78 + pull.unique('link'),
79 + pull.drain(function (image) {
80 + also_pictured.appendChild(
81 + h('a', {href:'#', onclick: function (ev) {
82 + ev.stopPropagation()
83 + ev.preventDefault()
84 + selected = image
85 + img.src = api.blob_url(image.link || image)
86 + }},
87 + h('img.avatar--thumbnail', {src: api.blob_url(image)})
88 + )
89 + )
90 + })
91 + )
9792
98- if(err) return alert(err.stack)
99- selected = {
100- link: hash,
101- size: _data.data.length,
102- type: _data.mimetype,
103- width: 512,
104- height: 512
105- }
93 + return h('div.row.profile',
94 + lb,
95 + img,
96 + h('div.column.profile__info',
97 + h('strong', name),
98 + name_input,
10699
107- })
108- )
109- }
110- lb.close()
111- })
112- lb.show(el)
113- }),
114- h('button', 'update', {onclick: function () {
115- if(name_input.value)
116- name.textContent = name_input.value
100 + hyperfile.asDataURL(function (data) {
101 + var el = crop(data, function (err, data) {
102 + if(data) {
103 + img.src = data
104 + var _data = dataurl.parse(data)
105 + pull(
106 + pull.once(_data.data),
107 + api.sbot_blobs_add(function (err, hash) {
108 + //TODO. Alerts are EVIL.
109 + //I use them only in a moment of weakness.
117110
118- if(selected)
119- confirm({
120- type: 'about',
121- about: id,
122- name: name_input.value || undefined,
123- image: selected
111 + if(err) return alert(err.stack)
112 + selected = {
113 + link: hash,
114 + size: _data.data.length,
115 + type: _data.mimetype,
116 + width: 512,
117 + height: 512
118 + }
119 +
120 + })
121 + )
122 + }
123 + lb.close()
124124 })
125- else if(name_input.value) //name only
126- confirm({
127- type: 'about',
128- about: id,
129- name: name_input.value || undefined,
130- })
131- else
132- //another moment of weakness
133- alert('must select a name or image')
134- }}),
135- also_pictured
125 + lb.show(el)
126 + }),
127 + h('button', 'update', {onclick: function () {
128 + if(name_input.value)
129 + name.textContent = name_input.value
130 +
131 + if(selected)
132 + api.message_confirm({
133 + type: 'about',
134 + about: id,
135 + name: name_input.value || undefined,
136 + image: selected
137 + })
138 + else if(name_input.value) //name only
139 + confirm({
140 + type: 'about',
141 + about: id,
142 + name: name_input.value || undefined,
143 + })
144 + else
145 + //another moment of weakness
146 + alert('must select a name or image')
147 + }}),
148 + also_pictured
149 + )
136150 )
137- )
151 + }
138152 }
139-
140-
141-
modules_basic/avatar-image.jsView
@@ -1,108 +1,110 @@
1-
1 +'use strict'
22 var getAvatar = require('ssb-avatar')
33 var h = require('hyperscript')
44 var ref = require('ssb-ref')
55 var path = require('path')
66 var visualize = require('visualize-buffer')
77
8-var plugs = require('../plugs')
9-var sbot_query = plugs.first(exports.sbot_query = [])
10-var blob_url = require('../plugs').first(exports.blob_url = [])
11-
128 var pull = require('pull-stream')
139
14-var id = require('../keys').id
10 +var self_id = require('../keys').id
1511
16-var avatars = AVATARS = {}
12 +//var plugs = require('../plugs')
13 +//var sbot_query = plugs.first(exports.sbot_query = [])
14 +//var blob_url = require('../plugs').first(exports.blob_url = [])
15 +//
1716
17 +exports.needs = {
18 + sbot_query: 'first',
19 + blob_url: 'first'
20 +}
21 +
22 +exports.gives = {
23 + connection_status: true, avatar_image: true
24 +}
25 +
26 +
1827 function isFunction (f) {
1928 return 'function' === typeof f
2029 }
2130
22-var self_id = require('../keys').id
2331
2432 var ready = false
2533 var waiting = []
2634
2735 var last = 0
2836
29-//blah blah
30-exports.connection_status = function (err) {
31- if (err) return
32-pull(
33- sbot_query({
34- query: [{
35- $filter: {
36- timestamp: {$gt: last || 0 },
37- value: { content: {
38- type: "about",
39- about: {$prefix: "@"},
40- image: {link: {$prefix: "&"}}
41- }}
42- }},
43- {
44- $map: {
45- id: ["value", "content", "about"],
46- image: ["value", "content", "image", "link"],
47- by: ["value", "author"],
48- ts: 'timestamp'
49- }}],
50- live: true
51- }),
52- pull.drain(function (a) {
53- if(a.sync) {
54- ready = true
55- while(waiting.length) waiting.shift()()
56- return
57- }
58- last = a.ts
59- //set image for avatar.
60- //overwrite another avatar
61- //you picked.
62- if(
63- //if there is no avatar
64- (!avatars[a.id]) ||
65- //if i chose this avatar
66- (a.by == self_id) ||
67- //they chose their own avatar,
68- //and current avatar was not chosen by me
69- (a.by === a.id && avatars[a.id].by != self_id)
70- )
71- avatars[a.id] = a
37 +exports.create = function (api) {
38 + var avatars = {}
7239
73- })
74-)
75-}
40 + //blah blah
41 + return {
42 + connection_status: function (err) {
43 + if (err) return
44 + pull(
45 + api.sbot_query({
46 + query: [{
47 + $filter: {
48 + timestamp: {$gt: last || 0 },
49 + value: { content: {
50 + type: "about",
51 + about: {$prefix: "@"},
52 + image: {link: {$prefix: "&"}}
53 + }}
54 + }},
55 + {
56 + $map: {
57 + id: ["value", "content", "about"],
58 + image: ["value", "content", "image", "link"],
59 + by: ["value", "author"],
60 + ts: 'timestamp'
61 + }}],
62 + live: true
63 + }),
64 + pull.drain(function (a) {
65 + if(a.sync) {
66 + ready = true
67 + while(waiting.length) waiting.shift()()
68 + return
69 + }
70 + last = a.ts
71 + //set image for avatar.
72 + //overwrite another avatar
73 + //you picked.
74 + if(
75 + //if there is no avatar
76 + (!avatars[a.id]) ||
77 + //if i chose this avatar
78 + (a.by == self_id) ||
79 + //they chose their own avatar,
80 + //and current avatar was not chosen by me
81 + (a.by === a.id && avatars[a.id].by != self_id)
82 + )
83 + avatars[a.id] = a
7684
77-exports.avatar_image = function (author, classes) {
78- classes = classes || ''
79- if(classes && 'string' === typeof classes) classes = '.avatar--'+classes
85 + })
86 + )
87 + },
8088
81- var img = visualize(new Buffer(author.substring(1), 'base64'), 256)
82- ;(classes || '').split('.').filter(Boolean).forEach(function (c) {
83- img.classList.add(c)
84- })
89 + avatar_image: function (author, classes) {
90 + classes = classes || ''
91 + if(classes && 'string' === typeof classes) classes = '.avatar--'+classes
8592
86- function go () {
87- if(avatars[author]) img.src = blob_url(avatars[author].image)
88- }
93 + var img = visualize(new Buffer(author.substring(1), 'base64'), 256)
94 + ;(classes || '').split('.').filter(Boolean).forEach(function (c) {
95 + img.classList.add(c)
96 + })
8997
90- if(!ready)
91- waiting.push(go)
92- else go()
98 + function go () {
99 + if(avatars[author]) img.src = api.blob_url(avatars[author].image)
100 + }
93101
94- return img
102 + if(!ready)
103 + waiting.push(go)
104 + else go()
105 +
106 + return img
107 + }
108 + }
95109 }
96110
97-
98-
99-
100-
101-
102-
103-
104-
105-
106-
107-
108-
modules_basic/avatar-link.jsView
@@ -1,18 +1,22 @@
11 var h = require('hyperscript')
2-var plugs = require('../plugs')
3-var avatar_name = plugs.first(exports.avatar_name = [])
42
5-var signifier = require('../plugs').first(exports.signifier = [])
3 +exports.needs = {signifier: 'first'}
64
7-exports.avatar_link = function (id, element) {
5 +exports.gives = 'avatar_link'
86
9- var link = h('a.avatar', {href: "#"+id, title: id}, element)
7 +exports.create = function (api) {
8 + return function (id, element) {
109
11- signifier(id, function (_, names) {
12- if(names.length)
13- link.title = names[0].name + '\n '+id
14- })
10 + var link = h('a.avatar', {href: "#"+id, title: id}, element)
1511
16- return link
12 + api.signifier(id, function (_, names) {
13 + if(names.length)
14 + link.title = names[0].name + '\n '+id
15 + })
16 +
17 + return link
18 + }
1719 }
1820
21 +
22 +
modules_basic/avatar-name.jsView
@@ -1,22 +1,29 @@
11
22 var signifier = require('../plugs').first(exports.signifier = [])
33 var h = require('hyperscript')
44
5-exports.avatar_name =
6-function name (id) {
7- var n = h('span', id.substring(0, 10))
5 +exports.needs = { signifier: 'first' }
86
9- //choose the most popular name for this person.
10- //for anything like this you'll see I have used sbot.links2
11- //which is the ssb-links plugin. as you'll see the query interface
12- //is pretty powerful!
13- //TODO: "most popular" name is easily gameable.
14- //must come up with something better than this.
7 +exports.gives = 'avatar_name'
158
16- signifier(id, function (_, names) {
17- if(names.length) n.textContent = names[0].name
18- })
9 +exports.create = function (api) {
1910
20- return n
11 + return function name (id) {
12 + var n = h('span', id.substring(0, 10))
13 +
14 + //choose the most popular name for this person.
15 + //for anything like this you'll see I have used sbot.links2
16 + //which is the ssb-links plugin. as you'll see the query interface
17 + //is pretty powerful!
18 + //TODO: "most popular" name is easily gameable.
19 + //must come up with something better than this.
20 +
21 + api.signifier(id, function (_, names) {
22 + if(names.length) n.textContent = names[0].name
23 + })
24 +
25 + return n
26 + }
27 +
2128 }
2229
modules_basic/avatar-profile.jsView
@@ -1,15 +1,25 @@
11 var h = require('hyperscript')
2-var plugs = require('../plugs')
32 var pull = require('pull-stream')
43
5-var avatar_image_link = plugs.first(exports.avatar_image_link = [])
6-var avatar_action = plugs.map(exports.avatar_action = [])
7-var avatar_edit = plugs.first(exports.avatar_edit = [])
4 +//var plugs = require('../plugs')
5 +//var avatar_image_link = plugs.first(exports.avatar_image_link = [])
6 +//var avatar_action = plugs.map(exports.avatar_action = [])
7 +//var avatar_edit = plugs.first(exports.avatar_edit = [])
88
9-var follows = plugs.first(exports.follows = [])
10-var followers = plugs.first(exports.followers = [])
9 +//var follows = plugs.first(exports.follows = [])
10 +//var followers = plugs.first(exports.followers = [])
11 +//
12 +exports.needs = {
13 + avatar_image_link: 'first',
14 + avatar_action: 'map',
15 + avatar_edit: 'first',
16 + follows: 'first',
17 + followers: 'first'
18 +}
1119
20 +exports.gives = 'avatar_profile'
21 +
1222 function streamToList(stream, el) {
1323 pull(
1424 stream,
1525 pull.drain(function (item) {
@@ -18,57 +28,61 @@
1828 )
1929 return el
2030 }
2131
22-function image_link (id) {
23- return avatar_image_link(id, 'thumbnail')
24-}
32 +exports.create = function (api) {
2533
26-exports.avatar_profile = function (id) {
34 + function image_link (id) {
35 + return api.avatar_image_link(id, 'thumbnail')
36 + }
2737
28- var follows_el = h('div.profile__follows.wrap')
29- var friends_el = h('div.profile__friendss.wrap')
30- var followers_el = h('div.profile__followers.wrap')
31- var a, b
38 + return function (id) {
3239
33- pull(follows(id), pull.unique(), pull.collect(function (err, ary) {
34- a = ary || []; next()
35- }))
36- pull(followers(id), pull.unique(), pull.collect(function (err, ary) {
37- b = ary || {}; next()
38- }))
40 + var follows_el = h('div.profile__follows.wrap')
41 + var friends_el = h('div.profile__friendss.wrap')
42 + var followers_el = h('div.profile__followers.wrap')
43 + var a, b
3944
40- function next () {
41- if(!(a && b)) return
42- var _c = [], _a = [], _b = []
45 + pull(api.follows(id), pull.unique(), pull.collect(function (err, ary) {
46 + a = ary || []; next()
47 + }))
48 + pull(api.followers(id), pull.unique(), pull.collect(function (err, ary) {
49 + b = ary || {}; next()
50 + }))
4351
44- a.forEach(function (id) {
45- if(!~b.indexOf(id)) _a.push(id)
46- else _c.push(id)
47- })
48- b.forEach(function (id) {
49- if(!~_c.indexOf(id)) _b.push(id)
50- })
51- function add (ary, el) {
52- ary.forEach(function (id) { el.appendChild(image_link(id)) })
52 + function next () {
53 + if(!(a && b)) return
54 + var _c = [], _a = [], _b = []
55 +
56 + a.forEach(function (id) {
57 + if(!~b.indexOf(id)) _a.push(id)
58 + else _c.push(id)
59 + })
60 + b.forEach(function (id) {
61 + if(!~_c.indexOf(id)) _b.push(id)
62 + })
63 + function add (ary, el) {
64 + ary.forEach(function (id) { el.appendChild(image_link(id)) })
65 + }
66 +
67 + add(_a, follows_el)
68 + add(_c, friends_el)
69 + add(_b, followers_el)
5370 }
5471
55- add(_a, follows_el)
56- add(_c, friends_el)
57- add(_b, followers_el)
72 +
73 + return h('div.column.profile',
74 + api.avatar_edit(id),
75 + api.avatar_action(id),
76 + h('div.profile__relationships.column',
77 + h('strong', 'follows'),
78 + follows_el,
79 + h('strong', 'friends'),
80 + friends_el,
81 + h('strong', 'followers'),
82 + followers_el
83 + )
84 + )
5885 }
5986
60-
61- return h('div.column.profile',
62- avatar_edit(id),
63- avatar_action(id),
64- h('div.profile__relationships.column',
65- h('strong', 'follows'),
66- follows_el,
67- h('strong', 'friends'),
68- friends_el,
69- h('strong', 'followers'),
70- followers_el
71- )
72- )
7387 }
7488
modules_basic/avatar.jsView
@@ -1,23 +1,37 @@
11 var h = require('hyperscript')
22 var u = require('../util')
3-var plugs = require('../plugs')
43
5-var avatar_name = plugs.first(exports.avatar_name = [])
6-var avatar_image = plugs.first(exports.avatar_image = [])
7-var avatar_link = plugs.first(exports.avatar_link = [])
8-
9-exports.avatar = function (author, classes) {
10- return exports.avatar_image_name_link(author, classes)
4 +exports.needs = {
5 + avatar_name: 'first',
6 + avatar_image: 'first',
7 + avatar_link: 'first'
118 }
129
13-exports.avatar_image_name_link = function (author, classes) {
14- return avatar_link(author, [
15- avatar_image(author, classes),
16- avatar_name(author)
17- ])
10 +exports.gives = {
11 + avatar: true,
12 + avatar_image_name_link: true,
13 + avatar_image_link: true
1814 }
1915
20-exports.avatar_image_link = function (author, classes) {
21- return avatar_link(author, avatar_image(author, classes))
16 +exports.create = function (api) {
17 +
18 + var exports = {}
19 + exports.avatar = function (author, classes) {
20 + return exports.avatar_image_name_link(author, classes)
21 + }
22 +
23 + exports.avatar_image_name_link = function (author, classes) {
24 + return api.avatar_link(author, [
25 + api.avatar_image(author, classes),
26 + api.avatar_name(author)
27 + ])
28 + }
29 +
30 + exports.avatar_image_link = function (author, classes) {
31 + return api.avatar_link(author, api.avatar_image(author, classes))
32 + }
33 +
34 + return exports
2235 }
2336
37 +
modules_basic/compose.jsView
@@ -3,17 +3,27 @@
33 var u = require('../util')
44 var suggest = require('suggest-box')
55 var mentions = require('ssb-mentions')
66 var lightbox = require('hyperlightbox')
7 +var cont = require('cont')
78
8-var plugs = require('../plugs')
9 +//var plugs = require('../plugs')
10 +//var suggest_mentions= plugs.asyncConcat(exports.suggest_mentions = [])
11 +//var publish = plugs.first(exports.sbot_publish = [])
12 +//var message_content = plugs.first(exports.message_content = [])
13 +//var message_confirm = plugs.first(exports.message_confirm = [])
14 +//var file_input = plugs.first(exports.file_input = [])
915
10-var suggest_mentions= plugs.asyncConcat(exports.suggest_mentions = [])
11-var publish = plugs.first(exports.sbot_publish = [])
12-var message_content = plugs.first(exports.message_content = [])
13-var message_confirm = plugs.first(exports.message_confirm = [])
14-var file_input = plugs.first(exports.file_input = [])
16 +exports.needs = {
17 + suggest_mentions: 'map', //<-- THIS MUST BE REWRITTEN
18 + publish: 'first',
19 + message_content: 'first',
20 + message_confirm: 'first',
21 + file_input: 'first'
22 +}
1523
24 +exports.gives = 'message_compose'
25 +
1626 function id (e) { return e }
1727
1828 /*
1929 opts can take
@@ -22,111 +32,122 @@
2232 prepublish: function. called before publishing a message.
2333 shrink: boolean. set to false, to make composer not shrink (or hide controls) when unfocused.
2434 */
2535
26-exports.message_compose = function (meta, opts, cb) {
27- if('function' === typeof cb) {
28- if('function' === typeof opts)
29- opts = {prepublish: opts}
30- }
36 +exports.create = function (api) {
3137
32- if(!opts) opts = {}
33- opts.prepublish = opts.prepublish || id
38 + return function (meta, opts, cb) {
39 + if('function' === typeof cb) {
40 + if('function' === typeof opts)
41 + opts = {prepublish: opts}
42 + }
3443
35- var accessories
36- meta = meta || {}
37- if(!meta.type) throw new Error('message must have type')
38- var ta = h('textarea', {
39- placeholder: opts.placeholder || 'Write a message',
40- style: {height: opts.shrink === false ? '200px' : ''}
41- })
44 + if(!opts) opts = {}
45 + opts.prepublish = opts.prepublish || id
4246
43- if(opts.shrink !== false) {
44- var blur
45- ta.addEventListener('focus', function () {
46- clearTimeout(blur)
47- if(!ta.value) {
48- ta.style.height = '200px'
49- }
50- accessories.style.display = 'block'
47 + var accessories
48 + meta = meta || {}
49 + if(!meta.type) throw new Error('message must have type')
50 + var ta = h('textarea', {
51 + placeholder: opts.placeholder || 'Write a message',
52 + style: {height: opts.shrink === false ? '200px' : ''}
5153 })
52- ta.addEventListener('blur', function () {
53- //don't shrink right away, so there is time
54- //to click the publish button.
55- clearTimeout(blur)
56- blur = setTimeout(function () {
57- if(ta.value) return
58- ta.style.height = '50px'
59- accessories.style.display = 'none'
60- }, 200)
54 +
55 + if(opts.shrink !== false) {
56 + var blur
57 + ta.addEventListener('focus', function () {
58 + clearTimeout(blur)
59 + if(!ta.value) {
60 + ta.style.height = '200px'
61 + }
62 + accessories.style.display = 'block'
63 + })
64 + ta.addEventListener('blur', function () {
65 + //don't shrink right away, so there is time
66 + //to click the publish button.
67 + clearTimeout(blur)
68 + blur = setTimeout(function () {
69 + if(ta.value) return
70 + ta.style.height = '50px'
71 + accessories.style.display = 'none'
72 + }, 200)
73 + })
74 + }
75 +
76 + ta.addEventListener('keydown', function (ev) {
77 + if(ev.keyCode === 13 && ev.ctrlKey) publish()
6178 })
62- }
6379
64- ta.addEventListener('keydown', function (ev) {
65- if(ev.keyCode === 13 && ev.ctrlKey) publish()
66- })
80 + var files = []
81 + var filesById = {}
6782
68- var files = []
69- var filesById = {}
70-
71- function publish() {
72- publishBtn.disabled = true
73- var content
74- try {
75- content = JSON.parse(ta.value)
76- } catch (err) {
77- meta.text = ta.value
78- meta.mentions = mentions(ta.value).map(function (mention) {
79- // merge markdown-detected mention with file info
80- var file = filesById[mention.link]
81- if (file) {
82- if (file.type) mention.type = file.type
83- if (file.size) mention.size = file.size
84- }
85- return mention
86- })
83 + function publish() {
84 + publishBtn.disabled = true
85 + var content
8786 try {
88- meta = opts.prepublish(meta)
87 + content = JSON.parse(ta.value)
8988 } catch (err) {
90- publishBtn.disabled = false
91- if (cb) cb(err)
92- else alert(err.message)
89 + meta.text = ta.value
90 + meta.mentions = mentions(ta.value).map(function (mention) {
91 + // merge markdown-detected mention with file info
92 + var file = filesById[mention.link]
93 + if (file) {
94 + if (file.type) mention.type = file.type
95 + if (file.size) mention.size = file.size
96 + }
97 + return mention
98 + })
99 + try {
100 + meta = opts.prepublish(meta)
101 + } catch (err) {
102 + publishBtn.disabled = false
103 + if (cb) cb(err)
104 + else alert(err.message)
105 + }
106 + return message_confirm(meta, done)
93107 }
94- return message_confirm(meta, done)
95- }
96- message_confirm(content, done)
97108
98- function done (err, msg) {
99- publishBtn.disabled = false
100- if(err) return alert(err.stack)
101- else if (msg) ta.value = ''
109 + api.message_confirm(content, done)
102110
103- if (cb) cb(err, msg)
111 + function done (err, msg) {
112 + publishBtn.disabled = false
113 + if(err) return alert(err.stack)
114 + else if (msg) ta.value = ''
115 +
116 + if (cb) cb(err, msg)
117 + }
104118 }
105- }
106119
107120
108- var publishBtn = h('button', 'Publish', {onclick: publish})
109- var composer =
110- h('div.compose', h('div.column', ta,
111- accessories = h('div.row.compose__controls',
112- //hidden until you focus the textarea
113- {style: {display: opts.shrink === false ? '' : 'none'}},
114- file_input(function (file) {
115- files.push(file)
116- filesById[file.link] = file
121 + var publishBtn = h('button', 'Publish', {onclick: publish})
122 + var composer =
123 + h('div.compose', h('div.column', ta,
124 + accessories = h('div.row.compose__controls',
125 + //hidden until you focus the textarea
126 + {style: {display: opts.shrink === false ? '' : 'none'}},
127 + api.file_input(function (file) {
128 + files.push(file)
129 + filesById[file.link] = file
117130
118- var embed = file.type.indexOf('image/') === 0 ? '!' : ''
119- ta.value += embed + '['+file.name+']('+file.link+')'
120- console.log('added:', file)
121- }),
122- publishBtn)
131 + var embed = file.type.indexOf('image/') === 0 ? '!' : ''
132 + ta.value += embed + '['+file.name+']('+file.link+')'
133 + console.log('added:', file)
134 + }),
135 + publishBtn)
136 + )
123137 )
124- )
125138
126- suggest(ta, suggest_mentions, {})
139 + suggest(ta, function (name, cb) {
140 + cont.para(suggest_mentions.map(function (e) { return e(name) }))
141 + (function (err, ary) {
142 + cb(null, ary.reduce(function (a, b) {
143 + return a.concat(b)
144 + }))
145 + })
146 + }, {})
127147
128- return composer
148 + return composer
129149
150 + }
151 +
130152 }
131153
132-
modules_basic/feed.jsView
@@ -3,54 +3,63 @@
33 var h = require('hyperscript')
44 var pull = require('pull-stream')
55 var u = require('../util')
66
7-var plugs = require('../plugs')
8-var sbot_user_feed = plugs.first(exports.sbot_user_feed = [])
9-var message_render = plugs.first(exports.message_render = [])
10-var avatar_profile = plugs.first(exports.avatar_profile = [])
11-var signifier = plugs.first(exports.signifier = [])
7 +//var plugs = require('../plugs')
8 +//var sbot_user_feed = plugs.first(exports.sbot_user_feed = [])
9 +//var message_render = plugs.first(exports.message_render = [])
10 +//var avatar_profile = plugs.first(exports.avatar_profile = [])
11 +//var signifier = plugs.first(exports.signifier = [])
1212
13-exports.screen_view = function (id) {
14- //TODO: header of user info, avatars, names, follows.
13 +exports.needs = {
14 + sbot_user_feed: 'first',
15 + message_render: 'first',
16 + avatar_profile: 'first',
17 + signifier: 'first'
18 +}
1519
16- if(ref.isFeed(id)) {
20 +exports.gives = 'screen_view'
1721
18- var content = h('div.column.scroller__content')
19- var div = h('div.column.scroller',
20- {style: {'overflow':'auto'}},
21- h('div.scroller__wrapper',
22- h('div', avatar_profile(id)),
23- content
24- )
25- )
2622
27- signifier(id, function (_, names) {
28- if(names.length) div.title = names[0].name
29- })
23 +exports.create = function (api) {
3024
25 + return function (id) {
26 + //TODO: header of user info, avatars, names, follows.
3127
32- pull(
33- sbot_user_feed({id: id, old: false, live: true}),
34- Scroller(div, content, message_render, true, false)
35- )
28 + if(ref.isFeed(id)) {
3629
37- //how to handle when have scrolled past the start???
30 + var content = h('div.column.scroller__content')
31 + var div = h('div.column.scroller',
32 + {style: {'overflow':'auto'}},
33 + h('div.scroller__wrapper',
34 + h('div', api.avatar_profile(id)),
35 + api.content
36 + )
37 + )
3838
39- pull(
40- u.next(sbot_user_feed, {
41- id: id, reverse: true,
42- limit: 50, live: false
43- }, ['value', 'sequence']),
44- Scroller(div, content, message_render, false, false)
45- )
39 + api.signifier(id, function (_, names) {
40 + if(names.length) div.title = names[0].name
41 + })
4642
47- return div
4843
49- }
50-}
44 + pull(
45 + api.sbot_user_feed({id: id, old: false, live: true}),
46 + Scroller(div, content, api.message_render, true, false)
47 + )
5148
49 + //how to handle when have scrolled past the start???
5250
51 + pull(
52 + u.next(api.sbot_user_feed, {
53 + id: id, reverse: true,
54 + limit: 50, live: false
55 + }, ['value', 'sequence']),
56 + Scroller(div, content, api.message_render, false, false)
57 + )
5358
59 + return div
5460
61 + }
62 + }
5563
64 +}
5665
modules_basic/follow.jsView
@@ -1,86 +1,99 @@
11 var h = require('hyperscript')
22 var u = require('../util')
3-var plugs = require('../plugs')
4-var avatar = plugs.first(exports.avatar = [])
5-var avatar_name = plugs.first(exports.avatar_name = [])
6-var avatar_link = plugs.first(exports.avatar_link = [])
73 var pull = require('pull-stream')
8-var plugs = require('../plugs')
94
5 +//var plugs = require('../plugs')
6 +//var avatar = plugs.first(exports.avatar = [])
7 +//var avatar_name = plugs.first(exports.avatar_name = [])
8 +//var avatar_link = plugs.first(exports.avatar_link = [])
9 +//var message_confirm = plugs.first(exports.message_confirm = [])
10 +//var follower_of = plugs.first(exports.follower_of = [])
11 +
1012 //render a message when someone follows someone,
1113 //so you see new users
1214 function isRelated(value, name) {
1315 return value ? name : value === false ? 'un'+name : ''
1416 }
1517
16-exports.message_content =
17-exports.message_content_mini = function (msg) {
18- var content = msg.value.content
19- if(content.type == 'contact' && content.contact) {
20- var relation = isRelated(content.following, 'follows')
21- if(content.blocking) relation = 'blocks'
22- return [
23- relation, ' ',
24- avatar_link(content.contact, avatar_name(content.contact), '')
25- ]
26- }
18 +exports.needs = {
19 + avatar: 'first',
20 + avatar_name: 'first',
21 + avatar_link: 'first',
22 + message_confirm: 'first',
23 + follower_of: 'first'
2724 }
2825
29-exports.message_content = function (msg) {
26 +exports.gives = {
27 + message_content: true,
28 + message_content_mini: true,
29 + avatar_action: true,
30 +}
3031
31- var content = msg.value.content
32- if(content.type == 'contact' && content.contact) {
33- var relation = isRelated(content.following, 'follows')
34- if(content.blocking) relation = 'blocks'
35- return h('div.contact', relation, avatar(msg.value.content.contact, 'thumbnail'))
32 +exports.create = function (api) {
33 + var exports = {}
34 + exports.message_content =
35 + exports.message_content_mini = function (msg) {
36 + var content = msg.value.content
37 + if(content.type == 'contact' && content.contact) {
38 + var relation = isRelated(content.following, 'follows')
39 + if(content.blocking) relation = 'blocks'
40 + return [
41 + relation, ' ',
42 + api.avatar_link(content.contact, api.avatar_name(content.contact), '')
43 + ]
44 + }
3645 }
37-}
3846
39-var message_confirm = plugs.first(exports.message_confirm = [])
40-var follower_of = plugs.first(exports.follower_of = [])
47 + exports.message_content = function (msg) {
4148
42-exports.avatar_action = function (id) {
43- var follows_you, you_follow
49 + var content = msg.value.content
50 + if(content.type == 'contact' && content.contact) {
51 + var relation = isRelated(content.following, 'follows')
52 + if(content.blocking) relation = 'blocks'
53 + return h('div.contact', relation, api.avatar(msg.value.content.contact, 'thumbnail'))
54 + }
55 + }
4456
45- var self_id = require('../keys').id
46- follower_of(self_id, id, function (err, f) {
47- you_follow = f
48- update()
49- })
50- follower_of(id, self_id, function (err, f) {
51- follows_you = f
52- update()
53- })
57 + exports.avatar_action = function (id) {
58 + var follows_you, you_follow
5459
55- var state = h('label')
56- var label = h('span')
60 + var self_id = require('../keys').id
61 + api.follower_of(self_id, id, function (err, f) {
62 + you_follow = f
63 + update()
64 + })
65 + api.follower_of(id, self_id, function (err, f) {
66 + follows_you = f
67 + update()
68 + })
5769
58- function update () {
59- state.textContent = (
60- follows_you && you_follow ? 'friend'
61- : follows_you ? 'follows you'
62- : you_follow ? 'you follow'
63- : ''
70 + var state = h('label')
71 + var label = h('span')
72 +
73 + function update () {
74 + state.textContent = (
75 + follows_you && you_follow ? 'friend'
76 + : follows_you ? 'follows you'
77 + : you_follow ? 'you follow'
78 + : ''
79 + )
80 +
81 + label.textContent = you_follow ? 'unfollow' : 'follow'
82 + }
83 +
84 + return h('div', state,
85 + h('a', {href:'#', onclick: function () {
86 + api.message_confirm({
87 + type: 'contact',
88 + contact: id,
89 + following: !you_follow
90 + }, function (err, msg) {
91 + if (err) return console.error(err)
92 + you_follow = msg.value.content.following
93 + update()
94 + })
95 + }}, h('br'), label)
6496 )
65-
66- label.textContent = you_follow ? 'unfollow' : 'follow'
6797 }
68-
69- return h('div', state,
70- h('a', {href:'#', onclick: function () {
71- message_confirm({
72- type: 'contact',
73- contact: id,
74- following: !you_follow
75- }, function (err, msg) {
76- if (err) return console.error(err)
77- you_follow = msg.value.content.following
78- update()
79- })
80- }}, h('br'), label)
81- )
98 + return exports
8299 }
83-
84-
85-
86-
modules_basic/index.jsView
@@ -23,8 +23,8 @@
2323 "relationships.js": require('./relationships.js'),
2424 "search-box.js": require('./search-box.js'),
2525 "setup.js": require('./setup'),
2626 "suggest-mentions.js": require('./suggest-mentions.js'),
27- "suggest.js": require('./suggest.js'),
2827 "thread.js": require('./thread.js'),
2928 "timestamp.js": require('./timestamp.js')
3029 }
30 +
modules_basic/invite.jsView
@@ -1,112 +1,126 @@
1-
1 +'use strict'
22 var ref = require('ssb-ref')
33 var ssbClient = require('ssb-client')
44 var id = require('../keys').id
55 var h = require('hyperscript')
66
77 var Progress = require('hyperprogress')
88
9-var plugs = require('../plugs')
10-var sbot_publish = plugs.first(exports.sbot_publish = [])
11-var sbot_gossip_connect = plugs.first(exports.sbot_gossip_connect = [])
12-var follower_of = plugs.first(exports.follower_of = [])
9 +//var plugs = require('../plugs')
10 +//var sbot_publish = plugs.first(exports.sbot_publish = [])
11 +//var sbot_gossip_connect = plugs.first(exports.sbot_gossip_connect = [])
12 +//var follower_of = plugs.first(exports.follower_of = [])
1313
14-exports.invite_parse = function (invite) {
15- return ref.parseInvite(invite)
14 +exports.needs = {
15 + sbot_publish: 'first',
16 + sbot_gossip_connect: 'first',
17 + follower_of: 'first',
18 + invite_parse: 'first',
1619 }
1720
18-exports.invite_accept = function (invite, onProgress, cb) {
19- var data = exports.invite_parse(invite)
20- if(!data) return cb(new Error('not a valid invite code:' + invite))
21 +exports.gives = {
22 + invite_parse: true,
23 + invite_accept: true,
24 + screen_view: true
25 +}
2126
22- onProgress('connecting...')
27 +exports.create = function (api) {
28 + var self
29 + return self = {
30 + invite_parse: function (invite) {
31 + return ref.parseInvite(invite)
32 + },
33 +
34 + invite_accept: function (invite, onProgress, cb) {
35 + var data = self.invite_parse(invite)
36 + if(!data) return cb(new Error('not a valid invite code:' + invite))
37 +
38 + onProgress('connecting...')
2339
24- sbot_gossip_connect(data.remote, function (err) {
25- if(err) console.log(err)
26- })
40 + api.sbot_gossip_connect(data.remote, function (err) {
41 + if(err) console.log(err)
42 + })
2743
28- ssbClient(null, {
29- remote: data.invite,
30- manifest: { invite: {use: 'async'}, getAddress: 'async' }
31- }, function (err, sbot) {
32- if(err) return cb(err)
33- onProgress('requesting follow...')
34- console.log(sbot)
35- sbot.invite.use({feed: id}, function (err, msg) {
44 + ssbClient(null, {
45 + remote: data.invite,
46 + manifest: { invite: {use: 'async'}, getAddress: 'async' }
47 + }, function (err, sbot) {
48 + if(err) return cb(err)
49 + onProgress('requesting follow...')
50 + console.log(sbot)
51 + sbot.invite.use({feed: id}, function (err, msg) {
3652
37- //if they already follow us, just check we actually follow them.
38- if(err) follower_of(id, data.key, function (_err, follows) {
39- if(follows) cb(err)
53 + //if they already follow us, just check we actually follow them.
54 + if(err) api.follower_of(id, data.key, function (_err, follows) {
55 + if(follows) cb(err)
56 + else next()
57 + })
4058 else next()
41- })
42- else next()
4359
44- function next () {
45- onProgress('following...')
60 + function next () {
61 + onProgress('following...')
4662
47- //remove the seed from the shs address.
48- //then it's correct address.
49- //this should make the browser connect to this as remote.
50- //we don't want to do this if when using this locally, though.
51- if(process.title === 'browser')
52- localStorage.remote = data.remote
63 + //remove the seed from the shs address.
64 + //then it's correct address.
65 + //this should make the browser connect to this as remote.
66 + //we don't want to do this if when using this locally, though.
67 + if(process.title === 'browser')
68 + localStorage.remote = data.remote
5369
54- sbot_publish({
55- type: 'contact',
56- contact: data.key,
57- following: true,
58- }, cb)
59- }
60- })
61- })
62-}
70 + api.sbot_publish({
71 + type: 'contact',
72 + contact: data.key,
73 + following: true,
74 + }, cb)
75 + }
76 + })
77 + })
78 + },
6379
64-exports.screen_view = function (invite) {
80 + screen_view: function (invite) {
6581
66- var data = ref.parseInvite(invite)
67- if(!data) return
82 + var data = ref.parseInvite(invite)
83 + if(!data) return
6884
69- var progress = Progress(4)
85 + var progress = Progress(4)
7086
71- //connect to server
72- //request follow
73- //post pub announce
74- //post follow pub
75- var div = h('div.column',
76- h('div',
77- "you have been invited to join:", h('br'),
78- h('code', data.invite)
79- ),
80- h('button', 'accept', {onclick: attempt}),
81- progress
82- )
87 + //connect to server
88 + //request follow
89 + //post pub announce
90 + //post follow pub
91 + var div = h('div.column',
92 + h('div',
93 + "you have been invited to join:", h('br'),
94 + h('code', data.invite)
95 + ),
96 + h('button', 'accept', {onclick: attempt}),
97 + progress
98 + )
8399
84- function attempt () {
85- exports.invite_accept(invite, function (message) {
86- progress.next(message)
87- }, function (err) {
88- if(err) return progress.fail(err)
89- progress.complete()
90- //check for redirect
91- var parts = location.hash.substring(1).split('#')
100 + function attempt () {
101 + self.invite_accept(invite, function (message) {
102 + progress.next(message)
103 + }, function (err) {
104 + if(err) return progress.fail(err)
105 + progress.complete()
106 + //check for redirect
107 + var parts = location.hash.substring(1).split('#')
92108
93- //TODO: handle in a consistent way with either hashrouting
94- //or with tabs...
95- if(parts[0] === data.invite)
96- location.hash = ''
97- else
98- console.log("NO REDIRECT")
99- })
100- }
109 + //TODO: handle in a consistent way with either hashrouting
110 + //or with tabs...
111 + if(parts[0] === data.invite)
112 + location.hash = ''
113 + else
114 + console.log("NO REDIRECT")
115 + })
116 + }
101117
102- // If we are in the browser,
103- // and do not already have a remote set, automatically trigger the invite.
104- if(process.title == 'browser' && !localStorage.remote) attempt()
118 + // If we are in the browser,
119 + // and do not already have a remote set, automatically trigger the invite.
120 + if(process.title == 'browser' && !localStorage.remote) attempt()
105121
106- return div
122 + return div
123 + }
124 + }
107125 }
108126
109-
110-
111-
112-
modules_basic/like.jsView
@@ -4,59 +4,75 @@
44 var pull = require('pull-stream')
55
66 var plugs = require('../plugs')
77
8-var message_confirm = plugs.first(exports.message_confirm = [])
9-var message_link = plugs.first(exports.message_link = [])
10-var sbot_links = plugs.first(exports.sbot_links = [])
8 +//var message_confirm = plugs.first(exports.message_confirm = [])
9 +//var message_link = plugs.first(exports.message_link = [])
10 +//var sbot_links = plugs.first(exports.sbot_links = [])
1111
12 +exports.needs = {
13 + message_confirm: 'first',
14 + message_link: 'first',
15 + sbot_links: 'first'
16 +}
1217
13-exports.message_content =
14-exports.message_content_mini = function (msg, sbot) {
15- if(msg.value.content.type !== 'vote') return
16- var link = msg.value.content.vote.link
17- return [
18- msg.value.content.vote.value > 0 ? 'dug' : 'undug',
19- ' ', message_link(link)
20- ]
18 +exports.gives = {
19 + message_content: true,
20 + message_content_mini: true,
21 + message_meta: true,
22 + message_action: true
2123 }
2224
23-exports.message_meta = function (msg, sbot) {
24- var digs = h('a')
25 +exports.create = function (api) {
26 + var exports = {}
2527
26- var votes = []
27- for(var k in CACHE) {
28- if(CACHE[k].content.type == 'vote' &&
29- (CACHE[k].content.vote == msg.key ||
30- CACHE[k].content.vote.link == msg.key
31- ))
32- votes.push({source: CACHE[k].author, dest: k, rel: 'vote'})
28 + exports.message_content =
29 + exports.message_content_mini = function (msg, sbot) {
30 + if(msg.value.content.type !== 'vote') return
31 + var link = msg.value.content.vote.link
32 + return [
33 + msg.value.content.vote.value > 0 ? 'dug' : 'undug',
34 + ' ', api.message_link(link)
35 + ]
3336 }
3437
35- if(votes.length === 1)
36- digs.textContent = ' 1 Dig'
37- if(votes.length > 1)
38- digs.textContent = ' ' + votes.length + ' Digs'
38 + exports.message_meta = function (msg, sbot) {
39 + var digs = h('a')
3940
40- return digs
41-}
41 + var votes = []
42 + for(var k in CACHE) {
43 + if(CACHE[k].content.type == 'vote' &&
44 + (CACHE[k].content.vote == msg.key ||
45 + CACHE[k].content.vote.link == msg.key
46 + ))
47 + votes.push({source: CACHE[k].author, dest: k, rel: 'vote'})
48 + }
4249
43-exports.message_action = function (msg, sbot) {
44- if(msg.value.content.type !== 'vote')
45- return h('a.dig', {href: '#', onclick: function () {
46- var dig = {
47- type: 'vote',
48- vote: { link: msg.key, value: 1, expression: 'Dig' }
49- }
50- if(msg.value.content.recps) {
51- dig.recps = msg.value.content.recps.map(function (e) {
52- return e && typeof e !== 'string' ? e.link : e
53- })
54- dig.private = true
55- }
56- //TODO: actually publish...
50 + if(votes.length === 1)
51 + digs.textContent = ' 1 Dig'
52 + if(votes.length > 1)
53 + digs.textContent = ' ' + votes.length + ' Digs'
5754
58- message_confirm(dig)
59- }}, 'Dig')
55 + return digs
56 + }
6057
58 + exports.message_action = function (msg, sbot) {
59 + if(msg.value.content.type !== 'vote')
60 + return h('a.dig', {href: '#', onclick: function () {
61 + var dig = {
62 + type: 'vote',
63 + vote: { link: msg.key, value: 1, expression: 'Dig' }
64 + }
65 + if(msg.value.content.recps) {
66 + dig.recps = msg.value.content.recps.map(function (e) {
67 + return e && typeof e !== 'string' ? e.link : e
68 + })
69 + dig.private = true
70 + }
71 + //TODO: actually publish...
72 +
73 + api.message_confirm(dig)
74 + }}, 'Dig')
75 +
76 + }
77 + return exports
6178 }
62-
modules_basic/markdown.jsView
@@ -1,40 +1,52 @@
11 var markdown = require('ssb-markdown')
22 var h = require('hyperscript')
33 var ref = require('ssb-ref')
44
5-var plugs = require('../plugs')
6-var blob_url = plugs.first(exports.blob_url = [])
7-var emoji_url = plugs.first(exports.emoji_url = [])
5 +//var plugs = require('../plugs')
6 +//var blob_url = plugs.first(exports.blob_url = [])
7 +//var emoji_url = plugs.first(exports.emoji_url = [])
88
9-function renderEmoji(emoji) {
10- var url = emoji_url(emoji)
11- if (!url) return ':' + emoji + ':'
12- return '<img src="' + encodeURI(url) + '"'
13- + ' alt=":' + escape(emoji) + ':"'
14- + ' title=":' + escape(emoji) + ':"'
15- + ' class="emoji">'
9 +exports.needs = {
10 + blob_url: 'first',
11 +// emoji_url: 'first'
1612 }
1713
18-exports.markdown = function (content) {
19- if('string' === typeof content)
20- content = {text: content}
21- //handle patchwork style mentions.
22- var mentions = {}
23- if(Array.isArray(content.mentions))
24- content.mentions.forEach(function (link) {
25- if(link.name) mentions["@"+link.name] = link.link
14 +exports.gives = 'markdown'
15 +
16 +exports.create = function (api) {
17 +
18 +//emoji is in extra, disable for a sec
19 +
20 +// function renderEmoji(emoji) {
21 +// var url = api.emoji_url(emoji)
22 +// if (!url) return ':' + emoji + ':'
23 +// return '<img src="' + encodeURI(url) + '"'
24 +// + ' alt=":' + escape(emoji) + ':"'
25 +// + ' title=":' + escape(emoji) + ':"'
26 +// + ' class="emoji">'
27 +// }
28 +
29 + return function (content) {
30 + if('string' === typeof content)
31 + content = {text: content}
32 + //handle patchwork style mentions.
33 + var mentions = {}
34 + if(Array.isArray(content.mentions))
35 + content.mentions.forEach(function (link) {
36 + if(link.name) mentions["@"+link.name] = link.link
37 + })
38 +
39 + var md = h('div.markdown')
40 + md.innerHTML = markdown.block(content.text, {
41 + // emoji: renderEmoji,
42 + toUrl: function (id) {
43 + if(ref.isBlob(id)) return api.blob_url(id)
44 + return '#'+(mentions[id]?mentions[id]:id)
45 + }
2646 })
2747
28- var md = h('div.markdown')
29- md.innerHTML = markdown.block(content.text, {
30- emoji: renderEmoji,
31- toUrl: function (id) {
32- if(ref.isBlob(id)) return blob_url(id)
33- return '#'+(mentions[id]?mentions[id]:id)
34- }
35- })
48 + return md
3649
37- return md
38-
50 + }
3951 }
4052
modules_basic/message-link.jsView
@@ -1,29 +1,35 @@
11 var h = require('hyperscript')
22 var ref = require('ssb-ref')
33
4-var first = require('../plugs').first
5-var sbot_get = first(exports.sbot_get = [])
6-var message_name = first(exports.message_name = [])
4 +//var first = require('../plugs').first
5 +//var sbot_get = first(exports.sbot_get = [])
6 +//var message_name = first(exports.message_name = [])
77
8-exports.message_link = function (id) {
8 +exports.needs = {
9 + message_name: 'first'
10 +}
911
10- if('string' !== typeof id)
11- throw new Error('link must be to message id')
12 +exports.gives = 'message_link'
1213
13- var link = h('a', {href: '#'+id}, id.substring(0, 10)+'...')
14 +exports.create = function (api) {
1415
15- if(ref.isMsg(id))
16- message_name(id, function (err, name) {
17- if(err) console.error(err)
18- else link.textContent = name
19- })
16 + return function (id) {
2017
21- return link
22-}
18 + if('string' !== typeof id)
19 + throw new Error('link must be to message id')
2320
21 + var link = h('a', {href: '#'+id}, id.substring(0, 10)+'...')
2422
23 + if(ref.isMsg(id))
24 + api.message_name(id, function (err, name) {
25 + if(err) console.error(err)
26 + else link.textContent = name
27 + })
2528
29 + return link
30 + }
31 +}
2632
2733
2834
2935
modules_basic/message-name.jsView
@@ -1,21 +1,26 @@
11
2-var sbot_get = require('../plugs').first(exports.sbot_get = [])
3-
42 function title (s) {
53 var m = /^\n*([^\n]{0,40})/.exec(s)
64 return m && (m[1].length == 40 ? m[1]+'...' : m[1])
75 }
86
9-exports.message_name = function (id, cb) {
10- sbot_get(id, function (err, value) {
11- if(err && err.name == 'NotFoundError')
12- return cb(null, id.substring(0, 10)+'...(missing)')
13- if(value.content.type === 'post' && 'string' === typeof value.content.text)
14- return cb(null, title(value.content.text))
15- else if('string' === typeof value.content.text)
16- return cb(null, value.content.type + ':'+title(value.content.text))
17- else
18- return cb(null, id.substring(0, 10)+'...')
19- })
7 +exports.needs = { sbot_get: 'first' }
8 +exports.gives = 'message_name'
9 +
10 +//TODO: rewrite as observable?
11 +
12 +exports.create = function (api) {
13 + return function (id, cb) {
14 + api.sbot_get(id, function (err, value) {
15 + if(err && err.name == 'NotFoundError')
16 + return cb(null, id.substring(0, 10)+'...(missing)')
17 + if(value.content.type === 'post' && 'string' === typeof value.content.text)
18 + return cb(null, title(value.content.text))
19 + else if('string' === typeof value.content.text)
20 + return cb(null, value.content.type + ':'+title(value.content.text))
21 + else
22 + return cb(null, id.substring(0, 10)+'...')
23 + })
24 + }
2025 }
2126
modules_basic/message.jsView
@@ -1,109 +1,122 @@
11 var h = require('hyperscript')
22 var u = require('../util')
33 var pull = require('pull-stream')
44
5-var plugs = require('../plugs')
6-var message_content = plugs.first(exports.message_content = [])
7-var message_content_mini = plugs.first(exports.message_content_mini = [])
8-var avatar = plugs.first(exports.avatar = [])
9-var avatar_name = plugs.first(exports.avatar_name = [])
10-var avatar_link = plugs.first(exports.avatar_link = [])
11-var message_meta = plugs.map(exports.message_meta = [])
12-var message_action = plugs.map(exports.message_action = [])
13-var message_link = plugs.first(exports.message_link = [])
5 +//var plugs = require('../plugs')
6 +//
7 +//var message_content = plugs.first(exports.message_content = [])
8 +//var message_content_mini = plugs.first(exports.message_content_mini = [])
9 +//
10 +//var avatar = plugs.first(exports.avatar = [])
11 +//var avatar_name = plugs.first(exports.avatar_name = [])
12 +//var avatar_link = plugs.first(exports.avatar_link = [])
13 +//var message_meta = plugs.map(exports.message_meta = [])
14 +//var message_action = plugs.map(exports.message_action = [])
15 +//var message_link = plugs.first(exports.message_link = [])
16 +//
17 +//var sbot_links = plugs.first(exports.sbot_links = [])
1418
15-var sbot_links = plugs.first(exports.sbot_links = [])
16-
17-function mini(msg, el) {
18- var div = h('div.message.message--mini',
19- h('div.row',
20- h('div',
21- avatar_link(msg.value.author, avatar_name(msg.value.author)),
22- h('span.message_content', el)),
23- h('div.message_meta.row', message_meta(msg))
24- )
25- )
26- div.setAttribute('tabindex', '0')
27- return div
19 +exports.needs = {
20 + message_content: 'first',
21 + message_content_mini: 'first',
22 + avatar: 'first',
23 + avatar_name: 'first',
24 + avatar_link: 'first',
25 + message_meta: 'map',
26 + message_action: 'map',
27 + message_link: 'first',
28 +// sbot_links: 'first'
2829 }
2930
31 +exports.gives = 'message_render'
32 +
3033 function message_content_mini_fallback(msg) {
3134 return h('code', msg.value.content.type)
3235 }
3336
34-exports.message_render = function (msg, sbot) {
35- var el = message_content_mini(msg)
36- if(el) return mini(msg, el)
37 +exports.create = function (api) {
3738
38- var el = message_content(msg)
39- if(!el) return mini(msg, message_content_mini_fallback(msg))
40-
41- var links = []
42- for(var k in CACHE) {
43- var _msg = CACHE[k]
44- if(Array.isArray(_msg.content.mentions)) {
45- for(var i = 0; i < _msg.content.mentions.length; i++)
46- if(_msg.content.mentions[i].link == msg.key)
47- links.push(k)
48- }
39 + function mini(msg, el) {
40 + var div = h('div.message.message--mini',
41 + h('div.row',
42 + h('div',
43 + api.avatar_link(msg.value.author, api.avatar_name(msg.value.author)),
44 + h('span.message_content', el)),
45 + h('div.message_meta.row', api.message_meta(msg))
46 + )
47 + )
48 + div.setAttribute('tabindex', '0')
49 + return div
4950 }
5051
51- var backlinks = h('div.backlinks')
52- if(links.length)
53- backlinks.appendChild(h('label', 'backlinks:',
54- h('div', links.map(function (key) {
55- return message_link(key)
56- }))
57- ))
52 + return function (msg, sbot) {
53 + var el = api.message_content_mini(msg)
54 + if(el) return mini(msg, el)
5855
56 + var el = api.message_content(msg)
57 + if(!el) return mini(msg, message_content_mini_fallback(msg))
5958
60-// pull(
61-// sbot_links({dest: msg.key, rel: 'mentions', keys: true}),
62-// pull.collect(function (err, links) {
63-// if(links.length)
64-// backlinks.appendChild(h('label', 'backlinks:',
65-// h('div', links.map(function (link) {
66-// return message_link(link.key)
67-// }))
68-// ))
69-// })
70-// )
71-
72- var msg = h('div.message',
73- h('div.title.row',
74- h('div.avatar', avatar(msg.value.author, 'thumbnail')),
75- h('div.message_meta.row', message_meta(msg))
76- ),
77- h('div.message_content', el),
78- h('div.message_actions.row',
79- h('div.actions', message_action(msg),
80- h('a', {href: '#' + msg.key}, 'Reply')
81- )
82- ),
83- backlinks,
84- {onkeydown: function (ev) {
85- //on enter, hit first meta.
86- if(ev.keyCode == 13) {
87-
88- // unless in an input
89- if (ev.target.nodeName === 'INPUT'
90- || ev.target.nodeName === 'TEXTAREA') return
91-
92- msg.querySelector('.enter').click()
59 + var links = []
60 + for(var k in CACHE) {
61 + var _msg = CACHE[k]
62 + if(Array.isArray(_msg.content.mentions)) {
63 + for(var i = 0; i < _msg.content.mentions.length; i++)
64 + if(_msg.content.mentions[i].link == msg.key)
65 + links.push(k)
9366 }
94- }}
95- )
67 + }
9668
97- // ); hyperscript does not seem to set attributes correctly.
98- msg.setAttribute('tabindex', '0')
69 + var backlinks = h('div.backlinks')
70 + if(links.length)
71 + backlinks.appendChild(h('label', 'backlinks:',
72 + h('div', links.map(function (key) {
73 + return api.message_link(key)
74 + }))
75 + ))
9976
100- return msg
101-}
10277
78 + // pull(
79 + // sbot_links({dest: msg.key, rel: 'mentions', keys: true}),
80 + // pull.collect(function (err, links) {
81 + // if(links.length)
82 + // backlinks.appendChild(h('label', 'backlinks:',
83 + // h('div', links.map(function (link) {
84 + // return message_link(link.key)
85 + // }))
86 + // ))
87 + // })
88 + // )
10389
90 + var msg = h('div.message',
91 + h('div.title.row',
92 + h('div.avatar', api.avatar(msg.value.author, 'thumbnail')),
93 + h('div.message_meta.row', api.message_meta(msg))
94 + ),
95 + h('div.message_content', el),
96 + h('div.message_actions.row',
97 + h('div.actions', api.message_action(msg),
98 + h('a', {href: '#' + msg.key}, 'Reply')
99 + )
100 + ),
101 + backlinks,
102 + {onkeydown: function (ev) {
103 + //on enter, hit first meta.
104 + if(ev.keyCode == 13) {
104105
106 + // unless in an input
107 + if (ev.target.nodeName === 'INPUT'
108 + || ev.target.nodeName === 'TEXTAREA') return
105109
110 + msg.querySelector('.enter').click()
111 + }
112 + }}
113 + )
106114
115 + // ); hyperscript does not seem to set attributes correctly.
116 + msg.setAttribute('tabindex', '0')
107117
118 + return msg
119 + }
120 +}
108121
109122
modules_basic/names.jsView
@@ -5,12 +5,23 @@
55 function all(stream, cb) {
66 pull(stream, pull.collect(cb))
77 }
88
9-var plugs = require('../plugs')
10-var sbot_links2 = plugs.first(exports.sbot_links2 = [])
11-var sbot_query = plugs.first(exports.sbot_query = [])
9 +//var plugs = require('../plugs')
10 +//var sbot_links2 = plugs.first(exports.sbot_links2 = [])
11 +//var sbot_query = plugs.first(exports.sbot_query = [])
12 +//
13 +exports.needs = {
14 + sbot_links2: 'first',
15 + sbot_query: 'first'
16 +}
1217
18 +exports.gives = {
19 + connection_status: true,
20 + signifier: true,
21 + signified: true,
22 +}
23 +
1324 /*
1425 filter(rel: ['mentions', prefix('@')]) | reduce(name: rel[1], value: count())
1526 */
1627
@@ -107,63 +118,66 @@
107118 ts: "timestamp"
108119 }},
109120 reduce
110121 ]
122 +exports.create = function (api) {
111123
124 + var exports = {}
125 + exports.connection_status = function (err) {
126 + if(!err) {
127 + pull(
128 + many([
129 + api.sbot_links2({query: [filter, map, reduce]}),
130 + add_sigil(api.sbot_query({query: [filter2, map2, reduce]})),
131 + add_sigil(api.sbot_query({query: queryNamedGitRepos}))
132 + ]),
133 + //reducing also ensures order by the lookup properties
134 + //in this case: [name, id]
135 + mfr.reduce(merge),
136 + pull.collect(function (err, ary) {
137 + if(!err) {
138 + NAMES = names = ary
139 + ready = true
140 + while(waiting.length) waiting.shift()()
141 + }
142 + })
143 + )
112144
113-exports.connection_status = function (err) {
114- if(!err) {
115- pull(
116- many([
117- sbot_links2({query: [filter, map, reduce]}),
118- add_sigil(sbot_query({query: [filter2, map2, reduce]})),
119- add_sigil(sbot_query({query: queryNamedGitRepos}))
145 + pull(many([
146 + api.sbot_links2({query: [filter, map], old: false}),
147 + add_sigil(api.sbot_query({query: [filter2, map2], old: false})),
148 + add_sigil(api.sbot_query({query: queryNamedGitRepos, old: false}))
120149 ]),
121- //reducing also ensures order by the lookup properties
122- //in this case: [name, id]
123- mfr.reduce(merge),
124- pull.collect(function (err, ary) {
125- if(!err) {
126- NAMES = names = ary
127- ready = true
128- while(waiting.length) waiting.shift()()
129- }
130- })
131- )
150 + pull.drain(update))
151 + }
152 + }
132153
133- pull(many([
134- sbot_links2({query: [filter, map], old: false}),
135- add_sigil(sbot_query({query: [filter2, map2], old: false})),
136- add_sigil(sbot_query({query: queryNamedGitRepos, old: false}))
137- ]),
138- pull.drain(update))
154 + function async(fn) {
155 + return function (value, cb) {
156 + function go () { cb(null, fn(value)) }
157 + if(ready) go()
158 + else waiting.push(go)
159 + }
139160 }
140-}
141161
142-function async(fn) {
143- return function (value, cb) {
144- function go () { cb(null, fn(value)) }
145- if(ready) go()
146- else waiting.push(go)
162 + function rank(ary) {
163 + //sort by most used, or most recently used
164 + return ary.sort(function (a, b) { return b.rank - a.rank || b.ts - a.ts })
147165 }
148-}
149166
150-function rank(ary) {
151- //sort by most used, or most recently used
152- return ary.sort(function (a, b) { return b.rank - a.rank || b.ts - a.ts })
153-}
167 + //we are just iterating over the entire array.
168 + //if this becomes a problem, maintain two arrays
169 + //one of each sort order, but do not duplicate the objects.
170 + //that should mean the space required is just 2x object references,
171 + //not 2x objects, and we can use binary search to find matches.
154172
155-//we are just iterating over the entire array.
156-//if this becomes a problem, maintain two arrays
157-//one of each sort order, but do not duplicate the objects.
158-//that should mean the space required is just 2x object references,
159-//not 2x objects, and we can use binary search to find matches.
173 + exports.signifier = async(function (id) {
174 + return rank(names.filter(function (e) { return e.id == id}))
175 + })
160176
161-exports.signifier = async(function (id) {
162- return rank(names.filter(function (e) { return e.id == id}))
163-})
177 + exports.signified = async(function (name) {
178 + var rx = new RegExp('^'+name)
179 + return rank(names.filter(function (e) { return rx.test(e.name) }))
180 + })
164181
165-exports.signified = async(function (name) {
166- var rx = new RegExp('^'+name)
167- return rank(names.filter(function (e) { return rx.test(e.name) }))
168-})
169-
182 + return exports
183 +}
modules_basic/post.jsView
@@ -4,23 +4,30 @@
44 var ref = require('ssb-ref')
55
66 //render a message
77
8-var plugs = require('../plugs')
9-var message_link = plugs.first(exports.message_link = [])
10-var markdown = plugs.first(exports.markdown = [])
8 +//var plugs = require('../plugs')
9 +//var message_link = plugs.first(exports.message_link = [])
10 +//var markdown = plugs.first(exports.markdown = [])
11 +//
1112
12-exports.message_content = function (data) {
13- if(!data.value.content || !data.value.content.text) return
13 +exports.needs = { message_link: 'first', markdown: 'first' }
1414
15- var root = data.value.content.root
16- var re = !root ? null : h('span', 're: ', message_link(root))
15 +exports.gives = 'message_content'
1716
18- return h('div',
19- re,
20- markdown(data.value.content)
21- )
17 +exports.create = function (api) {
18 + return function (data) {
19 + if(!data.value.content || !data.value.content.text) return
2220
21 + var root = data.value.content.root
22 + var re = !root ? null : h('span', 're: ', api.message_link(root))
23 +
24 + return h('div',
25 + re,
26 + api.markdown(data.value.content)
27 + )
28 +
29 + }
2330 }
2431
2532
2633
@@ -33,5 +40,4 @@
3340
3441
3542
3643
37-
modules_basic/private.jsView
@@ -1,105 +1,128 @@
1 +'use strict'
12 var h = require('hyperscript')
23 var u = require('../util')
34 var pull = require('pull-stream')
45 var Scroller = require('pull-scroll')
56 var ref = require('ssb-ref')
67
7-var plugs = require('../plugs')
8 +//var plugs = require('../plugs')
9 +//
10 +//var message_render = plugs.first(exports.message_render = [])
11 +//var message_compose = plugs.first(exports.message_compose = [])
12 +//var message_unbox = plugs.first(exports.message_unbox = [])
13 +//var sbot_log = plugs.first(exports.sbot_log = [])
14 +//var sbot_whoami = plugs.first(exports.sbot_whoami = [])
15 +//var avatar_image_link = plugs.first(exports.avatar_image_link = [])
16 +//var emoji_url = plugs.first(exports.emoji_url = [])
817
9-var message_render = plugs.first(exports.message_render = [])
10-var message_compose = plugs.first(exports.message_compose = [])
11-var message_unbox = plugs.first(exports.message_unbox = [])
12-var sbot_log = plugs.first(exports.sbot_log = [])
13-var sbot_whoami = plugs.first(exports.sbot_whoami = [])
14-var avatar_image_link = plugs.first(exports.avatar_image_link = [])
15-var emoji_url = plugs.first(exports.emoji_url = [])
18 +function map(ary, iter) {
19 + if(Array.isArray(ary)) return ary.map(iter)
20 +}
1621
17-function unbox () {
18- return pull(
19- pull.filter(function (msg) {
20- return 'string' == typeof msg.value.content
21- }),
22- pull.map(function (msg) {
23- return message_unbox(msg)
24- }),
25- pull.filter(Boolean)
26- )
22 +exports.needs = {
23 + message_render: 'first',
24 + message_compose: 'first',
25 + message_unbox: 'first',
26 + sbot_log: 'first',
27 + sbot_whoami: 'first',
28 + avatar_image_link: 'first',
29 +// emoji_link: 'first'
2730 }
2831
29-exports.builtin_tabs = function () {
30- return ['/private']
32 +exports.gives = {
33 + builtin_tabs: true,
34 + screen_view: true,
35 + message_meta: true,
36 + message_content_mini: true
3137 }
3238
33-exports.screen_view = function (path) {
34- if(path !== '/private') return
39 +exports.create = function (api) {
3540
36- var div = h('div.column.scroller',
37- {style: {'overflow':'auto'}})
41 + function unbox () {
42 + return pull(
43 + pull.filter(function (msg) {
44 + return 'string' == typeof msg.value.content
45 + }),
46 + pull.map(function (msg) {
47 + return api.message_unbox(msg)
48 + }),
49 + pull.filter(Boolean)
50 + )
51 + }
3852
39- // if local id is different from sbot id, sbot won't have indexes of
40- // private threads
41- var id = require('../keys').id
42- sbot_whoami(function (err, feed) {
43- if (err) return console.error(err)
44- if(id !== feed.id)
45- return div.appendChild(h('h4',
46- 'Private messages are not supported in the lite client.'))
53 + return {
54 + builtin_tabs: function () {
55 + return ['/private']
56 + },
4757
48- var compose = message_compose(
49- {type: 'post', recps: [], private: true},
50- {
51- prepublish: function (msg) {
52- msg.recps = [id].concat(msg.mentions).filter(function (e) {
53- return ref.isFeed('string' === typeof e ? e : e.link)
54- })
55- if(!msg.recps.length)
56- throw new Error('cannot make private message without recipients - just mention the user in an at reply in the message you send')
57- return msg
58- },
59- placeholder: 'Write a private message'
60- }
61- )
58 + screen_view: function (path) {
59 + if(path !== '/private') return
6260
63- var content = h('div.column.scroller__content')
64- div.appendChild(h('div.scroller__wrapper', compose, content))
61 + var div = h('div.column.scroller',
62 + {style: {'overflow':'auto'}})
6563
66- pull(
67- u.next(sbot_log, {old: false, limit: 100}),
68- unbox(),
69- Scroller(div, content, message_render, true, false)
70- )
64 + // if local id is different from sbot id, sbot won't have indexes of
65 + // private threads
66 + //TODO: put all private indexes client side.
67 + var id = require('../keys').id
68 + api.sbot_whoami(function (err, feed) {
69 + if (err) return console.error(err)
70 + if(id !== feed.id)
71 + return div.appendChild(h('h4',
72 + 'Private messages are not supported in the lite client.'))
7173
72- pull(
73- u.next(sbot_log, {reverse: true, limit: 1000}),
74- unbox(),
75- Scroller(div, content, message_render, false, false, function (err) {
76- if(err) throw err
74 + var compose = api.message_compose(
75 + {type: 'post', recps: [], private: true},
76 + {
77 + prepublish: function (msg) {
78 + msg.recps = [id].concat(msg.mentions).filter(function (e) {
79 + return ref.isFeed('string' === typeof e ? e : e.link)
80 + })
81 + if(!msg.recps.length)
82 + throw new Error('cannot make private message without recipients - just mention the user in an at reply in the message you send')
83 + return msg
84 + },
85 + placeholder: 'Write a private message'
86 + }
87 + )
88 +
89 + var content = h('div.column.scroller__content')
90 + div.appendChild(h('div.scroller__wrapper', compose, content))
91 +
92 + pull(
93 + u.next(api.sbot_log, {old: false, limit: 100}),
94 + unbox(),
95 + Scroller(div, content, api.message_render, true, false)
96 + )
97 +
98 + pull(
99 + u.next(api.sbot_log, {reverse: true, limit: 1000}),
100 + unbox(),
101 + Scroller(div, content, api.message_render, false, false, function (err) {
102 + if(err) throw err
103 + })
104 + )
77105 })
78- )
79- })
80106
81- return div
82-}
107 + return div
108 + },
83109
84-function map(ary, iter) {
85- if(Array.isArray(ary)) return ary.map(iter)
86-}
110 + message_meta: function (msg) {
111 + if(msg.value.content.recps || msg.value.private)
112 + return h('span.row', 'PRIVATE', map(msg.value.content.recps, function (id) {
113 + return api.avatar_image_link('string' == typeof id ? id : id.link, 'thumbnail')
114 + }))
115 + },
87116
88-exports.message_meta = function (msg) {
89- if(msg.value.content.recps || msg.value.private)
90- return h('span.row', 'PRIVATE', map(msg.value.content.recps, function (id) {
91- return avatar_image_link('string' == typeof id ? id : id.link, 'thumbnail')
92- }))
93-}
117 + message_content_mini: function (msg, sbot) {
118 + if (typeof msg.value.content === 'string') {
119 + var icon = false //api.emoji_url('lock')
120 + return icon
121 + ? h('img', {className: 'emoji', src: icon})
122 + : 'PRIVATE'
123 + }
124 + }
125 + }
94126
95-exports.message_content_mini = function (msg, sbot) {
96- if (typeof msg.value.content === 'string') {
97- var icon = emoji_url('lock')
98- return icon
99- ? h('img', {className: 'emoji', src: icon})
100- : 'PRIVATE'
101- }
102127 }
103128
104-
105-
modules_basic/pub.jsView
@@ -1,18 +1,29 @@
11 var h = require('hyperscript')
2-var plugs = require('../plugs')
3-var avatar_name = plugs.first(exports.avatar_name = [])
4-var avatar_link = plugs.first(exports.avatar_link = [])
2 +//var plugs = require('../plugs')
3 +//var avatar_name = plugs.first(exports.avatar_name = [])
4 +//var avatar_link = plugs.first(exports.avatar_link = [])
5 +//
6 +exports.needs = {
7 + avatar_name: 'first',
8 + avatar_link: 'first'
9 +}
510
6-exports.message_content = function (msg, sbot) {
7- var c = msg.value.content
8- if (c.type === 'pub') {
9- var address = c.address || {}
10- return [
11- h('p', 'announced an address for ',
12- avatar_link(address.key, avatar_name(address.key)), ':'),
13- h('blockquote',
14- h('code', address.host + ':' + address.port)
15- )
16- ]
11 +exports.gives = 'message_content'
12 +
13 +exports.create = function (api) {
14 +
15 + return function (msg, sbot) {
16 + var c = msg.value.content
17 + if (c.type === 'pub') {
18 + var address = c.address || {}
19 + return [
20 + h('p', 'announced an address for ',
21 + api.avatar_link(address.key, api.avatar_name(address.key)), ':'),
22 + h('blockquote',
23 + h('code', address.host + ':' + address.port)
24 + )
25 + ]
26 + }
1727 }
28 +
1829 }
modules_basic/public.jsView
@@ -2,39 +2,53 @@
22 var u = require('../util')
33 var pull = require('pull-stream')
44 var Scroller = require('pull-scroll')
55
6-var plugs = require('../plugs')
7-var message_render = plugs.first(exports.message_render = [])
8-var message_compose = plugs.first(exports.message_compose = [])
9-var sbot_log = plugs.first(exports.sbot_log = [])
6 +//var plugs = require('../plugs')
7 +//var message_render = plugs.first(exports.message_render = [])
8 +//var message_compose = plugs.first(exports.message_compose = [])
9 +//var sbot_log = plugs.first(exports.sbot_log = [])
1010
11-exports.builtin_tabs = function () {
12- return ['/public']
11 +exports.needs = {
12 + message_render: 'first',
13 + message_compose: 'first',
14 + sbot_log: 'first',
1315 }
1416
15-exports.screen_view = function (path, sbot) {
16- if(path === '/public') {
17 +exports.gives = {
18 + builtin_tabs: true, screen_view: true
19 +}
1720
18- var content = h('div.column.scroller__content')
19- var div = h('div.column.scroller',
20- {style: {'overflow':'auto'}},
21- h('div.scroller__wrapper',
22- message_compose({type: 'post'}, {placeholder: 'Write a public message'}),
23- content
24- )
25- )
21 +exports.create = function (api) {
2622
27- pull(
28- u.next(sbot_log, {old: false, limit: 100}),
29- Scroller(div, content, message_render, true, false)
30- )
23 + return {
24 + builtin_tabs: function () {
25 + return ['/public']
26 + },
3127
32- pull(
33- u.next(sbot_log, {reverse: true, limit: 100, live: false}),
34- Scroller(div, content, message_render, false, false)
35- )
28 + screen_view: function (path, sbot) {
29 + if(path === '/public') {
3630
37- return div
31 + var content = h('div.column.scroller__content')
32 + var div = h('div.column.scroller',
33 + {style: {'overflow':'auto'}},
34 + h('div.scroller__wrapper',
35 + api.message_compose({type: 'post'}, {placeholder: 'Write a public message'}),
36 + content
37 + )
38 + )
39 +
40 + pull(
41 + u.next(api.sbot_log, {old: false, limit: 100}),
42 + Scroller(div, content, api.message_render, true, false)
43 + )
44 +
45 + pull(
46 + u.next(api.sbot_log, {reverse: true, limit: 100, live: false}),
47 + Scroller(div, content, api.message_render, false, false)
48 + )
49 +
50 + return div
51 + }
52 + }
3853 }
3954 }
40-
modules_basic/relationships.jsView
@@ -1,8 +1,8 @@
11 var pull = require('pull-stream')
2-var plugs = require('../plugs')
2 +//var plugs = require('../plugs')
33
4-var sbot_query = plugs.first(exports.sbot_query = [])
4 +//var sbot_query = plugs.first(exports.sbot_query = [])
55
66 //this is a bit crude, and doesn't actually show unfollows yet.
77
88 function makeQuery (a, b) {
@@ -18,33 +18,45 @@
1818 }}
1919 }
2020
2121
22-exports.follows = function (id, cb) {
23- return sbot_query({query: [
24- makeQuery(id, {$prefix:"@"}),
25- {"$map": ['value', 'content', 'contact']}
26- ]})
27-}
22 +exports.needs = { sbot_query: 'first' }
2823
29-exports.followers = function (id) {
30- return sbot_query({query: [
31- makeQuery({$prefix:"@"}, id),
32- {"$map": ['value', 'author']}
33- ]})
24 +exports.gives = {
25 + follows: true,
26 + followers: true,
27 + follower_of: true
3428 }
3529
36-exports.follower_of = function (source, dest, cb) {
37- pull(
38- sbot_query({query: [
39- makeQuery(source, dest),
40- {$map: ['value', 'content', 'following']}
41- ]}),
42- pull.collect(function (err, ary) {
43- if(err) return cb(err)
44- else cb(null, ary.pop()) //will be true, or undefined/false
45- })
46- )
47-}
30 +exports.create = function (api) {
4831
32 + return {
33 + follows: function (id, cb) {
34 + return api.sbot_query({query: [
35 + makeQuery(id, {$prefix:"@"}),
36 + {"$map": ['value', 'content', 'contact']}
37 + ]})
38 + },
4939
40 + followers: function (id) {
41 + return api.sbot_query({query: [
42 + makeQuery({$prefix:"@"}, id),
43 + {"$map": ['value', 'author']}
44 + ]})
45 + },
5046
47 + follower_of: function (source, dest, cb) {
48 + pull(
49 + api.sbot_query({query: [
50 + makeQuery(source, dest),
51 + {$map: ['value', 'content', 'following']}
52 + ]}),
53 + pull.collect(function (err, ary) {
54 + if(err) return cb(err)
55 + else cb(null, ary.pop()) //will be true, or undefined/false
56 + })
57 + )
58 + }
59 + }
60 +
61 +}
62 +
modules_basic/search-box.jsView
@@ -1,55 +1,74 @@
1 +'use strict'
2 +var cont = require('cont')
13 var h = require('hyperscript')
24 var suggest = require('suggest-box')
35 var pull = require('pull-stream')
4-var plugs = require('../plugs')
5-var sbot_query = plugs.first(exports.sbot_query = [])
6-var sbot_links2 = plugs.first(exports.sbot_links2 = [])
7-var suggest_search = plugs.asyncConcat(exports.suggest_search = [])
86
7 +//var plugs = require('../plugs')
8 +//var sbot_query = plugs.first(exports.sbot_query = [])
9 +//var sbot_links2 = plugs.first(exports.sbot_links2 = [])
10 +//var suggest_search = plugs.asyncConcat(exports.suggest_search = [])
11 +
12 +exports.needs = {
13 + sbot_query: 'first', sbot_links2: 'first',
14 + suggest_search: 'map' //REWRITE
15 +}
16 +
917 var channels = []
1018
19 +exports.gives = 'search_box'
1120
12-exports.search_box = function (go) {
21 +exports.create = function (api) {
1322
14- var suggestBox
15- var search = h('input.searchprompt', {
16- type: 'search',
17- placeholder: 'Commands',
18- onkeydown: function (ev) {
19- switch (ev.keyCode) {
20- case 13: // enter
21- if (suggestBox && suggestBox.active) {
22- suggestBox.complete()
23- ev.stopPropagation()
24- }
25- if (go(search.value.trim(), !ev.ctrlKey))
23 + return function (go) {
24 +
25 + var suggestBox
26 + var search = h('input.searchprompt', {
27 + type: 'search',
28 + placeholder: 'Commands',
29 + onkeydown: function (ev) {
30 + switch (ev.keyCode) {
31 + case 13: // enter
32 + if (suggestBox && suggestBox.active) {
33 + suggestBox.complete()
34 + ev.stopPropagation()
35 + }
36 + if (go(search.value.trim(), !ev.ctrlKey))
37 + search.blur()
38 + return
39 + case 27: // escape
40 + ev.preventDefault()
2641 search.blur()
27- return
28- case 27: // escape
29- ev.preventDefault()
30- search.blur()
31- return
42 + return
43 + }
3244 }
45 + })
46 +
47 + search.activate = function (sigil, ev) {
48 + search.focus()
49 + ev.preventDefault()
50 + if (search.value[0] === sigil) {
51 + search.selectionStart = 1
52 + search.selectionEnd = search.value.length
53 + } else {
54 + search.value = sigil
55 + }
3356 }
34- })
3557
36- search.activate = function (sigil, ev) {
37- search.focus()
38- ev.preventDefault()
39- if (search.value[0] === sigil) {
40- search.selectionStart = 1
41- search.selectionEnd = search.value.length
42- } else {
43- search.value = sigil
44- }
58 + var suggestions = {}
59 +
60 + // delay until the element has a parent
61 + setTimeout(function () {
62 + suggestBox = suggest(search, function (word, cb) {
63 + cont.para(api.suggest_search.map(function (e) {
64 + return function (cb) { e(word, cb) }
65 + }))(cb)
66 + }, {})
67 + }, 10)
68 +
69 + return search
4570 }
4671
47- var suggestions = {}
72 +}
4873
49- // delay until the element has a parent
50- setTimeout(function () {
51- suggestBox = suggest(search, suggest_search, {})
52- }, 10)
5374
54- return search
55-}
modules_basic/setup.jsView
@@ -1,16 +1,25 @@
11
22 var h = require('hyperscript')
33 var pull = require('pull-stream')
44
5-var plugs = require('../plugs')
5 +//var plugs = require('../plugs')
6 +//
7 +//var avatar_edit = plugs.first(exports.avatar_edit = [])
8 +//var invite_parse = plugs.first(exports.invite_parse = [])
9 +//var invite_accept = plugs.first(exports.invite_accept = [])
10 +//var sbot_progress = plugs.first(exports.sbot_progress = [])
11 +//var sbot_query = plugs.first(exports.sbot_query = [])
12 +//var avatar = plugs.first(exports.avatar = [])
613
7-var avatar_edit = plugs.first(exports.avatar_edit = [])
8-var invite_parse = plugs.first(exports.invite_parse = [])
9-var invite_accept = plugs.first(exports.invite_accept = [])
10-var sbot_progress = plugs.first(exports.sbot_progress = [])
11-var sbot_query = plugs.first(exports.sbot_query = [])
12-var avatar = plugs.first(exports.avatar = [])
14 +exports.needs = {
15 + avatar: 'first',
16 + avatar_edit: 'first',
17 + invite_parse: 'first',
18 + invite_accept: 'first',
19 + sbot_progress: 'first',
20 + sbot_query: 'first'
21 +}
1322
1423 //maybe this could show the pubs, or
1524 //if someone locally follows you,
1625 //it could show the second degree pubs?
@@ -27,119 +36,125 @@
2736 }}
2837 }}]
2938 }
3039
31-//test whether we are connected to the ssb network.
32-exports.setup_is_fresh_install = function (cb) {
33- //test by checking whether you have any friends following you?
34- pull(
35- sbot_query({query: followers_query(id), limit: 1, live: false}),
36- pull.collect(function (err, ary) {
37- cb(err, !!ary.length)
38- })
39- )
40-}
40 +exports.create = function (api) {
4141
42-function invite_form () {
43- var accept = h('button', 'enter code', {disabled: true, onclick: function () {
44- invite_accept(input.value, function (msg) {
45- status.textContent = msg
46- }, function (err) {
47- if(err) {
48- accept.textContent = 'error:'+(err.message || err.stack || error.type)
49- console.error(err)
42 + var exports = {}
43 +
44 + //test whether we are connected to the ssb network.
45 + exports.setup_is_fresh_install = function (cb) {
46 + //test by checking whether you have any friends following you?
47 + pull(
48 + api.sbot_query({query: followers_query(id), limit: 1, live: false}),
49 + pull.collect(function (err, ary) {
50 + cb(err, !!ary.length)
51 + })
52 + )
53 + }
54 +
55 + function invite_form () {
56 + var accept = h('button', 'enter code', {disabled: true, onclick: function () {
57 + api.invite_accept(input.value, function (msg) {
58 + status.textContent = msg
59 + }, function (err) {
60 + if(err) {
61 + accept.textContent = 'error:'+(err.message || err.stack || error.type)
62 + console.error(err)
63 + }
64 + else {
65 + input.value = ''
66 + accept.textContent = 'success!'
67 + }
68 + })
69 + }})
70 +
71 + function parseInput () {
72 + if(!input.value) {
73 + accept.disabled = true
74 + accept.textContent = 'enter code'
5075 }
76 + else if(!invite_parse(input.value)) {
77 + accept.disabled = true
78 + accept.textContent = 'invalid code'
79 + }
5180 else {
52- input.value = ''
53- accept.textContent = 'success!'
81 + accept.disabled = false
82 + accept.textContent = 'accept'
5483 }
55- })
56- }})
84 + }
5785
58- function parseInput () {
59- if(!input.value) {
60- accept.disabled = true
61- accept.textContent = 'enter code'
62- }
63- else if(!invite_parse(input.value)) {
64- accept.disabled = true
65- accept.textContent = 'invalid code'
66- }
67- else {
68- accept.disabled = false
69- accept.textContent = 'accept'
70- }
86 + var input = h('input.wide', {placeholder: 'invite code', oninput: parseInput, onchange: parseInput})
87 +
88 + return h('div.invite-form.row', input, accept)
7189 }
7290
73- var input = h('input.wide', {placeholder: 'invite code', oninput: parseInput, onchange: parseInput})
91 + exports.progress_bar = function () {
92 + var liquid = h('div.hyperprogress__liquid', '.')
93 + var bar = h('div.hyperprogress__bar', liquid)
94 + liquid.style.width = '0%'
7495
75- return h('div.invite-form.row', input, accept)
76-}
96 + pull(
97 + api.sbot_progress(),
98 + pull.drain(function (e) {
99 + liquid.style.width = Math.round((e.progress/e.total)*100)+'%'
100 + })
101 + )
77102
78-exports.progress_bar = function () {
79- var liquid = h('div.hyperprogress__liquid', '.')
80- var bar = h('div.hyperprogress__bar', liquid)
81- liquid.style.width = '0%'
103 + return bar
104 + }
82105
83- pull(
84- sbot_progress(),
85- pull.drain(function (e) {
86- liquid.style.width = Math.round((e.progress/e.total)*100)+'%'
87- })
88- )
106 + //show the first 5 followers, and how they join you to the network.
107 + //so this will show if a local peer follows you.
89108
90- return bar
91-}
109 + //when you join the network, I want this to show as people follow you.
110 + //that could be when a pub accepts the invite, or when a local peer accepts.
92111
93-//show the first 5 followers, and how they join you to the network.
94-//so this will show if a local peer follows you.
112 + exports.setup_joined_network = function (id) {
113 + var followers = h('div.column')
114 + var label = h('label', 'not connected to a network')
115 + var joined = h('div.setup__joined', label, followers)
95116
96-//when you join the network, I want this to show as people follow you.
97-//that could be when a pub accepts the invite, or when a local peer accepts.
117 + pull(
118 + api.sbot_query({query: followers_query(id), limit: 5, live: true, sync: false}),
119 + pull.drain(function (follower) {
120 + if(follower.sync) return
121 + label.textContent = 'connected to network via...'
122 + followers.appendChild(
123 + api.avatar(follower.value.author, 'thumbnail')
124 + )
125 + })
126 + )
98127
99-exports.setup_joined_network = function (id) {
100- var followers = h('div.column')
101- var label = h('label', 'not connected to a network')
102- var joined = h('div.setup__joined', label,followers)
128 + return joined
129 + }
103130
104- pull(
105- sbot_query({query: followers_query(id), limit: 5, live: true, sync: false}),
106- pull.drain(function (follower) {
107- if(follower.sync) return
108- label.textContent = 'connected to network via...'
109- followers.appendChild(
110- avatar(follower.value.author, 'thumbnail')
111- )
112- })
113- )
131 + exports.screen_view = function (path) {
114132
115- return joined
116-}
133 + if(path !== '/setup') return
117134
118-exports.screen_view = function (path) {
135 + var id = require('../keys').id
119136
120- if(path !== '/setup') return
137 + //set up an avatar
121138
122- var id = require('../keys').id
123139
124- //set up an avatar
140 + var status = h('span')
141 + var invite = h('input', {placeholder: 'invite code'})
142 + return h('div.scroller', h('div.scroller__wrapper',
143 + h('h1', 'welcome to patchbay!'),
144 + h('div',
145 + 'please choose avatar image and name',
146 + api.avatar_edit(id)
147 + ),
148 + h('h2', 'join network'),
149 + invite_form(),
150 + //show avatars of anyone on the same local network.
151 + //show realtime changes in your followers, especially for local.
125152
153 + exports.progress_bar(),
154 + exports.setup_joined_network(require('../keys').id)
155 + ))
156 + }
126157
127- var status = h('span')
128- var invite = h('input', {placeholder: 'invite code'})
129- return h('div.scroller', h('div.scroller__wrapper',
130- h('h1', 'welcome to patchbay!'),
131- h('div',
132- 'please choose avatar image and name',
133- avatar_edit(id)
134- ),
135- h('h2', 'join network'),
136- invite_form(),
137- //show avatars of anyone on the same local network.
138- //show realtime changes in your followers, especially for local.
158 + return exports
139159
140- exports.progress_bar(),
141- exports.setup_joined_network(require('../keys').id)
142- ))
143160 }
144-
145-
modules_basic/suggest-mentions.jsView
@@ -2,64 +2,69 @@
22 function isImage (filename) {
33 return /\.(gif|jpg|png|svg)$/i.test(filename)
44 }
55
6-var sbot_links2 = require('../plugs').first(exports.sbot_links2 = [])
7-var blob_url = require('../plugs').first(exports.blob_url = [])
8-var signified = require('../plugs').first(exports.signified = [])
9-var builtin_tabs = require('../plugs').map(exports.builtin_tabs = [])
6 +//var sbot_links2 = require('../plugs').first(exports.sbot_links2 = [])
7 +//var blob_url = require('../plugs').first(exports.blob_url = [])
8 +//var signified = require('../plugs').first(exports.signified = [])
9 +//var builtin_tabs = require('../plugs').map(exports.builtin_tabs = [])
1010
11-exports.suggest_mentions = function (word, cb) {
12- if(!/^[%&@]\w/.test(word)) return cb()
13-
14-
15- signified(word, function (err, names) {
16- if(err) cb(err)
17- else cb(null, names.map(function (e) {
18- return {
19- title: e.name + ': ' + e.id.substring(0,10)+' ('+e.rank+')',
20- value: '['+e.name+']('+e.id+')',
21- rank: e.rank,
22- //TODO: avatar images...
23- }
24- }))
25- })
11 +exports.needs = {
12 + sbot_links2: 'first',
13 + blob_url: 'first',
14 + signified: 'first',
15 + bultin_tabs: 'map'
2616 }
2717
28-exports.suggest_search = function (query, cb) {
29- if(/^[@%]\w/.test(query)) {
30- signified(query, function (_, names) {
31- cb(null, names.map(function (e) {
32- return {
33- title: e.name + ':'+e.id.substring(0, 10),
34- value: e.id,
35- subtitle: e.rank,
36- rank: e.rank
37- }
38- }))
39- })
40-
41- } else if(/^\//.test(query)) {
42- var tabs = [].concat.apply([], builtin_tabs())
43- cb(null, tabs.filter(function (name) {
44- return name.substr(0, query.length) === query
45- }).map(function (name) {
46- return {
47- title: name,
48- value: name,
49- }
50- }))
51- } else cb()
18 +exports.gives = {
19 + suggest_mentions: true,
20 + suggest_search: true
5221 }
5322
23 +exports.create = function (api) {
5424
25 + return {
26 + suggest_mentions: function (word) {
27 + return function (cb) {
28 + if(!/^[%&@]\w/.test(word)) return cb()
5529
30 + api.signified(word, function (err, names) {
31 + if(err) cb(err)
32 + else cb(null, names.map(function (e) {
33 + return {
34 + title: e.name + ': ' + e.id.substring(0,10)+' ('+e.rank+')',
35 + value: '['+e.name+']('+e.id+')',
36 + rank: e.rank,
37 + //TODO: avatar images...
38 + }
39 + }))
40 + })
41 + }
42 + },
5643
44 + suggest_search: function (query, cb) {
45 + if(/^[@%]\w/.test(query)) {
46 + api.signified(query, function (_, names) {
47 + cb(null, names.map(function (e) {
48 + return {
49 + title: e.name + ':'+e.id.substring(0, 10),
50 + value: e.id,
51 + subtitle: e.rank,
52 + rank: e.rank
53 + }
54 + }))
55 + })
5756
58-
59-
60-
61-
62-
63-
64-
65-
57 + } else if(/^\//.test(query)) {
58 + var tabs = [].concat.apply([], builtin_tabs())
59 + cb(null, tabs.filter(function (name) {
60 + return name.substr(0, query.length) === query
61 + }).map(function (name) {
62 + return {
63 + title: name,
64 + value: name,
65 + }
66 + }))
67 + } else cb()
68 + }
69 + }
70 +}
modules_basic/thread.jsView
@@ -20,106 +20,119 @@
2020 })
2121 }
2222 }
2323
24-var plugs = require('../plugs')
24 +//var plugs = require('../plugs')
25 +//
26 +//var message_render = plugs.first(exports.message_render = [])
27 +//var message_name = plugs.first(exports.message_name = [])
28 +//var message_compose = plugs.first(exports.message_compose = [])
29 +//var message_unbox = plugs.first(exports.message_unbox = [])
30 +//
31 +//var sbot_get = plugs.first(exports.sbot_get = [])
32 +//var sbot_links = plugs.first(exports.sbot_links = [])
2533
26-var message_render = plugs.first(exports.message_render = [])
27-var message_name = plugs.first(exports.message_name = [])
28-var message_compose = plugs.first(exports.message_compose = [])
29-var message_unbox = plugs.first(exports.message_unbox = [])
34 +exports.needs = {
35 + message_render: 'first',
36 + message_name: 'first',
37 + message_compose: 'first',
38 + message_unbox: 'first',
39 + sbot_get: 'first',
40 + sbot_links: 'first'
41 +}
3042
31-var sbot_get = plugs.first(exports.sbot_get = [])
32-var sbot_links = plugs.first(exports.sbot_links = [])
43 +exports.gives = 'screen_view'
3344
34-function getThread (root, cb) {
35- //in this case, it's inconvienent that panel only takes
36- //a stream. maybe it would be better to accept an array?
3745
38- sbot_get(root, function (err, value) {
39- if (err) return cb(err)
40- var msg = {key: root, value: value}
41-// if(value.content.root) return getThread(value.content.root, cb)
46 +exports.create = function (api) {
4247
43- pull(
44- sbot_links({rel: 'root', dest: root, values: true, keys: true}),
45- pull.collect(function (err, ary) {
46- if(err) return cb(err)
47- ary.unshift(msg)
48- cb(null, ary)
49- })
50- )
51- })
48 + function getThread (root, cb) {
49 + //in this case, it's inconvienent that panel only takes
50 + //a stream. maybe it would be better to accept an array?
5251
53-}
52 + api.sbot_get(root, function (err, value) {
53 + if (err) return cb(err)
54 + var msg = {key: root, value: value}
55 + // if(value.content.root) return getThread(value.content.root, cb)
5456
55-exports.screen_view = function (id) {
56- if(ref.isMsg(id)) {
57- var meta = {
58- type: 'post',
59- root: id,
60- branch: id //mutated when thread is loaded.
61- }
57 + pull(
58 + api.sbot_links({rel: 'root', dest: root, values: true, keys: true}),
59 + pull.collect(function (err, ary) {
60 + if(err) return cb(err)
61 + ary.unshift(msg)
62 + cb(null, ary)
63 + })
64 + )
65 + })
6266
63- var content = h('div.column.scroller__content')
64- var div = h('div.column.scroller',
65- {style: {'overflow-y': 'auto'}},
66- h('div.scroller__wrapper',
67- content,
68- message_compose(meta, {shrink: false, placeholder: 'Write a reply'})
67 + }
68 +
69 + return function (id) {
70 + if(ref.isMsg(id)) {
71 + var meta = {
72 + type: 'post',
73 + root: id,
74 + branch: id //mutated when thread is loaded.
75 + }
76 +
77 + var content = h('div.column.scroller__content')
78 + var div = h('div.column.scroller',
79 + {style: {'overflow-y': 'auto'}},
80 + h('div.scroller__wrapper',
81 + content,
82 + api.message_compose(meta, {shrink: false, placeholder: 'Write a reply'})
83 + )
6984 )
70- )
7185
72- message_name(id, function (err, name) {
73- div.title = name
74- })
86 + api.message_name(id, function (err, name) {
87 + div.title = name
88 + })
7589
76- pull(
77- sbot_links({
78- rel: 'root', dest: id, keys: true, old: false
79- }),
80- pull.drain(function (msg) {
81- loadThread() //redraw thread
82- }, function () {} )
83- )
90 + pull(
91 + api.sbot_links({
92 + rel: 'root', dest: id, keys: true, old: false
93 + }),
94 + pull.drain(function (msg) {
95 + loadThread() //redraw thread
96 + }, function () {} )
97 + )
8498
8599
86- function loadThread () {
87- getThread(id, function (err, thread) {
88- //would probably be better keep an id for each message element
89- //(i.e. message key) and then update it if necessary.
90- //also, it may have moved (say, if you received a missing message)
91- content.innerHTML = ''
92- if(err) return content.appendChild(h('pre', err.stack))
100 + function loadThread () {
101 + getThread(id, function (err, thread) {
102 + //would probably be better keep an id for each message element
103 + //(i.e. message key) and then update it if necessary.
104 + //also, it may have moved (say, if you received a missing message)
105 + content.innerHTML = ''
106 + if(err) return content.appendChild(h('pre', err.stack))
93107
94- //decrypt
95- thread = thread.map(function (msg) {
96- return 'string' === typeof msg.value.content ? message_unbox(msg) : msg
97- })
108 + //decrypt
109 + thread = thread.map(function (msg) {
110 + return 'string' === typeof msg.value.content ? message_unbox(msg) : msg
111 + })
98112
99- if(err) return content.appendChild(h('pre', err.stack))
100- sort(thread).map(message_render).filter(Boolean).forEach(function (el) {
101- content.appendChild(el)
113 + if(err) return content.appendChild(h('pre', err.stack))
114 + sort(thread).map(api.message_render).filter(Boolean).forEach(function (el) {
115 + content.appendChild(el)
116 + })
117 +
118 + var branches = sort.heads(thread)
119 + meta.branch = branches.length > 1 ? branches : branches[0]
120 + meta.root = thread[0].value.content.root || thread[0].key
121 + meta.channel = thread[0].value.content.channel
122 +
123 + var recps = thread[0].value.content.recps
124 + var private = thread[0].value.private
125 + if(private) {
126 + if(recps)
127 + meta.recps = recps
128 + else
129 + meta.recps = [thread[0].value.author, self_id]
130 + }
102131 })
132 + }
103133
104- var branches = sort.heads(thread)
105- meta.branch = branches.length > 1 ? branches : branches[0]
106- meta.root = thread[0].value.content.root || thread[0].key
107- meta.channel = thread[0].value.content.channel
108-
109- var recps = thread[0].value.content.recps
110- var private = thread[0].value.private
111- if(private) {
112- if(recps)
113- meta.recps = recps
114- else
115- meta.recps = [thread[0].value.author, self_id]
116- }
117- })
134 + loadThread()
135 + return div
118136 }
119-
120- loadThread()
121- return div
122137 }
123138 }
124-
125-
modules_basic/timestamp.jsView
@@ -1,21 +1,28 @@
11 var h = require('hyperscript')
22 var human = require('human-time')
33
4-function updateTimestampEl(el) {
5- el.firstChild.nodeValue = human(new Date(el.timestamp))
6- return el
7-}
4 +exports.needs = {}
85
9-setInterval(function () {
10- var els = [].slice.call(document.querySelectorAll('.timestamp'))
11- els.forEach(updateTimestampEl)
12-}, 60e3)
6 +exports.gives = 'message_meta'
137
14-exports.message_meta = function (msg) {
15- return updateTimestampEl(h('a.enter.timestamp', {
16- href: '#'+msg.key,
17- timestamp: msg.value.timestamp,
18- title: new Date(msg.value.timestamp)
19- }, ''))
8 +exports.create = function () {
9 +
10 + function updateTimestampEl(el) {
11 + el.firstChild.nodeValue = human(new Date(el.timestamp))
12 + return el
13 + }
14 +
15 + setInterval(function () {
16 + var els = [].slice.call(document.querySelectorAll('.timestamp'))
17 + els.forEach(updateTimestampEl)
18 + }, 60e3)
19 +
20 + return function (msg) {
21 + return updateTimestampEl(h('a.enter.timestamp', {
22 + href: '#'+msg.key,
23 + timestamp: msg.value.timestamp,
24 + title: new Date(msg.value.timestamp)
25 + }, ''))
26 + }
27 +
2028 }
21-
modules_basic/suggest.jsView
@@ -1,3 +1,0 @@
1-
2-
3-
modules_core/app.jsView
@@ -1,68 +1,42 @@
11 var plugs = require('../plugs')
22 var h = require('hyperscript')
33
4-var screen_view = plugs.first(exports.screen_view = [])
4 +module.exports = {
5 + needs: {screen_view: 'first'},
6 + gives: 'app',
7 + create: function (api) {
8 + return function () {
9 + document.head.appendChild(h('style', require('../style.css.json')))
510
11 + window.addEventListener('error', window.onError = function (e) {
12 + document.body.appendChild(h('div.error',
13 + h('h1', e.message),
14 + h('big', h('code', e.filename + ':' + e.lineno)),
15 + h('pre', e.error ? (e.error.stack || e.error.toString()) : e.toString())))
16 + })
617
7-exports.app = function () {
8- document.head.appendChild(h('style', require('../style.css.json')))
18 + function hash() {
19 + return window.location.hash.substring(1)
20 + }
921
10- window.addEventListener('error', window.onError = function (e) {
11- document.body.appendChild(h('div.error',
12- h('h1', e.message),
13- h('big', h('code', e.filename + ':' + e.lineno)),
14- h('pre', e.error ? (e.error.stack || e.error.toString()) : e.toString())))
15- })
22 + console.log(hash() || 'tabs')
23 + var view = api.screen_view(hash() || 'tabs')
1624
17- function hash() {
18- return window.location.hash.substring(1)
19- }
25 + var screen = h('div.screen.column', view)
2026
21- var view = screen_view(hash() || 'tabs')
27 + window.onhashchange = function (ev) {
28 + var _view = view
29 + view = api.screen_view(hash() || 'tabs')
2230
23- var screen = h('div.screen.column', view)
31 + if(_view) screen.replaceChild(view, _view)
32 + else document.body.appendChild(view)
33 + }
2434
25- window.onhashchange = function (ev) {
26- var _view = view
27- view = screen_view(hash() || 'tabs')
35 + document.body.appendChild(screen)
2836
29- if(_view) screen.replaceChild(view, _view)
30- else document.body.appendChild(view)
37 + return screen
38 + }
3139 }
32-
33- document.body.appendChild(screen)
34-
35- return screen
36-
3740 }
3841
3942
40-
41-
42-
43-
44-
45-
46-
47-
48-
49-
50-
51-
52-
53-
54-
55-
56-
57-
58-
59-
60-
61-
62-
63-
64-
65-
66-
67-
68-
modules_core/blob-url.jsView
@@ -1,9 +1,13 @@
11 var config = require('../config')
22
3-exports.blob_url = function (link) {
4- if('string' == typeof link.link)
5- link = link.link
6- return config().blobsUrl + '/'+link
3 +module.exports = {
4 + gives: 'blob_url',
5 + create: function () {
6 + return function (link) {
7 + if('string' == typeof link.link)
8 + link = link.link
9 + return config().blobsUrl + '/'+link
10 + }
11 + }
712 }
813
9-
modules_core/crypto.jsView
@@ -16,33 +16,44 @@
1616 }
1717 }
1818
1919
20-var sbot_publish = require('../plugs').first(exports.sbot_publish = [])
20 +module.exports = {
2121
22-exports.message_unbox = function (msg) {
23- if(msg.value) {
24- var value = unbox_value(msg.value)
25- if(value)
26- return {
27- key: msg.key, value: value, timestamp: msg.timestamp
22 + needs: {sbot_publish: 'first'},
23 + gives: {
24 + message_unbox: true, message_box: true, publish: true
25 + },
26 + create: function (api) {
27 +
28 + var exports = {}
29 + exports.message_unbox = function (msg) {
30 + if(msg.value) {
31 + var value = unbox_value(msg.value)
32 + if(value)
33 + return {
34 + key: msg.key, value: value, timestamp: msg.timestamp
35 + }
36 + }
37 + else
38 + return unbox_value(msg)
2839 }
29- }
30- else
31- return unbox_value(msg)
32-}
3340
34-exports.message_box = function (content) {
35- return ssbKeys.box(content, content.recps.map(function (e) {
36- return ref.isFeed(e) ? e : e.link
37- }))
38-}
41 + exports.message_box = function (content) {
42 + return ssbKeys.box(content, content.recps.map(function (e) {
43 + return ref.isFeed(e) ? e : e.link
44 + }))
45 + }
3946
40-exports.publish = function (content, id) {
41- if(content.recps)
42- content = exports.message_box(content)
43- sbot_publish(content, function (err, msg) {
44- if(err) throw err
45- console.log('PUBLISHED', msg)
46- })
47 + exports.publish = function (content, id) {
48 + if(content.recps)
49 + content = exports.message_box(content)
50 + api.sbot_publish(content, function (err, msg) {
51 + if(err) throw err
52 + console.log('PUBLISHED', msg)
53 + })
54 + }
55 +
56 + return exports
57 + }
4758 }
4859
modules_core/file-input.jsView
@@ -7,31 +7,36 @@
77 var plugs = require('../plugs')
88
99 var add = plugs.first(exports.sbot_blobs_add = [])
1010
11-exports.file_input = function FileInput(onAdded) {
11 +module.exports = {
12 + needs: {sbot_blobs_add: 'first'},
13 + gives: 'file_input',
14 + create: function () {
15 + return function FileInput(onAdded) {
16 + return h('input', { type: 'file',
17 + onchange: function (ev) {
18 + var file = ev.target.files[0]
19 + if (!file) return
20 + var reader = new FileReader()
21 + reader.onload = function () {
22 + pull(
23 + pull.values(split(new Buffer(reader.result), 64*1024)),
24 + add(function (err, blob) {
25 + if(err) return console.error(err)
26 + onAdded({
27 + link: blob,
28 + name: file.name,
29 + size: reader.result.length || reader.result.byteLength,
30 + type: mime(file.name)
31 + })
1232
13- return h('input', { type: 'file',
14- onchange: function (ev) {
15- var file = ev.target.files[0]
16- if (!file) return
17- var reader = new FileReader()
18- reader.onload = function () {
19- pull(
20- pull.values(split(new Buffer(reader.result), 64*1024)),
21- add(function (err, blob) {
22- if(err) return console.error(err)
23- onAdded({
24- link: blob,
25- name: file.name,
26- size: reader.result.length || reader.result.byteLength,
27- type: mime(file.name)
28- })
29-
30- })
31- )
32- }
33- reader.readAsArrayBuffer(file)
33 + })
34 + )
35 + }
36 + reader.readAsArrayBuffer(file)
37 + }
38 + })
3439 }
35- })
40 + }
3641 }
3742
modules_core/index.jsView
@@ -1,6 +1,6 @@
11 module.exports = {
2- "_screen_view.js": require('./_screen_view.js'),
2 +// "_screen_view.js": require('./_screen_view.js'),
33 "app.js": require('./app.js'),
44 "blob-url.js": require('./blob-url.js'),
55 "crypto.js": require('./crypto.js'),
66 "file-input.js": require('./file-input.js'),
@@ -8,4 +8,5 @@
88 "message-confirm.js": require('./message-confirm.js'),
99 "tabs.js": require('./tabs.js'),
1010 "sbot.js": require('./sbot.js')
1111 }
12 +
modules_core/menu.jsView
@@ -1,31 +1,39 @@
11 var plugs = require('../plugs')
22 var h = require('hyperscript')
33
4-var menu_items = plugs.map(exports.menu_items = [])
4 +module.exports = {
5 + needs: {menu_items: 'map'},
6 + gives: {connection_status: true, menu: true},
7 + create: function (api) {
58
6-var status = h('div.status.error') //start off disconnected
7- var list = h('div.menu.column', {style: 'display: none;'})
9 + var menu_items = api.menu_items //plugs.map(exports.menu_items = [])
810
9-var menu = h('div.column', status, list , {
10- onmouseover: function (e) {
11- list.style.display = 'flex'
12- }, onmouseout: function () {
13- list.style.display = 'none'
11 + var status = h('div.status.error') //start off disconnected
12 + var list = h('div.menu.column', {style: 'display: none;'})
13 +
14 + var menu = h('div.column', status, list , {
15 + onmouseover: function (e) {
16 + list.style.display = 'flex'
17 + }, onmouseout: function () {
18 + list.style.display = 'none'
19 + }
20 + })
21 +
22 + return {
23 + connection_status: function (err) {
24 + if(err) status.classList.add('error')
25 + else status.classList.remove('error')
26 + },
27 + menu: function () {
28 + menu_items().forEach(function (el) {
29 + if(el)
30 + list.appendChild(el)
31 + })
32 + }
33 + }
1434 }
15-})
16-
17-exports.connection_status = function (err) {
18- if(err) status.classList.add('error')
19- else status.classList.remove('error')
2035 }
2136
22-exports.menu = function () {
23- menu_items().forEach(function (el) {
24- list.appendChild(el)
25- })
2637
27- return menu
28-}
2938
3039
31-
modules_core/message-confirm.jsView
@@ -5,57 +5,65 @@
55 //publish or add
66
77 var plugs = require('../plugs')
88
9-var publish = plugs.first(exports.sbot_publish = [])
10-var message_content = plugs.first(exports.message_content = [])
11-var avatar = plugs.first(exports.avatar = [])
12-var message_meta = plugs.map(exports.message_meta = [])
9 +exports.needs = {
10 + publish: 'first', message_content: 'first', avatar: 'first',
11 + message_meta: 'map'
12 +}
1313
14-exports.message_confirm = function (content, cb) {
14 +exports.gives = 'message_confirm'
1515
16- cb = cb || function () {}
16 +//var publish = plugs.first(exports.sbot_publish = [])
17 +//var message_content = plugs.first(exports.message_content = [])
18 +//var avatar = plugs.first(exports.avatar = [])
19 +//var message_meta = plugs.map(exports.message_meta = [])
20 +//
21 +exports.create = function (api) {
22 + return function (content, cb) {
1723
18- var lb = lightbox()
19- document.body.appendChild(lb)
24 + cb = cb || function () {}
2025
21- var msg = {
22- key: "DRAFT",
23- value: {
24- author: self_id,
25- previous: null,
26- sequence: null,
27- timestamp: Date.now(),
28- content: content
26 + var lb = lightbox()
27 + document.body.appendChild(lb)
28 +
29 + var msg = {
30 + key: "DRAFT",
31 + value: {
32 + author: self_id,
33 + previous: null,
34 + sequence: null,
35 + timestamp: Date.now(),
36 + content: content
37 + }
2938 }
30- }
3139
32- var okay = h('button', 'okay', {onclick: function () {
33- lb.remove()
34- publish(content, cb)
35- }})
40 + var okay = h('button', 'okay', {onclick: function () {
41 + lb.remove()
42 + api.publish(content, cb)
43 + }})
3644
37- var cancel = h('button', 'Cancel', {onclick: function () {
38- lb.remove()
39- cb(null)
40- }})
45 + var cancel = h('button', 'Cancel', {onclick: function () {
46 + lb.remove()
47 + cb(null)
48 + }})
4149
42- okay.addEventListener('keydown', function (ev) {
43- if(ev.keyCode === 27) cancel.click() //escape
44- })
50 + okay.addEventListener('keydown', function (ev) {
51 + if(ev.keyCode === 27) cancel.click() //escape
52 + })
4553
46- lb.show(h('div.column.message-confirm',
47- h('div.message',
48- h('div.title.row',
49- h('div.avatar', avatar(msg.value.author, 'thumbnail')),
50- h('div.message_meta.row', message_meta(msg))
54 + lb.show(h('div.column.message-confirm',
55 + h('div.message',
56 + h('div.title.row',
57 + h('div.avatar', api.avatar(msg.value.author, 'thumbnail')),
58 + h('div.message_meta.row', api.message_meta(msg))
59 + ),
60 + h('div.message_content', api.message_content(msg)
61 + || h('pre', JSON.stringify(msg, null, 2)))
5162 ),
52- h('div.message_content', message_content(msg)
53- || h('pre', JSON.stringify(msg, null, 2)))
54- ),
55- h('div.row.message-confirm__controls', okay, cancel)
56- ))
63 + h('div.row.message-confirm__controls', okay, cancel)
64 + ))
5765
58- okay.focus()
59-
66 + okay.focus()
67 + }
6068 }
6169
modules_core/sbot.jsView
@@ -30,128 +30,158 @@
3030 var createFeed = require('ssb-feed')
3131 var keys = require('../keys')
3232 var ssbKeys = require('ssb-keys')
3333
34-
3534 var cache = CACHE = {}
3635
37-var opts = createConfig()
38-var sbot = null
39-var connection_status = []
36 +module.exports = {
37 + needs: {
38 + connection_status: 'map'
39 + },
40 + gives: {
41 +// connection_status: true,
42 + sbot_blobs_add: true,
43 + sbot_links: true,
44 + sbot_links2: true,
45 + sbot_query: true,
46 + sbot_get: true,
47 + sbot_log: true,
48 + sbot_user_feed: true,
49 + sbot_gossip_peers: true,
50 + sbot_gossip_connect: true,
51 + sbot_progress: true,
52 + sbot_publish: true,
53 + sbot_whoami: true
54 + },
4055
41-var rec = Reconnect(function (isConn) {
42- function notify (value) {
43- console.log('connection_status', value, connection_status)
44- isConn(value); connection_status.forEach(function (fn) { fn(value) })
45- }
56 +//module.exports = {
57 + create: function (api) {
4658
47- createClient(keys, {
48- manifest: require('../manifest.json'),
49- remote: require('../config')().remote
50- }, function (err, _sbot) {
51- if(err)
52- return notify(err)
59 + var opts = createConfig()
60 + var sbot = null
61 + var connection_status = []
5362
54- sbot = _sbot
55- sbot.on('closed', function () {
56- sbot = null
57- notify(new Error('closed'))
58- })
63 + var rec = Reconnect(function (isConn) {
64 + function notify (value) {
65 + console.log('connection_status', value, connection_status)
66 + isConn(value); api.connection_status(value) //.forEach(function (fn) { fn(value) })
67 + }
5968
60- notify()
61- })
62-})
69 + createClient(keys, {
70 + manifest: require('../manifest.json'),
71 + remote: require('../config')().remote
72 + }, function (err, _sbot) {
73 + if(err)
74 + return notify(err)
75 + console.log("SboT CONNECT", _sbot)
6376
64-var internal = {
65- getLatest: rec.async(function (id, cb) {
66- sbot.getLatest(id, cb)
67- }),
68- add: rec.async(function (msg, cb) {
69- sbot.add(msg, cb)
70- })
71-}
77 + sbot = _sbot
78 + sbot.on('closed', function () {
79 + sbot = null
80 + notify(new Error('closed'))
81 + })
7282
73-var feed = createFeed(internal, keys, {remote: true})
83 + notify()
84 + })
85 + })
7486
75-module.exports = {
76- connection_status: connection_status,
77- sbot_blobs_add: rec.sink(function (cb) {
78- return pull(
79- Hash(function (err, id) {
80- if(err) return cb(err)
81- //completely UGLY hack to tell when the blob has been sucessfully written...
82- var start = Date.now(), n = 5
83- ;(function next () {
84- setTimeout(function () {
85- sbot.blobs.has(id, function (err, has) {
86- if(has) return cb(null, id)
87- if(n--) next()
88- else cb(new Error('write failed'))
89- })
90- }, Date.now() - start)
91- })()
87 + var internal = {
88 + getLatest: rec.async(function (id, cb) {
89 + sbot.getLatest(id, cb)
9290 }),
93- sbot.blobs.add()
94- )
95- }),
96- sbot_links: rec.source(function (query) {
97- return sbot.links(query)
98- }),
99- sbot_links2: rec.source(function (query) {
100- return sbot.links2.read(query)
101- }),
102- sbot_query: rec.source(function (query) {
103- return sbot.query.read(query)
104- }),
105- sbot_log: rec.source(function (opts) {
106- return pull(
107- sbot.createLogStream(opts),
108- pull.through(function (e) {
109- CACHE[e.key] = CACHE[e.key] || e.value
91 + add: rec.async(function (msg, cb) {
92 + sbot.add(msg, cb)
11093 })
111- )
112- }),
113- sbot_user_feed: rec.source(function (opts) {
114- return sbot.createUserStream(opts)
115- }),
116- sbot_get: rec.async(function (key, cb) {
117- if(CACHE[key]) cb(null, CACHE[key])
118- else sbot.get(key, function (err, value) {
119- if(err) return cb(err)
120- cb(null, CACHE[key] = value)
121- })
122- }),
123- sbot_gossip_peers: rec.async(function (cb) {
124- sbot.gossip.peers(cb)
125- }),
126- //liteclient won't have permissions for this
127- sbot_gossip_connect: rec.async(function (opts, cb) {
128- sbot.gossip.connect(opts, cb)
129- }),
130- sbot_progress: rec.source(function () {
131- return sbot.replicate.changes()
132- }),
133- sbot_publish: rec.async(function (content, cb) {
134- if(content.recps)
135- content = ssbKeys.box(content, content.recps.map(function (e) {
136- return ref.isFeed(e) ? e : e.link
137- }))
138- else if(content.mentions)
139- content.mentions.forEach(function (mention) {
140- if(ref.isBlob(mention.link)) {
141- sbot.blobs.push(mention.link, function (err) {
142- if(err) console.error(err)
94 + }
95 +
96 + var feed = createFeed(internal, keys, {remote: true})
97 + console.log('create SBOT')
98 + return {
99 + connection_status: connection_status,
100 + sbot_blobs_add: rec.sink(function (cb) {
101 + return pull(
102 + Hash(function (err, id) {
103 + if(err) return cb(err)
104 + //completely UGLY hack to tell when the blob has been sucessfully written...
105 + var start = Date.now(), n = 5
106 + ;(function next () {
107 + setTimeout(function () {
108 + sbot.blobs.has(id, function (err, has) {
109 + if(has) return cb(null, id)
110 + if(n--) next()
111 + else cb(new Error('write failed'))
112 + })
113 + }, Date.now() - start)
114 + })()
115 + }),
116 + sbot.blobs.add()
117 + )
118 + }),
119 + sbot_links: rec.source(function (query) {
120 + return sbot.links(query)
121 + }),
122 + sbot_links2: rec.source(function (query) {
123 + return sbot.links2.read(query)
124 + }),
125 + sbot_query: rec.source(function (query) {
126 + return sbot.query.read(query)
127 + }),
128 + sbot_log: rec.source(function (opts) {
129 + console.log('sbot_log', opts)
130 + return pull(
131 + sbot.createLogStream(opts),
132 + pull.through(function (e) {
133 + CACHE[e.key] = CACHE[e.key] || e.value
143134 })
144- }
135 + )
136 + }),
137 + sbot_user_feed: rec.source(function (opts) {
138 + return sbot.createUserStream(opts)
139 + }),
140 + sbot_get: rec.async(function (key, cb) {
141 + if('function' !== typeof cb)
142 + throw new Error('cb must be function')
143 + if(CACHE[key]) cb(null, CACHE[key])
144 + else sbot.get(key, function (err, value) {
145 + if(err) return cb(err)
146 + cb(null, CACHE[key] = value)
147 + })
148 + }),
149 + sbot_gossip_peers: rec.async(function (cb) {
150 + sbot.gossip.peers(cb)
151 + }),
152 + //liteclient won't have permissions for this
153 + sbot_gossip_connect: rec.async(function (opts, cb) {
154 + sbot.gossip.connect(opts, cb)
155 + }),
156 + sbot_progress: rec.source(function () {
157 + return sbot.replicate.changes()
158 + }),
159 + sbot_publish: rec.async(function (content, cb) {
160 + if(content.recps)
161 + content = ssbKeys.box(content, content.recps.map(function (e) {
162 + return ref.isFeed(e) ? e : e.link
163 + }))
164 + else if(content.mentions)
165 + content.mentions.forEach(function (mention) {
166 + if(ref.isBlob(mention.link)) {
167 + sbot.blobs.push(mention.link, function (err) {
168 + if(err) console.error(err)
169 + })
170 + }
171 + })
172 +
173 + feed.add(content, function (err, msg) {
174 + if(err) console.error(err)
175 + else if(!cb) console.log(msg)
176 + cb && cb(err, msg)
177 + })
178 + }),
179 + sbot_whoami: rec.async(function (cb) {
180 + sbot.whoami(cb)
145181 })
146-
147- feed.add(content, function (err, msg) {
148- if(err) console.error(err)
149- else if(!cb) console.log(msg)
150- cb && cb(err, msg)
151- })
152- }),
153- sbot_whoami: rec.async(function (cb) {
154- sbot.whoami(cb)
155- })
182 + }
183 + }
156184 }
157185
186 +
187 +
modules_core/tabs.jsView
@@ -10,214 +10,210 @@
1010 if(el.tagName !== 'A') return ancestor(el.parentElement)
1111 return el
1212 }
1313
14-var plugs = require('../plugs')
15-var screen_view = plugs.first(exports._screen_view = [])
16-var search_box = plugs.first(exports.search_box = [])
17-var menu = plugs.first(exports.menu = [])
14 +//var plugs = require('../plugs')
15 +//var screen_view = plugs.first(exports._screen_view = [])
16 +//var search_box = plugs.first(exports.search_box = [])
17 +//var menu = plugs.first(exports.menu = [])
1818
19-exports.message_render = []
19 +exports.needs = {screen_view: 'first', search_box: 'first', menu: 'first'}
2020
21-exports.screen_view = function (path) {
22- if(path !== 'tabs')
23- return
21 +exports.gives = 'screen_view'
2422
25- function setSelected (indexes) {
26- var ids = indexes.map(function (index) {
27- return tabs.get(index).id
28- })
29- if(ids.length > 1)
30- search.value = 'split('+ids.join(',')+')'
31- else
32- search.value = ids[0]
33- }
23 +exports.create = function (api) {
24 + return function (path) {
25 + if(path !== 'tabs')
26 + return
3427
35- var search
36- var tabs = Tabs(setSelected)
37-
38- search = search_box(function (path, change) {
39-
40- if(tabs.has(path)) {
41- tabs.select(path)
42- return true
28 + function setSelected (indexes) {
29 + var ids = indexes.map(function (index) {
30 + return tabs.get(index).id
31 + })
32 + if(search)
33 + if(ids.length > 1)
34 + search.value = 'split('+ids.join(',')+')'
35 + else
36 + search.value = ids[0]
4337 }
44- var el = screen_view(path)
4538
46- if(el) {
47- if(!el.title) el.title = path
48- el.scroll = keyscroll(el.querySelector('.scroller__content'))
49- tabs.add(el, change)
50-// localStorage.openTabs = JSON.stringify(tabs.tabs)
51- return change
52- }
53- })
39 + var search
40 + var tabs = Tabs(setSelected)
5441
55- //reposition hypertabs menu to inside a container...
56- tabs.insertBefore(h('div.header.row',
57- h('div.header__tabs.row', tabs.firstChild), //tabs
58- h('div.header__search.row.end', h('div', search), menu())
59- ), tabs.firstChild)
60-// tabs.insertBefore(search, tabs.firstChild.nextSibling)
42 + search = api.search_box(function (path, change) {
6143
62- var saved = []
63-// try { saved = JSON.parse(localStorage.openTabs) }
64-// catch (_) { }
44 + if(tabs.has(path)) {
45 + tabs.select(path)
46 + return true
47 + }
48 + var el = api.screen_view(path)
6549
66- if(!saved || saved.length < 3)
67- saved = ['/public', '/private', '/notifications']
50 + if(el) {
51 + if(!el.title) el.title = path
52 + el.scroll = keyscroll(el.querySelector('.scroller__content'))
53 + tabs.add(el, change)
54 + // localStorage.openTabs = JSON.stringify(tabs.tabs)
55 + return change
56 + }
57 + })
6858
69- saved.forEach(function (path) {
70- var el = screen_view(path)
71- if(!el) return
72- el.id = el.id || path
73- if (!el) return
74- el.scroll = keyscroll(el.querySelector('.scroller__content'))
75- if(el) tabs.add(el, false, false)
76- })
59 + //reposition hypertabs menu to inside a container...
60 + tabs.insertBefore(h('div.header.row',
61 + h('div.header__tabs.row', tabs.firstChild), //tabs
62 + h('div.header__search.row.end', h('div', search), api.menu())
63 + ), tabs.firstChild)
64 + // tabs.insertBefore(search, tabs.firstChild.nextSibling)
7765
78- tabs.select(0)
66 + var saved = []
67 + // try { saved = JSON.parse(localStorage.openTabs) }
68 + // catch (_) { }
7969
80- //handle link clicks
81- window.onclick = function (ev) {
82- var link = ancestor(ev.target)
83- if(!link) return
84- var path = link.hash.substring(1)
70 + if(!saved || saved.length < 3)
71 + saved = ['/public', '/private', '/notifications', '/data']
8572
86- ev.preventDefault()
87- ev.stopPropagation()
88-
89- //let the application handle this link
90- if (link.getAttribute('href') === '#') return
91-
92- //open external links.
93- //this ought to be made into something more runcible
94- if(open.isExternal(link.href)) return open(link.href)
95-
96- if(tabs.has(path))
97- return tabs.select(path, !ev.ctrlKey, !!ev.shiftKey)
98-
99- var el = screen_view(path)
100- if(el) {
73 + saved.forEach(function (path) {
74 + var el = api.screen_view(path)
75 + if(!el) return
10176 el.id = el.id || path
77 + if (!el) return
10278 el.scroll = keyscroll(el.querySelector('.scroller__content'))
103- tabs.add(el, !ev.ctrlKey, !!ev.shiftKey)
104-// localStorage.openTabs = JSON.stringify(tabs.tabs)
105- }
79 + if(el) tabs.add(el, false, false)
80 + })
10681
107- return false
108- }
82 + tabs.select(0)
10983
110- window.addEventListener('keydown', function (ev) {
111- if (ev.target.nodeName === 'INPUT' || ev.target.nodeName === 'TEXTAREA')
112- return
113- switch(ev.keyCode) {
84 + //handle link clicks
85 + window.onclick = function (ev) {
86 + var link = ancestor(ev.target)
87 + if(!link) return
88 + var path = link.hash.substring(1)
11489
115- // scroll through tabs
116- case 72: // h
117- return tabs.selectRelative(-1)
118- case 76: // l
119- return tabs.selectRelative(1)
90 + ev.preventDefault()
91 + ev.stopPropagation()
12092
121- // scroll through messages
122- case 74: // j
123- return tabs.get(tabs.selected[0]).scroll(1)
124- case 75: // k
125- return tabs.get(tabs.selected[0]).scroll(-1)
93 + //let the application handle this link
94 + if (link.getAttribute('href') === '#') return
12695
127- // close a tab
128- case 88: // x
129- if (tabs.selected) {
130- var sel = tabs.selected
131- var i = sel.reduce(function (a, b) { return Math.min(a, b) })
132- tabs.remove(sel)
133- tabs.select(Math.max(i-1, 0))
134- }
135- return
96 + //open external links.
97 + //this ought to be made into something more runcible
98 + if(open.isExternal(link.href)) return open(link.href)
13699
137- // activate the search field
138- case 191: // /
139- if (ev.shiftKey)
140- search.activate('?', ev)
141- else
142- search.activate('/', ev)
143- return
100 + if(tabs.has(path))
101 + return tabs.select(path, !ev.ctrlKey, !!ev.shiftKey)
144102
145- // navigate to a feed
146- case 50: // 2
147- if (ev.shiftKey)
148- search.activate('@', ev)
149- return
103 + var el = api.screen_view(path)
104 + if(el) {
105 + el.id = el.id || path
106 + el.scroll = keyscroll(el.querySelector('.scroller__content'))
107 + tabs.add(el, !ev.ctrlKey, !!ev.shiftKey)
108 + // localStorage.openTabs = JSON.stringify(tabs.tabs)
109 + }
150110
151- // navigate to a channel
152- case 51: // 3
153- if (ev.shiftKey)
154- search.activate('#', ev)
155- return
111 + return false
112 + }
156113
157- // navigate to a message
158- case 53: // 5
159- if (ev.shiftKey)
160- search.activate('%', ev)
114 + window.addEventListener('keydown', function (ev) {
115 + if (ev.target.nodeName === 'INPUT' || ev.target.nodeName === 'TEXTAREA')
161116 return
162- }
163- })
117 + switch(ev.keyCode) {
164118
165- // errors tab
166- var errorsContent = h('div.column.scroller__content')
167- var errors = h('div.column.scroller', {
168- id: 'errors',
169- style: {'overflow':'auto'}
170- }, h('div.scroller__wrapper',
171- errorsContent
172- )
173- )
119 + // scroll through tabs
120 + case 72: // h
121 + return tabs.selectRelative(-1)
122 + case 76: // l
123 + return tabs.selectRelative(1)
174124
175- // remove loader error handler
176- if (window.onError) {
177- window.removeEventListener('error', window.onError)
178- delete window.onError
179- }
125 + // scroll through messages
126 + case 74: // j
127 + return tabs.get(tabs.selected[0]).scroll(1)
128 + case 75: // k
129 + return tabs.get(tabs.selected[0]).scroll(-1)
180130
181- // put errors in a tab
182- window.addEventListener('error', function (ev) {
183- var err = ev.error || ev
184- if(!tabs.has('errors'))
185- tabs.add(errors, false)
186- var el = h('div.message',
187- h('strong', err.message),
188- h('pre', err.stack))
189- if (errorsContent.firstChild)
190- errorsContent.insertBefore(el, errorsContent.firstChild)
191- else
192- errorsContent.appendChild(el)
193- })
131 + // close a tab
132 + case 88: // x
133 + if (tabs.selected) {
134 + var sel = tabs.selected
135 + var i = sel.reduce(function (a, b) { return Math.min(a, b) })
136 + tabs.remove(sel)
137 + tabs.select(Math.max(i-1, 0))
138 + }
139 + return
194140
195- if (process.versions.electron) {
196- window.addEventListener('contextmenu', function (ev) {
197- ev.preventDefault()
198- var remote = require('electron').remote
199- var Menu = remote.Menu
200- var MenuItem = remote.MenuItem
201- var menu = new Menu()
202- menu.append(new MenuItem({
203- label: 'Inspect Element',
204- click: function () {
205- remote.getCurrentWindow().inspectElement(ev.x, ev.y)
206- }
207- }))
208- menu.popup(remote.getCurrentWindow())
209- })
210- }
141 + // activate the search field
142 + case 191: // /
143 + if (ev.shiftKey)
144 + search.activate('?', ev)
145 + else
146 + search.activate('/', ev)
147 + return
211148
212- return tabs
213-}
149 + // navigate to a feed
150 + case 50: // 2
151 + if (ev.shiftKey)
152 + search.activate('@', ev)
153 + return
214154
155 + // navigate to a channel
156 + case 51: // 3
157 + if (ev.shiftKey)
158 + search.activate('#', ev)
159 + return
215160
161 + // navigate to a message
162 + case 53: // 5
163 + if (ev.shiftKey)
164 + search.activate('%', ev)
165 + return
166 + }
167 + })
216168
169 + // errors tab
170 + var errorsContent = h('div.column.scroller__content')
171 + var errors = h('div.column.scroller', {
172 + id: 'errors',
173 + style: {'overflow':'auto'}
174 + }, h('div.scroller__wrapper',
175 + errorsContent
176 + )
177 + )
217178
179 + // remove loader error handler
180 + if (window.onError) {
181 + window.removeEventListener('error', window.onError)
182 + delete window.onError
183 + }
218184
185 + // put errors in a tab
186 + window.addEventListener('error', function (ev) {
187 + var err = ev.error || ev
188 + if(!tabs.has('errors'))
189 + tabs.add(errors, false)
190 + var el = h('div.message',
191 + h('strong', err.message),
192 + h('pre', err.stack))
193 + if (errorsContent.firstChild)
194 + errorsContent.insertBefore(el, errorsContent.firstChild)
195 + else
196 + errorsContent.appendChild(el)
197 + })
219198
199 + if (process.versions.electron) {
200 + window.addEventListener('contextmenu', function (ev) {
201 + ev.preventDefault()
202 + var remote = require('electron').remote
203 + var Menu = remote.Menu
204 + var MenuItem = remote.MenuItem
205 + var menu = new Menu()
206 + menu.append(new MenuItem({
207 + label: 'Inspect Element',
208 + click: function () {
209 + remote.getCurrentWindow().inspectElement(ev.x, ev.y)
210 + }
211 + }))
212 + menu.popup(remote.getCurrentWindow())
213 + })
214 + }
220215
216 + return tabs
217 + }
221218
222-
223-
219 +}

Built with git-ssb-web