├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── blog.sql ├── build.sh ├── conf ├── config.go └── dev.yml ├── go.mod ├── go.sum ├── internal ├── daos │ ├── category.go │ ├── init.go │ ├── page.go │ ├── post.go │ ├── tag.go │ └── user.go ├── es │ ├── blog.go │ └── init.go ├── handler │ ├── admin │ │ ├── auth.go │ │ ├── category.go │ │ ├── page.go │ │ ├── post.go │ │ └── tag.go │ └── front │ │ ├── page.go │ │ ├── post.go │ │ └── tag.go ├── model │ ├── category.go │ ├── configure.go │ ├── page.go │ ├── post.go │ ├── tag.go │ └── user.go ├── pkg │ └── template.go └── routers │ ├── middleware │ ├── auth.go │ ├── log.go │ └── recover.go │ └── router.go ├── main.go ├── pkg ├── cache │ └── cache.go ├── ding │ └── ding.go ├── logger │ ├── config.go │ ├── logger.go │ └── zap.go ├── mail │ ├── mail.go │ └── mail_test.go ├── redis │ ├── redis.go │ └── redis_test.go ├── shutdown │ └── shutdown.go ├── storage │ ├── elasticsearch │ │ ├── README.md │ │ └── elasticsearch.go │ ├── mongodb │ │ └── mongodb.go │ ├── mysql │ │ └── mysql.go │ └── orm │ │ └── orm.go ├── time_parse │ ├── time_parse.go │ └── time_parse_test.go └── utils │ ├── README.md │ ├── file.go │ ├── ip.go │ ├── ip_test.go │ ├── pagination.go │ ├── slice.go │ ├── slice_test.go │ ├── string.go │ ├── time.go │ ├── utils.go │ ├── utils_test.go │ └── valid.go ├── startup.sh ├── static ├── admin │ ├── assets │ │ ├── all.min.js │ │ ├── demo │ │ │ ├── chart-area-demo.js │ │ │ ├── chart-bar-demo.js │ │ │ ├── chart-pie-demo.js │ │ │ └── datatables-demo.js │ │ └── img │ │ │ └── error-404-monochrome.svg │ ├── css │ │ └── styles.css │ └── js │ │ ├── Simple example - Editor.md examples.html │ │ ├── Simple example - Editor.md examples_files │ │ ├── addons.min.js │ │ ├── bootstrap.min.css │ │ ├── codemirror.min.css │ │ ├── codemirror.min.js │ │ ├── dialog.css │ │ ├── editormd.css │ │ ├── editormd.min.js │ │ ├── jquery.min.js │ │ ├── marked.min.js │ │ ├── matchesonscrollbar.css │ │ ├── modes.min.js │ │ ├── prettify.min.js │ │ └── style.css │ │ ├── all.min.js │ │ ├── bootstrap.bundle.min.js │ │ ├── datatables-simple-demo.js │ │ ├── scripts.js │ │ └── simple-datatables.js ├── css │ ├── bootstrap.min.css │ ├── gitalk.css │ └── style.css ├── favicon.ico ├── fonts │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 ├── js │ ├── bootstrap.min.js │ ├── gitalk.min.js │ └── jquery.min.js └── md │ ├── .gitignore │ ├── .jshintrc │ ├── BUGS.md │ ├── CHANGE.md │ ├── Gulpfile.js │ ├── LICENSE │ ├── README.md │ ├── bower.json │ ├── css │ ├── editormd.css │ ├── editormd.logo.css │ ├── editormd.logo.min.css │ ├── editormd.min.css │ ├── editormd.preview.css │ ├── editormd.preview.min.css │ └── style.css │ ├── docs │ ├── editormd.js.html │ ├── fonts │ │ ├── OpenSans-Bold-webfont.eot │ │ ├── OpenSans-Bold-webfont.svg │ │ ├── OpenSans-Bold-webfont.woff │ │ ├── OpenSans-BoldItalic-webfont.eot │ │ ├── OpenSans-BoldItalic-webfont.svg │ │ ├── OpenSans-BoldItalic-webfont.woff │ │ ├── OpenSans-Italic-webfont.eot │ │ ├── OpenSans-Italic-webfont.svg │ │ ├── OpenSans-Italic-webfont.woff │ │ ├── OpenSans-Light-webfont.eot │ │ ├── OpenSans-Light-webfont.svg │ │ ├── OpenSans-Light-webfont.woff │ │ ├── OpenSans-LightItalic-webfont.eot │ │ ├── OpenSans-LightItalic-webfont.svg │ │ ├── OpenSans-LightItalic-webfont.woff │ │ ├── OpenSans-Regular-webfont.eot │ │ ├── OpenSans-Regular-webfont.svg │ │ └── OpenSans-Regular-webfont.woff │ ├── index.html │ ├── scripts │ │ ├── linenumber.js │ │ └── prettify │ │ │ ├── Apache-License-2.0.txt │ │ │ ├── lang-css.js │ │ │ └── prettify.js │ └── styles │ │ ├── jsdoc-default.css │ │ ├── prettify-jsdoc.css │ │ └── prettify-tomorrow.css │ ├── editormd.amd.js │ ├── editormd.amd.min.js │ ├── editormd.js │ ├── editormd.min.js │ ├── examples │ ├── @links.html │ ├── auto-height.html │ ├── change-mode.html │ ├── code-fold.html │ ├── css │ │ └── style.css │ ├── custom-keyboard-shortcuts.html │ ├── custom-toolbar.html │ ├── define-plugin.html │ ├── delay-renderer-preview.html │ ├── dynamic-create-editormd.html │ ├── emoji.html │ ├── extends.html │ ├── external-use.html │ ├── flowchart.html │ ├── form-get-value.html │ ├── full.html │ ├── goto-line.html │ ├── html-preview-markdown-to-html-custom-toc-container.html │ ├── html-preview-markdown-to-html.html │ ├── html-tags-decode.html │ ├── image-cross-domain-upload.html │ ├── image-upload.html │ ├── images │ │ ├── 4.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ └── editormd-screenshot.png │ ├── index.html │ ├── js │ │ ├── jquery.min.js │ │ ├── require.min.js │ │ ├── sea.js │ │ ├── seajs-main.js │ │ └── zepto.min.js │ ├── katex.html │ ├── manually-load-modules.html │ ├── multi-editormd.html │ ├── multi-languages.html │ ├── on-off.html │ ├── onchange.html │ ├── onfullscreen.html │ ├── onload.html │ ├── onpreviewing-onpreviewed.html │ ├── onresize.html │ ├── onscroll-onpreviewscroll.html │ ├── onwatch-onunwatch.html │ ├── page-break.html │ ├── php │ │ ├── cross-domain-upload.php │ │ ├── editormd.uploader.class.php │ │ ├── post.php │ │ ├── upload.php │ │ └── upload_callback.html │ ├── readonly.html │ ├── resettings.html │ ├── search-replace.html │ ├── sequence-diagram.html │ ├── set-get-replace-selection.html │ ├── simple.html │ ├── sync-scrolling.html │ ├── task-lists.html │ ├── test.md │ ├── themes.html │ ├── toc.html │ ├── toolbar-auto-fixed.html │ ├── use-requirejs.html │ ├── use-seajs.html │ └── use-zepto.html │ ├── fonts │ ├── FontAwesome.otf │ ├── editormd-logo.eot │ ├── editormd-logo.svg │ ├── editormd-logo.ttf │ ├── editormd-logo.woff │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 │ ├── images │ ├── 4.jpg │ ├── 7.jpg │ ├── 8.jpg │ ├── loading.gif │ ├── loading@2x.gif │ ├── loading@3x.gif │ └── logos │ │ ├── editormd-favicon-16x16.ico │ │ ├── editormd-favicon-24x24.ico │ │ ├── editormd-favicon-32x32.ico │ │ ├── editormd-favicon-48x48.ico │ │ ├── editormd-favicon-64x64.ico │ │ ├── editormd-logo-114x114.png │ │ ├── editormd-logo-120x120.png │ │ ├── editormd-logo-144x144.png │ │ ├── editormd-logo-16x16.png │ │ ├── editormd-logo-180x180.png │ │ ├── editormd-logo-240x240.png │ │ ├── editormd-logo-24x24.png │ │ ├── editormd-logo-320x320.png │ │ ├── editormd-logo-32x32.png │ │ ├── editormd-logo-48x48.png │ │ ├── editormd-logo-57x57.png │ │ ├── editormd-logo-64x64.png │ │ ├── editormd-logo-72x72.png │ │ ├── editormd-logo-96x96.png │ │ └── vi.png │ ├── js │ ├── jquery.min.js │ ├── require.min.js │ ├── sea.js │ ├── seajs-main.js │ └── zepto.min.js │ ├── languages │ ├── en.js │ └── zh-tw.js │ ├── lib │ ├── codemirror │ │ ├── AUTHORS │ │ ├── LICENSE │ │ ├── README.md │ │ ├── addon │ │ │ ├── comment │ │ │ │ ├── comment.js │ │ │ │ └── continuecomment.js │ │ │ ├── dialog │ │ │ │ ├── dialog.css │ │ │ │ └── dialog.js │ │ │ ├── display │ │ │ │ ├── fullscreen.css │ │ │ │ ├── fullscreen.js │ │ │ │ ├── panel.js │ │ │ │ ├── placeholder.js │ │ │ │ └── rulers.js │ │ │ ├── edit │ │ │ │ ├── closebrackets.js │ │ │ │ ├── closetag.js │ │ │ │ ├── continuelist.js │ │ │ │ ├── matchbrackets.js │ │ │ │ ├── matchtags.js │ │ │ │ └── trailingspace.js │ │ │ ├── fold │ │ │ │ ├── brace-fold.js │ │ │ │ ├── comment-fold.js │ │ │ │ ├── foldcode.js │ │ │ │ ├── foldgutter.css │ │ │ │ ├── foldgutter.js │ │ │ │ ├── indent-fold.js │ │ │ │ ├── markdown-fold.js │ │ │ │ └── xml-fold.js │ │ │ ├── hint │ │ │ │ ├── anyword-hint.js │ │ │ │ ├── css-hint.js │ │ │ │ ├── html-hint.js │ │ │ │ ├── javascript-hint.js │ │ │ │ ├── show-hint.css │ │ │ │ ├── show-hint.js │ │ │ │ ├── sql-hint.js │ │ │ │ └── xml-hint.js │ │ │ ├── lint │ │ │ │ ├── coffeescript-lint.js │ │ │ │ ├── css-lint.js │ │ │ │ ├── javascript-lint.js │ │ │ │ ├── json-lint.js │ │ │ │ ├── lint.css │ │ │ │ ├── lint.js │ │ │ │ └── yaml-lint.js │ │ │ ├── merge │ │ │ │ ├── merge.css │ │ │ │ └── merge.js │ │ │ ├── mode │ │ │ │ ├── loadmode.js │ │ │ │ ├── multiplex.js │ │ │ │ ├── multiplex_test.js │ │ │ │ ├── overlay.js │ │ │ │ └── simple.js │ │ │ ├── runmode │ │ │ │ ├── colorize.js │ │ │ │ ├── runmode-standalone.js │ │ │ │ ├── runmode.js │ │ │ │ └── runmode.node.js │ │ │ ├── scroll │ │ │ │ ├── annotatescrollbar.js │ │ │ │ ├── scrollpastend.js │ │ │ │ ├── simplescrollbars.css │ │ │ │ └── simplescrollbars.js │ │ │ ├── search │ │ │ │ ├── match-highlighter.js │ │ │ │ ├── matchesonscrollbar.css │ │ │ │ ├── matchesonscrollbar.js │ │ │ │ ├── search.js │ │ │ │ └── searchcursor.js │ │ │ ├── selection │ │ │ │ ├── active-line.js │ │ │ │ ├── mark-selection.js │ │ │ │ └── selection-pointer.js │ │ │ ├── tern │ │ │ │ ├── tern.css │ │ │ │ ├── tern.js │ │ │ │ └── worker.js │ │ │ └── wrap │ │ │ │ └── hardwrap.js │ │ ├── addons.min.js │ │ ├── bower.json │ │ ├── codemirror.min.css │ │ ├── codemirror.min.js │ │ ├── lib │ │ │ ├── codemirror.css │ │ │ └── codemirror.js │ │ ├── mode │ │ │ ├── apl │ │ │ │ ├── apl.js │ │ │ │ └── index.html │ │ │ ├── asterisk │ │ │ │ ├── asterisk.js │ │ │ │ └── index.html │ │ │ ├── clike │ │ │ │ ├── clike.js │ │ │ │ ├── index.html │ │ │ │ └── scala.html │ │ │ ├── clojure │ │ │ │ ├── clojure.js │ │ │ │ └── index.html │ │ │ ├── cobol │ │ │ │ ├── cobol.js │ │ │ │ └── index.html │ │ │ ├── coffeescript │ │ │ │ ├── coffeescript.js │ │ │ │ └── index.html │ │ │ ├── commonlisp │ │ │ │ ├── commonlisp.js │ │ │ │ └── index.html │ │ │ ├── css │ │ │ │ ├── css.js │ │ │ │ ├── index.html │ │ │ │ ├── less.html │ │ │ │ ├── less_test.js │ │ │ │ ├── scss.html │ │ │ │ ├── scss_test.js │ │ │ │ └── test.js │ │ │ ├── cypher │ │ │ │ ├── cypher.js │ │ │ │ └── index.html │ │ │ ├── d │ │ │ │ ├── d.js │ │ │ │ └── index.html │ │ │ ├── dart │ │ │ │ ├── dart.js │ │ │ │ └── index.html │ │ │ ├── diff │ │ │ │ ├── diff.js │ │ │ │ └── index.html │ │ │ ├── django │ │ │ │ ├── django.js │ │ │ │ └── index.html │ │ │ ├── dockerfile │ │ │ │ ├── dockerfile.js │ │ │ │ └── index.html │ │ │ ├── dtd │ │ │ │ ├── dtd.js │ │ │ │ └── index.html │ │ │ ├── dylan │ │ │ │ ├── dylan.js │ │ │ │ └── index.html │ │ │ ├── ebnf │ │ │ │ ├── ebnf.js │ │ │ │ └── index.html │ │ │ ├── ecl │ │ │ │ ├── ecl.js │ │ │ │ └── index.html │ │ │ ├── eiffel │ │ │ │ ├── eiffel.js │ │ │ │ └── index.html │ │ │ ├── erlang │ │ │ │ ├── erlang.js │ │ │ │ └── index.html │ │ │ ├── forth │ │ │ │ ├── forth.js │ │ │ │ └── index.html │ │ │ ├── fortran │ │ │ │ ├── fortran.js │ │ │ │ └── index.html │ │ │ ├── gas │ │ │ │ ├── gas.js │ │ │ │ └── index.html │ │ │ ├── gfm │ │ │ │ ├── gfm.js │ │ │ │ ├── index.html │ │ │ │ └── test.js │ │ │ ├── gherkin │ │ │ │ ├── gherkin.js │ │ │ │ └── index.html │ │ │ ├── go │ │ │ │ ├── go.js │ │ │ │ └── index.html │ │ │ ├── groovy │ │ │ │ ├── groovy.js │ │ │ │ └── index.html │ │ │ ├── haml │ │ │ │ ├── haml.js │ │ │ │ ├── index.html │ │ │ │ └── test.js │ │ │ ├── haskell │ │ │ │ ├── haskell.js │ │ │ │ └── index.html │ │ │ ├── haxe │ │ │ │ ├── haxe.js │ │ │ │ └── index.html │ │ │ ├── htmlembedded │ │ │ │ ├── htmlembedded.js │ │ │ │ └── index.html │ │ │ ├── htmlmixed │ │ │ │ ├── htmlmixed.js │ │ │ │ └── index.html │ │ │ ├── http │ │ │ │ ├── http.js │ │ │ │ └── index.html │ │ │ ├── idl │ │ │ │ ├── idl.js │ │ │ │ └── index.html │ │ │ ├── index.html │ │ │ ├── jade │ │ │ │ ├── index.html │ │ │ │ └── jade.js │ │ │ ├── javascript │ │ │ │ ├── index.html │ │ │ │ ├── javascript.js │ │ │ │ ├── json-ld.html │ │ │ │ ├── test.js │ │ │ │ └── typescript.html │ │ │ ├── jinja2 │ │ │ │ ├── index.html │ │ │ │ └── jinja2.js │ │ │ ├── julia │ │ │ │ ├── index.html │ │ │ │ └── julia.js │ │ │ ├── kotlin │ │ │ │ ├── index.html │ │ │ │ └── kotlin.js │ │ │ ├── livescript │ │ │ │ ├── index.html │ │ │ │ └── livescript.js │ │ │ ├── lua │ │ │ │ ├── index.html │ │ │ │ └── lua.js │ │ │ ├── markdown │ │ │ │ ├── index.html │ │ │ │ ├── markdown.js │ │ │ │ └── test.js │ │ │ ├── meta.js │ │ │ ├── mirc │ │ │ │ ├── index.html │ │ │ │ └── mirc.js │ │ │ ├── mllike │ │ │ │ ├── index.html │ │ │ │ └── mllike.js │ │ │ ├── modelica │ │ │ │ ├── index.html │ │ │ │ └── modelica.js │ │ │ ├── nginx │ │ │ │ ├── index.html │ │ │ │ └── nginx.js │ │ │ ├── ntriples │ │ │ │ ├── index.html │ │ │ │ └── ntriples.js │ │ │ ├── octave │ │ │ │ ├── index.html │ │ │ │ └── octave.js │ │ │ ├── pascal │ │ │ │ ├── index.html │ │ │ │ └── pascal.js │ │ │ ├── pegjs │ │ │ │ ├── index.html │ │ │ │ └── pegjs.js │ │ │ ├── perl │ │ │ │ ├── index.html │ │ │ │ └── perl.js │ │ │ ├── php │ │ │ │ ├── index.html │ │ │ │ ├── php.js │ │ │ │ └── test.js │ │ │ ├── pig │ │ │ │ ├── index.html │ │ │ │ └── pig.js │ │ │ ├── properties │ │ │ │ ├── index.html │ │ │ │ └── properties.js │ │ │ ├── puppet │ │ │ │ ├── index.html │ │ │ │ └── puppet.js │ │ │ ├── python │ │ │ │ ├── index.html │ │ │ │ └── python.js │ │ │ ├── q │ │ │ │ ├── index.html │ │ │ │ └── q.js │ │ │ ├── r │ │ │ │ ├── index.html │ │ │ │ └── r.js │ │ │ ├── rpm │ │ │ │ ├── changes │ │ │ │ │ └── index.html │ │ │ │ ├── index.html │ │ │ │ └── rpm.js │ │ │ ├── rst │ │ │ │ ├── index.html │ │ │ │ └── rst.js │ │ │ ├── ruby │ │ │ │ ├── index.html │ │ │ │ ├── ruby.js │ │ │ │ └── test.js │ │ │ ├── rust │ │ │ │ ├── index.html │ │ │ │ └── rust.js │ │ │ ├── sass │ │ │ │ ├── index.html │ │ │ │ └── sass.js │ │ │ ├── scheme │ │ │ │ ├── index.html │ │ │ │ └── scheme.js │ │ │ ├── shell │ │ │ │ ├── index.html │ │ │ │ ├── shell.js │ │ │ │ └── test.js │ │ │ ├── sieve │ │ │ │ ├── index.html │ │ │ │ └── sieve.js │ │ │ ├── slim │ │ │ │ ├── index.html │ │ │ │ ├── slim.js │ │ │ │ └── test.js │ │ │ ├── smalltalk │ │ │ │ ├── index.html │ │ │ │ └── smalltalk.js │ │ │ ├── smarty │ │ │ │ ├── index.html │ │ │ │ └── smarty.js │ │ │ ├── smartymixed │ │ │ │ ├── index.html │ │ │ │ └── smartymixed.js │ │ │ ├── solr │ │ │ │ ├── index.html │ │ │ │ └── solr.js │ │ │ ├── soy │ │ │ │ ├── index.html │ │ │ │ └── soy.js │ │ │ ├── sparql │ │ │ │ ├── index.html │ │ │ │ └── sparql.js │ │ │ ├── spreadsheet │ │ │ │ ├── index.html │ │ │ │ └── spreadsheet.js │ │ │ ├── sql │ │ │ │ ├── index.html │ │ │ │ └── sql.js │ │ │ ├── stex │ │ │ │ ├── index.html │ │ │ │ ├── stex.js │ │ │ │ └── test.js │ │ │ ├── stylus │ │ │ │ ├── index.html │ │ │ │ └── stylus.js │ │ │ ├── tcl │ │ │ │ ├── index.html │ │ │ │ └── tcl.js │ │ │ ├── textile │ │ │ │ ├── index.html │ │ │ │ ├── test.js │ │ │ │ └── textile.js │ │ │ ├── tiddlywiki │ │ │ │ ├── index.html │ │ │ │ ├── tiddlywiki.css │ │ │ │ └── tiddlywiki.js │ │ │ ├── tiki │ │ │ │ ├── index.html │ │ │ │ ├── tiki.css │ │ │ │ └── tiki.js │ │ │ ├── toml │ │ │ │ ├── index.html │ │ │ │ └── toml.js │ │ │ ├── tornado │ │ │ │ ├── index.html │ │ │ │ └── tornado.js │ │ │ ├── turtle │ │ │ │ ├── index.html │ │ │ │ └── turtle.js │ │ │ ├── vb │ │ │ │ ├── index.html │ │ │ │ └── vb.js │ │ │ ├── vbscript │ │ │ │ ├── index.html │ │ │ │ └── vbscript.js │ │ │ ├── velocity │ │ │ │ ├── index.html │ │ │ │ └── velocity.js │ │ │ ├── verilog │ │ │ │ ├── index.html │ │ │ │ ├── test.js │ │ │ │ └── verilog.js │ │ │ ├── xml │ │ │ │ ├── index.html │ │ │ │ ├── test.js │ │ │ │ └── xml.js │ │ │ ├── xquery │ │ │ │ ├── index.html │ │ │ │ ├── test.js │ │ │ │ └── xquery.js │ │ │ ├── yaml │ │ │ │ ├── index.html │ │ │ │ └── yaml.js │ │ │ └── z80 │ │ │ │ ├── index.html │ │ │ │ └── z80.js │ │ ├── modes.min.js │ │ ├── package.json │ │ └── theme │ │ │ ├── 3024-day.css │ │ │ ├── 3024-night.css │ │ │ ├── ambiance-mobile.css │ │ │ ├── ambiance.css │ │ │ ├── base16-dark.css │ │ │ ├── base16-light.css │ │ │ ├── blackboard.css │ │ │ ├── cobalt.css │ │ │ ├── colorforth.css │ │ │ ├── eclipse.css │ │ │ ├── elegant.css │ │ │ ├── erlang-dark.css │ │ │ ├── lesser-dark.css │ │ │ ├── mbo.css │ │ │ ├── mdn-like.css │ │ │ ├── midnight.css │ │ │ ├── monokai.css │ │ │ ├── neat.css │ │ │ ├── neo.css │ │ │ ├── night.css │ │ │ ├── paraiso-dark.css │ │ │ ├── paraiso-light.css │ │ │ ├── pastel-on-dark.css │ │ │ ├── rubyblue.css │ │ │ ├── solarized.css │ │ │ ├── the-matrix.css │ │ │ ├── tomorrow-night-bright.css │ │ │ ├── tomorrow-night-eighties.css │ │ │ ├── twilight.css │ │ │ ├── vibrant-ink.css │ │ │ ├── xq-dark.css │ │ │ ├── xq-light.css │ │ │ └── zenburn.css │ ├── flowchart.min.js │ ├── jquery.flowchart.min.js │ ├── marked.min.js │ ├── prettify.min.js │ ├── raphael.min.js │ ├── sequence-diagram.min.js │ └── underscore.min.js │ ├── package.json │ ├── plugins │ ├── code-block-dialog │ │ └── code-block-dialog.js │ ├── emoji-dialog │ │ ├── emoji-dialog.js │ │ └── emoji.json │ ├── goto-line-dialog │ │ └── goto-line-dialog.js │ ├── help-dialog │ │ ├── help-dialog.js │ │ └── help.md │ ├── html-entities-dialog │ │ ├── html-entities-dialog.js │ │ └── html-entities.json │ ├── image-dialog │ │ └── image-dialog.js │ ├── link-dialog │ │ └── link-dialog.js │ ├── plugin-template.js │ ├── preformatted-text-dialog │ │ └── preformatted-text-dialog.js │ ├── reference-link-dialog │ │ └── reference-link-dialog.js │ ├── table-dialog │ │ └── table-dialog.js │ └── test-plugin │ │ └── test-plugin.js │ ├── scss │ ├── editormd.codemirror.scss │ ├── editormd.dialog.scss │ ├── editormd.form.scss │ ├── editormd.grid.scss │ ├── editormd.logo.scss │ ├── editormd.menu.scss │ ├── editormd.preview.scss │ ├── editormd.preview.themes.scss │ ├── editormd.scss │ ├── editormd.tab.scss │ ├── editormd.themes.scss │ ├── font-awesome.scss │ ├── github-markdown.scss │ ├── lib │ │ ├── prefixes.scss │ │ └── variables.scss │ └── prettify.scss │ ├── src │ └── editormd.js │ └── tests │ ├── bootstrap-test.html │ ├── codemirror-searchbox-test.html │ ├── codemirror-test.html │ ├── css │ ├── bootstrap-theme.min.css │ └── bootstrap.min.css │ ├── js │ ├── bootstrap.min.js │ └── searchbox.js │ ├── katex-tests.html │ ├── marked-@at-test.html │ ├── marked-emoji-test.html │ ├── marked-heading-link-test.html │ ├── marked-todo-list-test.html │ └── qunit │ ├── qunit-1.16.0.css │ └── qunit-1.16.0.js ├── templates ├── admin │ ├── 401.html │ ├── 404.html │ ├── 500.html │ ├── category_add.html │ ├── category_list.html │ ├── login.html │ ├── page_add.html │ ├── page_list.html │ ├── password.html │ ├── post_add.html │ ├── post_list.html │ ├── register.html │ └── tag_list.html └── default │ ├── 404.html │ ├── about.html │ ├── index.html │ ├── layout.html │ ├── page.html │ ├── post.html │ └── tag.html └── tests └── auth_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | goblog* 4 | conf/prod.yml 5 | conf/local.yml 6 | logs/* 7 | __debug_bin -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | BASEDIR = $(shell pwd) 3 | 4 | COMMIT = $(shell git rev-parse --short HEAD) 5 | TIME = $(shell TZ=Asia/Shanghai date +%Y%m%d%H) 6 | 7 | .PHONY: build 8 | # make build, Build the binary file 9 | build: dep 10 | GOOS=linux GOARCH=amd64 go build -o "goblog" -v -ldflags "-X main.Commit=$COMMIT" 11 | 12 | .PHONY: dep 13 | # make dep Get the dependencies 14 | dep: 15 | @go mod tidy 16 | 17 | .PHONY: tar 18 | # pack file 19 | tar: 20 | @tar zcvf goblog-"${TIME}".tar.gz templates/ static/ goblog conf/ *.sh 21 | 22 | .PHONY: fmt 23 | # make fmt 24 | fmt: 25 | @gofmt -s -w . 26 | 27 | .PHONY: clean 28 | # make clean 29 | clean: 30 | @-rm -vrf goblog* 31 | @go mod tidy 32 | @echo "clean finished" 33 | 34 | # show help 35 | help: 36 | @echo 'Usage: make [target]' 37 | @echo 'Targets:' 38 | @awk '/^[a-zA-Z\-\_0-9]+:/ { \ 39 | helpMessage = match(lastLine, /^# (.*)/); \ 40 | if (helpMessage) { \ 41 | helpCommand = substr($$1, 0, index($$1, ":")-1); \ 42 | helpMessage = substr(lastLine, RSTART + 2, RLENGTH); \ 43 | printf "\033[36m%-22s\033[0m %s\n", helpCommand,helpMessage; \ 44 | } \ 45 | } \ 46 | { lastLine = $$0 }' $(MAKEFILE_LIST) 47 | 48 | .DEFAULT_GOAL := all 49 | 50 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | COMMIT=$(git rev-parse --short HEAD) 4 | TIME=$(date +%Y%m%d%H) 5 | 6 | case "$1" in 7 | 'build') 8 | GOOS=linux GOARCH=amd64 go build -v -ldflags "-X main.Commit=$COMMIT" 9 | ;; 10 | 'tar') 11 | tar zcvf blog"$TIME".tar.gz ./blog ./templates ./static ./conf 12 | ;; 13 | *) 14 | echo "usage: $0 {build|tar}" 15 | exit 1 16 | ;; 17 | esac 18 | -------------------------------------------------------------------------------- /conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/convee/goblog/pkg/logger" 5 | "github.com/convee/goblog/pkg/redis" 6 | "github.com/convee/goblog/pkg/storage/elasticsearch" 7 | "github.com/convee/goblog/pkg/storage/mysql" 8 | "github.com/convee/goblog/pkg/storage/orm" 9 | 10 | "github.com/fsnotify/fsnotify" 11 | "github.com/spf13/viper" 12 | ) 13 | 14 | // Config global config 15 | type Config struct { 16 | // common 17 | App AppConfig 18 | // component config 19 | Logger logger.Config 20 | ORM orm.Config 21 | Mysql mysql.Config 22 | Redis redis.Config 23 | Elasticsearch elasticsearch.Config 24 | } 25 | 26 | // AppConfig app config 27 | type AppConfig struct { 28 | Name string 29 | Version bool 30 | Mode string 31 | Addr string 32 | Host string 33 | Cdn string 34 | DisableDingDing bool 35 | } 36 | 37 | var ( 38 | // Conf app global config 39 | Conf = &Config{} 40 | ) 41 | 42 | func Init(configPath string) *Config { 43 | viper.SetConfigType("yml") 44 | viper.SetConfigFile(configPath) 45 | if err := viper.ReadInConfig(); err != nil { 46 | panic(err) 47 | } 48 | if err := viper.Unmarshal(&Conf); err != nil { 49 | panic(err) 50 | } 51 | viper.WatchConfig() 52 | viper.OnConfigChange(func(e fsnotify.Event) { 53 | if err := viper.Unmarshal(&Conf); err != nil { 54 | panic(err) 55 | } 56 | }) 57 | return Conf 58 | } 59 | -------------------------------------------------------------------------------- /conf/dev.yml: -------------------------------------------------------------------------------- 1 | app: 2 | name: 柚子吧 3 | version: true 4 | mode: debug 5 | addr: localhost:9091 6 | host: http://localhost:9091 7 | cdn: "http://localhost:9091/static" 8 | DisableDingDing: true 9 | 10 | mysql: 11 | Dsn: "root:root@tcp(127.0.0.1:3306)/blog?timeout=2s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4" 12 | ShowLog: true # 是否打印SQL日志 13 | MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 14 | MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 15 | ConnMaxLifeTime: 4000 # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 16 | 17 | elasticsearch: 18 | Disable: true 19 | Urls: "http://127.0.0.1:9200" 20 | 21 | logger: 22 | Development: false 23 | DisableCaller: false 24 | DisableStacktrace: false 25 | Encoding: json # json or console 26 | Level: info # 日志级别,INFO, WARN, ERROR 27 | Name: goblog 28 | Writers: file # 有2个可选项:file,console 选择file会将日志记录到logger_file指定的日志文件中,选择console会将日志输出到标准输出,当然也可以两者同时选择 29 | LoggerFile: logs/access.log 30 | LoggerWarnFile: logs/warn.log 31 | LoggerErrorFile: logs/error.log 32 | LogRollingPolicy: daily 33 | LogRotateDate: 1 34 | LogRotateSize: 1 35 | LogBackupCount: 7 36 | 37 | orm: 38 | Name: blog # 数据库名称 39 | Addr: 127.0.0.1:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306 40 | UserName: root 41 | Password: root 42 | ShowLog: true # 是否打印所有SQL日志 43 | MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 44 | MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 45 | ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 46 | SlowThreshold: 0 # 慢查询阈值,设置后只打印慢查询日志,默认为500ms 47 | 48 | redis: 49 | Addr: 127.0.0.1:6379 50 | Password: "" 51 | DB: 0 52 | MinIdleConn: 200 53 | DialTimeout: 60s 54 | ReadTimeout: 500ms 55 | WriteTimeout: 500ms 56 | PoolSize: 100 57 | PoolTimeout: 240s 58 | IsTrace: true -------------------------------------------------------------------------------- /internal/daos/category.go: -------------------------------------------------------------------------------- 1 | package daos 2 | 3 | import ( 4 | "database/sql" 5 | "github.com/convee/goblog/internal/model" 6 | "log" 7 | ) 8 | 9 | func GetCategories() (categories []model.Category, err error) { 10 | rs, err := db.Query("select id,name from category") 11 | if err != nil { 12 | return nil, err 13 | } 14 | defer rs.Close() 15 | for rs.Next() { 16 | var category model.Category 17 | rs.Scan(&category.Id, &category.Name) 18 | categories = append(categories, category) 19 | } 20 | return 21 | } 22 | 23 | func GetCategoryIdsByName(name string) (categoryIds []string, err error) { 24 | rs, err := db.Query("select id from category where name like ?", "%"+name+"%") 25 | if err != nil { 26 | return nil, err 27 | } 28 | defer rs.Close() 29 | for rs.Next() { 30 | var categoryId string 31 | rs.Scan(&categoryId) 32 | categoryIds = append(categoryIds, categoryId) 33 | } 34 | return 35 | } 36 | 37 | func GetCategory(id int) (category model.Category) { 38 | row := db.QueryRow("select id,name from category where id=?", id) 39 | row.Scan(&category.Id, &category.Name) 40 | return 41 | } 42 | 43 | func CategoryDelete(category model.Category) (id int, err error) { 44 | id = category.Id 45 | log.Println(category) 46 | _, err = db.Exec("delete from category where id=?", id) 47 | if err != nil { 48 | log.Printf("category %d delete err %v", id, err) 49 | return 50 | } 51 | return 52 | } 53 | 54 | func CategorySave(category model.Category) (id int, err error) { 55 | 56 | var rs sql.Result 57 | if category.Id > 0 { 58 | id = category.Id 59 | log.Println(category) 60 | _, err = db.Exec("update category set name=? where id=?", category.Name, id) 61 | if err != nil { 62 | log.Printf("category %d update err %v", id, err) 63 | return 64 | } 65 | } else { 66 | rs, err = db.Exec("insert into category (`name`) values (?)", category.Name) 67 | if err != nil { 68 | log.Printf("category %d insert err %v", id, err) 69 | return 70 | } 71 | id64, _ := rs.LastInsertId() 72 | id = int(id64) 73 | 74 | } 75 | return 76 | } 77 | -------------------------------------------------------------------------------- /internal/daos/init.go: -------------------------------------------------------------------------------- 1 | package daos 2 | 3 | import ( 4 | "database/sql" 5 | 6 | "github.com/convee/goblog/pkg/storage/mysql" 7 | 8 | _ "github.com/go-sql-driver/mysql" 9 | ) 10 | 11 | var ( 12 | db *sql.DB 13 | ) 14 | 15 | // Init 初始化数据库 16 | func Init(cfg *mysql.Config) *sql.DB { 17 | db = mysql.NewMySQL(cfg) 18 | return db 19 | } 20 | 21 | // GetDB 返回默认的数据库 22 | func GetDB() *sql.DB { 23 | return db 24 | } 25 | -------------------------------------------------------------------------------- /internal/daos/tag.go: -------------------------------------------------------------------------------- 1 | package daos 2 | 3 | import ( 4 | "github.com/convee/goblog/internal/model" 5 | "github.com/convee/goblog/pkg/logger" 6 | "go.uber.org/zap" 7 | ) 8 | 9 | func GetTags() (tags []model.Tag, err error) { 10 | rows, err := db.Query("select id,name,count from tag order by count desc") 11 | if err != nil { 12 | return nil, err 13 | } 14 | defer rows.Close() 15 | for rows.Next() { 16 | var tag model.Tag 17 | rows.Scan(&tag.Id, &tag.Name, &tag.Count) 18 | tags = append(tags, tag) 19 | } 20 | return 21 | } 22 | 23 | func GetTagIdsByName(name string) (tagIds []string, err error) { 24 | rs, err := db.Query("select id from tag where name like ?", "%"+name+"%") 25 | if err != nil { 26 | return nil, err 27 | } 28 | defer rs.Close() 29 | for rs.Next() { 30 | var tagId string 31 | rs.Scan(&tagId) 32 | tagIds = append(tagIds, tagId) 33 | } 34 | return 35 | } 36 | 37 | func AddTag(tag model.Tag) (id int, err error) { 38 | rs, err := db.Exec("insert into tag (name) values (?)", tag.Name) 39 | if err != nil { 40 | return 41 | } 42 | id64, err := rs.LastInsertId() 43 | return int(id64), err 44 | } 45 | 46 | func IncrTagCount(id string) { 47 | count, err := GetPostCountByTagId(id) 48 | if err != nil { 49 | logger.Error("incr_tag_count_err", zap.Error(err)) 50 | return 51 | } 52 | db.Exec("update tag set count=? where id = ?", count, id) 53 | } 54 | -------------------------------------------------------------------------------- /internal/daos/user.go: -------------------------------------------------------------------------------- 1 | package daos 2 | 3 | import ( 4 | "github.com/convee/goblog/internal/model" 5 | ) 6 | 7 | func GetUser(email string) (user model.User) { 8 | row := db.QueryRow("select email,password from user where email=?", email) 9 | row.Scan(&user.Email, &user.Password) 10 | return 11 | } 12 | 13 | func AddUser(user model.User) (id int, err error) { 14 | rs, err := db.Exec("insert into user (email, password) values (?, ?)", user.Email, user.Password) 15 | if err != nil { 16 | return 17 | } 18 | id64, err := rs.LastInsertId() 19 | return int(id64), err 20 | } 21 | -------------------------------------------------------------------------------- /internal/es/init.go: -------------------------------------------------------------------------------- 1 | package es 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/convee/goblog/pkg/storage/elasticsearch" 8 | 9 | "github.com/olivere/elastic/v7" 10 | ) 11 | 12 | var esClient *elastic.Client 13 | 14 | const blogIndex = "blog" 15 | const mapping = ` 16 | { 17 | "mappings": { 18 | "properties": { 19 | "title": { 20 | "type": "text" 21 | }, 22 | "content": { 23 | "type": "keyword" 24 | } 25 | } 26 | } 27 | }` 28 | 29 | func Init(cfg *elasticsearch.Config) { 30 | client, err := elastic.NewClient(elastic.SetURL(cfg.Urls...)) 31 | if err != nil { 32 | log.Fatalln("es new client err ", err) 33 | } 34 | esClient = client 35 | 36 | createBlogIndex() 37 | 38 | } 39 | 40 | func createBlogIndex() { 41 | // 执行ES请求需要提供一个上下文对象 42 | ctx := context.Background() 43 | 44 | // 检测下索引是否存在 45 | exists, err := esClient.IndexExists(blogIndex).Do(ctx) 46 | if err != nil { 47 | log.Fatalln("es exists handle err ", err) 48 | } 49 | if !exists { 50 | // 索引不存在,则创建一个 51 | _, err := esClient.CreateIndex(blogIndex).BodyString(mapping).Do(ctx) 52 | if err != nil { 53 | log.Fatalln("es create index handle err ", err) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /internal/handler/admin/auth.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "github.com/convee/artgo" 5 | "github.com/convee/goblog/internal/daos" 6 | "github.com/convee/goblog/internal/pkg" 7 | "net/http" 8 | 9 | "golang.org/x/crypto/bcrypt" 10 | ) 11 | 12 | func Login(c *artgo.Context) { 13 | data := make(map[string]interface{}) 14 | pkg.AdminRender(data, c, "login") 15 | } 16 | 17 | func Register(c *artgo.Context) { 18 | data := make(map[string]interface{}) 19 | pkg.AdminRender(data, c, "register") 20 | } 21 | 22 | func Logout(c *artgo.Context) { 23 | c.SetCookie(&http.Cookie{ 24 | Name: "email", 25 | Value: "", 26 | Path: "/", 27 | MaxAge: -1, 28 | }) 29 | c.Redirect(http.StatusFound, "/login") 30 | } 31 | 32 | func Signup(c *artgo.Context) { 33 | c.Redirect(http.StatusFound, "/admin") 34 | } 35 | 36 | func Signin(c *artgo.Context) { 37 | email := c.PostForm("email") 38 | password := c.PostForm("password") 39 | 40 | if email == "" || password == "" { 41 | c.Status(http.StatusInternalServerError) 42 | return 43 | } 44 | user := daos.GetUser(email) 45 | 46 | if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { 47 | data := make(map[string]interface{}) 48 | data["msg"] = "密码不正确,请重试" 49 | pkg.AdminRender(data, c, "401") 50 | return 51 | } 52 | cookie := &http.Cookie{ 53 | Name: "email", 54 | Value: email, 55 | Path: "/", 56 | HttpOnly: true, 57 | } 58 | c.SetCookie(cookie) 59 | c.Redirect(http.StatusFound, "/admin") 60 | return 61 | } 62 | -------------------------------------------------------------------------------- /internal/handler/admin/category.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "github.com/convee/goblog/internal/daos" 7 | "github.com/convee/goblog/internal/model" 8 | "github.com/convee/goblog/internal/pkg" 9 | "net/http" 10 | "strconv" 11 | ) 12 | 13 | func CategoryList(c *artgo.Context) { 14 | categories, err := daos.GetCategories() 15 | if err != nil { 16 | fmt.Println("get categories err:", err) 17 | return 18 | } 19 | data := make(map[string]interface{}) 20 | data["categories"] = categories 21 | pkg.AdminRender(data, c, "category_list") 22 | } 23 | 24 | func CategoryAdd(c *artgo.Context) { 25 | data := make(map[string]interface{}) 26 | id, _ := strconv.Atoi(c.PostForm("id")) 27 | var category model.Category 28 | if id > 0 { 29 | category = daos.GetCategory(id) 30 | } 31 | categories, _ := daos.GetCategories() 32 | data["categories"] = categories 33 | 34 | if category.Id > 0 { 35 | 36 | data["id"] = category.Id 37 | data["name"] = category.Name 38 | } 39 | pkg.AdminRender(data, c, "category_add") 40 | } 41 | 42 | func CategoryDelete(c *artgo.Context) { 43 | var category model.Category 44 | category.Id, _ = strconv.Atoi(c.Query("id")) 45 | _, err := daos.CategoryDelete(category) 46 | if err != nil { 47 | data := make(map[string]interface{}) 48 | data["msg"] = "删除失败,请重试" 49 | pkg.AdminRender(data, c, "401") 50 | return 51 | } 52 | c.Redirect(http.StatusFound, "/admin/category") 53 | } 54 | 55 | func CategorySave(c *artgo.Context) { 56 | var category model.Category 57 | category.Id, _ = strconv.Atoi(c.PostForm("id")) 58 | category.Name = c.PostForm("name") 59 | _, err := daos.CategorySave(category) 60 | if err != nil { 61 | data := make(map[string]interface{}) 62 | data["msg"] = "添加或修改失败,请重试" 63 | pkg.AdminRender(data, c, "401") 64 | return 65 | } 66 | c.Redirect(http.StatusFound, "/admin/category") 67 | } 68 | -------------------------------------------------------------------------------- /internal/handler/admin/page.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "github.com/convee/goblog/internal/daos" 7 | "github.com/convee/goblog/internal/model" 8 | "github.com/convee/goblog/internal/pkg" 9 | "net/http" 10 | "strconv" 11 | ) 12 | 13 | func PageList(c *artgo.Context) { 14 | perPage, _ := strconv.Atoi(c.Query("per_page")) 15 | page, _ := strconv.Atoi(c.Query("page")) 16 | if perPage <= 0 { 17 | perPage = 20 18 | } 19 | if page <= 1 { 20 | page = 1 21 | } 22 | pages, err := daos.GetPages(daos.PageParams{ 23 | PerPage: perPage, 24 | Page: page, 25 | }) 26 | if err != nil { 27 | fmt.Println("get pages err:", err) 28 | return 29 | } 30 | data := make(map[string]interface{}) 31 | data["pages"] = pages 32 | data["page"] = page 33 | pkg.AdminRender(data, c, "page_list") 34 | } 35 | 36 | func PageAdd(c *artgo.Context) { 37 | data := make(map[string]interface{}) 38 | id := c.PostForm("id") 39 | var page model.Page 40 | if len(id) > 0 { 41 | page = daos.GetPage(id) 42 | } 43 | if page.Id > 0 { 44 | 45 | data["id"] = page.Id 46 | data["title"] = page.Title 47 | data["ident"] = page.Ident 48 | data["content"] = page.Content 49 | } 50 | pkg.AdminRender(data, c, "page_add") 51 | } 52 | 53 | func PageDelete(c *artgo.Context) { 54 | var page model.Page 55 | page.Id, _ = strconv.Atoi(c.Query("id")) 56 | _, err := daos.PageDelete(page) 57 | if err != nil { 58 | data := make(map[string]interface{}) 59 | data["msg"] = "删除失败,请重试" 60 | pkg.AdminRender(data, c, "401") 61 | return 62 | } 63 | c.Redirect(http.StatusFound, "/admin/page") 64 | } 65 | 66 | func PageSave(c *artgo.Context) { 67 | var page model.Page 68 | page.Id, _ = strconv.Atoi(c.PostForm("id")) 69 | page.Title = c.PostForm("title") 70 | page.Ident = c.PostForm("ident") 71 | page.Content = c.PostForm("content") 72 | _, err := daos.PageSave(page) 73 | if err != nil { 74 | data := make(map[string]interface{}) 75 | data["msg"] = "添加或修改失败,请重试" 76 | pkg.AdminRender(data, c, "401") 77 | return 78 | } 79 | c.Redirect(http.StatusFound, "/admin/page") 80 | } 81 | -------------------------------------------------------------------------------- /internal/handler/admin/tag.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "github.com/convee/goblog/internal/daos" 7 | "github.com/convee/goblog/internal/pkg" 8 | ) 9 | 10 | func TagList(c *artgo.Context) { 11 | tags, err := daos.GetTags() 12 | if err != nil { 13 | fmt.Println("get ags err:", err) 14 | return 15 | } 16 | data := make(map[string]interface{}) 17 | data["tags"] = tags 18 | pkg.AdminRender(data, c, "tag_list") 19 | } 20 | -------------------------------------------------------------------------------- /internal/handler/front/page.go: -------------------------------------------------------------------------------- 1 | package front 2 | 3 | import ( 4 | "github.com/convee/artgo" 5 | "github.com/convee/goblog/internal/daos" 6 | "github.com/convee/goblog/internal/pkg" 7 | ) 8 | 9 | func Page(c *artgo.Context) { 10 | ident := c.Param("ident") 11 | 12 | page := daos.GetPageByIdent(ident) 13 | data := make(map[string]interface{}) 14 | data["title"] = page.Title 15 | data["description"] = page.Title 16 | data["page"] = page 17 | pkg.Render(data, c, "page") 18 | } 19 | -------------------------------------------------------------------------------- /internal/handler/front/tag.go: -------------------------------------------------------------------------------- 1 | package front 2 | 3 | import ( 4 | "github.com/convee/artgo" 5 | "github.com/convee/goblog/internal/daos" 6 | "github.com/convee/goblog/internal/pkg" 7 | ) 8 | 9 | func Tag(c *artgo.Context) { 10 | tags, _ := daos.GetTags() 11 | data := make(map[string]interface{}) 12 | data["title"] = "标签" 13 | data["description"] = "柚子吧的博客标签" 14 | data["tags"] = tags 15 | pkg.Render(data, c, "tag") 16 | } 17 | -------------------------------------------------------------------------------- /internal/model/category.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Category struct { 4 | Id int 5 | Name string 6 | CreatedAt string 7 | UpdatedAt string 8 | Cur int 9 | } 10 | -------------------------------------------------------------------------------- /internal/model/configure.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Configure struct { 4 | Id int 5 | Name string 6 | Value string 7 | } 8 | -------------------------------------------------------------------------------- /internal/model/page.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Page struct { 4 | Id int 5 | Title string 6 | Ident string 7 | Content string 8 | } 9 | -------------------------------------------------------------------------------- /internal/model/post.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type Post struct { 6 | Id int 7 | Title string 8 | Views int 9 | CreatedAt time.Time 10 | UpdatedAt time.Time 11 | CategoryId int 12 | CategoryName string 13 | TagIds []int 14 | Description string 15 | Content string 16 | TagNames []string 17 | Status int 18 | } 19 | -------------------------------------------------------------------------------- /internal/model/tag.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Tag struct { 4 | Id int 5 | Name string 6 | Count int 7 | CreatedAt string 8 | UpdatedAt string 9 | } 10 | 11 | type TagPost struct { 12 | Id int 13 | TagId int 14 | PostId int 15 | } 16 | -------------------------------------------------------------------------------- /internal/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type User struct { 4 | Email string 5 | Password string 6 | } 7 | -------------------------------------------------------------------------------- /internal/pkg/template.go: -------------------------------------------------------------------------------- 1 | package pkg 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "html/template" 7 | "log" 8 | "net/http" 9 | "time" 10 | 11 | "github.com/convee/goblog/conf" 12 | ) 13 | 14 | var FuncMap = template.FuncMap{ 15 | "noescape": func(s string) template.HTML { 16 | return template.HTML(s) 17 | }, 18 | "formatTime": func(t time.Time, layout string) string { 19 | return t.Format(layout) 20 | }, 21 | "tagStyle": func(count int) string { 22 | var size string 23 | if count >= 11 { 24 | size = "60px" 25 | } else if count == 10 { 26 | size = "55px" 27 | } else if count == 9 { 28 | size = "50px" 29 | } else if count == 8 { 30 | size = "45px" 31 | } else if count == 7 { 32 | size = "40px" 33 | } else if count == 6 { 34 | size = "35px" 35 | } else if count == 5 { 36 | size = "30px" 37 | } else if count == 4 { 38 | size = "25px" 39 | } else if count == 3 { 40 | size = "20px" 41 | } else if count == 2 { 42 | size = "15px" 43 | } else { 44 | size = "12px" 45 | } 46 | return fmt.Sprintf("font-size:%s", size) 47 | }, 48 | } 49 | 50 | func Render(data map[string]interface{}, c *artgo.Context, tpl string) { 51 | var tplPaths []string 52 | tplPaths = append(tplPaths, "templates/default/layout.html") 53 | tplPaths = append(tplPaths, "templates/default/"+tpl+".html") 54 | t, err := template.New("layout.html").Funcs(FuncMap).ParseFiles(tplPaths...) 55 | if err != nil { 56 | log.Println("posts template err:", err) 57 | return 58 | } 59 | data["name"] = conf.Conf.App.Name 60 | data["cdn"] = conf.Conf.App.Cdn 61 | // seo title 62 | if _, ok := data["title"]; !ok { 63 | data["title"] = "Go Markdown 博客系统" 64 | } 65 | // seo description 66 | if _, ok := data["description"]; !ok { 67 | data["description"] = "Go Markdown 博客系统" 68 | } 69 | t.Execute(c.Writer, data) 70 | } 71 | 72 | func AdminRender(data map[string]interface{}, c *artgo.Context, template string) { 73 | data["cdn"] = conf.Conf.App.Cdn 74 | c.HTML(http.StatusOK, template+".html", data) 75 | } 76 | -------------------------------------------------------------------------------- /internal/routers/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/convee/artgo" 5 | "net/http" 6 | ) 7 | 8 | func AuthWithCookie() artgo.HandlerFunc { 9 | return func(c *artgo.Context) { 10 | if cookie, err := c.Req.Cookie("email"); err != nil || cookie.Value == "" { 11 | c.Redirect(http.StatusFound, "/login") 12 | return 13 | } 14 | c.Next() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /internal/routers/middleware/log.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "github.com/convee/goblog/pkg/logger" 7 | "time" 8 | ) 9 | 10 | func Logger() artgo.HandlerFunc { 11 | return func(c *artgo.Context) { 12 | t := time.Now() 13 | c.Next() 14 | logger.Info(fmt.Sprintf("[%d] %s %v", c.StatusCode, c.Req.RequestURI, time.Since(t))) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /internal/routers/middleware/recover.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "github.com/convee/artgo" 6 | "github.com/convee/goblog/conf" 7 | "github.com/convee/goblog/pkg/ding" 8 | "github.com/convee/goblog/pkg/logger" 9 | "github.com/pkg/errors" 10 | "go.uber.org/zap" 11 | "net/http" 12 | "runtime/debug" 13 | ) 14 | 15 | func RecoverWrap(h http.Handler) http.Handler { 16 | return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { 17 | var err error 18 | defer func() { 19 | r := recover() 20 | if r != nil { 21 | switch t := r.(type) { 22 | case string: 23 | err = errors.New(t) 24 | case error: 25 | err = t 26 | default: 27 | err = errors.New("Unknown error") 28 | } 29 | logger.Error("http_router_panic", zap.Any("err", r), zap.Stack(string(debug.Stack()))) 30 | if !conf.Conf.App.DisableDingDing { 31 | _, _ = ding.SendAlert(fmt.Sprintf("http_router_panic:err:%v;stack:%s", r, string(debug.Stack())), false) 32 | } 33 | http.Error(writer, err.Error(), http.StatusInternalServerError) 34 | 35 | } 36 | }() 37 | h.ServeHTTP(writer, request) 38 | }) 39 | } 40 | 41 | func Recover() artgo.HandlerFunc { 42 | return func(c *artgo.Context) { 43 | var err error 44 | defer func() { 45 | r := recover() 46 | if r != nil { 47 | switch t := r.(type) { 48 | case string: 49 | err = errors.New(t) 50 | case error: 51 | err = t 52 | default: 53 | err = errors.New("Unknown error") 54 | } 55 | logger.Error("http_router_panic", zap.Any("err", r), zap.Stack(string(debug.Stack()))) 56 | if !conf.Conf.App.DisableDingDing { 57 | _, _ = ding.SendAlert(fmt.Sprintf("http_router_panic:err:%v;stack:%s", r, string(debug.Stack())), false) 58 | } 59 | c.Error(http.StatusInternalServerError, err.Error()) 60 | 61 | } 62 | }() 63 | c.Next() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /internal/routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "github.com/convee/artgo" 5 | "github.com/convee/goblog/internal/handler/admin" 6 | "github.com/convee/goblog/internal/handler/front" 7 | "github.com/convee/goblog/internal/pkg" 8 | "github.com/convee/goblog/internal/routers/middleware" 9 | "net/http" 10 | ) 11 | 12 | // InitRouter 自定义 http 服务器 13 | func InitRouter() *artgo.Engine { 14 | r := artgo.New() 15 | // 日志中间件,记录全局请求响应日志 16 | r.Use(middleware.Logger()) 17 | // Recover 中间件,捕获 http server 协程panic错误信息 18 | r.Use(middleware.Recover()) 19 | 20 | // 渲染自定义模板 21 | r.SetFuncMap(pkg.FuncMap) 22 | // 加载模板到内存 23 | r.LoadHTMLGlob("templates/admin/*") 24 | // 静态文件服务 25 | r.Static("/static/", "static") 26 | 27 | // 前台路由 28 | r.GET("/", front.Index) 29 | r.GET("/favicon.ico", func(c *artgo.Context) { 30 | http.ServeFile(c.Writer, c.Req, "static/favicon.ico") 31 | }) 32 | r.GET("/post/:id", front.PostInfo) 33 | r.GET("/page/:ident", front.Page) 34 | r.GET("/tag", front.Tag) 35 | 36 | // 后台登录路由,不需要校验登录态 37 | r.GET("/login", admin.Login) 38 | r.GET("/register", admin.Register) 39 | r.POST("/signin", admin.Signin) 40 | r.POST("/signup", admin.Signup) 41 | 42 | // 后台管理页面路由,继承AuthWithCookie中间件,校验登录态 43 | adminGroup := r.Group("/admin") 44 | adminGroup.Use(middleware.AuthWithCookie()) 45 | adminGroup.POST("/logout", admin.Logout) 46 | adminGroup.GET("/", admin.PostList) 47 | adminGroup.GET("/post/add", admin.PostAdd) 48 | adminGroup.POST("/post/save", admin.PostSave) 49 | adminGroup.GET("/post/delete", admin.PostDelete) 50 | adminGroup.GET("/page", admin.PageList) 51 | adminGroup.GET("/page/add", admin.PageAdd) 52 | adminGroup.POST("/page/save", admin.PageSave) 53 | adminGroup.GET("/page/delete", admin.PageDelete) 54 | adminGroup.GET("/category", admin.CategoryList) 55 | adminGroup.GET("/category/add", admin.CategoryAdd) 56 | adminGroup.POST("/category/save", admin.CategorySave) 57 | adminGroup.GET("/category/delete", admin.CategoryDelete) 58 | adminGroup.GET("/tag", admin.TagList) 59 | 60 | return r 61 | } 62 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/convee/goblog/internal/daos" 6 | "github.com/convee/goblog/internal/es" 7 | "github.com/convee/goblog/pkg/logger" 8 | "log" 9 | "net/http" 10 | "time" 11 | 12 | "github.com/convee/goblog/conf" 13 | "github.com/convee/goblog/internal/routers" 14 | "github.com/convee/goblog/pkg/redis" 15 | "github.com/convee/goblog/pkg/shutdown" 16 | 17 | "github.com/spf13/pflag" 18 | ) 19 | 20 | var ( 21 | cfgFile = pflag.StringP("config", "c", "./conf/dev.yml", "config file path.") 22 | //version = pflag.BoolP("version", "v", false, "show version info.") 23 | ) 24 | 25 | func main() { 26 | 27 | pflag.Parse() 28 | 29 | // init config 30 | cfg := conf.Init(*cfgFile) 31 | 32 | // init logger 33 | logger.Init(&cfg.Logger) 34 | 35 | // init redis 36 | redis.Init(&cfg.Redis) 37 | 38 | // init orm 39 | //model.Init(&cfg.ORM) 40 | 41 | // init mysql 42 | daos.Init(&cfg.Mysql) 43 | 44 | // init elasticsearch 45 | if !cfg.Elasticsearch.Disable { 46 | es.Init(&cfg.Elasticsearch) 47 | } 48 | 49 | addr := cfg.App.Addr 50 | log.Println("start serve: [", addr, "]") 51 | srv := &http.Server{ 52 | Addr: addr, 53 | Handler: routers.InitRouter(), 54 | } 55 | go func() { 56 | if err := srv.ListenAndServe(); err != nil { 57 | log.Println("server run:", err) 58 | } 59 | }() 60 | 61 | shutdown.NewHook().Close( 62 | // 关闭 http server 63 | func() { 64 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 65 | defer cancel() 66 | if err := srv.Shutdown(ctx); err != nil { 67 | log.Println("http server closed err", err) 68 | } else { 69 | log.Println("http server closed") 70 | } 71 | }, 72 | ) 73 | 74 | } 75 | -------------------------------------------------------------------------------- /pkg/cache/cache.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/patrickmn/go-cache" 7 | ) 8 | 9 | var cacheAdapter *cache.Cache 10 | 11 | func init() { 12 | // 创建一个默认过期时间为5分钟的缓存适配器 13 | // 每60清除一次过期的项目 14 | cacheAdapter = cache.New(5*time.Minute, 60*time.Second) 15 | } 16 | 17 | func SetCache(k string, x interface{}, d time.Duration) { 18 | cacheAdapter.Set(k, x, d) 19 | } 20 | 21 | func GetCache(k string) (interface{}, bool) { 22 | return cacheAdapter.Get(k) 23 | } 24 | 25 | //设置cache 无时间参数 26 | func SetDefaultCache(k string, x interface{}) { 27 | cacheAdapter.SetDefault(k, x) 28 | } 29 | 30 | //删除 cache 31 | func DeleteCache(k string) { 32 | cacheAdapter.Delete(k) 33 | } 34 | 35 | // Add() 加入缓存 36 | func AddCache(k string, x interface{}, d time.Duration) { 37 | cacheAdapter.Add(k, x, d) 38 | } 39 | 40 | // IncrementInt() 对已存在的key 值自增n 41 | func IncrementIntCache(k string, n int) (num int, err error) { 42 | return cacheAdapter.IncrementInt(k, n) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/ding/ding.go: -------------------------------------------------------------------------------- 1 | package ding 2 | 3 | import ( 4 | "bytes" 5 | jsoniter "github.com/json-iterator/go" 6 | "io/ioutil" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | const ( 12 | dingTalkHost = "https://oapi.dingtalk.com" 13 | Token = "" 14 | ) 15 | 16 | /** 17 | * 发送钉钉报警 18 | * token:报警机器人的token 19 | * content:报警内容 20 | * all:true:at所有人 21 | */ 22 | 23 | // SendAlert 发送钉钉报警 24 | func SendAlert(content string, all bool) ([]byte, error) { 25 | dingUrl := dingTalkHost + "/robot/send?access_token=" + Token 26 | data := make(map[string]interface{}) 27 | 28 | data["msgtype"] = "text" 29 | data["text"] = map[string]string{"content": "【" + time.Now().Format("2006-01-02 03:04:05") + "】" + content} 30 | data["at"] = map[string]interface{}{"atMobiles": [0]string{}, "isAtAll": all} 31 | 32 | bytePayload, err := jsoniter.Marshal(data) 33 | if err != nil { 34 | return nil, err 35 | } 36 | resp, postErr := http.Post(dingUrl, "application/json", bytes.NewBuffer(bytePayload)) 37 | if postErr != nil { 38 | return nil, postErr 39 | } 40 | defer resp.Body.Close() 41 | 42 | return ioutil.ReadAll(resp.Body) 43 | } 44 | -------------------------------------------------------------------------------- /pkg/logger/config.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | // Config log config 4 | type Config struct { 5 | Development bool 6 | DisableCaller bool 7 | DisableStacktrace bool 8 | Encoding string 9 | Level string 10 | Name string 11 | Writers string 12 | LoggerFile string 13 | LoggerWarnFile string 14 | LoggerErrorFile string 15 | LogFormatText bool 16 | LogRollingPolicy string 17 | LogBackupCount uint 18 | } 19 | -------------------------------------------------------------------------------- /pkg/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | "go.uber.org/zap" 6 | ) 7 | 8 | // log is A global variable so that log functions can be directly accessed 9 | var log *zap.Logger 10 | 11 | // Fields Type to pass when we want to call WithFields for structured logging 12 | type Fields map[string]interface{} 13 | 14 | // Logger is a contract for the logger 15 | type Logger interface { 16 | Info(args ...interface{}) 17 | Warn(args ...interface{}) 18 | Error(args ...interface{}) 19 | } 20 | 21 | // Init init log 22 | func Init(cfg *Config) *zap.Logger { 23 | var err error 24 | // new zap logger 25 | log, err = newZapLogger(cfg) 26 | if err != nil { 27 | _ = fmt.Errorf("init newZapLogger err: %v", err) 28 | } 29 | return log 30 | } 31 | 32 | // GetLogger return a log 33 | func GetLogger() *zap.Logger { 34 | return log 35 | } 36 | 37 | // Info logger 38 | func Info(msg string, fields ...zap.Field) { 39 | //requestId := new(http.Request).Header.Get("request_id") 40 | //fields = append(fields, zap.String("request_id", requestId)) 41 | log.Info(msg, fields...) 42 | } 43 | 44 | // Warn logger 45 | func Warn(msg string, fields ...zap.Field) { 46 | //requestId := new(http.Request).Header.Get("request_id") 47 | //fields = append(fields, zap.String("request_id", requestId)) 48 | log.Warn(msg, fields...) 49 | } 50 | 51 | // Error logger 52 | func Error(msg string, fields ...zap.Field) { 53 | //requestId := new(http.Request).Header.Get("request_id") 54 | //fields = append(fields, zap.String("request_id", requestId)) 55 | log.Error(msg, fields...) 56 | } 57 | -------------------------------------------------------------------------------- /pkg/mail/mail.go: -------------------------------------------------------------------------------- 1 | package mail 2 | 3 | import ( 4 | "strings" 5 | 6 | "gopkg.in/gomail.v2" 7 | ) 8 | 9 | type Options struct { 10 | MailHost string 11 | MailPort int 12 | MailUser string // 发件人 13 | MailPass string // 发件人密码 14 | MailTo string // 收件人 多个用,分割 15 | Subject string // 邮件主题 16 | Body string // 邮件内容 17 | } 18 | 19 | func Send(o *Options) error { 20 | 21 | m := gomail.NewMessage() 22 | 23 | //设置发件人 24 | m.SetHeader("From", o.MailUser) 25 | 26 | //设置发送给多个用户 27 | mailArrTo := strings.Split(o.MailTo, ",") 28 | m.SetHeader("To", mailArrTo...) 29 | 30 | //设置邮件主题 31 | m.SetHeader("Subject", o.Subject) 32 | 33 | //设置邮件正文 34 | m.SetBody("text/html", o.Body) 35 | 36 | d := gomail.NewDialer(o.MailHost, o.MailPort, o.MailUser, o.MailPass) 37 | 38 | return d.DialAndSend(m) 39 | } 40 | -------------------------------------------------------------------------------- /pkg/mail/mail_test.go: -------------------------------------------------------------------------------- 1 | package mail 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSend(t *testing.T) { 8 | options := &Options{ 9 | MailHost: "smtp.163.com", 10 | MailPort: 465, 11 | MailUser: "xxx@163.com", 12 | MailPass: "", //密码或授权码 13 | MailTo: "", 14 | Subject: "subject", 15 | Body: "body", 16 | } 17 | err := Send(options) 18 | if err != nil { 19 | t.Error("Mail Send error", err) 20 | return 21 | } 22 | t.Log("success") 23 | } 24 | -------------------------------------------------------------------------------- /pkg/redis/redis.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/alicebob/miniredis/v2" 9 | "github.com/go-redis/redis/extra/redisotel/v8" 10 | "github.com/go-redis/redis/v8" 11 | ) 12 | 13 | // RedisClient redis 客户端 14 | var RedisClient *redis.Client 15 | 16 | // ErrRedisNotFound not exist in redis 17 | const ErrRedisNotFound = redis.Nil 18 | 19 | // Config redis config 20 | type Config struct { 21 | Addr string 22 | Password string 23 | DB int 24 | MinIdleConn int 25 | DialTimeout time.Duration 26 | ReadTimeout time.Duration 27 | WriteTimeout time.Duration 28 | PoolSize int 29 | PoolTimeout time.Duration 30 | // tracing switch 31 | EnableTrace bool 32 | } 33 | 34 | // Init 实例化一个redis client 35 | func Init(c *Config) *redis.Client { 36 | RedisClient = redis.NewClient(&redis.Options{ 37 | Addr: c.Addr, 38 | Password: c.Password, 39 | DB: c.DB, 40 | MinIdleConns: c.MinIdleConn, 41 | DialTimeout: c.DialTimeout, 42 | ReadTimeout: c.ReadTimeout, 43 | WriteTimeout: c.WriteTimeout, 44 | PoolSize: c.PoolSize, 45 | PoolTimeout: c.PoolTimeout, 46 | }) 47 | 48 | _, err := RedisClient.Ping(context.Background()).Result() 49 | if err != nil { 50 | panic(err) 51 | } 52 | 53 | // hook tracing (using open telemetry) 54 | if c.EnableTrace { 55 | RedisClient.AddHook(redisotel.NewTracingHook()) 56 | } 57 | 58 | return RedisClient 59 | } 60 | 61 | // InitTestRedis 实例化一个可以用于单元测试的redis 62 | func InitTestRedis() { 63 | mr, err := miniredis.Run() 64 | if err != nil { 65 | panic(err) 66 | } 67 | // 打开下面命令可以测试链接关闭的情况 68 | // defer mr.Close() 69 | 70 | RedisClient = redis.NewClient(&redis.Options{ 71 | Addr: mr.Addr(), 72 | }) 73 | fmt.Println("mini redis addr:", mr.Addr()) 74 | } 75 | -------------------------------------------------------------------------------- /pkg/redis/redis_test.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | func TestInitTestRedis(t *testing.T) { 10 | InitTestRedis() 11 | 12 | err := RedisClient.Ping(context.Background()).Err() 13 | if err != nil { 14 | t.Error("ping redis server err: ", err) 15 | return 16 | } 17 | t.Log("ping redis server pass") 18 | } 19 | 20 | func TestRedisSetGet(t *testing.T) { 21 | InitTestRedis() 22 | 23 | var setGetKey = "test-set" 24 | var setGetValue = "test-content" 25 | RedisClient.Set(context.Background(), setGetKey, setGetValue, time.Second*100) 26 | 27 | expectValue := RedisClient.Get(context.Background(), setGetKey).Val() 28 | if setGetValue != expectValue { 29 | t.Log("original value: ", setGetValue) 30 | t.Log("expect value: ", expectValue) 31 | return 32 | } 33 | 34 | t.Log("redis set get test pass") 35 | } 36 | -------------------------------------------------------------------------------- /pkg/shutdown/shutdown.go: -------------------------------------------------------------------------------- 1 | package shutdown 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "syscall" 7 | ) 8 | 9 | var _ Hook = (*hook)(nil) 10 | 11 | // Hook a graceful shutdown hook, default with signals of SIGINT and SIGTERM 12 | type Hook interface { 13 | // WithSignals add more signals into hook 14 | WithSignals(signals ...syscall.Signal) Hook 15 | 16 | // Close register shutdown handles 17 | Close(funcs ...func()) 18 | } 19 | 20 | type hook struct { 21 | ctx chan os.Signal 22 | } 23 | 24 | // NewHook create a Hook instance 25 | func NewHook() Hook { 26 | hook := &hook{ 27 | ctx: make(chan os.Signal, 1), 28 | } 29 | 30 | return hook.WithSignals(syscall.SIGINT, syscall.SIGTERM) 31 | } 32 | 33 | func (h *hook) WithSignals(signals ...syscall.Signal) Hook { 34 | for _, s := range signals { 35 | signal.Notify(h.ctx, s) 36 | } 37 | 38 | return h 39 | } 40 | 41 | func (h *hook) Close(funcs ...func()) { 42 | select { 43 | case <-h.ctx: 44 | } 45 | signal.Stop(h.ctx) 46 | 47 | for _, f := range funcs { 48 | f() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/storage/elasticsearch/README.md: -------------------------------------------------------------------------------- 1 | # Elasticsearch 2 | -------------------------------------------------------------------------------- /pkg/storage/elasticsearch/elasticsearch.go: -------------------------------------------------------------------------------- 1 | package elasticsearch 2 | 3 | type Config struct { 4 | Disable bool 5 | Urls []string 6 | } 7 | -------------------------------------------------------------------------------- /pkg/storage/mongodb/mongodb.go: -------------------------------------------------------------------------------- 1 | package mongodb 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "go.mongodb.org/mongo-driver/mongo" 8 | "go.mongodb.org/mongo-driver/mongo/options" 9 | ) 10 | 11 | const ( 12 | connectTimeout = 30 * time.Second 13 | maxConnIdleTime = 3 * time.Minute 14 | minPoolSize = 20 15 | maxPoolSize = 300 16 | ) 17 | 18 | // Config MongoDB config 19 | type Config struct { 20 | URI string 21 | User string 22 | Password string 23 | DB string 24 | } 25 | 26 | // NewMongoDBConn Create new MongoDB client 27 | func NewMongoDBConn(ctx context.Context, cfg *Config) (*mongo.Client, error) { 28 | client, err := mongo.NewClient( 29 | options.Client().ApplyURI(cfg.URI). 30 | SetAuth(options.Credential{ 31 | Username: cfg.User, 32 | Password: cfg.Password, 33 | }). 34 | SetConnectTimeout(connectTimeout). 35 | SetMaxConnIdleTime(maxConnIdleTime). 36 | SetMinPoolSize(minPoolSize). 37 | SetMaxPoolSize(maxPoolSize)) 38 | if err != nil { 39 | return nil, err 40 | } 41 | 42 | if err := client.Connect(ctx); err != nil { 43 | return nil, err 44 | } 45 | 46 | if err := client.Ping(ctx, nil); err != nil { 47 | return nil, err 48 | } 49 | 50 | return client, nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/storage/mysql/mysql.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | import ( 4 | "database/sql" 5 | "time" 6 | 7 | "github.com/pkg/errors" 8 | 9 | // database driver 10 | _ "github.com/go-sql-driver/mysql" 11 | ) 12 | 13 | // Config mysql config. 14 | type Config struct { 15 | DSN string // write data source name. 16 | MaxOpenConn int // open pool 17 | MaxIdleConn int // idle pool 18 | ConnMaxLifeTime int 19 | } 20 | 21 | // NewMySQL new db and retry connection when has error. 22 | func NewMySQL(c *Config) (db *sql.DB) { 23 | 24 | db, err := connect(c, c.DSN) 25 | if err != nil { 26 | panic(err) 27 | } 28 | return 29 | } 30 | 31 | func connect(c *Config, dataSourceName string) (*sql.DB, error) { 32 | d, err := sql.Open("mysql", dataSourceName) 33 | if err != nil { 34 | err = errors.WithStack(err) 35 | return nil, err 36 | } 37 | d.SetMaxOpenConns(c.MaxOpenConn) 38 | d.SetMaxIdleConns(c.MaxIdleConn) 39 | d.SetConnMaxLifetime(time.Duration(c.ConnMaxLifeTime)) 40 | return d, nil 41 | } 42 | -------------------------------------------------------------------------------- /pkg/time_parse/time_parse.go: -------------------------------------------------------------------------------- 1 | package time_parse 2 | 3 | import ( 4 | "math" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | var ( 10 | cst *time.Location 11 | ) 12 | 13 | // CSTLayout China Standard Time Layout 14 | const CSTLayout = "2006-01-02 15:04:05" 15 | 16 | func init() { 17 | var err error 18 | if cst, err = time.LoadLocation("Asia/Shanghai"); err != nil { 19 | panic(err) 20 | } 21 | } 22 | 23 | // RFC3339ToCSTLayout convert rfc3339 value to china standard time layout 24 | // 2020-11-08T08:18:46+08:00 => 2020-11-08 08:18:46 25 | func RFC3339ToCSTLayout(value string) (string, error) { 26 | ts, err := time.Parse(time.RFC3339, value) 27 | if err != nil { 28 | return "", err 29 | } 30 | 31 | return ts.In(cst).Format(CSTLayout), nil 32 | } 33 | 34 | // CSTLayoutString 格式化时间 35 | // 返回 "2006-01-02 15:04:05" 格式的时间 36 | func CSTLayoutString() string { 37 | ts := time.Now() 38 | return ts.In(cst).Format(CSTLayout) 39 | } 40 | 41 | // ParseCSTInLocation 格式化时间 42 | func ParseCSTInLocation(date string) (time.Time, error) { 43 | return time.ParseInLocation(CSTLayout, date, cst) 44 | } 45 | 46 | // CSTLayoutStringToUnix 返回 unix 时间戳 47 | // 2020-01-24 21:11:11 => 1579871471 48 | func CSTLayoutStringToUnix(cstLayoutString string) (int64, error) { 49 | stamp, err := time.ParseInLocation(CSTLayout, cstLayoutString, cst) 50 | if err != nil { 51 | return 0, err 52 | } 53 | return stamp.Unix(), nil 54 | } 55 | 56 | // GMTLayoutString 格式化时间 57 | // 返回 "Mon, 02 Jan 2006 15:04:05 GMT" 格式的时间 58 | func GMTLayoutString() string { 59 | return time.Now().In(cst).Format(http.TimeFormat) 60 | } 61 | 62 | // ParseGMTInLocation 格式化时间 63 | func ParseGMTInLocation(date string) (time.Time, error) { 64 | return time.ParseInLocation(http.TimeFormat, date, cst) 65 | } 66 | 67 | // SubInLocation 计算时间差 68 | func SubInLocation(ts time.Time) float64 { 69 | return math.Abs(time.Now().In(cst).Sub(ts).Seconds()) 70 | } 71 | -------------------------------------------------------------------------------- /pkg/time_parse/time_parse_test.go: -------------------------------------------------------------------------------- 1 | package time_parse 2 | 3 | import "testing" 4 | 5 | func TestRFC3339ToCSTLayout(t *testing.T) { 6 | t.Log(RFC3339ToCSTLayout("2020-11-08T08:18:46+08:00")) 7 | } 8 | 9 | func TestCSTLayoutString(t *testing.T) { 10 | t.Log(CSTLayoutString()) 11 | } 12 | 13 | func TestCSTLayoutStringToUnix(t *testing.T) { 14 | t.Log(CSTLayoutStringToUnix("2020-01-24 21:11:11")) 15 | } 16 | 17 | func TestGMTLayoutString(t *testing.T) { 18 | t.Log(GMTLayoutString()) 19 | } 20 | -------------------------------------------------------------------------------- /pkg/utils/README.md: -------------------------------------------------------------------------------- 1 | # util 2 | 3 | 业务工具包 -------------------------------------------------------------------------------- /pkg/utils/file.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "os" 4 | 5 | // 判断所给路径文件/文件夹是否存在 6 | 7 | func FileExists(path string) bool { 8 | _, err := os.Stat(path) //os.Stat获取文件信息 9 | if err != nil { 10 | if os.IsExist(err) { 11 | return true 12 | } 13 | return false 14 | } 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /pkg/utils/ip.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net" 5 | "strings" 6 | "sync" 7 | 8 | tnet "github.com/toolkits/net" 9 | ) 10 | 11 | var ( 12 | once sync.Once 13 | clientIP = "127.0.0.1" 14 | ) 15 | 16 | // GetLocalIP 获取本地内网IP 17 | func GetLocalIP() string { 18 | once.Do(func() { 19 | ips, _ := tnet.IntranetIP() 20 | if len(ips) > 0 { 21 | clientIP = ips[0] 22 | } else { 23 | clientIP = "127.0.0.1" 24 | } 25 | }) 26 | return clientIP 27 | } 28 | 29 | // GetInternalIP get internal ip. 30 | func GetInternalIP() string { 31 | inters, err := net.Interfaces() 32 | if err != nil { 33 | return "" 34 | } 35 | for _, inter := range inters { 36 | if inter.Flags&net.FlagUp != 0 && !strings.HasPrefix(inter.Name, "lo") { 37 | addrs, err := inter.Addrs() 38 | if err != nil { 39 | continue 40 | } 41 | for _, addr := range addrs { 42 | if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 43 | if ipnet.IP.To4() != nil { 44 | return ipnet.IP.String() 45 | } 46 | } 47 | } 48 | } 49 | } 50 | return "" 51 | } 52 | -------------------------------------------------------------------------------- /pkg/utils/ip_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | -------------------------------------------------------------------------------- /pkg/utils/string.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "strconv" 6 | "strings" 7 | "unsafe" 8 | ) 9 | 10 | // IsEmpty 是否是空字符串 11 | func IsEmpty(s string) bool { 12 | if s == "" { 13 | return true 14 | } 15 | 16 | return strings.TrimSpace(s) == "" 17 | } 18 | 19 | // ConcatString 连接字符串 20 | // NOTE: 性能比fmt.Sprintf和+号要好 21 | func ConcatString(s ...string) string { 22 | if len(s) == 0 { 23 | return "" 24 | } 25 | var buffer bytes.Buffer 26 | for _, i := range s { 27 | buffer.WriteString(i) 28 | } 29 | return buffer.String() 30 | } 31 | 32 | // StringToUint64 字符串转uint64 33 | func StringToUint64(str string) (uint64, error) { 34 | if str == "" { 35 | return 0, nil 36 | } 37 | valInt, err := strconv.Atoi(str) 38 | if err != nil { 39 | return 0, err 40 | } 41 | 42 | return uint64(valInt), nil 43 | } 44 | 45 | // StringToInt64 字符串转int64 46 | func StringToInt64(str string) (int64, error) { 47 | if str == "" { 48 | return 0, nil 49 | } 50 | valInt, err := strconv.Atoi(str) 51 | if err != nil { 52 | return 0, err 53 | } 54 | 55 | return int64(valInt), nil 56 | } 57 | 58 | // StringToInt 字符串转int 59 | func StringToInt(str string) (int, error) { 60 | if str == "" { 61 | return 0, nil 62 | } 63 | valInt, err := strconv.Atoi(str) 64 | if err != nil { 65 | return 0, err 66 | } 67 | 68 | return valInt, nil 69 | } 70 | 71 | // --------- 字节切片和字符串转换 ---------- 72 | // 性能很高, 原因在于底层无新的内存申请与拷贝 73 | 74 | // BytesToString 字节切片转字符串 75 | func BytesToString(b []byte) string { 76 | return *(*string)(unsafe.Pointer(&b)) 77 | } 78 | 79 | // StringToBytes convert string to byte 80 | func StringToBytes(s string) []byte { 81 | x := (*[2]uintptr)(unsafe.Pointer(&s)) 82 | h := [3]uintptr{x[0], x[1], x[1]} 83 | return *(*[]byte)(unsafe.Pointer(&h)) 84 | } 85 | -------------------------------------------------------------------------------- /pkg/utils/time.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | // GetDate 获取字符串日期 10 | func GetDate() string { 11 | return time.Now().Format("2006/01/02") 12 | } 13 | 14 | // GetTodayDateInt 获取整形的日期 15 | func GetTodayDateInt() int { 16 | dateStr := time.Now().Format("200601") 17 | date, err := strconv.Atoi(dateStr) 18 | if err != nil { 19 | return 0 20 | } 21 | return date 22 | } 23 | 24 | // TimeLayout 常用日期格式化模板 25 | func TimeLayout() string { 26 | return "2006-01-02 15:04:05" 27 | } 28 | 29 | // TimeToString 时间转字符串 30 | func TimeToString(ts time.Time) string { 31 | return time.Unix(ts.Unix(), 00).Format(TimeLayout()) 32 | } 33 | 34 | // TimeToShortString 时间转日期 35 | func TimeToShortString(ts time.Time) string { 36 | return time.Unix(ts.Unix(), 00).Format("2006.01.02") 37 | } 38 | 39 | // GetShowTime 格式化时间 40 | func GetShowTime(ts time.Time) string { 41 | duration := time.Now().Unix() - ts.Unix() 42 | timeStr := "" 43 | if duration < 60 { 44 | timeStr = "刚刚发布" 45 | } else if duration < 3600 { 46 | timeStr = fmt.Sprintf("%d分钟前更新", duration/60) 47 | } else if duration < 86400 { 48 | timeStr = fmt.Sprintf("%d小时前更新", duration/3600) 49 | } else if duration < 86400*2 { 50 | timeStr = "昨天更新" 51 | } else { 52 | timeStr = TimeToShortString(ts) + "前更新" 53 | } 54 | return timeStr 55 | } 56 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/md5" 6 | "encoding/gob" 7 | "fmt" 8 | "io" 9 | "math/rand" 10 | "os" 11 | "regexp" 12 | "time" 13 | 14 | "github.com/teris-io/shortid" 15 | ) 16 | 17 | // GenShortID 生成一个id 18 | func GenShortID() (string, error) { 19 | return shortid.Generate() 20 | } 21 | 22 | // GetBytes interface 转 byte 23 | func GetBytes(key interface{}) ([]byte, error) { 24 | var buf bytes.Buffer 25 | enc := gob.NewEncoder(&buf) 26 | err := enc.Encode(key) 27 | if err != nil { 28 | return nil, err 29 | } 30 | return buf.Bytes(), nil 31 | } 32 | 33 | // Md5 字符串转md5 34 | func Md5(str string) (string, error) { 35 | h := md5.New() 36 | 37 | _, err := io.WriteString(h, str) 38 | if err != nil { 39 | return "", err 40 | } 41 | 42 | // 注意:这里不能使用string将[]byte转为字符串,否则会显示乱码 43 | return fmt.Sprintf("%x", h.Sum(nil)), nil 44 | } 45 | 46 | // RandomStr 随机字符串 47 | func RandomStr(n int) string { 48 | var r = rand.New(rand.NewSource(time.Now().UnixNano())) 49 | const pattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" 50 | 51 | salt := make([]byte, 0, n) 52 | l := len(pattern) 53 | 54 | for i := 0; i < n; i++ { 55 | p := r.Intn(l) 56 | salt = append(salt, pattern[p]) 57 | } 58 | 59 | return string(salt) 60 | } 61 | 62 | // RegexpReplace ... 63 | func RegexpReplace(reg, src, temp string) string { 64 | result := []byte{} 65 | pattern := regexp.MustCompile(reg) 66 | for _, submatches := range pattern.FindAllStringSubmatchIndex(src, -1) { 67 | result = pattern.ExpandString(result, temp, src, submatches) 68 | } 69 | return string(result) 70 | } 71 | 72 | // GetHostname 获取主机名 73 | func GetHostname() string { 74 | name, err := os.Hostname() 75 | if err != nil { 76 | name = "unknown" 77 | } 78 | return name 79 | } 80 | -------------------------------------------------------------------------------- /pkg/utils/utils_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestGenShortID(t *testing.T) { 8 | shortID, err := GenShortID() 9 | if shortID == "" || err != nil { 10 | t.Error("GenShortID failed!") 11 | } 12 | 13 | t.Log("GenShortID test pass") 14 | } 15 | 16 | func BenchmarkGenShortID(b *testing.B) { 17 | for i := 0; i < b.N; i++ { 18 | GenShortID() 19 | } 20 | } 21 | 22 | func BenchmarkGenShortIDTimeConsuming(b *testing.B) { 23 | b.StopTimer() //调用该函数停止压力测试的时间计数 24 | 25 | shortID, err := GenShortID() 26 | if shortID == "" || err != nil { 27 | b.Error(err) 28 | } 29 | 30 | b.StartTimer() //重新开始时间 31 | 32 | for i := 0; i < b.N; i++ { 33 | GenShortID() 34 | } 35 | } 36 | 37 | func TestRandomStr(t *testing.T) { 38 | test := RandomStr(8) 39 | t.Log(test) 40 | } 41 | -------------------------------------------------------------------------------- /pkg/utils/valid.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // IsZero 检查是否是零值 8 | func IsZero(i ...interface{}) bool { 9 | ret := false 10 | for _, j := range i { 11 | v := reflect.ValueOf(j) 12 | if isZero(v) { 13 | return true 14 | } 15 | } 16 | return ret 17 | } 18 | 19 | func isZero(v reflect.Value) bool { 20 | switch v.Kind() { 21 | case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice: 22 | return v.IsNil() 23 | case reflect.Invalid: 24 | return true 25 | default: 26 | z := reflect.Zero(v.Type()) 27 | return reflect.DeepEqual(z.Interface(), v.Interface()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | process="goblog" 4 | echo ${process} $1 5 | 6 | start(){ 7 | pid=`pgrep ${process}` 8 | if [ "${pid}"x = ""x ];then 9 | echo "start new process..." 10 | nohup ./${process} -c conf/prod.yml & 11 | else 12 | for i in ${pid} 13 | do 14 | echo "reload the process [ $i ]" 15 | kill -9 $i 16 | done 17 | fi 18 | sleep 1 19 | nohup ./${process} -c conf/prod.yml & 20 | pid=`pgrep ${process}` 21 | echo "new process id: ${pid}" 22 | } 23 | 24 | stop(){ 25 | pid=`pgrep ${process}` 26 | echo ${pid} 27 | for i in ${pid} 28 | do 29 | echo "kill the process [ $i ]" 30 | kill -9 $i 31 | done 32 | } 33 | 34 | status(){ 35 | ps aux | grep -w ${process} | grep -v 'grep' 36 | } 37 | 38 | 39 | case "$1" in 40 | start) 41 | start $1;; 42 | stop) 43 | stop ;; 44 | status) 45 | status ;; 46 | *) 47 | echo "Usage: $0 {start|stop|reload|status}" 48 | 49 | esac 50 | -------------------------------------------------------------------------------- /static/admin/assets/demo/chart-area-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Area Chart Example 6 | var ctx = document.getElementById("myAreaChart"); 7 | var myLineChart = new Chart(ctx, { 8 | type: 'line', 9 | data: { 10 | labels: ["Mar 1", "Mar 2", "Mar 3", "Mar 4", "Mar 5", "Mar 6", "Mar 7", "Mar 8", "Mar 9", "Mar 10", "Mar 11", "Mar 12", "Mar 13"], 11 | datasets: [{ 12 | label: "Sessions", 13 | lineTension: 0.3, 14 | backgroundColor: "rgba(2,117,216,0.2)", 15 | borderColor: "rgba(2,117,216,1)", 16 | pointRadius: 5, 17 | pointBackgroundColor: "rgba(2,117,216,1)", 18 | pointBorderColor: "rgba(255,255,255,0.8)", 19 | pointHoverRadius: 5, 20 | pointHoverBackgroundColor: "rgba(2,117,216,1)", 21 | pointHitRadius: 50, 22 | pointBorderWidth: 2, 23 | data: [10000, 30162, 26263, 18394, 18287, 28682, 31274, 33259, 25849, 24159, 32651, 31984, 38451], 24 | }], 25 | }, 26 | options: { 27 | scales: { 28 | xAxes: [{ 29 | time: { 30 | unit: 'date' 31 | }, 32 | gridLines: { 33 | display: false 34 | }, 35 | ticks: { 36 | maxTicksLimit: 7 37 | } 38 | }], 39 | yAxes: [{ 40 | ticks: { 41 | min: 0, 42 | max: 40000, 43 | maxTicksLimit: 5 44 | }, 45 | gridLines: { 46 | color: "rgba(0, 0, 0, .125)", 47 | } 48 | }], 49 | }, 50 | legend: { 51 | display: false 52 | } 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /static/admin/assets/demo/chart-bar-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Bar Chart Example 6 | var ctx = document.getElementById("myBarChart"); 7 | var myLineChart = new Chart(ctx, { 8 | type: 'bar', 9 | data: { 10 | labels: ["January", "February", "March", "April", "May", "June"], 11 | datasets: [{ 12 | label: "Revenue", 13 | backgroundColor: "rgba(2,117,216,1)", 14 | borderColor: "rgba(2,117,216,1)", 15 | data: [4215, 5312, 6251, 7841, 9821, 14984], 16 | }], 17 | }, 18 | options: { 19 | scales: { 20 | xAxes: [{ 21 | time: { 22 | unit: 'month' 23 | }, 24 | gridLines: { 25 | display: false 26 | }, 27 | ticks: { 28 | maxTicksLimit: 6 29 | } 30 | }], 31 | yAxes: [{ 32 | ticks: { 33 | min: 0, 34 | max: 15000, 35 | maxTicksLimit: 5 36 | }, 37 | gridLines: { 38 | display: true 39 | } 40 | }], 41 | }, 42 | legend: { 43 | display: false 44 | } 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /static/admin/assets/demo/chart-pie-demo.js: -------------------------------------------------------------------------------- 1 | // Set new default font family and font color to mimic Bootstrap's default styling 2 | Chart.defaults.global.defaultFontFamily = '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif'; 3 | Chart.defaults.global.defaultFontColor = '#292b2c'; 4 | 5 | // Pie Chart Example 6 | var ctx = document.getElementById("myPieChart"); 7 | var myPieChart = new Chart(ctx, { 8 | type: 'pie', 9 | data: { 10 | labels: ["Blue", "Red", "Yellow", "Green"], 11 | datasets: [{ 12 | data: [12.21, 15.58, 11.25, 8.32], 13 | backgroundColor: ['#007bff', '#dc3545', '#ffc107', '#28a745'], 14 | }], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /static/admin/assets/demo/datatables-demo.js: -------------------------------------------------------------------------------- 1 | // Call the dataTables jQuery plugin 2 | $(document).ready(function () { 3 | $('#dataTable').DataTable(); 4 | }); 5 | -------------------------------------------------------------------------------- /static/admin/js/Simple example - Editor.md examples_files/dialog.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-dialog { 2 | position: absolute; 3 | left: 0; 4 | right: 0; 5 | background: white; 6 | z-index: 15; 7 | padding: .1em .8em; 8 | overflow: hidden; 9 | color: #333; 10 | } 11 | 12 | .CodeMirror-dialog-top { 13 | border-bottom: 1px solid #eee; 14 | top: 0; 15 | } 16 | 17 | .CodeMirror-dialog-bottom { 18 | border-top: 1px solid #eee; 19 | bottom: 0; 20 | } 21 | 22 | .CodeMirror-dialog input { 23 | border: none; 24 | outline: none; 25 | background: transparent; 26 | width: 20em; 27 | color: inherit; 28 | font-family: monospace; 29 | } 30 | 31 | .CodeMirror-dialog button { 32 | font-size: 70%; 33 | } 34 | -------------------------------------------------------------------------------- /static/admin/js/Simple example - Editor.md examples_files/matchesonscrollbar.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-search-match { 2 | background: gold; 3 | border-top: 1px solid orange; 4 | border-bottom: 1px solid orange; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | opacity: .5; 8 | } 9 | -------------------------------------------------------------------------------- /static/admin/js/datatables-simple-demo.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('DOMContentLoaded', event => { 2 | // Simple-DataTables 3 | // https://github.com/fiduswriter/Simple-DataTables/wiki 4 | 5 | const datatablesSimple = document.getElementById('datatablesSimple'); 6 | if (datatablesSimple) { 7 | new simpleDatatables.DataTable(datatablesSimple); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /static/admin/js/scripts.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - Admin v7.0.3 (https://startbootstrap.com/template/sb-admin) 3 | * Copyright 2013-2021 Start Bootstrap 4 | * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE) 5 | */ 6 | // 7 | // Scripts 8 | // 9 | 10 | window.addEventListener('DOMContentLoaded', event => { 11 | 12 | // Toggle the side navigation 13 | const sidebarToggle = document.body.querySelector('#sidebarToggle'); 14 | if (sidebarToggle) { 15 | // Uncomment Below to persist sidebar toggle between refreshes 16 | // if (localStorage.getItem('sb|sidebar-toggle') === 'true') { 17 | // document.body.classList.toggle('sb-sidenav-toggled'); 18 | // } 19 | sidebarToggle.addEventListener('click', event => { 20 | event.preventDefault(); 21 | document.body.classList.toggle('sb-sidenav-toggled'); 22 | localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled')); 23 | }); 24 | } 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/favicon.ico -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /static/md/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | *.pid 4 | *.seed 5 | node_modules/ 6 | .sass-cache/ 7 | research/ 8 | test/ 9 | backup/ 10 | examples/uploads/**/* 11 | *.bat 12 | *.sh 13 | .project 14 | .url 15 | css/*.map -------------------------------------------------------------------------------- /static/md/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "bitwise": true, 4 | "camelcase": true, 5 | "curly": true, 6 | "eqeqeq": true, 7 | "immed": true, 8 | "indent": 4, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "quotmark": "double", 13 | "regexp": true, 14 | "undef": true, 15 | "unused": true, 16 | "strict": true, 17 | "trailing": true, 18 | "smarttabs": true, 19 | "white": true 20 | } -------------------------------------------------------------------------------- /static/md/BUGS.md: -------------------------------------------------------------------------------- 1 | #Bugs 2 | 3 | > 说明:删除线表示已经解决。 4 | 5 | ####IE8 6 | 7 | - ~~不能加载;~~ 8 | - flowChart(流程图)、sequenceDiagram(序列图)不支持IE8; 9 | - ~~不支持Markdown转HTML页面解析预览;~~ 10 | 11 | ####IE8 & IE9 & IE10 12 | 13 | - KaTeX会出现解析错误,但不影响程序运行; 14 | 15 | ####Sea.js 16 | 17 | - ~~Raphael.js无法加载;~~ 18 | 19 | ####Require.js 20 | 21 | - ~~CodeMirror编辑器的代码无法高亮;~~ 22 | - ~~sequenceDiagram不支持: `Uncaught TypeError: Cannot call method 'isArray' of undefined.`~~ 23 | -------------------------------------------------------------------------------- /static/md/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 pandao 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 | 23 | -------------------------------------------------------------------------------- /static/md/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editor.md", 3 | "version": "1.5.0", 4 | "homepage": "https://github.com/pandao/editor.md", 5 | "authors": [ 6 | "Pandao " 7 | ], 8 | "description": "Open source online markdown editor.", 9 | "keywords": [ 10 | "editor.md", 11 | "markdown", 12 | "editor" 13 | ], 14 | "license": "MIT", 15 | "ignore": [ 16 | "**/.*", 17 | "research", 18 | "docs", 19 | "node_modules", 20 | "bower_components", 21 | "test", 22 | "tests" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /static/md/css/editormd.logo.min.css: -------------------------------------------------------------------------------- 1 | /*! Editor.md v1.5.0 | editormd.logo.min.css | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ 2 | /*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */@font-face{font-family:editormd-logo;src:url(../fonts/editormd-logo.eot?-5y8q6h);src:url(.../fonts/editormd-logo.eot?#iefix-5y8q6h)format("embedded-opentype"),url(../fonts/editormd-logo.woff?-5y8q6h)format("woff"),url(../fonts/editormd-logo.ttf?-5y8q6h)format("truetype"),url(../fonts/editormd-logo.svg?-5y8q6h#icomoon)format("svg");font-weight:400;font-style:normal}.editormd-logo,.editormd-logo-1x,.editormd-logo-2x,.editormd-logo-3x,.editormd-logo-4x,.editormd-logo-5x,.editormd-logo-6x,.editormd-logo-7x,.editormd-logo-8x{font-family:editormd-logo;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;font-size:inherit;line-height:1;display:inline-block;text-rendering:auto;vertical-align:inherit;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.editormd-logo-1x:before,.editormd-logo-2x:before,.editormd-logo-3x:before,.editormd-logo-4x:before,.editormd-logo-5x:before,.editormd-logo-6x:before,.editormd-logo-7x:before,.editormd-logo-8x:before,.editormd-logo:before{content:"\e1987"}.editormd-logo-1x{font-size:1em}.editormd-logo-lg{font-size:1.2em}.editormd-logo-2x{font-size:2em}.editormd-logo-3x{font-size:3em}.editormd-logo-4x{font-size:4em}.editormd-logo-5x{font-size:5em}.editormd-logo-6x{font-size:6em}.editormd-logo-7x{font-size:7em}.editormd-logo-8x{font-size:8em}.editormd-logo-color{color:#2196F3} -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /static/md/docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /static/md/docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 |

