Commit 5e5bef4d7a2202ff89f9fd54978ed73376abe898
fix search page and searchBar behaviour
mix irving committed on 8/31/2017, 4:03:47 AMParent: dc8089d99ba36f4718ee8f2c3baee8306eb1ccb5
Files changed
app/html/search-bar.js | changed |
app/html/tabs.js | changed |
app/page/search.js | changed |
app/sync/addPage.js | changed |
app/sync/catch-keyboard-shortcut.js | changed |
router/sync/routes.js | changed |
app/html/search-bar.js | ||
---|---|---|
@@ -15,9 +15,8 @@ | ||
15 | 15 | |
16 | 16 | return nest('app.html.searchBar', function searchBar () { |
17 | 17 | if (_search) return _search |
18 | 18 | |
19 | - const goTo = api.app.sync.goTo | |
20 | 19 | const getProfileSuggestions = api.about.async.suggest() |
21 | 20 | const getChannelSuggestions = api.channel.async.suggest() |
22 | 21 | |
23 | 22 | const input = h('input', { |
@@ -26,9 +25,15 @@ | ||
26 | 25 | 'ev-keyup': ev => { |
27 | 26 | switch (ev.keyCode) { |
28 | 27 | case 13: // enter |
29 | 28 | var location = input.value.trim() |
30 | - if (goTo(location, !ev.ctrlKey)) input.blur() | |
29 | + if (location[0] == '?') | |
30 | + location = { page: 'search', query: location.substring(1) } | |
31 | + else if (!['@', '#', '%', '&'].includes(location[0])) | |
32 | + location = { page: 'search', query: location } | |
33 | + | |
34 | + api.app.sync.goTo(location) | |
35 | + if (!ev.ctrlKey) input.blur() | |
31 | 36 | return |
32 | 37 | case 27: // escape |
33 | 38 | ev.preventDefault() |
34 | 39 | input.blur() |
app/html/tabs.js | ||
---|---|---|
@@ -23,16 +23,14 @@ | ||
23 | 23 | const onSelect = (indexes) => { |
24 | 24 | const { id } = _tabs.get(indexes[0]).content |
25 | 25 | |
26 | 26 | try { |
27 | - const location = JSON.parse(id) | |
28 | - var locationForSearchBar = Object.keys(location) | |
29 | - .map(k => location[k]) | |
30 | - .join(' + ') | |
27 | + var location = JSON.parse(id) | |
31 | 28 | } catch (e) { |
32 | 29 | throw new Error('app.html.tabs expects all page ids to be stringified location objects') |
33 | 30 | } |
34 | - search.input.value = locationForSearchBar | |
31 | + | |
32 | + search.input.value = buildSearchBarTermFromLocation(location) | |
35 | 33 | } |
36 | 34 | _tabs = Tabs(onSelect, { |
37 | 35 | append: h('div.navExtra', [ search, menu ]) |
38 | 36 | }) |
@@ -47,4 +45,17 @@ | ||
47 | 45 | return nest({ |
48 | 46 | 'app.html.tabs': tabs |
49 | 47 | }) |
50 | 48 | } |
49 | + | |
50 | +function buildSearchBarTermFromLocation (location) { | |
51 | + if (location.page === 'search') | |
52 | + return '?'+location.query | |
53 | + | |
54 | + if (location.page && Object.keys(location).length === 1) | |
55 | + return '/'+location.page | |
56 | + | |
57 | + return Object.keys(location) | |
58 | + .map(k => location[k]) | |
59 | + .join(', ') | |
60 | +} | |
61 | + |
app/page/search.js | ||
---|---|---|
@@ -74,13 +74,14 @@ | ||
74 | 74 | |
75 | 75 | exports.create = function (api) { |
76 | 76 | return nest('app.page.search', searchPage) |
77 | 77 | |
78 | - function searchPage (path) { | |
79 | - var queryStr = path.replace(/^\??/, '').trim() | |
80 | - var query = queryStr.split(whitespace) | |
81 | - var matchesQuery = searchFilter(query) | |
78 | + function searchPage (location) { | |
79 | + const query = location.query.trim() | |
82 | 80 | |
81 | + var queryTerms = query.split(whitespace) | |
82 | + var matchesQuery = searchFilter(queryTerms) | |
83 | + | |
83 | 84 | const search = Struct({ |
84 | 85 | isLinear: Value(false), |
85 | 86 | linear: Struct({ |
86 | 87 | checked: Value(0) |
@@ -93,9 +94,9 @@ | ||
93 | 94 | const hasNoFulltextMatches = computed([search.fulltext.isDone, search.matches], |
94 | 95 | (done, matches) => done && matches === 0) |
95 | 96 | |
96 | 97 | const searchHeader = h('Search', [ |
97 | - h('header', h('h1', query.join(' '))), | |
98 | + h('header', h('h1', query)), | |
98 | 99 | when(search.isLinear, |
99 | 100 | h('section.details', [ |
100 | 101 | h('div.searched', ['Searched: ', search.linear.checked]), |
101 | 102 | h('div.matches', [search.matches, ' matches']) |
@@ -107,13 +108,12 @@ | ||
107 | 108 | ) |
108 | 109 | ]) |
109 | 110 | const { filterMenu, filterDownThrough, filterUpThrough, resetFeed } = api.app.html.filter(draw) |
110 | 111 | const { container, content } = api.app.html.scroller({ prepend: [searchHeader, filterMenu] }) |
111 | - container.id = path // helps tabs find this tab | |
112 | 112 | |
113 | 113 | function renderMsg (msg) { |
114 | 114 | var el = api.message.html.render(msg) |
115 | - highlight(el, createOrRegExp(query)) | |
115 | + highlight(el, createOrRegExp(queryTerms)) | |
116 | 116 | return el |
117 | 117 | } |
118 | 118 | |
119 | 119 | function draw () { |
@@ -126,9 +126,9 @@ | ||
126 | 126 | Scroller(container, content, renderMsg, true, false) |
127 | 127 | ) |
128 | 128 | |
129 | 129 | pull( |
130 | - api.sbot.pull.stream(sbot => next(sbot.fulltext.search, {query: queryStr, reverse: true, limit: 500, live: false})), | |
130 | + api.sbot.pull.stream(sbot => next(sbot.fulltext.search, {query, reverse: true, limit: 500, live: false})), | |
131 | 131 | fallback((err) => { |
132 | 132 | if (err === true) { |
133 | 133 | search.fulltext.isDone.set(true) |
134 | 134 | } else if (/^no source/.test(err.message)) { |
@@ -147,8 +147,8 @@ | ||
147 | 147 | } |
148 | 148 | |
149 | 149 | draw() |
150 | 150 | |
151 | - container.title = '/search' | |
151 | + container.title = '?'+query | |
152 | 152 | return container |
153 | 153 | } |
154 | 154 | } |
app/sync/addPage.js | ||
---|---|---|
@@ -14,15 +14,20 @@ | ||
14 | 14 | }) |
15 | 15 | |
16 | 16 | // TODO : make it so error catching doesn't need this, move it into goTo |
17 | 17 | function addPage (location, change, split) { |
18 | - location = api.router.sync.normalise(location) | |
19 | 18 | const tabs = api.app.html.tabs() |
20 | - | |
21 | 19 | const page = api.router.sync.router(location) |
22 | 20 | if (!page) return |
23 | 21 | |
24 | 22 | // TODO - review unique page id + naming system |
25 | - page.id = page.id || JSON.stringify(location) | |
23 | + page.id = page.id || buildId(location) | |
26 | 24 | tabs.add(page, change, split) |
27 | 25 | } |
26 | + | |
27 | + function buildId (location) { | |
28 | + return JSON.stringify( | |
29 | + api.router.sync.normalise(location) | |
30 | + ) | |
31 | + } | |
28 | 32 | } |
33 | + |
app/sync/catch-keyboard-shortcut.js | ||
---|---|---|
@@ -75,8 +75,9 @@ | ||
75 | 75 | var i = sel.reduce(function (a, b) { return Math.min(a, b) }) |
76 | 76 | tabs.remove(sel) |
77 | 77 | tabs.select(Math.max(i - 1, 0)) |
78 | 78 | } |
79 | + // TODO add history call in here | |
79 | 80 | return |
80 | 81 | |
81 | 82 | // Search |
82 | 83 | case 191: // / = routes search |
router/sync/routes.js | ||
---|---|---|
@@ -9,8 +9,9 @@ | ||
9 | 9 | 'public': 'first', |
10 | 10 | 'private': 'first', |
11 | 11 | 'notifications': 'first', |
12 | 12 | 'profile': 'first', |
13 | + 'search': 'first', | |
13 | 14 | 'blob': 'first', |
14 | 15 | 'thread': 'first', |
15 | 16 | 'channel': 'first' |
16 | 17 | }, |
@@ -28,10 +29,10 @@ | ||
28 | 29 | [ loc => loc.page === 'private', pages.private ], |
29 | 30 | [ loc => loc.page === 'notifications', pages.notifications ], |
30 | 31 | [ loc => loc.page === 'errors', pages.errors ], |
31 | 32 | [ loc => loc.page === 'profile', () => pages.profile({ id: myId }) ], |
33 | + [ loc => loc.page === 'search' && loc.query, pages.search ], | |
32 | 34 | |
33 | - // TODO - use is-my-json-valid ? | |
34 | 35 | [ loc => isBlob(loc.blob), pages.blob ], |
35 | 36 | [ loc => isPresent(loc.channel), pages.channel ], |
36 | 37 | [ loc => isFeed(loc.feed), pages.profile ], |
37 | 38 | [ loc => isMsg(loc.key), pages.thread ] |
Built with git-ssb-web