commit
96032092f6
|
|
@ -1,10 +1,9 @@
|
|||
# amWiki 版本日志
|
||||
|
||||
<!--
|
||||
## [v1.2.0]()
|
||||
_2017-**-**_
|
||||
## [v1.2.0](https://github.com/TevinLi/amWiki/releases/tag/v1.2.0)
|
||||
_2017-07-18_
|
||||
|
||||
- 新增本地数据挂载模式,可以直接双击 index 在浏览器中访问整个文库
|
||||
- 新增本地数据挂载模式,可以直接双击 index 在浏览器中访问整个文库s
|
||||
- Atom 平台和 Node-Npm 平台挂载数据操作绑定
|
||||
- 本地页面挂载数据生成与嵌入模块
|
||||
- 页面加载数据,页面打开时立即判断和读取挂载数据
|
||||
|
|
@ -19,7 +18,6 @@ _2017-**-**_
|
|||
- 对带`&`符号的文件名在URL地址上用特殊转义替代,不会再被作为参数截断 ([#64](https://github.com/TevinLi/amWiki/issues/64))
|
||||
- 修复服务器文件系统为GBK编码时深目录无法读取的bug
|
||||
- 调整大量注释、调整一些变量名,标记私有与公有
|
||||
-->
|
||||
|
||||
## [v1.1.3](https://github.com/TevinLi/amWiki/releases/tag/v1.1.3)
|
||||
_2017-06-25_
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# amWiki 轻文库
|
||||
|
||||

|
||||
amWiki 是一款基于 Javascript 脚本语言、依赖 Atom 编辑器或 Nodejs-npm 命令行、使用 Markdown 标记语法的轻量级开源 Wiki 文库系统。
|
||||
amWiki 是一款由 JS 开发、依赖 Atom 或 Nodejs-Npm 的 Markdown 轻量级前端化开源文库系统。
|
||||
amWiki 致力于让大家可以更简单、更便捷的建设个人和团队文库!
|
||||
|
||||
[[view amWiki on Github](https://github.com/TevinLi/amWiki)]
|
||||
|
|
@ -62,7 +62,7 @@ amWiki 可以同时在 Atom 编辑器和 nodejs npm 的命令行两个平台工
|
|||
## 更新日志
|
||||
### 如何获取最新版本信息与动态?
|
||||
- QQ群 **347125653**
|
||||
- 如果可以,欢迎直接加我微信
|
||||
- 如果可以,欢迎直接加我微信
|
||||

|
||||
|
||||
### 如何查看历史版本日志?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# amWiki 开发计划表
|
||||
|
||||
## v1.2.1 _(under way)_
|
||||
|
||||
- 增加修改 web 端 library 目录路径的配置项 #47
|
||||
- markdown 基础语法扩展,允许使用高亮标签对文字飘红
|
||||
- 目录生成优化,识别标题是否已经带有序号 #33
|
||||
- 增加扩展名识别,允许使用 `.markdown` 扩展名 #49
|
||||
|
||||
## v1.2.2
|
||||
|
||||
- 增加短链接模式 #53
|
||||
- 增加数学公式渲染
|
||||
- 增加 markdown 式脑图渲染
|
||||
- 增加转义识别,允许使用 `\` 转义来阻止语法符解析 #71
|
||||
|
||||
## v1.2.3
|
||||
|
||||
- markdown 新式语法设计,允许表格单元格合并
|
||||
- 引入第三方评论系统
|
||||
- 允许导航栏拖动大小和完全折叠 #63
|
||||
- 导航栏目录增加悬停 title #63
|
||||
|
||||
## v1.3.0
|
||||
|
||||
- 增加接口 Mock 模块,没有后端服务也有接口
|
||||
- 创建基于 WorkerService 的请求拦截与响应机制
|
||||
- 增加控制 Mock 增、改、删、暂停、继续的操作句柄
|
||||
- 增加基于 fetch 请求的高级接口测试模式
|
||||
- fetch 与 $.ajax 协作封装,不支持 fetch 降级为 $.ajax
|
||||
- 增加 form-data 请求模式,允许上传文件
|
||||
- 增加 raw 请求模式,提供数种 Content-Type 以供选择
|
||||
- 调整测试面板 UI 布局
|
||||
|
||||
## v1.3.1
|
||||
|
||||
- 同一接口允许定义多个地址,可在测试面板上切换
|
||||
- 更加友好的接口信息抓取和提示
|
||||
|
||||
## v1.3.2
|
||||
|
||||
- 全局参数单个开关
|
||||
- 增加接口响应类型为 json 时的语法高亮
|
||||
- 优化两处文字按钮为图标
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- 新增 SEO 模块
|
||||
|
||||
## v1.5.0
|
||||
|
||||
- 新增插件接入模块
|
||||
|
||||
## v1.6.0
|
||||
|
||||
- 新增自定义主题模块
|
||||
10
bin/main.js
10
bin/main.js
|
|
@ -35,6 +35,9 @@ const exportGithub = require('../build/exportGithub');
|
|||
//格式化显示
|
||||
const printFn = require('./printf');
|
||||
|
||||
//读取项目包配置
|
||||
const packageConf = JSON.parse(fs.readFileSync(mainPath.split(/bin[\\\/]main/)[0] + 'package.json', 'utf-8'));
|
||||
|
||||
//项目根目录
|
||||
const root = mngFolder.isAmWiki(process.cwd());
|
||||
const wikis = {};
|
||||
|
|
@ -60,7 +63,7 @@ co(function*() {
|
|||
//项目 files 文件夹路径
|
||||
const filesPath = mainPath.replace(/\\/g, '/').split('bin')[0] + 'files/';
|
||||
//开始创建
|
||||
const root2 = yield creator.create(configPath, filesPath);
|
||||
const root2 = yield creator.create(configPath, filesPath, packageConf);
|
||||
if (!root2) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -155,13 +158,12 @@ co(function*() {
|
|||
if (typeof outPath === 'undefined') {
|
||||
outPath = yield prompt2('请输入导出文件夹:');
|
||||
}
|
||||
outPath = outPath.replace(/\\/g, '/');
|
||||
yield exportGithub.export(root, outPath);
|
||||
yield exportGithub.export(root, outPath.replace(/\\/g, '/'));
|
||||
break;
|
||||
//显示版本号
|
||||
case 'version':
|
||||
case '-v':
|
||||
printFn.ver(mainPath);
|
||||
printFn.ver(packageConf);
|
||||
break;
|
||||
//显示帮助
|
||||
case 'help':
|
||||
|
|
|
|||
|
|
@ -120,12 +120,10 @@ const printf = (function () {
|
|||
},
|
||||
/**
|
||||
* 显示版本信息
|
||||
* @param {String} mainPath
|
||||
* @param {Object} packageConf
|
||||
* @public
|
||||
*/
|
||||
ver: function (mainPath) {
|
||||
const packageStr = fs.readFileSync(mainPath.split(/bin[\\\/]main/)[0] + 'package.json', 'utf-8');
|
||||
const packageConf = JSON.parse(packageStr);
|
||||
ver: function (packageConf) {
|
||||
const text = [
|
||||
'Package: amWiki',
|
||||
`Version: ${clc(0, packageConf.version)}`,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
const fs = require('fs');
|
||||
const co = require('../modules/co');
|
||||
const mngWiki = require('./manageWiki');
|
||||
const mngFolder = require('./manageFolder');
|
||||
const makeNav = require('./makeNavigation');
|
||||
|
||||
const creator = (function () {
|
||||
|
|
@ -16,10 +17,8 @@ const creator = (function () {
|
|||
* @param {String} to
|
||||
* @private
|
||||
*/
|
||||
_copyWikiFile: function (from, to) {
|
||||
const encoding = from.indexOf('png') >= 0 ? 'binary' : 'utf-8';
|
||||
const file = fs.readFileSync(from, encoding);
|
||||
fs.writeFileSync(to, file, encoding);
|
||||
_copyFile: function (from, to) {
|
||||
fs.createReadStream(from).pipe(fs.createWriteStream(to));
|
||||
},
|
||||
/**
|
||||
* 创建 amWiki 必要的文件夹
|
||||
|
|
@ -211,8 +210,8 @@ const creator = (function () {
|
|||
const that = this;
|
||||
return co(function*() {
|
||||
const {options, config} = yield that._checkConfig(configPath, filesPath);
|
||||
//创建
|
||||
const files = fs.readdirSync(options.outputPath);
|
||||
//开始创建
|
||||
const files = mngFolder.readFolder(options.outputPath);
|
||||
if (files.length > 1) {
|
||||
if (!(yield confirm2('此处已有一些文件或文件夹,是否仍然在此创建amWiki?'))) {
|
||||
return false;
|
||||
|
|
@ -223,6 +222,8 @@ const creator = (function () {
|
|||
indexPage = indexPage.replace(/\{\{name\}\}/g, config.name)
|
||||
.replace('{{version}}', config.version)
|
||||
.replace('{{logo}}', config.logo);
|
||||
//嵌入配置
|
||||
indexPage = indexPage.replace('{{config}}', 'AWConfig=' + JSON.stringify(config));
|
||||
//测试模块
|
||||
if (config.testing) {
|
||||
const testingTpl = fs.readFileSync(options.filesPath + 'amWiki.testing.tpl', 'utf-8');
|
||||
|
|
@ -295,7 +296,7 @@ const creator = (function () {
|
|||
['menubar_bg.png', 'amWiki/images/menubar_bg.png']
|
||||
];
|
||||
for (let file of fileList) {
|
||||
that._copyWikiFile(options.filesPath + file[0], options.outputPath + file[1]);
|
||||
that._copyFile(options.filesPath + file[0], options.outputPath + file[1]);
|
||||
}
|
||||
//如果没有library则复制一套默认文档
|
||||
if (!hasLibrary) {
|
||||
|
|
@ -318,7 +319,7 @@ const creator = (function () {
|
|||
['doc.demo-long-article.md', 'library/002-文档示范/002-超长文档页内目录示例.md']
|
||||
];
|
||||
for (let file of fileList2) {
|
||||
that._copyWikiFile(options.filesPath + file[0], options.outputPath + file[1]);
|
||||
that._copyFile(options.filesPath + file[0], options.outputPath + file[1]);
|
||||
}
|
||||
}
|
||||
return options.outputPath;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
const fs = require('fs');
|
||||
const co = require('../modules/co');
|
||||
const mngFolder = require('./manageFolder');
|
||||
const mngWiki = require('./manageWiki');
|
||||
|
||||
const exportGithub = (function () {
|
||||
return {
|
||||
|
|
@ -65,10 +66,10 @@ const exportGithub = (function () {
|
|||
navigation = navigation.replace('?file=' + path, this._githubUrl + 'wiki/' + name);
|
||||
}
|
||||
navigation = navigation
|
||||
.replace('?file=首页', this._githubUrl + 'wiki')
|
||||
.replace('#### [首页]', '## WIKI 导航\n\n##### [首页]');
|
||||
.replace(/\?file=(home[-_].*?\))|(首页\))/, this._githubUrl + 'wiki)')
|
||||
.replace(/#### \[(.*?)]/, '## WIKI 导航\n\n##### [$1]');
|
||||
navigation += '\n\n﹊﹊﹊﹊﹊﹊﹊﹊﹊﹊ \n' +
|
||||
'**This wiki is created by [[amWiki](https://github.com/TevinLi/amWiki)]**';
|
||||
'**This wiki is created by [[amWiki](http://amwiki.org)]**';
|
||||
fs.writeFileSync(pathTo + '/_Sidebar.md', navigation, 'utf-8');
|
||||
},
|
||||
/**
|
||||
|
|
@ -78,7 +79,12 @@ const exportGithub = (function () {
|
|||
* @private
|
||||
*/
|
||||
_exportHome: function (pathFrom, pathTo) {
|
||||
let file = fs.readFileSync(pathFrom + '/首页.md', 'utf-8');
|
||||
let file = null;
|
||||
for (let fileName of mngFolder.readFolder(pathFrom)) {
|
||||
if (/^home[-_].*?\.md$/.test(fileName) || fileName === '首页.md') {
|
||||
file = fs.readFileSync(pathFrom + '/' + fileName, 'utf-8');
|
||||
}
|
||||
}
|
||||
file = file
|
||||
//相对路径图片地址转换
|
||||
.replace(/!\[(.*?)]\(assets(.*?)\)/g, '')
|
||||
|
|
@ -87,7 +93,7 @@ const exportGithub = (function () {
|
|||
.replace(/<a(.*?)href="assets(.*?)"/g, '<a$1href="' + this._githubUrl + 'wiki/images$2"')
|
||||
//logo复制与图片引用地址转换
|
||||
.replace('amWiki/images/logo.png', () => {
|
||||
this._copyImg(pathFrom + '../amWiki/images/logo.png', pathTo + '\\images\\amWiki-logo.png');
|
||||
this._copyImg(pathFrom + '../amWiki/images/logo.png', pathTo + '/images/amWiki-logo.png');
|
||||
return this._githubUrl + 'wiki/images/amWiki-logo.png';
|
||||
});
|
||||
fs.writeFileSync(pathTo + '/Home.md', file, 'utf-8');
|
||||
|
|
@ -102,23 +108,8 @@ const exportGithub = (function () {
|
|||
if (!fs.existsSync(pathTo + '/images/')) {
|
||||
fs.mkdirSync(pathTo + '/images/', 0o777);
|
||||
}
|
||||
//文件夹拷贝
|
||||
const copyFolder = (from, to) => {
|
||||
const list = fs.readdirSync(from);
|
||||
let path, to2;
|
||||
for (let item of list) {
|
||||
path = from + '/' + item;
|
||||
to2 = to + '/' + item;
|
||||
if (fs.statSync(path).isDirectory(path)) {
|
||||
fs.mkdirSync(to2, 0o777);
|
||||
copyFolder(path, to + '/' + item);
|
||||
} else {
|
||||
this._copyImg(path, to + '/' + item);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (fs.existsSync(pathFrom + '../assets/')) {
|
||||
copyFolder(pathFrom + '../assets/', pathTo + '/images/');
|
||||
mngFolder.copyFolder(pathFrom + '../assets/', pathTo + '/images/');
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
|
@ -189,7 +180,7 @@ const exportGithub = (function () {
|
|||
_toExport: function (pathFrom, pathTo, fileList, duplicates) {
|
||||
const that = this;
|
||||
return co(function* () {
|
||||
if (fs.readdirSync(pathTo).length > 0 && (yield confirm2('所选导出文件夹不为空,是否需要清空?'))) {
|
||||
if (mngFolder.readFolder(pathTo).length > 0 && (yield confirm2('所选导出文件夹不为空,是否需要清空?'))) {
|
||||
mngFolder.cleanFolder(pathTo);
|
||||
}
|
||||
let fileList2 = [];
|
||||
|
|
@ -271,32 +262,31 @@ const exportGithub = (function () {
|
|||
});
|
||||
},
|
||||
/**
|
||||
* GitHub地址
|
||||
* GitHub项目地址
|
||||
* @private
|
||||
*/
|
||||
_githubUrl: '',
|
||||
/**
|
||||
* 解析 GitHub url
|
||||
* @param {String} path
|
||||
* @param {String} url
|
||||
* @returns {Boolean|String}
|
||||
* @private
|
||||
*/
|
||||
_parseGithubUrl: function (path) {
|
||||
const config = JSON.parse(fs.readFileSync(path + '/config.json', 'utf-8'));
|
||||
if (typeof config['github-url'] === 'undefined') {
|
||||
_parseGithubUrl: function (url) {
|
||||
if (url === '') {
|
||||
alert('导出失败!\n未检测到 “github-url” 配置,请在 config.json 中配置您项目的 github-url');
|
||||
return false;
|
||||
}
|
||||
const url = config['github-url'];
|
||||
if (url.indexOf('github.com') === 0 || url.split('github.com')[1] === '') {
|
||||
alert('导出失败!\n请以https开头,配置完整的 github URL!');
|
||||
if (url.indexOf('github.com') === -1) {
|
||||
alert('导出失败!\n配置完整的 Github 项目 URL!\n例如 https://github.com/TevinLi/amWiki');
|
||||
return false;
|
||||
}
|
||||
const urlArr = url.split('github.com')[1].split('/');
|
||||
if (urlArr.length < 3) {
|
||||
alert('导出失败!\n请配置完整 github 项目路径!');
|
||||
alert('导出失败!\n请配置完整 Github 项目 URL!\n例如 https://github.com/TevinLi/amWiki');
|
||||
return false;
|
||||
}
|
||||
urlArr[2] = urlArr[2].split(/\?#/)[0].split(/\.git/i)[0];
|
||||
return '/' + urlArr[1] + '/' + urlArr[2] + '/';
|
||||
},
|
||||
/**
|
||||
|
|
@ -309,8 +299,9 @@ const exportGithub = (function () {
|
|||
export: function (root, outputPath) {
|
||||
const that = this;
|
||||
return co(function* () {
|
||||
const wikiConfig = mngWiki.getWikiByRoot(root).config;
|
||||
//检测 GitHub 项目地址
|
||||
that._githubUrl = that._parseGithubUrl(root.split('library')[0]);
|
||||
that._githubUrl = that._parseGithubUrl(wikiConfig.githubUrl);
|
||||
if (!that._githubUrl) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ const makeMounts = (function () {
|
|||
* @private
|
||||
*/
|
||||
_getHomeMount: function (libPath) {
|
||||
var list = fs.readdirSync(libPath);
|
||||
const list = mngFolder.readFolder(libPath);
|
||||
for (let name of list) {
|
||||
if (/^home[-_].*?\.md$/.test(name) || name === '首页.md') {
|
||||
const homePath = libPath + name;
|
||||
|
|
@ -174,10 +174,10 @@ const makeMounts = (function () {
|
|||
linksHtml += '<script src="amWiki/mounts/' + fileName + '"></script>';
|
||||
}
|
||||
let indexSrc = fs.readFileSync(rootPath + 'index.html', 'utf-8');
|
||||
const mountReg = /<div(.*?)aw-include="mountLinks"(.*?)>(.*?)<\/div>/;
|
||||
indexSrc = indexSrc.replace(mountReg, function (m, s1, s2) {
|
||||
const mountReg = /<div(.*?)aw-include="mountLinks"(.*?)>([\s\S]*?)<\/div>/;
|
||||
indexSrc = indexSrc.replace(mountReg, function (m, s1, s2, s3) {
|
||||
return '<div' + s1 + 'aw-include="mountLinks"' + s2 + '>' +
|
||||
linksHtml + '</div>';
|
||||
linksHtml + s3 + '</div>';
|
||||
});
|
||||
fs.writeFileSync(rootPath + 'index.html', indexSrc, 'utf-8');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,35 @@ const fs = require('fs');
|
|||
|
||||
const manageFolder = (function () {
|
||||
return {
|
||||
/**
|
||||
* 判断一个文件夹是否为 amWiki 文库项目
|
||||
* @param {String} path - 需要判断的文件夹路径
|
||||
* @returns {Boolean|String} 判断为否时返回 false,判断为真时返回项目根目录的路径
|
||||
* @public
|
||||
*/
|
||||
isAmWiki: function (path) {
|
||||
if (!path && typeof path !== 'string') {
|
||||
return false;
|
||||
}
|
||||
path = path.replace(/\\/g, '/');
|
||||
path = path.indexOf('config.json') < 0 ? path : path.split('config.json')[0];
|
||||
path = path.indexOf('index.html') < 0 ? path : path.split('index.html')[0];
|
||||
//获取 library 路径
|
||||
path = this.getProjectFolder(path);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
//通过识别文件夹子项来判定
|
||||
else {
|
||||
let states = [
|
||||
fs.existsSync(path + 'library/'),
|
||||
fs.existsSync(path + 'amWiki/'),
|
||||
fs.existsSync(path + 'config.json'),
|
||||
fs.existsSync(path + 'index.html')
|
||||
];
|
||||
return states[0] && states[1] && states[2] && states[3] ? path : false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 递归分析指定文件夹下的目录结构
|
||||
* @param {String} dirPath - 指定要分析的目录
|
||||
|
|
@ -20,15 +49,11 @@ const manageFolder = (function () {
|
|||
_listSubFolder: function (dirPath, depth = 0, tree = {}, list = [], files = []) {
|
||||
try {
|
||||
let filePath;
|
||||
for (let fileName of fs.readdirSync(dirPath)) {
|
||||
for (let fileName of this.readFolder(dirPath)) {
|
||||
//文件路径
|
||||
filePath = dirPath + (depth > 0 ? '/' : '') + fileName;
|
||||
//跳过点号开头的系统保留文件
|
||||
if (/^\./.test(fileName)) {
|
||||
continue;
|
||||
}
|
||||
//文件夹及其递归处理
|
||||
if (fs.statSync(filePath).isDirectory(filePath)) {
|
||||
if (this.isFolder(filePath)) {
|
||||
//读取下一级数据
|
||||
const [tempTree, tempList, tempFiles] = this._listSubFolder(filePath, depth + 1);
|
||||
//记录子级的树形
|
||||
|
|
@ -78,7 +103,7 @@ const manageFolder = (function () {
|
|||
return [];
|
||||
}
|
||||
const tree = {};
|
||||
for (let fileName of fs.readdirSync(path)) {
|
||||
for (let fileName of this.readFolder(path)) {
|
||||
if (/^home[-_].*?\.md$/.test(fileName) || fileName === '首页.md') {
|
||||
tree[fileName] = false;
|
||||
break;
|
||||
|
|
@ -87,21 +112,47 @@ const manageFolder = (function () {
|
|||
return this._listSubFolder(path, 0, tree);
|
||||
},
|
||||
/**
|
||||
* 递归清空文件夹
|
||||
* @param {String} path - 要清空的文件夹
|
||||
* fs 同步读取文件夹改进版,忽略以点开头的文件
|
||||
* (比如 Mac 的 .DS_Store 文件)
|
||||
* @param {String} path
|
||||
* @param {Boolean} [force] - 是否强制读取文件夹内所有内容
|
||||
* @returns {Array}
|
||||
* @public
|
||||
*/
|
||||
cleanFolder: function (path) {
|
||||
const list = fs.readdirSync(path);
|
||||
readFolder: function (path, force) {
|
||||
let files = [];
|
||||
try {
|
||||
if (force === true) {
|
||||
files = fs.readdirSync(path);
|
||||
} else {
|
||||
fs.readdirSync(path).forEach(function (fileName) {
|
||||
//忽略点开头的文件
|
||||
if (fileName.indexOf('.') !== 0) {
|
||||
files.push(fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
return files;
|
||||
},
|
||||
/**
|
||||
* 递归清空文件夹
|
||||
* @param {String} path - 要清空的文件夹
|
||||
* @param {Boolean} [force] - 是否强制清理文件夹内所有文件
|
||||
* @public
|
||||
*/
|
||||
cleanFolder: function (path, force) {
|
||||
const list = this.readFolder(path, force);
|
||||
let path2;
|
||||
for (let item of list) {
|
||||
path2 = path.replace(/[\\\/]?&/, '/') + item;
|
||||
if (fs.statSync(path2).isDirectory(path2)) {
|
||||
if (item.indexOf('.') !== 0) { //跳过特殊文件夹
|
||||
this.cleanFolder(path2);
|
||||
fs.rmdirSync(path2);
|
||||
}
|
||||
} else {
|
||||
path2 = path.replace(/\\?$/, '/') + item;
|
||||
//文件夹,递归删除
|
||||
if (this.isFolder(path2)) {
|
||||
this.cleanFolder(path2, true);
|
||||
fs.rmdirSync(path2);
|
||||
}
|
||||
//文件
|
||||
else {
|
||||
fs.unlinkSync(path2);
|
||||
}
|
||||
}
|
||||
|
|
@ -125,6 +176,41 @@ const manageFolder = (function () {
|
|||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 深度拷贝一个文件夹到指定位置
|
||||
* @param {String} from
|
||||
* @param {String} to
|
||||
* @public
|
||||
*/
|
||||
copyFolder: function (from, to) {
|
||||
const list = this.readFolder(from);
|
||||
let from2, to2;
|
||||
for (let item of list) {
|
||||
from2 = from + '/' + item;
|
||||
to2 = to + '/' + item;
|
||||
if (this.isFolder(from2)) {
|
||||
this.createFolder(to2);
|
||||
this.copyFolder(from2, to2);
|
||||
} else {
|
||||
fs.createReadStream(from2).pipe(fs.createWriteStream(to2));
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 判断一个地址是否为文件夹
|
||||
* @param {String} path
|
||||
* @returns {Boolean}
|
||||
* @public
|
||||
*/
|
||||
isFolder: function (path) {
|
||||
let state;
|
||||
try {
|
||||
state = fs.statSync(path).isDirectory(path);
|
||||
} catch (e) {
|
||||
state = false;
|
||||
}
|
||||
return state;
|
||||
},
|
||||
/**
|
||||
* 获取项目文件夹
|
||||
* @param {String} path - 需要计算的文件夹路径
|
||||
|
|
@ -214,35 +300,6 @@ const manageFolder = (function () {
|
|||
}
|
||||
}
|
||||
return path.substr(libPath.length).split(/[-_]/)[0];
|
||||
},
|
||||
/**
|
||||
* 判断一个文件夹是否为 amWiki 文库项目
|
||||
* @param {String} path - 需要判断的文件夹路径
|
||||
* @returns {Boolean|String} 判断为否时返回 false,判断为真时返回项目根目录的路径
|
||||
* @public
|
||||
*/
|
||||
isAmWiki: function (path) {
|
||||
if (!path && typeof path !== 'string') {
|
||||
return false;
|
||||
}
|
||||
path = path.replace(/\\/g, '/');
|
||||
path = path.indexOf('config.json') < 0 ? path : path.split('config.json')[0];
|
||||
path = path.indexOf('index.html') < 0 ? path : path.split('index.html')[0];
|
||||
//获取 library 路径
|
||||
path = this.getProjectFolder(path);
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
//通过识别文件夹子项来判定
|
||||
else {
|
||||
let states = [
|
||||
fs.existsSync(path + 'library/'),
|
||||
fs.existsSync(path + 'amWiki/'),
|
||||
fs.existsSync(path + 'config.json'),
|
||||
fs.existsSync(path + 'index.html')
|
||||
];
|
||||
return states[0] && states[1] && states[2] && states[3] ? path : false;
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -153,21 +153,26 @@ const manageWiki = (function () {
|
|||
*/
|
||||
parseConfig: function (config) {
|
||||
//库名称
|
||||
config.name = config.name || 'amWiki轻文库';
|
||||
config.name = typeof config.name === 'undefined' ? 'amWiki轻文库' : config.name + '';
|
||||
//库版本号
|
||||
config.version = config.ver || 'by Tevin';
|
||||
config.version = typeof config.ver === 'undefined' ? 'by Tevin' : config.ver + '';
|
||||
//logo地址
|
||||
config.logo = config.logo || 'amWiki/images/logo.png';
|
||||
config.logo = typeof config.logo === 'undefined' ? 'amWiki/images/logo.png' : config.logo + '';
|
||||
//是否开启接口测试
|
||||
config.testing = config.testing || false;
|
||||
config.testing = !!config.testing || false;
|
||||
//设置自定义颜色
|
||||
config.colour = config.colour || '#4296eb';
|
||||
config.colour = typeof config.colour === 'undefined' ? '#4296eb' : config.color + '';
|
||||
//本地页面数据挂载
|
||||
config.pageMounts = config['page-mounts'] || config.pageMounts || false;
|
||||
config.pageMounts = !!(config['page-mounts'] || config.pageMounts) || false;
|
||||
delete config['page-mounts'];
|
||||
//项目的 github 地址
|
||||
config.githubUrl = config['github-url'] || config.githubUrl || '';
|
||||
config.githubUrl = config['github-url'] || config.githubUrl;
|
||||
config.githubUrl = typeof config.githubUrl === 'undefined' ? '' : config.githubUrl + '';
|
||||
delete config['github-url'];
|
||||
//转接 library 地址
|
||||
config.libraryPrefix = config['library-prefix'] || config.libraryPrefix;
|
||||
config.libraryPrefix = typeof config.libraryPrefix === 'undefined' ? '' : config.libraryPrefix + '';
|
||||
delete config['library-prefix'];
|
||||
//自定义 css、js 文件
|
||||
if (tools.isArray(config.imports) && config.imports.length > 0) {
|
||||
const imports2 = {
|
||||
|
|
|
|||
|
|
@ -32,9 +32,11 @@
|
|||
.markdown-body .lang-off-js-comment:hover i{color:#999;}
|
||||
.markdown-body .lang-off-js-comment.on{display:block;color:#333;background:#ccc;}
|
||||
.markdown-body .lang-off-js-comment.on i{color:#f00;}
|
||||
.markdown-body mark{color:#e61e1e;background:transparent;}
|
||||
|
||||
/* ---------- base ---------- */
|
||||
body{position:relative;background:#e7e8eb;}
|
||||
html{height:100%;}
|
||||
body{position:relative;height:100%;background:#e7e8eb;}
|
||||
.hidden{display:none !important;}
|
||||
|
||||
/* ---------- header ---------- */
|
||||
|
|
@ -48,7 +50,7 @@ body{position:relative;background:#e7e8eb;}
|
|||
.header .menu-icon{display:none;}
|
||||
|
||||
/* ---------- container ---------- */
|
||||
.container{position:relative;margin:20px 18px 20px;background:url(../images/menubar_bg.png) repeat-y #fff;border:#c3c4c6 1px solid;border-top:@colour-base 2px solid;}
|
||||
.container{position:relative;margin:20px 18px 0;background:url(../images/menubar_bg.png) repeat-y #fff;border:#c3c4c6 1px solid;border-top:@colour-base 2px solid;}
|
||||
|
||||
/* ---------- menu ---------- */
|
||||
.container .nav{position:absolute;left:0px;top:0px;width:250px;height:100%;}
|
||||
|
|
@ -157,7 +159,7 @@ body[onselectstart]{cursor:pointer;-moz-user-select:none;-webkit-user-select:non
|
|||
.imgsv-panel li:hover{background:rgba(225,225,225,1);}
|
||||
.imgsv-panel li.off:hover{background:none;}
|
||||
|
||||
/* ---------- aside-contents ---------- */
|
||||
/* ---------- contents ---------- */
|
||||
aside .contents{position:fixed;bottom:137px;right:7px;z-index:9900;height:38px;width:38px;background:#f4f5f9;border:1px solid #ccc;}
|
||||
aside .contents .btn{cursor:pointer;}
|
||||
aside .contents .btn svg{position:absolute;top:7px;left:7px;width:22px;height:22px;color:#aaa;}
|
||||
|
|
@ -167,7 +169,10 @@ aside .contents.hover .btn span,aside .contents.on .btn span{display:block;}
|
|||
aside .contents-list{display:none;position:absolute;right:36px;bottom:-1px;width:270px;max-height:500px;padding:18px;overflow:hidden;overflow-y:scroll;background:#f4f5f9;border:1px solid #ccc;}
|
||||
aside .contents.hover .contents-list,aside .contents.on .contents-list{display:block;}
|
||||
aside .contents-list p{padding-bottom:5px;margin-bottom:8px;border-bottom:#ccc 1px solid;}
|
||||
aside .contents-list ol{padding-left:20px;}
|
||||
blockquote.markdown-contents{padding-left:20px;}
|
||||
.markdown-contents ol{padding-left:0;list-style:none;}
|
||||
.markdown-contents ol ol{padding-left:2em;}
|
||||
.markdown-contents ol li>i{font-style:normal;margin-right:4px;color:#4078c0;}
|
||||
|
||||
/* ---------- aside-backTop ---------- */
|
||||
aside .back-top{position:fixed;bottom:100px;right:7px;z-index: 9900;height:38px;width:38px;background:#f4f5f9;border:1px solid #ccc;}
|
||||
|
|
@ -179,8 +184,8 @@ aside .back-top:hover .back-icon{border:none;}
|
|||
aside .back-top:hover .back-text{display:block;color:#aaa;}
|
||||
|
||||
/* ---------- footer ---------- */
|
||||
footer{position:relative;width:100%;}
|
||||
footer .signature{position:absolute;right:20px;bottom:-5px;color:#999;}
|
||||
footer{position:absolute;left:0;bottom:0;width:100%;}
|
||||
footer .signature{position:absolute;right:20px;bottom:8px;color:#999;}
|
||||
|
||||
/* ---------- lowBrowser ---------- */
|
||||
#lowBrowser{position:fixed;top:0;left:0;z-index:9999999;width:100%;height:100%;}
|
||||
|
|
@ -259,7 +264,7 @@ footer .signature{position:absolute;right:20px;bottom:-5px;color:#999;}
|
|||
aside .back-top:hover .back-text{display:none;}
|
||||
|
||||
/* ---------- footer ---------- */
|
||||
footer{position:relative;width:100%;height:0;}
|
||||
footer{position:relative;left:0;bottom:0;width:100%;height:0;}
|
||||
footer .signature{position:absolute;right:12px;bottom:6px;color:#ccc;}
|
||||
footer .signature a{color:#aaa;}
|
||||
|
||||
|
|
|
|||
|
|
@ -142,12 +142,12 @@
|
|||
* @returns {String}
|
||||
* @private
|
||||
*/
|
||||
Docs.prototype._createFootnote = function (text) {
|
||||
Docs.prototype._setFootnote = function (text) {
|
||||
var footnotes = [];
|
||||
var noteReg = /\[\^([ a-zA-Z\d]+)]/g;
|
||||
var footReg = /\[\^([ a-zA-Z\d]+)]: ?([\S\s]+?)(?=\[\^(?:[ a-zA-Z\d]+)]|\n\n|$)/g;
|
||||
var templates = $.trim($('#template\\:footnote').text()).split(/[\r\n]+\s*/g);
|
||||
templates[4] += templates[5] + templates[6] +templates[7] +templates[8];
|
||||
templates[4] += templates[5] + templates[6] + templates[7] + templates[8];
|
||||
var html = '';
|
||||
//提取脚注内容
|
||||
text = text.replace(footReg, function (match, s1, s2, index) {
|
||||
|
|
@ -233,7 +233,7 @@
|
|||
var chart = flowchart.parse(code);
|
||||
chart.drawSVG(id, {
|
||||
'line-width': 1.3,
|
||||
'line-length': 55,
|
||||
'line-length': 56,
|
||||
'line-color': '#666',
|
||||
'text-margin': 10,
|
||||
'font-size': 12,
|
||||
|
|
@ -252,12 +252,22 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* 自定义图片大小与对齐方式
|
||||
* 解析 Markdown 目录
|
||||
* @param {String} html
|
||||
* @returns {String}
|
||||
* @private
|
||||
*/
|
||||
Docs.prototype._resizeImg = function (html) {
|
||||
Docs.prototype._setTOC = function (html) {
|
||||
return html.replace(/\[(TOC|MENU)]/g, '<blockquote class="markdown-contents"></blockquote>');
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析 Markdown 自定义图片大小与对齐方式
|
||||
* @param {String} html
|
||||
* @returns {String}
|
||||
* @private
|
||||
*/
|
||||
Docs.prototype._setImgResize = function (html) {
|
||||
return html.replace(/<img(.*?)src="(.*?)=(\d*[-x×]\d*)(-[lrc])?"/g, function (m, s1, s2, s3, s4) {
|
||||
var imgHtml = '<img' + s1 + 'src="' + s2 + '"';
|
||||
var imgSize = s3.split(/[-x×]/);
|
||||
|
|
@ -290,6 +300,76 @@
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 解析 markdown 文字飘红
|
||||
* @param {String} html
|
||||
* @returns {String}
|
||||
* @private
|
||||
*/
|
||||
Docs.prototype._setRedText = function (html) {
|
||||
return html.replace(/==(.*?)==/g, function (m, s1) {
|
||||
return '<mark>' + s1 + '</mark>';
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建目录
|
||||
* @param {String} contents - markdown 目录
|
||||
* @private
|
||||
*/
|
||||
Docs.prototype._createContents = function (contents) {
|
||||
var $contents = $('.markdown-contents').html(marked(contents));
|
||||
$('blockquote').each(function () {
|
||||
var $this = $(this);
|
||||
var $links = $this.find('ol>li>a');
|
||||
//至少2条链接才视为目录
|
||||
if ($links.length > 1) {
|
||||
$this.addClass('markdown-contents');
|
||||
$contents = $contents.add($this);
|
||||
}
|
||||
});
|
||||
//自带序号的目录,不再额外显示一层序号
|
||||
$contents.find('ol').each(function () {
|
||||
var $this = $(this);
|
||||
var $links = $this.children('li').children('a');
|
||||
var text1 = $links.eq(0).text(),
|
||||
text2 = $links.eq(1).text();
|
||||
var conditions = [
|
||||
//普通数字类型
|
||||
/^[\((]?(\d+\.?)+[^\d]{2,}/,
|
||||
//汉字序号类型
|
||||
/^[\((【第]?[一二三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+/,
|
||||
//英文序号类型
|
||||
/^(chapter)|(section)|(part)|(step)/i,
|
||||
//罗马序号类型
|
||||
/^[ⅠⅡⅢⅣIⅤⅥⅦⅧⅨⅩⅪⅫLCDM]+\.?/
|
||||
];
|
||||
for (var i = 0, cond; cond = conditions[i]; i++) {
|
||||
if (cond.test(text1) && cond.test(text2)) {
|
||||
$this.addClass('unindex');
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
//没写序号的目录,创建序号
|
||||
var setIndex = function ($elm, index1) {
|
||||
if ($elm.length == 0) {
|
||||
return;
|
||||
}
|
||||
$elm.children('li').each(function (index2) {
|
||||
var $this = $(this);
|
||||
if (!$elm.hasClass('unindex')) {
|
||||
var index = typeof index1 == 'number' ? (index1 + 1) + '.' + (index2 + 1): (index2 + 1);
|
||||
$this.prepend('<i>' + index + '</i>');
|
||||
}
|
||||
setIndex($this.children('ol'), index2);
|
||||
});
|
||||
};
|
||||
$contents.children('ol').each(function () {
|
||||
setIndex($(this));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 编码 url
|
||||
* 由于服务器可能存在 GBK 或 UTF-8 两种编码,中文路径编码不对需要切换才能访问
|
||||
|
|
@ -299,28 +379,31 @@
|
|||
* @private
|
||||
*/
|
||||
Docs.prototype._encodeUrl = function (path, type) {
|
||||
var url = '';
|
||||
var url = 'library/';
|
||||
if (typeof AWConfig.libraryPrefix == 'string' && AWConfig.libraryPrefix.length > 0) {
|
||||
url = AWConfig.libraryPrefix.replace(/\\/g, '/').replace(/\/?&/, '/');
|
||||
}
|
||||
var paths = [];
|
||||
//正常编码
|
||||
if (type == 'normal') {
|
||||
if (localStorage[URL_ENCODE_NAME] == 'utf8') {
|
||||
url = 'library/' + encodeURI(path);
|
||||
url += encodeURI(path);
|
||||
} else if (localStorage[URL_ENCODE_NAME] == 'gbk') {
|
||||
paths = path.split('/').map(function(path) {
|
||||
paths = path.split('/').map(function (path) {
|
||||
return GBK.encode(path);
|
||||
});
|
||||
url = 'library/' + paths.join('/');
|
||||
url += paths.join('/');
|
||||
}
|
||||
}
|
||||
//反转编码
|
||||
else if (type == 'reverse') {
|
||||
if (localStorage[URL_ENCODE_NAME] == 'utf8') {
|
||||
paths = path.split('/').map(function(path) {
|
||||
paths = path.split('/').map(function (path) {
|
||||
return GBK.encode(path);
|
||||
});
|
||||
url = 'library/' + paths.join('/');
|
||||
url += paths.join('/');
|
||||
} else if (localStorage[URL_ENCODE_NAME] == 'gbk') {
|
||||
url = 'library/' + encodeURI(path);
|
||||
url += encodeURI(path);
|
||||
}
|
||||
}
|
||||
url += '.md?t=' + (new Date()).getTime();
|
||||
|
|
@ -337,15 +420,17 @@
|
|||
var html = '';
|
||||
this.cleanView();
|
||||
//创建脚注
|
||||
content = this._createFootnote(content);
|
||||
content = this._setFootnote(content);
|
||||
//编译 markdown
|
||||
html = marked(content);
|
||||
//创建目录标记,和悬浮窗格式统一
|
||||
html = html.replace(/\[(TOC|MENU)]/g, '<blockquote class="markdown-contents"></blockquote>');
|
||||
html = this._setTOC(html);
|
||||
//自定义图片大小与对齐方式
|
||||
html = this._resizeImg(html);
|
||||
html = this._setImgResize(html);
|
||||
//复选框
|
||||
html = this._setCheckbox(html);
|
||||
//文字飘红
|
||||
html = this._setRedText(html);
|
||||
//填充到页面
|
||||
this.$e.view.html(html);
|
||||
//功能化代码块
|
||||
|
|
@ -373,7 +458,7 @@
|
|||
//创建描点
|
||||
var contents = this._setTitlesAnchor();
|
||||
//创建目录
|
||||
$('.markdown-contents').html(marked(contents));
|
||||
this._createContents(contents);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@
|
|||
//接口地址命中
|
||||
if (this._documents[id].api) {
|
||||
var apiMatch = this._documents[id].api.match(wordsReg);
|
||||
if (titleMatch && titleMatch.length > 0) {
|
||||
if (apiMatch && apiMatch.length > 0) {
|
||||
var api = '<p class="p1"><em>接口</em>' +
|
||||
this._documents[id].api.replace(wordsReg, function (match) {
|
||||
return '<mark>' + match + '</mark>';
|
||||
|
|
|
|||
|
|
@ -158,7 +158,9 @@
|
|||
</div>
|
||||
</footer>
|
||||
<!-- mounts -->
|
||||
<div class="hidden" aw-include="mountLinks"></div>
|
||||
<div class="hidden" aw-include="mountLinks">
|
||||
<script>{{config}}</script>
|
||||
</div>
|
||||
<!-- js -->
|
||||
<div class="hidden">
|
||||
<script type="text/javascript" src="amWiki/js/gbk.js"></script>
|
||||
|
|
|
|||
|
|
@ -99,8 +99,9 @@ const main = (function () {
|
|||
alert('创建失败,当前不是"config.json"文件!');
|
||||
return;
|
||||
}
|
||||
const filesPath = atom.configDirPath.replace(/\\/g, '/') + '/packages/amWiki/files/';
|
||||
creator.create(editPath, filesPath).then((root) => {
|
||||
const packagePath = atom.configDirPath.replace(/\\/g, '/') + '/packages/amWiki/';
|
||||
const packageConf = JSON.parse(fs.readFileSync(packagePath + 'package.json', 'utf-8'));
|
||||
creator.create(editPath, packagePath + 'files/', packageConf).then((root) => {
|
||||
if (!root) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -190,14 +191,14 @@ const main = (function () {
|
|||
if (typeof editPath !== 'undefined') {
|
||||
const root = mngFolder.isAmWiki(editPath);
|
||||
if (root) {
|
||||
mngWiki.checkAddWiki(root);
|
||||
//选取导出地址
|
||||
eDialog.showOpenDialog({properties: ['openDirectory']}, (data) => {
|
||||
if (data && data.length) {
|
||||
//开始导出
|
||||
exportGithub.export(root, data[0]);
|
||||
exportGithub.export(root, data[0].replace(/\\/g, '/'));
|
||||
}
|
||||
});
|
||||
mngWiki.checkAddWiki(root);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
"name": "amWiki",
|
||||
"main": "./lib/main.js",
|
||||
"bin": "./bin/main.js",
|
||||
"version": "1.1.3",
|
||||
"description": "amWiki 是一款基于 Javascript 脚本语言、依赖 Atom 编辑器或 Nodejs-npm 命令行、使用 Markdown 标记语法的轻量级开源 wiki 文库系统。amWiki 致力于让大家可以更简单、更便捷的建设个人和团队文库系统!",
|
||||
"version": "1.2.0",
|
||||
"description": "amWiki 是一款由 JS 开发、依赖 Atom 或 Nodejs-Npm 的 Markdown 轻量级前端化开源文库系统。amWiki 致力于让大家可以更简单、更便捷的建设个人和团队文库!",
|
||||
"keywords": [
|
||||
"amWiki",
|
||||
"markdown",
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
"bugs": {
|
||||
"url": "https://github.com/TevinLi/amWiki/issues"
|
||||
},
|
||||
"homepage": "https://github.com/TevinLi/amWiki",
|
||||
"homepage": "http://amwiki.org",
|
||||
"configSchema": {
|
||||
"checkLibraryOnWindowFocus": {
|
||||
"type": "boolean",
|
||||
|
|
|
|||
Loading…
Reference in New Issue