24 | 25 | 26 |
27 | 28 | 31 | 32 |
33 | 34 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /static/md/docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function () { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /static/md/docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /static/md/examples/auto-height.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Auto height - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Auto height test

14 |
15 |
16 | 17 |
18 |
19 | 27 |
28 |
29 | 30 | 31 | 54 | 55 | -------------------------------------------------------------------------------- /static/md/examples/code-fold.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Code folding - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Code folding

14 |

Switch code folding : Press Ctrl + Q / Command + Q

15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 | 43 | 44 | -------------------------------------------------------------------------------- /static/md/examples/delay-renderer-preview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Delay Rerender & Preview - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Delay Rerender & Preview

14 |

P.S. If you input the content too much and too fast, You can setting the delay value.

15 |

P.S. 适用于输入内容太多太快的情形,但要是一个合理的值,不然会显得预览太慢。打字慢会相对显得慢,打字快时则相对显得快。

16 |
17 |
18 | 26 |
27 |
28 | 29 | 30 | 55 | 56 | -------------------------------------------------------------------------------- /static/md/examples/dynamic-create-editormd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 动态创建 Editor.md - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

动态创建 Editor.md

14 |

Dynamic create Editor.md

15 |
16 |
17 | 18 | 19 |
20 |
21 |
22 | 23 | 24 | 46 | 47 | -------------------------------------------------------------------------------- /static/md/examples/flowchart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FlowChart - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

FlowChart 流程图

14 |

Based on flowchart.js:http://adrai.github.io/flowchart.js/ 15 |

16 |
17 |
18 | 38 |
39 |
40 | 41 | 42 | 43 | 53 | 54 | -------------------------------------------------------------------------------- /static/md/examples/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/examples/images/4.jpg -------------------------------------------------------------------------------- /static/md/examples/images/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/examples/images/7.jpg -------------------------------------------------------------------------------- /static/md/examples/images/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/examples/images/8.jpg -------------------------------------------------------------------------------- /static/md/examples/images/editormd-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/examples/images/editormd-screenshot.png -------------------------------------------------------------------------------- /static/md/examples/multi-editormd.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Multi Editor.md - Editor.md examples 6 | 7 | 8 | 9 | 19 | 20 | 21 |
22 |
23 |

Multi Editor.md

24 |

多个 Editor.md 并存

25 |
26 |
27 |

Editor.md A

28 |
29 |

Editor.md B

30 |
31 |

Editor.md C

32 |
33 |
34 | 35 | 36 | 37 | 63 | 64 | -------------------------------------------------------------------------------- /static/md/examples/onchange.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onchange - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Onchange event

14 |

Plaese press F12, open the develop tools.

15 |

16 |
17 |
18 | 29 |
30 |
31 | 32 | 33 | 48 | 49 | -------------------------------------------------------------------------------- /static/md/examples/onfullscreen.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onfullscreen & onfullscreenExit - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Onfullscreen & onfullscreenExit event

14 |

Plaese press F12, open the develop tools.

15 |
16 |
17 | 33 |
34 |
35 | 36 | 37 | 54 | 55 | -------------------------------------------------------------------------------- /static/md/examples/onload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onload - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Onload event

14 |

Plaese press F12, open the develop tools.

15 |
16 |
17 | 29 |
30 |
31 | 32 | 33 | 51 | 52 | -------------------------------------------------------------------------------- /static/md/examples/onpreviewing-onpreviewed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onpreviewing / Onpreviewed - Editor.md examples 6 | 7 | 8 | 9 | 15 | 16 | 17 |
18 |
19 |

Onpreviewing / Onpreviewed event handle

20 |

Plaese press F12, open the develop tools.

21 |
22 |
23 | 38 |
39 |
40 | 41 | 42 | 57 | 58 | -------------------------------------------------------------------------------- /static/md/examples/onresize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onresize - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Onresize event handle

14 |

Plaese press F12, open the develop tools.

15 |
16 |
17 | 31 |
32 |
33 | 34 | 35 | 48 | 49 | -------------------------------------------------------------------------------- /static/md/examples/onwatch-onunwatch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Onwatch / Onunwatch - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Onwatch / Onunwatch event handle

14 |

Plaese press F12, open the develop tools.

15 |
16 |
17 | 31 |
32 |
33 | 34 | 35 | 50 | 51 | -------------------------------------------------------------------------------- /static/md/examples/php/cross-domain-upload.php: -------------------------------------------------------------------------------- 1 | array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'webp') 28 | ); 29 | 30 | $name = 'editormd-image-file'; // file input name 31 | $callbackUrl = $_GET['callback']; 32 | 33 | if (isset($_FILES[$name])) 34 | { 35 | $imageUploader = new EditorMdUploader($savePath, $saveURL, $formats['image'], false); // Ymdhis表示按日期生成文件名,利用date()函数 36 | 37 | $imageUploader->config(array( 38 | 'maxSize' => 1024, // 允许上传的最大文件大小,以KB为单位,默认值为1024 39 | 'cover' => true // 是否覆盖同名文件,默认为true 40 | )); 41 | 42 | $imageUploader->redirect = true; 43 | $imageUploader->redirectURL = $callbackUrl . (empty(parse_url($callbackUrl)['query']) ? '?' : '&') . 'dialog_id=' . $_GET['dialog_id'] . '&temp=' . date('ymdhis'); 44 | 45 | if ($imageUploader->upload($name)) 46 | { 47 | $imageUploader->message('上传成功!', 1); 48 | } 49 | else 50 | { 51 | $imageUploader->message('上传失败!', 0); 52 | } 53 | } 54 | ?> -------------------------------------------------------------------------------- /static/md/examples/php/post.php: -------------------------------------------------------------------------------- 1 | "; 7 | echo htmlspecialchars($_POST["test-editormd-markdown-doc"]); 8 | 9 | if(isset($_POST["test-editormd-html-code"])) { 10 | echo "

