├── .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 |
64 | 65 |
66 | {{template}} 67 |
68 | 69 | 70 |
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 | 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 | 4 | Copyright (C) 2015 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /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 | 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]*?(?:[^\\n]*\\n+|$)' // (1) 25 | + '|comment[^\\n]*(\\n+|$)' // (2) 26 | + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) 27 | + '|\\n*' // (4) 28 | + '|\\n*' // (5) 29 | + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) 30 | + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag 31 | + '|(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag 32 | + ')', 33 | def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\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]+? *(?:\\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: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\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 | + '|^' // 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 '' 957 | + text 958 | + '\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 + '\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 + '\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 = '
    '; 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 = '' + text + '' : '>'; 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 --------------------------------------------------------------------------------