index.jsView |
---|
18 | 18 | var Issues = require('ssb-issues') |
19 | 19 | var paramap = require('pull-paramap') |
20 | 20 | var gitPack = require('pull-git-pack') |
21 | 21 | var Mentions = require('ssb-mentions') |
| 22 | +var Highlight = require('highlight.js') |
22 | 23 | |
23 | 24 | |
24 | 25 | var blockRenderer = new marked.Renderer() |
25 | 26 | blockRenderer.urltransform = function (url) { |
29 | 30 | return encodeLink([this.options.repo.id, 'commit', url]) |
30 | 31 | return url |
31 | 32 | } |
32 | 33 | |
| 34 | +function highlight(code, lang) { |
| 35 | + return lang |
| 36 | + ? Highlight.highlight(lang, code).value |
| 37 | + : Highlight.highlightAuto(code).value |
| 38 | +} |
| 39 | + |
33 | 40 | marked.setOptions({ |
34 | 41 | gfm: true, |
35 | 42 | mentions: true, |
36 | 43 | tables: true, |
38 | 45 | pedantic: false, |
39 | 46 | sanitize: true, |
40 | 47 | smartLists: true, |
41 | 48 | smartypants: false, |
| 49 | + highlight: highlight, |
42 | 50 | renderer: blockRenderer |
43 | 51 | }) |
44 | 52 | |
45 | 53 | |
107 | 115 | .replace(/>/g, '>') |
108 | 116 | .replace(/"/g, '"') |
109 | 117 | } |
110 | 118 | |
111 | | -function escapeHTMLStream() { |
112 | | - return pull.map(function (buf) { |
113 | | - return escapeHTML(buf.toString('utf8')) |
114 | | - }) |
115 | | -} |
116 | | - |
117 | 119 | function ucfirst(str) { |
118 | 120 | return str[0].toLocaleUpperCase() + str.slice(1) |
119 | 121 | } |
120 | 122 | |
294 | 296 | var contentTypes = { |
295 | 297 | css: 'text/css' |
296 | 298 | } |
297 | 299 | |
298 | | -var staticBase = path.join(__dirname, 'static') |
299 | | - |
300 | 300 | function readReqJSON(req, cb) { |
301 | 301 | pull( |
302 | 302 | toPull(req), |
303 | 303 | pull.collect(function (err, bufs) { |
344 | 344 | svg: 'image/svg+xml', |
345 | 345 | bmp: 'image/bmp' |
346 | 346 | } |
347 | 347 | |
348 | | -var markdownFilenameRegex = /\.md$|\/.markdown$/i |
349 | | - |
350 | 348 | module.exports = function (opts, cb) { |
351 | 349 | var ssb, reconnect, myId, getRepo, getVotes, getMsg, issues |
352 | 350 | var about = function (id, cb) { cb(null, {name: id}) } |
353 | 351 | var reqQueue = [] |
504 | 502 | return serveFile(req, dirs) |
505 | 503 | } |
506 | 504 | |
507 | 505 | function serveFile(req, dirs) { |
508 | | - var filename = path.join.apply(path, [staticBase].concat(dirs)) |
| 506 | + var filename = path.join.apply(path, [__dirname].concat(dirs)) |
509 | 507 | |
510 | | - if (filename.indexOf(staticBase) !== 0) |
| 508 | + if (filename.indexOf('../') === 0) |
511 | 509 | return servePlainError(403, '403 Forbidden') |
512 | 510 | |
513 | 511 | return readNext(function (cb) { |
514 | 512 | fs.stat(filename, function (err, stats) { |
597 | 595 | 'Content-Type': 'text/html' |
598 | 596 | }], |
599 | 597 | '<!doctype html><html><head><meta charset=utf-8>', |
600 | 598 | '<title>' + escapeHTML(title || 'git ssb') + '</title>', |
601 | | - '<link rel=stylesheet href="/styles.css"/>', |
| 599 | + '<link rel=stylesheet href="/static/styles.css"/>', |
| 600 | + '<link rel=stylesheet href="/node_modules/highlight.js/styles/github.css"/>', |
602 | 601 | '</head>\n', |
603 | 602 | '<body>', |
604 | 603 | '<header>', |
605 | 604 | '<h1><a href="/">git ssb' + |
622 | 621 | serveTemplate(err.name, status || 500) |
623 | 622 | ) |
624 | 623 | } |
625 | 624 | |
| 625 | + function renderObjectData(obj, filename, repo) { |
| 626 | + var ext = (/\.([^.]+)$/.exec(filename) || [,filename])[1] |
| 627 | + return readOnce(function (cb) { |
| 628 | + pull(obj.read, pull.collect(function (err, bufs) { |
| 629 | + if (err) return cb(err) |
| 630 | + var buf = Buffer.concat(bufs, obj.length).toString('utf8') |
| 631 | + cb(null, (ext == 'md' || ext == 'markdown') |
| 632 | + ? markdown(buf, repo) |
| 633 | + : '<pre>' + highlight(buf, ext) + '</pre>') |
| 634 | + })) |
| 635 | + }) |
| 636 | + } |
| 637 | + |
626 | 638 | |
627 | 639 | |
628 | 640 | function renderFeed(feedId) { |
629 | 641 | var opts = { |
1019 | 1031 | var commitPath = [repo.id, 'commit', commit.id] |
1020 | 1032 | var treePath = [repo.id, 'tree', commit.id] |
1021 | 1033 | return '<section class="collapse">' + |
1022 | 1034 | '<strong>' + link(commitPath, commit.title) + '</strong><br>' + |
1023 | | - '<code>' + commit.id + '</code> ' + |
| 1035 | + '<tt>' + commit.id + '</tt> ' + |
1024 | 1036 | link(treePath, 'Tree') + '<br>' + |
1025 | 1037 | escapeHTML(commit.author.name) + ' · ' + commit.author.date.toLocaleString() + |
1026 | 1038 | (commit.separateAuthor ? '<br>' + escapeHTML(commit.committer.name) + ' committed on ' + commit.committer.date.toLocaleString() : "") + |
1027 | 1039 | '</section>' |
1055 | 1067 | var commitPath = [repo.id, 'commit', commit.id] |
1056 | 1068 | cb(null, |
1057 | 1069 | 'Latest: <strong>' + link(commitPath, commit.title) + |
1058 | 1070 | '</strong><br>' + |
1059 | | - '<code>' + commit.id + '</code><br> ' + |
| 1071 | + '<tt>' + commit.id + '</tt><br> ' + |
1060 | 1072 | escapeHTML(commit.committer.name) + ' committed on ' + |
1061 | 1073 | commit.committer.date.toLocaleString() + |
1062 | 1074 | (commit.separateAuthor ? '<br>' + |
1063 | 1075 | escapeHTML(commit.author.name) + ' authored on ' + |
1113 | 1125 | return cb(null, pull.once(path.length ? '' : '<p>No readme</p>')) |
1114 | 1126 | repo.getObjectFromAny(file.id, function (err, obj) { |
1115 | 1127 | if (err) return cb(err) |
1116 | 1128 | cb(null, cat([ |
1117 | | - pull.once('<section><h4>' + escapeHTML(file.name) + '</h4><hr/>'), |
1118 | | - markdownFilenameRegex.test(file.name) ? |
1119 | | - readOnce(function (cb) { |
1120 | | - pull(obj.read, pull.collect(function (err, bufs) { |
1121 | | - if (err) return cb(err) |
1122 | | - var buf = Buffer.concat(bufs, obj.length) |
1123 | | - cb(null, markdown(buf.toString(), repo)) |
1124 | | - })) |
1125 | | - }) |
1126 | | - : cat([ |
1127 | | - pull.once('<pre>'), |
1128 | | - pull(obj.read, escapeHTMLStream()), |
1129 | | - pull.once('</pre>') |
1130 | | - ]), |
| 1129 | + pull.once('<section><h4><a name="readme">' + |
| 1130 | + escapeHTML(file.name) + '</a></h4><hr/>'), |
| 1131 | + renderObjectData(obj, file.name, repo), |
1131 | 1132 | pull.once('</section>') |
1132 | 1133 | ])) |
1133 | 1134 | }) |
1134 | 1135 | }) |
1147 | 1148 | var commitPath = [repo.id, 'commit', commit.id] |
1148 | 1149 | var treePath = [repo.id, 'tree', commit.tree] |
1149 | 1150 | cb(null, '<section class="collapse">' + |
1150 | 1151 | '<strong>' + link(commitPath, commit.title) + '</strong>' + |
1151 | | - pre(commit.body) + |
| 1152 | + (commit.body ? pre(commit.body) : '') + |
1152 | 1153 | '<p>' + |
1153 | 1154 | (commit.separateAuthor ? escapeHTML(commit.author.name) + |
1154 | 1155 | ' authored on ' + commit.author.date.toLocaleString() + '<br>' |
1155 | 1156 | : '') + |
1282 | 1283 | '<section>'), |
1283 | 1284 | extension in imgMimes |
1284 | 1285 | ? pull.once('<img src="' + encodeLink(rawFilePath) + |
1285 | 1286 | '" alt="' + escapeHTML(filename) + '" />') |
1286 | | - : markdownFilenameRegex.test(filename) |
1287 | | - ? readOnce(function (cb) { |
1288 | | - pull(object.read, pull.collect(function (err, bufs) { |
1289 | | - if (err) return cb(err) |
1290 | | - var buf = Buffer.concat(bufs, object.length) |
1291 | | - cb(null, markdown(buf.toString('utf8'), repo)) |
1292 | | - })) |
1293 | | - }) |
1294 | | - : pull(object.read, escapeHTMLStream(), wrap('pre')), |
| 1287 | + : renderObjectData(object, filename, repo), |
1295 | 1288 | pull.once('</section>') |
1296 | 1289 | ]))) |
1297 | 1290 | }) |
1298 | 1291 | }) |