"; 11 | echo htmlspecialchars($_POST["test-editormd-html-code"]); 12 | } 13 | 14 | echo ""; 15 | } 16 | 17 | exit; 18 | ?> -------------------------------------------------------------------------------- /static/md/examples/php/upload.php: -------------------------------------------------------------------------------- 1 | array('gif', 'jpg', 'jpeg', 'png', 'bmp') 29 | ); 30 | 31 | $name = 'editormd-image-file'; 32 | 33 | if (isset($_FILES[$name])) 34 | { 35 | $imageUploader = new EditorMdUploader($savePath, $saveURL, $formats['image'], false); // Ymdhis表示按日期生成文件名,利用date()函数 36 | 37 | $imageUploader->config(array( 38 | 'maxSize' => 1024, // 允许上传的最大文件大小,以KB为单位,默认值为1024 39 | 'cover' => true // 是否覆盖同名文件,默认为true 40 | )); 41 | 42 | if ($imageUploader->upload($name)) 43 | { 44 | $imageUploader->message('上传成功!', 1); 45 | } 46 | else 47 | { 48 | $imageUploader->message('上传失败!', 0); 49 | } 50 | } 51 | ?> -------------------------------------------------------------------------------- /static/md/examples/php/upload_callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 30 | 31 | -------------------------------------------------------------------------------- /static/md/examples/readonly.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Read only mode - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

