├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── generate-index.py
├── index.html
├── lib
├── vuep.css
└── vuep.js
├── package.json
├── templates
├── elementui-demo
│ ├── config.json
│ ├── data.json
│ └── index.vue
├── index.json
├── resume-diygod
│ ├── config.json
│ ├── data.json
│ ├── font
│ │ ├── fontello.eot
│ │ ├── fontello.svg
│ │ ├── fontello.ttf
│ │ └── fontello.woff
│ ├── img
│ │ └── resume-head.jpg
│ ├── index.vue
│ └── lib
│ │ └── marked.js
├── resume-for-cpp
│ ├── config.json
│ ├── data.json
│ └── img
│ │ └── resume-head.jpg
└── resume-for-java
│ ├── config.json
│ ├── data.json
│ └── img
│ └── resume-head.jpg
└── yarn.lock
/.eslintignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/.eslintignore
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "standard"
4 | ],
5 | "env": {
6 | "browser": true,
7 | "es6": true
8 | },
9 | "plugins": [
10 | "html",
11 | "vue"
12 | ],
13 | "settings": {
14 | "html/html-extensions": [
15 | ".html",
16 | ".vue"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | node_modules
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Junlin Liu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-json-template
2 |
3 | 一个基于 vue,根据 json 渲染 html 的模板系统,**无需构建工具即可使用\*.vue单文件组件**作为模板。
4 |
5 | 使用 vuep 实现在线编译,用一个简易的配置文件动态加载外部JS/CSS,便于使用第三方组件。
6 |
7 | ## 配置
8 |
9 | 模板目录结结构
10 |
11 | ```
12 | ├── index.html
13 | └── templates
14 | ├── index.json
15 | ├── a
16 | │ ├── config.json
17 | │ ├── data.json
18 | │ └── index.vue (可选)
19 | └── b
20 | ├── config.json
21 | ├── data.json
22 | └── index.vue
23 |
24 | ```
25 |
26 | `index.json` 为模板索引文件 `default` 用于指定默认模板,`templates` 用于声明模板列表,`loaclhost/127.0.0.1` 域下右键可以快速切换模板。
27 |
28 | ```json
29 | {
30 | "default": "",
31 | "templates": []
32 | }
33 | ```
34 |
35 | `data.json` 为数据文件,用于注入到模板中 `index.vue` 的 `data`。必须包含`html-title`。
36 |
37 | `index.vue` 为模板入口组件,`data`中必须包含 `DATA_INJECT_HERE` ,用于提供注入点(用文本替换实现注入,比较粗暴2333)。
38 |
39 | `config.json` 为模板配置文件,可以指定自定义的外部 JS/CSS,指定需要继承的模板。
40 |
41 | ```json
42 | {
43 | "external-js": [
44 | "https://unpkg.com/element-ui/lib/index.js"
45 | ],
46 | "external-css": [
47 | "https://unpkg.com/element-ui/lib/theme-chalk/index.css"
48 | ]
49 | // ,"extends": "resume-diygod"
50 | }
51 | ```
52 |
53 | [vuep.run 在线调试](https://vuep.netlify.com/)
54 |
55 | ## 注意
56 |
57 | 由于加载组件是直接读取源码,故所有相对路径均是相对于`index.html` 而不是模板根目录。
58 |
59 | 故相对于模板根目录路径请以 `__TEMPLATE_ROOT__/`开头。
60 | 相对于父模板根目录路径请以 `__TEMPLATE_PARENT_ROOT__/`开头。
61 |
62 | > 对 vue 文件内容、外部 css、js 路径生效
63 |
64 | ## 协议
65 |
66 | MIT
67 |
--------------------------------------------------------------------------------
/generate-index.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import os
3 | import json
4 | import logging
5 |
6 | TEMPLATE_ROOT = "templates"
7 | TEMPLATE_INDEX = os.path.join(TEMPLATE_ROOT, "index.json")
8 |
9 | template_list = []
10 |
11 | dirs = os.listdir(TEMPLATE_ROOT)
12 | for template_name in dirs:
13 | template_dir = os.path.join(TEMPLATE_ROOT, template_name)
14 | template_config = os.path.join(template_dir, "config.json")
15 | if (os.path.isdir(template_dir) and os.path.isfile(template_config)):
16 | template_list.append(template_name)
17 | print(template_name)
18 |
19 | index_obj = {"default": template_list[0], "templates": template_list}
20 |
21 | with open(TEMPLATE_INDEX, "r") as f:
22 | try:
23 | index_obj["default"] = json.loads(f.read(), encoding='utf-8')["default"]
24 | except Exception:
25 | logging.warn("default is missing.")
26 | print(index_obj)
27 |
28 | with open(TEMPLATE_INDEX, "w") as f:
29 | json.dump(index_obj, f, ensure_ascii=False, sort_keys=True, indent=4);
30 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Loading...
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
60 |
61 |
62 |
63 |
71 |
72 |
251 |
252 |
253 |
--------------------------------------------------------------------------------
/lib/vuep.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 | .CodeMirror {
3 | /* Set height, width, borders, and global font properties here */
4 | font-family: monospace;
5 | height: 300px;
6 | color: black;
7 | }
8 | /* PADDING */
9 | .CodeMirror-lines {
10 | padding: 4px 0;
11 | /* Vertical padding around content */
12 | }
13 | .CodeMirror pre {
14 | padding: 0 4px;
15 | /* Horizontal padding of content */
16 | }
17 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
18 | background-color: white;
19 | /* The little square between H and V scrollbars */
20 | }
21 | /* GUTTER */
22 | .CodeMirror-gutters {
23 | border-right: 1px solid #ddd;
24 | background-color: #f7f7f7;
25 | white-space: nowrap;
26 | }
27 | .CodeMirror-linenumbers {}
28 | .CodeMirror-linenumber {
29 | padding: 0 3px 0 5px;
30 | min-width: 20px;
31 | text-align: right;
32 | color: #999;
33 | white-space: nowrap;
34 | }
35 | .CodeMirror-guttermarker {
36 | color: black;
37 | }
38 | .CodeMirror-guttermarker-subtle {
39 | color: #999;
40 | }
41 | /* CURSOR */
42 | .CodeMirror-cursor {
43 | border-left: 1px solid black;
44 | border-right: none;
45 | width: 0;
46 | }
47 | /* Shown when moving in bi-directional text */
48 | .CodeMirror div.CodeMirror-secondarycursor {
49 | border-left: 1px solid silver;
50 | }
51 | .cm-fat-cursor .CodeMirror-cursor {
52 | width: auto;
53 | border: 0 !important;
54 | background: #7e7;
55 | }
56 | .cm-fat-cursor div.CodeMirror-cursors {
57 | z-index: 1;
58 | }
59 | .cm-animate-fat-cursor {
60 | width: auto;
61 | border: 0;
62 | -webkit-animation: blink 1.06s steps(1) infinite;
63 | animation: blink 1.06s steps(1) infinite;
64 | background-color: #7e7;
65 | }
66 | @-webkit-keyframes blink {
67 | 0% {}
68 | 50% {
69 | background-color: transparent;
70 | }
71 | 100% {}
72 | }
73 | @keyframes blink {
74 | 0% {}
75 | 50% {
76 | background-color: transparent;
77 | }
78 | 100% {}
79 | }
80 | /* Can style cursor different in overwrite (non-insert) mode */
81 | .CodeMirror-overwrite .CodeMirror-cursor {}
82 | .cm-tab {
83 | display: inline-block;
84 | text-decoration: inherit;
85 | }
86 | .CodeMirror-rulers {
87 | position: absolute;
88 | left: 0;
89 | right: 0;
90 | top: -50px;
91 | bottom: -20px;
92 | overflow: hidden;
93 | }
94 | .CodeMirror-ruler {
95 | border-left: 1px solid #ccc;
96 | top: 0;
97 | bottom: 0;
98 | position: absolute;
99 | }
100 | /* DEFAULT THEME */
101 | .cm-s-default .cm-header {
102 | color: blue;
103 | }
104 | .cm-s-default .cm-quote {
105 | color: #090;
106 | }
107 | .cm-negative {
108 | color: #d44;
109 | }
110 | .cm-positive {
111 | color: #292;
112 | }
113 | .cm-header, .cm-strong {
114 | font-weight: 700;
115 | }
116 | .cm-em {
117 | font-style: italic;
118 | }
119 | .cm-link {
120 | text-decoration: underline;
121 | }
122 | .cm-strikethrough {
123 | text-decoration: line-through;
124 | }
125 | .cm-s-default .cm-keyword {
126 | color: #708;
127 | }
128 | .cm-s-default .cm-atom {
129 | color: #219;
130 | }
131 | .cm-s-default .cm-number {
132 | color: #164;
133 | }
134 | .cm-s-default .cm-def {
135 | color: #00f;
136 | }
137 | .cm-s-default .cm-variable, .cm-s-default .cm-punctuation, .cm-s-default .cm-property, .cm-s-default .cm-operator {}
138 | .cm-s-default .cm-variable-2 {
139 | color: #05a;
140 | }
141 | .cm-s-default .cm-variable-3 {
142 | color: #085;
143 | }
144 | .cm-s-default .cm-comment {
145 | color: #a50;
146 | }
147 | .cm-s-default .cm-string {
148 | color: #a11;
149 | }
150 | .cm-s-default .cm-string-2 {
151 | color: #f50;
152 | }
153 | .cm-s-default .cm-meta {
154 | color: #555;
155 | }
156 | .cm-s-default .cm-qualifier {
157 | color: #555;
158 | }
159 | .cm-s-default .cm-builtin {
160 | color: #30a;
161 | }
162 | .cm-s-default .cm-bracket {
163 | color: #997;
164 | }
165 | .cm-s-default .cm-tag {
166 | color: #170;
167 | }
168 | .cm-s-default .cm-attribute {
169 | color: #00c;
170 | }
171 | .cm-s-default .cm-hr {
172 | color: #999;
173 | }
174 | .cm-s-default .cm-link {
175 | color: #00c;
176 | }
177 | .cm-s-default .cm-error {
178 | color: #f00;
179 | }
180 | .cm-invalidchar {
181 | color: #f00;
182 | }
183 | .CodeMirror-composing {
184 | border-bottom: 2px solid;
185 | }
186 | /* Default styles for common addons */
187 | div.CodeMirror span.CodeMirror-matchingbracket {
188 | color: #0f0;
189 | }
190 | div.CodeMirror span.CodeMirror-nonmatchingbracket {
191 | color: #f22;
192 | }
193 | .CodeMirror-matchingtag {
194 | background: rgba(255, 150, 0, .3);
195 | }
196 | .CodeMirror-activeline-background {
197 | background: #e8f2ff;
198 | }
199 | /* STOP */
200 | /* The rest of this file contains styles related to the mechanics of
201 | the editor. You probably shouldn't touch them. */
202 | .CodeMirror {
203 | position: relative;
204 | overflow: hidden;
205 | background: white;
206 | }
207 | .CodeMirror-scroll {
208 | overflow: scroll !important;
209 | /* Things will break if this is overridden */
210 | /* 30px is the magic margin used to hide the element's real scrollbars */
211 | /* See overflow: hidden in .CodeMirror */
212 | margin-bottom: -30px;
213 | margin-right: -30px;
214 | padding-bottom: 30px;
215 | height: 100%;
216 | outline: none;
217 | /* Prevent dragging from highlighting the element */
218 | position: relative;
219 | }
220 | .CodeMirror-sizer {
221 | position: relative;
222 | border-right: 30px solid transparent;
223 | }
224 | /* The fake, visible scrollbars. Used to force redraw during scrolling
225 | before actual scrolling happens, thus preventing shaking and
226 | flickering artifacts. */
227 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
228 | position: absolute;
229 | z-index: 6;
230 | display: none;
231 | }
232 | .CodeMirror-vscrollbar {
233 | right: 0;
234 | top: 0;
235 | overflow-x: hidden;
236 | overflow-y: scroll;
237 | }
238 | .CodeMirror-hscrollbar {
239 | bottom: 0;
240 | left: 0;
241 | overflow-y: hidden;
242 | overflow-x: scroll;
243 | }
244 | .CodeMirror-scrollbar-filler {
245 | right: 0;
246 | bottom: 0;
247 | }
248 | .CodeMirror-gutter-filler {
249 | left: 0;
250 | bottom: 0;
251 | }
252 | .CodeMirror-gutters {
253 | position: absolute;
254 | left: 0;
255 | top: 0;
256 | min-height: 100%;
257 | z-index: 3;
258 | }
259 | .CodeMirror-gutter {
260 | white-space: normal;
261 | height: 100%;
262 | display: inline-block;
263 | vertical-align: top;
264 | margin-bottom: -30px;
265 | }
266 | .CodeMirror-gutter-wrapper {
267 | position: absolute;
268 | z-index: 4;
269 | background: none !important;
270 | border: none !important;
271 | }
272 | .CodeMirror-gutter-background {
273 | position: absolute;
274 | top: 0;
275 | bottom: 0;
276 | z-index: 4;
277 | }
278 | .CodeMirror-gutter-elt {
279 | position: absolute;
280 | cursor: default;
281 | z-index: 4;
282 | }
283 | .CodeMirror-gutter-wrapper {
284 | -webkit-user-select: none;
285 | -moz-user-select: none;
286 | -ms-user-select: none;
287 | user-select: none;
288 | }
289 | .CodeMirror-lines {
290 | cursor: text;
291 | min-height: 1px;
292 | /* prevents collapsing before first draw */
293 | }
294 | .CodeMirror pre {
295 | /* Reset some styles that the rest of the page might have set */
296 | border-radius: 0;
297 | border-width: 0;
298 | background: transparent;
299 | font-family: inherit;
300 | font-size: inherit;
301 | margin: 0;
302 | white-space: pre;
303 | word-wrap: normal;
304 | line-height: inherit;
305 | color: inherit;
306 | z-index: 2;
307 | position: relative;
308 | overflow: visible;
309 | -webkit-tap-highlight-color: transparent;
310 | -webkit-font-variant-ligatures: contextual;
311 | font-variant-ligatures: contextual;
312 | }
313 | .CodeMirror-wrap pre {
314 | word-wrap: break-word;
315 | white-space: pre-wrap;
316 | word-break: normal;
317 | }
318 | .CodeMirror-linebackground {
319 | position: absolute;
320 | left: 0;
321 | right: 0;
322 | top: 0;
323 | bottom: 0;
324 | z-index: 0;
325 | }
326 | .CodeMirror-linewidget {
327 | position: relative;
328 | z-index: 2;
329 | overflow: auto;
330 | }
331 | .CodeMirror-widget {}
332 | .CodeMirror-code {
333 | outline: none;
334 | }
335 | /* Force content-box sizing for the elements where we expect it */
336 | .CodeMirror-scroll, .CodeMirror-sizer, .CodeMirror-gutter, .CodeMirror-gutters, .CodeMirror-linenumber {
337 | box-sizing: content-box;
338 | }
339 | .CodeMirror-measure {
340 | position: absolute;
341 | width: 100%;
342 | height: 0;
343 | overflow: hidden;
344 | visibility: hidden;
345 | }
346 | .CodeMirror-cursor {
347 | position: absolute;
348 | pointer-events: none;
349 | }
350 | .CodeMirror-measure pre {
351 | position: static;
352 | }
353 | div.CodeMirror-cursors {
354 | visibility: hidden;
355 | position: relative;
356 | z-index: 3;
357 | }
358 | div.CodeMirror-dragcursors {
359 | visibility: visible;
360 | }
361 | .CodeMirror-focused div.CodeMirror-cursors {
362 | visibility: visible;
363 | }
364 | .CodeMirror-selected {
365 | background: #d9d9d9;
366 | }
367 | .CodeMirror-focused .CodeMirror-selected {
368 | background: #d7d4f0;
369 | }
370 | .CodeMirror-crosshair {
371 | cursor: crosshair;
372 | }
373 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection {
374 | background: #d7d4f0;
375 | }
376 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection {
377 | background: #d7d4f0;
378 | }
379 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection {
380 | background: #d7d4f0;
381 | }
382 | .cm-searching {
383 | background: #ffa;
384 | background: rgba(255, 255, 0, .4);
385 | }
386 | /* Used to force a border model for a node */
387 | .cm-force-border {
388 | padding-right: .1px;
389 | }
390 | @media print {
391 | /* Hide the cursor when printing */
392 | .CodeMirror div.CodeMirror-cursors {
393 | visibility: hidden;
394 | }
395 | }
396 | /* See issue #2901 */
397 | .cm-tab-wrap-hack:after {
398 | content: '';
399 | }
400 | /* Help users use markselection to safely style text background */
401 | span.CodeMirror-selectedtext {
402 | background: none;
403 | }
404 | /*
405 |
406 | Name: material
407 | Author: Michael Kaminsky (http://github.com/mkaminsky11)
408 |
409 | Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
410 |
411 | */
412 | .cm-s-material.CodeMirror {
413 | background-color: #263238;
414 | color: rgba(233, 237, 237, 1);
415 | }
416 | .cm-s-material .CodeMirror-gutters {
417 | background: #263238;
418 | color: rgb(83,127,126);
419 | border: none;
420 | }
421 | .cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber {
422 | color: rgb(83,127,126);
423 | }
424 | .cm-s-material .CodeMirror-cursor {
425 | border-left: 1px solid #f8f8f0;
426 | }
427 | .cm-s-material div.CodeMirror-selected {
428 | background: rgba(255, 255, 255, 0.15);
429 | }
430 | .cm-s-material.CodeMirror-focused div.CodeMirror-selected {
431 | background: rgba(255, 255, 255, 0.10);
432 | }
433 | .cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection {
434 | background: rgba(255, 255, 255, 0.10);
435 | }
436 | .cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection {
437 | background: rgba(255, 255, 255, 0.10);
438 | }
439 | .cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection {
440 | background: rgba(255, 255, 255, 0.10);
441 | }
442 | .cm-s-material .CodeMirror-activeline-background {
443 | background: rgba(0, 0, 0, 0);
444 | }
445 | .cm-s-material .cm-keyword {
446 | color: rgba(199, 146, 234, 1);
447 | }
448 | .cm-s-material .cm-operator {
449 | color: rgba(233, 237, 237, 1);
450 | }
451 | .cm-s-material .cm-variable-2 {
452 | color: #80CBC4;
453 | }
454 | .cm-s-material .cm-variable-3 {
455 | color: #82B1FF;
456 | }
457 | .cm-s-material .cm-builtin {
458 | color: #DECB6B;
459 | }
460 | .cm-s-material .cm-atom {
461 | color: #F77669;
462 | }
463 | .cm-s-material .cm-number {
464 | color: #F77669;
465 | }
466 | .cm-s-material .cm-def {
467 | color: rgba(233, 237, 237, 1);
468 | }
469 | .cm-s-material .cm-string {
470 | color: #C3E88D;
471 | }
472 | .cm-s-material .cm-string-2 {
473 | color: #80CBC4;
474 | }
475 | .cm-s-material .cm-comment {
476 | color: #546E7A;
477 | }
478 | .cm-s-material .cm-variable {
479 | color: #82B1FF;
480 | }
481 | .cm-s-material .cm-tag {
482 | color: #80CBC4;
483 | }
484 | .cm-s-material .cm-meta {
485 | color: #80CBC4;
486 | }
487 | .cm-s-material .cm-attribute {
488 | color: #FFCB6B;
489 | }
490 | .cm-s-material .cm-property {
491 | color: #80CBAE;
492 | }
493 | .cm-s-material .cm-qualifier {
494 | color: #DECB6B;
495 | }
496 | .cm-s-material .cm-variable-3 {
497 | color: #DECB6B;
498 | }
499 | .cm-s-material .cm-tag {
500 | color: rgba(255, 83, 112, 1);
501 | }
502 | .cm-s-material .cm-error {
503 | color: rgba(255, 255, 255, 1.0);
504 | background-color: #EC5F67;
505 | }
506 | .cm-s-material .CodeMirror-matchingbracket {
507 | text-decoration: underline;
508 | color: white !important;
509 | }
510 |
511 | .vuep {
512 | display: -webkit-box;
513 | display: -ms-flexbox;
514 | display: flex;
515 | font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
516 | height: 400px;
517 | }
518 |
519 | .vuep ::-webkit-scrollbar-track {
520 | border-radius: 10px;
521 | background-color: #F5F5F5;
522 | }
523 |
524 | .vuep ::-webkit-scrollbar {
525 | width: 8px;
526 | height: 8px;
527 | background-color: #F5F5F5;
528 | }
529 |
530 | .vuep ::-webkit-scrollbar-thumb {
531 | border-radius: 8px;
532 | background-color: #bbb;
533 | -webkit-transition: all 0.5s;
534 | transition: all 0.5s;
535 | }
536 |
537 | .vuep ::-webkit-scrollbar-thumb:hover {
538 | border-radius: 8px;
539 | background-color: #777;
540 | }
541 |
542 | .vuep-editor, .vuep-preview, .vuep-error {
543 | border-radius: 2px;
544 | height: inherit;
545 | margin-right: 10px;
546 | overflow: auto;
547 | width: 50%;
548 | }
549 |
550 | .vuep-editor .CodeMirror, .vuep-preview .CodeMirror, .vuep-error .CodeMirror {
551 | height: inherit;
552 | }
553 |
554 | .vuep-editor:last-child, .vuep-preview:last-child, .vuep-error:last-child {
555 | margin-right: 0;
556 | }
557 |
558 | .vuep-editor {
559 | line-height: 1.2em;
560 | }
561 |
562 | .vuep-error {
563 | color: #f66;
564 | }
565 |
566 | .vuep-preview, .vuep-error {
567 | border: 1px solid #eee;
568 | box-sizing: border-box;
569 | padding: 25px 35px;
570 | }
571 |
572 | @media (max-width: 600px) {
573 | .vuep {
574 | display: block;
575 | height: auto;
576 | }
577 |
578 | .vuep-editor, .vuep-preview, .vuep-error {
579 | margin: 0 0 15px 0;
580 | height: 400px;
581 | width: 100%;
582 | }
583 | }
584 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-json-template",
3 | "version": "1.1.0",
4 | "main": "index.js",
5 | "repository": "",
6 | "author": "NoCLin ",
7 | "license": "MIT",
8 | "scripts": {
9 | "dev": "puer .",
10 | "index": "python generate-index.py",
11 | "lint": "eslint index.html **/*.vue",
12 | "lint-fix": "eslint index.html **/*.vue --fix"
13 | },
14 | "devDependencies": {
15 | "eslint": "^5.13.0",
16 | "eslint-config-standard": "^12.0.0",
17 | "eslint-plugin-html": "^3.0.0",
18 | "eslint-plugin-import": "^2.16.0",
19 | "eslint-plugin-node": "^8.0.1",
20 | "eslint-plugin-promise": "^4.0.1",
21 | "eslint-plugin-standard": "^4.0.0",
22 | "eslint-plugin-vue": "^5.1.0",
23 | "puer": "^2.0.1"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/templates/elementui-demo/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "external-js": [
3 | "https://unpkg.com/element-ui/lib/index.js"
4 | ],
5 | "external-css": [
6 | "https://unpkg.com/element-ui/lib/theme-chalk/index.css"
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/templates/elementui-demo/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "html-title": "elementui-demo",
3 | "form": {
4 | "name": "hello vue-json-template",
5 | "region": "beijing",
6 | "date1": "2019-01-31T16:00:00.000Z",
7 | "date2": "2019-02-13T16:00:27.000Z",
8 | "delivery": true,
9 | "type": [
10 | "美食/餐厅线上活动",
11 | "地推活动",
12 | "线下主题活动",
13 | "单纯品牌曝光"
14 | ],
15 | "resource": "线下场地免费",
16 | "desc": "形式"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/templates/elementui-demo/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 |
18 | -
19 |
20 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 立即创建
46 | 取消
47 |
48 |
49 |
50 |
51 |
52 |
71 |
72 |
--------------------------------------------------------------------------------
/templates/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "default": "resume-diygod",
3 | "templates": [
4 | "resume-for-cpp",
5 | "resume-for-java",
6 | "resume-diygod",
7 | "elementui-demo"
8 | ]
9 | }
--------------------------------------------------------------------------------
/templates/resume-diygod/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "external-js": [
3 | "__TEMPLATE_PARENT_ROOT__/lib/marked.js"
4 | ],
5 | "external-css": [
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/templates/resume-diygod/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "html-title": "XXX的简历",
3 | "name": "XXX",
4 | "gender": "男",
5 | "birth": "19XX.XX",
6 | "slogan": "hhh",
7 | "school": "XXU",
8 | "apply-position": "XX工程师",
9 | "contact":{
10 | "wechat": "hhh",
11 | "qq": "10001",
12 | "email": "xxx@email.xxu.edu.cn",
13 | "blog": "https://github.com",
14 | "github": "~~~",
15 | "cellphone": "13800138000"
16 | },
17 | "note": [
18 | "hhh"
19 | ],
20 | "educations": [
21 | {
22 | "school": "XX大学 XXXX (20XX.9 - 20XX.6)",
23 | "info": [
24 | "...",
25 | "..."
26 | ]
27 | }
28 | ],
29 | "exps": [
30 | {
31 | "company": "XXX",
32 | "img": "",
33 | "info": "",
34 | "projects": [
35 | {
36 | "name": "Project1",
37 | "info": [
38 | "Situation: \n\n",
39 | "Task: \n\n",
40 | "Action: \n\n",
41 | "Result: \n\n"
42 | ]
43 | },
44 | {
45 | "name": "Project2",
46 | "info": [
47 | "Situation: \n\n",
48 | "Task: \n\n",
49 | "Action: \n\n",
50 | "Result: \n\n"
51 | ]
52 | }
53 | ]
54 | }
55 | ],
56 | "skills": [
57 | {
58 | "type": "type1",
59 | "info": "精通..."
60 | },
61 | {
62 | "type": "type2",
63 | "info": "熟悉..."
64 | }
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/templates/resume-diygod/font/fontello.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-diygod/font/fontello.eot
--------------------------------------------------------------------------------
/templates/resume-diygod/font/fontello.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/templates/resume-diygod/font/fontello.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-diygod/font/fontello.ttf
--------------------------------------------------------------------------------
/templates/resume-diygod/font/fontello.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-diygod/font/fontello.woff
--------------------------------------------------------------------------------
/templates/resume-diygod/img/resume-head.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-diygod/img/resume-head.jpg
--------------------------------------------------------------------------------
/templates/resume-diygod/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 |
39 | -
40 |
- Basic info. 基本信息
41 |
42 | template root is __TEMPLATE_ROOT__/
43 |
44 |
45 | template parent root is __TEMPLATE_PARENT_ROOT__/
46 |
47 | - {{name}} / {{gender}} / {{birth}}
48 | - 毕业院校: {{school}}
49 | -
50 | 博客:
51 | {{contact.blog}}
52 |
53 | -
54 | GitHub:
55 | @{{contact.github}}
56 |
57 |
58 | -
59 |
- Education. 教育背景
60 |
61 |
62 | -
63 |
64 |
{{education.school}}
65 |
66 |
67 |
68 |
69 |
70 | -
71 |
- Experience. 项目与工作经验
72 |
73 |
74 |
75 |
76 |
77 |
{{exp.info}}
78 |
79 | -
80 |
81 |
82 | {{project.name}}
83 | 源代码
85 | Demo
87 |
88 |
89 |
90 |
91 |
92 |
93 | -
94 |
- Skill. 技能清单
95 |
96 | -
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | 加载错误
107 |
108 |
109 |
110 |
111 |
130 |
131 |
510 |
--------------------------------------------------------------------------------
/templates/resume-diygod/lib/marked.js:
--------------------------------------------------------------------------------
1 | /**
2 | * marked - a markdown parser
3 | * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT Licensed)
4 | * https://github.com/markedjs/marked
5 | */
6 |
7 | ;(function(root) {
8 | 'use strict';
9 |
10 | /**
11 | * Block-Level Grammar
12 | */
13 |
14 | var block = {
15 | newline: /^\n+/,
16 | code: /^( {4}[^\n]+\n*)+/,
17 | fences: noop,
18 | hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
19 | heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
20 | nptable: noop,
21 | blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
22 | list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
23 | html: '^ {0,3}(?:' // optional indentation
24 | + '<(script|pre|style)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)' // (1)
25 | + '|comment[^\\n]*(\\n+|$)' // (2)
26 | + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
27 | + '|\\n*' // (4)
28 | + '|\\n*' // (5)
29 | + '|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
30 | + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
31 | + '|(?!script|pre|style)[a-z][\\w-]*\\s*>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
32 | + ')',
33 | def: /^ {0,3}\[(label)\]: *\n? *([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
34 | table: noop,
35 | lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
36 | paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,
37 | text: /^[^\n]+/
38 | };
39 |
40 | block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
41 | block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
42 | block.def = edit(block.def)
43 | .replace('label', block._label)
44 | .replace('title', block._title)
45 | .getRegex();
46 |
47 | block.bullet = /(?:[*+-]|\d+\.)/;
48 | block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
49 | block.item = edit(block.item, 'gm')
50 | .replace(/bull/g, block.bullet)
51 | .getRegex();
52 |
53 | block.list = edit(block.list)
54 | .replace(/bull/g, block.bullet)
55 | .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
56 | .replace('def', '\\n+(?=' + block.def.source + ')')
57 | .getRegex();
58 |
59 | block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
60 | + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
61 | + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
62 | + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
63 | + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
64 | + '|track|ul';
65 | block._comment = //;
66 | block.html = edit(block.html, 'i')
67 | .replace('comment', block._comment)
68 | .replace('tag', block._tag)
69 | .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
70 | .getRegex();
71 |
72 | block.paragraph = edit(block.paragraph)
73 | .replace('hr', block.hr)
74 | .replace('heading', block.heading)
75 | .replace('lheading', block.lheading)
76 | .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
77 | .getRegex();
78 |
79 | block.blockquote = edit(block.blockquote)
80 | .replace('paragraph', block.paragraph)
81 | .getRegex();
82 |
83 | /**
84 | * Normal Block Grammar
85 | */
86 |
87 | block.normal = merge({}, block);
88 |
89 | /**
90 | * GFM Block Grammar
91 | */
92 |
93 | block.gfm = merge({}, block.normal, {
94 | fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,
95 | paragraph: /^/,
96 | heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
97 | });
98 |
99 | block.gfm.paragraph = edit(block.paragraph)
100 | .replace('(?!', '(?!'
101 | + block.gfm.fences.source.replace('\\1', '\\2') + '|'
102 | + block.list.source.replace('\\1', '\\3') + '|')
103 | .getRegex();
104 |
105 | /**
106 | * GFM + Tables Block Grammar
107 | */
108 |
109 | block.tables = merge({}, block.gfm, {
110 | nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,
111 | table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/
112 | });
113 |
114 | /**
115 | * Pedantic grammar
116 | */
117 |
118 | block.pedantic = merge({}, block.normal, {
119 | html: edit(
120 | '^ *(?:comment *(?:\\n|\\s*$)'
121 | + '|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)' // closed tag
122 | + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
123 | .replace('comment', block._comment)
124 | .replace(/tag/g, '(?!(?:'
125 | + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
126 | + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
127 | + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
128 | .getRegex(),
129 | def: /^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/
130 | });
131 |
132 | /**
133 | * Block Lexer
134 | */
135 |
136 | function Lexer(options) {
137 | this.tokens = [];
138 | this.tokens.links = Object.create(null);
139 | this.options = options || marked.defaults;
140 | this.rules = block.normal;
141 |
142 | if (this.options.pedantic) {
143 | this.rules = block.pedantic;
144 | } else if (this.options.gfm) {
145 | if (this.options.tables) {
146 | this.rules = block.tables;
147 | } else {
148 | this.rules = block.gfm;
149 | }
150 | }
151 | }
152 |
153 | /**
154 | * Expose Block Rules
155 | */
156 |
157 | Lexer.rules = block;
158 |
159 | /**
160 | * Static Lex Method
161 | */
162 |
163 | Lexer.lex = function(src, options) {
164 | var lexer = new Lexer(options);
165 | return lexer.lex(src);
166 | };
167 |
168 | /**
169 | * Preprocessing
170 | */
171 |
172 | Lexer.prototype.lex = function(src) {
173 | src = src
174 | .replace(/\r\n|\r/g, '\n')
175 | .replace(/\t/g, ' ')
176 | .replace(/\u00a0/g, ' ')
177 | .replace(/\u2424/g, '\n');
178 |
179 | return this.token(src, true);
180 | };
181 |
182 | /**
183 | * Lexing
184 | */
185 |
186 | Lexer.prototype.token = function(src, top) {
187 | src = src.replace(/^ +$/gm, '');
188 | var next,
189 | loose,
190 | cap,
191 | bull,
192 | b,
193 | item,
194 | listStart,
195 | listItems,
196 | t,
197 | space,
198 | i,
199 | tag,
200 | l,
201 | isordered,
202 | istask,
203 | ischecked;
204 |
205 | while (src) {
206 | // newline
207 | if (cap = this.rules.newline.exec(src)) {
208 | src = src.substring(cap[0].length);
209 | if (cap[0].length > 1) {
210 | this.tokens.push({
211 | type: 'space'
212 | });
213 | }
214 | }
215 |
216 | // code
217 | if (cap = this.rules.code.exec(src)) {
218 | src = src.substring(cap[0].length);
219 | cap = cap[0].replace(/^ {4}/gm, '');
220 | this.tokens.push({
221 | type: 'code',
222 | text: !this.options.pedantic
223 | ? rtrim(cap, '\n')
224 | : cap
225 | });
226 | continue;
227 | }
228 |
229 | // fences (gfm)
230 | if (cap = this.rules.fences.exec(src)) {
231 | src = src.substring(cap[0].length);
232 | this.tokens.push({
233 | type: 'code',
234 | lang: cap[2],
235 | text: cap[3] || ''
236 | });
237 | continue;
238 | }
239 |
240 | // heading
241 | if (cap = this.rules.heading.exec(src)) {
242 | src = src.substring(cap[0].length);
243 | this.tokens.push({
244 | type: 'heading',
245 | depth: cap[1].length,
246 | text: cap[2]
247 | });
248 | continue;
249 | }
250 |
251 | // table no leading pipe (gfm)
252 | if (top && (cap = this.rules.nptable.exec(src))) {
253 | item = {
254 | type: 'table',
255 | header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
256 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
257 | cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
258 | };
259 |
260 | if (item.header.length === item.align.length) {
261 | src = src.substring(cap[0].length);
262 |
263 | for (i = 0; i < item.align.length; i++) {
264 | if (/^ *-+: *$/.test(item.align[i])) {
265 | item.align[i] = 'right';
266 | } else if (/^ *:-+: *$/.test(item.align[i])) {
267 | item.align[i] = 'center';
268 | } else if (/^ *:-+ *$/.test(item.align[i])) {
269 | item.align[i] = 'left';
270 | } else {
271 | item.align[i] = null;
272 | }
273 | }
274 |
275 | for (i = 0; i < item.cells.length; i++) {
276 | item.cells[i] = splitCells(item.cells[i], item.header.length);
277 | }
278 |
279 | this.tokens.push(item);
280 |
281 | continue;
282 | }
283 | }
284 |
285 | // hr
286 | if (cap = this.rules.hr.exec(src)) {
287 | src = src.substring(cap[0].length);
288 | this.tokens.push({
289 | type: 'hr'
290 | });
291 | continue;
292 | }
293 |
294 | // blockquote
295 | if (cap = this.rules.blockquote.exec(src)) {
296 | src = src.substring(cap[0].length);
297 |
298 | this.tokens.push({
299 | type: 'blockquote_start'
300 | });
301 |
302 | cap = cap[0].replace(/^ *> ?/gm, '');
303 |
304 | // Pass `top` to keep the current
305 | // "toplevel" state. This is exactly
306 | // how markdown.pl works.
307 | this.token(cap, top);
308 |
309 | this.tokens.push({
310 | type: 'blockquote_end'
311 | });
312 |
313 | continue;
314 | }
315 |
316 | // list
317 | if (cap = this.rules.list.exec(src)) {
318 | src = src.substring(cap[0].length);
319 | bull = cap[2];
320 | isordered = bull.length > 1;
321 |
322 | listStart = {
323 | type: 'list_start',
324 | ordered: isordered,
325 | start: isordered ? +bull : '',
326 | loose: false
327 | };
328 |
329 | this.tokens.push(listStart);
330 |
331 | // Get each top-level item.
332 | cap = cap[0].match(this.rules.item);
333 |
334 | listItems = [];
335 | next = false;
336 | l = cap.length;
337 | i = 0;
338 |
339 | for (; i < l; i++) {
340 | item = cap[i];
341 |
342 | // Remove the list item's bullet
343 | // so it is seen as the next token.
344 | space = item.length;
345 | item = item.replace(/^ *([*+-]|\d+\.) +/, '');
346 |
347 | // Outdent whatever the
348 | // list item contains. Hacky.
349 | if (~item.indexOf('\n ')) {
350 | space -= item.length;
351 | item = !this.options.pedantic
352 | ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
353 | : item.replace(/^ {1,4}/gm, '');
354 | }
355 |
356 | // Determine whether the next list item belongs here.
357 | // Backpedal if it does not belong in this list.
358 | if (this.options.smartLists && i !== l - 1) {
359 | b = block.bullet.exec(cap[i + 1])[0];
360 | if (bull !== b && !(bull.length > 1 && b.length > 1)) {
361 | src = cap.slice(i + 1).join('\n') + src;
362 | i = l - 1;
363 | }
364 | }
365 |
366 | // Determine whether item is loose or not.
367 | // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
368 | // for discount behavior.
369 | loose = next || /\n\n(?!\s*$)/.test(item);
370 | if (i !== l - 1) {
371 | next = item.charAt(item.length - 1) === '\n';
372 | if (!loose) loose = next;
373 | }
374 |
375 | if (loose) {
376 | listStart.loose = true;
377 | }
378 |
379 | // Check for task list items
380 | istask = /^\[[ xX]\] /.test(item);
381 | ischecked = undefined;
382 | if (istask) {
383 | ischecked = item[1] !== ' ';
384 | item = item.replace(/^\[[ xX]\] +/, '');
385 | }
386 |
387 | t = {
388 | type: 'list_item_start',
389 | task: istask,
390 | checked: ischecked,
391 | loose: loose
392 | };
393 |
394 | listItems.push(t);
395 | this.tokens.push(t);
396 |
397 | // Recurse.
398 | this.token(item, false);
399 |
400 | this.tokens.push({
401 | type: 'list_item_end'
402 | });
403 | }
404 |
405 | if (listStart.loose) {
406 | l = listItems.length;
407 | i = 0;
408 | for (; i < l; i++) {
409 | listItems[i].loose = true;
410 | }
411 | }
412 |
413 | this.tokens.push({
414 | type: 'list_end'
415 | });
416 |
417 | continue;
418 | }
419 |
420 | // html
421 | if (cap = this.rules.html.exec(src)) {
422 | src = src.substring(cap[0].length);
423 | this.tokens.push({
424 | type: this.options.sanitize
425 | ? 'paragraph'
426 | : 'html',
427 | pre: !this.options.sanitizer
428 | && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
429 | text: cap[0]
430 | });
431 | continue;
432 | }
433 |
434 | // def
435 | if (top && (cap = this.rules.def.exec(src))) {
436 | src = src.substring(cap[0].length);
437 | if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
438 | tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
439 | if (!this.tokens.links[tag]) {
440 | this.tokens.links[tag] = {
441 | href: cap[2],
442 | title: cap[3]
443 | };
444 | }
445 | continue;
446 | }
447 |
448 | // table (gfm)
449 | if (top && (cap = this.rules.table.exec(src))) {
450 | item = {
451 | type: 'table',
452 | header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
453 | align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
454 | cells: cap[3] ? cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') : []
455 | };
456 |
457 | if (item.header.length === item.align.length) {
458 | src = src.substring(cap[0].length);
459 |
460 | for (i = 0; i < item.align.length; i++) {
461 | if (/^ *-+: *$/.test(item.align[i])) {
462 | item.align[i] = 'right';
463 | } else if (/^ *:-+: *$/.test(item.align[i])) {
464 | item.align[i] = 'center';
465 | } else if (/^ *:-+ *$/.test(item.align[i])) {
466 | item.align[i] = 'left';
467 | } else {
468 | item.align[i] = null;
469 | }
470 | }
471 |
472 | for (i = 0; i < item.cells.length; i++) {
473 | item.cells[i] = splitCells(
474 | item.cells[i].replace(/^ *\| *| *\| *$/g, ''),
475 | item.header.length);
476 | }
477 |
478 | this.tokens.push(item);
479 |
480 | continue;
481 | }
482 | }
483 |
484 | // lheading
485 | if (cap = this.rules.lheading.exec(src)) {
486 | src = src.substring(cap[0].length);
487 | this.tokens.push({
488 | type: 'heading',
489 | depth: cap[2] === '=' ? 1 : 2,
490 | text: cap[1]
491 | });
492 | continue;
493 | }
494 |
495 | // top-level paragraph
496 | if (top && (cap = this.rules.paragraph.exec(src))) {
497 | src = src.substring(cap[0].length);
498 | this.tokens.push({
499 | type: 'paragraph',
500 | text: cap[1].charAt(cap[1].length - 1) === '\n'
501 | ? cap[1].slice(0, -1)
502 | : cap[1]
503 | });
504 | continue;
505 | }
506 |
507 | // text
508 | if (cap = this.rules.text.exec(src)) {
509 | // Top-level should never reach here.
510 | src = src.substring(cap[0].length);
511 | this.tokens.push({
512 | type: 'text',
513 | text: cap[0]
514 | });
515 | continue;
516 | }
517 |
518 | if (src) {
519 | throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
520 | }
521 | }
522 |
523 | return this.tokens;
524 | };
525 |
526 | /**
527 | * Inline-Level Grammar
528 | */
529 |
530 | var inline = {
531 | escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
532 | autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
533 | url: noop,
534 | tag: '^comment'
535 | + '|^[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
536 | + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
537 | + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g.
538 | + '|^' // declaration, e.g.
539 | + '|^', // CDATA section
540 | link: /^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,
541 | reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
542 | nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
543 | strong: /^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
544 | em: /^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
545 | code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
546 | br: /^( {2,}|\\)\n(?!\s*$)/,
547 | del: noop,
548 | text: /^(`+|[^`])[\s\S]*?(?=[\\?@\[\]\\^_`{|}~])/g;
552 |
553 | inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
554 | inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
555 | inline.autolink = edit(inline.autolink)
556 | .replace('scheme', inline._scheme)
557 | .replace('email', inline._email)
558 | .getRegex();
559 |
560 | inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
561 |
562 | inline.tag = edit(inline.tag)
563 | .replace('comment', block._comment)
564 | .replace('attribute', inline._attribute)
565 | .getRegex();
566 |
567 | inline._label = /(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/;
568 | inline._href = /\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/;
569 | inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
570 |
571 | inline.link = edit(inline.link)
572 | .replace('label', inline._label)
573 | .replace('href', inline._href)
574 | .replace('title', inline._title)
575 | .getRegex();
576 |
577 | inline.reflink = edit(inline.reflink)
578 | .replace('label', inline._label)
579 | .getRegex();
580 |
581 | /**
582 | * Normal Inline Grammar
583 | */
584 |
585 | inline.normal = merge({}, inline);
586 |
587 | /**
588 | * Pedantic Inline Grammar
589 | */
590 |
591 | inline.pedantic = merge({}, inline.normal, {
592 | strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
593 | em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
594 | link: edit(/^!?\[(label)\]\((.*?)\)/)
595 | .replace('label', inline._label)
596 | .getRegex(),
597 | reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
598 | .replace('label', inline._label)
599 | .getRegex()
600 | });
601 |
602 | /**
603 | * GFM Inline Grammar
604 | */
605 |
606 | inline.gfm = merge({}, inline.normal, {
607 | escape: edit(inline.escape).replace('])', '~|])').getRegex(),
608 | _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
609 | url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
610 | _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
611 | del: /^~+(?=\S)([\s\S]*?\S)~+/,
612 | text: edit(inline.text)
613 | .replace(']|', '~]|')
614 | .replace('|$', '|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&\'*+/=?^_`{\\|}~-]+@|$')
615 | .getRegex()
616 | });
617 |
618 | inline.gfm.url = edit(inline.gfm.url)
619 | .replace('email', inline.gfm._extended_email)
620 | .getRegex();
621 | /**
622 | * GFM + Line Breaks Inline Grammar
623 | */
624 |
625 | inline.breaks = merge({}, inline.gfm, {
626 | br: edit(inline.br).replace('{2,}', '*').getRegex(),
627 | text: edit(inline.gfm.text).replace('{2,}', '*').getRegex()
628 | });
629 |
630 | /**
631 | * Inline Lexer & Compiler
632 | */
633 |
634 | function InlineLexer(links, options) {
635 | this.options = options || marked.defaults;
636 | this.links = links;
637 | this.rules = inline.normal;
638 | this.renderer = this.options.renderer || new Renderer();
639 | this.renderer.options = this.options;
640 |
641 | if (!this.links) {
642 | throw new Error('Tokens array requires a `links` property.');
643 | }
644 |
645 | if (this.options.pedantic) {
646 | this.rules = inline.pedantic;
647 | } else if (this.options.gfm) {
648 | if (this.options.breaks) {
649 | this.rules = inline.breaks;
650 | } else {
651 | this.rules = inline.gfm;
652 | }
653 | }
654 | }
655 |
656 | /**
657 | * Expose Inline Rules
658 | */
659 |
660 | InlineLexer.rules = inline;
661 |
662 | /**
663 | * Static Lexing/Compiling Method
664 | */
665 |
666 | InlineLexer.output = function(src, links, options) {
667 | var inline = new InlineLexer(links, options);
668 | return inline.output(src);
669 | };
670 |
671 | /**
672 | * Lexing/Compiling
673 | */
674 |
675 | InlineLexer.prototype.output = function(src) {
676 | var out = '',
677 | link,
678 | text,
679 | href,
680 | title,
681 | cap,
682 | prevCapZero;
683 |
684 | while (src) {
685 | // escape
686 | if (cap = this.rules.escape.exec(src)) {
687 | src = src.substring(cap[0].length);
688 | out += cap[1];
689 | continue;
690 | }
691 |
692 | // autolink
693 | if (cap = this.rules.autolink.exec(src)) {
694 | src = src.substring(cap[0].length);
695 | if (cap[2] === '@') {
696 | text = escape(this.mangle(cap[1]));
697 | href = 'mailto:' + text;
698 | } else {
699 | text = escape(cap[1]);
700 | href = text;
701 | }
702 | out += this.renderer.link(href, null, text);
703 | continue;
704 | }
705 |
706 | // url (gfm)
707 | if (!this.inLink && (cap = this.rules.url.exec(src))) {
708 | if (cap[2] === '@') {
709 | text = escape(cap[0]);
710 | href = 'mailto:' + text;
711 | } else {
712 | // do extended autolink path validation
713 | do {
714 | prevCapZero = cap[0];
715 | cap[0] = this.rules._backpedal.exec(cap[0])[0];
716 | } while (prevCapZero !== cap[0]);
717 | text = escape(cap[0]);
718 | if (cap[1] === 'www.') {
719 | href = 'http://' + text;
720 | } else {
721 | href = text;
722 | }
723 | }
724 | src = src.substring(cap[0].length);
725 | out += this.renderer.link(href, null, text);
726 | continue;
727 | }
728 |
729 | // tag
730 | if (cap = this.rules.tag.exec(src)) {
731 | if (!this.inLink && /^/i.test(cap[0])) {
734 | this.inLink = false;
735 | }
736 | if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
737 | this.inRawBlock = true;
738 | } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
739 | this.inRawBlock = false;
740 | }
741 |
742 | src = src.substring(cap[0].length);
743 | out += this.options.sanitize
744 | ? this.options.sanitizer
745 | ? this.options.sanitizer(cap[0])
746 | : escape(cap[0])
747 | : cap[0]
748 | continue;
749 | }
750 |
751 | // link
752 | if (cap = this.rules.link.exec(src)) {
753 | src = src.substring(cap[0].length);
754 | this.inLink = true;
755 | href = cap[2];
756 | if (this.options.pedantic) {
757 | link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
758 |
759 | if (link) {
760 | href = link[1];
761 | title = link[3];
762 | } else {
763 | title = '';
764 | }
765 | } else {
766 | title = cap[3] ? cap[3].slice(1, -1) : '';
767 | }
768 | href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
769 | out += this.outputLink(cap, {
770 | href: InlineLexer.escapes(href),
771 | title: InlineLexer.escapes(title)
772 | });
773 | this.inLink = false;
774 | continue;
775 | }
776 |
777 | // reflink, nolink
778 | if ((cap = this.rules.reflink.exec(src))
779 | || (cap = this.rules.nolink.exec(src))) {
780 | src = src.substring(cap[0].length);
781 | link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
782 | link = this.links[link.toLowerCase()];
783 | if (!link || !link.href) {
784 | out += cap[0].charAt(0);
785 | src = cap[0].substring(1) + src;
786 | continue;
787 | }
788 | this.inLink = true;
789 | out += this.outputLink(cap, link);
790 | this.inLink = false;
791 | continue;
792 | }
793 |
794 | // strong
795 | if (cap = this.rules.strong.exec(src)) {
796 | src = src.substring(cap[0].length);
797 | out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1]));
798 | continue;
799 | }
800 |
801 | // em
802 | if (cap = this.rules.em.exec(src)) {
803 | src = src.substring(cap[0].length);
804 | out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]));
805 | continue;
806 | }
807 |
808 | // code
809 | if (cap = this.rules.code.exec(src)) {
810 | src = src.substring(cap[0].length);
811 | out += this.renderer.codespan(escape(cap[2].trim(), true));
812 | continue;
813 | }
814 |
815 | // br
816 | if (cap = this.rules.br.exec(src)) {
817 | src = src.substring(cap[0].length);
818 | out += this.renderer.br();
819 | continue;
820 | }
821 |
822 | // del (gfm)
823 | if (cap = this.rules.del.exec(src)) {
824 | src = src.substring(cap[0].length);
825 | out += this.renderer.del(this.output(cap[1]));
826 | continue;
827 | }
828 |
829 | // text
830 | if (cap = this.rules.text.exec(src)) {
831 | src = src.substring(cap[0].length);
832 | if (this.inRawBlock) {
833 | out += this.renderer.text(cap[0]);
834 | } else {
835 | out += this.renderer.text(escape(this.smartypants(cap[0])));
836 | }
837 | continue;
838 | }
839 |
840 | if (src) {
841 | throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
842 | }
843 | }
844 |
845 | return out;
846 | };
847 |
848 | InlineLexer.escapes = function(text) {
849 | return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
850 | }
851 |
852 | /**
853 | * Compile Link
854 | */
855 |
856 | InlineLexer.prototype.outputLink = function(cap, link) {
857 | var href = link.href,
858 | title = link.title ? escape(link.title) : null;
859 |
860 | return cap[0].charAt(0) !== '!'
861 | ? this.renderer.link(href, title, this.output(cap[1]))
862 | : this.renderer.image(href, title, escape(cap[1]));
863 | };
864 |
865 | /**
866 | * Smartypants Transformations
867 | */
868 |
869 | InlineLexer.prototype.smartypants = function(text) {
870 | if (!this.options.smartypants) return text;
871 | return text
872 | // em-dashes
873 | .replace(/---/g, '\u2014')
874 | // en-dashes
875 | .replace(/--/g, '\u2013')
876 | // opening singles
877 | .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
878 | // closing singles & apostrophes
879 | .replace(/'/g, '\u2019')
880 | // opening doubles
881 | .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
882 | // closing doubles
883 | .replace(/"/g, '\u201d')
884 | // ellipses
885 | .replace(/\.{3}/g, '\u2026');
886 | };
887 |
888 | /**
889 | * Mangle Links
890 | */
891 |
892 | InlineLexer.prototype.mangle = function(text) {
893 | if (!this.options.mangle) return text;
894 | var out = '',
895 | l = text.length,
896 | i = 0,
897 | ch;
898 |
899 | for (; i < l; i++) {
900 | ch = text.charCodeAt(i);
901 | if (Math.random() > 0.5) {
902 | ch = 'x' + ch.toString(16);
903 | }
904 | out += '' + ch + ';';
905 | }
906 |
907 | return out;
908 | };
909 |
910 | /**
911 | * Renderer
912 | */
913 |
914 | function Renderer(options) {
915 | this.options = options || marked.defaults;
916 | }
917 |
918 | Renderer.prototype.code = function(code, lang, escaped) {
919 | if (this.options.highlight) {
920 | var out = this.options.highlight(code, lang);
921 | if (out != null && out !== code) {
922 | escaped = true;
923 | code = out;
924 | }
925 | }
926 |
927 | if (!lang) {
928 | return ''
929 | + (escaped ? code : escape(code, true))
930 | + '
';
931 | }
932 |
933 | return ''
937 | + (escaped ? code : escape(code, true))
938 | + '
\n';
939 | };
940 |
941 | Renderer.prototype.blockquote = function(quote) {
942 | return '\n' + quote + '
\n';
943 | };
944 |
945 | Renderer.prototype.html = function(html) {
946 | return html;
947 | };
948 |
949 | Renderer.prototype.heading = function(text, level, raw) {
950 | if (this.options.headerIds) {
951 | return '\n';
961 | }
962 | // ignore IDs
963 | return '' + text + '\n';
964 | };
965 |
966 | Renderer.prototype.hr = function() {
967 | return this.options.xhtml ? '
\n' : '
\n';
968 | };
969 |
970 | Renderer.prototype.list = function(body, ordered, start) {
971 | var type = ordered ? 'ol' : 'ul',
972 | startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
973 | return '<' + type + startatt + '>\n' + body + '' + type + '>\n';
974 | };
975 |
976 | Renderer.prototype.listitem = function(text) {
977 | return '' + text + '\n';
978 | };
979 |
980 | Renderer.prototype.checkbox = function(checked) {
981 | return ' ';
986 | }
987 |
988 | Renderer.prototype.paragraph = function(text) {
989 | return '' + text + '
\n';
990 | };
991 |
992 | Renderer.prototype.table = function(header, body) {
993 | if (body) body = '' + body + '';
994 |
995 | return '\n'
996 | + '\n'
997 | + header
998 | + '\n'
999 | + body
1000 | + '
\n';
1001 | };
1002 |
1003 | Renderer.prototype.tablerow = function(content) {
1004 | return '\n' + content + '
\n';
1005 | };
1006 |
1007 | Renderer.prototype.tablecell = function(content, flags) {
1008 | var type = flags.header ? 'th' : 'td';
1009 | var tag = flags.align
1010 | ? '<' + type + ' align="' + flags.align + '">'
1011 | : '<' + type + '>';
1012 | return tag + content + '' + type + '>\n';
1013 | };
1014 |
1015 | // span level renderer
1016 | Renderer.prototype.strong = function(text) {
1017 | return '' + text + '';
1018 | };
1019 |
1020 | Renderer.prototype.em = function(text) {
1021 | return '' + text + '';
1022 | };
1023 |
1024 | Renderer.prototype.codespan = function(text) {
1025 | return '' + text + '
';
1026 | };
1027 |
1028 | Renderer.prototype.br = function() {
1029 | return this.options.xhtml ? '
' : '
';
1030 | };
1031 |
1032 | Renderer.prototype.del = function(text) {
1033 | return '' + text + '';
1034 | };
1035 |
1036 | Renderer.prototype.link = function(href, title, text) {
1037 | if (this.options.sanitize) {
1038 | try {
1039 | var prot = decodeURIComponent(unescape(href))
1040 | .replace(/[^\w:]/g, '')
1041 | .toLowerCase();
1042 | } catch (e) {
1043 | return text;
1044 | }
1045 | if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
1046 | return text;
1047 | }
1048 | }
1049 | if (this.options.baseUrl && !originIndependentUrl.test(href)) {
1050 | href = resolveUrl(this.options.baseUrl, href);
1051 | }
1052 | try {
1053 | href = encodeURI(href).replace(/%25/g, '%');
1054 | } catch (e) {
1055 | return text;
1056 | }
1057 | var out = '' + text + '';
1062 | return out;
1063 | };
1064 |
1065 | Renderer.prototype.image = function(href, title, text) {
1066 | if (this.options.baseUrl && !originIndependentUrl.test(href)) {
1067 | href = resolveUrl(this.options.baseUrl, href);
1068 | }
1069 | var out = '
' : '>';
1074 | return out;
1075 | };
1076 |
1077 | Renderer.prototype.text = function(text) {
1078 | return text;
1079 | };
1080 |
1081 | /**
1082 | * TextRenderer
1083 | * returns only the textual part of the token
1084 | */
1085 |
1086 | function TextRenderer() {}
1087 |
1088 | // no need for block level renderers
1089 |
1090 | TextRenderer.prototype.strong =
1091 | TextRenderer.prototype.em =
1092 | TextRenderer.prototype.codespan =
1093 | TextRenderer.prototype.del =
1094 | TextRenderer.prototype.text = function (text) {
1095 | return text;
1096 | }
1097 |
1098 | TextRenderer.prototype.link =
1099 | TextRenderer.prototype.image = function(href, title, text) {
1100 | return '' + text;
1101 | }
1102 |
1103 | TextRenderer.prototype.br = function() {
1104 | return '';
1105 | }
1106 |
1107 | /**
1108 | * Parsing & Compiling
1109 | */
1110 |
1111 | function Parser(options) {
1112 | this.tokens = [];
1113 | this.token = null;
1114 | this.options = options || marked.defaults;
1115 | this.options.renderer = this.options.renderer || new Renderer();
1116 | this.renderer = this.options.renderer;
1117 | this.renderer.options = this.options;
1118 | }
1119 |
1120 | /**
1121 | * Static Parse Method
1122 | */
1123 |
1124 | Parser.parse = function(src, options) {
1125 | var parser = new Parser(options);
1126 | return parser.parse(src);
1127 | };
1128 |
1129 | /**
1130 | * Parse Loop
1131 | */
1132 |
1133 | Parser.prototype.parse = function(src) {
1134 | this.inline = new InlineLexer(src.links, this.options);
1135 | // use an InlineLexer with a TextRenderer to extract pure text
1136 | this.inlineText = new InlineLexer(
1137 | src.links,
1138 | merge({}, this.options, {renderer: new TextRenderer()})
1139 | );
1140 | this.tokens = src.reverse();
1141 |
1142 | var out = '';
1143 | while (this.next()) {
1144 | out += this.tok();
1145 | }
1146 |
1147 | return out;
1148 | };
1149 |
1150 | /**
1151 | * Next Token
1152 | */
1153 |
1154 | Parser.prototype.next = function() {
1155 | return this.token = this.tokens.pop();
1156 | };
1157 |
1158 | /**
1159 | * Preview Next Token
1160 | */
1161 |
1162 | Parser.prototype.peek = function() {
1163 | return this.tokens[this.tokens.length - 1] || 0;
1164 | };
1165 |
1166 | /**
1167 | * Parse Text Tokens
1168 | */
1169 |
1170 | Parser.prototype.parseText = function() {
1171 | var body = this.token.text;
1172 |
1173 | while (this.peek().type === 'text') {
1174 | body += '\n' + this.next().text;
1175 | }
1176 |
1177 | return this.inline.output(body);
1178 | };
1179 |
1180 | /**
1181 | * Parse Current Token
1182 | */
1183 |
1184 | Parser.prototype.tok = function() {
1185 | switch (this.token.type) {
1186 | case 'space': {
1187 | return '';
1188 | }
1189 | case 'hr': {
1190 | return this.renderer.hr();
1191 | }
1192 | case 'heading': {
1193 | return this.renderer.heading(
1194 | this.inline.output(this.token.text),
1195 | this.token.depth,
1196 | unescape(this.inlineText.output(this.token.text)));
1197 | }
1198 | case 'code': {
1199 | return this.renderer.code(this.token.text,
1200 | this.token.lang,
1201 | this.token.escaped);
1202 | }
1203 | case 'table': {
1204 | var header = '',
1205 | body = '',
1206 | i,
1207 | row,
1208 | cell,
1209 | j;
1210 |
1211 | // header
1212 | cell = '';
1213 | for (i = 0; i < this.token.header.length; i++) {
1214 | cell += this.renderer.tablecell(
1215 | this.inline.output(this.token.header[i]),
1216 | { header: true, align: this.token.align[i] }
1217 | );
1218 | }
1219 | header += this.renderer.tablerow(cell);
1220 |
1221 | for (i = 0; i < this.token.cells.length; i++) {
1222 | row = this.token.cells[i];
1223 |
1224 | cell = '';
1225 | for (j = 0; j < row.length; j++) {
1226 | cell += this.renderer.tablecell(
1227 | this.inline.output(row[j]),
1228 | { header: false, align: this.token.align[j] }
1229 | );
1230 | }
1231 |
1232 | body += this.renderer.tablerow(cell);
1233 | }
1234 | return this.renderer.table(header, body);
1235 | }
1236 | case 'blockquote_start': {
1237 | body = '';
1238 |
1239 | while (this.next().type !== 'blockquote_end') {
1240 | body += this.tok();
1241 | }
1242 |
1243 | return this.renderer.blockquote(body);
1244 | }
1245 | case 'list_start': {
1246 | body = '';
1247 | var ordered = this.token.ordered,
1248 | start = this.token.start;
1249 |
1250 | while (this.next().type !== 'list_end') {
1251 | body += this.tok();
1252 | }
1253 |
1254 | return this.renderer.list(body, ordered, start);
1255 | }
1256 | case 'list_item_start': {
1257 | body = '';
1258 | var loose = this.token.loose;
1259 |
1260 | if (this.token.task) {
1261 | body += this.renderer.checkbox(this.token.checked);
1262 | }
1263 |
1264 | while (this.next().type !== 'list_item_end') {
1265 | body += !loose && this.token.type === 'text'
1266 | ? this.parseText()
1267 | : this.tok();
1268 | }
1269 |
1270 | return this.renderer.listitem(body);
1271 | }
1272 | case 'html': {
1273 | // TODO parse inline content if parameter markdown=1
1274 | return this.renderer.html(this.token.text);
1275 | }
1276 | case 'paragraph': {
1277 | return this.renderer.paragraph(this.inline.output(this.token.text));
1278 | }
1279 | case 'text': {
1280 | return this.renderer.paragraph(this.parseText());
1281 | }
1282 | }
1283 | };
1284 |
1285 | /**
1286 | * Helpers
1287 | */
1288 |
1289 | function escape(html, encode) {
1290 | if (encode) {
1291 | if (escape.escapeTest.test(html)) {
1292 | return html.replace(escape.escapeReplace, function (ch) { return escape.replacements[ch] });
1293 | }
1294 | } else {
1295 | if (escape.escapeTestNoEncode.test(html)) {
1296 | return html.replace(escape.escapeReplaceNoEncode, function (ch) { return escape.replacements[ch] });
1297 | }
1298 | }
1299 |
1300 | return html;
1301 | }
1302 |
1303 | escape.escapeTest = /[&<>"']/;
1304 | escape.escapeReplace = /[&<>"']/g;
1305 | escape.replacements = {
1306 | '&': '&',
1307 | '<': '<',
1308 | '>': '>',
1309 | '"': '"',
1310 | "'": '''
1311 | };
1312 |
1313 | escape.escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
1314 | escape.escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
1315 |
1316 | function unescape(html) {
1317 | // explicitly match decimal, hex, and named HTML entities
1318 | return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
1319 | n = n.toLowerCase();
1320 | if (n === 'colon') return ':';
1321 | if (n.charAt(0) === '#') {
1322 | return n.charAt(1) === 'x'
1323 | ? String.fromCharCode(parseInt(n.substring(2), 16))
1324 | : String.fromCharCode(+n.substring(1));
1325 | }
1326 | return '';
1327 | });
1328 | }
1329 |
1330 | function edit(regex, opt) {
1331 | regex = regex.source || regex;
1332 | opt = opt || '';
1333 | return {
1334 | replace: function(name, val) {
1335 | val = val.source || val;
1336 | val = val.replace(/(^|[^\[])\^/g, '$1');
1337 | regex = regex.replace(name, val);
1338 | return this;
1339 | },
1340 | getRegex: function() {
1341 | return new RegExp(regex, opt);
1342 | }
1343 | };
1344 | }
1345 |
1346 | function resolveUrl(base, href) {
1347 | if (!baseUrls[' ' + base]) {
1348 | // we can ignore everything in base after the last slash of its path component,
1349 | // but we might need to add _that_
1350 | // https://tools.ietf.org/html/rfc3986#section-3
1351 | if (/^[^:]+:\/*[^/]*$/.test(base)) {
1352 | baseUrls[' ' + base] = base + '/';
1353 | } else {
1354 | baseUrls[' ' + base] = rtrim(base, '/', true);
1355 | }
1356 | }
1357 | base = baseUrls[' ' + base];
1358 |
1359 | if (href.slice(0, 2) === '//') {
1360 | return base.replace(/:[\s\S]*/, ':') + href;
1361 | } else if (href.charAt(0) === '/') {
1362 | return base.replace(/(:\/*[^/]*)[\s\S]*/, '$1') + href;
1363 | } else {
1364 | return base + href;
1365 | }
1366 | }
1367 | var baseUrls = {};
1368 | var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
1369 |
1370 | function noop() {}
1371 | noop.exec = noop;
1372 |
1373 | function merge(obj) {
1374 | var i = 1,
1375 | target,
1376 | key;
1377 |
1378 | for (; i < arguments.length; i++) {
1379 | target = arguments[i];
1380 | for (key in target) {
1381 | if (Object.prototype.hasOwnProperty.call(target, key)) {
1382 | obj[key] = target[key];
1383 | }
1384 | }
1385 | }
1386 |
1387 | return obj;
1388 | }
1389 |
1390 | function splitCells(tableRow, count) {
1391 | // ensure that every cell-delimiting pipe has a space
1392 | // before it to distinguish it from an escaped pipe
1393 | var row = tableRow.replace(/\|/g, function (match, offset, str) {
1394 | var escaped = false,
1395 | curr = offset;
1396 | while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
1397 | if (escaped) {
1398 | // odd number of slashes means | is escaped
1399 | // so we leave it alone
1400 | return '|';
1401 | } else {
1402 | // add space before unescaped |
1403 | return ' |';
1404 | }
1405 | }),
1406 | cells = row.split(/ \|/),
1407 | i = 0;
1408 |
1409 | if (cells.length > count) {
1410 | cells.splice(count);
1411 | } else {
1412 | while (cells.length < count) cells.push('');
1413 | }
1414 |
1415 | for (; i < cells.length; i++) {
1416 | // leading or trailing whitespace is ignored per the gfm spec
1417 | cells[i] = cells[i].trim().replace(/\\\|/g, '|');
1418 | }
1419 | return cells;
1420 | }
1421 |
1422 | // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
1423 | // /c*$/ is vulnerable to REDOS.
1424 | // invert: Remove suffix of non-c chars instead. Default falsey.
1425 | function rtrim(str, c, invert) {
1426 | if (str.length === 0) {
1427 | return '';
1428 | }
1429 |
1430 | // Length of suffix matching the invert condition.
1431 | var suffLen = 0;
1432 |
1433 | // Step left until we fail to match the invert condition.
1434 | while (suffLen < str.length) {
1435 | var currChar = str.charAt(str.length - suffLen - 1);
1436 | if (currChar === c && !invert) {
1437 | suffLen++;
1438 | } else if (currChar !== c && invert) {
1439 | suffLen++;
1440 | } else {
1441 | break;
1442 | }
1443 | }
1444 |
1445 | return str.substr(0, str.length - suffLen);
1446 | }
1447 |
1448 | /**
1449 | * Marked
1450 | */
1451 |
1452 | function marked(src, opt, callback) {
1453 | // throw error in case of non string input
1454 | if (typeof src === 'undefined' || src === null) {
1455 | throw new Error('marked(): input parameter is undefined or null');
1456 | }
1457 | if (typeof src !== 'string') {
1458 | throw new Error('marked(): input parameter is of type '
1459 | + Object.prototype.toString.call(src) + ', string expected');
1460 | }
1461 |
1462 | if (callback || typeof opt === 'function') {
1463 | if (!callback) {
1464 | callback = opt;
1465 | opt = null;
1466 | }
1467 |
1468 | opt = merge({}, marked.defaults, opt || {});
1469 |
1470 | var highlight = opt.highlight,
1471 | tokens,
1472 | pending,
1473 | i = 0;
1474 |
1475 | try {
1476 | tokens = Lexer.lex(src, opt)
1477 | } catch (e) {
1478 | return callback(e);
1479 | }
1480 |
1481 | pending = tokens.length;
1482 |
1483 | var done = function(err) {
1484 | if (err) {
1485 | opt.highlight = highlight;
1486 | return callback(err);
1487 | }
1488 |
1489 | var out;
1490 |
1491 | try {
1492 | out = Parser.parse(tokens, opt);
1493 | } catch (e) {
1494 | err = e;
1495 | }
1496 |
1497 | opt.highlight = highlight;
1498 |
1499 | return err
1500 | ? callback(err)
1501 | : callback(null, out);
1502 | };
1503 |
1504 | if (!highlight || highlight.length < 3) {
1505 | return done();
1506 | }
1507 |
1508 | delete opt.highlight;
1509 |
1510 | if (!pending) return done();
1511 |
1512 | for (; i < tokens.length; i++) {
1513 | (function(token) {
1514 | if (token.type !== 'code') {
1515 | return --pending || done();
1516 | }
1517 | return highlight(token.text, token.lang, function(err, code) {
1518 | if (err) return done(err);
1519 | if (code == null || code === token.text) {
1520 | return --pending || done();
1521 | }
1522 | token.text = code;
1523 | token.escaped = true;
1524 | --pending || done();
1525 | });
1526 | })(tokens[i]);
1527 | }
1528 |
1529 | return;
1530 | }
1531 | try {
1532 | if (opt) opt = merge({}, marked.defaults, opt);
1533 | return Parser.parse(Lexer.lex(src, opt), opt);
1534 | } catch (e) {
1535 | e.message += '\nPlease report this to https://github.com/markedjs/marked.';
1536 | if ((opt || marked.defaults).silent) {
1537 | return 'An error occurred:
'
1538 | + escape(e.message + '', true)
1539 | + '
';
1540 | }
1541 | throw e;
1542 | }
1543 | }
1544 |
1545 | /**
1546 | * Options
1547 | */
1548 |
1549 | marked.options =
1550 | marked.setOptions = function(opt) {
1551 | merge(marked.defaults, opt);
1552 | return marked;
1553 | };
1554 |
1555 | marked.getDefaults = function () {
1556 | return {
1557 | baseUrl: null,
1558 | breaks: false,
1559 | gfm: true,
1560 | headerIds: true,
1561 | headerPrefix: '',
1562 | highlight: null,
1563 | langPrefix: 'language-',
1564 | mangle: true,
1565 | pedantic: false,
1566 | renderer: new Renderer(),
1567 | sanitize: false,
1568 | sanitizer: null,
1569 | silent: false,
1570 | smartLists: false,
1571 | smartypants: false,
1572 | tables: true,
1573 | xhtml: false
1574 | };
1575 | }
1576 |
1577 | marked.defaults = marked.getDefaults();
1578 |
1579 | /**
1580 | * Expose
1581 | */
1582 |
1583 | marked.Parser = Parser;
1584 | marked.parser = Parser.parse;
1585 |
1586 | marked.Renderer = Renderer;
1587 | marked.TextRenderer = TextRenderer;
1588 |
1589 | marked.Lexer = Lexer;
1590 | marked.lexer = Lexer.lex;
1591 |
1592 | marked.InlineLexer = InlineLexer;
1593 | marked.inlineLexer = InlineLexer.output;
1594 |
1595 | marked.parse = marked;
1596 |
1597 | if (typeof module !== 'undefined' && typeof exports === 'object') {
1598 | module.exports = marked;
1599 | } else if (typeof define === 'function' && define.amd) {
1600 | define(function() { return marked; });
1601 | } else {
1602 | root.marked = marked;
1603 | }
1604 | })(this || (typeof window !== 'undefined' ? window : global));
1605 |
--------------------------------------------------------------------------------
/templates/resume-for-cpp/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "resume-diygod"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/resume-for-cpp/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "html-title": "XXX-C++",
3 | "name": "XXX",
4 | "gender": "男",
5 | "birth": "19XX.XX",
6 | "slogan": "hhh",
7 | "school": "XXU",
8 | "apply-position": "C++工程师",
9 | "contact":{
10 | "wechat": "hhh",
11 | "qq": "10001",
12 | "email": "xxx@email.xxu.edu.cn",
13 | "blog": "https://github.com",
14 | "github": "~~~",
15 | "cellphone": "13800138000"
16 | },
17 | "note": [
18 | "hhh"
19 | ],
20 | "educations": [
21 | {
22 | "school": "XX大学 XXXX (20XX.9 - 20XX.6)",
23 | "info": [
24 | "...",
25 | "..."
26 | ]
27 | }
28 | ],
29 | "exps": [
30 | {
31 | "company": "XXX",
32 | "img": "",
33 | "info": "",
34 | "projects": [
35 | {
36 | "name": "Project1",
37 | "info": [
38 | "Situation: \n\n",
39 | "Task: \n\n",
40 | "Action: \n\n",
41 | "Result: \n\n"
42 | ]
43 | },
44 | {
45 | "name": "Project2",
46 | "info": [
47 | "Situation: \n\n",
48 | "Task: \n\n",
49 | "Action: \n\n",
50 | "Result: \n\n"
51 | ]
52 | }
53 | ]
54 | }
55 | ],
56 | "skills": [
57 | {
58 | "type": "type1",
59 | "info": "精通..."
60 | },
61 | {
62 | "type": "type2",
63 | "info": "熟悉..."
64 | }
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/templates/resume-for-cpp/img/resume-head.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-for-cpp/img/resume-head.jpg
--------------------------------------------------------------------------------
/templates/resume-for-java/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "resume-diygod"
3 | }
4 |
--------------------------------------------------------------------------------
/templates/resume-for-java/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "html-title": "extends demo",
3 | "name": "extends demo",
4 | "gender": "男",
5 | "birth": "19XX.XX",
6 | "slogan": "hhh",
7 | "school": "XXU",
8 | "apply-position": "Java工程师",
9 | "contact":{
10 | "wechat": "hhh",
11 | "qq": "10001",
12 | "email": "xxx@email.xxu.edu.cn",
13 | "blog": "https://github.com",
14 | "github": "~~~",
15 | "cellphone": "13800138000"
16 | },
17 | "note": [
18 | "hhh"
19 | ],
20 | "educations": [
21 | {
22 | "school": "XX大学 XXXX (20XX.9 - 20XX.6)",
23 | "info": [
24 | "...",
25 | "..."
26 | ]
27 | }
28 | ],
29 | "exps": [
30 | {
31 | "company": "XXX",
32 | "img": "",
33 | "info": "",
34 | "projects": [
35 | {
36 | "name": "Project1",
37 | "info": [
38 | "Situation: \n\n",
39 | "Task: \n\n",
40 | "Action: \n\n",
41 | "Result: \n\n"
42 | ]
43 | },
44 | {
45 | "name": "Project2",
46 | "info": [
47 | "Situation: \n\n",
48 | "Task: \n\n",
49 | "Action: \n\n",
50 | "Result: \n\n"
51 | ]
52 | }
53 | ]
54 | }
55 | ],
56 | "skills": [
57 | {
58 | "type": "type1",
59 | "info": "精通..."
60 | },
61 | {
62 | "type": "type2",
63 | "info": "熟悉..."
64 | }
65 | ]
66 | }
67 |
--------------------------------------------------------------------------------
/templates/resume-for-java/img/resume-head.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NoCLin/vue-json-template/9eda58aeb6fd77f7c833ca2b70d1fc3954f14c59/templates/resume-for-java/img/resume-head.jpg
--------------------------------------------------------------------------------