Hackerspace Istanbul'un web sitesi
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.
 
 
 
 

159 lines
4.7 KiB

{{ define "title" -}}
{{ .Title }} | {{ .Site.Title }}
{{- end }}
{{ define "header" }}
{{ partial "menu.html" . }}
{{ end }}
{{ define "main" }}
<header>
<h1>{{ .Title }}</h1>
</header>
<noscript>
Aw-shucks! Search requires use of JavaScript to function properly.
</noscript>
<div id="search-app">
<div v-cloak>
<section>
<form v-on:submit.prevent class="form" action="{{ "search" | absURL }}">
<fieldset class="form-group">
<input v-model="query" id="query" name="s" type="search" class="form-control" maxlength="32" autocomplete="off">
<div class="help-block">Press <kbd>s</kbd> to focus search input anytime.</div>
</fieldset>
</form>
</section>
<section v-if="results.length">
<p><i>Showing results for “{ resultsForSearch }”.</i></p>
<div id="search-results">
<article v-for="result in results" itemscope itemtype="http://schema.org/CreativeWork">
<header itemprop="name">
<h2 itemprop="name"><a :href="result.item.url"><span v-html="result.item.title"></span></a></h2>
</header>
<div v-html=result.item.summary itemprop="description"></div>
<nav class="readmore"><a itemprop="url" :href="result.item.url">Read More&nbsp;&raquo;</a></nav>
</article>
</div>
</section>
</div>
</div>
{{ end }}
{{ define "footer" }}
{{ partial "powered-by.html" . }}
<script src="/js/vue.min.js"></script>
<script src="/js/lodash.custom.min.js"></script>
<script src="/js/fuse.min.js"></script>
<script src="/js/mark.min.js"></script>
<script>
(function (window, document, undefined) {
"use strict"
const getQueryByParam = param => decodeURIComponent(
(location.search.split(param + '=')[1] || '').split('&')[0]
).replace(/\+/g, ' ')
const queryParam = 's'
const selectors = {
appContainer: '#search-app',
resultContainer: '#search-results',
searchInput: '#query'
}
const fuseOpts = {
shouldSort: true,
tokenize: true,
matchAllTokens: true,
includeScore: true,
includeMatches: true,
keys: [
{ name: "title", weight: 0.8 },
{ name: "contents", weight: 0.5 },
{ name: "tags", weight: 0.3 },
{ name: "categories", weight: 0.3 }
]
}
const getSearchInput = () => document.querySelector(selectors.searchInput)
const focusSearchInput = () => getSearchInput().focus()
const searchQuery = getSearchInput().value = getQueryByParam(queryParam)
const fuse = new Fuse([], fuseOpts)
window.fetch('/index.json').then(response => {
response.text().then(searchData => {
fuse.setCollection(JSON.parse(searchData))
if (searchQuery) search(searchQuery)
})
})
const getUrl = (query) => {
const encodedQuery = encodeURIComponent(query)
const url = {{ .URL }}
return (encodedQuery)
? `${url}?${queryParam}=${encodedQuery}`
: url
}
let mark = new Mark(
document.querySelector(
selectors.resultContainer
)
)
const app = new Vue({
delimiters: ['{', '}'],
el: selectors.appContainer,
data: {
fuse: null,
results: [],
query: getQueryByParam(queryParam),
resultsForSearch: getQueryByParam(queryParam)
},
mounted () {
this.fuse = fuse
window.onpopstate = (evt) => {
this.query = evt.state.query
}
document.onkeyup = function (evt) {
if (evt.key === 's') focusSearchInput()
}
focusSearchInput()
},
watch: {
query () {
this.executeSearch()
window.history.replaceState(
{query: this.query},
null,
getUrl(this.query)
)
}
},
beforeUpdate: function () {
mark.unmark()
},
updated: function () {
this.$nextTick(function () {
mark = new Mark(
document.querySelector(
selectors.resultContainer
)
)
mark.mark(this.query.trim())
})
},
methods: {
executeSearch: _.debounce(function () {
const trimmedQuery = this.query.trim()
this.resultsForSearch = trimmedQuery
this.results = (trimmedQuery)
? this.fuse.search(trimmedQuery)
: []
}, 250)
}
})
const search = query => {
app.results = fuse.search(query)
}
})(window, document)
</script>
{{ end }}