Commit 2368dc2750e7187e31f959a729f0c3d539a8e2bf
Add search
Charles Lehner committed on 6/28/2016, 12:36:10 AMParent: 2c3326a3f3c4bf8abcccb2b2b36cf5da28804862
Files changed
modules/index.js | changed |
modules/tabs.js | changed |
modules/search.js | added |
sbot-api.js | changed |
style.css | changed |
modules/index.js | ||
---|---|---|
@@ -18,8 +18,9 @@ | ||
18 | 18 | require('./names.js'), |
19 | 19 | require('./post.js'), |
20 | 20 | require('./private.js'), |
21 | 21 | require('./public.js'), |
22 | + require('./search.js'), | |
22 | 23 | require('./suggest-mentions.js'), |
23 | 24 | require('./suggest.js'), |
24 | 25 | require('./tabs.js'), |
25 | 26 | require('./thread.js'), |
modules/tabs.js | ||
---|---|---|
@@ -33,14 +33,40 @@ | ||
33 | 33 | exports.app = function () { |
34 | 34 | var tabs = Tabs() |
35 | 35 | tabs.classList.add('screen') |
36 | 36 | |
37 | + var search = h('input.searchprompt', { | |
38 | + type: 'search', | |
39 | + style: {'float': 'right'}, | |
40 | + onkeydown: function (ev) { | |
41 | + switch (ev.keyCode) { | |
42 | + case 13: // enter | |
43 | + var path = '?' + search.value | |
44 | + if(tabs.has(path)) return tabs.select(path) | |
45 | + var el = screen_view(path) | |
46 | + if(el) { | |
47 | + el.scroll = keyscroll(el.querySelector('.scroller__content')) | |
48 | + tabs.add('?' + search.value, el, !ev.ctrlKey) | |
49 | + localStorage.openTabs = JSON.stringify(tabs.tabs) | |
50 | + search.blur() | |
51 | + } | |
52 | + return | |
53 | + case 27: // escape | |
54 | + ev.preventDefault() | |
55 | + search.blur() | |
56 | + return | |
57 | + } | |
58 | + } | |
59 | + }) | |
60 | + tabs.insertBefore(search, tabs.querySelector('.hypertabs__content')) | |
61 | + | |
37 | 62 | var saved |
38 | 63 | try { saved = JSON.parse(localStorage.openTabs) } |
39 | 64 | catch (_) { saved = ['/public', '/private'] } |
40 | 65 | |
41 | 66 | saved.forEach(function (path) { |
42 | 67 | var el = screen_view(path) |
68 | + if (!el) return | |
43 | 69 | el.scroll = keyscroll(el.querySelector('.scroller__content')) |
44 | 70 | if(el) tabs.add(path, el, true) |
45 | 71 | }) |
46 | 72 | |
@@ -71,25 +97,36 @@ | ||
71 | 97 | window.addEventListener('keydown', function (ev) { |
72 | 98 | if (ev.target.nodeName === 'INPUT' || ev.target.nodeName === 'TEXTAREA') |
73 | 99 | return |
74 | 100 | switch(ev.keyCode) { |
101 | + | |
75 | 102 | // scroll through tabs |
76 | 103 | case 72: // h |
77 | 104 | return tabs.selectRelative(-1) |
78 | 105 | case 76: // l |
79 | 106 | return tabs.selectRelative(1) |
107 | + | |
80 | 108 | // scroll through messages |
81 | 109 | case 74: // j |
82 | 110 | return tabs.selectedTab.scroll(1) |
83 | 111 | case 75: // k |
84 | 112 | return tabs.selectedTab.scroll(-1) |
113 | + | |
85 | 114 | // close a tab |
86 | 115 | case 88: // x |
87 | 116 | if (tabs.selected !== '/public' && tabs.selected !== '/private') { |
88 | 117 | tabs.remove(tabs.selected) |
89 | 118 | localStorage.openTabs = JSON.stringify(tabs.tabs) |
90 | 119 | } |
91 | 120 | return |
121 | + | |
122 | + // activate the search field | |
123 | + case 191: // / | |
124 | + ev.preventDefault() | |
125 | + search.focus() | |
126 | + search.selectionStart = 0 | |
127 | + search.selectionEnd = search.value.length | |
128 | + return | |
92 | 129 | } |
93 | 130 | }) |
94 | 131 | |
95 | 132 | return tabs |
modules/search.js | ||
---|---|---|
@@ -1,0 +1,35 @@ | ||
1 | +var h = require('hyperscript') | |
2 | +var u = require('../util') | |
3 | +var pull = require('pull-stream') | |
4 | +var Scroller = require('pull-scroll') | |
5 | + | |
6 | +var plugs = require('../plugs') | |
7 | +var message_render = plugs.first(exports.message_render = []) | |
8 | +var sbot_search = plugs.first(exports.sbot_search = []) | |
9 | + | |
10 | +exports.screen_view = function (path) { | |
11 | + if(path[0] === '?') { | |
12 | + var query = path.substr(1) | |
13 | + | |
14 | + var content = h('div.column.scroller__content') | |
15 | + var div = h('div.column.scroller', | |
16 | + {style: {'overflow':'auto'}}, | |
17 | + h('div.scroller__wrapper', | |
18 | + content | |
19 | + ) | |
20 | + ) | |
21 | + | |
22 | + pull( | |
23 | + sbot_search({query: query, old: false}), | |
24 | + Scroller(div, content, message_render, true, false) | |
25 | + ) | |
26 | + | |
27 | + pull( | |
28 | + u.next(sbot_search, {query: query, | |
29 | + reverse: true, limit: 100, live: false}), | |
30 | + Scroller(div, content, message_render, false, false) | |
31 | + ) | |
32 | + | |
33 | + return div | |
34 | + } | |
35 | +} |
sbot-api.js | ||
---|---|---|
@@ -51,8 +51,25 @@ | ||
51 | 51 | }), |
52 | 52 | sbot_user_feed: rec.source(function (opts) { |
53 | 53 | return sbot.createUserStream(opts) |
54 | 54 | }), |
55 | + sbot_search: rec.source(function (opts) { | |
56 | + var search = new RegExp(opts.query, 'i') | |
57 | + var limit = opts.limit || Infinity | |
58 | + delete opts.limit | |
59 | + return pull( | |
60 | + sbot.createLogStream(opts), | |
61 | + pull.filter(function (msg) { | |
62 | + var c = msg && msg.value && msg.value.content | |
63 | + return c && ( | |
64 | + msg.key == opts.query || | |
65 | + c.text && search.test(c.text) || | |
66 | + c.name && search.test(c.name) || | |
67 | + c.title && search.test(c.title)) | |
68 | + }), | |
69 | + pull.take(limit) | |
70 | + ) | |
71 | + }), | |
55 | 72 | sbot_get: rec.async(function (key, cb) { |
56 | 73 | sbot.get(key, cb) |
57 | 74 | }), |
58 | 75 | sbot_publish: rec.async(function (msg, cb) { |
Built with git-ssb-web