只读模式

14 |

Read only mode

15 |
16 |
17 | 18 | 19 |
20 |
21 | 32 |
33 |
34 | 35 | 36 | 59 | 60 | -------------------------------------------------------------------------------- /static/md/examples/search-replace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Search / Replace - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Search / Replace

14 |

Search: Press Ctrl + F / Command + F

15 |

Replace: Press Ctrl + Shift + F / Command + Option + F

16 |

Replace All: Press Ctrl + Shift + R / Command + Option + R

17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 | 45 | 46 | -------------------------------------------------------------------------------- /static/md/examples/sequence-diagram.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SequenceDiagram - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

SequenceDiagram 时序图/序列图

14 |

Based on SequenceDiagram.js:http://bramp.github.io/js-sequence-diagrams/ 15 |

16 |
17 |
18 | 50 |
51 |
52 | 53 | 54 | 55 | 65 | 66 | -------------------------------------------------------------------------------- /static/md/examples/simple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Simple example - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Simple example

14 |
15 |
16 | 49 |
50 |
51 | 52 | 53 | 75 | 76 | -------------------------------------------------------------------------------- /static/md/examples/sync-scrolling.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sync scrolling - Editor.md examples 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

Sync scrolling

14 |
15 |
16 | 17 | 18 | 19 |
20 |
21 | 42 |
43 |
44 | 45 | 46 | 69 | 70 | -------------------------------------------------------------------------------- /static/md/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /static/md/fonts/editormd-logo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/editormd-logo.eot -------------------------------------------------------------------------------- /static/md/fonts/editormd-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/md/fonts/editormd-logo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/editormd-logo.ttf -------------------------------------------------------------------------------- /static/md/fonts/editormd-logo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/editormd-logo.woff -------------------------------------------------------------------------------- /static/md/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/md/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/md/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/md/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /static/md/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/4.jpg -------------------------------------------------------------------------------- /static/md/images/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/7.jpg -------------------------------------------------------------------------------- /static/md/images/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/8.jpg -------------------------------------------------------------------------------- /static/md/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/loading.gif -------------------------------------------------------------------------------- /static/md/images/loading@2x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/loading@2x.gif -------------------------------------------------------------------------------- /static/md/images/loading@3x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/loading@3x.gif -------------------------------------------------------------------------------- /static/md/images/logos/editormd-favicon-16x16.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-favicon-16x16.ico -------------------------------------------------------------------------------- /static/md/images/logos/editormd-favicon-24x24.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-favicon-24x24.ico -------------------------------------------------------------------------------- /static/md/images/logos/editormd-favicon-32x32.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-favicon-32x32.ico -------------------------------------------------------------------------------- /static/md/images/logos/editormd-favicon-48x48.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-favicon-48x48.ico -------------------------------------------------------------------------------- /static/md/images/logos/editormd-favicon-64x64.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-favicon-64x64.ico -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-114x114.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-120x120.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-144x144.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-16x16.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-180x180.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-240x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-240x240.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-24x24.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-320x320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-320x320.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-32x32.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-48x48.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-57x57.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-64x64.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-72x72.png -------------------------------------------------------------------------------- /static/md/images/logos/editormd-logo-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/editormd-logo-96x96.png -------------------------------------------------------------------------------- /static/md/images/logos/vi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/convee/goblog/e1f24a396d81b9f9c30a203ccab6daf89a134017/static/md/images/logos/vi.png -------------------------------------------------------------------------------- /static/md/lib/codemirror/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 by Marijn Haverbeke and others 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/README.md: -------------------------------------------------------------------------------- 1 | # CodeMirror 2 | 3 | [![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror) 4 | [![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror) 5 | [Funding status: ![maintainer happiness](https://marijnhaverbeke.nl/fund/status_s.png)](https://marijnhaverbeke.nl/fund/) 6 | 7 | CodeMirror is a JavaScript component that provides a code editor in 8 | the browser. When a mode is available for the language you are coding 9 | in, it will color your code, and optionally help with indentation. 10 | 11 | The project page is http://codemirror.net 12 | The manual is at http://codemirror.net/doc/manual.html 13 | The contributing guidelines are 14 | in [CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md) 15 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/dialog/dialog.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-dialog { 2 | position: absolute; 3 | left: 0; 4 | right: 0; 5 | background: white; 6 | z-index: 15; 7 | padding: .1em .8em; 8 | overflow: hidden; 9 | color: #333; 10 | } 11 | 12 | .CodeMirror-dialog-top { 13 | border-bottom: 1px solid #eee; 14 | top: 0; 15 | } 16 | 17 | .CodeMirror-dialog-bottom { 18 | border-top: 1px solid #eee; 19 | bottom: 0; 20 | } 21 | 22 | .CodeMirror-dialog input { 23 | border: none; 24 | outline: none; 25 | background: transparent; 26 | width: 20em; 27 | color: inherit; 28 | font-family: monospace; 29 | } 30 | 31 | .CodeMirror-dialog button { 32 | font-size: 70%; 33 | } 34 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/display/fullscreen.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-fullscreen { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | bottom: 0; 7 | height: auto; 8 | z-index: 9; 9 | } 10 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/display/fullscreen.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineOption("fullScreen", false, function (cm, val, old) { 15 | if (old == CodeMirror.Init) old = false; 16 | if (!old == !val) return; 17 | if (val) setFullscreen(cm); 18 | else setNormal(cm); 19 | }); 20 | 21 | function setFullscreen(cm) { 22 | var wrap = cm.getWrapperElement(); 23 | cm.state.fullScreenRestore = { 24 | scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, 25 | width: wrap.style.width, height: wrap.style.height 26 | }; 27 | wrap.style.width = ""; 28 | wrap.style.height = "auto"; 29 | wrap.className += " CodeMirror-fullscreen"; 30 | document.documentElement.style.overflow = "hidden"; 31 | cm.refresh(); 32 | } 33 | 34 | function setNormal(cm) { 35 | var wrap = cm.getWrapperElement(); 36 | wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); 37 | document.documentElement.style.overflow = ""; 38 | var info = cm.state.fullScreenRestore; 39 | wrap.style.width = info.width; 40 | wrap.style.height = info.height; 41 | window.scrollTo(info.scrollLeft, info.scrollTop); 42 | cm.refresh(); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/edit/trailingspace.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | CodeMirror.defineOption("showTrailingSpace", false, function (cm, val, prev) { 13 | if (prev == CodeMirror.Init) prev = false; 14 | if (prev && !val) 15 | cm.removeOverlay("trailingspace"); 16 | else if (!prev && val) 17 | cm.addOverlay({ 18 | token: function (stream) { 19 | for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) { 20 | } 21 | if (i > stream.pos) { 22 | stream.pos = i; 23 | return null; 24 | } 25 | stream.pos = l; 26 | return "trailingspace"; 27 | }, 28 | name: "trailingspace" 29 | }); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/fold/foldgutter.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-foldmarker { 2 | color: blue; 3 | text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; 4 | font-family: arial; 5 | line-height: .3; 6 | cursor: pointer; 7 | } 8 | 9 | .CodeMirror-foldgutter { 10 | width: .7em; 11 | } 12 | 13 | .CodeMirror-foldgutter-open, 14 | .CodeMirror-foldgutter-folded { 15 | cursor: pointer; 16 | } 17 | 18 | .CodeMirror-foldgutter-open:after { 19 | content: "\25BE"; 20 | } 21 | 22 | .CodeMirror-foldgutter-folded:after { 23 | content: "\25B8"; 24 | } 25 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/fold/indent-fold.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.registerHelper("fold", "indent", function (cm, start) { 15 | var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); 16 | if (!/\S/.test(firstLine)) return; 17 | var getIndent = function (line) { 18 | return CodeMirror.countColumn(line, null, tabSize); 19 | }; 20 | var myIndent = getIndent(firstLine); 21 | var lastLineInFold = null; 22 | // Go through lines until we find a line that definitely doesn't belong in 23 | // the block we're folding, or to the end. 24 | for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { 25 | var curLine = cm.getLine(i); 26 | var curIndent = getIndent(curLine); 27 | if (curIndent > myIndent) { 28 | // Lines with a greater indent are considered part of the block. 29 | lastLineInFold = i; 30 | } else if (!/\S/.test(curLine)) { 31 | // Empty lines might be breaks within the block we're trying to fold. 32 | } else { 33 | // A non-empty line at an indent equal to or less than ours marks the 34 | // start of another block. 35 | break; 36 | } 37 | } 38 | if (lastLineInFold) return { 39 | from: CodeMirror.Pos(start.line, firstLine.length), 40 | to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) 41 | }; 42 | }); 43 | 44 | }); 45 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/fold/markdown-fold.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.registerHelper("fold", "markdown", function (cm, start) { 15 | var maxDepth = 100; 16 | 17 | function isHeader(lineNo) { 18 | var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); 19 | return tokentype && /\bheader\b/.test(tokentype); 20 | } 21 | 22 | function headerLevel(lineNo, line, nextLine) { 23 | var match = line && line.match(/^#+/); 24 | if (match && isHeader(lineNo)) return match[0].length; 25 | match = nextLine && nextLine.match(/^[=\-]+\s*$/); 26 | if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; 27 | return maxDepth; 28 | } 29 | 30 | var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); 31 | var level = headerLevel(start.line, firstLine, nextLine); 32 | if (level === maxDepth) return undefined; 33 | 34 | var lastLineNo = cm.lastLine(); 35 | var end = start.line, nextNextLine = cm.getLine(end + 2); 36 | while (end < lastLineNo) { 37 | if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; 38 | ++end; 39 | nextLine = nextNextLine; 40 | nextNextLine = cm.getLine(end + 2); 41 | } 42 | 43 | return { 44 | from: CodeMirror.Pos(start.line, firstLine.length), 45 | to: CodeMirror.Pos(end, cm.getLine(end).length) 46 | }; 47 | }); 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/hint/anyword-hint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | var WORD = /[\w$]+/, RANGE = 500; 15 | 16 | CodeMirror.registerHelper("hint", "anyword", function (editor, options) { 17 | var word = options && options.word || WORD; 18 | var range = options && options.range || RANGE; 19 | var cur = editor.getCursor(), curLine = editor.getLine(cur.line); 20 | var end = cur.ch, start = end; 21 | while (start && word.test(curLine.charAt(start - 1))) --start; 22 | var curWord = start != end && curLine.slice(start, end); 23 | 24 | var list = [], seen = {}; 25 | var re = new RegExp(word.source, "g"); 26 | for (var dir = -1; dir <= 1; dir += 2) { 27 | var line = cur.line, 28 | endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; 29 | for (; line != endLine; line += dir) { 30 | var text = editor.getLine(line), m; 31 | while (m = re.exec(text)) { 32 | if (line == cur.line && m[0] === curWord) continue; 33 | if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { 34 | seen[m[0]] = true; 35 | list.push(m[0]); 36 | } 37 | } 38 | } 39 | } 40 | return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/hint/show-hint.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-hints { 2 | position: absolute; 3 | z-index: 10; 4 | overflow: hidden; 5 | list-style: none; 6 | 7 | margin: 0; 8 | padding: 2px; 9 | 10 | -webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); 11 | -moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); 12 | box-shadow: 2px 3px 5px rgba(0, 0, 0, .2); 13 | border-radius: 3px; 14 | border: 1px solid silver; 15 | 16 | background: white; 17 | font-size: 90%; 18 | font-family: monospace; 19 | 20 | max-height: 20em; 21 | overflow-y: auto; 22 | } 23 | 24 | .CodeMirror-hint { 25 | margin: 0; 26 | padding: 0 4px; 27 | border-radius: 2px; 28 | max-width: 19em; 29 | overflow: hidden; 30 | white-space: pre; 31 | color: black; 32 | cursor: pointer; 33 | } 34 | 35 | li.CodeMirror-hint-active { 36 | background: #08f; 37 | color: white; 38 | } 39 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/lint/coffeescript-lint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js 5 | 6 | // declare global: coffeelint 7 | 8 | (function (mod) { 9 | if (typeof exports == "object" && typeof module == "object") // CommonJS 10 | mod(require("../../lib/codemirror")); 11 | else if (typeof define == "function" && define.amd) // AMD 12 | define(["../../lib/codemirror"], mod); 13 | else // Plain browser env 14 | mod(CodeMirror); 15 | })(function (CodeMirror) { 16 | "use strict"; 17 | 18 | CodeMirror.registerHelper("lint", "coffeescript", function (text) { 19 | var found = []; 20 | var parseError = function (err) { 21 | var loc = err.lineNumber; 22 | found.push({ 23 | from: CodeMirror.Pos(loc - 1, 0), 24 | to: CodeMirror.Pos(loc, 0), 25 | severity: err.level, 26 | message: err.message 27 | }); 28 | }; 29 | try { 30 | var res = coffeelint.lint(text); 31 | for (var i = 0; i < res.length; i++) { 32 | parseError(res[i]); 33 | } 34 | } catch (e) { 35 | found.push({ 36 | from: CodeMirror.Pos(e.location.first_line, 0), 37 | to: CodeMirror.Pos(e.location.last_line, e.location.last_column), 38 | severity: 'error', 39 | message: e.message 40 | }); 41 | } 42 | return found; 43 | }); 44 | 45 | }); 46 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/lint/css-lint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | // Depends on csslint.js from https://github.com/stubbornella/csslint 5 | 6 | // declare global: CSSLint 7 | 8 | (function (mod) { 9 | if (typeof exports == "object" && typeof module == "object") // CommonJS 10 | mod(require("../../lib/codemirror")); 11 | else if (typeof define == "function" && define.amd) // AMD 12 | define(["../../lib/codemirror"], mod); 13 | else // Plain browser env 14 | mod(CodeMirror); 15 | })(function (CodeMirror) { 16 | "use strict"; 17 | 18 | CodeMirror.registerHelper("lint", "css", function (text) { 19 | var found = []; 20 | if (!window.CSSLint) return found; 21 | var results = CSSLint.verify(text), messages = results.messages, message = null; 22 | for (var i = 0; i < messages.length; i++) { 23 | message = messages[i]; 24 | var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, 25 | endCol = message.col; 26 | found.push({ 27 | from: CodeMirror.Pos(startLine, startCol), 28 | to: CodeMirror.Pos(endLine, endCol), 29 | message: message.message, 30 | severity: message.type 31 | }); 32 | } 33 | return found; 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/lint/json-lint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | // Depends on jsonlint.js from https://github.com/zaach/jsonlint 5 | 6 | // declare global: jsonlint 7 | 8 | (function (mod) { 9 | if (typeof exports == "object" && typeof module == "object") // CommonJS 10 | mod(require("../../lib/codemirror")); 11 | else if (typeof define == "function" && define.amd) // AMD 12 | define(["../../lib/codemirror"], mod); 13 | else // Plain browser env 14 | mod(CodeMirror); 15 | })(function (CodeMirror) { 16 | "use strict"; 17 | 18 | CodeMirror.registerHelper("lint", "json", function (text) { 19 | var found = []; 20 | jsonlint.parseError = function (str, hash) { 21 | var loc = hash.loc; 22 | found.push({ 23 | from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), 24 | to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), 25 | message: str 26 | }); 27 | }; 28 | try { 29 | jsonlint.parse(text); 30 | } catch (e) { 31 | } 32 | return found; 33 | }); 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/lint/yaml-lint.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | // Depends on js-yaml.js from https://github.com/nodeca/js-yaml 15 | 16 | // declare global: jsyaml 17 | 18 | CodeMirror.registerHelper("lint", "yaml", function (text) { 19 | var found = []; 20 | try { 21 | jsyaml.load(text); 22 | } catch (e) { 23 | var loc = e.mark; 24 | found.push({ 25 | from: CodeMirror.Pos(loc.line, loc.column), 26 | to: CodeMirror.Pos(loc.line, loc.column), 27 | message: e.message 28 | }); 29 | } 30 | return found; 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/mode/multiplex_test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function () { 5 | CodeMirror.defineMode("markdown_with_stex", function () { 6 | var inner = CodeMirror.getMode({}, "stex"); 7 | var outer = CodeMirror.getMode({}, "markdown"); 8 | 9 | var innerOptions = { 10 | open: '$', 11 | close: '$', 12 | mode: inner, 13 | delimStyle: 'delim', 14 | innerStyle: 'inner' 15 | }; 16 | 17 | return CodeMirror.multiplexingMode(outer, innerOptions); 18 | }); 19 | 20 | var mode = CodeMirror.getMode({}, "markdown_with_stex"); 21 | 22 | function MT(name) { 23 | test.mode( 24 | name, 25 | mode, 26 | Array.prototype.slice.call(arguments, 1), 27 | 'multiplexing'); 28 | } 29 | 30 | MT( 31 | "stexInsideMarkdown", 32 | "[strong **Equation:**] [delim $][inner&tag \\pi][delim $]"); 33 | })(); 34 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/runmode/colorize.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror"), require("./runmode")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror", "./runmode"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; 15 | 16 | function textContent(node, out) { 17 | if (node.nodeType == 3) return out.push(node.nodeValue); 18 | for (var ch = node.firstChild; ch; ch = ch.nextSibling) { 19 | textContent(ch, out); 20 | if (isBlock.test(node.nodeType)) out.push("\n"); 21 | } 22 | } 23 | 24 | CodeMirror.colorize = function (collection, defaultMode) { 25 | if (!collection) collection = document.body.getElementsByTagName("pre"); 26 | 27 | for (var i = 0; i < collection.length; ++i) { 28 | var node = collection[i]; 29 | var mode = node.getAttribute("data-lang") || defaultMode; 30 | if (!mode) continue; 31 | 32 | var text = []; 33 | textContent(node, text); 34 | node.innerHTML = ""; 35 | CodeMirror.runMode(text.join(""), mode, node); 36 | 37 | node.className += " cm-s-default"; 38 | } 39 | }; 40 | }); 41 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/scroll/scrollpastend.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineOption("scrollPastEnd", false, function (cm, val, old) { 15 | if (old && old != CodeMirror.Init) { 16 | cm.off("change", onChange); 17 | cm.off("refresh", updateBottomMargin); 18 | cm.display.lineSpace.parentNode.style.paddingBottom = ""; 19 | cm.state.scrollPastEndPadding = null; 20 | } 21 | if (val) { 22 | cm.on("change", onChange); 23 | cm.on("refresh", updateBottomMargin); 24 | updateBottomMargin(cm); 25 | } 26 | }); 27 | 28 | function onChange(cm, change) { 29 | if (CodeMirror.changeEnd(change).line == cm.lastLine()) 30 | updateBottomMargin(cm); 31 | } 32 | 33 | function updateBottomMargin(cm) { 34 | var padding = ""; 35 | if (cm.lineCount() > 1) { 36 | var totalH = cm.display.scroller.clientHeight - 30, 37 | lastLineH = cm.getLineHandle(cm.lastLine()).height; 38 | padding = (totalH - lastLineH) + "px"; 39 | } 40 | if (cm.state.scrollPastEndPadding != padding) { 41 | cm.state.scrollPastEndPadding = padding; 42 | cm.display.lineSpace.parentNode.style.paddingBottom = padding; 43 | cm.setSize(); 44 | } 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/scroll/simplescrollbars.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { 2 | position: absolute; 3 | background: #ccc; 4 | -moz-box-sizing: border-box; 5 | box-sizing: border-box; 6 | border: 1px solid #bbb; 7 | border-radius: 2px; 8 | } 9 | 10 | .CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical { 11 | position: absolute; 12 | z-index: 6; 13 | background: #eee; 14 | } 15 | 16 | .CodeMirror-simplescroll-horizontal { 17 | bottom: 0; 18 | left: 0; 19 | height: 8px; 20 | } 21 | 22 | .CodeMirror-simplescroll-horizontal div { 23 | bottom: 0; 24 | height: 100%; 25 | } 26 | 27 | .CodeMirror-simplescroll-vertical { 28 | right: 0; 29 | top: 0; 30 | width: 8px; 31 | } 32 | 33 | .CodeMirror-simplescroll-vertical div { 34 | right: 0; 35 | width: 100%; 36 | } 37 | 38 | 39 | .CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { 40 | display: none; 41 | } 42 | 43 | .CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div { 44 | position: absolute; 45 | background: #bcd; 46 | border-radius: 3px; 47 | } 48 | 49 | .CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical { 50 | position: absolute; 51 | z-index: 6; 52 | } 53 | 54 | .CodeMirror-overlayscroll-horizontal { 55 | bottom: 0; 56 | left: 0; 57 | height: 6px; 58 | } 59 | 60 | .CodeMirror-overlayscroll-horizontal div { 61 | bottom: 0; 62 | height: 100%; 63 | } 64 | 65 | .CodeMirror-overlayscroll-vertical { 66 | right: 0; 67 | top: 0; 68 | width: 6px; 69 | } 70 | 71 | .CodeMirror-overlayscroll-vertical div { 72 | right: 0; 73 | width: 100%; 74 | } 75 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/search/matchesonscrollbar.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-search-match { 2 | background: gold; 3 | border-top: 1px solid orange; 4 | border-bottom: 1px solid orange; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | opacity: .5; 8 | } 9 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/addon/tern/worker.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | // declare global: tern, server 5 | 6 | var server; 7 | 8 | this.onmessage = function (e) { 9 | var data = e.data; 10 | switch (data.type) { 11 | case "init": 12 | return startServer(data.defs, data.plugins, data.scripts); 13 | case "add": 14 | return server.addFile(data.name, data.text); 15 | case "del": 16 | return server.delFile(data.name); 17 | case "req": 18 | return server.request(data.body, function (err, reqData) { 19 | postMessage({id: data.id, body: reqData, err: err && String(err)}); 20 | }); 21 | case "getFile": 22 | var c = pending[data.id]; 23 | delete pending[data.id]; 24 | return c(data.err, data.text); 25 | default: 26 | throw new Error("Unknown message type: " + data.type); 27 | } 28 | }; 29 | 30 | var nextId = 0, pending = {}; 31 | 32 | function getFile(file, c) { 33 | postMessage({type: "getFile", name: file, id: ++nextId}); 34 | pending[nextId] = c; 35 | } 36 | 37 | function startServer(defs, plugins, scripts) { 38 | if (scripts) importScripts.apply(null, scripts); 39 | 40 | server = new tern.Server({ 41 | getFile: getFile, 42 | async: true, 43 | defs: defs, 44 | plugins: plugins 45 | }); 46 | } 47 | 48 | var console = { 49 | log: function (v) { 50 | postMessage({type: "debug", message: v}); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codemirror", 3 | "version": "5.0.0", 4 | "main": [ 5 | "lib/codemirror.js", 6 | "lib/codemirror.css" 7 | ], 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "components", 12 | "bin", 13 | "demo", 14 | "doc", 15 | "test", 16 | "index.html", 17 | "package.json" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/dart/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Dart mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 26 | 27 |
28 |

