nodebb-plugin-markdown 9.0.8 → 10.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/.eslintrc +1 -126
- package/index.js +43 -36
- package/lib/controllers.js +1 -1
- package/package.json +9 -9
- package/plugin.json +3 -4
- package/public/js/.eslintrc +3 -0
- package/public/js/admin.js +1 -1
- package/public/js/client.js +74 -41
- package/upgrades/use_unminified_hljs_theme.js +14 -0
- package/.eslintignore +0 -2
- package/public/js/highlightjs-line-numbers.js +0 -373
package/.eslintrc
CHANGED
|
@@ -1,128 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "
|
|
3
|
-
"parserOptions": {
|
|
4
|
-
"sourceType": "script"
|
|
5
|
-
},
|
|
6
|
-
|
|
7
|
-
"rules": {
|
|
8
|
-
// Customized
|
|
9
|
-
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
|
|
10
|
-
"comma-dangle": ["error", {
|
|
11
|
-
"arrays": "always-multiline",
|
|
12
|
-
"objects": "always-multiline",
|
|
13
|
-
"imports": "always-multiline",
|
|
14
|
-
"exports": "always-multiline",
|
|
15
|
-
"functions": "never"
|
|
16
|
-
}],
|
|
17
|
-
"no-empty": ["error", { "allowEmptyCatch": true }],
|
|
18
|
-
"no-underscore-dangle": "off",
|
|
19
|
-
"newline-per-chained-call": "off",
|
|
20
|
-
"no-console": "off",
|
|
21
|
-
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
|
|
22
|
-
"strict": ["error", "global"],
|
|
23
|
-
"consistent-return": "off",
|
|
24
|
-
"func-names": "off",
|
|
25
|
-
"no-tabs": "off",
|
|
26
|
-
"indent": ["error", "tab"],
|
|
27
|
-
"no-eq-null": "off",
|
|
28
|
-
"camelcase": "off",
|
|
29
|
-
"no-new": "off",
|
|
30
|
-
"no-shadow": "off",
|
|
31
|
-
"no-use-before-define": ["error", "nofunc"],
|
|
32
|
-
"no-prototype-builtins": "off",
|
|
33
|
-
"new-cap": "off",
|
|
34
|
-
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
|
35
|
-
"import/no-unresolved": "error",
|
|
36
|
-
|
|
37
|
-
// ES6
|
|
38
|
-
"prefer-rest-params": "off",
|
|
39
|
-
"prefer-spread": "off",
|
|
40
|
-
"prefer-arrow-callback": "off",
|
|
41
|
-
"prefer-template": "off",
|
|
42
|
-
"no-var": "off",
|
|
43
|
-
"object-shorthand": "off",
|
|
44
|
-
"vars-on-top": "off",
|
|
45
|
-
|
|
46
|
-
// TODO
|
|
47
|
-
"import/no-extraneous-dependencies": "off",
|
|
48
|
-
"import/no-dynamic-require": "off",
|
|
49
|
-
"import/newline-after-import": "off",
|
|
50
|
-
"no-bitwise": "off",
|
|
51
|
-
"global-require": "off",
|
|
52
|
-
"max-len": "off",
|
|
53
|
-
"no-param-reassign": "off",
|
|
54
|
-
"no-restricted-syntax": "off",
|
|
55
|
-
"no-script-url": "off",
|
|
56
|
-
"default-case": "off",
|
|
57
|
-
"linebreak-style": "off",
|
|
58
|
-
|
|
59
|
-
// "no-multi-assign": "off",
|
|
60
|
-
// "one-var": "off",
|
|
61
|
-
// "no-undef": "off",
|
|
62
|
-
// "max-nested-callbacks": "off",
|
|
63
|
-
// "no-mixed-requires": "off",
|
|
64
|
-
// "brace-style": "off",
|
|
65
|
-
// "max-statements-per-line": "off",
|
|
66
|
-
// "no-unused-vars": "off",
|
|
67
|
-
// "no-mixed-spaces-and-tabs": "off",
|
|
68
|
-
// "no-useless-concat": "off",
|
|
69
|
-
// "require-jsdoc": "off",
|
|
70
|
-
// "eqeqeq": "off",
|
|
71
|
-
// "no-negated-condition": "off",
|
|
72
|
-
// "one-var-declaration-per-line": "off",
|
|
73
|
-
// "no-lonely-if": "off",
|
|
74
|
-
// "radix": "off",
|
|
75
|
-
// "no-else-return": "off",
|
|
76
|
-
// "no-useless-escape": "off",
|
|
77
|
-
// "block-scoped-var": "off",
|
|
78
|
-
// "operator-assignment": "off",
|
|
79
|
-
// "yoda": "off",
|
|
80
|
-
// "no-loop-func": "off",
|
|
81
|
-
// "no-void": "off",
|
|
82
|
-
// "valid-jsdoc": "off",
|
|
83
|
-
// "no-cond-assign": "off",
|
|
84
|
-
// "no-redeclare": "off",
|
|
85
|
-
// "no-unreachable": "off",
|
|
86
|
-
// "no-nested-ternary": "off",
|
|
87
|
-
// "operator-linebreak": "off",
|
|
88
|
-
// "guard-for-in": "off",
|
|
89
|
-
// "no-unneeded-ternary": "off",
|
|
90
|
-
// "no-sequences": "off",
|
|
91
|
-
// "no-extend-native": "off",
|
|
92
|
-
// "no-shadow-restricted-names": "off",
|
|
93
|
-
// "no-extra-boolean-cast": "off",
|
|
94
|
-
// "no-path-concat": "off",
|
|
95
|
-
// "no-unused-expressions": "off",
|
|
96
|
-
// "no-return-assign": "off",
|
|
97
|
-
// "no-restricted-modules": "off",
|
|
98
|
-
// "object-curly-spacing": "off",
|
|
99
|
-
// "indent": "off",
|
|
100
|
-
// "padded-blocks": "off",
|
|
101
|
-
// "eol-last": "off",
|
|
102
|
-
// "lines-around-directive": "off",
|
|
103
|
-
// "strict": "off",
|
|
104
|
-
// "comma-dangle": "off",
|
|
105
|
-
// "no-multi-spaces": "off",
|
|
106
|
-
// "quotes": "off",
|
|
107
|
-
// "keyword-spacing": "off",
|
|
108
|
-
// "no-mixed-operators": "off",
|
|
109
|
-
// "comma-spacing": "off",
|
|
110
|
-
// "no-trailing-spaces": "off",
|
|
111
|
-
// "key-spacing": "off",
|
|
112
|
-
// "no-multiple-empty-lines": "off",
|
|
113
|
-
// "spaced-comment": "off",
|
|
114
|
-
// "space-in-parens": "off",
|
|
115
|
-
// "block-spacing": "off",
|
|
116
|
-
// "quote-props": "off",
|
|
117
|
-
// "space-unary-ops": "off",
|
|
118
|
-
// "no-empty": "off",
|
|
119
|
-
// "dot-notation": "off",
|
|
120
|
-
// "func-call-spacing": "off",
|
|
121
|
-
// "array-bracket-spacing": "off",
|
|
122
|
-
// "object-property-newline": "off",
|
|
123
|
-
// "no-continue": "off",
|
|
124
|
-
// "no-extra-semi": "off",
|
|
125
|
-
// "no-spaced-func": "off",
|
|
126
|
-
// "no-useless-return": "off"
|
|
127
|
-
}
|
|
2
|
+
"extends": "nodebb"
|
|
128
3
|
}
|
package/index.js
CHANGED
|
@@ -23,10 +23,13 @@ let parser;
|
|
|
23
23
|
const Markdown = {
|
|
24
24
|
config: {},
|
|
25
25
|
_externalImageCache: undefined,
|
|
26
|
+
_externalImageFailures: new Set(),
|
|
26
27
|
onLoad: async function (params) {
|
|
27
28
|
const controllers = require('./lib/controllers');
|
|
28
29
|
const hostMiddleware = require.main.require('./src/middleware');
|
|
29
|
-
const middlewares = [
|
|
30
|
+
const middlewares = [
|
|
31
|
+
hostMiddleware.maintenanceMode, hostMiddleware.registrationComplete, hostMiddleware.pluginHooks,
|
|
32
|
+
];
|
|
30
33
|
|
|
31
34
|
params.router.get('/admin/plugins/markdown', params.middleware.admin.buildHeader, controllers.renderAdmin);
|
|
32
35
|
params.router.get('/api/admin/plugins/markdown', controllers.renderAdmin);
|
|
@@ -46,7 +49,7 @@ const Markdown = {
|
|
|
46
49
|
config.markdown = {
|
|
47
50
|
highlight: Markdown.highlight ? 1 : 0,
|
|
48
51
|
highlightLinesLanguageList: Markdown.config.highlightLinesLanguageList,
|
|
49
|
-
theme: highlightTheme || 'default.
|
|
52
|
+
theme: highlightTheme || 'default.css',
|
|
50
53
|
defaultHighlightLanguage: defaultHighlightLanguage || '',
|
|
51
54
|
};
|
|
52
55
|
|
|
@@ -59,13 +62,10 @@ const Markdown = {
|
|
|
59
62
|
hookData.links.push({
|
|
60
63
|
rel: 'prefetch stylesheet',
|
|
61
64
|
type: '',
|
|
62
|
-
href: `${nconf.get('relative_path')}/assets/plugins/nodebb-plugin-markdown/
|
|
65
|
+
href: `${nconf.get('relative_path')}/assets/plugins/nodebb-plugin-markdown/styles/${highlightTheme || 'default.css'}`,
|
|
63
66
|
}, {
|
|
64
67
|
rel: 'prefetch',
|
|
65
68
|
href: `${nconf.get('relative_path')}/assets/language/${meta.config.defaultLang || 'en-GB'}/markdown.json?${meta.config['cache-buster']}`,
|
|
66
|
-
}, {
|
|
67
|
-
rel: 'prefetch',
|
|
68
|
-
href: `${nconf.get('relative_path')}/assets/src/modules/highlight.js`,
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
return hookData;
|
|
@@ -80,7 +80,7 @@ const Markdown = {
|
|
|
80
80
|
langPrefix: 'language-',
|
|
81
81
|
highlight: true,
|
|
82
82
|
highlightLinesLanguageList: [],
|
|
83
|
-
highlightTheme: 'default.
|
|
83
|
+
highlightTheme: 'default.css',
|
|
84
84
|
|
|
85
85
|
probe: true,
|
|
86
86
|
probeCacheSize: 256,
|
|
@@ -97,12 +97,12 @@ const Markdown = {
|
|
|
97
97
|
};
|
|
98
98
|
const notCheckboxes = ['langPrefix', 'highlightTheme', 'highlightLinesLanguageList', 'probeCacheSize'];
|
|
99
99
|
|
|
100
|
-
meta.settings.get('markdown',
|
|
100
|
+
meta.settings.get('markdown', (err, options) => {
|
|
101
101
|
if (err) {
|
|
102
102
|
winston.warn(`[plugin/markdown] Unable to retrieve settings, assuming defaults: ${err.message}`);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
Object.keys(defaults).forEach((field) => {
|
|
106
106
|
// If not set in config (nil)
|
|
107
107
|
if (!options.hasOwnProperty(field)) {
|
|
108
108
|
_self.config[field] = defaults[field];
|
|
@@ -111,7 +111,7 @@ const Markdown = {
|
|
|
111
111
|
} else {
|
|
112
112
|
_self.config[field] = options[field];
|
|
113
113
|
}
|
|
114
|
-
}
|
|
114
|
+
});
|
|
115
115
|
|
|
116
116
|
_self.highlight = _self.config.highlight;
|
|
117
117
|
delete _self.config.highlight;
|
|
@@ -137,7 +137,7 @@ const Markdown = {
|
|
|
137
137
|
name: 'markdown.externalImageCache',
|
|
138
138
|
max: parseInt(_self.config.probeCacheSize, 10) || 256,
|
|
139
139
|
length: function () { return 1; },
|
|
140
|
-
maxAge: 1000 * 60 * 60 * 24,
|
|
140
|
+
maxAge: 1000 * 60 * 60 * 24, // 1 day
|
|
141
141
|
});
|
|
142
142
|
}
|
|
143
143
|
});
|
|
@@ -145,13 +145,11 @@ const Markdown = {
|
|
|
145
145
|
|
|
146
146
|
loadThemes: async () => {
|
|
147
147
|
try {
|
|
148
|
-
const files = await fs.promises.readdir(path.
|
|
148
|
+
const files = await fs.promises.readdir(path.join(require.resolve('highlight.js'), '../../styles'));
|
|
149
149
|
const isStylesheet = /\.css$/;
|
|
150
|
-
Markdown.themes = files.filter(
|
|
151
|
-
return isStylesheet.test(file);
|
|
152
|
-
});
|
|
150
|
+
Markdown.themes = files.filter(file => isStylesheet.test(file));
|
|
153
151
|
} catch (err) {
|
|
154
|
-
winston.error(
|
|
152
|
+
winston.error(`[plugin/markdown] Could not load Markdown themes: ${err.message}`);
|
|
155
153
|
Markdown.themes = [];
|
|
156
154
|
}
|
|
157
155
|
},
|
|
@@ -205,17 +203,24 @@ const Markdown = {
|
|
|
205
203
|
// eslint-disable-next-line no-cond-assign
|
|
206
204
|
while ((current = matcher.exec(data.postData.content)) !== null) {
|
|
207
205
|
const match = current[1];
|
|
208
|
-
if (match && Markdown.isExternalLink(match)) {
|
|
206
|
+
if (match && Markdown.isExternalLink(match)) { // for security only parse external images
|
|
209
207
|
const parsedUrl = url.parse(match);
|
|
210
208
|
const filename = path.basename(parsedUrl.pathname);
|
|
211
209
|
const size = Markdown._externalImageCache.get(match);
|
|
210
|
+
|
|
211
|
+
// Short-circuit to ignore previous failures
|
|
212
|
+
const hasFailed = Markdown._externalImageFailures.has(match);
|
|
213
|
+
if (hasFailed) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
212
217
|
if (size) {
|
|
213
218
|
env.images.set(filename, size);
|
|
214
219
|
} else {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
// Size checked asynchronously, see: https://github.com/tomas/needle/issues/389
|
|
221
|
+
probe(match, {
|
|
222
|
+
follow_max: 2,
|
|
223
|
+
}).then((size) => {
|
|
219
224
|
let { width, height } = size;
|
|
220
225
|
|
|
221
226
|
// Swap width and height if orientation bit is set
|
|
@@ -223,11 +228,11 @@ const Markdown = {
|
|
|
223
228
|
[width, height] = [height, width];
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
env.images.set(filename, { width, height });
|
|
227
231
|
Markdown._externalImageCache.set(match, { width, height });
|
|
228
|
-
}
|
|
229
|
-
//
|
|
230
|
-
|
|
232
|
+
}).catch(() => {
|
|
233
|
+
// Likely an issue getting the external image size, ignore in the future
|
|
234
|
+
Markdown._externalImageFailures.add(match);
|
|
235
|
+
});
|
|
231
236
|
}
|
|
232
237
|
}
|
|
233
238
|
}
|
|
@@ -245,13 +250,9 @@ const Markdown = {
|
|
|
245
250
|
const execute = function (html) {
|
|
246
251
|
// Replace all italicised mentions back to regular mentions
|
|
247
252
|
if (italicMention.test(html)) {
|
|
248
|
-
html = html.replace(italicMention,
|
|
249
|
-
return '@_' + slug + '_';
|
|
250
|
-
});
|
|
253
|
+
html = html.replace(italicMention, (match, slug) => `@_${slug}_`);
|
|
251
254
|
} else if (boldMention.test(html)) {
|
|
252
|
-
html = html.replace(boldMention,
|
|
253
|
-
return '@__' + slug + '__';
|
|
254
|
-
});
|
|
255
|
+
html = html.replace(boldMention, (match, slug) => `@__${slug}__`);
|
|
255
256
|
}
|
|
256
257
|
|
|
257
258
|
return html;
|
|
@@ -330,12 +331,15 @@ const Markdown = {
|
|
|
330
331
|
|
|
331
332
|
// Update renderer to add some classes to all images
|
|
332
333
|
const renderImage = parser.renderer.rules.image || function (tokens, idx, options, env, self) {
|
|
334
|
+
// eslint-disable-next-line prefer-spread,prefer-rest-params
|
|
333
335
|
return self.renderToken.apply(self, arguments);
|
|
334
336
|
};
|
|
335
337
|
const renderLink = parser.renderer.rules.link_open || function (tokens, idx, options, env, self) {
|
|
338
|
+
// eslint-disable-next-line prefer-spread,prefer-rest-params
|
|
336
339
|
return self.renderToken.apply(self, arguments);
|
|
337
340
|
};
|
|
338
341
|
const renderTable = parser.renderer.rules.table_open || function (tokens, idx, options, env, self) {
|
|
342
|
+
// eslint-disable-next-line prefer-spread,prefer-rest-params
|
|
339
343
|
return self.renderToken.apply(self, arguments);
|
|
340
344
|
};
|
|
341
345
|
|
|
@@ -347,7 +351,7 @@ const Markdown = {
|
|
|
347
351
|
// Validate the url
|
|
348
352
|
if (!Markdown.isUrlValid(attributes.get('src'))) { return ''; }
|
|
349
353
|
|
|
350
|
-
token.attrSet('class',
|
|
354
|
+
token.attrSet('class', `${token.attrGet('class') || ''} img-responsive img-markdown`);
|
|
351
355
|
|
|
352
356
|
// Append sizes to images
|
|
353
357
|
if (parsedSrc.pathname) {
|
|
@@ -428,7 +432,7 @@ const Markdown = {
|
|
|
428
432
|
* get updated.
|
|
429
433
|
*/
|
|
430
434
|
const allowedRoots = [nconf.get('upload_url'), '/uploads'];
|
|
431
|
-
const allowed =
|
|
435
|
+
const allowed = pathname => allowedRoots.some(root => pathname.toString().startsWith(root) || pathname.toString().startsWith(nconf.get('relative_path') + root));
|
|
432
436
|
|
|
433
437
|
try {
|
|
434
438
|
const urlObj = url.parse(src, false, true);
|
|
@@ -449,9 +453,12 @@ const Markdown = {
|
|
|
449
453
|
}
|
|
450
454
|
|
|
451
455
|
if (
|
|
452
|
-
urlObj.host === null
|
|
453
|
-
|
|
454
|
-
|
|
456
|
+
urlObj.host === null || // Relative paths are always internal links...
|
|
457
|
+
(
|
|
458
|
+
urlObj.host === baseUrlObj.host &&
|
|
459
|
+
urlObj.protocol === baseUrlObj.protocol && // Otherwise need to check that protocol and host match
|
|
460
|
+
(nconf.get('relative_path').length > 0 ? urlObj.pathname.indexOf(nconf.get('relative_path')) === 0 : true) // Subfolder installs need this additional check
|
|
461
|
+
)
|
|
455
462
|
) {
|
|
456
463
|
return false;
|
|
457
464
|
}
|
package/lib/controllers.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-markdown",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "10.0.0",
|
|
4
4
|
"description": "A Markdown parser for NodeBB",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"husky": {
|
|
21
21
|
"hooks": {
|
|
22
|
-
"pre-commit": "lint-staged",
|
|
23
|
-
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
|
22
|
+
"pre-commit": "npx lint-staged",
|
|
23
|
+
"commit-msg": "npx commitlint -E HUSKY_GIT_PARAMS"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"lint-staged": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
]
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"
|
|
32
|
+
"highlight.js": "11.4.0",
|
|
33
33
|
"highlightjs-line-numbers.js": "^2.8.0",
|
|
34
34
|
"markdown-it": "^12.0.6",
|
|
35
35
|
"markdown-it-checkbox": "^1.1.0",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"probe-image-size": "^7.2.1"
|
|
38
38
|
},
|
|
39
39
|
"nbbpm": {
|
|
40
|
-
"compatibility": "^
|
|
40
|
+
"compatibility": "^2.0.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@commitlint/cli": "16.2.1",
|
|
44
44
|
"@commitlint/config-angular": "16.2.1",
|
|
45
|
-
"eslint": "8.
|
|
46
|
-
"eslint-config-
|
|
47
|
-
"eslint-plugin-import": "2.
|
|
45
|
+
"eslint": "8.x",
|
|
46
|
+
"eslint-config-nodebb": "0.1.1",
|
|
47
|
+
"eslint-plugin-import": "2.x",
|
|
48
48
|
"husky": "7.0.4",
|
|
49
|
-
"lint-staged": "12.3.
|
|
49
|
+
"lint-staged": "12.3.5"
|
|
50
50
|
}
|
|
51
51
|
}
|
package/plugin.json
CHANGED
|
@@ -11,11 +11,9 @@
|
|
|
11
11
|
"public/js/client.js"
|
|
12
12
|
],
|
|
13
13
|
"staticDirs": {
|
|
14
|
-
"
|
|
14
|
+
"styles": "node_modules/highlight.js/styles"
|
|
15
15
|
},
|
|
16
16
|
"modules": {
|
|
17
|
-
"highlight.js": "../@highlightjs/cdn-assets/highlight.min.js",
|
|
18
|
-
"highlightjs-line-numbers.js": "./public/js/highlightjs-line-numbers.js",
|
|
19
17
|
"../admin/plugins/markdown.js": "./public/js/admin.js"
|
|
20
18
|
},
|
|
21
19
|
"languages": "public/languages",
|
|
@@ -36,6 +34,7 @@
|
|
|
36
34
|
{ "hook": "filter:sanitize.config", "method": "updateSanitizeConfig" }
|
|
37
35
|
],
|
|
38
36
|
"upgrades": [
|
|
39
|
-
"upgrades/reset_md_hljs_theme.js"
|
|
37
|
+
"upgrades/reset_md_hljs_theme.js",
|
|
38
|
+
"upgrades/use_unminified_hljs_theme.js"
|
|
40
39
|
]
|
|
41
40
|
}
|
package/public/js/admin.js
CHANGED
|
@@ -17,7 +17,7 @@ define('admin/plugins/markdown', ['settings', 'alerts'], function (Settings, ale
|
|
|
17
17
|
langPrefix: 'language-',
|
|
18
18
|
highlight: true,
|
|
19
19
|
highlightLinesLanguageList: [],
|
|
20
|
-
highlightTheme: 'default.
|
|
20
|
+
highlightTheme: 'default.css',
|
|
21
21
|
|
|
22
22
|
probe: true,
|
|
23
23
|
probeCacheSize: 256,
|
package/public/js/client.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
/* global window, jQuery, $, config, socket */
|
|
4
|
-
|
|
5
3
|
(function () {
|
|
6
4
|
var Markdown = {};
|
|
7
5
|
|
|
@@ -33,13 +31,14 @@
|
|
|
33
31
|
// Otherwise, edit the post to reflect state change
|
|
34
32
|
var _this = this;
|
|
35
33
|
var pid = $(this).parents('li[data-pid]').attr('data-pid');
|
|
36
|
-
var index = $(this).parents('.content').find('input[type="checkbox"]').toArray()
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
var index = $(this).parents('.content').find('input[type="checkbox"]').toArray()
|
|
35
|
+
.reduce(function (memo, cur, index) {
|
|
36
|
+
if (cur === _this) {
|
|
37
|
+
memo = index;
|
|
38
|
+
}
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
return memo;
|
|
41
|
+
}, null);
|
|
43
42
|
|
|
44
43
|
socket.emit('plugins.markdown.checkbox.edit', {
|
|
45
44
|
pid: pid,
|
|
@@ -119,11 +118,15 @@
|
|
|
119
118
|
controls.updateTextareaSelection(textarea, selectionStart + 2, selectionStart + 2);
|
|
120
119
|
} else {
|
|
121
120
|
controls.insertIntoTextarea(textarea, '**' + strings.bold + '**');
|
|
122
|
-
controls.updateTextareaSelection(
|
|
121
|
+
controls.updateTextareaSelection(
|
|
122
|
+
textarea, selectionStart + 2, selectionStart + strings.bold.length + 2
|
|
123
|
+
);
|
|
123
124
|
}
|
|
124
125
|
} else {
|
|
125
126
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '**');
|
|
126
|
-
controls.updateTextareaSelection(
|
|
127
|
+
controls.updateTextareaSelection(
|
|
128
|
+
textarea, selectionStart + 2 + wrapDelta[0], selectionEnd + 2 - wrapDelta[1]
|
|
129
|
+
);
|
|
127
130
|
}
|
|
128
131
|
});
|
|
129
132
|
|
|
@@ -136,11 +139,15 @@
|
|
|
136
139
|
controls.updateTextareaSelection(textarea, selectionStart + 1, selectionStart + 1);
|
|
137
140
|
} else {
|
|
138
141
|
controls.insertIntoTextarea(textarea, '*' + strings.italic + '*');
|
|
139
|
-
controls.updateTextareaSelection(
|
|
142
|
+
controls.updateTextareaSelection(
|
|
143
|
+
textarea, selectionStart + 1, selectionStart + strings.italic.length + 1
|
|
144
|
+
);
|
|
140
145
|
}
|
|
141
146
|
} else {
|
|
142
147
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '*');
|
|
143
|
-
controls.updateTextareaSelection(
|
|
148
|
+
controls.updateTextareaSelection(
|
|
149
|
+
textarea, selectionStart + 1 + wrapDelta[0], selectionEnd + 1 - wrapDelta[1]
|
|
150
|
+
);
|
|
144
151
|
}
|
|
145
152
|
});
|
|
146
153
|
|
|
@@ -149,10 +156,14 @@
|
|
|
149
156
|
controls.insertIntoTextarea(textarea, '\n* ' + strings.list_item);
|
|
150
157
|
|
|
151
158
|
// Highlight "list item"
|
|
152
|
-
controls.updateTextareaSelection(
|
|
159
|
+
controls.updateTextareaSelection(
|
|
160
|
+
textarea, selectionStart + 3, selectionStart + strings.list_item.length + 3
|
|
161
|
+
);
|
|
153
162
|
} else {
|
|
154
163
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '\n* ', '');
|
|
155
|
-
controls.updateTextareaSelection(
|
|
164
|
+
controls.updateTextareaSelection(
|
|
165
|
+
textarea, selectionStart + 3 + wrapDelta[0], selectionEnd + 3 - wrapDelta[1]
|
|
166
|
+
);
|
|
156
167
|
}
|
|
157
168
|
});
|
|
158
169
|
|
|
@@ -165,41 +176,61 @@
|
|
|
165
176
|
controls.updateTextareaSelection(textarea, selectionStart + 2, selectionStart + 2);
|
|
166
177
|
} else {
|
|
167
178
|
controls.insertIntoTextarea(textarea, '~~' + strings.strikethrough_text + '~~');
|
|
168
|
-
controls.updateTextareaSelection(
|
|
179
|
+
controls.updateTextareaSelection(
|
|
180
|
+
textarea, selectionStart + 2, selectionEnd + strings.strikethrough_text.length + 2
|
|
181
|
+
);
|
|
169
182
|
}
|
|
170
183
|
} else {
|
|
171
184
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '~~', '~~');
|
|
172
|
-
controls.updateTextareaSelection(
|
|
185
|
+
controls.updateTextareaSelection(
|
|
186
|
+
textarea, selectionStart + 2 + wrapDelta[0], selectionEnd + 2 - wrapDelta[1]
|
|
187
|
+
);
|
|
173
188
|
}
|
|
174
189
|
});
|
|
175
190
|
|
|
176
191
|
formatting.addButtonDispatch('code', function (textarea, selectionStart, selectionEnd) {
|
|
177
192
|
if (selectionStart === selectionEnd) {
|
|
178
193
|
controls.insertIntoTextarea(textarea, '```\n' + strings.code_text + '\n```');
|
|
179
|
-
controls.updateTextareaSelection(
|
|
194
|
+
controls.updateTextareaSelection(
|
|
195
|
+
textarea, selectionStart + 4, selectionEnd + strings.code_text.length + 4
|
|
196
|
+
);
|
|
180
197
|
} else {
|
|
181
198
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '```\n', '\n```');
|
|
182
|
-
controls.updateTextareaSelection(
|
|
199
|
+
controls.updateTextareaSelection(
|
|
200
|
+
textarea, selectionStart + 4 + wrapDelta[0], selectionEnd + 4 - wrapDelta[1]
|
|
201
|
+
);
|
|
183
202
|
}
|
|
184
203
|
});
|
|
185
204
|
|
|
186
205
|
formatting.addButtonDispatch('link', function (textarea, selectionStart, selectionEnd) {
|
|
187
206
|
if (selectionStart === selectionEnd) {
|
|
188
207
|
controls.insertIntoTextarea(textarea, '[' + strings.link_text + '](' + strings.link_url + ')');
|
|
189
|
-
controls.updateTextareaSelection(
|
|
208
|
+
controls.updateTextareaSelection(
|
|
209
|
+
textarea,
|
|
210
|
+
selectionStart + strings.link_text.length + 3,
|
|
211
|
+
selectionEnd + strings.link_text.length + strings.link_url.length + 3
|
|
212
|
+
);
|
|
190
213
|
} else {
|
|
191
214
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '[', '](' + strings.link_url + ')');
|
|
192
|
-
controls.updateTextareaSelection(
|
|
215
|
+
controls.updateTextareaSelection(
|
|
216
|
+
textarea, selectionEnd + 3 - wrapDelta[1], selectionEnd + strings.link_url.length + 3 - wrapDelta[1]
|
|
217
|
+
);
|
|
193
218
|
}
|
|
194
219
|
});
|
|
195
220
|
|
|
196
221
|
formatting.addButtonDispatch('picture-o', function (textarea, selectionStart, selectionEnd) {
|
|
197
222
|
if (selectionStart === selectionEnd) {
|
|
198
223
|
controls.insertIntoTextarea(textarea, '');
|
|
199
|
-
controls.updateTextareaSelection(
|
|
224
|
+
controls.updateTextareaSelection(
|
|
225
|
+
textarea,
|
|
226
|
+
selectionStart + strings.picture_text.length + 4,
|
|
227
|
+
selectionEnd + strings.picture_text.length + strings.picture_url.length + 4
|
|
228
|
+
);
|
|
200
229
|
} else {
|
|
201
230
|
var wrapDelta = controls.wrapSelectionInTextareaWith(textarea, '');
|
|
202
|
-
controls.updateTextareaSelection(
|
|
231
|
+
controls.updateTextareaSelection(
|
|
232
|
+
textarea, selectionEnd + 4 - wrapDelta[1], selectionEnd + strings.picture_url.length + 4 - wrapDelta[1]
|
|
233
|
+
);
|
|
203
234
|
}
|
|
204
235
|
});
|
|
205
236
|
});
|
|
@@ -207,30 +238,32 @@
|
|
|
207
238
|
});
|
|
208
239
|
};
|
|
209
240
|
|
|
210
|
-
function highlight(elements) {
|
|
241
|
+
async function highlight(elements) {
|
|
211
242
|
if (parseInt(config.markdown.highlight, 10)) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
243
|
+
const { default: hljs } = await import('highlight.js/lib/common');
|
|
244
|
+
window.hljs = hljs;
|
|
245
|
+
require('highlightjs-line-numbers.js');
|
|
215
246
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
block.classList.add(`language-${config.markdown.defaultHighlightLanguage}`);
|
|
219
|
-
}
|
|
247
|
+
elements.each(function (i, block) {
|
|
248
|
+
$(block.parentNode).addClass('markdown-highlight');
|
|
220
249
|
|
|
221
|
-
|
|
250
|
+
// Default language if set in ACP
|
|
251
|
+
if (!Array.prototype.some.call(block.classList, (className) => className.startsWith('language-')) && config.markdown.defaultHighlightLanguage) {
|
|
252
|
+
block.classList.add(`language-${config.markdown.defaultHighlightLanguage}`);
|
|
253
|
+
}
|
|
222
254
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}).some(Boolean)) {
|
|
230
|
-
$(block).attr('data-lines', 1);
|
|
231
|
-
window.hljs.lineNumbersBlock(block);
|
|
255
|
+
window.hljs.highlightElement(block);
|
|
256
|
+
|
|
257
|
+
// Check detected language against whitelist and add lines if enabled
|
|
258
|
+
if (block.className.split(' ').map(function (className) {
|
|
259
|
+
if (className.indexOf('language-') === 0) {
|
|
260
|
+
className = className.slice(9);
|
|
232
261
|
}
|
|
233
|
-
|
|
262
|
+
return config.markdown.highlightLinesLanguageList.includes(className) || config.markdown.highlightLinesLanguageList.includes(className);
|
|
263
|
+
}).some(Boolean)) {
|
|
264
|
+
$(block).attr('data-lines', 1);
|
|
265
|
+
window.hljs.lineNumbersBlock(block);
|
|
266
|
+
}
|
|
234
267
|
});
|
|
235
268
|
}
|
|
236
269
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const meta = require.main.require('./src/meta');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
name: 'Update Markdown Theme to point to unminified file',
|
|
7
|
+
timestamp: Date.UTC(2022, 1, 17),
|
|
8
|
+
method: async () => {
|
|
9
|
+
const { highlightTheme } = await meta.settings.get('markdown');
|
|
10
|
+
if (highlightTheme) {
|
|
11
|
+
await meta.settings.setOne('markdown', 'highlightTheme', highlightTheme.replace('.min.css', '.css'));
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
};
|
package/.eslintignore
DELETED
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* STOP! This file was edited from the version found in the repo
|
|
3
|
-
* https://github.com/wcoder/highlightjs-line-numbers.js
|
|
4
|
-
*
|
|
5
|
-
* Changes:
|
|
6
|
-
* - Made into a requirejs module
|
|
7
|
-
* - Instead of passing window, document in as w and d, they
|
|
8
|
-
* are defined at top of module
|
|
9
|
-
*/
|
|
10
|
-
define('highlightjs-line-numbers', ['highlight'], function () {
|
|
11
|
-
var w = window;
|
|
12
|
-
var d = document;
|
|
13
|
-
|
|
14
|
-
var TABLE_NAME = 'hljs-ln',
|
|
15
|
-
LINE_NAME = 'hljs-ln-line',
|
|
16
|
-
CODE_BLOCK_NAME = 'hljs-ln-code',
|
|
17
|
-
NUMBERS_BLOCK_NAME = 'hljs-ln-numbers',
|
|
18
|
-
NUMBER_LINE_NAME = 'hljs-ln-n',
|
|
19
|
-
DATA_ATTR_NAME = 'data-line-number',
|
|
20
|
-
BREAK_LINE_REGEXP = /\r\n|\r|\n/g;
|
|
21
|
-
|
|
22
|
-
if (w.hljs) {
|
|
23
|
-
w.hljs.initLineNumbersOnLoad = initLineNumbersOnLoad;
|
|
24
|
-
w.hljs.lineNumbersBlock = lineNumbersBlock;
|
|
25
|
-
w.hljs.lineNumbersValue = lineNumbersValue;
|
|
26
|
-
|
|
27
|
-
addStyles();
|
|
28
|
-
} else {
|
|
29
|
-
w.console.error('highlight.js not detected!');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function isHljsLnCodeDescendant(domElt) {
|
|
33
|
-
var curElt = domElt;
|
|
34
|
-
while (curElt) {
|
|
35
|
-
if (curElt.className && curElt.className.indexOf('hljs-ln-code') !== -1) {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
curElt = curElt.parentNode;
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getHljsLnTable(hljsLnDomElt) {
|
|
44
|
-
var curElt = hljsLnDomElt;
|
|
45
|
-
while (curElt.nodeName !== 'TABLE') {
|
|
46
|
-
curElt = curElt.parentNode;
|
|
47
|
-
}
|
|
48
|
-
return curElt;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Function to workaround a copy issue with Microsoft Edge.
|
|
52
|
-
// Due to hljs-ln wrapping the lines of code inside a <table> element,
|
|
53
|
-
// itself wrapped inside a <pre> element, window.getSelection().toString()
|
|
54
|
-
// does not contain any line breaks. So we need to get them back using the
|
|
55
|
-
// rendered code in the DOM as reference.
|
|
56
|
-
function edgeGetSelectedCodeLines(selection) {
|
|
57
|
-
// current selected text without line breaks
|
|
58
|
-
var selectionText = selection.toString();
|
|
59
|
-
|
|
60
|
-
// get the <td> element wrapping the first line of selected code
|
|
61
|
-
var tdAnchor = selection.anchorNode;
|
|
62
|
-
while (tdAnchor.nodeName !== 'TD') {
|
|
63
|
-
tdAnchor = tdAnchor.parentNode;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// get the <td> element wrapping the last line of selected code
|
|
67
|
-
var tdFocus = selection.focusNode;
|
|
68
|
-
while (tdFocus.nodeName !== 'TD') {
|
|
69
|
-
tdFocus = tdFocus.parentNode;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// extract line numbers
|
|
73
|
-
var firstLineNumber = parseInt(tdAnchor.dataset.lineNumber);
|
|
74
|
-
var lastLineNumber = parseInt(tdFocus.dataset.lineNumber);
|
|
75
|
-
|
|
76
|
-
// multi-lines copied case
|
|
77
|
-
if (firstLineNumber != lastLineNumber) {
|
|
78
|
-
|
|
79
|
-
var firstLineText = tdAnchor.textContent;
|
|
80
|
-
var lastLineText = tdFocus.textContent;
|
|
81
|
-
|
|
82
|
-
// if the selection was made backward, swap values
|
|
83
|
-
if (firstLineNumber > lastLineNumber) {
|
|
84
|
-
var tmp = firstLineNumber;
|
|
85
|
-
firstLineNumber = lastLineNumber;
|
|
86
|
-
lastLineNumber = tmp;
|
|
87
|
-
tmp = firstLineText;
|
|
88
|
-
firstLineText = lastLineText;
|
|
89
|
-
lastLineText = tmp;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// discard not copied characters in first line
|
|
93
|
-
while (selectionText.indexOf(firstLineText) !== 0) {
|
|
94
|
-
firstLineText = firstLineText.slice(1);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// discard not copied characters in last line
|
|
98
|
-
while (selectionText.lastIndexOf(lastLineText) === -1) {
|
|
99
|
-
lastLineText = lastLineText.slice(0, -1);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// reconstruct and return the real copied text
|
|
103
|
-
var selectedText = firstLineText;
|
|
104
|
-
var hljsLnTable = getHljsLnTable(tdAnchor);
|
|
105
|
-
for (var i = firstLineNumber + 1 ; i < lastLineNumber ; ++i) {
|
|
106
|
-
var codeLineSel = format('.{0}[{1}="{2}"]', [CODE_BLOCK_NAME, DATA_ATTR_NAME, i]);
|
|
107
|
-
var codeLineElt = hljsLnTable.querySelector(codeLineSel);
|
|
108
|
-
selectedText += '\n' + codeLineElt.textContent;
|
|
109
|
-
}
|
|
110
|
-
selectedText += '\n' + lastLineText;
|
|
111
|
-
return selectedText;
|
|
112
|
-
// single copied line case
|
|
113
|
-
} else {
|
|
114
|
-
return selectionText;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// ensure consistent code copy/paste behavior across all browsers
|
|
119
|
-
// (see https://github.com/wcoder/highlightjs-line-numbers.js/issues/51)
|
|
120
|
-
document.addEventListener('copy', function(e) {
|
|
121
|
-
// get current selection
|
|
122
|
-
var selection = window.getSelection();
|
|
123
|
-
// override behavior when one wants to copy line of codes
|
|
124
|
-
if (isHljsLnCodeDescendant(selection.anchorNode)) {
|
|
125
|
-
var selectionText;
|
|
126
|
-
// workaround an issue with Microsoft Edge as copied line breaks
|
|
127
|
-
// are removed otherwise from the selection string
|
|
128
|
-
if (window.navigator.userAgent.indexOf('Edge') !== -1) {
|
|
129
|
-
selectionText = edgeGetSelectedCodeLines(selection);
|
|
130
|
-
} else {
|
|
131
|
-
// other browsers can directly use the selection string
|
|
132
|
-
selectionText = selection.toString();
|
|
133
|
-
}
|
|
134
|
-
e.clipboardData.setData('text/plain', selectionText);
|
|
135
|
-
e.preventDefault();
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
function addStyles () {
|
|
140
|
-
var css = d.createElement('style');
|
|
141
|
-
css.type = 'text/css';
|
|
142
|
-
css.innerHTML = format(
|
|
143
|
-
'.{0}{border-collapse:collapse}' +
|
|
144
|
-
'.{0} td{padding:0}' +
|
|
145
|
-
'.{1}:before{content:attr({2})}',
|
|
146
|
-
[
|
|
147
|
-
TABLE_NAME,
|
|
148
|
-
NUMBER_LINE_NAME,
|
|
149
|
-
DATA_ATTR_NAME
|
|
150
|
-
]);
|
|
151
|
-
d.getElementsByTagName('head')[0].appendChild(css);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function initLineNumbersOnLoad (options) {
|
|
155
|
-
if (d.readyState === 'interactive' || d.readyState === 'complete') {
|
|
156
|
-
documentReady(options);
|
|
157
|
-
} else {
|
|
158
|
-
w.addEventListener('DOMContentLoaded', function () {
|
|
159
|
-
documentReady(options);
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function documentReady (options) {
|
|
165
|
-
try {
|
|
166
|
-
var blocks = d.querySelectorAll('code.hljs,code.nohighlight');
|
|
167
|
-
|
|
168
|
-
for (var i in blocks) {
|
|
169
|
-
if (blocks.hasOwnProperty(i)) {
|
|
170
|
-
if (!isPluginDisabledForBlock(blocks[i])) {
|
|
171
|
-
lineNumbersBlock(blocks[i], options);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
} catch (e) {
|
|
176
|
-
w.console.error('LineNumbers error: ', e);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function isPluginDisabledForBlock(element) {
|
|
181
|
-
return element.classList.contains('nohljsln');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function lineNumbersBlock (element, options) {
|
|
185
|
-
if (typeof element !== 'object') return;
|
|
186
|
-
|
|
187
|
-
async(function () {
|
|
188
|
-
element.innerHTML = lineNumbersInternal(element, options);
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function lineNumbersValue (value, options) {
|
|
193
|
-
if (typeof value !== 'string') return;
|
|
194
|
-
|
|
195
|
-
var element = document.createElement('code')
|
|
196
|
-
element.innerHTML = value
|
|
197
|
-
|
|
198
|
-
return lineNumbersInternal(element, options);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function lineNumbersInternal (element, options) {
|
|
202
|
-
|
|
203
|
-
var internalOptions = mapOptions(element, options);
|
|
204
|
-
|
|
205
|
-
duplicateMultilineNodes(element);
|
|
206
|
-
|
|
207
|
-
return addLineNumbersBlockFor(element.innerHTML, internalOptions);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function addLineNumbersBlockFor (inputHtml, options) {
|
|
211
|
-
var lines = getLines(inputHtml);
|
|
212
|
-
|
|
213
|
-
// if last line contains only carriage return remove it
|
|
214
|
-
if (lines[lines.length-1].trim() === '') {
|
|
215
|
-
lines.pop();
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (lines.length > 1 || options.singleLine) {
|
|
219
|
-
var html = '';
|
|
220
|
-
|
|
221
|
-
for (var i = 0, l = lines.length; i < l; i++) {
|
|
222
|
-
html += format(
|
|
223
|
-
'<tr>' +
|
|
224
|
-
'<td class="{0} {1}" {3}="{5}">' +
|
|
225
|
-
'<div class="{2}" {3}="{5}"></div>' +
|
|
226
|
-
'</td>' +
|
|
227
|
-
'<td class="{0} {4}" {3}="{5}">' +
|
|
228
|
-
'{6}' +
|
|
229
|
-
'</td>' +
|
|
230
|
-
'</tr>',
|
|
231
|
-
[
|
|
232
|
-
LINE_NAME,
|
|
233
|
-
NUMBERS_BLOCK_NAME,
|
|
234
|
-
NUMBER_LINE_NAME,
|
|
235
|
-
DATA_ATTR_NAME,
|
|
236
|
-
CODE_BLOCK_NAME,
|
|
237
|
-
i + options.startFrom,
|
|
238
|
-
lines[i].length > 0 ? lines[i] : ' '
|
|
239
|
-
]);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
return format('<table class="{0}">{1}</table>', [ TABLE_NAME, html ]);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return inputHtml;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* @param {HTMLElement} element Code block.
|
|
250
|
-
* @param {Object} options External API options.
|
|
251
|
-
* @returns {Object} Internal API options.
|
|
252
|
-
*/
|
|
253
|
-
function mapOptions (element, options) {
|
|
254
|
-
options = options || {};
|
|
255
|
-
return {
|
|
256
|
-
singleLine: getSingleLineOption(options),
|
|
257
|
-
startFrom: getStartFromOption(element, options)
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function getSingleLineOption (options) {
|
|
262
|
-
var defaultValue = false;
|
|
263
|
-
if (!!options.singleLine) {
|
|
264
|
-
return options.singleLine;
|
|
265
|
-
}
|
|
266
|
-
return defaultValue;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function getStartFromOption (element, options) {
|
|
270
|
-
var defaultValue = 1;
|
|
271
|
-
var startFrom = defaultValue;
|
|
272
|
-
|
|
273
|
-
if (isFinite(options.startFrom)) {
|
|
274
|
-
startFrom = options.startFrom;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// can be overridden because local option is priority
|
|
278
|
-
var value = getAttribute(element, 'data-ln-start-from');
|
|
279
|
-
if (value !== null) {
|
|
280
|
-
startFrom = toNumber(value, defaultValue);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return startFrom;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Recursive method for fix multi-line elements implementation in highlight.js
|
|
288
|
-
* Doing deep passage on child nodes.
|
|
289
|
-
* @param {HTMLElement} element
|
|
290
|
-
*/
|
|
291
|
-
function duplicateMultilineNodes (element) {
|
|
292
|
-
var nodes = element.childNodes;
|
|
293
|
-
for (var node in nodes) {
|
|
294
|
-
if (nodes.hasOwnProperty(node)) {
|
|
295
|
-
var child = nodes[node];
|
|
296
|
-
if (getLinesCount(child.textContent) > 0) {
|
|
297
|
-
if (child.childNodes.length > 0) {
|
|
298
|
-
duplicateMultilineNodes(child);
|
|
299
|
-
} else {
|
|
300
|
-
duplicateMultilineNode(child.parentNode);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Method for fix multi-line elements implementation in highlight.js
|
|
309
|
-
* @param {HTMLElement} element
|
|
310
|
-
*/
|
|
311
|
-
function duplicateMultilineNode (element) {
|
|
312
|
-
var className = element.className;
|
|
313
|
-
|
|
314
|
-
if ( ! /hljs-/.test(className)) return;
|
|
315
|
-
|
|
316
|
-
var lines = getLines(element.innerHTML);
|
|
317
|
-
|
|
318
|
-
for (var i = 0, result = ''; i < lines.length; i++) {
|
|
319
|
-
var lineText = lines[i].length > 0 ? lines[i] : ' ';
|
|
320
|
-
result += format('<span class="{0}">{1}</span>\n', [ className, lineText ]);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
element.innerHTML = result.trim();
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function getLines (text) {
|
|
327
|
-
if (text.length === 0) return [];
|
|
328
|
-
return text.split(BREAK_LINE_REGEXP);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function getLinesCount (text) {
|
|
332
|
-
return (text.trim().match(BREAK_LINE_REGEXP) || []).length;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
///
|
|
336
|
-
/// HELPERS
|
|
337
|
-
///
|
|
338
|
-
|
|
339
|
-
function async (func) {
|
|
340
|
-
w.setTimeout(func, 0);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* {@link https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript}
|
|
345
|
-
* @param {string} format
|
|
346
|
-
* @param {array} args
|
|
347
|
-
*/
|
|
348
|
-
function format (format, args) {
|
|
349
|
-
return format.replace(/\{(\d+)\}/g, function(m, n){
|
|
350
|
-
return args[n] !== undefined ? args[n] : m;
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* @param {HTMLElement} element Code block.
|
|
356
|
-
* @param {String} attrName Attribute name.
|
|
357
|
-
* @returns {String} Attribute value or empty.
|
|
358
|
-
*/
|
|
359
|
-
function getAttribute (element, attrName) {
|
|
360
|
-
return element.hasAttribute(attrName) ? element.getAttribute(attrName) : null;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* @param {String} str Source string.
|
|
365
|
-
* @param {Number} fallback Fallback value.
|
|
366
|
-
* @returns Parsed number or fallback value.
|
|
367
|
-
*/
|
|
368
|
-
function toNumber (str, fallback) {
|
|
369
|
-
if (!str) return fallback;
|
|
370
|
-
var number = Number(str);
|
|
371
|
-
return isFinite(number) ? number : fallback;
|
|
372
|
-
}
|
|
373
|
-
});
|