;(function () { /** * Converts a colon formatted string to a object with properties. * * This is process a provided string and look for any tokens in the format * of `:name[=value]` and then convert it to a object and return. * An example of this is ':include :type=code :fragment=demo' is taken and * then converted to: * * ``` * { * include: '', * type: 'code', * fragment: 'demo' * } * ``` * * @param {string} str The string to parse. * * @return {object} The original string and parsed object, { str, config }. */ function getAndRemoveConfig(str) { if (str === void 0) str = "" var config = {} if (str) { str = str .replace(/^('|")/, "") .replace(/('|")$/, "") .replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g, function (m, key, value) { if (key.indexOf(":") === -1) { config[key] = (value && value.replace(/"/g, "")) || true return "" } return m }) .trim() } return { str: str, config: config } } function removeDocsifyIgnoreTag(str) { return str .replace(//, "") .replace(/{docsify-ignore}/, "") .replace(//, "") .replace(/{docsify-ignore-all}/, "") .trim() } /* eslint-disable no-unused-vars */ var INDEXS = {} var LOCAL_STORAGE = { EXPIRE_KEY: "docsify.search.expires", INDEX_KEY: "docsify.search.index" } function resolveExpireKey(namespace) { return namespace ? LOCAL_STORAGE.EXPIRE_KEY + "/" + namespace : LOCAL_STORAGE.EXPIRE_KEY } function resolveIndexKey(namespace) { return namespace ? LOCAL_STORAGE.INDEX_KEY + "/" + namespace : LOCAL_STORAGE.INDEX_KEY } function escapeHtml(string) { var entityMap = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" } return String(string).replace(/[&<>"']/g, function (s) { return entityMap[s] }) } function getAllPaths(router) { var paths = [] Docsify.dom.findAll(".sidebar-nav a:not(.section-link):not([data-nosearch])").forEach(function (node) { var href = node.href var originHref = node.getAttribute("href") var path = router.parse(href).path if (path && paths.indexOf(path) === -1 && !Docsify.util.isAbsolutePath(originHref)) { paths.push(path) } }) return paths } function getTableData(token) { if (!token.text && token.type === "table") { token.cells.unshift(token.header) token.text = token.cells .map(function (rows) { return rows.join(" | ") }) .join(" |\n ") } return token.text } function getListData(token) { if (!token.text && token.type === "list") { token.text = token.raw } return token.text } function saveData(maxAge, expireKey, indexKey) { localStorage.setItem(expireKey, Date.now() + maxAge) localStorage.setItem(indexKey, JSON.stringify(INDEXS)) } function genIndex(path, content, router, depth) { if (content === void 0) content = "" var tokens = window.marked.lexer(content) var slugify = window.Docsify.slugify var index = {} var slug var title = "" tokens.forEach(function (token, tokenIndex) { if (token.type === "heading" && token.depth <= depth) { var ref = getAndRemoveConfig(token.text) var str = ref.str var config = ref.config var text = removeDocsifyIgnoreTag(token.text) if (config.id) { slug = router.toURL(path, { id: slugify(config.id) }) } else { slug = router.toURL(path, { id: slugify(escapeHtml(text)) }) } if (str) { title = removeDocsifyIgnoreTag(str) } index[slug] = { slug: slug, title: title, body: "" } } else { if (tokenIndex === 0) { slug = router.toURL(path) index[slug] = { slug: slug, title: path !== "/" ? path.slice(1) : "Home Page", body: token.text || "" } } if (!slug) { return } if (!index[slug]) { index[slug] = { slug: slug, title: "", body: "" } } else if (index[slug].body) { token.text = getTableData(token) token.text = getListData(token) index[slug].body += "\n" + (token.text || "") } else { token.text = getTableData(token) token.text = getListData(token) index[slug].body = index[slug].body ? index[slug].body + token.text : token.text } } }) slugify.clear() return index } function ignoreDiacriticalMarks(keyword) { if (keyword && keyword.normalize) { return keyword.normalize("NFD").replace(/[\u0300-\u036f]/g, "") } return keyword } /** * @param {String} query Search query * @returns {Array} Array of results */ function search(query) { var matchingResults = [] var data = [] Object.keys(INDEXS).forEach(function (key) { data = data.concat( Object.keys(INDEXS[key]).map(function (page) { return INDEXS[key][page] }) ) }) query = query.trim() var keywords = query.split(/[\s\-,\\/]+/) if (keywords.length !== 1) { keywords = [].concat(query, keywords) } var loop = function (i) { var post = data[i] var matchesScore = 0 var resultStr = "" var handlePostTitle = "" var handlePostContent = "" var postTitle = post.title && post.title.trim() var postContent = post.body && post.body.trim() var postUrl = post.slug || "" if (postTitle) { keywords.forEach(function (keyword) { // From https://github.com/sindresorhus/escape-string-regexp var regEx = new RegExp(escapeHtml(ignoreDiacriticalMarks(keyword)).replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"), "gi") var indexTitle = -1 var indexContent = -1 handlePostTitle = postTitle ? escapeHtml(ignoreDiacriticalMarks(postTitle)) : postTitle handlePostContent = postContent ? escapeHtml(ignoreDiacriticalMarks(postContent)) : postContent indexTitle = postTitle ? handlePostTitle.search(regEx) : -1 indexContent = postContent ? handlePostContent.search(regEx) : -1 if (indexTitle >= 0 || indexContent >= 0) { matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0 if (indexContent < 0) { indexContent = 0 } var start = 0 var end = 0 start = indexContent < 11 ? 0 : indexContent - 10 end = start === 0 ? 70 : indexContent + keyword.length + 60 if (postContent && end > postContent.length) { end = postContent.length } var matchContent = handlePostContent && "..." + handlePostContent.substring(start, end).replace(regEx, function (word) { return '' + word + "" }) + "..." resultStr += matchContent } }) if (matchesScore > 0) { var matchingPost = { title: handlePostTitle, content: postContent ? resultStr : "", url: postUrl, score: matchesScore } matchingResults.push(matchingPost) } } } for (var i = 0; i < data.length; i++) loop(i) return matchingResults.sort(function (r1, r2) { return r2.score - r1.score }) } function init(config, vm) { var isAuto = config.paths === "auto" var paths = isAuto ? getAllPaths(vm.router) : config.paths var namespaceSuffix = "" // only in auto mode if (paths.length && isAuto && config.pathNamespaces) { var path = paths[0] if (Array.isArray(config.pathNamespaces)) { namespaceSuffix = config.pathNamespaces.filter(function (prefix) { return path.slice(0, prefix.length) === prefix })[0] || namespaceSuffix } else if (config.pathNamespaces instanceof RegExp) { var matches = path.match(config.pathNamespaces) if (matches) { namespaceSuffix = matches[0] } } var isExistHome = paths.indexOf(namespaceSuffix + "/") === -1 var isExistReadme = paths.indexOf(namespaceSuffix + "/README") === -1 if (isExistHome && isExistReadme) { paths.unshift(namespaceSuffix + "/") } } else if (paths.indexOf("/") === -1 && paths.indexOf("/README") === -1) { paths.unshift("/") } var expireKey = resolveExpireKey(config.namespace) + namespaceSuffix var indexKey = resolveIndexKey(config.namespace) + namespaceSuffix var isExpired = localStorage.getItem(expireKey) < Date.now() INDEXS = JSON.parse(localStorage.getItem(indexKey)) if (isExpired) { INDEXS = {} } else if (!isAuto) { return } var len = paths.length var count = 0 paths.forEach(function (path) { if (INDEXS[path]) { return count++ } Docsify.get(vm.router.getFile(path), false, vm.config.requestHeaders).then(function (result) { INDEXS[path] = genIndex(path, result, vm.router, config.depth) len === ++count && saveData(config.maxAge, expireKey, indexKey) }) }) } /* eslint-disable no-unused-vars */ var NO_DATA_TEXT = "" var options function style() { var code = "\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}" Docsify.dom.style(code) } function tpl(defaultValue) { if (defaultValue === void 0) defaultValue = "" var html = '
' + NO_DATA_TEXT + "
" if (options.hideOtherSidebarContent) { $sidebarNav && $sidebarNav.classList.add("hide") $appName && $appName.classList.add("hide") } } function bindEvents() { var $search = Docsify.dom.find("div.search") var $input = Docsify.dom.find($search, "input") var $inputWrap = Docsify.dom.find($search, ".input-wrap") var timeId /** Prevent to Fold sidebar. When searching on the mobile end, the sidebar is collapsed when you click the INPUT box, making it impossible to search. */ Docsify.dom.on($search, "click", function (e) { return ["A", "H2", "P", "EM"].indexOf(e.target.tagName) === -1 && e.stopPropagation() }) Docsify.dom.on($input, "input", function (e) { clearTimeout(timeId) timeId = setTimeout(function (_) { return doSearch(e.target.value.trim()) }, 100) }) Docsify.dom.on($inputWrap, "click", function (e) { // Click input outside if (e.target.tagName !== "INPUT") { $input.value = "" doSearch() } }) } function updatePlaceholder(text, path) { var $input = Docsify.dom.getNode('.search input[type="search"]') if (!$input) { return } if (typeof text === "string") { $input.placeholder = text } else { var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1 })[0] $input.placeholder = text[match] } } function updateNoData(text, path) { if (typeof text === "string") { NO_DATA_TEXT = text } else { var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1 })[0] NO_DATA_TEXT = text[match] } } function updateOptions(opts) { options = opts } function init$1(opts, vm) { var keywords = vm.router.parse().query.s updateOptions(opts) style() tpl(keywords) bindEvents() keywords && setTimeout(function (_) { return doSearch(keywords) }, 500) } function update(opts, vm) { updateOptions(opts) updatePlaceholder(opts.placeholder, vm.route.path) updateNoData(opts.noData, vm.route.path) } /* eslint-disable no-unused-vars */ var CONFIG = { placeholder: "Type to search", noData: "No Results!", paths: "auto", depth: 2, maxAge: 86400000, // 1 day hideOtherSidebarContent: false, namespace: undefined, pathNamespaces: undefined } var install = function (hook, vm) { var util = Docsify.util var opts = vm.config.search || CONFIG if (Array.isArray(opts)) { CONFIG.paths = opts } else if (typeof opts === "object") { CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : "auto" CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge CONFIG.placeholder = opts.placeholder || CONFIG.placeholder CONFIG.noData = opts.noData || CONFIG.noData CONFIG.depth = opts.depth || CONFIG.depth CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent CONFIG.namespace = opts.namespace || CONFIG.namespace CONFIG.pathNamespaces = opts.pathNamespaces || CONFIG.pathNamespaces } var isAuto = CONFIG.paths === "auto" hook.mounted(function (_) { init$1(CONFIG, vm) !isAuto && init(CONFIG, vm) }) hook.doneEach(function (_) { update(CONFIG, vm) isAuto && init(CONFIG, vm) }) } $docsify.plugins = [].concat(install, $docsify.plugins) })()