Skip to content

Commit f1a34f6

Browse files
committed
document search
1 parent d82272b commit f1a34f6

12 files changed

+1521
-610
lines changed

Cakefile

+139-9
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,17 @@ buildDocs = (watch = no) ->
179179
sectionsSourceFolder = 'documentation/sections'
180180
examplesSourceFolder = 'documentation/examples'
181181
outputFolder = "docs/v#{majorVersion}"
182+
searchCollections = docs: [], changelogs: []
183+
{structure} = require "./documentation/structure.coffee"
182184

183-
# Helpers
184-
releaseHeader = (date, version, prevVersion) ->
185-
monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
185+
monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
186186

187-
formatDate = (date) ->
188-
date.replace /^(\d\d\d\d)-(\d\d)-(\d\d)$/, (match, $1, $2, $3) ->
189-
"#{monthNames[$2 - 1]} #{+$3}, #{$1}"
187+
formatDate = (date) ->
188+
date.replace /^(\d\d\d\d)-(\d\d)-(\d\d)$/, (match, $1, $2, $3) ->
189+
"#{monthNames[$2 - 1]} #{+$3}, #{$1}"
190190

191+
# Helpers
192+
releaseHeader = (date, version, prevVersion) ->
191193
"""
192194
<div class="anchor" id="#{version}"></div>
193195
<h2 class="header">
@@ -198,6 +200,69 @@ buildDocs = (watch = no) ->
198200

199201
codeFor = require "./documentation/site/code.coffee"
200202

203+
# Template for search results.
204+
searchResults = """
205+
<div class="ds-suggestion">
206+
<div class="cs-docsearch-suggestion cs-docsearch-suggestion__main cs-docsearch-suggestion__secondary" style="white-space: normal;">
207+
<div class="cs-docsearch-suggestion--category-header">
208+
<span class="cs-docsearch-suggestion--category-header-lvl0"><%= section %></span>
209+
</div>
210+
<%= results %>
211+
</div>
212+
</div>
213+
"""
214+
# Template for search result item.
215+
searchResultsList = """
216+
<div class="cs-docsearch-suggestion--wrapper searchWrapper" data-href="<%= href %>">
217+
<div class="cs-docsearch-suggestion--subcategory-column">
218+
<span class="cs-docsearch-suggestion--subcategory-column-text">
219+
<%= subsection %>
220+
</span>
221+
</div>
222+
<div class="cs-docsearch-suggestion--content">
223+
<div class="cs-docsearch-suggestion--title">
224+
<%= title %>
225+
</div>
226+
<div class="cs-docsearch-suggestion--text"><%= content %></div>
227+
</div>
228+
</div>
229+
"""
230+
searchResultsTemplate = _.template(searchResults).source
231+
searchResultsListTemplate = _.template(searchResultsList).source
232+
233+
# Remove markup from content used for search collections
234+
clean = (content) ->
235+
content
236+
.replace /<[^>]*>/g, " " # remove HTML tags
237+
.replace /\[([^\]]+)\]\([^\)]+\)/g, "$1" # remove URL link
238+
.replace /\*[^\S]+/g, "" # remove list markup
239+
.replace /\*\*?|__?|#+?/g, "" # remove Markdown format
240+
.replace /\t|\n/g, " "
241+
.replace /^\s+/g, " "
242+
243+
# Build search catalogue.
244+
searchCatalogue = (mdDoc, section, data) ->
245+
return unless match = /^(#+?)\s+([^\n]+)\s+([\s\S]+)/.exec mdDoc
246+
[, level, title, body] = match
247+
content = clean body
248+
unless section is "changelog"
249+
content = content.replace /```[^\`]+```/g, ""
250+
weight = level.length
251+
searchCollections.docs.push {section, title, weight, content, data...}
252+
else
253+
# Break changelogs into (release) chunks.
254+
releaseLogs = content.split /```\s*releaseHeader\(([^\)]+)\)\s*```/
255+
for rlog, ix in releaseLogs when ix % 2 isnt 0
256+
data = rlog.replace(/\\?'/g, "").split /,\s*/
257+
date = formatDate data[0]
258+
release = data[1]
259+
searchCollections.changelogs.push
260+
section: "Changelogs"
261+
title: "#{release} &mdash; #{date}"
262+
content: releaseLogs[ix + 1]
263+
parent: "Changelogs"
264+
href: "##{release}"
265+
201266
htmlFor = ->
202267
hljs = require 'highlight.js'
203268
hljs.configure classPrefix: ''
@@ -212,7 +277,6 @@ buildDocs = (watch = no) ->
212277
catch ex
213278
return '' # No syntax highlighting
214279

215-
216280
# Add some custom overrides to Markdown-It’s rendering, per
217281
# https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
218282
defaultFence = markdownRenderer.renderer.rules.fence
@@ -223,11 +287,12 @@ buildDocs = (watch = no) ->
223287
else
224288
"<blockquote class=\"uneditable-code-block\">#{defaultFence.apply @, arguments}</blockquote>"
225289

226-
(file, bookmark) ->
290+
(file, searchData) ->
227291
md = fs.readFileSync "#{sectionsSourceFolder}/#{file}.md", 'utf-8'
228292
md = md.replace /<%= releaseHeader %>/g, releaseHeader
229293
md = md.replace /<%= majorVersion %>/g, majorVersion
230294
md = md.replace /<%= fullVersion %>/g, CoffeeScript.VERSION
295+
searchCatalogue md, file, searchData
231296
html = markdownRenderer.render md
232297
html = _.template(html)
233298
codeFor: codeFor()
@@ -241,6 +306,64 @@ buildDocs = (watch = no) ->
241306
code = transpile code
242307
code
243308

309+
# Build body HTML.
310+
buildBody = ->
311+
sectionTemplate = """
312+
<section id="<%= id %>">
313+
<%= sectionBody %>
314+
</section>
315+
"""
316+
body = []
317+
sectionTemplate = _.template sectionTemplate
318+
buildSection = (section) ->
319+
sectionTemplate section
320+
321+
for section in structure when section.html and section.html.length > 0
322+
{id, title, html, href = no, children = []} = section
323+
href = "##{id}" unless href
324+
sectionBody = (@htmlFor(h, {parent: title, href}) for h in html)
325+
if children.length > 0
326+
for child in children when child.html and child.html.length > 0
327+
cHref = "##{child.id}" unless child.href
328+
childBody = (@htmlFor(h, {parent: title, href:cHref}) for h in child.html)
329+
sectionBody.push buildSection {id: child.id, sectionBody: childBody.join("")}
330+
body.push buildSection {id: section.id, sectionBody: sectionBody.join("")}
331+
332+
body.join ""
333+
334+
# Build sidebar HTML.
335+
buildSidebar = ->
336+
link = """
337+
<a href="<%= href %>" class="nav-link<%= className %>" data-action="sidebar-nav"><%= title %></a>
338+
"""
339+
nav = """
340+
<nav class="nav flex-column">
341+
<%= links %>
342+
</nav>
343+
"""
344+
sidebar = []
345+
linkTemplate = _.template link
346+
navTemplate = _.template nav
347+
buildNav = (links) ->
348+
navTemplate links
349+
buildLink = (link) ->
350+
link.className = " #{link.className}" unless link.className is ""
351+
linkTemplate link
352+
353+
for section in structure
354+
{id, title, href = no, className = "", children = []} = section
355+
href = "##{id}" unless href
356+
sidebar.push buildLink {title, href, className}
357+
if children.length > 0
358+
childLinks = []
359+
for child in children
360+
{id:cId, title:cTitle, href:cHref = no, className:cClassName = ""} = child
361+
cHref = "##{cId}" unless cHref
362+
childLinks.push buildLink {title: cTitle, href: cHref, className: cClassName}
363+
sidebar.push buildNav {links: childLinks.join ""}
364+
365+
buildNav links: sidebar.join ""
366+
244367
include = ->
245368
(file) ->
246369
file = "#{siteSourceFolder}/#{file}" unless '/' in file
@@ -252,16 +375,23 @@ buildDocs = (watch = no) ->
252375
majorVersion: majorVersion
253376
fullVersion: CoffeeScript.VERSION
254377
htmlFor: htmlFor()
378+
buildBody: buildBody
379+
buildSidebar: buildSidebar
255380
codeFor: codeFor()
256381
include: include()
257382
includeScript: includeScript()
258383
output
259384

260-
# Task
261385
do renderIndex = ->
262386
render = _.template fs.readFileSync(indexFile, 'utf-8')
263387
output = render
264388
include: include()
389+
searchIdx = """
390+
window.searchResultTemplate = #{searchResultsTemplate};
391+
window.searchResultsListTemplate = #{searchResultsListTemplate};
392+
window.searchCollections = #{JSON.stringify searchCollections};
393+
"""
394+
fs.writeFileSync "#{outputFolder}/search_index.js", searchIdx
265395
fs.writeFileSync "#{outputFolder}/index.html", output
266396
log 'compiled', green, "#{indexFile}#{outputFolder}/index.html"
267397
try

0 commit comments

Comments
 (0)