好多年没碰过前端jquery了,用一两天时间重温一下,刚好写个小工具, 不递归取文件夹和文件,只写一层,保持足够简单,验证和参数判断暂不写,毕竟只写了几个小时而已,功能算完备了,添加一个简单的管理员权限管理修改的所有功能即可放出去了,看来还不错

1. 后台

var fs = require('fs')
var path = require('path')
var basePath = 'docs'
let markdown = require('markdown-it')
var md = new markdown({
html: true,
langPrefix: 'code-',
}) function mkCate(cate) {
fs.mkdir(path.join(basePath, cate), function (err) { })
} function getDirsInDocsFolder() {
var paths = fs.readdirSync(basePath)
return paths
} function getMdsInFolder(folderName) {
let paths = fs.readdirSync(path.join(basePath, folderName))
return paths
} function writeMdFile(folderPath, fileName, content) {
fs.writeFile(path.join(basePath, folderPath, fileName), content, function (err) {
console.error(err)
})
} function readMd(fileName, folderPath) {
let content = fs.readFileSync(path.join(basePath, folderPath, fileName), 'utf-8')
return content
} function readMdFileToHtml(fileName, folderPath) {
var content = readMd(fileName, folderPath)
var html = md.render(content)
return html
} function main() {
console.log('Starting web server')
var express = require('express')
var app = express()
app.use(express.static('.')) const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false })); app.get('/', function (req, res, next) {
}) app.get('/cates', function (req, res, next) {
var list = getDirsInDocsFolder()
res.send(list)
}) app.post('/cate', function (req, res, next) {
const { cate } = req.body
mkCate(cate)
}) app.get('/mds', function (req, res, next) {
const { cate } = req.query
if (!cate) res.send([])
var mds = getMdsInFolder(cate)
res.send(mds)
}) app.get('/mdhtml', function (req, res, next) {
const { cate, name } = req.query
var html = readMdFileToHtml(`${name}`, cate)
res.send(html)
})
app.get('/md', function (req, res, next) {
const { cate, name } = req.query
var md = readMd(`${name}`, cate)
res.send(md)
}) app.post('/md', function (req, res, next) {
const { cate, name, content } = req.body
writeMdFile(cate, name, content)
res.send(content) }) var server = app.listen(8081, function () {
const { address, port } = server.address()
console.log('Listening on http://%s:%s', address, port) }) }
main();

2. 前台

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="index.css">
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head> <body>
<h1>Caloch开洛奇</h1>
<nav>
<button onclick="add('c',prompt('Category:'));">+</button>
<ul id="cates">
<li><a href="#" data-cate="cate">cate</a></li>
</ul>
</nav>
<hr>
<div class="menu">
<button onclick="add('a',prompt('Name:'));">+</button>
<ul id="mds">
<li><a href="view.html?name='a1'" target="mainframe">文章.1</a></li>
</ul>
</div>
<div id="main" class="main">
<iframe id="#mainframe" name="mainframe" src="" frameborder="0"></iframe>
</div>
<div id="main1" class="main">
<textarea id="content" cols="20" rows="10"></textarea>
<button id="save">Save</button>
</div>
<footer>
©Caloch开洛奇 2019~
<span id="today"></span>
</footer>
<script>
var current = {} function add(key, val) {
var iframe = document.getElementById('#mainframe')
switch (key) {
case 'c':
if (val) {
mkCate(val)
getCates()
}
break;
case 'a':
iframe.src = "view.html?name=" + val;
break; default:
break;
}
} function getCates() {
$.get('/cates', function (data) {
let $el = $('#cates')
$el.empty()
data.forEach(cate => {
$el.append(`<li><a href="#" data-cate="${cate}">${cate}</a></li>`);
});
current.cate = data[0]
getMds(data[0])
})
} function mkCate(cate) {
if (!cate) return
$.post('/cate', { cate }, function (data) { })
} function getMds(cate) {
$.get('/mds?cate=' + cate, function (data) {
let $el = $('#mds')
$el.empty()
data.forEach(function (md) {
$el.append(`<li><a href="javascript:void(0)" data-name=${md} >${md}</a><span data-name=${md}>Edit</span></li>`)
})
})
} function getMdHtml(cate, name) {
$.get('/mdhtml?cate=' + cate + '&name=' + name, function (data) {
let $el = $('#main')
$el.html(data)
})
} function getMd(cate, name, callback) {
$.get('/md?cate=' + cate + '&name=' + name, function (data) {
let $el = $('#content')
$el.text(data)
})
}
function save(cate, name, content) {
if (!name) return
$.post('/md', { cate, name, content }, function (data) { })
} $.fn.timelyfy = function () {
let $this = $(this)
$this.html(new Date().toLocaleDateString())
} function showContent() {
$('#main').show()
$('#main1').hide()
} function showEditor() {
$('#main1').show()
$('#main').hide()
} $(document).ready(function () {
$.ajaxSetup({
beforeSend: function (xhr, settings) {
console.log(xhr)
},
dataFilter: function (data) {
console.log(data)
return data
}
})
$('#today').timelyfy()
$('#main1').hide()
getCates()
$('#cates').on('click', 'a', function () {
let $this = $(this)
current.cate = $this.data().cate
getMds(current.cate)
})
$('#mds').on('click', 'a', function () {
let $this = $(this)
current.name = $this.data().name
console.log(current); getMdHtml(current.cate, current.name)
showContent() })
$('#mds').on('click', 'span', function () {
let $this = $(this)
getMd(current.cate, $this.data().name)
showEditor()
})
$('#save').on('click', function () {
save(current.cate, current.name, $('#content').val())
})
}) </script>
</body> </html>

