@kobalab/liulian 0.9.1 → 1.0.2
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 +15 -0
- package/css/liulian.css +20 -3
- package/lib/html/folder.js +1 -1
- package/lib/html/index.js +4 -5
- package/lib/module/paiga.js +1 -1
- 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/markdown.js +25 -0
- package/lib/util/html-escape.js +6 -1
- package/package.json +3 -1
package/ChangeLog.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
### v1.0.2 / 2022-04-11
|
|
2
|
+
|
|
3
|
+
- iPhone で form がリサイズしないよう修正
|
|
4
|
+
- Windows用の等幅フォントを変更
|
|
5
|
+
|
|
6
|
+
### v1.0.1 / 2022-04-10
|
|
7
|
+
|
|
8
|
+
- paiga モジュールのMサイズの指定の誤りを修正
|
|
9
|
+
|
|
10
|
+
# v1.0.0 / 2022-04-09
|
|
11
|
+
|
|
12
|
+
- 正式バージョンリリース
|
|
13
|
+
- #6 Markdown記法に対応した
|
|
14
|
+
- JavaScriptを編集可能にした
|
|
15
|
+
|
|
1
16
|
### v0.9.1 / 2022-04-06
|
|
2
17
|
|
|
3
18
|
- paiga モジュールに空文字列を指定した場合に異常終了するバグを修正
|
package/css/liulian.css
CHANGED
|
@@ -95,7 +95,7 @@ pre {
|
|
|
95
95
|
background: #eee;
|
|
96
96
|
overflow: auto;
|
|
97
97
|
overflow-wrap: normal;
|
|
98
|
-
font-family: Osaka-Mono, "
|
|
98
|
+
font-family: Osaka-Mono, "BIZ UDゴシック", "MS ゴシック", Courier, monospace;
|
|
99
99
|
font-size: 100%;
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -133,6 +133,16 @@ div.l-footnote a[id] {
|
|
|
133
133
|
form {
|
|
134
134
|
margin: 1em auto;
|
|
135
135
|
}
|
|
136
|
+
@media screen and (max-width: 640px) {
|
|
137
|
+
form {
|
|
138
|
+
font-size: 16px;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
@media screen and (max-height: 640px) {
|
|
142
|
+
form {
|
|
143
|
+
font-size: 16px;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
136
146
|
fieldset {
|
|
137
147
|
border: solid 1px #080;
|
|
138
148
|
border-radius: 4px;
|
|
@@ -151,7 +161,7 @@ input[disabled] {
|
|
|
151
161
|
}
|
|
152
162
|
textarea {
|
|
153
163
|
padding: 4px;
|
|
154
|
-
font-family: Osaka-Mono, "
|
|
164
|
+
font-family: Osaka-Mono, "BIZ UDゴシック", "MS ゴシック", Courier, monospace;
|
|
155
165
|
font-size: 100%;
|
|
156
166
|
border: solid 1px #999;
|
|
157
167
|
border-radius: 4px;
|
|
@@ -285,7 +295,7 @@ input[type="submit"] {
|
|
|
285
295
|
#l-mkfile input[name="filename"],
|
|
286
296
|
#l-udfile input[name="filename"],
|
|
287
297
|
#l-mkdir input[name="dirname"] {
|
|
288
|
-
width:
|
|
298
|
+
width: 200px;
|
|
289
299
|
}
|
|
290
300
|
#l-udfile input[disable] {
|
|
291
301
|
pointer-events: none;
|
|
@@ -333,6 +343,13 @@ input[type="submit"] {
|
|
|
333
343
|
color: red;
|
|
334
344
|
}
|
|
335
345
|
|
|
346
|
+
.footnotes {
|
|
347
|
+
font-size: 90%;
|
|
348
|
+
}
|
|
349
|
+
.footnotes li p {
|
|
350
|
+
margin: 0.2em auto;
|
|
351
|
+
}
|
|
352
|
+
|
|
336
353
|
.hljs-comment,
|
|
337
354
|
.hljs-quote {
|
|
338
355
|
color: #a0a1a7;
|
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/paiga.js
CHANGED
|
@@ -114,7 +114,7 @@ module.exports = class Paiga {
|
|
|
114
114
|
let w = 24, h = 34;
|
|
115
115
|
if (! param) { w = 24; h = 34 }
|
|
116
116
|
else if (param == 'L') { w = 24; h = 34 }
|
|
117
|
-
else if (param == 'M') { w = 19; h =
|
|
117
|
+
else if (param == 'M') { w = 19; h = 26 }
|
|
118
118
|
else if (param == 'S') { w = 16; h = 23 }
|
|
119
119
|
else if (param.match(/^\d+x\d+$/)) {
|
|
120
120
|
[ w, h ] = param.split(/x/);
|
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
|
}
|
|
@@ -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.2",
|
|
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",
|