mjz update
This commit is contained in:
292
vdoing/util/index.js
Normal file
292
vdoing/util/index.js
Normal file
@@ -0,0 +1,292 @@
|
||||
export const hashRE = /#.*$/
|
||||
export const extRE = /\.(md|html)$/
|
||||
export const endingSlashRE = /\/$/
|
||||
export const outboundRE = /^[a-z]+:/i
|
||||
|
||||
export function normalize(path) {
|
||||
return decodeURI(path)
|
||||
.replace(hashRE, '')
|
||||
.replace(extRE, '')
|
||||
}
|
||||
|
||||
export function getHash(path) {
|
||||
const match = path && path.match(hashRE)
|
||||
if (match) {
|
||||
return match[0]
|
||||
}
|
||||
}
|
||||
|
||||
export function isExternal(path) {
|
||||
return outboundRE.test(path)
|
||||
}
|
||||
|
||||
export function isMailto(path) {
|
||||
return /^mailto:/.test(path)
|
||||
}
|
||||
|
||||
export function isTel(path) {
|
||||
return /^tel:/.test(path)
|
||||
}
|
||||
|
||||
export function ensureExt(path) {
|
||||
if (isExternal(path)) {
|
||||
return path
|
||||
}
|
||||
if (!path) return '404'
|
||||
const hashMatch = path.match(hashRE)
|
||||
const hash = hashMatch ? hashMatch[0] : ''
|
||||
const normalized = normalize(path)
|
||||
|
||||
if (endingSlashRE.test(normalized)) {
|
||||
return path
|
||||
}
|
||||
return normalized + '.html' + hash
|
||||
}
|
||||
|
||||
export function isActive(route, path) {
|
||||
const routeHash = route.hash
|
||||
const linkHash = getHash(path)
|
||||
if (linkHash && routeHash !== linkHash) {
|
||||
return false
|
||||
}
|
||||
const routePath = normalize(route.path)
|
||||
const pagePath = normalize(path)
|
||||
return routePath === pagePath
|
||||
}
|
||||
|
||||
export function resolvePage(pages, rawPath, base) {
|
||||
if (isExternal(rawPath)) {
|
||||
return {
|
||||
type: 'external',
|
||||
path: rawPath
|
||||
}
|
||||
}
|
||||
if (base) {
|
||||
rawPath = resolvePath(rawPath, base)
|
||||
}
|
||||
const path = normalize(rawPath)
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
if (normalize(pages[i].regularPath) === path) {
|
||||
return Object.assign({}, pages[i], {
|
||||
type: 'page',
|
||||
path: ensureExt(pages[i].path)
|
||||
})
|
||||
}
|
||||
}
|
||||
console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`)
|
||||
return {}
|
||||
}
|
||||
|
||||
function resolvePath(relative, base, append) {
|
||||
const firstChar = relative.charAt(0)
|
||||
if (firstChar === '/') {
|
||||
return relative
|
||||
}
|
||||
|
||||
if (firstChar === '?' || firstChar === '#') {
|
||||
return base + relative
|
||||
}
|
||||
|
||||
const stack = base.split('/')
|
||||
|
||||
// remove trailing segment if:
|
||||
// - not appending
|
||||
// - appending to trailing slash (last segment is empty)
|
||||
if (!append || !stack[stack.length - 1]) {
|
||||
stack.pop()
|
||||
}
|
||||
|
||||
// resolve relative path
|
||||
const segments = relative.replace(/^\//, '').split('/')
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const segment = segments[i]
|
||||
if (segment === '..') {
|
||||
stack.pop()
|
||||
} else if (segment !== '.') {
|
||||
stack.push(segment)
|
||||
}
|
||||
}
|
||||
|
||||
// ensure leading slash
|
||||
if (stack[0] !== '') {
|
||||
stack.unshift('')
|
||||
}
|
||||
|
||||
return stack.join('/')
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Page } page
|
||||
* @param { string } regularPath
|
||||
* @param { SiteData } site
|
||||
* @param { string } localePath
|
||||
* @returns { SidebarGroup }
|
||||
*/
|
||||
export function resolveSidebarItems(page, regularPath, site, localePath) {
|
||||
const { pages, themeConfig } = site
|
||||
|
||||
const localeConfig = localePath && themeConfig.locales
|
||||
? themeConfig.locales[localePath] || themeConfig
|
||||
: themeConfig
|
||||
|
||||
const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar
|
||||
if (pageSidebarConfig === 'auto') {
|
||||
return resolveHeaders(page)
|
||||
}
|
||||
|
||||
const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar
|
||||
if (!sidebarConfig) {
|
||||
return []
|
||||
} else {
|
||||
const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig)
|
||||
if (config === 'auto') {
|
||||
return resolveHeaders(page)
|
||||
}
|
||||
return config
|
||||
? config.map(item => resolveItem(item, pages, base))
|
||||
: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Page } page
|
||||
* @returns { SidebarGroup }
|
||||
*/
|
||||
function resolveHeaders(page) {
|
||||
const headers = groupHeaders(page.headers || [])
|
||||
return [{
|
||||
type: 'group',
|
||||
collapsable: false,
|
||||
title: page.title,
|
||||
path: null,
|
||||
children: headers.map(h => ({
|
||||
type: 'auto',
|
||||
title: h.title,
|
||||
basePath: page.path,
|
||||
path: page.path + '#' + h.slug,
|
||||
children: h.children || []
|
||||
}))
|
||||
}]
|
||||
}
|
||||
|
||||
export function groupHeaders(headers) {
|
||||
// group h3s under h2
|
||||
headers = headers.map(h => Object.assign({}, h))
|
||||
let lastH2
|
||||
headers.forEach(h => {
|
||||
if (h.level === 2) {
|
||||
lastH2 = h
|
||||
} else if (lastH2) {
|
||||
(lastH2.children || (lastH2.children = [])).push(h)
|
||||
}
|
||||
})
|
||||
return headers.filter(h => h.level === 2)
|
||||
}
|
||||
|
||||
export function resolveNavLinkItem(linkItem) {
|
||||
return Object.assign(linkItem, {
|
||||
type: linkItem.items && linkItem.items.length ? 'links' : 'link'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Route } route
|
||||
* @param { Array<string|string[]> | Array<SidebarGroup> | [link: string]: SidebarConfig } config
|
||||
* @returns { base: string, config: SidebarConfig }
|
||||
*/
|
||||
export function resolveMatchingConfig(regularPath, config) {
|
||||
if (Array.isArray(config)) {
|
||||
return {
|
||||
base: '/',
|
||||
config: config
|
||||
}
|
||||
}
|
||||
for (const base in config) {
|
||||
if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) {
|
||||
return {
|
||||
base,
|
||||
config: config[base]
|
||||
}
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
function ensureEndingSlash(path) {
|
||||
return /(\.html|\/)$/.test(path)
|
||||
? path
|
||||
: path + '/'
|
||||
}
|
||||
|
||||
function resolveItem(item, pages, base, groupDepth = 1) {
|
||||
if (typeof item === 'string') {
|
||||
return resolvePage(pages, item, base)
|
||||
} else if (Array.isArray(item)) {
|
||||
return Object.assign(resolvePage(pages, item[0], base), {
|
||||
title: item[1]
|
||||
})
|
||||
} else {
|
||||
if (groupDepth > 3) {
|
||||
console.error(
|
||||
'[vuepress] detected a too deep nested sidebar group.'
|
||||
)
|
||||
}
|
||||
const children = item.children || []
|
||||
if (children.length === 0 && item.path) {
|
||||
return Object.assign(resolvePage(pages, item.path, base), {
|
||||
title: item.title
|
||||
})
|
||||
}
|
||||
return {
|
||||
type: 'group',
|
||||
path: item.path,
|
||||
title: item.title,
|
||||
sidebarDepth: item.sidebarDepth,
|
||||
initialOpenGroupIndex: item.initialOpenGroupIndex,
|
||||
children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)),
|
||||
collapsable: item.collapsable !== false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 类型判断
|
||||
export function type(o) {
|
||||
const s = Object.prototype.toString.call(o)
|
||||
return s.match(/\[object (.*?)\]/)[1].toLowerCase()
|
||||
}
|
||||
|
||||
// 日期格式化(只获取年月日)
|
||||
export function dateFormat(date) {
|
||||
if (!(date instanceof Date)) {
|
||||
date = new Date(date)
|
||||
}
|
||||
return `${date.getUTCFullYear()}-${zero(date.getUTCMonth() + 1)}-${zero(date.getUTCDate())}`
|
||||
}
|
||||
|
||||
// 小于10补0
|
||||
export function zero(d) {
|
||||
return d.toString().padStart(2, '0')
|
||||
}
|
||||
|
||||
// 获取时间的时间戳
|
||||
export function getTimeNum(post) {
|
||||
let dateStr = post.frontmatter.date || post.lastUpdated || new Date()
|
||||
let date = new Date(dateStr)
|
||||
if (date == "Invalid Date" && dateStr) { // 修复new Date()在Safari下出现Invalid Date的问题
|
||||
date = new Date(dateStr.replace(/-/g, '/'))
|
||||
}
|
||||
return date.getTime()
|
||||
}
|
||||
|
||||
// 比对时间
|
||||
export function compareDate(a, b) {
|
||||
return getTimeNum(b) - getTimeNum(a)
|
||||
}
|
||||
|
||||
// 将特殊符号编码(应用于url)
|
||||
export function encodeUrl(str) {
|
||||
str = str + ''
|
||||
str = str.replace(/ |((?=[\x21-\x7e]+)[^A-Za-z0-9])/g, '-')
|
||||
return str
|
||||
}
|
||||
108
vdoing/util/postData.js
Normal file
108
vdoing/util/postData.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import { type, compareDate } from './index'
|
||||
|
||||
/**
|
||||
* 过滤非文章页
|
||||
* @param {Array} posts 所有文章数据
|
||||
*/
|
||||
export function filterPosts (posts) {
|
||||
posts = posts.filter(item => {
|
||||
const { frontmatter: { pageComponent, article, home } } = item
|
||||
return !(pageComponent || article === false || home === true) // 存在页面组件、article字段为false,以及首页
|
||||
})
|
||||
return posts
|
||||
}
|
||||
|
||||
/**
|
||||
* 按置顶和时间排序
|
||||
* @param {Array} posts 过滤非文章页之后的文章数据
|
||||
*/
|
||||
export function sortPosts (posts) {
|
||||
posts.sort((prev, next) => {
|
||||
const prevSticky = prev.frontmatter.sticky
|
||||
const nextSticky = next.frontmatter.sticky
|
||||
if (prevSticky && nextSticky) {
|
||||
return prevSticky == nextSticky ? compareDate(prev, next) : (prevSticky - nextSticky)
|
||||
} else if (prevSticky && !nextSticky) {
|
||||
return -1
|
||||
} else if (!prevSticky && nextSticky) {
|
||||
return 1
|
||||
}
|
||||
return compareDate(prev, next)
|
||||
})
|
||||
return posts
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间排序
|
||||
* @param {Array} posts 过滤非文章页之后的文章数据
|
||||
*/
|
||||
export function sortPostsByDate (posts) {
|
||||
posts.sort((prev, next) => {
|
||||
return compareDate(prev, next)
|
||||
})
|
||||
return posts
|
||||
}
|
||||
|
||||
/**
|
||||
* 按分类和标签分组
|
||||
* @param {Array} posts 按时间排序之后的文章数据
|
||||
*/
|
||||
export function groupPosts (posts) {
|
||||
const categoriesObj = {}
|
||||
const tagsObj = {}
|
||||
|
||||
for (let i = 0, postsL = posts.length; i < postsL; i++) {
|
||||
const { frontmatter: { categories, tags } } = posts[i]
|
||||
if (type(categories) === 'array') {
|
||||
categories.forEach(item => {
|
||||
if (item) { // 分类值是有效的
|
||||
if (!categoriesObj[item]) {
|
||||
categoriesObj[item] = []
|
||||
}
|
||||
categoriesObj[item].push(posts[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
if (type(tags) === 'array') {
|
||||
tags.forEach(item => {
|
||||
if (item) { // 标签值是有效的
|
||||
if (!tagsObj[item]) {
|
||||
tagsObj[item] = []
|
||||
}
|
||||
tagsObj[item].push(posts[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return {
|
||||
categories: categoriesObj,
|
||||
tags: tagsObj
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有分类和标签
|
||||
* @param {Object} groupPosts 按分类和标签分组之后的文章数据
|
||||
*/
|
||||
export function categoriesAndTags (groupPosts) {
|
||||
const categoriesArr = []
|
||||
const tagsArr = []
|
||||
|
||||
for (let key in groupPosts.categories) {
|
||||
categoriesArr.push({
|
||||
key,
|
||||
length: groupPosts.categories[key].length
|
||||
})
|
||||
}
|
||||
|
||||
for (let key in groupPosts.tags) {
|
||||
tagsArr.push({
|
||||
key,
|
||||
length: groupPosts.tags[key].length
|
||||
})
|
||||
}
|
||||
return {
|
||||
categories: categoriesArr,
|
||||
tags: tagsArr
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user