Merge pull request #78 from TevinLi/develop

pull v1.2.1 from develop
This commit is contained in:
Tevin 2017-08-03 22:17:30 +08:00 committed by GitHub
commit 96032092f6
16 changed files with 346 additions and 145 deletions

View File

@ -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_

View File

@ -1,7 +1,7 @@
# amWiki 轻文库
![amWiki logo](https://amwiki.xf09.net/docs/assets/logo.png)
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**
- 如果可以,欢迎直接加我微信
- 如果可以,欢迎直接加我微信
![](http://amwiki.org/doc/assets/wx.qrcode.150.png)
### 如何查看历史版本日志?

56
SCHEDULE.md Normal file
View File

@ -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
- 新增自定义主题模块

View File

@ -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':

View File

@ -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)}`,

View File

@ -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;

View File

@ -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, '![$1](' + this._githubUrl + 'wiki/images$2)')
@ -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;
}

View File

@ -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');
}

View File

@ -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;
}
}
};
})();

View File

@ -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 = {

View File

@ -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;}

View File

@ -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);
};
/**

View File

@ -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>';

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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",