Dart mode

29 |
30 | 64 |
65 | 66 | 72 | 73 |
74 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/diff/diff.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function (mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function (CodeMirror) { 12 | "use strict"; 13 | 14 | CodeMirror.defineMode("diff", function () { 15 | 16 | var TOKEN_NAMES = { 17 | '+': 'positive', 18 | '-': 'negative', 19 | '@': 'meta' 20 | }; 21 | 22 | return { 23 | token: function (stream) { 24 | var tw_pos = stream.string.search(/[\t ]+?$/); 25 | 26 | if (!stream.sol() || tw_pos === 0) { 27 | stream.skipToEnd(); 28 | return ("error " + ( 29 | TOKEN_NAMES[stream.string.charAt(0)] || '')).replace(/ $/, ''); 30 | } 31 | 32 | var token_name = TOKEN_NAMES[stream.peek()] || stream.skipToEnd(); 33 | 34 | if (tw_pos === -1) { 35 | stream.skipToEnd(); 36 | } else { 37 | stream.pos = tw_pos; 38 | } 39 | 40 | return token_name; 41 | } 42 | }; 43 | }); 44 | 45 | CodeMirror.defineMIME("text/x-diff", "diff"); 46 | 47 | }); 48 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/ecl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: ECL mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 26 | 27 |
28 |

