@kobalab/liulian 0.8.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ChangeLog.md +17 -0
- package/css/liulian.css +7 -0
- package/lib/html/folder.js +1 -1
- package/lib/html/index.js +4 -5
- package/lib/module/index.js +9 -9
- package/lib/module/paiga.js +124 -0
- package/lib/module/pinyin.js +51 -0
- package/lib/resource/folder.js +12 -3
- package/lib/resource/index.js +7 -0
- package/lib/resource/liulian.js +8 -34
- package/lib/resource/markdown.js +33 -0
- package/lib/resource/text.js +20 -1
- package/lib/text/liulian.js +6 -0
- package/lib/text/markdown.js +25 -0
- package/lib/util/html-escape.js +6 -1
- package/package.json +3 -1
package/ChangeLog.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# v1.0.0 / 2022-04-09
|
|
2
|
+
|
|
3
|
+
- 正式バージョンリリース
|
|
4
|
+
- #6 Markdown記法に対応した
|
|
5
|
+
- JavaScriptを編集可能にした
|
|
6
|
+
|
|
7
|
+
### v0.9.1 / 2022-04-06
|
|
8
|
+
|
|
9
|
+
- paiga モジュールに空文字列を指定した場合に異常終了するバグを修正
|
|
10
|
+
|
|
11
|
+
## v0.9.0 / 2022-04-03
|
|
12
|
+
|
|
13
|
+
- import モジュールで外部モジュールをインポートできるようにした
|
|
14
|
+
- pinyin モジュール(中国語のピンインを表示する)を追加
|
|
15
|
+
- paiga モジュール(麻雀の牌画像を表示する)を追加
|
|
16
|
+
- 脆弱性警告に対処(minimist 1.2.5 → 1.2.6)
|
|
17
|
+
|
|
1
18
|
### v0.8.1 / 2022-01-24
|
|
2
19
|
|
|
3
20
|
- 脆弱性警告に対処(mocha 9.1.3 → 9.2.0)
|
package/css/liulian.css
CHANGED
package/lib/html/folder.js
CHANGED
|
@@ -97,7 +97,7 @@ module.exports = class Folder extends File {
|
|
|
97
97
|
for (let file of this._r.files.sort(cmp(s))) {
|
|
98
98
|
|
|
99
99
|
if (req.cmd != 'edit'
|
|
100
|
-
&& file.name.match(/^(?:README|HEAD|TAIL)
|
|
100
|
+
&& file.name.match(/^(?:README|HEAD|TAIL)(?:\.md)?$/)) continue;
|
|
101
101
|
|
|
102
102
|
let name = file.name + (file.type ? '' : '/');
|
|
103
103
|
let link = encodeURIComponent(file.name) + (file.type ? '' : '/')
|
package/lib/html/index.js
CHANGED
|
@@ -30,8 +30,8 @@ module.exports = class HTML {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
title(title) {
|
|
33
|
-
if (title) this._.title = title;
|
|
34
|
-
else
|
|
33
|
+
if (title != null) this._.title = title;
|
|
34
|
+
else return this._.title;
|
|
35
35
|
return this;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -68,8 +68,6 @@ module.exports = class HTML {
|
|
|
68
68
|
_head() {
|
|
69
69
|
const req = this._req;
|
|
70
70
|
|
|
71
|
-
if (! this._.stylesheet.length)
|
|
72
|
-
this._.stylesheet.push({url: DEFAULT_STYLE});
|
|
73
71
|
const stylesheet = this._.stylesheet.map(opt=>
|
|
74
72
|
'<link rel="stylesheet" type="text/css" '
|
|
75
73
|
+ `href="${cdata(fixpath(opt.url, req.baseUrl))}"`
|
|
@@ -151,7 +149,8 @@ module.exports = class HTML {
|
|
|
151
149
|
+ `</div>\n`;
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
stringify(content = '') {
|
|
152
|
+
stringify(content = '', needDefaultStyle = ! this._.stylesheet.length) {
|
|
153
|
+
if (needDefaultStyle) this._.stylesheet.push({url: DEFAULT_STYLE});
|
|
155
154
|
return '<!DOCTYPE html>\n'
|
|
156
155
|
+ `<html lang="${cdata(this.lang())}">\n`
|
|
157
156
|
+ this._head()
|
package/lib/module/index.js
CHANGED
|
@@ -15,16 +15,16 @@ module.exports = class Module {
|
|
|
15
15
|
this.import('core');
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
require(path) {
|
|
19
|
-
try { return require(path) }
|
|
20
|
-
catch(err) { console.log(err) }
|
|
21
|
-
}
|
|
22
|
-
|
|
23
18
|
import(module) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
try {
|
|
20
|
+
if (! modules[module]) modules[module] = require('./' + module);
|
|
21
|
+
this._modules.push(new modules[module](this._parser));
|
|
22
|
+
return modules[module];
|
|
23
|
+
}
|
|
24
|
+
catch(err) {
|
|
25
|
+
if (err.code) console.log(module, err.code);
|
|
26
|
+
else console.log(err);
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
callInlineModule(str, name, param, value) {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* module/paiga
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const imgbase = '//kobalab.github.io/paiga/';
|
|
7
|
+
const img = {
|
|
8
|
+
_: 'ura.gif',
|
|
9
|
+
|
|
10
|
+
m0: 'man5red.gif',
|
|
11
|
+
m1: 'man1.gif', m2: 'man2.gif', m3: 'man3.gif',
|
|
12
|
+
m4: 'man4.gif', m5: 'man5.gif', m6: 'man6.gif',
|
|
13
|
+
m7: 'man7.gif', m8: 'man8.gif', m9: 'man9.gif',
|
|
14
|
+
|
|
15
|
+
p0: 'pin5red.gif',
|
|
16
|
+
p1: 'pin1.gif', p2: 'pin2.gif', p3: 'pin3.gif',
|
|
17
|
+
p4: 'pin4.gif', p5: 'pin5.gif', p6: 'pin6.gif',
|
|
18
|
+
p7: 'pin7.gif', p8: 'pin8.gif', p9: 'pin9.gif',
|
|
19
|
+
|
|
20
|
+
s0: 'sou5red.gif',
|
|
21
|
+
s1: 'sou1.gif', s2: 'sou2.gif', s3: 'sou3.gif',
|
|
22
|
+
s4: 'sou4.gif', s5: 'sou5.gif', s6: 'sou6.gif',
|
|
23
|
+
s7: 'sou7.gif', s8: 'sou8.gif', s9: 'sou9.gif',
|
|
24
|
+
|
|
25
|
+
z1: 'ton.gif', z2: 'nan.gif', z3: 'sha.gif', z4: 'pei.gif',
|
|
26
|
+
z5: 'haku.gif', z6: 'hatu.gif', z7: 'tyun.gif',
|
|
27
|
+
|
|
28
|
+
m0_: 'yman5red.gif',
|
|
29
|
+
m1_: 'yman1.gif', m2_: 'yman2.gif', m3_: 'yman3.gif',
|
|
30
|
+
m4_: 'yman4.gif', m5_: 'yman5.gif', m6_: 'yman6.gif',
|
|
31
|
+
m7_: 'yman7.gif', m8_: 'yman8.gif', m9_: 'yman9.gif',
|
|
32
|
+
|
|
33
|
+
p0_: 'ypin5red.gif',
|
|
34
|
+
p1_: 'ypin1.gif', p2_: 'ypin2.gif', p3_: 'ypin3.gif',
|
|
35
|
+
p4_: 'ypin4.gif', p5_: 'ypin5.gif', p6_: 'ypin6.gif',
|
|
36
|
+
p7_: 'ypin7.gif', p8_: 'ypin8.gif', p9_: 'ypin9.gif',
|
|
37
|
+
|
|
38
|
+
s0_: 'ysou5red.gif',
|
|
39
|
+
s1_: 'ysou1.gif', s2_: 'ysou2.gif', s3_: 'ysou3.gif',
|
|
40
|
+
s4_: 'ysou4.gif', s5_: 'ysou5.gif', s6_: 'ysou6.gif',
|
|
41
|
+
s7_: 'ysou7.gif', s8_: 'ysou8.gif', s9_: 'ysou9.gif',
|
|
42
|
+
|
|
43
|
+
z1_: 'yton.gif', z2_: 'ynan.gif', z3_: 'ysha.gif', z4_: 'ypei.gif',
|
|
44
|
+
z5_: 'yhaku.gif', z6_: 'yhatu.gif', z7_: 'ytyun.gif'
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
function markup(paistr, w, h) {
|
|
48
|
+
|
|
49
|
+
let url, v = 0;
|
|
50
|
+
let html = '<span class="l-mod-paiga" style="white-space:pre;">';
|
|
51
|
+
|
|
52
|
+
for (let pai of paistr.match(/[mpsz](?:\d+[\-\=]?)+|[ _]|.+/g)||[]) {
|
|
53
|
+
|
|
54
|
+
if (pai == ' ') {
|
|
55
|
+
html += ' ';
|
|
56
|
+
}
|
|
57
|
+
else if (pai == '_') {
|
|
58
|
+
url = imgbase + img._;
|
|
59
|
+
html += `<img src="${url}" width="${w}" height="${h}"`
|
|
60
|
+
+ ` alt="${pai}">`;
|
|
61
|
+
}
|
|
62
|
+
else if (pai.match(/^[mpsz](?:\d+[\-\=]?)+/)) {
|
|
63
|
+
let s = pai[0];
|
|
64
|
+
for (let n of pai.match(/\d[\-\=]?/g)) {
|
|
65
|
+
let d = n[1]||''; n = n[0];
|
|
66
|
+
if (d == '=' && ! v) {
|
|
67
|
+
html += `<span style="display:inline-block;width:${h}px">`;
|
|
68
|
+
v = 1;
|
|
69
|
+
}
|
|
70
|
+
if (d || v) {
|
|
71
|
+
url = imgbase + img[s+n+'_'];
|
|
72
|
+
if (d == '=') {
|
|
73
|
+
html += `<img src="${url}" width="${h}" height="${w}"`
|
|
74
|
+
+ ` style="vertical-align:bottom;display:block"`
|
|
75
|
+
+ ` alt="${s+n+'='}">`;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
html += `<img src="${url}" width="${h}" height="${w}"`
|
|
79
|
+
+ ` alt="${s+n+'-'}">`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
url = imgbase + img[s+n];
|
|
84
|
+
html += `<img src="${url}" width="${w}" height="${h}"`
|
|
85
|
+
+ ` alt="${s+n}">`;
|
|
86
|
+
}
|
|
87
|
+
if (d != '=') {
|
|
88
|
+
if (v) html += '</span>';
|
|
89
|
+
v = 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
html += `<span style="color:red;">${pai}</span>`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (v) html += '</span>';
|
|
98
|
+
html += '</span>';
|
|
99
|
+
return html;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = class Paiga {
|
|
103
|
+
|
|
104
|
+
constructor(parser) {
|
|
105
|
+
this._parser = parser;
|
|
106
|
+
this._r = parser._r;
|
|
107
|
+
this._req = parser._r._req;
|
|
108
|
+
this._inline = ['paiga'];
|
|
109
|
+
this._block = [];
|
|
110
|
+
this._np = [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
paiga(type, param, value) {
|
|
114
|
+
let w = 24, h = 34;
|
|
115
|
+
if (! param) { w = 24; h = 34 }
|
|
116
|
+
else if (param == 'L') { w = 24; h = 34 }
|
|
117
|
+
else if (param == 'M') { w = 19; h = 24 }
|
|
118
|
+
else if (param == 'S') { w = 16; h = 23 }
|
|
119
|
+
else if (param.match(/^\d+x\d+$/)) {
|
|
120
|
+
[ w, h ] = param.split(/x/);
|
|
121
|
+
}
|
|
122
|
+
return markup(value, w, h);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* module/pinyin
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const tone_letter = {
|
|
7
|
+
a: ['ā','á','ǎ','à'],
|
|
8
|
+
e: ['ē','é','ě','è'],
|
|
9
|
+
o: ['ō','ó','ǒ','ò'],
|
|
10
|
+
i: ['ī','í','ǐ','ì'],
|
|
11
|
+
u: ['ū','ú','ǔ','ù'],
|
|
12
|
+
v: ['ǖ','ǘ','ǚ','ǜ'],
|
|
13
|
+
n: ['n̄','ń','ň','ǹ'],
|
|
14
|
+
A: ['Ā','Á','Ǎ','À'],
|
|
15
|
+
E: ['Ē','É','Ě','È'],
|
|
16
|
+
O: ['Ō','Ó','Ǒ','Ò'],
|
|
17
|
+
I: ['Ī','Í','Ǐ','Ì'],
|
|
18
|
+
U: ['Ū','Ú','Ǔ','Ù'],
|
|
19
|
+
V: ['Ǖ','Ǘ','Ǚ','Ǜ'],
|
|
20
|
+
N: ['N̄','Ń','Ň','Ǹ'],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function mark(str) {
|
|
24
|
+
const code = (c)=>tone_letter[c][n-1];
|
|
25
|
+
let [ , s, n ] = str.match(/^(.*?)(\d)$/);
|
|
26
|
+
if (s.match(/[aeo]/i)) return s.replace(/[aeo]/i, code);
|
|
27
|
+
if (s.match(/[iu]$/i)) return s.replace(/[iu]$/i, code);
|
|
28
|
+
if (s.match(/^[iuv]/i)) return s.replace(/^[iuv]/i, code);
|
|
29
|
+
else return s.replace(/n/i, code);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = class Pinyin {
|
|
33
|
+
|
|
34
|
+
constructor(parser) {
|
|
35
|
+
this._parser = parser;
|
|
36
|
+
this._r = parser._r;
|
|
37
|
+
this._req = parser._r._req;
|
|
38
|
+
this._inline = ['pinyin'];
|
|
39
|
+
this._block = ['pinyin'];
|
|
40
|
+
this._np = [];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
pinyin(type, param, value) {
|
|
44
|
+
value = value.replace(/([aeouiv][1234])([aeo])/ig, '$1-$2');
|
|
45
|
+
value = value.replace(/[iuv]?[aeo]?(?:i|u|o|n|ng)?[1234]/ig, mark);
|
|
46
|
+
value = value.replace(/v/g, 'ü').replace(/V/g, 'Ü');
|
|
47
|
+
return type == '#'
|
|
48
|
+
? `<div class="l-mod-pinyin">${value}</div>`
|
|
49
|
+
: `<span class="l-mod-pinyin">${value}</span>`;
|
|
50
|
+
}
|
|
51
|
+
}
|
package/lib/resource/folder.js
CHANGED
|
@@ -7,6 +7,7 @@ const fs = require('fs').promises;
|
|
|
7
7
|
const { join } = require('path');
|
|
8
8
|
const HTML = require('../html/folder');
|
|
9
9
|
const parse = require('../text/liulian');
|
|
10
|
+
const md = require('../text/markdown');
|
|
10
11
|
|
|
11
12
|
const File = require('./file');
|
|
12
13
|
|
|
@@ -39,7 +40,7 @@ module.exports = class Folder extends File {
|
|
|
39
40
|
catch(err) {}
|
|
40
41
|
}
|
|
41
42
|
if (this._req.cmd != 'edit') {
|
|
42
|
-
for (let ext of ['', '.html', '.htm']) {
|
|
43
|
+
for (let ext of ['', '.md', '.html', '.htm']) {
|
|
43
44
|
let index = this._files.find(f=>f.name == 'index' + ext);
|
|
44
45
|
if (index) return index.open();
|
|
45
46
|
}
|
|
@@ -99,11 +100,19 @@ module.exports = class Folder extends File {
|
|
|
99
100
|
res.sendText(new HTML(this).edit());
|
|
100
101
|
}
|
|
101
102
|
else {
|
|
102
|
-
let readme
|
|
103
|
+
let readme;
|
|
104
|
+
for (let file of ['README','README.md']) {
|
|
105
|
+
readme = this._files.find(f=>f.name == file);
|
|
106
|
+
if (readme) break;
|
|
107
|
+
}
|
|
103
108
|
if (readme) {
|
|
104
109
|
await readme.open();
|
|
105
110
|
readme._html = new HTML(this);
|
|
106
|
-
res.sendText(readme._html.folder(
|
|
111
|
+
res.sendText(readme._html.folder(
|
|
112
|
+
readme.type == 'text/x-liulian'
|
|
113
|
+
? await parse(readme)
|
|
114
|
+
: md.render(readme._text)
|
|
115
|
+
));
|
|
107
116
|
}
|
|
108
117
|
else if (this._req.user) {
|
|
109
118
|
res.sendText(new HTML(this).folder());
|
package/lib/resource/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const File = require('./file');
|
|
|
11
11
|
const Folder = require('./folder');
|
|
12
12
|
const Text = require('./text');
|
|
13
13
|
const LiuLian = require('./liulian');
|
|
14
|
+
const Markdown = require('./markdown');
|
|
14
15
|
|
|
15
16
|
async function resource(req, file) {
|
|
16
17
|
let location;
|
|
@@ -35,6 +36,12 @@ async function resource(req, file) {
|
|
|
35
36
|
else if (! basename(path).match(/\./))
|
|
36
37
|
return new LiuLian(req, path, stat,
|
|
37
38
|
location, resource);
|
|
39
|
+
else if (mime.getType(path) == 'text/markdown')
|
|
40
|
+
return new Markdown (req, path, stat,
|
|
41
|
+
location, resource);
|
|
42
|
+
else if (mime.getType(path) == 'application/javascript')
|
|
43
|
+
return new Text (req, path, stat,
|
|
44
|
+
location, resource);
|
|
38
45
|
else if ((mime.getType(path)||'').match(/^text\//))
|
|
39
46
|
return new Text(req, path, stat,
|
|
40
47
|
location, resource);
|
package/lib/resource/liulian.js
CHANGED
|
@@ -18,44 +18,18 @@ module.exports = class LiuLian extends Text {
|
|
|
18
18
|
script(script) { this._html.script(script) }
|
|
19
19
|
meta(attr) { this._html.meta(attr) }
|
|
20
20
|
|
|
21
|
-
async _seekToParent(filename) {
|
|
22
|
-
let pathDir = this._req.pathDir;
|
|
23
|
-
while (pathDir) {
|
|
24
|
-
try {
|
|
25
|
-
const r = await this.openFile(this._req, pathDir + filename);
|
|
26
|
-
await r.open();
|
|
27
|
-
return r.text;
|
|
28
|
-
}
|
|
29
|
-
catch(e) {
|
|
30
|
-
pathDir = pathDir.replace(/[^\/]*\/$/,'');
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return '';
|
|
34
|
-
}
|
|
35
|
-
|
|
36
21
|
async update() {
|
|
37
22
|
await super.update();
|
|
38
23
|
if (this._req.param('text')) this._redirect = [303, this.name];
|
|
39
24
|
}
|
|
40
25
|
|
|
41
|
-
async
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
res.sendText(new HTML(this).diff());
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
this._text = (this.name != 'HEAD'
|
|
53
|
-
? await this._seekToParent('HEAD') + '\n' : '')
|
|
54
|
-
+ this._text + '\n'
|
|
55
|
-
+ (this.name != 'TAIL'
|
|
56
|
-
? await this._seekToParent('TAIL') : '');
|
|
57
|
-
this._html = new HTML(this);
|
|
58
|
-
res.sendText(this._html.stringify(await parse(this)));
|
|
59
|
-
}
|
|
26
|
+
async _send(res) {
|
|
27
|
+
this._text = (this.name != 'HEAD'
|
|
28
|
+
? await this._seekToParent('HEAD') + '\n' : '')
|
|
29
|
+
+ this._text + '\n'
|
|
30
|
+
+ (this.name != 'TAIL'
|
|
31
|
+
? await this._seekToParent('TAIL') : '');
|
|
32
|
+
this._html = new HTML(this);
|
|
33
|
+
res.sendText(this._html.stringify(await parse(this)));
|
|
60
34
|
}
|
|
61
35
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* resource/markdown
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const { strip } = require('../util/html-escape');
|
|
7
|
+
|
|
8
|
+
const HTML = require('../html/text');
|
|
9
|
+
const Text = require('./text');
|
|
10
|
+
const md = require('../text/markdown');
|
|
11
|
+
|
|
12
|
+
module.exports = class Markdown extends Text {
|
|
13
|
+
|
|
14
|
+
async update() {
|
|
15
|
+
await super.update();
|
|
16
|
+
if (this._req.param('text')) this._redirect = [303, this.name];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async _send(res) {
|
|
20
|
+
this._text = (this.name != 'HEAD.md'
|
|
21
|
+
? await this._seekToParent('HEAD.md') + '\n' : '')
|
|
22
|
+
+ this._text + '\n'
|
|
23
|
+
+ (this.name != 'TAIL.md'
|
|
24
|
+
? await this._seekToParent('TAIL.md') : '');
|
|
25
|
+
let html = md.render(this._text);
|
|
26
|
+
let title = strip((html.match(/<title>(.*?)<\/title>/i)||
|
|
27
|
+
html.match(/<h1>(.*?)<\/h1>/i)||[])[1]);
|
|
28
|
+
let style = (html.match(/<link\s?.*?>/ig)||[])
|
|
29
|
+
.filter(tag=>tag.match(/\srel="stylesheet"/i));
|
|
30
|
+
this._html = new HTML(this);
|
|
31
|
+
res.sendText(this._html.title(title).stringify(html, ! style.length));
|
|
32
|
+
}
|
|
33
|
+
}
|
package/lib/resource/text.js
CHANGED
|
@@ -13,6 +13,21 @@ module.exports = class Text extends File {
|
|
|
13
13
|
get text() { return this._text }
|
|
14
14
|
get diff() { return this._diff }
|
|
15
15
|
|
|
16
|
+
async _seekToParent(filename) {
|
|
17
|
+
let pathDir = this._req.pathDir;
|
|
18
|
+
while (pathDir) {
|
|
19
|
+
try {
|
|
20
|
+
const r = await this.openFile(this._req, pathDir + filename);
|
|
21
|
+
await r.open();
|
|
22
|
+
return r.text;
|
|
23
|
+
}
|
|
24
|
+
catch(e) {
|
|
25
|
+
pathDir = pathDir.replace(/[^\/]*\/$/,'');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
async open() {
|
|
17
32
|
await super.open();
|
|
18
33
|
if (this._backup && this._req.cmd == 'diff') {
|
|
@@ -57,6 +72,10 @@ module.exports = class Text extends File {
|
|
|
57
72
|
if (this._req.cmd == 'edit') res.sendText(new HTML(this).edit());
|
|
58
73
|
else if (this._req.cmd == 'log') res.sendText(new HTML(this).log());
|
|
59
74
|
else if (this._req.cmd == 'diff') res.sendText(new HTML(this).diff());
|
|
60
|
-
else
|
|
75
|
+
else this._send(res);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_send(res) {
|
|
79
|
+
res.sendFile(this._path, this.type);
|
|
61
80
|
}
|
|
62
81
|
}
|
package/lib/text/liulian.js
CHANGED
|
@@ -381,6 +381,7 @@ class LiuLian {
|
|
|
381
381
|
let [ , name, param, eod ]
|
|
382
382
|
= line.match(/^#(\w+)(?:\((.*?)\))?(?:<<(\S+))?$/);
|
|
383
383
|
if (name == '_') return await this.tag(line, param, eod);
|
|
384
|
+
if (name == 'import') return this.import(line, param);
|
|
384
385
|
|
|
385
386
|
return await this._module.callBlockModule(line, name, param, eod);
|
|
386
387
|
}
|
|
@@ -402,6 +403,11 @@ class LiuLian {
|
|
|
402
403
|
}
|
|
403
404
|
}
|
|
404
405
|
|
|
406
|
+
import(line, param) {
|
|
407
|
+
if (this._module.import(param)) return '';
|
|
408
|
+
return '<div style="color:red">' + cdata(line) + '</div>\n\n';
|
|
409
|
+
}
|
|
410
|
+
|
|
405
411
|
inlineModule(str, name, param, value) {
|
|
406
412
|
return this._module.callInlineModule(str, name, param, value);
|
|
407
413
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* text/markdown
|
|
3
|
+
*/
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const hljs = require('highlight.js');
|
|
7
|
+
|
|
8
|
+
module.exports = require('markdown-it')({
|
|
9
|
+
html: true,
|
|
10
|
+
linkify: true,
|
|
11
|
+
highlight: function(str, lang) {
|
|
12
|
+
const error = console.error; console.error = ()=>{};
|
|
13
|
+
let html = '';
|
|
14
|
+
if (lang) {
|
|
15
|
+
try {
|
|
16
|
+
html = hljs.highlight(lang, str).value;
|
|
17
|
+
}
|
|
18
|
+
catch(err) {
|
|
19
|
+
html = hljs.highlightAuto(str).value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
console.error = error;
|
|
23
|
+
return html;
|
|
24
|
+
}
|
|
25
|
+
}).use(require('markdown-it-footnote'));
|
package/lib/util/html-escape.js
CHANGED
|
@@ -15,8 +15,13 @@ function cdata(str = '') {
|
|
|
15
15
|
|
|
16
16
|
const cref = replacer(cref_pt, null, cdata);
|
|
17
17
|
|
|
18
|
+
function getAlt(img) {
|
|
19
|
+
return cref((img.match(/\salt="(.*?)"/)||[])[1]);
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
function strip(html = '') {
|
|
19
|
-
return html.replace(
|
|
23
|
+
return html.replace(/<img\s?.*?>/g, getAlt)
|
|
24
|
+
.replace(/<.*?>/g, '')
|
|
20
25
|
.replace(/>/g, '>')
|
|
21
26
|
.replace(/</g, '<')
|
|
22
27
|
.replace(/"/g,'"')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kobalab/liulian",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Node.jsで動作するWebサイト作成ツール",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"express": "^4.17.1",
|
|
35
35
|
"express-session": "^1.17.1",
|
|
36
36
|
"highlight.js": "^10.4.1",
|
|
37
|
+
"markdown-it": "^12.3.2",
|
|
38
|
+
"markdown-it-footnote": "^3.0.3",
|
|
37
39
|
"mime": "^2.4.6",
|
|
38
40
|
"multer": "^1.4.2",
|
|
39
41
|
"passport": "^0.4.1",
|