index.jsView |
---|
635 | 635 | } |
636 | 636 | |
637 | 637 | if (dir == '') |
638 | 638 | return serveIndex(req) |
| 639 | + else if (dir == 'search') |
| 640 | + return serveSearch(req) |
639 | 641 | else if (ref.isBlobId(dir)) |
640 | 642 | return serveBlob(req, dir) |
641 | 643 | else if (ref.isMsgId(dir)) |
642 | 644 | return serveMessage(req, dir, dirs.slice(1)) |
735 | 737 | }) |
736 | 738 | } |
737 | 739 | } |
738 | 740 | |
739 | | - function serveTemplate(title, code, read) { |
740 | | - if (read === undefined) return serveTemplate.bind(this, title, code) |
| 741 | + function serveTemplate(title, code, req, read) { |
| 742 | + if (read === undefined) return serveTemplate.bind(this, title, code, req) |
| 743 | + var q = req && req._u.query.q && escapeHTML(req._u.query.q) || '' |
741 | 744 | return cat([ |
742 | 745 | pull.values([ |
743 | 746 | [code || 200, { |
744 | 747 | 'Content-Type': 'text/html' |
748 | 751 | '<link rel=stylesheet href="/static/styles.css"/>', |
749 | 752 | '<link rel=stylesheet href="/highlight/github.css"/>', |
750 | 753 | '</head>\n', |
751 | 754 | '<body>', |
752 | | - '<header>', |
| 755 | + '<header><form action="/search" method="get">' + |
753 | 756 | '<h1><a href="/">git ssb' + |
754 | 757 | (ssbAppname != 'ssb' ? ' <sub>' + ssbAppname + '</sub>' : '') + |
755 | | - '</a></h1>', |
756 | | - '</header>', |
| 758 | + '</a> ' + |
| 759 | + '<input class="search-bar" name="q" size="60"' + |
| 760 | + ' placeholder="๐" value="' + q + '" />' + |
| 761 | + '</h1>', |
| 762 | + '</form></header>', |
757 | 763 | '<article>']), |
758 | 764 | renderTry(read), |
759 | 765 | pull.once('<hr/></article></body></html>') |
760 | 766 | ]) |
794 | 800 | } |
795 | 801 | |
796 | 802 | |
797 | 803 | |
798 | | - function renderFeed(req, feedId) { |
| 804 | + function renderFeed(req, feedId, filter) { |
799 | 805 | var query = req._u.query |
800 | 806 | var opts = { |
801 | 807 | reverse: !query.forwards, |
802 | 808 | lt: query.lt && +query.lt || Date.now(), |
807 | 813 | feedId ? ssb.createUserStream(opts) : ssb.createFeedStream(opts), |
808 | 814 | pull.filter(function (msg) { |
809 | 815 | return msg.value.content.type in msgTypes |
810 | 816 | }), |
| 817 | + filter, |
811 | 818 | pull.take(20), |
812 | 819 | addAuthorName(about), |
813 | 820 | query.forwards && pullReverse(), |
814 | 821 | paginate( |
815 | 822 | function (first, cb) { |
816 | 823 | if (!query.lt && !query.gt) return cb(null, '') |
817 | 824 | var gt = feedId ? first.value.sequence : first.value.timestamp + 1 |
818 | | - var q = qs.stringify({ |
819 | | - gt: gt, |
820 | | - forwards: 1 |
821 | | - }) |
822 | | - cb(null, '<a href="?' + q + '">Newer</a>') |
| 825 | + query.gt = gt |
| 826 | + query.forwards = 1 |
| 827 | + delete query.lt |
| 828 | + cb(null, '<a href="?' + qs.stringify(query) + '">Newer</a>') |
823 | 829 | }, |
824 | 830 | paramap(renderFeedItem, 8), |
825 | 831 | function (last, cb) { |
826 | | - cb(null, '<a href="?' + qs.stringify({ |
827 | | - lt: feedId ? last.value.sequence : last.value.timestamp - 1 |
828 | | - }) + '">Older</a>') |
| 832 | + query.lt = feedId ? last.value.sequence : last.value.timestamp - 1 |
| 833 | + delete query.gt |
| 834 | + delete query.forwards |
| 835 | + cb(null, '<a href="?' + qs.stringify(query) + '">Older</a>') |
829 | 836 | }, |
830 | 837 | function (cb) { |
831 | | - cb(null, query.forwards ? |
832 | | - '<a href="?lt=' + (opts.gt + 1) + '">Older</a>' : |
833 | | - '<a href="?gt=' + (opts.lt - 1) + '&forwards=1">Newer</a>') |
| 838 | + if (query.forwards) { |
| 839 | + delete query.gt |
| 840 | + delete query.forwards |
| 841 | + query.lt = opts.gt + 1 |
| 842 | + } else { |
| 843 | + delete query.lt |
| 844 | + query.gt = opts.lt - 1 |
| 845 | + query.forwards = 1 |
| 846 | + } |
| 847 | + cb(null, '<a href="?' + qs.stringify(query) + '">' + |
| 848 | + (query.forwards ? 'Older' : 'Newer') + '</a>') |
834 | 849 | } |
835 | 850 | ) |
836 | 851 | ) |
837 | 852 | } |
1126 | 1141 | } |
1127 | 1142 | } |
1128 | 1143 | |
1129 | 1144 | function serveRepoNotFound(id, err) { |
1130 | | - return serveTemplate('Repo not found', 404, pull.values([ |
| 1145 | + return serveTemplate('Repo not found', 404)(pull.values([ |
1131 | 1146 | '<h2>Repo not found</h2>', |
1132 | 1147 | '<p>Repo ' + id + ' was not found</p>', |
1133 | 1148 | '<pre>' + escapeHTML(err.stack) + '</pre>', |
1134 | 1149 | ])) |
1240 | 1255 | renderRepoReadme(repo, rev, path) |
1241 | 1256 | ])) |
1242 | 1257 | } |
1243 | 1258 | |
| 1259 | + |
| 1260 | + |
| 1261 | + function serveSearch(req) { |
| 1262 | + var q = String(req._u.query.q || '') |
| 1263 | + if (!q) return serveIndex(req) |
| 1264 | + var qId = q.replace(/^ssb:\/*/, '') |
| 1265 | + if (ref.type(qId)) |
| 1266 | + return serveRedirect(encodeURI(qId)) |
| 1267 | + |
| 1268 | + var search = new RegExp(q, 'i') |
| 1269 | + return serveTemplate('git ssb search', 200, req)( |
| 1270 | + renderFeed(req, null, pull.filter(function (msg) { |
| 1271 | + var c = msg.value.content |
| 1272 | + return ( |
| 1273 | + search.test(msg.key) || |
| 1274 | + c.text && search.test(c.text) || |
| 1275 | + c.title && search.test(c.title)) |
| 1276 | + })) |
| 1277 | + ) |
| 1278 | + } |
| 1279 | + |
1244 | 1280 | |
1245 | 1281 | |
1246 | 1282 | function serveRepoActivity(repo, branch) { |
1247 | 1283 | return renderRepoPage(repo, 'activity', branch, cat([ |
1724 | 1760 | }) |
1725 | 1761 | } |
1726 | 1762 | |
1727 | 1763 | function serveBlobNotFound(repoId, err) { |
1728 | | - return serveTemplate('Blob not found', 404, pull.values([ |
| 1764 | + return serveTemplate('Blob not found', 404)(pull.values([ |
1729 | 1765 | '<h2>Blob not found</h2>', |
1730 | 1766 | '<p>Blob in repo ' + link([repoId]) + ' was not found</p>', |
1731 | 1767 | '<pre>' + escapeHTML(err.stack) + '</pre>' |
1732 | 1768 | ])) |