3. scss样式

$common-height: 150px;
@mixin with100minus($px) {
width: calc(100% - #{$px});
}
@mixin height100($px) {
height: calc(100% - #{$px});
}
* {
box-sizing: border-box;
}
h1 {
color: red;
}
ul li {
list-style-type: none;
}
nav {
width: 100%;
display: flex;
flex-direction: row;
justify-content: flex-start;
text-align: right;
a {
margin-left: 15px;
display: block;
}
a:first-child {
margin-left:;
}
}
div {
float: left;
}
.menu {
width: 200px;
height: $common-height;
}
.main {
@include with100minus(200px);
@include height100(200px);
background-color: orange;
}
iframe {
width: 100%;
min-height: 500px;
}
footer {
position: fixed;
bottom: 0px;
text-align: center;
width: 100%;
}
button {
border-radius: 5px;
}

github repository:

https://github.com/CalosChen/mementowriter

使用nodejs开发一个markdown文档管理小系统(一)Using Nodejs to quickly develop a markdown management system的更多相关文章

  1. 坚果云Markdown - 文档管理编辑器

    坚果云Markdown - 文档管理编辑器 Markdown是什么? Markdown是一种上手简单.应用十分广泛的轻量级标记语法.您可以使用Markdown轻松记录您的灵感.想法.创意.整个记录过程 ...

  2. ShowDoc 软件开发团队接口文档管理利器

    ShowDoc是一个非常适合IT团队的在线API文档.技术文档工具.你可以使用Showdoc来编写在线API文档.技术文档.数据字典.在线手册. 这里介绍 Showdoc 这款开源(免费)文档管理系统 ...

  3. 帮哥们做的一个整理文档的小工具(C++ string的标准函数还是很给力的,代码在最下)

    其实把程序用到生活中,真的能节约不少时间!程序的力量是无穷滴! 哥们的毕业设计是要做法律文书匹配之类的东东,有一步是要抽取所有的法律法规名称,而刚好我们要处理的文件中,法规的名称之前都有个‘.‘,所以 ...

  4. C#解析Markdown文档,实现替换图片链接操作

    前言 又是好久没写博客了 其实也不是没写,是最近在「做一个博客」,从2月21日开始,大概一个多星期的时间,疯狂刷进度,边写代码边写了一整系列的博客开发笔记,目前为止已经写了16篇了,然后上3月之后工作 ...

  5. 使用Python从Markdown文档中自动生成标题导航

    概述 知识与思路 代码实现 概述 Markdown 很适合于技术写作,因为技术写作并不需要花哨的排版和内容, 只要内容生动而严谨,文笔朴实而优美. 为了编写对读者更友好的文章,有必要生成文章的标题导航 ...

  6. 基于 React 开发了一个 Markdown 文档站点生成工具

    Create React Doc 是一个使用 React 的 markdown 文档站点生成工具.就像 create-react-app 一样,开发者可以使用 Create React Doc 来开发 ...

  7. Api接口文档管理工具,你知道哪些呢?

    上周看到有人在我的Github开源项目中提了个issue,说是否考虑接入swagger.那今天我就用swagger与其他接口文档工具做对比,同时说说Api接口文档工具的那点事.如今,在前后端分离开发的 ...

  8. 使用gitbook 发布一个教程文档网站

    gitbook是一个好用的发布电子书的项目:使用gitbook 可以在本地写好文档再远程推送到库:也可以在gitbook提供的在线平台上制作电子书:要想在自己的服务器上使用gitbook 发布一个网站 ...

  9. Markdown 文档生成工具

    之前用了很多Markdown 文档生成工具,发现有几个挺好用的,现在整理出来,方便大家快速学习. loppo: 非常简单的静态站点生成器 idoc:简单的文档生成工具 gitbook:大名鼎鼎的文档协 ...

随机推荐

  1. kubernetes学习:CKA考试题

    1. 列出环境内所有的pv 并以 name字段排序(使用kubectl自带排序功能) kubectl get pv --sort-by=.metadata.name 2. 列出指定pod的日志中状态为 ...

  2. jq 点击除了某元素以外的其他所有元素

    $('body').click(function(e){ if(($(e.target).attr('class')!='header-top-nav-ipt')){ alert('除了class=h ...

  3. 【转】一次HBase问题的解决过程(Status: INCONSISTENT)

    [From]https://www.cnblogs.com/quchunhui/p/9583746.html ==版本信息== HBase:2.7.1 Storm:1.0.1 RocketMQ:3.4 ...

  4. 从 SPIR-V 到 ISPC:将 GPU 计算转化为 CPU 计算

    游戏行业越来越多地趋向于将计算工作转移到图形处理单元 (GPU) 中,导致引擎和/或工作室需要开发大量 GPU 计算着色器来处理不同的计算任务.但有时候在 CPU 上运行这些计算着色器非常方便,不必重 ...

  5. Python学习之初识

    第一章 1.1 typora 的安装与使用 1.1.1 标题的创建: 方法一:用 ###+空格 表示标题,几个#就是几级标题 方法二:菜单栏-->段落-->选择标题 1.1.2 有序列表与 ...

  6. spring 给容器中注册组件的几种方式

    1.@Bean 导入第三方的类或包的组件 2.包扫描+组件的标注注解(@ComponentScan: @Controller,@service,@Reponsitory,@Componet), 自己写 ...

  7. 【Python开发】网页爬取心得

    转载:python 爬虫抓取心得分享 title:python 爬虫抓取心得分享 0x1.urllib.quote('要编码的字符串')如果你要在url请求里面放入中文,对相应的中文进行编码的话,可以 ...

  8. 色彩空间RGB/CMYK/HSL/HSB/HSV/Lab/YUV基础理论及转换方法:RGB与YUV

    之前做个设计,现在从事IT,脑子里面关于RGB,RGBA,CMY,CMYK,YUV,但是具体理论还是不扎实.若干年前之前写过<水煮RGB与CMYK色彩模型—色彩与光学相关物理理论浅叙>&l ...

  9. 谷歌云SSH开启root密码登陆

    废话不多说,开始教程 1.先选择从浏览器打开ssh连接服务器连接登录成功后,输入以下命令 sudo -i #切换到root passwd #修改密码 然后会要求输入新密码,然后再重复一次密码,输入密码 ...

  10. [转帖]从Intel和ARM争霸,谈芯片前世今生

    从Intel和ARM争霸,谈芯片前世今生 http://www.itpub.net/2019/07/24/2476/ 长文预警, 写的非常好.. 我尽量写得轻松一些,因为其实这个话题很有趣,仔细探究起 ...