ECL mode

29 |
47 | 50 | 51 |

Based on CodeMirror's clike mode. For more information see HPCC Systems web 52 | site.

53 |

MIME types defined: text/x-ecl.

54 | 55 |
56 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/gherkin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Gherkin mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Gherkin mode

30 |
45 | 48 | 49 |

MIME types defined: text/x-feature.

50 | 51 |
52 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/http/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: HTTP mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

HTTP mode

30 | 31 | 32 |
42 | 43 | 46 | 47 |

MIME types defined: message/http.

48 |
49 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/idl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: IDL mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

IDL mode

30 | 31 |
55 | 67 | 68 |

MIME types defined: text/x-idl.

69 |
70 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/javascript/typescript.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: TypeScript mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

TypeScript mode

30 | 31 | 32 |
54 | 55 | 62 | 63 |

This is a specialization of the JavaScript mode.

64 |
65 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/ntriples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: NTriples mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 28 | 29 |
30 |

NTriples mode

31 |
32 | 39 |
40 | 41 | 44 |

MIME types defined: text/n-triples.

45 |
46 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/pascal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Pascal mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Pascal mode

30 | 31 | 32 |
55 | 56 | 62 | 63 |

MIME types defined: text/x-pascal.

64 |
65 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/perl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Perl mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Perl mode

