You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

203 lines
4.1 KiB

import {search} from './search'
let NO_DATA_TEXT = ''
function style() {
const code = `
.sidebar {
padding-top: 0;
}
.search {
margin-bottom: 20px;
padding: 6px;
border-bottom: 1px solid #eee;
}
.search .input-wrap {
display: flex;
align-items: center;
}
.search .results-panel {
display: none;
}
.search .results-panel.show {
display: block;
}
.search input {
outline: none;
border: none;
width: 100%;
padding: 0 7px;
line-height: 36px;
font-size: 14px;
}
.search input::-webkit-search-decoration,
.search input::-webkit-search-cancel-button,
.search input {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.search .clear-button {
width: 36px;
text-align: right;
display: none;
}
.search .clear-button.show {
display: block;
}
.search .clear-button svg {
transform: scale(.5);
}
.search h2 {
font-size: 17px;
margin: 10px 0;
}
.search a {
text-decoration: none;
color: inherit;
}
.search .matching-post {
border-bottom: 1px solid #eee;
}
.search .matching-post:last-child {
border-bottom: 0;
}
.search p {
font-size: 14px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.search p.empty {
text-align: center;
}`
Docsify.dom.style(code)
}
function tpl(opts, defaultValue = '') {
const html =
`<div class="input-wrap">
<input type="search" value="${defaultValue}" />
<div class="clear-button">
<svg width="26" height="24">
<circle cx="12" cy="12" r="11" fill="#ccc" />
<path stroke="white" stroke-width="2" d="M8.25,8.25,15.75,15.75" />
<path stroke="white" stroke-width="2"d="M8.25,15.75,15.75,8.25" />
</svg>
</div>
</div>
<div class="results-panel"></div>
</div>`
const el = Docsify.dom.create('div', html)
const aside = Docsify.dom.find('aside')
Docsify.dom.toggleClass(el, 'search')
Docsify.dom.before(aside, el)
}
function doSearch(value) {
const $search = Docsify.dom.find('div.search')
const $panel = Docsify.dom.find($search, '.results-panel')
const $clearBtn = Docsify.dom.find($search, '.clear-button')
if (!value) {
$panel.classList.remove('show')
$clearBtn.classList.remove('show')
$panel.innerHTML = ''
return
}
const matchs = search(value)
let html = ''
matchs.forEach(post => {
html += `<div class="matching-post">
<a href="${post.url}">
<h2>${post.title}</h2>
<p>${post.content}</p>
</a>
</div>`
})
$panel.classList.add('show')
$clearBtn.classList.add('show')
$panel.innerHTML = html || `<p class="empty">${NO_DATA_TEXT}</p>`
}
function bindEvents() {
const $search = Docsify.dom.find('div.search')
const $input = Docsify.dom.find($search, 'input')
const $inputWrap = Docsify.dom.find($search, '.input-wrap')
let timeId
// Prevent to Fold sidebar
Docsify.dom.on(
$search,
'click',
e => e.target.tagName !== 'A' && e.stopPropagation()
)
Docsify.dom.on($input, 'input', e => {
clearTimeout(timeId)
timeId = setTimeout(_ => doSearch(e.target.value.trim()), 100)
})
Docsify.dom.on($inputWrap, 'click', e => {
// Click input outside
if (e.target.tagName !== 'INPUT') {
$input.value = ''
doSearch()
}
})
}
function updatePlaceholder(text, path) {
const $input = Docsify.dom.getNode('.search input[type="search"]')
if (!$input) {
return
}
if (typeof text === 'string') {
$input.placeholder = text
} else {
const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]
$input.placeholder = text[match]
}
}
function updateNoData(text, path) {
if (typeof text === 'string') {
NO_DATA_TEXT = text
} else {
const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]
NO_DATA_TEXT = text[match]
}
}
export function init(opts, vm) {
const keywords = vm.router.parse().query.s
style()
tpl(opts, keywords)
bindEvents()
keywords && setTimeout(_ => doSearch(keywords), 500)
}
export function update(opts, vm) {
updatePlaceholder(opts.placeholder, vm.route.path)
updateNoData(opts.noData, vm.route.path)
}