git ssb

2+

mixmix / ticktack



Commit 453e088bb1a566f6624aca8299dbbac2fee35272

Merge branch 'master' into patchwork_friendly (and small friends subs

page fix)
mix irving committed on 2/13/2018, 10:58:20 PM
Parent: b4bb2278fc6720ae4aa5470a30a66da315b74f00
Parent: bee2958f3a890cd7ecae7658ea242acbfdcfdc52

Files changed

about/html/avatar.jschanged
about/index.jschanged
app/async/catch-link-click.jschanged
app/html/app.jschanged
app/html/blogCard.jschanged
app/html/channelCard.jschanged
app/html/comments.jschanged
app/html/header.jschanged
app/html/lightbox.jschanged
app/html/link.jschanged
app/html/scroller.jschanged
app/html/sideNav/sideNavAddressBook.jschanged
app/html/sideNav/sideNavDiscovery.jschanged
app/html/thread.jschanged
app/html/topNav/topNavAddressBook.jschanged
app/html/topNav/topNavBlog.jschanged
app/html/topNav/zz_topNavBack.jschanged
app/index.jschanged
app/page/addressBook.jschanged
app/page/blogIndex.jschanged
app/page/blogIndex.mcsschanged
app/page/blogNew.jschanged
app/page/blogSearch.jschanged
app/page/blogSearch.mcsschanged
app/page/blogShow.jschanged
app/page/channel.jschanged
app/page/channelShow.jschanged
app/page/channelShow.mcsschanged
app/page/channelSubscriptions.jschanged
app/page/error.jschanged
app/page/groupFind.jschanged
app/page/groupIndex.jschanged
app/page/groupNew.jschanged
app/page/groupShow.jschanged
app/page/image.jschanged
app/page/settings.jschanged
app/page/splash.jschanged
app/page/threadNew.jschanged
app/page/threadShow.jschanged
app/page/userEdit.jschanged
app/page/userFind.jschanged
app/page/userShow.jschanged
app/sync/initialize/clickHandler.jschanged
app/sync/initialize/styles.jschanged
app/sync/initialize/suggests.jschanged
app/sync/initialize/zoomMemory.jschanged
blog/html/blog.jschanged
blog/html/post.jschanged
blog/index.jschanged
channel/async.jschanged
channel/html/subscribe.jschanged
channel/index.jschanged
channel/obs.jschanged
config.jschanged
contact/html/block.jschanged
contact/html/follow.jschanged
contact/index.jschanged
contact/obs/relationships.jschanged
main.jschanged
message/async/publish.jschanged
message/html/channel.jschanged
message/html/compose.jschanged
message/html/likes.jschanged
message/html/subject.jschanged
message/html/timeago.jschanged
message/index.jschanged
message/sync/getParticipants.jschanged
router/sync/routes.jschanged
state/obs.jschanged
styles/css/fontAwesome.jschanged
translations/checker.jschanged
translations/en.jschanged
translations/sync.jschanged
translations/zh.jschanged
unread.jschanged
about/html/avatar.jsView
@@ -22,5 +22,4 @@
2222 }
2323 })
2424 })
2525 }
26-
about/index.jsView
@@ -1,5 +1,5 @@
11 module.exports = {
22 html: {
33 avatar: require('./html/avatar')
4- },
4 + }
55 }
app/async/catch-link-click.jsView
@@ -30,22 +30,20 @@
app/html/app.jsView
@@ -20,17 +20,18 @@
2020 'sbot.async.get': 'first'
2121 })
2222
2323 exports.create = (api) => {
24- var view = Value()
24 + var view
2525
2626 return nest({
2727 'app.html.app': function app () {
2828 api.app.sync.initialize()
2929
30 + view = Value()
3031 var app = h('App', view)
3132 api.history.obs.location()(renderLocation)
32- api.history.obs.location()(logLocation)
33 + api.history.obs.location()(loc => console.log('location:', loc))
3334
3435 startApp()
3536
3637 return app
@@ -38,72 +39,65 @@
3839 })
3940
4041 function renderLocation (loc) {
4142 var page = api.router.sync.router(loc)
42- if (page) view.set([
43- api.app.html.header({location: loc, push: api.history.sync.push}),
44- api.app.html.warning(),
45- page
46- ])
43 + if (page) {
44 + view.set([
45 + api.app.html.header({location: loc, push: api.history.sync.push}),
46 + api.app.html.warning(),
47 + page
48 + ])
49 + }
4750 }
4851
4952 function startApp () {
5053 api.history.sync.push({page: 'splash'})
5154
5255 const delay = process.env.STARTUP_DELAY || 2000
5356 setTimeout(enterApp, delay)
57 + }
5458
55- function enterApp() {
56- const isOnboarded = api.settings.sync.get('onboarded')
57- const initialPage = process.env.STARTUP_PAGE || 'blogIndex'
58- if (isOnboarded) {
59- autoPub()
60- api.history.sync.push({page: initialPage})
61- }
62- else {
63- api.history.sync.push({
64- page:'userEdit',
65- feed: api.keys.sync.id(),
66- callback: (err, didEdit) => {
67- if (err) throw new Error ('Error editing profile', err)
59 + function enterApp () {
60 + const isOnboarded = api.settings.sync.get('onboarded')
61 + const initialPage = process.env.STARTUP_PAGE || 'blogIndex'
62 + if (isOnboarded) {
63 + autoPub()
64 + api.history.sync.push({page: initialPage})
65 + } else {
66 + api.history.sync.push({
67 + page: 'userEdit',
68 + feed: api.keys.sync.id(),
69 + callback: (err, didEdit) => {
70 + if (err) throw new Error('Error editing profile', err)
6871
69- // if they clicked something, just mark them onboarded
70- api.settings.sync.set({ onboarded: true })
72 + // if they clicked something, just mark them onboarded
73 + api.settings.sync.set({ onboarded: true })
7174
72- autoPub()
73- api.history.sync.push({page: initialPage})
74- }
75- })
76- }
75 + autoPub()
76 + api.history.sync.push({page: initialPage})
77 + }
78 + })
7779 }
80 + }
7881
79- function autoPub () {
80- var invites = api.config.sync.load().autoinvites
81- if(!invites) {
82- console.log('no invites')
83- return
84- }
82 + function autoPub () {
83 + var invites = api.config.sync.load().autoinvites
84 + if (!invites) {
85 + console.log('no invites')
86 + return
87 + }
8588
86- var self_id = api.config.sync.load().keys.id
87- api.sbot.async.friendsGet({dest: self_id}, function (err, friends) {
88- //if you have less than 5 followers, maybe use the autoinvite
89- if(Object.keys(friends).length <= 5)
90- invites.forEach(invite => {
91- console.log('using invite:', invite)
92- api.invite.async.autofollow(invite, (err, follows) => {
93- if (err) console.error('Autofollow error:', err)
94- else console.log('Autofollow success', follows)
95- })
89 + var self_id = api.config.sync.load().keys.id
90 + api.sbot.async.friendsGet({dest: self_id}, function (err, friends) {
91 + // if you have less than 5 followers, maybe use the autoinvite
92 + if (Object.keys(friends).length <= 5) {
93 + invites.forEach(invite => {
94 + console.log('using invite:', invite)
95 + api.invite.async.autofollow(invite, (err, follows) => {
96 + if (err) console.error('Autofollow error:', err)
97 + else console.log('Autofollow success', follows)
9698 })
97- else
98- console.log('no autoinvite - you have friends already')
99- })
100- }
99 + })
100 + } else { console.log('no autoinvite - you have friends already') }
101 + })
101102 }
102103 }
103-
104-function logLocation (loc) {
105- console.groupCollapsed('%c location', 'color: #00f')
106- console.log(loc)
107- console.groupEnd()
108-
109-}
app/html/blogCard.jsView
@@ -1,23 +1,22 @@
11 var nest = require('depnest')
22 var h = require('mutant/h')
3-var isString= require('lodash/isString')
4-var maxBy= require('lodash/maxBy')
5-var markdown = require('ssb-markdown')
6-var ref = require('ssb-ref')
7-var htmlEscape = require('html-escape')
3 +// var maxBy = require('lodash/maxBy')
4 +// var markdown = require('ssb-markdown')
5 +// var ref = require('ssb-ref')
6 +// var htmlEscape = require('html-escape')
87
9-function renderEmoji (emoji, url) {
10- if (!url) return ':' + emoji + ':'
11- return `
12- <img
13- src="${htmlEscape(url)}"
14- alt=":${htmlEscape(emoji)}:"
15- title=":${htmlEscape(emoji)}:"
16- class="emoji"
17- >
18- `
19-}
8 +// function renderEmoji (emoji, url) {
9 +// if (!url) return ':' + emoji + ':'
10 +// return `
11 +// <img
12 +// src="${htmlEscape(url)}"
13 +// alt=":${htmlEscape(emoji)}:"
14 +// title=":${htmlEscape(emoji)}:"
15 +// class="emoji"
16 +// >
17 +// `
18 +// }
2019
2120 exports.gives = nest('app.html.blogCard', true)
2221
2322 exports.needs = nest({
@@ -25,99 +24,88 @@
2524 'history.sync.push': 'first',
2625 'about.obs.color': 'first',
2726 'about.obs.name': 'first',
2827 'about.html.avatar': 'first',
29- 'translations.sync.strings': 'first',
3028 'unread.sync.isUnread': 'first',
3129 'message.html.channel': 'first',
3230 'message.html.timeago': 'first',
3331 'blob.sync.url': 'first',
3432 'emoji.sync.url': 'first',
3533
3634 'blog.html.title': 'first',
3735 'blog.html.summary': 'first',
38- 'blog.html.thumbnail': 'first',
36 + 'blog.html.thumbnail': 'first'
3937 })
4038
4139 exports.create = function (api) {
40 + // render markdown, but don't support patchwork@2 style mentions or custom emoji right now.
41 + // function render (source) {
42 + // return markdown.block(source, {
43 + // emoji: (emoji) => {
44 + // return renderEmoji(emoji, api.emoji.sync.url(emoji))
45 + // },
46 + // toUrl: (id) => {
47 + // if (ref.isBlob(id)) return api.blob.sync.url(id)
48 + // return id
49 + // },
50 + // imageLink: (id) => id
51 + // })
52 + // }
4253
43- //render markdown, but don't support patchwork@2 style mentions or custom emoji right now.
44- function render (source) {
45- return markdown.block(source, {
46- emoji: (emoji) => {
47- return renderEmoji(emoji, api.emoji.sync.url(emoji))
48- },
49- toUrl: (id) => {
50- if (ref.isBlob(id)) return api.blob.sync.url(id)
51- return id
52- },
53- imageLink: (id) => id
54- })
55- }
54 + // render the icon for a blog.
55 + // it would be more depjecty to split this
56 + // into two methods, one in a private plugin
57 + // one in a channel plugin
58 + // function blogIcon (msg) {
59 + // if (msg.value.private) {
60 + // const myId = api.keys.sync.id()
5661
62 + // return msg.value.content.recps
63 + // .map(link => isString(link) ? link : link.link)
64 + // .filter(link => link !== myId)
65 + // .map(link => api.about.html.avatar)
66 + // } else if (msg.value.content.channel) { return '#' + msg.value.content.channel }
67 + // }
5768
58- //render the icon for a blog.
59- //it would be more depjecty to split this
60- //into two methods, one in a private plugin
61- //one in a channel plugin
62- function blogIcon (msg) {
63- if(msg.value.private) {
64- const myId = api.keys.sync.id()
65-
66- return msg.value.content.recps
67- .map(link => isString(link) ? link : link.link)
68- .filter(link => link !== myId)
69- .map(link => api.about.html.avatar)
70- }
71- else if(msg.value.content.channel)
72- return '#'+msg.value.content.channel
73- }
74-
75-
7669 // REFACTOR: move this to a template?
77- function buildRecipientNames (blog) {
78- const myId = api.keys.sync.id()
70 + // function buildRecipientNames (blog) {
71 + // const myId = api.keys.sync.id()
7972
80- return blog.value.content.recps
81- .map(link => isString(link) ? link : link.link)
82- .filter(link => link !== myId)
83- .map(api.about.obs.name)
84- }
73 + // return blog.value.content.recps
74 + // .map(link => isString(link) ? link : link.link)
75 + // .filter(link => link !== myId)
76 + // .map(api.about.obs.name)
77 + // }
8578
8679 return nest('app.html.blogCard', (blog, opts = {}) => {
87- var strings = api.translations.sync.strings()
80 + if (!blog.value) return
8881
89- if(!blog.value) return
82 + // const lastReply = blog.replies && maxBy(blog.replies, r => r.timestamp)
9083
91- const lastReply = blog.replies && maxBy(blog.replies, r => r.timestamp)
92-
9384 const goToBlog = () => api.history.sync.push(blog)
9485 const onClick = opts.onClick || goToBlog
95- const id = `${blog.key.replace(/[^a-z0-9]/gi, '')}` //-${JSON.stringify(opts)}`
86 + const id = `${blog.key.replace(/[^a-z0-9]/gi, '')}` // -${JSON.stringify(opts)}`
9687 // id is only here to help morphdom morph accurately
9788
9889 const { content, author } = blog.value
9990
10091 var img = h('Thumbnail')
10192
10293 var image = api.blog.html.thumbnail(blog)
10394
104- if(image) {
105- //Hey this works! fit an image into a specific size (see blog-card.mcss)
106- //centered, and scaled to fit the square (works with both landscape and portrait!)
107- //This is functional css not opinionated css, so all embedded.
108- img.style = 'background-image: url("'+api.blob.sync.url(image)+'"); background-position:center; background-size: cover;'
109-
110- }
111- else {
112- var style = { 'background-color': api.about.obs.color(blog.key) }
95 + if (image) {
96 + // Hey this works! fit an image into a specific size (see blog-card.mcss)
97 + // centered, and scaled to fit the square (works with both landscape and portrait!)
98 + // This is functional css not opinionated css, so all embedded.
99 + img.style = 'background-image: url("' + api.blob.sync.url(image) + '"); background-position:center; background-size: cover;'
100 + } else {
101 + var style = { 'background-color': api.about.obs.color(blog.key) }
113102 img = h('Thumbnail -empty', { style }, [
114103 h('i.fa.fa-file-text-o')
115104 ])
116-
117105 }
118106
119- const className = blog.unread ? '-unread': ''
107 + const className = blog.unread ? '-unread' : ''
120108
121109 var b = h('BlogCard', { id, className, 'ev-click': onClick }, [
122110 h('div.context', [
123111 api.about.html.avatar(author, 'tiny'),
@@ -138,5 +126,4 @@
138126
139127 return b
140128 })
141129 }
142-
app/html/channelCard.jsView
@@ -1,33 +1,20 @@
11 const nest = require('depnest')
2-const { h, when } = require('mutant')
2 +const { h } = require('mutant')
33
44 exports.gives = nest('app.html.channelCard')
55
66 exports.needs = nest({
7- 'keys.sync.id': 'first',
87 'history.sync.push': 'first',
9- 'translations.sync.strings': 'first',
10- 'channel.obs.subscribed': 'first',
11- 'channel.obs.isSubscribedTo': 'first',
12- 'channel.async.subscribe': 'first',
13- 'channel.async.unsubscribe': 'first',
14- 'channel.html.subscribe': 'first',
8 + 'channel.html.subscribe': 'first'
159 })
1610
1711 exports.create = function (api) {
18-
1912 return nest('app.html.channelCard', (channel) => {
20- const strings = api.translations.sync.strings()
21- const myId = api.keys.sync.id()
22- const { subscribe, unsubscribe } = api.channel.async
23- const { isSubscribedTo } = api.channel.obs
24- const youSubscribe = isSubscribedTo(channel, myId)
25-
2613 const goToChannel = () => {
2714 api.history.sync.push({ page: 'channelShow', channel: channel })
2815 }
29-
16 +
3017 return h('ChannelCard', [
3118 h('div.content', [
3219 h('div.text', [
3320 h('h2', {'ev-click': goToChannel}, channel),
@@ -36,5 +23,4 @@
3623 ])
3724 ])
3825 })
3926 }
40-
app/html/comments.jsView
@@ -1,6 +1,6 @@
11 const nest = require('depnest')
2-const { h, Array: MutantArray, Value, map, computed, when, resolve, throttle } = require('mutant')
2 +const { h, Value, map, computed, when, resolve, throttle } = require('mutant')
33 const get = require('lodash/get')
44
55 exports.gives = nest('app.html.comments')
66
@@ -14,9 +14,9 @@
1414 'message.html.timeago': 'first',
1515 'message.html.likes': 'first',
1616 'unread.sync.markRead': 'first',
1717 'unread.sync.isUnread': 'first',
18- 'translations.sync.strings': 'first',
18 + 'translations.sync.strings': 'first'
1919 })
2020
2121 exports.create = (api) => {
2222 return nest('app.html.comments', comments)
@@ -28,9 +28,9 @@
2828 // TODO - move this up into Patchcore
2929 const messagesTree = computed(throttle(messages, 200), msgs => {
3030 return msgs
3131 .filter(msg => forkOf(msg) === undefined)
32- .map(threadMsg => {
32 + .map(threadMsg => {
3333 const nestedReplies = msgs.filter(msg => forkOf(msg) === threadMsg.key)
3434 threadMsg.replies = nestedReplies
3535 return threadMsg
3636 })
@@ -55,9 +55,9 @@
5555
5656 return h('Comments', [
5757 // when(twoComposers, compose({ meta, shrink: true, canAttach: false })),
5858 map(messagesTree, msg => Comment(msg, root, branch)),
59- compose({ meta, feedIdsInThread, shrink: false, canAttach: true, placeholder: strings.writeComment }),
59 + compose({ meta, feedIdsInThread, shrink: false, canAttach: true, placeholder: strings.writeComment })
6060 ])
6161 }
6262
6363 function Comment (msgObs, root, branch) {
@@ -73,9 +73,9 @@
7373 const { author, content } = msg.value
7474
7575 // // TODO - move this upstream into patchcore:feed.obs.thread ??
7676 // // OR change strategy to use forks
77- // const backlinks = api.backlinks.obs.for(msg.key)
77 + // const backlinks = api.backlinks.obs.for(msg.key)
7878 // const nestedReplies = computed(backlinks, backlinks => {
7979 // return backlinks.filter(backlinker => {
8080 // const { type, root } = backlinker.value.content
8181 // return type === 'post' && root === msg.key
@@ -94,9 +94,9 @@
9494 },
9595 shrink: false,
9696 canAttach: true,
9797 canPreview: false,
98- placeholder: strings.writeComment
98 + placeholder: strings.writeComment
9999 }, toggleCompose)
100100
101101 return h('Comment', { className }, [
102102 h('div.left', api.about.html.avatar(author, 'tiny')),
@@ -105,20 +105,20 @@
105105 h('div.name', api.about.obs.name(author)),
106106 api.message.html.timeago(msg)
107107 ]),
108108 h('section.content', api.message.html.markdown(raw)),
109- when(msgObs.replies,
110- h('section.replies',
109 + when(msgObs.replies,
110 + h('section.replies',
111111 map(msgObs.replies, NestedComment)
112112 )
113113 ),
114114 h('section.actions', [
115- h('div.reply', { 'ev-click': toggleCompose }, [
116- h('i.fa.fa-commenting-o'),
115 + h('div.reply', { 'ev-click': toggleCompose }, [
116 + h('i.fa.fa-commenting-o')
117117 ]),
118118 api.message.html.likes(msg)
119119 ]),
120- when(nestedReplyCompose, nestedReplyComposer),
120 + when(nestedReplyCompose, nestedReplyComposer)
121121 ])
122122 ])
123123 }
124124
@@ -135,9 +135,9 @@
135135 h('section.context', [
136136 h('div.name', api.about.obs.name(author)),
137137 api.message.html.timeago(msg)
138138 ]),
139- h('section.content', api.message.html.markdown(raw)),
139 + h('section.content', api.message.html.markdown(raw))
140140 ])
141141 ])
142142
143143 api.message.html.markdown(raw)
@@ -146,8 +146,4 @@
146146
147147 function forkOf (msg) {
148148 return get(msg, 'value.content.fork')
149149 }
150-
151-
152-
153-
app/html/header.jsView
@@ -1,28 +1,22 @@
11 const nest = require('depnest')
22 const { h, computed, when } = require('mutant')
3-const get = require('lodash/get')
43 const path = require('path')
54 const { remote } = require('electron')
65
76 exports.gives = nest('app.html.header')
87
9-exports.needs = nest({
10- 'keys.sync.id': 'first'
11-})
12-
138 const SETTINGS_PAGES = [
149 'settings',
15- 'userEdit',
10 + 'userEdit'
1611 ]
1712
1813 exports.create = (api) => {
1914 return nest('app.html.header', (nav) => {
2015 const { location, push } = nav
21- const myKey = api.keys.sync.id()
2216
2317 const loc = computed(location, location => {
24- if (typeof location != 'object') return {}
18 + if (typeof location !== 'object') return {}
2519 return location
2620 })
2721
2822 if (loc().page === 'splash') return
@@ -56,19 +50,19 @@
5650 ]),
5751 h('nav', [
5852 h('img.feed', {
5953 src: when(isFeed, assetPath('feed_on.png'), assetPath('feed.png')),
60- 'ev-click': () => push({page: 'blogIndex'}),
54 + 'ev-click': () => push({page: 'blogIndex'})
6155 }),
6256 h('img.addressBook', {
6357 src: when(isAddressBook, assetPath('address_bk_on.png'), assetPath('address_bk.png')),
6458 'ev-click': () => push({page: 'addressBook'})
6559 }),
6660 h('img.settings', {
6761 src: when(isSettings, assetPath('settings_on.png'), assetPath('settings.png')),
6862 'ev-click': () => push({page: 'settings'})
69- }),
70- ]),
63 + })
64 + ])
7165 ])
7266 })
7367 }
7468
app/html/lightbox.jsView
@@ -1,12 +1,11 @@
11 const nest = require('depnest')
2-const { h, computed, when, Value } = require('mutant')
2 +const { h, when, Value } = require('mutant')
33
44 exports.gives = nest('app.html.lightbox')
55
66 exports.create = (api) => {
77 return nest('app.html.lightbox', (content, isOpen) => {
8-
98 if (typeof isOpen !== 'function') isOpen = Value(false)
109
1110 const openMe = () => isOpen.set(true)
1211 const closeMe = () => isOpen.set(false)
@@ -21,5 +20,4 @@
2120
2221 return lb
2322 })
2423 }
25-
app/html/link.jsView
@@ -3,16 +3,15 @@
33
44 exports.gives = nest('app.html.link')
55
66 exports.needs = nest({
7- 'history.sync.push': 'first',
7 + 'history.sync.push': 'first'
88 })
99
1010 exports.create = (api) => {
1111 return nest('app.html.link', (location, body) => {
12- return h('Link', {
12 + return h('Link', {
1313 'ev-click': () => api.history.sync.push(location),
1414 className: typeof body === 'string' ? '-string' : ''
1515 }, body)
1616 })
1717 }
18-
app/html/scroller.jsView
@@ -1,6 +1,5 @@
11 const nest = require('depnest')
2-const { h } = require('mutant')
32 const pull = require('pull-stream')
43 const Scroller = require('mutant-scroll')
54 const next = require('pull-next-step')
65
@@ -13,9 +12,9 @@
1312 exports.create = function (api) {
1413 return nest('app.html.scroller', createScroller)
1514
1615 function createScroller (opts = {}) {
17- const {
16 + const {
1817 stream,
1918 filter = () => pull.filter((msg) => true),
2019 indexProperty = ['value', 'timestamp']
2120 } = opts
@@ -43,39 +42,4 @@
4342 // store = MutantArray(),
4443 // cb = (err) => { if (err) throw err }
4544 }
4645 }
47-
48-function keyscroll (content) {
49- var curMsgEl
50-
51- if (!content) return () => {}
52-
53- content.addEventListener('click', onActivateChild, false)
54- content.addEventListener('focus', onActivateChild, true)
55-
56- function onActivateChild (ev) {
57- for (var el = ev.target; el; el = el.parentNode) {
58- if (el.parentNode === content) {
59- curMsgEl = el
60- return
61- }
62- }
63- }
64-
65- function selectChild (el) {
66- if (!el) { return }
67-
68- ;(el.scrollIntoViewIfNeeded || el.scrollIntoView).call(el)
69- el.focus()
70- curMsgEl = el
71- }
72-
73- return function scroll (d) {
74- selectChild((!curMsgEl || d === 'first') ? content.firstChild
75- : d < 0 ? curMsgEl.previousElementSibling || content.firstChild
76- : d > 0 ? curMsgEl.nextElementSibling || content.lastChild
77- : curMsgEl)
78-
79- return curMsgEl
80- }
81-}
app/html/sideNav/sideNavAddressBook.jsView
@@ -1,14 +1,9 @@
11 const nest = require('depnest')
2-const { h, computed, Struct, map, when, Dict, Array: MutantArray, Value, Set, resolve } = require('mutant')
3-const pull = require('pull-stream')
4-const next = require('pull-next-step')
5-const get = require('lodash/get')
6-const isEmpty = require('lodash/isEmpty')
7-const path = require('path')
2 +const { h, computed } = require('mutant')
83
94 exports.gives = nest({
10- 'app.html.sideNav': true,
5 + 'app.html.sideNav': true
116 })
127
138 exports.needs = nest({
149 // 'app.html.scroller': 'first',
@@ -17,15 +12,15 @@
1712 // 'feed.pull.private': 'first',
1813 'history.sync.push': 'first',
1914 // 'message.html.subject': 'first',
2015 // 'sbot.obs.localPeers': 'first',
21- 'translations.sync.strings': 'first',
16 + 'translations.sync.strings': 'first'
2217 // 'unread.sync.isUnread': 'first'
2318 })
2419
2520 exports.create = (api) => {
2621 return nest({
27- 'app.html.sideNav': sideNav,
22 + 'app.html.sideNav': sideNav
2823 })
2924
3025 function sideNav (location, relationships) {
3126 if (location.page !== 'addressBook') return
@@ -37,35 +32,35 @@
3732 // TODO - show local peers?
3833 // var nearby = api.sbot.obs.localPeers()
3934
4035 return h('SideNav -addressBook', [
41- LevelOneSideNav(),
36 + LevelOneSideNav()
4237 ])
4338
4439 function LevelOneSideNav () {
4540 return h('div.level.-one', [
4641 h('section', [
4742 SectionOption('search', [
4843 h('Button -primary', {}, strings.action.addUser)
4944 ]),
50- h('hr'),
45 + h('hr')
5146 ]),
52-
53- //Friends
47 +
48 + // Friends
5449 h('section', [
55- h('header',strings.heading.people),
50 + h('header', strings.heading.people),
5651 SectionOption('friends'),
5752 SectionOption('following'),
58- SectionOption('followers'),
53 + SectionOption('followers')
5954 ])
6055 ])
6156 }
6257
6358 function SectionOption (section, body) {
6459 const className = section === location.section
6560 ? '-selected'
6661 : ''
67- return h('Option',
62 + return h('Option',
6863 { className, 'ev-click': goTo({page: 'addressBook', section }) },
6964 body || defaulBody(section)
7065 )
7166
@@ -82,6 +77,4 @@
8277 return computed(relationships, rels => rels[relationshipType].length)
8378 }
8479 }
8580 }
86-
87-
app/html/sideNav/sideNavDiscovery.jsView
@@ -15,11 +15,11 @@
1515 'app.html.scroller': 'first',
1616 'about.html.avatar': 'first',
1717 'about.obs.name': 'first',
1818 'feed.pull.private': 'first',
19- 'keys.sync.id': 'first',
2019 'history.sync.push': 'first',
2120 'history.obs.store': 'first',
21 + 'keys.sync.id': 'first',
2222 'message.html.subject': 'first',
2323 'message.sync.getParticipants': 'first',
2424 'sbot.obs.localPeers': 'first',
2525 'translations.sync.strings': 'first',
@@ -31,48 +31,38 @@
3131 var usersLastMsgCache = Dict() // { id: [ msgs ] }
3232 var unreadMsgsCache = Dict() // { id: [ msgs ] }
3333
3434 return nest({
35- //intercept markUnread and remove them from the cache.
36- 'unread.sync.markUnread': function (msg) {
37- unreadMsgsCache.get(msg.value.content.root || msg.key)
38- .delete(msg.key)
39- unreadMsgsCache.get(msg.value.author)
40- .delete(msg.key)
41- },
42- 'app.html.sideNav': sideNav,
35 + // intercept markUnread and remove them from the cache.
36 + 'unread.sync.markUnread': markUnread,
37 + 'app.html.sideNav': sideNav
4338 })
4439
45- function isMatch (location) {
46- if (location.page) {
47- if (location.page.match(/^blog/)) return true
48- if (location.page.match(/^thread/)) return true
49- if (location.page.match(/^user/)) return true
50- if (location.page.match(/^channel/)) return true
51- }
52- if (location.key) {
53- return true
54- }
55- return false
40 + function markUnread (msg) {
41 + unreadMsgsCache.get(msg.value.content.root || msg.key)
42 + .delete(msg.key)
43 +
44 + const participants = api.message.sync.getParticipants(msg)
45 + unreadMsgsCache.get(participants.key)
46 + .delete(msg.key)
5647 }
5748
5849 function sideNav (location) {
59- if (!isMatch(location)) return
50 + if (!isSideNavDiscovery(location)) return
6051
6152 const strings = api.translations.sync.strings()
62- const myKey = api.keys.sync.id()
6353 var nearby = api.sbot.obs.localPeers()
6454 const getParticipants = api.message.sync.getParticipants
55 + const myKey = api.keys.sync.id()
6556
6657 // Unread message counts
6758 function updateCache (cache, msg) {
68- if(api.unread.sync.isUnread(msg))
69- cache.add(msg.key)
70- else
71- cache.delete(msg.key)
59 + if (api.unread.sync.isUnread(msg)) { cache.add(msg.key) } else { cache.delete(msg.key) }
7260 }
7361
7462 function updateUnreadMsgsCache (msg) {
63 + if (msg.value.author === myKey) return
64 +
7565 const participantsKey = getParticipants(msg).key
7666 updateCache(getUnreadMsgsCache(participantsKey), msg)
7767
7868 const rootKey = get(msg, 'value.content.root', msg.key)
@@ -100,10 +90,10 @@
10090 function isDiscoverLocation (loc) {
10191 const PAGES_UNDER_DISCOVER = ['blogIndex', 'blogShow', 'userShow']
10292
10393 if (PAGES_UNDER_DISCOVER.includes(location.page)) return true
104- if (location.page === 'threadNew') return false
105- if (location.page === 'channelSubscriptions') return false
94 + if (location.page === 'threadNew') return false
95 + if (location.page === 'channelSubscriptions') return false
10696 if (get(location, 'value.private') === undefined) return true
10797 return false
10898 }
10999
@@ -119,22 +109,22 @@
119109 const lastMsg = recent.find(msg => msg.value.author === feedId)
120110 return lastMsg
121111 ? Object.assign(lastMsg, { participants: [feedId] })
122112 : { page: 'threadNew', participants: [feedId] }
123- }),
113 + })
124114 }), { comparer: (a, b) => a === b }),
125115
126116 // ---------------------
127- computed(nearby, n => !isEmpty(n) ? h('hr') : null),
117 + computed(nearby, n => !isEmpty(n) ? h('hr') : null),
128118
129119 // Discover
130120 Option({
131121 imageEl: h('i', [
132122 h('img', { src: path.join(__dirname, '../../../assets', 'discover.png') })
133123 ]),
134124 label: strings.blogIndex.title,
135125 selected: isDiscoverLocation(location),
136- location: { page: 'blogIndex' },
126 + location: { page: 'blogIndex' }
137127 }),
138128
139129 // My subscriptions
140130 Option({
@@ -142,9 +132,9 @@
142132 h('img', { src: path.join(__dirname, '../../../assets', 'my_subscribed.png') })
143133 ]),
144134 label: strings.subscriptions.user,
145135 selected: location.page === 'channelSubscriptions' && location.scope === 'user',
146- location: { page: 'channelSubscriptions', scope: 'user' },
136 + location: { page: 'channelSubscriptions', scope: 'user' }
147137 }),
148138
149139 // Friends subscriptions
150140 Option({
@@ -152,9 +142,9 @@
152142 h('img', { src: path.join(__dirname, '../../../assets', 'friends_subscribed.png') })
153143 ]),
154144 label: strings.subscriptions.friends,
155145 selected: location.page === 'channelSubscriptions' && location.scope === 'friends',
156- location: { page: 'channelSubscriptions', scope: 'friends' },
146 + location: { page: 'channelSubscriptions', scope: 'friends' }
157147 })
158148 ]
159149
160150 return api.app.html.scroller({
@@ -166,32 +156,31 @@
166156 updateTop: updateRecentMsgCache,
167157 updateBottom: updateRecentMsgCache,
168158 render
169159 })
170-
160 +
171161 function render (msgObs) {
172162 const msg = resolve(msgObs)
173163 const participants = getParticipants(msg)
174164 // TODO msg has been decorated with a flat participantsKey, could re-hydrate
175165
176166 if (participants.length === 1 && nearby.has(participants.key)) return
177- const locParticipantsKey = get(location, 'participants', []).join(' ') //TODO collect logic
167 + const locParticipantsKey = get(location, 'participants', []).join(' ') // TODO collect logic
178168
179169 if (participants.length === 1) {
180170 const author = participants[0]
181171 return Option({
182- //the number of threads with each peer
172 + // the number of threads with each peer
183173 notifications: notifications(author),
184174 imageEl: api.about.html.avatar(author),
185175 label: api.about.obs.name(author),
186176 selected: locParticipantsKey === author,
187177 location: Object.assign({}, msg, { participants }) // TODO make obs?
188178 })
189- }
190- else {
179 + } else {
191180 const rootMsg = get(msg, 'value.content.root', msg)
192181 return Option({
193- //the number of threads with each peer
182 + // the number of threads with each peer
194183 notifications: notifications(participants),
195184 imageEl: participants.map(p => api.about.html.avatar(p, 'halfSmall')),
196185 label: api.message.html.subject(rootMsg),
197186 selected: locParticipantsKey === participants.key,
@@ -200,19 +189,19 @@
200189 }
201190 }
202191
203192 function updateRecentMsgCache (soFar, newMsg) {
204- soFar.transaction(() => {
193 + soFar.transaction(() => {
205194 const { timestamp } = newMsg.value
206- newMsg.participantsKey = getParticipants(newMsg).key
207- const index = indexOf(soFar, (msg) => newMsg.participantsKey === resolve(msg).participantsKey)
195 + newMsg.participants = getParticipants(newMsg)
196 + const index = indexOf(soFar, (msg) => newMsg.participants.key === resolve(msg).participants.key)
208197 var object = Value()
209198
210199 if (index >= 0) {
211200 // reference already exists, lets use this instead!
212201 const existingMsg = soFar.get(index)
213202
214- if (resolve(existingMsg).value.timestamp > timestamp) return
203 + if (resolve(existingMsg).value.timestamp > timestamp) return
215204 // but abort if the existing reference is newer
216205
217206 object = existingMsg
218207 soFar.deleteAt(index)
@@ -227,15 +216,14 @@
227216 soFar.push(object)
228217 }
229218 })
230219 }
231-
232220 }
233221
234222 function getUnreadMsgsCache (key) {
235223 var cache = unreadMsgsCache.get(key)
236224 if (!cache) {
237- cache = Set ()
225 + cache = Set()
238226 unreadMsgsCache.put(key, cache)
239227 }
240228 return cache
241229 }
@@ -255,9 +243,9 @@
255243
256244 const prepend = Option({
257245 selected: page === 'threadNew',
258246 location: {page: 'threadNew', participants},
259- label: h('Button', strings.threadNew.action.new),
247 + label: h('Button', strings.threadNew.action.new)
260248 })
261249
262250 var participantsKey = participants.join(' ') // TODO collect this repeated logic
263251 var userLastMsgCache = usersLastMsgCache.get(participantsKey)
@@ -287,14 +275,14 @@
287275 return Option({
288276 notifications: notifications(rootMsg.key),
289277 label: api.message.html.subject(rootMsg),
290278 selected: rootMsg.key === root,
291- location: Object.assign(rootMsg, { participants }),
279 + location: Object.assign(rootMsg, { participants })
292280 })
293281 }
294282
295283 function updateLastMsgCache (soFar, newMsg) {
296- soFar.transaction(() => {
284 + soFar.transaction(() => {
297285 const { timestamp } = newMsg.value
298286 const index = indexOf(soFar, (msg) => timestamp === resolve(msg).value.timestamp)
299287
300288 if (index >= 0) return
@@ -312,9 +300,9 @@
312300 }
313301 }
314302
315303 function Option ({ notifications = 0, imageEl, label, location, selected }) {
316- const className = selected ? '-selected' : ''
304 + const className = selected ? '-selected' : ''
317305 function goToLocation (e) {
318306 e.preventDefault()
319307 e.stopPropagation()
320308 api.history.sync.push(resolve(location))
@@ -330,9 +318,9 @@
330318 return h('Option', { className }, [
331319 h('div.circle', [
332320 when(notifications, h('div.alert', notifications)),
333321 Array.isArray(imageEl)
334- ? h('div.many-images', imageEl.slice(0,4)) // not ideal? not enough space to show more though
322 + ? h('div.many-images', imageEl.slice(0, 4)) // not ideal? not enough space to show more though
335323 : imageEl
336324 ]),
337325 h('div.label', { 'ev-click': goToLocation }, label)
338326 ])
@@ -355,5 +343,17 @@
355343 }
356344 return -1
357345 }
358346
347 +function isSideNavDiscovery (location) {
348 + if (location.page) {
349 + if (location.page.match(/^blog/)) return true
350 + if (location.page.match(/^thread/)) return true
351 + if (location.page.match(/^user/)) return true
352 + if (location.page.match(/^channel/)) return true
353 + }
354 + if (location.key) {
355 + return true
356 + }
357 + return false
358 +}
359359
app/html/thread.jsView
@@ -16,10 +16,10 @@
1616 })
1717
1818 exports.create = (api) => {
1919 return nest('app.html.thread', function (thread) {
20- //catch any code that still uses this the old way...
21- if('string' === typeof thread) throw new Error('thread should be observable')
20 + // catch any code that still uses this the old way...
21 + if (typeof thread === 'string') throw new Error('thread should be observable')
2222 const myId = api.keys.sync.id()
2323 const chunkedMessages = buildChunkedMessages(thread.messages)
2424
2525 const threadView = h('Thread',
@@ -53,9 +53,9 @@
5353 function message (msg) {
5454 const raw = get(msg, 'value.content.text')
5555 var unread = api.unread.sync.isUnread(msg) ? ' -unread' : ''
5656 api.unread.sync.markRead(msg)
57- return h('div.msg'+unread, api.message.html.markdown(raw))
57 + return h('div.msg' + unread, api.message.html.markdown(raw))
5858 }
5959
6060 threadView.subject = computed(thread.messages, msgs => {
6161 return get(msgs, '[0].value.content.subject')
@@ -98,8 +98,4 @@
9898 function isSameAuthor (msgA, msgB) {
9999 // TODO (mix) use lodash/get
100100 return msgA.value.author === msgB.value.author
101101 }
102-
103-
104-
105-
app/html/topNav/topNavAddressBook.jsView
@@ -1,29 +1,27 @@
11 const nest = require('depnest')
2-const { h, computed, when } = require('mutant')
3-const get = require('lodash/get')
2 +const { h } = require('mutant')
43
54 exports.gives = nest('app.html.topNav')
65
76 exports.needs = nest({
8- 'translations.sync.strings': 'first',
7 + 'translations.sync.strings': 'first'
98 })
109
1110 exports.create = (api) => {
1211 return nest('app.html.topNav', (location, input) => {
13- if (location.page !== 'addressBook') return
12 + if (location.page !== 'addressBook') return
1413
1514 const strings = api.translations.sync.strings()
1615
1716 return h('TopNav -addressBook', [
1817 h('div.search', [
1918 h('i.fa.fa-search'),
20- h('input', {
19 + h('input', {
2120 placeholder: strings.addressBook.action.find[location.section],
2221 autofocus: 'autofocus',
23- 'ev-input': e => input.set(e.target.value)
24- }),
22 + 'ev-input': e => input.set(e.target.value)
23 + })
2524 ])
2625 ])
2726 })
2827 }
29-
app/html/topNav/topNavBlog.jsView
@@ -1,36 +1,34 @@
11 const nest = require('depnest')
2-const { h, computed, when } = require('mutant')
3-const get = require('lodash/get')
2 +const { h } = require('mutant')
43
54 exports.gives = nest('app.html.topNav')
65
76 exports.needs = nest({
87 'history.sync.push': 'first',
9- 'translations.sync.strings': 'first',
8 + 'translations.sync.strings': 'first'
109 })
1110
1211 exports.create = (api) => {
1312 return nest('app.html.topNav', (location) => {
1413 const strings = api.translations.sync.strings()
1514 const goTo = (loc) => () => api.history.sync.push(loc)
1615
17- if (!['blogIndex', 'blogSearch'].includes(location.page)) return
16 + if (!['blogIndex', 'blogSearch'].includes(location.page)) return
1817
1918 return h('TopNav -blog', [
20- h('div.left', [
21- h('div', {
19 + h('div.left', [
20 + h('div', {
2221 className: location.page === 'blogIndex' ? '-active' : '',
23- 'ev-click': goTo({ page: 'blogIndex' })
22 + 'ev-click': goTo({ page: 'blogIndex' })
2423 }, strings.topNav.blogsAll),
25- h('div', {
24 + h('div', {
2625 className: location.page === 'blogSearch' ? '-active' : '',
27- 'ev-click': goTo({ page: 'blogSearch' })
28- }, strings.topNav.blogSearch),
26 + 'ev-click': goTo({ page: 'blogSearch' })
27 + }, strings.topNav.blogSearch)
2928 ]),
30- h('div.right', [
31- h('Button -strong', { 'ev-click': () => api.history.sync.push({ page: 'blogNew' }) }, strings.blogNew.actions.writeBlog),
29 + h('div.right', [
30 + h('Button -strong', { 'ev-click': () => api.history.sync.push({ page: 'blogNew' }) }, strings.blogNew.actions.writeBlog)
3231 ])
3332 ])
3433 })
3534 }
36-
app/html/topNav/zz_topNavBack.jsView
@@ -1,29 +1,27 @@
11 const nest = require('depnest')
2-const { h, computed, when } = require('mutant')
3-const get = require('lodash/get')
2 +const { h } = require('mutant')
43
54 exports.gives = nest('app.html.topNav')
65
76 exports.needs = nest({
87 'history.sync.back': 'first',
9- 'translations.sync.strings': 'first',
8 + 'translations.sync.strings': 'first'
109 })
1110
1211 exports.create = (api) => {
1312 return nest('app.html.topNav', (location) => {
1413 // const strings = api.translations.sync.strings()
1514 const back = () => api.history.sync.back()
1615
1716 return h('TopNav -back', [
18- h('div.left', [
19- h('div', { 'ev-click': back }, [
20- h('i.fa.fa-chevron-left'),
17 + h('div.left', [
18 + h('div', { 'ev-click': back }, [
19 + h('i.fa.fa-chevron-left')
2120 // strings.blogIndex.title
22- ]),
21 + ])
2322 ]),
24- h('div.right', [
23 + h('div.right', [
2524 ])
2625 ])
2726 })
2827 }
29-
app/index.jsView
@@ -1,7 +1,7 @@
11 module.exports = {
22 async: {
3- catchLinkClick: require('./async/catch-link-click'),
3 + catchLinkClick: require('./async/catch-link-click')
44 },
55 html: {
66 app: require('./html/app'),
77 comments: require('./html/comments'),
@@ -13,14 +13,14 @@
1313 channelCard: require('./html/channelCard'),
1414 topNav: {
1515 topNavAddressBook: require('./html/topNav/topNavAddressBook'),
1616 topNavBlog: require('./html/topNav/topNavBlog'),
17- topNavBack: require('./html/topNav/zz_topNavBack'),
17 + topNavBack: require('./html/topNav/zz_topNavBack')
1818 },
1919 scroller: require('./html/scroller'),
2020 sideNav: {
2121 addressBook: require('./html/sideNav/sideNavAddressBook'),
22- discovery: require('./html/sideNav/sideNavDiscovery'),
22 + discovery: require('./html/sideNav/sideNavDiscovery')
2323 },
2424 warning: require('./html/warning'),
2525 },
2626 obs: {
@@ -47,16 +47,15 @@
4747 // userFind: require('./page/userFind'),
4848 userShow: require('./page/userShow'),
4949 splash: require('./page/splash'),
5050 threadNew: require('./page/threadNew'),
51- threadShow: require('./page/threadShow'),
51 + threadShow: require('./page/threadShow')
5252 },
5353 sync: {
5454 initialize: {
5555 clickHandler: require('./sync/initialize/clickHandler'),
5656 styles: require('./sync/initialize/styles'),
5757 suggests: require('./sync/initialize/suggests'),
58- zoomMemory: require('./sync/initialize/zoomMemory'),
59- },
58 + zoomMemory: require('./sync/initialize/zoomMemory')
59 + }
6060 }
6161 }
62-
app/page/addressBook.jsView
@@ -3,9 +3,9 @@
33 const pull = require('pull-stream')
44
55 exports.gives = nest('app.page.addressBook')
66
7-//declare consts to avoid magic-string errors
7 +// declare consts to avoid magic-string errors
88 const FRIENDS = 'friends'
99 const FOLLOWING = 'following'
1010 const FOLLOWERS = 'followers'
1111 const SEARCH = 'search'
@@ -21,15 +21,15 @@
2121 'contact.html.follow': 'first',
2222 'contact.obs.relationships': 'first',
2323 'history.sync.push': 'first',
2424 'keys.sync.id': 'first',
25- 'translations.sync.strings': 'first',
25 + 'translations.sync.strings': 'first'
2626 })
2727
2828 exports.create = (api) => {
2929 return nest('app.page.addressBook', function (location) {
3030 // location here can expected to be: { page: 'addressBook'}
31-
31 +
3232 const strings = api.translations.sync.strings()
3333 const myKey = api.keys.sync.id()
3434 const relationships = api.contact.obs.relationships(myKey)
3535
@@ -40,18 +40,15 @@
4040 const input = Value()
4141
4242 const suggester = api.about.async.suggest()
4343 const users = computed([relationships, input], (relationships, input) => {
44- if (section === SEARCH)
45- return suggester(input)
46- else {
44 + if (section === SEARCH) { return suggester(input) } else {
4745 const sectionRels = relationships[section]
4846 if (!input) {
4947 return sectionRels // show all e.g. friends
5048 .reverse()
5149 .map(id => { return { id, title: api.about.obs.name(id) } })
52- }
53- else { // show suggestions, and filter just the ones we want e.g. friends
50 + } else { // show suggestions, and filter just the ones we want e.g. friends
5451 return suggester(input, relationships.followers) // add extraIds to suggester
5552 .filter(user => sectionRels.includes(user.id))
5653 }
5754 }
@@ -62,9 +59,9 @@
6259 return h('Page -addressBook', [
6360 api.app.html.sideNav(location, relationships),
6461 h('Scroller.content', [
6562 h('section.top', [
66- api.app.html.topNav(location, input),
63 + api.app.html.topNav(location, input)
6764 ]),
6865 h('section.content', [
6966 h('div.results', map(users, user => {
7067 return h('div.result', { 'ev-click': goTo({page: 'userShow', feed: user.id}) }, [
@@ -72,11 +69,10 @@
7269 h('div.alias', user.title),
7370 // h('pre.key', user.id),
7471 api.contact.html.follow(user.id)
7572 ])
76- })),
73 + }))
7774 ])
7875 ])
7976 ])
8077 })
8178 }
82-
app/page/blogIndex.jsView
@@ -20,9 +20,9 @@
2020
2121 exports.create = (api) => {
2222 return nest('app.page.blogIndex', function (location) {
2323 // location here can expected to be: { page: 'blogIndex'}
24-
24 +
2525 var strings = api.translations.sync.strings()
2626
2727 var blogs = api.app.html.scroller({
2828 classList: ['content'],
@@ -50,15 +50,14 @@
5050 blogs
5151 ])
5252 })
5353
54-
5554 function update (soFar, newBlog) {
56- soFar.transaction(() => {
55 + soFar.transaction(() => {
5756 const { timestamp } = newBlog.value
5857
5958 var object = newBlog // Value(newBlog)
60-
59 +
6160 // Orders by: time received
6261 const justOlderPosition = indexOf(soFar, (msg) => newBlog.timestamp > resolve(msg).timestamp)
6362
6463 // Orders by: time published BUT the messagesByType stream streams _by time received_
@@ -72,14 +71,12 @@
7271 }
7372 })
7473 }
7574
76-
7775 function render (blog) {
7876 const { recps, channel } = blog.value.content
7977 var onClick
80- if (channel && !recps)
81- onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' }))
78 + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) }
8279 return api.app.html.blogCard(blog, { onClick })
8380 }
8481 }
8582
@@ -90,5 +87,4 @@
9087 }
9188 }
9289 return -1
9390 }
94-
app/page/blogIndex.mcssView
@@ -9,8 +9,12 @@
99 section.content {
1010 div.BlogCard {
1111 flex-basis: 100%
1212 border-bottom: 1px solid rgba(0,0,0, .1)
13 +
14 + :last-child {
15 + border-bottom: none
16 + }
1317 }
1418 }
1519
1620 section.bottom {
app/page/blogNew.jsView
@@ -27,9 +27,9 @@
2727 const meta = Struct({
2828 type: 'blog',
2929 channel: Value(),
3030 title: Value(),
31- summary: Value(),
31 + summary: Value()
3232 })
3333
3434 const composer = api.message.html.compose(
3535 {
@@ -43,16 +43,16 @@
4343
4444 var stream = pull.values([content.text])
4545 delete content.text
4646 api.sbot.async.addBlob(stream, function (err, hash) {
47- if(err) return cb(err)
48- if(!hash) throw new Error('missing hash')
47 + if (err) return cb(err)
48 + if (!hash) throw new Error('missing hash')
4949 content.blog = hash
5050 cb(null, content)
5151 })
5252 }
5353 },
54- (err, msg) => api.history.sync.push(err ? err : { page: 'blogIndex' })
54 + (err, msg) => api.history.sync.push(err || { page: 'blogIndex' })
5555 )
5656
5757 const channelInput = h('input', {
5858 'ev-input': e => meta.channel.set(e.target.value),
@@ -71,16 +71,16 @@
7171 h('div.label', strings.blogNew.field.title),
7272 h('input', {
7373 'ev-input': e => meta.title.set(e.target.value),
7474 placeholder: strings.blogNew.field.title
75- }),
75 + })
7676 ]),
7777 h('div.field -summary', [
7878 h('div.label', strings.blogNew.field.summary),
7979 h('input', {
8080 'ev-input': e => meta.summary.set(e.target.value),
8181 placeholder: strings.blogNew.field.summary
82- }),
82 + })
8383 ]),
8484 composer
8585 ])
8686 ])
@@ -93,10 +93,9 @@
9393 s.value = s.value.replace(/^#/, '') // strip the defualt # prefix here
9494 return s
9595 })
9696 .map(s => {
97- if (s.subtitle === 'subscribed')
98- s.subtitle = h('i.fa.fa-heart') // TODO - translation-friendly subscribed
97 + if (s.subtitle === 'subscribed') { s.subtitle = h('i.fa.fa-heart') } // TODO - translation-friendly subscribed
9998 return s
10099 })
101100
102101 // HACK add the input text if it's not an option already
@@ -117,9 +116,4 @@
117116
118117 return page
119118 }
120119 }
121-
122-
123-
124-
125-
app/page/blogSearch.jsView
@@ -20,31 +20,31 @@
2020 })
2121
2222 exports.create = (api) => {
2323 return nest('app.page.blogSearch', blogSearch)
24-
24 +
2525 function blogSearch (location) {
2626 // location here can expected to be: { page: 'blogSearch'}
2727 // OR { page: 'blogSearch', channel: 'scuttlebutt', searchVal: 'scutt'}
28-
28 +
2929 var strings = api.translations.sync.strings()
3030
3131 var searchVal = Value(resolve(location.searchVal) || resolve(location.channel) || '')
32- var searchResults = computed([api.channel.obs.recent(), searchVal], (channels, val) => {
32 + var searchResults = computed([api.channel.obs.recent(), searchVal], (channels, val) => {
3333 if (val.length < 2) return []
3434
3535 return channels.filter(c => c.toLowerCase().indexOf(val.toLowerCase()) > -1)
3636 })
3737 var searchField = h('div.search', [
3838 h('div.input', [
3939 h('i.fa.fa-search'),
40- h('input', {
40 + h('input', {
4141 'ev-input': e => searchVal.set(e.target.value),
42- value: searchVal
42 + value: searchVal
4343 })
4444 ]),
45- when(searchResults,
46- h('div.results', map(searchResults, channel => {
45 + when(searchResults,
46 + h('div.results', map(searchResults, channel => {
4747 const classList = channel === location.channel
4848 ? ['-channelActive']
4949 : ''
5050 const newLocation = {
@@ -89,16 +89,12 @@
8989 blogs
9090 ])
9191 }
9292
93-
9493 function render (blog) {
9594 const { recps, channel } = blog.value.content
9695 var onClick
97- if (channel && !recps)
98- onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' }))
96 + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) }
9997
10098 return api.app.html.blogCard(blog, { onClick })
10199 }
102100 }
103-
104-
app/page/blogSearch.mcssView
@@ -47,8 +47,12 @@
4747 div.BlogCard {
4848 flex-basis: 100%
4949
5050 border-bottom: 1px solid gainsboro
51 +
52 + :last-child {
53 + border-bottom: none
54 + }
5155 }
5256 }
5357
5458 section.bottom {
app/page/blogShow.jsView
@@ -1,9 +1,6 @@
11 const nest = require('depnest')
2-const { h, computed, when } = require('mutant')
3-const { title: getTitle } = require('markdown-summary')
4-const last = require('lodash/last')
5-const get = require('lodash/get')
2 +const { h } = require('mutant')
63
74 exports.gives = nest('app.page.blogShow')
85
96 exports.needs = nest({
@@ -14,31 +11,29 @@
1411 'app.html.sideNav': 'first',
1512 'contact.html.follow': 'first',
1613 'message.html.channel': 'first',
1714 'message.html.likes': 'first',
18- 'message.html.markdown': 'first',
1915 'message.html.timeago': 'first',
2016 'feed.obs.thread': 'first',
2117 'blog.html.title': 'first',
22- 'blog.html.content': 'first',
18 + 'blog.html.content': 'first'
2319 })
2420
2521 exports.create = (api) => {
2622 return nest('app.page.blogShow', blogShow)
2723
2824 function blogShow (blogMsg) {
2925 // blogMsg = a thread (message, may be decorated with replies)
3026
31- const { author, content } = blogMsg.value
27 + const { author } = blogMsg.value
3228
3329 const blog = api.blog.html.content(blogMsg)
3430 const title = api.blog.html.title(blogMsg)
3531
3632 const thread = api.feed.obs.thread(blogMsg.key)
3733 const comments = api.app.html.comments(thread)
38- const branch = thread.lastId
3934
40- const { timeago, channel, markdown } = api.message.html
35 + const { timeago, channel } = api.message.html
4136
4237 return h('Page -blogShow', [
4338 api.app.html.sideNav({ page: 'blogShow' }), // HACK to highlight discover
4439 h('Scroller.content', [
@@ -57,20 +52,15 @@
5752 h('div.leftCol', api.about.html.avatar(author, 'medium')),
5853 h('div.rightCol', [
5954 h('div.name', api.about.obs.name(author)),
6055 api.contact.html.follow(author)
61- ]),
56 + ])
6257 ])
6358 ]),
6459 h('div.break', h('hr')),
6560 h('section.blog', blog),
66- comments,
67- ]),
61 + comments
62 + ])
6863 ])
6964 ])
7065 }
7166 }
72-
73-
74-
75-
76-
app/page/channel.jsView
@@ -10,17 +10,16 @@
1010 'app.html.link': 'first',
1111 'app.html.blogCard': 'first',
1212 'history.sync.push': 'first',
1313 'state.obs.channel': 'first',
14- 'translations.sync.strings': 'first',
14 + 'translations.sync.strings': 'first'
1515 })
1616
17-function latestUpdate(thread) {
17 +function latestUpdate (thread) {
1818 var m = thread.timestamp
19- if(!thread.replies) return m
19 + if (!thread.replies) return m
2020
21- for(var i = 0; i < thread.replies.length; i++)
22- m = Math.max(thread.replies[i].timestamp, m)
21 + for (var i = 0; i < thread.replies.length; i++) { m = Math.max(thread.replies[i].timestamp, m) }
2322 return m
2423 }
2524
2625 exports.create = (api) => {
@@ -29,9 +28,9 @@
2928 var strings = api.translations.sync.strings()
3029
3130 var channelObs = api.state.obs.channel(channel)
3231
33- //disable "Show More" button when we are at the last thread.
32 + // disable "Show More" button when we are at the last thread.
3433 var disableShowMore = computed([channelObs], threads => !!threads.ended)
3534
3635 var updates = h('div.threads', [])
3736 var threadsHtmlObs = More(
@@ -56,11 +55,9 @@
5655 Link({ page: 'threadNew', channel }, h('Button -strong', strings.channel.action.newThread)),
5756 h('div.content', [ threadsHtmlObs ]),
5857 h('Button -showMore', {
5958 'ev-click': threadsHtmlObs.more,
60- disabled: disableShowMore
59 + disabled: disableShowMore
6160 }, [strings.showMore])
6261 ])
6362 })
6463 }
65-
66-
app/page/channelShow.jsView
@@ -1,6 +1,6 @@
11 const nest = require('depnest')
2-const { h, Value, computed, map, when, resolve } = require('mutant')
2 +const { h } = require('mutant')
33 const pull = require('pull-stream')
44
55 exports.gives = nest('app.page.channelShow')
66
@@ -8,33 +8,31 @@
88 'app.html.sideNav': 'first',
99 'app.html.topNav': 'first',
1010 'app.html.scroller': 'first',
1111 'app.html.blogCard': 'first',
12 + 'channel.html.subscribe': 'first',
1213 'feed.pull.channel': 'first',
1314 'history.sync.push': 'first',
14- 'translations.sync.strings': 'first',
15- 'channel.obs.recent': 'first',
16- 'channel.html.subscribe': 'first'
15 + 'translations.sync.strings': 'first'
1716 })
1817
1918 exports.create = (api) => {
2019 return nest('app.page.channelShow', channelShow)
2120
22- function channelShow(location) {
23- var strings = api.translations.sync.strings()
21 + function channelShow (location) {
22 + const strings = api.translations.sync.strings()
23 + const { channel } = location
2424
25- var searchVal = resolve(location.channel)
26-
27- createStream = api.feed.pull.channel(location.channel)
25 + createStream = api.feed.pull.channel(channel)
2826
2927 const prepend = [
3028 api.app.html.topNav(location),
3129 h('section.about', [
32- h('h1', location.channel),
30 + h('h1', channel),
3331 h('div.actions', [
34- api.channel.html.subscribe(location.channel)
32 + api.channel.html.subscribe(channel)
3533 ])
36- ]),
34 + ])
3735 ]
3836
3937 var channelPosts = api.app.html.scroller({
4038 classList: ['content'],
@@ -54,22 +52,22 @@
5452 // updateBottom: updateRecentMsgCache,
5553 render
5654 })
5755
56 + location.page = location.page || 'channelShow'
57 + // covers case where router.sync.normalise delivers a loc = { channel: '#channelName' }
58 + // HACK: helps sideNav
59 +
5860 return h('Page -channelShow', { title: strings.home }, [
5961 api.app.html.sideNav(location),
6062 channelPosts
6163 ])
6264 }
6365
64-
65- function render(blog) {
66 + function render (blog) {
6667 const { recps, channel } = blog.value.content
6768 var onClick
68- if (channel && !recps)
69- onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' }))
69 + if (channel && !recps) { onClick = (ev) => api.history.sync.push(Object.assign({}, blog, { page: 'blogShow' })) }
7070
7171 return api.app.html.blogCard(blog, { onClick })
7272 }
7373 }
74-
75-
app/page/channelShow.mcssView
@@ -8,37 +8,34 @@
88 right: 0
99 top: 0
1010 z-index: 99
1111
12-
12 + padding-bottom: 1rem
13 + margin-bottom: 1rem
1314
1415 section.about {
15-
16 + padding-bottom: 1rem
17 +
1618 display: flex
1719 flex-direction: column
1820 align-items: center
19- padding-bottom: 1rem
20-
2121
2222 h1 {
2323 font-weight: bold
2424 font-size: 1.5rem
2525 padding: 1rem
2626
2727 margin: auto
28-
2928 }
3029
3130 div.actions {
3231 display: flex
3332
3433 div.Button {
3534 margin: auto
3635 }
37-
3836 }
3937 }
40-
4138 }
4239
4340 section.content {
4441 background-color: #fff
@@ -52,8 +49,12 @@
5249 div.BlogCard {
5350 flex-basis: 100%
5451
5552 border-bottom: 1px solid gainsboro
53 +
54 + :last-child {
55 + border-bottom: none
56 + }
5657 }
5758 }
5859
5960 section.bottom {
app/page/channelSubscriptions.jsView
@@ -1,6 +1,6 @@
11 const nest = require('depnest')
2-const { h, when, Value, Array: MutantArray, onceTrue, computed, map: mutantMap } = require('mutant')
2 +const { h, when, Value, Array: MutantArray, onceTrue, watch, computed, map: mutantMap } = require('mutant')
33 const sortBy = require('lodash/sortBy')
44 const map = require('lodash/map')
55 const difference = require('lodash/difference')
66
@@ -14,46 +14,46 @@
1414 'app.obs.pluginWarnings': 'first',
1515 'history.sync.push': 'first',
1616 'keys.sync.id': 'first',
1717 'channel.obs.subscribed': 'first',
18- 'channel.obs.recent':'first',
18 + 'channel.obs.recent': 'first',
1919 'channel.html.link': 'first',
2020 'translations.sync.strings': 'first',
2121 'sbot.async.friendsGet': 'first',
2222 'sbot.pull.userFeed': 'first',
2323 'sbot.obs.connection': 'first'
2424 })
2525
2626 exports.create = (api) => {
27- const otherChannels = MutantArray ()
27 + const otherChannels = MutantArray()
2828
2929 return nest('app.page.channelSubscriptions', function (location) {
3030 const strings = api.translations.sync.strings()
3131 const myId = api.keys.sync.id()
3232
3333 const rawSubs = api.channel.obs.subscribed(myId)
34- const mySubs = computed(rawSubs, myChannels => [...myChannels.values()].reverse() )
34 + const mySubs = computed(rawSubs, myChannels => [...myChannels.values()].reverse())
3535
36- if (location.scope === "user") {
37-
36 + if (location.scope === 'user') {
3837 return h('Page -channelSubscriptions', { title: strings.home }, [
3938 api.app.html.sideNav(location),
4039 h('div.content', [
41- when(rawSubs.sync,
40 + when(rawSubs.sync,
4241 [
4342 computed(mySubs, mys => mys.length === 0 ? strings.subscriptions.state.noSubscriptions : ''),
44- mutantMap(mySubs, api.app.html.channelCard),
43 + mutantMap(mySubs, api.app.html.channelCard)
4544 ],
4645 h('p', strings.loading)
4746 )
4847 ])
4948 ])
5049 }
5150
52- if (location.scope === "friends") {
51 + if (location.scope === 'friends') {
5352 // update list of other all channels
54- onceTrue(
55- api.app.obs.pluginWarnings,
53 + // NOTE can't use onceTrue right now, because warnings are true/ false
54 + watch(
55 + api.app.obs.pluginWarnings(),
5656 isWarnings => {
5757 if (isWarnings) {
5858 return
5959 }
@@ -63,18 +63,18 @@
6363
6464 const showMoreCounter = Value(1)
6565 const newChannels = computed([otherChannels, mySubs, showMoreCounter], (other, mine, more) => {
6666 return difference(other, mine)
67- .slice(0, 10*more)
67 + .slice(0, 10 * more)
6868 })
6969
7070 return h('Page -channelSubscriptions', { title: strings.home }, [
7171 api.app.html.sideNav(location),
7272 h('div.content', [
7373 when(otherChannels,
7474 [
7575 mutantMap(newChannels, api.app.html.channelCard),
76- h('Button', { 'ev-click': () => showMoreCounter.set(showMoreCounter()+1) },
76 + h('Button', { 'ev-click': () => showMoreCounter.set(showMoreCounter() + 1) },
7777 strings.showMore
7878 )
7979 ],
8080 h('p', strings.loading)
@@ -84,8 +84,9 @@
8484 }
8585 })
8686
8787 function getChannels (sbot) {
88 + console.log('fetching channel subscriptions')
8889 sbot.channel.subscriptions((err, c) => {
8990 if (err) throw err
9091 let b = map(c, (v,k) => {return {channel: k, users: v}})
9192 b = sortBy(b, o => o.users.length)
app/page/error.jsView
@@ -18,5 +18,4 @@
1818 h('pre', [JSON.stringify(location, null, 2)])
1919 ])
2020 }
2121 }
22-
app/page/groupFind.jsView
@@ -5,9 +5,9 @@
55
66 exports.needs = nest({
77 'app.html.link': 'first',
88 'channel.async.suggest': 'first',
9- 'translations.sync.strings': 'first',
9 + 'translations.sync.strings': 'first'
1010 })
1111
1212 exports.create = (api) => {
1313 return nest('app.page.groupFind', groupFind)
@@ -16,30 +16,30 @@
1616 const strings = api.translations.sync.strings()
1717 const input = Value('')
1818
1919 // CHANNEL != GROUP
20- // note we're using channels in initial approximation of groups
20 + // note we're using channels in initial approximation of groups
2121 const suggester = api.channel.async.suggest()
22- const groups = computed(input, input => suggester(input))
22 + const groups = computed(input, input => suggester(input))
2323
2424 const Link = api.app.html.link
2525
2626 return h('Page -groupFind', {title: strings.groupFind.pageTitle}, [
2727 h('div.content', [
2828 h('div.search', [
2929 h('i.fa.fa-search'),
30- h('input', {
30 + h('input', {
3131 placeholder: strings.groupFind.action.findAGroup,
3232 autofocus: 'autofocus',
33- 'ev-input': e => input.set(e.target.value)
34- }),
33 + 'ev-input': e => input.set(e.target.value)
34 + })
3535 ]),
3636 h('div.results', map(groups, group => {
3737 return Link({ channel: group.title },
3838 h('div.result', [
3939 // api.about.html.image(user.id),
4040 h('div.alias', group.id), // channel with #
41- h('pre.key', group.subtitle || ' '), // subscribed or not
41 + h('pre.key', group.subtitle || ' ') // subscribed or not
4242 ])
4343 )
4444 })),
4545 computed([input, groups], (input, groups) => {
@@ -56,9 +56,4 @@
5656 ])
5757 ])
5858 }
5959 }
60-
61-
62-
63-
64-
app/page/groupIndex.jsView
@@ -16,8 +16,4 @@
1616 '****'
1717 ])
1818 }
1919 }
20-
21-
22-
23-
app/page/groupNew.jsView
@@ -15,7 +15,4 @@
1515 '****'
1616 ])
1717 }
1818 }
19-
20-
21-
app/page/groupShow.jsView
@@ -3,9 +3,9 @@
33
44 exports.gives = nest('app.page.groupShow')
55
66 exports.needs = nest({
7- 'translations.sync.strings': 'first',
7 + 'translations.sync.strings': 'first'
88 })
99
1010 exports.create = (api) => {
1111 var strings = api.translations.sync.strings()
@@ -19,9 +19,4 @@
1919 h('p', `key: ${location.key}`)
2020 ])
2121 }
2222 }
23-
24-
25-
26-
27-
app/page/image.jsView
@@ -18,6 +18,4 @@
1818 ])
1919 ])
2020 })
2121 }
22-
23-
app/page/settings.jsView
@@ -15,9 +15,9 @@
1515 'message.html.markdown': 'first',
1616 'settings.sync.get': 'first',
1717 'settings.sync.set': 'first',
1818 'settings.obs.get': 'first',
19- 'translations.sync.strings': 'first',
19 + 'translations.sync.strings': 'first'
2020 })
2121
2222 const LANGUAGES = ['zh', 'en']
2323
@@ -30,9 +30,8 @@
3030 exports.create = (api) => {
3131 return nest('app.page.settings', settings)
3232
3333 function settings (location) {
34-
3534 // RESET the app when the settings are changed
3635 api.settings.obs.get('language')(() => {
3736 console.log('language changed, resetting view')
3837
@@ -50,30 +49,30 @@
5049 const editProfile = () => api.history.sync.push({
5150 page: 'userEdit',
5251 feed,
5352 callback: (err, didEdit) => {
54- if (err) throw new Error ('Error editing profile', err)
53 + if (err) throw new Error('Error editing profile', err)
5554 api.history.sync.push({ page: 'settings' })
5655 }
57- })
56 + })
5857
5958 return h('Page -settings', [
6059 h('div.content', [
6160 h('h1', strings.settingsPage.title),
6261 h('section -avatar', [
6362 h('div.left'),
64- h('div.right', api.about.html.image(feed)),
63 + h('div.right', api.about.html.image(feed))
6564 ]),
6665 h('section -name', [
6766 h('div.left', strings.settingsPage.section.name),
68- h('div.right', [
67 + h('div.right', [
6968 api.about.obs.name(feed),
70- h('img', {
69 + h('img', {
7170 src: path.join(__dirname, '../../assets', 'edit.png'),
7271 'ev-click': editProfile
7372 })
7473 // h('i.fa.fa-pencil', { 'ev-click': editProfile })
75- ]),
74 + ])
7675 ]),
7776 h('section -introduction', [
7877 h('div.left', strings.settingsPage.section.introduction),
7978 h('div.right', computed(api.about.obs.description(feed), d => api.message.html.markdown(d || '')))
@@ -84,38 +83,37 @@
8483 ]),
8584 h('section -zoom', [
8685 h('div.left', strings.settingsPage.section.zoom),
8786 h('div.right', [ zoomButton(-0.1, '-'), zoomButton(+0.1, '+') ])
88- ]),
87 + ])
8988 ])
9089 ])
9190
9291 function Language (lang) {
9392 const selectLang = () => api.settings.sync.set({ language: lang })
94- const className = currentLanguage === lang ? '-strong' : ''
93 + const className = currentLanguage === lang ? '-strong' : ''
9594
96- return h('Button -language',
97- {
98- 'ev-click': () => selectLang(lang),
99- className
100- },
95 + return h('Button -language',
96 + {
97 + 'ev-click': () => selectLang(lang),
98 + className
99 + },
101100 strings.languages[lang]
102101 )
103102 }
104103
105104 function zoomButton (increment, symbol) {
106105 const { getCurrentWebContents } = electron.remote
107- return h('Button -zoom',
108- {
106 + return h('Button -zoom',
107 + {
109108 'ev-click': () => {
110109 var zoomFactor = api.settings.sync.get('ticktack.electron.zoomFactor', 1)
111110 var newZoomFactor = zoomFactor + increment
112111 var zoomFactor = api.settings.sync.set('ticktack.electron.zoomFactor', newZoomFactor)
113112 getCurrentWebContents().setZoomFactor(newZoomFactor)
114113 }
115- },
114 + },
116115 symbol
117116 )
118117 }
119118 }
120119 }
121-
app/page/splash.jsView
@@ -30,9 +30,9 @@
3030 h('img.logoName', { src: assetPath('logo_and_name.png') })
3131 ]),
3232 h('div.bottom', { style }, [
3333 h('div.about', strings.splash.about),
34- h('pre.slogan', strings.splash.slogan),
34 + h('pre.slogan', strings.splash.slogan)
3535 ])
3636 ])
3737 }
3838 }
app/page/threadNew.jsView
@@ -14,18 +14,17 @@
1414 'history.sync.push': 'first',
1515 'keys.sync.id': 'first',
1616 'message.html.compose': 'first',
1717 'message.sync.unbox': 'first',
18- 'translations.sync.strings': 'first',
18 + 'translations.sync.strings': 'first'
1919 })
2020
2121 exports.create = (api) => {
22-
2322 return nest('app.page.threadNew', threadNew)
2423
2524 function threadNew (location) {
2625 if (isEmpty(location.participants)) return
27-
26 +
2827 return threadNewFeed(location)
2928 }
3029
3130 function threadNewFeed (location) {
@@ -35,14 +34,14 @@
3534 const { participants } = location
3635
3736 const meta = Struct({
3837 type: 'post',
39- recps: MutantArray ([
38 + recps: MutantArray([
4039 myId,
4140 ...participants.map(p => {
42- return {
43- link: p,
44- name: resolve(api.about.obs.name(p))
41 + return {
42 + link: p,
43 + name: resolve(api.about.obs.name(p))
4544 }
4645 })
4746 ]),
4847 subject: Value()
@@ -63,9 +62,9 @@
6362 h('div.label', strings.threadNew.field.subject),
6463 h('input', {
6564 'ev-input': e => meta.subject.set(e.target.value),
6665 placeholder: strings.optionalField
67- }),
66 + })
6867 ]),
6968 Composer(meta)
7069 ])
7170 ])
@@ -91,10 +90,9 @@
9190 addSuggest()
9291
9392 input.addEventListener('suggestselect', (e) => {
9493 const { id, title: name } = e.detail
95- if (!recps.find(r => r === id || r.link === id))
96- recps.push({ link: id, name })
94 + if (!recps.find(r => r === id || r.link === id)) { recps.push({ link: id, name }) }
9795
9896 boxActive = false
9997 e.target.value = ''
10098 e.target.placeholder = ''
@@ -148,7 +146,5 @@
148146 }
149147 )
150148 }
151149 }
152-
153150 }
154-
app/page/threadShow.jsView
@@ -22,9 +22,9 @@
2222 const { key, value } = location
2323 const root = get(value, 'content.root', key)
2424 const channel = get(value, 'content.channel')
2525
26- //unread state is set in here...
26 + // unread state is set in here...
2727 const thread = api.feed.obs.thread(root)
2828 const subject = get(location, 'value.content.subject')
2929 const recps = get(location, 'value.content.recps')
3030
@@ -41,21 +41,21 @@
4141 api.app.html.sideNav(location),
4242 h('div.content', [
4343 h('header', [
4444 when(subject, h('h1', subject)),
45- Recipients(recps),
45 + Recipients(recps)
4646 ]),
4747 api.app.html.thread(thread),
4848 composer
49- ]),
49 + ])
5050 ])
5151 }
5252
5353 function Recipients (recps) {
54- if (recps && recps.length > 2)
54 + if (recps && recps.length > 2) {
5555 return h('div.recps', recps.map(r => {
5656 const recp = typeof r === 'string' ? r : r.link
5757 return api.about.html.avatar(recp, 'tiny')
5858 }))
59 + }
5960 }
6061 }
61-
app/page/userEdit.jsView
@@ -5,9 +5,9 @@
55
66 exports.needs = nest({
77 'about.page.edit': 'first',
88 'history.sync.push': 'first',
9- 'translations.sync.strings': 'first',
9 + 'translations.sync.strings': 'first'
1010 })
1111
1212 exports.create = (api) => {
1313 return nest('app.page.userEdit', userEdit)
@@ -26,18 +26,18 @@
2626 description: strings.userEdit.section.introduction,
2727 instructionCrop: strings.userEdit.instruction.crop,
2828 okay: strings.userEdit.action.okay,
2929 cancel: strings.userEdit.action.cancel,
30- save: strings.userEdit.action.save,
30 + save: strings.userEdit.action.save
3131 }
3232 })
3333
3434 const defaultCallback = (err, didEdit) => {
35- if (err) throw new Error ('Error editing profile', err)
35 + if (err) throw new Error('Error editing profile', err)
3636
3737 api.history.sync.push({ page: 'userShow', feed })
3838 }
39- callback = typeof callback == 'function'
39 + callback = typeof callback === 'function'
4040 ? callback
4141 : defaultCallback
4242
4343 return h('Page -userEdit', {}, [
@@ -46,5 +46,4 @@
4646 ])
4747 ])
4848 }
4949 }
50-
app/page/userFind.jsView
@@ -6,9 +6,9 @@
66 exports.needs = nest({
77 'about.html.image': 'first',
88 'app.html.link': 'first',
99 'about.async.suggest': 'first',
10- 'translations.sync.strings': 'first',
10 + 'translations.sync.strings': 'first'
1111 })
1212
1313 exports.create = (api) => {
1414 return nest('app.page.userFind', userFind)
@@ -17,35 +17,31 @@
1717 const strings = api.translations.sync.strings()
1818 const input = Value()
1919
2020 const suggester = api.about.async.suggest()
21- const users = computed(input, input => suggester(input))
21 + const users = computed(input, input => suggester(input))
2222
2323 const Link = api.app.html.link
2424
2525 return h('Page -userFind', {title: strings.userFind.pageTitle}, [
2626 h('div.content', [
2727 h('div.search', [
2828 h('i.fa.fa-search'),
29- h('input', {
29 + h('input', {
3030 placeholder: strings.userFind.action.findAUser,
3131 autofocus: 'autofocus',
32- 'ev-input': e => input.set(e.target.value)
33- }),
32 + 'ev-input': e => input.set(e.target.value)
33 + })
3434 ]),
3535 h('div.results', map(users, user => {
3636 return Link({ feed: user.id },
3737 h('div.result', [
3838 api.about.html.image(user.id),
3939 h('div.alias', user.title),
40- h('pre.key', user.id),
40 + h('pre.key', user.id)
4141 ])
4242 )
4343 }))
4444 ])
4545 ])
4646 }
4747 }
48-
49-
50-
51-
app/page/userShow.jsView
@@ -37,9 +37,9 @@
3737 const strings = api.translations.sync.strings()
3838
3939 const Link = api.app.html.link
4040 const userEditButton = Link(
41- { page: 'userEdit', feed },
41 + { page: 'userEdit', feed },
4242 // h('i.fa.fa-pencil')
4343 h('img', { src: path.join(__dirname, '../../assets', 'edit.png') })
4444 )
4545 const directMessageButton = Link({ page: 'threadNew', participants: [feed] }, h('Button', strings.userShow.action.directMessage))
@@ -47,9 +47,9 @@
4747 const BLOG_TYPES = ['blog', 'post']
4848
4949 // TODO return some of this ?
5050 // but maybe this shouldn't be done here ?
51- // pull.through(function (blog) {
51 + // pull.through(function (blog) {
5252 // if(isUnread(blog))
5353 // blog.unread = true
5454 // blog.replies.forEach(function (data) { // this was fed rollups
5555 // if(isUnread(data))
@@ -69,14 +69,14 @@
6969 ]),
7070 h('div.introduction', computed(api.about.obs.description(feed), d => api.message.html.markdown(d || ''))),
7171 feed !== myId
7272 ? h('div.actions', [
73- h('div.directMessage', directMessageButton),
74- api.contact.html.follow(feed),
75- api.contact.html.block(feed)
76- ])
77- : '',
78- ]),
73 + h('div.directMessage', directMessageButton),
74 + api.contact.html.follow(feed),
75 + api.contact.html.block(feed)
76 + ])
77 + : ''
78 + ])
7979 ]
8080
8181 const store = MutantArray()
8282 // store(console.log)
@@ -84,9 +84,9 @@
8484 return h('Page -userShow', [
8585 api.app.html.sideNav(location),
8686 api.app.html.scroller({
8787 classList: ['content'],
88- prepend,
88 + prepend,
8989 // stream: api.feed.pull.profile(feed),
9090 stream: opts => api.sbot.pull.userFeed(Object.assign({}, { id: feed }, opts)),
9191 indexProperty: ['value', 'sequence'],
9292 filter: () => pull(
@@ -102,5 +102,4 @@
102102 })
103103 ])
104104 }
105105 }
106-
app/sync/initialize/clickHandler.jsView
@@ -4,9 +4,9 @@
44 exports.gives = nest('app.sync.initialize')
55
66 exports.needs = nest({
77 'app.async.catchLinkClick': 'first',
8- 'history.sync.push': 'first',
8 + 'history.sync.push': 'first'
99 })
1010
1111 exports.create = (api) => {
1212 return nest({
@@ -20,5 +20,4 @@
2020 })
2121 }
2222 })
2323 }
24-
app/sync/initialize/styles.jsView
@@ -15,5 +15,4 @@
1515 insertCss(css)
1616 }
1717 })
1818 }
19-
app/sync/initialize/suggests.jsView
@@ -3,9 +3,9 @@
33 exports.gives = nest('app.sync.initialize')
44
55 exports.needs = nest({
66 'about.async.suggest': 'first',
7- 'channel.async.suggest': 'first',
7 + 'channel.async.suggest': 'first'
88 // 'channel.obs.recent': 'first'
99 })
1010
1111 exports.create = (api) => {
@@ -18,5 +18,4 @@
1818 // api.channel.obs.recent()() TODO - figure out how to initialise this store
1919 }
2020 })
2121 }
22-
app/sync/initialize/zoomMemory.jsView
@@ -10,15 +10,15 @@
1010
1111 exports.create = (api) => {
1212 return nest('app.sync.initialize', zoomMemory)
1313
14- function zoomMemory() {
14 + function zoomMemory () {
1515 const { getCurrentWebContents, getCurrentWindow } = electron.remote
1616
1717 window.addEventListener('resize', () => {
1818 var wc = getCurrentWebContents()
1919 wc && wc.getZoomFactor(zf => {
20- console.log(zf)
20 + console.log(zf)
2121 api.settings.sync.set({
2222 ticktack: {
2323 electron: {
2424 zoomFactor: zf,
@@ -29,13 +29,10 @@
2929 })
3030 })
3131
3232 var zoomFactor = api.settings.sync.get('ticktack.electron.zoomFactor')
33- if (zoomFactor)
34- getCurrentWebContents().setZoomFactor(zoomFactor)
33 + if (zoomFactor) { getCurrentWebContents().setZoomFactor(zoomFactor) }
3534
3635 var bounds = api.settings.sync.get('ticktack.electron.windowBounds')
37- if (bounds)
38- getCurrentWindow().setBounds(bounds)
36 + if (bounds) { getCurrentWindow().setBounds(bounds) }
3937 }
4038 }
41-
blog/html/blog.jsView
@@ -7,22 +7,21 @@
77 exports.gives = nest({
88 'blog.html.title': true,
99 'blog.html.summary': true,
1010 'blog.html.thumbnail': true,
11- 'blog.html.content': true,
11 + 'blog.html.content': true
1212 })
1313
1414 exports.needs = nest({
1515 'message.html.markdown': 'first',
1616 'sbot.pull.stream': 'first',
1717 'sbot.obs.connection': 'first'
1818 })
1919
20-
2120 exports.create = function (api) {
2221 function loadBlob (data) {
2322 const { blog } = data.value.content
24- if (!isBlob(blog)) {
23 + if (!isBlob(blog)) {
2524 console.log(`malformed Blog blog: ${blog}`, data)
2625 return
2726 }
2827
@@ -37,33 +36,33 @@
3736 }
3837
3938 return nest({
4039 'blog.html.title': function (data) {
41- if(!isBlog(data)) return
40 + if (!isBlog(data)) return
4241
4342 return data.value.content.title
4443 },
4544 'blog.html.summary': function (data) {
46- if(!isBlog(data)) return
45 + if (!isBlog(data)) return
4746
4847 loadBlob(data)
4948 return data.value.content.summary
5049 },
5150 'blog.html.thumbnail': function (data) {
52- if(!isBlog(data)) return
51 + if (!isBlog(data)) return
5352 return data.value.content.thumbnail
5453 },
5554 'blog.html.content': function (data) {
56- if(!isBlog(data)) return
55 + if (!isBlog(data)) return
5756
5857 loadBlob(data)
5958 var div = h('Markdown')
6059 pull(
6160 api.sbot.pull.stream(function (sbot) {
6261 return sbot.blobs.get(data.value.content.blog)
6362 }),
6463 pull.collect(function (err, ary) {
65- if(err) return
64 + if (err) return
6665 var md = api.message.html.markdown({text: Buffer.concat(ary).toString()})
6766 div.innerHTML = md.innerHTML
6867 })
6968 )
@@ -74,5 +73,4 @@
7473
7574 function isBlog (msg) {
7675 return get(msg, 'value.content.type') === 'blog'
7776 }
78-
blog/html/post.jsView
@@ -4,21 +4,20 @@
44 exports.gives = nest({
55 'blog.html.title': true,
66 'blog.html.summary': true,
77 'blog.html.thumbnail': true,
8- 'blog.html.content': true,
8 + 'blog.html.content': true
99 })
1010
1111 exports.needs = nest({
12- 'message.html.markdown': 'first',
12 + 'message.html.markdown': 'first'
1313 })
1414
1515 exports.create = function (api) {
16-
17- function fromPost(fn) {
16 + function fromPost (fn) {
1817 return function (data) {
19- if('post' !== data.value.content.type) return
20- return api.message.html.markdown ({text: fn(data.value.content)})
18 + if (data.value.content.type !== 'post') return
19 + return api.message.html.markdown({text: fn(data.value.content)})
2120 }
2221 }
2322
2423 return nest({
@@ -30,19 +29,17 @@
3029 if (content.summary) return content.summary
3130 if (content.text) return marksum.summary(content.text)
3231 }),
3332 'blog.html.thumbnail': function (data) {
34- const { type, thumbnail, text } = data.value.content
35- if('post' !== type) return
33 + const { type, thumbnail, text } = data.value.content
34 + if (type !== 'post') return
3635 if (thumbnail) return thumbnail
3736
3837 if (text) {
3938 var img = marksum.image(text)
4039 var m = /\!\[[^]+\]\(([^\)]+)\)/.exec(img)
41- if(m) return m[1]
40 + if (m) return m[1]
4241 }
4342 },
4443 'blog.html.content': fromPost(content => content.text)
4544 })
4645 }
47-
48-
blog/index.jsView
@@ -3,5 +3,4 @@
33 post: require('./html/post'),
44 blog: require('./html/blog')
55 }
66 }
7-
channel/async.jsView
@@ -3,9 +3,9 @@
33
44 exports.needs = nest({
55 'keys.sync.id': 'first',
66 'sbot.async.publish': 'first',
7- 'channel.obs.subscribed': 'first',
7 + 'channel.obs.subscribed': 'first'
88 })
99
1010 exports.gives = nest({
1111 'channel.async': ['subscribe', 'unsubscribe']
@@ -16,8 +16,9 @@
1616 'channel.async': {subscribe, unsubscribe}
1717 })
1818
1919 function subscribe (channel, cb) {
20 + channel = channel.replace(/^#/, '')
2021 if (!channel) throw new Error('a channel must be specified')
2122 api.sbot.async.publish({
2223 type: 'channel',
2324 channel: channel,
@@ -25,13 +26,13 @@
2526 }, cb)
2627 }
2728
2829 function unsubscribe (channel, cb) {
30 + channel = channel.replace(/^#/, '')
2931 if (!channel) throw new Error('a channel must be specified')
3032 api.sbot.async.publish({
3133 type: 'channel',
3234 channel: channel,
3335 subscribed: false
3436 }, cb)
3537 }
36-
3738 }
channel/html/subscribe.jsView
@@ -3,25 +3,27 @@
33
44 exports.gives = nest('channel.html.subscribe')
55
66 exports.needs = nest({
7- 'keys.sync.id': 'first',
87 'translations.sync.strings': 'first',
98 'channel.obs.isSubscribedTo': 'first',
109 'channel.async.subscribe': 'first',
11- 'channel.async.unsubscribe': 'first',
10 + 'channel.async.unsubscribe': 'first'
1211 })
1312
1413 exports.create = function (api) {
15-
1614 return nest('channel.html.subscribe', (channel) => {
15 + channel = channel.replace(/^#/, '')
1716 const strings = api.translations.sync.strings()
18- const myId = api.keys.sync.id()
1917 const { subscribe, unsubscribe } = api.channel.async
20-
21- return when(api.channel.obs.isSubscribedTo(channel, myId),
18 + const isSubscribed = api.channel.obs.isSubscribedTo(channel)
19 +
20 + isSubscribed(val => {
21 + console.log(channel, 'subscribed:', val)
22 + })
23 +
24 + return when(isSubscribed,
2225 h('Button', { 'ev-click': () => unsubscribe(channel) }, strings.channelShow.action.unsubscribe),
2326 h('Button -primary', { 'ev-click': () => subscribe(channel) }, strings.channelShow.action.subscribe)
2427 )
2528 })
2629 }
27-
channel/index.jsView
@@ -1,9 +1,7 @@
1-module.exports = {
1 +module.exports = {
22 async: require('./async'),
33 obs: require('./obs'),
44 html: {
55 subscribe: require('./html/subscribe')
66 }
77 }
8-
9-
channel/obs.jsView
@@ -1,11 +1,12 @@
11 const nest = require('depnest')
22 const ref = require('ssb-ref')
3-const computed = require('mutant/computed')
3 +const { computed, onceTrue } = require('mutant')
44
55 exports.needs = nest({
66 'keys.sync.id': 'first',
77 'channel.obs.subscribed': 'first',
8 + 'sbot.obs.connection': 'first'
89 })
910
1011 exports.gives = nest('channel.obs.isSubscribedTo')
1112
@@ -15,24 +16,27 @@
1516
1617 return nest('channel.obs.isSubscribedTo', isSubscribedTo)
1718
1819 function isSubscribedTo (channel, id) {
20 + channel = channel.replace(/^#/, '')
1921 if (!ref.isFeed(id)) {
2022 id = getMyId()
2123 }
22-
23- return computed(getSubscriptions(id), (v) => v.has(channel))
24 +
25 + // TODO - use ssb-server-channel index to make a better subscribed obs
26 + return computed(getSubscriptions(id), set => {
27 + return set.has(channel)
28 + })
2429 }
2530
26- //cache getters
31 + // cache getters
2732
2833 function getMyId () {
2934 if (!myId) myId = api.keys.sync.id()
3035 return myId
3136 }
3237
3338 function getSubscriptions (id) {
34- if (!subscriptions[id]) subscriptions[id] = api.channel.obs.subscribed(id)
39 + if (subscriptions[id] === undefined) subscriptions[id] = api.channel.obs.subscribed(id)
3540 return subscriptions[id]
3641 }
3742 }
38-
config.jsView
@@ -20,5 +20,4 @@
2020 }
2121 return config
2222 })
2323 }
24-
contact/html/block.jsView
@@ -12,9 +12,8 @@
1212 'app.html.lightbox': 'first'
1313 })
1414
1515 exports.create = (api) => {
16-
1716 return nest('contact.html.block', block)
1817
1918 function block (feed) {
2019 const strings = api.translations.sync.strings()
@@ -34,11 +33,11 @@
3433 block(feed)
3534 isOpen.set(false)
3635 }
3736
38- const confirmationDialog = h("div.dialog", [
39- h("div.message",strings.userShow.action.blockConfirmationMessage),
40- h("div.actions", [
37 + const confirmationDialog = h('div.dialog', [
38 + h('div.message', strings.userShow.action.blockConfirmationMessage),
39 + h('div.actions', [
4140 h('Button', {'ev-click': () => isOpen.set(false)}, strings.userShow.action.cancel),
4241 h('Button -primary', {'ev-click': () => blockAndClose(feed)}, strings.userShow.action.block)
4342 ])
4443 ])
@@ -50,11 +49,10 @@
5049 when(youBlockThem,
5150 h('Button', { 'ev-click': () => unblock(feed) }, strings.userShow.action.unblock),
5251 h('Button', { 'ev-click': () => isOpen.set(true) }, strings.userShow.action.block)
5352 ),
54- h('Button', { disabled: 'disabled' }, strings.loading )
53 + h('Button', { disabled: 'disabled' }, strings.loading)
5554 ),
5655 lb
5756 ])
5857 }
5958 }
60-
contact/html/follow.jsView
@@ -7,9 +7,9 @@
77 'contact.async.follow': 'first',
88 'contact.async.unfollow': 'first',
99 'contact.obs.followers': 'first',
1010 'keys.sync.id': 'first',
11- 'translations.sync.strings': 'first',
11 + 'translations.sync.strings': 'first'
1212 })
1313
1414 exports.create = (api) => {
1515 return nest('contact.html.follow', follow)
@@ -32,17 +32,16 @@
3232 const unfollow = (feed) => ev => {
3333 ev.stopPropagation()
3434 api.contact.async.unfollow(feed)
3535 }
36-
36 +
3737 return h('Follow', { className },
3838 when(theirFollowers.sync,
3939 when(youFollowThem,
4040 h('Button', { 'ev-click': unfollow(feed) }, strings.userShow.action.unfollow),
4141 h('Button -strong', { 'ev-click': follow(feed) }, strings.userShow.action.follow)
4242 ),
43- h('Button', { disabled: 'disabled' }, strings.loading )
43 + h('Button', { disabled: 'disabled' }, strings.loading)
4444 )
4545 )
4646 }
4747 }
48-
contact/index.jsView
@@ -1,11 +1,9 @@
1-module.exports = {
1 +module.exports = {
22 html: {
33 follow: require('./html/follow'),
44 block: require('./html/block')
55 },
66 obs: {
7- relationships: require('./obs/relationships'),
8- },
7 + relationships: require('./obs/relationships')
8 + }
99 }
10-
11-
contact/obs/relationships.jsView
@@ -26,6 +26,5 @@
2626
2727 return { friends, followers, following }
2828 })
2929 }
30-}
31-
30 +}
main.jsView
@@ -9,21 +9,21 @@
99 require('./context-menu')
1010
1111 // from more specialized to more general
1212 const sockets = combine(
13- //need some modules first
14- {
13 + // need some modules first
14 + {
1515 settings: require('patch-settings'),
1616 translations: require('./translations/sync'),
17- suggestions: require('patch-suggest'), // so that styles can be over-ridden
17 + suggestions: require('patch-suggest') // so that styles can be over-ridden
1818 },
1919 {
2020 about: require('./about'),
2121 app: require('./app'),
2222 blob: require('./blob'),
2323 blog: require('./blog'),
2424 contact: require('./contact'),
25- //config: require('./ssb-config'),
25 + // config: require('./ssb-config'),
2626 config: require('./config'),
2727 // group: require('./group'),
2828 message: require('./message'),
2929 router: require('./router'),
@@ -39,10 +39,9 @@
3939 }
4040 )
4141
4242 const api = entry(sockets, nest({
43- 'app.html.app': 'first',
43 + 'app.html.app': 'first'
4444 }))
4545
4646 document.body.appendChild(api.app.html.app())
4747 // console.log(api.config.sync.load())
48-
message/async/publish.jsView
@@ -16,5 +16,4 @@
1616
1717 return true
1818 })
1919 }
20-
message/html/channel.jsView
@@ -9,18 +9,19 @@
99
1010 exports.create = function (api) {
1111 return nest('message.html.channel', channel)
1212
13- function channel (msgOrChannel, opts = {} ) {
14- const channel = typeof msgOrChannel === 'string'
13 + function channel (msgOrChannel, opts = {}) {
14 + var channel = typeof msgOrChannel === 'string'
1515 ? msgOrChannel
1616 : msgOrChannel.value.content.channel
17 + channel = channel.replace(/^#/, '')
1718
1819 if (!channel) return
1920
20- const {
21 + const {
2122 classList = [],
22- location = { page: 'blogSearch', channel }
23 + location = { page: 'channelShow', channel }
2324 } = opts
2425
2526 const goToChannel = (e) => {
2627 e.stopPropagation()
@@ -33,6 +34,4 @@
3334 classList
3435 }, channel)
3536 }
3637 }
37-
38-
message/html/compose.jsView
@@ -28,9 +28,9 @@
2828 feedIdsInThread = [],
2929 placeholder,
3030 shrink = true,
3131 canAttach = true, canPreview = true,
32- prepublish,
32 + prepublish
3333 } = options
3434
3535 const strings = api.translations.sync.strings()
3636 const getUserSuggestions = api.about.async.suggest()
@@ -67,9 +67,9 @@
6767
6868 textArea.publish = publish // TODO: fix - clunky api for the keyboard shortcut to target
6969
7070 var fileInput
71- if(!meta.recps) {
71 + if (!meta.recps) {
7272 fileInput = api.blob.html.input(file => {
7373 files.push(file)
7474 filesById[file.link] = file
7575
@@ -88,18 +88,17 @@
8888 fileInput.onclick = () => hasContent.set(true)
8989 }
9090 // if fileInput is null, send button moves to the left side
9191 // and we don't want that.
92- else
93- fileInput = h('input', { style: {visibility: 'hidden'} })
92 + else { fileInput = h('input', { style: {visibility: 'hidden'} }) }
9493
9594 function PreviewSetup (strings) {
9695 var showPreview = Value(false)
9796 var previewBtn = h('Button',
9897 {
9998 className: when(showPreview, '-strong', '-subtle'),
10099 'ev-click': () => showPreview.set(!showPreview())
101- },
100 + },
102101 when(showPreview, strings.blogNew.actions.edit, strings.blogNew.actions.preview)
103102 )
104103 return { previewBtn, showPreview }
105104 }
@@ -151,28 +150,25 @@
151150 var content = assign({}, resolve(meta), {
152151 text,
153152 mentions
154153 })
155- for(var k in content)
156- content[k] = resolve(content[k])
154 + for (var k in content) { content[k] = resolve(content[k]) }
157155
158156 if (!content.channel) delete content.channel
159157 if (!mentions.length) delete content.mentions
160158 if (content.recps && content.recps.length === 0) delete content.recps
161159
162160 if (typeof prepublish === 'function') {
163161 prepublish(content, function (err, content) {
164- if(err) handleErr(err)
162 + if (err) handleErr(err)
165163 else api.message.async.publish(content, done)
166164 })
167- }
168- else
169- api.message.async.publish(content, done)
165 + } else { api.message.async.publish(content, done) }
170166
171167 function done (err, msg) {
172168 publishBtn.disabled = false
173169 if (err) handleErr(err)
174- else if (msg) {
170 + else if (msg) {
175171 textRaw.set('')
176172 textArea.value = ''
177173 }
178174 if (cb) cb(err, msg)
@@ -185,6 +181,4 @@
185181 }
186182 }
187183 }
188184 }
189-
190-
message/html/likes.jsView
@@ -41,5 +41,4 @@
4141 }
4242 api.sbot.async.publish(like)
4343 }
4444 }
45-
message/html/subject.jsView
@@ -2,47 +2,47 @@
22 const { computed, Value } = require('mutant')
33 const { title } = require('markdown-summary')
44 const { isMsg } = require('ssb-ref')
55
6-
76 exports.gives = nest('message.html.subject')
87
98 exports.needs = nest({
109 'message.html.markdown': 'first',
1110 'message.sync.unbox': 'first',
12- 'sbot.async.get': 'first',
11 + 'sbot.async.get': 'first'
1312 })
1413
1514 exports.create = function (api) {
15 + var subjectCache = {}
16 +
1617 return nest('message.html.subject', subject)
1718
1819 function subject (msg) {
1920 if (msg === undefined) debugger
2021 // test if it's a message ref, or a full message object
22 + // a message ref is generally passed in if we're fetching the subject of a root message
2123 if (isMsg(msg)) {
24 + if (subjectCache[msg]) return subjectCache[msg]
25 +
2226 var subject = Value()
2327
2428 api.sbot.async.get(msg, (err, value) => {
2529 if (err) throw err
2630
27- subject.set(getMsgSubject({
28- key: msg,
29- value: api.message.sync.unbox(value)
30- }))
31 + var _subject = getMsgSubject({ key: msg, value: api.message.sync.unbox(value) })
32 + subject.set(_subject)
33 + subjectCache[msg] = _subject
3134 })
3235
3336 return subject
34- }
35- else
36- return getMsgSubject(msg)
37 + } else { return getMsgSubject(msg) }
3738 }
3839
3940 function getMsgSubject (msg) {
4041 const { subject, text } = msg.value.content
41- if(!(subject || text)) return
42 + if (!(subject || text)) return
4243
4344 return subject
4445 ? api.message.html.markdown(subject)
4546 : api.message.html.markdown(title(text))
4647 }
4748 }
48-
message/html/timeago.jsView
@@ -14,5 +14,4 @@
1414 // perhaps by adding an initializer which sweeps for data-timestamp elements and updates them
1515 return h('Timeago', humanTime(new Date(timestamp)))
1616 }
1717 }
18-
message/index.jsView
@@ -1,7 +1,7 @@
1-module.exports = {
1 +module.exports = {
22 async: {
3- publish: require('./async/publish'),
3 + publish: require('./async/publish')
44 },
55 html: {
66 channel: require('./html/channel'),
77 compose: require('./html/compose'),
@@ -9,8 +9,7 @@
99 subject: require('./html/subject'),
1010 timeago: require('./html/timeago')
1111 },
1212 sync: {
13- getParticipants: require('./sync/getParticipants'),
14- },
13 + getParticipants: require('./sync/getParticipants')
14 + }
1515 }
16-
message/sync/getParticipants.jsView
@@ -3,9 +3,9 @@
33
44 exports.gives = nest('message.sync.getParticipants')
55
66 exports.needs = nest({
7- 'keys.sync.id': 'first',
7 + 'keys.sync.id': 'first'
88 })
99
1010 exports.create = function (api) {
1111 return nest('message.sync.getParticipants', getParticipants)
@@ -21,7 +21,4 @@
2121 participants.key = participants.join(' ')
2222 return participants
2323 }
2424 }
25-
26-
27-
router/sync/routes.jsView
@@ -26,9 +26,9 @@
2626 'app.page.splash': 'first',
2727 'app.page.threadNew': 'first',
2828 'app.page.threadShow': 'first',
2929 // 'app.page.image': 'first',
30- 'blob.sync.url': 'first',
30 + 'blob.sync.url': 'first'
3131 })
3232
3333 exports.create = (api) => {
3434 return nest('router.sync.routes', (sofar = []) => {
@@ -43,19 +43,19 @@
4343 [ location => location.page === 'blogNew', pages.blogNew ],
4444 [ location => location.page === 'blogSearch', pages.blogSearch ],
4545 [ location => location.page === 'blogShow', pages.blogShow ],
4646 [ location => isMsg(location.key) && get(location, 'value.content.type') === 'blog', pages.blogShow ],
47- [ location => {
48- return isMsg(location.key)
49- && get(location, 'value.content.type') === 'post'
50- && !get(location, 'value.private') // treats public posts as 'blogs'
47 + [ location => {
48 + return isMsg(location.key) &&
49 + get(location, 'value.content.type') === 'post' &&
50 + !get(location, 'value.private') // treats public posts as 'blogs'
5151 }, pages.blogShow ],
5252
5353 // Channel related pages
5454 [ location => location.page === 'channelSubscriptions', pages.channelSubscriptions],
5555 [ location => location.page === 'channelShow', pages.channelShow ],
56 + [ location => location.channel, pages.channelShow ],
5657
57-
5858 // AddressBook pages
5959 [ location => location.page === 'addressBook', pages.addressBook ],
6060
6161 // Private Thread pages
@@ -88,5 +88,4 @@
8888
8989 return [...routes, ...sofar]
9090 })
9191 }
92-
state/obs.jsView
@@ -25,10 +25,10 @@
2525 var lastTimestamp = opts.last || Date.now()
2626 var firstTimestamp = opts.first || Date.now()
2727
2828 function unbox (data) {
29- if(data.sync) return data
30- if(isObject(data.value.content)) return data
29 + if (data.sync) return data
30 + if (isObject(data.value.content)) return data
3131 return api.message.sync.unbox(data)
3232 }
3333
3434 var obs = PullObv(
@@ -43,41 +43,39 @@
4343 pull.map(unbox),
4444 pull.filter(Boolean),
4545 api.feed.pull.rollup()
4646 ),
47- //value recovered from localStorage
47 + // value recovered from localStorage
4848 initial
4949 )
5050
51- //stream live messages. this *should* work.
52- //there is no back pressure on new events
53- //only a show more on the top (currently)
51 + // stream live messages. this *should* work.
52 + // there is no back pressure on new events
53 + // only a show more on the top (currently)
5454 pull(
5555 Next(function () {
5656 return createStream({limit: 500, gt: firstTimestamp, live: true})
5757 }),
5858 pull.map(unbox), pull.filter(Boolean),
5959 pull.drain(function (data) {
60- if(data.sync) return
60 + if (data.sync) return
6161 firstTimestamp = data.timestamp
6262 obs.set(reduce(obs.value, data))
6363 })
6464 )
6565
6666 return obs
6767 }
6868
69-
7069 return nest({
71- 'state.obs.channel': function (channel) {
72-
70 + 'state.obs.channel': function (channel) {
7371 return createStateObs(
7472 threadReduce,
7573 function (opts) {
76- return opts.reverse ?
77- api.feed.pull.channel(channel)(opts):
78- pull(api.sbot.pull.log(opts), pull.filter(function (data) {
79- if(data.sync) return false
74 + return opts.reverse
75 + ? api.feed.pull.channel(channel)(opts)
76 + : pull(api.sbot.pull.log(opts), pull.filter(function (data) {
77 + if (data.sync) return false
8078 return data.value.content.channel === channel
8179 }))
8280 },
8381 {}
@@ -86,13 +84,11 @@
8684 // var channelObs = PullObv(
8785 // threadReduce,
8886 // createChannelStream({reverse: true, limit: 1000})
8987 // )
88 + },
9089
91-
92- },
93-
94- 'state.obs.threads': function buildThreadObs() {
90 + 'state.obs.threads': function buildThreadObs () {
9591 if (threadsObs) return threadsObs
9692
9793 // DISABLE localStorage cache. mainly disabling this to make debugging the other stuff
9894 // easier. maybe re-enable this later? also, should this be for every channel too? not sure.
@@ -105,10 +101,9 @@
105101
106102 threadsObs = createStateObs(threadReduce, api.sbot.pull.log, initial, {})
107103
108104 threadsObs(function (threadsState) {
109- if(threadsState.ended && threadsState.ended !== true)
110- console.error('threadObs error:', threadsState.ended)
105 + if (threadsState.ended && threadsState.ended !== true) { console.error('threadObs error:', threadsState.ended) }
111106 })
112107
113108 // var timer
114109 // //keep localStorage up to date
@@ -125,14 +120,4 @@
125120 return threadsObs
126121 }
127122 })
128123 }
129-
130-
131-
132-
133-
134-
135-
136-
137-
138-
styles/css/fontAwesome.jsView
@@ -8,5 +8,4 @@
88 return nest('styles.css', (sofar = {}) => {
99 return assign(sofar, { css: requireStyle('font-awesome') })
1010 })
1111 }
12-
translations/checker.jsView
@@ -9,12 +9,11 @@
99 function customizer (objVal, srcVal, key, obj, src, stack) {
1010 // See docs https://lodash.com/docs/4.17.4#mergeWith
1111
1212 if (objVal == undefined) { // implies zh is missing key
13- if (typeof srcVal == 'string') console.log(key, '=', srcVal)
13 + if (typeof srcVal === 'string') console.log(key, '=', srcVal)
1414 }
1515 }
1616
17-
1817 merge(zh, en, customizer)
1918 // signature: obj, src, customizer
2019 // order matters because of customizer
translations/en.jsView
@@ -13,9 +13,9 @@
1313 ok: 'Okay'
1414 }
1515 },
1616 blogIndex: {
17- title: 'Discover',
17 + title: 'Discover'
1818 },
1919 topNav: {
2020 blogsAll: 'Dynamics',
2121 blogSearch: 'Search'
@@ -27,9 +27,9 @@
2727 },
2828 actions: {
2929 edit: 'Edit',
3030 preview: 'Preview',
31- writeBlog: 'Write a blog',
31 + writeBlog: 'Write a blog'
3232 }
3333 },
3434 channel: 'Channel',
3535 loading: 'Loading...',
@@ -39,12 +39,12 @@
3939 peopleNearby: 'People nearby',
4040 sendMessage: 'Send',
4141 showMore: 'Show More',
4242 directMessages: 'Direct Messages',
43- home: "Home",
44- error: "Error",
43 + home: 'Home',
44 + error: 'Error',
4545 errorNotFound: "The page wasn't found",
46- groupNew: "New Group",
46 + groupNew: 'New Group',
4747 groupFind: {
4848 action: {
4949 findAGroup: 'Find Group',
5050 newGroup: 'Create this group'
@@ -55,13 +55,13 @@
5555 flash: {
5656 createFirstThread: 'Start this group by posting the first thread.'
5757 }
5858 },
59- groupIndex: "Group Index",
59 + groupIndex: 'Group Index',
6060 settingsPage: {
61- title: "Settings",
61 + title: 'Settings',
6262 action: {
63- edit: 'Edit',
63 + edit: 'Edit'
6464 },
6565 section: {
6666 name: 'Name',
6767 introduction: 'Introduction',
@@ -75,9 +75,9 @@
7575 find: {
7676 friends: 'Search your friends',
7777 following: "Search people you're following",
7878 followers: 'Search your followers',
79- search: 'Search for a user',
79 + search: 'Search for a user'
8080 }
8181 },
8282 heading: {
8383 people: 'People'
@@ -91,9 +91,9 @@
9191 threadNew: {
9292 pageTitle: 'New Thread',
9393 field: {
9494 to: 'To',
95- subject: 'Subject',
95 + subject: 'Subject'
9696 },
9797 action: {
9898 new: 'New Message',
9999 addMoreRecps: 'add more recipients (optional)'
@@ -103,9 +103,9 @@
103103 userEdit: {
104104 section: {
105105 avatar: 'Avatar',
106106 name: 'Name',
107- introduction: 'Introduction',
107 + introduction: 'Introduction'
108108 },
109109 instruction: {
110110 crop: 'Click and drag to crop your avatar'
111111 },
@@ -116,9 +116,9 @@
116116 }
117117 },
118118 userFind: {
119119 action: {
120- findAUser: 'Find a user',
120 + findAUser: 'Find a user'
121121 }
122122 },
123123 userShow: {
124124 action: {
@@ -133,11 +133,11 @@
133133 state: {
134134 friends: 'You are friends',
135135 youFollow: 'You follow them',
136136 theyFollow: 'They follow you',
137- userIsInGroups: "is in groups:",
137 + userIsInGroups: 'is in groups:',
138138 userConversationsWith: 'conversations you\'ve had with',
139- follow: "Follow",
139 + follow: 'Follow',
140140 friendsInCommon: 'friends in common'
141141 }
142142 },
143143 channelShow: {
@@ -146,10 +146,10 @@
146146 unsubscribe: 'Unsubscribe'
147147 }
148148 },
149149 subscriptions: {
150- user: "My subscriptions",
151- friends: "Friends subscriptions",
150 + user: 'My subscriptions',
151 + friends: 'Friends subscriptions',
152152 state: {
153153 noSubscriptions: 'You have no subscriptions yet'
154154 }
155155 },
translations/sync.jsView
@@ -16,5 +16,4 @@
1616
1717 return merge({}, languages.en, languages[language])
1818 })
1919 }
20-
translations/zh.jsView
@@ -13,32 +13,32 @@
1313 writeComment: '留言',
1414 peopleNearby: '附件的朋友',
1515 addressBook: {
1616 heading: {
17- people: '用户',
17 + people: '用户'
1818 },
1919 section: {
2020 friends: '好友',
2121 following: '我关注的',
22- followers: '关注我的',
22 + followers: '关注我的'
2323 },
2424 action: {
2525 addUser: '添加好友',
2626 find: {
2727 friends: '查找好友',
2828 following: '查找我关注的人',
2929 followers: '查找关注我的人',
30- search: '查找用户',
30 + search: '查找用户'
3131 }
32- },
32 + }
3333 },
3434 blogIndex: {
3535 title: '发现'
3636 },
3737 blogNew: {
3838 field: {
3939 title: '标题',
40- summary: '序言',
40 + summary: '序言'
4141 },
4242 actions: {
4343 edit: '编辑',
4444 preview: '预览',
@@ -47,9 +47,9 @@
4747 },
4848 channelShow: {
4949 action: {
5050 subscribe: '订阅',
51- unsubscribe: '取消订阅',
51 + unsubscribe: '取消订阅'
5252 }
5353 },
5454 topNav: {
5555 blogsAll: '最新',
@@ -70,9 +70,9 @@
7070 groupIndex: '群组列表',
7171 settingsPage: {
7272 title: '设置',
7373 action: {
74- edit: '编辑',
74 + edit: '编辑'
7575 },
7676 section: {
7777 language: '语言',
7878 profile: '自我介绍',
@@ -84,13 +84,13 @@
8484 threadNew: {
8585 pageTitle: '新建话题',
8686 field: {
8787 to: '发送给',
88- subject: '主题',
88 + subject: '主题'
8989 },
9090 action: {
9191 new: '创建私信',
92- addMoreRecps: '添加多个用户(可选)',
92 + addMoreRecps: '添加多个用户(可选)'
9393 }
9494 },
9595 threadShow: '所有私信',
9696 userEdit: {
@@ -104,10 +104,10 @@
104104 },
105105 action: {
106106 okay: '完成',
107107 cancel: '取消',
108- save: '保存',
109- },
108 + save: '保存'
109 + }
110110 },
111111 userFind: {
112112 action: {
113113 findAUser: '查找用户'
@@ -120,9 +120,9 @@
120120 directMessage: '创建私信',
121121 block: '拉黑',
122122 unblock: '原谅',
123123 blockConfirmationMessage: '拉黑意味着您再也不会接收到此用户的信息',
124- cancel: '取消',
124 + cancel: '取消'
125125 },
126126 state: {
127127 friends: '你们成为了好友',
128128 youFollow: '你关注了的',
@@ -136,9 +136,9 @@
136136 subscriptions: {
137137 user: '我的订阅',
138138 friends: '朋友的订阅',
139139 state: {
140- noSubscriptions: '您还没有任何订阅',
140 + noSubscriptions: '您还没有任何订阅'
141141 }
142142 },
143143 languages: {
144144 en: 'English',
unread.jsView
@@ -6,54 +6,51 @@
66 'unread.sync.markRead': true,
77 'unread.obs.userMessages': true
88 })
99
10-//load current state of unread messages.
10 +// load current state of unread messages.
1111
1212 exports.create = function (api) {
13-
1413 var unread = null
15- if(localStorage.unread) {
14 + if (localStorage.unread) {
1615 try {
1716 unread = JSON.parse(localStorage.unread)
1817 } catch (err) {}
1918 }
20- if(!unread)
21- unread = {timestamp: Date.now()}
19 + if (!unread) { unread = {timestamp: Date.now()} }
2220
2321 unread.timestamp = unread.timestamp || Date.now()
2422
25- if(!unread.filter)
26- unread.filter = {}
23 + if (!unread.filter) { unread.filter = {} }
2724
2825 var timer
2926 function save () {
30- if(timer) return
27 + if (timer) return
3128
3229 timer = setTimeout(function () {
3330 timer = null
3431 localStorage.unread = JSON.stringify(unread)
3532 }, 2e3)
3633 }
3734
38- function isUnread(msg) {
39- if(msg.timestamp && msg.timestamp < unread.timestamp) return false
35 + function isUnread (msg) {
36 + if (msg.timestamp && msg.timestamp < unread.timestamp) return false
4037 return !unread.filter[msg.key]
4138 }
4239
43- function markRead(msg) {
44- if(msg && 'string' === typeof msg.key) {
45- //note: there is a quirk where some messages don't have a timestamp
46- if(isUnread(msg)) {
47- var userUser
40 + function markRead (msg) {
41 + if (msg && typeof msg.key === 'string') {
42 + // note: there is a quirk where some messages don't have a timestamp
43 + if (isUnread(msg)) {
44 + var userUser
4845 unread.filter[msg.key] = true
4946 save()
5047 return true
5148 }
5249 }
5350 }
5451
55- function userMessages(feedId) {
52 + function userMessages (feedId) {
5653
5754 }
5855
5956 document.body.onunload = save
@@ -63,5 +60,4 @@
6360 'unread.sync.markRead': markRead,
6461 'unread.obs.userMessages': userMessages
6562 })
6663 }
67-

Built with git-ssb-web