30 | 31 | 32 |
70 | 71 | 76 | 77 |

MIME types defined: text/x-perl.

78 |
79 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/pig/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Pig Latin mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 26 | 27 |
28 |

Pig Latin mode

29 |
41 | 42 | 49 | 50 |

51 | Simple mode that handles Pig Latin language. 52 |

53 | 54 |

MIME type defined: text/x-pig 55 | (PIG code) 56 | 57 |

58 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/properties/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Properties files mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Properties files mode

30 |
49 | 52 | 53 |

MIME types defined: text/x-properties, 54 | text/x-ini.

55 | 56 |
57 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/ruby/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function () { 5 | var mode = CodeMirror.getMode({indentUnit: 2}, "ruby"); 6 | 7 | function MT(name) { 8 | test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); 9 | } 10 | 11 | MT("divide_equal_operator", 12 | "[variable bar] [operator /=] [variable foo]"); 13 | 14 | MT("divide_equal_operator_no_spacing", 15 | "[variable foo][operator /=][number 42]"); 16 | 17 | })(); 18 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/rust/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Rust mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Rust mode

30 | 31 | 32 |
55 | 56 | 61 | 62 |

MIME types defined: text/x-rustsrc.

63 |
64 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/sass/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Sass mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 29 | 30 |
31 |

Sass mode

32 |
62 | 68 | 69 |

MIME types defined: text/x-sass.

70 |
71 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/solr/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Solr mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 33 | 34 |
35 |

Solr mode

36 | 37 |
38 | 47 |
48 | 49 | 55 | 56 |

MIME types defined: text/x-solr.

57 |
58 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/sparql/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: SPARQL mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 28 | 29 |
30 |

SPARQL mode

31 |
55 | 61 | 62 |

MIME types defined: application/sparql-query.

63 | 64 |
65 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/spreadsheet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Spreadsheet mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 28 | 29 |
30 |

Spreadsheet mode

31 |
32 | 33 | 40 | 41 |

MIME types defined: text/x-spreadsheet.

42 | 43 |

The Spreadsheet Mode

44 |

Created by Robert Plummer

