talos

Форк
0
/
offline-search.js 
201 строка · 6.7 Кб
1
// Adapted from code by Matt Walters https://www.mattwalters.net/posts/hugo-and-lunr/
2

3
(function ($) {
4
    'use strict';
5

6
    $(document).ready(function () {
7
        const $searchInput = $('.td-search-input');
8

9
        //
10
        // Options for popover
11
        //
12

13
        $searchInput.data('html', true);
14
        $searchInput.data('placement', 'bottom');
15
        $searchInput.data(
16
            'template',
17
            '<div class="popover offline-search-result" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'
18
        );
19

20
        //
21
        // Register handler
22
        //
23

24
        $searchInput.on('change', (event) => {
25
            render($(event.target));
26

27
            // Hide keyboard on mobile browser
28
            $searchInput.blur();
29
        });
30

31
        // Prevent reloading page by enter key on sidebar search.
32
        $searchInput.closest('form').on('submit', () => {
33
            return false;
34
        });
35

36
        //
37
        // Lunr
38
        //
39

40
        let idx = null; // Lunr index
41
        const resultDetails = new Map(); // Will hold the data for the search results (titles and summaries)
42

43
        // Set up for an Ajax call to request the JSON data file that is created by Hugo's build process
44
        $.ajax($searchInput.data('offline-search-index-json-src')).then(
45
            (data) => {
46
                idx = lunr(function () {
47
                    this.ref('ref');
48

49
                    // If you added more searchable fields to the search index, list them here.
50
                    // Here you can specify searchable fields to the search index - e.g. individual toxonomies for you project
51
                    // With "boost" you can add weighting for specific (default weighting without boost: 1)
52
                    this.field('title', { boost: 5 });
53
                    this.field('categories', { boost: 3 });
54
                    this.field('tags', { boost: 3 });
55
                    // this.field('projects', { boost: 3 }); // example for an individual toxonomy called projects
56
                    this.field('description', { boost: 2 });
57
                    this.field('body');
58

59
                    data.forEach((doc) => {
60
                        this.add(doc);
61

62
                        resultDetails.set(doc.ref, {
63
                            title: doc.title,
64
                            excerpt: doc.excerpt,
65
                        });
66
                    });
67
                });
68

69
                $searchInput.trigger('change');
70
            }
71
        );
72

73
        const render = ($targetSearchInput) => {
74
            // Dispose the previous result
75
            $targetSearchInput.popover('dispose');
76

77
            //
78
            // Search
79
            //
80

81
            if (idx === null) {
82
                return;
83
            }
84

85
            const searchQuery = $targetSearchInput.val();
86
            if (searchQuery === '') {
87
                return;
88
            }
89

90
            const results = idx
91
                .query((q) => {
92
                    const tokens = lunr.tokenizer(searchQuery.toLowerCase());
93
                    tokens.forEach((token) => {
94
                        const queryString = token.toString();
95
                        q.term(queryString, {
96
                            boost: 100,
97
                        });
98
                        q.term(queryString, {
99
                            wildcard:
100
                                lunr.Query.wildcard.LEADING |
101
                                lunr.Query.wildcard.TRAILING,
102
                            boost: 10,
103
                        });
104
                        q.term(queryString, {
105
                            editDistance: 2,
106
                        });
107
                    });
108
                })
109
                .slice(
110
                    0,
111
                    $targetSearchInput.data('offline-search-max-results')
112
                );
113

114
            //
115
            // Make result html
116
            //
117

118
            const $html = $('<div>');
119

120
            $html.append(
121
                $('<div>')
122
                    .css({
123
                        display: 'flex',
124
                        justifyContent: 'space-between',
125
                        marginBottom: '1em',
126
                    })
127
                    .append(
128
                        $('<span>')
129
                            .text('Search results')
130
                            .css({ fontWeight: 'bold' })
131
                    )
132
                    .append(
133
                        $('<i>')
134
                            .addClass('fas fa-times search-result-close-button')
135
                            .css({
136
                                cursor: 'pointer',
137
                            })
138
                    )
139
            );
140

141
            const $searchResultBody = $('<div>').css({
142
                maxHeight: `calc(100vh - ${
143
                    $targetSearchInput.offset().top -
144
                    $(window).scrollTop() +
145
                    180
146
                }px)`,
147
                overflowY: 'auto',
148
            });
149
            $html.append($searchResultBody);
150

151
            if (results.length === 0) {
152
                $searchResultBody.append(
153
                    $('<p>').text(`No results found for query "${searchQuery}"`)
154
                );
155
            } else {
156
                results.forEach((r) => {
157
                    const doc = resultDetails.get(r.ref);
158
                    const href =
159
                        $searchInput.data('offline-search-base-href') +
160
                        r.ref.replace(/^\//, '');
161

162
                    const $entry = $('<div>').addClass('mt-4');
163

164
                    $entry.append(
165
                        $('<small>').addClass('d-block text-muted').text(r.ref)
166
                    );
167

168
                    $entry.append(
169
                        $('<a>')
170
                            .addClass('d-block')
171
                            .css({
172
                                fontSize: '1.2rem',
173
                            })
174
                            .attr('href', href)
175
                            .text(doc.title)
176
                    );
177

178
                    $entry.append($('<p>').text(doc.excerpt));
179

180
                    $searchResultBody.append($entry);
181
                });
182
            }
183

184
            $targetSearchInput.on('shown.bs.popover', () => {
185
                $('.search-result-close-button').on('click', () => {
186
                    $targetSearchInput.val('');
187
                    $targetSearchInput.trigger('change');
188
                });
189
            });
190

191
            // Enable inline styles in popover.
192
            const whiteList = $.fn.tooltip.Constructor.Default.whiteList;
193
            whiteList['*'].push('style');
194

195
            $targetSearchInput
196
                .data('content', $html[0].outerHTML)
197
                .popover({ whiteList: whiteList })
198
                .popover('show');
199
        };
200
    });
201
})(jQuery);
202

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.