45 |
46 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/tiddlywiki/tiddlywiki.css: -------------------------------------------------------------------------------- 1 | span.cm-underlined { 2 | text-decoration: underline; 3 | } 4 | 5 | span.cm-strikethrough { 6 | text-decoration: line-through; 7 | } 8 | 9 | span.cm-brace { 10 | color: #170; 11 | font-weight: bold; 12 | } 13 | 14 | span.cm-table { 15 | color: blue; 16 | font-weight: bold; 17 | } 18 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/tiki/tiki.css: -------------------------------------------------------------------------------- 1 | .cm-tw-syntaxerror { 2 | color: #FFF; 3 | background-color: #900; 4 | } 5 | 6 | .cm-tw-deleted { 7 | text-decoration: line-through; 8 | } 9 | 10 | .cm-tw-header5 { 11 | font-weight: bold; 12 | } 13 | 14 | .cm-tw-listitem:first-child { /*Added first child to fix duplicate padding when highlighting*/ 15 | padding-left: 10px; 16 | } 17 | 18 | .cm-tw-box { 19 | border-top-width: 0px ! important; 20 | border-style: solid; 21 | border-width: 1px; 22 | border-color: inherit; 23 | } 24 | 25 | .cm-tw-underline { 26 | text-decoration: underline; 27 | } -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/turtle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Turtle mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Turtle mode

30 |
44 | 50 | 51 |

MIME types defined: text/turtle.

52 | 53 |
54 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/vbscript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: VBScript mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

VBScript mode

30 | 31 | 32 |
49 | 50 | 56 | 57 |

MIME types defined: text/vbscript.

58 |
59 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/xml/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: http://codemirror.net/LICENSE 3 | 4 | (function () { 5 | var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; 6 | 7 | function MT(name) { 8 | test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); 9 | } 10 | 11 | MT("matching", 12 | "[tag&bracket <][tag top][tag&bracket >]", 13 | " text", 14 | " [tag&bracket <][tag inner][tag&bracket />]", 15 | "[tag&bracket ]"); 16 | 17 | MT("nonmatching", 18 | "[tag&bracket <][tag top][tag&bracket >]", 19 | " [tag&bracket <][tag inner][tag&bracket />]", 20 | " [tag&bracket ]"); 21 | 22 | MT("doctype", 23 | "[meta ]", 24 | "[tag&bracket <][tag top][tag&bracket />]"); 25 | 26 | MT("cdata", 27 | "[tag&bracket <][tag top][tag&bracket >]", 28 | " [atom ]", 30 | "[tag&bracket ]"); 31 | 32 | // HTML tests 33 | mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); 34 | 35 | MT("selfclose", 36 | "[tag&bracket <][tag html][tag&bracket >]", 37 | " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", 38 | "[tag&bracket ]"); 39 | 40 | MT("list", 41 | "[tag&bracket <][tag ol][tag&bracket >]", 42 | " [tag&bracket <][tag li][tag&bracket >]one", 43 | " [tag&bracket <][tag li][tag&bracket >]two", 44 | "[tag&bracket ]"); 45 | 46 | MT("valueless", 47 | "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); 48 | 49 | MT("pThenArticle", 50 | "[tag&bracket <][tag p][tag&bracket >]", 51 | " foo", 52 | "[tag&bracket <][tag article][tag&bracket >]bar"); 53 | 54 | })(); 55 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/mode/z80/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CodeMirror: Z80 assembly mode 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 27 | 28 |
29 |

Z80 assembly mode

30 | 31 | 32 |
47 | 48 | 53 | 54 |

MIME type defined: text/x-z80.

55 |
56 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codemirror", 3 | "version": "5.0.0", 4 | "main": "lib/codemirror.js", 5 | "description": "In-browser code editing made bearable", 6 | "licenses": [ 7 | { 8 | "type": "MIT", 9 | "url": "http://codemirror.net/LICENSE" 10 | } 11 | ], 12 | "directories": { 13 | "lib": "./lib" 14 | }, 15 | "scripts": { 16 | "test": "node ./test/run.js" 17 | }, 18 | "devDependencies": { 19 | "node-static": "0.6.0", 20 | "phantomjs": "1.9.2-5", 21 | "blint": ">=0.1.1" 22 | }, 23 | "bugs": "http://github.com/codemirror/CodeMirror/issues", 24 | "keywords": [ 25 | "JavaScript", 26 | "CodeMirror", 27 | "Editor" 28 | ], 29 | "homepage": "http://codemirror.net", 30 | "maintainers": [ 31 | { 32 | "name": "Marijn Haverbeke", 33 | "email": "marijnh@gmail.com", 34 | "web": "http://marijnhaverbeke.nl" 35 | } 36 | ], 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/codemirror/CodeMirror.git" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/ambiance-mobile.css: -------------------------------------------------------------------------------- 1 | .cm-s-ambiance.CodeMirror { 2 | -webkit-box-shadow: none; 3 | -moz-box-shadow: none; 4 | box-shadow: none; 5 | } 6 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/cobalt.css: -------------------------------------------------------------------------------- 1 | .cm-s-cobalt.CodeMirror { 2 | background: #002240; 3 | color: white; 4 | } 5 | 6 | .cm-s-cobalt div.CodeMirror-selected { 7 | background: #b36539 !important; 8 | } 9 | 10 | .cm-s-cobalt.CodeMirror ::selection { 11 | background: rgba(179, 101, 57, .99); 12 | } 13 | 14 | .cm-s-cobalt.CodeMirror ::-moz-selection { 15 | background: rgba(179, 101, 57, .99); 16 | } 17 | 18 | .cm-s-cobalt .CodeMirror-gutters { 19 | background: #002240; 20 | border-right: 1px solid #aaa; 21 | } 22 | 23 | .cm-s-cobalt .CodeMirror-guttermarker { 24 | color: #ffee80; 25 | } 26 | 27 | .cm-s-cobalt .CodeMirror-guttermarker-subtle { 28 | color: #d0d0d0; 29 | } 30 | 31 | .cm-s-cobalt .CodeMirror-linenumber { 32 | color: #d0d0d0; 33 | } 34 | 35 | .cm-s-cobalt .CodeMirror-cursor { 36 | border-left: 1px solid white !important; 37 | } 38 | 39 | .cm-s-cobalt span.cm-comment { 40 | color: #08f; 41 | } 42 | 43 | .cm-s-cobalt span.cm-atom { 44 | color: #845dc4; 45 | } 46 | 47 | .cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { 48 | color: #ff80e1; 49 | } 50 | 51 | .cm-s-cobalt span.cm-keyword { 52 | color: #ffee80; 53 | } 54 | 55 | .cm-s-cobalt span.cm-string { 56 | color: #3ad900; 57 | } 58 | 59 | .cm-s-cobalt span.cm-meta { 60 | color: #ff9d00; 61 | } 62 | 63 | .cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { 64 | color: #9effff; 65 | } 66 | 67 | .cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def { 68 | color: white; 69 | } 70 | 71 | .cm-s-cobalt span.cm-bracket { 72 | color: #d8d8d8; 73 | } 74 | 75 | .cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { 76 | color: #ff9e59; 77 | } 78 | 79 | .cm-s-cobalt span.cm-link { 80 | color: #845dc4; 81 | } 82 | 83 | .cm-s-cobalt span.cm-error { 84 | color: #9d1e15; 85 | } 86 | 87 | .cm-s-cobalt .CodeMirror-activeline-background { 88 | background: #002D57 !important; 89 | } 90 | 91 | .cm-s-cobalt .CodeMirror-matchingbracket { 92 | outline: 1px solid grey; 93 | color: white !important 94 | } 95 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/eclipse.css: -------------------------------------------------------------------------------- 1 | .cm-s-eclipse span.cm-meta { 2 | color: #FF1717; 3 | } 4 | 5 | .cm-s-eclipse span.cm-keyword { 6 | line-height: 1em; 7 | font-weight: bold; 8 | color: #7F0055; 9 | } 10 | 11 | .cm-s-eclipse span.cm-atom { 12 | color: #219; 13 | } 14 | 15 | .cm-s-eclipse span.cm-number { 16 | color: #164; 17 | } 18 | 19 | .cm-s-eclipse span.cm-def { 20 | color: #00f; 21 | } 22 | 23 | .cm-s-eclipse span.cm-variable { 24 | color: black; 25 | } 26 | 27 | .cm-s-eclipse span.cm-variable-2 { 28 | color: #0000C0; 29 | } 30 | 31 | .cm-s-eclipse span.cm-variable-3 { 32 | color: #0000C0; 33 | } 34 | 35 | .cm-s-eclipse span.cm-property { 36 | color: black; 37 | } 38 | 39 | .cm-s-eclipse span.cm-operator { 40 | color: black; 41 | } 42 | 43 | .cm-s-eclipse span.cm-comment { 44 | color: #3F7F5F; 45 | } 46 | 47 | .cm-s-eclipse span.cm-string { 48 | color: #2A00FF; 49 | } 50 | 51 | .cm-s-eclipse span.cm-string-2 { 52 | color: #f50; 53 | } 54 | 55 | .cm-s-eclipse span.cm-qualifier { 56 | color: #555; 57 | } 58 | 59 | .cm-s-eclipse span.cm-builtin { 60 | color: #30a; 61 | } 62 | 63 | .cm-s-eclipse span.cm-bracket { 64 | color: #cc7; 65 | } 66 | 67 | .cm-s-eclipse span.cm-tag { 68 | color: #170; 69 | } 70 | 71 | .cm-s-eclipse span.cm-attribute { 72 | color: #00c; 73 | } 74 | 75 | .cm-s-eclipse span.cm-link { 76 | color: #219; 77 | } 78 | 79 | .cm-s-eclipse span.cm-error { 80 | color: #f00; 81 | } 82 | 83 | .cm-s-eclipse .CodeMirror-activeline-background { 84 | background: #e8f2ff !important; 85 | } 86 | 87 | .cm-s-eclipse .CodeMirror-matchingbracket { 88 | outline: 1px solid grey; 89 | color: black !important; 90 | } 91 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/elegant.css: -------------------------------------------------------------------------------- 1 | .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { 2 | color: #762; 3 | } 4 | 5 | .cm-s-elegant span.cm-comment { 6 | color: #262; 7 | font-style: italic; 8 | line-height: 1em; 9 | } 10 | 11 | .cm-s-elegant span.cm-meta { 12 | color: #555; 13 | font-style: italic; 14 | line-height: 1em; 15 | } 16 | 17 | .cm-s-elegant span.cm-variable { 18 | color: black; 19 | } 20 | 21 | .cm-s-elegant span.cm-variable-2 { 22 | color: #b11; 23 | } 24 | 25 | .cm-s-elegant span.cm-qualifier { 26 | color: #555; 27 | } 28 | 29 | .cm-s-elegant span.cm-keyword { 30 | color: #730; 31 | } 32 | 33 | .cm-s-elegant span.cm-builtin { 34 | color: #30a; 35 | } 36 | 37 | .cm-s-elegant span.cm-link { 38 | color: #762; 39 | } 40 | 41 | .cm-s-elegant span.cm-error { 42 | background-color: #fdd; 43 | } 44 | 45 | .cm-s-elegant .CodeMirror-activeline-background { 46 | background: #e8f2ff !important; 47 | } 48 | 49 | .cm-s-elegant .CodeMirror-matchingbracket { 50 | outline: 1px solid grey; 51 | color: black !important; 52 | } 53 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/neat.css: -------------------------------------------------------------------------------- 1 | .cm-s-neat span.cm-comment { 2 | color: #a86; 3 | } 4 | 5 | .cm-s-neat span.cm-keyword { 6 | line-height: 1em; 7 | font-weight: bold; 8 | color: blue; 9 | } 10 | 11 | .cm-s-neat span.cm-string { 12 | color: #a22; 13 | } 14 | 15 | .cm-s-neat span.cm-builtin { 16 | line-height: 1em; 17 | font-weight: bold; 18 | color: #077; 19 | } 20 | 21 | .cm-s-neat span.cm-special { 22 | line-height: 1em; 23 | font-weight: bold; 24 | color: #0aa; 25 | } 26 | 27 | .cm-s-neat span.cm-variable { 28 | color: black; 29 | } 30 | 31 | .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { 32 | color: #3a3; 33 | } 34 | 35 | .cm-s-neat span.cm-meta { 36 | color: #555; 37 | } 38 | 39 | .cm-s-neat span.cm-link { 40 | color: #3a3; 41 | } 42 | 43 | .cm-s-neat .CodeMirror-activeline-background { 44 | background: #e8f2ff !important; 45 | } 46 | 47 | .cm-s-neat .CodeMirror-matchingbracket { 48 | outline: 1px solid grey; 49 | color: black !important; 50 | } 51 | -------------------------------------------------------------------------------- /static/md/lib/codemirror/theme/neo.css: -------------------------------------------------------------------------------- 1 | /* neo theme for codemirror */ 2 | 3 | /* Color scheme */ 4 | 5 | .cm-s-neo.CodeMirror { 6 | background-color: #ffffff; 7 | color: #2e383c; 8 | line-height: 1.4375; 9 | } 10 | 11 | .cm-s-neo .cm-comment { 12 | color: #75787b 13 | } 14 | 15 | .cm-s-neo .cm-keyword, .cm-s-neo .cm-property { 16 | color: #1d75b3 17 | } 18 | 19 | .cm-s-neo .cm-atom, .cm-s-neo .cm-number { 20 | color: #75438a 21 | } 22 | 23 | .cm-s-neo .cm-node, .cm-s-neo .cm-tag { 24 | color: #9c3328 25 | } 26 | 27 | .cm-s-neo .cm-string { 28 | color: #b35e14 29 | } 30 | 31 | .cm-s-neo .cm-variable, .cm-s-neo .cm-qualifier { 32 | color: #047d65 33 | } 34 | 35 | 36 | /* Editor styling */ 37 | 38 | .cm-s-neo pre { 39 | padding: 0; 40 | } 41 | 42 | .cm-s-neo .CodeMirror-gutters { 43 | border: none; 44 | border-right: 10px solid transparent; 45 | background-color: transparent; 46 | } 47 | 48 | .cm-s-neo .CodeMirror-linenumber { 49 | padding: 0; 50 | color: #e0e2e5; 51 | } 52 | 53 | .cm-s-neo .CodeMirror-guttermarker { 54 | color: #1d75b3; 55 | } 56 | 57 | .cm-s-neo .CodeMirror-guttermarker-subtle { 58 | color: #e0e2e5; 59 | } 60 | 61 | .cm-s-neo div.CodeMirror-cursor { 62 | width: auto; 63 | border: 0; 64 | background: rgba(155, 157, 162, 0.37); 65 | z-index: 1; 66 | } 67 | -------------------------------------------------------------------------------- /static/md/lib/jquery.flowchart.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery.flowchart.js v1.1.0 | jquery.flowchart.min.js | jQuery plugin for flowchart.js. | MIT License | By: Pandao | https://github.com/pandao/jquery.flowchart.js | 2015-03-09 */ 2 | (function(factory){if(typeof require==="function"&&typeof exports==="object"&&typeof module==="object"){module.exports=factory}else{if(typeof define==="function"){factory(jQuery,flowchart)}else{factory($,flowchart)}}}(function(jQuery,flowchart){(function($){$.fn.flowChart=function(options){options=options||{};var defaults={"x":0,"y":0,"line-width":2,"line-length":50,"text-margin":10,"font-size":14,"font-color":"black","line-color":"black","element-color":"black","fill":"white","yes-text":"yes","no-text":"no","arrow-end":"block","symbols":{"start":{"font-color":"black","element-color":"black","fill":"white"},"end":{"class":"end-element"}},"flowstate":{"past":{"fill":"#CCCCCC","font-size":12},"current":{"fill":"black","font-color":"white","font-weight":"bold"},"future":{"fill":"white"},"request":{"fill":"blue"},"invalid":{"fill":"#444444"},"approved":{"fill":"#58C4A3","font-size":12,"yes-text":"APPROVED","no-text":"n/a"},"rejected":{"fill":"#C45879","font-size":12,"yes-text":"n/a","no-text":"REJECTED"}}};return this.each(function(){var $this=$(this);var diagram=flowchart.parse($this.text());var settings=$.extend(true,defaults,options);$this.html("");diagram.drawSVG(this,settings)})}})(jQuery)})); -------------------------------------------------------------------------------- /static/md/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "editor.md", 3 | "version": "1.5.0", 4 | "description": "Open source online markdown editor.", 5 | "directories": { 6 | "doc": "docs", 7 | "example": "examples", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/pandao/editor.md.git" 16 | }, 17 | "keywords": [ 18 | "editor.md", 19 | "markdown", 20 | "editor" 21 | ], 22 | "author": "Pandao", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/pandao/editor.md/issues" 26 | }, 27 | "homepage": "https://github.com/pandao/editor.md", 28 | "devDependencies": { 29 | "dateformatter": "^0.1.0", 30 | "gulp": "^3.8.11", 31 | "gulp-concat": "^2.4.2", 32 | "gulp-header": "^1.2.2", 33 | "gulp-jshint": "^1.9.0", 34 | "gulp-minify-css": "^0.4.4", 35 | "gulp-notify": "^2.1.0", 36 | "gulp-rename": "^1.2.0", 37 | "gulp-replace": "^0.5.3", 38 | "gulp-ruby-sass": "^1.0.1", 39 | "gulp-uglifyjs": "^0.6.1", 40 | "gulp-util": "^3.0.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /static/md/plugins/test-plugin/test-plugin.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Test plugin for Editor.md 3 | * 4 | * @file test-plugin.js 5 | * @author pandao 6 | * @version 1.2.0 7 | * @updateTime 2015-03-07 8 | * {@link https://github.com/pandao/editor.md} 9 | * @license MIT 10 | */ 11 | 12 | (function () { 13 | 14 | var factory = function (exports) { 15 | 16 | var $ = jQuery; // if using module loader(Require.js/Sea.js). 17 | 18 | exports.testPlugin = function () { 19 | alert("testPlugin"); 20 | }; 21 | 22 | exports.fn.testPluginMethodA = function () { 23 | /* 24 | var _this = this; // this == the current instance object of Editor.md 25 | var lang = _this.lang; 26 | var settings = _this.settings; 27 | var editor = this.editor; 28 | var cursor = cm.getCursor(); 29 | var selection = cm.getSelection(); 30 | var classPrefix = this.classPrefix; 31 | 32 | cm.focus(); 33 | */ 34 | //.... 35 | 36 | alert("testPluginMethodA"); 37 | }; 38 | 39 | }; 40 | 41 | // CommonJS/Node.js 42 | if (typeof require === "function" && typeof exports === "object" && typeof module === "object") { 43 | module.exports = factory; 44 | } else if (typeof define === "function") // AMD/CMD/Sea.js 45 | { 46 | if (define.amd) { // for Require.js 47 | 48 | define(["editormd"], function (editormd) { 49 | factory(editormd); 50 | }); 51 | 52 | } else { // for Sea.js 53 | define(function (require) { 54 | var editormd = require("./../../editormd"); 55 | factory(editormd); 56 | }); 57 | } 58 | } else { 59 | factory(window.editormd); 60 | } 61 | 62 | })(); 63 | -------------------------------------------------------------------------------- /static/md/scss/editormd.grid.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | .editormd-grid-table { 4 | width: 99%; 5 | display: table; 6 | border: 1px solid #ddd; 7 | border-collapse: collapse; 8 | } 9 | 10 | .editormd-grid-table-row { 11 | width: 100%; 12 | display: table-row; 13 | 14 | a { 15 | font-size: 1.4em; 16 | width: 5%; 17 | height: 36px; 18 | color: #999; 19 | text-align: center; 20 | display: table-cell; 21 | vertical-align: middle; 22 | border: 1px solid #ddd; 23 | text-decoration: none; 24 | @include transition(background-color 300ms ease-out, color 100ms ease-in); 25 | 26 | &.selected { 27 | color: #666; 28 | background-color: #eee; 29 | } 30 | 31 | &:hover { 32 | color: #777; 33 | background-color: #f6f6f6; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /static/md/scss/editormd.tab.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | .editormd-tab { 4 | } 5 | 6 | .editormd-tab-head { 7 | list-style: none; 8 | border-bottom: 1px solid #ddd; 9 | 10 | li { 11 | display: inline-block; 12 | 13 | a { 14 | color: #999; 15 | display: block; 16 | padding: 6px 12px 5px; 17 | text-align: center; 18 | text-decoration: none; 19 | margin-bottom: -1px; 20 | border: 1px solid #ddd; 21 | @include border-top-left-radius(3px); 22 | @include border-top-right-radius(3px); 23 | background: #f6f6f6; 24 | @include transition(all 300ms ease-out); 25 | 26 | &:hover { 27 | color: #666; 28 | background: #eee; 29 | } 30 | } 31 | 32 | &.active a { 33 | color: #666; 34 | background: #fff; 35 | border-bottom-color: #fff; 36 | } 37 | } 38 | 39 | li + li { 40 | margin-left: 3px; 41 | } 42 | } 43 | 44 | .editormd-tab-container { 45 | } 46 | 47 | .editormd-tab-box { 48 | padding: 20px 0; 49 | } -------------------------------------------------------------------------------- /static/md/scss/editormd.themes.scss: -------------------------------------------------------------------------------- 1 | /* Editor.md Dark theme */ 2 | 3 | #{$prefix}theme-dark { 4 | border-color: #1a1a17; 5 | 6 | #{$prefix}toolbar { 7 | background: #1A1A17; 8 | border-color: #1a1a17; 9 | } 10 | 11 | #{$prefix}menu > li > a { 12 | color: #777; 13 | border-color: #1a1a17; 14 | 15 | &:hover, &.active { 16 | border-color: #333; 17 | background: #333; 18 | } 19 | } 20 | 21 | #{$prefix}menu > li.divider { 22 | border-right: 1px solid #111; 23 | } 24 | 25 | .CodeMirror { 26 | border-right: 1px solid rgba(0,0,0,0.1); 27 | } 28 | } -------------------------------------------------------------------------------- /static/md/scss/lib/variables.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | // Global Variables 4 | 5 | $prefix : ".editormd-"; 6 | $color : #666; 7 | $mainColor : #2196F3; 8 | $primaryColor : $mainColor; 9 | $secondColor : #33CC66; 10 | $thirdColor : #999999; 11 | $borderColor : #ddd; -------------------------------------------------------------------------------- /static/md/scss/prettify.scss: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | 3 | /*! Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | .pln { color: #000 } /* plain text */ 6 | 7 | @media screen { 8 | .str { color: #080 } /* string content */ 9 | .kwd { color: #008 } /* a keyword */ 10 | .com { color: #800 } /* a comment */ 11 | .typ { color: #606 } /* a type name */ 12 | .lit { color: #066 } /* a literal value */ 13 | /* punctuation, lisp open bracket, lisp close bracket */ 14 | .pun, .opn, .clo { color: #660 } 15 | .tag { color: #008 } /* a markup tag name */ 16 | .atn { color: #606 } /* a markup attribute name */ 17 | .atv { color: #080 } /* a markup attribute value */ 18 | .dec, .var { color: #606 } /* a declaration; a variable name */ 19 | .fun { color: red } /* a function name */ 20 | } 21 | 22 | /* Use higher contrast and text-weight for printable form. */ 23 | @media print, projection { 24 | .str { color: #060 } 25 | .kwd { color: #006; font-weight: bold } 26 | .com { color: #600; font-style: italic } 27 | .typ { color: #404; font-weight: bold } 28 | .lit { color: #044 } 29 | .pun, .opn, .clo { color: #440 } 30 | .tag { color: #006; font-weight: bold } 31 | .atn { color: #404 } 32 | .atv { color: #060 } 33 | } 34 | 35 | /* Put a border around prettyprinted code snippets. */ 36 | pre.prettyprint { padding: 2px; border: 1px solid #888 } 37 | 38 | /* Specify class=linenums on a pre to get line numbering */ 39 | ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ 40 | li.L0, 41 | li.L1, 42 | li.L2, 43 | li.L3, 44 | li.L5, 45 | li.L6, 46 | li.L7, 47 | li.L8 { list-style-type: none } 48 | /* Alternate shading for lines */ 49 | li.L1, 50 | li.L3, 51 | li.L5, 52 | li.L7, 53 | li.L9 { background: #eee } -------------------------------------------------------------------------------- /templates/admin/category_add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dashboard - Admin 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |

添加分类 返回列表

15 |
16 | 25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /templates/admin/page_add.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dashboard - Admin 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

添加页面 返回列表

16 |
17 | 32 |
33 | 34 | 35 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /templates/default/404.html: -------------------------------------------------------------------------------- 1 | {{template "header.html" .}} 2 |
3 |
4 |
5 |

6 | 很抱歉,您要找的页面不存在 7 |

8 |
9 | 返回首页 10 | 联系我们 11 |
12 |
13 |
14 |
15 | {{template "footer.html" .}} -------------------------------------------------------------------------------- /templates/default/about.html: -------------------------------------------------------------------------------- 1 | {{template "header.html" .}} 2 |
3 |
4 |
5 |

6 | 关于我 7 |

8 | 9 |
10 |
11 |
12 | {{template "footer.html" .}} -------------------------------------------------------------------------------- /templates/default/page.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 |
4 |
5 |
6 |

{{.page.Title}}

7 | 8 |
9 | 10 |
11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | {{end}} -------------------------------------------------------------------------------- /templates/default/post.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 |
4 |
5 |
6 |

{{.post.Title}}

7 | 18 |
19 | 20 |
21 |
22 | 23 |
24 | 25 |
26 |
27 |
28 | 29 |
30 |
31 | {{end}} -------------------------------------------------------------------------------- /templates/default/tag.html: -------------------------------------------------------------------------------- 1 | {{define "content"}} 2 |
3 |
4 |
5 |
6 | 12 |
13 |
14 |
15 |
16 | {{end}} -------------------------------------------------------------------------------- /tests/auth_test.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import ( 4 | "golang.org/x/crypto/bcrypt" 5 | "testing" 6 | ) 7 | 8 | func TestName(t *testing.T) { 9 | password, _ := bcrypt.GenerateFromPassword([]byte("123456"), 8) 10 | t.Log(string(password)) 11 | } 12 | --------------------------------------------------------------------------------